Simplify tool execution and hook APIs#2132
Open
gold-silver-copper wants to merge 14 commits into
Open
Conversation
This was referenced Jul 13, 2026
deb0d39 to
788e4ef
Compare
* preserve typed tool errors at dispatch * fix streaming tool commit event ordering
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.
Description
Closes #2126 by replacing Rig's parallel tool execution, metadata, result, dynamic-dispatch, and hook-control APIs with one canonical structured path:
Tool::call(&mut ToolContext, Args) -> Result<Output, ToolExecutionError>→ private erased dispatch →ToolResult→ hooks, telemetry, and provider presentation.This is intentionally a one-step breaking replacement. No compatibility aliases, forwarding wrappers, or second dispatch hierarchy remain.
Root concerns addressed
callmethod.ToolSet::executeandToolServerHandle::executeare the public dispatch surfaces, object-safe erasure is crate-private, and runtime-defined tools useDynamicTool.ToolContextcarries typed inbound values and host-only result metadata. Dispatch snapshots inbound context once, isolates tool-local mutation, clears stale result metadata, and publishes only metadata from the current execution.ToolExecutionErrorcarries normalized kind, detailed diagnostics, retryability, code, HTTP status, refusal disposition, and a downcastable concrete source. Detailed diagnostics are model-visible by default so models can self-correct; sensitive tools can explicitly callredact_model_feedback,with_model_feedback, orwith_model_output.ToolOutputis the canonical ordered container ofToolResultContentblocks. Ordinary Rust strings remain literal text, explicitserde_json::Valueremains JSON even when it is a JSON string, and directly authored rich blocks retain their type and order. Rig never reparses ordinary strings to guess structured or multimodal content.ToolResultkeeps success, execution failure, intentional refusal, and framework skip distinct through a private mutually exclusive disposition, without creating another author-facing outcome hierarchy.CompletionCallAction,ToolCallAction,ToolResultAction,InvalidToolCallAction, orObservationAction, making unsupported event/action combinations unrepresentable. Completion patches merge, rewrites chain through nested stacks, and terminal actions short-circuit with consistent streaming/non-streaming behavior.active_toolsfilters definitions and executable handles together.ToolFunction.argumentsis canonical JSON, including strings, scalars, and arrays, across normal dispatch, invalid-call repair, output-tool finalization, and streaming eviction/EOF paths.ToolContext.#[rig_tool]automatically recognizes fully qualifiedrig::tool::ToolContextandrig_core::tool::ToolContext. Imported aliases use#[rig(context)], while an unrelated user type merely namedToolContextremains an ordinary model argument. The one mutable runtime context is forwarded and excluded from generated arguments/schema.Breaking migration
Tool::call*methods and associatedtype ErrorTool::call(&mut ToolContext, Args) -> Result<Output, ToolExecutionError>ToolDynand public erasure rolesDynamicToolToolError,ToolFailure, and parallel failure typesToolExecutionError/ToolErrorKindToolReturn,ToolExecutionResult, and parallel outcome enumsResultplus hook-facingToolResultToolCallExtensions/ToolResultExtensionsToolContextToolSet::call*/ToolServerHandle::call_tool*executeFlow/StepEventcontrolAgentBuilder::tools(Vec<Box<dyn ToolDyn>>).tool(...)calls for typed tools, ordynamic_tools(Vec<DynamicTool>)for runtime-defined callbacksdynamic_toolsretrieved_toolsToolSetBuilder::dynamic_tool(ToolEmbeddingDyn)retrieved_tool(ToolEmbedding); runtime-defined callbacks usedynamic_tool(DynamicTool)Behavioral invariants covered
Regression hardening
ToolContextparameters.Verification
cargo fmt --all -- --checkgit diff --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test— passed across the default workspace suite and provider replay targetscargo test -p rig-core --all-features --lib— 1,348 passed, 8 ignoredcargo test -p rig-derive --tests— passed, includingToolContexttrybuild and runtime coveragecargo check -p rig-core --lib --target wasm32-unknown-unknown --features wasmcargo doc --workspace --no-depscargo nextest run --all-features --retries 2— 1,121 passed, 220 skippedType of change