diff --git a/packages/core/src/agents/background-tasks.test.ts b/packages/core/src/agents/background-tasks.test.ts index 3e42eb25b8..3ee0e4cc20 100644 --- a/packages/core/src/agents/background-tasks.test.ts +++ b/packages/core/src/agents/background-tasks.test.ts @@ -511,16 +511,24 @@ describe('BackgroundTaskRegistry', () => { expect(registry.get('bg-1')?.prompt).toBe('resumed continuation'); }); - it('does not count foreground, paused, or terminal entries toward the cap', () => { + it('counts foreground agents toward the cap but not paused or terminal entries', () => { registry = new BackgroundTaskRegistry({ maxConcurrentBackgroundAgents: 1, }); + // A foreground agent occupies a slot. registry.register( makeRegistration('fg-1', { isBackgrounded: false, }), ); + + expect(() => registry.register(makeRegistration('bg-1'))).toThrow( + 'maximum concurrent background agents (1) reached', + ); + + // Paused entries do not occupy a slot. + registry.unregisterForeground('fg-1'); registry.register( makeRegistration('paused-1', { status: 'paused', @@ -535,7 +543,6 @@ describe('BackgroundTaskRegistry', () => { registry.complete('bg-1', 'done'); registry.register(makeRegistration('bg-2')); - expect(registry.get('fg-1')).toBeDefined(); expect(registry.get('paused-1')).toBeDefined(); expect(registry.get('bg-2')?.status).toBe('running'); }); diff --git a/packages/core/src/agents/background-tasks.ts b/packages/core/src/agents/background-tasks.ts index b069cd2b00..0c45c87293 100644 --- a/packages/core/src/agents/background-tasks.ts +++ b/packages/core/src/agents/background-tasks.ts @@ -428,10 +428,9 @@ export class BackgroundTaskRegistry { registration: AgentTaskRegistration, options: BackgroundTaskRegisterOptions = {}, ): AgentTask { - if (registration.isBackgrounded && registration.status === 'running') { + if (registration.status === 'running') { const existing = this.agents.get(registration.agentId); - const isReplacingRunning = - existing?.isBackgrounded === true && existing.status === 'running'; + const isReplacingRunning = existing?.status === 'running'; if (!isReplacingRunning) { this.assertCanStartBackgroundAgent(); } @@ -852,7 +851,7 @@ export class BackgroundTaskRegistry { private getRunningBackgroundCount(): number { return Array.from(this.agents.values()).filter( - (entry) => entry.isBackgrounded && entry.status === 'running', + (entry) => entry.status === 'running', ).length; } diff --git a/packages/core/src/tools/agent/agent.ts b/packages/core/src/tools/agent/agent.ts index f23163bc47..3bc0b7c3f9 100644 --- a/packages/core/src/tools/agent/agent.ts +++ b/packages/core/src/tools/agent/agent.ts @@ -2135,26 +2135,22 @@ class AgentToolInvocation extends BaseToolInvocation { // This is not redundant with registry.register() below — that call // remains the authoritative race guard, but by then the launch path // has already run hooks and created a child agent. - if (shouldRunInBackground) { - try { - this.config - .getBackgroundTaskRegistry() - .assertCanStartBackgroundAgent(); - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : String(error); - this.updateDisplay( - { - status: 'failed', - terminateReason: errorMessage, - }, - updateOutput, - ); - return { - llmContent: errorMessage, - returnDisplay: this.currentDisplay!, - }; - } + try { + this.config.getBackgroundTaskRegistry().assertCanStartBackgroundAgent(); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + this.updateDisplay( + { + status: 'failed', + terminateReason: errorMessage, + }, + updateOutput, + ); + return { + llmContent: errorMessage, + returnDisplay: this.currentDisplay!, + }; } // ── Optional worktree isolation (Phase 1: provision) ──────────