Skip to content

Fix stripping of Gemma reasoning markers in streamed output#6398

Open
C0deRatoR wants to merge 2 commits into
livekit:mainfrom
C0deRatoR:fix/gemma-reasoning-markers
Open

Fix stripping of Gemma reasoning markers in streamed output#6398
C0deRatoR wants to merge 2 commits into
livekit:mainfrom
C0deRatoR:fix/gemma-reasoning-markers

Conversation

@C0deRatoR

Copy link
Copy Markdown

Fixes #6375

Problem

Gemma channel-thought markers and their hidden reasoning pass through the shared thinking-token filter into customer-visible output, including TTS, transcripts, and chat history.

Root cause

strip_thinking_tokens only recognizes <think> blocks and uses an asyncio.Event, which records whether the stream is inside a reasoning block but cannot retain marker fragments split across chunks. It also does not handle complete or multiple reasoning blocks within one chunk.

Change

  • add a stateful streaming filter for existing <think> and Gemma <|channel>thought / <channel|> blocks
  • buffer only possible marker prefixes across chunk boundaries
  • preserve visible content before and after reasoning blocks
  • flush incomplete visible marker-like text when the stream finishes while dropping unclosed reasoning

Tests

  • uv run --frozen pytest tests/test_llm_utils.py --unit -q — 11 passed
  • uv run --frozen pytest --unit --no-concurrent --ignore=tests/test_room.py -q — 1116 passed, 2 skipped
  • make check — formatting, Ruff, and mypy passed

tests/test_room.py could not run locally because this environment has no Docker executable; its nine failures were fixture setup errors before test execution.

Scope

No new dependencies, provider calls, or unrelated inference changes.

@C0deRatoR C0deRatoR requested a review from a team as a code owner July 13, 2026 07:29
@CLAassistant

CLAassistant commented Jul 13, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

THINK_TAG_END = "</think>"
THINK_TAG_PAIRS = (
(THINK_TAG_START, THINK_TAG_END),
("<|channel>thought", "<channel|>"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is gemma only, can we make the start and end tags configurable per model, so it applies to only gamma. for future models we can set that tag directly, and if not set fallback to the default

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 68b535d. ThinkingTokenFilter now accepts configurable start/end tags; the Inference path maps only google/gemma-4-31b-it to the Gemma markers and falls back to <think>/</think> for every other model. I also added a regression test confirming Gemma markers remain untouched without explicit tag configuration.

return call_chunk

delta.content = llm_utils.strip_thinking_tokens(delta.content, thinking)
delta.content = llm_utils.strip_thinking_tokens(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe move strip to the top of _parse_choice so it also applied for the text content alongside a tool call?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 68b535d. Filtering now runs immediately after the delta is None guard, before tool-call handling, so text emitted alongside a tool call is filtered too. Added a regression covering visible text followed by an empty Gemma thought block on a tool-call chunk.

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.

Inference: strip Gemma 4 <|channel>thought…<channel|> markers (strip_thinking_tokens only knows <think>)

3 participants