Agent 对话可配置最大工具调用次数 + Token 优化 + 循环检测升级#1549
Conversation
针对 scriptscat#1545:UI 对话此前硬编码 50 次工具调用上限且无法调整,达到上限 后用户误以为必须新建对话、丢失已探索的上下文。 - 新增 AgentConfigRepo(chatMaxIterations,默认 50,1-1000),Settings 页新增"对话"分类可视化配置 - 达到 max_iterations 时持久化 errorCode,聊天界面据此渲染"继续对话" 按钮,一键复用已持久化的完整历史继续执行 - 全部 8 个 locale 补齐相应文案 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 scriptscat#1545 的 Token 消耗问题:长 tool loop 每轮都全量计费输入 token, 且 execute_script 返回值(如 DOM dump、模块映射)不设上限,被完整保留 并在后续每轮重复发送。 - Anthropic provider 为最后一条消息追加 cache_control 断点,使已产生的 历史前缀被缓存,下一轮仅新增部分计费(system/tools 断点已存在,此为 第三个断点,未超过 4 个断点上限) - execute_script 返回值超过 30000 字符时截断为首尾各 15000 字符并标注 truncated / original_length,避免超大返回值反复占用上下文 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 scriptscat#1545:在触及 80% 的 autoCompact 阈值之前,长对话的旧 tool 结果 (如 DOM dump)会在后续每一轮都被完整重复发送,进一步放大 Token 消耗。 - 新增 elideOldToolResults:保留最近 5 轮 assistant/tool 消息原文, 更早的 tool 结果替换为占位文本;只裁剪内存中传给 LLM 的消息,不影响 chatRepo 持久化与 UI 历史 - 在 40% / 60% 两个上下文占用阈值各触发一次(而非逐轮触发),避免 频繁重写消息前缀导致 Anthropic 的 prompt cache 断点失效 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 scriptscat#1545 的 Loop Guard 诉求:现有 tool_call_guard 检测到重复/死循环 模式时只向 LLM 注入提醒,LLM 不理会则持续烧 Token,用户无法介入。 - ToolLoopOrchestrator 新增 askUserForGuard 可选回调:循环检测连续命中 达到 2 次时暂停循环,询问用户"继续"或"停止";回答停止则以 done(非 error)优雅收尾并持久化提示 - 仅 UI 对话(含后台会话,复用既有 ask_user 事件/resolver 机制,5 分钟 无人应答默认继续)传入该回调;定时任务与子代理不传,保持原有的 仅告警不暂停行为,避免无人值守场景被阻塞 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 PR scriptscat#1549 的审查反馈: 1. 【阻断性】继续对话时,历史中 max_iterations 错误占位消息(content 为空字符串)此前会被完整重放进 LLM 请求,部分 provider(如 Anthropic)会因空 content 拒绝请求。buildAndPersistUserMessage 现在 跳过带 error 字段的历史消息,仅用于 UI 展示,不进入 LLM 上下文。 2. 循环检测升级提问 5 分钟无人应答超时后,此前只删除 resolver,未清除 后台会话的 rc.pendingAskUser,导致后续 attach 的 UI 仍会看到已失效 的提问,回答会静默无效。超时回调现在同步清除 pendingAskUser。 3. chatMaxIterations 的合法范围此前只在 Settings UI 校验, AgentConfigRepo 直接读写未归一化的原始值;损坏的 storage、旧版本 遗留值或绕过 UI 的写入都可能导致 0/负数/超大值,进而导致循环立即 报错或失控运行。新增 normalizeChatMaxIterations,在 getConfig / saveConfig 中统一归一化到 [1, 1000];ChatService 解析最终值时改用 ?? 并对结果做同样的兜底截断。 4. 循环检测升级的连续命中计数此前永不重置,用户选择"继续"后,此后 每一次告警都会重新暂停询问,比"连续命中 2 次暂停"更激进。现在回答 继续后重置计数,需再次连续命中 2 次才会重新暂停。 均已按 TDD 补充回归测试(先复现失败用例,再修复)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for the review — all 4 issues confirmed and fixed in de83fd3, each with a regression test written to fail first, then pass after the fix. 1. Blocker — empty error message replayed to LLM on Continue. Confirmed: 2. Stale 3. Bounds enforced only in Settings UI. Confirmed — 4. Strike count never resets. Confirmed as described — agreed it was more aggressive than intended. Now resets to 0 after a "Continue" answer, so escalation requires 2 fresh hits again rather than pausing on every subsequent warning for the rest of the run. Test drives 8 rounds of repeated calls (4 hits total) and asserts the pause only fires on hits 2 and 4, not on hit 3. Full verification after the fixes: |
Summary
Implements the proposal for #1545 (Agent 内置 AI Agent 高频工具调用的痛点:迭代次数硬限制、Token 消耗过高、缺少死循环检测)。
AgentConfigRepo(chatMaxIterations,默认 50,可调 1–1000),Settings 页新增"对话"分类;达到上限时消息持久化errorCode,聊天界面渲染"继续对话"按钮一键复用已持久化的完整历史继续执行(不再需要新建对话、不会丢失已探索的上下文)。cache_control断点,使长 tool loop 中已产生的历史前缀被缓存,后续每轮仅新增部分计费(现有 system/tools 断点 + 此断点共 3 个,未超过 4 个上限)。execute_script返回值超过 30000 字符时截断为首尾各 15000 字符并标注truncated/original_length,避免超大返回值(如 DOM dump)被完整重复发送。tool_call_guard检测到重复/循环模式时只向 LLM 注入提醒;新增askUserForGuard回调,连续命中达到 2 次时暂停循环、询问用户"继续"或"停止",停止则优雅收尾(done而非error)。仅 UI 对话(含后台会话,复用既有 ask_user 机制,5 分钟无人应答默认继续)传入该回调;定时任务与子代理保持原有的仅告警不暂停行为,避免无人值守场景被阻塞。调查过程与技术方案细节见随本次改动附带的 issue-1545-proposal.md。
Test plan
describe/it),再实现npm run test:ci— 全量 3033 个测试通过(289 个测试文件)npm run lint— prettier / tsc / eslint 全部通过🤖 Generated with Claude Code