Skip to content

fix(js): don't treat <thinking> inside code blocks as thinking tags#235

Open
gadenbuie wants to merge 2 commits into
mainfrom
fix/inline-thinking-tags
Open

fix(js): don't treat <thinking> inside code blocks as thinking tags#235
gadenbuie wants to merge 2 commits into
mainfrom
fix/inline-thinking-tags

Conversation

@gadenbuie
Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug in the streaming <thinking>-tag state machine where <thinking> appearing inside a fenced code block (``` or ~~~) or an inline backtick span was incorrectly treated as the start of a thinking/reasoning block, causing that content to disappear from the visible output into an invisible panel.

Two related bugs are fixed:

  1. Fenced code block exclusion (streaming). The state machine now enters a "fence" mode when it encounters a fenced code block opener, treating all content until the matching closer as plain text. Fence state is persisted across chunk boundaries so split chunks work correctly.

  2. Chunk-boundary false positive. A chunk ending with a non-whitespace character (e.g., a backtick in `<thinking>`) followed by a new chunk starting with <thinking> previously entered thinking mode incorrectly because before.trim() === "" was the only guard. The fix also requires a newline boundary to precede the tag.

  3. Inline code span exclusion (non-streaming). The full-message path now also excludes inline backtick spans (`...`) from thinking-tag detection, matching the existing fenced-block exclusion.

Four new test cases cover: (1) chunk-boundary false positive, (2) valid cross-chunk <thinking> after a real newline, (3) inline code span exclusion, and (4) fenced code block exclusion during streaming.

Verification

Construct a message that includes <thinking> inside a fenced code block, e.g. from a model that uses XML-style reasoning syntax or by appending a chunk manually:

<thinking>
This is code, not reasoning
</thinking>

Previously the content inside the fence would vanish into an invisible thinking panel. After this fix, it renders as plain code content.

gadenbuie added 2 commits May 27, 2026 16:39
Track fenced code block state during streaming so that <thinking> tags
encountered inside ``` or ~~~ blocks are emitted as plain content rather
than parsed as thinking blocks. Also exclude inline backtick spans from
thinking-tag detection in the non-streaming (splitThinkingBlocks) path.

Previously, a chunk boundary where the prior chunk ended with a non-newline
character (e.g. a backtick) and the next chunk began with <thinking> would
incorrectly enter thinking mode because `before.trim() === ""` was the only
guard — the newline-boundary check was missing.
@gadenbuie gadenbuie marked this pull request as ready for review May 27, 2026 20:49
@gadenbuie gadenbuie requested a review from cpsievert May 27, 2026 20:49
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.

2 participants