Skip to content

WO-08: in-app chat in direct-model mode (stacked on #3) - #4

Merged
RoseBludd merged 1 commit into
devvy/wo-02-per-dot-memoryfrom
devvy/wo-08-direct-chat-ui
Oct 16, 2026
Merged

RoseBludd merged 1 commit into
devvy/wo-02-per-dot-memoryfrom
devvy/wo-08-direct-chat-ui

Conversation

@RoseBludd

Copy link
Copy Markdown
Owner

WO-08: in-app chat panel in direct-model mode

Base: stacked on #3 (head b31611c), because #1, #2 and #3 weren't merged into devvy/host-base-timeouts yet (it was still at 61dff53 at 02:00 CT). Once they land, rebase onto devvy/host-base-timeouts and retarget. The only commit here is f422276.

What changes

Intelligence mode is unchanged: Chat, ThreadList with useThreads, CopilotKitProvider and every control render exactly as before. All new branches are guarded by isDirectMode(workspace), which is GET /api/workspace → mode: "direct-model" from #1.

In direct-model mode:

  • Chat panel: src/client/DirectChat.tsx uses the same layout, CSS classes and components as Chat.tsx: ChatTranscript (markdown bubbles), Mascot, chat-persona, chat-transcript, thinking, chat-error, chat-composer and send-button. Only the transport differs:
    • History: GET /api/conversations/:id/messages loads on open and on reopen.
    • Send: POST /api/conversations/:id/messages {stream:true}, which shows SSE delta events as they arrive, then done.
    • Stop: cancels the request; nothing is saved for that turn.
    • Errors: the server's plain message, and the conversation is restored.
  • State (src/client/direct-chat.ts): DirectChatSession is a small store the component reads with useSyncExternalStore, plus streamReply (SSE parser) and loadHistory.
  • Threads: the sidebar uses LocalThreadList, the same ThreadList markup with no Intelligence useThreads. Creating a thread from the start composer and the New chat buttons use POST /api/conversations (WO-07: direct-model mode (Dot chat, threads, tasks without Intelligence) #1).
  • Model: shown in the chat header and on the empty Dot card (dot.model from WO-03: per-Dot model and desk key (stacked on #1) #2, otherwise the server default from /api/workspace).
  • Hidden (they need Intelligence): voice, save-as-page, attachments, source link, the computer pane and toggle, Spaces/pages navigation and view, and Create/Edit Dot and Space (the direct routes answer 501). A single plain note replaces them: "Voice, computers and pages need Intelligence. This server runs Dots on the model directly, so chat and scheduled tasks work here." Schedule a task stays, since tasks work in direct mode. The top badge reads DIRECT MODEL. No CopilotKitProvider is mounted.
  • WorkspaceState gains optional mode and model, matching the WO-07: direct-model mode (Dot chat, threads, tasks without Intelligence) #1 /api/workspace response.

Reused components (cited)

Component Where Reused for
Chat transcript src/client/ChatTranscript.tsx Message rendering (markdown, user/assistant bubbles), unchanged
Chat layout and classes src/client/Chat.tsx, style.css (live-chat, chat-persona, chat-composer, thinking, chat-error) Same structure and look; no new CSS
Mascot src/client/Mascot.tsx Header persona with working, paused and idle states
Thread list src/client/ThreadList.tsx Same markup through ThreadListView; the Intelligence path still uses useThreads
API auth src/client/api.ts (authHeaders, ApiError) Owner-token header and error shape
Direct-model routes #1 src/server/direct-model/routes.ts History, send and stream endpoints
Per-Dot model #2 Dot.model Model label

Acceptance and proof

tests/direct-chat.test.tsx has 7 tests. The client runs against the real #1 routes (createApp + DirectModel), with a stub model that streams in pieces:

Criterion Test
Send, then a streamed reply appears piece by piece and is saved sends a message and shows the reply as it streams, then saves it (asserts the intermediate states Hel, Hello , Hello there)
History loads on reopen loads saved history when a conversation is reopened
Clean errors shows the server error and restores the conversation when a turn fails
SSE parsing across chunk boundaries, error event, interrupted stream parses split SSE chunks and reports a stream error event
Intelligence-only controls hidden, model shown, existing transcript used renders history with the existing transcript, shows the model and hides Intelligence-only controls
Thread list without the Intelligence thread service (useThreads is mocked to throw) lists local conversations without the Intelligence thread service
Mode detection and model label detects direct mode and labels the Dot model

Results:

Screenshot: a real browser run (headless Chromium through Playwright) against the built server (dist/server/server/index.js) with no Intelligence key and OPENAI_BASE_URL pointed at a local streaming stub. The script started a conversation, waited for the streamed reply, reloaded, reopened the thread and confirmed history loaded. It also checked for the model label and the note, and confirmed there were 0 voice buttons and 0 computer buttons. Saved on the shared box at /workspace/projects/opendots-failover/proof/ui-chat-direct-model.png.

Not in this PR

  • Editing a Dot (including its model) from the UI in direct mode: the Dot dialog uses PUT /api/dots/:id, which answers 501 in direct mode. The model can be set with PUT /api/dots/:id/model (WO-03: per-Dot model and desk key (stacked on #1) #2). A follow-up can point the dialog at that route.

… and history on the WO-07 routes; Intelligence-only controls hidden (WO-08)

When /api/workspace reports mode direct-model, the chat column renders DirectChat (reusing ChatTranscript, Mascot and the chat-composer layout) and the sidebar uses LocalThreadList instead of the Intelligence thread service. Shows the Dot model (WO-03). Voice, computer, pages and Dot/Space editing are hidden with one plain note. Intelligence mode renders exactly as before.
@RoseBludd
RoseBludd merged commit fd1352b into devvy/wo-02-per-dot-memory Oct 16, 2026
RoseBludd added a commit that referenced this pull request Oct 16, 2026
Stack catch-up: land #2 (WO-03), #3 (WO-02), #4 (WO-08) on devvy/host-base-timeouts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant