CL-6557: Chat: false "no reply arrived" notice after a fully rendered reply - #270
Merged
Merged
Conversation
A parked folded run's chat.agent stream never carries connector.reply, so the reply-timeout backstop can fire after the reply has already rendered via its own chat.message. These tests reproduce that: a rendered reply followed by silence (no terminal run event) or a post-reply tool round must never show the timeout notice, while a turn with no content at all must still time out.
… connector.reply connector.reply only ever arrives on the chat.agent stream, which a parked folded run's post-turn park never emits a terminal event on; the persisted reply's own chat.message posts from a separate pipeline and was the only thing actually on screen. The reply-timeout backstop stayed armed off connector.reply alone, so it could fire after a complete reply had already rendered. Now an awaiting turn's chat.message also moves it to replied the moment the agent's own reply content is observed to have posted, independent of whether connector.reply ever arrives on the chat.agent stream.
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.
Summary
packages/chat-ui/src/streaming-reply.tsfires even after a complete reply has rendered, because it only ever moves a turn to"replied"on thechat.agentstream'sconnector.replyevent — a signal a parked folded run's stream may never carry, and which can otherwise be dropped/delayed independent of the actual reply.chat.messageevent (posted bypostReplyinchat-orchestrator.ts), an entirely separate pipeline fromchat.agent. Whenconnector.replynever lands but thechat.messagedoes, the client'sstreamingReplystate stays stuck in"awaiting"and the 120s backstop eventually shows the false notice right under the already-rendered reply.chat.message(agent sender, real content, notpostUndeliveredNotice'sturnFailedpart) now also moves the turn to"replied", independent of whetherconnector.replyever arrives. The transition is keyed on rendered content — an observable fact — rather than a lifecycle event that may never arrive.Test plan
packages/chat-ui/src/streaming-reply.test.ts— new pure-reducer cases for thechat.message-driven"replied"transition (agent sender + content → replied;turnFailednotice never counts; human sender never counts; empty parts never count)packages/chat-ui/test/use-streaming-reply.test.tsx— hook-level repro: a rendered reply followed by silence with no terminal run event (mimicking a parked folded run) shows no notice; a rendered reply followed by a post-reply tool round shows no notice; a turn with no content at all still times out correctlybun testinpackages/chat-ui: 661 pass, 0 failtsc --noEmitandeslintclean on changed filesprettier --checkclean on changed filesLinear: CL-6557