Skip to content

[Fix] Tasks stall when interrupted subtasks resume - #1470

Open
zoomote[bot] wants to merge 1 commit into
mainfrom
fix/native-tool-call-parser-race-189jg1xq3yp5w
Open

[Fix] Tasks stall when interrupted subtasks resume#1470
zoomote[bot] wants to merge 1 commit into
mainfrom
fix/native-tool-call-parser-race-189jg1xq3yp5w

Conversation

@zoomote

@zoomote zoomote Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

​Created by Roomote. Follow up by mentioning @roomote, in the web UI, or in Discord.

What changed

  • Isolated native tool-call chunk and argument state by API request so late chunks from an abandoned task cannot contaminate the active task.
  • Kept provider completion events stream-local instead of relying on shared parser state.
  • Added a deterministic regression test that interleaves two index-0 tool streams and verifies that clearing, accumulating, and finalizing one scope cannot affect the other.

Why this change was made

An overlapping subtask E2E run combined a tool ID and name from one request with arguments from the next request, causing malformed tool execution and a 30-second timeout. The same commit passed on rerun, exposing a real production race behind the flaky timing.

Closes #1468.

Impact

Cancelling, abandoning, or draining one task no longer corrupts another task's streamed native tool call. Existing unscoped parser callers remain compatible, and provider tool completion timing is preserved.

@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review process

This PR was opened by an automated account. A human maintainer must verify the change intent, provenance, and validation before merging.

  1. Required CI checks pass.
  2. The workflow starts CodeRabbit automatically.
  3. For eligible human-authored PRs, CodeRabbit reviews and approves the latest commit.
  4. A human maintainer reviews and approves after CodeRabbit.

Current step: Ready for human maintainer review and approval.

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.33333% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/assistant-message/NativeToolCallParser.ts 84.44% 4 Missing and 3 partials ⚠️
src/core/task/Task.ts 33.33% 4 Missing ⚠️
src/api/providers/openrouter.ts 85.71% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@edelauna

Copy link
Copy Markdown
Contributor

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: 67187baa-ecb3-4845-af8d-ec2d1fe4f2e2

📥 Commits

Reviewing files that changed from the base of the PR and between dfed27d and dfd6f81.

📒 Files selected for processing (6)
  • src/api/providers/lm-studio.ts
  • src/api/providers/openrouter.ts
  • src/api/providers/qwen-code.ts
  • src/core/assistant-message/NativeToolCallParser.ts
  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
  • src/core/task/Task.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.

📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (9)
Check persistence and lifecycle invariants: awaited atomic writes, rollback or explicit partial-failure behavior, cross-window state consistency, stale listeners/watchers, cancellation, idempotency, and safe restart/resume without lost or d...

⚙️ CodeRabbit configuration file

Files:

  • src/core/task/Task.ts
Treat model, provider, MCP, path, command, and tool data as untrusted. Check approval and allowlist bypasses, injection and traversal risks, secrets/PII exposure in logs, abort and stream behavior, retries, provider compatibility, and enfor...

⚙️ CodeRabbit configuration file

Files:

  • src/api/providers/lm-studio.ts
  • src/api/providers/qwen-code.ts
  • src/api/providers/openrouter.ts
Require regression coverage at the lowest valid harness with behavior-focused assertions, including relevant negative, error, false/unset, and boundary cases. Check cleanup and deterministic async behavior and prefer shared typed test helpe...

⚙️ CodeRabbit configuration file

Files:

  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
Check strict typing and exhaustive behavior across normal, boundary, error, cancellation, retry, and compatibility paths. Verify promises and errors are handled, existing helpers are reused, and new code introduces no `any`, unjustified dou...

⚙️ CodeRabbit configuration file

Files:

  • src/api/providers/lm-studio.ts
  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
  • src/api/providers/qwen-code.ts
  • src/core/task/Task.ts
  • src/api/providers/openrouter.ts
  • src/core/assistant-message/NativeToolCallParser.ts
Verify extension/webview contracts, cancellation and error propagation, VS Code lifecycle correctness, and behavior under retries and partial failure. Check listeners, resources, and providers are disposed without stale state or duplicate w...

⚙️ CodeRabbit configuration file

Files:

  • src/api/providers/lm-studio.ts
  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
  • src/api/providers/qwen-code.ts
  • src/core/task/Task.ts
  • src/api/providers/openrouter.ts
  • src/core/assistant-message/NativeToolCallParser.ts
Act as an adversarial second-opinion reviewer. Verify PR claims against implementation, contracts, and tests. Trace changed inputs through normal, boundary, error, cancellation, retry, and default paths and their consumers. Seek plausible c...

⚙️ CodeRabbit configuration file

Files:

  • src/api/providers/lm-studio.ts
  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
  • src/api/providers/qwen-code.ts
  • src/core/task/Task.ts
  • src/api/providers/openrouter.ts
  • src/core/assistant-message/NativeToolCallParser.ts
Add focused tests for UI binding and save behavior, persistence or normalization, and the value returned by `getStateToPostToWebview()`, including true and false/unset cases when defaults could hide omissions.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
Fix lint violations in new TypeScript code instead of suppressing them.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • src/api/providers/lm-studio.ts
  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
  • src/api/providers/qwen-code.ts
  • src/core/task/Task.ts
  • src/api/providers/openrouter.ts
  • src/core/assistant-message/NativeToolCallParser.ts
After editing a file, run ESLint with pruning and zero warnings for that relative file, and confirm its suppression count did not increase.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • src/api/providers/lm-studio.ts
  • src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
  • src/api/providers/qwen-code.ts
  • src/core/task/Task.ts
  • src/api/providers/openrouter.ts
  • src/core/assistant-message/NativeToolCallParser.ts
🔇 Additional comments (6)
src/core/assistant-message/NativeToolCallParser.ts (1)

54-90: LGTM!

Also applies to: 114-127, 137-137, 189-197, 212-226, 235-245, 257-275, 318-320, 334-337

src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts (1)

297-355: LGTM!

src/core/task/Task.ts (1)

3002-3002: LGTM!

Also applies to: 3097-3105, 3122-3126, 3158-3161, 3181-3184, 3582-3589

src/api/providers/lm-studio.ts (1)

120-120: LGTM!

Also applies to: 145-147, 159-163

src/api/providers/openrouter.ts (1)

402-402: LGTM!

Also applies to: 493-495, 513-517

src/api/providers/qwen-code.ts (1)

244-244: LGTM!

Also applies to: 295-297, 309-313


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability of streamed tool calls across concurrent requests.
    • Ensured tool-call completion events are emitted correctly when streaming finishes.
    • Prevented interleaved tasks from sharing or corrupting tool-call state.
  • Tests

    • Added coverage confirming independent streaming tasks remain isolated.

Walkthrough

Changes

Native tool-call streaming

Layer / File(s) Summary
Scope parser state
src/core/assistant-message/NativeToolCallParser.ts, src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts
NativeToolCallParser now stores raw-chunk and streaming state per scope. Its cleanup and finalization methods use the matching scope. Tests interleave two scopes and verify separate parsed arguments.
Wire request-local task scopes
src/core/task/Task.ts
Task creates one parser scope per request and passes it through streaming, parsing, finalization, and cleanup operations.
Handle provider tool-call completion
src/api/providers/lm-studio.ts, src/api/providers/openrouter.ts, src/api/providers/qwen-code.ts
Providers track streamed tool-call IDs locally and emit tool_call_end events when the finish reason is tool_calls.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: 🔵 Low · up to dfd6f

The change isolates streamed tool-call state for normal tasks and prevents interrupted work from corrupting another task. A bounded residual risk remains for concurrent callers that omit the optional scope, which could still mix tool data; this is mergeable with explicit owner awareness and follow-up.

Suggested reviewers: edelauna

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the production symptom fixed by the changes: interrupted or resumed task streams no longer stall because native tool-call state is isolated.
Description check ✅ Passed The description explains the cause, implementation, regression test, linked issue, and impact. It does not include the template's detailed test procedure or completed checklist, but the core required …
Linked Issues check ✅ Passed The changes satisfy issue #1468. Parser state is scoped per request, Task uses the scope throughout streaming and cleanup, provider completion events are stream-local, an interleaving regression test …
Out of Scope Changes check ✅ Passed All changed files support issue #1468. The provider updates, parser scoping changes, Task integration, and regression test directly address cross-request native tool-call state corruption. No unrelate…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 6…
Regression Evidence ✅ Passed The changed parser concurrency behavior has focused unit coverage in NativeToolCallParser.spec.ts. The test creates two scopes, interleaves index-0 raw chunks, clears one scope, processes deltas, fi…
Trust And Persistence Invariants ✅ Passed PASS. The changed paths only isolate in-memory native tool-call state. Task.ts creates one parser scope per request and passes it to every raw-chunk, streaming, and finalization call. `NativeToolCal…
Full details: Description check

Explanation

The description explains the cause, implementation, regression test, linked issue, and impact. It does not include the template's detailed test procedure or completed checklist, but the core required information is present.

Full details: Linked Issues check

Explanation

The changes satisfy issue #1468. Parser state is scoped per request, Task uses the scope throughout streaming and cleanup, provider completion events are stream-local, an interleaving regression test was added, and default-scope compatibility is preserved.

Full details: Out of Scope Changes check

Explanation

All changed files support issue #1468. The provider updates, parser scoping changes, Task integration, and regression test directly address cross-request native tool-call state corruption. No unrelated code changes are evident.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 6 files.

Full details: Regression Evidence

Explanation

The changed parser concurrency behavior has focused unit coverage in NativeToolCallParser.spec.ts. The test creates two scopes, interleaves index-0 raw chunks, clears one scope, processes deltas, finalizes both scopes, and verifies separate IDs and nativeArgs. Existing provider tests cover tool_call_end emission for finish_reason: "tool_calls" in LM Studio, OpenRouter, and Qwen Code. The changed files contain no durable visible UI change, so no Playwright snapshot is required.

Full details: Trust And Persistence Invariants

Explanation

PASS. The changed paths only isolate in-memory native tool-call state. Task.ts creates one parser scope per request and passes it to every raw-chunk, streaming, and finalization call. NativeToolCallParser stores scope state in WeakMaps, and normal finalization deletes the raw tracker and empty streaming state. The LM Studio, OpenRouter, and Qwen handlers keep completion IDs in local Sets and clear them after emitting tool_call_end. No changed path writes persisted data, omits an await, changes approval or allowlist checks, executes new unvalidated input, exposes secrets or PII, or retains an external lifecycle resource.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/native-tool-call-parser-race-189jg1xq3yp5w

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/api/providers/lm-studio.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

src/api/providers/openrouter.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).

src/api/providers/qwen-code.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).

  • 3 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@edelauna
edelauna marked this pull request as ready for review September 1, 2026 00:29
@github-actions github-actions Bot added the awaiting-maintainer CodeRabbit approved; waiting for a human maintainer label Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-maintainer CodeRabbit approved; waiting for a human maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Overlapping task streams corrupt native tool-call parser state

2 participants