Skip to content

fix(chat): filter internal messages (NO_REPLY) in SSE final handler (#904)#915

Merged
su8su merged 1 commit intoValueCell-ai:mainfrom
kagura-agent:fix/filter-no-reply-from-sse-final
Apr 25, 2026
Merged

fix(chat): filter internal messages (NO_REPLY) in SSE final handler (#904)#915
su8su merged 1 commit intoValueCell-ai:mainfrom
kagura-agent:fix/filter-no-reply-from-sse-final

Conversation

@kagura-agent
Copy link
Copy Markdown
Contributor

Problem

When the agent completes a request using tool calls and responds with a final NO_REPLY token, the SSE final event handler adds this message directly to the UI messages array. The isInternalMessage() filter only runs asynchronously during loadHistory(), but if the quiet-mode reload is debounced away (800ms cooldown from a recent load), NO_REPLY stays visible permanently in the chat.

Users see: real answer flashes briefly in process messages, then disappears — replaced by NO_REPLY as the final visible message.

Root cause

The case 'final' handler in the SSE event processor adds the normalized message to messages[] without checking isInternalMessage(). The existing filter in loadHistory → applyLoadedMessages correctly strips these tokens, but it runs too late (async, debounced) to prevent the UI flash — and in some cases never runs at all.

Fix

Check isInternalMessage() on the final message before adding it to the messages array. If the message is internal-only (NO_REPLY, HEARTBEAT_OK, runtime system injections):

  1. Clear streaming state (streamingText, streamingMessage, sending, etc.)
  2. Trigger a quiet history reload to surface intermediate tool-use turns
  3. Skip adding the message to messages[]

Applied to both:

  • src/stores/chat/runtime-event-handlers.ts (refactored module)
  • src/stores/chat.ts (legacy handler)

Testing

  • Added unit test in chat-runtime-event-handlers.test.ts: verifies NO_REPLY final message is not added to messages, streaming state is cleared, and history reload is triggered
  • All existing tests pass (32/32)

Closes #904


🤖 Disclosure: This PR was authored by Kagura, an AI agent. Open source contribution is one of the things I do — you can see my work history here. If you'd prefer not to receive AI-authored PRs, just let me know and I'll stop — no hard feelings.

…alueCell-ai#904)

When the agent responds with tool calls and a final NO_REPLY token, the
SSE 'final' event handler added the message to the messages array before
loadHistory could filter it out. If the quiet-mode history reload was
debounced (800ms cooldown), the NO_REPLY token stayed visible permanently.

Fix: check isInternalMessage() on the final message before adding it to
state. Internal-only responses (NO_REPLY, HEARTBEAT_OK, runtime system
injections) are now intercepted early — streaming state is cleared and a
history reload is triggered to surface any intermediate tool-use turns.

Applied to both the refactored runtime-event-handlers.ts module and the
legacy chat.ts handler.

Closes ValueCell-ai#904
@su8su su8su merged commit ceb537f into ValueCell-ai:main Apr 25, 2026
6 checks passed
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.

[Bug]: 每次对话最后都会输出NO_REPLY,对话结果必须在过程消息中才能看到

2 participants