agno 2.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.
- agno/agent/agent.py +5540 -2273
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +689 -6
- agno/db/dynamo/dynamo.py +933 -37
- agno/db/dynamo/schemas.py +174 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +831 -9
- agno/db/firestore/schemas.py +51 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +660 -12
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +287 -14
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +590 -14
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +43 -13
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +879 -11
- agno/db/mongo/schemas.py +42 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +946 -68
- agno/db/mysql/schemas.py +72 -10
- agno/db/mysql/utils.py +198 -7
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +942 -57
- agno/db/postgres/schemas.py +81 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +671 -7
- agno/db/redis/schemas.py +50 -0
- agno/db/redis/utils.py +65 -7
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +17 -2
- agno/db/singlestore/schemas.py +63 -0
- agno/db/singlestore/singlestore.py +949 -83
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +62 -0
- agno/db/sqlite/sqlite.py +965 -46
- agno/db/sqlite/utils.py +169 -8
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +2 -0
- agno/eval/__init__.py +10 -0
- agno/eval/accuracy.py +75 -55
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +16 -7
- agno/eval/reliability.py +28 -16
- agno/eval/utils.py +35 -17
- agno/exceptions.py +27 -2
- agno/filters.py +354 -0
- agno/guardrails/prompt_injection.py +1 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +1 -1
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/semantic.py +9 -4
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +8 -0
- agno/knowledge/embedder/openai.py +8 -8
- agno/knowledge/embedder/sentence_transformer.py +6 -2
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/knowledge.py +1618 -318
- agno/knowledge/reader/base.py +6 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +16 -20
- agno/knowledge/reader/json_reader.py +5 -4
- agno/knowledge/reader/markdown_reader.py +8 -8
- agno/knowledge/reader/pdf_reader.py +17 -19
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +32 -3
- agno/knowledge/reader/s3_reader.py +3 -3
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +22 -10
- agno/knowledge/reader/web_search_reader.py +1 -48
- agno/knowledge/reader/website_reader.py +10 -10
- agno/knowledge/reader/wikipedia_reader.py +33 -1
- agno/knowledge/types.py +1 -0
- agno/knowledge/utils.py +72 -7
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +544 -83
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +515 -40
- agno/models/aws/bedrock.py +102 -21
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +41 -19
- agno/models/azure/openai_chat.py +39 -8
- agno/models/base.py +1249 -525
- agno/models/cerebras/cerebras.py +91 -21
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +40 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +877 -80
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +51 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +44 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +28 -5
- agno/models/meta/llama.py +47 -14
- agno/models/meta/llama_openai.py +22 -17
- agno/models/mistral/mistral.py +8 -4
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/chat.py +24 -8
- agno/models/openai/chat.py +104 -29
- agno/models/openai/responses.py +101 -81
- agno/models/openrouter/openrouter.py +60 -3
- agno/models/perplexity/perplexity.py +17 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +24 -4
- agno/models/response.py +73 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +549 -152
- agno/os/auth.py +190 -3
- agno/os/config.py +23 -0
- agno/os/interfaces/a2a/router.py +8 -11
- agno/os/interfaces/a2a/utils.py +1 -1
- agno/os/interfaces/agui/router.py +18 -3
- agno/os/interfaces/agui/utils.py +152 -39
- agno/os/interfaces/slack/router.py +55 -37
- agno/os/interfaces/slack/slack.py +9 -1
- agno/os/interfaces/whatsapp/router.py +0 -1
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/mcp.py +110 -52
- agno/os/middleware/__init__.py +2 -0
- agno/os/middleware/jwt.py +676 -112
- agno/os/router.py +40 -1478
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/evals.py +96 -39
- agno/os/routers/evals/schemas.py +65 -33
- agno/os/routers/evals/utils.py +80 -10
- agno/os/routers/health.py +10 -4
- agno/os/routers/knowledge/knowledge.py +196 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +279 -52
- agno/os/routers/memory/schemas.py +46 -17
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +462 -34
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +256 -693
- agno/os/scopes.py +469 -0
- agno/os/utils.py +514 -36
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/openai.py +5 -0
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +155 -32
- agno/run/base.py +55 -3
- agno/run/requirement.py +181 -0
- agno/run/team.py +125 -38
- agno/run/workflow.py +72 -18
- agno/session/agent.py +102 -89
- agno/session/summary.py +56 -15
- agno/session/team.py +164 -90
- agno/session/workflow.py +405 -40
- agno/table.py +10 -0
- agno/team/team.py +3974 -1903
- agno/tools/dalle.py +2 -4
- agno/tools/eleven_labs.py +23 -25
- agno/tools/exa.py +21 -16
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +16 -10
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +193 -38
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +271 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +3 -3
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/notion.py +204 -0
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +76 -36
- agno/tools/redshift.py +406 -0
- agno/tools/scrapegraph.py +1 -1
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +18 -3
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +146 -0
- agno/tools/toolkit.py +25 -0
- agno/tools/workflow.py +8 -1
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +151 -3
- agno/utils/gemini.py +15 -5
- agno/utils/hooks.py +118 -4
- agno/utils/http.py +113 -2
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +92 -2
- agno/utils/media.py +187 -1
- agno/utils/merge_dict.py +3 -3
- agno/utils/message.py +60 -0
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +49 -14
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/print_response/agent.py +109 -16
- agno/utils/print_response/team.py +223 -30
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/streamlit.py +1 -1
- agno/utils/team.py +98 -9
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +39 -7
- agno/vectordb/cassandra/cassandra.py +21 -5
- agno/vectordb/chroma/chromadb.py +43 -12
- agno/vectordb/clickhouse/clickhousedb.py +21 -5
- agno/vectordb/couchbase/couchbase.py +29 -5
- agno/vectordb/lancedb/lance_db.py +92 -181
- agno/vectordb/langchaindb/langchaindb.py +24 -4
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/llamaindexdb.py +25 -5
- agno/vectordb/milvus/milvus.py +50 -37
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +36 -30
- agno/vectordb/pgvector/pgvector.py +201 -77
- agno/vectordb/pineconedb/pineconedb.py +41 -23
- agno/vectordb/qdrant/qdrant.py +67 -54
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/singlestore.py +50 -29
- agno/vectordb/surrealdb/surrealdb.py +31 -41
- agno/vectordb/upstashdb/upstashdb.py +34 -6
- agno/vectordb/weaviate/weaviate.py +53 -14
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +120 -18
- agno/workflow/loop.py +77 -10
- agno/workflow/parallel.py +231 -143
- agno/workflow/router.py +118 -17
- agno/workflow/step.py +609 -170
- agno/workflow/steps.py +73 -6
- agno/workflow/types.py +96 -21
- agno/workflow/workflow.py +2039 -262
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/METADATA +201 -66
- agno-2.3.13.dist-info/RECORD +613 -0
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -679
- agno/tools/memori.py +0 -339
- agno-2.1.2.dist-info/RECORD +0 -543
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +0 -0
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/licenses/LICENSE +0 -0
- {agno-2.1.2.dist-info → agno-2.3.13.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,13 @@ 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,
|
|
129
|
+
background_tasks: Optional[Any] = None,
|
|
122
130
|
) -> StepOutput:
|
|
123
131
|
"""Execute all steps in sequence and return the final result"""
|
|
124
132
|
log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
|
|
@@ -147,7 +155,12 @@ class Steps:
|
|
|
147
155
|
user_id=user_id,
|
|
148
156
|
workflow_run_response=workflow_run_response,
|
|
149
157
|
store_executor_outputs=store_executor_outputs,
|
|
158
|
+
run_context=run_context,
|
|
150
159
|
session_state=session_state,
|
|
160
|
+
workflow_session=workflow_session,
|
|
161
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
162
|
+
num_history_runs=num_history_runs,
|
|
163
|
+
background_tasks=background_tasks,
|
|
151
164
|
)
|
|
152
165
|
|
|
153
166
|
# Handle both single StepOutput and List[StepOutput] (from Loop/Condition/Router steps)
|
|
@@ -197,13 +210,20 @@ class Steps:
|
|
|
197
210
|
self,
|
|
198
211
|
step_input: StepInput,
|
|
199
212
|
workflow_run_response: WorkflowRunOutput,
|
|
213
|
+
run_context: Optional[RunContext] = None,
|
|
200
214
|
session_state: Optional[Dict[str, Any]] = None,
|
|
201
215
|
session_id: Optional[str] = None,
|
|
202
216
|
user_id: Optional[str] = None,
|
|
217
|
+
stream_events: bool = False,
|
|
203
218
|
stream_intermediate_steps: bool = False,
|
|
219
|
+
stream_executor_events: bool = True,
|
|
204
220
|
step_index: Optional[Union[int, tuple]] = None,
|
|
205
221
|
store_executor_outputs: bool = True,
|
|
206
222
|
parent_step_id: Optional[str] = None,
|
|
223
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
224
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
225
|
+
num_history_runs: int = 3,
|
|
226
|
+
background_tasks: Optional[Any] = None,
|
|
207
227
|
) -> Iterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
|
|
208
228
|
"""Execute all steps in sequence with streaming support"""
|
|
209
229
|
log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
|
|
@@ -212,7 +232,16 @@ class Steps:
|
|
|
212
232
|
|
|
213
233
|
self._prepare_steps()
|
|
214
234
|
|
|
215
|
-
|
|
235
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
236
|
+
if stream_intermediate_steps is not None:
|
|
237
|
+
warnings.warn(
|
|
238
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
239
|
+
DeprecationWarning,
|
|
240
|
+
stacklevel=2,
|
|
241
|
+
)
|
|
242
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
243
|
+
|
|
244
|
+
if stream_events:
|
|
216
245
|
# Yield steps execution started event
|
|
217
246
|
yield StepsExecutionStartedEvent(
|
|
218
247
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -254,12 +283,18 @@ class Steps:
|
|
|
254
283
|
current_step_input,
|
|
255
284
|
session_id=session_id,
|
|
256
285
|
user_id=user_id,
|
|
286
|
+
run_context=run_context,
|
|
257
287
|
session_state=session_state,
|
|
258
|
-
|
|
288
|
+
stream_events=stream_events,
|
|
289
|
+
stream_executor_events=stream_executor_events,
|
|
259
290
|
workflow_run_response=workflow_run_response,
|
|
260
291
|
step_index=child_step_index,
|
|
261
292
|
store_executor_outputs=store_executor_outputs,
|
|
262
293
|
parent_step_id=steps_id,
|
|
294
|
+
workflow_session=workflow_session,
|
|
295
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
296
|
+
num_history_runs=num_history_runs,
|
|
297
|
+
background_tasks=background_tasks,
|
|
263
298
|
):
|
|
264
299
|
if isinstance(event, StepOutput):
|
|
265
300
|
step_outputs_for_step.append(event)
|
|
@@ -294,7 +329,7 @@ class Steps:
|
|
|
294
329
|
|
|
295
330
|
log_debug(f"Steps End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
296
331
|
|
|
297
|
-
if
|
|
332
|
+
if stream_events:
|
|
298
333
|
# Yield steps execution completed event
|
|
299
334
|
yield StepsExecutionCompletedEvent(
|
|
300
335
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -335,8 +370,13 @@ class Steps:
|
|
|
335
370
|
session_id: Optional[str] = None,
|
|
336
371
|
user_id: Optional[str] = None,
|
|
337
372
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
373
|
+
run_context: Optional[RunContext] = None,
|
|
338
374
|
session_state: Optional[Dict[str, Any]] = None,
|
|
339
375
|
store_executor_outputs: bool = True,
|
|
376
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
377
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
378
|
+
num_history_runs: int = 3,
|
|
379
|
+
background_tasks: Optional[Any] = None,
|
|
340
380
|
) -> StepOutput:
|
|
341
381
|
"""Execute all steps in sequence asynchronously and return the final result"""
|
|
342
382
|
log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
|
|
@@ -365,7 +405,12 @@ class Steps:
|
|
|
365
405
|
user_id=user_id,
|
|
366
406
|
workflow_run_response=workflow_run_response,
|
|
367
407
|
store_executor_outputs=store_executor_outputs,
|
|
408
|
+
run_context=run_context,
|
|
368
409
|
session_state=session_state,
|
|
410
|
+
workflow_session=workflow_session,
|
|
411
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
412
|
+
num_history_runs=num_history_runs,
|
|
413
|
+
background_tasks=background_tasks,
|
|
369
414
|
)
|
|
370
415
|
|
|
371
416
|
# Handle both single StepOutput and List[StepOutput] (from Loop/Condition/Router steps)
|
|
@@ -414,13 +459,20 @@ class Steps:
|
|
|
414
459
|
self,
|
|
415
460
|
step_input: StepInput,
|
|
416
461
|
workflow_run_response: WorkflowRunOutput,
|
|
462
|
+
run_context: Optional[RunContext] = None,
|
|
417
463
|
session_state: Optional[Dict[str, Any]] = None,
|
|
418
464
|
session_id: Optional[str] = None,
|
|
419
465
|
user_id: Optional[str] = None,
|
|
466
|
+
stream_events: bool = False,
|
|
420
467
|
stream_intermediate_steps: bool = False,
|
|
468
|
+
stream_executor_events: bool = True,
|
|
421
469
|
step_index: Optional[Union[int, tuple]] = None,
|
|
422
470
|
store_executor_outputs: bool = True,
|
|
423
471
|
parent_step_id: Optional[str] = None,
|
|
472
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
473
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
474
|
+
num_history_runs: int = 3,
|
|
475
|
+
background_tasks: Optional[Any] = None,
|
|
424
476
|
) -> AsyncIterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
|
|
425
477
|
"""Execute all steps in sequence with async streaming support"""
|
|
426
478
|
log_debug(f"Steps Start: {self.name} ({len(self.steps)} steps)", center=True, symbol="-")
|
|
@@ -429,7 +481,16 @@ class Steps:
|
|
|
429
481
|
|
|
430
482
|
self._prepare_steps()
|
|
431
483
|
|
|
432
|
-
|
|
484
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
485
|
+
if stream_intermediate_steps is not None:
|
|
486
|
+
warnings.warn(
|
|
487
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
488
|
+
DeprecationWarning,
|
|
489
|
+
stacklevel=2,
|
|
490
|
+
)
|
|
491
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
492
|
+
|
|
493
|
+
if stream_events:
|
|
433
494
|
# Yield steps execution started event
|
|
434
495
|
yield StepsExecutionStartedEvent(
|
|
435
496
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -471,12 +532,18 @@ class Steps:
|
|
|
471
532
|
current_step_input,
|
|
472
533
|
session_id=session_id,
|
|
473
534
|
user_id=user_id,
|
|
535
|
+
run_context=run_context,
|
|
474
536
|
session_state=session_state,
|
|
475
|
-
|
|
537
|
+
stream_events=stream_events,
|
|
538
|
+
stream_executor_events=stream_executor_events,
|
|
476
539
|
workflow_run_response=workflow_run_response,
|
|
477
540
|
step_index=child_step_index,
|
|
478
541
|
store_executor_outputs=store_executor_outputs,
|
|
479
542
|
parent_step_id=steps_id,
|
|
543
|
+
workflow_session=workflow_session,
|
|
544
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
545
|
+
num_history_runs=num_history_runs,
|
|
546
|
+
background_tasks=background_tasks,
|
|
480
547
|
):
|
|
481
548
|
if isinstance(event, StepOutput):
|
|
482
549
|
step_outputs_for_step.append(event)
|
|
@@ -511,7 +578,7 @@ class Steps:
|
|
|
511
578
|
|
|
512
579
|
log_debug(f"Steps End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
513
580
|
# Yield steps execution completed event
|
|
514
|
-
if
|
|
581
|
+
if stream_events:
|
|
515
582
|
yield StepsExecutionCompletedEvent(
|
|
516
583
|
run_id=workflow_run_response.run_id or "",
|
|
517
584
|
workflow_name=workflow_run_response.workflow_name or "",
|
agno/workflow/types.py
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import Any, Dict, List, Optional, Union
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
5
5
|
|
|
6
6
|
from fastapi import WebSocket
|
|
7
7
|
from pydantic import BaseModel
|
|
8
8
|
|
|
9
9
|
from agno.media import Audio, File, Image, Video
|
|
10
10
|
from agno.models.metrics import Metrics
|
|
11
|
+
from agno.session.workflow import WorkflowSession
|
|
11
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
|
+
)
|
|
12
19
|
from agno.utils.serialize import json_serializer
|
|
20
|
+
from agno.utils.timer import Timer
|
|
13
21
|
|
|
14
22
|
|
|
15
23
|
@dataclass
|
|
@@ -80,6 +88,8 @@ class StepInput:
|
|
|
80
88
|
audio: Optional[List[Audio]] = None
|
|
81
89
|
files: Optional[List[File]] = None
|
|
82
90
|
|
|
91
|
+
workflow_session: Optional["WorkflowSession"] = None
|
|
92
|
+
|
|
83
93
|
def get_input_as_string(self) -> Optional[str]:
|
|
84
94
|
"""Convert input to string representation"""
|
|
85
95
|
if self.input is None:
|
|
@@ -97,10 +107,46 @@ class StepInput:
|
|
|
97
107
|
return str(self.input)
|
|
98
108
|
|
|
99
109
|
def get_step_output(self, step_name: str) -> Optional["StepOutput"]:
|
|
100
|
-
"""Get output from a specific previous step by name
|
|
110
|
+
"""Get output from a specific previous step by name
|
|
111
|
+
|
|
112
|
+
Searches recursively through nested steps (Parallel, Condition, Router, Loop, Steps)
|
|
113
|
+
to find step outputs at any depth.
|
|
114
|
+
"""
|
|
115
|
+
if not self.previous_step_outputs:
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
# First try direct lookup
|
|
119
|
+
direct = self.previous_step_outputs.get(step_name)
|
|
120
|
+
if direct:
|
|
121
|
+
return direct
|
|
122
|
+
|
|
123
|
+
# Search recursively in nested steps
|
|
124
|
+
return self._search_nested_steps(step_name)
|
|
125
|
+
|
|
126
|
+
def _search_nested_steps(self, step_name: str) -> Optional["StepOutput"]:
|
|
127
|
+
"""Recursively search for a step output in nested steps (Parallel, Condition, etc.)"""
|
|
101
128
|
if not self.previous_step_outputs:
|
|
102
129
|
return None
|
|
103
|
-
|
|
130
|
+
|
|
131
|
+
for step_output in self.previous_step_outputs.values():
|
|
132
|
+
result = self._search_in_step_output(step_output, step_name)
|
|
133
|
+
if result:
|
|
134
|
+
return result
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
def _search_in_step_output(self, step_output: "StepOutput", step_name: str) -> Optional["StepOutput"]:
|
|
138
|
+
"""Helper to recursively search within a single StepOutput"""
|
|
139
|
+
if not step_output.steps:
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
for nested_step in step_output.steps:
|
|
143
|
+
if nested_step.step_name == step_name:
|
|
144
|
+
return nested_step
|
|
145
|
+
# Recursively search deeper
|
|
146
|
+
result = self._search_in_step_output(nested_step, step_name)
|
|
147
|
+
if result:
|
|
148
|
+
return result
|
|
149
|
+
return None
|
|
104
150
|
|
|
105
151
|
def get_step_content(self, step_name: str) -> Optional[Union[str, Dict[str, str]]]:
|
|
106
152
|
"""Get content from a specific previous step by name
|
|
@@ -171,13 +217,35 @@ class StepInput:
|
|
|
171
217
|
# Use the helper method to get the deepest content
|
|
172
218
|
return self._get_deepest_step_content(last_output) # type: ignore[return-value]
|
|
173
219
|
|
|
220
|
+
def get_workflow_history(self, num_runs: Optional[int] = None) -> List[Tuple[str, str]]:
|
|
221
|
+
"""Get workflow conversation history as structured data for custom function steps
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
num_runs: Number of recent runs to include. If None, returns all available history.
|
|
225
|
+
"""
|
|
226
|
+
if not self.workflow_session:
|
|
227
|
+
return []
|
|
228
|
+
|
|
229
|
+
return self.workflow_session.get_workflow_history(num_runs=num_runs)
|
|
230
|
+
|
|
231
|
+
def get_workflow_history_context(self, num_runs: Optional[int] = None) -> Optional[str]:
|
|
232
|
+
"""Get formatted workflow conversation history context for custom function steps
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
num_runs: Number of recent runs to include. If None, returns all available history.
|
|
236
|
+
"""
|
|
237
|
+
if not self.workflow_session:
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
return self.workflow_session.get_workflow_history_context(num_runs=num_runs)
|
|
241
|
+
|
|
174
242
|
def to_dict(self) -> Dict[str, Any]:
|
|
175
243
|
"""Convert to dictionary"""
|
|
176
244
|
# Handle the unified message field
|
|
177
245
|
input_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
178
246
|
if self.input is not None:
|
|
179
247
|
if isinstance(self.input, BaseModel):
|
|
180
|
-
input_dict = self.input.model_dump(exclude_none=True)
|
|
248
|
+
input_dict = self.input.model_dump(exclude_none=True, mode="json")
|
|
181
249
|
elif isinstance(self.input, (dict, list)):
|
|
182
250
|
input_dict = self.input
|
|
183
251
|
else:
|
|
@@ -249,7 +317,7 @@ class StepOutput:
|
|
|
249
317
|
content_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
250
318
|
if self.content is not None:
|
|
251
319
|
if isinstance(self.content, BaseModel):
|
|
252
|
-
content_dict = self.content.model_dump(exclude_none=True)
|
|
320
|
+
content_dict = self.content.model_dump(exclude_none=True, mode="json")
|
|
253
321
|
elif isinstance(self.content, (dict, list)):
|
|
254
322
|
content_dict = self.content
|
|
255
323
|
else:
|
|
@@ -283,21 +351,10 @@ class StepOutput:
|
|
|
283
351
|
def from_dict(cls, data: Dict[str, Any]) -> "StepOutput":
|
|
284
352
|
"""Create StepOutput from dictionary"""
|
|
285
353
|
# Reconstruct media artifacts
|
|
286
|
-
images = data.get("images")
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
videos = data.get("videos")
|
|
291
|
-
if videos:
|
|
292
|
-
videos = [Video.model_validate(vid) for vid in videos]
|
|
293
|
-
|
|
294
|
-
audio = data.get("audio")
|
|
295
|
-
if audio:
|
|
296
|
-
audio = [Audio.model_validate(aud) for aud in audio]
|
|
297
|
-
|
|
298
|
-
files = data.get("files")
|
|
299
|
-
if files:
|
|
300
|
-
files = [File.model_validate(file) for file in files]
|
|
354
|
+
images = reconstruct_images(data.get("images"))
|
|
355
|
+
videos = reconstruct_videos(data.get("videos"))
|
|
356
|
+
audio = reconstruct_audio_list(data.get("audio"))
|
|
357
|
+
files = reconstruct_files(data.get("files"))
|
|
301
358
|
|
|
302
359
|
metrics_data = data.get("metrics")
|
|
303
360
|
metrics = None
|
|
@@ -385,12 +442,18 @@ class WorkflowMetrics:
|
|
|
385
442
|
"""Complete metrics for a workflow execution"""
|
|
386
443
|
|
|
387
444
|
steps: Dict[str, StepMetrics]
|
|
445
|
+
# Timer utility for tracking execution time
|
|
446
|
+
timer: Optional[Timer] = None
|
|
447
|
+
# Total workflow execution time
|
|
448
|
+
duration: Optional[float] = None
|
|
388
449
|
|
|
389
450
|
def to_dict(self) -> Dict[str, Any]:
|
|
390
451
|
"""Convert to dictionary"""
|
|
391
|
-
|
|
452
|
+
result: Dict[str, Any] = {
|
|
392
453
|
"steps": {name: step.to_dict() for name, step in self.steps.items()},
|
|
454
|
+
"duration": self.duration,
|
|
393
455
|
}
|
|
456
|
+
return result
|
|
394
457
|
|
|
395
458
|
@classmethod
|
|
396
459
|
def from_dict(cls, data: Dict[str, Any]) -> "WorkflowMetrics":
|
|
@@ -399,8 +462,20 @@ class WorkflowMetrics:
|
|
|
399
462
|
|
|
400
463
|
return cls(
|
|
401
464
|
steps=steps,
|
|
465
|
+
duration=data.get("duration"),
|
|
402
466
|
)
|
|
403
467
|
|
|
468
|
+
def start_timer(self):
|
|
469
|
+
if self.timer is None:
|
|
470
|
+
self.timer = Timer()
|
|
471
|
+
self.timer.start()
|
|
472
|
+
|
|
473
|
+
def stop_timer(self, set_duration: bool = True):
|
|
474
|
+
if self.timer is not None:
|
|
475
|
+
self.timer.stop()
|
|
476
|
+
if set_duration:
|
|
477
|
+
self.duration = self.timer.elapsed
|
|
478
|
+
|
|
404
479
|
|
|
405
480
|
@dataclass
|
|
406
481
|
class WebSocketHandler:
|