agno 2.0.0rc2__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.
- agno/agent/agent.py +6009 -2874
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- 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 +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +595 -187
- agno/knowledge/reader/base.py +9 -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 +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +339 -266
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +1011 -566
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +110 -37
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +143 -4
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +60 -6
- agno/models/openai/chat.py +102 -43
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +81 -5
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -175
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +266 -112
- agno/run/base.py +53 -24
- agno/run/team.py +252 -111
- agno/run/workflow.py +156 -45
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1692
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +9 -8
- agno/tools/decorator.py +4 -2
- agno/tools/desi_vocal.py +2 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +20 -13
- agno/tools/eleven_labs.py +26 -28
- agno/tools/exa.py +21 -16
- agno/tools/fal.py +4 -4
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +257 -37
- agno/tools/giphy.py +2 -2
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/lumalab.py +3 -3
- 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 +284 -0
- agno/tools/mem0.py +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/azure_openai.py +2 -2
- agno/tools/models/gemini.py +3 -3
- agno/tools/models/groq.py +3 -5
- agno/tools/models/nebius.py +7 -7
- agno/tools/models_labs.py +25 -15
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/parallel.py +314 -0
- agno/tools/replicate.py +7 -7
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +222 -7
- agno/utils/gemini.py +181 -23
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +95 -5
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +183 -135
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +645 -136
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +71 -33
- agno/workflow/workflow.py +2113 -300
- agno-2.3.0.dist-info/METADATA +618 -0
- agno-2.3.0.dist-info/RECORD +577 -0
- agno-2.3.0.dist-info/licenses/LICENSE +201 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.0rc2.dist-info/METADATA +0 -355
- agno-2.0.0rc2.dist-info/RECORD +0 -515
- agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc2.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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
from agno.media import
|
|
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
|
|
@@ -19,9 +29,9 @@ class WorkflowExecutionInput:
|
|
|
19
29
|
additional_data: Optional[Dict[str, Any]] = None
|
|
20
30
|
|
|
21
31
|
# Media inputs
|
|
22
|
-
images: Optional[List[
|
|
23
|
-
videos: Optional[List[
|
|
24
|
-
audio: Optional[List[
|
|
32
|
+
images: Optional[List[Image]] = None
|
|
33
|
+
videos: Optional[List[Video]] = None
|
|
34
|
+
audio: Optional[List[Audio]] = None
|
|
25
35
|
files: Optional[List[File]] = None
|
|
26
36
|
|
|
27
37
|
def get_input_as_string(self) -> Optional[str]:
|
|
@@ -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
|
|
|
@@ -72,11 +83,13 @@ class StepInput:
|
|
|
72
83
|
additional_data: Optional[Dict[str, Any]] = None
|
|
73
84
|
|
|
74
85
|
# Media inputs
|
|
75
|
-
images: Optional[List[
|
|
76
|
-
videos: Optional[List[
|
|
77
|
-
audio: Optional[List[
|
|
86
|
+
images: Optional[List[Image]] = None
|
|
87
|
+
videos: Optional[List[Video]] = None
|
|
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
|
|
@@ -225,9 +260,9 @@ class StepOutput:
|
|
|
225
260
|
step_run_id: Optional[str] = None
|
|
226
261
|
|
|
227
262
|
# Media outputs
|
|
228
|
-
images: Optional[List[
|
|
229
|
-
videos: Optional[List[
|
|
230
|
-
audio: Optional[List[
|
|
263
|
+
images: Optional[List[Image]] = None
|
|
264
|
+
videos: Optional[List[Video]] = None
|
|
265
|
+
audio: Optional[List[Audio]] = None
|
|
231
266
|
files: Optional[List[File]] = None
|
|
232
267
|
|
|
233
268
|
# Metrics for this step execution
|
|
@@ -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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
videos = data.get("videos")
|
|
288
|
-
if videos:
|
|
289
|
-
videos = [VideoArtifact.model_validate(vid) for vid in videos]
|
|
290
|
-
|
|
291
|
-
audio = data.get("audio")
|
|
292
|
-
if audio:
|
|
293
|
-
audio = [AudioArtifact.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|