fix(background-agent): preserve parent agent on retry wakes

Background fallback retry notifications were queued as bare internal user messages, so OpenCode could treat the notification as a new default-agent turn. Reuse the same parent prompt context resolver used by completion notifications for retrying and retry-ready wakes, and pin regression coverage for Hephaestus parent sessions plus missing-context fallbacks.
This commit is contained in:
YeonGyu-Kim
2026-05-18 14:05:01 +09:00
parent 3b50b7c8ba
commit d44cd1c1a0
3 changed files with 287 additions and 77 deletions
@@ -6,6 +6,10 @@ type PromptAsyncCall = {
path: { id: string }
body: {
noReply?: boolean
agent?: string
model?: { providerID: string; modelID: string }
variant?: string
tools?: Record<string, boolean>
parts?: unknown[]
}
query?: {
@@ -40,9 +44,7 @@ function createNotifier(args: {
},
abort: async () => ({ data: {} }),
},
} as unknown as Parameters<typeof ParentWakeNotifier>[0] extends never
? never
: ConstructorParameters<typeof ParentWakeNotifier>[0]["client"]
} as unknown as ConstructorParameters<typeof ParentWakeNotifier>[0]["client"]
const notifier = new ParentWakeNotifier(
{
@@ -139,6 +141,49 @@ describe("ParentWakeNotifier — user message race guard (issue #4120)", () => {
releaseAllPromptAsyncReservationsForTesting()
})
test("#given pending wake has parent prompt context #when flushing #then promptAsync receives the context", async () => {
// given
const { notifier, promptAsyncCalls } = createNotifier({
sessionMessages: [
{
info: {
role: "assistant",
finish: "stop",
time: { created: Date.now() - 100 },
},
},
],
})
notifier.queuePendingParentWake(
"parent-context",
"task retrying",
{
agent: "hephaestus",
model: { providerID: "openai", modelID: "gpt-5" },
variant: "xhigh",
tools: { bash: true, edit: false },
},
false,
)
// when
await notifier.flushPendingParentWake("parent-context")
// then
expect(promptAsyncCalls).toHaveLength(1)
expect(promptAsyncCalls[0]?.body).toMatchObject({
noReply: true,
agent: "hephaestus",
model: { providerID: "openai", modelID: "gpt-5" },
variant: "xhigh",
tools: { bash: true, edit: false },
})
expect(promptAsyncCalls[0]?.body.parts).toHaveLength(1)
notifier.shutdown()
releaseAllPromptAsyncReservationsForTesting()
})
test("#given user message is older than the race window #when flushing pending wake #then dispatch proceeds", async () => {
// given
const { notifier, promptAsyncCalls } = createNotifier({