-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Labels
questionFurther information is requestedFurther information is requested
Description
Initial Checks
- I confirm that I'm using the latest version of Pydantic AI
- I confirm that I searched for my issue in https://github.com/pydantic/pydantic-ai/issues before opening this issue
Description
I am building up tools for my agents from static configuration. Because I'd like to be able to use my tool functions without the agent context, I want to "curry" the configuration into the tool functions passed to the agent. E.g., the script below configures a tool function with two separate tool configurations to create two tools for the agent.
That script only works if I apply the following patch to pydantic_ai._function_schema.function_schema:
--- a/_function_schema.py
+++ b/_function_schema.py
@@ -99,7 +99,7 @@ def function_schema( # noqa: C901
errors: list[str] = []
try:
- sig = signature(function)
+ sig = signature(function, follow_wrapped=False)
except ValueError as e:
errors.append(str(e))
sig = signature(lambda: None)
:A similar patch to pydantic_ai._function_schema._is_ctx would also make it regular:
--- a/_function_schema.py
+++ b/_function_schema.py
@@ -244,7 +244,7 @@ def _takes_ctx(function: TargetFunc[P, R]) -> TypeIs[WithCtx[P, R]]:
`True` if the function takes a `RunContext` as first argument, `False` otherwise.
"""
try:
- sig = signature(function)
+ sig = signature(function, follow_wrapped=False)
except ValueError: # pragma: no cover
return False # pragma: no cover
try:
I believe that I should be able to pass through a functools.partial instance as a tool function, as long as I fix up any values which are needed.
Example Code
import functools
import importlib
import inspect
import math
import pydantic_ai
SYSTEM_PROMPT = """\
This is a test
"""
PI_MULTIPLES_CONFIG = {
"name": "pi_multiples",
"description": "Return multiples of math.pi",
"start_value": "math.pi",
}
E_MULTIPLES_CONFIG = {
"name": "e_multiples",
"description": "Return multiples of math.e",
"start_value": "math.e",
}
def multiples(n_multiples: int, tool_config: dict) -> list[float]:
"""Multiply a given value by a range of multiples
Params:
n_multiples: the number of multiples to return
"""
module_name, tool_name = tool_config["start_value"].rsplit(".", 1)
module = importlib.import_module(module_name)
start_value = getattr(module, tool_name)
print(f"Multiplying {start_value} by {n_multiples} multiples")
return [start_value * i for i in range(n_multiples)]
def agent_tool(tool_func, tool_config: dict):
curried_tool_func = functools.update_wrapper(
functools.partial(tool_func, tool_config=tool_config),
tool_func,
)
tool = pydantic_ai.Tool(
curried_tool_func,
takes_ctx=False,
name=tool_config["name"],
description=tool_config["description"],
)
json_schema = tool.function_schema.json_schema
del json_schema["properties"]["tool_config"]
return tool
def main():
configured_tool_specs = [
(multiples, PI_MULTIPLES_CONFIG),
(multiples, E_MULTIPLES_CONFIG),
]
configured_tools = [
agent_tool(tool_func, tool_config)
for (tool_func, tool_config) in configured_tool_specs
]
agent = pydantic_ai.Agent(
model='openai:gpt-4o',
instructions=SYSTEM_PROMPT,
tools=configured_tools,
)
result = agent.run_sync("Multiply pi times three?")
print(result.output)
result = agent.run_sync("Multiply e times four?")
if __name__ == "__main__":
main()Python, Pydantic AI & LLM client version
Python 3.13.5
pydantic_ai 0.7.0
LLM client None
Metadata
Metadata
Assignees
Labels
questionFurther information is requestedFurther information is requested