Skip to content

fix(core): keep token escalation warm across agent rounds#5062

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
he-yufeng:fix/sticky-max-token-escalation
Jun 14, 2026
Merged

fix(core): keep token escalation warm across agent rounds#5062
wenshao merged 1 commit into
QwenLM:mainfrom
he-yufeng:fix/sticky-max-token-escalation

Conversation

@he-yufeng

@he-yufeng he-yufeng commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

What this PR does

This PR keeps automatic output-token escalation warm across the rest of a headless agent run. When GeminiChat has to retry a truncated response with a larger maxOutputTokens, AgentCore now carries that escalated limit into later tool-result rounds instead of dropping back to the capped default. It also prevents GeminiChat from re-escalating when the current request is already using the escalated output limit.

Why it's needed

In #4964, a headless agent could successfully retry a truncated first response, execute a tool call, and then truncate again on the next agent round because the larger output budget was not preserved. The first version of this PR preserved the budget at the agent layer, but review caught one remaining edge: GeminiChat still treated the per-request sticky limit as non-user config, so a later MAX_TOKENS finish could emit another identical escalation retry and duplicate API call. This update closes that edge without changing user-provided or environment-provided token limits.

Reviewer Test Plan

How to verify

Run the core tests below. The new regression checks that a request already carrying the escalated maxOutputTokens does not emit another maxOutputTokensEscalated retry and does not make a duplicate stream call. The existing agent-headless regression checks that the escalated limit is preserved into the next agent round after a tool call.

Evidence (Before & After)

N/A. This is non-UI agent/core behavior.

Tested on

OS Status
🍏 macOS ⚠️ not tested
🪟 Windows ✅ tested
🐧 Linux ⚠️ not tested

Environment (optional)

Windows 11, Node/npm from the repo workspace.

Validated locally:

npm run test --workspace=packages/core -- src/core/geminiChat.test.ts
npm run test --workspace=packages/core -- src/agents/runtime/agent-headless.test.ts
npm run typecheck --workspace=packages/core
npx prettier --check packages/core/src/core/geminiChat.ts packages/core/src/core/geminiChat.test.ts packages/core/src/agents/runtime/agent-core.ts packages/core/src/agents/runtime/agent-headless.test.ts
npx eslint packages/core/src/core/geminiChat.ts packages/core/src/core/geminiChat.test.ts packages/core/src/agents/runtime/agent-core.ts packages/core/src/agents/runtime/agent-headless.test.ts --max-warnings 0
git diff --check

One parallel verification attempt ran two coverage-enabled Vitest targets at the same time and hit a coverage/.tmp/coverage-0.json ENOENT while the tests themselves had passed. Re-running the affected target by itself passed.

Risk & Scope

  • Main risk or tradeoff: a later round that is already at the escalated limit will keep the truncated partial response instead of making an identical second API call at the same limit.
  • Not validated / out of scope: full integration flow against a live provider.
  • Breaking changes / migration notes: none.

Linked Issues

Fixes #4964

中文说明

这个 PR 做了什么

这个 PR 让 headless agent run 中的自动 output-token 升级在后续轮次继续生效。GeminiChat 因为响应被截断而用更大的 maxOutputTokens 重试后,AgentCore 会把这个升级后的限制带到后面的工具结果轮次里,而不是回到 capped default。同时,如果当前请求已经使用升级后的 output limit,GeminiChat 不会再触发一次相同额度的升级重试。

为什么需要

#4964 里,headless agent 可能第一轮响应被截断,重试成功并执行工具调用;但下一轮 agent 响应又回到较小输出预算,导致再次截断。这个 PR 的第一版已经在 agent 层保留了预算,但 review 指出还有一个边界:GeminiChat 没有把 per-request sticky limit 视为已经升级过的限制,所以后续 MAX_TOKENS 仍可能发出一次相同额度的 retry,造成重复 API 调用。本次更新补上这个边界,同时不改变用户显式配置或环境变量里的 token limit。

Reviewer Test Plan

How to verify

运行上面的 core 测试。新增回归测试会确认:当请求已经携带升级后的 maxOutputTokens 时,不会再发出 maxOutputTokensEscalated retry,也不会重复调用 stream API。已有 agent-headless 回归测试会确认:工具调用后的下一轮 agent round 仍然复用升级后的限制。

