Frontend components (agency-ui) =============================== **agency-ui** maps each schema ``type`` string to a Vue component via ``componentRegistry`` in ``src/renderer/registry.ts``. ``UiRenderer`` looks up ``node.type`` and renders recursively. Source of truth for the type list is that registry (and ``src/schema/ui.ts``). This page summarises what each registration is for. Self-rendering types -------------------- These nodes iterate ``children`` themselves (no default child slot from ``UiRenderer``): ``page``, ``split``, ``desktop``, ``window``. Layout ------ .. list-table:: :header-rows: 1 :widths: 22 28 50 * - Schema ``type`` - Vue component - Role * - ``page`` - ``AgencyPage`` - Top-level page chrome * - ``panel`` - ``AgencyPanel`` - Generic panel container * - ``pad`` - ``AgencyPad`` - Padded content region * - ``split`` - ``AgencySplit`` - Splitpanes (see :doc:`schema` for ``direction``) * - ``sidebar`` - ``AgencySidebar`` - Side navigation region * - ``toolbar`` - ``AgencyToolbar`` - Toolbar strip * - ``menu`` - ``AgencyMenu`` - Menu container * - ``menu-item`` - ``AgencyMenuItem`` - Single menu entry Primitives ---------- .. list-table:: :header-rows: 1 :widths: 22 28 50 * - Schema ``type`` - Vue component - Role * - ``card`` - ``AgencyCard`` - Card surface with optional title * - ``button`` / ``agency-button`` - ``AgencyButton`` - Button; optional ``action``. Address: inherited prefix + ``name`` * - ``agency-mission`` - ``AgencyMission`` - One mission instance (``channel`` + ``uuid``). Not the catalog explorer. * - ``progress`` - ``AgencyProgress`` - Progress / indeterminate bar * - ``text`` - ``AgencyText`` - Plain text * - ``markdown`` - ``AgencyMarkdown`` - Markdown body Desktop chrome -------------- .. list-table:: :header-rows: 1 :widths: 22 28 50 * - Schema ``type`` - Vue component - Role * - ``desktop`` - ``AgencyDesktop`` - Root desktop surface (icons + floating windows) * - ``desktop-icon`` - ``AgencyDesktopIcon`` - Desktop launcher icon * - ``window`` - ``AgencyWindow`` - Registers window state; hosts child schema * - ``dock`` - ``AgencyDock`` - Schema stub (no UI; kept for fixtures compatibility) * - (chrome) - ``AgencyAgentFace`` - 128×128 agent portrait + CSS overlay (eyes / mouth). Moods: idle, thinking, speaking (South Park jaw). First desktop icon (chrome, not schema) and Agents explorer. Not a schema node. Window chrome (not schema types) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Native Vue MDI — **no WinBox**. State lives in Pinia ``windowsStore`` (``agency-ui/src/stores/windows.ts``). Chrome pose (``z`` / rotation / scale) is on the store + desktop snapshot, not overlay. DSM ``desktop.projection`` ``flat | perspective`` is a thin 3D stage (drawer / deck / Options). In perspective the seat is an FPS helm: triple glass 2 · 1 · 3, world origin at the center pane's bottom edge, identity camera ``{ x: 0, y: -400, z: 72 }``. WASD walks; Space is mouselook + pointer lock (no RMB look); wheel is head height; Ctrl crouches from the current Y. Sit / Home resets the camera and does not move windows. There is no desk, orbit gizmo, or pistol mode. Windows carry ``screen`` (left / center / right) and hop on release past a hinge. 2D minimize is a top-right quarter-width column (the stack scales if it does not fit); 3D minimize is a bottom carousel. Min / restore / maximize interpolate ``left`` / ``top`` / size / scale. Restore seeds ``minimized`` before ``openAddress`` so F5 does not dump shelved windows back onto the desktop. The body is ``transform-style: flat``. Wheel on maximize changes chrome ``pose.scale`` (CSS 3D, origin center) 5%, anchored on the cursor so the window grows under the mouse, never larger than the viewport. On F5 a window under the app bar is pushed down; overflow on two sides pins to those edges. Scale is in the desktop snapshot. Mosaic (``tileMosaic``) lays out every open window in a CCTV grid; the active window gets the featured pane. .. list-table:: :header-rows: 1 :widths: 28 32 40 * - Component - File - Role * - ``AgencyWindowFrame`` - ``components/desktop/AgencyWindowFrame.vue`` - Title bar, drag, resize, min / max / close * - ``AgencyWindowsList`` - ``components/desktop/AgencyWindowsList.vue`` - Open-window list for the shell drawer (**Windows** tab) * - ``ShellDrawerHeader`` - ``components/shell/ShellDrawerHeader.vue`` - Drawer profile (48px avatar + name) + Media preview * - ``ShellDrawerTools`` - ``components/shell/ShellDrawerTools.vue`` - Theme, mosaic, 3D stage, labeled Install * - ``ShellBarActivity`` - ``components/shell/ShellBarActivity.vue`` - App-bar **System** icon: channel glyph (two PCs) while idle; REST / telemetry glyphs during recent activity. Click opens System. * - ``AgencyInboxList`` - ``components/shell/AgencyInboxList.vue`` - Drawer **Inbox** tab (pending HITL; opens reply dialog) * - ``AgencySitesList`` - ``components/shell/AgencySitesList.vue`` - External links in ``user.me`` **Sites** tab * - ``useWindowDrag`` - ``composables/useWindowDrag.ts`` - Pointer drag on the title bar **Lifecycle** (persistent windows): .. list-table:: :header-rows: 1 :widths: 18 62 * - State - Meaning * - ``closed`` - ``open=false`` — not listed in the drawer. Layout (``x/y`` + chrome pose) is forgotten; the next open takes a cascade slot. * - floating - ``open=true``, ``minimized=false``, ``maximized=false`` — ``x/y/w/h`` * - maximized - Same chrome as mobile: fills below the app bar, no window title bar, title + min/close in the app bar (desktop also has restore). Flat app bar (no shadow). Only one maximized window. * - minimized - 2D: top-right shelf (¼ width). 3D: bottom carousel. Listed dimmed in the drawer. Ephemeral windows (``props.ephemeral``) are removed from schema + store on close. **Typography** — the Agency desktop uses a compact scale inside window bodies: 13px body, 12px labels/captions (``styles/main.scss``, ``styles/explorer.scss``). System pane toolbars use icon-only actions with ``title`` tooltips. Explorer form styling ~~~~~~~~~~~~~~~~~~~~~ Shared field chrome lives in ``agency-ui/src/styles/explorer.scss`` (imported from ``main.scss``). **Do not** add per-component scoped CSS for Vuetify ``v-text-field`` / ``v-select`` / ``v-textarea`` sizing in explorers or admin windows — use the markup hooks below so every surface matches. .. list-table:: :header-rows: 1 :widths: 28 72 * - Hook class - Use * - ``agency-explorer`` - Root on list+ficha explorers (Agents, Missions, Models, …). Layout: ``explorer-list`` + ``explorer-detail``. Photos/Agents/Missions/Tools use ``agency-split`` (resizable); others keep a 260px list. Photos/Agents/Missions/Tools add ``agency-explorer--chrome``: ``AgencyChromeBar`` header + list Filter + hideable detail + footer. * - ``agency-chrome-bar`` - Shared 40px header / footer (``AgencyChromeBar``). Explorers, secretary chat, execution chat, and Media all use it. Buttons inside windows use ``--agency-btn-font-size`` (Image / Speak). * - ``detail-form`` - Right-hand CRUD column. Flex column; children are full-width Vuetify fields with ``density="compact"`` and ``variant="outlined"``. * - ``list-toolbar`` / ``list-toolbar--run`` - Sidebar toolbar, 40px (same as window tabs). ``--run`` = column stack. Selects keep native compact height (not the single-line crunch). * - ``detail-header__run`` / ``agency-chrome-bar__end`` - Top-bar run cluster, right side, hide-detail last. Photos: Open in Media. Missions: Agent (plain) + play. Agents: **Chat**. Tools: Sync (icon). Selected title in the chrome-bar title slot. * - ``list-toolbar__filter`` - Fixed-width filter select in a horizontal toolbar (Executions). * - ``form-top`` - Two-column grid row inside ``detail-form`` (e.g. Name + Model). * - ``form-fill-area`` - ``v-textarea`` that grows to fill space above the footer (Prompt, Instructions, Notes, Summary). * - ``form-tools`` - Multi-select with chips (Tools); natural height, wraps chips. * - ``agency-form-fields`` - Admin **Options** and similar preference forms (not inside ``agency-explorer``). CSS variables (on ``detail-form``, ``agency-form-fields``, ``list-toolbar``): - ``--agency-field-input-size`` — 13px value text - ``--agency-field-label-size`` — 11px labels - ``--agency-field-min-height`` — 28px single-line input (detail-form only) Domain-only layout (flags row, file upload row, etc.) may stay in component scoped CSS; field paint does not. Workbench chrome (split tool windows) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tool windows that pair a navigation tree with a detail pane — **UI Schema**, **Help** — share ``agency-ui/src/styles/workbench.scss`` (imported from ``main.scss``). Explorers keep ``explorer.scss``; the two are separate chromes for different shapes. .. list-table:: :header-rows: 1 :widths: 30 70 * - Hook class - Use * - ``agency-split`` - Root ````. Styles the splitter; panes get the canvas background. * - ``agency-pane`` / ``agency-pane--nav`` - Column inside a ````. ``--nav`` is the canvas (same floor as explorer lists). The other pane's body is ``surface`` — the raised sheet used under window tabs. * - ``agency-pane__toolbar`` / ``__title`` - Pane header, 40px (same as window tabs), uppercase muted title. Use a plain ``div``, not ``v-toolbar``, so both panes align. * - ``agency-pane__body`` / ``--flush`` - Scrolling region. ``--flush`` for children that scroll themselves (AG Grid, terminals). * - ``agency-tree`` - On ``v-treeview``. File-explorer density: 22px rows, 16px toggle gutter (leaves keep an empty ``v-treeview-item__level`` of the same width so icons line up), 12px indent, 12.5px labels. * - ``agency-grid`` - On an AG Grid host (``ag-theme-quartz`` / ``-dark``). 22px rows, 24px header, same canvas/border tokens as the tree. Set ``rowHeight`` / ``headerHeight`` on the grid to match — CSS vars alone do not size rows. Palette is the Vuetify theme in ``agency-ui/src/theme/agency.ts`` — ``background`` (canvas) and ``surface`` (raised sheet). Shared as ``--agency-wb-canvas`` / ``--agency-wb-subtle``. Light/dark is the user toggle. Do not add a second hex palette. Window title bars, ``AgencyChromeBar`` headers/footers, explorer list-toolbars, System pane toolbars, Help pane toolbars, and window tabs are all 40px (``--agency-chrome-height``). Buttons inside windows use ``--agency-btn-font-size`` (0.875rem — Image / Speak). Tab labels are 13px with a 2px primary underline. Explorer ``v-btn`` height rules must exclude ``.v-tab``. Header UUID / agent face is 26px. The shell app bar is always flat (no drop shadow). Vuetify 4 emits its component CSS inside ``@layer vuetify-components``, so these unlayered rules win without ``!important``. Data display ------------ .. list-table:: :header-rows: 1 :widths: 22 28 50 * - Schema ``type`` - Vue component - Role * - ``list`` - ``AgencyList`` - Simple list * - ``table`` - ``AgencyTable`` - Table * - ``tree`` - ``AgencyTree`` - Tree * - ``ag-grid`` - ``AgencyAgGrid`` - AG Grid table Agents & missions ----------------- .. list-table:: :header-rows: 1 :widths: 24 30 46 * - Schema ``type`` - Vue component - Role * - ``agent-explorer`` - ``AgencyAgentExplorer`` - Agent catalog: Filter + namespace list, hideable tabs (Properties, Tools, Executions). Top bar: selected name; Chat then hide-detail. * - ``agent-chat`` - ``AgencyAgentChat`` - Alias of ``agent-interface`` (legacy type name) * - ``agent-interface`` - ``AgencyAgentInterface`` - Persistent secretary conversation with the user's **active Agent**. Hydrates from REST ``/api/thread/`` and applies Messenger deltas on ``/channel/``. **New conversation** archives the previous personal Thread. Image attach/drop like agent-test (compose, then Send). A retractable split pane (closed by default) hosts Display previews when Veronica ``open_window``s a screen. Address: ``secretary``. Not ``agent-test``. * - ``agent-test`` - ``AgencyAgentTest`` - Multi-turn test chat on ``/channel/agent/``; optional mic STT + TTS via ``/api/voice/``; TTS uses the agent's ``Voice`` (fallback: user system voice). Speaks ``forSpeech`` (no ``**`` / emoji). Vision attach: base64 on the wire **and** a ``Photo`` row under ``/media/uploads/user-/upload/`` * - ``agent-status`` - ``AgencyAgentStatus`` - Agent status indicator * - ``task-progress`` - ``AgencyTaskProgress`` - Task progress UI * - ``log`` - ``AgencyLog`` - Simple log panel * - ``mission-explorer`` - ``AgencyMissionExplorer`` - Mission catalog + dispatch; Filter + namespace list, hideable tabs Properties / Prompt / Loop / Executions. Top bar: title; Agent + play then hide-detail. * - ``execution-explorer`` - ``AgencyExecutionExplorer`` - Execution list * - ``execution-view`` - ``AgencyExecutionView`` - Mission Control execution window: chat + collapsible steps + continue turn; HITL via channel overlay * - ``execution-result`` - ``AgencyExecutionResult`` - Stored execution result view Models & providers ------------------ .. list-table:: :header-rows: 1 :widths: 24 30 46 * - Schema ``type`` - Vue component - Role * - ``model-explorer`` - ``AgencyModelExplorer`` - LLM Model catalog * - ``provider-explorer`` - ``AgencyProviderExplorer`` - Provider catalog (kind, key env, sync) * - ``tool-explorer`` - ``AgencyToolExplorer`` - Tool catalog; ids are ``tools..`` grouped by namespace. Same chrome as Photos/Agents/Missions (Filter, hideable detail, footer). Top bar: selected id; Sync from code (icon). Tabs Properties / Help. Help is a read-only ``
`` (Python docstring; Sync refreshes).

