问题描述
Sisyphus 通过 task(run_in_background=true) 或 call_omo_agent 派活给其他 agent 后,被告知 "Wait for system-reminder notification" 于是结束回合说"我在等待"。但 background agent 完成后,通知没有送达 Sisyphus 的 session,导致 Sisyphus 永远卡住。除非人类手动输入 "继续",否则不会恢复。
根因分析
通知链路极其脆弱,任何一环失败 + retry 时机重叠 = 通知永久丢失:
根因 1: settleMs: 0
packages/omo-opencode/src/features/background-agent/parent-wake-prompt-dispatch.ts:43
settleMs: 0, // ← 没有 idle settle 时间
正常 dispatch 会等 150ms (DEFAULT_SESSION_IDLE_SETTLE_MS) 让 session 状态稳定,但 parent-wake 设成了 0。dispatchAfterSessionIdle 调 isSessionActive() 时,parent session 可能刚 idle 但 OpenCode session status API 还返回 "busy",dispatch 直接返回 "active" 失败,通知被 requeue。
根因 2: scheduleFlush 遇到已有 timer 静默丢弃
packages/omo-opencode/src/features/background-agent/parent-wake-pending-queue.ts:98-101
scheduleFlush(sessionID, operation, delayMs): void {
if (this.pendingParentWakeTimers.has(sessionID)) {
return // ← 已有 timer?新 retry 直接扔了
}
根因 1 导致 dispatch 失败后,sendParentWakePrompt 调 scheduleFlush()(无 delay → 1s 默认值)。但如果此时已有 timer(比如初始 100ms debounce timer),重试被静默丢弃。通知永久丢失。
根因 3: forceNoReply admit-only 死循环
packages/omo-opencode/src/features/background-agent/parent-wake-flush-runner.ts:56-73
if (this.hasRecentParentSessionActivity(sessionID)) {
await this.sendParentWakePrompt(sessionID, latestWake, {
forceNoReply: true, // noReply 注入(不触发 AI 新回合)
retainPendingWake: true, // 保留 wake
});
if (latestWake.shouldReply) {
this.schedulePendingParentWakeFlush(sessionID) // 再调度
}
}
PARENT_WAKE_SESSION_ACTIVITY_IN_PROGRESS_WINDOW_MS = 5000ms。如果 parent session 在这 5 秒内有 activity 记录(message.part.delta 等 event),就进这个分支。如果 activity 持续被记录(child session 事件传播等),永远进不了真正的 reply dispatch。
根因 4: 检查链路过长,无端到端确认
tryCompleteTask → notifyParentSession → queuePendingParentWake(100ms debounce)
→ flushPendingParentWake → sendParentWakePrompt → dispatchInternalPrompt(settleMs=0)
→ dispatchAfterSessionIdle → isSessionActive + sessionLatestAssistantBlocksInternalPrompt
→ session.promptAsync
每个环节都可能失败,且失败后依赖重试机制(根因 2 表明重试可能被静默丢弃)。没有端到端的 ACK 确认通知确实送达了 parent session。
修复方向
settleMs: 0 → DEFAULT_SESSION_IDLE_SETTLE_MS (150ms) — parent-wake-prompt-dispatch.ts:43
scheduleFlush 的 silent-drop 改为 cancel existing + reschedule — parent-wake-pending-queue.ts:98-101
forceNoReply 循环加 max-retry limit — N 次连续 admit-only 后强制 reply dispatch
- 考虑在 notification 注入成功后加一个 ACK 回写机制
复现步骤
- Sisyphus:
task(agent="explore", run_in_background=true, prompt="...")
- Sisyphus 收到 "Background task launched" → 说 "我在等待" → 结束回合
- explore agent 完成任务
- Sisyphus 永远收不到通知,卡死
环境
- OS: Windows
- OpenCode plugin: oh-my-openagent
- Config: 无
disabled_hooks,notification 默认启用
问题描述
Sisyphus 通过
task(run_in_background=true)或call_omo_agent派活给其他 agent 后,被告知 "Wait for system-reminder notification" 于是结束回合说"我在等待"。但 background agent 完成后,通知没有送达 Sisyphus 的 session,导致 Sisyphus 永远卡住。除非人类手动输入 "继续",否则不会恢复。根因分析
通知链路极其脆弱,任何一环失败 + retry 时机重叠 = 通知永久丢失:
根因 1:
settleMs: 0packages/omo-opencode/src/features/background-agent/parent-wake-prompt-dispatch.ts:43正常 dispatch 会等 150ms (
DEFAULT_SESSION_IDLE_SETTLE_MS) 让 session 状态稳定,但 parent-wake 设成了 0。dispatchAfterSessionIdle调isSessionActive()时,parent session 可能刚 idle 但 OpenCode session status API 还返回 "busy",dispatch 直接返回"active"失败,通知被 requeue。根因 2:
scheduleFlush遇到已有 timer 静默丢弃packages/omo-opencode/src/features/background-agent/parent-wake-pending-queue.ts:98-101根因 1 导致 dispatch 失败后,
sendParentWakePrompt调scheduleFlush()(无 delay → 1s 默认值)。但如果此时已有 timer(比如初始 100ms debounce timer),重试被静默丢弃。通知永久丢失。根因 3:
forceNoReplyadmit-only 死循环packages/omo-opencode/src/features/background-agent/parent-wake-flush-runner.ts:56-73PARENT_WAKE_SESSION_ACTIVITY_IN_PROGRESS_WINDOW_MS = 5000ms。如果 parent session 在这 5 秒内有 activity 记录(message.part.delta等 event),就进这个分支。如果 activity 持续被记录(child session 事件传播等),永远进不了真正的 reply dispatch。根因 4: 检查链路过长,无端到端确认
每个环节都可能失败,且失败后依赖重试机制(根因 2 表明重试可能被静默丢弃)。没有端到端的 ACK 确认通知确实送达了 parent session。
修复方向
settleMs: 0→DEFAULT_SESSION_IDLE_SETTLE_MS(150ms) —parent-wake-prompt-dispatch.ts:43scheduleFlush的 silent-drop 改为 cancel existing + reschedule —parent-wake-pending-queue.ts:98-101forceNoReply循环加 max-retry limit — N 次连续 admit-only 后强制 reply dispatch复现步骤
task(agent="explore", run_in_background=true, prompt="...")环境
disabled_hooks,notification 默认启用