agno 2.0.0rc2__py3-none-any.whl → 2.3.0__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 (331) hide show
  1. agno/agent/agent.py +6009 -2874
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/culture/__init__.py +3 -0
  5. agno/culture/manager.py +956 -0
  6. agno/db/async_postgres/__init__.py +3 -0
  7. agno/db/base.py +385 -6
  8. agno/db/dynamo/dynamo.py +388 -81
  9. agno/db/dynamo/schemas.py +47 -10
  10. agno/db/dynamo/utils.py +63 -4
  11. agno/db/firestore/firestore.py +435 -64
  12. agno/db/firestore/schemas.py +11 -0
  13. agno/db/firestore/utils.py +102 -4
  14. agno/db/gcs_json/gcs_json_db.py +384 -42
  15. agno/db/gcs_json/utils.py +60 -26
  16. agno/db/in_memory/in_memory_db.py +351 -66
  17. agno/db/in_memory/utils.py +60 -2
  18. agno/db/json/json_db.py +339 -48
  19. agno/db/json/utils.py +60 -26
  20. agno/db/migrations/manager.py +199 -0
  21. agno/db/migrations/v1_to_v2.py +510 -37
  22. agno/db/migrations/versions/__init__.py +0 -0
  23. agno/db/migrations/versions/v2_3_0.py +938 -0
  24. agno/db/mongo/__init__.py +15 -1
  25. agno/db/mongo/async_mongo.py +2036 -0
  26. agno/db/mongo/mongo.py +653 -76
  27. agno/db/mongo/schemas.py +13 -0
  28. agno/db/mongo/utils.py +80 -8
  29. agno/db/mysql/mysql.py +687 -25
  30. agno/db/mysql/schemas.py +61 -37
  31. agno/db/mysql/utils.py +60 -2
  32. agno/db/postgres/__init__.py +2 -1
  33. agno/db/postgres/async_postgres.py +2001 -0
  34. agno/db/postgres/postgres.py +676 -57
  35. agno/db/postgres/schemas.py +43 -18
  36. agno/db/postgres/utils.py +164 -2
  37. agno/db/redis/redis.py +344 -38
  38. agno/db/redis/schemas.py +18 -0
  39. agno/db/redis/utils.py +60 -2
  40. agno/db/schemas/__init__.py +2 -1
  41. agno/db/schemas/culture.py +120 -0
  42. agno/db/schemas/memory.py +13 -0
  43. agno/db/singlestore/schemas.py +26 -1
  44. agno/db/singlestore/singlestore.py +687 -53
  45. agno/db/singlestore/utils.py +60 -2
  46. agno/db/sqlite/__init__.py +2 -1
  47. agno/db/sqlite/async_sqlite.py +2371 -0
  48. agno/db/sqlite/schemas.py +24 -0
  49. agno/db/sqlite/sqlite.py +774 -85
  50. agno/db/sqlite/utils.py +168 -5
  51. agno/db/surrealdb/__init__.py +3 -0
  52. agno/db/surrealdb/metrics.py +292 -0
  53. agno/db/surrealdb/models.py +309 -0
  54. agno/db/surrealdb/queries.py +71 -0
  55. agno/db/surrealdb/surrealdb.py +1361 -0
  56. agno/db/surrealdb/utils.py +147 -0
  57. agno/db/utils.py +50 -22
  58. agno/eval/accuracy.py +50 -43
  59. agno/eval/performance.py +6 -3
  60. agno/eval/reliability.py +6 -3
  61. agno/eval/utils.py +33 -16
  62. agno/exceptions.py +68 -1
  63. agno/filters.py +354 -0
  64. agno/guardrails/__init__.py +6 -0
  65. agno/guardrails/base.py +19 -0
  66. agno/guardrails/openai.py +144 -0
  67. agno/guardrails/pii.py +94 -0
  68. agno/guardrails/prompt_injection.py +52 -0
  69. agno/integrations/discord/client.py +1 -0
  70. agno/knowledge/chunking/agentic.py +13 -10
  71. agno/knowledge/chunking/fixed.py +1 -1
  72. agno/knowledge/chunking/semantic.py +40 -8
  73. agno/knowledge/chunking/strategy.py +59 -15
  74. agno/knowledge/embedder/aws_bedrock.py +9 -4
  75. agno/knowledge/embedder/azure_openai.py +54 -0
  76. agno/knowledge/embedder/base.py +2 -0
  77. agno/knowledge/embedder/cohere.py +184 -5
  78. agno/knowledge/embedder/fastembed.py +1 -1
  79. agno/knowledge/embedder/google.py +79 -1
  80. agno/knowledge/embedder/huggingface.py +9 -4
  81. agno/knowledge/embedder/jina.py +63 -0
  82. agno/knowledge/embedder/mistral.py +78 -11
  83. agno/knowledge/embedder/nebius.py +1 -1
  84. agno/knowledge/embedder/ollama.py +13 -0
  85. agno/knowledge/embedder/openai.py +37 -65
  86. agno/knowledge/embedder/sentence_transformer.py +8 -4
  87. agno/knowledge/embedder/vllm.py +262 -0
  88. agno/knowledge/embedder/voyageai.py +69 -16
  89. agno/knowledge/knowledge.py +595 -187
  90. agno/knowledge/reader/base.py +9 -2
  91. agno/knowledge/reader/csv_reader.py +8 -10
  92. agno/knowledge/reader/docx_reader.py +5 -6
  93. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  94. agno/knowledge/reader/json_reader.py +6 -5
  95. agno/knowledge/reader/markdown_reader.py +13 -13
  96. agno/knowledge/reader/pdf_reader.py +43 -68
  97. agno/knowledge/reader/pptx_reader.py +101 -0
  98. agno/knowledge/reader/reader_factory.py +51 -6
  99. agno/knowledge/reader/s3_reader.py +3 -15
  100. agno/knowledge/reader/tavily_reader.py +194 -0
  101. agno/knowledge/reader/text_reader.py +13 -13
  102. agno/knowledge/reader/web_search_reader.py +2 -43
  103. agno/knowledge/reader/website_reader.py +43 -25
  104. agno/knowledge/reranker/__init__.py +3 -0
  105. agno/knowledge/types.py +9 -0
  106. agno/knowledge/utils.py +20 -0
  107. agno/media.py +339 -266
  108. agno/memory/manager.py +336 -82
  109. agno/models/aimlapi/aimlapi.py +2 -2
  110. agno/models/anthropic/claude.py +183 -37
  111. agno/models/aws/bedrock.py +52 -112
  112. agno/models/aws/claude.py +33 -1
  113. agno/models/azure/ai_foundry.py +33 -15
  114. agno/models/azure/openai_chat.py +25 -8
  115. agno/models/base.py +1011 -566
  116. agno/models/cerebras/cerebras.py +19 -13
  117. agno/models/cerebras/cerebras_openai.py +8 -5
  118. agno/models/cohere/chat.py +27 -1
  119. agno/models/cometapi/__init__.py +5 -0
  120. agno/models/cometapi/cometapi.py +57 -0
  121. agno/models/dashscope/dashscope.py +1 -0
  122. agno/models/deepinfra/deepinfra.py +2 -2
  123. agno/models/deepseek/deepseek.py +2 -2
  124. agno/models/fireworks/fireworks.py +2 -2
  125. agno/models/google/gemini.py +110 -37
  126. agno/models/groq/groq.py +28 -11
  127. agno/models/huggingface/huggingface.py +2 -1
  128. agno/models/internlm/internlm.py +2 -2
  129. agno/models/langdb/langdb.py +4 -4
  130. agno/models/litellm/chat.py +18 -1
  131. agno/models/litellm/litellm_openai.py +2 -2
  132. agno/models/llama_cpp/__init__.py +5 -0
  133. agno/models/llama_cpp/llama_cpp.py +22 -0
  134. agno/models/message.py +143 -4
  135. agno/models/meta/llama.py +27 -10
  136. agno/models/meta/llama_openai.py +5 -17
  137. agno/models/nebius/nebius.py +6 -6
  138. agno/models/nexus/__init__.py +3 -0
  139. agno/models/nexus/nexus.py +22 -0
  140. agno/models/nvidia/nvidia.py +2 -2
  141. agno/models/ollama/chat.py +60 -6
  142. agno/models/openai/chat.py +102 -43
  143. agno/models/openai/responses.py +103 -106
  144. agno/models/openrouter/openrouter.py +41 -3
  145. agno/models/perplexity/perplexity.py +4 -5
  146. agno/models/portkey/portkey.py +3 -3
  147. agno/models/requesty/__init__.py +5 -0
  148. agno/models/requesty/requesty.py +52 -0
  149. agno/models/response.py +81 -5
  150. agno/models/sambanova/sambanova.py +2 -2
  151. agno/models/siliconflow/__init__.py +5 -0
  152. agno/models/siliconflow/siliconflow.py +25 -0
  153. agno/models/together/together.py +2 -2
  154. agno/models/utils.py +254 -8
  155. agno/models/vercel/v0.py +2 -2
  156. agno/models/vertexai/__init__.py +0 -0
  157. agno/models/vertexai/claude.py +96 -0
  158. agno/models/vllm/vllm.py +1 -0
  159. agno/models/xai/xai.py +3 -2
  160. agno/os/app.py +543 -175
  161. agno/os/auth.py +24 -14
  162. agno/os/config.py +1 -0
  163. agno/os/interfaces/__init__.py +1 -0
  164. agno/os/interfaces/a2a/__init__.py +3 -0
  165. agno/os/interfaces/a2a/a2a.py +42 -0
  166. agno/os/interfaces/a2a/router.py +250 -0
  167. agno/os/interfaces/a2a/utils.py +924 -0
  168. agno/os/interfaces/agui/agui.py +23 -7
  169. agno/os/interfaces/agui/router.py +27 -3
  170. agno/os/interfaces/agui/utils.py +242 -142
  171. agno/os/interfaces/base.py +6 -2
  172. agno/os/interfaces/slack/router.py +81 -23
  173. agno/os/interfaces/slack/slack.py +29 -14
  174. agno/os/interfaces/whatsapp/router.py +11 -4
  175. agno/os/interfaces/whatsapp/whatsapp.py +14 -7
  176. agno/os/mcp.py +111 -54
  177. agno/os/middleware/__init__.py +7 -0
  178. agno/os/middleware/jwt.py +233 -0
  179. agno/os/router.py +556 -139
  180. agno/os/routers/evals/evals.py +71 -34
  181. agno/os/routers/evals/schemas.py +31 -31
  182. agno/os/routers/evals/utils.py +6 -5
  183. agno/os/routers/health.py +31 -0
  184. agno/os/routers/home.py +52 -0
  185. agno/os/routers/knowledge/knowledge.py +185 -38
  186. agno/os/routers/knowledge/schemas.py +82 -22
  187. agno/os/routers/memory/memory.py +158 -53
  188. agno/os/routers/memory/schemas.py +20 -16
  189. agno/os/routers/metrics/metrics.py +20 -8
  190. agno/os/routers/metrics/schemas.py +16 -16
  191. agno/os/routers/session/session.py +499 -38
  192. agno/os/schema.py +308 -198
  193. agno/os/utils.py +401 -41
  194. agno/reasoning/anthropic.py +80 -0
  195. agno/reasoning/azure_ai_foundry.py +2 -2
  196. agno/reasoning/deepseek.py +2 -2
  197. agno/reasoning/default.py +3 -1
  198. agno/reasoning/gemini.py +73 -0
  199. agno/reasoning/groq.py +2 -2
  200. agno/reasoning/ollama.py +2 -2
  201. agno/reasoning/openai.py +7 -2
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +266 -112
  205. agno/run/base.py +53 -24
  206. agno/run/team.py +252 -111
  207. agno/run/workflow.py +156 -45
  208. agno/session/agent.py +105 -89
  209. agno/session/summary.py +65 -25
  210. agno/session/team.py +176 -96
  211. agno/session/workflow.py +406 -40
  212. agno/team/team.py +3854 -1692
  213. agno/tools/brightdata.py +3 -3
  214. agno/tools/cartesia.py +3 -5
  215. agno/tools/dalle.py +9 -8
  216. agno/tools/decorator.py +4 -2
  217. agno/tools/desi_vocal.py +2 -2
  218. agno/tools/duckduckgo.py +15 -11
  219. agno/tools/e2b.py +20 -13
  220. agno/tools/eleven_labs.py +26 -28
  221. agno/tools/exa.py +21 -16
  222. agno/tools/fal.py +4 -4
  223. agno/tools/file.py +153 -23
  224. agno/tools/file_generation.py +350 -0
  225. agno/tools/firecrawl.py +4 -4
  226. agno/tools/function.py +257 -37
  227. agno/tools/giphy.py +2 -2
  228. agno/tools/gmail.py +238 -14
  229. agno/tools/google_drive.py +270 -0
  230. agno/tools/googlecalendar.py +36 -8
  231. agno/tools/googlesheets.py +20 -5
  232. agno/tools/jira.py +20 -0
  233. agno/tools/knowledge.py +3 -3
  234. agno/tools/lumalab.py +3 -3
  235. agno/tools/mcp/__init__.py +10 -0
  236. agno/tools/mcp/mcp.py +331 -0
  237. agno/tools/mcp/multi_mcp.py +347 -0
  238. agno/tools/mcp/params.py +24 -0
  239. agno/tools/mcp_toolbox.py +284 -0
  240. agno/tools/mem0.py +11 -17
  241. agno/tools/memori.py +1 -53
  242. agno/tools/memory.py +419 -0
  243. agno/tools/models/azure_openai.py +2 -2
  244. agno/tools/models/gemini.py +3 -3
  245. agno/tools/models/groq.py +3 -5
  246. agno/tools/models/nebius.py +7 -7
  247. agno/tools/models_labs.py +25 -15
  248. agno/tools/notion.py +204 -0
  249. agno/tools/openai.py +4 -9
  250. agno/tools/opencv.py +3 -3
  251. agno/tools/parallel.py +314 -0
  252. agno/tools/replicate.py +7 -7
  253. agno/tools/scrapegraph.py +58 -31
  254. agno/tools/searxng.py +2 -2
  255. agno/tools/serper.py +2 -2
  256. agno/tools/slack.py +18 -3
  257. agno/tools/spider.py +2 -2
  258. agno/tools/tavily.py +146 -0
  259. agno/tools/whatsapp.py +1 -1
  260. agno/tools/workflow.py +278 -0
  261. agno/tools/yfinance.py +12 -11
  262. agno/utils/agent.py +820 -0
  263. agno/utils/audio.py +27 -0
  264. agno/utils/common.py +90 -1
  265. agno/utils/events.py +222 -7
  266. agno/utils/gemini.py +181 -23
  267. agno/utils/hooks.py +57 -0
  268. agno/utils/http.py +111 -0
  269. agno/utils/knowledge.py +12 -5
  270. agno/utils/log.py +1 -0
  271. agno/utils/mcp.py +95 -5
  272. agno/utils/media.py +188 -10
  273. agno/utils/merge_dict.py +22 -1
  274. agno/utils/message.py +60 -0
  275. agno/utils/models/claude.py +40 -11
  276. agno/utils/models/cohere.py +1 -1
  277. agno/utils/models/watsonx.py +1 -1
  278. agno/utils/openai.py +1 -1
  279. agno/utils/print_response/agent.py +105 -21
  280. agno/utils/print_response/team.py +103 -38
  281. agno/utils/print_response/workflow.py +251 -34
  282. agno/utils/reasoning.py +22 -1
  283. agno/utils/serialize.py +32 -0
  284. agno/utils/streamlit.py +16 -10
  285. agno/utils/string.py +41 -0
  286. agno/utils/team.py +98 -9
  287. agno/utils/tools.py +1 -1
  288. agno/vectordb/base.py +23 -4
  289. agno/vectordb/cassandra/cassandra.py +65 -9
  290. agno/vectordb/chroma/chromadb.py +182 -38
  291. agno/vectordb/clickhouse/clickhousedb.py +64 -11
  292. agno/vectordb/couchbase/couchbase.py +105 -10
  293. agno/vectordb/lancedb/lance_db.py +183 -135
  294. agno/vectordb/langchaindb/langchaindb.py +25 -7
  295. agno/vectordb/lightrag/lightrag.py +17 -3
  296. agno/vectordb/llamaindex/__init__.py +3 -0
  297. agno/vectordb/llamaindex/llamaindexdb.py +46 -7
  298. agno/vectordb/milvus/milvus.py +126 -9
  299. agno/vectordb/mongodb/__init__.py +7 -1
  300. agno/vectordb/mongodb/mongodb.py +112 -7
  301. agno/vectordb/pgvector/pgvector.py +142 -21
  302. agno/vectordb/pineconedb/pineconedb.py +80 -8
  303. agno/vectordb/qdrant/qdrant.py +125 -39
  304. agno/vectordb/redis/__init__.py +9 -0
  305. agno/vectordb/redis/redisdb.py +694 -0
  306. agno/vectordb/singlestore/singlestore.py +111 -25
  307. agno/vectordb/surrealdb/surrealdb.py +31 -5
  308. agno/vectordb/upstashdb/upstashdb.py +76 -8
  309. agno/vectordb/weaviate/weaviate.py +86 -15
  310. agno/workflow/__init__.py +2 -0
  311. agno/workflow/agent.py +299 -0
  312. agno/workflow/condition.py +112 -18
  313. agno/workflow/loop.py +69 -10
  314. agno/workflow/parallel.py +266 -118
  315. agno/workflow/router.py +110 -17
  316. agno/workflow/step.py +645 -136
  317. agno/workflow/steps.py +65 -6
  318. agno/workflow/types.py +71 -33
  319. agno/workflow/workflow.py +2113 -300
  320. agno-2.3.0.dist-info/METADATA +618 -0
  321. agno-2.3.0.dist-info/RECORD +577 -0
  322. agno-2.3.0.dist-info/licenses/LICENSE +201 -0
  323. agno/knowledge/reader/url_reader.py +0 -128
  324. agno/tools/googlesearch.py +0 -98
  325. agno/tools/mcp.py +0 -610
  326. agno/utils/models/aws_claude.py +0 -170
  327. agno-2.0.0rc2.dist-info/METADATA +0 -355
  328. agno-2.0.0rc2.dist-info/RECORD +0 -515
  329. agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
  330. {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
  331. {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/run/team.py CHANGED
@@ -5,13 +5,125 @@ from typing import Any, Dict, List, Optional, Sequence, Union
5
5
 
6
6
  from pydantic import BaseModel
7
7
 
8
- from agno.media import AudioArtifact, AudioResponse, File, ImageArtifact, VideoArtifact
8
+ from agno.media import Audio, File, Image, Video
9
9
  from agno.models.message import Citations, Message
10
10
  from agno.models.metrics import Metrics
11
11
  from agno.models.response import ToolExecution
12
12
  from agno.reasoning.step import ReasoningStep
13
13
  from agno.run.agent import RunEvent, RunOutput, RunOutputEvent, run_output_event_from_dict
14
14
  from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
15
+ from agno.utils.log import log_error
16
+ from agno.utils.media import (
17
+ reconstruct_audio_list,
18
+ reconstruct_files,
19
+ reconstruct_images,
20
+ reconstruct_response_audio,
21
+ reconstruct_videos,
22
+ )
23
+
24
+
25
+ @dataclass
26
+ class TeamRunInput:
27
+ """Container for the raw input data passed to Agent.run().
28
+ This captures the original input exactly as provided by the user,
29
+ separate from the processed messages that go to the model.
30
+ Attributes:
31
+ input_content: The literal input message/content passed to run()
32
+ images: Images directly passed to run()
33
+ videos: Videos directly passed to run()
34
+ audios: Audio files directly passed to run()
35
+ files: Files directly passed to run()
36
+ """
37
+
38
+ input_content: Union[str, List, Dict, Message, BaseModel, List[Message]]
39
+ images: Optional[Sequence[Image]] = None
40
+ videos: Optional[Sequence[Video]] = None
41
+ audios: Optional[Sequence[Audio]] = None
42
+ files: Optional[Sequence[File]] = None
43
+
44
+ def input_content_string(self) -> str:
45
+ import json
46
+
47
+ if isinstance(self.input_content, (str)):
48
+ return self.input_content
49
+ elif isinstance(self.input_content, BaseModel):
50
+ return self.input_content.model_dump_json(exclude_none=True)
51
+ elif isinstance(self.input_content, Message):
52
+ return json.dumps(self.input_content.to_dict())
53
+ elif isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], Message):
54
+ return json.dumps([m.to_dict() for m in self.input_content])
55
+ else:
56
+ return str(self.input_content)
57
+
58
+ def to_dict(self) -> Dict[str, Any]:
59
+ """Convert to dictionary representation"""
60
+ result: Dict[str, Any] = {}
61
+
62
+ if self.input_content is not None:
63
+ if isinstance(self.input_content, (str)):
64
+ result["input_content"] = self.input_content
65
+ elif isinstance(self.input_content, BaseModel):
66
+ result["input_content"] = self.input_content.model_dump(exclude_none=True)
67
+ elif isinstance(self.input_content, Message):
68
+ result["input_content"] = self.input_content.to_dict()
69
+
70
+ # Handle input_content provided as a list of Message objects
71
+ elif (
72
+ isinstance(self.input_content, list)
73
+ and self.input_content
74
+ and isinstance(self.input_content[0], Message)
75
+ ):
76
+ result["input_content"] = [m.to_dict() for m in self.input_content]
77
+
78
+ # Handle input_content provided as a list of dicts
79
+ elif (
80
+ isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
81
+ ):
82
+ for content in self.input_content:
83
+ # Handle media input
84
+ if isinstance(content, dict):
85
+ if content.get("images"):
86
+ content["images"] = [
87
+ img.to_dict() if isinstance(img, Image) else img for img in content["images"]
88
+ ]
89
+ if content.get("videos"):
90
+ content["videos"] = [
91
+ vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
92
+ ]
93
+ if content.get("audios"):
94
+ content["audios"] = [
95
+ aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
96
+ ]
97
+ if content.get("files"):
98
+ content["files"] = [
99
+ file.to_dict() if isinstance(file, File) else file for file in content["files"]
100
+ ]
101
+ result["input_content"] = self.input_content
102
+ else:
103
+ result["input_content"] = self.input_content
104
+
105
+ if self.images:
106
+ result["images"] = [img.to_dict() for img in self.images]
107
+ if self.videos:
108
+ result["videos"] = [vid.to_dict() for vid in self.videos]
109
+ if self.audios:
110
+ result["audios"] = [aud.to_dict() for aud in self.audios]
111
+ if self.files:
112
+ result["files"] = [file.to_dict() for file in self.files]
113
+
114
+ return result
115
+
116
+ @classmethod
117
+ def from_dict(cls, data: Dict[str, Any]) -> "TeamRunInput":
118
+ """Create TeamRunInput from dictionary"""
119
+ images = reconstruct_images(data.get("images"))
120
+ videos = reconstruct_videos(data.get("videos"))
121
+ audios = reconstruct_audio_list(data.get("audios"))
122
+ files = reconstruct_files(data.get("files"))
123
+
124
+ return cls(
125
+ input_content=data.get("input_content", ""), images=images, videos=videos, audios=audios, files=files
126
+ )
15
127
 
