Skip to content

[Story 4.3] Serialize approval dialogs for parallel tools #377

@edelauna

Description

@edelauna

Part of #359 (Epic 4: Parallel Tool Execution).

Depends on: Story 4.2b (Core parallel dispatch).

Context

cline.ask() writes to clineMessages and waits for a response. If two parallel tools both call ask() concurrently, their writes interleave and produce broken UI state — the second approval prompt would overwrite the first before it's answered. This story adds a write-through promise chain to ask() so concurrent approval requests are serialized transparently.

Developer Notes

In src/core/task/Task.ts:

  • Add private approvalQueue = pLimit(1)p-limit is already in deps at ^6.2.0. Using pLimit(1) instead of a hand-rolled promise chain provides better error isolation — a rejected promise in a raw chain breaks the queue unless errors are explicitly caught, whereas p-limit handles this correctly.
  • Wrap ask() so concurrent calls serialize: return this.approvalQueue(() => actualAsk(...)).
  • Non-approval paths (auto-approved tools that never call ask()) are unaffected.
  • Abort drain behavior: When abortTask(true) fires while approvals are queued, pending approvals resolve with denial (not rejection) — producing valid tool_denied results. The queue settles cleanly with no unhandled rejections.

Files: src/core/task/Task.ts

Tests (extend src/core/assistant-message/__tests__/presentAssistantMessageParallel.spec.ts):

  • Two parallel tools both requiring approval: second prompt never appears before first resolves. Use controlled promises for ask() mock.
  • A third tool with auto-approval runs without waiting for the approval queue.
  • Abort drain: trigger abortTask(true) while two approvals are queued → both resolve with denial → userMessageContent has valid tool_denied results for both with no unhandled rejections.

Acceptance Criteria

  • No concurrent ask() calls produce overlapping UI state.
  • Sequential tool execution (flag off) is unaffected.
  • Abort during queued approvals produces valid results — no unhandled rejections, no missing tool_result entries.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions