diff --git a/src/plugin/pty/notification-manager.ts b/src/plugin/pty/notification-manager.ts index 52c2ba7..2fd8109 100644 --- a/src/plugin/pty/notification-manager.ts +++ b/src/plugin/pty/notification-manager.ts @@ -20,17 +20,19 @@ export class NotificationManager { model?: { providerID: string; modelID: string } variant?: string } = {} + let currentAgent: string | undefined try { const parent = await this.client.session.get({ path: { id: session.parentSessionId }, }) - const model = ( - parent.data as - | (typeof parent.data & { - model?: { id: string; providerID: string; variant?: string } - }) - | undefined - )?.model + const info = parent.data as + | (typeof parent.data & { + agent?: string + model?: { id: string; providerID: string; variant?: string } + }) + | undefined + currentAgent = info?.agent + const model = info?.model if (model) { modelContext = { model: { providerID: model.providerID, modelID: model.id }, @@ -38,13 +40,16 @@ export class NotificationManager { } } } catch { - // Older OpenCode versions may not expose the session model. + // Older OpenCode versions may not expose the session agent or model. } + // Prefer the parent session's current agent over the spawn-time snapshot + // so an exit notification can't flip the session back to a stale agent. + const agent = currentAgent ?? session.parentAgent await this.client.session.promptAsync({ path: { id: session.parentSessionId }, body: { parts: [{ type: 'text', text: message }], - ...(session.parentAgent ? { agent: session.parentAgent } : {}), + ...(agent ? { agent } : {}), ...modelContext, }, }) diff --git a/test/notification-manager.test.ts b/test/notification-manager.test.ts index b0cbb56..e3ce7ac 100644 --- a/test/notification-manager.test.ts +++ b/test/notification-manager.test.ts @@ -101,6 +101,36 @@ describe('NotificationManager', () => { expect(Object.hasOwn(payload.body, 'variant')).toBe(false) }) + it("prefers the parent session's current agent over the spawn-time agent", async () => { + const get = mock(async () => ({ + data: { agent: 'agent-current' }, + })) + const promptAsync = mock(async (_payload: PromptPayload) => {}) + const manager = new NotificationManager() + + manager.init({ session: { get, promptAsync } } as unknown as OpencodeClient) + + await manager.sendExitNotification(createSession({ parentAgent: 'agent-two' }), 0) + + const payload = promptAsync.mock.calls[0]?.[0] + if (!payload) throw new Error('Expected a prompt payload') + expect(payload.body.agent).toBe('agent-current') + }) + + it('falls back to the spawn-time agent when the parent session has none', async () => { + const get = mock(async () => ({ data: {} })) + const promptAsync = mock(async (_payload: PromptPayload) => {}) + const manager = new NotificationManager() + + manager.init({ session: { get, promptAsync } } as unknown as OpencodeClient) + + await manager.sendExitNotification(createSession({ parentAgent: 'agent-two' }), 0) + + const payload = promptAsync.mock.calls[0]?.[0] + if (!payload) throw new Error('Expected a prompt payload') + expect(payload.body.agent).toBe('agent-two') + }) + it('includes body.agent when originating agent is present', async () => { const promptAsync = mock(async (_payload: PromptPayload) => {}) const manager = new NotificationManager()