16
128
 
17
129
  class TeamRunEvent(str, Enum):
@@ -20,10 +132,17 @@ class TeamRunEvent(str, Enum):
20
132
  run_started = "TeamRunStarted"
21
133
  run_content = "TeamRunContent"
22
134
  run_intermediate_content = "TeamRunIntermediateContent"
135
+ run_content_completed = "TeamRunContentCompleted"
23
136
  run_completed = "TeamRunCompleted"
24
137
  run_error = "TeamRunError"
25
138
  run_cancelled = "TeamRunCancelled"
26
139
 
140
+ pre_hook_started = "TeamPreHookStarted"
141
+ pre_hook_completed = "TeamPreHookCompleted"
142
+
143
+ post_hook_started = "TeamPostHookStarted"
144
+ post_hook_completed = "TeamPostHookCompleted"
145
+
27
146
  tool_call_started = "TeamToolCallStarted"
28
147
  tool_call_completed = "TeamToolCallCompleted"
29
148
 
@@ -34,6 +153,9 @@ class TeamRunEvent(str, Enum):
34
153
  memory_update_started = "TeamMemoryUpdateStarted"
35
154
  memory_update_completed = "TeamMemoryUpdateCompleted"
36
155
 
156
+ session_summary_started = "TeamSessionSummaryStarted"
157
+ session_summary_completed = "TeamSessionSummaryCompleted"
158
+
37
159
  parser_model_response_started = "TeamParserModelResponseStarted"
