mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-23 15:45:13 +00:00
* 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. |
||
|---|---|---|
| .. | ||
| assets | ||
| design | ||
| developers | ||
| e2e-tests | ||
| images | ||
| plans | ||
| superpowers | ||
| users | ||
| verification/abort-controller-refactor | ||
| _meta.ts | ||
| index.md | ||