Files
Daniele 505f2e95c1
Nightly Build / build (push) Successful in 7m51s
feat(chat): view context — tell the assistant what you're looking at
An eye next to the paperclip shares what the user has open with their next
message: the page, the folder being browsed, the file open in the viewer and
any highlighted passage (line numbers where a source view exists), plus which
entity a detail page is about. The bag is client-authored {label, value} pairs
in English — the backend only clamps (chars, never bytes), neutralizes the
harness tag and renders one <system-extra> block per message, deduped
consecutively so it appears exactly when the view changed. On by default,
per-device toggle, hover/tap to preview, a chip on every sent message;
docs/view-context.md for users, an updated harness.md clause for the model.
2026-08-23 20:53:30 +01:00

43 lines
2.1 KiB
JavaScript

/**
* Hash routing, shared.
*
* `pageFromHash()` turns `location.hash` into the page id the app navigates by
* (`llm-page-change`'s `detail.page`, the sidebar's `_activePage`, the value the
* view-context store describes). It lives here — and not in `sidebar.js`, where
* it grew — because there are now two readers of it: the menu highlight and the
* view context attached to a message. Two copies of this logic would drift, and
* the drift would be invisible: the assistant would be told the user is on one
* page while the menu highlights another.
*
* The mobile shell (`mobile-app.js`) routes a fixed set of sections of its own
* and does not go through this.
*/
// Every hash segment the app accepts as a page. Anything else falls back to
// `home`, so a hand-typed or stale URL lands on the chat rather than nowhere.
export const KNOWN_PAGES = [
'inbox', 'dashboard', 'tasks', 'projects', 'files', 'models', 'providers',
'approval', 'agents', 'users', 'roles', 'shared-folders', 'connectors',
'connector', 'plugins', 'plugin-detail', 'marketplace', 'profile', 'config',
'llm-requests', 'session', 'system-agents', 'file_viewer', 'tool_detail',
];
export function pageFromHash() {
const hash = location.hash.slice(1);
if (!hash) return 'home';
// Segment ends at the first `/` (e.g. `#session/123`) or `?` (e.g. `#file_viewer?path=...`).
const match = hash.match(/^([^/?]+)/);
const segment = match ? match[1] : '';
// Plugin pages: `#plugin/<plugin_id>/<page_id>` — the route is accepted by
// shape (deep links must survive the async `/api/plugins/pages` load); the
// host reports an error if the page turns out not to exist for this user.
if (segment === 'plugin') {
const m = hash.match(/^plugin\/([^/?]+)\/([^/?]+)/);
return m ? `plugin/${m[1]}/${m[2]}` : 'home';
}
// `connector` (singular) is the per-connector detail page, `connectors` the list.
// `plugin-catalog` is the pre-merge hash of what is now `#plugins`.
const page = segment === 'plugin-catalog' ? 'plugins' : segment;
return KNOWN_PAGES.includes(page) ? page : 'home';
}