Ensure that input_guardrails can block model/tools from running #1622
+574
−28
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
main
branch it has been redone from scratch. It should close FileSearchTool runs despite InputGuardrailTripwireTriggered #889 and Input guardrail tripwire allows tool execution to continue after exception is raised #991or run in parallel.
task errors surface even if no model events are produced.
Motivation
concurrently (e.g., telemetry or advisory checks). Previously, all input guardrails ran in parallel with the first
model call, which meant tripwires could trigger after downstream actions had already started.
awaiting events that never arrive.
Key Changes
block_downstream_calls: bool = True
toInputGuardrail
.@input_guardrail
decorator withblock_downstream_calls
(defaultTrue
for safety/back-compat)._separate_blocking_guardrails(...)
: returns(blocking, non_blocking)
._get_model_response_only(...)
: obtains the model response without executing tools._execute_tools_from_model_response(...)
: runs tool execution/side effects from a model response.tripwire triggers, the run task exits and the stream consumer detects the error.
RunResultStreaming.input_guardrail_results
to avoid overwriting.RunResultStreaming.stream_events()
, wrapself._event_queue.get()
in a short timeout:item = await asyncio.wait_for(self._event_queue.get(), timeout=0.1)
TimeoutError
, loop continues and re-checks for stored exceptions and guardrail tripwires.forever. The timeout wakes the loop to:
_input_guardrail_queue
and raiseInputGuardrailTripwireTriggered
.consumer still yields events as they arrive.
Behavior
safest behavior.
call/tools.
responsiveness.
Tests
test_agent_runner_streamed.py::test_input_guardrail_tripwire_triggered_causes_exception_streamed previously hung; with
the timeout it surfaces the tripwire and exits as expected.
Files Touched