agno 0.1.2__py3-none-any.whl → 2.3.13__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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,574 @@
1
+ """Logic used by the AG-UI router."""
2
+
3
+ import json
4
+ import uuid
5
+ from collections.abc import Iterator
6
+ from dataclasses import asdict, dataclass, is_dataclass
7
+ from typing import Any, AsyncIterator, Dict, List, Optional, Set, Tuple, Union
8
+
9
+ from ag_ui.core import (
10
+ BaseEvent,
11
+ CustomEvent,
12
+ EventType,
13
+ RunFinishedEvent,
14
+ StepFinishedEvent,
15
+ StepStartedEvent,
16
+ TextMessageContentEvent,
17
+ TextMessageEndEvent,
18
+ TextMessageStartEvent,
19
+ ToolCallArgsEvent,
20
+ ToolCallEndEvent,
21
+ ToolCallResultEvent,
22
+ ToolCallStartEvent,
23
+ )
24
+ from ag_ui.core.types import Message as AGUIMessage
25
+ from pydantic import BaseModel
26
+
27
+ from agno.models.message import Message
28
+ from agno.run.agent import RunContentEvent, RunEvent, RunOutputEvent, RunPausedEvent
29
+ from agno.run.team import RunContentEvent as TeamRunContentEvent
30
+ from agno.run.team import TeamRunEvent, TeamRunOutputEvent
31
+ from agno.utils.log import log_debug, log_warning
32
+ from agno.utils.message import get_text_from_message
33
+
34
+
35
+ def validate_agui_state(state: Any, thread_id: str) -> Optional[Dict[str, Any]]:
36
+ """Validate the given AGUI state is of the expected type (dict)."""
37
+ if state is None:
38
+ return None
39
+
40
+ if isinstance(state, dict):
41
+ return state
42
+
43
+ if isinstance(state, BaseModel):
44
+ try:
45
+ return state.model_dump()
46
+ except Exception:
47
+ pass
48
+
49
+ if is_dataclass(state):
50
+ try:
51
+ return asdict(state) # type: ignore
52
+ except Exception:
53
+ pass
54
+
55
+ if hasattr(state, "to_dict") and callable(getattr(state, "to_dict")):
56
+ try:
57
+ result = state.to_dict() # type: ignore
58
+ if isinstance(result, dict):
59
+ return result
60
+ except Exception:
61
+ pass
62
+
63
+ log_warning(f"AGUI state must be a dict, got {type(state).__name__}. State will be ignored. Thread: {thread_id}")
64
+ return None
65
+
66
+
67
+ @dataclass
68
+ class EventBuffer:
69
+ """Buffer to manage event ordering constraints, relevant when mapping Agno responses to AG-UI events."""
70
+
71
+ active_tool_call_ids: Set[str] # All currently active tool calls
72
+ ended_tool_call_ids: Set[str] # All tool calls that have ended
73
+ current_text_message_id: str = "" # ID of the current text message context (for tool call parenting)
74
+ next_text_message_id: str = "" # Pre-generated ID for the next text message
75
+ pending_tool_calls_parent_id: str = "" # Parent message ID for pending tool calls
76
+
77
+ def __init__(self):
78
+ self.active_tool_call_ids = set()
79
+ self.ended_tool_call_ids = set()
80
+ self.current_text_message_id = ""
81
+ self.next_text_message_id = str(uuid.uuid4())
82
+ self.pending_tool_calls_parent_id = ""
83
+
84
+ def start_tool_call(self, tool_call_id: str) -> None:
85
+ """Start a new tool call."""
86
+ self.active_tool_call_ids.add(tool_call_id)
87
+
88
+ def end_tool_call(self, tool_call_id: str) -> None:
89
+ """End a tool call."""
90
+ self.active_tool_call_ids.discard(tool_call_id)
91
+ self.ended_tool_call_ids.add(tool_call_id)
92
+
93
+ def start_text_message(self) -> str:
94
+ """Start a new text message and return its ID."""
95
+ # Use the pre-generated next ID as current, and generate a new next ID
96
+ self.current_text_message_id = self.next_text_message_id
97
+ self.next_text_message_id = str(uuid.uuid4())
98
+ return self.current_text_message_id
99
+
100
+ def get_parent_message_id_for_tool_call(self) -> str:
101
+ """Get the message ID to use as parent for tool calls."""
102
+ # If we have a pending parent ID set (from text message end), use that
103
+ if self.pending_tool_calls_parent_id:
104
+ return self.pending_tool_calls_parent_id
105
+ # Otherwise use current text message ID
106
+ return self.current_text_message_id
107
+
108
+ def set_pending_tool_calls_parent_id(self, parent_id: str) -> None:
109
+ """Set the parent message ID for upcoming tool calls."""
110
+ self.pending_tool_calls_parent_id = parent_id
111
+
112
+ def clear_pending_tool_calls_parent_id(self) -> None:
113
+ """Clear the pending parent ID when a new text message starts."""
114
+ self.pending_tool_calls_parent_id = ""
115
+
116
+
117
+ def convert_agui_messages_to_agno_messages(messages: List[AGUIMessage]) -> List[Message]:
118
+ """Convert AG-UI messages to Agno messages."""
119
+ # First pass: collect all tool_call_ids that have results
120
+ tool_call_ids_with_results: Set[str] = set()
121
+ for msg in messages:
122
+ if msg.role == "tool" and msg.tool_call_id:
123
+ tool_call_ids_with_results.add(msg.tool_call_id)
124
+
125
+ # Second pass: convert messages
126
+ result: List[Message] = []
127
+ seen_tool_call_ids: Set[str] = set()
128
+
129
+ for msg in messages:
130
+ if msg.role == "tool":
131
+ # Deduplicate tool results - keep only first occurrence
132
+ if msg.tool_call_id in seen_tool_call_ids:
133
+ log_debug(f"Skipping duplicate AGUI tool result: {msg.tool_call_id}")
134
+ continue
135
+ seen_tool_call_ids.add(msg.tool_call_id)
136
+ result.append(Message(role="tool", tool_call_id=msg.tool_call_id, content=msg.content))
137
+
138
+ elif msg.role == "assistant":
139
+ tool_calls = None
140
+ if msg.tool_calls:
141
+ # Filter tool_calls to only those with results in this message sequence
142
+ filtered_calls = [call for call in msg.tool_calls if call.id in tool_call_ids_with_results]
143
+ if filtered_calls:
144
+ tool_calls = [call.model_dump() for call in filtered_calls]
145
+ result.append(Message(role="assistant", content=msg.content, tool_calls=tool_calls))
146
+
147
+ elif msg.role == "user":
148
+ result.append(Message(role="user", content=msg.content))
149
+
150
+ elif msg.role == "system":
151
+ pass # Skip - agent builds its own system message from configuration
152
+
153
+ else:
154
+ log_warning(f"Unknown AGUI message role: {msg.role}")
155
+
156
+ return result
157
+
158
+
159
+ def extract_team_response_chunk_content(response: TeamRunContentEvent) -> str:
160
+ """Given a response stream chunk, find and extract the content."""
161
+
162
+ # Handle Team members' responses
163
+ members_content = []
164
+ if hasattr(response, "member_responses") and response.member_responses: # type: ignore
165
+ for member_resp in response.member_responses: # type: ignore
166
+ if isinstance(member_resp, RunContentEvent):
167
+ member_content = extract_response_chunk_content(member_resp)
168
+ if member_content:
169
+ members_content.append(f"Team member: {member_content}")
170
+ elif isinstance(member_resp, TeamRunContentEvent):
171
+ member_content = extract_team_response_chunk_content(member_resp)
172
+ if member_content:
173
+ members_content.append(f"Team member: {member_content}")
174
+ members_response = "\n".join(members_content) if members_content else ""
175
+
176
+ # Handle structured outputs
177
+ main_content = get_text_from_message(response.content) if response.content is not None else ""
178
+
179
+ return main_content + members_response
180
+
181
+
182
+ def extract_response_chunk_content(response: RunContentEvent) -> str:
183
+ """Given a response stream chunk, find and extract the content."""
184
+
185
+ if hasattr(response, "messages") and response.messages: # type: ignore
186
+ for msg in reversed(response.messages): # type: ignore
187
+ if hasattr(msg, "role") and msg.role == "assistant" and hasattr(msg, "content") and msg.content:
188
+ # Handle structured outputs from messages
189
+ return get_text_from_message(msg.content)
190
+
191
+ # Handle structured outputs
192
+ return get_text_from_message(response.content) if response.content is not None else ""
193
+
194
+
195
+ def _create_events_from_chunk(
196
+ chunk: Union[RunOutputEvent, TeamRunOutputEvent],
197
+ message_id: str,
198
+ message_started: bool,
199
+ event_buffer: EventBuffer,
200
+ ) -> Tuple[List[BaseEvent], bool, str]:
201
+ """
202
+ Process a single chunk and return events to emit + updated message_started state.
203
+
204
+ Args:
205
+ chunk: The event chunk to process
206
+ message_id: Current message identifier
207
+ message_started: Whether a message is currently active
208
+ event_buffer: Event buffer for tracking tool call state
209
+
210
+ Returns:
211
+ Tuple of (events_to_emit, new_message_started_state, message_id)
212
+ """
213
+ events_to_emit: List[BaseEvent] = []
214
+
215
+ # Extract content if the contextual event is a content event
216
+ if chunk.event == RunEvent.run_content:
217
+ content = extract_response_chunk_content(chunk) # type: ignore
218
+ elif chunk.event == TeamRunEvent.run_content:
219
+ content = extract_team_response_chunk_content(chunk) # type: ignore
220
+ else:
221
+ content = None
222
+
223
+ # Handle text responses
224
+ if content is not None:
225
+ # Handle the message start event, emitted once per message
226
+ if not message_started:
227
+ message_started = True
228
+ message_id = event_buffer.start_text_message()
229
+
230
+ # Clear pending tool calls parent ID when starting new text message
231
+ event_buffer.clear_pending_tool_calls_parent_id()
232
+
233
+ start_event = TextMessageStartEvent(
234
+ type=EventType.TEXT_MESSAGE_START,
235
+ message_id=message_id,
236
+ role="assistant",
237
+ )
238
+ events_to_emit.append(start_event)
239
+
240
+ # Handle the text content event, emitted once per text chunk
241
+ if content is not None and content != "":
242
+ content_event = TextMessageContentEvent(
243
+ type=EventType.TEXT_MESSAGE_CONTENT,
244
+ message_id=message_id,
245
+ delta=content,
246
+ )
247
+ events_to_emit.append(content_event) # type: ignore
248
+
249
+ # Handle starting a new tool
250
+ elif chunk.event == RunEvent.tool_call_started or chunk.event == TeamRunEvent.tool_call_started:
251
+ if chunk.tool is not None: # type: ignore
252
+ tool_call = chunk.tool # type: ignore
253
+
254
+ # End current text message and handle for tool calls
255
+ current_message_id = message_id
256
+ if message_started:
257
+ # End the current text message
258
+ end_message_event = TextMessageEndEvent(type=EventType.TEXT_MESSAGE_END, message_id=current_message_id)
259
+ events_to_emit.append(end_message_event)
260
+
261
+ # Set this message as the parent for any upcoming tool calls
262
+ # This ensures multiple sequential tool calls all use the same parent
263
+ event_buffer.set_pending_tool_calls_parent_id(current_message_id)
264
+
265
+ # Reset message started state and generate new message_id for future messages
266
+ message_started = False
267
+ message_id = str(uuid.uuid4())
268
+
269
+ # Get the parent message ID - this will use pending parent if set, ensuring multiple tool calls in sequence have the same parent
270
+ parent_message_id = event_buffer.get_parent_message_id_for_tool_call()
271
+
272
+ if not parent_message_id:
273
+ # Create parent message for tool calls without preceding assistant message
274
+ parent_message_id = str(uuid.uuid4())
275
+
276
+ # Emit a text message to serve as the parent
277
+ text_start = TextMessageStartEvent(
278
+ type=EventType.TEXT_MESSAGE_START,
279
+ message_id=parent_message_id,
280
+ role="assistant",
281
+ )
282
+ events_to_emit.append(text_start)
283
+
284
+ text_end = TextMessageEndEvent(
285
+ type=EventType.TEXT_MESSAGE_END,
286
+ message_id=parent_message_id,
287
+ )
288
+ events_to_emit.append(text_end)
289
+
290
+ # Set this as the pending parent for subsequent tool calls in this batch
291
+ event_buffer.set_pending_tool_calls_parent_id(parent_message_id)
292
+
293
+ start_event = ToolCallStartEvent(
294
+ type=EventType.TOOL_CALL_START,
295
+ tool_call_id=tool_call.tool_call_id, # type: ignore
296
+ tool_call_name=tool_call.tool_name, # type: ignore
297
+ parent_message_id=parent_message_id,
298
+ )
299
+ events_to_emit.append(start_event)
300
+
301
+ args_event = ToolCallArgsEvent(
302
+ type=EventType.TOOL_CALL_ARGS,
303
+ tool_call_id=tool_call.tool_call_id, # type: ignore
304
+ delta=json.dumps(tool_call.tool_args),
305
+ )
306
+ events_to_emit.append(args_event) # type: ignore
307
+
308
+ # Handle tool call completion
309
+ elif chunk.event == RunEvent.tool_call_completed or chunk.event == TeamRunEvent.tool_call_completed:
310
+ if chunk.tool is not None: # type: ignore
311
+ tool_call = chunk.tool # type: ignore
312
+ if tool_call.tool_call_id not in event_buffer.ended_tool_call_ids:
313
+ end_event = ToolCallEndEvent(
314
+ type=EventType.TOOL_CALL_END,
315
+ tool_call_id=tool_call.tool_call_id, # type: ignore
316
+ )
317
+ events_to_emit.append(end_event)
318
+
319
+ if tool_call.result is not None:
320
+ result_event = ToolCallResultEvent(
321
+ type=EventType.TOOL_CALL_RESULT,
322
+ tool_call_id=tool_call.tool_call_id, # type: ignore
323
+ content=str(tool_call.result),
324
+ role="tool",
325
+ message_id=str(uuid.uuid4()),
326
+ )
327
+ events_to_emit.append(result_event)
328
+
329
+ # Handle reasoning
330
+ elif chunk.event == RunEvent.reasoning_started:
331
+ step_started_event = StepStartedEvent(type=EventType.STEP_STARTED, step_name="reasoning")
332
+ events_to_emit.append(step_started_event)
333
+ elif chunk.event == RunEvent.reasoning_completed:
334
+ step_finished_event = StepFinishedEvent(type=EventType.STEP_FINISHED, step_name="reasoning")
335
+ events_to_emit.append(step_finished_event)
336
+
337
+ # Handle custom events
338
+ elif chunk.event == RunEvent.custom_event:
339
+ # Use the name of the event class if available, otherwise default to the CustomEvent
340
+ try:
341
+ custom_event_name = chunk.__class__.__name__
342
+ except Exception:
343
+ custom_event_name = chunk.event
344
+
345
+ # Use the complete Agno event as value if parsing it works, else the event content field
346
+ try:
347
+ custom_event_value = chunk.to_dict()
348
+ except Exception:
349
+ custom_event_value = chunk.content # type: ignore
350
+
351
+ custom_event = CustomEvent(name=custom_event_name, value=custom_event_value)
352
+ events_to_emit.append(custom_event)
353
+
354
+ return events_to_emit, message_started, message_id
355
+
356
+
357
+ def _create_completion_events(
358
+ chunk: Union[RunOutputEvent, TeamRunOutputEvent],
359
+ event_buffer: EventBuffer,
360
+ message_started: bool,
361
+ message_id: str,
362
+ thread_id: str,
363
+ run_id: str,
364
+ ) -> List[BaseEvent]:
365
+ """Create events for run completion."""
366
+ events_to_emit: List[BaseEvent] = []
367
+
368
+ # End remaining active tool calls if needed
369
+ for tool_call_id in list(event_buffer.active_tool_call_ids):
370
+ if tool_call_id not in event_buffer.ended_tool_call_ids:
371
+ end_event = ToolCallEndEvent(
372
+ type=EventType.TOOL_CALL_END,
373
+ tool_call_id=tool_call_id,
374
+ )
375
+ events_to_emit.append(end_event)
376
+
377
+ # End the message and run, denoting the end of the session
378
+ if message_started:
379
+ end_message_event = TextMessageEndEvent(type=EventType.TEXT_MESSAGE_END, message_id=message_id)
380
+ events_to_emit.append(end_message_event)
381
+
382
+ # Emit external execution tools
383
+ if isinstance(chunk, RunPausedEvent):
384
+ external_tools = chunk.tools_awaiting_external_execution
385
+ if external_tools:
386
+ # First, emit an assistant message for external tool calls
387
+ assistant_message_id = str(uuid.uuid4())
388
+ assistant_start_event = TextMessageStartEvent(
389
+ type=EventType.TEXT_MESSAGE_START,
390
+ message_id=assistant_message_id,
391
+ role="assistant",
392
+ )
393
+ events_to_emit.append(assistant_start_event)
394
+
395
+ # Add any text content if present for the assistant message
396
+ if chunk.content:
397
+ content_event = TextMessageContentEvent(
398
+ type=EventType.TEXT_MESSAGE_CONTENT,
399
+ message_id=assistant_message_id,
400
+ delta=str(chunk.content),
401
+ )
402
+ events_to_emit.append(content_event)
403
+
404
+ # End the assistant message
405
+ assistant_end_event = TextMessageEndEvent(
406
+ type=EventType.TEXT_MESSAGE_END,
407
+ message_id=assistant_message_id,
408
+ )
409
+ events_to_emit.append(assistant_end_event)
410
+
411
+ # Emit tool call events for external execution
412
+ for tool in external_tools:
413
+ if tool.tool_call_id is None or tool.tool_name is None:
414
+ continue
415
+
416
+ start_event = ToolCallStartEvent(
417
+ type=EventType.TOOL_CALL_START,
418
+ tool_call_id=tool.tool_call_id,
419
+ tool_call_name=tool.tool_name,
420
+ parent_message_id=assistant_message_id, # Use the assistant message as parent
421
+ )
422
+ events_to_emit.append(start_event)
423
+
424
+ args_event = ToolCallArgsEvent(
425
+ type=EventType.TOOL_CALL_ARGS,
426
+ tool_call_id=tool.tool_call_id,
427
+ delta=json.dumps(tool.tool_args),
428
+ )
429
+ events_to_emit.append(args_event)
430
+
431
+ end_event = ToolCallEndEvent(
432
+ type=EventType.TOOL_CALL_END,
433
+ tool_call_id=tool.tool_call_id,
434
+ )
435
+ events_to_emit.append(end_event)
436
+
437
+ run_finished_event = RunFinishedEvent(type=EventType.RUN_FINISHED, thread_id=thread_id, run_id=run_id)
438
+ events_to_emit.append(run_finished_event)
439
+
440
+ return events_to_emit
441
+
442
+
443
+ def _emit_event_logic(event: BaseEvent, event_buffer: EventBuffer) -> List[BaseEvent]:
444
+ """Process an event and return events to actually emit."""
445
+ events_to_emit: List[BaseEvent] = [event]
446
+
447
+ # Update the event buffer state for tracking purposes
448
+ if event.type == EventType.TOOL_CALL_START:
449
+ tool_call_id = getattr(event, "tool_call_id", None)
450
+ if tool_call_id:
451
+ event_buffer.start_tool_call(tool_call_id)
452
+ elif event.type == EventType.TOOL_CALL_END:
453
+ tool_call_id = getattr(event, "tool_call_id", None)
454
+ if tool_call_id:
455
+ event_buffer.end_tool_call(tool_call_id)
456
+
457
+ return events_to_emit
458
+
459
+
460
+ def stream_agno_response_as_agui_events(
461
+ response_stream: Iterator[Union[RunOutputEvent, TeamRunOutputEvent]], thread_id: str, run_id: str
462
+ ) -> Iterator[BaseEvent]:
463
+ """Map the Agno response stream to AG-UI format, handling event ordering constraints."""
464
+ message_id = "" # Will be set by EventBuffer when text message starts
465
+ message_started = False
466
+ event_buffer = EventBuffer()
467
+ stream_completed = False
468
+
469
+ completion_chunk = None
470
+
471
+ for chunk in response_stream:
472
+ # Check if this is a completion event
473
+ if (
474
+ chunk.event == RunEvent.run_completed
475
+ or chunk.event == TeamRunEvent.run_completed
476
+ or chunk.event == RunEvent.run_paused
477
+ ):
478
+ # Store completion chunk but don't process it yet
479
+ completion_chunk = chunk
480
+ stream_completed = True
481
+ else:
482
+ # Process regular chunk immediately
483
+ events_from_chunk, message_started, message_id = _create_events_from_chunk(
484
+ chunk, message_id, message_started, event_buffer
485
+ )
486
+
487
+ for event in events_from_chunk:
488
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
489
+ for emit_event in events_to_emit:
490
+ yield emit_event
491
+
492
+ # Process ONLY completion cleanup events, not content from completion chunk
493
+ if completion_chunk:
494
+ completion_events = _create_completion_events(
495
+ completion_chunk, event_buffer, message_started, message_id, thread_id, run_id
496
+ )
497
+ for event in completion_events:
498
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
499
+ for emit_event in events_to_emit:
500
+ yield emit_event
501
+
502
+ # Ensure completion events are always emitted even when stream ends naturally
503
+ if not stream_completed:
504
+ # Create a synthetic completion event to ensure proper cleanup
505
+ from agno.run.agent import RunCompletedEvent
506
+
507
+ synthetic_completion = RunCompletedEvent()
508
+ completion_events = _create_completion_events(
509
+ synthetic_completion, event_buffer, message_started, message_id, thread_id, run_id
510
+ )
511
+ for event in completion_events:
512
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
513
+ for emit_event in events_to_emit:
514
+ yield emit_event
515
+
516
+
517
+ # Async version - thin wrapper
518
+ async def async_stream_agno_response_as_agui_events(
519
+ response_stream: AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent]],
520
+ thread_id: str,
521
+ run_id: str,
522
+ ) -> AsyncIterator[BaseEvent]:
523
+ """Map the Agno response stream to AG-UI format, handling event ordering constraints."""
524
+ message_id = "" # Will be set by EventBuffer when text message starts
525
+ message_started = False
526
+ event_buffer = EventBuffer()
527
+ stream_completed = False
528
+
529
+ completion_chunk = None
530
+
531
+ async for chunk in response_stream:
532
+ # Check if this is a completion event
533
+ if (
534
+ chunk.event == RunEvent.run_completed
535
+ or chunk.event == TeamRunEvent.run_completed
536
+ or chunk.event == RunEvent.run_paused
537
+ ):
538
+ # Store completion chunk but don't process it yet
539
+ completion_chunk = chunk
540
+ stream_completed = True
541
+ else:
542
+ # Process regular chunk immediately
543
+ events_from_chunk, message_started, message_id = _create_events_from_chunk(
544
+ chunk, message_id, message_started, event_buffer
545
+ )
546
+
547
+ for event in events_from_chunk:
548
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
549
+ for emit_event in events_to_emit:
550
+ yield emit_event
551
+
552
+ # Process ONLY completion cleanup events, not content from completion chunk
553
+ if completion_chunk:
554
+ completion_events = _create_completion_events(
555
+ completion_chunk, event_buffer, message_started, message_id, thread_id, run_id
556
+ )
557
+ for event in completion_events:
558
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
559
+ for emit_event in events_to_emit:
560
+ yield emit_event
561
+
562
+ # Ensure completion events are always emitted even when stream ends naturally
563
+ if not stream_completed:
564
+ # Create a synthetic completion event to ensure proper cleanup
565
+ from agno.run.agent import RunCompletedEvent
566
+
567
+ synthetic_completion = RunCompletedEvent()
568
+ completion_events = _create_completion_events(
569
+ synthetic_completion, event_buffer, message_started, message_id, thread_id, run_id
570
+ )
571
+ for event in completion_events:
572
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
573
+ for emit_event in events_to_emit:
574
+ yield emit_event
@@ -0,0 +1,25 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import List, Optional
3
+
4
+ from fastapi import APIRouter
5
+
6
+ from agno.agent import Agent
7
+ from agno.team import Team
8
+ from agno.workflow.workflow import Workflow
9
+
10
+
11
+ class BaseInterface(ABC):
12
+ type: str
13
+ version: str = "1.0"
14
+ agent: Optional[Agent] = None
15
+ team: Optional[Team] = None
16
+ workflow: Optional[Workflow] = None
17
+
18
+ prefix: str
19
+ tags: List[str]
20
+
21
+ router: APIRouter
22
+
23
+ @abstractmethod
24
+ def get_router(self, use_async: bool = True, **kwargs) -> APIRouter:
25
+ pass
@@ -0,0 +1,3 @@
1
+ from agno.os.interfaces.slack.slack import Slack
2
+
3
+ __all__ = ["Slack"]