fix(sdk): tell a tool its call id, and let a debounce callback see user input - #35
Merged
Merged
Conversation
`Agent.executeToolCall` captures `agentState` before it emits `tool_started`, and the reducer clears `executingToolCall` when a call completes. A tool that read `context.agentState.executingToolCall?.toolCallId` therefore always got `undefined`. Any tool that keys state on its own call id (for example, to point a later result back at an earlier one in the conversation) silently never did so. `ToolContext` now carries `toolCallId` explicitly, set from the call that is actually executed. Also export the `DebounceCallback`, `DebounceContext` and `DebounceDecision` types, so a preset can type its own `debounceCallback` without reaching into `src/`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012cebkT9kA2XbNtbdLM3HFt
`DebounceContext.messages` and `totalPending` read the mailbox alone. A user chat message is delivered through the user-chat plugin's dequeue, so a callback deciding to wait for a child agent's report could not see that the user had written, and held the message until its own timeout ran out. The context now carries `hasPendingInput`, the same check the agent already makes before calling the callback, and `waitForResponseDebounceCallback` processes immediately when it is set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012cebkT9kA2XbNtbdLM3HFt
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.
Problem
Agent.executeToolCallreadsagentStatebefore it emitstool_started, and thetool_completed/tool_failedreducers clearexecutingToolCall. So insideexecute,context.agentState.executingToolCallis alwaysundefined.A tool that needs its own call id cannot get it. In a production consumer, a snapshot tool used this id to anchor "only what changed since your last capture" results. The memo was never written, so every repeat capture re-sent the full page into the agent's context. The feature had been shipped for weeks and never ran.
Change
ToolContextis nowAgentContext & { toolCallId: ToolCallId }.executeToolCallsets it from the call it actually runs (after abeforeToolCallreplace, that is the replaced call).ToolContextis built in exactly one place, so this is additive for tools. Code that constructs aToolContextitself (tests) must add the field.DebounceCallback,DebounceContextandDebounceDecisiontypes from the package root, so a preset can type a customdebounceCallback.DebounceContextgainshasPendingInput.messages/totalPendingread the mailbox alone, but a user chat message arrives through the user-chat plugin's dequeue. A callback that waits for a child's report therefore could not see that the user had written, and held the message until its timeout. The agent already computed this flag before calling the callback; now it passes it on.waitForResponseDebounceCallbackprocesses immediately when the flag is set.Tests
agent-loop.integration.test.ts: two tool calls in one turn each see their own id, and a debounce callback sees a user message that is not in the mailbox. Both fail without theiragent.tsline.agent-config.test.ts:waitForResponseDebounceCallbackprocesses a pending non-mailbox input immediately.bun test packages/sdk/src: 1500 pass, 0 fail.bun run ts:buildandbun run lintare clean.I left out a test for the replace path: on
main, a replace that changes the id stalls the turn. #31 fixes that (keep the tool_use identity across a beforeToolCall replace).🤖 Generated with Claude Code
https://claude.ai/code/session_012cebkT9kA2XbNtbdLM3HFt