-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Describe the bug
When creating a new tool from function in python by client.tools.create_from_function
, server will parse sources if no args_schema
is provided. In this case, function type with Literal
is parsed in wrong format.
If args_schema
is provided by a pydantic model, the client slide convert it into json schema, but the server side ignore enum and some others in properties.
Please describe your setup
- How are you running Letta?
- Docker
- From source
- Describe your setup
- What's your OS (Windows/MacOS/Linux)? Linux
- What is your
docker run ...
command (if applicable)uv sync --all-packages --all-groups --all-extras; letta --port ... --debug
Example codes
The following function is function to create.
def custom_tool_for_test(foo: Literal['a', 'b']) -> str:
"""
Simulate the roll of a 20-sided die (d20).
This function generates a random integer between 1 and 20, inclusive,
which represents the outcome of a single roll of a d20.
Args:
foo: a value from given range.
Returns:
str: The result of the die roll.
"""
import random
dice_role_outcome = random.randint(1, 20)
output_string = f"You rolled a {dice_role_outcome}"
return output_string
And the generate schema is
{
"name": "custom_tool_for_test",
"description": "Simulate the roll of a 20-sided die (d20).\n\nThis function generates a random integer between 1 and 20, inclusive,\n\nwhich represents the outcome of a single roll of a d20.",
"parameters": {
"type": "object",
"properties": {
"foo": {
"type": "string",
"enum": [
"('a', 'b')"
],
"description": "a value from given range."
}
},
"required": [
"foo"
]
}
}
The "enum" field should be ["a", "b"]
instead.
Issue trace
It is caused by _parse_type_annotation
in letta/functions/functions.py
called by derive_openai_json_schema
and Tool.refresh_source_code_and_json_schema
in letta/schemas/tool.py
.
_parse_type_annotation
handles ast.Name
only for ast.Subscript
, but it doesn't handle ast.Tuple
, which is parsed from `Literal["foo", "bar"].
It can fix by
elif isinstance(annotation_node.slice, ast.Tuple):
# Type like as Literal["foo", "bar"]
return [_parse_type_annotation(elt, imports_map) for elt in annotation_node.slice.elts]
However, the return type is checked generate_schema
, so the patch cannot work directly.
If args_schema
is passed, generate_model_from_args_json_schema
and generate_schema_from_args_schema_v2
are used. enum
and some others are omited in these functions during rebuilding schema.