agno 2.3.16__py3-none-any.whl → 2.3.18__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.
Files changed (76) hide show
  1. agno/agent/__init__.py +2 -0
  2. agno/agent/agent.py +4 -53
  3. agno/agent/remote.py +351 -0
  4. agno/client/__init__.py +3 -0
  5. agno/client/os.py +2669 -0
  6. agno/db/base.py +20 -0
  7. agno/db/mongo/async_mongo.py +11 -0
  8. agno/db/mongo/mongo.py +10 -0
  9. agno/db/mysql/async_mysql.py +9 -0
  10. agno/db/mysql/mysql.py +9 -0
  11. agno/db/postgres/async_postgres.py +9 -0
  12. agno/db/postgres/postgres.py +9 -0
  13. agno/db/postgres/utils.py +3 -2
  14. agno/db/sqlite/async_sqlite.py +9 -0
  15. agno/db/sqlite/sqlite.py +11 -1
  16. agno/exceptions.py +23 -0
  17. agno/knowledge/chunking/semantic.py +123 -46
  18. agno/knowledge/reader/csv_reader.py +1 -1
  19. agno/knowledge/reader/field_labeled_csv_reader.py +1 -1
  20. agno/knowledge/reader/json_reader.py +1 -1
  21. agno/models/google/gemini.py +5 -0
  22. agno/os/app.py +108 -25
  23. agno/os/auth.py +25 -1
  24. agno/os/interfaces/a2a/a2a.py +7 -6
  25. agno/os/interfaces/a2a/router.py +13 -13
  26. agno/os/interfaces/agui/agui.py +5 -3
  27. agno/os/interfaces/agui/router.py +23 -16
  28. agno/os/interfaces/base.py +7 -7
  29. agno/os/interfaces/slack/router.py +6 -6
  30. agno/os/interfaces/slack/slack.py +7 -7
  31. agno/os/interfaces/whatsapp/router.py +29 -6
  32. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  33. agno/os/managers.py +326 -0
  34. agno/os/mcp.py +651 -79
  35. agno/os/router.py +125 -18
  36. agno/os/routers/agents/router.py +65 -22
  37. agno/os/routers/agents/schema.py +16 -4
  38. agno/os/routers/database.py +5 -0
  39. agno/os/routers/evals/evals.py +93 -11
  40. agno/os/routers/evals/utils.py +6 -6
  41. agno/os/routers/knowledge/knowledge.py +104 -16
  42. agno/os/routers/memory/memory.py +124 -7
  43. agno/os/routers/metrics/metrics.py +21 -4
  44. agno/os/routers/session/session.py +141 -12
  45. agno/os/routers/teams/router.py +40 -14
  46. agno/os/routers/teams/schema.py +12 -4
  47. agno/os/routers/traces/traces.py +54 -4
  48. agno/os/routers/workflows/router.py +223 -117
  49. agno/os/routers/workflows/schema.py +65 -1
  50. agno/os/schema.py +38 -12
  51. agno/os/utils.py +87 -166
  52. agno/remote/__init__.py +3 -0
  53. agno/remote/base.py +484 -0
  54. agno/run/workflow.py +1 -0
  55. agno/team/__init__.py +2 -0
  56. agno/team/remote.py +287 -0
  57. agno/team/team.py +25 -54
  58. agno/tracing/exporter.py +10 -6
  59. agno/tracing/setup.py +2 -1
  60. agno/utils/agent.py +58 -1
  61. agno/utils/http.py +68 -20
  62. agno/utils/os.py +0 -0
  63. agno/utils/remote.py +23 -0
  64. agno/vectordb/chroma/chromadb.py +452 -16
  65. agno/vectordb/pgvector/pgvector.py +7 -0
  66. agno/vectordb/redis/redisdb.py +1 -1
  67. agno/workflow/__init__.py +2 -0
  68. agno/workflow/agent.py +2 -2
  69. agno/workflow/remote.py +222 -0
  70. agno/workflow/types.py +0 -73
  71. agno/workflow/workflow.py +119 -68
  72. {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/METADATA +1 -1
  73. {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/RECORD +76 -66
  74. {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/WHEEL +0 -0
  75. {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/licenses/LICENSE +0 -0
  76. {agno-2.3.16.dist-info → agno-2.3.18.dist-info}/top_level.txt +0 -0
agno/remote/base.py ADDED
@@ -0,0 +1,484 @@
1
+ import time
2
+ from abc import abstractmethod
3
+ from dataclasses import dataclass, field
4
+ from datetime import date
5
+ from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Optional, Sequence, Tuple, Union
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from agno.db.base import SessionType
10
+ from agno.media import Audio, File, Image, Video
11
+ from agno.models.message import Message
12
+ from agno.models.response import ToolExecution
13
+ from agno.run.agent import RunOutput, RunOutputEvent
14
+ from agno.run.team import TeamRunOutput, TeamRunOutputEvent
15
+ from agno.run.workflow import WorkflowRunOutput, WorkflowRunOutputEvent
16
+
17
+ if TYPE_CHECKING:
18
+ from fastapi import UploadFile
19
+
20
+ from agno.client import AgentOSClient
21
+ from agno.os.routers.evals.schemas import EvalSchema
22
+ from agno.os.routers.knowledge.schemas import (
23
+ ConfigResponseSchema,
24
+ ContentResponseSchema,
25
+ ContentStatusResponse,
26
+ VectorSearchResult,
27
+ )
28
+ from agno.os.routers.memory.schemas import OptimizeMemoriesResponse, UserMemorySchema, UserStatsSchema
29
+ from agno.os.routers.metrics.schemas import DayAggregatedMetrics, MetricsResponse
30
+ from agno.os.routers.traces.schemas import TraceDetail, TraceNode, TraceSessionStats, TraceSummary
31
+ from agno.os.schema import (
32
+ AgentSessionDetailSchema,
33
+ ConfigResponse,
34
+ PaginatedResponse,
35
+ RunSchema,
36
+ SessionSchema,
37
+ TeamRunSchema,
38
+ TeamSessionDetailSchema,
39
+ WorkflowRunSchema,
40
+ WorkflowSessionDetailSchema,
41
+ )
42
+
43
+
44
+ @dataclass
45
+ class RemoteDb:
46
+ id: str
47
+ client: "AgentOSClient"
48
+ session_table_name: Optional[str] = None
49
+ knowledge_table_name: Optional[str] = None
50
+ memory_table_name: Optional[str] = None
51
+ metrics_table_name: Optional[str] = None
52
+ eval_table_name: Optional[str] = None
53
+ traces_table_name: Optional[str] = None
54
+ spans_table_name: Optional[str] = None
55
+ culture_table_name: Optional[str] = None
56
+
57
+ @classmethod
58
+ def from_config(
59
+ cls,
60
+ db_id: str,
61
+ client: "AgentOSClient",
62
+ config: "ConfigResponse",
63
+ ) -> Optional["RemoteDb"]:
64
+ """Create a RemoteDb instance from an AgentResponse/TeamResponse/WorkflowResponse and ConfigResponse.
65
+
66
+ Args:
67
+ response: The agent, team, or workflow response containing the db_id.
68
+ client: The AgentOSClient for remote operations.
69
+ config: The ConfigResponse containing database table information.
70
+
71
+ Returns:
72
+ RemoteDb instance if db_id is present, None otherwise.
73
+ """
74
+
75
+ session_table_name = None
76
+ knowledge_table_name = None
77
+ memory_table_name = None
78
+ metrics_table_name = None
79
+ eval_table_name = None
80
+ traces_table_name = None
81
+
82
+ if config and config.session and config.session.dbs is not None:
83
+ session_dbs = [db for db in config.session.dbs if db.db_id == db_id]
84
+ session_table_name = session_dbs[0].tables[0] if session_dbs and session_dbs[0].tables else None
85
+
86
+ if config and config.knowledge and config.knowledge.dbs is not None:
87
+ knowledge_dbs = [db for db in config.knowledge.dbs if db.db_id == db_id]
88
+ knowledge_table_name = knowledge_dbs[0].tables[0] if knowledge_dbs and knowledge_dbs[0].tables else None
89
+
90
+ if config and config.memory and config.memory.dbs is not None:
91
+ memory_dbs = [db for db in config.memory.dbs if db.db_id == db_id]
92
+ memory_table_name = memory_dbs[0].tables[0] if memory_dbs and memory_dbs[0].tables else None
93
+
94
+ if config and config.metrics and config.metrics.dbs is not None:
95
+ metrics_dbs = [db for db in config.metrics.dbs if db.db_id == db_id]
96
+ metrics_table_name = metrics_dbs[0].tables[0] if metrics_dbs and metrics_dbs[0].tables else None
97
+
98
+ if config and config.evals and config.evals.dbs is not None:
99
+ eval_dbs = [db for db in config.evals.dbs if db.db_id == db_id]
100
+ eval_table_name = eval_dbs[0].tables[0] if eval_dbs and eval_dbs[0].tables else None
101
+
102
+ if config and config.traces and config.traces.dbs is not None:
103
+ traces_dbs = [db for db in config.traces.dbs if db.db_id == db_id]
104
+ traces_table_name = traces_dbs[0].tables[0] if traces_dbs and traces_dbs[0].tables else None
105
+
106
+ return cls(
107
+ id=db_id,
108
+ client=client,
109
+ session_table_name=session_table_name,
110
+ knowledge_table_name=knowledge_table_name,
111
+ memory_table_name=memory_table_name,
112
+ metrics_table_name=metrics_table_name,
113
+ eval_table_name=eval_table_name,
114
+ traces_table_name=traces_table_name,
115
+ )
116
+
117
+ # SESSIONS
118
+ async def get_sessions(self, **kwargs: Any) -> "PaginatedResponse[SessionSchema]":
119
+ return await self.client.get_sessions(**kwargs)
120
+
121
+ async def get_session(
122
+ self, session_id: str, **kwargs: Any
123
+ ) -> Union["AgentSessionDetailSchema", "TeamSessionDetailSchema", "WorkflowSessionDetailSchema"]:
124
+ return await self.client.get_session(session_id, **kwargs)
125
+
126
+ async def get_session_runs(
127
+ self, session_id: str, **kwargs: Any
128
+ ) -> List[Union["RunSchema", "TeamRunSchema", "WorkflowRunSchema"]]:
129
+ return await self.client.get_session_runs(session_id, **kwargs)
130
+
131
+ async def create_session(
132
+ self,
133
+ session_id: Optional[str] = None,
134
+ session_name: Optional[str] = None,
135
+ session_state: Optional[Dict[str, Any]] = None,
136
+ metadata: Optional[Dict[str, Any]] = None,
137
+ user_id: Optional[str] = None,
138
+ agent_id: Optional[str] = None,
139
+ team_id: Optional[str] = None,
140
+ workflow_id: Optional[str] = None,
141
+ **kwargs: Any,
142
+ ) -> Union["AgentSessionDetailSchema", "TeamSessionDetailSchema", "WorkflowSessionDetailSchema"]:
143
+ return await self.client.create_session(
144
+ session_id=session_id,
145
+ session_name=session_name,
146
+ session_state=session_state,
147
+ metadata=metadata,
148
+ user_id=user_id,
149
+ agent_id=agent_id,
150
+ team_id=team_id,
151
+ workflow_id=workflow_id,
152
+ **kwargs,
153
+ )
154
+
155
+ async def get_session_run(
156
+ self, session_id: str, run_id: str, **kwargs: Any
157
+ ) -> Union["RunSchema", "TeamRunSchema", "WorkflowRunSchema"]:
158
+ return await self.client.get_session_run(session_id, run_id, **kwargs)
159
+
160
+ async def rename_session(
161
+ self, session_id: str, session_name: str, **kwargs: Any
162
+ ) -> Union["AgentSessionDetailSchema", "TeamSessionDetailSchema", "WorkflowSessionDetailSchema"]:
163
+ return await self.client.rename_session(session_id, session_name, **kwargs)
164
+
165
+ async def update_session(
166
+ self, session_id: str, session_type: SessionType, **kwargs: Any
167
+ ) -> Union["AgentSessionDetailSchema", "TeamSessionDetailSchema", "WorkflowSessionDetailSchema"]:
168
+ return await self.client.update_session(session_id=session_id, session_type=session_type, **kwargs)
169
+
170
+ async def delete_session(self, session_id: str, **kwargs: Any) -> None:
171
+ return await self.client.delete_session(session_id, **kwargs)
172
+
173
+ async def delete_sessions(self, session_ids: List[str], session_types: List[SessionType], **kwargs: Any) -> None:
174
+ return await self.client.delete_sessions(session_ids, session_types, **kwargs)
175
+
176
+ # MEMORIES
177
+ async def create_memory(self, memory: str, topics: List[str], user_id: str, **kwargs: Any) -> "UserMemorySchema":
178
+ return await self.client.create_memory(memory=memory, topics=topics, user_id=user_id, **kwargs)
179
+
180
+ async def delete_memory(self, memory_id: str, **kwargs: Any) -> None:
181
+ return await self.client.delete_memory(memory_id, **kwargs)
182
+
183
+ async def delete_memories(self, memory_ids: List[str], **kwargs: Any) -> None:
184
+ return await self.client.delete_memories(memory_ids, **kwargs)
185
+
186
+ async def get_memory(self, memory_id: str, **kwargs: Any) -> "UserMemorySchema":
187
+ return await self.client.get_memory(memory_id, **kwargs)
188
+
189
+ async def get_memories(self, user_id: Optional[str] = None, **kwargs: Any) -> "PaginatedResponse[UserMemorySchema]":
190
+ return await self.client.list_memories(user_id, **kwargs)
191
+
192
+ async def update_memory(self, memory_id: str, **kwargs: Any) -> "UserMemorySchema":
193
+ return await self.client.update_memory(memory_id, **kwargs)
194
+
195
+ async def get_user_memory_stats(self, **kwargs: Any) -> "PaginatedResponse[UserStatsSchema]":
196
+ return await self.client.get_user_memory_stats(**kwargs)
197
+
198
+ async def optimize_memories(self, **kwargs: Any) -> "OptimizeMemoriesResponse":
199
+ return await self.client.optimize_memories(**kwargs)
200
+
201
+ async def get_memory_topics(self, **kwargs: Any) -> List[str]:
202
+ return await self.client.get_memory_topics(**kwargs)
203
+
204
+ # TRACES
205
+ async def get_traces(self, **kwargs: Any) -> "PaginatedResponse[TraceSummary]":
206
+ return await self.client.get_traces(**kwargs)
207
+
208
+ async def get_trace(self, trace_id: str, **kwargs: Any) -> Union["TraceDetail", "TraceNode"]:
209
+ return await self.client.get_trace(trace_id, **kwargs)
210
+
211
+ async def get_trace_session_stats(self, **kwargs: Any) -> "PaginatedResponse[TraceSessionStats]":
212
+ return await self.client.get_trace_session_stats(**kwargs)
213
+
214
+ # EVALS
215
+ async def get_eval_runs(self, **kwargs: Any) -> "PaginatedResponse[EvalSchema]":
216
+ return await self.client.list_eval_runs(**kwargs)
217
+
218
+ async def get_eval_run(self, eval_run_id: str, **kwargs: Any) -> "EvalSchema":
219
+ return await self.client.get_eval_run(eval_run_id, **kwargs)
220
+
221
+ async def delete_eval_runs(self, eval_run_ids: List[str], **kwargs: Any) -> None:
222
+ return await self.client.delete_eval_runs(eval_run_ids, **kwargs)
223
+
224
+ async def update_eval_run(self, eval_run_id: str, **kwargs: Any) -> "EvalSchema":
225
+ return await self.client.update_eval_run(eval_run_id, **kwargs)
226
+
227
+ async def create_eval_run(self, **kwargs: Any) -> Optional["EvalSchema"]:
228
+ return await self.client.run_eval(**kwargs)
229
+
230
+ # METRICS
231
+ async def get_metrics(
232
+ self, starting_date: Optional[date] = None, ending_date: Optional[date] = None, **kwargs: Any
233
+ ) -> "MetricsResponse":
234
+ return await self.client.get_metrics(starting_date=starting_date, ending_date=ending_date, **kwargs)
235
+
236
+ async def refresh_metrics(self, **kwargs: Any) -> List["DayAggregatedMetrics"]:
237
+ return await self.client.refresh_metrics(**kwargs)
238
+
239
+ # OTHER
240
+ async def migrate_database(self, target_version: Optional[str] = None) -> None:
241
+ """Migrate the database to a target version.
242
+
243
+ Args:
244
+ target_version: Target version to migrate to
245
+ """
246
+
247
+ return await self.client.migrate_database(self.id, target_version)
248
+
249
+
250
+ @dataclass
251
+ class RemoteKnowledge:
252
+ client: "AgentOSClient"
253
+ contents_db: Optional[RemoteDb] = None
254
+
255
+ async def get_config(self, headers: Optional[Dict[str, str]] = None) -> "ConfigResponseSchema":
256
+ return await self.client.get_knowledge_config(
257
+ db_id=self.contents_db.id if self.contents_db else None, headers=headers
258
+ )
259
+
260
+ async def search_knowledge(self, query: str, **kwargs: Any) -> "PaginatedResponse[VectorSearchResult]":
261
+ return await self.client.search_knowledge(query, **kwargs)
262
+
263
+ async def upload_content(
264
+ self,
265
+ name: Optional[str] = None,
266
+ description: Optional[str] = None,
267
+ url: Optional[str] = None,
268
+ metadata: Optional[Dict[str, Any]] = None,
269
+ file: Optional[Union[File, "UploadFile"]] = None,
270
+ text_content: Optional[str] = None,
271
+ reader_id: Optional[str] = None,
272
+ chunker: Optional[str] = None,
273
+ chunk_size: Optional[int] = None,
274
+ chunk_overlap: Optional[int] = None,
275
+ db_id: Optional[str] = None,
276
+ **kwargs: Any,
277
+ ) -> "ContentResponseSchema":
278
+ return await self.client.upload_knowledge_content(
279
+ name=name,
280
+ description=description,
281
+ url=url,
282
+ metadata=metadata,
283
+ file=file,
284
+ text_content=text_content,
285
+ reader_id=reader_id,
286
+ chunker=chunker,
287
+ chunk_size=chunk_size,
288
+ chunk_overlap=chunk_overlap,
289
+ db_id=db_id,
290
+ **kwargs,
291
+ )
292
+
293
+ async def update_content(
294
+ self,
295
+ content_id: str,
296
+ name: Optional[str] = None,
297
+ description: Optional[str] = None,
298
+ metadata: Optional[Dict[str, Any]] = None,
299
+ reader_id: Optional[str] = None,
300
+ db_id: Optional[str] = None,
301
+ **kwargs: Any,
302
+ ) -> "ContentResponseSchema":
303
+ return await self.client.update_knowledge_content(
304
+ content_id=content_id,
305
+ name=name,
306
+ description=description,
307
+ metadata=metadata,
308
+ reader_id=reader_id,
309
+ db_id=db_id,
310
+ **kwargs,
311
+ )
312
+
313
+ async def get_content(
314
+ self,
315
+ limit: Optional[int] = None,
316
+ page: Optional[int] = None,
317
+ sort_by: Optional[str] = None,
318
+ sort_order: Optional[str] = None,
319
+ db_id: Optional[str] = None,
320
+ **kwargs: Any,
321
+ ) -> "PaginatedResponse[ContentResponseSchema]":
322
+ return await self.client.list_knowledge_content(
323
+ limit=limit, page=page, sort_by=sort_by, sort_order=sort_order, db_id=db_id, **kwargs
324
+ )
325
+
326
+ async def get_content_by_id(
327
+ self, content_id: str, db_id: Optional[str] = None, **kwargs: Any
328
+ ) -> "ContentResponseSchema":
329
+ return await self.client.get_knowledge_content(content_id=content_id, db_id=db_id, **kwargs)
330
+
331
+ async def delete_content_by_id(self, content_id: str, db_id: Optional[str] = None, **kwargs: Any) -> None:
332
+ await self.client.delete_knowledge_content(content_id=content_id, db_id=db_id, **kwargs)
333
+
334
+ async def delete_all_content(self, db_id: Optional[str] = None, **kwargs: Any) -> None:
335
+ await self.client.delete_all_knowledge_content(db_id=db_id, **kwargs)
336
+
337
+ async def get_content_status(
338
+ self, content_id: str, db_id: Optional[str] = None, **kwargs: Any
339
+ ) -> "ContentStatusResponse":
340
+ return await self.client.get_knowledge_content_status(content_id=content_id, db_id=db_id, **kwargs)
341
+
342
+
343
+ @dataclass
344
+ class BaseRemote:
345
+ # Private cache for OS config with TTL: (config, timestamp)
346
+ _cached_config: Optional[Tuple["ConfigResponse", float]] = field(default=None, init=False, repr=False)
347
+
348
+ def __init__(
349
+ self,
350
+ base_url: str,
351
+ timeout: float = 60.0,
352
+ config_ttl: float = 300.0,
353
+ ):
354
+ """Initialize BaseRemote for remote execution.
355
+
356
+ For local execution, provide agent/team/workflow instances.
357
+ For remote execution, provide base_url.
358
+
359
+ Args:
360
+ base_url: Base URL for remote instance (e.g., "http://localhost:7777")
361
+ timeout: Request timeout in seconds (default: 60)
362
+ config_ttl: Time-to-live for cached config in seconds (default: 300)
363
+ """
364
+ self.base_url = base_url.rstrip("/")
365
+ self.timeout: float = timeout
366
+ self.config_ttl: float = config_ttl
367
+ self._cached_config = None
368
+
369
+ self.client = self.get_client()
370
+
371
+ def get_client(self) -> "AgentOSClient":
372
+ """Get an AgentOSClient for fetching remote configuration.
373
+
374
+ This is used internally by AgentOS to fetch configuration from remote
375
+ AgentOS instances when this runner represents a remote resource.
376
+
377
+ Returns:
378
+ AgentOSClient: Client configured for this remote resource's base URL
379
+ """
380
+ from agno.client import AgentOSClient
381
+
382
+ return AgentOSClient(
383
+ base_url=self.base_url,
384
+ timeout=self.timeout,
385
+ )
386
+
387
+ @property
388
+ def _config(self) -> "ConfigResponse":
389
+ """Get the OS config from remote, cached with TTL."""
390
+ from agno.os.schema import ConfigResponse
391
+
392
+ current_time = time.time()
393
+
394
+ # Check if cache is valid
395
+ if self._cached_config is not None:
396
+ config, cached_at = self._cached_config
397
+ if current_time - cached_at < self.config_ttl:
398
+ return config
399
+
400
+ # Fetch fresh config
401
+ config: ConfigResponse = self.client.get_config() # type: ignore
402
+ self._cached_config = (config, current_time)
403
+ return config
404
+
405
+ def refresh_os_config(self) -> "ConfigResponse":
406
+ """Force refresh the cached OS config."""
407
+ from agno.os.schema import ConfigResponse
408
+
409
+ config: ConfigResponse = self.client.get_config()
410
+ self._cached_config = (config, time.time())
411
+ return config
412
+
413
+ def _get_headers(self, auth_token: Optional[str] = None) -> Dict[str, str]:
414
+ """Get headers for HTTP requests.
415
+
416
+ Args:
417
+ auth_token: Optional JWT token for authentication
418
+
419
+ Returns:
420
+ Dict[str, str]: Headers including Content-Type and optional Authorization
421
+ """
422
+ headers = {"Content-Type": "application/x-www-form-urlencoded"}
423
+ if auth_token:
424
+ headers["Authorization"] = f"Bearer {auth_token}"
425
+ return headers
426
+
427
+ def _get_auth_headers(self, auth_token: Optional[str] = None) -> Optional[Dict[str, str]]:
428
+ """Get Authorization headers for HTTP requests.
429
+
430
+ Args:
431
+ auth_token: Optional JWT token for authentication
432
+
433
+ Returns:
434
+ Dict[str, str] with Authorization header if auth_token is provided, None otherwise
435
+ """
436
+ if auth_token:
437
+ return {"Authorization": f"Bearer {auth_token}"}
438
+ return None
439
+
440
+ @abstractmethod
441
+ def arun( # type: ignore
442
+ self,
443
+ input: Union[str, List, Dict, Message, BaseModel, List[Message]],
444
+ *,
445
+ stream: Optional[bool] = None,
446
+ user_id: Optional[str] = None,
447
+ session_id: Optional[str] = None,
448
+ session_state: Optional[Dict[str, Any]] = None,
449
+ audio: Optional[Sequence[Audio]] = None,
450
+ images: Optional[Sequence[Image]] = None,
451
+ videos: Optional[Sequence[Video]] = None,
452
+ files: Optional[Sequence[File]] = None,
453
+ stream_events: Optional[bool] = None,
454
+ retries: Optional[int] = None,
455
+ knowledge_filters: Optional[Dict[str, Any]] = None,
456
+ add_history_to_context: Optional[bool] = None,
457
+ add_dependencies_to_context: Optional[bool] = None,
458
+ add_session_state_to_context: Optional[bool] = None,
459
+ dependencies: Optional[Dict[str, Any]] = None,
460
+ metadata: Optional[Dict[str, Any]] = None,
461
+ auth_token: Optional[str] = None,
462
+ **kwargs: Any,
463
+ ) -> Union[
464
+ RunOutput,
465
+ TeamRunOutput,
466
+ WorkflowRunOutput,
467
+ AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, WorkflowRunOutputEvent]],
468
+ ]:
469
+ raise NotImplementedError("arun method must be implemented by the subclass")
470
+
471
+ @abstractmethod
472
+ async def acontinue_run( # type: ignore
473
+ self,
474
+ run_id: str,
475
+ stream: Optional[bool] = None,
476
+ updated_tools: Optional[List[ToolExecution]] = None,
477
+ user_id: Optional[str] = None,
478
+ session_id: Optional[str] = None,
479
+ ) -> Union[RunOutput, TeamRunOutput, WorkflowRunOutput]:
480
+ raise NotImplementedError("acontinue_run method must be implemented by the subclass")
481
+
482
+ @abstractmethod
483
+ async def cancel_run(self, run_id: str) -> bool:
484
+ raise NotImplementedError("cancel_run method must be implemented by the subclass")
agno/run/workflow.py CHANGED
@@ -500,6 +500,7 @@ class WorkflowRunOutput:
500
500
 
501
501
  run_id: Optional[str] = None
502
502
  session_id: Optional[str] = None
503
+ user_id: Optional[str] = None
503
504
 
504
505
  # Media content fields
505
506
  images: Optional[List[Image]] = None
agno/team/__init__.py CHANGED
@@ -15,10 +15,12 @@ from agno.run.team import (
15
15
  ToolCallCompletedEvent,
16
16
  ToolCallStartedEvent,
17
17
  )
18
+ from agno.team.remote import RemoteTeam
18
19
  from agno.team.team import Team
19
20
 
20
21
  __all__ = [
21
22
  "Team",
23
+ "RemoteTeam",
22
24
  "TeamRunOutput",
23
25
  "TeamRunOutputEvent",
24
26
  "TeamRunEvent",