Skip to content

修复 Claude /anthropic 模型发现回退#554

Merged
cita-777 merged 1 commit into
cita-777:mainfrom
bluicezhen:fix/claude-anthropic-model-fallback
May 17, 2026
Merged

修复 Claude /anthropic 模型发现回退#554
cita-777 merged 1 commit into
cita-777:mainfrom
bluicezhen:fix/claude-anthropic-model-fallback

Conversation

@bluicezhen
Copy link
Copy Markdown
Contributor

@bluicezhen bluicezhen commented May 14, 2026

摘要

  • 为 Claude 站点增加模型发现回退:当配置的 /anthropic/v1/models 没有返回模型时,改查父级 OpenAI 兼容的 /v1/models
  • 保持 Claude 聊天路由不变,仍然走配置的 /anthropic/v1/messages
  • 新增 Claude 适配器测试,覆盖正常 Claude 模型接口、OpenAI 兼容回退接口,以及非 /anthropic 地址不回退的场景。

测试

  • npm test -- src/server/services/platforms/claude.test.ts

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Enhanced Claude platform integration with improved model discovery. The adapter now automatically falls back to alternative endpoint configurations when the primary endpoint is unavailable, ensuring better compatibility across different setups.

Review Change Stack

Allow Claude sites configured under an /anthropic path to fall back to the parent OpenAI-compatible models endpoint so model refresh works without changing chat routing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

ClaudeAdapter now implements a two-stage model discovery mechanism: it first attempts to fetch models from the /anthropic/v1/models endpoint using Anthropic-specific authentication headers, and if that fails, it derives an OpenAI-compatible base URL and retries the /v1/models endpoint with standard bearer token authentication. The implementation includes a new URL normalization helper and comprehensive test coverage for all fallback paths.

Changes

Claude Adapter Fallback Model Discovery

Layer / File(s) Summary
URL resolution helper and local constant
src/server/services/platforms/claude.ts
CLAUDE_DEFAULT_ANTHROPIC_VERSION is now defined locally, and resolveOpenAiCompatibleBaseUrl() strips trailing /anthropic path segments to derive fallback endpoints.
Model discovery with Anthropic fallback
src/server/services/platforms/claude.ts
ClaudeAdapter.getModels first attempts Anthropic model fetching with x-api-key and anthropic-version headers; on failure, it derives an OpenAI-compatible URL and retries with Authorization: Bearer, returning empty array if no fallback exists.
Comprehensive test suite for fallback behavior
src/server/services/platforms/claude.test.ts
Test suite validates three scenarios: direct Anthropic endpoint success with x-api-key, fallback to derived URL on 404 with bearer auth, and non-anthropic base URLs skipping the primary attempt and returning empty on failure; includes per-test local server setup and cleanup.

Sequence Diagram

sequenceDiagram
  participant ClaudeAdapter
  participant AnthroPrimary as /anthropic/v1/models
  participant OpenAiFallback as /v1/models (fallback)
  ClaudeAdapter->>AnthroPrimary: GET with x-api-key, anthropic-version
  alt Primary Success
    AnthroPrimary-->>ClaudeAdapter: 200 models response
    ClaudeAdapter->>ClaudeAdapter: Return model IDs
  else Primary Fails (404)
    AnthroPrimary-->>ClaudeAdapter: 404 error
    ClaudeAdapter->>OpenAiFallback: GET with Authorization: Bearer
    OpenAiFallback-->>ClaudeAdapter: 200 models response
    ClaudeAdapter->>ClaudeAdapter: Return model IDs
  else Non-Anthropic URL
    ClaudeAdapter->>OpenAiFallback: GET with Authorization: Bearer
    OpenAiFallback-->>ClaudeAdapter: error or non-success
    ClaudeAdapter->>ClaudeAdapter: Return []
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • cita-777/metapi#236: Both PRs adjust Claude OAuth model discovery to query the /v1/models endpoint with correct auth/header handling (fallback derived base URL in ClaudeAdapter.getModels vs live /v1/models discovery in modelService/tests).

Suggested labels

area: server, size: M

Poem

