Skip to content

Commit 116a90d

Browse files
committed
enhance(background-agent): Prevent recursive tool calls and wait for session todos before completion
- Remove call_omo_agent from blocked tools (only calls explore/librarian, safe) - Keep task and background_task blocked to prevent recursion - Add checkSessionTodos() to verify incomplete todos before marking tasks complete - Update session.idle event handler to respect todo status - Add polling check in task completion to wait for todo-continuation 🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
1 parent 060e58e commit 116a90d

File tree

1 file changed

+42
-6
lines changed

1 file changed

+42
-6
lines changed

src/features/background-agent/manager.ts

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ interface Event {
3030
properties?: EventProperties
3131
}
3232

33+
interface Todo {
34+
content: string
35+
status: string
36+
priority: string
37+
id: string
38+
}
39+
3340
function getMessageDir(sessionID: string): string | null {
3441
if (!existsSync(MESSAGE_STORAGE)) return null
3542

@@ -103,7 +110,6 @@ export class BackgroundManager {
103110
agent: input.agent,
104111
tools: {
105112
task: false,
106-
call_omo_agent: false,
107113
background_task: false,
108114
},
109115
parts: [{ type: "text", text: input.prompt }],
@@ -151,6 +157,23 @@ export class BackgroundManager {
151157
return undefined
152158
}
153159

160+
private async checkSessionTodos(sessionID: string): Promise<boolean> {
161+
try {
162+
const response = await this.client.session.todo({
163+
path: { id: sessionID },
164+
})
165+
const todos = (response.data ?? response) as Todo[]
166+
if (!todos || todos.length === 0) return false
167+
168+
const incomplete = todos.filter(
169+
(t) => t.status !== "completed" && t.status !== "cancelled"
170+
)
171+
return incomplete.length > 0
172+
} catch {
173+
return false
174+
}
175+
}
176+
154177
handleEvent(event: Event): void {
155178
const props = event.properties
156179

@@ -183,11 +206,18 @@ export class BackgroundManager {
183206
const task = this.findBySession(sessionID)
184207
if (!task || task.status !== "running") return
185208

186-
task.status = "completed"
187-
task.completedAt = new Date()
188-
this.markForNotification(task)
189-
this.notifyParentSession(task)
190-
log("[background-agent] Task completed via session.idle event:", task.id)
209+
this.checkSessionTodos(sessionID).then((hasIncompleteTodos) => {
210+
if (hasIncompleteTodos) {
211+
log("[background-agent] Task has incomplete todos, waiting for todo-continuation:", task.id)
212+
return
213+
}
214+
215+
task.status = "completed"
216+
task.completedAt = new Date()
217+
this.markForNotification(task)
218+
this.notifyParentSession(task)
219+
log("[background-agent] Task completed via session.idle event:", task.id)
220+
})
191221
}
192222

193223
if (event.type === "session.deleted") {
@@ -329,6 +359,12 @@ export class BackgroundManager {
329359
}
330360

331361
if (sessionStatus.type === "idle") {
362+
const hasIncompleteTodos = await this.checkSessionTodos(task.sessionID)
363+
if (hasIncompleteTodos) {
364+
log("[background-agent] Task has incomplete todos via polling, waiting:", task.id)
365+
continue
366+
}
367+
332368
task.status = "completed"
333369
task.completedAt = new Date()
334370
this.markForNotification(task)

0 commit comments

Comments
 (0)