agno 2.0.1__py3-none-any.whl → 2.3.0__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 (314) hide show
  1. agno/agent/agent.py +6015 -2823
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/culture/__init__.py +3 -0
  5. agno/culture/manager.py +956 -0
  6. agno/db/async_postgres/__init__.py +3 -0
  7. agno/db/base.py +385 -6
  8. agno/db/dynamo/dynamo.py +388 -81
  9. agno/db/dynamo/schemas.py +47 -10
  10. agno/db/dynamo/utils.py +63 -4
  11. agno/db/firestore/firestore.py +435 -64
  12. agno/db/firestore/schemas.py +11 -0
  13. agno/db/firestore/utils.py +102 -4
  14. agno/db/gcs_json/gcs_json_db.py +384 -42
  15. agno/db/gcs_json/utils.py +60 -26
  16. agno/db/in_memory/in_memory_db.py +351 -66
  17. agno/db/in_memory/utils.py +60 -2
  18. agno/db/json/json_db.py +339 -48
  19. agno/db/json/utils.py +60 -26
  20. agno/db/migrations/manager.py +199 -0
  21. agno/db/migrations/v1_to_v2.py +510 -37
  22. agno/db/migrations/versions/__init__.py +0 -0
  23. agno/db/migrations/versions/v2_3_0.py +938 -0
  24. agno/db/mongo/__init__.py +15 -1
  25. agno/db/mongo/async_mongo.py +2036 -0
  26. agno/db/mongo/mongo.py +653 -76
  27. agno/db/mongo/schemas.py +13 -0
  28. agno/db/mongo/utils.py +80 -8
  29. agno/db/mysql/mysql.py +687 -25
  30. agno/db/mysql/schemas.py +61 -37
  31. agno/db/mysql/utils.py +60 -2
  32. agno/db/postgres/__init__.py +2 -1
  33. agno/db/postgres/async_postgres.py +2001 -0
  34. agno/db/postgres/postgres.py +676 -57
  35. agno/db/postgres/schemas.py +43 -18
  36. agno/db/postgres/utils.py +164 -2
  37. agno/db/redis/redis.py +344 -38
  38. agno/db/redis/schemas.py +18 -0
  39. agno/db/redis/utils.py +60 -2
  40. agno/db/schemas/__init__.py +2 -1
  41. agno/db/schemas/culture.py +120 -0
  42. agno/db/schemas/memory.py +13 -0
  43. agno/db/singlestore/schemas.py +26 -1
  44. agno/db/singlestore/singlestore.py +687 -53
  45. agno/db/singlestore/utils.py +60 -2
  46. agno/db/sqlite/__init__.py +2 -1
  47. agno/db/sqlite/async_sqlite.py +2371 -0
  48. agno/db/sqlite/schemas.py +24 -0
  49. agno/db/sqlite/sqlite.py +774 -85
  50. agno/db/sqlite/utils.py +168 -5
  51. agno/db/surrealdb/__init__.py +3 -0
  52. agno/db/surrealdb/metrics.py +292 -0
  53. agno/db/surrealdb/models.py +309 -0
  54. agno/db/surrealdb/queries.py +71 -0
  55. agno/db/surrealdb/surrealdb.py +1361 -0
  56. agno/db/surrealdb/utils.py +147 -0
  57. agno/db/utils.py +50 -22
  58. agno/eval/accuracy.py +50 -43
  59. agno/eval/performance.py +6 -3
  60. agno/eval/reliability.py +6 -3
  61. agno/eval/utils.py +33 -16
  62. agno/exceptions.py +68 -1
  63. agno/filters.py +354 -0
  64. agno/guardrails/__init__.py +6 -0
  65. agno/guardrails/base.py +19 -0
  66. agno/guardrails/openai.py +144 -0
  67. agno/guardrails/pii.py +94 -0
  68. agno/guardrails/prompt_injection.py +52 -0
  69. agno/integrations/discord/client.py +1 -0
  70. agno/knowledge/chunking/agentic.py +13 -10
  71. agno/knowledge/chunking/fixed.py +1 -1
  72. agno/knowledge/chunking/semantic.py +40 -8
  73. agno/knowledge/chunking/strategy.py +59 -15
  74. agno/knowledge/embedder/aws_bedrock.py +9 -4
  75. agno/knowledge/embedder/azure_openai.py +54 -0
  76. agno/knowledge/embedder/base.py +2 -0
  77. agno/knowledge/embedder/cohere.py +184 -5
  78. agno/knowledge/embedder/fastembed.py +1 -1
  79. agno/knowledge/embedder/google.py +79 -1
  80. agno/knowledge/embedder/huggingface.py +9 -4
  81. agno/knowledge/embedder/jina.py +63 -0
  82. agno/knowledge/embedder/mistral.py +78 -11
  83. agno/knowledge/embedder/nebius.py +1 -1
  84. agno/knowledge/embedder/ollama.py +13 -0
  85. agno/knowledge/embedder/openai.py +37 -65
  86. agno/knowledge/embedder/sentence_transformer.py +8 -4
  87. agno/knowledge/embedder/vllm.py +262 -0
  88. agno/knowledge/embedder/voyageai.py +69 -16
  89. agno/knowledge/knowledge.py +594 -186
  90. agno/knowledge/reader/base.py +9 -2
  91. agno/knowledge/reader/csv_reader.py +8 -10
  92. agno/knowledge/reader/docx_reader.py +5 -6
  93. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  94. agno/knowledge/reader/json_reader.py +6 -5
  95. agno/knowledge/reader/markdown_reader.py +13 -13
  96. agno/knowledge/reader/pdf_reader.py +43 -68
  97. agno/knowledge/reader/pptx_reader.py +101 -0
  98. agno/knowledge/reader/reader_factory.py +51 -6
  99. agno/knowledge/reader/s3_reader.py +3 -15
  100. agno/knowledge/reader/tavily_reader.py +194 -0
  101. agno/knowledge/reader/text_reader.py +13 -13
  102. agno/knowledge/reader/web_search_reader.py +2 -43
  103. agno/knowledge/reader/website_reader.py +43 -25
  104. agno/knowledge/reranker/__init__.py +2 -8
  105. agno/knowledge/types.py +9 -0
  106. agno/knowledge/utils.py +20 -0
  107. agno/media.py +72 -0
  108. agno/memory/manager.py +336 -82
  109. agno/models/aimlapi/aimlapi.py +2 -2
  110. agno/models/anthropic/claude.py +183 -37
  111. agno/models/aws/bedrock.py +52 -112
  112. agno/models/aws/claude.py +33 -1
  113. agno/models/azure/ai_foundry.py +33 -15
  114. agno/models/azure/openai_chat.py +25 -8
  115. agno/models/base.py +999 -519
  116. agno/models/cerebras/cerebras.py +19 -13
  117. agno/models/cerebras/cerebras_openai.py +8 -5
  118. agno/models/cohere/chat.py +27 -1
  119. agno/models/cometapi/__init__.py +5 -0
  120. agno/models/cometapi/cometapi.py +57 -0
  121. agno/models/dashscope/dashscope.py +1 -0
  122. agno/models/deepinfra/deepinfra.py +2 -2
  123. agno/models/deepseek/deepseek.py +2 -2
  124. agno/models/fireworks/fireworks.py +2 -2
  125. agno/models/google/gemini.py +103 -31
  126. agno/models/groq/groq.py +28 -11
  127. agno/models/huggingface/huggingface.py +2 -1
  128. agno/models/internlm/internlm.py +2 -2
  129. agno/models/langdb/langdb.py +4 -4
  130. agno/models/litellm/chat.py +18 -1
  131. agno/models/litellm/litellm_openai.py +2 -2
  132. agno/models/llama_cpp/__init__.py +5 -0
  133. agno/models/llama_cpp/llama_cpp.py +22 -0
  134. agno/models/message.py +139 -0
  135. agno/models/meta/llama.py +27 -10
  136. agno/models/meta/llama_openai.py +5 -17
  137. agno/models/nebius/nebius.py +6 -6
  138. agno/models/nexus/__init__.py +3 -0
  139. agno/models/nexus/nexus.py +22 -0
  140. agno/models/nvidia/nvidia.py +2 -2
  141. agno/models/ollama/chat.py +59 -5
  142. agno/models/openai/chat.py +69 -29
  143. agno/models/openai/responses.py +103 -106
  144. agno/models/openrouter/openrouter.py +41 -3
  145. agno/models/perplexity/perplexity.py +4 -5
  146. agno/models/portkey/portkey.py +3 -3
  147. agno/models/requesty/__init__.py +5 -0
  148. agno/models/requesty/requesty.py +52 -0
  149. agno/models/response.py +77 -1
  150. agno/models/sambanova/sambanova.py +2 -2
  151. agno/models/siliconflow/__init__.py +5 -0
  152. agno/models/siliconflow/siliconflow.py +25 -0
  153. agno/models/together/together.py +2 -2
  154. agno/models/utils.py +254 -8
  155. agno/models/vercel/v0.py +2 -2
  156. agno/models/vertexai/__init__.py +0 -0
  157. agno/models/vertexai/claude.py +96 -0
  158. agno/models/vllm/vllm.py +1 -0
  159. agno/models/xai/xai.py +3 -2
  160. agno/os/app.py +543 -178
  161. agno/os/auth.py +24 -14
  162. agno/os/config.py +1 -0
  163. agno/os/interfaces/__init__.py +1 -0
  164. agno/os/interfaces/a2a/__init__.py +3 -0
  165. agno/os/interfaces/a2a/a2a.py +42 -0
  166. agno/os/interfaces/a2a/router.py +250 -0
  167. agno/os/interfaces/a2a/utils.py +924 -0
  168. agno/os/interfaces/agui/agui.py +23 -7
  169. agno/os/interfaces/agui/router.py +27 -3
  170. agno/os/interfaces/agui/utils.py +242 -142
  171. agno/os/interfaces/base.py +6 -2
  172. agno/os/interfaces/slack/router.py +81 -23
  173. agno/os/interfaces/slack/slack.py +29 -14
  174. agno/os/interfaces/whatsapp/router.py +11 -4
  175. agno/os/interfaces/whatsapp/whatsapp.py +14 -7
  176. agno/os/mcp.py +111 -54
  177. agno/os/middleware/__init__.py +7 -0
  178. agno/os/middleware/jwt.py +233 -0
  179. agno/os/router.py +556 -139
  180. agno/os/routers/evals/evals.py +71 -34
  181. agno/os/routers/evals/schemas.py +31 -31
  182. agno/os/routers/evals/utils.py +6 -5
  183. agno/os/routers/health.py +31 -0
  184. agno/os/routers/home.py +52 -0
  185. agno/os/routers/knowledge/knowledge.py +185 -38
  186. agno/os/routers/knowledge/schemas.py +82 -22
  187. agno/os/routers/memory/memory.py +158 -53
  188. agno/os/routers/memory/schemas.py +20 -16
  189. agno/os/routers/metrics/metrics.py +20 -8
  190. agno/os/routers/metrics/schemas.py +16 -16
  191. agno/os/routers/session/session.py +499 -38
  192. agno/os/schema.py +308 -198
  193. agno/os/utils.py +401 -41
  194. agno/reasoning/anthropic.py +80 -0
  195. agno/reasoning/azure_ai_foundry.py +2 -2
  196. agno/reasoning/deepseek.py +2 -2
  197. agno/reasoning/default.py +3 -1
  198. agno/reasoning/gemini.py +73 -0
  199. agno/reasoning/groq.py +2 -2
  200. agno/reasoning/ollama.py +2 -2
  201. agno/reasoning/openai.py +7 -2
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +248 -94
  205. agno/run/base.py +44 -5
  206. agno/run/team.py +238 -97
  207. agno/run/workflow.py +144 -33
  208. agno/session/agent.py +105 -89
  209. agno/session/summary.py +65 -25
  210. agno/session/team.py +176 -96
  211. agno/session/workflow.py +406 -40
  212. agno/team/team.py +3854 -1610
  213. agno/tools/dalle.py +2 -4
  214. agno/tools/decorator.py +4 -2
  215. agno/tools/duckduckgo.py +15 -11
  216. agno/tools/e2b.py +14 -7
  217. agno/tools/eleven_labs.py +23 -25
  218. agno/tools/exa.py +21 -16
  219. agno/tools/file.py +153 -23
  220. agno/tools/file_generation.py +350 -0
  221. agno/tools/firecrawl.py +4 -4
  222. agno/tools/function.py +250 -30
  223. agno/tools/gmail.py +238 -14
  224. agno/tools/google_drive.py +270 -0
  225. agno/tools/googlecalendar.py +36 -8
  226. agno/tools/googlesheets.py +20 -5
  227. agno/tools/jira.py +20 -0
  228. agno/tools/knowledge.py +3 -3
  229. agno/tools/mcp/__init__.py +10 -0
  230. agno/tools/mcp/mcp.py +331 -0
  231. agno/tools/mcp/multi_mcp.py +347 -0
  232. agno/tools/mcp/params.py +24 -0
  233. agno/tools/mcp_toolbox.py +284 -0
  234. agno/tools/mem0.py +11 -17
  235. agno/tools/memori.py +1 -53
  236. agno/tools/memory.py +419 -0
  237. agno/tools/models/nebius.py +5 -5
  238. agno/tools/models_labs.py +20 -10
  239. agno/tools/notion.py +204 -0
  240. agno/tools/parallel.py +314 -0
  241. agno/tools/scrapegraph.py +58 -31
  242. agno/tools/searxng.py +2 -2
  243. agno/tools/serper.py +2 -2
  244. agno/tools/slack.py +18 -3
  245. agno/tools/spider.py +2 -2
  246. agno/tools/tavily.py +146 -0
  247. agno/tools/whatsapp.py +1 -1
  248. agno/tools/workflow.py +278 -0
  249. agno/tools/yfinance.py +12 -11
  250. agno/utils/agent.py +820 -0
  251. agno/utils/audio.py +27 -0
  252. agno/utils/common.py +90 -1
  253. agno/utils/events.py +217 -2
  254. agno/utils/gemini.py +180 -22
  255. agno/utils/hooks.py +57 -0
  256. agno/utils/http.py +111 -0
  257. agno/utils/knowledge.py +12 -5
  258. agno/utils/log.py +1 -0
  259. agno/utils/mcp.py +92 -2
  260. agno/utils/media.py +188 -10
  261. agno/utils/merge_dict.py +22 -1
  262. agno/utils/message.py +60 -0
  263. agno/utils/models/claude.py +40 -11
  264. agno/utils/print_response/agent.py +105 -21
  265. agno/utils/print_response/team.py +103 -38
  266. agno/utils/print_response/workflow.py +251 -34
  267. agno/utils/reasoning.py +22 -1
  268. agno/utils/serialize.py +32 -0
  269. agno/utils/streamlit.py +16 -10
  270. agno/utils/string.py +41 -0
  271. agno/utils/team.py +98 -9
  272. agno/utils/tools.py +1 -1
  273. agno/vectordb/base.py +23 -4
  274. agno/vectordb/cassandra/cassandra.py +65 -9
  275. agno/vectordb/chroma/chromadb.py +182 -38
  276. agno/vectordb/clickhouse/clickhousedb.py +64 -11
  277. agno/vectordb/couchbase/couchbase.py +105 -10
  278. agno/vectordb/lancedb/lance_db.py +124 -133
  279. agno/vectordb/langchaindb/langchaindb.py +25 -7
  280. agno/vectordb/lightrag/lightrag.py +17 -3
  281. agno/vectordb/llamaindex/__init__.py +3 -0
  282. agno/vectordb/llamaindex/llamaindexdb.py +46 -7
  283. agno/vectordb/milvus/milvus.py +126 -9
  284. agno/vectordb/mongodb/__init__.py +7 -1
  285. agno/vectordb/mongodb/mongodb.py +112 -7
  286. agno/vectordb/pgvector/pgvector.py +142 -21
  287. agno/vectordb/pineconedb/pineconedb.py +80 -8
  288. agno/vectordb/qdrant/qdrant.py +125 -39
  289. agno/vectordb/redis/__init__.py +9 -0
  290. agno/vectordb/redis/redisdb.py +694 -0
  291. agno/vectordb/singlestore/singlestore.py +111 -25
  292. agno/vectordb/surrealdb/surrealdb.py +31 -5
  293. agno/vectordb/upstashdb/upstashdb.py +76 -8
  294. agno/vectordb/weaviate/weaviate.py +86 -15
  295. agno/workflow/__init__.py +2 -0
  296. agno/workflow/agent.py +299 -0
  297. agno/workflow/condition.py +112 -18
  298. agno/workflow/loop.py +69 -10
  299. agno/workflow/parallel.py +266 -118
  300. agno/workflow/router.py +110 -17
  301. agno/workflow/step.py +638 -129
  302. agno/workflow/steps.py +65 -6
  303. agno/workflow/types.py +61 -23
  304. agno/workflow/workflow.py +2085 -272
  305. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/METADATA +182 -58
  306. agno-2.3.0.dist-info/RECORD +577 -0
  307. agno/knowledge/reader/url_reader.py +0 -128
  308. agno/tools/googlesearch.py +0 -98
  309. agno/tools/mcp.py +0 -610
  310. agno/utils/models/aws_claude.py +0 -170
  311. agno-2.0.1.dist-info/RECORD +0 -515
  312. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
  313. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/licenses/LICENSE +0 -0
  314. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/workflow/steps.py CHANGED
