diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx index a4978f32..52008275 100644 --- a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx +++ b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx @@ -258,6 +258,49 @@ type ResumeState = { title: string | null; }; +/** + * The chat itself, mounted only once the transcript is in hand and keyed on the session. + * + * Split from the fetch above, and that split is the whole point. `useChat` seeds its message list with + * `useState(initialMessages ?? [])` — read on the FIRST render and never again. So a component that + * fetches and calls `useChat` in one body seeds itself empty, because on that first render the fetch has + * not landed. The early `Loading…` return does not save it: hooks run before it. The messages arrive, the + * hook ignores them, and a commander that had run and answered showed "Send a message to start" over a + * metadata bar reading `1 turn · $0.28`. + * + * `ChatPanelWrapper` has always done it this way — `if (selectedSessionId && resuming) return null` sits + * ABOVE the component that owns the hook, so the hook's first render is its only render with real data. + * Same shape here. + */ +function ResumedCommander({ sessionId, resume }: { sessionId: string; resume: ResumeState }) { + const chat = useChat(undefined, resume.model ?? undefined, { + replaceUrl: false, + context: 'command-hq', + resumeSessionId: sessionId, + initialMessages: resume.messages, + paginate: { sessionId, total: resume.total, initialOffset: resume.offset }, + }); + + return ( +
+ + +
+ ); +} + +/** Fetches the transcript and nothing else. Mounts the chat only when it has one. */ function ExistingCommander({ sessionId }: { sessionId: string }) { const client = useClient(); const [resume, setResume] = useState(undefined); @@ -290,40 +333,11 @@ function ExistingCommander({ sessionId }: { sessionId: string }) { }; }, [sessionId]); - const chat = useChat(undefined, resume?.model ?? undefined, { - replaceUrl: false, - context: 'command-hq', - ...(resume - ? { - resumeSessionId: sessionId, - initialMessages: resume.messages, - paginate: { sessionId, total: resume.total, initialOffset: resume.offset }, - } - : {}), - }); - if (resuming || !resume) { return
Loading…
; } - return ( -
- - -
- ); + return ; } export const CommandHqDetail = () => {