-
Notifications
You must be signed in to change notification settings - Fork 0
Structured Types in @tool Arguments
In addition to the basic primitive types supported in Archytas tools (dict
, list
, int
, float
, bool
, str
None
), more structured data types are supported in limited form. Currently supported structured types include:
dataclass
-
BaseModel
frompydantic
For example:
from archytas.tool_utils import tool
from dataclasses import dataclass, field
@dataclass
class A:
val1: int
val2: str = 'hello'
@dataclass
class B:
val3: list[int]
val4: dict[str, int] = field(default_factory=dict)
@dataclass
class C:
b: B
val5: bool
@tool
def some_tool(a: A, c: C) -> str:
"""
description of some tool
Args:
a (A): description of what `a` is for.
c (C): description of what `c` is for.
Returns:
(str): ...
"""
# implementation of tool ...
Or with pydantic models
from archytas.tool_utils import tool
from pydantic import BaseModel, Field
class A(BaseModel):
val1: int = Field(..., description="what is val1 for")
val2: str = Field(default='hello', description="what is val2 for")
class B(BaseModel):
val3: list[int] = Field(..., description="what is val3 for")
val4: dict[str, int] = Field(default_factory=dict, description="what is val4 for")
class C(BaseModel):
b: B = Field(..., description="what is b for")
val5: bool = Field(..., description="what is val5 for")
@tool
def some_tool(a: A, c: C) -> str:
"""
description of some tool
Args:
a (A): description of what `a` is for.
c (C): description of what `c` is for.
Returns:
(str): ...
"""
# implementation of tool ...
Once created, Archytas will generate an appropriate prompt explaining how the agent can construct the structured type by providing it in nested dictionary format. At runtime, when the agent calls a tool expecting a structured type, the agent generates the json string for the dictionary, which is then parsed and converted into an instance of the structured type for use in the tool function.
Dataclasses and pydantic models are both commonly used to represent structured data, so supporting both formats is a good initial start. There could be other structured types that would be valuable to support in the future, but this is a good starting point.
The prompt generated for the above tools would look something like this:
some_tool:
_input_: a json object with the following fields:
{
"a": Description of what `a` is for. a json object with the following fields:
{
"val1": (int).
"val2": (str, optional). Defaults to "hello".
}
"c": Description of what `c` is for. a json object with the following fields:
{
"b": a json object with the following fields:
{
"val3": (list[int]).
"val4": (dict[str, int], optional). Defaults to {}.
}
"val5": (bool)
}
}
_output_: None
- position-only arguments in tools. e.g.
@tool
def positional_only(a: int, b: B, /) -> tuple[int, B]:
"""
test tool that has positional only arguments
Args:
a (int): Description of the argument `a`
b (B): Description of the argument `b`
Returns:
tuple[int, B]: The arguments you gave me
"""
return a, b
- currently no support for fields to be unions of dataclasses/pydantic models:
@dataclass
class A: ...
@dataclass
class B: ...
@dataclass
class C:
aorb: A | B # not supported
other: int | list[int] # this is fine
this mostly comes down to not having a good method to describe to the agent how to construct one or the other of the structured types, and indicate which one. might just require some prompt engineering for the tool description though
- dataclasses don't typically support per-argument descriptions, but descriptions are supported via the dataclass.field metadata parameter:
@dataclass
class A:
a: type = field(metadata={"description": "description of this parameter"})