fix(conversations): broadcast new chat to list live (#155)#348
Open
mgoldsborough wants to merge 1 commit into
Open
fix(conversations): broadcast new chat to list live (#155)#348mgoldsborough wants to merge 1 commit into
mgoldsborough wants to merge 1 commit into
Conversation
A brand-new conversation did not appear in the Conversations list until the user refreshed or switched tabs (#155). The runtime emitted the data.changed signal onto the per-request chat sink, which never reaches the /v1/events SSE channel that useDataSync consumes. Route the emit through the runtime's default sink (the one api/server.ts wraps for /v1/events). Fire once right after the user message is persisted so the conversation surfaces with its first-message preview as the label, and once more after auto-title generation settles so the label flips to the generated title. Two adjacent issues surfaced during investigation and are filed separately: - #253: auto-generated titles often contain assistant response content instead of a short summary (pre-existing prompt-shape bug) - #254: mid-turn conversation switch bleeds the streaming response into the destination chat (pre-existing client-side state contamination) Supporting hardening in this commit, in service of the broadcast both reaching its destination and surviving along the way: - FaultIsolatedSink wraps each sink in the defaultEvents fan-out so a logger throw can't abort the SSE-broadcast wrap downstream. Engine-time sink chain stays loud. - generateTitle uses AbortSignal.timeout to hard-cap a hung fast-model call so the title-block .finally always fires. - Dead chat-stream data.changed branch removed from handlers.ts (nothing relays it now; confirmed via grep). Closes #155 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
A brand-new conversation didn't appear in the Conversations list until the user refreshed or switched tabs (#155). The runtime emitted the new-conversation
data.changedsignal onto the per-request chat sink, which never reaches the/v1/eventsSSE channel thatuseDataSyncconsumes. This routes the emit through the runtime's default sink instead (the oneapi/server.tswraps for/v1/events).It fires twice for a new conversation:
No broadcast on resume (the pre-turn emit is guarded by
if (!request.conversationId), and the title block only runs whenconversation.title === null).Hardening
FaultIsolatedSinkwraps each sink in thedefaultEventsfan-out so a logger throw can't abort the SSE broadcast fan-out.AbortSignal.timeoutingenerateTitlehard-caps a hung fast-model call so the title block's.finallyalways fires (the list re-pull happens even if title generation/persist fails).data.changedbranch inhandlers.ts(nothing relays it).Note
This is a rebased + reduced version of #255. The conversation-index
pull-on-demandrefactor from that PR is deferred to a separate follow-up — it needs mtime+size staleness handling, an ownership-gating caller audit, and a search/stats limit cap.Test plan
bun run verifygreen for everything touching the changed files; the only red is a pre-existing 15s-timeout flake inbody-limit-routes.test.ts(a multipart-upload HTTP test) that reproduces identically on cleanorigin/mainand is unrelated to this change.test/integration/runtime/chat-start-event.test.tsasserts the new-conversationdata.changedreaches the default (SSE-bound) sink and that resume does not broadcast (12 pass, 0 fail in isolation).Closes #155