Skip to content

fix: route anthropic through OpenAI-compat endpoint (+ extract shared helper) - #216

Merged
KrasimirKralev merged 4 commits into
ID-Robots:betafrom
KrasimirKralev:fix/anthropic-openai-compat-reroute
Jun 19, 2026
Merged

KrasimirKralev merged 4 commits into
ID-Robots:betafrom
KrasimirKralev:fix/anthropic-openai-compat-reroute

Conversation

@KrasimirKralev

@KrasimirKralev KrasimirKralev commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Problem

On OpenClaw 2026.6.8, Anthropic chats fail with:

ProviderAuthError: No API key found for provider "anthropic".
Auth store: …/agents/main/agent/openclaw-agent.sqlite … | missing-provider-auth

6.8 added a per-agent sqlite auth store, and the native anthropic plugin reads auth from there — but ClawBox writes a file-based auth profile, which doesn't get loaded into it. So even with a valid api_key profile (#214), the call fails "No API key found" at runtime. Same class as the google bug (#215), different symptom.

Fix

Route anthropic through Anthropic's OpenAI-compatible endpoint (api.anthropic.com/v1) with the key inline, exactly like google/openrouter — the gateway then authenticates the call itself.

Since this is the third openai-compat provider, also extracted the shared writeOpenAICompatProvider() helper (flagged on #215) and refactored openrouter + google onto it. The chat/model auto-extend gates on a shared OPENAI_COMPAT_PROVIDERS set.

  • configure/route.ts: writeOpenAICompatProvider() helper; openrouter/google/anthropic branches use it.
  • chat/model/route.ts: auto-extend now covers anthropic via the shared set.
  • /simplify applied: helper reuses the tested extractProviderModelId; dropped a redundant guard; corrected a now-wrong comment.

Why not openai-direct?

openai-direct (API-key) has the same root cause, but is intentionally not rerouted: it's untested (Codex/oauth is the common path) and OpenAI's native /responses + reasoning-effort behavior could degrade under a plain openai-completions shim. Separate follow-up if anyone hits it.

Verification

  • On device (OpenClaw 2026.6.8): api.anthropic.com/v1/chat/completions returns 200 + a real reply for claude-opus-4-8; the rerouted provider resolves and runs every Claude model, no auth fallback.
  • Unit test added (anthropic → openai-compat provider with inline key + api_key profile).

Follow-up (not this PR)

/simplify (reuse + altitude) flagged that "which providers are openai-compat" lives in two places (the configure branches + the chat/model set). A single-source-of-truth record (collapsing the three branches into one data-driven branch) is the clean fix — deferred here to keep the diff's blast radius small.

Summary by CodeRabbit

  • New Features

    • Anthropic provider can now be configured during the initial setup process.
    • Anthropic is now included in automatic model list management, matching the behavior of other compatible providers.
  • Tests

    • Added test coverage for Anthropic provider configuration, including API key management and model selection verification.

… helper)

Anthropic's native plugin reads a per-agent sqlite auth store that ClawBox's
file auth profile doesn't populate, so chats fail with ProviderAuthError 'No API
key found' at call time (missing-provider-auth) on 2026.6.8 — the same class as
google. Route anthropic through Anthropic's OpenAI-compatible endpoint
(api.anthropic.com/v1) with the key inline, like google/openrouter.

