feat(claude): add ttl to cache_control with default 5m
Real Claude CLI traffic sends cache_control as
`{"type":"ephemeral","ttl":"1h"}`. Our previous payload only
sent `{"type":"ephemeral"}`, which is a bytewise mismatch with
the official CLI and one more third-party detection signal.
Policy: client-provided ttl is always passed through unchanged.
Proxy-generated cache_control blocks default to 5m (vs Parrot's 1h)
to avoid burning the 1h cache budget on automatic breakpoints while
still aligning with the `ttl` field being present.
- claude/constants.go: DefaultCacheControlTTL = "5m"
- apicompat/types.go: new AnthropicCacheControl type with TTL field;
AnthropicTool gains optional CacheControl pointer so the mimicry
path can attach a cache breakpoint to tools[-1] later.
- service/gateway_service.go: anthropicCacheControlPayload gains TTL;
marshalAnthropicSystemTextBlock and rewriteSystemForNonClaudeCode
emit ttl=5m by default.
This commit is contained in:
parent
165553cfb0
commit
66d6454535
@ -82,10 +82,18 @@ type AnthropicImageSource struct {
|
|||||||
|
|
||||||
// AnthropicTool describes a tool available to the model.
|
// AnthropicTool describes a tool available to the model.
|
||||||
type AnthropicTool struct {
|
type AnthropicTool struct {
|
||||||
Type string `json:"type,omitempty"` // e.g. "web_search_20250305" for server tools
|
Type string `json:"type,omitempty"` // e.g. "web_search_20250305" for server tools
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
InputSchema json.RawMessage `json:"input_schema"` // JSON Schema object
|
InputSchema json.RawMessage `json:"input_schema"` // JSON Schema object
|
||||||
|
CacheControl *AnthropicCacheControl `json:"cache_control,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnthropicCacheControl 对应 Anthropic API 的 cache_control 字段。
|
||||||
|
// ttl 默认由调用方决定;本项目策略见 claude.DefaultCacheControlTTL。
|
||||||
|
type AnthropicCacheControl struct {
|
||||||
|
Type string `json:"type"` // "ephemeral"
|
||||||
|
TTL string `json:"ttl,omitempty"` // "5m" / "1h" / 省略=默认 5m(由 Anthropic 判定)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnthropicResponse is the non-streaming response from POST /v1/messages.
|
// AnthropicResponse is the non-streaming response from POST /v1/messages.
|
||||||
|
|||||||
@ -57,6 +57,11 @@ const APIKeyBetaHeader = BetaClaudeCode + "," + BetaInterleavedThinking + "," +
|
|||||||
// APIKeyHaikuBetaHeader Haiku 模型在 API-key 账号下使用的 anthropic-beta header(不包含 oauth / claude-code)
|
// APIKeyHaikuBetaHeader Haiku 模型在 API-key 账号下使用的 anthropic-beta header(不包含 oauth / claude-code)
|
||||||
const APIKeyHaikuBetaHeader = BetaInterleavedThinking
|
const APIKeyHaikuBetaHeader = BetaInterleavedThinking
|
||||||
|
|
||||||
|
// DefaultCacheControlTTL 是网关代理为自己生成的 cache_control 块默认使用的 ttl。
|
||||||
|
// 真实 Claude Code CLI 当前使用 "1h",但本仓策略是"客户端透传 ttl 优先;
|
||||||
|
// 客户端缺省时统一使用 5m",这样既不浪费 1h 缓存额度,也保留客户端自定义能力。
|
||||||
|
const DefaultCacheControlTTL = "5m"
|
||||||
|
|
||||||
// FullClaudeCodeMimicryBetas 返回最"像"真实 Claude Code CLI 的完整 beta 列表,
|
// FullClaudeCodeMimicryBetas 返回最"像"真实 Claude Code CLI 的完整 beta 列表,
|
||||||
// 用于 OAuth 账号伪装成 Claude Code 时使用。
|
// 用于 OAuth 账号伪装成 Claude Code 时使用。
|
||||||
// 顺序与真实 CLI 抓包一致。
|
// 顺序与真实 CLI 抓包一致。
|
||||||
|
|||||||
@ -850,6 +850,7 @@ func (s *GatewayService) hashContent(content string) string {
|
|||||||
|
|
||||||
type anthropicCacheControlPayload struct {
|
type anthropicCacheControlPayload struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
TTL string `json:"ttl,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type anthropicSystemTextBlockPayload struct {
|
type anthropicSystemTextBlockPayload struct {
|
||||||
@ -898,7 +899,10 @@ func marshalAnthropicSystemTextBlock(text string, includeCacheControl bool) ([]b
|
|||||||
Text: text,
|
Text: text,
|
||||||
}
|
}
|
||||||
if includeCacheControl {
|
if includeCacheControl {
|
||||||
block.CacheControl = &anthropicCacheControlPayload{Type: "ephemeral"}
|
block.CacheControl = &anthropicCacheControlPayload{
|
||||||
|
Type: "ephemeral",
|
||||||
|
TTL: claude.DefaultCacheControlTTL,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return json.Marshal(block)
|
return json.Marshal(block)
|
||||||
}
|
}
|
||||||
@ -3856,7 +3860,7 @@ func rewriteSystemForNonClaudeCode(body []byte, system any) []byte {
|
|||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"text": claudeCodeSystemPrompt,
|
"text": claudeCodeSystemPrompt,
|
||||||
"cache_control": map[string]string{"type": "ephemeral"},
|
"cache_control": map[string]string{"type": "ephemeral", "ttl": claude.DefaultCacheControlTTL},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
out, ok := setJSONValueBytes(body, "system", claudeCodeSystemBlock)
|
out, ok := setJSONValueBytes(body, "system", claudeCodeSystemBlock)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user