fix(background-agent): handle SDK error response in spawn limit lineage lookup
- Check response.error and !response.data after session.get() to fail closed - Prevents unlimited spawning when SDK returns non-throwing error responses - Added regression tests for SDK error and missing data scenarios
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import type { OpencodeClient } from "./constants"
|
||||||
|
import { resolveSubagentSpawnContext } from "./subagent-spawn-limits"
|
||||||
|
|
||||||
|
function createMockClient(sessionGet: OpencodeClient["session"]["get"]): OpencodeClient {
|
||||||
|
return {
|
||||||
|
session: {
|
||||||
|
get: sessionGet,
|
||||||
|
},
|
||||||
|
} as OpencodeClient
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("resolveSubagentSpawnContext", () => {
|
||||||
|
describe("#given session.get returns an SDK error response", () => {
|
||||||
|
test("throws a fail-closed spawn blocked error", async () => {
|
||||||
|
// given
|
||||||
|
const client = createMockClient(async () => ({
|
||||||
|
error: "lookup failed",
|
||||||
|
data: undefined,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = resolveSubagentSpawnContext(client, "parent-session")
|
||||||
|
|
||||||
|
// then
|
||||||
|
await expect(result).rejects.toThrow(/background_task\.maxDescendants cannot be enforced safely.*lookup failed/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given session.get returns no session data", () => {
|
||||||
|
test("throws a fail-closed spawn blocked error", async () => {
|
||||||
|
// given
|
||||||
|
const client = createMockClient(async () => ({
|
||||||
|
data: undefined,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = resolveSubagentSpawnContext(client, "parent-session")
|
||||||
|
|
||||||
|
// then
|
||||||
|
await expect(result).rejects.toThrow(/background_task\.maxDescendants cannot be enforced safely.*No session data returned/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -36,10 +36,18 @@ export async function resolveSubagentSpawnContext(
|
|||||||
|
|
||||||
let nextParentSessionID: string | undefined
|
let nextParentSessionID: string | undefined
|
||||||
try {
|
try {
|
||||||
const session = await client.session.get({
|
const response = await client.session.get({
|
||||||
path: { id: currentSessionID },
|
path: { id: currentSessionID },
|
||||||
})
|
})
|
||||||
nextParentSessionID = session.data?.parentID
|
if (response.error) {
|
||||||
|
throw new Error(String(response.error))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.data) {
|
||||||
|
throw new Error("No session data returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
nextParentSessionID = response.data.parentID
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const reason = error instanceof Error ? error.message : String(error)
|
const reason = error instanceof Error ? error.message : String(error)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
Reference in New Issue
Block a user