agno 2.3.21__py3-none-any.whl → 2.3.22__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 +26 -1
- agno/agent/remote.py +233 -72
- 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/postgres/async_postgres.py +162 -40
- agno/db/postgres/postgres.py +181 -31
- agno/db/postgres/utils.py +6 -2
- agno/knowledge/chunking/document.py +3 -2
- agno/knowledge/chunking/markdown.py +8 -3
- agno/knowledge/chunking/recursive.py +2 -2
- 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 +2 -2
- agno/os/routers/knowledge/knowledge.py +3 -3
- agno/os/routers/teams/router.py +2 -2
- agno/os/routers/workflows/router.py +2 -2
- 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 +105 -8
- 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 +219 -59
- agno/team/team.py +22 -2
- agno/tools/mcp/mcp.py +299 -17
- agno/tools/mcp/multi_mcp.py +269 -14
- 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 +172 -32
- agno/workflow/router.py +4 -1
- agno/workflow/steps.py +4 -0
- {agno-2.3.21.dist-info → agno-2.3.22.dist-info}/METADATA +13 -14
- {agno-2.3.21.dist-info → agno-2.3.22.dist-info}/RECORD +52 -38
- {agno-2.3.21.dist-info → agno-2.3.22.dist-info}/WHEEL +0 -0
- {agno-2.3.21.dist-info → agno-2.3.22.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.21.dist-info → agno-2.3.22.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -77,6 +77,7 @@ from agno.run.requirement import RunRequirement
|
|
|
77
77
|
from agno.run.team import TeamRunOutputEvent
|
|
78
78
|
from agno.session import AgentSession, SessionSummaryManager, TeamSession, WorkflowSession
|
|
79
79
|
from agno.session.summary import SessionSummary
|
|
80
|
+
from agno.skills import Skills
|
|
80
81
|
from agno.tools import Toolkit
|
|
81
82
|
from agno.tools.function import Function
|
|
82
83
|
from agno.utils.agent import (
|
|
@@ -264,6 +265,10 @@ class Agent:
|
|
|
264
265
|
knowledge_retriever: Optional[Callable[..., Optional[List[Union[Dict, str]]]]] = None
|
|
265
266
|
references_format: Literal["json", "yaml"] = "json"
|
|
266
267
|
|
|
268
|
+
# --- Skills ---
|
|
269
|
+
# Skills provide structured instructions, reference docs, and scripts for agents
|
|
270
|
+
skills: Optional[Skills] = None
|
|
271
|
+
|
|
267
272
|
# --- Agent Tools ---
|
|
268
273
|
# A list of tools provided to the Model.
|
|
269
274
|
# Tools are functions the model may generate JSON inputs for.
|
|
@@ -487,6 +492,7 @@ class Agent:
|
|
|
487
492
|
add_knowledge_to_context: bool = False,
|
|
488
493
|
knowledge_retriever: Optional[Callable[..., Optional[List[Union[Dict, str]]]]] = None,
|
|
489
494
|
references_format: Literal["json", "yaml"] = "json",
|
|
495
|
+
skills: Optional[Skills] = None,
|
|
490
496
|
metadata: Optional[Dict[str, Any]] = None,
|
|
491
497
|
tools: Optional[Sequence[Union[Toolkit, Callable, Function, Dict]]] = None,
|
|
492
498
|
tool_call_limit: Optional[int] = None,
|
|
@@ -610,6 +616,8 @@ class Agent:
|
|
|
610
616
|
self.knowledge_retriever = knowledge_retriever
|
|
611
617
|
self.references_format = references_format
|
|
612
618
|
|
|
619
|
+
self.skills = skills
|
|
620
|
+
|
|
613
621
|
self.metadata = metadata
|
|
614
622
|
|
|
615
623
|
self.tools = list(tools) if tools else []
|
|
@@ -6396,6 +6404,10 @@ class Agent:
|
|
|
6396
6404
|
if self.update_knowledge:
|
|
6397
6405
|
agent_tools.append(self.add_to_knowledge)
|
|
6398
6406
|
|
|
6407
|
+
# Add tools for accessing skills
|
|
6408
|
+
if self.skills is not None:
|
|
6409
|
+
agent_tools.extend(self.skills.get_tools())
|
|
6410
|
+
|
|
6399
6411
|
return agent_tools
|
|
6400
6412
|
|
|
6401
6413
|
async def aget_tools(
|
|
@@ -6489,6 +6501,10 @@ class Agent:
|
|
|
6489
6501
|
if self.update_knowledge:
|
|
6490
6502
|
agent_tools.append(self.add_to_knowledge)
|
|
6491
6503
|
|
|
6504
|
+
# Add tools for accessing skills
|
|
6505
|
+
if self.skills is not None:
|
|
6506
|
+
agent_tools.extend(self.skills.get_tools())
|
|
6507
|
+
|
|
6492
6508
|
return agent_tools
|
|
6493
6509
|
|
|
6494
6510
|
def _determine_tools_for_model(
|
|
@@ -7171,7 +7187,6 @@ class Agent:
|
|
|
7171
7187
|
"""
|
|
7172
7188
|
if self._has_async_db():
|
|
7173
7189
|
raise ValueError("Async database not supported for save_session")
|
|
7174
|
-
|
|
7175
7190
|
# If the agent is a member of a team, do not save the session to the database
|
|
7176
7191
|
if (
|
|
7177
7192
|
self.db is not None
|
|
@@ -7937,6 +7952,11 @@ class Agent:
|
|
|
7937
7952
|
# 3.3.8 Then add additional context
|
|
7938
7953
|
if self.additional_context is not None:
|
|
7939
7954
|
system_message_content += f"{self.additional_context}\n"
|
|
7955
|
+
# 3.3.8.1 Then add skills to the system prompt
|
|
7956
|
+
if self.skills is not None:
|
|
7957
|
+
skills_snippet = self.skills.get_system_prompt_snippet()
|
|
7958
|
+
if skills_snippet:
|
|
7959
|
+
system_message_content += f"\n{skills_snippet}\n"
|
|
7940
7960
|
# 3.3.9 Then add memories to the system prompt
|
|
7941
7961
|
if self.add_memories_to_context:
|
|
7942
7962
|
_memory_manager_not_set = False
|
|
@@ -8281,6 +8301,11 @@ class Agent:
|
|
|
8281
8301
|
# 3.3.8 Then add additional context
|
|
8282
8302
|
if self.additional_context is not None:
|
|
8283
8303
|
system_message_content += f"{self.additional_context}\n"
|
|
8304
|
+
# 3.3.8.1 Then add skills to the system prompt
|
|
8305
|
+
if self.skills is not None:
|
|
8306
|
+
skills_snippet = self.skills.get_system_prompt_snippet()
|
|
8307
|
+
if skills_snippet:
|
|
8308
|
+
system_message_content += f"\n{skills_snippet}\n"
|
|
8284
8309
|
# 3.3.9 Then add memories to the system prompt
|
|
8285
8310
|
if self.add_memories_to_context:
|
|
8286
8311
|
_memory_manager_not_set = False
|
agno/agent/remote.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import time
|
|
3
2
|
from dataclasses import dataclass, field
|
|
4
3
|
from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Literal, Optional, Sequence, Tuple, Union, overload
|
|
5
4
|
|
|
@@ -29,19 +28,25 @@ class RemoteAgent(BaseRemote):
|
|
|
29
28
|
base_url: str,
|
|
30
29
|
agent_id: str,
|
|
31
30
|
timeout: float = 60.0,
|
|
31
|
+
protocol: Literal["agentos", "a2a"] = "agentos",
|
|
32
|
+
a2a_protocol: Literal["json-rpc", "rest"] = "rest",
|
|
32
33
|
config_ttl: float = 300.0,
|
|
33
34
|
):
|
|
34
|
-
"""Initialize
|
|
35
|
+
"""Initialize RemoteAgent for remote execution.
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
Supports two protocols:
|
|
38
|
+
- "agentos": Agno's proprietary AgentOS REST API (default)
|
|
39
|
+
- "a2a": A2A (Agent-to-Agent) protocol for cross-framework communication
|
|
37
40
|
|
|
38
41
|
Args:
|
|
39
|
-
base_url: Base URL for remote
|
|
40
|
-
agent_id: ID of remote agent
|
|
42
|
+
base_url: Base URL for remote instance (e.g., "http://localhost:7777")
|
|
43
|
+
agent_id: ID of remote agent on the remote server
|
|
41
44
|
timeout: Request timeout in seconds (default: 60)
|
|
45
|
+
protocol: Communication protocol - "agentos" (default) or "a2a"
|
|
46
|
+
a2a_protocol: For A2A protocol only - Whether to use JSON-RPC or REST protocol.
|
|
42
47
|
config_ttl: Time-to-live for cached config in seconds (default: 300)
|
|
43
48
|
"""
|
|
44
|
-
super().__init__(base_url, timeout, config_ttl)
|
|
49
|
+
super().__init__(base_url, timeout, protocol, a2a_protocol, config_ttl)
|
|
45
50
|
self.agent_id = agent_id
|
|
46
51
|
self._cached_agent_config = None
|
|
47
52
|
|
|
@@ -50,14 +55,48 @@ class RemoteAgent(BaseRemote):
|
|
|
50
55
|
return self.agent_id
|
|
51
56
|
|
|
52
57
|
async def get_agent_config(self) -> "AgentResponse":
|
|
53
|
-
"""
|
|
54
|
-
|
|
58
|
+
"""
|
|
59
|
+
Get the agent config from remote.
|
|
60
|
+
|
|
61
|
+
For A2A protocol, returns a minimal AgentResponse since A2A servers
|
|
62
|
+
don't expose the same config endpoints as AgentOS. For AgentOS, always fetches fresh config.
|
|
63
|
+
"""
|
|
64
|
+
from agno.os.routers.agents.schema import AgentResponse
|
|
65
|
+
|
|
66
|
+
if self.a2a_client:
|
|
67
|
+
from agno.client.a2a.schemas import AgentCard
|
|
68
|
+
|
|
69
|
+
agent_card: Optional[AgentCard] = await self.a2a_client.aget_agent_card()
|
|
70
|
+
|
|
71
|
+
return AgentResponse(
|
|
72
|
+
id=self.agent_id,
|
|
73
|
+
name=agent_card.name if agent_card else self.agent_id,
|
|
74
|
+
description=agent_card.description if agent_card else f"A2A agent: {self.agent_id}",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return await self.agentos_client.aget_agent(self.agent_id) # type: ignore
|
|
55
78
|
|
|
56
79
|
@property
|
|
57
|
-
def _agent_config(self) -> "AgentResponse":
|
|
58
|
-
"""
|
|
80
|
+
def _agent_config(self) -> Optional["AgentResponse"]:
|
|
81
|
+
"""
|
|
82
|
+
Get the agent config from remote, cached with TTL.
|
|
83
|
+
Returns None for A2A protocol since A2A servers don't expose agent config endpoints.
|
|
84
|
+
"""
|
|
85
|
+
import time
|
|
86
|
+
|
|
59
87
|
from agno.os.routers.agents.schema import AgentResponse
|
|
60
88
|
|
|
89
|
+
if self.a2a_client:
|
|
90
|
+
from agno.client.a2a.schemas import AgentCard
|
|
91
|
+
|
|
92
|
+
agent_card: Optional[AgentCard] = self.a2a_client.get_agent_card()
|
|
93
|
+
|
|
94
|
+
return AgentResponse(
|
|
95
|
+
id=self.agent_id,
|
|
96
|
+
name=agent_card.name if agent_card else self.agent_id,
|
|
97
|
+
description=agent_card.description if agent_card else f"A2A agent: {self.agent_id}",
|
|
98
|
+
)
|
|
99
|
+
|
|
61
100
|
current_time = time.time()
|
|
62
101
|
|
|
63
102
|
# Check if cache is valid
|
|
@@ -67,15 +106,24 @@ class RemoteAgent(BaseRemote):
|
|
|
67
106
|
return config
|
|
68
107
|
|
|
69
108
|
# Fetch fresh config
|
|
70
|
-
config: AgentResponse = self.
|
|
109
|
+
config: AgentResponse = self.agentos_client.get_agent(self.agent_id) # type: ignore
|
|
71
110
|
self._cached_agent_config = (config, current_time)
|
|
72
111
|
return config
|
|
73
112
|
|
|
74
|
-
def refresh_config(self) -> "AgentResponse":
|
|
75
|
-
"""
|
|
113
|
+
async def refresh_config(self) -> Optional["AgentResponse"]:
|
|
114
|
+
"""
|
|
115
|
+
Force refresh the cached agent config.
|
|
116
|
+
Returns None for A2A protocol.
|
|
117
|
+
"""
|
|
118
|
+
import time
|
|
119
|
+
|
|
76
120
|
from agno.os.routers.agents.schema import AgentResponse
|
|
77
121
|
|
|
78
|
-
|
|
122
|
+
if self.a2a_client:
|
|
123
|
+
self._cached_agent_config = None
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
config: AgentResponse = await self.agentos_client.aget_agent(self.agent_id) # type: ignore
|
|
79
127
|
self._cached_agent_config = (config, time.time())
|
|
80
128
|
return config
|
|
81
129
|
|
|
@@ -91,7 +139,6 @@ class RemoteAgent(BaseRemote):
|
|
|
91
139
|
return self._agent_config.description
|
|
92
140
|
return ""
|
|
93
141
|
|
|
94
|
-
@property
|
|
95
142
|
def role(self) -> Optional[str]:
|
|
96
143
|
if self._agent_config is not None:
|
|
97
144
|
return self._agent_config.role
|
|
@@ -109,23 +156,27 @@ class RemoteAgent(BaseRemote):
|
|
|
109
156
|
|
|
110
157
|
@property
|
|
111
158
|
def db(self) -> Optional[RemoteDb]:
|
|
112
|
-
if
|
|
159
|
+
if (
|
|
160
|
+
self.agentos_client
|
|
161
|
+
and self._config
|
|
162
|
+
and self._agent_config is not None
|
|
163
|
+
and self._agent_config.db_id is not None
|
|
164
|
+
):
|
|
113
165
|
return RemoteDb.from_config(
|
|
114
166
|
db_id=self._agent_config.db_id,
|
|
115
|
-
client=self.
|
|
167
|
+
client=self.agentos_client,
|
|
116
168
|
config=self._config,
|
|
117
169
|
)
|
|
118
170
|
return None
|
|
119
171
|
|
|
120
172
|
@property
|
|
121
173
|
def knowledge(self) -> Optional[RemoteKnowledge]:
|
|
122
|
-
|
|
123
|
-
if self._agent_config is not None and self._agent_config.knowledge is not None:
|
|
174
|
+
if self.agentos_client and self._agent_config is not None and self._agent_config.knowledge is not None:
|
|
124
175
|
return RemoteKnowledge(
|
|
125
|
-
client=self.
|
|
176
|
+
client=self.agentos_client,
|
|
126
177
|
contents_db=RemoteDb(
|
|
127
178
|
id=self._agent_config.knowledge.get("db_id"), # type: ignore
|
|
128
|
-
client=self.
|
|
179
|
+
client=self.agentos_client,
|
|
129
180
|
knowledge_table_name=self._agent_config.knowledge.get("knowledge_table"),
|
|
130
181
|
)
|
|
131
182
|
if self._agent_config.knowledge.get("db_id") is not None
|
|
@@ -139,7 +190,7 @@ class RemoteAgent(BaseRemote):
|
|
|
139
190
|
return None
|
|
140
191
|
|
|
141
192
|
async def aget_tools(self, **kwargs: Any) -> List[Dict]:
|
|
142
|
-
if self._agent_config.tools is not None:
|
|
193
|
+
if self._agent_config is not None and self._agent_config.tools is not None:
|
|
143
194
|
return json.loads(self._agent_config.tools["tools"])
|
|
144
195
|
return []
|
|
145
196
|
|
|
@@ -222,52 +273,156 @@ class RemoteAgent(BaseRemote):
|
|
|
222
273
|
serialized_input = serialize_input(validated_input)
|
|
223
274
|
headers = self._get_auth_headers(auth_token)
|
|
224
275
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return self.
|
|
228
|
-
agent_id=self.agent_id,
|
|
276
|
+
# A2A protocol path
|
|
277
|
+
if self.a2a_client:
|
|
278
|
+
return self._arun_a2a( # type: ignore[return-value]
|
|
229
279
|
message=serialized_input,
|
|
230
|
-
|
|
280
|
+
stream=stream or False,
|
|
231
281
|
user_id=user_id,
|
|
282
|
+
context_id=session_id, # Map session_id → context_id for A2A
|
|
232
283
|
audio=audio,
|
|
233
284
|
images=images,
|
|
234
285
|
videos=videos,
|
|
235
286
|
files=files,
|
|
236
|
-
session_state=session_state,
|
|
237
|
-
stream_events=stream_events,
|
|
238
|
-
retries=retries,
|
|
239
|
-
knowledge_filters=knowledge_filters,
|
|
240
|
-
add_history_to_context=add_history_to_context,
|
|
241
|
-
add_dependencies_to_context=add_dependencies_to_context,
|
|
242
|
-
add_session_state_to_context=add_session_state_to_context,
|
|
243
|
-
dependencies=dependencies,
|
|
244
|
-
metadata=metadata,
|
|
245
287
|
headers=headers,
|
|
246
|
-
**kwargs,
|
|
247
288
|
)
|
|
289
|
+
|
|
290
|
+
# AgentOS protocol path (default)
|
|
291
|
+
if self.agentos_client:
|
|
292
|
+
if stream:
|
|
293
|
+
# Handle streaming response
|
|
294
|
+
return self.agentos_client.run_agent_stream(
|
|
295
|
+
agent_id=self.agent_id,
|
|
296
|
+
message=serialized_input,
|
|
297
|
+
session_id=session_id,
|
|
298
|
+
user_id=user_id,
|
|
299
|
+
audio=audio,
|
|
300
|
+
images=images,
|
|
301
|
+
videos=videos,
|
|
302
|
+
files=files,
|
|
303
|
+
session_state=session_state,
|
|
304
|
+
stream_events=stream_events,
|
|
305
|
+
retries=retries,
|
|
306
|
+
knowledge_filters=knowledge_filters,
|
|
307
|
+
add_history_to_context=add_history_to_context,
|
|
308
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
309
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
310
|
+
dependencies=dependencies,
|
|
311
|
+
metadata=metadata,
|
|
312
|
+
headers=headers,
|
|
313
|
+
**kwargs,
|
|
314
|
+
)
|
|
315
|
+
else:
|
|
316
|
+
return self.agentos_client.run_agent( # type: ignore
|
|
317
|
+
agent_id=self.agent_id,
|
|
318
|
+
message=serialized_input,
|
|
319
|
+
session_id=session_id,
|
|
320
|
+
user_id=user_id,
|
|
321
|
+
audio=audio,
|
|
322
|
+
images=images,
|
|
323
|
+
videos=videos,
|
|
324
|
+
files=files,
|
|
325
|
+
session_state=session_state,
|
|
326
|
+
stream_events=stream_events,
|
|
327
|
+
retries=retries,
|
|
328
|
+
knowledge_filters=knowledge_filters,
|
|
329
|
+
add_history_to_context=add_history_to_context,
|
|
330
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
331
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
332
|
+
dependencies=dependencies,
|
|
333
|
+
metadata=metadata,
|
|
334
|
+
headers=headers,
|
|
335
|
+
**kwargs,
|
|
336
|
+
)
|
|
248
337
|
else:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
338
|
+
raise ValueError("No client available")
|
|
339
|
+
|
|
340
|
+
def _arun_a2a(
|
|
341
|
+
self,
|
|
342
|
+
message: str,
|
|
343
|
+
stream: bool,
|
|
344
|
+
user_id: Optional[str],
|
|
345
|
+
context_id: Optional[str],
|
|
346
|
+
audio: Optional[Sequence[Audio]],
|
|
347
|
+
images: Optional[Sequence[Image]],
|
|
348
|
+
videos: Optional[Sequence[Video]],
|
|
349
|
+
files: Optional[Sequence[File]],
|
|
350
|
+
headers: Optional[Dict[str, str]],
|
|
351
|
+
) -> Union[RunOutput, AsyncIterator[RunOutputEvent]]:
|
|
352
|
+
"""Execute via A2A protocol.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
message: Serialized message string
|
|
356
|
+
stream: Whether to stream the response
|
|
357
|
+
user_id: User identifier
|
|
358
|
+
context_id: Session/context ID (maps to session_id)
|
|
359
|
+
audio: Audio files to include
|
|
360
|
+
images: Images to include
|
|
361
|
+
videos: Videos to include
|
|
362
|
+
files: Files to include
|
|
363
|
+
headers: HTTP headers to include in the request (optional)
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
RunOutput for non-streaming, AsyncIterator[RunOutputEvent] for streaming
|
|
367
|
+
"""
|
|
368
|
+
if not self.a2a_client:
|
|
369
|
+
raise ValueError("A2A client not available")
|
|
370
|
+
from agno.client.a2a.utils import map_stream_events_to_run_events
|
|
371
|
+
|
|
372
|
+
if stream:
|
|
373
|
+
# Return async generator for streaming
|
|
374
|
+
event_stream = self.a2a_client.stream_message(
|
|
375
|
+
message=message,
|
|
376
|
+
context_id=context_id,
|
|
253
377
|
user_id=user_id,
|
|
378
|
+
images=list(images) if images else None,
|
|
379
|
+
audio=list(audio) if audio else None,
|
|
380
|
+
videos=list(videos) if videos else None,
|
|
381
|
+
files=list(files) if files else None,
|
|
382
|
+
headers=headers,
|
|
383
|
+
)
|
|
384
|
+
return map_stream_events_to_run_events(event_stream, agent_id=self.agent_id)
|
|
385
|
+
else:
|
|
386
|
+
# Return coroutine for non-streaming
|
|
387
|
+
return self._arun_a2a_send( # type: ignore[return-value]
|
|
388
|
+
message=message,
|
|
389
|
+
user_id=user_id,
|
|
390
|
+
context_id=context_id,
|
|
254
391
|
audio=audio,
|
|
255
392
|
images=images,
|
|
256
393
|
videos=videos,
|
|
257
394
|
files=files,
|
|
258
|
-
session_state=session_state,
|
|
259
|
-
stream_events=stream_events,
|
|
260
|
-
retries=retries,
|
|
261
|
-
knowledge_filters=knowledge_filters,
|
|
262
|
-
add_history_to_context=add_history_to_context,
|
|
263
|
-
add_dependencies_to_context=add_dependencies_to_context,
|
|
264
|
-
add_session_state_to_context=add_session_state_to_context,
|
|
265
|
-
dependencies=dependencies,
|
|
266
|
-
metadata=metadata,
|
|
267
395
|
headers=headers,
|
|
268
|
-
**kwargs,
|
|
269
396
|
)
|
|
270
397
|
|
|
398
|
+
async def _arun_a2a_send(
|
|
399
|
+
self,
|
|
400
|
+
message: str,
|
|
401
|
+
user_id: Optional[str],
|
|
402
|
+
context_id: Optional[str],
|
|
403
|
+
audio: Optional[Sequence[Audio]],
|
|
404
|
+
images: Optional[Sequence[Image]],
|
|
405
|
+
videos: Optional[Sequence[Video]],
|
|
406
|
+
files: Optional[Sequence[File]],
|
|
407
|
+
headers: Optional[Dict[str, str]],
|
|
408
|
+
) -> RunOutput:
|
|
409
|
+
"""Send a non-streaming A2A message and convert response to RunOutput."""
|
|
410
|
+
if not self.a2a_client:
|
|
411
|
+
raise ValueError("A2A client not available")
|
|
412
|
+
from agno.client.a2a.utils import map_task_result_to_run_output
|
|
413
|
+
|
|
414
|
+
task_result = await self.a2a_client.send_message(
|
|
415
|
+
message=message,
|
|
416
|
+
context_id=context_id,
|
|
417
|
+
user_id=user_id,
|
|
418
|
+
images=list(images) if images else None,
|
|
419
|
+
audio=list(audio) if audio else None,
|
|
420
|
+
videos=list(videos) if videos else None,
|
|
421
|
+
files=list(files) if files else None,
|
|
422
|
+
headers=headers,
|
|
423
|
+
)
|
|
424
|
+
return map_task_result_to_run_output(task_result, agent_id=self.agent_id, user_id=user_id)
|
|
425
|
+
|
|
271
426
|
@overload
|
|
272
427
|
async def acontinue_run(
|
|
273
428
|
self,
|
|
@@ -307,27 +462,31 @@ class RemoteAgent(BaseRemote):
|
|
|
307
462
|
]:
|
|
308
463
|
headers = self._get_auth_headers(auth_token)
|
|
309
464
|
|
|
310
|
-
if
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
465
|
+
if self.agentos_client:
|
|
466
|
+
if stream:
|
|
467
|
+
# Handle streaming response
|
|
468
|
+
return self.agentos_client.continue_agent_run_stream( # type: ignore
|
|
469
|
+
agent_id=self.agent_id,
|
|
470
|
+
run_id=run_id,
|
|
471
|
+
user_id=user_id,
|
|
472
|
+
session_id=session_id,
|
|
473
|
+
tools=updated_tools,
|
|
474
|
+
headers=headers,
|
|
475
|
+
**kwargs,
|
|
476
|
+
)
|
|
477
|
+
else:
|
|
478
|
+
return self.agentos_client.continue_agent_run( # type: ignore
|
|
479
|
+
agent_id=self.agent_id,
|
|
480
|
+
run_id=run_id,
|
|
481
|
+
tools=updated_tools,
|
|
482
|
+
user_id=user_id,
|
|
483
|
+
session_id=session_id,
|
|
484
|
+
headers=headers,
|
|
485
|
+
**kwargs,
|
|
486
|
+
)
|
|
487
|
+
|
|
321
488
|
else:
|
|
322
|
-
|
|
323
|
-
agent_id=self.agent_id,
|
|
324
|
-
run_id=run_id,
|
|
325
|
-
tools=updated_tools,
|
|
326
|
-
user_id=user_id,
|
|
327
|
-
session_id=session_id,
|
|
328
|
-
headers=headers,
|
|
329
|
-
**kwargs,
|
|
330
|
-
)
|
|
489
|
+
raise ValueError("No client available")
|
|
331
490
|
|
|
332
491
|
async def cancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
|
|
333
492
|
"""Cancel a running agent execution.
|
|
@@ -340,8 +499,10 @@ class RemoteAgent(BaseRemote):
|
|
|
340
499
|
bool: True if the run was successfully cancelled, False otherwise.
|
|
341
500
|
"""
|
|
342
501
|
headers = self._get_auth_headers(auth_token)
|
|
502
|
+
if not self.agentos_client:
|
|
503
|
+
raise ValueError("AgentOS client not available")
|
|
343
504
|
try:
|
|
344
|
-
await self.
|
|
505
|
+
await self.agentos_client.cancel_agent_run(
|
|
345
506
|
agent_id=self.agent_id,
|
|
346
507
|
run_id=run_id,
|
|
347
508
|
headers=headers,
|