Skip to content

Fix unlimited task concurrency#3306

Open
daandden wants to merge 1 commit into
can1357:mainfrom
daandden:fix/task-max-concurrency-unlimited
Open

Fix unlimited task concurrency#3306
daandden wants to merge 1 commit into
can1357:mainfrom
daandden:fix/task-max-concurrency-unlimited

Conversation

@daandden

Copy link
Copy Markdown
Contributor

What

  • Treat task.maxConcurrency: 0 as unlimited for task spawns.
  • Add async and sync batch regressions.

Why

Fixes #3305

Testing

  • bun --cwd=packages/coding-agent test test/task/task-spawn.test.ts test/task/task-batch.test.ts — 17 pass, 0 fail.
  • bun --cwd=packages/coding-agent run check — fails in pre-existing unrelated type errors:
    • ../ai/src/providers/cursor.ts: Message<string> not assignable to generated agent.v1.* message types; missing message, turn, matches, customSystemPrompt.
    • ../ai/src/providers/devin.ts: Message<string> missing messageId, deltaThinking, deltaText, usage, userJwt.
    • src/modes/acp/acp-agent.ts / test/acp-agent.test.ts: @agentclientprotocol/sdk missing elicitation exports and client capability fields.
    • Biome warning: src/internal-urls/docs-index.generated.ts exceeds configured 1.0 MiB max size.

  • bun check passes
  • Tested locally
  • CHANGELOG updated (if user-facing)

@github-actions github-actions Bot added the vouched Passed the vouch gate label Jun 23, 2026
@daandden daandden force-pushed the fix/task-max-concurrency-unlimited branch from 35794e2 to 15bfa7a Compare June 23, 2026 10:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 35794e283d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/coding-agent/CHANGELOG.md Outdated
Comment on lines +30 to +31
- Fixed MCP tool calls forwarding unused optional placeholder arguments to servers, allowing schema-optional fields to be omitted before `tools/call`.
- Fixed `task.maxConcurrency: 0` serializing subagent spawns instead of disabling the task semaphore limit ([#3305](https://github.com/can1357/oh-my-pi/issues/3305)).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Move new changelog entries to Unreleased

These new entries are being added under the already released 16.1.16 section while ## [Unreleased] remains empty. The repo's AGENTS.md changelog rules say new entries always go under [Unreleased] and released sections are immutable; leaving this here mutates historical release notes and means the next release will not pick up this task-concurrency fix in its unreleased notes.

Useful? React with 👍 / 👎.

@roboomp roboomp added agent Agent runtime planning and orchestration fix review:p1 tool Tool behavior and integrations triaged labels Jun 23, 2026

@roboomp roboomp left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix, @daandden — the bug and root cause match #3305 exactly, and the two regression tests pin the contract well (both task.batch sync fan-out and background spawns assert all spawns clear the semaphore before any release). Code change in Semaphore's constructor is correct and handles 0/negative/NaN/Infinity symmetrically; aligns with the task.maxConcurrency: 0 → "Unlimited" UI label and runEvalConcurrency's existing semantics.

Two CHANGELOG fixes before merge:

  • The unrelated MCP bullet on line 30 has no corresponding code change in this diff — looks like a stray rebase artifact, please drop it.
  • The remaining task-concurrency bullet lands inside the released ## [16.1.16] section; move it to the empty ## [Unreleased] block at the top per AGENTS.md.

One nit: the new task-batch.test.ts case races on Bun.sleep(250) while task-spawn.test.ts uses a pollUntil helper — same gate, more CI-robust. Not blocking.

FYI for the maintainer: parallel PR #3307 (by @roboomp) targets the same constructor with the same Infinity-on-non-positive fix. Functionally equivalent — pick one.


### Fixed

- Fixed `task.maxConcurrency: 0` serializing subagent spawns instead of disabling the task semaphore limit ([#3305](https://github.com/can1357/oh-my-pi/issues/3305)).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking — this bullet ("Fixed MCP tool calls forwarding unused optional placeholder arguments…") has no corresponding code change in the PR diff (git diff origin/main...HEAD only touches parallel.ts plus two test files). Looks like a stray entry from an unrelated branch. Please drop it.

### Fixed

- Fixed `task.maxConcurrency: 0` serializing subagent spawns instead of disabling the task semaphore limit ([#3305](https://github.com/can1357/oh-my-pi/issues/3305)).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should-fix — this entry lands inside ## [16.1.16] - 2026-06-23 (header at line 5), which is already a released section. Per AGENTS.md: "Never modify already-released sections (e.g. ## [0.12.2]) — they are immutable. New entries always go under ## [Unreleased]." The [Unreleased] block on line 3 is currently empty — please move the task.maxConcurrency: 0 bullet there.


const race = await Promise.race([
bothStarted.promise.then(() => "started" as const),
Bun.sleep(250).then(() => "timeout" as const),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit — the sibling task-spawn.test.ts test already imports a pollUntil helper and uses it for "both started". A fixed Bun.sleep(250) race here makes the test flake-prone on slow CI without any benefit; consider polling on started.length === 2 for consistency.

Minor: Deferred/deferred() are now duplicated between task-batch.test.ts (lines 80-88, new) and task-spawn.test.ts (lines 68-76, existing). Same shape in test/memories-runtime.test.ts and test/registry/agent-lifecycle.test.ts too — a shared test/helpers/deferred.ts would avoid the 4th copy, but that's out of scope for this PR.


constructor(max: number) {
this.#max = Math.max(1, max);
const normalizedMax = Number.isFinite(max) ? Math.floor(max) : Number.POSITIVE_INFINITY;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code fix is correct — 0, negatives, NaN, and +Infinity all collapse to POSITIVE_INFINITY; positive finite values get Math.floor'd. Matches the task.maxConcurrency schema's "0" → "Unlimited" UI label (src/config/settings-schema.ts:3816) and the runEvalConcurrency 0 = unbounded contract (src/eval/concurrency-bridge.ts:31-33).

nitMath.trunc would mirror runEvalConcurrency exactly; Math.floor only differs for negatives, which already fall through to Infinity here, so the runtime behaviour is identical. Not worth changing on its own.

Also note: there's a parallel PR #3307 (by @roboomp) targeting the same constructor with the same Infinity-on-non-positive shape. Functionally equivalent — maintainer's call which lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Agent runtime planning and orchestration fix review:p1 tool Tool behavior and integrations triaged vouched Passed the vouch gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

task.maxConcurrency 0 serializes subagents

2 participants