feat: add Human-in-the-Loop (HITL) deferred tool calls support#481
Closed
tchardonnens wants to merge 1 commit intomainfrom
Closed
feat: add Human-in-the-Loop (HITL) deferred tool calls support#481tchardonnens wants to merge 1 commit intomainfrom
tchardonnens wants to merge 1 commit intomainfrom
Conversation
Add DeferredToolCallsException and supporting classes to enable human confirmation flows in run_async and run_stream_async. When a tool is registered with requires_confirmation=True or the server returns a function call with confirmation_status="pending", run_async raises DeferredToolCallsException. The user catches it, calls .confirm() or .reject() on each deferred call, and passes the responses back to run_async to resume the conversation. Changes: - extra/exceptions.py: Add DeferralReason, DeferredToolCallEntry, DeferredToolCallConfirmation, DeferredToolCallRejection, DeferredToolCallsException with serialization support - extra/run/deferred.py: New module with helpers for processing deferred responses (client-side execution, server-side ToolCallConfirmation) - extra/run/context.py: Add requires_confirmation() method, _tool_configurations dict, requires_confirmation param on register_func() and register_mcp_client(), tool include/exclude filtering, FunctionResultEntry pass-through in _validate_run - client/conversations.py: Update run_async and run_stream_async to partition function calls into deferred vs executable, process DeferredToolCallResponse inputs, and pass tool_confirmations to append_async/append_stream_async Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2e1af21 to
87fdfa4
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.
Summary
DeferredToolCallsExceptionand supporting classes to enable human confirmation flows inrun_asyncandrun_stream_asyncrequires_confirmation=Trueor the server returns a function call withconfirmation_status="pending",run_asyncraisesDeferredToolCallsException.confirm()or.reject()on each deferred call, and passes the responses back torun_asyncto resume the conversationFiles changed
extra/exceptions.pyDeferralReason,DeferredToolCallEntry,DeferredToolCallConfirmation,DeferredToolCallRejection,DeferredToolCallsExceptionwith serializationextra/run/deferred.pyToolCallConfirmation)extra/run/context.pyrequires_confirmation(),_tool_configurations,requires_confirmationparam onregister_func()andregister_mcp_client(), tool include/exclude filtering,FunctionResultEntrypass-through in_validate_runclient/conversations.pyrun_asyncandrun_stream_asyncto partition function calls, processDeferredToolCallResponseinputs, passtool_confirmationstoappend_async/append_stream_asyncTest plan
Unit tests
src/mistralai/extra/tests/) — 0 regressionstest_otel_tracing.py(Python 3.14asyncio.get_event_loop()deprecation) — unrelated to this PRManual integration tests (all run against live API)
Client-side HITL (local functions with
requires_confirmation=True):register_func(get_weather, requires_confirmation=True)→DeferredToolCallsExceptionraised →.confirm()→ resumed → model responds with weather ✅.reject("User does not want weather info")→ model responds gracefully without weather ✅get_weather(requires confirmation) +get_time(auto-execute) →DeferredToolCallsExceptionwithexecuted_results=[get_time result]→ passexecuted_results + confirmations→ model responds with both weather and time ✅Server-side HITL (MCP connectors with
requires_confirmationinToolConfiguration):CustomConnector(connector_id='deepwiki', tool_configuration=ToolConfiguration(requires_confirmation=[...]))→function.callwithconfirmation_status=pending→ToolCallConfirmation(confirmation="allow")→ search results returned ✅DeferredToolCallsExceptionraised withreason=SERVER_SIDE_CONFIRMATION_REQUIRED→.confirm()→ resumed → model responds with wiki structure ✅CustomConnector(connector_id='notion', ...)→notion_notion-searchwithconfirmation_status=pending→ approved → Notion search results returned ✅DeferredToolCallsException→.confirm()→ Notion meeting notes returned ✅🤖 Generated with Claude Code