# PR3 Recon — SCREEN 02 · Chat (ship Variation B "Split work canvas") Branch: `feature/warm-hive-redesign`. Maps the **current Chat/agent-runtime** implementation in `apps/web` against `docs/design_handoff_waggle_app/SCREENS.md` §02 + `design-files/screens/chat.html`. **Headline:** the conversation surface, activity stream (steps), tool cards, approval card, model pill, persona pill, composer, artifact card, and provenance primitive **all already exist** and are functional. The **right work-canvas (Variation B's ~42% live-drafting side panel) does NOT exist** — it must be built. There is also **no provenance pill inside the activity stream**, and the agent's streamed "thinking" steps render as a **flat inline list, not the design's collapsible Activity card with `⬡ provenance` pills**. The visual styling is current "Hive DS" (primary/secondary/muted, emerald/amber/sky/violet) — it needs the warm-token migration but the structure is mostly there. --- ## 1. Current structure (with line refs) ### Component tree ``` ChatHost.tsx keep-alive portal host: 1 ChatWindowInstance per visited workspace └ ChatHostInstance portals into per-workspace container; composes title bar └ ChatWindowInstance.tsx data wiring: useChat + useSessions + model/team fetch └ ChatApp.tsx ALL of the chat UI (793 lines) — single big component ├
(chat-header) persona pill · Memory chip · storage/team chips · autonomy · model pill ├ Agent Profile panel (collapsible) ├ Pins bar ├
thread messages.map → bubbles │ └ BlockRenderer (per assistant msg with blocks) │ ├ TextBlock / StepBlock / ToolUseBlock / ArtifactBlock / ModelSwitchBlock │ └ ToolCard (legacy tools[] path) │ └ FeedbackButtons · suggested-action chips │ └ ApprovalGate (pendingApproval) └ composer (textarea + slash menu + attach + send) ``` ### Key file:line anchors - **ChatHost.tsx** — keep-alive via React portals. `ChatSlot` (`:85`) is the seam node `WorkspaceRoute` passes into `WorkspaceDesktopApp`'s `chatSlot` prop. `ChatHostInstance` (`:96`) portals `` into a stable per-workspace `
` (`getChatContainer` `:57`), kept alive (hidden, not unmounted) so in-flight SSE survives navigation. **The split canvas must live INSIDE this kept-alive subtree** (either in ChatApp or a wrapper it renders), or the canvas state is lost on navigation. ChatHost itself only does title + keep-alive; it is NOT the place to add a sibling canvas pane. - **ChatWindowInstance.tsx** — thin data layer. `FALLBACK_MODELS` (`:14`); calls `useChat` (`:98`) and `useSessions` (`:97`); fetches model list/current-model with a 20s retry loop (`:126–211`); `handleModelChange` (`:213`). Passes ~20 props straight into `ChatApp` (`:221`). - **ChatApp.tsx** — the entire rendered surface: - Header bar: `:746` (`data-testid="chat-header"`). Persona picker `:765`; **Memory chip** `:815` (always-visible trust signal, `Brain` icon); storage badge `:829`; team presence `:843`; overflow `⋯` menu in compact mode `:867`; **AutonomyToggle** `:920`; **model picker** `:931`. - `ToolCard` (`:99`) — legacy `msg.tools[]` render path (only used when a msg has no `blocks`). - `ApprovalGate` (`:223`) — the inline approval card with RiskBadge + Allow once / Always allow / Deny / Show details. - `AutonomyToggle` (`:339`) — Ask first / Trusted / Autopilot chip + TTL dropdown. - Thread render `:1050–1191`; per-message bubble `:1093`; `BlockRenderer` invocation `:1115`; plain-content fallback `:1121`; suggested-action chips `:1160`. - Composer `:1194–1236`; slash menu `:1195`; textarea `:1219` ("Message Waggle... (/ for commands)"). - `WorkspaceBriefing` empty-state `:1051` (renders when `messages.length === 0`). - **chat-blocks/** (the progressive-disclosure renderers): - `BlockRenderer.tsx` — switch over block.type; routes completed file-writes to `ArtifactBlock` (`:34`), else `ToolUseBlock`. - `StepBlock.tsx` — a single agent "thinking" step: spinner/check + description. **Flat inline row — NOT wrapped in a collapsible Activity card and has NO provenance pill.** - `ToolUseBlock.tsx` — collapsible tool row (status icon + name + input summary + duration + raw JSON on expand). - `ArtifactBlock.tsx` — the Cowork "artifact card": icon + filename + "Created/Updated by the agent" + **Open in Files** (stashes deep-link + fires `waggle:open-app`). `isArtifactBlock` (`:21`). - `ModelSwitchBlock.tsx` — fallback-model banner. - **chat-header-layout.ts** — pure `shouldCollapseChatHeader(width)` decision (threshold 480px, `:16`); `CHAT_HEADER_OVERFLOW_CONTROLS` / `CHAT_HEADER_PRIMARY_CONTROLS` classify which chips fold. ### Container / layout the canvas must slot into `WorkspaceDesktopApp.tsx:841` — `{/* Body: main canvas + right context panel */}` is a `flex-1 flex overflow-hidden` row. The chat tab renders `chatSlot ?? ` at `:882–902` inside `
`. The chat slot is given the full main column. **The split canvas should be implemented as a horizontal flex INSIDE ChatApp's own root `
` (`:697`)** — append the canvas `