openclaw - ✅(Solved) Fix Bug: preserve fallback thinking signatures at replay boundary [1 pull requests, 1 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#44580Fetched 2026-04-08 00:44:59
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
referenced ×3cross-referenced ×1

Session-history replay can mishandle provider-native thinking signatures during model fallback.

Root Cause

The bug is local to replay-boundary sanitization and provider-capability resolution, not general transcript policy.

Fix Action

Fixed

PR fix notes

PR #44581: fix(agents): preserve fallback thinking signatures at replay boundary

Description (problem / solution / changelog)

Summary

Keeps provider-native thinking signatures intact until the replay target is known, then strips only signatures that openai-completions cannot safely replay.

Problem

Session-history fallback was handling thinking signatures too broadly. That risks dropping valid Anthropic signatures before compatible Gemini replay, while also replaying incompatible provider-specific signatures into openai-completions.

Root cause

The bug is at the replay boundary. Signature validity depends on the replay target, not on a global transcript-policy decision made earlier in sanitization.

Fix

  • add sanitizeOpenAICompletionsThinkingSignatures() for OpenAI-compatible chat-completions replay
  • apply it only when modelApi == "openai-completions"
  • preserve Anthropic signatures for Gemini fallback
  • restore strict9 transcript tool-call-id detection for wrapped Mistral model ids such as mistralai/devstral-2512:free

Files changed

  • src/agents/pi-embedded-helpers/openai.ts: provider-specific replay sanitizer
  • src/agents/pi-embedded-helpers.ts: helper re-export
  • src/agents/pi-embedded-runner/google.ts: apply sanitizer at replay boundary only
  • src/agents/pi-embedded-runner.sanitize-session-history.test.ts: fallback-signature regression coverage
  • src/agents/provider-capabilities.ts: wrapped-Mistral strict9 detection
  • src/agents/provider-capabilities.test.ts: regression coverage for wrapped-Mistral strict9

Test plan

  • pnpm exec vitest run src/agents/pi-embedded-runner.sanitize-session-history.test.ts
  • pnpm exec vitest run src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/provider-capabilities.test.ts

Both passed locally.

Why this shape

This keeps the fix local to the actual boundaries involved:

  • replay-target compatibility for thinking signatures
  • provider-capability resolution for wrapped Mistral strict9

It avoids changing broader transcript policy behavior.

Refs: #44580

Changed files

  • src/agents/pi-embedded-helpers.ts (modified, +1/-0)
  • src/agents/pi-embedded-helpers/images.ts (modified, +5/-3)
  • src/agents/pi-embedded-helpers/openai.ts (modified, +67/-0)
  • src/agents/pi-embedded-runner.sanitize-session-history.test.ts (modified, +138/-0)
  • src/agents/pi-embedded-runner/compact.ts (modified, +7/-1)
  • src/agents/pi-embedded-runner/google.ts (modified, +7/-1)
  • src/agents/pi-embedded-runner/run/attempt.ts (modified, +11/-5)
  • src/agents/provider-capabilities.test.ts (modified, +3/-0)
  • src/agents/provider-capabilities.ts (modified, +12/-1)
  • src/agents/transcript-policy.test.ts (modified, +199/-0)
  • src/agents/transcript-policy.ts (modified, +43/-1)
RAW_BUFFERClick to expand / collapse

Summary

Session-history replay can mishandle provider-native thinking signatures during model fallback.

Expected behavior

  • Anthropic signed thinking is preserved when replay remains compatible, including Gemini fallback
  • incompatible signatures are stripped only when replay target is openai-completions
  • wrapped Mistral model ids that require strict9 tool-call-id sanitization continue to resolve that mode

Actual behavior

The fallback path can sanitize too broadly, destroying valid provider-native thinking signatures before replay target is known. During final validation, wrapped Mistral model ids routed through providers like OpenRouter also stopped resolving strict9 transcript sanitization.

Root cause

The bug is local to replay-boundary sanitization and provider-capability resolution, not general transcript policy.

Proposed fix

  • preserve provider-native thinking signatures earlier in transcript sanitization
  • strip unsupported signatures only at the openai-completions replay boundary
  • preserve strict9 tool-call-id sanitization for wrapped Mistral model ids

Validation

  • pnpm exec vitest run src/agents/pi-embedded-runner.sanitize-session-history.test.ts
  • pnpm exec vitest run src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/provider-capabilities.test.ts

extent analysis

Fix Plan

To address the issue, we need to modify the session history replay logic to preserve provider-native thinking signatures and only strip unsupported signatures at the openai-completions replay boundary. We also need to ensure that strict9 tool-call-id sanitization is preserved for wrapped Mistral model ids.

Here are the concrete steps:

  • Modify the sanitizeSessionHistory function to check the replay target before sanitizing the signatures.
  • Add a conditional statement to strip unsupported signatures only when the replay target is openai-completions.
  • Update the resolveProviderCapabilities function to preserve strict9 tool-call-id sanitization for wrapped Mistral model ids.

Example code:

// Modified sanitizeSessionHistory function
function sanitizeSessionHistory(sessionHistory, replayTarget) {
  if (replayTarget === 'openai-completions') {
    // Strip unsupported signatures
    sessionHistory.signatures = sessionHistory.signatures.filter(signature => {
      return signature.provider === 'openai';
    });
  }
  return sessionHistory;
}

// Updated resolveProviderCapabilities function
function resolveProviderCapabilities(modelId) {
  if (modelId.startsWith('wrapped-mistral')) {
    // Preserve strict9 tool-call-id sanitization
    return { sanitization: 'strict9' };
  }
  return {};
}

Verification

To verify the fix, run the following tests:

  • pnpm exec vitest run src/agents/pi-embedded-runner.sanitize-session-history.test.ts
  • pnpm exec vitest run src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/provider-capabilities.test.ts

Extra Tips

  • Make sure to test the fix thoroughly to ensure that it does not introduce any regressions.
  • Consider adding additional logging or monitoring to detect any issues with the modified logic.

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…

FAQ

Expected behavior

  • Anthropic signed thinking is preserved when replay remains compatible, including Gemini fallback
  • incompatible signatures are stripped only when replay target is openai-completions
  • wrapped Mistral model ids that require strict9 tool-call-id sanitization continue to resolve that mode

Still need to ship something?

×6

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

Back to top recommendations

TRENDING