Skip to content

Commit 0f71092

Browse files
committed
Support tools to add parameter descriptions using typing.Annotated
1 parent 675ac47 commit 0f71092

File tree

3 files changed

+118
-9
lines changed

3 files changed

+118
-9
lines changed

coagent/agents/aswarm/util.py

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import inspect
2+
import typing
23
from datetime import datetime
34
from typing import Any
45

@@ -172,15 +173,34 @@ def greet(
172173
# Determine the default value
173174
default = param.default
174175

175-
# Check if the parameter has a Field with description
176-
if isinstance(param.default, FieldInfo):
177-
field = param.default
178-
fields[param_name] = (annotation, field)
179-
elif param.default != inspect.Parameter.empty:
180-
fields[param_name] = (annotation, param.default)
176+
# Determine the field information.
177+
if isinstance(default, FieldInfo):
178+
# The default value is already a Field.
179+
typ = annotation
180+
field = default
181+
elif default != inspect.Parameter.empty:
182+
# Normal default value
183+
if typing.get_origin(annotation) == typing.Annotated:
184+
# The parameter is annotated with metadata.
185+
typ, description = typing.get_args(annotation)[:2]
186+
field = Field(default=default, description=str(description))
187+
else:
188+
# No metadata, use Field without description.
189+
typ = annotation
190+
field = Field(default=default)
181191
else:
182-
# If no default value, use Field without default
183-
fields[param_name] = (annotation, Field(...))
192+
# No default value
193+
if typing.get_origin(annotation) == typing.Annotated:
194+
# The parameter is annotated with metadata.
195+
# Always treat the first metadata element as the description.
196+
typ, description = typing.get_args(annotation)[:2]
197+
field = Field(..., description=str(description))
198+
else:
199+
# No default value and no metadata, use Field without default.
200+
typ = annotation
201+
field = Field(...)
202+
203+
fields[param_name] = (typ, field)
184204

185205
# 3. Create the Pydantic model
186206
model_name = f"{func.__name__}"

tests/agents/test_util.py

+89
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
from typing import Annotated
2+
13
import pytest
24

35
from coagent.agents.util import chat
6+
from coagent.agents.aswarm.util import function_to_jsonschema
7+
from pydantic import Field
48

59

610
@pytest.mark.asyncio
@@ -25,3 +29,88 @@ async def test_chat_stream(mock_model_client):
2529
# Only one chunk.
2630
chunk = _chunk
2731
assert chunk and chunk.content == "hello"
32+
33+
34+
def test_function_to_jsonschema_normal():
35+
def func(a: int, b: str = "ok") -> None:
36+
"""This is a test function."""
37+
pass
38+
39+
schema = function_to_jsonschema(func)
40+
assert schema == {
41+
"function": {
42+
"description": "This is a test function.",
43+
"name": "func",
44+
"parameters": {
45+
"properties": {
46+
"a": {"title": "A", "type": "integer"},
47+
"b": {"default": "ok", "title": "B", "type": "string"},
48+
},
49+
"required": ["a"],
50+
"title": "func",
51+
"type": "object",
52+
},
53+
},
54+
"type": "function",
55+
}
56+
57+
58+
def test_function_to_jsonschema_annotated():
59+
def func(a: Annotated[int, "Param a"], b: Annotated[str, "Param b"] = "ok") -> None:
60+
"""This is a test function."""
61+
pass
62+
63+
schema = function_to_jsonschema(func)
64+
assert schema == {
65+
"function": {
66+
"description": "This is a test function.",
67+
"name": "func",
68+
"parameters": {
69+
"properties": {
70+
"a": {"description": "Param a", "title": "A", "type": "integer"},
71+
"b": {
72+
"default": "ok",
73+
"description": "Param b",
74+
"title": "B",
75+
"type": "string",
76+
},
77+
},
78+
"required": ["a"],
79+
"title": "func",
80+
"type": "object",
81+
},
82+
},
83+
"type": "function",
84+
}
85+
86+
87+
def test_function_to_jsonschema_pydantic_field():
88+
def func(
89+
a: int = Field(description="Param a"),
90+
b: str = Field(default="ok", description="Param b"),
91+
) -> None:
92+
"""This is a test function."""
93+
pass
94+
95+
schema = function_to_jsonschema(func)
96+
assert schema == {
97+
"function": {
98+
"description": "This is a test function.",
99+
"name": "func",
100+
"parameters": {
101+
"properties": {
102+
"a": {"description": "Param a", "title": "A", "type": "integer"},
103+
"b": {
104+
"default": "ok",
105+
"description": "Param b",
106+
"title": "B",
107+
"type": "string",
108+
},
109+
},
110+
"required": ["a"],
111+
"title": "func",
112+
"type": "object",
113+
},
114+
},
115+
"type": "function",
116+
}

uv.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)