qwen-code/docs
Shaojin Wen a9d338684d
fix(core): make the per-turn tool-call cap adaptive (#7052)
* fix(core): make the per-turn tool-call cap adaptive

The per-turn tool-call cap (model.maxToolCallsPerTurn, default 100) was a
blunt circuit breaker: it halted any turn on the 101st tool call regardless
of whether the model was stuck or doing productive work. Large multi-package
implementation turns legitimately exceed 100 calls, so the cap killed
productive turns — a false positive.

Make the cap adaptive. The configured value is now a soft cap: once a turn
exceeds it, the cap halts only when a stuck-repetition signal is present (the
same (tool, args) call repeated 6+ times); a productive turn (diverse calls,
no repetition) continues up to a hard backstop of 3x the soft cap, which
always halts to bound an argument-varying runaway.

Validated against a real session whose 100-call turn was halted mid-build
with no repetition (max key repeat 2): that turn now continues, while genuine
stuck loops still halt at the soft cap. The always-on cap keeps its own
per-(tool,args) repeat tracker so it stays independent of skipLoopDetection.

The ACP/daemon path has a separate blunt cap that is not aligned here; noted
as a follow-up in the design doc.

* chore: regenerate settings schema for adaptive cap

* fix(core): clarify adaptive cap is interactive-only; strengthen cap tests

Address review feedback:
- The setting description now notes the daemon/ACP path still halts at the
  configured value regardless of repetition, so it no longer overclaims the
  adaptive behavior for non-interactive paths.
- Rename the misleading "fires at the built-in default soft cap value" test
  (it only asserts diverse calls are allowed past the cap).
- Add a retry test that builds a stuck-repetition signal before the retry and
  verifies it is cleared, so removing the capMaxKeyRepeat reset would fail.

* test(core): cover productive-then-stuck cap; clarify cap halt hint

Address review round 2:
- Add a test for a turn that crosses the soft cap with diverse calls and then
  becomes stuck mid-range, so the stuck check is verified across the whole
  (softCap, hardCap] range, not just at the boundary.
- Make the headless cap-halt message accurate for both triggers: it no longer
  only suggests raising maxToolCallsPerTurn (correct for the hard backstop but
  misleading for a stuck repeat) and now also points at the repetition.

* refactor(core): hash tool-call key once in always-on cap path; tighten cap tests

Address review round 3:
- Compute the (tool,args) key once in checkAlwaysOnSafeties and share it
  between the consecutive-identical guard and the cap stuck tracker (was
  hashed twice per call; args can be large). Skip hashing entirely when loop
  detection is disabled for the session (no consumer).
- Add a test that the stuck signal accumulates across Finished round-trip
  boundaries within a turn.
- Tighten the Stop-hook continuation budget test (cap 4 -> 1) so it still
  guards the reset under the adaptive cap, where diverse calls no longer trip
  the soft cap.
- Document the monotone stuck-signal non-goal and the telemetry-differentiation
  follow-up in the design doc.

* fix(core): canonicalize tool-call key fields; clarify adaptive cap scope

Address Codex review (2 Critical):
- getToolCallKey now canonicalizes object keys recursively (preserving array
  order) before hashing, so a stuck model cannot evade the repeat guards by
  reordering argument fields. Adds a reordered-arguments regression test.
- Correct the maxToolCallsPerTurn description: the adaptive behavior applies to
  both the interactive TUI and non-interactive (-p / JSON / stream-JSON)
  core-client runs; only the daemon/ACP path is strict. Updated in
  settingsSchema.ts, settings.md, and the regenerated settings.schema.json.

* test(core): cover nested key reordering and the consecutive guard's canonicalization

Address review:
- Extend the reordered-args stuck-signal test to include nested objects, so a
  regression that breaks canonicalizeForHash's recursion is caught.
- Add a reordered-args test for the consecutive-identical guard, pinning the
  canonicalization contract for that always-on detector (not just the cap).

* fix(core): treat explicit maxToolCallsPerTurn as a hard cap; keep default adaptive

Address yiliang114's Critical: v0.19.10 shipped maxToolCallsPerTurn as a hard
cap, but the adaptive change multiplied every configured value by 3, turning an
explicit N into a 3N budget — a breaking change for users who set it to bound
unattended cost.

Behavior now depends on whether the value was explicitly configured
(Config.isMaxToolCallsPerTurnExplicit):
- Explicit N -> hard cap (halt at N+1), preserving the released contract.
- Default (unset) -> adaptive: soft cap 100, halt only on a stuck-repetition
  signal, with the hard backstop raised to 1000 (10x) so modern models making
  hundreds of legitimate calls per task are not false-positived.

Adds the explicit-hard-cap regression (cap of 2 halts call 3) and a contrast
test proving the explicit flag drives the behavior. Updates the setting
description, headless hint/label, and design doc accordingly.
2026-07-17 16:42:41 +00:00
..
assets feat(web-shell): support custom Hex session group colors (#6752) 2026-07-12 10:41:17 +00:00
design fix(core): make the per-turn tool-call cap adaptive (#7052) 2026-07-17 16:42:41 +00:00
developers feat(serve): Complete legacy session workspace telemetry (#7003) 2026-07-17 15:25:15 +00:00
e2e-tests feat(worktree): Phase D — startup --worktree flag + symlinkDirectories + PR refs (#4381) 2026-05-27 17:04:51 +08:00
images fix(web-shell): render built-in tag icons (#7024) 2026-07-17 15:33:34 +00:00
plans feat(channels): support DingTalk webhook delivery to direct messages (#6891) 2026-07-15 03:07:30 +00:00
superpowers fix(feishu): validate credentials before WebSocket startup (#6780) 2026-07-13 02:10:16 +00:00
users fix(core): make the per-turn tool-call cap adaptive (#7052) 2026-07-17 16:42:41 +00:00
verification/abort-controller-refactor fix(core): stop AbortSignal listener leak in long sessions (MaxListenersExceededWarning) (#4366) 2026-05-26 14:21:49 +08:00
_meta.ts feat: refactor docs 2025-12-05 10:51:57 +08:00
index.md fix: lint issues 2025-12-19 15:52:11 +08:00