@@ -1,8 +1,10 @@
1
+ import warnings
1
2
  from dataclasses import dataclass
2
3
  from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
3
4
  from uuid import uuid4
4
5
 
5
6
  from agno.run.agent import RunOutputEvent
7
+ from agno.run.base import RunContext
6
8
  from agno.run.team import TeamRunOutputEvent
7
9
  from agno.run.workflow import (
8
10
  StepsExecutionCompletedEvent,
@@ -10,6 +12,7 @@ from agno.run.workflow import (
10
12
  WorkflowRunOutput,
11
13
  WorkflowRunOutputEvent,
12
14
  )
15
+ from agno.session.workflow import WorkflowSession
13
16
  from agno.utils.log import log_debug, logger
14
17
  from agno.workflow.step import Step, StepInput, StepOutput, StepType
15
18
 
@@ -117,8 +120,12 @@ class Steps:
117
120
  session_id: Optional[str] = None,
118
121
  user_id: Optional[str] = None,
119
122
  workflow_run_response: Optional[WorkflowRunOutput] = None,
123
+ run_context: Optional[RunContext] = None,
120
124
  session_state: Optional[Dict[str, Any]] = None,
121
125
  store_executor_outputs: bool = True,
126
+ workflow_session: Optional[WorkflowSession] = None,
127
+ add_workflow_history_to_steps: Optional[bool] = False,
128
+ num_history_runs: int = 3,
122
129
  ) -> StepOutput:
