Skip to content

Add Annotated[T, Field(...)] syntax for tool arguments (@function_tool)#2428

Open
georg-wolflein wants to merge 3 commits intoopenai:mainfrom
georg-wolflein:feat/annotated-field-schema
Open

Add Annotated[T, Field(...)] syntax for tool arguments (@function_tool)#2428
georg-wolflein wants to merge 3 commits intoopenai:mainfrom
georg-wolflein:feat/annotated-field-schema

Conversation

@georg-wolflein
Copy link
Contributor

Summary

This PR adds support for Annotated[T, Field(...)] on tool parameters in addition to the existing = Field(...) syntax. The original = Field(...) support was introduced in #1124.

Why add this variant?

  1. Pydantic supports it. Pydantic allows Field either as the default (x: int = Field(ge=1)) or inside Annotated (x: Annotated[int, Field(ge=1)]). Supporting both in function_schema keeps the SDK aligned with how users define constrained fields in Pydantic models.

  2. Parameter ordering in Python. A parameter like x: int = Field(..., ge=1) still has a default value as far as Python is concerned (the default is the Field(...) object). So you cannot put another parameter without a default after it — that would be a SyntaxError:

    # SyntaxError: parameter without default follows parameter with default
    @function_tool
    def bad(
        positive_number: int = Field(..., ge=1),
        another_arg: str,
    ) -> str:
        ...

    With Annotated, the constrained parameter has no default in the signature, so you can have multiple required arguments (some with Field constraints) in any order:

    @function_tool
    def good(
        positive_number: Annotated[int, Field(..., ge=1)],
        another_arg: str,
    ) -> str:
        ...

Examples

Required argument with constraints:

from typing import Annotated
from pydantic import Field
from agents import function_tool

@function_tool
def score_task(score: Annotated[int, Field(..., ge=0, le=100)]) -> str:
    return f"Score recorded: {score}"

Optional argument with default and constraints:

@function_tool
def search(
    query: str,
    limit: Annotated[int, Field(default=10, ge=1, le=100)] = 10,
) -> str:
    return f"Searching for {query} with limit {limit}"

Multiple required arguments where one has constraints (only possible without SyntaxError using Annotated):

@function_tool
def process(
    positive_number: Annotated[int, Field(..., ge=1)],
    another_arg: str,
) -> str:
    return f"{positive_number}: {another_arg}"

Implementation: we preserve per-parameter Annotated metadata in function_schema, detect FieldInfo in that metadata, and use it when building the Pydantic model and JSON schema so that constraints, defaults, and descriptions are applied the same way as for = Field(...).


Test plan

Documentation: the Pydantic Field feature for tool arguments was not documented before. As requested in the PR #1124 review, a new subsection "Constraining and describing arguments with Pydantic Field" in docs/tools.md now documents both forms (default-based = Field(...) and Annotated[T, Field(...)]) with example code for each.

The new unit tests mirror the existing tests for the = Field(...) format: required constraints (test_function_with_field_required_constraintstest_function_with_annotated_field_required_constraints), optional with default and constraints, string constraints (min/max length, pattern), and multiple parameters with mixed constraints. Each new test uses the same assertions (JSON schema shape, valid input round-trip, invalid input raises ValidationError) as its counterpart, so both syntaxes are covered consistently.


Checks

  • I've added new tests (if relevant)
  • I've added/updated the relevant documentation
  • I've run make lint and make format
  • I've made sure tests pass

…rameters

- Preserve per-parameter Annotated metadata and extract FieldInfo when building fields
- Add _extract_field_info_from_metadata() helper; use it in normal-parameter branch
- Merge annotated Field with docstring description and optional signature default
- Add tests for required/optional constraints, string constraints, and multiple params
Document both default-based and Annotated forms for constraining
and describing function-tool arguments (addresses review request
in PR openai#1124).
@github-actions github-actions bot added documentation Improvements or additions to documentation feature:core labels Feb 6, 2026

Tools let agents take actions: things like fetching data, running code, calling external APIs, and even using a computer. The SDK supports five categories:

- Hosted OpenAI tools: run alongside the model on OpenAI servers.
Copy link
Member

Choose a reason for hiding this comment

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

these may be fine, but can you apply these unrelated changes separately?


The code for the schema extraction lives in [`agents.function_schema`][].

### Constraining argument values
Copy link
Member

Choose a reason for hiding this comment

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

Having the document change in this PR requires us to immediately release a new version when merging it. Can you create a separate PR for doc chnages?

@haasonsaas
Copy link

I can’t push updates to the fork branch from here, so I opened split PRs instead per the review request to keep docs separate:

If you prefer updating this PR directly, the minimal change is to revert docs/tools.md back to main and keep only the src/ + tests/ changes here.

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

Labels

documentation Improvements or additions to documentation feature:core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants