feat: expose output_schema in ModelInputData for call_model_input_filter#3571
feat: expose output_schema in ModelInputData for call_model_input_filter#3571jordanchendev wants to merge 2 commits into
Conversation
Add an optional `output_schema` field to `ModelInputData` so that `call_model_input_filter` callbacks can inspect and override the response format used for a given model call. When the filter returns `output_schema=None` (or omits it), the runner falls back to the schema derived from `agent.output_type`, preserving backward compatibility. Both the streaming (`run_single_turn_streamed`) and non-streaming (`get_new_response`) paths honour the override. `ToolOutputTrimmer` is updated to forward `output_schema` unchanged so it is not silently dropped by that built-in filter. Fixes openai#3563
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57df396a73
ℹ️ 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".
| system_instructions=system_prompt, | ||
| output_schema=output_schema, | ||
| ) | ||
| output_schema = filtered.output_schema if filtered.output_schema is not None else output_schema |
There was a problem hiding this comment.
Propagate overridden schema to final-output parsing
In non-streamed runs, this reassignment only changes the local output_schema inside get_new_response; after it returns, run_single_turn still passes the original schema to get_single_step_result_from_response. When a call_model_input_filter sets a structured schema for an agent without output_type, the model request uses the override, but the final response is processed with None, so Runner.run returns the raw JSON string instead of validating/parsing it with the override. The streamed path keeps the updated schema in the same function, so this regression is specific to non-streamed runs.
Useful? React with 👍 / 👎.
…e parsing get_new_response now returns (ModelResponse, AgentOutputSchemaBase | None) so that run_single_turn can pass the filter-overridden schema to get_single_step_result_from_response. Previously the local reassignment inside get_new_response was invisible to the caller, causing non-streamed runs to parse the model response with the original (pre-filter) schema instead of the override. Fixes the regression identified in review on openai#3571.
jordanchendev
left a comment
There was a problem hiding this comment.
Good catch — fixed in e7e0bbb.
get_new_response now returns tuple[ModelResponse, AgentOutputSchemaBase | None] so the caller (run_single_turn) unpacks and forwards the effective schema to get_single_step_result_from_response. The existing non-streamed test was strengthened to assert result.final_output is a parsed _Reply instance (not a raw string), making the regression impossible to re-introduce silently.
Summary
Add an optional
output_schemafield toModelInputDataso thatcall_model_input_filtercallbacks can inspect and override the structured-output schema used for a given model call.Before:
ModelInputDataonly exposedinputandinstructions, making it impossible for a filter to change (or even read) the response format without reaching outside the callback.After: Filters receive the current
output_schema(derived fromagent.output_type) inmodel_data.output_schemaand may return a differentAgentOutputSchemaBaseinstance to override it for that call. ReturningNoneor omitting the field preserves the agent's schema unchanged, so existing filters are fully backward-compatible.Both the streaming (
run_single_turn_streamed) and non-streaming (get_new_response) paths honour the override.ToolOutputTrimmeris updated to forwardoutput_schemaso it is not silently dropped by that built-in filter.Test plan
Four new tests in
tests/test_call_model_input_filter.py:test_filter_can_override_output_schema_non_streamed— filter replaces schema; model receives the override.test_filter_can_override_output_schema_streamed— same for the streaming path.test_filter_receives_agent_output_schema— filter can observe the agent's schema before deciding.test_filter_not_setting_output_schema_preserves_agent_schema— omittingoutput_schemain the return value must not clear the agent's schema (backward-compat regression test).All existing tests continue to pass.
Issue number
Closes #3563
Checks
make lintandmake format