123
130
  """Execute all steps in sequence and return the final result"""
124
131
  log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
@@ -147,7 +154,11 @@ class Steps:
147
154
  user_id=user_id,
148
155
  workflow_run_response=workflow_run_response,
149
156
  store_executor_outputs=store_executor_outputs,
157
+ run_context=run_context,
150
158
  session_state=session_state,
159
+ workflow_session=workflow_session,
160
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
161
+ num_history_runs=num_history_runs,
151
162
  )
152
163
 
153
164
  # Handle both single StepOutput and List[StepOutput] (from Loop/Condition/Router steps)
@@ -197,13 +208,19 @@ class Steps:
197
208
  self,
198
209
  step_input: StepInput,
199
210
  workflow_run_response: WorkflowRunOutput,
211
+ run_context: Optional[RunContext] = None,
200
212
  session_state: Optional[Dict[str, Any]] = None,
201
213
  session_id: Optional[str] = None,
202
214
  user_id: Optional[str] = None,
215
+ stream_events: bool = False,
203
216
  stream_intermediate_steps: bool = False,
217
+ stream_executor_events: bool = True,
204
218
  step_index: Optional[Union[int, tuple]] = None,
205
219
  store_executor_outputs: bool = True,
206
220
  parent_step_id: Optional[str] = None,