38
160
  parser_model_response_completed = "TeamParserModelResponseCompleted"
39
161
 
@@ -50,6 +172,7 @@ class BaseTeamRunEvent(BaseRunOutputEvent):
50
172
  team_id: str = ""
51
173
  team_name: str = ""
52
174
  run_id: Optional[str] = None
175
+ parent_run_id: Optional[str] = None
53
176
  session_id: Optional[str] = None
54
177
 
55
178
  workflow_id: Optional[str] = None
@@ -97,9 +220,10 @@ class RunContentEvent(BaseTeamRunEvent):
97
220
  content: Optional[Any] = None
98
221
  content_type: str = "str"
99
222
  reasoning_content: Optional[str] = None
223
+ model_provider_data: Optional[Dict[str, Any]] = None
100
224
  citations: Optional[Citations] = None
101
- response_audio: Optional[AudioResponse] = None # Model audio response
102
- image: Optional[ImageArtifact] = None # Image attached to the response
225
+ response_audio: Optional[Audio] = None # Model audio response
226
+ image: Optional[Image] = None # Image attached to the response
103
227
  references: Optional[List[MessageReferences]] = None
104
228
  additional_input: Optional[List[Message]] = None
105
229
  reasoning_steps: Optional[List[ReasoningStep]] = None
