openclaw - ✅(Solved) Fix [Bug]: strict9 tool-call-id regression — Mistral via proxy providers fails again after provider-capabilities refactors [2 pull requests, 2 comments, 2 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#58012Fetched 2026-04-08 01:54:52
View on GitHub
Comments
2
Participants
2
Timeline
12
Reactions
0
Author
Participants
Timeline (top)
mentioned ×3subscribed ×3commented ×2cross-referenced ×2

Error Message

  1. Observe invalid_function_call error (code 3280) — tool call IDs are not sanitized to strict 9-char alphanumeric format

Root Cause

The original fix (commit 4d06910665) was landed on main, but three subsequent refactors restructured the provider-capabilities system and removed the cross-provider strict9 fallback:

  • 4ca07559ab — move provider seams behind plugin SDK surfaces
  • 724a9cfdba — preserve fallback provider capabilities under partial overrides
  • 637b4c8193 — move remaining provider policy into plugins

After these refactors, resolveTranscriptToolCallIdMode("openrouter", "mistral-large-latest") returns undefined because:

  1. OpenRouter's capabilities have transcriptToolCallIdMode: "default" (not "strict9")
  2. OpenRouter's transcriptToolCallIdModelHints is [] (empty)
  3. The cross-provider hint fallback that checked all known providers' strict9 hints was lost

Fix Action

Fixed

PR fix notes

PR #58014: fix(agents): restore strict9 tool-call-id mode for Mistral via proxy providers (#58012)

Description (problem / solution / changelog)

Summary

Restores the cross-provider strict9 tool-call-id fallback that was lost during the provider-capabilities refactors, fixing Mistral models routed through proxy providers (OpenRouter, Together, etc.) failing with invalid_function_call (code 3280).

Root Cause

Three refactors restructured the provider-capability system (4ca07559ab, 724a9cfdba, 637b4c8193) and removed the cross-provider strict9 hint fallback. resolveTranscriptToolCallIdMode("openrouter", "mistral-large-latest") returned undefined because OpenRouter's capabilities have no strict9 hints — the check only looked at the current provider's capabilities.

Changes

  • src/agents/provider-capabilities.ts: After checking the current provider's capabilities, iterate PLUGIN_CAPABILITIES_FALLBACKS entries with transcriptToolCallIdMode: "strict9" and match their model hints against the model ID.
  • src/agents/provider-capabilities.test.ts: Added regression tests for OpenRouter + Mistral, OpenRouter + Codestral, OpenRouter + non-Mistral, and unknown proxy + Mistral scenarios.

Test

pnpm test -- src/agents/provider-capabilities.test.ts
✓ 11 tests passed

Closes #58012


Regression of the original fix (commit 4d06910665), previously tracked in #52567 and #52548. Verified by @hartmark via local cherry-pick of the original fix.

Changed files

  • src/agents/provider-capabilities.test.ts (modified, +8/-0)
  • src/agents/provider-capabilities.ts (modified, +12/-0)

PR #52567: fix(agents): resolve strict9 tool-call-id mode for Mistral models via proxy providers (#52548)

Description (problem / solution / changelog)

Summary

When Mistral-family models are routed through proxy providers like OpenRouter, tool calls fail with invalid_function_call (code 3280) because tool call IDs are not sanitized to the strict 9-char alphanumeric format Mistral requires.

Root Cause

resolveTranscriptToolCallIdMode() only checks the current provider's capabilities. When the provider is openrouter, it returns default capabilities with an empty transcriptToolCallIdModelHints array, so the Mistral model hints ("mistral", "mistralai", etc.) are never evaluated — even though the model ID clearly identifies a Mistral model.

Changes

  • src/agents/provider-capabilities.ts: After checking the current provider's capabilities, also iterate through all providers with transcriptToolCallIdMode: "strict9" and check their model hints against the model ID. This handles any proxy provider transparently.
  • src/agents/provider-capabilities.test.ts: Added regression tests for OpenRouter + Mistral, OpenRouter + non-Mistral, and unknown proxy + Mistral scenarios.

Test

pnpm test -- src/agents/provider-capabilities.test.ts
✓ 9 tests passed

Closes #52548

Changed files

  • src/agents/provider-capabilities.test.ts (modified, +16/-0)
  • src/agents/provider-capabilities.ts (modified, +14/-0)
RAW_BUFFERClick to expand / collapse

Bug Description

The strict9 tool-call-id fix for Mistral models routed through proxy providers (OpenRouter, Together, etc.) has regressed. Tool calls fail with invalid_function_call (code 3280) because the 9-char alphanumeric sanitization is no longer applied.

Root Cause

The original fix (commit 4d06910665) was landed on main, but three subsequent refactors restructured the provider-capabilities system and removed the cross-provider strict9 fallback:

  • 4ca07559ab — move provider seams behind plugin SDK surfaces
  • 724a9cfdba — preserve fallback provider capabilities under partial overrides
  • 637b4c8193 — move remaining provider policy into plugins

After these refactors, resolveTranscriptToolCallIdMode("openrouter", "mistral-large-latest") returns undefined because:

  1. OpenRouter's capabilities have transcriptToolCallIdMode: "default" (not "strict9")
  2. OpenRouter's transcriptToolCallIdModelHints is [] (empty)
  3. The cross-provider hint fallback that checked all known providers' strict9 hints was lost

Steps to Reproduce

  1. Configure OpenClaw with OpenRouter as the provider
  2. Use a Mistral-family model (e.g. mistral-large-latest, codestral-latest)
  3. Trigger a tool call
  4. Observe invalid_function_call error (code 3280) — tool call IDs are not sanitized to strict 9-char alphanumeric format

Expected Behavior

resolveTranscriptToolCallIdMode("openrouter", "mistral-large-latest") should return "strict9", and tool call IDs should be sanitized regardless of whether the Mistral model is accessed directly or through a proxy provider.

Related

  • Original issue: #52548 (closed + locked)
  • Original fix PR: #52567 (closed — code outdated after refactors)
  • Verified by @hartmark via local cherry-pick

extent analysis

Fix Plan

To resolve the issue, we need to reintroduce the cross-provider strict9 fallback. We can achieve this by modifying the resolveTranscriptToolCallIdMode function to check all known providers' strict9 hints.

Code Changes

// Update the resolveTranscriptToolCallIdMode function
function resolveTranscriptToolCallIdMode(provider, model) {
  // Check if the provider has a specific transcript tool call ID mode
  if (providerCapabilities[provider] && providerCapabilities[provider].transcriptToolCallIdMode) {
    return providerCapabilities[provider].transcriptToolCallIdMode;
  }

  // Check if the model has a specific transcript tool call ID mode hint
  if (modelHints[model] && modelHints[model].transcriptToolCallIdMode) {
    return modelHints[model].transcriptToolCallIdMode;
  }

  // Fallback to check all known providers' strict9 hints
  for (const knownProvider in providerCapabilities) {
    if (providerCapabilities[knownProvider].transcriptToolCallIdMode === 'strict9') {
      return 'strict9';
    }
  }

  // Default to 'default' mode if no strict9 hint is found
  return 'default';
}

Configuration Changes

No configuration changes are required for this fix.

Verification

To verify the fix, follow these steps:

  • Configure OpenClaw with OpenRouter as the provider
  • Use a Mistral-family model (e.g. mistral-large-latest, codestral-latest)
  • Trigger a tool call
  • Check that the tool call ID is sanitized to the strict 9-char alphanumeric format
  • Verify that resolveTranscriptToolCallIdMode("openrouter", "mistral-large-latest") returns "strict9"

Extra Tips

  • Make sure to test the fix with different providers and models to ensure the cross-provider fallback is working correctly.
  • Consider adding additional logging or monitoring to detect any future regressions.

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