221
+ workflow_session: Optional[WorkflowSession] = None,
222
+ add_workflow_history_to_steps: Optional[bool] = False,
223
+ num_history_runs: int = 3,
207
224
  ) -> Iterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
208
225
  """Execute all steps in sequence with streaming support"""
209
226
  log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
@@ -212,7 +229,16 @@ class Steps:
212
229
 
213
230
  self._prepare_steps()
214
231
 
215
- if stream_intermediate_steps:
232
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
233
+ if stream_intermediate_steps is not None:
234
+ warnings.warn(
235
+ "The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
236
+ DeprecationWarning,
237
+ stacklevel=2,
238
+ )
239
+ stream_events = stream_events or stream_intermediate_steps
240
+
241
+ if stream_events:
216
242
  # Yield steps execution started event
217
243
  yield StepsExecutionStartedEvent(
218
244
  run_id=workflow_run_response.run_id or "",
@@ -254,12 +280,17 @@ class Steps:
254
280
  current_step_input,
255
281
  session_id=session_id,
256
282
  user_id=user_id,
283
+ run_context=run_context,
257
284
  session_state=session_state,
258
- stream_intermediate_steps=stream_intermediate_steps,
285
+ stream_events=stream_events,
286
+ stream_executor_events=stream_executor_events,
259
287
  workflow_run_response=workflow_run_response,
260
288
  step_index=child_step_index,
261
289
  store_executor_outputs=store_executor_outputs,
262
290
  parent_step_id=steps_id,
291
+ workflow_session=workflow_session,
292
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
293
+ num_history_runs=num_history_runs,
263
294
  ):
264
295
  if isinstance(event, StepOutput):
265
296
  step_outputs_for_step.append(event)
@@ -294,7 +325,7 @@ class Steps:
294
325
 
295
326
  log_debug(f"Steps End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
296
327
 
297
- if stream_intermediate_steps:
328
+ if stream_events:
298
329
  # Yield steps execution completed event
299
330
  yield StepsExecutionCompletedEvent(
300
331
  run_id=workflow_run_response.run_id or "",
@@ -335,8 +366,12 @@ class Steps:
335
366
  session_id: Optional[str] = None,
336
367
  user_id: Optional[str] = None,
337
368
  workflow_run_response: Optional[WorkflowRunOutput] = None,
369
+ run_context: Optional[RunContext] = None,
338
370
  session_state: Optional[Dict[str, Any]] = None,
339
371
  store_executor_outputs: bool = True,
372
+ workflow_session: Optional[WorkflowSession] = None,
373
+ add_workflow_history_to_steps: Optional[bool] = False,
374
+ num_history_runs: int = 3,
340
375
  ) -> StepOutput:
341
376
  """Execute all steps in sequence asynchronously and return the final result"""
342
377
  log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
@@ -365,7 +400,11 @@ class Steps:
365
400
  user_id=user_id,
366
401
  workflow_run_response=workflow_run_response,
367
402
  store_executor_outputs=store_executor_outputs,
403
+ run_context=run_context,
368
404
  session_state=session_state,
405
+ workflow_session=workflow_session,
406
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
407
+ num_history_runs=num_history_runs,
369
408
  )
