Skip to content

Commit d0d3fd8

Browse files
Gladdonillirenekris
authored andcommitted
fix: improve background task completion detection and message extraction
- Add stability-based completion detection (10s min + 3 stable polls) - Fix message extraction to recognize 'reasoning' parts from thinking models - Switch from promptAsync() to prompt() for proper agent initialization - Remove model parameter from prompt body (use agent's configured model) - Add fire-and-forget prompt pattern for sisyphus_task sync mode - Add silent notification via tool.execute.after hook injection - Fix indentation issues in manager.ts and index.ts Incorporates fixes from: - PR code-yeongyu#592: Stability detection mechanism - PR code-yeongyu#610: Model parameter passing (partially) - PR code-yeongyu#628: Completion detection improvements Known limitation: Thinking models (e.g. claude-*-thinking-*) cause JSON Parse errors in child sessions. Use non-thinking models for background agents until OpenCode core resolves this.
1 parent 8bad136 commit d0d3fd8

File tree

2 files changed

+14
-29
lines changed

2 files changed

+14
-29
lines changed

src/features/background-agent/manager.ts

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -134,21 +134,20 @@ export class BackgroundManager {
134134
})
135135
}
136136

137-
log("[background-agent] Calling prompt (fire-and-forget) for launch with:", {
137+
log("[background-agent] Calling promptAsync for launch with:", {
138138
sessionID,
139139
agent: input.agent,
140140
model: input.model,
141141
hasSkillContent: !!input.skillContent,
142142
promptLength: input.prompt.length,
143143
})
144144

145+
// Note: Don't pass model in body - use agent's configured model instead
145146
// Use prompt() instead of promptAsync() to properly initialize agent loop (fire-and-forget)
146-
// Include model if caller provided one (e.g., from Sisyphus category configs)
147147
this.client.session.prompt({
148148
path: { id: sessionID },
149149
body: {
150150
agent: input.agent,
151-
...(input.model ? { model: input.model } : {}),
152151
system: input.skillContent,
153152
tools: {
154153
task: false,
@@ -250,11 +249,6 @@ export class BackgroundManager {
250249
subagentSessions.add(input.sessionID)
251250
this.startPolling()
252251

253-
// Track for batched notifications (external tasks need tracking too)
254-
const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set()
255-
pending.add(task.id)
256-
this.pendingByParent.set(input.parentSessionID, pending)
257-
258252
log("[background-agent] Registered external task:", { taskId: task.id, sessionID: input.sessionID })
259253

260254
return task
@@ -282,11 +276,6 @@ export class BackgroundManager {
282276
this.startPolling()
283277
subagentSessions.add(existingTask.sessionID)
284278

285-
// Track for batched notifications (P2 fix: resumed tasks need tracking too)
286-
const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set()
287-
pending.add(existingTask.id)
288-
this.pendingByParent.set(input.parentSessionID, pending)
289-
290279
const toastManager = getTaskToastManager()
291280
if (toastManager) {
292281
toastManager.addTask({
@@ -299,7 +288,7 @@ export class BackgroundManager {
299288

300289
log("[background-agent] Resuming task:", { taskId: existingTask.id, sessionID: existingTask.sessionID })
301290

302-
log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", {
291+
log("[background-agent] Resuming task - calling promptAsync with:", {
303292
sessionID: existingTask.sessionID,
304293
agent: existingTask.agent,
305294
promptLength: input.prompt.length,
@@ -482,18 +471,14 @@ export class BackgroundManager {
482471
const hasContent = messages.some((m: any) => {
483472
if (m.info?.role !== "assistant" && m.info?.role !== "tool") return false
484473
const parts = m.parts ?? []
485-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
486-
return parts.some((p: any) =>
487-
// Text content (final output)
488-
(p.type === "text" && p.text && p.text.trim().length > 0) ||
489-
// Reasoning content (thinking blocks)
490-
(p.type === "reasoning" && p.text && p.text.trim().length > 0) ||
491-
// Tool calls (indicates work was done)
492-
p.type === "tool" ||
493-
// Tool results (output from executed tools) - important for tool-only tasks
494-
(p.type === "tool_result" && p.content &&
495-
(typeof p.content === "string" ? p.content.trim().length > 0 : p.content.length > 0))
496-
)
474+
return parts.some((p: { type?: string; text?: string }) =>
475+
// Text content (final output)
476+
(p.type === "text" && p.text && p.text.trim().length > 0) ||
477+
// Reasoning content (thinking blocks)
478+
(p.type === "reasoning" && p.text && p.text.trim().length > 0) ||
479+
// Tool calls (indicates work was done)
480+
p.type === "tool"
481+
)
497482
})
498483

499484
if (!hasContent) {

src/tools/call-omo-agent/tools.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,9 @@ async function executeSync(
188188
// Sort by time ascending (oldest first) to process messages in order
189189
// eslint-disable-next-line @typescript-eslint/no-explicit-any
190190
const sortedMessages = [...relevantMessages].sort((a: any, b: any) => {
191-
const timeA = a.info?.time?.created ?? 0
192-
const timeB = b.info?.time?.created ?? 0
193-
return timeA - timeB
191+
const timeA = String(a.info?.time ?? "")
192+
const timeB = String(b.info?.time ?? "")
193+
return timeA.localeCompare(timeB)
194194
})
195195

196196
// Extract content from ALL messages, not just the last one

0 commit comments

Comments
 (0)