fix(background-agent): resolve parent wake agent aliases

This commit is contained in:
YeonGyu-Kim
2026-05-15 21:52:40 +09:00
parent 2bd4944bad
commit 39fef2042b
2 changed files with 63 additions and 10 deletions
+46 -1
View File
@@ -7,7 +7,7 @@ import { getSessionPromptParams, clearSessionPromptParams } from "../../shared/s
import { tmpdir } from "node:os"
import type { PluginInput } from "@opencode-ai/plugin"
import * as sharedModule from "../../shared"
import { _resetForTesting as resetClaudeCodeSessionState, subagentSessions } from "../claude-code-session-state"
import { _resetForTesting as resetClaudeCodeSessionState, registerAgentName, subagentSessions } from "../claude-code-session-state"
import type { BackgroundTask, ResumeInput } from "./types"
import { MIN_IDLE_TIME_MS } from "./constants"
import { BackgroundManager } from "./manager"
@@ -5204,6 +5204,51 @@ describe("BackgroundManager.handleEvent - session.error", () => {
manager.shutdown()
})
test("pins the registered parent agent alias before dispatching a deferred parent wake", async () => {
//#given
resetClaudeCodeSessionState()
registerAgentName("\u200B\u200B\u200B\u200BAtlas - Plan Executor")
const promptCalls: Array<{ path: { id: string }; body: Record<string, unknown> }> = []
const client = {
session: {
status: async () => ({ data: { "parent-session-alias": { type: "idle" } } }),
promptAsync: async (args: { path: { id: string }; body: Record<string, unknown> }) => {
promptCalls.push(args)
return {}
},
abort: async () => ({}),
},
}
const manager = new BackgroundManager({ pluginContext: createPluginInput(client) })
const managerInternals = cast<{
queuePendingParentWake: (
sessionID: string,
notification: string,
promptContext: Record<string, unknown>,
shouldReply: boolean,
delayMs?: number,
) => void
flushPendingParentWake: (sessionID: string) => Promise<void>
}>(manager)
//#when
managerInternals.queuePendingParentWake(
"parent-session-alias",
"<system-reminder>done</system-reminder>",
{ agent: "atlas" },
true,
0,
)
await managerInternals.flushPendingParentWake("parent-session-alias")
//#then
expect(promptCalls).toHaveLength(1)
expect(promptCalls[0]?.body.agent).toBe("\u200B\u200B\u200B\u200BAtlas - Plan Executor")
manager.shutdown()
resetClaudeCodeSessionState()
})
test("does not requeue dispatched parent wake when session.error arrives before accepted history is visible", async () => {
//#given
const promptCalls: Array<{ path: { id: string }; body: Record<string, unknown> }> = []
+17 -9
View File
@@ -37,7 +37,7 @@ import {
type QueueItem,
} from "./constants"
import { subagentSessions } from "../claude-code-session-state"
import { resolveRegisteredAgentName, subagentSessions } from "../claude-code-session-state"
import { getTaskToastManager } from "../task-toast-manager"
import { formatDuration } from "./duration-formatter"
import {
@@ -1385,13 +1385,20 @@ The fallback retry session is now created and can be inspected directly.
this.observedOutputSessions.add(sessionID)
}
private cloneParentWake(wake: PendingParentWake): PendingParentWake {
private resolveParentWakePromptContext(promptContext: ParentWakePromptContext): ParentWakePromptContext {
const resolvedAgent = resolveRegisteredAgentName(promptContext.agent)
return {
promptContext: {
...wake.promptContext,
...(wake.promptContext.model ? { model: { ...wake.promptContext.model } } : {}),
...(wake.promptContext.tools ? { tools: { ...wake.promptContext.tools } } : {}),
},
...promptContext,
...(resolvedAgent ? { agent: resolvedAgent } : {}),
...(promptContext.model ? { model: { ...promptContext.model } } : {}),
...(promptContext.tools ? { tools: { ...promptContext.tools } } : {}),
}
}
private cloneParentWake(wake: PendingParentWake): PendingParentWake {
const promptContext = this.resolveParentWakePromptContext(wake.promptContext)
return {
promptContext,
notifications: [...wake.notifications],
shouldReply: wake.shouldReply,
...(wake.dispatchedAt !== undefined ? { dispatchedAt: wake.dispatchedAt } : {}),
@@ -2692,14 +2699,15 @@ The task was re-queued on a fallback model after a retryable failure.
shouldReply: boolean,
delayMs?: number,
): void {
const resolvedPromptContext = this.resolveParentWakePromptContext(promptContext)
const pendingWake = this.pendingParentWakes.get(sessionID)
if (pendingWake) {
pendingWake.notifications.push(notification)
pendingWake.promptContext = promptContext
pendingWake.promptContext = resolvedPromptContext
pendingWake.shouldReply = pendingWake.shouldReply || shouldReply
} else {
this.pendingParentWakes.set(sessionID, {
promptContext,
promptContext: resolvedPromptContext,
notifications: [notification],
shouldReply,
})