370
409
 
371
410
  # Handle both single StepOutput and List[StepOutput] (from Loop/Condition/Router steps)
@@ -414,13 +453,19 @@ class Steps:
414
453
  self,
415
454
  step_input: StepInput,
416
455
  workflow_run_response: WorkflowRunOutput,
456
+ run_context: Optional[RunContext] = None,
417
457
  session_state: Optional[Dict[str, Any]] = None,
418
458
  session_id: Optional[str] = None,
419
459
  user_id: Optional[str] = None,
460
+ stream_events: bool = False,
420
461
  stream_intermediate_steps: bool = False,
462
+ stream_executor_events: bool = True,
421
463
  step_index: Optional[Union[int, tuple]] = None,
422
464
  store_executor_outputs: bool = True,
423
465
  parent_step_id: Optional[str] = None,
466
+ workflow_session: Optional[WorkflowSession] = None,
467
+ add_workflow_history_to_steps: Optional[bool] = False,
468
+ num_history_runs: int = 3,
424
469
  ) -> AsyncIterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
425
470
  """Execute all steps in sequence with async streaming support"""
426
471
  log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
@@ -429,7 +474,16 @@ class Steps:
429
474
 
430
475
  self._prepare_steps()
431
476
 
432
- if stream_intermediate_steps:
477
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
478
+ if stream_intermediate_steps is not None:
479
+ warnings.warn(
480
+ "The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
481
+ DeprecationWarning,
482
+ stacklevel=2,
483
+ )
484
+ stream_events = stream_events or stream_intermediate_steps
485
+
486
+ if stream_events:
433
487
  # Yield steps execution started event