Corpus / RAG
------------

.. list-table::
   :header-rows: 1
   :widths: 26 32 42

   * - Schema ``type``
     - Vue component
     - Role
   * - ``document-explorer``
     - ``AgencyDocumentExplorer``
     - Document catalog
   * - ``knowledge-search``
     - ``AgencyKnowledgeSearch``
     - Workspace search / ask UI
   * - ``document-extraction``
     - ``AgencyDocumentExtraction``
     - Extraction detail for a document
   * - ``photo-explorer``
     - ``AgencyPhotoExplorer``
     - User photo library. Origin select (All / Uploads / Generated) in the
       chrome; list filter + hideable Image / Data split. Drag a row onto
       Veronica, Media, or the wallpaper (thumbnail pin).
   * - ``photo-view``
     - ``AgencyPhotoView``
     - One photo on the desktop (legacy ephemeral Open; Photos now sends Media)
   * - ``agency-media``
     - ``AgencyMediaPlayer``
     - Singleton Media player (images + YouTube). Letterboxed stage; library
       pane on the right, closed by default. Download on the chrome for the
       current image. Drop ``file.image`` (from the PC) or ``photo.*`` (from
       Photos) onto the window / desktop icon — namespaced via Agency Bus
       drop routing. Veronica ``show_media`` / chat click / Photos → Open in
       Media.

