feat(gateway): align body shape with real Claude Code CLI defaults
Three field-level alignments in normalizeClaudeOAuthRequestBody to
match real Claude Code CLI traffic byte-for-byte:
1. temperature: previously deleted unconditionally; now passes
through client value, defaults to 1 when absent (real CLI
always sends temperature, default 1).
2. max_tokens: defaults to 128000 when absent (real CLI default).
3. context_management: when thinking.type is enabled/adaptive
and the client did not provide context_management, inject
{"edits":[{"type":"clear_thinking_20251015","keep":"all"}]}
to mirror real CLI behavior.
tool_choice removal is unchanged (Claude Code OAuth credentials
do not allow client-supplied tool_choice).
Tests updated:
- gateway_body_order_test.go: temperature/max_tokens are now
expected in output; tool_choice still removed.
- gateway_prompt_test.go: system array is now 2 blocks
(billing + cc prompt), assertions adjusted.
- gateway_anthropic_apikey_passthrough_test.go: same 2-block
assertion.
This commit is contained in:
@@ -1078,12 +1078,38 @@ func normalizeClaudeOAuthRequestBody(body []byte, modelID string, opts claudeOAu
|
||||
}
|
||||
}
|
||||
|
||||
if gjson.GetBytes(out, "temperature").Exists() {
|
||||
if next, ok := deleteJSONPathBytes(out, "temperature"); ok {
|
||||
// temperature:真实 Claude Code CLI 总是发送 temperature(默认 1,客户端可覆盖)。
|
||||
// 之前的实现直接 delete 会导致 payload 缺字段,与真实 CLI 字节级不一致。
|
||||
// 策略:客户端传了什么就透传;没传则补默认 1。
|
||||
if !gjson.GetBytes(out, "temperature").Exists() {
|
||||
if next, ok := setJSONValueBytes(out, "temperature", 1); ok {
|
||||
out = next
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
|
||||
// max_tokens:真实 CLI 的默认值是 128000。缺失时补齐以对齐指纹。
|
||||
if !gjson.GetBytes(out, "max_tokens").Exists() {
|
||||
if next, ok := setJSONValueBytes(out, "max_tokens", 128000); ok {
|
||||
out = next
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
|
||||
// context_management:thinking.type 为 enabled/adaptive 时,真实 CLI 会自动
|
||||
// 附带 {"edits":[{"type":"clear_thinking_20251015","keep":"all"}]}。
|
||||
// 客户端显式传了就透传;否则按 CLI 行为补齐。
|
||||
if !gjson.GetBytes(out, "context_management").Exists() {
|
||||
thinkingType := gjson.GetBytes(out, "thinking.type").String()
|
||||
if thinkingType == "enabled" || thinkingType == "adaptive" {
|
||||
const cmDefault = `{"edits":[{"type":"clear_thinking_20251015","keep":"all"}]}`
|
||||
if next, ok := setJSONRawBytes(out, "context_management", []byte(cmDefault)); ok {
|
||||
out = next
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if gjson.GetBytes(out, "tool_choice").Exists() {
|
||||
if next, ok := deleteJSONPathBytes(out, "tool_choice"); ok {
|
||||
out = next
|
||||
|
||||
Reference in New Issue
Block a user