Skip to content

fix(core): reject fixed-length tuple annotations for variadic tool arguments - #4735

Merged
seratch merged 1 commit into
openai:mainfrom
subhashpolisetti:fix/reject-fixed-length-tuple-variadics
Aug 28, 2026
Merged

fix(core): reject fixed-length tuple annotations for variadic tool arguments#4735
seratch merged 1 commit into
openai:mainfrom
subhashpolisetti:fix/reject-fixed-length-tuple-variadics

Conversation

@subhashpolisetti

@subhashpolisetti subhashpolisetti commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

A variadic parameter annotated with a fixed-length tuple silently loses every element constraint. function_schema() maps that annotation to list[Any]:

args_of_tuple = get_args(ann)
if len(args_of_tuple) == 2 and args_of_tuple[1] is Ellipsis:
    ann = list[ann]  # type: ignore
else:
    ann = list[Any]  # tuple[int, str] lands here

So def f(*args: tuple[int, str]) produces {"args": {"items": {}, "title": "Args", "type": "array"}}. The empty items schema constrains nothing, so the model may send any JSON for each positional argument, validation accepts it, and the reconstructed call violates the annotation the author wrote. The neighbouring supported forms all keep their element types: *args: int, *args: list[int], and *args: tuple[int, ...] (the last one since #4655).

This change rejects the fixed-length form during tool construction and names the two supported alternatives in the error, which is the direction requested on #4696:

The narrower SDK behavior should be to reject fixed-length tuple annotations during tool construction and identify tuple[T, ...] or list[T] as the supported alternative. A focused follow-up PR implementing that fail-fast behavior would be welcome.

tuple[()] is included in the rejection: it parameterizes an empty tuple but reports no args, so the check tests whether the annotation is parameterized rather than whether get_args() is non-empty. That distinction also keeps the behavior stable across the supported interpreters, because get_args(Tuple[()]) is ((),) on 3.10 and () on 3.12 while __args__ is present on both. Unparameterized tuple and bare typing.Tuple are unchanged, since they carry no element type to preserve or reject. This is a behavior change for callers who previously built such a tool: the annotation used to be accepted and silently widened, and now raises UserError at construction rather than producing a schema that cannot describe the call.

Test plan

test_var_positional_fixed_length_tuple_annotation_is_rejected is parametrized over tuple[int, str], tuple[int], and tuple[()], and asserts the message names both supported alternatives. Bare typing.Tuple also reports no args but must keep building, so it is covered by the condition rather than by a test: ruff bans that annotation in this repository, and writing the test required contortions that were worse than the coverage they bought. test_var_positional_supported_annotations_still_build is parametrized over tuple[T, ...], list[T], and a plain scalar so the alternatives named in the error keep working.

Verified the rejection test fails without the source change by stashing src/agents/function_schema.py and rerunning: DID NOT RAISE <class 'agents.exceptions.UserError'>, with the supported-annotations test still passing.

.agents/skills/code-change-verification/scripts/run.sh passes end to end: format, lint, typecheck and the full suite. The complete suite is 9362 passed, 32 skipped, so nothing in the repository depended on the previously accepted annotation.

Issue number

None. Requested by a maintainer on #4696.

Checks

  • I've added new tests, if relevant
  • I've run .agents/skills/code-change-verification/scripts/run.sh
  • I've confirmed all verification steps pass
  • If using Codex, I've run /review before submitting this PR

@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: 2282250479

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

Comment thread src/agents/function_schema.py Outdated
@subhashpolisetti
subhashpolisetti force-pushed the fix/reject-fixed-length-tuple-variadics branch from 2282250 to e92b299 Compare August 28, 2026 07:24
@seratch seratch added this to the 0.22.x milestone Aug 28, 2026
@seratch
seratch merged commit 89c02c8 into openai:main Aug 28, 2026
18 checks passed
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