@@ -113,6 +237,11 @@ class IntermediateRunContentEvent(BaseTeamRunEvent):
113
237
  content_type: str = "str"
114
238
 
115
239
 
240
+ @dataclass
241
+ class RunContentCompletedEvent(BaseTeamRunEvent):
242
+ event: str = TeamRunEvent.run_content_completed.value
243
+
244
+
116
245
  @dataclass
117
246
  class RunCompletedEvent(BaseTeamRunEvent):
118
247
  event: str = TeamRunEvent.run_completed.value
@@ -120,10 +249,11 @@ class RunCompletedEvent(BaseTeamRunEvent):
120
249
  content_type: str = "str"
121
250
  reasoning_content: Optional[str] = None
122
251
  citations: Optional[Citations] = None
123
- images: Optional[List[ImageArtifact]] = None # Images attached to the response
124
- videos: Optional[List[VideoArtifact]] = None # Videos attached to the response
125
- audio: Optional[List[AudioArtifact]] = None # Audio attached to the response
126
- response_audio: Optional[AudioResponse] = None # Model audio response
252
+ model_provider_data: Optional[Dict[str, Any]] = None
253
+ images: Optional[List[Image]] = None # Images attached to the response
254
+ videos: Optional[List[Video]] = None # Videos attached to the response
255
+ audio: Optional[List[Audio]] = None # Audio attached to the response
256
+ response_audio: Optional[Audio] = None # Model audio response
127
257
  references: Optional[List[MessageReferences]] = None
128
258
  additional_input: Optional[List[Message]] = None
129
259
  reasoning_steps: Optional[List[ReasoningStep]] = None
@@ -131,6 +261,7 @@ class RunCompletedEvent(BaseTeamRunEvent):
131
261
  member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
132
262
  metadata: Optional[Dict[str, Any]] = None
133
263
  metrics: Optional[Metrics] = None
264
+ session_state: Optional[Dict[str, Any]] = None
134
265
 
135
266
 
136
267
  @dataclass
@@ -138,6 +269,11 @@ class RunErrorEvent(BaseTeamRunEvent):
138
269
  event: str = TeamRunEvent.run_error.value
139
270
  content: Optional[str] = None
140
271
 
272
+ # From exceptions
273
+ error_type: Optional[str] = None
274
+ error_id: Optional[str] = None
275
+ additional_data: Optional[Dict[str, Any]] = None
276
+
141
277
 
142
278
  @dataclass
143
279
  class RunCancelledEvent(BaseTeamRunEvent):
@@ -149,6 +285,32 @@ class RunCancelledEvent(BaseTeamRunEvent):
149
285
  return True
150
286
 
151
287
 
288
+ @dataclass
289
+ class PreHookStartedEvent(BaseTeamRunEvent):
290
+ event: str = TeamRunEvent.pre_hook_started.value
291
+ pre_hook_name: Optional[str] = None
292
+ run_input: Optional[TeamRunInput] = None
293
+
294
+
295
+ @dataclass
296
+ class PreHookCompletedEvent(BaseTeamRunEvent):
297
+ event: str = TeamRunEvent.pre_hook_completed.value
298
+ pre_hook_name: Optional[str] = None
299
+ run_input: Optional[TeamRunInput] = None
300
+
301
+
302
+ @dataclass
303
+ class PostHookStartedEvent(BaseTeamRunEvent):
304
+ event: str = TeamRunEvent.post_hook_started.value
305
+ post_hook_name: Optional[str] = None
306
+
307
+
308
+ @dataclass
309
+ class PostHookCompletedEvent(BaseTeamRunEvent):
310
+ event: str = TeamRunEvent.post_hook_completed.value
311
+ post_hook_name: Optional[str] = None
312
+
313
+
152
314
  @dataclass
153
315
  class MemoryUpdateStartedEvent(BaseTeamRunEvent):
154
316
  event: str = TeamRunEvent.memory_update_started.value
@@ -159,6 +321,17 @@ class MemoryUpdateCompletedEvent(BaseTeamRunEvent):
159
321
  event: str = TeamRunEvent.memory_update_completed.value
160
322
 
161
323
 
324
+ @dataclass
325
+ class SessionSummaryStartedEvent(BaseTeamRunEvent):
326
+ event: str = TeamRunEvent.session_summary_started.value
327
+
328
+
329
+ @dataclass
330
+ class SessionSummaryCompletedEvent(BaseTeamRunEvent):
331
+ event: str = TeamRunEvent.session_summary_completed.value
332
+ session_summary: Optional[Any] = None
333
+
334
+
162
335
  @dataclass
163
336
  class ReasoningStartedEvent(BaseTeamRunEvent):
164
337
  event: str = TeamRunEvent.reasoning_started.value
@@ -190,9 +363,9 @@ class ToolCallCompletedEvent(BaseTeamRunEvent):
190
363
  event: str = TeamRunEvent.tool_call_completed.value
191
364
  tool: Optional[ToolExecution] = None
192
365
  content: Optional[Any] = None
193
- images: Optional[List[ImageArtifact]] = None # Images produced by the tool call
194
- videos: Optional[List[VideoArtifact]] = None # Videos produced by the tool call
195
- audio: Optional[List[AudioArtifact]] = None # Audio produced by the tool call
366
+ images: Optional[List[Image]] = None # Images produced by the tool call
367
+ videos: Optional[List[Video]] = None # Videos produced by the tool call
368
+ audio: Optional[List[Audio]] = None # Audio produced by the tool call
196
369
 
197
370
 
198
371
  @dataclass
@@ -219,19 +392,29 @@ class OutputModelResponseCompletedEvent(BaseTeamRunEvent):
219
392
  class CustomEvent(BaseTeamRunEvent):
220
393
  event: str = TeamRunEvent.custom_event.value
221
394
 
395
+ def __init__(self, **kwargs):
396
+ # Store arbitrary attributes directly on the instance
397
+ for key, value in kwargs.items():
398
+ setattr(self, key, value)
399
+
222
400
 
