openclaw - ✅(Solved) Fix [Bug] Gemini thinking blocks may use different tag format that escapes current regex filter [1 pull requests, 7 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#48974Fetched 2026-04-08 00:50:16
View on GitHub
Comments
7
Participants
3
Timeline
11
Reactions
0
Timeline (top)
commented ×7cross-referenced ×2closed ×1referenced ×1

When using Google Gemini models (e.g., google-gemini-cli/gemini-2.5-pro), internal reasoning blocks (<think>...</think>) may not be properly stripped from the final output. This exposes the model's internal monologue to users.

Root Cause

After analyzing the source code at dist/image-BYrAeHdw.js:129-196:

Fix Action

Fixed

PR fix notes

PR #48593: Fix Gemini final tags leaking into delivered messages

Description (problem / solution / changelog)

Summary

Fixes issue #48587 where Google Gemini model responses leak <final> tag fragments into delivered messages on channels like Telegram.

The root cause was inconsistent regex patterns for matching <final> tags across different parts of the codebase:

  • The main reasoning tags logic used a robust regex that handles attributes: /<\s*\/?\s*final\b[^<>]*>/gi
  • The streaming logic used a restrictive regex that only matched basic tags: /<\s*(\/?)\s*final\s*>/gi

When Gemini outputs tags with attributes like <final id="1">content</final>, the streaming regex would miss them, causing fragments like </final> to leak through to the delivered message.

Changes

Updated all final tag regexes to use the robust pattern that handles attributes:

  • src/agents/pi-embedded-subscribe.ts: Updated FINAL_TAG_SCAN_RE
  • src/agents/pi-embedded-helpers/errors.ts: Updated FINAL_TAG_RE
  • src/agents/pi-embedded-subscribe.handlers.messages.ts: Updated inline regex
  • src/gateway/gateway-models.profiles.live.test.ts: Updated test helper regex

Test plan

  • Review existing tests in reasoning-tags.test.ts to ensure they cover final tag behavior
  • Verify regex patterns now consistently match final tags with attributes
  • Confirm the fix addresses the specific issue described in #48587

Impact

This fix ensures that Google Gemini model responses are properly cleaned before delivery to messaging channels, eliminating the tag fragments that were previously leaking through.

🤖 Generated with Claude Code

Changed files

  • src/agents/pi-embedded-helpers/errors.ts (modified, +1/-1)
  • src/agents/pi-embedded-subscribe.handlers.messages.ts (modified, +1/-1)
  • src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.filters-final-suppresses-output-without-start-tag.test.ts (modified, +38/-0)
  • src/agents/pi-embedded-subscribe.ts (modified, +15/-3)
  • src/gateway/gateway-models.profiles.live.test.ts (modified, +1/-1)
  • src/shared/text/reasoning-tags.test.ts (modified, +4/-0)
  • src/shared/text/reasoning-tags.ts (modified, +6/-1)

Code Example

if (!QUICK_TAG_RE.test(text)) return text;
RAW_BUFFERClick to expand / collapse

Summary

When using Google Gemini models (e.g., google-gemini-cli/gemini-2.5-pro), internal reasoning blocks (<think>...</think>) may not be properly stripped from the final output. This exposes the model's internal monologue to users.

Steps to Reproduce

  1. Configure an agent to use google-gemini-cli/gemini-2.5-pro model
  2. Start a conversation that triggers extended reasoning
  3. Observe that the response may contain raw <think> blocks

Expected Behavior

All <think>...</think> blocks should be filtered out before the response reaches the user.

Actual Behavior

Internal thinking blocks leak into the user-facing response.

Root Cause Analysis

After analyzing the source code at dist/image-BYrAeHdw.js:129-196:

Code Location

  • File: src/agents/pi-embedded-utils.ts (compiled to dist/image-BYrAeHdw.js)
  • Function: stripReasoningTagsFromText()
  • Key Line: 129 - const QUICK_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking|final)\b/i;

Analysis

The current regex THINKING_TAG_RE only matches:

  • <thought>, <thinking>, <think>, <antthinking> (and their closing tags)

However, Gemini models may output thinking blocks in alternative formats that the current regex doesn't catch:

  1. Different casing variations (e.g., <THONKING>, <Thinking > with trailing space)
  2. Nested or malformed tags
  3. Unicode variants that may slip through

Additionally, the quick-exit optimization at line 139:

if (!QUICK_TAG_RE.test(text)) return text;

relies on the same limited regex, potentially missing edge cases.

Proposed Solution

  1. Expand regex patterns to cover more variations:

    • Add case-insensitive matching for all permutations
    • Consider Unicode-aware matching for international deployments
  2. Add fallback detection:

    • If primary regex fails, try secondary patterns
    • Consider using a more comprehensive parsing approach
  3. Add unit tests for Gemini-specific edge cases

Environment

  • Model: google-gemini-cli/gemini-2.5-pro
  • OpenClaw Version: 2026.3.14
  • Interface: openclaw-tui

Tags

bug, regression, provider:google-gemini-cli

extent analysis

Fix Plan

To address the issue of internal reasoning blocks not being properly stripped from the final output, we will:

  • Update the regex pattern to cover more variations and edge cases
  • Implement a fallback detection mechanism
  • Add unit tests for Gemini-specific edge cases

Code Changes

// Update the regex pattern to include case-insensitive matching and Unicode-aware matching
const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking|final)[^>]*>/gi;

// Add fallback detection using secondary patterns
const SECONDARY_TAG_RE = /<\s*\/?\s*(?:thonking|thinking\s+|think\s+)[^>]*>/gi;

// Update the stripReasoningTagsFromText function
function stripReasoningTagsFromText(text) {
  // Primary regex replacement
  text = text.replace(THINKING_TAG_RE, '');
  
  // Fallback detection using secondary patterns
  if (text.includes('<think') || text.includes('<thinking')) {
    text = text.replace(SECONDARY_TAG_RE, '');
  }
  
  return text;
}

Verification

To verify that the fix worked, test the stripReasoningTagsFromText function with various input scenarios, including:

  • Different casing variations (e.g., <THONKING>, <Thinking > with trailing space)
  • Nested or malformed tags
  • Unicode variants

Example test cases:

console.log(stripReasoningTagsFromText('<think>This is a thinking block</think>')); // Should output: ''
console.log(stripReasoningTagsFromText('<Thinking >This is a thinking block</Thinking>')); // Should output: ''
console.log(stripReasoningTagsFromText('<THONKING>This is a thinking block</THONKING>')); // Should output: ''

Extra Tips

  • Consider using a more comprehensive parsing approach, such as using an HTML parser library, to handle edge cases and malformed tags.
  • Add unit tests for Gemini-specific edge cases to ensure the fix is robust and effective.
  • Monitor the issue and gather feedback from users to identify any remaining edge cases or issues.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING