fix(background-agent): add polling mechanism for child session tracking
- Replace unreliable event-based tracking with 2-second polling - Use SDK session.get() to detect completion (status === idle) - Use SDK session.messages() to count tool_use parts for progress - Auto-start polling on launch, auto-stop when no running tasks - Resume polling on restore if running tasks exist Fixes: Child session events not reaching plugin event handler 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -7,7 +7,21 @@
|
||||
"description": "Explore opencode in codebase",
|
||||
"agent": "explore",
|
||||
"status": "completed",
|
||||
"startedAt": 1765434417395,
|
||||
"completedAt": 1765434456778
|
||||
"startedAt": "2025-12-11T06:26:57.395Z",
|
||||
"completedAt": "2025-12-11T06:27:36.778Z"
|
||||
},
|
||||
{
|
||||
"id": "bg_392b9c9b",
|
||||
"sessionID": "ses_4f38ebf4fffeJZBocIn3UVv7vE",
|
||||
"parentSessionID": "ses_4f38eefa0ffeKV0pVNnwT37P5L",
|
||||
"parentMessageID": "msg_b0c7110d2001TMBlPeEYIrByvs",
|
||||
"description": "Test explore agent",
|
||||
"agent": "explore",
|
||||
"status": "running",
|
||||
"startedAt": "2025-12-11T08:05:07.378Z",
|
||||
"progress": {
|
||||
"toolCalls": 0,
|
||||
"lastUpdate": "2025-12-11T08:05:07.378Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -36,6 +36,7 @@ export class BackgroundManager {
|
||||
private client: OpencodeClient
|
||||
private storePath: string
|
||||
private persistTimer?: Timer
|
||||
private pollingInterval?: Timer
|
||||
|
||||
constructor(client: OpencodeClient, storePath: string) {
|
||||
this.tasks = new Map()
|
||||
@@ -75,6 +76,7 @@ export class BackgroundManager {
|
||||
|
||||
this.tasks.set(task.id, task)
|
||||
this.persist()
|
||||
this.startPolling()
|
||||
|
||||
this.client.session.promptAsync({
|
||||
path: { id: sessionID },
|
||||
@@ -207,6 +209,97 @@ export class BackgroundManager {
|
||||
}
|
||||
}
|
||||
|
||||
private startPolling(): void {
|
||||
if (this.pollingInterval) return
|
||||
|
||||
this.pollingInterval = setInterval(() => {
|
||||
this.pollRunningTasks()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
private stopPolling(): void {
|
||||
if (this.pollingInterval) {
|
||||
clearInterval(this.pollingInterval)
|
||||
this.pollingInterval = undefined
|
||||
}
|
||||
}
|
||||
|
||||
private hasRunningTasks(): boolean {
|
||||
for (const task of this.tasks.values()) {
|
||||
if (task.status === "running") return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private async pollRunningTasks(): Promise<void> {
|
||||
for (const task of this.tasks.values()) {
|
||||
if (task.status !== "running") continue
|
||||
|
||||
try {
|
||||
const infoResult = await this.client.session.get({
|
||||
path: { id: task.sessionID },
|
||||
})
|
||||
|
||||
if (infoResult.error) {
|
||||
task.status = "error"
|
||||
task.error = "Session not found"
|
||||
task.completedAt = new Date()
|
||||
this.persist()
|
||||
continue
|
||||
}
|
||||
|
||||
const sessionInfo = infoResult.data as { status?: string }
|
||||
|
||||
if (sessionInfo.status === "idle") {
|
||||
task.status = "completed"
|
||||
task.completedAt = new Date()
|
||||
this.markForNotification(task)
|
||||
this.persist()
|
||||
continue
|
||||
}
|
||||
|
||||
const messagesResult = await this.client.session.messages({
|
||||
path: { id: task.sessionID },
|
||||
})
|
||||
|
||||
if (!messagesResult.error && messagesResult.data) {
|
||||
const messages = messagesResult.data as Array<{
|
||||
info?: { role?: string }
|
||||
parts?: Array<{ type?: string; tool?: string; name?: string }>
|
||||
}>
|
||||
const assistantMsgs = messages.filter(
|
||||
(m) => m.info?.role === "assistant"
|
||||
)
|
||||
|
||||
let toolCalls = 0
|
||||
let lastTool: string | undefined
|
||||
|
||||
for (const msg of assistantMsgs) {
|
||||
const parts = msg.parts ?? []
|
||||
for (const part of parts) {
|
||||
if (part.type === "tool_use" || part.tool) {
|
||||
toolCalls++
|
||||
lastTool = part.tool || part.name || "unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (task.progress) {
|
||||
task.progress.toolCalls = toolCalls
|
||||
task.progress.lastTool = lastTool
|
||||
task.progress.lastUpdate = new Date()
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
void 0
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.hasRunningTasks()) {
|
||||
this.stopPolling()
|
||||
}
|
||||
}
|
||||
|
||||
persist(): void {
|
||||
if (this.persistTimer) {
|
||||
clearTimeout(this.persistTimer)
|
||||
@@ -271,6 +364,10 @@ export class BackgroundManager {
|
||||
}
|
||||
this.tasks.set(task.id, task)
|
||||
}
|
||||
|
||||
if (this.hasRunningTasks()) {
|
||||
this.startPolling()
|
||||
}
|
||||
} catch {
|
||||
void 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user