fix(delegation): replace message-count-stability polling with native finish-based completion detection
Sync task completion was fragile — detecting premature stability during brief idle periods between tool calls. Now mirrors opencode's native SessionPrompt.loop() logic: checks assistant finish reason is terminal (not tool-calls/unknown) and assistant.id > user.id. Also switches sync prompt sender from blocking HTTP (promptSync) to async fire-and-forget (promptAsync) to avoid JSON parse errors in ACP.
This commit is contained in:
@@ -1,7 +1,27 @@
|
||||
import type { ToolContextWithMetadata, OpencodeClient } from "./types"
|
||||
import type { SessionMessage } from "./executor-types"
|
||||
import { getTimingConfig } from "./timing"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
const NON_TERMINAL_FINISH_REASONS = new Set(["tool-calls", "unknown"])
|
||||
|
||||
export function isSessionComplete(messages: SessionMessage[]): boolean {
|
||||
let lastUser: SessionMessage | undefined
|
||||
let lastAssistant: SessionMessage | undefined
|
||||
|
||||
for (let i = messages.length - 1; i >= 0; i--) {
|
||||
const msg = messages[i]
|
||||
if (!lastAssistant && msg.info?.role === "assistant") lastAssistant = msg
|
||||
if (!lastUser && msg.info?.role === "user") lastUser = msg
|
||||
if (lastUser && lastAssistant) break
|
||||
}
|
||||
|
||||
if (!lastAssistant?.info?.finish) return false
|
||||
if (NON_TERMINAL_FINISH_REASONS.has(lastAssistant.info.finish)) return false
|
||||
if (!lastUser?.info?.id || !lastAssistant?.info?.id) return false
|
||||
return lastUser.info.id < lastAssistant.info.id
|
||||
}
|
||||
|
||||
export async function pollSyncSession(
|
||||
ctx: ToolContextWithMetadata,
|
||||
client: OpencodeClient,
|
||||
@@ -14,8 +34,6 @@ export async function pollSyncSession(
|
||||
): Promise<string | null> {
|
||||
const syncTiming = getTimingConfig()
|
||||
const pollStart = Date.now()
|
||||
let lastMsgCount = 0
|
||||
let stablePolls = 0
|
||||
let pollCount = 0
|
||||
|
||||
log("[task] Starting poll loop", { sessionID: input.sessionID, agentToUse: input.agentToUse })
|
||||
@@ -35,45 +53,29 @@ export async function pollSyncSession(
|
||||
const sessionStatus = allStatuses[input.sessionID]
|
||||
|
||||
if (pollCount % 10 === 0) {
|
||||
log("[task] Poll status", {
|
||||
log("[task] Poll status", {
|
||||
sessionID: input.sessionID,
|
||||
pollCount,
|
||||
elapsed: Math.floor((Date.now() - pollStart) / 1000) + "s",
|
||||
sessionStatus: sessionStatus?.type ?? "not_in_status",
|
||||
stablePolls,
|
||||
lastMsgCount,
|
||||
})
|
||||
}
|
||||
|
||||
if (sessionStatus && sessionStatus.type !== "idle") {
|
||||
stablePolls = 0
|
||||
lastMsgCount = 0
|
||||
continue
|
||||
}
|
||||
|
||||
const elapsed = Date.now() - pollStart
|
||||
if (elapsed < syncTiming.MIN_STABILITY_TIME_MS) {
|
||||
continue
|
||||
}
|
||||
const messagesResult = await client.session.messages({ path: { id: input.sessionID } })
|
||||
const msgs = ((messagesResult as { data?: unknown }).data ?? messagesResult) as SessionMessage[]
|
||||
|
||||
const messagesCheck = await client.session.messages({ path: { id: input.sessionID } })
|
||||
const msgs = ((messagesCheck as { data?: unknown }).data ?? messagesCheck) as Array<unknown>
|
||||
const currentMsgCount = msgs.length
|
||||
|
||||
if (currentMsgCount === lastMsgCount) {
|
||||
stablePolls++
|
||||
if (stablePolls >= syncTiming.STABILITY_POLLS_REQUIRED) {
|
||||
log("[task] Poll complete - messages stable", { sessionID: input.sessionID, pollCount, currentMsgCount })
|
||||
break
|
||||
}
|
||||
} else {
|
||||
stablePolls = 0
|
||||
lastMsgCount = currentMsgCount
|
||||
if (isSessionComplete(msgs)) {
|
||||
log("[task] Poll complete - terminal finish detected", { sessionID: input.sessionID, pollCount })
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (Date.now() - pollStart >= syncTiming.MAX_POLL_TIME_MS) {
|
||||
log("[task] Poll timeout reached", { sessionID: input.sessionID, pollCount, lastMsgCount, stablePolls })
|
||||
log("[task] Poll timeout reached", { sessionID: input.sessionID, pollCount })
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user