223
401
  TeamRunOutputEvent = Union[
224
402
  RunStartedEvent,
225
403
  RunContentEvent,
226
404
  IntermediateRunContentEvent,
405
+ RunContentCompletedEvent,
227
406
  RunCompletedEvent,
228
407
  RunErrorEvent,
229
408
  RunCancelledEvent,
409
+ PreHookStartedEvent,
410
+ PreHookCompletedEvent,
230
411
  ReasoningStartedEvent,
231
412
  ReasoningStepEvent,
232
413
  ReasoningCompletedEvent,
233
414
  MemoryUpdateStartedEvent,
234
415
  MemoryUpdateCompletedEvent,
416
+ SessionSummaryStartedEvent,
417
+ SessionSummaryCompletedEvent,
235
418
  ToolCallStartedEvent,
236
419
  ToolCallCompletedEvent,
237
420
  ParserModelResponseStartedEvent,
@@ -246,14 +429,21 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
246
429
  TeamRunEvent.run_started.value: RunStartedEvent,
247
430
  TeamRunEvent.run_content.value: RunContentEvent,
248
431
  TeamRunEvent.run_intermediate_content.value: IntermediateRunContentEvent,
432
+ TeamRunEvent.run_content_completed.value: RunContentCompletedEvent,
249
433
  TeamRunEvent.run_completed.value: RunCompletedEvent,
250
434
  TeamRunEvent.run_error.value: RunErrorEvent,
251
435
  TeamRunEvent.run_cancelled.value: RunCancelledEvent,
436
+ TeamRunEvent.pre_hook_started.value: PreHookStartedEvent,
437
+ TeamRunEvent.pre_hook_completed.value: PreHookCompletedEvent,
438
+ TeamRunEvent.post_hook_started.value: PostHookStartedEvent,
439
+ TeamRunEvent.post_hook_completed.value: PostHookCompletedEvent,
252
440
  TeamRunEvent.reasoning_started.value: ReasoningStartedEvent,
253
441
  TeamRunEvent.reasoning_step.value: ReasoningStepEvent,
254
442
  TeamRunEvent.reasoning_completed.value: ReasoningCompletedEvent,
255
443
  TeamRunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
256
444
  TeamRunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
445
+ TeamRunEvent.session_summary_started.value: SessionSummaryStartedEvent,
446
+ TeamRunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
257
447
  TeamRunEvent.tool_call_started.value: ToolCallStartedEvent,
258
448
  TeamRunEvent.tool_call_completed.value: ToolCallCompletedEvent,
259
449
  TeamRunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
@@ -275,82 +465,23 @@ def team_run_output_event_from_dict(data: dict) -> BaseTeamRunEvent:
275
465
  return event_class.from_dict(data) # type: ignore
276
466
 
277
467
 
278
- @dataclass
279
- class TeamRunInput:
280
- """Container for the raw input data passed to Agent.run().
281
- This captures the original input exactly as provided by the user,
282
- separate from the processed messages that go to the model.
283
- Attributes:
284
- input_content: The literal input message/content passed to run()
285
- images: Images directly passed to run()
286
- videos: Videos directly passed to run()
287
- audios: Audio files directly passed to run()
288
- files: Files directly passed to run()
289
- """
290
-
291
- input_content: Optional[Union[str, List, Dict, Message, BaseModel, List[Message]]] = None
292
- images: Optional[Sequence[ImageArtifact]] = None
293
- videos: Optional[Sequence[VideoArtifact]] = None
294
- audios: Optional[Sequence[AudioArtifact]] = None
295
- files: Optional[Sequence[File]] = None
296
-
297
- def to_dict(self) -> Dict[str, Any]:
298
- """Convert to dictionary representation"""
299
- result: Dict[str, Any] = {}
300
-
301
- if self.input_content is not None:
302
- if isinstance(self.input_content, (str)):
303
- result["input_content"] = self.input_content
304
- elif isinstance(self.input_content, BaseModel):
305
- result["input_content"] = self.input_content.model_dump(exclude_none=True)
306
- elif isinstance(self.input_content, Message):
307
- result["input_content"] = self.input_content.to_dict()
308
- elif (
309
- isinstance(self.input_content, list)
310
- and self.input_content
311
- and isinstance(self.input_content[0], Message)
312
- ):
313
- result["input_content"] = [m.to_dict() for m in self.input_content]
314
- else:
315
- result["input_content"] = self.input_content
316
-
317
- if self.images:
318
- result["images"] = [img.to_dict() for img in self.images]
319
- if self.videos:
320
- result["videos"] = [vid.to_dict() for vid in self.videos]
321
- if self.audios:
322
- result["audios"] = [aud.to_dict() for aud in self.audios]
323
-
324
- return result
325
-
326
- @classmethod
327
- def from_dict(cls, data: Dict[str, Any]) -> "TeamRunInput":
328
- """Create TeamRunInput from dictionary"""
329
- images = None
330
- if data.get("images"):
331
- images = [ImageArtifact.model_validate(img_data) for img_data in data["images"]]
332
-
333
- videos = None
334
- if data.get("videos"):
335
- videos = [VideoArtifact.model_validate(vid_data) for vid_data in data["videos"]]
336
-
337
- audios = None
338
- if data.get("audios"):
339
- audios = [AudioArtifact.model_validate(aud_data) for aud_data in data["audios"]]
340
-
341
- files = None
342
- if data.get("files"):
343
- files = [File.model_validate(file_data) for file_data in data["files"]]
344
-
345
- return cls(input_content=data.get("input_content"), images=images, videos=videos, audios=audios, files=files)
346
-
347
-
348
468
  @dataclass
349
469
  class TeamRunOutput:
350
470
  """Response returned by Team.run() functions"""
351
471
 
472
+ run_id: Optional[str] = None
473
+ team_id: Optional[str] = None
474
+ team_name: Optional[str] = None
475
+ session_id: Optional[str] = None
476
+ parent_run_id: Optional[str] = None
477
+ user_id: Optional[str] = None
478
+
479
+ # Input media and messages from user
480
+ input: Optional[TeamRunInput] = None
481
+
352
482
  content: Optional[Any] = None
353
483
  content_type: str = "str"
484
+
354
485
  messages: Optional[List[Message]] = None
355
486
  metrics: Optional[Metrics] = None
356
487
  model: Optional[str] = None
@@ -358,28 +489,21 @@ class TeamRunOutput:
358
489
 
359
490
  member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
360
491
 
361
- run_id: Optional[str] = None
362
- team_id: Optional[str] = None
363
- team_name: Optional[str] = None
364
- session_id: Optional[str] = None
365
- parent_run_id: Optional[str] = None
366
-
367
492
  tools: Optional[List[ToolExecution]] = None
368
493
 
369
- images: Optional[List[ImageArtifact]] = None # Images from member runs
370
- videos: Optional[List[VideoArtifact]] = None # Videos from member runs
371
- audio: Optional[List[AudioArtifact]] = None # Audio from member runs
494
+ images: Optional[List[Image]] = None # Images from member runs
495
+ videos: Optional[List[Video]] = None # Videos from member runs
496
+ audio: Optional[List[Audio]] = None # Audio from member runs
497
+ files: Optional[List[File]] = None # Files from member runs
372
498
 
373
- response_audio: Optional[AudioResponse] = None # Model audio response
374
-
375
- # Input media and messages from user
376
- input: Optional[TeamRunInput] = None
499
+ response_audio: Optional[Audio] = None # Model audio response
377
500
 
378
501
  reasoning_content: Optional[str] = None
379
502
 
380
503
  citations: Optional[Citations] = None
381
-
504
+ model_provider_data: Optional[Dict[str, Any]] = None
382
505
  metadata: Optional[Dict[str, Any]] = None
506
+ session_state: Optional[Dict[str, Any]] = None
383
507
 
384
508
  references: Optional[List[MessageReferences]] = None
385
509
  additional_input: Optional[List[Message]] = None
@@ -418,6 +542,7 @@ class TeamRunOutput:
418
542
  "images",
419
543
  "videos",
420
544
  "audio",
545
+ "files",
421
546
  "response_audio",
422
547
  "citations",
423
548
  "events",
@@ -460,6 +585,9 @@ class TeamRunOutput:
460
585
  if self.audio is not None:
461
586
  _dict["audio"] = [aud.to_dict() for aud in self.audio]
462
587
 
588
+ if self.files is not None:
589
+ _dict["files"] = [file.to_dict() for file in self.files]
590
+
463
591
  if self.response_audio is not None:
464
592
  _dict["response_audio"] = self.response_audio.to_dict()
465
593
 
@@ -488,12 +616,19 @@ class TeamRunOutput:
488
616
 
489
617
  return _dict
490
618
 
491
- def to_json(self) -> str:
619
+ def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
492
620
  import json
493
621
 
494
- _dict = self.to_dict()
622
+ try:
623
+ _dict = self.to_dict()
624
+ except Exception:
625
+ log_error("Failed to convert response to json", exc_info=True)
626
+ raise
495
627
 
496
- return json.dumps(_dict, indent=2)
628
+ if indent is None:
629
+ return json.dumps(_dict, separators=separators)
630
+ else:
631
+ return json.dumps(_dict, indent=indent, separators=separators)
497
632
 
498
633
  @classmethod
499
634
  def from_dict(cls, data: Dict[str, Any]) -> "TeamRunOutput":
@@ -511,7 +646,7 @@ class TeamRunOutput:
511
646
  events = final_events
512
647
 
513
648
  messages = data.pop("messages", None)
514
- messages = [Message.model_validate(message) for message in messages] if messages else None
649
+ messages = [Message.from_dict(message) for message in messages] if messages else None
515
650
 
516
651
  member_responses = data.pop("member_responses", [])
517
652
  parsed_member_responses: List[Union["TeamRunOutput", RunOutput]] = []
@@ -524,7 +659,7 @@ class TeamRunOutput:
524
659
 
525
660
  additional_input = data.pop("additional_input", None)
526
661
  if additional_input is not None:
527
- additional_input = [Message.model_validate(message) for message in additional_input]
662
+ additional_input = [Message.from_dict(message) for message in additional_input]
528
663
 
529
664
  reasoning_steps = data.pop("reasoning_steps", None)
530
665
  if reasoning_steps is not None:
@@ -532,26 +667,21 @@ class TeamRunOutput:
532
667
 
533
668
  reasoning_messages = data.pop("reasoning_messages", None)
534
669
  if reasoning_messages is not None:
535
- reasoning_messages = [Message.model_validate(message) for message in reasoning_messages]
670
+ reasoning_messages = [Message.from_dict(message) for message in reasoning_messages]
536
671
 
537
672
  references = data.pop("references", None)
538
673
  if references is not None:
539
674
  references = [MessageReferences.model_validate(reference) for reference in references]
540
675
 
541
- images = data.pop("images", [])
542
- images = [ImageArtifact.model_validate(image) for image in images] if images else None
543
-
544
- videos = data.pop("videos", [])
545
- videos = [VideoArtifact.model_validate(video) for video in videos] if videos else None
546
-
547
- audio = data.pop("audio", [])
548
- audio = [AudioArtifact.model_validate(audio) for audio in audio] if audio else None
676
+ images = reconstruct_images(data.pop("images", []))
677
+ videos = reconstruct_videos(data.pop("videos", []))
678
+ audio = reconstruct_audio_list(data.pop("audio", []))
679
+ files = reconstruct_files(data.pop("files", []))
549
680
 
550
681
  tools = data.pop("tools", [])
551
682
  tools = [ToolExecution.from_dict(tool) for tool in tools] if tools else None
552
683
 
553
- response_audio = data.pop("response_audio", None)
554
- response_audio = AudioResponse.model_validate(response_audio) if response_audio else None
684
+ response_audio = reconstruct_response_audio(data.pop("response_audio", None))
555
685
 
556
686
  input_data = data.pop("input", None)
557
687
  input_obj = None
@@ -565,6 +695,12 @@ class TeamRunOutput:
565
695
  citations = data.pop("citations", None)
566
696
  citations = Citations.model_validate(citations) if citations else None
567
697
 
698
+ # Filter data to only include fields that are actually defined in the TeamRunOutput dataclass
699
+ from dataclasses import fields
700
+
701
+ supported_fields = {f.name for f in fields(cls)}
702
+ filtered_data = {k: v for k, v in data.items() if k in supported_fields}
703
+
568
704
  return cls(
569
705
  messages=messages,
570
706
  metrics=metrics,
@@ -576,12 +712,13 @@ class TeamRunOutput:
576
712
  images=images,
577
713
  videos=videos,
578
714
  audio=audio,
715
+ files=files,
579
716
  response_audio=response_audio,
580
717
  input=input_obj,
581
718
  citations=citations,
582
719
  tools=tools,
583
720
  events=events,
584
- **data,
721
+ **filtered_data,
585
722
  )
586
723
 
587
724
  def get_content_as_string(self, **kwargs) -> str:
@@ -610,3 +747,7 @@ class TeamRunOutput:
610
747
  if self.audio is None:
611
748
  self.audio = []
612
749
  self.audio.extend(run_response.audio)
750
+ if run_response.files is not None:
751
+ if self.files is None:
752
+ self.files = []
753
+ self.files.extend(run_response.files)