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/agent.py
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""WorkflowAgent - A restricted Agent for workflow orchestration"""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional
|
|
4
|
+
|
|
5
|
+
from agno.agent import Agent
|
|
6
|
+
from agno.models.base import Model
|
|
7
|
+
from agno.run import RunContext
|
|
8
|
+
from agno.workflow.types import WebSocketHandler
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from agno.session.workflow import WorkflowSession
|
|
12
|
+
from agno.workflow.types import WorkflowExecutionInput
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WorkflowAgent(Agent):
|
|
16
|
+
"""
|
|
17
|
+
A restricted Agent class specifically designed for workflow orchestration.
|
|
18
|
+
This agent can:
|
|
19
|
+
1. Decide whether to run the workflow or answer directly from history
|
|
20
|
+
2. Call the workflow execution tool when needed
|
|
21
|
+
3. Access workflow session history for context
|
|
22
|
+
Restrictions:
|
|
23
|
+
- Only model configuration allowed
|
|
24
|
+
- No custom tools (tools are set by workflow)
|
|
25
|
+
- No knowledge base
|
|
26
|
+
- Limited configuration options
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
model: Model,
|
|
32
|
+
instructions: Optional[str] = None,
|
|
33
|
+
add_workflow_history: bool = True,
|
|
34
|
+
num_history_runs: int = 5,
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Initialize WorkflowAgent with restricted parameters.
|
|
38
|
+
Args:
|
|
39
|
+
model: The model to use for the agent (required)
|
|
40
|
+
instructions: Custom instructions (will be combined with workflow context)
|
|
41
|
+
add_workflow_history: Whether to add workflow history to context (default: True)
|
|
42
|
+
num_history_runs: Number of previous workflow runs to include in context (default: 5)
|
|
43
|
+
"""
|
|
44
|
+
self.add_workflow_history = add_workflow_history
|
|
45
|
+
|
|
46
|
+
default_instructions = """You are a workflow orchestration agent. Your job is to help users by either:
|
|
47
|
+
1. **Answering directly** from the workflow history context if the question can be answered from previous runs
|
|
48
|
+
2. **Running the workflow** by calling the run_workflow tool ONCE when you need to process a new query
|
|
49
|
+
|
|
50
|
+
Guidelines:
|
|
51
|
+
- ALWAYS check the workflow history first before calling the tool
|
|
52
|
+
- Answer directly from history if:
|
|
53
|
+
* The user asks about something already in history
|
|
54
|
+
* The user asks for comparisons/analysis of things in history (e.g., "compare X and Y")
|
|
55
|
+
* The user asks follow-up questions about previous results
|
|
56
|
+
- Only call the run_workflow tool for NEW topics not covered in history
|
|
57
|
+
- IMPORTANT: Do NOT call the tool multiple times. Call it once and use the result.
|
|
58
|
+
- Keep your responses concise and helpful
|
|
59
|
+
- When you must call the workflow, pass a clear and concise query
|
|
60
|
+
|
|
61
|
+
{workflow_context}
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
if instructions:
|
|
65
|
+
if "{workflow_context}" not in instructions:
|
|
66
|
+
# Add the workflow context placeholder
|
|
67
|
+
final_instructions = f"{instructions}\n\n{{workflow_context}}"
|
|
68
|
+
else:
|
|
69
|
+
final_instructions = instructions
|
|
70
|
+
else:
|
|
71
|
+
final_instructions = default_instructions
|
|
72
|
+
|
|
73
|
+
super().__init__(
|
|
74
|
+
model=model,
|
|
75
|
+
instructions=final_instructions,
|
|
76
|
+
resolve_in_context=True,
|
|
77
|
+
num_history_runs=num_history_runs,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def create_workflow_tool(
|
|
81
|
+
self,
|
|
82
|
+
workflow: "Any", # Workflow type
|
|
83
|
+
session: "WorkflowSession",
|
|
84
|
+
execution_input: "WorkflowExecutionInput",
|
|
85
|
+
run_context: RunContext,
|
|
86
|
+
stream: bool = False,
|
|
87
|
+
) -> Callable:
|
|
88
|
+
"""
|
|
89
|
+
Create the workflow execution tool that this agent can call.
|
|
90
|
+
This is similar to how Agent has search_knowledge_base() method.
|
|
91
|
+
Args:
|
|
92
|
+
workflow: The workflow instance
|
|
93
|
+
session: The workflow session
|
|
94
|
+
execution_input: The execution input
|
|
95
|
+
run_context: The run context
|
|
96
|
+
stream: Whether to stream the workflow execution
|
|
97
|
+
Returns:
|
|
98
|
+
Callable tool function
|
|
99
|
+
"""
|
|
100
|
+
from datetime import datetime
|
|
101
|
+
from uuid import uuid4
|
|
102
|
+
|
|
103
|
+
from pydantic import BaseModel
|
|
104
|
+
|
|
105
|
+
from agno.run.workflow import WorkflowRunOutput
|
|
106
|
+
from agno.utils.log import log_debug
|
|
107
|
+
from agno.workflow.types import WorkflowExecutionInput
|
|
108
|
+
|
|
109
|
+
def run_workflow(query: str):
|
|
110
|
+
"""
|
|
111
|
+
Execute the complete workflow with the given query.
|
|
112
|
+
Use this tool when you need to run the workflow to answer the user's question.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
query: The input query/question to process through the workflow
|
|
116
|
+
Returns:
|
|
117
|
+
The workflow execution result (str in non-streaming, generator in streaming)
|
|
118
|
+
"""
|
|
119
|
+
# Reload session to get latest data from database
|
|
120
|
+
# This ensures we don't overwrite any updates made after the tool was created
|
|
121
|
+
session_from_db = workflow.get_session(session_id=session.session_id)
|
|
122
|
+
if session_from_db is None:
|
|
123
|
+
session_from_db = session # Fallback to closure session if reload fails
|
|
124
|
+
log_debug(f"Fallback to closure session: {len(session_from_db.runs or [])} runs")
|
|
125
|
+
else:
|
|
126
|
+
log_debug(f"Reloaded session before tool execution: {len(session_from_db.runs or [])} runs")
|
|
127
|
+
|
|
128
|
+
# Create a new run ID for this execution
|
|
129
|
+
run_id = str(uuid4())
|
|
130
|
+
|
|
131
|
+
workflow_run_response = WorkflowRunOutput(
|
|
132
|
+
run_id=run_id,
|
|
133
|
+
input=execution_input.input, # Use original user input
|
|
134
|
+
session_id=session_from_db.session_id,
|
|
135
|
+
workflow_id=workflow.id,
|
|
136
|
+
workflow_name=workflow.name,
|
|
137
|
+
created_at=int(datetime.now().timestamp()),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
workflow_execution_input = WorkflowExecutionInput(
|
|
141
|
+
input=query, # Agent's refined query for execution
|
|
142
|
+
additional_data=execution_input.additional_data,
|
|
143
|
+
audio=execution_input.audio,
|
|
144
|
+
images=execution_input.images,
|
|
145
|
+
videos=execution_input.videos,
|
|
146
|
+
files=execution_input.files,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# ===== EXECUTION LOGIC (Based on streaming mode) =====
|
|
150
|
+
if stream:
|
|
151
|
+
final_content = ""
|
|
152
|
+
for event in workflow._execute_stream(
|
|
153
|
+
session=session_from_db,
|
|
154
|
+
run_context=run_context,
|
|
155
|
+
execution_input=workflow_execution_input,
|
|
156
|
+
workflow_run_response=workflow_run_response,
|
|
157
|
+
stream_events=True,
|
|
158
|
+
):
|
|
159
|
+
yield event
|
|
160
|
+
|
|
161
|
+
# Capture final content from WorkflowCompletedEvent
|
|
162
|
+
from agno.run.workflow import WorkflowCompletedEvent
|
|
163
|
+
|
|
164
|
+
if isinstance(event, WorkflowCompletedEvent):
|
|
165
|
+
final_content = str(event.content) if event.content else ""
|
|
166
|
+
|
|
167
|
+
return final_content
|
|
168
|
+
else:
|
|
169
|
+
# NON-STREAMING MODE: Execute synchronously
|
|
170
|
+
result = workflow._execute(
|
|
171
|
+
session=session_from_db,
|
|
172
|
+
execution_input=workflow_execution_input,
|
|
173
|
+
workflow_run_response=workflow_run_response,
|
|
174
|
+
run_context=run_context,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if isinstance(result.content, str):
|
|
178
|
+
return result.content
|
|
179
|
+
elif isinstance(result.content, BaseModel):
|
|
180
|
+
return result.content.model_dump_json(exclude_none=True)
|
|
181
|
+
else:
|
|
182
|
+
return str(result.content)
|
|
183
|
+
|
|
184
|
+
return run_workflow
|
|
185
|
+
|
|
186
|
+
def async_create_workflow_tool(
|
|
187
|
+
self,
|
|
188
|
+
workflow: "Any", # Workflow type
|
|
189
|
+
session: "WorkflowSession",
|
|
190
|
+
execution_input: "WorkflowExecutionInput",
|
|
191
|
+
run_context: RunContext,
|
|
192
|
+
stream: bool = False,
|
|
193
|
+
websocket_handler: Optional[WebSocketHandler] = None,
|
|
194
|
+
) -> Callable:
|
|
195
|
+
"""
|
|
196
|
+
Create the async workflow execution tool that this agent can call.
|
|
197
|
+
This is the async counterpart of create_workflow_tool.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
workflow: The workflow instance
|
|
201
|
+
session: The workflow session
|
|
202
|
+
execution_input: The execution input
|
|
203
|
+
run_context: The run context
|
|
204
|
+
stream: Whether to stream the workflow execution
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Async callable tool function
|
|
208
|
+
"""
|
|
209
|
+
from datetime import datetime
|
|
210
|
+
from uuid import uuid4
|
|
211
|
+
|
|
212
|
+
from pydantic import BaseModel
|
|
213
|
+
|
|
214
|
+
from agno.run.workflow import WorkflowRunOutput
|
|
215
|
+
from agno.utils.log import log_debug
|
|
216
|
+
from agno.workflow.types import WorkflowExecutionInput
|
|
217
|
+
|
|
218
|
+
async def run_workflow(query: str):
|
|
219
|
+
"""
|
|
220
|
+
Execute the complete workflow with the given query asynchronously.
|
|
221
|
+
Use this tool when you need to run the workflow to answer the user's question.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
query: The input query/question to process through the workflow
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
The workflow execution result (str in non-streaming, async generator in streaming)
|
|
228
|
+
"""
|
|
229
|
+
# Reload session to get latest data from database
|
|
230
|
+
# This ensures we don't overwrite any updates made after the tool was created
|
|
231
|
+
# Use async or sync method based on database type
|
|
232
|
+
if workflow._has_async_db():
|
|
233
|
+
session_from_db = await workflow.aget_session(session_id=session.session_id)
|
|
234
|
+
else:
|
|
235
|
+
session_from_db = workflow.get_session(session_id=session.session_id)
|
|
236
|
+
|
|
237
|
+
if session_from_db is None:
|
|
238
|
+
session_from_db = session # Fallback to closure session if reload fails
|
|
239
|
+
log_debug(f"Fallback to closure session: {len(session_from_db.runs or [])} runs")
|
|
240
|
+
else:
|
|
241
|
+
log_debug(f"Reloaded session before async tool execution: {len(session_from_db.runs or [])} runs")
|
|
242
|
+
|
|
243
|
+
# Create a new run ID for this execution
|
|
244
|
+
run_id = str(uuid4())
|
|
245
|
+
|
|
246
|
+
workflow_run_response = WorkflowRunOutput(
|
|
247
|
+
run_id=run_id,
|
|
248
|
+
input=execution_input.input, # Use original user input
|
|
249
|
+
session_id=session_from_db.session_id,
|
|
250
|
+
workflow_id=workflow.id,
|
|
251
|
+
workflow_name=workflow.name,
|
|
252
|
+
created_at=int(datetime.now().timestamp()),
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
workflow_execution_input = WorkflowExecutionInput(
|
|
256
|
+
input=query, # Agent's refined query for execution
|
|
257
|
+
additional_data=execution_input.additional_data,
|
|
258
|
+
audio=execution_input.audio,
|
|
259
|
+
images=execution_input.images,
|
|
260
|
+
videos=execution_input.videos,
|
|
261
|
+
files=execution_input.files,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
if stream:
|
|
265
|
+
final_content = ""
|
|
266
|
+
async for event in workflow._aexecute_stream(
|
|
267
|
+
session_id=session_from_db.session_id,
|
|
268
|
+
user_id=session_from_db.user_id,
|
|
269
|
+
execution_input=workflow_execution_input,
|
|
270
|
+
workflow_run_response=workflow_run_response,
|
|
271
|
+
run_context=run_context,
|
|
272
|
+
stream_events=True,
|
|
273
|
+
websocket_handler=websocket_handler,
|
|
274
|
+
):
|
|
275
|
+
yield event
|
|
276
|
+
|
|
277
|
+
from agno.run.workflow import WorkflowCompletedEvent
|
|
278
|
+
|
|
279
|
+
if isinstance(event, WorkflowCompletedEvent):
|
|
280
|
+
final_content = str(event.content) if event.content else ""
|
|
281
|
+
|
|
282
|
+
yield final_content
|
|
283
|
+
else:
|
|
284
|
+
result = await workflow._aexecute(
|
|
285
|
+
session_id=session_from_db.session_id,
|
|
286
|
+
user_id=session_from_db.user_id,
|
|
287
|
+
execution_input=workflow_execution_input,
|
|
288
|
+
workflow_run_response=workflow_run_response,
|
|
289
|
+
run_context=run_context,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
if isinstance(result.content, str):
|
|
293
|
+
yield result.content
|
|
294
|
+
elif isinstance(result.content, BaseModel):
|
|
295
|
+
yield result.content.model_dump_json(exclude_none=True)
|
|
296
|
+
else:
|
|
297
|
+
yield str(result.content)
|
|
298
|
+
|
|
299
|
+
return run_workflow
|
agno/workflow/condition.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import inspect
|
|
2
|
+
import warnings
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
|
|
4
5
|
from uuid import uuid4
|
|
5
6
|
|
|
6
7
|
from agno.run.agent import RunOutputEvent
|
|
8
|
+
from agno.run.base import RunContext
|
|
7
9
|
from agno.run.team import TeamRunOutputEvent
|
|
8
10
|
from agno.run.workflow import (
|
|
9
11
|
ConditionExecutionCompletedEvent,
|
|
@@ -11,6 +13,7 @@ from agno.run.workflow import (
|
|
|
11
13
|
WorkflowRunOutput,
|
|
12
14
|
WorkflowRunOutputEvent,
|
|
13
15
|
)
|
|
16
|
+
from agno.session.workflow import WorkflowSession
|
|
14
17
|
from agno.utils.log import log_debug, logger
|
|
15
18
|
from agno.workflow.step import Step
|
|
16
19
|
from agno.workflow.types import StepInput, StepOutput, StepType
|
|
@@ -110,13 +113,16 @@ class Condition:
|
|
|
110
113
|
audio=current_audio + all_audio,
|
|
111
114
|
)
|
|
112
115
|
|
|
113
|
-
def _evaluate_condition(self, step_input: StepInput) -> bool:
|
|
116
|
+
def _evaluate_condition(self, step_input: StepInput, session_state: Optional[Dict[str, Any]] = None) -> bool:
|
|
114
117
|
"""Evaluate the condition and return boolean result"""
|
|
115
118
|
if isinstance(self.evaluator, bool):
|
|
116
119
|
return self.evaluator
|
|
117
120
|
|
|
118
121
|
if callable(self.evaluator):
|
|
119
|
-
|
|
122
|
+
if session_state is not None and self._evaluator_has_session_state_param():
|
|
123
|
+
result = self.evaluator(step_input, session_state=session_state) # type: ignore[call-arg]
|
|
124
|
+
else:
|
|
125
|
+
result = self.evaluator(step_input)
|
|
120
126
|
|
|
121
127
|
if isinstance(result, bool):
|
|
122
128
|
return result
|
|
@@ -126,16 +132,24 @@ class Condition:
|
|
|
126
132
|
|
|
127
133
|
return False
|
|
128
134
|
|
|
129
|
-
async def _aevaluate_condition(self, step_input: StepInput) -> bool:
|
|
135
|
+
async def _aevaluate_condition(self, step_input: StepInput, session_state: Optional[Dict[str, Any]] = None) -> bool:
|
|
130
136
|
"""Async version of condition evaluation"""
|
|
131
137
|
if isinstance(self.evaluator, bool):
|
|
132
138
|
return self.evaluator
|
|
133
139
|
|
|
134
140
|
if callable(self.evaluator):
|
|
141
|
+
has_session_state = session_state is not None and self._evaluator_has_session_state_param()
|
|
142
|
+
|
|
135
143
|
if inspect.iscoroutinefunction(self.evaluator):
|
|
136
|
-
|
|
144
|
+
if has_session_state:
|
|
145
|
+
result = await self.evaluator(step_input, session_state=session_state) # type: ignore[call-arg]
|
|
146
|
+
else:
|
|
147
|
+
result = await self.evaluator(step_input)
|
|
137
148
|
else:
|
|
138
|
-
|
|
149
|
+
if has_session_state:
|
|
150
|
+
result = self.evaluator(step_input, session_state=session_state) # type: ignore[call-arg]
|
|
151
|
+
else:
|
|
152
|
+
result = self.evaluator(step_input)
|
|
139
153
|
|
|
140
154
|
if isinstance(result, bool):
|
|
141
155
|
return result
|
|
@@ -145,6 +159,17 @@ class Condition:
|
|
|
145
159
|
|
|
146
160
|
return False
|
|
147
161
|
|
|
162
|
+
def _evaluator_has_session_state_param(self) -> bool:
|
|
163
|
+
"""Check if the evaluator function has a session_state parameter"""
|
|
164
|
+
if not callable(self.evaluator):
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
sig = inspect.signature(self.evaluator)
|
|
169
|
+
return "session_state" in sig.parameters
|
|
170
|
+
except Exception:
|
|
171
|
+
return False
|
|
172
|
+
|
|
148
173
|
def execute(
|
|
149
174
|
self,
|
|
150
175
|
step_input: StepInput,
|
|
@@ -152,7 +177,12 @@ class Condition:
|
|
|
152
177
|
user_id: Optional[str] = None,
|
|
153
178
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
154
179
|
store_executor_outputs: bool = True,
|
|
180
|
+
run_context: Optional[RunContext] = None,
|
|
155
181
|
session_state: Optional[Dict[str, Any]] = None,
|
|
182
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
183
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
184
|
+
num_history_runs: int = 3,
|
|
185
|
+
background_tasks: Optional[Any] = None,
|
|
156
186
|
) -> StepOutput:
|
|
157
187
|
"""Execute the condition and its steps with sequential chaining if condition is true"""
|
|
158
188
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
@@ -162,7 +192,11 @@ class Condition:
|
|
|
162
192
|
self._prepare_steps()
|
|
163
193
|
|
|
164
194
|
# Evaluate the condition
|
|
165
|
-
|
|
195
|
+
if run_context is not None and run_context.session_state is not None:
|
|
196
|
+
condition_result = self._evaluate_condition(step_input, session_state=run_context.session_state)
|
|
197
|
+
else:
|
|
198
|
+
condition_result = self._evaluate_condition(step_input, session_state=session_state)
|
|
199
|
+
|
|
166
200
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
167
201
|
|
|
168
202
|
if not condition_result:
|
|
@@ -188,7 +222,12 @@ class Condition:
|
|
|
188
222
|
user_id=user_id,
|
|
189
223
|
workflow_run_response=workflow_run_response,
|
|
190
224
|
store_executor_outputs=store_executor_outputs,
|
|
225
|
+
run_context=run_context,
|
|
191
226
|
session_state=session_state,
|
|
227
|
+
workflow_session=workflow_session,
|
|
228
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
229
|
+
num_history_runs=num_history_runs,
|
|
230
|
+
background_tasks=background_tasks,
|
|
192
231
|
)
|
|
193
232
|
|
|
194
233
|
# Handle both single StepOutput and List[StepOutput] (from Loop/Condition/Router steps)
|
|
@@ -249,12 +288,19 @@ class Condition:
|
|
|
249
288
|
step_input: StepInput,
|
|
250
289
|
session_id: Optional[str] = None,
|
|
251
290
|
user_id: Optional[str] = None,
|
|
252
|
-
|
|
291
|
+
stream_events: bool = False,
|
|
292
|
+
stream_intermediate_steps: bool = False, # type: ignore
|
|
293
|
+
stream_executor_events: bool = True,
|
|
253
294
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
254
295
|
step_index: Optional[Union[int, tuple]] = None,
|
|
255
296
|
store_executor_outputs: bool = True,
|
|
297
|
+
run_context: Optional[RunContext] = None,
|
|
256
298
|
session_state: Optional[Dict[str, Any]] = None,
|
|
257
299
|
parent_step_id: Optional[str] = None,
|
|
300
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
301
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
302
|
+
num_history_runs: int = 3,
|
|
303
|
+
background_tasks: Optional[Any] = None,
|
|
258
304
|
) -> Iterator[Union[WorkflowRunOutputEvent, StepOutput]]:
|
|
259
305
|
"""Execute the condition with streaming support - mirrors Loop logic"""
|
|
260
306
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
@@ -264,10 +310,22 @@ class Condition:
|
|
|
264
310
|
self._prepare_steps()
|
|
265
311
|
|
|
266
312
|
# Evaluate the condition
|
|
267
|
-
|
|
313
|
+
if run_context is not None and run_context.session_state is not None:
|
|
314
|
+
condition_result = self._evaluate_condition(step_input, session_state=run_context.session_state)
|
|
315
|
+
else:
|
|
316
|
+
condition_result = self._evaluate_condition(step_input, session_state=session_state)
|
|
268
317
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
269
318
|
|
|
270
|
-
|
|
319
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
320
|
+
if stream_intermediate_steps is not None:
|
|
321
|
+
warnings.warn(
|
|
322
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
323
|
+
DeprecationWarning,
|
|
324
|
+
stacklevel=2,
|
|
325
|
+
)
|
|
326
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
327
|
+
|
|
328
|
+
if stream_events and workflow_run_response:
|
|
271
329
|
# Yield condition started event
|
|
272
330
|
yield ConditionExecutionStartedEvent(
|
|
273
331
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -282,7 +340,7 @@ class Condition:
|
|
|
282
340
|
)
|
|
283
341
|
|
|
284
342
|
if not condition_result:
|
|
285
|
-
if
|
|
343
|
+
if stream_events and workflow_run_response:
|
|
286
344
|
# Yield condition completed event for empty case
|
|
287
345
|
yield ConditionExecutionCompletedEvent(
|
|
288
346
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -321,12 +379,18 @@ class Condition:
|
|
|
321
379
|
current_step_input,
|
|
322
380
|
session_id=session_id,
|
|
323
381
|
user_id=user_id,
|
|
324
|
-
|
|
382
|
+
stream_events=stream_events,
|
|
383
|
+
stream_executor_events=stream_executor_events,
|
|
325
384
|
workflow_run_response=workflow_run_response,
|
|
326
385
|
step_index=child_step_index,
|
|
327
386
|
store_executor_outputs=store_executor_outputs,
|
|
387
|
+
run_context=run_context,
|
|
328
388
|
session_state=session_state,
|
|
329
389
|
parent_step_id=conditional_step_id,
|
|
390
|
+
workflow_session=workflow_session,
|
|
391
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
392
|
+
num_history_runs=num_history_runs,
|
|
393
|
+
background_tasks=background_tasks,
|
|
330
394
|
):
|
|
331
395
|
if isinstance(event, StepOutput):
|
|
332
396
|
step_outputs_for_step.append(event)
|
|
@@ -374,7 +438,7 @@ class Condition:
|
|
|
374
438
|
break
|
|
375
439
|
|
|
376
440
|
log_debug(f"Condition End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
377
|
-
if
|
|
441
|
+
if stream_events and workflow_run_response:
|
|
378
442
|
# Yield condition completed event
|
|
379
443
|
yield ConditionExecutionCompletedEvent(
|
|
380
444
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -406,7 +470,12 @@ class Condition:
|
|
|
406
470
|
user_id: Optional[str] = None,
|
|
407
471
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
408
472
|
store_executor_outputs: bool = True,
|
|
473
|
+
run_context: Optional[RunContext] = None,
|
|
409
474
|
session_state: Optional[Dict[str, Any]] = None,
|
|
475
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
476
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
477
|
+
num_history_runs: int = 3,
|
|
478
|
+
background_tasks: Optional[Any] = None,
|
|
410
479
|
) -> StepOutput:
|
|
411
480
|
"""Async execute the condition and its steps with sequential chaining"""
|
|
412
481
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
@@ -416,7 +485,10 @@ class Condition:
|
|
|
416
485
|
self._prepare_steps()
|
|
417
486
|
|
|
418
487
|
# Evaluate the condition
|
|
419
|
-
|
|
488
|
+
if run_context is not None and run_context.session_state is not None:
|
|
489
|
+
condition_result = await self._aevaluate_condition(step_input, session_state=run_context.session_state)
|
|
490
|
+
else:
|
|
491
|
+
condition_result = await self._aevaluate_condition(step_input, session_state=session_state)
|
|
420
492
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
421
493
|
|
|
422
494
|
if not condition_result:
|
|
@@ -444,7 +516,12 @@ class Condition:
|
|
|
444
516
|
user_id=user_id,
|
|
445
517
|
workflow_run_response=workflow_run_response,
|
|
446
518
|
store_executor_outputs=store_executor_outputs,
|
|
519
|
+
run_context=run_context,
|
|
447
520
|
session_state=session_state,
|
|
521
|
+
workflow_session=workflow_session,
|
|
522
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
523
|
+
num_history_runs=num_history_runs,
|
|
524
|
+
background_tasks=background_tasks,
|
|
448
525
|
)
|
|
449
526
|
|
|
450
527
|
# Handle both single StepOutput and List[StepOutput]
|
|
@@ -503,12 +580,19 @@ class Condition:
|
|
|
503
580
|
step_input: StepInput,
|
|
504
581
|
session_id: Optional[str] = None,
|
|
505
582
|
user_id: Optional[str] = None,
|
|
583
|
+
stream_events: bool = False,
|
|
506
584
|
stream_intermediate_steps: bool = False,
|
|
585
|
+
stream_executor_events: bool = True,
|
|
507
586
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
508
587
|
step_index: Optional[Union[int, tuple]] = None,
|
|
509
588
|
store_executor_outputs: bool = True,
|
|
589
|
+
run_context: Optional[RunContext] = None,
|
|
510
590
|
session_state: Optional[Dict[str, Any]] = None,
|
|
511
591
|
parent_step_id: Optional[str] = None,
|
|
592
|
+
workflow_session: Optional[WorkflowSession] = None,
|
|
593
|
+
add_workflow_history_to_steps: Optional[bool] = False,
|
|
594
|
+
num_history_runs: int = 3,
|
|
595
|
+
background_tasks: Optional[Any] = None,
|
|
512
596
|
) -> AsyncIterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
|
|
513
597
|
"""Async execute the condition with streaming support - mirrors Loop logic"""
|
|
514
598
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
@@ -518,10 +602,22 @@ class Condition:
|
|
|
518
602
|
self._prepare_steps()
|
|
519
603
|
|
|
520
604
|
# Evaluate the condition
|
|
521
|
-
|
|
605
|
+
if run_context is not None and run_context.session_state is not None:
|
|
606
|
+
condition_result = await self._aevaluate_condition(step_input, session_state=run_context.session_state)
|
|
607
|
+
else:
|
|
608
|
+
condition_result = await self._aevaluate_condition(step_input, session_state=session_state)
|
|
522
609
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
523
610
|
|
|
524
|
-
|
|
611
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
612
|
+
if stream_intermediate_steps is not None:
|
|
613
|
+
warnings.warn(
|
|
614
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
615
|
+
DeprecationWarning,
|
|
616
|
+
stacklevel=2,
|
|
617
|
+
)
|
|
618
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
619
|
+
|
|
620
|
+
if stream_events and workflow_run_response:
|
|
525
621
|
# Yield condition started event
|
|
526
622
|
yield ConditionExecutionStartedEvent(
|
|
527
623
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -536,7 +632,7 @@ class Condition:
|
|
|
536
632
|
)
|
|
537
633
|
|
|
538
634
|
if not condition_result:
|
|
539
|
-
if
|
|
635
|
+
if stream_events and workflow_run_response:
|
|
540
636
|
# Yield condition completed event for empty case
|
|
541
637
|
yield ConditionExecutionCompletedEvent(
|
|
542
638
|
run_id=workflow_run_response.run_id or "",
|
|
@@ -577,12 +673,18 @@ class Condition:
|
|
|
577
673
|
current_step_input,
|
|
578
674
|
session_id=session_id,
|
|
579
675
|
user_id=user_id,
|
|
580
|
-
|
|
676
|
+
stream_events=stream_events,
|
|
677
|
+
stream_executor_events=stream_executor_events,
|
|
581
678
|
workflow_run_response=workflow_run_response,
|
|
582
679
|
step_index=child_step_index,
|
|
583
680
|
store_executor_outputs=store_executor_outputs,
|
|
681
|
+
run_context=run_context,
|
|
584
682
|
session_state=session_state,
|
|
585
683
|
parent_step_id=conditional_step_id,
|
|
684
|
+
workflow_session=workflow_session,
|
|
685
|
+
add_workflow_history_to_steps=add_workflow_history_to_steps,
|
|
686
|
+
num_history_runs=num_history_runs,
|
|
687
|
+
background_tasks=background_tasks,
|
|
586
688
|
):
|
|
587
689
|
if isinstance(event, StepOutput):
|
|
588
690
|
step_outputs_for_step.append(event)
|
|
@@ -631,7 +733,7 @@ class Condition:
|
|
|
631
733
|
|
|
632
734
|
log_debug(f"Condition End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
633
735
|
|
|
634
|
-
if
|
|
736
|
+
if stream_events and workflow_run_response:
|
|
635
737
|
# Yield condition completed event
|
|
636
738
|
yield ConditionExecutionCompletedEvent(
|
|
637
739
|
run_id=workflow_run_response.run_id or "",
|