openclaw - 💡(How to fix) Fix Custom anthropic-messages providers don't get Claude adaptive thinking (resolveProviderThinkingProfile fallback)

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…

Fix Action

Fix

In src/auto-reply/thinking.ts, add a Claude-family fallback to resolveProviderThinkingProfile:

 function resolveProviderThinkingProfile(params) {
   const activeProfile = resolveActiveThinkingProvider(params.provider)?.resolveThinkingProfile?.(params.context);
   if (activeProfile) return activeProfile;
-  return resolveBundledProviderPolicySurface(params.provider)?.resolveThinkingProfile?.(params.context);
+  const bundled = resolveBundledProviderPolicySurface(params.provider)?.resolveThinkingProfile?.(params.context);
+  if (bundled) return bundled;
+  // Custom anthropic-messages providers (e.g. bifrost-claude, litellm-claude) using Claude family models
+  // don't have a plugin/bundled hook, so they don't get adaptive thinking even though the model supports it.
+  // Fall back to the canonical Claude profile when the model id matches a known Claude family pattern.
+  const modelId = params.context?.modelId;
+  if (typeof modelId === "string" && /claude-(opus|sonnet|haiku)-4[._-](5|6|7)/i.test(modelId)) {
+    return resolveClaudeThinkingProfile(modelId);
+  }
+  return undefined;
 }

This requires resolveClaudeThinkingProfile imported from provider-model-shared (already exported there).

Code Example

// openclaw.json
"models": {
  "providers": {
    "bifrost-claude": {
      "baseUrl": "http://bifrost-host:4000/anthropic",
      "api": "anthropic-messages",
      "apiKey": { "$secretRef": "..." },
      "models": [
        {
          "id": "claude-sonnet-4-6",
          "reasoning": true,
          "input": ["text", "image"]
        }
      ]
    }
  }
}

---

/think adaptive

---

function resolveProviderThinkingProfile(params) {
   const activeProfile = resolveActiveThinkingProvider(params.provider)?.resolveThinkingProfile?.(params.context);
   if (activeProfile) return activeProfile;
-  return resolveBundledProviderPolicySurface(params.provider)?.resolveThinkingProfile?.(params.context);
+  const bundled = resolveBundledProviderPolicySurface(params.provider)?.resolveThinkingProfile?.(params.context);
+  if (bundled) return bundled;
+  // Custom anthropic-messages providers (e.g. bifrost-claude, litellm-claude) using Claude family models
+  // don't have a plugin/bundled hook, so they don't get adaptive thinking even though the model supports it.
+  // Fall back to the canonical Claude profile when the model id matches a known Claude family pattern.
+  const modelId = params.context?.modelId;
+  if (typeof modelId === "string" && /claude-(opus|sonnet|haiku)-4[._-](5|6|7)/i.test(modelId)) {
+    return resolveClaudeThinkingProfile(modelId);
+  }
+  return undefined;
 }
RAW_BUFFERClick to expand / collapse

Bug: custom anthropic-messages providers don't get Claude adaptive thinking

Problem

resolveProviderThinkingProfile (in bundled dist/thinking-uKUPba90.js) walks two layers:

  1. resolveActiveThinkingProvider(provider).resolveThinkingProfile(...) — plugin-registered providers
  2. resolveBundledProviderPolicySurface(provider).resolveThinkingProfile(...) — bundled providers

Custom providers configured under models.providers with api: "anthropic-messages" (e.g. a Bifrost or LiteLLM front-end pointing at Claude) miss both layers. They never get the Claude-specific profile from resolveClaudeThinkingProfile. The runtime falls back to BASE_THINKING_LEVELS (off / minimal / low / medium / high) and adaptive is rejected with:

Thinking level set to medium (adaptive not supported for bifrost-claude/claude-sonnet-4-6).

Per Anthropic's docs adaptive is supported on Opus 4.6, Opus 4.7, and Sonnet 4.6 — so this is a wiring miss on the custom-provider path rather than a model capability gap. The model and provider are configured exactly like the canonical anthropic provider but they're going through a proxy.

Repro

// openclaw.json
"models": {
  "providers": {
    "bifrost-claude": {
      "baseUrl": "http://bifrost-host:4000/anthropic",
      "api": "anthropic-messages",
      "apiKey": { "$secretRef": "..." },
      "models": [
        {
          "id": "claude-sonnet-4-6",
          "reasoning": true,
          "input": ["text", "image"]
        }
      ]
    }
  }
}

Then in a session running bifrost-claude/claude-sonnet-4-6:

/think adaptive

Observed: Thinking level set to medium (adaptive not supported for ...). Expected: Thinking level set to adaptive.

Fix

In src/auto-reply/thinking.ts, add a Claude-family fallback to resolveProviderThinkingProfile:

 function resolveProviderThinkingProfile(params) {
   const activeProfile = resolveActiveThinkingProvider(params.provider)?.resolveThinkingProfile?.(params.context);
   if (activeProfile) return activeProfile;
-  return resolveBundledProviderPolicySurface(params.provider)?.resolveThinkingProfile?.(params.context);
+  const bundled = resolveBundledProviderPolicySurface(params.provider)?.resolveThinkingProfile?.(params.context);
+  if (bundled) return bundled;
+  // Custom anthropic-messages providers (e.g. bifrost-claude, litellm-claude) using Claude family models
+  // don't have a plugin/bundled hook, so they don't get adaptive thinking even though the model supports it.
+  // Fall back to the canonical Claude profile when the model id matches a known Claude family pattern.
+  const modelId = params.context?.modelId;
+  if (typeof modelId === "string" && /claude-(opus|sonnet|haiku)-4[._-](5|6|7)/i.test(modelId)) {
+    return resolveClaudeThinkingProfile(modelId);
+  }
+  return undefined;
 }

This requires resolveClaudeThinkingProfile imported from provider-model-shared (already exported there).

Why it's safe

  • Plugin-registered and bundled hooks short-circuit first — they remain authoritative for their providers.
  • The regex is narrow (only post-4.4 Claude families with confirmed adaptive support).
  • resolveClaudeThinkingProfile returns the canonical profile shape ({ levels, defaultLevel }).
  • Returns undefined when the model id doesn't match, matching prior fall-through behavior.

Verified locally

Applied as a dist patch on 2026.5.19. /think adaptive now sets adaptive on bifrost-claude/claude-sonnet-4-6 and bifrost-claude/claude-opus-4-7. Existing plugin-anchored providers (azure-claude, anthropic) unaffected.

Related

Same fix pattern probably needed for the OpenAI side if anyone proxies GPT-5 family through a custom openai-completions provider — resolveOpenAIThinkingProfile would be the equivalent fallback. Out of scope here unless you want to fold it in.

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

openclaw - 💡(How to fix) Fix Custom anthropic-messages providers don't get Claude adaptive thinking (resolveProviderThinkingProfile fallback)