Skip to content

fix(chat): wrap content classifier in untracked() to fix NG0600 streaming crash#104

Merged
blove merged 2 commits into
mainfrom
claude/condescending-sanderson
Apr 10, 2026
Merged

fix(chat): wrap content classifier in untracked() to fix NG0600 streaming crash#104
blove merged 2 commits into
mainfrom
claude/condescending-sanderson

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented Apr 10, 2026

Summary

  • Bug: classifyMessage() is called during Angular template rendering (via @let classified = classifyMessage(content, index) in the AI message template). The classifier's update() method writes to signals (typeSignal.set(), markdownSignal.set(), etc.), which Angular 21's stricter signal write guards flag as NG0600 — writing signals during change detection is forbidden. This crashes the entire streaming render loop, causing the "flicker then nothing" behavior.
  • Fix: Wrap update() body in untracked() to opt out of the reactive graph for this imperative push-based API. The template reads the classifier's signals after the update call returns, so reactivity is preserved.
  • Verified: Multi-turn streaming conversation against production LangGraph backend — markdown renders correctly, streaming works, zero console errors.

Context

This is the actual root cause of the streaming chat being broken. PR #102 (metadata filtering) was a contributing issue but the NG0600 signal write error was the primary crash preventing any content from rendering.

Test plan

  • nx test chat — 175/175 pass
  • Multi-turn conversation in Chrome with real LangGraph backend — streaming, markdown rendering, and error-free console verified via screenshots

🤖 Generated with Claude Code

blove and others added 2 commits April 10, 2026 12:09
normalizeMessages() had two code paths: event['messages'] (returned
unfiltered) and event['data'] (filtered by isMessageLike). In
production, FetchStreamTransport's normalizeSdkEvent wraps the raw SDK
data array—which includes metadata objects like { langgraph_node,
langgraph_triggers }—into event.messages. These metadata objects lack
content/type/id fields, causing messageContent() to return undefined
and crashing the content classifier's detectType() on
undefined.length.

The fix applies the existing isMessageLike filter to the
event['messages'] path. Tests now simulate post-normalization event
shapes matching what FetchStreamTransport produces.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…G0600

classifyMessage() is called during Angular template rendering (in the
AI message template via @let). The classifier's update() method writes
to signals (typeSignal.set, markdownSignal.set, etc.), which Angular
21's stricter signal write guards flag as NG0600 — writing signals
during change detection is forbidden.

Wrapping update() in untracked() opts out of the reactive graph for
this imperative push-based API. The template reads the classifier's
signals after the update call returns, so reactivity is preserved.

Verified with multi-turn streaming conversation against production
LangGraph backend — markdown renders correctly, zero console errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cacheplane Ready Ready Preview, Comment Apr 10, 2026 8:27pm

Request Review

@blove blove merged commit 27d3d92 into main Apr 10, 2026
14 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.

1 participant