fix(tools): support positional-only parameters in beta_tool - #1912
Open
azrabano23 wants to merge 1 commit into
Open
fix(tools): support positional-only parameters in beta_tool#1912azrabano23 wants to merge 1 commit into
azrabano23 wants to merge 1 commit into
Conversation
`@beta_tool` / `@beta_async_tool` on a function with positional-only
parameters (`def f(a: int, /, b: str)`) produced an `input_schema` of
`type: "array"` and a tool whose `.call()` always failed. pydantic's
`GenerateJsonSchema.arguments_schema` renders the positional (array) form
whenever a signature has positional-only parameters or `*args` and no
keyword-only ones, so the docstring hook in `kw_arguments_schema` was never
reached, and `call()` forwarded the input purely by keyword, which a
positional-only parameter cannot accept. `InputSchema` requires
`type: "object"`, so the generated schema was invalid for the API as well.
Tool inputs are JSON objects passed by name, so:
- `arguments_schema` is overridden to render positional-only parameters as
ordinary named properties, giving the same object schema as a
keyword-capable signature;
- `call()` routes positional-only values back into positional slots via
`_split_input`, leaving missing or unexpected values to `validate_call`
so the existing `ValueError("Invalid arguments ...")` path is unchanged;
- `*args`, which a JSON object cannot represent, now raises a `TypeError`
at decoration time instead of silently producing an array schema.
Fixes anthropics#1911
Signed-off-by: Azra Bano <azrabano.work@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
What was wrong
@beta_tool/@beta_async_toolon a function with a positional-only parameter produced an invalid schema and an uncallable tool, without any error at decoration time:def collect(*values: int)produced{"items": {"type": "integer"}, "type": "array"}the same way.InputSchemarequirestype: "object", so both schemas are rejected by the API, and the positional-only tool could never be invoked by the tool runner even with a hand-writteninput_schema=.Root cause
_create_schema_from_functiondelegates to pydantic'sGenerateJsonSchema.arguments_schema, which renders the positional (array) form whenever a signature has positional-only parameters or*argsand no keyword-only ones, so the docstring hook inkw_arguments_schemanever runs for those signatures.call()then forwards the input object purely by keyword, which a positional-only parameter cannot accept.The fix
Tool inputs are JSON objects passed by name, so:
CustomGenerateJsonSchema.arguments_schemais overridden to render positional-only parameters as ordinary named properties. The schema forlookupabove is now identical to the one fordef lookup(user_id: int, field: str = "name").BetaFunctionTool.call/BetaAsyncFunctionTool.callroute positional-only values back into positional slots (_split_input). Missing or unexpected values are still left tovalidate_call, so the existingValueError("Invalid arguments for function ...")behaviour is unchanged.*args, which a JSON object cannot represent, now raises aTypeErrorat decoration time. This is the one behavioural change for existing code: such a tool previously constructed successfully but carried an array schema the API cannot accept.signature()failures (builtins, some callables) fall back to the previous behaviour, and the lazily-entered@asynccontextmanagerpath is unaffected since its wrapper only takes**kwargs.Verification
CPU only, no API calls. From the repo root with a
uv venv(Python 3.12, pydantic 2.13.5):The four new tests (
test_positional_only_parameters,test_positional_only_with_keyword_only_parameters,test_async_positional_only_parameters,test_var_positional_parameter_raises) fail onmainand pass with this change.Fixes #1911
🤖 Generated with Claude Code