Skip to content

fix(agent_tool_input): summarize Pydantic Optional[T] anyOf fields#3265

Draft
adityasingh2400 wants to merge 2 commits into
openai:mainfrom
adityasingh2400:fix/ati-audit
Draft

fix(agent_tool_input): summarize Pydantic Optional[T] anyOf fields#3265
adityasingh2400 wants to merge 2 commits into
openai:mainfrom
adityasingh2400:fix/ati-audit

Conversation

@adityasingh2400
Copy link
Copy Markdown
Contributor

Summary

  • The schema summary helper rejected any field with an anyOf key, but Pydantic renders T | None as anyOf: [{type: T}, {type: "null"}]. Because _summarize_json_schema returns None for the whole schema when any single field is unsupported, one Optional[T] field would silently suppress the entire structured-input summary, including sibling fields with valid types and descriptions.
  • Detect the 2-branch anyOf of a simple type plus null and render it as T | null, matching the existing type: ["T", "null"] path.
  • Other anyOf shapes (unions of two non-null types, anyOf with nested objects, etc.) are still rejected.

Repro

from pydantic import BaseModel, TypeAdapter
from agents.agent_tool_input import build_structured_input_schema_info

class Args(BaseModel):
    count: int | None = None  # Pydantic emits anyOf: [{type:integer},{type:null}]
    name: str  # has a description in the rendered schema

schema = TypeAdapter(Args).json_schema()
# add descriptions for the demo
schema["properties"]["count"]["description"] = "Optional count."
schema["properties"]["name"]["description"] = "A name."

print(build_structured_input_schema_info(schema, include_json_schema=False).summary)
# Before: None  (entire summary dropped)
# After:
#   - count (integer | null, optional) - Optional count.
#   - name (string, required) - A name.

Test plan

  • New test test_schema_summary_handles_pydantic_optional_anyof covers the nullable anyOf shape and confirms non-nullable anyOf unions are still rejected.
  • Test fails on main (assert None is not None) and passes with the fix.
  • All existing tests/test_agent_tool_input.py, tests/test_agent_tool_state.py, and tests/test_agent_as_tool.py tests still pass (60/60).

The schema summary helper rejected any field with an `anyOf` key, but
Pydantic renders `T | None` as `anyOf: [{type: T}, {type: "null"}]`.
Because `_summarize_json_schema` returns None for the whole schema when
any single field is unsupported, one Optional field would silently
suppress the entire structured-input summary - even for sibling fields
with valid types and descriptions.

Detect the 2-branch `anyOf` of a simple type and `null` and render it
as `T | null`, matching the existing `type: ["T", "null"]` path.
Other `anyOf` shapes (unions of two non-null types, anyOf with nested
objects, etc.) are still rejected.
@github-actions github-actions Bot added bug Something isn't working feature:core labels May 8, 2026
@seratch
Copy link
Copy Markdown
Member

seratch commented May 8, 2026

@codex review

Copy link
Copy Markdown

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

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: d6ae9a108b

ℹ️ 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".

Comment thread src/agents/agent_tool_input.py Outdated
Comment on lines +272 to +274
if entry_type in _SIMPLE_JSON_SCHEMA_TYPES and base_type is None:
base_type = cast(str, entry_type)
continue
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 Preserve enum/const constraints in nullable anyOf

Pydantic emits Optional[Literal[...]] as anyOf with an enum/const branch that also has type: "string". This helper now accepts that branch as a bare simple type, so the schema summary says e.g. string | null instead of the allowed literals, misleading the nested agent about valid structured input.

Useful? React with 👍 / 👎.

@seratch seratch marked this pull request as draft May 8, 2026 17:49
Pydantic emits Optional[Literal[...]] as a 2-branch anyOf where one
branch carries both enum/const and type: 'string'. The previous fix
collapsed that to 'string | null', hiding the allowed values from the
nested-agent schema summary. Prefer the enum/const label when present.
@seratch seratch removed the bug Something isn't working label May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants