Repository navigation
Collect tool worker context failures without hanging - #1329
Conversation
Context setup can fail before a worker publishes a result, leaving the caller waiting forever. Capture the workflow and subscriber wrappers with tool execution, and publish only after cleanup succeeds. Keep the execution value independent of subscriber return values. Retain already started workers when a later launch fails so cleanup can still join or wait for them. Keep cancellation and interrupts on the existing error path. List the captured value's initial nil as an equivalent mutant: every context wrapper yields, so the block always replaces it. Fixes crmne#1325
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Worker execution and result capture lib/ruby_llm/chat/tool_concurrency.rb, spec/ruby_llm/chat/tool_concurrency_spec.rb, .mutineer.yml |
Thread and fiber workers pass captured contexts to capture_result, which applies workflow and instrumentation scopes around tool execution. Specifications cover context setup and teardown failures, callback and workflow errors, empty inputs, and Rails executor failures. The mutant ignore list includes an entry for ToolConcurrency.capture_result. |
Worker startup and completion spec/ruby_llm/chat/tool_concurrency_spec.rb |
Specifications cover cleanup of workers started before a later startup failure, Async task stops, and thread interrupts. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix · Severity of issue fixed: Medium
Possibly related issues
- [BUG] Stopping an Async task leaves its fiber tool calls running #1324: The specifications cover
Async::Stopduring fiber execution, which is also the issue’s stated scenario.
Possibly related PRs
- crmne/ruby_llm#1300: This PR preserves workflow context during concurrent tool execution, which relates to the workflow context recorded by PR
#1300.
Suggested labels: bug
Suggested reviewers: crmne
Merge Risk: 
Minimal · up to 1b701
-
No specific issue in the changed worker behavior remains identified as a reason to delay merging. Normal validation is still appropriate.
Pre-merge checks: 
6 · 
1
-
Failed checks: 1 warning Passed checks: 6 passed-
Full details: Title check
-
Explanation
The title names the main change: tool worker context failures are now reported as results instead of leaving the collector waiting forever. It matches the linked issue
#1325and the description. It is specific and short, with 7 words and 52 characters.
Full details: Description check
-
Explanation
The description covers the problem, the fix, and the new specs. It fills in the Bug fix type, the Scope check, the related issue (Fixes
#1325), the test run results, and the API changes section. The Quality check item for VCR cassettes is unchecked. It is not required here because the change does not touch providers. The Ownership section is checked. The template's 'What this does' section is detailed and explains the why. The description follows the template structure closely.
Full details: Linked Issues check
-
Explanation
Issue
#1325requires each worker to report wrapper setup and teardown failures, avoid collector hangs, and wait for workers that started before a later launch failure.capture_resultnow encloses workflow and context wrappers in the existingrescue Exceptionboundary. It constructs success only after both wrappers return. Thread and fiber workers push one captured result, and the incremental worker lists support the existingensurejoins and waits. The added specs cover setup, teardown, workflow, callback, tool, launch, thread, fiber, reactor,Async::Stop, andInterruptpaths.
Full details: Out of Scope Changes check
-
Explanation
The changes stay within Issue
#1325. The source change fixes worker result publication and cleanup. The added specifications verify the required concurrency behavior and related error guards. The.mutineer.ymlentry supports mutation-test coverage for the changed implementation.
Full details: Review Evidence Stays Out Of The Repository
-
Explanation
The pull request changes only
.mutineer.yml,lib/ruby_llm/chat/tool_concurrency.rb, andspec/ruby_llm/chat/tool_concurrency_spec.rb. These are configuration, implementation, and automated test files. It adds no screenshots, recordings, comparison pages, or other review-evidence files.
Full details: Dependencies From Sources The Maintainer Controls
-
Explanation
The pull request changes only
.mutineer.yml,lib/ruby_llm/chat/tool_concurrency.rb, and its spec. It does not change a manifest, lockfile, or package-manager configuration, and added lines contain no dependency source, git URL, fork, patch, override, replace, or alternate registry entry.
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 5 functions across 2 files. (1 skipped: 1 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
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.
Comment @coderabbitai help to get the list of available commands.
What this does
ToolConcurrencywaits for one result per tool call, but each worker entered the workflow and subscriber context wrappers outside the rescue incapture_result. When a wrapper raised, the worker ended without a result and the caller waited forever. A wrapper failing on the way out could also follow a success that was already reported.capture_resultnow runs both wrappers inside its rescue and builds the success only after they return, so every worker publishes exactly one result, and a teardown failure becomes that worker's error. The tool's value is captured in the block, so a subscriber's return value never replaces it. Workers are recorded as they start, so when a laterThread.newortask.asyncraises, the existingensurestill joins or waits for the ones already running.The
rescue Exceptionstays as it is:Async::StopandInterruptstill reach the caller as errors and never as successful results. No thread is interrupted from outside.The new examples cover:
run!andcomplete!failures propagate.Async::StopandInterruptnever become successful results.Type of change
Scope check
Related issue
Fixes #1325
Quality check
overcommit --installand all hooks passbundle exec rake vcr:record[provider_name]bundle exec rspec --tag '~live' --tag '~generator'(6046 examples; the only 2 failures, inspec/ruby_llm/sandbox/mxc_spec.rb, fail the same way onmainon macOS)models.json,aliases.json)Ownership
API changes
Summary by CodeRabbit