agno 2.2.13__py3-none-any.whl → 2.4.3__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 (383) hide show
  1. agno/agent/__init__.py +6 -0
  2. agno/agent/agent.py +5252 -3145
  3. agno/agent/remote.py +525 -0
  4. agno/api/api.py +2 -0
  5. agno/client/__init__.py +3 -0
  6. agno/client/a2a/__init__.py +10 -0
  7. agno/client/a2a/client.py +554 -0
  8. agno/client/a2a/schemas.py +112 -0
  9. agno/client/a2a/utils.py +369 -0
  10. agno/client/os.py +2669 -0
  11. agno/compression/__init__.py +3 -0
  12. agno/compression/manager.py +247 -0
  13. agno/culture/manager.py +2 -2
  14. agno/db/base.py +927 -6
  15. agno/db/dynamo/dynamo.py +788 -2
  16. agno/db/dynamo/schemas.py +128 -0
  17. agno/db/dynamo/utils.py +26 -3
  18. agno/db/firestore/firestore.py +674 -50
  19. agno/db/firestore/schemas.py +41 -0
  20. agno/db/firestore/utils.py +25 -10
  21. agno/db/gcs_json/gcs_json_db.py +506 -3
  22. agno/db/gcs_json/utils.py +14 -2
  23. agno/db/in_memory/in_memory_db.py +203 -4
  24. agno/db/in_memory/utils.py +14 -2
  25. agno/db/json/json_db.py +498 -2
  26. agno/db/json/utils.py +14 -2
  27. agno/db/migrations/manager.py +199 -0
  28. agno/db/migrations/utils.py +19 -0
  29. agno/db/migrations/v1_to_v2.py +54 -16
  30. agno/db/migrations/versions/__init__.py +0 -0
  31. agno/db/migrations/versions/v2_3_0.py +977 -0
  32. agno/db/mongo/async_mongo.py +1013 -39
  33. agno/db/mongo/mongo.py +684 -4
  34. agno/db/mongo/schemas.py +48 -0
  35. agno/db/mongo/utils.py +17 -0
  36. agno/db/mysql/__init__.py +2 -1
  37. agno/db/mysql/async_mysql.py +2958 -0
  38. agno/db/mysql/mysql.py +722 -53
  39. agno/db/mysql/schemas.py +77 -11
  40. agno/db/mysql/utils.py +151 -8
  41. agno/db/postgres/async_postgres.py +1254 -137
  42. agno/db/postgres/postgres.py +2316 -93
  43. agno/db/postgres/schemas.py +153 -21
  44. agno/db/postgres/utils.py +22 -7
  45. agno/db/redis/redis.py +531 -3
  46. agno/db/redis/schemas.py +36 -0
  47. agno/db/redis/utils.py +31 -15
  48. agno/db/schemas/evals.py +1 -0
  49. agno/db/schemas/memory.py +20 -9
  50. agno/db/singlestore/schemas.py +70 -1
  51. agno/db/singlestore/singlestore.py +737 -74
  52. agno/db/singlestore/utils.py +13 -3
  53. agno/db/sqlite/async_sqlite.py +1069 -89
  54. agno/db/sqlite/schemas.py +133 -1
  55. agno/db/sqlite/sqlite.py +2203 -165
  56. agno/db/sqlite/utils.py +21 -11
  57. agno/db/surrealdb/models.py +25 -0
  58. agno/db/surrealdb/surrealdb.py +603 -1
  59. agno/db/utils.py +60 -0
  60. agno/eval/__init__.py +26 -3
  61. agno/eval/accuracy.py +25 -12
  62. agno/eval/agent_as_judge.py +871 -0
  63. agno/eval/base.py +29 -0
  64. agno/eval/performance.py +10 -4
  65. agno/eval/reliability.py +22 -13
  66. agno/eval/utils.py +2 -1
  67. agno/exceptions.py +42 -0
  68. agno/hooks/__init__.py +3 -0
  69. agno/hooks/decorator.py +164 -0
  70. agno/integrations/discord/client.py +13 -2
  71. agno/knowledge/__init__.py +4 -0
  72. agno/knowledge/chunking/code.py +90 -0
  73. agno/knowledge/chunking/document.py +65 -4
  74. agno/knowledge/chunking/fixed.py +4 -1
  75. agno/knowledge/chunking/markdown.py +102 -11
  76. agno/knowledge/chunking/recursive.py +2 -2
  77. agno/knowledge/chunking/semantic.py +130 -48
  78. agno/knowledge/chunking/strategy.py +18 -0
  79. agno/knowledge/embedder/azure_openai.py +0 -1
  80. agno/knowledge/embedder/google.py +1 -1
  81. agno/knowledge/embedder/mistral.py +1 -1
  82. agno/knowledge/embedder/nebius.py +1 -1
  83. agno/knowledge/embedder/openai.py +16 -12
  84. agno/knowledge/filesystem.py +412 -0
  85. agno/knowledge/knowledge.py +4261 -1199
  86. agno/knowledge/protocol.py +134 -0
  87. agno/knowledge/reader/arxiv_reader.py +3 -2
  88. agno/knowledge/reader/base.py +9 -7
  89. agno/knowledge/reader/csv_reader.py +91 -42
  90. agno/knowledge/reader/docx_reader.py +9 -10
  91. agno/knowledge/reader/excel_reader.py +225 -0
  92. agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
  93. agno/knowledge/reader/firecrawl_reader.py +3 -2
  94. agno/knowledge/reader/json_reader.py +16 -22
  95. agno/knowledge/reader/markdown_reader.py +15 -14
  96. agno/knowledge/reader/pdf_reader.py +33 -28
  97. agno/knowledge/reader/pptx_reader.py +9 -10
  98. agno/knowledge/reader/reader_factory.py +135 -1
  99. agno/knowledge/reader/s3_reader.py +8 -16
  100. agno/knowledge/reader/tavily_reader.py +3 -3
  101. agno/knowledge/reader/text_reader.py +15 -14
  102. agno/knowledge/reader/utils/__init__.py +17 -0
  103. agno/knowledge/reader/utils/spreadsheet.py +114 -0
  104. agno/knowledge/reader/web_search_reader.py +8 -65
  105. agno/knowledge/reader/website_reader.py +16 -13
  106. agno/knowledge/reader/wikipedia_reader.py +36 -3
  107. agno/knowledge/reader/youtube_reader.py +3 -2
  108. agno/knowledge/remote_content/__init__.py +33 -0
  109. agno/knowledge/remote_content/config.py +266 -0
  110. agno/knowledge/remote_content/remote_content.py +105 -17
  111. agno/knowledge/utils.py +76 -22
  112. agno/learn/__init__.py +71 -0
  113. agno/learn/config.py +463 -0
  114. agno/learn/curate.py +185 -0
  115. agno/learn/machine.py +725 -0
  116. agno/learn/schemas.py +1114 -0
  117. agno/learn/stores/__init__.py +38 -0
  118. agno/learn/stores/decision_log.py +1156 -0
  119. agno/learn/stores/entity_memory.py +3275 -0
  120. agno/learn/stores/learned_knowledge.py +1583 -0
  121. agno/learn/stores/protocol.py +117 -0
  122. agno/learn/stores/session_context.py +1217 -0
  123. agno/learn/stores/user_memory.py +1495 -0
  124. agno/learn/stores/user_profile.py +1220 -0
  125. agno/learn/utils.py +209 -0
  126. agno/media.py +22 -6
  127. agno/memory/__init__.py +14 -1
  128. agno/memory/manager.py +223 -8
  129. agno/memory/strategies/__init__.py +15 -0
  130. agno/memory/strategies/base.py +66 -0
  131. agno/memory/strategies/summarize.py +196 -0
  132. agno/memory/strategies/types.py +37 -0
  133. agno/models/aimlapi/aimlapi.py +17 -0
  134. agno/models/anthropic/claude.py +434 -59
  135. agno/models/aws/bedrock.py +121 -20
  136. agno/models/aws/claude.py +131 -274
  137. agno/models/azure/ai_foundry.py +10 -6
  138. agno/models/azure/openai_chat.py +33 -10
  139. agno/models/base.py +1162 -561
  140. agno/models/cerebras/cerebras.py +120 -24
  141. agno/models/cerebras/cerebras_openai.py +21 -2
  142. agno/models/cohere/chat.py +65 -6
  143. agno/models/cometapi/cometapi.py +18 -1
  144. agno/models/dashscope/dashscope.py +2 -3
  145. agno/models/deepinfra/deepinfra.py +18 -1
  146. agno/models/deepseek/deepseek.py +69 -3
  147. agno/models/fireworks/fireworks.py +18 -1
  148. agno/models/google/gemini.py +959 -89
  149. agno/models/google/utils.py +22 -0
  150. agno/models/groq/groq.py +48 -18
  151. agno/models/huggingface/huggingface.py +17 -6
  152. agno/models/ibm/watsonx.py +16 -6
  153. agno/models/internlm/internlm.py +18 -1
  154. agno/models/langdb/langdb.py +13 -1
  155. agno/models/litellm/chat.py +88 -9
  156. agno/models/litellm/litellm_openai.py +18 -1
  157. agno/models/message.py +24 -5
  158. agno/models/meta/llama.py +40 -13
  159. agno/models/meta/llama_openai.py +22 -21
  160. agno/models/metrics.py +12 -0
  161. agno/models/mistral/mistral.py +8 -4
  162. agno/models/n1n/__init__.py +3 -0
  163. agno/models/n1n/n1n.py +57 -0
  164. agno/models/nebius/nebius.py +6 -7
  165. agno/models/nvidia/nvidia.py +20 -3
  166. agno/models/ollama/__init__.py +2 -0
  167. agno/models/ollama/chat.py +17 -6
  168. agno/models/ollama/responses.py +100 -0
  169. agno/models/openai/__init__.py +2 -0
  170. agno/models/openai/chat.py +117 -26
  171. agno/models/openai/open_responses.py +46 -0
  172. agno/models/openai/responses.py +110 -32
  173. agno/models/openrouter/__init__.py +2 -0
  174. agno/models/openrouter/openrouter.py +67 -2
  175. agno/models/openrouter/responses.py +146 -0
  176. agno/models/perplexity/perplexity.py +19 -1
  177. agno/models/portkey/portkey.py +7 -6
  178. agno/models/requesty/requesty.py +19 -2
  179. agno/models/response.py +20 -2
  180. agno/models/sambanova/sambanova.py +20 -3
  181. agno/models/siliconflow/siliconflow.py +19 -2
  182. agno/models/together/together.py +20 -3
  183. agno/models/vercel/v0.py +20 -3
  184. agno/models/vertexai/claude.py +124 -4
  185. agno/models/vllm/vllm.py +19 -14
  186. agno/models/xai/xai.py +19 -2
  187. agno/os/app.py +467 -137
  188. agno/os/auth.py +253 -5
  189. agno/os/config.py +22 -0
  190. agno/os/interfaces/a2a/a2a.py +7 -6
  191. agno/os/interfaces/a2a/router.py +635 -26
  192. agno/os/interfaces/a2a/utils.py +32 -33
  193. agno/os/interfaces/agui/agui.py +5 -3
  194. agno/os/interfaces/agui/router.py +26 -16
  195. agno/os/interfaces/agui/utils.py +97 -57
  196. agno/os/interfaces/base.py +7 -7
  197. agno/os/interfaces/slack/router.py +16 -7
  198. agno/os/interfaces/slack/slack.py +7 -7
  199. agno/os/interfaces/whatsapp/router.py +35 -7
  200. agno/os/interfaces/whatsapp/security.py +3 -1
  201. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  202. agno/os/managers.py +326 -0
  203. agno/os/mcp.py +652 -79
  204. agno/os/middleware/__init__.py +4 -0
  205. agno/os/middleware/jwt.py +718 -115
  206. agno/os/middleware/trailing_slash.py +27 -0
  207. agno/os/router.py +105 -1558
  208. agno/os/routers/agents/__init__.py +3 -0
  209. agno/os/routers/agents/router.py +655 -0
  210. agno/os/routers/agents/schema.py +288 -0
  211. agno/os/routers/components/__init__.py +3 -0
  212. agno/os/routers/components/components.py +475 -0
  213. agno/os/routers/database.py +155 -0
  214. agno/os/routers/evals/evals.py +111 -18
  215. agno/os/routers/evals/schemas.py +38 -5
  216. agno/os/routers/evals/utils.py +80 -11
  217. agno/os/routers/health.py +3 -3
  218. agno/os/routers/knowledge/knowledge.py +284 -35
  219. agno/os/routers/knowledge/schemas.py +14 -2
  220. agno/os/routers/memory/memory.py +274 -11
  221. agno/os/routers/memory/schemas.py +44 -3
  222. agno/os/routers/metrics/metrics.py +30 -15
  223. agno/os/routers/metrics/schemas.py +10 -6
  224. agno/os/routers/registry/__init__.py +3 -0
  225. agno/os/routers/registry/registry.py +337 -0
  226. agno/os/routers/session/session.py +143 -14
  227. agno/os/routers/teams/__init__.py +3 -0
  228. agno/os/routers/teams/router.py +550 -0
  229. agno/os/routers/teams/schema.py +280 -0
  230. agno/os/routers/traces/__init__.py +3 -0
  231. agno/os/routers/traces/schemas.py +414 -0
  232. agno/os/routers/traces/traces.py +549 -0
  233. agno/os/routers/workflows/__init__.py +3 -0
  234. agno/os/routers/workflows/router.py +757 -0
  235. agno/os/routers/workflows/schema.py +139 -0
  236. agno/os/schema.py +157 -584
  237. agno/os/scopes.py +469 -0
  238. agno/os/settings.py +3 -0
  239. agno/os/utils.py +574 -185
  240. agno/reasoning/anthropic.py +85 -1
  241. agno/reasoning/azure_ai_foundry.py +93 -1
  242. agno/reasoning/deepseek.py +102 -2
  243. agno/reasoning/default.py +6 -7
  244. agno/reasoning/gemini.py +87 -3
  245. agno/reasoning/groq.py +109 -2
  246. agno/reasoning/helpers.py +6 -7
  247. agno/reasoning/manager.py +1238 -0
  248. agno/reasoning/ollama.py +93 -1
  249. agno/reasoning/openai.py +115 -1
  250. agno/reasoning/vertexai.py +85 -1
  251. agno/registry/__init__.py +3 -0
  252. agno/registry/registry.py +68 -0
  253. agno/remote/__init__.py +3 -0
  254. agno/remote/base.py +581 -0
  255. agno/run/__init__.py +2 -4
  256. agno/run/agent.py +134 -19
  257. agno/run/base.py +49 -1
  258. agno/run/cancel.py +65 -52
  259. agno/run/cancellation_management/__init__.py +9 -0
  260. agno/run/cancellation_management/base.py +78 -0
  261. agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
  262. agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
  263. agno/run/requirement.py +181 -0
  264. agno/run/team.py +111 -19
  265. agno/run/workflow.py +2 -1
  266. agno/session/agent.py +57 -92
  267. agno/session/summary.py +1 -1
  268. agno/session/team.py +62 -115
  269. agno/session/workflow.py +353 -57
  270. agno/skills/__init__.py +17 -0
  271. agno/skills/agent_skills.py +377 -0
  272. agno/skills/errors.py +32 -0
  273. agno/skills/loaders/__init__.py +4 -0
  274. agno/skills/loaders/base.py +27 -0
  275. agno/skills/loaders/local.py +216 -0
  276. agno/skills/skill.py +65 -0
  277. agno/skills/utils.py +107 -0
  278. agno/skills/validator.py +277 -0
  279. agno/table.py +10 -0
  280. agno/team/__init__.py +5 -1
  281. agno/team/remote.py +447 -0
  282. agno/team/team.py +3769 -2202
  283. agno/tools/brandfetch.py +27 -18
  284. agno/tools/browserbase.py +225 -16
  285. agno/tools/crawl4ai.py +3 -0
  286. agno/tools/duckduckgo.py +25 -71
  287. agno/tools/exa.py +0 -21
  288. agno/tools/file.py +14 -13
  289. agno/tools/file_generation.py +12 -6
  290. agno/tools/firecrawl.py +15 -7
  291. agno/tools/function.py +94 -113
  292. agno/tools/google_bigquery.py +11 -2
  293. agno/tools/google_drive.py +4 -3
  294. agno/tools/knowledge.py +9 -4
  295. agno/tools/mcp/mcp.py +301 -18
  296. agno/tools/mcp/multi_mcp.py +269 -14
  297. agno/tools/mem0.py +11 -10
  298. agno/tools/memory.py +47 -46
  299. agno/tools/mlx_transcribe.py +10 -7
  300. agno/tools/models/nebius.py +5 -5
  301. agno/tools/models_labs.py +20 -10
  302. agno/tools/nano_banana.py +151 -0
  303. agno/tools/parallel.py +0 -7
  304. agno/tools/postgres.py +76 -36
  305. agno/tools/python.py +14 -6
  306. agno/tools/reasoning.py +30 -23
  307. agno/tools/redshift.py +406 -0
  308. agno/tools/shopify.py +1519 -0
  309. agno/tools/spotify.py +919 -0
  310. agno/tools/tavily.py +4 -1
  311. agno/tools/toolkit.py +253 -18
  312. agno/tools/websearch.py +93 -0
  313. agno/tools/website.py +1 -1
  314. agno/tools/wikipedia.py +1 -1
  315. agno/tools/workflow.py +56 -48
  316. agno/tools/yfinance.py +12 -11
  317. agno/tracing/__init__.py +12 -0
  318. agno/tracing/exporter.py +161 -0
  319. agno/tracing/schemas.py +276 -0
  320. agno/tracing/setup.py +112 -0
  321. agno/utils/agent.py +251 -10
  322. agno/utils/cryptography.py +22 -0
  323. agno/utils/dttm.py +33 -0
  324. agno/utils/events.py +264 -7
  325. agno/utils/hooks.py +111 -3
  326. agno/utils/http.py +161 -2
  327. agno/utils/mcp.py +49 -8
  328. agno/utils/media.py +22 -1
  329. agno/utils/models/ai_foundry.py +9 -2
  330. agno/utils/models/claude.py +20 -5
  331. agno/utils/models/cohere.py +9 -2
  332. agno/utils/models/llama.py +9 -2
  333. agno/utils/models/mistral.py +4 -2
  334. agno/utils/os.py +0 -0
  335. agno/utils/print_response/agent.py +99 -16
  336. agno/utils/print_response/team.py +223 -24
  337. agno/utils/print_response/workflow.py +0 -2
  338. agno/utils/prompts.py +8 -6
  339. agno/utils/remote.py +23 -0
  340. agno/utils/response.py +1 -13
  341. agno/utils/string.py +91 -2
  342. agno/utils/team.py +62 -12
  343. agno/utils/tokens.py +657 -0
  344. agno/vectordb/base.py +15 -2
  345. agno/vectordb/cassandra/cassandra.py +1 -1
  346. agno/vectordb/chroma/__init__.py +2 -1
  347. agno/vectordb/chroma/chromadb.py +468 -23
  348. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  349. agno/vectordb/couchbase/couchbase.py +6 -2
  350. agno/vectordb/lancedb/lance_db.py +7 -38
  351. agno/vectordb/lightrag/lightrag.py +7 -6
  352. agno/vectordb/milvus/milvus.py +118 -84
  353. agno/vectordb/mongodb/__init__.py +2 -1
  354. agno/vectordb/mongodb/mongodb.py +14 -31
  355. agno/vectordb/pgvector/pgvector.py +120 -66
  356. agno/vectordb/pineconedb/pineconedb.py +2 -19
  357. agno/vectordb/qdrant/__init__.py +2 -1
  358. agno/vectordb/qdrant/qdrant.py +33 -56
  359. agno/vectordb/redis/__init__.py +2 -1
  360. agno/vectordb/redis/redisdb.py +19 -31
  361. agno/vectordb/singlestore/singlestore.py +17 -9
  362. agno/vectordb/surrealdb/surrealdb.py +2 -38
  363. agno/vectordb/weaviate/__init__.py +2 -1
  364. agno/vectordb/weaviate/weaviate.py +7 -3
  365. agno/workflow/__init__.py +5 -1
  366. agno/workflow/agent.py +2 -2
  367. agno/workflow/condition.py +12 -10
  368. agno/workflow/loop.py +28 -9
  369. agno/workflow/parallel.py +21 -13
  370. agno/workflow/remote.py +362 -0
  371. agno/workflow/router.py +12 -9
  372. agno/workflow/step.py +261 -36
  373. agno/workflow/steps.py +12 -8
  374. agno/workflow/types.py +40 -77
  375. agno/workflow/workflow.py +939 -213
  376. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
  377. agno-2.4.3.dist-info/RECORD +677 -0
  378. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
  379. agno/tools/googlesearch.py +0 -98
  380. agno/tools/memori.py +0 -339
  381. agno-2.2.13.dist-info/RECORD +0 -575
  382. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
  383. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/run/team.py CHANGED
