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/loop.py ADDED
@@ -0,0 +1,756 @@
1
+ import inspect
2
+ import warnings
3
+ from dataclasses import dataclass
4
+ from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
5
+ from uuid import uuid4
6
+
7
+ from agno.run.agent import RunOutputEvent
8
+ from agno.run.base import RunContext
9
+ from agno.run.team import TeamRunOutputEvent
10
+ from agno.run.workflow import (
11
+ LoopExecutionCompletedEvent,
12
+ LoopExecutionStartedEvent,
13
+ LoopIterationCompletedEvent,
14
+ LoopIterationStartedEvent,
15
+ WorkflowRunOutput,
16
+ WorkflowRunOutputEvent,
17
+ )
18
+ from agno.session.workflow import WorkflowSession
19
+ from agno.utils.log import log_debug, logger
20
+ from agno.workflow.step import Step
21
+ from agno.workflow.types import StepInput, StepOutput, StepType
22
+
23
+ WorkflowSteps = List[
24
+ Union[
25
+ Callable[
26
+ [StepInput], Union[StepOutput, Awaitable[StepOutput], Iterator[StepOutput], AsyncIterator[StepOutput]]
27
+ ],
28
+ Step,
29
+ "Steps", # type: ignore # noqa: F821
30
+ "Loop", # type: ignore # noqa: F821
31
+ "Parallel", # type: ignore # noqa: F821
32
+ "Condition", # type: ignore # noqa: F821
33
+ "Router", # type: ignore # noqa: F821
34
+ ]
35
+ ]
36
+
37
+
38
+ @dataclass
39
+ class Loop:
40
+ """A loop of steps that execute in order"""
41
+
42
+ steps: WorkflowSteps
43
+
44
+ name: Optional[str] = None
45
+ description: Optional[str] = None
46
+
47
+ max_iterations: int = 3 # Default to 3
48
+ end_condition: Optional[Callable[[List[StepOutput]], bool]] = None
49
+
50
+ def __init__(
51
+ self,
52
+ steps: WorkflowSteps,
53
+ name: Optional[str] = None,
54
+ description: Optional[str] = None,
55
+ max_iterations: int = 3,
56
+ end_condition: Optional[Callable[[List[StepOutput]], bool]] = None,
57
+ ):
58
+ self.steps = steps
59
+ self.name = name
60
+ self.description = description
61
+ self.max_iterations = max_iterations
62
+ self.end_condition = end_condition
63
+
64
+ def _prepare_steps(self):
65
+ """Prepare the steps for execution - mirrors workflow logic"""
66
+ from agno.agent.agent import Agent
67
+ from agno.team.team import Team
68
+ from agno.workflow.condition import Condition
69
+ from agno.workflow.parallel import Parallel
70
+ from agno.workflow.router import Router
71
+ from agno.workflow.step import Step
72
+ from agno.workflow.steps import Steps
73
+
74
+ prepared_steps: WorkflowSteps = []
75
+ for step in self.steps:
76
+ if callable(step) and hasattr(step, "__name__"):
77
+ prepared_steps.append(Step(name=step.__name__, description="User-defined callable step", executor=step))
78
+ elif isinstance(step, Agent):
79
+ prepared_steps.append(Step(name=step.name, description=step.description, agent=step))
80
+ elif isinstance(step, Team):
81
+ prepared_steps.append(Step(name=step.name, description=step.description, team=step))
82
+ elif isinstance(step, (Step, Steps, Loop, Parallel, Condition, Router)):
83
+ prepared_steps.append(step)
84
+ else:
85
+ raise ValueError(f"Invalid step type: {type(step).__name__}")
86
+
87
+ self.steps = prepared_steps
88
+
89
+ def _update_step_input_from_outputs(
90
+ self,
91
+ step_input: StepInput,
92
+ step_outputs: Union[StepOutput, List[StepOutput]],
93
+ loop_step_outputs: Optional[Dict[str, StepOutput]] = None,
94
+ ) -> StepInput:
95
+ """Helper to update step input from step outputs (handles both single and multiple outputs)"""
96
+ current_images = step_input.images or []
97
+ current_videos = step_input.videos or []
98
+ current_audio = step_input.audio or []
99
+
100
+ if isinstance(step_outputs, list):
101
+ all_images = sum([out.images or [] for out in step_outputs], [])
102
+ all_videos = sum([out.videos or [] for out in step_outputs], [])
103
+ all_audio = sum([out.audio or [] for out in step_outputs], [])
104
+
105
+ # Use the last output's content for chaining
106
+ previous_step_content = step_outputs[-1].content if step_outputs else None
107
+ else:
108
+ # Single output
109
+ all_images = step_outputs.images or []
110
+ all_videos = step_outputs.videos or []
111
+ all_audio = step_outputs.audio or []
112
+ previous_step_content = step_outputs.content
113
+
114
+ updated_previous_step_outputs = {}
115
+ if step_input.previous_step_outputs:
116
+ updated_previous_step_outputs.update(step_input.previous_step_outputs)
117
+ if loop_step_outputs:
118
+ updated_previous_step_outputs.update(loop_step_outputs)
119
+
120
+ return StepInput(
121
+ input=step_input.input,
122
+ previous_step_content=previous_step_content,
123
+ previous_step_outputs=updated_previous_step_outputs,
124
+ additional_data=step_input.additional_data,
125
+ images=current_images + all_images,
126
+ videos=current_videos + all_videos,
127
+ audio=current_audio + all_audio,
128
+ )
129
+
130
+ def execute(
131
+ self,
132
+ step_input: StepInput,
133
+ session_id: Optional[str] = None,
134
+ user_id: Optional[str] = None,
135
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
136
+ store_executor_outputs: bool = True,
137
+ run_context: Optional[RunContext] = None,
138
+ session_state: Optional[Dict[str, Any]] = None,
139
+ workflow_session: Optional[WorkflowSession] = None,
140
+ add_workflow_history_to_steps: Optional[bool] = False,
141
+ num_history_runs: int = 3,
142
+ background_tasks: Optional[Any] = None,
143
+ ) -> StepOutput:
144
+ """Execute loop steps with iteration control - mirrors workflow execution logic"""
145
+ # Use workflow logger for loop orchestration
146
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
147
+
148
+ # Prepare steps first
149
+ self._prepare_steps()
150
+
151
+ all_results = []
152
+ iteration = 0
153
+
154
+ while iteration < self.max_iterations:
155
+ # Execute all steps in this iteration - mirroring workflow logic
156
+ iteration_results: List[StepOutput] = []
157
+ current_step_input = step_input
158
+ loop_step_outputs = {} # Track outputs within this loop iteration
159
+
160
+ for i, step in enumerate(self.steps):
161
+ step_output = step.execute( # type: ignore[union-attr]
162
+ current_step_input,
163
+ session_id=session_id,
164
+ user_id=user_id,
165
+ workflow_run_response=workflow_run_response,
166
+ store_executor_outputs=store_executor_outputs,
167
+ run_context=run_context,
168
+ session_state=session_state,
169
+ workflow_session=workflow_session,
170
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
171
+ num_history_runs=num_history_runs,
172
+ background_tasks=background_tasks,
173
+ )
174
+
175
+ # Handle both single StepOutput and List[StepOutput] (from Loop/Condition steps)
176
+ if isinstance(step_output, list):
177
+ # This is a step that returns multiple outputs (Loop, Condition etc.)
178
+ iteration_results.extend(step_output)
179
+ if step_output: # Add last output to loop tracking
180
+ step_name = getattr(step, "name", f"step_{i + 1}")
181
+ loop_step_outputs[step_name] = step_output[-1]
182
+
183
+ if any(output.stop for output in step_output):
184
+ logger.info(f"Early termination requested by step {step_name}")
185
+ break
186
+ else:
187
+ # Single StepOutput
188
+ iteration_results.append(step_output)
189
+ step_name = getattr(step, "name", f"step_{i + 1}")
190
+ loop_step_outputs[step_name] = step_output
191
+
192
+ if step_output.stop:
193
+ logger.info(f"Early termination requested by step {step_name}")
194
+ break
195
+
196
+ # Update step input for next step
197
+ current_step_input = self._update_step_input_from_outputs(
198
+ current_step_input, step_output, loop_step_outputs
199
+ )
200
+
201
+ all_results.append(iteration_results)
202
+ iteration += 1
203
+
204
+ # Check end condition
205
+ if self.end_condition and callable(self.end_condition):
206
+ try:
207
+ should_break = self.end_condition(iteration_results)
208
+ if should_break:
209
+ break
210
+ except Exception as e:
211
+ logger.warning(f"End condition evaluation failed: {e}")
212
+ # Continue with loop if end condition fails
213
+
214
+ log_debug(f"Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
215
+
216
+ # Return flattened results from all iterations
217
+ flattened_results = []
218
+ for iteration_results in all_results:
219
+ flattened_results.extend(iteration_results)
220
+
221
+ return StepOutput(
222
+ step_name=self.name,
223
+ step_id=str(uuid4()),
224
+ step_type=StepType.LOOP,
225
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
226
+ success=all(result.success for result in flattened_results) if flattened_results else True,
227
+ steps=flattened_results,
228
+ )
229
+
230
+ def execute_stream(
231
+ self,
232
+ step_input: StepInput,
233
+ session_id: Optional[str] = None,
234
+ user_id: Optional[str] = None,
235
+ stream_events: bool = False,
236
+ stream_intermediate_steps: bool = False,
237
+ stream_executor_events: bool = True,
238
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
239
+ step_index: Optional[Union[int, tuple]] = None,
240
+ store_executor_outputs: bool = True,
241
+ run_context: Optional[RunContext] = None,
242
+ session_state: Optional[Dict[str, Any]] = None,
243
+ parent_step_id: Optional[str] = None,
244
+ workflow_session: Optional[WorkflowSession] = None,
245
+ add_workflow_history_to_steps: Optional[bool] = False,
246
+ num_history_runs: int = 3,
247
+ background_tasks: Optional[Any] = None,
248
+ ) -> Iterator[Union[WorkflowRunOutputEvent, StepOutput]]:
249
+ """Execute loop steps with streaming support - mirrors workflow execution logic"""
250
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
251
+
252
+ # Prepare steps first
253
+ self._prepare_steps()
254
+
255
+ loop_step_id = str(uuid4())
256
+
257
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
258
+ if stream_intermediate_steps is not None:
259
+ warnings.warn(
260
+ "The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
261
+ DeprecationWarning,
262
+ stacklevel=2,
263
+ )
264
+ stream_events = stream_events or stream_intermediate_steps
265
+
266
+ if stream_events and workflow_run_response:
267
+ # Yield loop started event
268
+ yield LoopExecutionStartedEvent(
269
+ run_id=workflow_run_response.run_id or "",
270
+ workflow_name=workflow_run_response.workflow_name or "",
271
+ workflow_id=workflow_run_response.workflow_id or "",
272
+ session_id=workflow_run_response.session_id or "",
273
+ step_name=self.name,
274
+ step_index=step_index,
275
+ max_iterations=self.max_iterations,
276
+ step_id=loop_step_id,
277
+ parent_step_id=parent_step_id,
278
+ )
279
+
280
+ all_results = []
281
+ iteration = 0
282
+ early_termination = False
283
+
284
+ while iteration < self.max_iterations:
285
+ log_debug(f"Loop iteration {iteration + 1}/{self.max_iterations}")
286
+
287
+ if stream_events and workflow_run_response:
288
+ # Yield iteration started event
289
+ yield LoopIterationStartedEvent(
290
+ run_id=workflow_run_response.run_id or "",
291
+ workflow_name=workflow_run_response.workflow_name or "",
292
+ workflow_id=workflow_run_response.workflow_id or "",
293
+ session_id=workflow_run_response.session_id or "",
294
+ step_name=self.name,
295
+ step_index=step_index,
296
+ iteration=iteration + 1,
297
+ max_iterations=self.max_iterations,
298
+ step_id=loop_step_id,
299
+ parent_step_id=parent_step_id,
300
+ )
301
+
302
+ # Execute all steps in this iteration - mirroring workflow logic
303
+ iteration_results = []
304
+ current_step_input = step_input
305
+ loop_step_outputs = {}
306
+
307
+ for i, step in enumerate(self.steps):
308
+ step_outputs_for_iteration = []
309
+
310
+ # Loop children always get sequential sub-indices: parent_index.1, parent_index.2, etc.
311
+ if step_index is None or isinstance(step_index, int):
312
+ # Loop is a main step
313
+ composite_step_index = (step_index if step_index is not None else 0, i)
314
+ else:
315
+ # Loop is a nested step - extend the tuple
316
+ composite_step_index = step_index + (i,)
317
+
318
+ # Stream step execution
319
+ for event in step.execute_stream( # type: ignore[union-attr]
320
+ current_step_input,
321
+ session_id=session_id,
322
+ user_id=user_id,
323
+ stream_events=stream_events,
324
+ stream_executor_events=stream_executor_events,
325
+ workflow_run_response=workflow_run_response,
326
+ step_index=composite_step_index,
327
+ store_executor_outputs=store_executor_outputs,
328
+ run_context=run_context,
329
+ session_state=session_state,
330
+ parent_step_id=loop_step_id,
331
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
332
+ workflow_session=workflow_session,
333
+ num_history_runs=num_history_runs,
334
+ background_tasks=background_tasks,
335
+ ):
336
+ if isinstance(event, StepOutput):
337
+ step_outputs_for_iteration.append(event)
338
+ iteration_results.append(event)
339
+ else:
340
+ # Yield other events (streaming content, step events, etc.)
341
+ yield event
342
+
343
+ # Update loop_step_outputs with this step's output
344
+ if step_outputs_for_iteration:
345
+ step_name = getattr(step, "name", f"step_{i + 1}")
346
+ if len(step_outputs_for_iteration) == 1:
347
+ loop_step_outputs[step_name] = step_outputs_for_iteration[0]
348
+
349
+ if step_outputs_for_iteration[0].stop:
350
+ logger.info(f"Early termination requested by step {step_name}")
351
+ early_termination = True
352
+ break # Break out of step loop
353
+
354
+ current_step_input = self._update_step_input_from_outputs(
355
+ current_step_input, step_outputs_for_iteration[0], loop_step_outputs
356
+ )
357
+ else:
358
+ # Use last output
359
+ loop_step_outputs[step_name] = step_outputs_for_iteration[-1]
360
+
361
+ if any(output.stop for output in step_outputs_for_iteration):
362
+ logger.info(f"Early termination requested by step {step_name}")
363
+ early_termination = True
364
+ break # Break out of step loop
365
+
366
+ current_step_input = self._update_step_input_from_outputs(
367
+ current_step_input, step_outputs_for_iteration, loop_step_outputs
368
+ )
369
+
370
+ all_results.append(iteration_results)
371
+
372
+ # Check end condition
373
+ should_continue = True
374
+ if self.end_condition and callable(self.end_condition):
375
+ try:
376
+ should_break = self.end_condition(iteration_results)
377
+ should_continue = not should_break
378
+ log_debug(f"End condition returned: {should_break}, should_continue: {should_continue}")
379
+ except Exception as e:
380
+ logger.warning(f"End condition evaluation failed: {e}")
381
+
382
+ if early_termination:
383
+ should_continue = False
384
+ log_debug(f"Loop ending early due to step termination request at iteration {iteration}")
385
+
386
+ if stream_events and workflow_run_response:
387
+ # Yield iteration completed event
388
+ yield LoopIterationCompletedEvent(
389
+ run_id=workflow_run_response.run_id or "",
390
+ workflow_name=workflow_run_response.workflow_name or "",
391
+ workflow_id=workflow_run_response.workflow_id or "",
392
+ session_id=workflow_run_response.session_id or "",
393
+ step_name=self.name,
394
+ step_index=step_index,
395
+ iteration=iteration + 1,
396
+ max_iterations=self.max_iterations,
397
+ iteration_results=iteration_results,
398
+ should_continue=should_continue,
399
+ step_id=loop_step_id,
400
+ parent_step_id=parent_step_id,
401
+ )
402
+
403
+ iteration += 1
404
+
405
+ if not should_continue:
406
+ log_debug(f"Loop ending early due to end_condition at iteration {iteration}")
407
+ break
408
+
409
+ log_debug(f"Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
410
+
411
+ if stream_events and workflow_run_response:
412
+ # Yield loop completed event
413
+ yield LoopExecutionCompletedEvent(
414
+ run_id=workflow_run_response.run_id or "",
415
+ workflow_name=workflow_run_response.workflow_name or "",
416
+ workflow_id=workflow_run_response.workflow_id or "",
417
+ session_id=workflow_run_response.session_id or "",
418
+ step_name=self.name,
419
+ step_index=step_index,
420
+ total_iterations=iteration,
421
+ max_iterations=self.max_iterations,
422
+ all_results=all_results,
423
+ step_id=loop_step_id,
424
+ parent_step_id=parent_step_id,
425
+ )
426
+
427
+ flattened_results = []
428
+ for iteration_results in all_results:
429
+ flattened_results.extend(iteration_results)
430
+
431
+ yield StepOutput(
432
+ step_name=self.name,
433
+ step_id=loop_step_id,
434
+ step_type=StepType.LOOP,
435
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
436
+ success=all(result.success for result in flattened_results) if flattened_results else True,
437
+ steps=flattened_results,
438
+ )
439
+
440
+ async def aexecute(
441
+ self,
442
+ step_input: StepInput,
443
+ session_id: Optional[str] = None,
444
+ user_id: Optional[str] = None,
445
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
446
+ store_executor_outputs: bool = True,
447
+ run_context: Optional[RunContext] = None,
448
+ session_state: Optional[Dict[str, Any]] = None,
449
+ workflow_session: Optional[WorkflowSession] = None,
450
+ add_workflow_history_to_steps: Optional[bool] = False,
451
+ num_history_runs: int = 3,
452
+ background_tasks: Optional[Any] = None,
453
+ ) -> StepOutput:
454
+ """Execute loop steps asynchronously with iteration control - mirrors workflow execution logic"""
455
+ # Use workflow logger for async loop orchestration
456
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
457
+
458
+ loop_step_id = str(uuid4())
459
+
460
+ # Prepare steps first
461
+ self._prepare_steps()
462
+
463
+ all_results = []
464
+ iteration = 0
465
+
466
+ while iteration < self.max_iterations:
467
+ # Execute all steps in this iteration - mirroring workflow logic
468
+ iteration_results: List[StepOutput] = []
469
+ current_step_input = step_input
470
+ loop_step_outputs = {} # Track outputs within this loop iteration
471
+
472
+ for i, step in enumerate(self.steps):
473
+ step_output = await step.aexecute( # type: ignore[union-attr]
474
+ current_step_input,
475
+ session_id=session_id,
476
+ user_id=user_id,
477
+ workflow_run_response=workflow_run_response,
478
+ store_executor_outputs=store_executor_outputs,
479
+ run_context=run_context,
480
+ session_state=session_state,
481
+ workflow_session=workflow_session,
482
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
483
+ num_history_runs=num_history_runs,
484
+ background_tasks=background_tasks,
485
+ )
486
+
487
+ # Handle both single StepOutput and List[StepOutput] (from Loop/Condition steps)
488
+ if isinstance(step_output, list):
489
+ # This is a step that returns multiple outputs (Loop, Condition etc.)
490
+ iteration_results.extend(step_output)
491
+ if step_output: # Add last output to loop tracking
492
+ step_name = getattr(step, "name", f"step_{i + 1}")
493
+ loop_step_outputs[step_name] = step_output[-1]
494
+
495
+ if any(output.stop for output in step_output):
496
+ logger.info(f"Early termination requested by step {step_name}")
497
+ break
498
+ else:
499
+ # Single StepOutput
500
+ iteration_results.append(step_output)
501
+ step_name = getattr(step, "name", f"step_{i + 1}")
502
+ loop_step_outputs[step_name] = step_output
503
+
504
+ if step_output.stop:
505
+ logger.info(f"Early termination requested by step {step_name}")
506
+ break
507
+
508
+ # Update step input for next step
509
+ current_step_input = self._update_step_input_from_outputs(
510
+ current_step_input, step_output, loop_step_outputs
511
+ )
512
+
513
+ all_results.append(iteration_results)
514
+ iteration += 1
515
+
516
+ # Check end condition
517
+ if self.end_condition and callable(self.end_condition):
518
+ try:
519
+ if inspect.iscoroutinefunction(self.end_condition):
520
+ should_break = await self.end_condition(iteration_results)
521
+ else:
522
+ should_break = self.end_condition(iteration_results)
523
+ if should_break:
524
+ break
525
+ except Exception as e:
526
+ logger.warning(f"End condition evaluation failed: {e}")
527
+
528
+ # Use workflow logger for async loop completion
529
+ log_debug(f"Async Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
530
+
531
+ # Return flattened results from all iterations
532
+ flattened_results = []
533
+ for iteration_results in all_results:
534
+ flattened_results.extend(iteration_results)
535
+
536
+ return StepOutput(
537
+ step_name=self.name,
538
+ step_id=loop_step_id,
539
+ step_type=StepType.LOOP,
540
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
541
+ success=all(result.success for result in flattened_results) if flattened_results else True,
542
+ steps=flattened_results,
543
+ )
544
+
545
+ async def aexecute_stream(
546
+ self,
547
+ step_input: StepInput,
548
+ session_id: Optional[str] = None,
549
+ user_id: Optional[str] = None,
550
+ stream_events: bool = False,
551
+ stream_intermediate_steps: bool = False,
552
+ stream_executor_events: bool = True,
553
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
554
+ step_index: Optional[Union[int, tuple]] = None,
555
+ store_executor_outputs: bool = True,
556
+ run_context: Optional[RunContext] = None,
557
+ session_state: Optional[Dict[str, Any]] = None,
558
+ parent_step_id: Optional[str] = None,
559
+ workflow_session: Optional[WorkflowSession] = None,
560
+ add_workflow_history_to_steps: Optional[bool] = False,
561
+ num_history_runs: int = 3,
562
+ background_tasks: Optional[Any] = None,
563
+ ) -> AsyncIterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
564
+ """Execute loop steps with async streaming support - mirrors workflow execution logic"""
565
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
566
+
567
+ loop_step_id = str(uuid4())
568
+
569
+ # Prepare steps first
570
+ self._prepare_steps()
571
+
572
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
573
+ if stream_intermediate_steps is not None:
574
+ warnings.warn(
575
+ "The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
576
+ DeprecationWarning,
577
+ stacklevel=2,
578
+ )
579
+ stream_events = stream_events or stream_intermediate_steps
580
+
581
+ if stream_events and workflow_run_response:
582
+ # Yield loop started event
583
+ yield LoopExecutionStartedEvent(
584
+ run_id=workflow_run_response.run_id or "",
585
+ workflow_name=workflow_run_response.workflow_name or "",
586
+ workflow_id=workflow_run_response.workflow_id or "",
587
+ session_id=workflow_run_response.session_id or "",
588
+ step_name=self.name,
589
+ step_index=step_index,
590
+ max_iterations=self.max_iterations,
591
+ step_id=loop_step_id,
592
+ parent_step_id=parent_step_id,
593
+ )
594
+
595
+ all_results = []
596
+ iteration = 0
597
+ early_termination = False
598
+
599
+ while iteration < self.max_iterations:
600
+ log_debug(f"Async loop iteration {iteration + 1}/{self.max_iterations}")
601
+
602
+ if stream_events and workflow_run_response:
603
+ # Yield iteration started event
604
+ yield LoopIterationStartedEvent(
605
+ run_id=workflow_run_response.run_id or "",
606
+ workflow_name=workflow_run_response.workflow_name or "",
607
+ workflow_id=workflow_run_response.workflow_id or "",
608
+ session_id=workflow_run_response.session_id or "",
609
+ step_name=self.name,
610
+ step_index=step_index,
611
+ iteration=iteration + 1,
612
+ max_iterations=self.max_iterations,
613
+ step_id=loop_step_id,
614
+ parent_step_id=parent_step_id,
615
+ )
616
+
617
+ # Execute all steps in this iteration - mirroring workflow logic
618
+ iteration_results = []
619
+ current_step_input = step_input
620
+ loop_step_outputs = {} # Track outputs within this loop iteration
621
+
622
+ for i, step in enumerate(self.steps):
623
+ step_outputs_for_iteration = []
624
+
625
+ # Loop children always get sequential sub-indices: parent_index.1, parent_index.2, etc.
626
+ if step_index is None or isinstance(step_index, int):
627
+ # Loop is a main step
628
+ composite_step_index = (step_index if step_index is not None else 0, i)
629
+ else:
630
+ # Loop is a nested step - extend the tuple
631
+ composite_step_index = step_index + (i,)
632
+
633
+ # Stream step execution - mirroring workflow logic
634
+ async for event in step.aexecute_stream( # type: ignore[union-attr]
635
+ current_step_input,
636
+ session_id=session_id,
637
+ user_id=user_id,
638
+ stream_events=stream_events,
639
+ stream_executor_events=stream_executor_events,
640
+ workflow_run_response=workflow_run_response,
641
+ step_index=composite_step_index,
642
+ store_executor_outputs=store_executor_outputs,
643
+ run_context=run_context,
644
+ session_state=session_state,
645
+ parent_step_id=loop_step_id,
646
+ workflow_session=workflow_session,
647
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
648
+ num_history_runs=num_history_runs,
649
+ background_tasks=background_tasks,
650
+ ):
651
+ if isinstance(event, StepOutput):
652
+ step_outputs_for_iteration.append(event)
653
+ iteration_results.append(event)
654
+ else:
655
+ # Yield other events (streaming content, step events, etc.)
656
+ yield event
657
+
658
+ # Update loop_step_outputs with this step's output
659
+ if step_outputs_for_iteration:
660
+ step_name = getattr(step, "name", f"step_{i + 1}")
661
+ if len(step_outputs_for_iteration) == 1:
662
+ loop_step_outputs[step_name] = step_outputs_for_iteration[0]
663
+
664
+ if step_outputs_for_iteration[0].stop:
665
+ logger.info(f"Early termination requested by step {step_name}")
666
+ early_termination = True
667
+ break # Break out of step loop
668
+
669
+ current_step_input = self._update_step_input_from_outputs(
670
+ current_step_input, step_outputs_for_iteration[0], loop_step_outputs
671
+ )
672
+ else:
673
+ # Use last output
674
+ loop_step_outputs[step_name] = step_outputs_for_iteration[-1]
675
+
676
+ if any(output.stop for output in step_outputs_for_iteration):
677
+ logger.info(f"Early termination requested by step {step_name}")
678
+ early_termination = True
679
+ break # Break out of step loop
680
+
681
+ current_step_input = self._update_step_input_from_outputs(
682
+ current_step_input, step_outputs_for_iteration, loop_step_outputs
683
+ )
684
+
685
+ all_results.append(iteration_results)
686
+
687
+ # Check end condition
688
+ should_continue = True
689
+ if self.end_condition and callable(self.end_condition):
690
+ try:
691
+ if inspect.iscoroutinefunction(self.end_condition):
692
+ should_break = await self.end_condition(iteration_results)
693
+ else:
694
+ should_break = self.end_condition(iteration_results)
695
+ should_continue = not should_break
696
+ log_debug(f"End condition returned: {should_break}, should_continue: {should_continue}")
697
+ except Exception as e:
698
+ logger.warning(f"End condition evaluation failed: {e}")
699
+
700
+ if early_termination:
701
+ should_continue = False
702
+ log_debug(f"Loop ending early due to step termination request at iteration {iteration}")
703
+
704
+ if stream_events and workflow_run_response:
705
+ # Yield iteration completed event
706
+ yield LoopIterationCompletedEvent(
707
+ run_id=workflow_run_response.run_id or "",
708
+ workflow_name=workflow_run_response.workflow_name or "",
709
+ workflow_id=workflow_run_response.workflow_id or "",
710
+ session_id=workflow_run_response.session_id or "",
711
+ step_name=self.name,
712
+ step_index=step_index,
713
+ iteration=iteration + 1,
714
+ max_iterations=self.max_iterations,
715
+ iteration_results=iteration_results,
716
+ should_continue=should_continue,
717
+ step_id=loop_step_id,
718
+ parent_step_id=parent_step_id,
719
+ )
720
+
721
+ iteration += 1
722
+
723
+ if not should_continue:
724
+ log_debug(f"Loop ending early due to end_condition at iteration {iteration}")
725
+ break
726
+
727
+ log_debug(f"Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
728
+
729
+ if stream_events and workflow_run_response:
730
+ # Yield loop completed event
731
+ yield LoopExecutionCompletedEvent(
732
+ run_id=workflow_run_response.run_id or "",
733
+ workflow_name=workflow_run_response.workflow_name or "",
734
+ workflow_id=workflow_run_response.workflow_id or "",
735
+ session_id=workflow_run_response.session_id or "",
736
+ step_name=self.name,
737
+ step_index=step_index,
738
+ total_iterations=iteration,
739
+ max_iterations=self.max_iterations,
740
+ all_results=all_results,
741
+ step_id=loop_step_id,
742
+ parent_step_id=parent_step_id,
743
+ )
744
+
745
+ flattened_results = []
746
+ for iteration_results in all_results:
747
+ flattened_results.extend(iteration_results)
748
+
749
+ yield StepOutput(
750
+ step_name=self.name,
751
+ step_id=loop_step_id,
752
+ step_type=StepType.LOOP,
753
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
754
+ success=all(result.success for result in flattened_results) if flattened_results else True,
755
+ steps=flattened_results,
756
+ )