diff --git a/packages/core/agent-loop/src/index.ts b/packages/core/agent-loop/src/index.ts index c37cce6a1a..0b8879c2b7 100644 --- a/packages/core/agent-loop/src/index.ts +++ b/packages/core/agent-loop/src/index.ts @@ -120,7 +120,11 @@ export class AgentLoop extends Service implements AgentFactory { this.ctx.logger.warn(`agent "${id}": config-driven resume of "${resumeSessionId}" failed: ${String(error)}`) }) }) - return () => void fiber.dispose() + // Return the EXACT child-fiber disposer. Cordis moves a returned + // effect into this labeled owner's teardown tree by function + // identity; a wrapper would leave the child as a concurrent sibling + // and could discard its async quiescence promise. + return fiber.dispose }, `agentLoop.resume(${id})`) } else { this.create(id, options, cwd === undefined ? {} : { cwd }) diff --git a/packages/core/agent-loop/tests/config-session-id.spec.ts b/packages/core/agent-loop/tests/config-session-id.spec.ts index 97f04cbbca..07d6cd9e9b 100644 --- a/packages/core/agent-loop/tests/config-session-id.spec.ts +++ b/packages/core/agent-loop/tests/config-session-id.spec.ts @@ -24,6 +24,24 @@ function waitForIdle(ctx: Context, agent: ReactLoopAgent): Promise { } describe('config-driven session id', () => { + it('identity-nests the deferred resume fiber under its labeled owner effect', async () => { + const ctx = new Context() + await ctx.plugin(LlmService) + await ctx.plugin(SessionStore) + await ctx.plugin(SystemPrompt) + await ctx.plugin(ToolRegistry) + await ctx.plugin(AgentRegistry) + const loopFiber = await ctx.plugin(AgentLoop, { + agents: [{ id: AgentId('main'), model: 'mock', resumeSessionId: SessionId('deferred') }], + }) + + const resumeEffect = loopFiber.getEffects().find(effect => effect.label === 'agentLoop.resume(main)') + expect(resumeEffect?.children.map(child => child.label)).toEqual(['ctx.plugin()']) + expect(loopFiber.getEffects().filter(effect => effect.label === 'ctx.plugin()')).toEqual([]) + + await loopFiber.dispose() + }) + it('config-driven create uses a fresh ${id}-session- per run (restart-safe)', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-cfg-session-')) dirs.push(root)