🐰 A clever rabbit hops between two doors,
When one won't open, tries another's floors,
With different keys for different locks,
The fallback flows where auth mocks,
Now three test cases guard the way—
Hopping smoothly, come what may! 🔐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title in Chinese refers to fixing Claude /anthropic model discovery fallback, which directly matches the main change: adding fallback logic to ClaudeAdapter.getModels when /anthropic/v1/models fails.
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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@github-actions github-actions Bot added area: server Server-side API and backend changes size: S 50 to 199 lines changed labels May 14, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/server/services/platforms/claude.test.ts (1)

3-3: ⚡ Quick win

Use a type-only import for AddressInfo as it's only used in a type assertion.

While the repo configuration doesn't enforce this rule (verbatimModuleSyntax is not enabled), it's a best practice to mark type-only imports explicitly.

💡 Suggested fix
-import { AddressInfo } from 'node:net';
+import type { AddressInfo } from 'node:net';
🤖 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/server/services/platforms/claude.test.ts` at line 3, The import of
AddressInfo is used only as a type assertion in claude.test.ts; change it to a
type-only import to avoid importing at runtime by replacing the current import
of AddressInfo with a type-only import (i.e., import type { AddressInfo } from
'node:net') so references to AddressInfo (used in the test assertions/type
casts) remain purely compile-time.
🤖 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.

Nitpick comments:
In `@src/server/services/platforms/claude.test.ts`:
- Line 3: The import of AddressInfo is used only as a type assertion in
claude.test.ts; change it to a type-only import to avoid importing at runtime by
replacing the current import of AddressInfo with a type-only import (i.e.,
import type { AddressInfo } from 'node:net') so references to AddressInfo (used
in the test assertions/type casts) remain purely compile-time.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d1fb89b-8506-4174-be56-766be0427b8f

📥 Commits

Reviewing files that changed from the base of the PR and between cdb12a9 and ed1e6e9.

📒 Files selected for processing (2)
  • src/server/services/platforms/claude.test.ts
  • src/server/services/platforms/claude.ts

@cita-777 cita-777 merged commit c308a3e into cita-777:main May 17, 2026
18 checks passed
linuxroc pushed a commit to linuxroc/metapi that referenced this pull request May 17, 2026
Brings in 8 upstream commits:
- fix: Claude anthropic model discovery fallback (cita-777#554)
- chore(deps): minor-and-patch group bumps (14 deps)
- chore(deps): marked 17 -> 18
- chore(deps-dev): electron 41 -> 42
- chore(deps-dev): react-router-dom 7.14 -> 7.15
- chore(deps): undici 6.24 -> 6.25 (runtime-http group)
- chore(deps-dev): build-tooling group
- chore(deps): github-actions group

Conflict resolution:
- src/server/services/platforms/claude.ts (content conflict)
- src/server/services/platforms/claude.test.ts (add/add conflict)

Both conflicts were resolved with --ours: the local fork's
implementation of the Claude model discovery fallback (commit 4ecf3f3,
"feat(claude-models): fall back to parent /v1/models when
/anthropic/v1/models is empty") is a strict superset of upstream PR
cita-777#554. Specifically, the local fork:

- reuses CLAUDE_DEFAULT_ANTHROPIC_VERSION from oauth/claudeProvider.js
  rather than re-hardcoding the literal '2023-06-01' string (single
  source of truth).
- exposes pure URL helpers (isAnthropicSuffixedBaseUrl,
  stripAnthropicSuffixSegment) on standardApiProvider.ts with 34
  parameterized unit tests covering case variants, trailing-slash,
  query/port preservation, host-only and /anthropic-proxy negatives.
- emits two info-level diagnostic logs ([claude-models-fallback]
  intent / hit) with token-free site labels for operator visibility.
- absorbs underlying errors from BOTH the standard and the fallback
  call so getModels() never throws a network/HTTP error to the caller.
- carries 27 integration tests via a node:http fixture covering every
  failure mode and zero cross-call state.

Verification:
- npm run typecheck:server: clean
- npm run build:server: clean
- npm run repo:drift-check: 0 new violations (5 pre-existing tracked)
- src/server/services/platforms/{claude,standardApiProvider,llmUpstream}.test.ts: 70/70
- session-stick-routing-binding-timing-fix suites: 72/72
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: server Server-side API and backend changes size: S 50 to 199 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants