agno 2.2.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 (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -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 +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -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 +1335 -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 +1160 -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 +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,534 @@
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_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
+ result = []
120
+ for msg in messages:
121
+ if msg.role == "tool":
122
+ result.append(Message(role="tool", tool_call_id=msg.tool_call_id, content=msg.content))
123
+ elif msg.role == "assistant":
124
+ tool_calls = None
125
+ if msg.tool_calls:
126
+ tool_calls = [call.model_dump() for call in msg.tool_calls]
127
+ result.append(
128
+ Message(
129
+ role="assistant",
130
+ content=msg.content,
131
+ tool_calls=tool_calls,
132
+ )
133
+ )
134
+ elif msg.role == "user":
135
+ result.append(Message(role="user", content=msg.content))
136
+ return result
137
+
138
+
139
+ def extract_team_response_chunk_content(response: TeamRunContentEvent) -> str:
140
+ """Given a response stream chunk, find and extract the content."""
141
+
142
+ # Handle Team members' responses
143
+ members_content = []
144
+ if hasattr(response, "member_responses") and response.member_responses: # type: ignore
145
+ for member_resp in response.member_responses: # type: ignore
146
+ if isinstance(member_resp, RunContentEvent):
147
+ member_content = extract_response_chunk_content(member_resp)
148
+ if member_content:
149
+ members_content.append(f"Team member: {member_content}")
150
+ elif isinstance(member_resp, TeamRunContentEvent):
151
+ member_content = extract_team_response_chunk_content(member_resp)
152
+ if member_content:
153
+ members_content.append(f"Team member: {member_content}")
154
+ members_response = "\n".join(members_content) if members_content else ""
155
+
156
+ # Handle structured outputs
157
+ main_content = get_text_from_message(response.content) if response.content is not None else ""
158
+
159
+ return main_content + members_response
160
+
161
+
162
+ def extract_response_chunk_content(response: RunContentEvent) -> str:
163
+ """Given a response stream chunk, find and extract the content."""
164
+
165
+ if hasattr(response, "messages") and response.messages: # type: ignore
166
+ for msg in reversed(response.messages): # type: ignore
167
+ if hasattr(msg, "role") and msg.role == "assistant" and hasattr(msg, "content") and msg.content:
168
+ # Handle structured outputs from messages
169
+ return get_text_from_message(msg.content)
170
+
171
+ # Handle structured outputs
172
+ return get_text_from_message(response.content) if response.content is not None else ""
173
+
174
+
175
+ def _create_events_from_chunk(
176
+ chunk: Union[RunOutputEvent, TeamRunOutputEvent],
177
+ message_id: str,
178
+ message_started: bool,
179
+ event_buffer: EventBuffer,
180
+ ) -> Tuple[List[BaseEvent], bool, str]:
181
+ """
182
+ Process a single chunk and return events to emit + updated message_started state.
183
+
184
+ Args:
185
+ chunk: The event chunk to process
186
+ message_id: Current message identifier
187
+ message_started: Whether a message is currently active
188
+ event_buffer: Event buffer for tracking tool call state
189
+
190
+ Returns:
191
+ Tuple of (events_to_emit, new_message_started_state, message_id)
192
+ """
193
+ events_to_emit: List[BaseEvent] = []
194
+
195
+ # Extract content if the contextual event is a content event
196
+ if chunk.event == RunEvent.run_content:
197
+ content = extract_response_chunk_content(chunk) # type: ignore
198
+ elif chunk.event == TeamRunEvent.run_content:
199
+ content = extract_team_response_chunk_content(chunk) # type: ignore
200
+ else:
201
+ content = None
202
+
203
+ # Handle text responses
204
+ if content is not None:
205
+ # Handle the message start event, emitted once per message
206
+ if not message_started:
207
+ message_started = True
208
+ message_id = event_buffer.start_text_message()
209
+
210
+ # Clear pending tool calls parent ID when starting new text message
211
+ event_buffer.clear_pending_tool_calls_parent_id()
212
+
213
+ start_event = TextMessageStartEvent(
214
+ type=EventType.TEXT_MESSAGE_START,
215
+ message_id=message_id,
216
+ role="assistant",
217
+ )
218
+ events_to_emit.append(start_event)
219
+
220
+ # Handle the text content event, emitted once per text chunk
221
+ if content is not None and content != "":
222
+ content_event = TextMessageContentEvent(
223
+ type=EventType.TEXT_MESSAGE_CONTENT,
224
+ message_id=message_id,
225
+ delta=content,
226
+ )
227
+ events_to_emit.append(content_event) # type: ignore
228
+
229
+ # Handle starting a new tool
230
+ elif chunk.event == RunEvent.tool_call_started or chunk.event == TeamRunEvent.tool_call_started:
231
+ if chunk.tool is not None: # type: ignore
232
+ tool_call = chunk.tool # type: ignore
233
+
234
+ # End current text message and handle for tool calls
235
+ current_message_id = message_id
236
+ if message_started:
237
+ # End the current text message
238
+ end_message_event = TextMessageEndEvent(type=EventType.TEXT_MESSAGE_END, message_id=current_message_id)
239
+ events_to_emit.append(end_message_event)
240
+
241
+ # Set this message as the parent for any upcoming tool calls
242
+ # This ensures multiple sequential tool calls all use the same parent
243
+ event_buffer.set_pending_tool_calls_parent_id(current_message_id)
244
+
245
+ # Reset message started state and generate new message_id for future messages
246
+ message_started = False
247
+ message_id = str(uuid.uuid4())
248
+
249
+ # Get the parent message ID - this will use pending parent if set, ensuring multiple tool calls in sequence have the same parent
250
+ parent_message_id = event_buffer.get_parent_message_id_for_tool_call()
251
+
252
+ if not parent_message_id:
253
+ parent_message_id = current_message_id
254
+
255
+ start_event = ToolCallStartEvent(
256
+ type=EventType.TOOL_CALL_START,
257
+ tool_call_id=tool_call.tool_call_id, # type: ignore
258
+ tool_call_name=tool_call.tool_name, # type: ignore
259
+ parent_message_id=parent_message_id,
260
+ )
261
+ events_to_emit.append(start_event)
262
+
263
+ args_event = ToolCallArgsEvent(
264
+ type=EventType.TOOL_CALL_ARGS,
265
+ tool_call_id=tool_call.tool_call_id, # type: ignore
266
+ delta=json.dumps(tool_call.tool_args),
267
+ )
268
+ events_to_emit.append(args_event) # type: ignore
269
+
270
+ # Handle tool call completion
271
+ elif chunk.event == RunEvent.tool_call_completed or chunk.event == TeamRunEvent.tool_call_completed:
272
+ if chunk.tool is not None: # type: ignore
273
+ tool_call = chunk.tool # type: ignore
274
+ if tool_call.tool_call_id not in event_buffer.ended_tool_call_ids:
275
+ end_event = ToolCallEndEvent(
276
+ type=EventType.TOOL_CALL_END,
277
+ tool_call_id=tool_call.tool_call_id, # type: ignore
278
+ )
279
+ events_to_emit.append(end_event)
280
+
281
+ if tool_call.result is not None:
282
+ result_event = ToolCallResultEvent(
283
+ type=EventType.TOOL_CALL_RESULT,
284
+ tool_call_id=tool_call.tool_call_id, # type: ignore
285
+ content=str(tool_call.result),
286
+ role="tool",
287
+ message_id=str(uuid.uuid4()),
288
+ )
289
+ events_to_emit.append(result_event)
290
+
291
+ # Handle reasoning
292
+ elif chunk.event == RunEvent.reasoning_started:
293
+ step_started_event = StepStartedEvent(type=EventType.STEP_STARTED, step_name="reasoning")
294
+ events_to_emit.append(step_started_event)
295
+ elif chunk.event == RunEvent.reasoning_completed:
296
+ step_finished_event = StepFinishedEvent(type=EventType.STEP_FINISHED, step_name="reasoning")
297
+ events_to_emit.append(step_finished_event)
298
+
299
+ # Handle custom events
300
+ elif chunk.event == RunEvent.custom_event:
301
+ # Use the name of the event class if available, otherwise default to the CustomEvent
302
+ try:
303
+ custom_event_name = chunk.__class__.__name__
304
+ except Exception:
305
+ custom_event_name = chunk.event
306
+
307
+ # Use the complete Agno event as value if parsing it works, else the event content field
308
+ try:
309
+ custom_event_value = chunk.to_dict()
310
+ except Exception:
311
+ custom_event_value = chunk.content # type: ignore
312
+
313
+ custom_event = CustomEvent(name=custom_event_name, value=custom_event_value)
314
+ events_to_emit.append(custom_event)
315
+
316
+ return events_to_emit, message_started, message_id
317
+
318
+
319
+ def _create_completion_events(
320
+ chunk: Union[RunOutputEvent, TeamRunOutputEvent],
321
+ event_buffer: EventBuffer,
322
+ message_started: bool,
323
+ message_id: str,
324
+ thread_id: str,
325
+ run_id: str,
326
+ ) -> List[BaseEvent]:
327
+ """Create events for run completion."""
328
+ events_to_emit: List[BaseEvent] = []
329
+
330
+ # End remaining active tool calls if needed
331
+ for tool_call_id in list(event_buffer.active_tool_call_ids):
332
+ if tool_call_id not in event_buffer.ended_tool_call_ids:
333
+ end_event = ToolCallEndEvent(
334
+ type=EventType.TOOL_CALL_END,
335
+ tool_call_id=tool_call_id,
336
+ )
337
+ events_to_emit.append(end_event)
338
+
339
+ # End the message and run, denoting the end of the session
340
+ if message_started:
341
+ end_message_event = TextMessageEndEvent(type=EventType.TEXT_MESSAGE_END, message_id=message_id)
342
+ events_to_emit.append(end_message_event)
343
+
344
+ # emit frontend tool calls, i.e. external_execution=True
345
+ if isinstance(chunk, RunPausedEvent) and chunk.tools is not None:
346
+ # First, emit an assistant message for external tool calls
347
+ assistant_message_id = str(uuid.uuid4())
348
+ assistant_start_event = TextMessageStartEvent(
349
+ type=EventType.TEXT_MESSAGE_START,
350
+ message_id=assistant_message_id,
351
+ role="assistant",
352
+ )
353
+ events_to_emit.append(assistant_start_event)
354
+
355
+ # Add any text content if present for the assistant message
356
+ if chunk.content:
357
+ content_event = TextMessageContentEvent(
358
+ type=EventType.TEXT_MESSAGE_CONTENT,
359
+ message_id=assistant_message_id,
360
+ delta=str(chunk.content),
361
+ )
362
+ events_to_emit.append(content_event)
363
+
364
+ # End the assistant message
365
+ assistant_end_event = TextMessageEndEvent(
366
+ type=EventType.TEXT_MESSAGE_END,
367
+ message_id=assistant_message_id,
368
+ )
369
+ events_to_emit.append(assistant_end_event)
370
+
371
+ # Now emit the tool call events with the assistant message as parent
372
+ for tool in chunk.tools:
373
+ if tool.tool_call_id is None or tool.tool_name is None:
374
+ continue
375
+
376
+ start_event = ToolCallStartEvent(
377
+ type=EventType.TOOL_CALL_START,
378
+ tool_call_id=tool.tool_call_id,
379
+ tool_call_name=tool.tool_name,
380
+ parent_message_id=assistant_message_id, # Use the assistant message as parent
381
+ )
382
+ events_to_emit.append(start_event)
383
+
384
+ args_event = ToolCallArgsEvent(
385
+ type=EventType.TOOL_CALL_ARGS,
386
+ tool_call_id=tool.tool_call_id,
387
+ delta=json.dumps(tool.tool_args),
388
+ )
389
+ events_to_emit.append(args_event)
390
+
391
+ end_event = ToolCallEndEvent(
392
+ type=EventType.TOOL_CALL_END,
393
+ tool_call_id=tool.tool_call_id,
394
+ )
395
+ events_to_emit.append(end_event)
396
+
397
+ run_finished_event = RunFinishedEvent(type=EventType.RUN_FINISHED, thread_id=thread_id, run_id=run_id)
398
+ events_to_emit.append(run_finished_event)
399
+
400
+ return events_to_emit
401
+
402
+
403
+ def _emit_event_logic(event: BaseEvent, event_buffer: EventBuffer) -> List[BaseEvent]:
404
+ """Process an event and return events to actually emit."""
405
+ events_to_emit: List[BaseEvent] = [event]
406
+
407
+ # Update the event buffer state for tracking purposes
408
+ if event.type == EventType.TOOL_CALL_START:
409
+ tool_call_id = getattr(event, "tool_call_id", None)
410
+ if tool_call_id:
411
+ event_buffer.start_tool_call(tool_call_id)
412
+ elif event.type == EventType.TOOL_CALL_END:
413
+ tool_call_id = getattr(event, "tool_call_id", None)
414
+ if tool_call_id:
415
+ event_buffer.end_tool_call(tool_call_id)
416
+
417
+ return events_to_emit
418
+
419
+
420
+ def stream_agno_response_as_agui_events(
421
+ response_stream: Iterator[Union[RunOutputEvent, TeamRunOutputEvent]], thread_id: str, run_id: str
422
+ ) -> Iterator[BaseEvent]:
423
+ """Map the Agno response stream to AG-UI format, handling event ordering constraints."""
424
+ message_id = "" # Will be set by EventBuffer when text message starts
425
+ message_started = False
426
+ event_buffer = EventBuffer()
427
+ stream_completed = False
428
+
429
+ completion_chunk = None
430
+
431
+ for chunk in response_stream:
432
+ # Check if this is a completion event
433
+ if (
434
+ chunk.event == RunEvent.run_completed
435
+ or chunk.event == TeamRunEvent.run_completed
436
+ or chunk.event == RunEvent.run_paused
437
+ ):
438
+ # Store completion chunk but don't process it yet
439
+ completion_chunk = chunk
440
+ stream_completed = True
441
+ else:
442
+ # Process regular chunk immediately
443
+ events_from_chunk, message_started, message_id = _create_events_from_chunk(
444
+ chunk, message_id, message_started, event_buffer
445
+ )
446
+
447
+ for event in events_from_chunk:
448
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
449
+ for emit_event in events_to_emit:
450
+ yield emit_event
451
+
452
+ # Process ONLY completion cleanup events, not content from completion chunk
453
+ if completion_chunk:
454
+ completion_events = _create_completion_events(
455
+ completion_chunk, event_buffer, message_started, message_id, thread_id, run_id
456
+ )
457
+ for event in completion_events:
458
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
459
+ for emit_event in events_to_emit:
460
+ yield emit_event
461
+
462
+ # Ensure completion events are always emitted even when stream ends naturally
463
+ if not stream_completed:
464
+ # Create a synthetic completion event to ensure proper cleanup
465
+ from agno.run.agent import RunCompletedEvent
466
+
467
+ synthetic_completion = RunCompletedEvent()
468
+ completion_events = _create_completion_events(
469
+ synthetic_completion, event_buffer, message_started, message_id, thread_id, run_id
470
+ )
471
+ for event in completion_events:
472
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
473
+ for emit_event in events_to_emit:
474
+ yield emit_event
475
+
476
+
477
+ # Async version - thin wrapper
478
+ async def async_stream_agno_response_as_agui_events(
479
+ response_stream: AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent]],
480
+ thread_id: str,
481
+ run_id: str,
482
+ ) -> AsyncIterator[BaseEvent]:
483
+ """Map the Agno response stream to AG-UI format, handling event ordering constraints."""
484
+ message_id = "" # Will be set by EventBuffer when text message starts
485
+ message_started = False
486
+ event_buffer = EventBuffer()
487
+ stream_completed = False
488
+
489
+ completion_chunk = None
490
+
491
+ async for chunk in response_stream:
492
+ # Check if this is a completion event
493
+ if (
494
+ chunk.event == RunEvent.run_completed
495
+ or chunk.event == TeamRunEvent.run_completed
496
+ or chunk.event == RunEvent.run_paused
497
+ ):
498
+ # Store completion chunk but don't process it yet
499
+ completion_chunk = chunk
500
+ stream_completed = True
501
+ else:
502
+ # Process regular chunk immediately
503
+ events_from_chunk, message_started, message_id = _create_events_from_chunk(
504
+ chunk, message_id, message_started, event_buffer
505
+ )
506
+
507
+ for event in events_from_chunk:
508
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
509
+ for emit_event in events_to_emit:
510
+ yield emit_event
511
+
512
+ # Process ONLY completion cleanup events, not content from completion chunk
513
+ if completion_chunk:
514
+ completion_events = _create_completion_events(
515
+ completion_chunk, event_buffer, message_started, message_id, thread_id, run_id
516
+ )
517
+ for event in completion_events:
518
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
519
+ for emit_event in events_to_emit:
520
+ yield emit_event
521
+
522
+ # Ensure completion events are always emitted even when stream ends naturally
523
+ if not stream_completed:
524
+ # Create a synthetic completion event to ensure proper cleanup
525
+ from agno.run.agent import RunCompletedEvent
526
+
527
+ synthetic_completion = RunCompletedEvent()
528
+ completion_events = _create_completion_events(
529
+ synthetic_completion, event_buffer, message_started, message_id, thread_id, run_id
530
+ )
531
+ for event in completion_events:
532
+ events_to_emit = _emit_event_logic(event_buffer=event_buffer, event=event)
533
+ for emit_event in events_to_emit:
534
+ 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"]