feat(provider): add anthropic chat format for new provider#20
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds an Anthropic gateway provider with OpenAI↔Anthropic request/response and SSE bridging, extends chat stream state to include response metadata, updates provider registry to register Changes
Sequence DiagramsequenceDiagram
participant Client
participant Gateway
participant AnthropicAPI as Anthropic API
Client->>Gateway: OpenAI ChatCompletionRequest
Note over Gateway: Transform request\n- Hoist system/developer into Anthropic system prompt\n- Convert messages & tools to Anthropic format\n- Map stop sequences / tool-choice
Gateway->>AnthropicAPI: AnthropicMessagesRequest
AnthropicAPI-->>Gateway: AnthropicMessagesResponse (id, model, created) / SSE events
Note over Gateway: Parse response/SSE\n- Capture response metadata into ChatStreamState\n- Map content blocks → assistant messages\n- Map tool_use → function/tool calls\n- Aggregate streaming deltas into ChatCompletionChunk(s)
Gateway->>Client: ChatCompletionResponse / streaming chunks
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/gateway/providers/anthropic/mod.rs (2)
201-206: Assertion can be simplified.The assertion
response.choices[0].message.content.as_ref().map(|_| true)just checks forSome. A cleaner approach would be to useis_some().✨ Suggested simplification
- assert_eq!( - response.choices[0].message.content.as_ref().map(|_| true), - Some(true) - ); + assert!(response.choices[0].message.content.is_some());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/gateway/providers/anthropic/mod.rs` around lines 201 - 206, The test assertion that checks presence of content uses a convoluted map-to-true pattern; replace the expression response.choices[0].message.content.as_ref().map(|_| true) == Some(true) with a direct is_some() check (e.g., assert!(response.choices[0].message.content.as_ref().is_some())) to simplify and clarify the intent for the Content field on response.choices[0].message.
47-50: Consider documenting or making the Anthropic API version configurable.The
anthropic-versionheader is hardcoded to2023-06-01. While this is a stable version, Anthropic periodically releases new API versions with additional features. Consider adding a comment explaining this choice or making it configurable if version-specific features become necessary.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/gateway/providers/anthropic/mod.rs` around lines 47 - 50, The Anthropic API version header is hardcoded in the headers.insert call (HeaderName::from_static("anthropic-version"), HeaderValue::from_static("2023-06-01")); update this to be configurable or at least documented: add a short comment explaining why this version is pinned and potential impacts, and refactor the HeaderValue to use a configurable constant or env var (e.g., ANTHROPIC_API_VERSION) so code paths that construct headers can reference that constant instead of the literal string; ensure the unique symbols headers.insert, HeaderName::from_static("anthropic-version"), and HeaderValue::from_static("2023-06-01") are updated to use the new constant or accompanied by the explanatory comment.src/gateway/providers/anthropic/transform.rs (2)
172-194: Tool call accumulator created viaor_default()may lack metadata ifContentBlockStartis missed.If a
ContentBlockDeltawithInputJsonDeltaarrives before its correspondingContentBlockStart(e.g., due to network issues or malformed streams), the accumulator will be created withoutid,kind, orname. Thebuild_stream_chunkwill still succeed, but the emittedChunkToolCallwill haveNonefor these fields.This is likely acceptable since a malformed stream from Anthropic would be an upstream issue, but consider adding a debug log or metric for this edge case.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/gateway/providers/anthropic/transform.rs` around lines 172 - 194, ContentDelta::InputJsonDelta handling currently creates an accumulator with state.tool_call_accumulators.entry((0, index)).or_default() which can produce a tool-call accumulator missing metadata (id/kind/name) if the corresponding ContentBlockStart was missed; update this branch to detect when the entry is newly created or when accumulator.id/kind/name are None and emit a debug log or increment a metric before pushing partial_json and calling build_stream_chunk (referencing ContentDelta::InputJsonDelta, state.tool_call_accumulators, build_stream_chunk, ChunkToolCall, ChunkFunctionCall); ensure the log/metric includes the index and any context to diagnose malformed streams.
119-160: Hardcoded choice index 0 may limit future extensibility.The tool call accumulator key uses a hardcoded choice index of
0(line 127:(0, index)). While Anthropic's current API doesn't support multiple choices (n > 1), this assumption is baked into multiple places. If Anthropic adds multi-choice streaming in the future, this would need refactoring.This is acceptable for now given Anthropic's current API constraints, but worth noting in a comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/gateway/providers/anthropic/transform.rs`:
- Around line 395-408: The crate uses if-let chain syntax (see
normalize_anthropic_content and its if let [...] && cache_control.is_none()
usage) which requires Rust 1.76; update Cargo.toml's [package] section to
declare the MSRV by adding rust-version = "1.76" so the minimum supported Rust
version is explicitly documented.
---
Nitpick comments:
In `@src/gateway/providers/anthropic/mod.rs`:
- Around line 201-206: The test assertion that checks presence of content uses a
convoluted map-to-true pattern; replace the expression
response.choices[0].message.content.as_ref().map(|_| true) == Some(true) with a
direct is_some() check (e.g.,
assert!(response.choices[0].message.content.as_ref().is_some())) to simplify and
clarify the intent for the Content field on response.choices[0].message.
- Around line 47-50: The Anthropic API version header is hardcoded in the
headers.insert call (HeaderName::from_static("anthropic-version"),
HeaderValue::from_static("2023-06-01")); update this to be configurable or at
least documented: add a short comment explaining why this version is pinned and
potential impacts, and refactor the HeaderValue to use a configurable constant
or env var (e.g., ANTHROPIC_API_VERSION) so code paths that construct headers
can reference that constant instead of the literal string; ensure the unique
symbols headers.insert, HeaderName::from_static("anthropic-version"), and
HeaderValue::from_static("2023-06-01") are updated to use the new constant or
accompanied by the explanatory comment.
In `@src/gateway/providers/anthropic/transform.rs`:
- Around line 172-194: ContentDelta::InputJsonDelta handling currently creates
an accumulator with state.tool_call_accumulators.entry((0, index)).or_default()
which can produce a tool-call accumulator missing metadata (id/kind/name) if the
corresponding ContentBlockStart was missed; update this branch to detect when
the entry is newly created or when accumulator.id/kind/name are None and emit a
debug log or increment a metric before pushing partial_json and calling
build_stream_chunk (referencing ContentDelta::InputJsonDelta,
state.tool_call_accumulators, build_stream_chunk, ChunkToolCall,
ChunkFunctionCall); ensure the log/metric includes the index and any context to
diagnose malformed streams.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 19913990-0e33-4442-90ca-a2db38b9fb6d
📒 Files selected for processing (5)
docs/internals/llm-types.mdsrc/gateway/providers/anthropic/mod.rssrc/gateway/providers/anthropic/transform.rssrc/gateway/providers/mod.rssrc/gateway/traits/chat_format.rs
There was a problem hiding this comment.
Pull request overview
Adds a first-class Anthropic provider implementation to the gateway’s new provider stack, including request/response bridging between the hub (OpenAI Chat Completions) types and Anthropic Messages, plus streaming adaptation.
Changes:
- Extend
ChatStreamStateto carry streamed response metadata (id,model,created) needed by provider SSE adapters. - Register a new
AnthropicDefprovider and expose it via the default provider registry. - Implement OpenAI↔Anthropic transform logic (including SSE stream event conversion) and document the new provider layering.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/gateway/traits/chat_format.rs | Adds response metadata fields to shared streaming state. |
| src/gateway/providers/mod.rs | Registers and exports the new Anthropic provider definition. |
| src/gateway/providers/anthropic/mod.rs | Implements ProviderMeta/ChatTransform and native Anthropic Messages support wiring. |
| src/gateway/providers/anthropic/transform.rs | Implements request/response and SSE streaming conversions between OpenAI hub types and Anthropic Messages. |
| docs/internals/llm-types.md | Documents stream-state metadata and Anthropic provider positioning in the new stack. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
As the 6th part of the major refactoring of the provider, add the Anthropic provider.
Summary by CodeRabbit
New Features
Bug Fixes / Improvements
Documentation