From 06ca03dbd82f72ff17e7e8ed252dc28b4acf69fb Mon Sep 17 00:00:00 2001 From: can1357 Date: Thu, 25 Jun 2026 19:10:12 +0200 Subject: [PATCH] fix(agent): release task spawn slot when progress reporting throws MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In #registerSpawnJob the markRunning()/reportProgress() calls sat between semaphore.acquire() and the try whose finally releases the slot. If progress reporting threw there, the acquired task.maxConcurrency slot leaked and permanently shrank subagent concurrency. Move those statements inside the try so finally always releases. The abort-before-execution branch is unchanged (releases once and throws before the try is entered — not a double release). Refs #3464 --- packages/coding-agent/CHANGELOG.md | 1 + packages/coding-agent/src/task/index.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 1a997916d..dc459d21f 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -12,6 +12,7 @@ - Fixed manual `/compact` leaving `session.isCompacting` false while active-turn abort teardown awaited, so the first steer/follow-up typed during compaction startup now routes through the compaction queue instead of being lost. ([#3485](https://github.com/can1357/oh-my-pi/issues/3485)) - Fixed ollama-cloud task/subagent fan-out exceeding the provider's three-request concurrency cap by adding a provider-specific subagent limiter, and let configured task/smol/advisor model roles inherit the default retry fallback chain when they do not define their own chain. ([#3464](https://github.com/can1357/oh-my-pi/issues/3464)) - Fixed the per-provider subagent concurrency limiter (e.g. `providers.ollama-cloud.maxConcurrency`) being replaced with a fresh semaphore whenever the configured limit changed, which orphaned the in-flight slots on the old instance and let a runtime or mixed limit value exceed the cap. The limiter now resizes a single shared semaphore in place — raising the ceiling admits queued waiters immediately, lowering it drains in-flight holders without admitting past the new cap. ([#3464](https://github.com/can1357/oh-my-pi/issues/3464)) +- Fixed a background-task spawn slot leaking from the `task.maxConcurrency` limiter when progress reporting threw between acquiring the slot and entering the guarded run: `markRunning`/`reportProgress` now run inside the try whose `finally` releases the semaphore, so a failed progress report can no longer permanently shrink subagent concurrency. ([#3464](https://github.com/can1357/oh-my-pi/issues/3464)) ## [16.1.19] - 2026-06-25 diff --git a/packages/coding-agent/src/task/index.ts b/packages/coding-agent/src/task/index.ts index d48091a1a..3287351ec 100644 --- a/packages/coding-agent/src/task/index.ts +++ b/packages/coding-agent/src/task/index.ts @@ -798,13 +798,13 @@ export class TaskTool implements AgentTool, - ); try { + markRunning(); + progress.status = "running"; + await reportProgress( + `Running background task ${agentId}...`, + buildDetails("running", ownJobId) as unknown as Record, + ); const result = await this.#executeSync( toolCallId, spawnParams,