Skip to content

fix: compare inspect sentinels by identity in function_schema - #3961

Merged
seratch merged 2 commits into
openai:mainfrom
TheSaiEaranti:fix-sentinel-identity-comparison
Jul 27, 2026
Merged

fix: compare inspect sentinels by identity in function_schema#3961
seratch merged 2 commits into
openai:mainfrom
TheSaiEaranti:fix-sentinel-identity-comparison

Conversation

@TheSaiEaranti

Copy link
Copy Markdown
Contributor

Summary

function_schema compares parameter defaults (and annotations) to inspect._empty with ==/!=, which invokes the user-supplied value's __eq__. Two observable failures on valid Python functions:

  1. Crash at decoration time — a default with elementwise equality semantics (a numpy array is the canonical case) makes default != inspect._empty return an array, whose truthiness raises:

    @function_tool
    def score(x: int, weights: Any = np.array([1.0, 2.0])) -> int: ...
    # ValueError: The truth value of an array with more than one element is ambiguous.

    Verified with real numpy; the regression test uses a dependency-free stub with the same __eq__ shape.

  2. Silent contract violation — a default whose __eq__ answers True (mocks, sentinels, some DSL objects) satisfies default == inspect._empty, so the parameter is marked required in the schema and its default silently discarded.

The inspect module's documented convention is identity comparison (param.default is Parameter.empty); the sentinel is a unique object precisely so user values can never influence the check. This PR switches all five sentinel comparisons in the file to is/is not — the two default checks above (the observable bugs) and the three annotation checks, which carry the same latent hazard. Identity is behavior-preserving for every value without a pathological __eq__.

Test plan

  • Two regression tests with pure-Python stubs (no numpy dependency): an elementwise-__eq__ default must build a schema, stay optional, and round-trip through to_call_args; an always-True-__eq__ default must not be marked required. Both fail on main and pass with the fix.
  • make format, make lint, make typecheck, make tests all pass.

Issue number

None — found by reading function_schema.py (same pass that produced #3956).

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

function_schema compared parameter defaults and annotations to inspect._empty
with == and !=, invoking the user value's __eq__. A default with elementwise
equality, such as a numpy array, crashes schema creation at decoration time
("The truth value of an array with more than one element is ambiguous"), and
a default whose __eq__ answers True is mistaken for the no-default sentinel,
silently marking the parameter required and discarding the default.

Use identity checks for all five sentinel comparisons, per the inspect
module's documented convention (param.default is Parameter.empty). Python
identifiers cannot shadow the sentinel, so this is behavior-preserving for
every value without a pathological __eq__.
@seratch
seratch enabled auto-merge (squash) July 26, 2026 21:43
@seratch seratch added this to the 0.19.x milestone Jul 26, 2026

@seratch seratch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you run make typecheck and resolve the errors?

Running make mypy and make pyright in parallel...
make[1]: Entering directory '/home/runner/work/openai-agents-python/openai-agents-python'
uv run mypy . --exclude site
make[1]: Entering directory '/home/runner/work/openai-agents-python/openai-agents-python'
uv run pyright --project pyrightconfig.json
0 errors, 0 warnings, 0 informations
WARNING: there is a new pyright version available (v1.1.408 -> v1.1.411).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`

make[1]: Leaving directory '/home/runner/work/openai-agents-python/openai-agents-python'
tests/test_function_schema.py:1072: error: Return type "_ElementwiseEqual" of "__eq__" incompatible with return type "bool" in supertype "builtins.object"  [override]
tests/test_function_schema.py:1075: error: Return type "_ElementwiseEqual" of "__ne__" incompatible with return type "bool" in supertype "builtins.object"  [override]
Found 2 errors in 1 file (checked 832 source files)
make[1]: *** [Makefile:24: mypy] Error 1
make[1]: Leaving directory '/home/runner/work/openai-agents-python/openai-agents-python'
make: *** [Makefile:32: typecheck] Error 2

The elementwise-equality stub returned its own type from __eq__ and __ne__,
which mypy rejects as an incompatible override of object. Annotate the
return as Any, matching how numpy's stubs type elementwise comparison.
auto-merge was automatically disabled July 26, 2026 23:32

Head branch was pushed to by a user without write access

@TheSaiEaranti

Copy link
Copy Markdown
Contributor Author

Fixed in 3de52d1, which crossed with your review by a few minutes. The stub's __eq__/__ne__ now return Any (matching how numpy's own stubs type elementwise comparison), which resolves the override incompatibility. uv run mypy . --exclude site passes locally with the same 832-file count as CI, and lint and the test suite are green. The Tests run for the new head is waiting on workflow approval.

@seratch
seratch merged commit a335b32 into openai:main Jul 27, 2026
9 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