fix(agent): broadcast tool.result per call as it settles, not after the round - #117
Open
w0nche0l wants to merge 1 commit into
Open
fix(agent): broadcast tool.result per call as it settles, not after the round#117w0nche0l wants to merge 1 commit into
w0nche0l wants to merge 1 commit into
Conversation
…he round (DEV-1067) Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary, root cause, and test plan (AGENT-WRITTEN)
Fixes DEV-1067
Problem
When a model emits multiple tool calls in one turn,
executeToolRoundawaitedPromise.allSettledover the entire round before broadcasting anytool.result/tool.call_outputevents. With serial execution (maxConcurrency: 1), an early call could be finished for minutes while its chip in the chatroom still showed "Running...", and then every chip flipped to completed at once when the last call finished.Change
executeToolRoundnow attaches a settle-time finalizer to each tool-call promise (finalizeSettledRoundCall/finalizeRejectedRoundCall): thetool.result, legacytool_result, andtool.call_outputbroadcasts — andcomputeToolOutputForModel— run the moment that call settles.Promise.all, an ordered loop collects the pre-finalizedfunction_call_outputs in call order, so the follow-up request input and prompt-cache behavior are byte-identical.allSettledparallel kickoff, so no(N-1)×graceMsstagger is reintroduced.executeSingleToolCalloutcome union into a namedSingleToolCallOutcometype and added apushToolCallOutputEventhelper (the push was previously duplicated at four sites).Behavior notes
tool.call_outputevents on the wire are now emitted in settlement order (previously call order).tool.resultevents were already only meaningful per call. The model-facingfunction_call_outputarray order is unchanged.computeToolOutputForModel(toModelOutput) throws for one call,executeToolRoundstill rejects, as before; sibling calls' broadcasts now still fire first since they finalize independently.Tests
New
tests/unit/tool-round-settle-broadcast.test.ts:tool.result+tool.call_outputappear on the turn broadcaster while a slow sibling in the same round is still gated, and the follow-up request'sfunction_call_outputs stay in call order (slow first) despite settling second.Full suite: 103 files / 1219 tests pass; lint and typecheck clean.
Release
Changeset included (patch). Follow-up after release: bump
@openrouter/agentin openrouter-web (the existingpatches/@openrouter%2Fagent@0.10.0.patchthere will need re-basing onto the new version).Made with Cursor