feat: Anthropic Messages -> Chat Completions#3336
Open
FjlI5 wants to merge 3 commits into
Open
Conversation
…s bridge
The first delta for a tool-call index was copied wholesale (copyCall := toolCall),
seeding Function.Arguments, and then the same fragment was appended again by the
accumulating +=. Upstreams that inline a tool call's full arguments in the first
delta (DeepSeek/GLM/Kimi, unlike OpenAI's empty first delta) thus produced doubled
arguments like {...}{...}, breaking JSON parsing and the non-streaming path.
Reset the seeded arguments so += accumulates each fragment exactly once.
Contributor
|
All contributors have signed the CLA. ✅ |
e8dcf1b to
ebb090a
Compare
Contributor
Author
|
recheck |
Serve /v1/messages clients on API-key accounts whose upstream only speaks /v1/chat/completions through a direct Anthropic<->Chat converter, bypassing the Responses hub. This avoids the orphan/doubling artifacts that surface when routing chat->responses->anthropic for parallel tool calls and reasoning. - apicompat/anthropic_chatcompletions.go: AnthropicToChatCompletions (request) plus a streaming chunk->Anthropic-SSE state machine and a sync stream->response collapse, reusing sanitizeAnthropicToolUseInput and ResponsesAnthropicEventToSSE. - service/openai_messages_chat_fallback.go: forwardMessagesViaRawChatCompletions (always-stream upstream with include_usage; client preference selects relay vs collapse), mirroring the responses raw-chat fallback send path. - ForwardAsAnthropic: top branch routes chat-only API-key accounts here. - tests: request conversion, streaming, parallel-tools no-orphan, Read buffering, reasoning-only fallback, sync collapse.
ebb090a to
2718093
Compare
|
Looking forward to having this merged. I really need this! |
|
首先非常感谢这个 PR,非常实用!🎉 在接入 Claude 时遇到一个问题,想反馈一下。 问题描述使用本功能提供的接口接入 Claude 时,在 auto 模式下,自动分类器会持续报错: 抓包分析我通过抓包定位到了原因: Claude 在 auto 模式下做安全分类时,会发起一个非流式(non-stream)的 这导致 Claude 客户端无法把非流式请求返回的 JSON 正常解析(它期望的是 期望希望能够在判断请求为非流式( 期待修复!🙏 |
The Anthropic<->Chat bridge always streams the upstream, so its text/event-stream Content-Type is forwarded by WriteFilteredHeaders and gin's c.JSON cannot override an already-set header. Non-stream /v1/messages clients (e.g. Claude auto-mode safety classification) then received a JSON body under a text/event-stream Content-Type and failed to parse it. Reset the header explicitly before c.JSON, matching the buffered Responses/Chat paths, and add a regression test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@VoidIsVoid 感谢反馈,已修复: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


本 PR 含两个提交。
1. fix(apicompat): 修复 chat→responses 桥接中工具调用参数翻倍
流式转换 Chat Completions → Responses 事件时,某 tool_call index 的首个带有
Function.Arguments的 delta 被整体拷贝(copyCall := toolCall),随后+=又把同一片Function.Arguments加了一遍。对于在首个 delta 内联完整参数的上游(如 DeepSeek/GLM/Kimi,区别于 OpenAI 首片为空),会产出{...}{...}这种翻倍参数,破坏 JSON 解析与非流式路径。修复:拷贝后清空种子参数,让+=对每片只累加一次。2. feat(openai): Anthropic Messages -> Chat Completions 直连桥接
OpenAI 平台分组开启 messages 调度后,客户端使用
/v1/messages请求,若调度到只支持/v1/chat/completions的API-key 账号上游时,仍然走/v1/responses而不会回退成/v1/chat/completions。此提交为「客户端走
/v1/messages、而 API-key 账号上游只支持/v1/chat/completions」的场景提供一条直连转换路径。apicompat/anthropic_chatcompletions.go:AnthropicToChatCompletions(请求)+ 流式 chunk→Anthropic-SSE 状态机 + 非流式 stream→response 折叠;复用sanitizeAnthropicToolUseInput、ResponsesAnthropicEventToSSE。service/openai_messages_chat_fallback.go:forwardMessagesViaRawChatCompletions(上游恒流式 +include_usage;按客户端偏好选择转发或折叠),与 responses 的 raw-chat fallback 发送逻辑对齐。ForwardAsAnthropic顶部按APIKey && !ShouldUseResponsesAPI分流到该直连路径。效果:


测试
go build通过;go test ./internal/pkg/apicompat/、go test ./internal/service/通过;golangci-lint 通过。