dock_chat turnThe Agent Dock on every workspace page LOOKED live but FAKED its answer. On send, agent-dock-mount.tsx POSTed the /session-context/resolve authority handshake and then appended a canned i18n string — turnResolved: "Got your message — I'm oriented on this page and ready." — as if it were Atlas. The brain (AgentCore) was never invoked: zero service.name=atlas Dock spans in Logfire. The component doc admitted it: "the brain's streamed reply … is a distinct runtime boundary not wired here."
The Dock's send now launches a real kind:"dock_chat" turn over the ADR-110 broker WebSocket and streams Atlas's answer into the thread. The producers it depends on are already on main: the contract kind/DockChatContext (#1663), the broker routing (#1660), the Atlas dock-chat brain (#1664), and the synced src/gen (#1669).
composer send
→ useDockChatRail.send(text)
→ AgentRailConnection (shared transport; dock launch builder)
→ WS { agentKey:"atlas_dock_chat", kind:"dock_chat",
dockChat:{ surface_key, available_surfaces, granted_permissions,
current_context, counsel_message, thinking_level } }
→ broker routes on kind → AgentCore Atlas dock_chat (#1664)
→ frames: run.accepted → turn.delta* → turn.completed → run.done
→ reduceFrame → streamingMessageMd (live bubble) → committed reply in thread
→ navigate_to (if any) → confirm-first nav chip (dispatcher, never auto-route)
The wizard intake rail and the Dock chat rail are now the same module-scoped connection machinery (atlas-rail-store) — the hard-won reconnect / watchdog / StrictMode-survival logic (Story-1373) is reused, not duplicated. The only agent-specific bit is the launch/query message, injected as a builder. The wizard path is byte-unchanged (its tests pass untouched).
| File | Change |
|---|---|
lib/agents/atlas-rail.ts | buildDockChatLaunch/buildDockChatQuery; RailNavigateTo; reduceFrame + RailState capture a completed turn's navigate_to. |
lib/agents/atlas-rail-store.ts | Connection generalized — injected launch/query builders + generic prime. getAtlasRailConnection (wizard) kept; getDockChatRailConnection added. |
lib/agents/use-dock-chat-rail.ts | New hook: builds DockChatContext from live CPC + surface + permissions + manifest + thinking_level; exposes status/stream/turn/navigateTo/send. |
components/agents/agent-dock-mount.tsx | Swapped HTTP resolve+turnResolved → WS rail; live streaming bubble; commit-once-per-run effect; navigate_to → confirm-first chip; status mapping. |
messages/en.json, hi.json | Deleted the orphan turnResolved key (both locales). |
The DockChatContext blocks (available_surfaces, granted_permissions, current_context) are orientation only. The broker re-resolves real authority from the Clerk session on the socket — a forged client context grants nothing. Browser context never becomes authority.
tsc --noEmit — 0 errors in src/pnpm lintpnpm test (agent rail + dock; wizard rail tests unchanged + green)pnpm buildservice.name=atlas dock_chat trace in Logfire — proven in the deploy step, NOT by this green build. Requires the functions Lambda + agents AgentCore deploys (producers) live first.use-agent-live-rail.ts (the HTTP resolve handshake) is no longer used by the Dock. Left in place — it may be the server-plane authz seam; removal is a separate cleanup once that's confirmed.6 file(s), +448 / -113 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +0 | -1 |
| messages/hi.json | Config | +0 | -1 |
| src/components/agents/agent-dock-mount.tsx | Component | +87 | -48 |
| src/lib/agents/atlas-rail-store.ts | Library | +131 | -61 |
| src/lib/agents/atlas-rail.ts | Library | +94 | -2 |
| src/lib/agents/use-dock-chat-rail.ts | Library | +136 | -0 |