Now that there are three openai-compat providers, extract the shared
writeOpenAICompatProvider() helper (CodeRabbit/simplify flagged the duplication
on ID-Robots#215) and refactor openrouter + google to use it. chat/model auto-extend
gates on a shared OPENAI_COMPAT_PROVIDERS set (openrouter, google, anthropic).

openai-direct (API-key) has the same root cause but is intentionally NOT
rerouted here: it's untested (Codex/oauth is the common path) and its native
responses/reasoning behavior could degrade under a plain openai-completions
shim — a separate follow-up if anyone hits it.

Verified on device: api.anthropic.com/v1/chat/completions returns 200 for
claude-opus-4-8 with the key; the rerouted provider resolves + runs.
@KrasimirKralev
KrasimirKralev requested a review from a team as a code owner June 19, 2026 10:41
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@KrasimirKralev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 38 minutes and 24 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b37d4c0f-04be-497d-a236-398f68f695e0

📥 Commits

Reviewing files that changed from the base of the PR and between ed21c65 and f17f872.

📒 Files selected for processing (3)
  • src/app/setup-api/chat/model/route.ts
  • src/tests/routes/ai-models/configure.test.ts
  • src/tests/routes/chat-model.test.ts
📝 Walkthrough

Walkthrough

Anthropic is added as an OpenAI-compatible provider. A shared writeOpenAICompatProvider helper is extracted in the configure route to centralize provider definition writing, model list seeding, models.mode merge, and fallback model setup. An OPENAI_COMPAT_PROVIDERS set expands auto-extension coverage to include Anthropic. A test covers the new Anthropic path.

Changes

Anthropic OpenAI-compat provider wiring

Layer / File(s) Summary
writeOpenAICompatProvider helper and Anthropic routing
src/app/setup-api/ai-models/configure/route.ts
Adds Anthropic catalog imports, extracts a writeOpenAICompatProvider helper (writes provider definition, seeds model list, sets models.mode, calls ensureFallbackModel), adds isAnthropic flag, and refactors openrouter/google/anthropic configure branches to call the helper.
OPENAI_COMPAT_PROVIDERS set and auto-extension guard
src/app/setup-api/chat/model/route.ts
Introduces OPENAI_COMPAT_PROVIDERS Set and replaces the explicit openrouter/google provider check with OPENAI_COMPAT_PROVIDERS.has(...), adding anthropic to model auto-extension coverage.
Anthropic configure endpoint test
src/tests/routes/ai-models/configure.test.ts
Adds a test verifying anthropic is configured as an OpenAI-compat provider with inline API key, correct models.providers.anthropic fields, and a valid anthropic:default auth profile.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • ID-Robots/clawbox#95: Modifies the same POST /setup-api/ai-models/configure handler to write models.providers.openrouter, which is the exact logic now centralized into writeOpenAICompatProvider.
  • ID-Robots/clawbox#215: Extends the same OpenAI-compat wiring in configure/route.ts and the auto-extend logic in chat/model/route.ts for the google provider — directly continued by this PR for anthropic.
  • ID-Robots/clawbox#102: Modifies the same model-selection and provider/model slug handling in both route files, including curated catalog seeding that this PR builds upon for Anthropic.

Suggested labels

bug

Suggested reviewers

  • yalexx

🐇 A new provider hops into the fold,
Anthropic's models, fresh and bold.
The helper writes them all with care,
One function for each compatible pair.
merge the modes and set the key—
Claude is ready! Come and see! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: routing Anthropic through OpenAI-compatible endpoint and extracting a shared helper function, which directly corresponds to the core fix and refactoring in the changeset.
Description check ✅ Passed The description comprehensively covers the problem, fix, and verification, but omits the testing checklist items and type-of-change classification from the required template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/setup-api/chat/model/route.ts (1)

361-372: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not auto-create partial OpenAI-compatible provider definitions.

When a legacy or failed setup has an auth profile but no complete models.providers.${providerId} entry, this path writes only .models. For Anthropic, that omits the baseUrl, api: "openai-completions", and inline apiKey required by the reroute, so the primary can switch back onto a broken/incomplete provider. Return a clear re-save error instead of mutating a partial provider definition.

As per coding guidelines, src/app/**/route.ts handlers should ensure proper input validation, HTTP status codes, and error responses.

Proposed guard for incomplete provider definitions
           const providerDef = openclawConfig.models?.providers?.[providerId] as
-            | { models?: { id?: string; name?: string }[] }
+            | {
+                api?: string;
+                baseUrl?: string;
+                apiKey?: string;
+                models?: { id?: string; name?: string }[];
+              }
             | undefined;
-          const existingModels = providerDef?.models ?? [];
+          if (
+            !providerDef ||
+            providerDef.api !== "openai-completions" ||
+            typeof providerDef.baseUrl !== "string" ||
+            providerDef.baseUrl.length === 0 ||
+            typeof providerDef.apiKey !== "string" ||
+            providerDef.apiKey.length === 0 ||
+            !Array.isArray(providerDef.models)
+          ) {
+            return NextResponse.json(
+              {
+                error: `${labelForProvider(providerId, providerId)} must be re-saved in Settings before switching to ${requestedModel}.`,
+              },
+              { status: 409 },
+            );
+          }
+          const existingModels = providerDef.models;
           const configuredIds = existingModels
             .map((m) => m?.id)
             .filter((id): id is string => typeof id === "string" && id.length > 0);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/setup-api/chat/model/route.ts` around lines 361 - 372, When handling
model configuration in this route handler, add validation before appending
models to detect incomplete provider definitions. Before the conditional check
with configuredIds.includes(parsed.modelId), verify that the providerDef
contains all required fields for a complete provider definition (such as
baseUrl, api configuration, and apiKey for OpenAI-compatible or Anthropic
providers). If the providerDef exists but is incomplete, return a clear error
response with an appropriate HTTP status code instead of allowing the code to
proceed with writing only partial provider configuration. This prevents mutating
incomplete provider definitions that would break subsequent operations.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tests/routes/ai-models/configure.test.ts`:
- Around line 806-827: Add a new test case to cover user-selected non-curated
Anthropic models. The current test only verifies the default model behavior.
Create an additional test that calls configurePost with a custom Anthropic model
parameter (not the default curated one) to exercise the extractProviderModelId
path in writeOpenAICompatProvider(). This test should verify that custom Claude
model IDs are properly handled and prevent regressions where a non-registered
custom model could be incorrectly set as the primary model in
models.providers.anthropic.models.

---

Outside diff comments:
In `@src/app/setup-api/chat/model/route.ts`:
- Around line 361-372: When handling model configuration in this route handler,
add validation before appending models to detect incomplete provider
definitions. Before the conditional check with
configuredIds.includes(parsed.modelId), verify that the providerDef contains all
required fields for a complete provider definition (such as baseUrl, api
configuration, and apiKey for OpenAI-compatible or Anthropic providers). If the
providerDef exists but is incomplete, return a clear error response with an
appropriate HTTP status code instead of allowing the code to proceed with
writing only partial provider configuration. This prevents mutating incomplete
provider definitions that would break subsequent operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dfafbf70-0227-4852-8eef-a3df6492f405

📥 Commits

Reviewing files that changed from the base of the PR and between d5ca0df and ed21c65.

📒 Files selected for processing (3)
  • src/app/setup-api/ai-models/configure/route.ts
  • src/app/setup-api/chat/model/route.ts
  • src/tests/routes/ai-models/configure.test.ts

Comment thread src/tests/routes/ai-models/configure.test.ts
Address CodeRabbit review on ID-Robots#216:
- chat/model auto-extend: if models.providers.<p> exists without an inline
  apiKey (legacy/partial state), appending only .models leaves an openai-compat
  provider that can't authenticate. Return 409 'Re-save in Settings' instead of
  switching the primary onto a broken provider.
- configure test: cover a user-picked non-curated model (claude-opus-4-8) — the
  helper must still seed the pick via defaultModel so the gateway resolves it.
The new 409 guard for half-written providers needs models.providers.<p>.apiKey;
the existing 'accepts an arbitrary openrouter slug' mock only had the auth
profile (no provider entry), so it 409'd. Add the realistic provider entry
(baseUrl/api/apiKey/models) a configured openrouter provider actually has.
CodeRabbit: a complete openai-compat provider entry has baseUrl + api + apiKey
(written atomically by ai-models/configure). Check all three before appending a
model, so a partially-written entry triggers the 409 re-save instead of leaving
the primary on an unusable provider.
@KrasimirKralev
KrasimirKralev merged commit 8eaaf94 into ID-Robots:beta Jun 19, 2026
7 checks passed
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.

1 participant