goal 拿的是完整工具集(含 write/edit/bash),不含 plan 三件套。
理由很直接:目标模式的价值是「放手做完」,给它只读工具就退化成 plan 了。
目标是一个显式状态机
goal 不是「跑到底」的布尔标志。终态和暂停态必须可区分, 全部迁移收敛在transitionGoal 里,非法迁移返回「没生效」而不是抛异常——
绝不让一次状态竞争毁掉整个回合。
两条停机阀 + 你输入即接管
判定收敛在一个纯函数里,逐条短路,顺序即优先级:1
provider 报错或被中止
立即暂停。
2
轮次上限
超过这条目标的
maxAutoTurns(默认 300,0 = 不限)就暂停。
上限挂在每条目标上而不是全局设置——「补个 README」和
「把整个鉴权重构完」差两个数量级,全局值注定对一半任务是错的。3
无进展停滞
连续 3 轮零实质工具调用、且输出指纹不变 → 暂停。
指纹是「本轮全部文本 → NFKC 归一 → 去空白 → sha256」,
模型卡住时的典型表现正是把同一句话换几种标点再吐一遍。
过期护栏(stale-turn guard)
两个出口工具goal_complete / goal_blocked 的 goal_id 是必填参数,
执行时与当前目标比对,不一致就拒绝并把当前目标原文回给模型。
这不是防御性编程,是真实竞态:模型的 goal_complete 在工具调用排队期间,
你可能已经发了新消息或换了目标。没有 id 比对就会出现
「旧目标的完成把新目标标成完成」——而这个 bug 的症状是静默的,
日志里什么都看不出来。
token 账是现累的,不是从转录重算的
Goal.tokensUsed 单调递增:每个轮边界把 run 上攒的增量折进来,只加不减。
早期实现是「会话累计 − 建目标时的基线」,有三个毛病,换掉的理由分别是:
看不见子代理
看不见子代理
子代理是独立 Agent、独立上下文,用量从不写进父会话转录。
而 goal 档的工具表带 Task 组,也就是鼓励委派——
「目标靠子代理干完了大半活」时读数会严重少报。
现在子代理自己记账,结算时汇给父 run,重复结算被状态守卫挡住。
把暂停期间的消耗算进来
把暂停期间的消耗算进来
基线只在建目标时取一次,resume 不重取——你在别的模式里干的活
全被记在这条目标账上。现累的增量只在「目标是 active 且这一轮正在跑」时累加。
是 O(n²)
是 O(n²)
旧实现每个轮边界都全量重读转录文件,300 轮的目标就是 300 次全长重读,
文件还在变长。现累是四个加法。
口径是四项相加(input + output + cacheRead + cacheWrite),与用量统计页同源。
含 cacheRead 意味着长循环里这个数会比直觉大一个数量级——
这是全局口径,不是目标模式特有的偏差,单改一处会让两个页面数字对不上。
为什么没有 token 预算
曾经有第四道阀:目标可带 token 预算,超限转入收尾。它被整体删除了, 因为设计上就说不清:- 你无法预判。一个「把测试跑通」的目标可能花 20k 也可能 2M, 预算填多少都是猜。填小了目标被腰斩,填大了等于没设。
- 它按累计量截断,不看进度。同一目标第 4 轮和第 24 轮花掉的 token 可能一样多,预算并不知道该在哪停。
- 收尾轮本身还要再烧一次模型请求去写完成说明,而此时你已经看不到 「还剩多少没做完」这个事实。
tokensUsed 降级为纯展示字段(常驻条上一个计数,悬停注明
「仅供参考,不参与停机判定」)。想省配额的正确反应是让人看见消耗再自己决定,
而不是让程序在你没定的数字上自动刹车。
停下之后,提示词必须跟着改口
一个很隐蔽的坑:模式段GOAL_MODE_PROMPT 是给 active 状态写的,
通篇是「别收手、别问、系统会自动续下一轮」,而它不随状态变化。
如果目标暂停后提示词不改口,模型会同时读到
「你正在自治循环里,别停下来问」和「目标已暂停」——
而后者如果不存在,模型就继续埋头干目标,而界面上明明写着「已暂停」。
你看到的是「上面说暂停了,对话还在进行中」。
修复前正是如此。现在 goalPromptBlock 是状态敏感的:
这也是为什么「你输入即接管」这条阀看起来生效了(状态确实变了)却没真的接管:
状态机停了,提示词没停。
状态是 active ≠ 循环在跑
这是本模块最容易踩的一条,一次踩出过三个 bug (「继续」按钮点了没用、切档后卡死、重启后谎报进行中), 共同症状都是「条上说在跑,实际什么都没跑」。 唯一的循环驱动源是:有一个 run 正在跑,并且它走到了回合边界。 所以把状态改成 active 不会启动任何东西;一个已停的目标不会被任何定时器唤醒。 凡是「让目标重新跑起来」的入口,都必须自己补起那一轮。下一步
目标模式鼓励委派——看看子代理是怎么设计的。
