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
agno/workflow/types.py ADDED
@@ -0,0 +1,556 @@
1
+ import json
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+ from typing import Any, Dict, List, Optional, Tuple, Union
5
+
6
+ from fastapi import WebSocket
7
+ from pydantic import BaseModel
8
+
9
+ from agno.media import Audio, File, Image, Video
10
+ from agno.models.metrics import Metrics
11
+ from agno.session.workflow import WorkflowSession
12
+ from agno.utils.log import log_warning
13
+ from agno.utils.media import (
14
+ reconstruct_audio_list,
15
+ reconstruct_files,
16
+ reconstruct_images,
17
+ reconstruct_videos,
18
+ )
19
+ from agno.utils.serialize import json_serializer
20
+ from agno.utils.timer import Timer
21
+
22
+
23
+ @dataclass
24
+ class WorkflowExecutionInput:
25
+ """Input data for a step execution"""
26
+
27
+ input: Optional[Union[str, Dict[str, Any], List[Any], BaseModel]] = None
28
+
29
+ additional_data: Optional[Dict[str, Any]] = None
30
+
31
+ # Media inputs
32
+ images: Optional[List[Image]] = None
33
+ videos: Optional[List[Video]] = None
34
+ audio: Optional[List[Audio]] = None
35
+ files: Optional[List[File]] = None
36
+
37
+ def get_input_as_string(self) -> Optional[str]:
38
+ """Convert input to string representation"""
39
+ if self.input is None:
40
+ return None
41
+
42
+ if isinstance(self.input, str):
43
+ return self.input
44
+ elif isinstance(self.input, BaseModel):
45
+ return self.input.model_dump_json(indent=2, exclude_none=True)
46
+ elif isinstance(self.input, (dict, list)):
47
+ import json
48
+
49
+ return json.dumps(self.input, indent=2, default=str)
50
+ else:
51
+ return str(self.input)
52
+
53
+ def to_dict(self) -> Dict[str, Any]:
54
+ """Convert to dictionary"""
55
+ input_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
56
+ if self.input is not None:
57
+ if isinstance(self.input, BaseModel):
58
+ input_dict = self.input.model_dump(exclude_none=True)
59
+ elif isinstance(self.input, (dict, list)):
60
+ input_dict = self.input
61
+ else:
62
+ input_dict = str(self.input)
63
+
64
+ return {
65
+ "input": input_dict,
66
+ "additional_data": self.additional_data,
67
+ "images": [img.to_dict() for img in self.images] if self.images else None,
68
+ "videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
69
+ "audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
70
+ "files": [file.to_dict() for file in self.files] if self.files else None,
71
+ }
72
+
73
+
74
+ @dataclass
75
+ class StepInput:
76
+ """Input data for a step execution"""
77
+
78
+ input: Optional[Union[str, Dict[str, Any], List[Any], BaseModel]] = None
79
+
80
+ previous_step_content: Optional[Any] = None
81
+ previous_step_outputs: Optional[Dict[str, "StepOutput"]] = None
82
+
83
+ additional_data: Optional[Dict[str, Any]] = None
84
+
85
+ # Media inputs
86
+ images: Optional[List[Image]] = None
87
+ videos: Optional[List[Video]] = None
88
+ audio: Optional[List[Audio]] = None
89
+ files: Optional[List[File]] = None
90
+
91
+ workflow_session: Optional["WorkflowSession"] = None
92
+
93
+ def get_input_as_string(self) -> Optional[str]:
94
+ """Convert input to string representation"""
95
+ if self.input is None:
96
+ return None
97
+
98
+ if isinstance(self.input, str):
99
+ return self.input
100
+ elif isinstance(self.input, BaseModel):
101
+ return self.input.model_dump_json(indent=2, exclude_none=True)
102
+ elif isinstance(self.input, (dict, list)):
103
+ import json
104
+
105
+ return json.dumps(self.input, indent=2, default=str)
106
+ else:
107
+ return str(self.input)
108
+
109
+ def get_step_output(self, step_name: str) -> Optional["StepOutput"]:
110
+ """Get output from a specific previous step by name
111
+
112
+ Searches recursively through nested steps (Parallel, Condition, Router, Loop, Steps)
113
+ to find step outputs at any depth.
114
+ """
115
+ if not self.previous_step_outputs:
116
+ return None
117
+
118
+ # First try direct lookup
119
+ direct = self.previous_step_outputs.get(step_name)
120
+ if direct:
121
+ return direct
122
+
123
+ # Search recursively in nested steps
124
+ return self._search_nested_steps(step_name)
125
+
126
+ def _search_nested_steps(self, step_name: str) -> Optional["StepOutput"]:
127
+ """Recursively search for a step output in nested steps (Parallel, Condition, etc.)"""
128
+ if not self.previous_step_outputs:
129
+ return None
130
+
131
+ for step_output in self.previous_step_outputs.values():
132
+ result = self._search_in_step_output(step_output, step_name)
133
+ if result:
134
+ return result
135
+ return None
136
+
137
+ def _search_in_step_output(self, step_output: "StepOutput", step_name: str) -> Optional["StepOutput"]:
138
+ """Helper to recursively search within a single StepOutput"""
139
+ if not step_output.steps:
140
+ return None
141
+
142
+ for nested_step in step_output.steps:
143
+ if nested_step.step_name == step_name:
144
+ return nested_step
145
+ # Recursively search deeper
146
+ result = self._search_in_step_output(nested_step, step_name)
147
+ if result:
148
+ return result
149
+ return None
150
+
151
+ def get_step_content(self, step_name: str) -> Optional[Union[str, Dict[str, str]]]:
152
+ """Get content from a specific previous step by name
153
+
154
+ For parallel steps, if you ask for the parallel step name, returns a dict
155
+ with {step_name: content} for each sub-step.
156
+ For other nested steps (Condition, Router, Loop, Steps), returns the deepest content.
157
+ """
158
+ step_output = self.get_step_output(step_name)
159
+ if not step_output:
160
+ return None
161
+
162
+ # Check if this is a parallel step with nested steps
163
+ if step_output.step_type == "Parallel" and step_output.steps:
164
+ # Return dict with {step_name: content} for each sub-step
165
+ parallel_content = {}
166
+ for sub_step in step_output.steps:
167
+ if sub_step.step_name and sub_step.content:
168
+ # Check if this sub-step has its own nested steps (like Condition -> Research Step)
169
+ if sub_step.steps and len(sub_step.steps) > 0:
170
+ # This is a composite step (like Condition) - get content from its nested steps
171
+ for nested_step in sub_step.steps:
172
+ if nested_step.step_name and nested_step.content:
173
+ parallel_content[nested_step.step_name] = str(nested_step.content)
174
+ else:
175
+ # This is a direct step - use its content
176
+ parallel_content[sub_step.step_name] = str(sub_step.content)
177
+ return parallel_content if parallel_content else str(step_output.content)
178
+
179
+ # For other nested step types (Condition, Router, Loop, Steps), get the deepest content
180
+ elif step_output.steps and len(step_output.steps) > 0:
181
+ # This is a nested step structure - recursively get the deepest content
182
+ return self._get_deepest_step_content(step_output.steps[-1])
183
+
184
+ # Regular step, return content directly
185
+ return step_output.content # type: ignore[return-value]
186
+
187
+ def _get_deepest_step_content(self, step_output: "StepOutput") -> Optional[Union[str, Dict[str, str]]]:
188
+ """Helper method to recursively extract deepest content from nested steps"""
189
+ # If this step has nested steps, go deeper
190
+ if step_output.steps and len(step_output.steps) > 0:
191
+ return self._get_deepest_step_content(step_output.steps[-1])
192
+
193
+ # Return the content of this step
194
+ return step_output.content # type: ignore[return-value]
195
+
196
+ def get_all_previous_content(self) -> str:
197
+ """Get concatenated content from all previous steps"""
198
+ if not self.previous_step_outputs:
199
+ return ""
200
+
201
+ content_parts = []
202
+ for step_name, output in self.previous_step_outputs.items():
203
+ if output.content:
204
+ content_parts.append(f"=== {step_name} ===\n{output.content}")
205
+
206
+ return "\n\n".join(content_parts)
207
+
208
+ def get_last_step_content(self) -> Optional[str]:
209
+ """Get content from the most recent step (for backward compatibility)"""
210
+ if not self.previous_step_outputs:
211
+ return None
212
+
213
+ last_output = list(self.previous_step_outputs.values())[-1] if self.previous_step_outputs else None
214
+ if not last_output:
215
+ return None
216
+
217
+ # Use the helper method to get the deepest content
218
+ return self._get_deepest_step_content(last_output) # type: ignore[return-value]
219
+
220
+ def get_workflow_history(self, num_runs: Optional[int] = None) -> List[Tuple[str, str]]:
221
+ """Get workflow conversation history as structured data for custom function steps
222
+
223
+ Args:
224
+ num_runs: Number of recent runs to include. If None, returns all available history.
225
+ """
226
+ if not self.workflow_session:
227
+ return []
228
+
229
+ return self.workflow_session.get_workflow_history(num_runs=num_runs)
230
+
231
+ def get_workflow_history_context(self, num_runs: Optional[int] = None) -> Optional[str]:
232
+ """Get formatted workflow conversation history context for custom function steps
233
+
234
+ Args:
235
+ num_runs: Number of recent runs to include. If None, returns all available history.
236
+ """
237
+ if not self.workflow_session:
238
+ return None
239
+
240
+ return self.workflow_session.get_workflow_history_context(num_runs=num_runs)
241
+
242
+ def to_dict(self) -> Dict[str, Any]:
243
+ """Convert to dictionary"""
244
+ # Handle the unified message field
245
+ input_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
246
+ if self.input is not None:
247
+ if isinstance(self.input, BaseModel):
248
+ input_dict = self.input.model_dump(exclude_none=True, mode="json")
249
+ elif isinstance(self.input, (dict, list)):
250
+ input_dict = self.input
251
+ else:
252
+ input_dict = str(self.input)
253
+
254
+ previous_step_content_str: Optional[str] = None
255
+ # Handle previous_step_content (keep existing logic)
256
+ if isinstance(self.previous_step_content, BaseModel):
257
+ previous_step_content_str = self.previous_step_content.model_dump_json(indent=2, exclude_none=True)
258
+ elif isinstance(self.previous_step_content, dict):
259
+ import json
260
+
261
+ previous_step_content_str = json.dumps(self.previous_step_content, indent=2, default=str)
262
+ elif self.previous_step_content:
263
+ previous_step_content_str = str(self.previous_step_content)
264
+
265
+ # Convert previous_step_outputs to serializable format (keep existing logic)
266
+ previous_steps_dict = {}
267
+ if self.previous_step_outputs:
268
+ for step_name, output in self.previous_step_outputs.items():
269
+ previous_steps_dict[step_name] = output.to_dict()
270
+
271
+ return {
272
+ "input": input_dict,
273
+ "previous_step_outputs": previous_steps_dict,
274
+ "previous_step_content": previous_step_content_str,
275
+ "additional_data": self.additional_data,
276
+ "images": [img.to_dict() for img in self.images] if self.images else None,
277
+ "videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
278
+ "audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
279
+ "files": [file for file in self.files] if self.files else None,
280
+ }
281
+
282
+
283
+ @dataclass
284
+ class StepOutput:
285
+ """Output data from a step execution"""
286
+
287
+ step_name: Optional[str] = None
288
+ step_id: Optional[str] = None
289
+ step_type: Optional[str] = None
290
+ executor_type: Optional[str] = None
291
+ executor_name: Optional[str] = None
292
+ # Primary output
293
+ content: Optional[Union[str, Dict[str, Any], List[Any], BaseModel, Any]] = None
294
+
295
+ # Link to the run ID of the step execution
296
+ step_run_id: Optional[str] = None
297
+
298
+ # Media outputs
299
+ images: Optional[List[Image]] = None
300
+ videos: Optional[List[Video]] = None
301
+ audio: Optional[List[Audio]] = None
302
+ files: Optional[List[File]] = None
303
+
304
+ # Metrics for this step execution
305
+ metrics: Optional[Metrics] = None
306
+
307
+ success: bool = True
308
+ error: Optional[str] = None
309
+
310
+ stop: bool = False
311
+
312
+ steps: Optional[List["StepOutput"]] = None
313
+
314
+ def to_dict(self) -> Dict[str, Any]:
315
+ """Convert to dictionary"""
316
+ # Handle the unified content field
317
+ content_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
318
+ if self.content is not None:
319
+ if isinstance(self.content, BaseModel):
320
+ content_dict = self.content.model_dump(exclude_none=True, mode="json")
321
+ elif isinstance(self.content, (dict, list)):
322
+ content_dict = self.content
323
+ else:
324
+ content_dict = str(self.content)
325
+
326
+ result = {
327
+ "content": content_dict,
328
+ "step_name": self.step_name,
329
+ "step_id": self.step_id,
330
+ "step_type": self.step_type,
331
+ "executor_type": self.executor_type,
332
+ "executor_name": self.executor_name,
333
+ "step_run_id": self.step_run_id,
334
+ "images": [img.to_dict() for img in self.images] if self.images else None,
335
+ "videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
336
+ "audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
337
+ "metrics": self.metrics.to_dict() if self.metrics else None,
338
+ "success": self.success,
339
+ "error": self.error,
340
+ "stop": self.stop,
341
+ "files": [file for file in self.files] if self.files else None,
342
+ }
343
+
344
+ # Add nested steps if they exist
345
+ if self.steps:
346
+ result["steps"] = [step.to_dict() for step in self.steps]
347
+
348
+ return result
349
+
350
+ @classmethod
351
+ def from_dict(cls, data: Dict[str, Any]) -> "StepOutput":
352
+ """Create StepOutput from dictionary"""
353
+ # Reconstruct media artifacts
354
+ images = reconstruct_images(data.get("images"))
355
+ videos = reconstruct_videos(data.get("videos"))
356
+ audio = reconstruct_audio_list(data.get("audio"))
357
+ files = reconstruct_files(data.get("files"))
358
+
359
+ metrics_data = data.get("metrics")
360
+ metrics = None
361
+ if metrics_data:
362
+ if isinstance(metrics_data, dict):
363
+ # Convert dict to Metrics object
364
+ from agno.models.metrics import Metrics
365
+
366
+ metrics = Metrics(**metrics_data)
367
+ else:
368
+ # Already a Metrics object
369
+ metrics = metrics_data
370
+
371
+ # Handle nested steps
372
+ steps_data = data.get("steps")
373
+ steps = None
374
+ if steps_data:
375
+ steps = [cls.from_dict(step_data) for step_data in steps_data]
376
+
377
+ return cls(
378
+ step_name=data.get("step_name"),
379
+ step_id=data.get("step_id"),
380
+ step_type=data.get("step_type"),
381
+ executor_type=data.get("executor_type"),
382
+ executor_name=data.get("executor_name"),
383
+ content=data.get("content"),
384
+ step_run_id=data.get("step_run_id"),
385
+ images=images,
386
+ videos=videos,
387
+ audio=audio,
388
+ files=files,
389
+ metrics=metrics,
390
+ success=data.get("success", True),
391
+ error=data.get("error"),
392
+ stop=data.get("stop", False),
393
+ steps=steps,
394
+ )
395
+
396
+
397
+ @dataclass
398
+ class StepMetrics:
399
+ """Metrics for a single step execution"""
400
+
401
+ step_name: str
402
+ executor_type: str # "agent", "team", etc.
403
+ executor_name: str
404
+ metrics: Optional[Metrics] = None
405
+
406
+ def to_dict(self) -> Dict[str, Any]:
407
+ """Convert to dictionary"""
408
+ return {
409
+ "step_name": self.step_name,
410
+ "executor_type": self.executor_type,
411
+ "executor_name": self.executor_name,
412
+ "metrics": self.metrics.to_dict() if self.metrics else None,
413
+ }
414
+
415
+ @classmethod
416
+ def from_dict(cls, data: Dict[str, Any]) -> "StepMetrics":
417
+ """Create StepMetrics from dictionary"""
418
+
419
+ # Handle metrics properly
420
+ metrics_data = data.get("metrics")
421
+ metrics = None
422
+ if metrics_data:
423
+ if isinstance(metrics_data, dict):
424
+ # Convert dict to Metrics object
425
+ from agno.models.metrics import Metrics
426
+
427
+ metrics = Metrics(**metrics_data)
428
+ else:
429
+ # Already a Metrics object
430
+ metrics = metrics_data
431
+
432
+ return cls(
433
+ step_name=data["step_name"],
434
+ executor_type=data["executor_type"],
435
+ executor_name=data["executor_name"],
436
+ metrics=metrics,
437
+ )
438
+
439
+
440
+ @dataclass
441
+ class WorkflowMetrics:
442
+ """Complete metrics for a workflow execution"""
443
+
444
+ steps: Dict[str, StepMetrics]
445
+ # Timer utility for tracking execution time
446
+ timer: Optional[Timer] = None
447
+ # Total workflow execution time
448
+ duration: Optional[float] = None
449
+
450
+ def to_dict(self) -> Dict[str, Any]:
451
+ """Convert to dictionary"""
452
+ result: Dict[str, Any] = {
453
+ "steps": {name: step.to_dict() for name, step in self.steps.items()},
454
+ "duration": self.duration,
455
+ }
456
+ return result
457
+
458
+ @classmethod
459
+ def from_dict(cls, data: Dict[str, Any]) -> "WorkflowMetrics":
460
+ """Create WorkflowMetrics from dictionary"""
461
+ steps = {name: StepMetrics.from_dict(step_data) for name, step_data in data["steps"].items()}
462
+
463
+ return cls(
464
+ steps=steps,
465
+ duration=data.get("duration"),
466
+ )
467
+
468
+ def start_timer(self):
469
+ if self.timer is None:
470
+ self.timer = Timer()
471
+ self.timer.start()
472
+
473
+ def stop_timer(self, set_duration: bool = True):
474
+ if self.timer is not None:
475
+ self.timer.stop()
476
+ if set_duration:
477
+ self.duration = self.timer.elapsed
478
+
479
+
480
+ @dataclass
481
+ class WebSocketHandler:
482
+ """Generic WebSocket handler for real-time workflow events"""
483
+
484
+ websocket: Optional[WebSocket] = None
485
+
486
+ def format_sse_event(self, json_data: str) -> str:
487
+ """Parse JSON data into SSE-compliant format.
488
+
489
+ Args:
490
+ json_data: JSON string containing the event data
491
+
492
+ Returns:
493
+ SSE-formatted response with event type and data
494
+ """
495
+ import json
496
+
497
+ try:
498
+ # Parse the JSON to extract the event type
499
+ data = json.loads(json_data)
500
+ event_type = data.get("event", "message")
501
+
502
+ # Format as SSE: event: <event_type>\ndata: <json_data>\n\n
503
+ return f"event: {event_type}\ndata: {json_data}\n\n"
504
+ except (json.JSONDecodeError, KeyError):
505
+ # Fallback to generic message event if parsing fails
506
+ return f"event: message\ndata: {json_data}\n\n"
507
+
508
+ async def handle_event(self, event: Any) -> None:
509
+ """Handle an event object - serializes and sends via WebSocket"""
510
+ if not self.websocket:
511
+ return
512
+
513
+ try:
514
+ if hasattr(event, "to_dict"):
515
+ data = event.to_dict()
516
+ elif hasattr(event, "__dict__"):
517
+ data = event.__dict__
518
+ elif isinstance(event, dict):
519
+ data = event
520
+ else:
521
+ data = {"type": "message", "content": str(event)}
522
+
523
+ await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
524
+
525
+ except Exception as e:
526
+ log_warning(f"Failed to handle WebSocket event: {e}")
527
+
528
+ async def handle_text(self, message: str) -> None:
529
+ """Handle a plain text message"""
530
+ if not self.websocket:
531
+ return
532
+
533
+ try:
534
+ await self.websocket.send_text(self.format_sse_event(message))
535
+ except Exception as e:
536
+ log_warning(f"Failed to send WebSocket text: {e}")
537
+
538
+ async def handle_dict(self, data: Dict[str, Any]) -> None:
539
+ """Handle a dictionary directly"""
540
+ if not self.websocket:
541
+ return
542
+
543
+ try:
544
+ await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
545
+ except Exception as e:
546
+ log_warning(f"Failed to send WebSocket dict: {e}")
547
+
548
+
549
+ class StepType(str, Enum):
550
+ FUNCTION = "Function"
551
+ STEP = "Step"
552
+ STEPS = "Steps"
553
+ LOOP = "Loop"
554
+ PARALLEL = "Parallel"
555
+ CONDITION = "Condition"
556
+ ROUTER = "Router"