fix(api): improve Anthropic adapter transparency and compatibility#66
Conversation
- Forward client User-Agent to upstream providers for gateway transparency - Add additionalProperties: true to Anthropic TypeBox validation schemas so tools, system prompts, and content blocks with cache_control are accepted - Make thinking block signature optional in validation schema - Append /v1/ to Anthropic upstream base URL to match actual API endpoint Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthrough规范化 Anthropic 上游 URL 为 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client as Client
participant API as Messages API
participant Adapter as Anthropic Adapter
participant Upstream as Anthropic /v1/messages
rect rgba(135,206,250,0.5)
Client->>API: 发起消息请求(含 blocks)
API->>Adapter: 转换请求(包含 thinking.signature & tools.cache_control)
Adapter->>Upstream: POST /v1/messages (带 user-agent)
Upstream-->>Adapter: 流式响应(text_delta / thinking_delta / signature_delta)
Adapter->>API: 转发内部流块(包含 signature_delta)
API->>Client: 将合并的流式事件推送到客户端
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
诗
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Summary of ChangesHello @pescn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Anthropic API adapter by improving its transparency and compatibility. It ensures that client-specific headers are propagated to upstream services and relaxes validation rules for Anthropic request schemas to accommodate additional properties and optional fields. Furthermore, it corrects the base URL used for Anthropic API calls, ensuring proper routing to the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces several improvements for the Anthropic adapter, enhancing compatibility and transparency. It correctly enables forwarding of the User-Agent header, updates the Anthropic API endpoint to include /v1/, and makes the validation schemas more flexible by allowing additional properties and making the signature field on thinking blocks optional.
My main feedback is that while allowing additional properties in the validation schema is a good first step, these properties are currently dropped during the conversion to the internal data model. This means fields like cache_control on tool definitions won't be forwarded to the upstream provider. I've left a detailed comment with suggestions on how to achieve full end-to-end passthrough for these properties.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/src/adapters/upstream/anthropic.ts (1)
461-466:⚠️ Potential issue | 🟠 Major修复 Anthropic baseUrl 拼接的 /v1 重复问题。
当前代码硬编码拼接
/v1/messages。若配置的provider.baseUrl已包含/v1(如https://api.anthropic.com/v1),会产生baseUrl/v1/v1/messages的重复路径,导致请求失败。应在拼接时检查是否已存在/v1前缀。修复方案
- const url = `${baseUrl}/v1/messages`; + const url = baseUrl.endsWith("/v1") + ? `${baseUrl}/messages` + : `${baseUrl}/v1/messages`;
…ter pipeline - Add cacheControl to InternalToolDefinition so tool-level cache_control is forwarded to upstream (was silently dropped after validation) - Add signature to ThinkingContentBlock so thinking blocks can be replayed in multi-turn conversations - Normalize Anthropic baseUrl to handle both with and without /v1 suffix Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
backend/src/adapters/upstream/anthropic.ts (2)
309-313:⚠️ Potential issue | 🟠 Major响应解析中缺少
signature字段的提取。
convertContentBlock函数在解析上游 Anthropic 响应时,没有将 thinking 块中的signature字段传递到内部格式。这将导致从 Anthropic 返回的signature丢失,破坏多轮对话中思维块重放功能。🐛 建议修复
case "thinking": return { type: "thinking", thinking: block.thinking || "", + signature: block.signature, } as ThinkingContentBlock;
544-548:⚠️ Potential issue | 🔴 Critical流式响应中 thinking 块的
signature字段未被处理。在流式响应中,Anthropic API 通过
signature_delta事件(在content_block_stop之前)传递 signature,但代码中存在两个问题:
AnthropicStreamEvent.delta接口(第 95-104 行)缺少signature字段定义,当前仅包含text、thinking、partial_json等。流式响应解析器中完全没有
signature_delta事件的处理逻辑,导致 thinking 块的 signature 在流式场景下丢失。这会破坏多轮对话功能,因为重新提交 thinking 块时需要原始的 signature 字段。需要在
AnthropicStreamEvent.delta中添加signature字段,并在content_block_delta事件处理中处理signature_delta类型的事件。
🧹 Nitpick comments (1)
backend/src/adapters/upstream/anthropic.ts (1)
467-474: URL 规范化逻辑合理,但建议添加注释说明预期行为。当前实现能正确处理常见的 baseUrl 格式变体。不过,对于自定义代理路径(如
https://proxy.example.com/custom-path/v1),末尾的/v1也会被移除。如果这是预期行为,建议在注释中明确说明。💡 建议增强注释
// Build URL — strip trailing slash and /v1 suffix to normalize, // then always append /v1/messages. This handles both // "https://api.anthropic.com" and "https://api.anthropic.com/v1". + // Note: Any path ending with /v1 will have it stripped (e.g., /custom/v1 → /custom). let baseUrl = provider.baseUrl.replace(/\/+$/, "");
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces several valuable improvements for the Anthropic adapter, enhancing its compatibility and transparency. The changes include forwarding the User-Agent header, making TypeBox validation schemas more flexible by allowing additional properties, making the signature field on thinking blocks optional, and improving the upstream URL construction logic. Support for cache_control on tools is also added.
The implementation is solid and all changes are consistent across the different layers of the application. The code is clean and the logic is robust. I have one suggestion to improve maintainability by reducing code repetition in the TypeBox schema definitions, but overall this is a great set of improvements.
| const tAnthropicTextBlock = t.Object( | ||
| { | ||
| type: t.Literal("text"), | ||
| text: t.String(), | ||
| }, | ||
| { additionalProperties: true }, | ||
| ); | ||
|
|
||
| const tAnthropicImageBlock = t.Object( | ||
| { | ||
| type: t.Literal("image"), | ||
| source: t.Object( | ||
| { | ||
| type: t.String(), | ||
| media_type: t.Optional(t.String()), | ||
| data: t.Optional(t.String()), | ||
| url: t.Optional(t.String()), | ||
| }, | ||
| { additionalProperties: true }, | ||
| ), | ||
| }, | ||
| { additionalProperties: true }, | ||
| ); | ||
|
|
||
| const tAnthropicToolUseBlock = t.Object( | ||
| { | ||
| type: t.Literal("tool_use"), | ||
| id: t.String(), | ||
| name: t.String(), | ||
| input: t.Record(t.String(), t.Unknown()), | ||
| }, | ||
| { additionalProperties: true }, | ||
| ); | ||
|
|
||
| const tAnthropicToolResultBlock = t.Object( | ||
| { | ||
| type: t.Literal("tool_result"), | ||
| tool_use_id: t.String(), | ||
| content: t.Optional(t.Union([t.String(), t.Array(t.Unknown())])), | ||
| is_error: t.Optional(t.Boolean()), | ||
| }, | ||
| { additionalProperties: true }, | ||
| ); | ||
|
|
||
| const tAnthropicThinkingBlock = t.Object( | ||
| { | ||
| type: t.Literal("thinking"), | ||
| thinking: t.String(), | ||
| signature: t.Optional(t.String()), | ||
| }, | ||
| { additionalProperties: true }, | ||
| ); |
There was a problem hiding this comment.
While adding { additionalProperties: true } is the correct fix, it introduces a lot of repetition across the schema definitions. To improve maintainability and reduce boilerplate, you could create a helper function that wraps t.Object and applies this option by default.
For example:
import { t, type TProperties } from "elysia";
const TObjectLoose = <T extends TProperties>(schema: T) => t.Object(schema, { additionalProperties: true });
// Then you can define your schemas more concisely:
const tAnthropicTextBlock = TObjectLoose({
type: t.Literal("text"),
text: t.String(),
});This would make the code in this file (and potentially others) cleaner and less error-prone if you need to apply other default options in the future.
There was a problem hiding this comment.
Agreed — introduced a tLooseObject helper in 80181ec to eliminate all 13 repeated { additionalProperties: true } occurrences in this file.
…line - Extract signature from thinking blocks in non-streaming response parsing - Add signature_delta handling in streaming response parser and serializer - Add signature field to AnthropicStreamEvent delta and InternalStreamChunk - Add clarifying comment on baseUrl /v1 normalization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract repeated t.Object(..., { additionalProperties: true }) pattern
into a reusable tLooseObject helper in the Anthropic Messages endpoint.
Reduces 13 occurrences to a single definition.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces several valuable improvements for the Anthropic adapter, enhancing its transparency and compatibility. Key changes include forwarding the User-Agent header, making the validation schemas for Anthropic requests more flexible by allowing additional properties, making the signature field on thinking blocks optional, and refining the upstream URL construction. These changes are well-implemented and align with the goal of making the gateway a more transparent and robust proxy for Anthropic's API. I've identified one area for improvement in the URL construction logic to make it more robust against edge cases, for which I've provided a suggestion.
Summary
User-Agentheader to upstream providers instead of stripping it, making the gateway behave as a transparent proxyadditionalProperties: trueto all Anthropic TypeBox validation schemas (messages.ts) so requests withcache_control, extended tool fields, etc. are no longer rejected at validationsignatureoptional on thinking blocks in the validation schema/v1/to Anthropic upstream base URL construction so the final URL becomes{BASE_URL}/v1/messagesTest plan
cache_controlon system prompt blocks and verify it is acceptedcache_controlon tool definitions and verify it is accepted{BASE_URL}/v1/messages🤖 Generated with Claude Code
Summary by CodeRabbit
发布说明
新特性
兼容性
修复
✏️ Tip: You can customize this high-level summary in your review settings.