Staff administration
--------------------

.. list-table::
   :header-rows: 1
   :widths: 24 30 46

   * - Schema ``type``
     - Vue component
     - Role
   * - ``user-explorer``
     - ``AgencyUserExplorer``
     - Staff-only Users explorer. Filter + list left, detail tabs right
       (Profile, Preferences, Groups). Manage user accounts, preferences,
       and group assignments. Menu → Configuration → **Users** (visible only
       when ``is_staff=True``). Requires ``/api/users/``, ``/api/users//prefs/``,
       ``/api/groups/`` staff endpoints. See :doc:`../../framework/agency/api`.
   * - ``lobby-chat``
     - ``AgencyLobbyChat``
     - Ephemeral public lobby room (not a catalog explorer)

Tools / System / shell
----------------------

.. list-table::
   :header-rows: 1
   :widths: 24 30 46

   * - Schema ``type``
     - Vue component
     - Role
   * - ``log-stream``
     - ``AgencyLogStream`` (Info tab: ``SystemInfoPane``)
     - System window: **Info** (sibling collapsibles Versions / Inference /
       System), Console, Channels, Tasks, Data, Logs (ops SSE: errors,
       tracebacks, restarts, GPU)
   * - ``channel-chat``
     - ``AgencyChannelChat``
     - Channel chat surface
   * - ``channel-console``
     - ``AgencyChannelConsole``
     - Raw channel / monitor console
   * - ``xterm``
     - ``AgencyXterm``
     - Terminal widget
   * - ``schema-inspector``
     - ``AgencySchemaInspector``
     - Inspect current UI schema JSON
   * - ``user-profile``
     - ``AgencyUserProfile``
     - Signed-in user window (**User** · **Options** · **Sites**); opened from drawer profile header
   * - ``options-panel``
     - ``AgencyOptionsPanel``
     - Options / preferences panel
   * - ``stage-interface``
     - ``AgencyStageNav``
     - Helm nav (``stage``): sit / Home resets the camera. FPS —
       WASD, Space look, wheel height, Ctrl crouch. No pistol.
   * - ``camera``
     - ``AgencyCamera``
     - Local webcam preview + device selector; **Ask agent** (JPEG frame + prompt) and
       **Portero watch** loop over ``/channel/agent//`` (requires ``Model.vision``)
   * - ``map``
     - ``AgencyMap``
     - Operator map: dark Carto **Aire** basemap, Esri satellite past zoom 13,
       click-to-fly cursor, optional **Satellite** split pane (lat/lng/alt)
   * - ``help``
     - ``AgencyHelp``
     - Sphinx singlehtml manual (fetch + sanitize, no iframe)
   * - ``lobby-chat``
     - ``AgencyLobbyChat``
     - Ephemeral public chat (Lobby). Desktop icon ``AgencyDesktopLobbyIcon``
       with presence badge; singleton address ``lobby``. Pinia ``lobbyRoom``
       store connects to ``/channel/room/lobby/`` with reconnect backoff. No
       local history beyond the live session. See
       :doc:`../../framework/connections` for the socket protocol.

Adding a component
------------------

1. Implement the Vue SFC under ``agency-ui/src/components/…``
2. Add a TypeScript node type in ``src/schema/ui.ts`` if props are typed
3. Register ``type`` → component in ``src/renderer/registry.ts``
4. Produce nodes from Django / host schema (desktop JSON or dynamic producers)
5. Publish with ``npm run build:django`` / ``./dev ui``

Do not introduce one-off host Vue pages for Agency desktop surfaces.