@@ -12,6 +12,7 @@ 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.run.requirement import RunRequirement
15
16
  from agno.utils.log import log_error
16
17
  from agno.utils.media import (
17
18
  reconstruct_audio_list,
@@ -50,8 +51,11 @@ class TeamRunInput:
50
51
  return self.input_content.model_dump_json(exclude_none=True)
51
52
  elif isinstance(self.input_content, Message):
52
53
  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])
54
+ elif isinstance(self.input_content, list):
55
+ try:
56
+ return json.dumps(self.to_dict().get("input_content"))
57
+ except Exception:
58
+ return str(self.input_content)
55
59
  else:
56
60
  return str(self.input_content)
57
61
 
@@ -66,22 +70,15 @@ class TeamRunInput:
66
70
  result["input_content"] = self.input_content.model_dump(exclude_none=True)
67
71
  elif isinstance(self.input_content, Message):
68
72
  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):
73
+ elif isinstance(self.input_content, list):
74
+ serialized_items: List[Any] = []
75
+ for item in self.input_content:
76
+ if isinstance(item, Message):
77
+ serialized_items.append(item.to_dict())
78
+ elif isinstance(item, BaseModel):
79
+ serialized_items.append(item.model_dump(exclude_none=True))
80
+ elif isinstance(item, dict):
81
+ content = dict(item)
85
82
  if content.get("images"):
