fix(background-agent): fail abort on SDK errors

Treat resolved abort responses with a non-null error payload the same as rejected aborts. This prevents stale-timeout cancellation bookkeeping from reporting success when the child session was not actually aborted.

Plan: .omo/plans/subagent-timeout-active-output.md
This commit is contained in:
YeonGyu-Kim
2026-05-21 15:23:52 +09:00
parent b68af25e41
commit 0bf8a9df25
2 changed files with 44 additions and 2 deletions
@@ -37,6 +37,22 @@ describe("abortWithTimeout", () => {
expect(logMock).not.toHaveBeenCalled()
})
test("#given abort resolves with an SDK error response #when abortWithTimeout runs #then it reports cancellation failure", async () => {
// given
const error = { message: "session not found" }
const abort = mock(async () => ({ error }))
// when
const result = await abortWithTimeout(createClient(abort), "session-error-response", 10)
// then
expect(result).toBe(false)
expect(logMock).toHaveBeenCalledWith(
"[background-agent] Session abort returned an error response:",
{ sessionID: "session-error-response", error },
)
})
test("#given abort hangs indefinitely #when abortWithTimeout runs #then it logs warning and continues", async () => {
// given
const abort = mock(() => new Promise<never>(() => {}))
@@ -1,6 +1,13 @@
import { log } from "../../shared"
import { isRecord } from "../../shared/record-type-guard"
import type { OpencodeClient } from "./opencode-client"
function getAbortResponseError(response: unknown): unknown | undefined {
if (!isRecord(response)) return undefined
const error = response.error
return error === undefined || error === null ? undefined : error
}
export async function abortWithTimeout(
client: OpencodeClient,
sessionID: string,
@@ -10,7 +17,26 @@ export async function abortWithTimeout(
try {
const result = await Promise.race([
client.session.abort({ path: { id: sessionID } }).then(() => "aborted" as const),
client.session.abort({ path: { id: sessionID } }).then(
(response) => {
const error = getAbortResponseError(response)
if (error !== undefined) {
log("[background-agent] Session abort returned an error response:", {
sessionID,
error,
})
return "failed" as const
}
return "aborted" as const
},
(error) => {
log("[background-agent] Session abort failed:", {
sessionID,
error,
})
return "failed" as const
},
),
new Promise<"timed_out">((resolve) => {
timeoutHandle = setTimeout(() => {
resolve("timed_out")
@@ -26,7 +52,7 @@ export async function abortWithTimeout(
return false
}
return true
return result === "aborted"
} finally {
if (timeoutHandle) {
clearTimeout(timeoutHandle)