Skip to content

Commit 7d6cef3

Browse files
authored
Add takes_ctx arg to Tool.from_schema (#2615)
1 parent 2f2c757 commit 7d6cef3

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

docs/tools.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ _(This example is complete, it can be run "as is")_
471471

472472
### Custom Tool Schema
473473

474-
If you have a function that lacks appropriate documentation (i.e. poorly named, no type information, poor docstring, use of \*args or \*\*kwargs and suchlike) then you can still turn it into a tool that can be effectively used by the agent with the [`Tool.from_schema`][pydantic_ai.Tool.from_schema] function. With this you provide the name, description and JSON schema for the function directly:
474+
If you have a function that lacks appropriate documentation (i.e. poorly named, no type information, poor docstring, use of \*args or \*\*kwargs and suchlike) then you can still turn it into a tool that can be effectively used by the agent with the [`Tool.from_schema`][pydantic_ai.Tool.from_schema] function. With this you provide the name, description, JSON schema, and whether the function takes a `RunContext` for the function directly:
475475

476476
```python
477477
from pydantic_ai import Agent, Tool
@@ -493,7 +493,8 @@ tool = Tool.from_schema(
493493
},
494494
'required': ['a', 'b'],
495495
'type': 'object',
496-
}
496+
},
497+
takes_ctx=False,
497498
)
498499

499500
test_model = TestModel()

pydantic_ai_slim/pydantic_ai/tools.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ def from_schema(
266266
name: str,
267267
description: str | None,
268268
json_schema: JsonSchemaValue,
269+
takes_ctx: bool = False,
269270
) -> Self:
270271
"""Creates a Pydantic tool from a function and a JSON schema.
271272
@@ -277,6 +278,8 @@ def from_schema(
277278
description: Used to tell the model how/when/why to use the tool.
278279
You can provide few-shot examples as a part of the description.
279280
json_schema: The schema for the function arguments
281+
takes_ctx: An optional boolean parameter indicating whether the function
282+
accepts the context object as an argument.
280283
281284
Returns:
282285
A Pydantic tool that calls the function
@@ -286,13 +289,13 @@ def from_schema(
286289
description=description,
287290
validator=SchemaValidator(schema=core_schema.any_schema()),
288291
json_schema=json_schema,
289-
takes_ctx=False,
292+
takes_ctx=takes_ctx,
290293
is_async=_utils.is_async_callable(function),
291294
)
292295

293296
return cls(
294297
function,
295-
takes_ctx=False,
298+
takes_ctx=takes_ctx,
296299
name=name,
297300
description=description,
298301
function_schema=function_schema,

tests/models/cassettes/test_model_names/test_known_model_names.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ interactions:
1212
uri: https://us.inference.heroku.com/available-models
1313
response:
1414
headers:
15-
connection:
16-
- keep-alive
1715
content-length:
1816
- '760'
1917
content-security-policy:

tests/test_tools.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,35 @@ def function(*args: Any, **kwargs: Any) -> str:
11501150
assert agent._function_toolset.tools['foobar'].max_retries == 0
11511151

11521152

1153+
def test_function_tool_from_schema_with_ctx():
1154+
def function(ctx: RunContext[str], *args: Any, **kwargs: Any) -> str:
1155+
assert len(args) == 0
1156+
assert set(kwargs) == {'one', 'two'}
1157+
return ctx.deps + 'I like being called like this'
1158+
1159+
json_schema = {
1160+
'type': 'object',
1161+
'additionalProperties': False,
1162+
'properties': {
1163+
'one': {'description': 'first argument', 'type': 'string'},
1164+
'two': {'description': 'second argument', 'type': 'object'},
1165+
},
1166+
'required': ['one', 'two'],
1167+
}
1168+
pydantic_tool = Tool[str].from_schema(
1169+
function, name='foobar', description='does foobar stuff', json_schema=json_schema, takes_ctx=True
1170+
)
1171+
1172+
assert pydantic_tool.takes_ctx is True
1173+
assert pydantic_tool.function_schema.takes_ctx is True
1174+
1175+
agent = Agent('test', tools=[pydantic_tool], retries=0, deps_type=str)
1176+
result = agent.run_sync('foobar', deps='Hello, ')
1177+
assert result.output == snapshot('{"foobar":"Hello, I like being called like this"}')
1178+
assert agent._function_toolset.tools['foobar'].takes_ctx is True
1179+
assert agent._function_toolset.tools['foobar'].max_retries == 0
1180+
1181+
11531182
def test_function_tool_inconsistent_with_schema():
11541183
def function(three: str, four: int) -> str:
11551184
return 'Coverage made me call this'

0 commit comments

Comments
 (0)