
开了会话亲和之后,一次子代理扇出能把单 key 打满、整条凭证冷却 12392 秒,而官方明确不按提供方粒度改;同一小时里 Claude Code 2.1.312 的四个头被证实过不了中转,sub2api 的指纹补丁把五处对齐到 2.1.311。
Retry-After 是 12392 秒。Resource has been exhausted (e.g. check quota).,status RESOURCE_EXHAUSTED。之后 CPA 对所有请求直接回 model_cooldown,响应头 Retry-After: 12392,折 3 小时 26 分。routing.session-affinity 本身默认 false,样例配置第 174 行写着 session-affinity: false # default: false2。多数人为了缓存收益会把它打开。session-affinity-subagents 这一档默认是 true:service_config.go 第 69 行写死默认值,config_types.go 第 478 行注释标注 Default: true,样例配置第 187 行也是 true34。selector.go 第 1785 行的 isSubagentSession 判 ID 里带 :agent:,或者这个 ID 有父级。认出来之后,第 1252 行那句 if !isSubagent || s.subagentAffinity 决定它能不能复用父会话绑定的凭证。默认条件下就是复用5。routing: 段下。没有按提供方、也没有按凭证的写法。对于需要按提供方、按凭证粒度区分该策略等更细粒度的调度场景,用户可以基于现有插件机制(例如scheduler.pick)自行实现插件来完成该功能。1
error.details[].RetryInfo.retryDelay,json_retry_helpers.go 第 28 行的 ParseRetryDelay 把它解析成时长,退回次序是 RetryInfo → ErrorInfo 的 metadata.quotaResetDelay → 消息里 after Ns 的正则6。
ParseRetryDelay 的三层回落:先找 google.rpc.RetryInfo 的 retryDelay,再找 ErrorInfo 的 metadata.quotaResetDelay,最后才用消息文本里的 after Ns 正则。三层都在 errorBody 上,与 HTTP 头无关。6result.RetryAfter,conductor_cooldown.go 第 1124 行的 429 分支第一句就是 if result.RetryAfter != nil:直接 now.Add(*result.RetryAfter),只保证不低于 10 秒(minQuotaCooldownFloor),没有上限7。
RetryAfter 时直接用,只保 10 秒下限;第 1131 行起没有提示才走 quotaCooldownAfterFailure 的指数退避。7quotaCooldownAfterFailure,指数退避封顶 30 分钟。所以像 3.44 小时这样的数字,一定是上游告诉它的——这也解释了为什么单看配置算不出冷却时长。routing.session-affinity-subagents: false。冷却风险没了,代价是所有提供方的子代理缓存复用一起没了。routing.session-affinity: false。整条亲和关掉,父会话也不再粘在同一凭证上。scheduler.pick 自己分。报障人提到的 Kiro 插件就是这么做的:主会话交回内置粘性,带 parent_session_id 的子代理放到负载最低的账号上保粘。POST /v8/management/routing/cooldown/reset 带 {"auth_index": "..."} 清那条凭证;auth_index 空回 400,找不到回 4048。带 401 失败记录的凭证清不动——clearCooldownStateForAuth 第一句就是 hasUnauthorizedAuthFailure 早退,先修好那个号再说。x-claude-code-sandy-plover(15/15)、anthropic-dispatch-id(14/15)、x-claude-code-prompt-id(10/15)、anthropic-usage-limit(7/15)9。metadata.user_id 被改、CCH 被重算、body 里的 betas 被删。这三处都能落到行号。metadata.user_id:claude_executor_cloaking.go 第 114 行在请求没有 metadata 时写入一个生成的 ID,第 124 行在现有 ID 不合法时覆盖,第 1662 行还有一处按条件删除。generateBillingHeader 拼 x-anthropic-billing-header: cc_version=<版本>.<3 位指纹>; cc_entrypoint=<入口>;,cc_entrypoint 缺省填 cli(第 154 行),签名路径上加 cch=00000; 占位(第 167 行),cc_prompt_id= 也只在签名路径才写(第 184 行)10。
generateBillingHeader 的第 151–196 行:cc_version 由版本号与 3 位 build 指纹拼成,entrypoint 缺省 cli,cch 只在签名路径写成 00000,cc_prompt_id 与 cc_prev_req 同属签名路径。10x-claude-code-prompt-id 里。CPA 不转发那个头,却在 system 的 billing header 里写 cc_prompt_id 字段。名字像,位置不是一处。| 项 | v0.2.18 现状 | #8394 改成 |
|---|---|---|
anthropic-beta 清单 | 缺 per-turn-control、thinking-token-count、advanced-tool-use、dangerous-tool-use、afk-mode 五个 | 按 2.1.311 抓包顺序补齐,默认列表里去掉 fine-grained-tool-streaming(PR #8394) |
X-Stainless-Package-Version | 0.94.0(identity_service.go) | 0.128.0 |
X-Stainless-Runtime-Version | v24.3.0(identity_service.go) | v26.12.1 |
X-Stainless-Timeout | 600(claude/constants.go) | 300 |
cc_entrypoint | 写死 cli(claude/constants.go) | sdk-cli,显式声明为 cli 的调用方式仍走 cli |
body safeguards | 没有 | 补一份 dangerous_tool_use 的 classifier 上下文(PR #8394) |

identity_service.go 第 123–136 行的 defaultFingerprint:浏览器侧三个值固定成 js / 0.94.0 / v24.3.0,OS 写 Linux、Arch 写 arm64。客户端没带这些头时,账号就带着这一组值去上游。11anthropic-beta 里那五个新令牌有没有。X-Stainless-* 值对不对得上你声称的 CLI 版本。cc_entrypoint 是 cli 还是 sdk-cli。safeguards,内容是不是按运行环境取值的。fine-grained-tool-streaming 还在不在(2.1.3x 起真机不再发)。streamWriter 与 chunkChannel 在 goroutine 启动前取好、当参数传进去,不再让 goroutine 读 wrapper 的字段12。作者补了昨天没说的第二种后果:goroutine 过了非空检查之后再 range 一个被置 nil 的通道,会永久阻塞,Finalize 就一直等 streamDone。50 个独立进程跑 -race,修前 50/50 失败,修后 0/50。/v1beta/models 改成按分组声明的模型应答。分组里每个可调度 Gemini 账号都配了 model_mapping 时,列表返回各账号映射键的并集,不再挑一个账号把它上游的列表原样透传;只要有一个账号没配映射,仍走原来的透传13。同一张 PR 把三处 Gemini 默认列表统一成 17 个现役模型,移除 2.0/2.5 系列。session-affinity-subagents 关掉;再对一遍出站指纹那五项;#8394 合并之前,beta 清单和三个 Stainless 值得自己先补。github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.