Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
46e5ac9
fix(网关): 对齐 Claude OAuth 请求适配
cyhhao Jan 15, 2026
c579439
fix(网关): 区分 Claude Code OAuth 适配
cyhhao Jan 15, 2026
98b65e6
fix(gateway): avoid injecting invalid SSE on client cancel
cyhhao Jan 15, 2026
c11f14f
fix(gateway): drain upstream after client disconnect
cyhhao Jan 15, 2026
65fd0d1
fix(网关): 补齐非 Claude Code OAuth 兼容
cyhhao Jan 15, 2026
bd854e1
fix(网关): Claude Code OAuth 补齐 oauth beta
cyhhao Jan 16, 2026
2a7d04f
fix(网关): 对齐 Claude OAuth 请求适配
cyhhao Jan 15, 2026
b8c48fb
fix(网关): 区分 Claude Code OAuth 适配
cyhhao Jan 15, 2026
0962ba4
fix(网关): 补齐非 Claude Code OAuth 兼容
cyhhao Jan 15, 2026
0c011b8
fix(网关): Claude Code OAuth 补齐 oauth beta
cyhhao Jan 16, 2026
8917a3e
fix(网关): 修复 golangci-lint
cyhhao Jan 16, 2026
39e4300
Merge pull request #1 from cyhhao/fix/responses-stream-cancel
cyhhao Jan 17, 2026
32c47b1
fix(gateway): satisfy golangci-lint checks
cyhhao Jan 17, 2026
6901b64
merge: sync upstream changes
cyhhao Jan 17, 2026
eca3898
fix(网关): SSE 缓冲 input_json_delta 反向转换
cyhhao Jan 18, 2026
a05b8b5
fix(网关): SSE 缓冲 input_json_delta 反向转换
cyhhao Jan 18, 2026
02db4c7
fix(网关): 修复流式 tool 输入参数转换
cyhhao Jan 18, 2026
eb7d830
fix(网关): 修复流式 tool 输入参数转换
cyhhao Jan 18, 2026
26298c4
fix(openai): emit OpenAI-compatible SSE error events
cyhhao Jan 19, 2026
bba5b3c
fix(网关): OAuth 请求统一 user_id 与指纹
cyhhao Jan 19, 2026
49be9d0
fix(网关): OAuth 请求统一 user_id 与指纹
cyhhao Jan 19, 2026
dd7f212
merge: resolve conflicts with main
cyhhao Jan 19, 2026
2f2e76f
fix(gateway): gate streaming tool rewrites behind mimic
cyhhao Jan 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/internal/handler/gateway_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,9 @@ func (h *GatewayHandler) CountTokens(c *gin.Context) {
return
}

// 检查是否为 Claude Code 客户端,设置到 context 中
SetClaudeCodeClientContext(c, body)

setOpsRequestContext(c, "", false, body)

parsedReq, err := service.ParseGatewayRequest(body)
Expand Down
54 changes: 50 additions & 4 deletions backend/internal/pkg/claude/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@ const (
BetaClaudeCode = "claude-code-20250219"
BetaInterleavedThinking = "interleaved-thinking-2025-05-14"
BetaFineGrainedToolStreaming = "fine-grained-tool-streaming-2025-05-14"
BetaTokenCounting = "token-counting-2024-11-01"
)

// DefaultBetaHeader Claude Code 客户端默认的 anthropic-beta header
const DefaultBetaHeader = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming

// MessageBetaHeaderNoTools /v1/messages 在无工具时的 beta header
const MessageBetaHeaderNoTools = BetaOAuth + "," + BetaInterleavedThinking

// MessageBetaHeaderWithTools /v1/messages 在有工具时的 beta header
const MessageBetaHeaderWithTools = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking

// CountTokensBetaHeader count_tokens 请求使用的 anthropic-beta header
const CountTokensBetaHeader = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaTokenCounting

// HaikuBetaHeader Haiku 模型使用的 anthropic-beta header(不需要 claude-code beta)
const HaikuBetaHeader = BetaOAuth + "," + BetaInterleavedThinking

Expand All @@ -25,15 +35,15 @@ const APIKeyHaikuBetaHeader = BetaInterleavedThinking

// DefaultHeaders 是 Claude Code 客户端默认请求头。
var DefaultHeaders = map[string]string{
"User-Agent": "claude-cli/2.0.62 (external, cli)",
"User-Agent": "claude-cli/2.1.2 (external, cli)",
"X-Stainless-Lang": "js",
"X-Stainless-Package-Version": "0.52.0",
"X-Stainless-Package-Version": "0.70.0",
"X-Stainless-OS": "Linux",
"X-Stainless-Arch": "x64",
"X-Stainless-Runtime": "node",
"X-Stainless-Runtime-Version": "v22.14.0",
"X-Stainless-Runtime-Version": "v24.3.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Timeout": "60",
"X-Stainless-Timeout": "600",
"X-App": "cli",
"Anthropic-Dangerous-Direct-Browser-Access": "true",
}
Expand Down Expand Up @@ -79,3 +89,39 @@ func DefaultModelIDs() []string {

// DefaultTestModel 测试时使用的默认模型
const DefaultTestModel = "claude-sonnet-4-5-20250929"

// ModelIDOverrides Claude OAuth 请求需要的模型 ID 映射
var ModelIDOverrides = map[string]string{
"claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
"claude-opus-4-5": "claude-opus-4-5-20251101",
"claude-haiku-4-5": "claude-haiku-4-5-20251001",
}

// ModelIDReverseOverrides 用于将上游模型 ID 还原为短名
var ModelIDReverseOverrides = map[string]string{
"claude-sonnet-4-5-20250929": "claude-sonnet-4-5",
"claude-opus-4-5-20251101": "claude-opus-4-5",
"claude-haiku-4-5-20251001": "claude-haiku-4-5",
}

// NormalizeModelID 根据 Claude OAuth 规则映射模型
func NormalizeModelID(id string) string {
if id == "" {
return id
}
if mapped, ok := ModelIDOverrides[id]; ok {
return mapped
}
return id
}

// DenormalizeModelID 将上游模型 ID 转换为短名
func DenormalizeModelID(id string) string {
if id == "" {
return id
}
if mapped, ok := ModelIDReverseOverrides[id]; ok {
return mapped
}
return id
}
16 changes: 16 additions & 0 deletions backend/internal/service/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,22 @@ func (a *Account) GetExtraString(key string) string {
return ""
}

func (a *Account) GetClaudeUserID() string {
if v := strings.TrimSpace(a.GetExtraString("claude_user_id")); v != "" {
return v
}
if v := strings.TrimSpace(a.GetExtraString("anthropic_user_id")); v != "" {
return v
}
if v := strings.TrimSpace(a.GetCredential("claude_user_id")); v != "" {
return v
}
if v := strings.TrimSpace(a.GetCredential("anthropic_user_id")); v != "" {
return v
}
return ""
}

func (a *Account) IsCustomErrorCodesEnabled() bool {
if a.Type != AccountTypeAPIKey || a.Credentials == nil {
return false
Expand Down
Loading
Loading