Skip to content

feat(models): add provider-level strict tool schema default compatibility - #4504

Closed
sylvesterkaczmarek wants to merge 1 commit into
openai:mainfrom
sylvesterkaczmarek:fix/strict-tool-schema-defaults-provider
Closed

feat(models): add provider-level strict tool schema default compatibility#4504
sylvesterkaczmarek wants to merge 1 commit into
openai:mainfrom
sylvesterkaczmarek:fix/strict-tool-schema-defaults-provider

Conversation

@sylvesterkaczmarek

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #4390, #4426, and the provider-boundary guidance in #4459.

This adds an opt-in compatibility setting for Chat Completions providers that reject strict function-tool schemas containing JSON Schema default keywords:

provider = OpenAIProvider(
    openai_client=client,
    use_responses=False,
    strip_tool_schema_defaults=True,
)

The default remains False, so existing OpenAI and OpenAI-compatible requests are unchanged.

Why this shape

The earlier proposals changed ensure_strict_json_schema() globally or exposed an option only at that low-level helper. The feedback on #4459 was that, if an escape hatch is needed, it should live at the user-facing tool or provider boundary so an affected @function_tool workflow can opt in directly.

This revision therefore keeps strict-schema generation unchanged and performs compatibility normalization only on the converted Chat Completions request payload.

When enabled:

  • only strict function/handoff tool parameter schemas are normalized
  • default is removed from actual JSON Schema nodes, including nested objects, definitions, unions, arrays, and conditionals
  • annotation payloads that happen to contain a key named default are left alone
  • the caller-owned FunctionTool.params_json_schema is not mutated
  • response-format schemas and non-strict tools are unchanged

This PR does not claim to establish the root cause of the Azure behavior reported in #4390. It provides the narrow provider-level compatibility boundary discussed in #4459 without changing the direct OpenAI default.

Test plan

Added focused coverage in tests/models/test_tool_schema_default_compat.py that exercises the public path:

OpenAIProvider -> OpenAIChatCompletionsModel -> Agent -> Runner.run() -> recorded Chat Completions request.

The tests verify that:

  • defaults remain in the outgoing strict tool schema by default
  • strip_tool_schema_defaults=True removes them from the outgoing request
  • the original FunctionTool.params_json_schema remains unchanged
  • schema annotation data containing its own default key is preserved

Full repository verification is left to GitHub Actions.

Issue number

Related to #4390. Supersedes the implementation approach in #4426 for the compatibility use case.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 532290ea63

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"definitions",
"properties",
"patternProperties",
"dependentSchemas",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Traverse all schema-bearing legacy keywords

When a strict tool uses a Draft 7 schema with a schema-valued dependencies entry or additionalItems, this keyword table never descends into that subschema, so any nested default survives in the outgoing request and the compatibility option still fails against providers that reject defaults. The repository's existing schema walker in tool_output_trimmer.py already recognizes both shapes, including preserving property-name lists under dependencies; align or reuse that vocabulary here.

AGENTS.md reference: AGENTS.md:L92-L94

Useful? React with 👍 / 👎.

agent_registration: OpenAIAgentRegistrationConfig | dict[str, Any] | None = None,
responses_websocket_options: OpenAIResponsesWebSocketOptions | None = None,
buffer_streamed_tool_calls: bool = False,
strip_tool_schema_defaults: bool = False,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Forward the compatibility option through MultiProvider

When an application uses the default RunConfig resolver or constructs MultiProvider(openai_client=..., openai_use_responses=False), there is no corresponding openai_strip_tool_schema_defaults argument, so its internal OpenAIProvider always retains this new setting as False. Bare model names are always routed through that internal provider and cannot be redirected through provider_map, leaving affected OpenAI-compatible providers unable to use the compatibility mode without replacing the entire run-level provider; mirror the existing strict-validation and streamed-tool-call-buffering passthroughs in MultiProvider.

AGENTS.md reference: AGENTS.md:L165-L167

Useful? React with 👍 / 👎.

@seratch

seratch commented Aug 17, 2026

Copy link
Copy Markdown
Member

Thanks for following up and moving the proposed escape hatch to the provider boundary. However, this PR still does not include the default-isolated Azure reproduction requested in #4459. The reported strict versus non-strict comparison changes the entire schema mode, and the nested Decimal schema remains a confounding variable. Direct OpenAI requests accept the current schema, while callers can already post-process FunctionTool.params_json_schema for an affected tool.

This PR therefore adds a public provider option and a separate JSON Schema traversal without a demonstrated unmet need. I am going to close it for now. We can reconsider if this PR provides otherwise-identical with-default and without-default Azure requests, including the endpoint, API version, deployment, raw schemas, and complete responses.

@seratch seratch closed this Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Understood. I’ve left this closed and posted a default-isolated Azure Chat Completions probe on #4390 that keeps strict mode and the schema shape fixed and changes only the default keyword. It asks for the endpoint, API version, deployment, raw paired requests, and complete responses you requested here and in #4459. I’ll wait for that evidence before revisiting the provider-boundary API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants