Add tool approval integration for Vercel AI adapter - #1
Closed
bendrucker wants to merge 21 commits into
Closed
Conversation
…f the original schema (pydantic#3758)
…chemaTransformer` (pydantic#3751) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
bendrucker
force-pushed
the
vercel-ai-tool-approval
branch
from
December 19, 2025 05:03
ab6ca8a to
099f07a
Compare
bendrucker
force-pushed
the
vercel-ai-tool-approval
branch
from
December 19, 2025 05:03
099f07a to
1160591
Compare
- Add test for from_request() with tool_approval parameter - Add test verifying approval chunks not emitted when tool_approval=False - Add test for deferred_tool_results fallback from instance field - Add test for denied_tool_ids with ToolUIPart (builtin tools) - Fix docs link to point to VercelAIAdapter.from_request - Reword Tool Approval section to clarify AI SDK UI vs AI Elements
- Make _extract_deferred_tool_results private and inline into from_request - Make _denied_tool_ids a private cached_property - Simplify approval values to True/False (per reviewer suggestion) - Add AI SDK v6 requirement note to documentation and docstrings - Update tests for new API and simplified return values
- Inline extract_deferred_tool_results logic into from_request() - Remove unit tests for private _extract_deferred_tool_results method - Remove unit tests for private _denied_tool_ids property - Update test_tool_output_denied_chunk_emission to use public interface
- Update test_tool_output_denied_chunk_emission to use from_request() with explicit type binding to test the full public interface - Remove test_from_request_with_tool_approval_enabled (now redundant) - Remove test_deferred_tool_results_fallback_from_instance (tested internal plumbing rather than observable behavior)
bendrucker
force-pushed
the
vercel-ai-tool-approval
branch
from
December 20, 2025 09:52
52dea3e to
676530b
Compare
bendrucker
force-pushed
the
vercel-ai-tool-approval
branch
from
December 20, 2025 11:03
2deeb25 to
9eebd80
Compare
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.
Adds tool approval integration for the Vercel AI adapter, enabling human-in-the-loop workflows with the AI SDK.
This PR builds on pydantic#3760 and implements the basic plumbing for tool approval. The integration is functional for emitting approval requests and parsing approval responses, but does not yet automatically wire up the full flow.
Changes
ToolApprovalRequestedandToolApprovalRespondedtypes to represent approval stateapprovalfield to allToolUIPartandDynamicToolUIPartvariantsToolApprovalRequestChunkwhen agent returnsDeferredToolRequestsdeferred_tool_resultsproperty onVercelAIAdapterto extract approval responses from incoming tool partsextract_deferred_tool_results()class method for parsing approvalsHow It Works
Approval Request (server → client):
requires_approval=TrueDeferredToolRequestsVercelAIEventStream.handle_run_result()emitstool-approval-requestchunkApproval Response (client → server):
approvalfield with{id, approved, reason?}SubmitMessageincludes tool parts with approval responsesVercelAIAdapter.deferred_tool_resultsextracts these intoDeferredToolResultsOpen Questions
1. Automatic vs Manual Integration
Currently, users must manually wire up the deferred tool results:
Question: Should
run_stream()automatically useself.deferred_tool_resultswhen not explicitly provided? This would make the integration seamless but less explicit.2. Approval ID Tracking
We generate a UUID for
approval_idinToolApprovalRequestChunk, but the AI SDK uses this ID to track the approval lifecycle. TheToolApprovalResponded.idfield should match the originalapproval_id.Question: Do we need to store/track these approval IDs to validate they match on response? Currently we don't validate this.
3. ToolOutputDeniedChunk
The
ToolOutputDeniedChunktype exists but isn't emitted anywhere. In Pydantic AI, denied tool results flow as regularToolReturnPartwith the denial message as content.Question: Should we emit
ToolOutputDeniedChunkwhen the deferred tool result is aToolDenied? This would require tracking which tool calls were denied through the agent run.4. Message History Handling
When continuing with deferred tool results, the message history needs to include the original messages. Currently the adapter's
messagesproperty processes all incoming messages, but:Question: Should tool parts with pending approvals (only
ToolApprovalRequested, notToolApprovalResponded) be filtered out or handled specially when building message history?Testing
ToolApprovalRequestChunkemission whenrequires_approval=Truetool is calledextract_deferred_tool_results()covering approved, denied, and no-approval casesReferences