fix(core): reject fixed-length tuple annotations for variadic tool arguments - #4735
Merged
seratch merged 1 commit intoAug 28, 2026
Conversation
There was a problem hiding this comment.
💡 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".
subhashpolisetti
force-pushed
the
fix/reject-fixed-length-tuple-variadics
branch
from
August 28, 2026 07:24
2282250 to
e92b299
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
A variadic parameter annotated with a fixed-length tuple silently loses every element constraint.
function_schema()maps that annotation tolist[Any]:So
def f(*args: tuple[int, str])produces{"args": {"items": {}, "title": "Args", "type": "array"}}. The emptyitemsschema 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:
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 whetherget_args()is non-empty. That distinction also keeps the behavior stable across the supported interpreters, becauseget_args(Tuple[()])is((),)on 3.10 and()on 3.12 while__args__is present on both. Unparameterizedtupleand baretyping.Tupleare 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 raisesUserErrorat construction rather than producing a schema that cannot describe the call.Test plan
test_var_positional_fixed_length_tuple_annotation_is_rejectedis parametrized overtuple[int, str],tuple[int], andtuple[()], and asserts the message names both supported alternatives. Baretyping.Tuplealso 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_buildis parametrized overtuple[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.pyand rerunning:DID NOT RAISE <class 'agents.exceptions.UserError'>, with the supported-annotations test still passing..agents/skills/code-change-verification/scripts/run.shpasses 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
.agents/skills/code-change-verification/scripts/run.sh/reviewbefore submitting this PR