feat: add on_tool_call_sealed hook for eager tool dispatch#3558
feat: add on_tool_call_sealed hook for eager tool dispatch#3558Oxygen56 wants to merge 2 commits into
Conversation
Add a new lifecycle hook to both RunHooksBase and AgentHooksBase that fires during streaming when a tool call's arguments are sealed and ready, before the full response is complete and before the tool is invoked. This provides a hook point for consumers to implement early tool preparation or eager dispatch without changing the SDK's execution flow. The default runner does not act on this hook - callers that do nothing with it see unchanged behavior. The hook is wired into run_single_turn_streamed at the point where ToolCallItem is created from a ResponseOutputItemDoneEvent. Refs: openai#3404 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8f480a434
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| This hook fires when the LLM has finished producing a tool call during streaming, before | ||
| the full response is complete and before the tool is invoked. It carries the sealed | ||
| ``ToolCallItem`` with ``call_id``, ``tool_name``, and ``arguments``. |
There was a problem hiding this comment.
Expose sealed arguments on the hook item
When a consumer implements this new hook and follows the documented contract, tool_call.arguments raises AttributeError: ToolCallItem currently only exposes call_id and tool_name, with arguments reachable only through the raw OpenAI item. Since the hook is specifically for eager dispatch after arguments are sealed, this makes the advertised API fail for normal streamed function-call hooks unless callers know to use tool_call.raw_item.arguments instead.
Useful? React with 👍 / 👎.
|
Thanks for picking this up, this is the read-only seam I wanted in #3404. Going through This is enough to build real eager dispatch on top. My reference impl (cloudthinker-ai/eager-tools) takes a sealed One thing to confirm: when several tool calls stream in one turn, does it fire once per call as each seals? The test covers the single-call case. A two-tool case asserting it fires twice with the right |
|
@bmd1905 Good catch — I've added The implementation already fires per-call via the |
Summary
Adds a new lifecycle hook
on_tool_call_sealedto bothRunHooksBaseandAgentHooksBasethat fires during streaming when a tool call's arguments are sealed and ready, before the full response is complete and before the tool is invoked.This provides a hook point for consumers to implement early tool preparation or eager dispatch without changing the SDK's execution flow. The default runner does not act on this hook — callers that do nothing with it see unchanged behavior.
Refs #3404
Changes
on_tool_call_sealedmethod toRunHooksBaseandAgentHooksBaserun_single_turn_streamedat the point whereToolCallItemis created from aResponseOutputItemDoneEventtest_streamed_run_hooks_tool_call_sealedtest that verifies the hook fires with the correct tool name and call_id during streamingTest plan
make format— passedmake lint— passedmake tests— all 44 relevant tests passtest_streamed_run_hooks_tool_call_sealedpassesCloses #3404