Evidence (Before & After)

N/A。这是非 UI 的 agent/core 行为。

Tested on

同英文表格。

Environment (optional)

Windows 11,本地仓库 Node/npm 环境。

Risk & Scope

  • 主要风险或取舍:如果后续轮次已经达到升级后的 limit 仍被截断,会保留当前 partial response,而不是再用相同 limit 重复调用一次 API。
  • 未验证 / 不在范围:真实 provider 的完整 integration flow。
  • 破坏性变更 / 迁移说明:无。

Linked Issues

Fixes #4964

config: {
abortSignal: roundAbortController.signal,
tools: [{ functionDeclarations: toolsList }],
...(stickyMaxOutputTokens !== undefined

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Redundant re-escalation on subsequent truncated rounds

hasUserMaxTokensOverride in geminiChat.ts (line 1889) only checks cgConfig.samplingParams.max_tokens and QWEN_CODE_MAX_OUTPUT_TOKENS — it does not see params.config.maxOutputTokens. When this sticky value flows through to a subsequent agent round and the model still hits MAX_TOKENS at the already-escalated limit, GeminiChat's inner escalation block fires again: maxTokensEscalated resets per call, hasUserMaxTokensOverride stays false, so all guards pass. The escalation computes Math.max(ESCALATED_MAX_TOKENS, tokenLimit(model, 'output')) — the identical value — pops the partial response from history, yields a spurious RETRY, and makes a duplicate API call at the same limit.

This wastes one API call (with full request history) per subsequent truncated round. In a long agent session with many truncation-heavy rounds, the cost compounds.

Fix options:

  • Broaden hasUserMaxTokensOverride to also check params.config?.maxOutputTokens !== undefined, or
  • Add a guard in the escalation condition: && (params.config?.maxOutputTokens ?? 0) < escalatedLimit
Suggested change
...(stickyMaxOutputTokens !== undefined
...(stickyMaxOutputTokens !== undefined
? { maxOutputTokens: stickyMaxOutputTokens }
: {}),

— qwen3.7-max via Qwen Code /review

}
// Signal UI to discard partial output
yield { type: StreamEventType.RETRY };
yield {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Misleading log message when sticky escalation is active

The log at line 2219 reads "Output truncated at capped default. Escalating to ${escalatedLimit} tokens." — but when stickyMaxOutputTokens is already applied via params.config.maxOutputTokens, the request was not at the capped default (8K); it was already at the escalated limit (e.g., 65536). An oncall engineer reading this log would conclude the request used 8K when it actually used 65536, leading to misdiagnosis.

Consider including the actual starting limit:

debugLogger.info(
  `Output truncated at ${params.config?.maxOutputTokens ?? 'capped default'}. Escalating to ${escalatedLimit} tokens.`,
);

Or skip the log + escalation entirely when no real escalation would occur (i.e., params.config.maxOutputTokens >= escalatedLimit).

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @he-yufeng — thanks for the PR! The fix itself looks well-scoped, but the PR body doesn't follow our PR template. A few required sections are missing:

  • What this PR does / Why it's needed — the ## Summary section covers the "what" but the template asks for these as separate headings so reviewers can quickly distinguish the change from the motivation.
  • Reviewer Test Plan## To verify lists commands, but the template needs the full structure: ### How to verify (reproduction steps), ### Evidence (Before & After) (output or N/A for non-UI changes), and the ### Tested on OS table.
  • Risk & Scope — tradeoffs, out-of-scope items, breaking changes.
  • Linked Issues — formal Fixes #4964 so the issue auto-closes on merge.
  • Chinese translation — the <details> block with a full translation of the English body.

Could you update the PR description to match the template? Happy to re-run triage once that's done.

中文说明

你好 @he-yufeng — 感谢你的 PR!修复本身范围合理,但 PR 描述没有按照我们的 PR 模板 填写,缺少以下必要部分:

  • What this PR does / Why it's needed## Summary 涵盖了"做了什么",但模板要求分成两个独立标题,方便审阅者快速区分变更内容和动机。
  • Reviewer Test Plan## To verify 列出了命令,但模板需要完整结构:### How to verify(复现步骤)、### Evidence (Before & After)(输出或非 UI 变更写 N/A)、以及 ### Tested on 操作系统表格。
  • Risk & Scope — 权衡取舍、不在范围内的内容、破坏性变更。
  • Linked Issues — 正式的 Fixes #4964,以便合并后自动关闭 issue。
  • 中文说明<details> 块内包含英文正文的完整翻译。

请按照模板更新 PR 描述,完成后可以重新触发审查。

Qwen Code · qwen3.7-max

@he-yufeng
he-yufeng force-pushed the fix/sticky-max-token-escalation branch from a39064b to cd8d4f1 Compare June 13, 2026 18:43
@he-yufeng

Copy link
Copy Markdown
Contributor Author

Addressed the requested changes in the latest force-push.\n\nWhat changed:\n- GeminiChat now checks the per-request maxOutputTokens before automatic escalation. If the request already uses the escalated limit, it does not emit another identical escalation retry or make a duplicate stream call.\n- The escalation log now reports the actual starting limit when one is present, instead of always saying capped default.\n- Added a core regression test for the sticky-limit case, alongside the existing agent-headless test that verifies the escalated limit is carried into the next agent round.\n- Updated the PR body to the repository template.\n\nValidated on Windows:\n-
pm run test --workspace=packages/core -- src/core/geminiChat.test.ts\n-
pm run test --workspace=packages/core -- src/agents/runtime/agent-headless.test.ts\n-
pm run typecheck --workspace=packages/core\n-
px prettier --check packages/core/src/core/geminiChat.ts packages/core/src/core/geminiChat.test.ts packages/core/src/agents/runtime/agent-core.ts packages/core/src/agents/runtime/agent-headless.test.ts\n-
px eslint packages/core/src/core/geminiChat.ts packages/core/src/core/geminiChat.test.ts packages/core/src/agents/runtime/agent-core.ts packages/core/src/agents/runtime/agent-headless.test.ts --max-warnings 0\n- git diff --check\n\nOne verification attempt ran two coverage-enabled Vitest targets in parallel and hit a coverage temp-file race after the tests had passed. Re-running the affected target by itself passed.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✅ — The sticky escalation mechanism is clean and well-scoped. Both regression tests validate the core behavior correctly. The two prior inline suggestions (redundant re-escalation, misleading log) are addressed by the shouldEscalateMaxOutputTokens guard and the improved startingLimitLabel in this commit.\n\n_— qwen3.7-max via Qwen Code /review_

@wenshao

wenshao commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Local verification (merge reference)

I built cd8d4f1b75 and verified the fix live in the real binary — driving a real /fork (which runs AgentCore in-process) through tmux against a local OpenAI-compatible mock that truncates the first response (finish_reason: lengthMAX_TOKENS), so I could watch the max_tokens each round actually sends. Linux, Node 22.22.2, head cd8d4f1b75 (merge-base ce4b0cf6).

Verdict: works as designed and reproduces/fixes #4964 on the wire. The escalated output budget is now preserved into the next agent round after a tool call; the re-escalation guard and the warm-escalation logic are both correct. LGTM.

1. Live A/B in the real binary — the headline

Same fork scenario on the pre-fix (merge-base) vs PR binary. The mock records the max_tokens of every request the fork's AgentCore makes:

Fork request (AgentCore) pre-fix (merge-base) PR cd8d4f1b75
round 1 — initial 8000 (capped default) → truncated 8000 → truncated
round 1 — escalated retry 64000 → tool call (ListFiles) 64000 → tool call
round 2 — after the tool result 8000 ← reverts to default (this is #4964) 64000 ← escalated limit preserved ✅

The only behavioral difference is round 2's budget: pre-fix drops back to the 8K cap (so the next response would truncate again — exactly #4964), and the PR keeps the 64K escalated limit warm. Verified end-to-end through the real AgentCore round loop, not just unit mocks.

2. GeminiChat escalation also confirmed live

A separate headless -p run (mock truncates the first reply) shows the escalation firing in the real binary: request 1 max_tokens=8000 (length) → request 2 max_tokens=64000. So the RETRY event now carrying maxOutputTokensEscalated (which AgentCore reads into its sticky limit) works on the real path.

3. PR test plan — green

Check Result
vitest geminiChat.test.ts + agent-headless.test.ts 201 passed, 2 skipped
typecheck --workspace packages/core exit 0
prettier --check (4 files) · eslint --max-warnings 0 · git diff --check clean

4. Mutation — both new tests are non-vacuous

Reverting agent-core.ts + geminiChat.ts to merge-base (keeping the PR's tests) fails exactly the two new tests:

× agent-headless › keeps automatic max token escalation warm for the next agent round
× geminiChat    › should not re-escalate when the request already uses the escalated output limit
   (199 passed | 2 failed)

So the sticky-carry and the re-escalation guard are each genuinely guarded.

Notes

  • Re-escalation guard (shouldEscalateMaxOutputTokens: skip when the request already sits at/above the escalated limit): verified via the new geminiChat unit test + the mutation above. It's a within-round GeminiChat decision, so I leaned on the unit test rather than a separate live capture.
  • Scope is AgentCore-only, by design. In a plain -p main-loop run the next turn goes back to 8000 (the main loop doesn't carry the sticky limit) — that's expected; this PR targets the agent runtime, which is where Recover from the previous truncation caused by the max_tokens limit. #4964 lives.
  • The trailing 8000 request I saw after the fork completed is a post-completion main-loop turn (identical on both builds), not an AgentCore round — it doesn't affect the result.

Good to merge. The behavior is correct, reproduced and fixed on the real wire via the AgentCore fork path, with green and non-vacuous tests.

中文版(Chinese version)

本地验证(合并参考)

我构建了 cd8d4f1b75,并在真实二进制中验证了修复——通过 tmux 驱动真实的 /fork(它在进程内运行 AgentCore),对接一个本地 OpenAI 兼容 mock:mock 把第一次响应截断(finish_reason: lengthMAX_TOKENS),这样我就能观察每一轮实际发送的 max_tokens。环境 Linux、Node 22.22.2、head cd8d4f1b75(merge-base ce4b0cf6)。

结论:行为符合设计,并在"线缆"上复现并修复了 #4964。升级后的 output 预算现在会保留到工具调用后的下一轮 agent;re-escalation 守卫与"保温升级"逻辑均正确。建议合并。

1. 真实二进制 A/B —— 要点

在修复前(merge-base)与 PR 二进制上跑同一个 fork 场景。mock 记录 fork 的 AgentCore 每个请求的 max_tokens

Fork 请求(AgentCore) 修复前(merge-base) PR cd8d4f1b75
第 1 轮 —— 初始 8000(capped default)→ 截断 8000 → 截断
第 1 轮 —— 升级重试 64000 → 工具调用(ListFiles 64000 → 工具调用
第 2 轮 —— 工具结果之后 8000 ← 回退到默认(即 #4964 64000 ← 升级后的 limit 被保留 ✅

唯一的行为差异在第 2 轮的预算:修复前回退到 8K 上限(下一次响应会再次截断——正是 #4964),PR 则让 64K 升级 limit 保持"温热"。这是通过真实 AgentCore round 循环端到端验证的,而非仅靠单元 mock。

2. GeminiChat 升级也已线上确认

另跑一个 headless -p(mock 截断首条回复)显示升级在真实二进制里触发:请求 1 max_tokens=8000length)→ 请求 2 max_tokens=64000。因此 RETRY 事件新增携带的 maxOutputTokensEscalated(被 AgentCore 读入 sticky limit)在真实路径上是生效的。

3. PR 测试计划 —— 全绿

检查 结果
vitest geminiChat.test.ts + agent-headless.test.ts 201 通过,2 skipped
typecheck --workspace packages/core exit 0
prettier --check(4 文件)· eslint --max-warnings 0 · git diff --check 干净

4. 变异测试 —— 两个新测试都非空壳

agent-core.ts + geminiChat.ts 回退到 merge-base(保留 PR 测试),恰好让两个新测试失败:

× agent-headless › keeps automatic max token escalation warm for the next agent round
× geminiChat    › should not re-escalate when the request already uses the escalated output limit
   (199 passed | 2 failed)

所以 sticky 保留与 re-escalation 守卫都被真正守护。

说明

  • re-escalation 守卫shouldEscalateMaxOutputTokens:当请求已处于/超过升级 limit 时跳过):通过新增 geminiChat 单元测试 + 上述变异验证。它是 GeminiChat 轮内决策,所以我用单元测试覆盖,而非单独线上捕获。
  • 范围按设计仅限 AgentCore。 普通 -p 主循环里下一轮会回到 8000(主循环不携带 sticky limit),这是预期的;本 PR 针对 agent 运行时,Recover from the previous truncation caused by the max_tokens limit. #4964 正发生在那里。
  • fork 完成后我看到的那个 8000 请求是完成后的主循环轮次(两个构建一致),不是 AgentCore round,不影响结论。

可以合并。 行为正确,已在真实 AgentCore fork 路径上复现并修复,测试全绿且非空壳。

@wenshao

wenshao commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required headings present, bilingual, test plan clear.

On direction: This is a clean bug fix for #4964 — headless agent rounds lose the escalated output-token budget after a tool call, causing repeated truncation. The CHANGELOG has recent related work (stabilize truncated tool retry keys #4970, layered tool-output truncation #4880), confirming this is an active area. Solidly in scope.

On approach: The scope is tight — 150 additions across 4 files, two changes that map 1:1 to the two failure modes:

  1. agent-core.ts carries the escalated limit into subsequent rounds via stickyMaxOutputTokens — fixes the round-to-round budget loss
  2. geminiChat.ts skips re-escalation when the request already sits at the escalated limit — prevents duplicate API calls

This is about as minimal as it gets. The stickyMaxOutputTokens scoping (AgentCore only, not the main conversation loop) is correct by design. Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必需章节齐全,双语,测试计划清晰。

方向: 这是对 #4964 的干净 bug 修复 — headless agent 在工具调用后丢失升级后的 output-token 预算,导致反复截断。CHANGELOG 中有近期相关工作(stabilize truncated tool retry keys #4970layered tool-output truncation #4880),确认这是活跃领域。完全在范围内。

方案: 范围紧凑 — 4 个文件 150 行新增,两处改动一一对应两种失败模式:

  1. agent-core.ts 通过 stickyMaxOutputTokens 将升级后的 limit 带入后续轮次 — 修复轮次间预算丢失
  2. geminiChat.ts 在请求已处于升级 limit 时跳过再次升级 — 防止重复 API 调用

这基本上是最小化方案。stickyMaxOutputTokens 的作用域仅限 AgentCore(不进入主对话循环),设计正确。进入代码审查。🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal matches the PR: track escalated limit across agent rounds via a sticky variable, and guard against duplicate escalation in GeminiChat. The diff implements exactly that.

No blockers. The logic is clean:

  • stickyMaxOutputTokens in AgentCore captures maxOutputTokensEscalated from retry events and injects it into subsequent rounds' config. Scoped to _runReasoningLoopInner (agent runtime only), which is correct — the main conversation loop intentionally does not carry it.
  • Re-escalation guard in GeminiChat (shouldEscalateMaxOutputTokens) correctly handles three cases: no limit set (escalate), below escalated limit (escalate), at/above escalated limit (skip). Prevents duplicate API calls when the sticky limit from a prior round already matches the escalation target.
  • The maxOutputTokensEscalated field on the retry event is a clean signal carrier — no new coupling between layers.

Tests are non-vacuous: the new agent-headless test verifies round-2 gets the escalated limit, the new geminiChat test verifies no duplicate escalation when already at the limit. CI mutation (by maintainer) confirmed both tests fail when the fix is reverted.

Test Results

Check Result
vitest geminiChat.test.ts 170 passed
vitest agent-headless.test.ts 31 passed, 2 skipped
typecheck (packages/core) exit 0, clean
CI (all platforms) 7 successful, 11 skipped
CLI headless smoke test clean

Real-Scenario Test (tmux)

The bug requires a provider that returns finish_reason: MAX_TOKENS to trigger escalation — not reproducible against a live API without a mock provider. Basic smoke test confirms no CLI regression. The maintainer (wenshao) already performed comprehensive live A/B testing on Linux with a mock provider, confirming the fix end-to-end on the wire:

Fork request pre-fix (merge-base) PR cd8d4f1
round 1 initial 8000 → truncated 8000 → truncated
round 1 escalated retry 64000 → tool call 64000 → tool call
round 2 after tool result 8000 ← reverts (#4964) 64000 ← preserved ✅

CLI smoke test output (headless -p 'say hello'):

$ npm run dev -- -p 'say hello'

> @qwen-code/[email protected] dev
> node scripts/dev.js -p say hello

DEV is set to true, but the React DevTools server is not running. Start it with:

$ npx react-devtools

Hello! How can I help you today?

No errors, no regression.

中文说明

代码审查

独立方案与 PR 一致:通过 sticky 变量跨 agent 轮次追踪升级后的 limit,并在 GeminiChat 中防止重复升级。diff 精确实现了这一点。

无阻塞问题。 逻辑清晰:

  • AgentCore 中的 stickyMaxOutputTokens 从 retry 事件捕获 maxOutputTokensEscalated 并注入后续轮次的 config。作用域仅限 _runReasoningLoopInner(agent 运行时),设计正确——主对话循环有意不携带。
  • GeminiChat 中的再升级守卫(shouldEscalateMaxOutputTokens)正确处理三种情况:未设置 limit(升级)、低于升级 limit(升级)、达到/超过升级 limit(跳过)。防止前一轮 sticky limit 已等于升级目标时的重复 API 调用。
  • retry 事件上的 maxOutputTokensEscalated 字段是干净的信号载体——层间无新增耦合。

测试非空壳:新 agent-headless 测试验证第 2 轮获得升级后的 limit,新 geminiChat 测试验证已处于升级 limit 时不重复升级。CI 变异测试(由维护者执行)确认两个新测试在回退修复后均失败。

测试结果

检查 结果
vitest geminiChat.test.ts 170 通过
vitest agent-headless.test.ts 31 通过,2 跳过
typecheck (packages/core) exit 0,干净
CI(全平台) 7 成功,11 跳过
CLI headless 冒烟测试 干净

真实场景测试 (tmux)

该 bug 需要返回 finish_reason: MAX_TOKENS 的 provider 才能触发升级——无法在没有 mock provider 的情况下对真实 API 复现。基本冒烟测试确认无 CLI 回归。维护者 (wenshao) 已在 Linux 上使用 mock provider 完成了全面的线上 A/B 测试,在线缆上端到端确认了修复效果。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Reflection

This is a textbook bug fix. The problem is real and well-documented (#4964), the fix is minimal (150 lines, 2 source files), and the approach is the obvious one — carry the escalated limit forward, don't re-escalate when already there.

Looking back at my independent proposal from Stage 2: the PR matches it exactly. I can't find a simpler path. The two changes (sticky carry in AgentCore, re-escalation guard in GeminiChat) each address one failure mode, and neither adds complexity that doesn't directly solve the problem.

The tests are honest — both new tests fail when the fix is reverted, and the 201-test suite is clean. CI is green across all three platforms. The maintainer's live wire-level A/B testing (documented in a comment on this PR) provides the definitive proof that the fix works end-to-end.

Risk is low: the sticky limit is scoped to AgentCore's reasoning loop, so the main conversation loop is unaffected. The only tradeoff — keeping a truncated partial response instead of making an identical duplicate API call — is clearly the right choice.

Verdict: Approve. Clean fix, real bug, well-tested, ready to ship. ✅

中文说明

总结

这是一个教科书级的 bug 修复。问题真实且有据可查(#4964),修复最小化(150 行,2 个源文件),方案直观——将升级后的 limit 向后传递,已处于升级状态时不再重复升级。

回顾我在 Stage 2 的独立方案:PR 与之完全一致。找不到更简路径。两处改动(AgentCore 中的 sticky 传递、GeminiChat 中的再升级守卫)各解决一种失败模式,且都没有增加与问题无关的复杂度。

测试诚实——两个新测试在回退修复后均失败,201 个测试的套件全部通过。CI 在三个平台上全绿。维护者的线上 A/B 测试(记录在本 PR 评论中)提供了修复端到端生效的决定性证据。

风险低:sticky limit 作用域仅限 AgentCore 的推理循环,主对话循环不受影响。唯一的取舍——保留截断的 partial response 而非发出相同的重复 API 调用——显然是正确的选择。

结论:批准。 干净的修复,真实的 bug,测试充分,可以合并。✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao
wenshao merged commit e043587 into QwenLM:main Jun 14, 2026
23 checks passed
doudouOUC pushed a commit that referenced this pull request Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recover from the previous truncation caused by the max_tokens limit.

3 participants