makecindy / makecindy/cindy

Claude Code + GPT-5.6-Sol 报 400 context_length_exceeded,但上下文环显示 0% 且自动压缩永不触发

Open
#1,429 3 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

**提交人**: Jack Zhou
**客户端版本**: 0.1.27

---

## 现象

Claude Code agent + GPT-5.6-Sol(effort 超高)的会话,turn 进行中直接以 400 终止,同一错误连续出现两次,横幅原文:

```
API Error: 400 litellm.BadRequestError: AzureException BadRequestError - { "error": { "message": "Your input exceeds the context window of this model. Please adjust your input and try again.", "type": "invalid_request_error", "param": "input", "code": "context_length_exceeded" } }
```

同一屏的其它读数互相矛盾(以下为截图转写,原图可另附):

- 右下角上下文环显示 **0%**,不是 100%
- 该 turn 已「已工作 1m 32s · 读取 5 个文件」
- 「本任务 $20.81」,说明此前已有大量成功轮次,会话历史很大
- 底部「步骤 1 / 4」仍在转,错误横幅只提供「重试」

会话自此不可用:每次发送都复现同一个 400,上下文环始终 0%,用户拿不到任何「上下文过大」的信号,点「重试」是把同一份超长 payload 原样再发一次,必然同样失败。

## 复现步骤

1. Claude Code agent,模型选 GPT-5.6-Sol(经 XD 网关 → Azure),effort 超高。
2. 在一个 workdir 持续跑重上下文任务(大量文件读取、命令输出、若干张截图),直到会话历史很大(本例累计 $20.81)。
3. 继续发送一条新消息。
4. 观察错误横幅与右下角上下文环。

## 期望行为

- 自动压缩应在触到上游真实上限前触发,而不是只在 turn 结束判定。
- 上下文环应反映真实占用;拿不到 usage 时应显示「未知」而不是 0%。
- `context_length_exceeded` 应被识别为不可重试,给出「压缩上下文 / 新建会话」这类可执行入口,而不是原样抛 litellm JSON 加一个必然失败的「重试」。

## 实际行为与初步原因

**(1) 上下文环恒 0%,自动压缩因此永不触发**

`usage-tracker.ts:296` 的 `contextTokens = lastApi.input + cacheRead + cacheCreate`,只来自**成功返回**的请求 usage。请求以 400 结束时拿不到 usage,`lastApi` 保持 0,环显示 0%。同一个 0 喂给 `AutoCompactController`(`auto-compact-controller.ts:34-42`),ratio 恒为 0,永远低于阈值(默认 75%,`compaction-settings-store.ts:28`),`shouldCompactNow()` 恒 false。会话进入自锁:越界 → 拿不到 usage → 不压缩 → 继续越界。

此外 `shouldCompactNow()` 只在 **turn 结束**判定,单个长 turn(本例 1m32s、读 5 个文件)本身就能从阈值以下一路冲过上游硬顶,中途没有任何判定点。

**(2) 目录声明的窗口可能大于该路由的真实上限**

`packages/model-providers/catalog/model-registry.json` 里 `openai/gpt-5.6-sol` 的 model 级 `contextWindow` 是 1,050,000,`perAgent.claude-code` 未覆盖(继承 1.05M),而 `perAgent.codex` 是 372,000——同一模型两个 agent 差 2.8 倍;同文件 referencePrices 的分价档卡在 `maxInputTokens: 272001`。窗口 ≥1M 还会让 `claude-code/index.ts:166-172` 给模型串追加 `[1m]`。

结构性根因:`ModelRegistryRoute`(cindy-protocol `packages/model-access-protocol/src/types.ts:81-86`)没有 `contextWindow` 字段,窗口只能挂在 model / perAgent 上,于是同一个 gpt-5.6-sol 直连 openai 与走 xd 网关(→ Azure)只能共用一个声明值。

**(3) 错误呈现**

`providerErrors.ts:81-125` 已能把这段文本分类成 `CONTEXT_TOO_LONG` / `retryable: false`,但唯一的实时消费者 `provider-upstream-error-observer.ts` 是自定义(user)供应商专用,内置 `xd` 反解不到 providerId 就整条跳过,所以既没有友好提示,也没拦掉「重试」。

## 与已有 issue 的关系

- **#934**(已闭,PR #940)是同一条失效链的下游:那次窗口显示 272K/272K(100%),修复只放开了「撞顶后手动压缩被 session busy 拦住」。本 issue 的 0% 自锁、以及撞顶前不压缩,都未覆盖。
- **#680**(未闭)是同族根因:本地目录声明 ≠ XD 网关真实能力 → 400,只是维度是模型存在性而非窗口大小。
- 方向相反的 #1198 / #1151 及已合并的 #909、在审的 #1189 都在把窗口往上调,会放大本问题的暴露面。

## 待补充

出问题那台机器上 `logs/main-*.log` 里 `contextWindowSource` / `fallback:model-capability-config` 附近的行,可确认该会话生效的窗口声明到底是 372K 还是 1.05M。
---
**版本区域**: CN
**OS**: darwin arm64 (25.5.0)
**界面语言**: en

Contributor guide

Open the contributing guide

Research direction

Start by reading usage-tracker.ts, auto-compact-controller.ts, compaction-settings-store.ts, providerErrors.ts, and provider-upstream-error-observer.ts, then inspect the relevant model-registry.json entries and the cited contextWindowSource logs. Compare behavior for failed requests and long turns; done means context state is not falsely reported as 0%, oversized-context errors are handled as non-retryable, and users receive an actionable recovery path.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, typescript
Domain
ai, api, backend
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.