434
488
  yield StepsExecutionStartedEvent(
435
489
  run_id=workflow_run_response.run_id or "",
@@ -471,12 +525,17 @@ class Steps:
471
525
  current_step_input,
472
526
  session_id=session_id,
473
527
  user_id=user_id,
528
+ run_context=run_context,
474
529
  session_state=session_state,
475
- stream_intermediate_steps=stream_intermediate_steps,
530
+ stream_events=stream_events,
531
+ stream_executor_events=stream_executor_events,
476
532
  workflow_run_response=workflow_run_response,
477
533
  step_index=child_step_index,
478
534
  store_executor_outputs=store_executor_outputs,
479
535
  parent_step_id=steps_id,
536
+ workflow_session=workflow_session,
537
+ add_workflow_history_to_steps=add_workflow_history_to_steps,
538
+ num_history_runs=num_history_runs,
480
539
  ):
481
540
  if isinstance(event, StepOutput):
482
541
  step_outputs_for_step.append(event)
@@ -511,7 +570,7 @@ class Steps:
511
570
 
512
571
  log_debug(f"Steps End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
513
572
  # Yield steps execution completed event
514
- if stream_intermediate_steps:
573
+ if stream_events:
515
574
  yield StepsExecutionCompletedEvent(
516
575
  run_id=workflow_run_response.run_id or "",
517
576
  workflow_name=workflow_run_response.workflow_name or "",
agno/workflow/types.py CHANGED
@@ -1,13 +1,23 @@
1
+ import json
1
2
  from dataclasses import dataclass
2
3
  from enum import Enum
3
- from typing import Any, Dict, List, Optional, Union
4
+ from typing import Any, Dict, List, Optional, Tuple, Union
4
5
 
5
6
  from fastapi import WebSocket
6
7
  from pydantic import BaseModel
7
8
 
8
9
  from agno.media import Audio, File, Image, Video
9
10
  from agno.models.metrics import Metrics
11
+ from agno.session.workflow import WorkflowSession
10
12
  from agno.utils.log import log_warning
13
+ from agno.utils.media import (
14
+ reconstruct_audio_list,
15
+ reconstruct_files,
16
+ reconstruct_images,
17
+ reconstruct_videos,
18
+ )
19
+ from agno.utils.serialize import json_serializer
20
+ from agno.utils.timer import Timer
11
21
 
12
22
 
13
23
  @dataclass
@@ -57,6 +67,7 @@ class WorkflowExecutionInput:
57
67
  "images": [img.to_dict() for img in self.images] if self.images else None,
58
68
  "videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
59
69
  "audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
70
+ "files": [file.to_dict() for file in self.files] if self.files else None,
60
71
  }
61
72
 
62
73
 
@@ -77,6 +88,8 @@ class StepInput:
77
88
  audio: Optional[List[Audio]] = None
78
89
  files: Optional[List[File]] = None
79
90
 
91
+ workflow_session: Optional["WorkflowSession"] = None
92
+
80
93
  def get_input_as_string(self) -> Optional[str]:
81
94
  """Convert input to string representation"""
82
95
  if self.input is None:
@@ -168,6 +181,28 @@ class StepInput:
168
181
  # Use the helper method to get the deepest content
169
182
  return self._get_deepest_step_content(last_output) # type: ignore[return-value]
170
183
 
184
+ def get_workflow_history(self, num_runs: Optional[int] = None) -> List[Tuple[str, str]]:
185
+ """Get workflow conversation history as structured data for custom function steps
186
+
187
+ Args:
188
+ num_runs: Number of recent runs to include. If None, returns all available history.
189
+ """
190
+ if not self.workflow_session:
191
+ return []
192
+
193
+ return self.workflow_session.get_workflow_history(num_runs=num_runs)
194
+
195
+ def get_workflow_history_context(self, num_runs: Optional[int] = None) -> Optional[str]:
196
+ """Get formatted workflow conversation history context for custom function steps
197
+
198
+ Args:
199
+ num_runs: Number of recent runs to include. If None, returns all available history.
200
+ """
201
+ if not self.workflow_session:
202
+ return None
203
+
204
+ return self.workflow_session.get_workflow_history_context(num_runs=num_runs)
205
+
171
206
  def to_dict(self) -> Dict[str, Any]:
172
207
  """Convert to dictionary"""
173
208
  # Handle the unified message field
@@ -280,21 +315,10 @@ class StepOutput:
280
315
  def from_dict(cls, data: Dict[str, Any]) -> "StepOutput":
281
316
  """Create StepOutput from dictionary"""
282
317
  # Reconstruct media artifacts
283
- images = data.get("images")
284
- if images:
285
- images = [Image.model_validate(img) for img in images]
286
-
287
- videos = data.get("videos")
288
- if videos:
289
- videos = [Video.model_validate(vid) for vid in videos]
290
-
291
- audio = data.get("audio")
292
- if audio:
293
- audio = [Audio.model_validate(aud) for aud in audio]
294
-
295
- files = data.get("files")
296
- if files:
297
- files = [File.model_validate(file) for file in files]
318
+ images = reconstruct_images(data.get("images"))
319
+ videos = reconstruct_videos(data.get("videos"))
320
+ audio = reconstruct_audio_list(data.get("audio"))
321
+ files = reconstruct_files(data.get("files"))
298
322
 
299
323
  metrics_data = data.get("metrics")
300
324
  metrics = None
@@ -382,12 +406,18 @@ class WorkflowMetrics:
382
406
  """Complete metrics for a workflow execution"""
383
407
 
384
408
  steps: Dict[str, StepMetrics]
409
+ # Timer utility for tracking execution time
410
+ timer: Optional[Timer] = None
411
+ # Total workflow execution time
412
+ duration: Optional[float] = None
385
413
 
386
414
  def to_dict(self) -> Dict[str, Any]:
387
415
  """Convert to dictionary"""
388
- return {
416
+ result: Dict[str, Any] = {
389
417
  "steps": {name: step.to_dict() for name, step in self.steps.items()},
418
+ "duration": self.duration,
390
419
  }
420
+ return result
391
421
 
392
422
  @classmethod
393
423
  def from_dict(cls, data: Dict[str, Any]) -> "WorkflowMetrics":
@@ -396,8 +426,20 @@ class WorkflowMetrics:
396
426
 
397
427
  return cls(
398
428
  steps=steps,
429
+ duration=data.get("duration"),
399
430
  )
400
431
 
432
+ def start_timer(self):
433
+ if self.timer is None:
434
+ self.timer = Timer()
435
+ self.timer.start()
436
+
437
+ def stop_timer(self, set_duration: bool = True):
438
+ if self.timer is not None:
439
+ self.timer.stop()
440
+ if set_duration:
441
+ self.duration = self.timer.elapsed
442
+
401
443
 
402
444
  @dataclass
403
445
  class WebSocketHandler:
@@ -442,9 +484,7 @@ class WebSocketHandler:
442
484
  else:
443
485
  data = {"type": "message", "content": str(event)}
444
486
 
445
- import json
446
-
447
- await self.websocket.send_text(self.format_sse_event(json.dumps(data)))
487
+ await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
448
488
 
449
489
  except Exception as e:
450
490
  log_warning(f"Failed to handle WebSocket event: {e}")
@@ -465,9 +505,7 @@ class WebSocketHandler:
465
505
  return
466
506
 
467
507
  try:
468
- import json
469
-
470
- await self.websocket.send_text(self.format_sse_event(json.dumps(data)))
508
+ await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
471
509
  except Exception as e:
472
510
  log_warning(f"Failed to send WebSocket dict: {e}")
473
511