86
83
  content["images"] = [
87
84
  img.to_dict() if isinstance(img, Image) else img for img in content["images"]
@@ -98,7 +95,11 @@ class TeamRunInput:
98
95
  content["files"] = [
99
96
  file.to_dict() if isinstance(file, File) else file for file in content["files"]
100
97
  ]
101
- result["input_content"] = self.input_content
98
+ serialized_items.append(content)
99
+ else:
100
+ serialized_items.append(item)
101
+
102
+ result["input_content"] = serialized_items
102
103
  else:
103
104
  result["input_content"] = self.input_content
104
105
 
@@ -145,9 +146,11 @@ class TeamRunEvent(str, Enum):
145
146
 
146
147
  tool_call_started = "TeamToolCallStarted"
147
148
  tool_call_completed = "TeamToolCallCompleted"
149
+ tool_call_error = "TeamToolCallError"
148
150
 
149
151
  reasoning_started = "TeamReasoningStarted"
150
152
  reasoning_step = "TeamReasoningStep"
153
+ reasoning_content_delta = "TeamReasoningContentDelta"
151
154
  reasoning_completed = "TeamReasoningCompleted"
152
155
 
153
156
  memory_update_started = "TeamMemoryUpdateStarted"
@@ -162,6 +165,12 @@ class TeamRunEvent(str, Enum):
162
165
  output_model_response_started = "TeamOutputModelResponseStarted"
163
166
  output_model_response_completed = "TeamOutputModelResponseCompleted"
164
167
 
168
+ model_request_started = "TeamModelRequestStarted"
169
+ model_request_completed = "TeamModelRequestCompleted"
170
+
171
+ compression_started = "TeamCompressionStarted"
172
+ compression_completed = "TeamCompressionCompleted"
173
+
165
174
  custom_event = "CustomEvent"
166
175
 
167
176
 
@@ -319,6 +328,7 @@ class MemoryUpdateStartedEvent(BaseTeamRunEvent):
319
328
  @dataclass
320
329
  class MemoryUpdateCompletedEvent(BaseTeamRunEvent):
321
330
  event: str = TeamRunEvent.memory_update_completed.value
331
+ memories: Optional[List[Any]] = None
322
332
 
323
333
 
324
334
  @dataclass
@@ -345,6 +355,14 @@ class ReasoningStepEvent(BaseTeamRunEvent):
345
355
  reasoning_content: str = ""
346
356
 
347
357
 
358
+ @dataclass
359
+ class ReasoningContentDeltaEvent(BaseTeamRunEvent):
360
+ """Event for streaming reasoning content chunks as they arrive."""
361
+
362
+ event: str = TeamRunEvent.reasoning_content_delta.value
363
+ reasoning_content: str = "" # The delta/chunk of reasoning content
364
+
365
+
348
366
  @dataclass
349
367
  class ReasoningCompletedEvent(BaseTeamRunEvent):
350
368
  event: str = TeamRunEvent.reasoning_completed.value
@@ -368,6 +386,13 @@ class ToolCallCompletedEvent(BaseTeamRunEvent):
368
386
  audio: Optional[List[Audio]] = None # Audio produced by the tool call
369
387
 
370
388
 
389
+ @dataclass
390
+ class ToolCallErrorEvent(BaseTeamRunEvent):
391
+ event: str = TeamRunEvent.tool_call_error.value
392
+ tool: Optional[ToolExecution] = None
393
+ error: Optional[str] = None
394
+
395
+
371
396
  @dataclass
372
397
  class ParserModelResponseStartedEvent(BaseTeamRunEvent):
373
398
  event: str = TeamRunEvent.parser_model_response_started.value
@@ -388,6 +413,48 @@ class OutputModelResponseCompletedEvent(BaseTeamRunEvent):
388
413
  event: str = TeamRunEvent.output_model_response_completed.value
389
414
 
390
415
 
416
+ @dataclass
417
+ class ModelRequestStartedEvent(BaseTeamRunEvent):
418
+ """Event sent when a model request is about to be made"""
419
+
420
+ event: str = TeamRunEvent.model_request_started.value
421
+ model: Optional[str] = None
422
+ model_provider: Optional[str] = None
423
+
424
+
425
+ @dataclass
426
+ class ModelRequestCompletedEvent(BaseTeamRunEvent):
427
+ """Event sent when a model request has completed"""
428
+
429
+ event: str = TeamRunEvent.model_request_completed.value
430
+ model: Optional[str] = None
431
+ model_provider: Optional[str] = None
432
+ input_tokens: Optional[int] = None
433
+ output_tokens: Optional[int] = None
434
+ total_tokens: Optional[int] = None
435
+ time_to_first_token: Optional[float] = None
436
+ reasoning_tokens: Optional[int] = None
437
+ cache_read_tokens: Optional[int] = None
438
+ cache_write_tokens: Optional[int] = None
439
+
440
+
441
+ @dataclass
442
+ class CompressionStartedEvent(BaseTeamRunEvent):
443
+ """Event sent when tool result compression is about to start"""
444
+
445
+ event: str = TeamRunEvent.compression_started.value
446
+
447
+
448
+ @dataclass
449
+ class CompressionCompletedEvent(BaseTeamRunEvent):
450
+ """Event sent when tool result compression has completed"""
451
+
452
+ event: str = TeamRunEvent.compression_completed.value
453
+ tool_results_compressed: Optional[int] = None
454
+ original_size: Optional[int] = None
455
+ compressed_size: Optional[int] = None
456
+
457
+
391
458
  @dataclass
392
459
  class CustomEvent(BaseTeamRunEvent):
393
460
  event: str = TeamRunEvent.custom_event.value
@@ -410,6 +477,7 @@ TeamRunOutputEvent = Union[
410
477
  PreHookCompletedEvent,
411
478
  ReasoningStartedEvent,
412
479
  ReasoningStepEvent,
480
+ ReasoningContentDeltaEvent,
413
481
  ReasoningCompletedEvent,
414
482
  MemoryUpdateStartedEvent,
415
483
  MemoryUpdateCompletedEvent,
@@ -417,10 +485,15 @@ TeamRunOutputEvent = Union[
417
485
  SessionSummaryCompletedEvent,
418
486
  ToolCallStartedEvent,
419
487
  ToolCallCompletedEvent,
488
+ ToolCallErrorEvent,
420
489
  ParserModelResponseStartedEvent,
421
490
  ParserModelResponseCompletedEvent,
422
491
  OutputModelResponseStartedEvent,
423
492
  OutputModelResponseCompletedEvent,
493
+ ModelRequestStartedEvent,
494
+ ModelRequestCompletedEvent,
495
+ CompressionStartedEvent,
496
+ CompressionCompletedEvent,
424
497
  CustomEvent,
425
498
  ]
426
499
 
@@ -439,6 +512,7 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
439
512
  TeamRunEvent.post_hook_completed.value: PostHookCompletedEvent,
440
513
  TeamRunEvent.reasoning_started.value: ReasoningStartedEvent,
441
514
  TeamRunEvent.reasoning_step.value: ReasoningStepEvent,
515
+ TeamRunEvent.reasoning_content_delta.value: ReasoningContentDeltaEvent,
442
516
  TeamRunEvent.reasoning_completed.value: ReasoningCompletedEvent,
443
517
  TeamRunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
444
518
  TeamRunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
@@ -446,10 +520,15 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
446
520
  TeamRunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
447
521
  TeamRunEvent.tool_call_started.value: ToolCallStartedEvent,
448
522
  TeamRunEvent.tool_call_completed.value: ToolCallCompletedEvent,
523
+ TeamRunEvent.tool_call_error.value: ToolCallErrorEvent,
449
524
  TeamRunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
450
525
  TeamRunEvent.parser_model_response_completed.value: ParserModelResponseCompletedEvent,
451
526
  TeamRunEvent.output_model_response_started.value: OutputModelResponseStartedEvent,
452
527
  TeamRunEvent.output_model_response_completed.value: OutputModelResponseCompletedEvent,
528
+ TeamRunEvent.model_request_started.value: ModelRequestStartedEvent,
529
+ TeamRunEvent.model_request_completed.value: ModelRequestCompletedEvent,
530
+ TeamRunEvent.compression_started.value: CompressionStartedEvent,
531
+ TeamRunEvent.compression_completed.value: CompressionCompletedEvent,
453
532
  TeamRunEvent.custom_event.value: CustomEvent,
454
533
  }
455
534
 
@@ -515,11 +594,20 @@ class TeamRunOutput:
515
594
 
516
595
  status: RunStatus = RunStatus.running
517
596
 
597
+ # User control flow (HITL) requirements to continue a run when paused, in order of arrival
598
+ requirements: Optional[list[RunRequirement]] = None
599
+
518
600
  # === FOREIGN KEY RELATIONSHIPS ===
519
601
  # These fields establish relationships to parent workflow/step structures
520
602
  # and should be treated as foreign keys for data integrity
521
603
  workflow_step_id: Optional[str] = None # FK: Points to StepOutput.step_id
522
604
 
605
+ @property
606
+ def active_requirements(self) -> list[RunRequirement]:
607
+ if not self.requirements:
608
+ return []
609
+ return [requirement for requirement in self.requirements if not requirement.is_resolved()]
610
+
523
611
  @property
524
612
  def is_paused(self):
525
613
  return self.status == RunStatus.paused
@@ -536,6 +624,7 @@ class TeamRunOutput:
536
624
  and k
537
625
  not in [
538
626
  "messages",
627
+ "metrics",
539
628
  "status",
540
629
  "tools",
541
630
  "metadata",
@@ -555,6 +644,9 @@ class TeamRunOutput:
555
644
  if self.events is not None:
556
645
  _dict["events"] = [e.to_dict() for e in self.events]
557
646
 
647
+ if self.metrics is not None:
648
+ _dict["metrics"] = self.metrics.to_dict() if isinstance(self.metrics, Metrics) else self.metrics
649
+
558
650
  if self.status is not None:
559
651
  _dict["status"] = self.status.value if isinstance(self.status, RunStatus) else self.status
560
652
 
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
@@ -597,7 +598,7 @@ class WorkflowRunOutput:
597
598
  _dict["input"] = self.input
598
599
 
599
600
  if self.content and isinstance(self.content, BaseModel):
600
- _dict["content"] = self.content.model_dump(exclude_none=True)
601
+ _dict["content"] = self.content.model_dump(exclude_none=True, mode="json")
601
602
 
602
603
  if self.events is not None:
603
604
  _dict["events"] = [e.to_dict() for e in self.events]
agno/session/agent.py CHANGED
@@ -112,71 +112,76 @@ class AgentSession:
112
112
  return run
113
113
  return None
114
114
 
115
- def _should_skip_message(
116
- self, message: Message, skip_role: Optional[str] = None, skip_history_messages: bool = True
117
- ) -> bool:
118
- """Processes a message for history"""
119
- # Skip messages that were tagged as history in previous runs
120
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
121
- return True
122
-
123
- # Skip messages with specified role
124
- if skip_role and message.role == skip_role:
125
- return True
126
- return False
127
-
128
- def get_messages_from_last_n_runs(
115
+ def get_messages(
129
116
  self,
130
117
  agent_id: Optional[str] = None,
131
118
  team_id: Optional[str] = None,
132
- last_n: Optional[int] = None,
133
- last_n_messages: Optional[int] = None,
134
- skip_role: Optional[str] = None,
135
- skip_status: Optional[List[RunStatus]] = None,
119
+ last_n_runs: Optional[int] = None,
120
+ limit: Optional[int] = None,
121
+ skip_roles: Optional[List[str]] = None,
122
+ skip_statuses: Optional[List[RunStatus]] = None,
136
123
  skip_history_messages: bool = True,
137
124
  ) -> List[Message]:
138
- """Returns the messages from the last_n runs, excluding previously tagged history messages.
125
+ """Returns the messages belonging to the session that fit the given criteria.
126
+
139
127
  Args:
140
128
  agent_id: The id of the agent to get the messages from.
141
129
  team_id: The id of the team to get the messages from.
142
- last_n: The number of runs to return from the end of the conversation. Defaults to all runs.
143
- last_n_messages: The number of messages to return from the end of the conversation. Defaults to all messages.
144
- skip_role: Skip messages with this role.
145
- skip_status: Skip messages with this status.
130
+ last_n_runs: The number of runs to return messages from, counting from the latest. Defaults to all runs.
131
+ last_n_messages: The number of messages to return, counting from the latest. Defaults to all messages.
132
+ skip_roles: Skip messages with these roles.
133
+ skip_statuses: Skip messages with these statuses.
146
134
  skip_history_messages: Skip messages that were tagged as history in previous runs.
135
+
147
136
  Returns:
148
- A list of Messages from the specified runs, excluding history messages.
137
+ A list of Messages belonging to the session.
149
138
  """
139
+
140
+ def _should_skip_message(
141
+ message: Message, skip_roles: Optional[List[str]] = None, skip_history_messages: bool = True
142
+ ) -> bool:
143
+ """Logic to determine if a message should be skipped"""
144
+ # Skip messages that were tagged as history in previous runs
145
+ if hasattr(message, "from_history") and message.from_history and skip_history_messages:
146
+ return True
147
+
148
+ # Skip messages with specified role
149
+ if skip_roles and message.role in skip_roles:
150
+ return True
151
+
152
+ return False
153
+
150
154
  if not self.runs:
151
155
  return []
152
156
 
153
- if skip_status is None:
154
- skip_status = [RunStatus.paused, RunStatus.cancelled, RunStatus.error]
157
+ if skip_statuses is None:
158
+ skip_statuses = [RunStatus.paused, RunStatus.cancelled, RunStatus.error]
159
+
160
+ runs = self.runs
155
161
 
156
- session_runs = self.runs
157
162
  # Filter by agent_id and team_id
158
163
  if agent_id:
159
- session_runs = [run for run in session_runs if hasattr(run, "agent_id") and run.agent_id == agent_id] # type: ignore
164
+ runs = [run for run in runs if hasattr(run, "agent_id") and run.agent_id == agent_id] # type: ignore
160
165
  if team_id:
161
- session_runs = [run for run in session_runs if hasattr(run, "team_id") and run.team_id == team_id] # type: ignore
166
+ runs = [run for run in runs if hasattr(run, "team_id") and run.team_id == team_id] # type: ignore
162
167
 
163
168
  # Skip any messages that might be part of members of teams (for session re-use)
164
- session_runs = [run for run in session_runs if run.parent_run_id is None] # type: ignore
169
+ runs = [run for run in runs if run.parent_run_id is None] # type: ignore
165
170
 
166
171
  # Filter by status
167
- session_runs = [run for run in session_runs if hasattr(run, "status") and run.status not in skip_status] # type: ignore
172
+ runs = [run for run in runs if hasattr(run, "status") and run.status not in skip_statuses] # type: ignore
168
173
 
169
174
  messages_from_history = []
170
175
  system_message = None
171
176
 
172
- # Filter by last_n_messages
173
- if last_n_messages is not None:
174
- for run_response in session_runs:
177
+ # Limit the number of messages returned if limit is set
178
+ if limit is not None:
179
+ for run_response in runs:
175
180
  if not run_response or not run_response.messages:
176
181
  continue
177
182
 
178
183
  for message in run_response.messages or []:
179
- if self._should_skip_message(message, skip_role, skip_history_messages):
184
+ if _should_skip_message(message, skip_roles, skip_history_messages):
180
185
  continue
181
186
 
182
187
  if message.role == "system":
@@ -188,24 +193,24 @@ class AgentSession:
188
193
 
189
194
  if system_message:
190
195
  messages_from_history = [system_message] + messages_from_history[
191
- -(last_n_messages - 1) :
196
+ -(limit - 1) :
192
197
  ] # Grab one less message then add the system message
193
198
  else:
194
- messages_from_history = messages_from_history[-last_n_messages:]
199
+ messages_from_history = messages_from_history[-limit:]
195
200
 
196
201
  # Remove tool result messages that don't have an associated assistant message with tool calls
197
202
  while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
198
203
  messages_from_history.pop(0)
199
204
 
205
+ # If limit is not set, return all messages
200
206
  else:
201
- # Filter by last_n runs
202
- runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
207
+ runs_to_process = runs[-last_n_runs:] if last_n_runs is not None else runs
203
208
  for run_response in runs_to_process:
204
209
  if not run_response or not run_response.messages:
205
210
  continue
206
211
 
207
212
  for message in run_response.messages or []:
208
- if self._should_skip_message(message, skip_role, skip_history_messages):
213
+ if _should_skip_message(message, skip_roles, skip_history_messages):
209
214
  continue
210
215
 
211
216
  if message.role == "system":
@@ -219,6 +224,18 @@ class AgentSession:
219
224
  log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
220
225
  return messages_from_history
221
226
 
227
+ def get_chat_history(self, last_n_runs: Optional[int] = None) -> List[Message]:
228
+ """Return the chat history (user and assistant messages) for the session.
229
+ Use get_messages() for more filtering options.
230
+
231
+ Args:
232
+ last_n_runs: Number of recent runs to include. If None, all runs will be considered.
233
+
234
+ Returns:
235
+ A list of user and assistant Messages belonging to the session.
236
+ """
237
+ return self.get_messages(skip_roles=["system", "tool"], last_n_runs=last_n_runs)
238
+
222
239
  def get_tool_calls(self, num_calls: Optional[int] = None) -> List[Dict[str, Any]]:
223
240
  """Returns a list of tool calls from the messages"""
224
241
 
@@ -235,61 +252,9 @@ class AgentSession:
235
252
  return tool_calls
236
253
  return tool_calls
237
254
 
238
- def get_messages_for_session(
239
- self,
240
- user_role: str = "user",
241
- assistant_role: Optional[List[str]] = None,
242
- skip_history_messages: bool = True,
243
- ) -> List[Message]:
244
- """Returns a list of messages for the session that iterate through user message and assistant response."""
245
-
246
- if assistant_role is None:
247
- # TODO: Check if we still need CHATBOT as a role
248
- assistant_role = ["assistant", "model", "CHATBOT"]
249
-
250
- final_messages: List[Message] = []
251
- session_runs = self.runs
252
- if not session_runs:
253
- return []
254
-
255
- for run_response in session_runs:
256
- if run_response and run_response.messages:
257
- user_message_from_run = None
258
- assistant_message_from_run = None
259
-
260
- # Start from the beginning to look for the user message
261
- for message in run_response.messages or []:
262
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
263
- continue
264
- if message.role == user_role:
265
- user_message_from_run = message
266
- break
267
-
268
- # Start from the end to look for the assistant response
269
- for message in run_response.messages[::-1]:
270
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
271
- continue
272
- if message.role in assistant_role:
273
- assistant_message_from_run = message
274
- break
275
-
276
- if user_message_from_run and assistant_message_from_run:
277
- final_messages.append(user_message_from_run)
278
- final_messages.append(assistant_message_from_run)
279
- return final_messages
280
-
281
255
  def get_session_summary(self) -> Optional[SessionSummary]:
282
256
  """Get the session summary for the session"""
283
257
 
284
258
  if self.summary is None:
285
259
  return None
286
260
  return self.summary
287
-
288
- # Chat History functions
289
- def get_chat_history(self) -> List[Message]:
290
- """Get the chat history for the session"""
291
-
292
- messages = []
293
- for run in self.runs or []:
294
- messages.extend([msg for msg in run.messages or [] if not msg.from_history])
295
- return messages
agno/session/summary.py CHANGED
@@ -150,7 +150,7 @@ class SessionSummaryManager:
150
150
  response_format = self.get_response_format(self.model)
151
151
 
152
152
  system_message = self.get_system_message(
153
- conversation=session.get_messages_for_session(), # type: ignore
153
+ conversation=session.get_messages(), # type: ignore
154
154
  response_format=response_format,
155
155
  )
156
156