agno 2.2.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1335 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1160 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
agno/workflow/loop.py ADDED
@@ -0,0 +1,735 @@
1
+ import inspect
2
+ from dataclasses import dataclass
3
+ from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
4
+ from uuid import uuid4
5
+
6
+ from agno.run.agent import RunOutputEvent
7
+ from agno.run.base import RunContext
8
+ from agno.run.team import TeamRunOutputEvent
9
+ from agno.run.workflow import (
10
+ LoopExecutionCompletedEvent,
11
+ LoopExecutionStartedEvent,
12
+ LoopIterationCompletedEvent,
13
+ LoopIterationStartedEvent,
14
+ WorkflowRunOutput,
15
+ WorkflowRunOutputEvent,
16
+ )
17
+ from agno.session.workflow import WorkflowSession
18
+ from agno.utils.log import log_debug, logger
19
+ from agno.workflow.step import Step
20
+ from agno.workflow.types import StepInput, StepOutput, StepType
21
+
22
+ WorkflowSteps = List[
23
+ Union[
24
+ Callable[
25
+ [StepInput], Union[StepOutput, Awaitable[StepOutput], Iterator[StepOutput], AsyncIterator[StepOutput]]
26
+ ],
27
+ Step,
28
+ "Steps", # type: ignore # noqa: F821
29
+ "Loop", # type: ignore # noqa: F821
30
+ "Parallel", # type: ignore # noqa: F821
31
+ "Condition", # type: ignore # noqa: F821
32
+ "Router", # type: ignore # noqa: F821
33
+ ]
34
+ ]
35
+
36
+
37
+ @dataclass
38
+ class Loop:
39
+ """A loop of steps that execute in order"""
40
+
41
+ steps: WorkflowSteps
42
+
43
+ name: Optional[str] = None
44
+ description: Optional[str] = None
45
+
46
+ max_iterations: int = 3 # Default to 3
47
+ end_condition: Optional[Callable[[List[StepOutput]], bool]] = None
48
+
49
+ def __init__(
50
+ self,
51
+ steps: WorkflowSteps,
52
+ name: Optional[str] = None,
53
+ description: Optional[str] = None,
54
+ max_iterations: int = 3,
55
+ end_condition: Optional[Callable[[List[StepOutput]], bool]] = None,
56
+ ):
57
+ self.steps = steps
58
+ self.name = name
59
+ self.description = description
60
+ self.max_iterations = max_iterations
61
+ self.end_condition = end_condition
62
+
63
+ def _prepare_steps(self):
64
+ """Prepare the steps for execution - mirrors workflow logic"""
65
+ from agno.agent.agent import Agent
66
+ from agno.team.team import Team
67
+ from agno.workflow.condition import Condition
68
+ from agno.workflow.parallel import Parallel
69
+ from agno.workflow.router import Router
70
+ from agno.workflow.step import Step
71
+ from agno.workflow.steps import Steps
72
+
73
+ prepared_steps: WorkflowSteps = []
74
+ for step in self.steps:
75
+ if callable(step) and hasattr(step, "__name__"):
76
+ prepared_steps.append(Step(name=step.__name__, description="User-defined callable step", executor=step))
77
+ elif isinstance(step, Agent):
78
+ prepared_steps.append(Step(name=step.name, description=step.description, agent=step))
79
+ elif isinstance(step, Team):
80
+ prepared_steps.append(Step(name=step.name, description=step.description, team=step))
81
+ elif isinstance(step, (Step, Steps, Loop, Parallel, Condition, Router)):
82
+ prepared_steps.append(step)
83
+ else:
84
+ raise ValueError(f"Invalid step type: {type(step).__name__}")
85
+
86
+ self.steps = prepared_steps
87
+
88
+ def _update_step_input_from_outputs(
89
+ self,
90
+ step_input: StepInput,
91
+ step_outputs: Union[StepOutput, List[StepOutput]],
92
+ loop_step_outputs: Optional[Dict[str, StepOutput]] = None,
93
+ ) -> StepInput:
94
+ """Helper to update step input from step outputs (handles both single and multiple outputs)"""
95
+ current_images = step_input.images or []
96
+ current_videos = step_input.videos or []
97
+ current_audio = step_input.audio or []
98
+
99
+ if isinstance(step_outputs, list):
100
+ all_images = sum([out.images or [] for out in step_outputs], [])
101
+ all_videos = sum([out.videos or [] for out in step_outputs], [])
102
+ all_audio = sum([out.audio or [] for out in step_outputs], [])
103
+
104
+ # Use the last output's content for chaining
105
+ previous_step_content = step_outputs[-1].content if step_outputs else None
106
+ else:
107
+ # Single output
108
+ all_images = step_outputs.images or []
109
+ all_videos = step_outputs.videos or []
110
+ all_audio = step_outputs.audio or []
111
+ previous_step_content = step_outputs.content
112
+
113
+ updated_previous_step_outputs = {}
114
+ if step_input.previous_step_outputs:
115
+ updated_previous_step_outputs.update(step_input.previous_step_outputs)
116
+ if loop_step_outputs:
117
+ updated_previous_step_outputs.update(loop_step_outputs)
118
+
119
+ return StepInput(
120
+ input=step_input.input,
121
+ previous_step_content=previous_step_content,
122
+ previous_step_outputs=updated_previous_step_outputs,
123
+ additional_data=step_input.additional_data,
124
+ images=current_images + all_images,
125
+ videos=current_videos + all_videos,
126
+ audio=current_audio + all_audio,
127
+ )
128
+
129
+ def execute(
130
+ self,
131
+ step_input: StepInput,
132
+ session_id: Optional[str] = None,
133
+ user_id: Optional[str] = None,
134
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
135
+ store_executor_outputs: bool = True,
136
+ run_context: Optional[RunContext] = None,
137
+ session_state: Optional[Dict[str, Any]] = None,
138
+ workflow_session: Optional[WorkflowSession] = None,
139
+ add_workflow_history_to_steps: Optional[bool] = False,
140
+ num_history_runs: int = 3,
141
+ ) -> StepOutput:
142
+ """Execute loop steps with iteration control - mirrors workflow execution logic"""
143
+ # Use workflow logger for loop orchestration
144
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
145
+
146
+ # Prepare steps first
147
+ self._prepare_steps()
148
+
149
+ all_results = []
150
+ iteration = 0
151
+
152
+ while iteration < self.max_iterations:
153
+ # Execute all steps in this iteration - mirroring workflow logic
154
+ iteration_results: List[StepOutput] = []
155
+ current_step_input = step_input
156
+ loop_step_outputs = {} # Track outputs within this loop iteration
157
+
158
+ for i, step in enumerate(self.steps):
159
+ step_output = step.execute( # type: ignore[union-attr]
160
+ current_step_input,
161
+ session_id=session_id,
162
+ user_id=user_id,
163
+ workflow_run_response=workflow_run_response,
164
+ store_executor_outputs=store_executor_outputs,
165
+ run_context=run_context,
166
+ session_state=session_state,
167
+ workflow_session=workflow_session,
168
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
169
+ num_history_runs=num_history_runs,
170
+ )
171
+
172
+ # Handle both single StepOutput and List[StepOutput] (from Loop/Condition steps)
173
+ if isinstance(step_output, list):
174
+ # This is a step that returns multiple outputs (Loop, Condition etc.)
175
+ iteration_results.extend(step_output)
176
+ if step_output: # Add last output to loop tracking
177
+ step_name = getattr(step, "name", f"step_{i + 1}")
178
+ loop_step_outputs[step_name] = step_output[-1]
179
+
180
+ if any(output.stop for output in step_output):
181
+ logger.info(f"Early termination requested by step {step_name}")
182
+ break
183
+ else:
184
+ # Single StepOutput
185
+ iteration_results.append(step_output)
186
+ step_name = getattr(step, "name", f"step_{i + 1}")
187
+ loop_step_outputs[step_name] = step_output
188
+
189
+ if step_output.stop:
190
+ logger.info(f"Early termination requested by step {step_name}")
191
+ break
192
+
193
+ # Update step input for next step
194
+ current_step_input = self._update_step_input_from_outputs(
195
+ current_step_input, step_output, loop_step_outputs
196
+ )
197
+
198
+ all_results.append(iteration_results)
199
+ iteration += 1
200
+
201
+ # Check end condition
202
+ if self.end_condition and callable(self.end_condition):
203
+ try:
204
+ should_break = self.end_condition(iteration_results)
205
+ if should_break:
206
+ break
207
+ except Exception as e:
208
+ logger.warning(f"End condition evaluation failed: {e}")
209
+ # Continue with loop if end condition fails
210
+
211
+ log_debug(f"Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
212
+
213
+ # Return flattened results from all iterations
214
+ flattened_results = []
215
+ for iteration_results in all_results:
216
+ flattened_results.extend(iteration_results)
217
+
218
+ return StepOutput(
219
+ step_name=self.name,
220
+ step_id=str(uuid4()),
221
+ step_type=StepType.LOOP,
222
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
223
+ success=all(result.success for result in flattened_results) if flattened_results else True,
224
+ steps=flattened_results,
225
+ )
226
+
227
+ def execute_stream(
228
+ self,
229
+ step_input: StepInput,
230
+ session_id: Optional[str] = None,
231
+ user_id: Optional[str] = None,
232
+ stream_events: bool = False,
233
+ stream_intermediate_steps: bool = False,
234
+ stream_executor_events: bool = True,
235
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
236
+ step_index: Optional[Union[int, tuple]] = None,
237
+ store_executor_outputs: bool = True,
238
+ run_context: Optional[RunContext] = None,
239
+ session_state: Optional[Dict[str, Any]] = None,
240
+ parent_step_id: Optional[str] = None,
241
+ workflow_session: Optional[WorkflowSession] = None,
242
+ add_workflow_history_to_steps: Optional[bool] = False,
243
+ num_history_runs: int = 3,
244
+ ) -> Iterator[Union[WorkflowRunOutputEvent, StepOutput]]:
245
+ """Execute loop steps with streaming support - mirrors workflow execution logic"""
246
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
247
+
248
+ # Prepare steps first
249
+ self._prepare_steps()
250
+
251
+ loop_step_id = str(uuid4())
252
+
253
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
254
+ stream_events = stream_events or stream_intermediate_steps
255
+
256
+ if stream_events and workflow_run_response:
257
+ # Yield loop started event
258
+ yield LoopExecutionStartedEvent(
259
+ run_id=workflow_run_response.run_id or "",
260
+ workflow_name=workflow_run_response.workflow_name or "",
261
+ workflow_id=workflow_run_response.workflow_id or "",
262
+ session_id=workflow_run_response.session_id or "",
263
+ step_name=self.name,
264
+ step_index=step_index,
265
+ max_iterations=self.max_iterations,
266
+ step_id=loop_step_id,
267
+ parent_step_id=parent_step_id,
268
+ )
269
+
270
+ all_results = []
271
+ iteration = 0
272
+ early_termination = False
273
+
274
+ while iteration < self.max_iterations:
275
+ log_debug(f"Loop iteration {iteration + 1}/{self.max_iterations}")
276
+
277
+ if stream_events and workflow_run_response:
278
+ # Yield iteration started event
279
+ yield LoopIterationStartedEvent(
280
+ run_id=workflow_run_response.run_id or "",
281
+ workflow_name=workflow_run_response.workflow_name or "",
282
+ workflow_id=workflow_run_response.workflow_id or "",
283
+ session_id=workflow_run_response.session_id or "",
284
+ step_name=self.name,
285
+ step_index=step_index,
286
+ iteration=iteration + 1,
287
+ max_iterations=self.max_iterations,
288
+ step_id=loop_step_id,
289
+ parent_step_id=parent_step_id,
290
+ )
291
+
292
+ # Execute all steps in this iteration - mirroring workflow logic
293
+ iteration_results = []
294
+ current_step_input = step_input
295
+ loop_step_outputs = {}
296
+
297
+ for i, step in enumerate(self.steps):
298
+ step_outputs_for_iteration = []
299
+
300
+ # Loop children always get sequential sub-indices: parent_index.1, parent_index.2, etc.
301
+ if step_index is None or isinstance(step_index, int):
302
+ # Loop is a main step
303
+ composite_step_index = (step_index if step_index is not None else 0, i)
304
+ else:
305
+ # Loop is a nested step - extend the tuple
306
+ composite_step_index = step_index + (i,)
307
+
308
+ # Stream step execution
309
+ for event in step.execute_stream( # type: ignore[union-attr]
310
+ current_step_input,
311
+ session_id=session_id,
312
+ user_id=user_id,
313
+ stream_events=stream_events,
314
+ stream_executor_events=stream_executor_events,
315
+ workflow_run_response=workflow_run_response,
316
+ step_index=composite_step_index,
317
+ store_executor_outputs=store_executor_outputs,
318
+ run_context=run_context,
319
+ session_state=session_state,
320
+ parent_step_id=loop_step_id,
321
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
322
+ workflow_session=workflow_session,
323
+ num_history_runs=num_history_runs,
324
+ ):
325
+ if isinstance(event, StepOutput):
326
+ step_outputs_for_iteration.append(event)
327
+ iteration_results.append(event)
328
+ else:
329
+ # Yield other events (streaming content, step events, etc.)
330
+ yield event
331
+
332
+ # Update loop_step_outputs with this step's output
333
+ if step_outputs_for_iteration:
334
+ step_name = getattr(step, "name", f"step_{i + 1}")
335
+ if len(step_outputs_for_iteration) == 1:
336
+ loop_step_outputs[step_name] = step_outputs_for_iteration[0]
337
+
338
+ if step_outputs_for_iteration[0].stop:
339
+ logger.info(f"Early termination requested by step {step_name}")
340
+ early_termination = True
341
+ break # Break out of step loop
342
+
343
+ current_step_input = self._update_step_input_from_outputs(
344
+ current_step_input, step_outputs_for_iteration[0], loop_step_outputs
345
+ )
346
+ else:
347
+ # Use last output
348
+ loop_step_outputs[step_name] = step_outputs_for_iteration[-1]
349
+
350
+ if any(output.stop for output in step_outputs_for_iteration):
351
+ logger.info(f"Early termination requested by step {step_name}")
352
+ early_termination = True
353
+ break # Break out of step loop
354
+
355
+ current_step_input = self._update_step_input_from_outputs(
356
+ current_step_input, step_outputs_for_iteration, loop_step_outputs
357
+ )
358
+
359
+ all_results.append(iteration_results)
360
+
361
+ # Check end condition
362
+ should_continue = True
363
+ if self.end_condition and callable(self.end_condition):
364
+ try:
365
+ should_break = self.end_condition(iteration_results)
366
+ should_continue = not should_break
367
+ log_debug(f"End condition returned: {should_break}, should_continue: {should_continue}")
368
+ except Exception as e:
369
+ logger.warning(f"End condition evaluation failed: {e}")
370
+
371
+ if early_termination:
372
+ should_continue = False
373
+ log_debug(f"Loop ending early due to step termination request at iteration {iteration}")
374
+
375
+ if stream_events and workflow_run_response:
376
+ # Yield iteration completed event
377
+ yield LoopIterationCompletedEvent(
378
+ run_id=workflow_run_response.run_id or "",
379
+ workflow_name=workflow_run_response.workflow_name or "",
380
+ workflow_id=workflow_run_response.workflow_id or "",
381
+ session_id=workflow_run_response.session_id or "",
382
+ step_name=self.name,
383
+ step_index=step_index,
384
+ iteration=iteration + 1,
385
+ max_iterations=self.max_iterations,
386
+ iteration_results=iteration_results,
387
+ should_continue=should_continue,
388
+ step_id=loop_step_id,
389
+ parent_step_id=parent_step_id,
390
+ )
391
+
392
+ iteration += 1
393
+
394
+ if not should_continue:
395
+ log_debug(f"Loop ending early due to end_condition at iteration {iteration}")
396
+ break
397
+
398
+ log_debug(f"Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
399
+
400
+ if stream_events and workflow_run_response:
401
+ # Yield loop completed event
402
+ yield LoopExecutionCompletedEvent(
403
+ run_id=workflow_run_response.run_id or "",
404
+ workflow_name=workflow_run_response.workflow_name or "",
405
+ workflow_id=workflow_run_response.workflow_id or "",
406
+ session_id=workflow_run_response.session_id or "",
407
+ step_name=self.name,
408
+ step_index=step_index,
409
+ total_iterations=iteration,
410
+ max_iterations=self.max_iterations,
411
+ all_results=all_results,
412
+ step_id=loop_step_id,
413
+ parent_step_id=parent_step_id,
414
+ )
415
+
416
+ flattened_results = []
417
+ for iteration_results in all_results:
418
+ flattened_results.extend(iteration_results)
419
+
420
+ yield StepOutput(
421
+ step_name=self.name,
422
+ step_id=loop_step_id,
423
+ step_type=StepType.LOOP,
424
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
425
+ success=all(result.success for result in flattened_results) if flattened_results else True,
426
+ steps=flattened_results,
427
+ )
428
+
429
+ async def aexecute(
430
+ self,
431
+ step_input: StepInput,
432
+ session_id: Optional[str] = None,
433
+ user_id: Optional[str] = None,
434
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
435
+ store_executor_outputs: bool = True,
436
+ run_context: Optional[RunContext] = None,
437
+ session_state: Optional[Dict[str, Any]] = None,
438
+ workflow_session: Optional[WorkflowSession] = None,
439
+ add_workflow_history_to_steps: Optional[bool] = False,
440
+ num_history_runs: int = 3,
441
+ ) -> StepOutput:
442
+ """Execute loop steps asynchronously with iteration control - mirrors workflow execution logic"""
443
+ # Use workflow logger for async loop orchestration
444
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
445
+
446
+ loop_step_id = str(uuid4())
447
+
448
+ # Prepare steps first
449
+ self._prepare_steps()
450
+
451
+ all_results = []
452
+ iteration = 0
453
+
454
+ while iteration < self.max_iterations:
455
+ # Execute all steps in this iteration - mirroring workflow logic
456
+ iteration_results: List[StepOutput] = []
457
+ current_step_input = step_input
458
+ loop_step_outputs = {} # Track outputs within this loop iteration
459
+
460
+ for i, step in enumerate(self.steps):
461
+ step_output = await step.aexecute( # type: ignore[union-attr]
462
+ current_step_input,
463
+ session_id=session_id,
464
+ user_id=user_id,
465
+ workflow_run_response=workflow_run_response,
466
+ store_executor_outputs=store_executor_outputs,
467
+ run_context=run_context,
468
+ session_state=session_state,
469
+ workflow_session=workflow_session,
470
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
471
+ num_history_runs=num_history_runs,
472
+ )
473
+
474
+ # Handle both single StepOutput and List[StepOutput] (from Loop/Condition steps)
475
+ if isinstance(step_output, list):
476
+ # This is a step that returns multiple outputs (Loop, Condition etc.)
477
+ iteration_results.extend(step_output)
478
+ if step_output: # Add last output to loop tracking
479
+ step_name = getattr(step, "name", f"step_{i + 1}")
480
+ loop_step_outputs[step_name] = step_output[-1]
481
+
482
+ if any(output.stop for output in step_output):
483
+ logger.info(f"Early termination requested by step {step_name}")
484
+ break
485
+ else:
486
+ # Single StepOutput
487
+ iteration_results.append(step_output)
488
+ step_name = getattr(step, "name", f"step_{i + 1}")
489
+ loop_step_outputs[step_name] = step_output
490
+
491
+ if step_output.stop:
492
+ logger.info(f"Early termination requested by step {step_name}")
493
+ break
494
+
495
+ # Update step input for next step
496
+ current_step_input = self._update_step_input_from_outputs(
497
+ current_step_input, step_output, loop_step_outputs
498
+ )
499
+
500
+ all_results.append(iteration_results)
501
+ iteration += 1
502
+
503
+ # Check end condition
504
+ if self.end_condition and callable(self.end_condition):
505
+ try:
506
+ if inspect.iscoroutinefunction(self.end_condition):
507
+ should_break = await self.end_condition(iteration_results)
508
+ else:
509
+ should_break = self.end_condition(iteration_results)
510
+ if should_break:
511
+ break
512
+ except Exception as e:
513
+ logger.warning(f"End condition evaluation failed: {e}")
514
+
515
+ # Use workflow logger for async loop completion
516
+ log_debug(f"Async Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
517
+
518
+ # Return flattened results from all iterations
519
+ flattened_results = []
520
+ for iteration_results in all_results:
521
+ flattened_results.extend(iteration_results)
522
+
523
+ return StepOutput(
524
+ step_name=self.name,
525
+ step_id=loop_step_id,
526
+ step_type=StepType.LOOP,
527
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
528
+ success=all(result.success for result in flattened_results) if flattened_results else True,
529
+ steps=flattened_results,
530
+ )
531
+
532
+ async def aexecute_stream(
533
+ self,
534
+ step_input: StepInput,
535
+ session_id: Optional[str] = None,
536
+ user_id: Optional[str] = None,
537
+ stream_events: bool = False,
538
+ stream_intermediate_steps: bool = False,
539
+ stream_executor_events: bool = True,
540
+ workflow_run_response: Optional[WorkflowRunOutput] = None,
541
+ step_index: Optional[Union[int, tuple]] = None,
542
+ store_executor_outputs: bool = True,
543
+ run_context: Optional[RunContext] = None,
544
+ session_state: Optional[Dict[str, Any]] = None,
545
+ parent_step_id: Optional[str] = None,
546
+ workflow_session: Optional[WorkflowSession] = None,
547
+ add_workflow_history_to_steps: Optional[bool] = False,
548
+ num_history_runs: int = 3,
549
+ ) -> AsyncIterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
550
+ """Execute loop steps with async streaming support - mirrors workflow execution logic"""
551
+ log_debug(f"Loop Start: {self.name}", center=True, symbol="=")
552
+
553
+ loop_step_id = str(uuid4())
554
+
555
+ # Prepare steps first
556
+ self._prepare_steps()
557
+
558
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
559
+ stream_events = stream_events or stream_intermediate_steps
560
+
561
+ if stream_events and workflow_run_response:
562
+ # Yield loop started event
563
+ yield LoopExecutionStartedEvent(
564
+ run_id=workflow_run_response.run_id or "",
565
+ workflow_name=workflow_run_response.workflow_name or "",
566
+ workflow_id=workflow_run_response.workflow_id or "",
567
+ session_id=workflow_run_response.session_id or "",
568
+ step_name=self.name,
569
+ step_index=step_index,
570
+ max_iterations=self.max_iterations,
571
+ step_id=loop_step_id,
572
+ parent_step_id=parent_step_id,
573
+ )
574
+
575
+ all_results = []
576
+ iteration = 0
577
+ early_termination = False
578
+
579
+ while iteration < self.max_iterations:
580
+ log_debug(f"Async loop iteration {iteration + 1}/{self.max_iterations}")
581
+
582
+ if stream_events and workflow_run_response:
583
+ # Yield iteration started event
584
+ yield LoopIterationStartedEvent(
585
+ run_id=workflow_run_response.run_id or "",
586
+ workflow_name=workflow_run_response.workflow_name or "",
587
+ workflow_id=workflow_run_response.workflow_id or "",
588
+ session_id=workflow_run_response.session_id or "",
589
+ step_name=self.name,
590
+ step_index=step_index,
591
+ iteration=iteration + 1,
592
+ max_iterations=self.max_iterations,
593
+ step_id=loop_step_id,
594
+ parent_step_id=parent_step_id,
595
+ )
596
+
597
+ # Execute all steps in this iteration - mirroring workflow logic
598
+ iteration_results = []
599
+ current_step_input = step_input
600
+ loop_step_outputs = {} # Track outputs within this loop iteration
601
+
602
+ for i, step in enumerate(self.steps):
603
+ step_outputs_for_iteration = []
604
+
605
+ # Loop children always get sequential sub-indices: parent_index.1, parent_index.2, etc.
606
+ if step_index is None or isinstance(step_index, int):
607
+ # Loop is a main step
608
+ composite_step_index = (step_index if step_index is not None else 0, i)
609
+ else:
610
+ # Loop is a nested step - extend the tuple
611
+ composite_step_index = step_index + (i,)
612
+
613
+ # Stream step execution - mirroring workflow logic
614
+ async for event in step.aexecute_stream( # type: ignore[union-attr]
615
+ current_step_input,
616
+ session_id=session_id,
617
+ user_id=user_id,
618
+ stream_events=stream_events,
619
+ stream_executor_events=stream_executor_events,
620
+ workflow_run_response=workflow_run_response,
621
+ step_index=composite_step_index,
622
+ store_executor_outputs=store_executor_outputs,
623
+ run_context=run_context,
624
+ session_state=session_state,
625
+ parent_step_id=loop_step_id,
626
+ workflow_session=workflow_session,
627
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
628
+ num_history_runs=num_history_runs,
629
+ ):
630
+ if isinstance(event, StepOutput):
631
+ step_outputs_for_iteration.append(event)
632
+ iteration_results.append(event)
633
+ else:
634
+ # Yield other events (streaming content, step events, etc.)
635
+ yield event
636
+
637
+ # Update loop_step_outputs with this step's output
638
+ if step_outputs_for_iteration:
639
+ step_name = getattr(step, "name", f"step_{i + 1}")
640
+ if len(step_outputs_for_iteration) == 1:
641
+ loop_step_outputs[step_name] = step_outputs_for_iteration[0]
642
+
643
+ if step_outputs_for_iteration[0].stop:
644
+ logger.info(f"Early termination requested by step {step_name}")
645
+ early_termination = True
646
+ break # Break out of step loop
647
+
648
+ current_step_input = self._update_step_input_from_outputs(
649
+ current_step_input, step_outputs_for_iteration[0], loop_step_outputs
650
+ )
651
+ else:
652
+ # Use last output
653
+ loop_step_outputs[step_name] = step_outputs_for_iteration[-1]
654
+
655
+ if any(output.stop for output in step_outputs_for_iteration):
656
+ logger.info(f"Early termination requested by step {step_name}")
657
+ early_termination = True
658
+ break # Break out of step loop
659
+
660
+ current_step_input = self._update_step_input_from_outputs(
661
+ current_step_input, step_outputs_for_iteration, loop_step_outputs
662
+ )
663
+
664
+ all_results.append(iteration_results)
665
+
666
+ # Check end condition
667
+ should_continue = True
668
+ if self.end_condition and callable(self.end_condition):
669
+ try:
670
+ if inspect.iscoroutinefunction(self.end_condition):
671
+ should_break = await self.end_condition(iteration_results)
672
+ else:
673
+ should_break = self.end_condition(iteration_results)
674
+ should_continue = not should_break
675
+ log_debug(f"End condition returned: {should_break}, should_continue: {should_continue}")
676
+ except Exception as e:
677
+ logger.warning(f"End condition evaluation failed: {e}")
678
+
679
+ if early_termination:
680
+ should_continue = False
681
+ log_debug(f"Loop ending early due to step termination request at iteration {iteration}")
682
+
683
+ if stream_events and workflow_run_response:
684
+ # Yield iteration completed event
685
+ yield LoopIterationCompletedEvent(
686
+ run_id=workflow_run_response.run_id or "",
687
+ workflow_name=workflow_run_response.workflow_name or "",
688
+ workflow_id=workflow_run_response.workflow_id or "",
689
+ session_id=workflow_run_response.session_id or "",
690
+ step_name=self.name,
691
+ step_index=step_index,
692
+ iteration=iteration + 1,
693
+ max_iterations=self.max_iterations,
694
+ iteration_results=iteration_results,
695
+ should_continue=should_continue,
696
+ step_id=loop_step_id,
697
+ parent_step_id=parent_step_id,
698
+ )
699
+
700
+ iteration += 1
701
+
702
+ if not should_continue:
703
+ log_debug(f"Loop ending early due to end_condition at iteration {iteration}")
704
+ break
705
+
706
+ log_debug(f"Loop End: {self.name} ({iteration} iterations)", center=True, symbol="=")
707
+
708
+ if stream_events and workflow_run_response:
709
+ # Yield loop completed event
710
+ yield LoopExecutionCompletedEvent(
711
+ run_id=workflow_run_response.run_id or "",
712
+ workflow_name=workflow_run_response.workflow_name or "",
713
+ workflow_id=workflow_run_response.workflow_id or "",
714
+ session_id=workflow_run_response.session_id or "",
715
+ step_name=self.name,
716
+ step_index=step_index,
717
+ total_iterations=iteration,
718
+ max_iterations=self.max_iterations,
719
+ all_results=all_results,
720
+ step_id=loop_step_id,
721
+ parent_step_id=parent_step_id,
722
+ )
723
+
724
+ flattened_results = []
725
+ for iteration_results in all_results:
726
+ flattened_results.extend(iteration_results)
727
+
728
+ yield StepOutput(
729
+ step_name=self.name,
730
+ step_id=loop_step_id,
731
+ step_type=StepType.LOOP,
732
+ content=f"Loop {self.name} completed {iteration} iterations with {len(flattened_results)} total steps",
733
+ success=all(result.success for result in flattened_results) if flattened_results else True,
734
+ steps=flattened_results,
735
+ )