Repository navigation
fix(core): send execute progress at most every 100 ms - #60120
Conversation
There was a problem hiding this comment.
This looks sound. Progress updates are held to at most one per 100 ms with a trailing update. On failure or interruption the waiting rows are sent while holding the lock, and on success a waiting update is dropped when the new local scope closes. That is safe because the tool's execute type never asked for an outer Scope.
To check it, I ran the new and updated tool-execute tests against dev's source: they fail there and pass with this change. The nearby core suites pass (315 tests), 20 reruns of tool-execute.test.ts passed without a failure, and typecheck:tsc is clean. The tests use TestClock, so they don't depend on real timing.
Public API: unchanged (internal throttling of execute progress only).
There was a problem hiding this comment.
The new commit only adds an assertion that the result metadata still has the completed echo row now that the trailing progress update is dropped. tool-registry.test.ts passes (42 tests). The source is unchanged since my last review, so nothing new to raise.
Public API: unchanged.
Problem
The
executetool sends a progress update when each nested call starts and when it finishes. Every update carries all rows so far, including each call's input, and replaces the one before it. So a program with N nested calls sends 2N updates that keep getting bigger.From my local sessions: median 1 nested call per
execute, p99 16, max 922. The average row is 391 bytes. The 922-call run sent roughly 372 MB of progress (an estimate from the saved rows, not a measurement). Other tools only send progress once or twice per call, so onlyexecuteneeds this.Change
executenow sends at most one progress update per 100 ms, always with the latest rows. The rows themselves still update right away; only sending is held back.step.ts, interrupted tool fibers are awaited beforefailUnsettledTools, so this lands in time.Clock, so tests drive it withTestClock.I left out a Visual section: nothing changes on screen besides rows refreshing at most every 100 ms.
Two existing tests asserted every intermediate update, and their calls finish within 100 ms, so the trailing "completed" update is now dropped. I updated them: "executions share the prepared runtime..." in
tool-execute.test.ts(now onTestClockso it can't depend on timing) and "executes and reports progress for codemode tools..." intool-registry.test.ts.Out of scope
Progress that a nested tool sends itself through
context.progressstill goes straight through, unthrottled.Verification
From
packages/core:bun run typecheck: no type errorsbun run typecheck:tsc: passesbun run script/test.ts test/tool-execute.test.ts test/codemode test/session-runner.test.ts test/mcp.test.ts test/tool-registry.test.ts: 389 pass, 0 failbun run script/test.ts test/tool-execute.test.ts --rerun-each 30 --randomize: 270 pass, 0 failsrc/codemode/tool.tsfromdev, both new tests and the updated one intool-execute.test.tsfail. With only the fail/interrupt flush removed, the interrupt test fails.tool-shell.test.ts,shell-scan). They fail the same way locally withdev's source, so they're unrelated.From the repo root:
bun run checkpasses.