agno 2.3.21__py3-none-any.whl → 2.3.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +48 -2
- agno/agent/remote.py +234 -73
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/v2_3_0.py +92 -53
- agno/db/mysql/async_mysql.py +5 -7
- agno/db/mysql/mysql.py +5 -7
- agno/db/mysql/schemas.py +39 -21
- agno/db/postgres/async_postgres.py +172 -42
- agno/db/postgres/postgres.py +186 -38
- agno/db/postgres/schemas.py +39 -21
- agno/db/postgres/utils.py +6 -2
- agno/db/singlestore/schemas.py +41 -21
- agno/db/singlestore/singlestore.py +14 -3
- agno/db/sqlite/async_sqlite.py +7 -2
- agno/db/sqlite/schemas.py +36 -21
- agno/db/sqlite/sqlite.py +3 -7
- agno/knowledge/chunking/document.py +3 -2
- agno/knowledge/chunking/markdown.py +8 -3
- agno/knowledge/chunking/recursive.py +2 -2
- agno/models/base.py +4 -0
- agno/models/google/gemini.py +27 -4
- agno/models/openai/chat.py +1 -1
- agno/models/openai/responses.py +14 -7
- agno/os/middleware/jwt.py +66 -27
- agno/os/routers/agents/router.py +3 -3
- agno/os/routers/evals/evals.py +2 -2
- agno/os/routers/knowledge/knowledge.py +5 -5
- agno/os/routers/knowledge/schemas.py +1 -1
- agno/os/routers/memory/memory.py +4 -4
- agno/os/routers/session/session.py +2 -2
- agno/os/routers/teams/router.py +4 -4
- agno/os/routers/traces/traces.py +3 -3
- agno/os/routers/workflows/router.py +3 -3
- agno/os/schema.py +1 -1
- agno/reasoning/deepseek.py +11 -1
- agno/reasoning/gemini.py +6 -2
- agno/reasoning/groq.py +8 -3
- agno/reasoning/openai.py +2 -0
- agno/remote/base.py +106 -9
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +370 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/team/remote.py +220 -60
- agno/team/team.py +41 -3
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +150 -13
- agno/tools/function.py +6 -1
- agno/tools/mcp/mcp.py +300 -17
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/toolkit.py +89 -21
- agno/utils/mcp.py +49 -8
- agno/utils/string.py +43 -1
- agno/workflow/condition.py +4 -2
- agno/workflow/loop.py +20 -1
- agno/workflow/remote.py +173 -33
- agno/workflow/router.py +4 -1
- agno/workflow/steps.py +4 -0
- agno/workflow/workflow.py +14 -0
- {agno-2.3.21.dist-info → agno-2.3.23.dist-info}/METADATA +13 -14
- {agno-2.3.21.dist-info → agno-2.3.23.dist-info}/RECORD +74 -60
- {agno-2.3.21.dist-info → agno-2.3.23.dist-info}/WHEEL +0 -0
- {agno-2.3.21.dist-info → agno-2.3.23.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.21.dist-info → agno-2.3.23.dist-info}/top_level.txt +0 -0
agno/team/remote.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import time
|
|
3
2
|
from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Literal, Optional, Sequence, Tuple, Union, overload
|
|
4
3
|
|
|
5
4
|
from pydantic import BaseModel
|
|
@@ -27,19 +26,25 @@ class RemoteTeam(BaseRemote):
|
|
|
27
26
|
base_url: str,
|
|
28
27
|
team_id: str,
|
|
29
28
|
timeout: float = 300.0,
|
|
29
|
+
protocol: Literal["agentos", "a2a"] = "agentos",
|
|
30
|
+
a2a_protocol: Literal["json-rpc", "rest"] = "rest",
|
|
30
31
|
config_ttl: float = 300.0,
|
|
31
32
|
):
|
|
32
|
-
"""Initialize
|
|
33
|
+
"""Initialize RemoteTeam for remote execution.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
Supports two protocols:
|
|
36
|
+
- "agentos": Agno's proprietary AgentOS REST API (default)
|
|
37
|
+
- "a2a": A2A (Agent-to-Agent) protocol for cross-framework communication
|
|
35
38
|
|
|
36
39
|
Args:
|
|
37
|
-
base_url: Base URL for remote
|
|
38
|
-
team_id: ID of remote team
|
|
40
|
+
base_url: Base URL for remote instance (e.g., "http://localhost:7777")
|
|
41
|
+
team_id: ID of remote team on the remote server
|
|
39
42
|
timeout: Request timeout in seconds (default: 300)
|
|
43
|
+
protocol: Communication protocol - "agentos" (default) or "a2a"
|
|
44
|
+
a2a_protocol: For A2A protocol only - Whether to use JSON-RPC or REST protocol.
|
|
40
45
|
config_ttl: Time-to-live for cached config in seconds (default: 300)
|
|
41
46
|
"""
|
|
42
|
-
super().__init__(base_url, timeout, config_ttl)
|
|
47
|
+
super().__init__(base_url, timeout, protocol, a2a_protocol, config_ttl)
|
|
43
48
|
self.team_id = team_id
|
|
44
49
|
self._cached_team_config = None
|
|
45
50
|
|
|
@@ -48,48 +53,95 @@ class RemoteTeam(BaseRemote):
|
|
|
48
53
|
return self.team_id
|
|
49
54
|
|
|
50
55
|
async def get_team_config(self) -> "TeamResponse":
|
|
51
|
-
"""
|
|
52
|
-
|
|
56
|
+
"""
|
|
57
|
+
Get the team config from remote.
|
|
58
|
+
|
|
59
|
+
- For AgentOS protocol, always fetches fresh config from the remote.
|
|
60
|
+
- For A2A protocol, returns a minimal TeamResponse because A2A servers
|
|
61
|
+
do not expose detailed config endpoints.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
TeamResponse: The remote team configuration.
|
|
65
|
+
"""
|
|
66
|
+
from agno.os.routers.teams.schema import TeamResponse
|
|
67
|
+
|
|
68
|
+
if self.a2a_client:
|
|
69
|
+
from agno.client.a2a.schemas import AgentCard
|
|
70
|
+
|
|
71
|
+
agent_card: Optional[AgentCard] = await self.a2a_client.aget_agent_card()
|
|
72
|
+
|
|
73
|
+
return TeamResponse(
|
|
74
|
+
id=self.team_id,
|
|
75
|
+
name=agent_card.name if agent_card else self.team_id,
|
|
76
|
+
description=agent_card.description if agent_card else f"A2A team: {self.team_id}",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Fetch fresh config from remote for AgentOS
|
|
80
|
+
return await self.agentos_client.aget_team(self.team_id) # type: ignore
|
|
53
81
|
|
|
54
82
|
@property
|
|
55
|
-
def _team_config(self) -> "TeamResponse":
|
|
56
|
-
"""
|
|
83
|
+
def _team_config(self) -> Optional["TeamResponse"]:
|
|
84
|
+
"""
|
|
85
|
+
Get the team config from remote, cached with TTL.
|
|
86
|
+
|
|
87
|
+
- Returns None for A2A protocol (no config available).
|
|
88
|
+
- For AgentOS protocol, uses TTL caching for efficiency.
|
|
89
|
+
"""
|
|
90
|
+
import time
|
|
91
|
+
|
|
57
92
|
from agno.os.routers.teams.schema import TeamResponse
|
|
58
93
|
|
|
59
|
-
|
|
94
|
+
if self.a2a_client:
|
|
95
|
+
from agno.client.a2a.schemas import AgentCard
|
|
96
|
+
|
|
97
|
+
agent_card: Optional[AgentCard] = self.a2a_client.get_agent_card()
|
|
60
98
|
|
|
61
|
-
|
|
99
|
+
return TeamResponse(
|
|
100
|
+
id=self.team_id,
|
|
101
|
+
name=agent_card.name if agent_card else self.team_id,
|
|
102
|
+
description=agent_card.description if agent_card else f"A2A team: {self.team_id}",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
current_time = time.time()
|
|
62
106
|
if self._cached_team_config is not None:
|
|
63
107
|
config, cached_at = self._cached_team_config
|
|
64
108
|
if current_time - cached_at < self.config_ttl:
|
|
65
109
|
return config
|
|
66
110
|
|
|
67
|
-
# Fetch fresh config
|
|
68
|
-
config: TeamResponse = self.
|
|
111
|
+
# Fetch fresh config and update cache
|
|
112
|
+
config: TeamResponse = self.agentos_client.get_team(self.team_id) # type: ignore
|
|
69
113
|
self._cached_team_config = (config, current_time)
|
|
70
114
|
return config
|
|
71
115
|
|
|
72
|
-
def refresh_config(self) -> "TeamResponse":
|
|
73
|
-
"""
|
|
116
|
+
async def refresh_config(self) -> Optional["TeamResponse"]:
|
|
117
|
+
"""
|
|
118
|
+
Force refresh the cached team config from remote.
|
|
119
|
+
"""
|
|
120
|
+
import time
|
|
121
|
+
|
|
74
122
|
from agno.os.routers.teams.schema import TeamResponse
|
|
75
123
|
|
|
76
|
-
|
|
124
|
+
if self.a2a_client:
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
config: TeamResponse = await self.agentos_client.aget_team(self.team_id) # type: ignore
|
|
77
128
|
self._cached_team_config = (config, time.time())
|
|
78
129
|
return config
|
|
79
130
|
|
|
80
131
|
@property
|
|
81
132
|
def name(self) -> Optional[str]:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
133
|
+
config = self._team_config
|
|
134
|
+
if config is not None:
|
|
135
|
+
return config.name
|
|
136
|
+
return self.team_id
|
|
85
137
|
|
|
86
138
|
@property
|
|
87
139
|
def description(self) -> Optional[str]:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
140
|
+
config = self._team_config
|
|
141
|
+
if config is not None:
|
|
142
|
+
return config.description
|
|
143
|
+
return ""
|
|
91
144
|
|
|
92
|
-
@property
|
|
93
145
|
def role(self) -> Optional[str]:
|
|
94
146
|
if self._team_config is not None:
|
|
95
147
|
return self._team_config.role
|
|
@@ -107,10 +159,15 @@ class RemoteTeam(BaseRemote):
|
|
|
107
159
|
|
|
108
160
|
@property
|
|
109
161
|
def db(self) -> Optional[RemoteDb]:
|
|
110
|
-
if
|
|
162
|
+
if (
|
|
163
|
+
self.agentos_client
|
|
164
|
+
and self._config
|
|
165
|
+
and self._team_config is not None
|
|
166
|
+
and self._team_config.db_id is not None
|
|
167
|
+
):
|
|
111
168
|
return RemoteDb.from_config(
|
|
112
169
|
db_id=self._team_config.db_id,
|
|
113
|
-
client=self.
|
|
170
|
+
client=self.agentos_client,
|
|
114
171
|
config=self._config,
|
|
115
172
|
)
|
|
116
173
|
return None
|
|
@@ -118,12 +175,12 @@ class RemoteTeam(BaseRemote):
|
|
|
118
175
|
@property
|
|
119
176
|
def knowledge(self) -> Optional[RemoteKnowledge]:
|
|
120
177
|
"""Whether the team has knowledge enabled."""
|
|
121
|
-
if self._team_config is not None and self._team_config.knowledge is not None:
|
|
178
|
+
if self.agentos_client and self._team_config is not None and self._team_config.knowledge is not None:
|
|
122
179
|
return RemoteKnowledge(
|
|
123
|
-
client=self.
|
|
180
|
+
client=self.agentos_client,
|
|
124
181
|
contents_db=RemoteDb(
|
|
125
182
|
id=self._team_config.knowledge.get("db_id"), # type: ignore
|
|
126
|
-
client=self.
|
|
183
|
+
client=self.agentos_client,
|
|
127
184
|
knowledge_table_name=self._team_config.knowledge.get("knowledge_table"),
|
|
128
185
|
)
|
|
129
186
|
if self._team_config.knowledge.get("db_id") is not None
|
|
@@ -219,53 +276,156 @@ class RemoteTeam(BaseRemote):
|
|
|
219
276
|
serialized_input = serialize_input(validated_input)
|
|
220
277
|
headers = self._get_auth_headers(auth_token)
|
|
221
278
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return self.
|
|
225
|
-
team_id=self.team_id,
|
|
279
|
+
# A2A protocol path
|
|
280
|
+
if self.a2a_client:
|
|
281
|
+
return self._arun_a2a( # type: ignore[return-value]
|
|
226
282
|
message=serialized_input,
|
|
227
|
-
|
|
283
|
+
stream=stream or False,
|
|
228
284
|
user_id=user_id,
|
|
285
|
+
context_id=session_id, # Map session_id → context_id for A2A
|
|
229
286
|
audio=audio,
|
|
230
287
|
images=images,
|
|
231
288
|
videos=videos,
|
|
232
289
|
files=files,
|
|
233
|
-
session_state=session_state,
|
|
234
|
-
stream_events=stream_events,
|
|
235
|
-
retries=retries,
|
|
236
|
-
knowledge_filters=knowledge_filters,
|
|
237
|
-
add_history_to_context=add_history_to_context,
|
|
238
|
-
add_dependencies_to_context=add_dependencies_to_context,
|
|
239
|
-
add_session_state_to_context=add_session_state_to_context,
|
|
240
|
-
dependencies=dependencies,
|
|
241
|
-
metadata=metadata,
|
|
242
290
|
headers=headers,
|
|
243
|
-
**kwargs,
|
|
244
291
|
)
|
|
292
|
+
|
|
293
|
+
# AgentOS protocol path (default)
|
|
294
|
+
if self.agentos_client:
|
|
295
|
+
if stream:
|
|
296
|
+
# Handle streaming response
|
|
297
|
+
return self.agentos_client.run_team_stream( # type: ignore
|
|
298
|
+
team_id=self.team_id,
|
|
299
|
+
message=serialized_input,
|
|
300
|
+
session_id=session_id,
|
|
301
|
+
user_id=user_id,
|
|
302
|
+
audio=audio,
|
|
303
|
+
images=images,
|
|
304
|
+
videos=videos,
|
|
305
|
+
files=files,
|
|
306
|
+
session_state=session_state,
|
|
307
|
+
stream_events=stream_events,
|
|
308
|
+
retries=retries,
|
|
309
|
+
knowledge_filters=knowledge_filters,
|
|
310
|
+
add_history_to_context=add_history_to_context,
|
|
311
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
312
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
313
|
+
dependencies=dependencies,
|
|
314
|
+
metadata=metadata,
|
|
315
|
+
headers=headers,
|
|
316
|
+
**kwargs,
|
|
317
|
+
)
|
|
318
|
+
else:
|
|
319
|
+
return self.agentos_client.run_team( # type: ignore
|
|
320
|
+
team_id=self.team_id,
|
|
321
|
+
message=serialized_input,
|
|
322
|
+
session_id=session_id,
|
|
323
|
+
user_id=user_id,
|
|
324
|
+
audio=audio,
|
|
325
|
+
images=images,
|
|
326
|
+
videos=videos,
|
|
327
|
+
files=files,
|
|
328
|
+
session_state=session_state,
|
|
329
|
+
stream_events=stream_events,
|
|
330
|
+
retries=retries,
|
|
331
|
+
knowledge_filters=knowledge_filters,
|
|
332
|
+
add_history_to_context=add_history_to_context,
|
|
333
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
334
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
335
|
+
dependencies=dependencies,
|
|
336
|
+
metadata=metadata,
|
|
337
|
+
headers=headers,
|
|
338
|
+
**kwargs,
|
|
339
|
+
)
|
|
245
340
|
else:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
341
|
+
raise ValueError("No client available")
|
|
342
|
+
|
|
343
|
+
def _arun_a2a(
|
|
344
|
+
self,
|
|
345
|
+
message: str,
|
|
346
|
+
stream: bool,
|
|
347
|
+
user_id: Optional[str],
|
|
348
|
+
context_id: Optional[str],
|
|
349
|
+
audio: Optional[Sequence[Audio]],
|
|
350
|
+
images: Optional[Sequence[Image]],
|
|
351
|
+
videos: Optional[Sequence[Video]],
|
|
352
|
+
files: Optional[Sequence[File]],
|
|
353
|
+
headers: Optional[Dict[str, str]],
|
|
354
|
+
) -> Union[TeamRunOutput, AsyncIterator[TeamRunOutputEvent]]:
|
|
355
|
+
"""Execute via A2A protocol.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
message: Serialized message string
|
|
359
|
+
stream: Whether to stream the response
|
|
360
|
+
user_id: User identifier
|
|
361
|
+
context_id: Session/context ID (maps to session_id)
|
|
362
|
+
audio: Audio files to include
|
|
363
|
+
images: Images to include
|
|
364
|
+
videos: Videos to include
|
|
365
|
+
files: Files to include
|
|
366
|
+
headers: HTTP headers to include in the request (optional)
|
|
367
|
+
Returns:
|
|
368
|
+
TeamRunOutput for non-streaming, AsyncIterator[TeamRunOutputEvent] for streaming
|
|
369
|
+
"""
|
|
370
|
+
from agno.client.a2a.utils import map_stream_events_to_team_run_events
|
|
371
|
+
|
|
372
|
+
if not self.a2a_client:
|
|
373
|
+
raise ValueError("A2A client not available")
|
|
374
|
+
if stream:
|
|
375
|
+
# Return async generator for streaming
|
|
376
|
+
event_stream = self.a2a_client.stream_message(
|
|
377
|
+
message=message,
|
|
378
|
+
context_id=context_id,
|
|
250
379
|
user_id=user_id,
|
|
380
|
+
audio=list(audio) if audio else None,
|
|
381
|
+
images=list(images) if images else None,
|
|
382
|
+
videos=list(videos) if videos else None,
|
|
383
|
+
files=list(files) if files else None,
|
|
384
|
+
headers=headers,
|
|
385
|
+
)
|
|
386
|
+
return map_stream_events_to_team_run_events(event_stream, team_id=self.team_id)
|
|
387
|
+
else:
|
|
388
|
+
# Return coroutine for non-streaming
|
|
389
|
+
return self._arun_a2a_send( # type: ignore[return-value]
|
|
390
|
+
message=message,
|
|
391
|
+
user_id=user_id,
|
|
392
|
+
context_id=context_id,
|
|
251
393
|
audio=audio,
|
|
252
394
|
images=images,
|
|
253
395
|
videos=videos,
|
|
254
396
|
files=files,
|
|
255
|
-
session_state=session_state,
|
|
256
|
-
stream_events=stream_events,
|
|
257
|
-
retries=retries,
|
|
258
|
-
knowledge_filters=knowledge_filters,
|
|
259
|
-
add_history_to_context=add_history_to_context,
|
|
260
|
-
add_dependencies_to_context=add_dependencies_to_context,
|
|
261
|
-
add_session_state_to_context=add_session_state_to_context,
|
|
262
|
-
dependencies=dependencies,
|
|
263
|
-
metadata=metadata,
|
|
264
397
|
headers=headers,
|
|
265
|
-
**kwargs,
|
|
266
398
|
)
|
|
267
399
|
|
|
268
|
-
async def
|
|
400
|
+
async def _arun_a2a_send(
|
|
401
|
+
self,
|
|
402
|
+
message: str,
|
|
403
|
+
user_id: Optional[str],
|
|
404
|
+
context_id: Optional[str],
|
|
405
|
+
audio: Optional[Sequence[Audio]],
|
|
406
|
+
images: Optional[Sequence[Image]],
|
|
407
|
+
videos: Optional[Sequence[Video]],
|
|
408
|
+
files: Optional[Sequence[File]],
|
|
409
|
+
headers: Optional[Dict[str, str]],
|
|
410
|
+
) -> TeamRunOutput:
|
|
411
|
+
"""Send a non-streaming A2A message and convert response to TeamRunOutput."""
|
|
412
|
+
if not self.a2a_client:
|
|
413
|
+
raise ValueError("A2A client not available")
|
|
414
|
+
from agno.client.a2a.utils import map_task_result_to_team_run_output
|
|
415
|
+
|
|
416
|
+
task_result = await self.a2a_client.send_message(
|
|
417
|
+
message=message,
|
|
418
|
+
context_id=context_id,
|
|
419
|
+
user_id=user_id,
|
|
420
|
+
images=list(images) if images else None,
|
|
421
|
+
audio=list(audio) if audio else None,
|
|
422
|
+
videos=list(videos) if videos else None,
|
|
423
|
+
files=list(files) if files else None,
|
|
424
|
+
headers=headers,
|
|
425
|
+
)
|
|
426
|
+
return map_task_result_to_team_run_output(task_result, team_id=self.team_id, user_id=user_id)
|
|
427
|
+
|
|
428
|
+
async def acancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
|
|
269
429
|
"""Cancel a running team execution.
|
|
270
430
|
|
|
271
431
|
Args:
|
|
@@ -277,7 +437,7 @@ class RemoteTeam(BaseRemote):
|
|
|
277
437
|
"""
|
|
278
438
|
headers = self._get_auth_headers(auth_token)
|
|
279
439
|
try:
|
|
280
|
-
await self.
|
|
440
|
+
await self.agentos_client.cancel_team_run( # type: ignore
|
|
281
441
|
team_id=self.team_id,
|
|
282
442
|
run_id=run_id,
|
|
283
443
|
headers=headers,
|
agno/team/team.py
CHANGED
|
@@ -56,6 +56,9 @@ from agno.models.utils import get_model
|
|
|
56
56
|
from agno.reasoning.step import NextAction, ReasoningStep, ReasoningSteps
|
|
57
57
|
from agno.run import RunContext, RunStatus
|
|
58
58
|
from agno.run.agent import RunEvent, RunOutput, RunOutputEvent
|
|
59
|
+
from agno.run.cancel import (
|
|
60
|
+
acancel_run as acancel_run_global,
|
|
61
|
+
)
|
|
59
62
|
from agno.run.cancel import (
|
|
60
63
|
acleanup_run,
|
|
61
64
|
araise_if_cancelled,
|
|
@@ -1011,6 +1014,18 @@ class Team:
|
|
|
1011
1014
|
"""
|
|
1012
1015
|
return cancel_run_global(run_id)
|
|
1013
1016
|
|
|
1017
|
+
@staticmethod
|
|
1018
|
+
async def acancel_run(run_id: str) -> bool:
|
|
1019
|
+
"""Cancel a running team execution.
|
|
1020
|
+
|
|
1021
|
+
Args:
|
|
1022
|
+
run_id (str): The run_id to cancel.
|
|
1023
|
+
|
|
1024
|
+
Returns:
|
|
1025
|
+
bool: True if the run was found and marked for cancellation, False otherwise.
|
|
1026
|
+
"""
|
|
1027
|
+
return await acancel_run_global(run_id)
|
|
1028
|
+
|
|
1014
1029
|
async def _connect_mcp_tools(self) -> None:
|
|
1015
1030
|
"""Connect the MCP tools to the agent."""
|
|
1016
1031
|
if self.tools is not None:
|
|
@@ -2652,6 +2667,8 @@ class Team:
|
|
|
2652
2667
|
"""
|
|
2653
2668
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2654
2669
|
|
|
2670
|
+
await aregister_run(run_context.run_id)
|
|
2671
|
+
|
|
2655
2672
|
memory_task = None
|
|
2656
2673
|
|
|
2657
2674
|
try:
|
|
@@ -5135,7 +5152,17 @@ class Team:
|
|
|
5135
5152
|
|
|
5136
5153
|
try:
|
|
5137
5154
|
sig = signature(value)
|
|
5138
|
-
|
|
5155
|
+
|
|
5156
|
+
# Build kwargs for the function
|
|
5157
|
+
kwargs: Dict[str, Any] = {}
|
|
5158
|
+
if "agent" in sig.parameters:
|
|
5159
|
+
kwargs["agent"] = self
|
|
5160
|
+
if "team" in sig.parameters:
|
|
5161
|
+
kwargs["team"] = self
|
|
5162
|
+
if "run_context" in sig.parameters:
|
|
5163
|
+
kwargs["run_context"] = run_context
|
|
5164
|
+
|
|
5165
|
+
resolved_value = value(**kwargs) if kwargs else value()
|
|
5139
5166
|
|
|
5140
5167
|
run_context.dependencies[key] = resolved_value
|
|
5141
5168
|
except Exception as e:
|
|
@@ -5156,7 +5183,17 @@ class Team:
|
|
|
5156
5183
|
|
|
5157
5184
|
try:
|
|
5158
5185
|
sig = signature(value)
|
|
5159
|
-
|
|
5186
|
+
|
|
5187
|
+
# Build kwargs for the function
|
|
5188
|
+
kwargs: Dict[str, Any] = {}
|
|
5189
|
+
if "agent" in sig.parameters:
|
|
5190
|
+
kwargs["agent"] = self
|
|
5191
|
+
if "team" in sig.parameters:
|
|
5192
|
+
kwargs["team"] = self
|
|
5193
|
+
if "run_context" in sig.parameters:
|
|
5194
|
+
kwargs["run_context"] = run_context
|
|
5195
|
+
|
|
5196
|
+
resolved_value = value(**kwargs) if kwargs else value()
|
|
5160
5197
|
|
|
5161
5198
|
if iscoroutine(resolved_value):
|
|
5162
5199
|
resolved_value = await resolved_value
|
|
@@ -5347,7 +5384,8 @@ class Team:
|
|
|
5347
5384
|
|
|
5348
5385
|
elif isinstance(tool, Toolkit):
|
|
5349
5386
|
# For each function in the toolkit and process entrypoint
|
|
5350
|
-
|
|
5387
|
+
toolkit_functions = tool.get_async_functions() if async_mode else tool.get_functions()
|
|
5388
|
+
for name, _func in toolkit_functions.items():
|
|
5351
5389
|
if name in _function_names:
|
|
5352
5390
|
continue
|
|
5353
5391
|
_function_names.append(name)
|
agno/tools/brandfetch.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Brandfetch API toolkit for retrieving brand data and searching brands.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import warnings
|
|
5
6
|
from os import getenv
|
|
6
|
-
from typing import Any, Optional
|
|
7
|
+
from typing import Any, List, Optional
|
|
7
8
|
|
|
8
9
|
try:
|
|
9
10
|
import httpx
|
|
@@ -31,8 +32,6 @@ class BrandfetchTools(Toolkit):
|
|
|
31
32
|
all: bool - if True, will use all tools
|
|
32
33
|
enable_search_by_identifier: bool - if True, will use search by identifier
|
|
33
34
|
enable_search_by_brand: bool - if True, will use search by brand
|
|
34
|
-
enable_asearch_by_identifier: bool - if True, will use async search by identifier
|
|
35
|
-
enable_asearch_by_brand: bool - if True, will use async search by brand
|
|
36
35
|
"""
|
|
37
36
|
|
|
38
37
|
def __init__(
|
|
@@ -44,9 +43,18 @@ class BrandfetchTools(Toolkit):
|
|
|
44
43
|
enable_search_by_identifier: bool = True,
|
|
45
44
|
enable_search_by_brand: bool = False,
|
|
46
45
|
all: bool = False,
|
|
47
|
-
async_tools: bool = False,
|
|
46
|
+
async_tools: bool = False, # Deprecated
|
|
48
47
|
**kwargs,
|
|
49
48
|
):
|
|
49
|
+
# Handle deprecated async_tools parameter
|
|
50
|
+
if async_tools:
|
|
51
|
+
warnings.warn(
|
|
52
|
+
"The 'async_tools' parameter is deprecated and will be removed in a future version. "
|
|
53
|
+
"Async tools are now automatically used when calling agent.arun() or agent.aprint_response().",
|
|
54
|
+
DeprecationWarning,
|
|
55
|
+
stacklevel=2,
|
|
56
|
+
)
|
|
57
|
+
|
|
50
58
|
self.api_key = api_key or getenv("BRANDFETCH_API_KEY")
|
|
51
59
|
self.client_id = client_id or getenv("BRANDFETCH_CLIENT_ID")
|
|
52
60
|
self.base_url = base_url
|
|
@@ -54,20 +62,21 @@ class BrandfetchTools(Toolkit):
|
|
|
54
62
|
self.search_url = f"{self.base_url}/search"
|
|
55
63
|
self.brand_url = f"{self.base_url}/brands"
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
# Build tools lists
|
|
66
|
+
# sync tools: used by agent.run() and agent.print_response()
|
|
67
|
+
# async tools: used by agent.arun() and agent.aprint_response()
|
|
68
|
+
tools: List[Any] = []
|
|
69
|
+
async_tools_list: List[tuple] = []
|
|
70
|
+
|
|
71
|
+
if all or enable_search_by_identifier:
|
|
72
|
+
tools.append(self.search_by_identifier)
|
|
73
|
+
async_tools_list.append((self.asearch_by_identifier, "search_by_identifier"))
|
|
74
|
+
if all or enable_search_by_brand:
|
|
75
|
+
tools.append(self.search_by_brand)
|
|
76
|
+
async_tools_list.append((self.asearch_by_brand, "search_by_brand"))
|
|
77
|
+
|
|
69
78
|
name = kwargs.pop("name", "brandfetch_tools")
|
|
70
|
-
super().__init__(name=name, tools=tools, **kwargs)
|
|
79
|
+
super().__init__(name=name, tools=tools, async_tools=async_tools_list, **kwargs)
|
|
71
80
|
|
|
72
81
|
async def asearch_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
73
82
|
"""
|