3.3 KiB
3.3 KiB
可持续对话 · 不停范式(v1.6.65 · 抽象层)
目的:消除「有时 2 秒停、有时 52 秒、有时 interrupted」的非确定性。
一、三层语义(必须分清)
| 层 | 含义 | 用户可见 |
|---|---|---|
| L1 Cursor turn | MCP 工具 return 后 turn 必然收工 | Working 消失 |
| L2 MCP 占用 | 单次 wait 内 poll 链(Hub 每 ~2.2s renewal) |
Working 持续 |
| L3 Hub 连接 | connectionHeld + steerQueue + 面板 |
13458 仍在线 |
「对话不结束」≠ L1 永远不收工
= L2 尽量长(默认无上限)+ L3 永不断 + turn 结束后下一轮再 wait
二、五类抽象问题(P1–P5)
| ID | 范式名 | 表现 | v1.6.65 解法 |
|---|---|---|---|
| P1 | 竞态唤醒 | STEER 与 RENEWAL 抢首 poll → 2s vs 48s 随机 | defer 不依赖 pollers.size(poll 在 add 前 takeSteer) |
| P2 | 假上限 | 52s/120s 被当成 wait 顶 | occupyBudgetMs=0 = 无限 poll 直到用户回复 |
| P3 | 同 turn 连环 | Agent 同 turn 多次 renewalOnly → Cursor interrupted | 一次 wait 内无限 poll;RENEWAL 仅 下一轮 再 wait |
| P4 | 态误报 | dialogueState≠OCCUPYING 却说「挂起中」 |
查 /api/link/status 三态 |
| P5 | 双轨版本 | Hub 新 / MCP 旧(未 Reload) | sync-runtime + Reload Window |
| P6 | 多标签互杀 | Tab B select/wait 打断 Tab A;进程锁拒第二标签 | v1.6.66:poll 按 ct_ 隔离 + wait 并行队列 + 标签独立 binding |
七、多标签并行铁律(v1.6.66)
| 禁止 | 改为 |
|---|---|
全局 waitPollAbort |
Map<ct_, AbortController> |
| fast 工具 abort 全部 wait | 不 abort 其它 ct_ |
| wait 占满 MCP 串行链 | wait_for_user_input 走并行 lane |
| 进程锁拒第二标签 | 按 cursorTitle/composer 读独立 binding 文件 |
验收:两标签同时 wait,互发面板消息,均不被 interrupted。
三、唯一循环(范式)
用户/面板输入
→ Agent 执行(或无任务)
→ 可选一句「已完成,现挂起」
→ wait(末 tool)
└─ MCP: hubPollUntilReply(∞)
└─ Hub: 每 2.2s renewal;48s 内 defer 自动 steer
└─ 面板人工消息:立即出队
→ [仅 Cursor 强杀] RENEWAL → 下一轮再 wait
→ 循环
禁止:
- 同 turn 连环
renewalOnly(触发 P3) - 同 turn 大量 Write + wait(~70s interrupted)
- 无
dialogueState证据说「挂起中」(P4)
四、占用预算语义
occupyBudgetMs |
行为 |
|---|---|
| 0(默认) | 无上限,直到用户回复或 Cursor 杀工具 |
| 5000–86400000 | 可选上限(面板「10s/30s/10min」) |
timedReplyPresets 里的 120000 不是 wait 上限,是定时续跑间隔选项。
五、验收
bash "…/Cursor持久对话/脚本/sync-runtime.sh"
# Reload Window
curl -s "http://127.0.0.1:13458/api/session/meta?token=ct_XXX" | jq '{neverStop,occupyBudgetMs,occupyBudgetInfinite}'
目测:wait 后 Working ≥40s 且非 2s 闪退;面板发「1」仍能在占用期送达。
六、Agent 一句话
一次 wait 挂到用户说话;不要同 turn 连环 renewal;不要假报挂起。