feat(host-service): emit chat:session-changed on the events bus

Closed
HA
1mo ago
+199-12

What

Adds a chat:session-changed message to the host-service /events WebSocket bus, so a client that watches many chat-v3 sessions across hosts (Roster) can react to a push instead of polling chat.listSessions on each host.

Event shape

interface ChatSessionChangedMessage {
  type: "chat:session-changed";
  sessionId: string;
  workspaceId: string;      // the session's scopeId
  status: SessionStatus;    // from @superset/chat/protocol, the value listSessions stores
  live: boolean;            // false once the session is closed, same meaning as getSession's `live`
  occurredAt: number;
}

live is one field more than the original sketch. Closing a session does not change its stored status: listSessions keeps returning the last status (for example idle, or running if a turn was cut off). Without live, the close event would look the same as the event before it.

When it fires

LiveSessionRegistry gets an optional onSessionChanged hook, which createChatRuntime passes through. Every session event a live session writes to its journal goes through the registry's publish wrapper, so the hook sees each status change:

  • Created: the first session event (starting) from LiveSession.start.
  • Status changed: any session event whose status differs from the last one reported for that session. Session events that keep the same status (title, mode, queue-pause updates) do not fire. Item and delta events never fire.
  • Closed: LiveSessionRegistry.dispose (called by closeSession) fires the last status with live: false, even if adapter teardown throws. A session event that arrives after close is ignored.

disposeAll (host shutdown) does not fire. The host wires the hook to EventBus.broadcastChatSessionChanged in app.ts. The chat-v3 mount is now created after the EventBus.

Compatibility with released clients

The only /events consumer is packages/workspace-client/src/lib/eventBus.ts (desktop renderer, mobile). Its handleMessage parses the JSON and calls only listeners where entry.type === message.type. A message type that has no registered listener goes through the loop and nothing happens. The only special case is type === "error". This dispatch has been in place since #3224 (April 2026), so released clients ignore chat:session-changed. Nothing on the client side subscribes to it in this PR.

Not included

  • setModel: setModelInputSchema exists in the protocol, but the runtime has no setModel command and HarnessAdapter has no method for it. Wiring it means changing every adapter, so it is left out.

Testing

  • packages/chat-runtime: bun test --isolate: 179 pass, 0 fail. New tests in registry.test.ts, using the fake harness:
    • one turn reports starting -> running -> idle with live: true, then idle with live: false on close
    • a second idle session event (title change) is not reported again
  • packages/host-service: bun test --isolate src/events/event-bus.test.ts src/chat-v3: 26 pass, 0 fail. The new test bridges a test runtime to EventBus and checks the exact message a socket receives when a session is created.
  • bunx biome check on the 10 changed files: clean.
  • bun run typecheck in host-service and workspace-client both fail with 22 errors, all in ../auth and ../trpc (better-auth plugin types). Plain origin/main fails with the same 22 errors in this checkout, and no errors are in the changed files. chat-runtime typecheck passes.

Summary by cubic

Emits chat:session-changed messages on the host /events WebSocket bus so clients watching chat-v3 sessions across hosts can react to pushes instead of polling chat.listSessions.

Details

  • Fires on session creation, each status change, and close; skips session events that keep the same status, and item/delta events never fire.
  • live is false on close, since closing a session does not change the status listSessions stores.
  • Host shutdown does not fire the event.
  • Released clients ignore the new message type, since /events dispatch only reaches registered listeners and none subscribe to it.
  • setModel wiring is out of scope: the runtime has no setModel command and no adapter method for it.

Summary by CodeRabbit

  • New Features
    • Chat session changes are now broadcast in real time, including the session’s workspace, status, and whether it is still active.
    • Notifications cover session creation, status changes, and closure. Repeated updates that leave the status unchanged are not sent.