Skip to content

Commit 6201af4

Browse files
authored
fix agent name (#156)
1 parent ac7bf6d commit 6201af4

File tree

7 files changed

+197
-15
lines changed

7 files changed

+197
-15
lines changed

pydantic_ai_examples/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "pydantic-ai-examples"
7-
version = "0.0.10"
7+
version = "0.0.11"
88
description = "Examples of how to use PydanticAI and what it can do."
99
authors = [
1010
{ name = "Samuel Colvin", email = "[email protected]" },
@@ -34,7 +34,7 @@ classifiers = [
3434
]
3535
requires-python = ">=3.9"
3636
dependencies = [
37-
"pydantic-ai-slim[openai,vertexai,groq]==0.0.10",
37+
"pydantic-ai-slim[openai,vertexai,groq]==0.0.11",
3838
"asyncpg>=0.30.0",
3939
"fastapi>=0.115.4",
4040
"logfire[asyncpg,fastapi]>=2.3",

pydantic_ai_slim/pydantic_ai/agent.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,12 @@ async def run(
171171
deps = self._get_deps(deps)
172172

173173
with _logfire.span(
174-
'{agent.name} run {prompt=}',
174+
'{agent_name} run {prompt=}',
175175
prompt=user_prompt,
176176
agent=self,
177177
custom_model=custom_model,
178178
model_name=model_used.name(),
179+
agent_name=self.name or 'agent',
179180
) as run_span:
180181
new_message_index, messages = await self._prepare_messages(deps, user_prompt, message_history)
181182
self.last_run_messages = messages
@@ -277,11 +278,12 @@ async def run_stream(
277278
deps = self._get_deps(deps)
278279

279280
with _logfire.span(
280-
'{agent.name} run stream {prompt=}',
281+
'{agent_name} run stream {prompt=}',
281282
prompt=user_prompt,
282283
agent=self,
283284
custom_model=custom_model,
284285
model_name=model_used.name(),
286+
agent_name=self.name or 'agent',
285287
) as run_span:
286288
new_message_index, messages = await self._prepare_messages(deps, user_prompt, message_history)
287289
self.last_run_messages = messages
@@ -837,6 +839,12 @@ def _infer_name(self, function_frame: FrameType | None) -> None:
837839
if item is self:
838840
self.name = name
839841
return
842+
if parent_frame.f_locals != parent_frame.f_globals:
843+
# if we couldn't find the agent in locals and globals are a different dict, try globals
844+
for name, item in parent_frame.f_globals.items():
845+
if item is self:
846+
self.name = name
847+
return
840848

841849

842850
@dataclass

pydantic_ai_slim/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "pydantic-ai-slim"
7-
version = "0.0.10"
7+
version = "0.0.11"
88
description = "Agent Framework / shim to use Pydantic with LLMs, slim package"
99
authors = [
1010
{ name = "Samuel Colvin", email = "[email protected]" },

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "pydantic-ai"
7-
version = "0.0.10"
7+
version = "0.0.11"
88
description = "Agent Framework / shim to use Pydantic with LLMs"
99
authors = [
1010
{ name = "Samuel Colvin", email = "[email protected]" },
@@ -36,7 +36,7 @@ classifiers = [
3636
"Framework :: Pytest",
3737
]
3838
requires-python = ">=3.9"
39-
dependencies = ["pydantic-ai-slim[openai,vertexai,groq]==0.0.10"]
39+
dependencies = ["pydantic-ai-slim[openai,vertexai,groq]==0.0.11"]
4040

4141
[project.urls]
4242
Homepage = "https://ai.pydantic.dev"
@@ -45,7 +45,7 @@ Documentation = "https://ai.pydantic.dev"
4545
Changelog = "https://github.com/pydantic/pydantic-ai/releases"
4646

4747
[project.optional-dependencies]
48-
examples = ["pydantic-ai-examples==0.0.10"]
48+
examples = ["pydantic-ai-examples==0.0.11"]
4949
logfire = ["logfire>=2.3"]
5050

5151
[tool.uv.sources]

tests/test_agent.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,21 @@ async def test_agent_name_changes():
574574

575575
await new_agent.run('Hello')
576576
assert new_agent.name == 'my_agent'
577+
578+
579+
def test_name_from_global(set_event_loop: None, create_module: Callable[[str], Any]):
580+
module_code = """
581+
from pydantic_ai import Agent
582+
583+
my_agent = Agent('test')
584+
585+
def foo():
586+
result = my_agent.run_sync('Hello')
587+
return result.data
588+
"""
589+
590+
mod = create_module(module_code)
591+
592+
assert mod.my_agent.name is None
593+
assert mod.foo() == snapshot('success (no tool calls)')
594+
assert mod.my_agent.name == 'my_agent'

tests/test_logfire.py

Lines changed: 160 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,21 @@ def get_summary() -> LogfireSummary:
6060

6161
@pytest.mark.skipif(not logfire_installed, reason='logfire not installed')
6262
def test_logfire(get_logfire_summary: Callable[[], LogfireSummary], set_event_loop: None) -> None:
63-
agent = Agent(model=TestModel())
63+
my_agent = Agent(model=TestModel())
6464

65-
@agent.tool_plain
65+
@my_agent.tool_plain
6666
async def my_ret(x: int) -> str:
6767
return str(x + 1)
6868

69-
result = agent.run_sync('Hello')
69+
result = my_agent.run_sync('Hello')
7070
assert result.data == snapshot('{"my_ret":"1"}')
7171

7272
summary = get_logfire_summary()
7373
assert summary.traces == snapshot(
7474
[
7575
{
7676
'id': 0,
77-
'message': 'agent run prompt=Hello',
77+
'message': 'my_agent run prompt=Hello',
7878
'children': [
7979
{'id': 1, 'message': 'model request -> model-structured-response'},
8080
{
@@ -88,6 +88,162 @@ async def my_ret(x: int) -> str:
8888
}
8989
]
9090
)
91+
assert summary.attributes[0] == snapshot(
92+
{
93+
'code.filepath': 'agent.py',
94+
'code.function': 'run',
95+
'code.lineno': 123,
96+
'prompt': 'Hello',
97+
'agent': IsJson(
98+
{
99+
'model': {
100+
'call_tools': 'all',
101+
'custom_result_text': None,
102+
'custom_result_args': None,
103+
'seed': 0,
104+
'agent_model_tools': {
105+
'my_ret': {
106+
'function': IsStr(regex='<function test_logfire.<locals>.my_ret at 0x.+>'),
107+
'takes_ctx': False,
108+
'max_retries': 1,
109+
'name': 'my_ret',
110+
'description': '',
111+
'_is_async': True,
112+
'_single_arg_name': None,
113+
'_positional_fields': [],
114+
'_var_positional_field': None,
115+
'_json_schema': {
116+
'properties': {'x': {'title': 'X', 'type': 'integer'}},
117+
'required': ['x'],
118+
'type': 'object',
119+
'additionalProperties': False,
120+
},
121+
'_current_retry': 0,
122+
}
123+
},
124+
'agent_model_allow_text_result': True,
125+
'agent_model_result_tools': None,
126+
},
127+
'name': 'my_agent',
128+
'last_run_messages': None,
129+
}
130+
),
131+
'logfire.null_args': ('custom_model',),
132+
'model_name': 'test-model',
133+
'agent_name': 'my_agent',
134+
'logfire.msg_template': '{agent_name} run {prompt=}',
135+
'logfire.msg': 'my_agent run prompt=Hello',
136+
'logfire.span_type': 'span',
137+
'all_messages': IsJson(
138+
[
139+
{'content': 'Hello', 'timestamp': IsStr(regex=r'\d{4}-\d{2}-.+'), 'role': 'user'},
140+
{
141+
'calls': [{'tool_name': 'my_ret', 'args': {'args_dict': {'x': 0}}, 'tool_id': None}],
142+
'timestamp': IsStr(regex=r'\d{4}-\d{2}-.+'),
143+
'role': 'model-structured-response',
144+
},
145+
{
146+
'tool_name': 'my_ret',
147+
'content': '1',
148+
'tool_id': None,
149+
'timestamp': IsStr(regex=r'\d{4}-\d{2}-.+'),
150+
'role': 'tool-return',
151+
},
152+
{
153+
'content': '{"my_ret":"1"}',
154+
'timestamp': IsStr(regex=r'\d{4}-\d{2}-.+'),
155+
'role': 'model-text-response',
156+
},
157+
]
158+
),
159+
'cost': IsJson({'request_tokens': None, 'response_tokens': None, 'total_tokens': None, 'details': None}),
160+
'logfire.json_schema': IsJson(
161+
{
162+
'type': 'object',
163+
'properties': {
164+
'prompt': {},
165+
'agent': {
166+
'type': 'object',
167+
'title': 'Agent',
168+
'x-python-datatype': 'dataclass',
169+
'properties': {
170+
'model': {
171+
'type': 'object',
172+
'title': 'TestModel',
173+
'x-python-datatype': 'dataclass',
174+
'properties': {
175+
'agent_model_tools': {
176+
'type': 'object',
177+
'properties': {
178+
'my_ret': {
179+
'type': 'object',
180+
'title': 'Tool',
181+
'x-python-datatype': 'dataclass',
182+
'properties': {
183+
'function': {'type': 'object', 'x-python-datatype': 'unknown'}
184+
},
185+
}
186+
},
187+
}
188+
},
189+
}
190+
},
191+
},
192+
'custom_model': {},
193+
'model_name': {},
194+
'agent_name': {},
195+
'all_messages': {
196+
'type': 'array',
197+
'prefixItems': [
198+
{
199+
'type': 'object',
200+
'title': 'UserPrompt',
201+
'x-python-datatype': 'dataclass',
202+
'properties': {'timestamp': {'type': 'string', 'format': 'date-time'}},
203+
},
204+
{
205+
'type': 'object',
206+
'title': 'ModelStructuredResponse',
207+
'x-python-datatype': 'dataclass',
208+
'properties': {
209+
'calls': {
210+
'type': 'array',
211+
'items': {
212+
'type': 'object',
213+
'title': 'ToolCall',
214+
'x-python-datatype': 'dataclass',
215+
'properties': {
216+
'args': {
217+
'type': 'object',
218+
'title': 'ArgsDict',
219+
'x-python-datatype': 'dataclass',
220+
}
221+
},
222+
},
223+
},
224+
'timestamp': {'type': 'string', 'format': 'date-time'},
225+
},
226+
},
227+
{
228+
'type': 'object',
229+
'title': 'ToolReturn',
230+
'x-python-datatype': 'dataclass',
231+
'properties': {'timestamp': {'type': 'string', 'format': 'date-time'}},
232+
},
233+
{
234+
'type': 'object',
235+
'title': 'ModelTextResponse',
236+
'x-python-datatype': 'dataclass',
237+
'properties': {'timestamp': {'type': 'string', 'format': 'date-time'}},
238+
},
239+
],
240+
},
241+
'cost': {'type': 'object', 'title': 'Cost', 'x-python-datatype': 'dataclass'},
242+
},
243+
}
244+
),
245+
}
246+
)
91247
assert summary.attributes[1] == snapshot(
92248
{
93249
'code.filepath': 'agent.py',

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)