agno 2.4.5__py3-none-any.whl → 2.4.7__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 +2 -1
- agno/db/singlestore/singlestore.py +4 -5
- agno/db/surrealdb/models.py +1 -1
- agno/knowledge/chunking/agentic.py +1 -5
- agno/knowledge/chunking/code.py +1 -1
- agno/knowledge/chunking/document.py +22 -42
- agno/knowledge/chunking/fixed.py +1 -5
- agno/knowledge/chunking/markdown.py +9 -25
- agno/knowledge/chunking/recursive.py +1 -3
- agno/knowledge/chunking/row.py +3 -2
- agno/knowledge/chunking/semantic.py +1 -1
- agno/knowledge/chunking/strategy.py +19 -0
- agno/knowledge/embedder/aws_bedrock.py +325 -106
- agno/knowledge/knowledge.py +173 -14
- agno/knowledge/reader/text_reader.py +1 -1
- agno/knowledge/reranker/aws_bedrock.py +299 -0
- agno/learn/machine.py +5 -6
- agno/learn/stores/learned_knowledge.py +108 -131
- agno/run/workflow.py +3 -0
- agno/tools/mcp/mcp.py +26 -1
- agno/utils/print_response/agent.py +8 -8
- agno/utils/print_response/team.py +8 -8
- agno/vectordb/lancedb/lance_db.py +9 -9
- agno/workflow/condition.py +135 -56
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/METADATA +34 -59
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/RECORD +29 -28
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/WHEEL +0 -0
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/licenses/LICENSE +0 -0
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/top_level.txt +0 -0
|
@@ -61,7 +61,7 @@ def print_response(
|
|
|
61
61
|
tags_to_include_in_markdown = {"think", "thinking"}
|
|
62
62
|
|
|
63
63
|
with Live(console=console) as live_console:
|
|
64
|
-
status = Status("
|
|
64
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
65
65
|
live_console.update(status)
|
|
66
66
|
|
|
67
67
|
response_timer = Timer()
|
|
@@ -349,7 +349,7 @@ def print_response(
|
|
|
349
349
|
panels.append(summary_panel)
|
|
350
350
|
team.session_summary_manager.summaries_updated = False
|
|
351
351
|
|
|
352
|
-
# Final update to remove the "
|
|
352
|
+
# Final update to remove the "Working..." status
|
|
353
353
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
354
354
|
live_console.update(Group(*panels))
|
|
355
355
|
|
|
@@ -410,7 +410,7 @@ def print_response_stream(
|
|
|
410
410
|
processed_tool_calls = set()
|
|
411
411
|
|
|
412
412
|
with Live(console=console) as live_console:
|
|
413
|
-
status = Status("
|
|
413
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
414
414
|
live_console.update(status)
|
|
415
415
|
response_timer = Timer()
|
|
416
416
|
response_timer.start()
|
|
@@ -735,7 +735,7 @@ def print_response_stream(
|
|
|
735
735
|
live_console.update(Group(*panels))
|
|
736
736
|
team.session_summary_manager.summaries_updated = False
|
|
737
737
|
|
|
738
|
-
# Final update to remove the "
|
|
738
|
+
# Final update to remove the "Working..." status
|
|
739
739
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
740
740
|
|
|
741
741
|
if markdown:
|
|
@@ -992,7 +992,7 @@ async def aprint_response(
|
|
|
992
992
|
tags_to_include_in_markdown = {"think", "thinking"}
|
|
993
993
|
|
|
994
994
|
with Live(console=console) as live_console:
|
|
995
|
-
status = Status("
|
|
995
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
996
996
|
live_console.update(status)
|
|
997
997
|
|
|
998
998
|
response_timer = Timer()
|
|
@@ -1278,7 +1278,7 @@ async def aprint_response(
|
|
|
1278
1278
|
panels.append(summary_panel)
|
|
1279
1279
|
team.session_summary_manager.summaries_updated = False
|
|
1280
1280
|
|
|
1281
|
-
# Final update to remove the "
|
|
1281
|
+
# Final update to remove the "Working..." status
|
|
1282
1282
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
1283
1283
|
live_console.update(Group(*panels))
|
|
1284
1284
|
|
|
@@ -1340,7 +1340,7 @@ async def aprint_response_stream(
|
|
|
1340
1340
|
final_panels = [] # type: ignore
|
|
1341
1341
|
|
|
1342
1342
|
with Live(console=console) as live_console:
|
|
1343
|
-
status = Status("
|
|
1343
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
1344
1344
|
live_console.update(status)
|
|
1345
1345
|
response_timer = Timer()
|
|
1346
1346
|
response_timer.start()
|
|
@@ -1663,7 +1663,7 @@ async def aprint_response_stream(
|
|
|
1663
1663
|
live_console.update(Group(*panels))
|
|
1664
1664
|
team.session_summary_manager.summaries_updated = False
|
|
1665
1665
|
|
|
1666
|
-
# Final update to remove the "
|
|
1666
|
+
# Final update to remove the "Working..." status
|
|
1667
1667
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
1668
1668
|
|
|
1669
1669
|
if markdown:
|
|
@@ -104,7 +104,7 @@ class LanceDb(VectorDb):
|
|
|
104
104
|
self.async_connection: Optional[lancedb.AsyncConnection] = async_connection
|
|
105
105
|
self.async_table: Optional[lancedb.db.AsyncTable] = async_table
|
|
106
106
|
|
|
107
|
-
if table_name and table_name in self.connection.
|
|
107
|
+
if table_name and table_name in self.connection.list_tables().tables:
|
|
108
108
|
# Open the table if it exists
|
|
109
109
|
try:
|
|
110
110
|
self.table = self.connection.open_table(name=table_name)
|
|
@@ -186,8 +186,8 @@ class LanceDb(VectorDb):
|
|
|
186
186
|
self.async_connection = await lancedb.connect_async(self.uri)
|
|
187
187
|
# Only try to open table if it exists and we don't have it already
|
|
188
188
|
if self.async_table is None:
|
|
189
|
-
|
|
190
|
-
if self.table_name in
|
|
189
|
+
table_list = await self.async_connection.list_tables()
|
|
190
|
+
if self.table_name in table_list.tables:
|
|
191
191
|
try:
|
|
192
192
|
self.async_table = await self.async_connection.open_table(self.table_name)
|
|
193
193
|
except ValueError:
|
|
@@ -199,7 +199,7 @@ class LanceDb(VectorDb):
|
|
|
199
199
|
"""Refresh the sync connection to see changes made by async operations."""
|
|
200
200
|
try:
|
|
201
201
|
# Re-establish sync connection to see async changes
|
|
202
|
-
if self.connection and self.table_name in self.connection.
|
|
202
|
+
if self.connection is not None and self.table_name in self.connection.list_tables().tables:
|
|
203
203
|
self.table = self.connection.open_table(self.table_name)
|
|
204
204
|
except Exception as e:
|
|
205
205
|
log_debug(f"Could not refresh sync connection: {e}")
|
|
@@ -459,7 +459,7 @@ class LanceDb(VectorDb):
|
|
|
459
459
|
Returns:
|
|
460
460
|
List[Document]: List of matching documents
|
|
461
461
|
"""
|
|
462
|
-
if self.connection:
|
|
462
|
+
if self.connection is not None:
|
|
463
463
|
self.table = self.connection.open_table(name=self.table_name)
|
|
464
464
|
|
|
465
465
|
results = None
|
|
@@ -641,8 +641,8 @@ class LanceDb(VectorDb):
|
|
|
641
641
|
# If we have an async table that was created, the table exists
|
|
642
642
|
if self.async_table is not None:
|
|
643
643
|
return True
|
|
644
|
-
if self.connection:
|
|
645
|
-
return self.table_name in self.connection.
|
|
644
|
+
if self.connection is not None:
|
|
645
|
+
return self.table_name in self.connection.list_tables().tables
|
|
646
646
|
return False
|
|
647
647
|
|
|
648
648
|
async def async_exists(self) -> bool:
|
|
@@ -653,8 +653,8 @@ class LanceDb(VectorDb):
|
|
|
653
653
|
# Check if table exists in database without trying to open it
|
|
654
654
|
if self.async_connection is None:
|
|
655
655
|
self.async_connection = await lancedb.connect_async(self.uri)
|
|
656
|
-
|
|
657
|
-
return self.table_name in
|
|
656
|
+
table_list = await self.async_connection.list_tables()
|
|
657
|
+
return self.table_name in table_list.tables
|
|
658
658
|
|
|
659
659
|
async def async_get_count(self) -> int:
|
|
660
660
|
"""Get the number of rows in the table asynchronously."""
|
agno/workflow/condition.py
CHANGED
|
@@ -17,6 +17,10 @@ from agno.utils.log import log_debug, logger
|
|
|
17
17
|
from agno.workflow.step import Step
|
|
18
18
|
from agno.workflow.types import StepInput, StepOutput, StepType
|
|
19
19
|
|
|
20
|
+
# Constants for condition branch identifiers
|
|
21
|
+
CONDITION_BRANCH_IF = "if"
|
|
22
|
+
CONDITION_BRANCH_ELSE = "else"
|
|
23
|
+
|
|
20
24
|
WorkflowSteps = List[
|
|
21
25
|
Union[
|
|
22
26
|
Callable[
|
|
@@ -34,7 +38,12 @@ WorkflowSteps = List[
|
|
|
34
38
|
|
|
35
39
|
@dataclass
|
|
36
40
|
class Condition:
|
|
37
|
-
"""A condition that executes a step (or list of steps) if the condition is met
|
|
41
|
+
"""A condition that executes a step (or list of steps) if the condition is met.
|
|
42
|
+
|
|
43
|
+
If the condition evaluates to True, the `steps` are executed.
|
|
44
|
+
If the condition evaluates to False and `else_steps` is provided (and not empty),
|
|
45
|
+
the `else_steps` are executed instead.
|
|
46
|
+
"""
|
|
38
47
|
|
|
39
48
|
# Evaluator should only return boolean
|
|
40
49
|
evaluator: Union[
|
|
@@ -44,6 +53,9 @@ class Condition:
|
|
|
44
53
|
]
|
|
45
54
|
steps: WorkflowSteps
|
|
46
55
|
|
|
56
|
+
# Steps to execute when condition is False (optional)
|
|
57
|
+
else_steps: Optional[WorkflowSteps] = None
|
|
58
|
+
|
|
47
59
|
name: Optional[str] = None
|
|
48
60
|
description: Optional[str] = None
|
|
49
61
|
|
|
@@ -57,20 +69,27 @@ class Condition:
|
|
|
57
69
|
from agno.workflow.step import Step
|
|
58
70
|
from agno.workflow.steps import Steps
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
def prepare_step_list(steps: WorkflowSteps) -> WorkflowSteps:
|
|
73
|
+
"""Helper to prepare a list of steps."""
|
|
74
|
+
prepared: WorkflowSteps = []
|
|
75
|
+
for step in steps:
|
|
76
|
+
if callable(step) and hasattr(step, "__name__"):
|
|
77
|
+
prepared.append(Step(name=step.__name__, description="User-defined callable step", executor=step))
|
|
78
|
+
elif isinstance(step, Agent):
|
|
79
|
+
prepared.append(Step(name=step.name, description=step.description, agent=step))
|
|
80
|
+
elif isinstance(step, Team):
|
|
81
|
+
prepared.append(Step(name=step.name, description=step.description, team=step))
|
|
82
|
+
elif isinstance(step, (Step, Steps, Loop, Parallel, Condition, Router)):
|
|
83
|
+
prepared.append(step)
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError(f"Invalid step type: {type(step).__name__}")
|
|
86
|
+
return prepared
|
|
87
|
+
|
|
88
|
+
self.steps = prepare_step_list(self.steps)
|
|
72
89
|
|
|
73
|
-
|
|
90
|
+
# Also prepare else_steps if provided and not empty
|
|
91
|
+
if self.else_steps and len(self.else_steps) > 0:
|
|
92
|
+
self.else_steps = prepare_step_list(self.else_steps)
|
|
74
93
|
|
|
75
94
|
def _update_step_input_from_outputs(
|
|
76
95
|
self,
|
|
@@ -169,6 +188,10 @@ class Condition:
|
|
|
169
188
|
except Exception:
|
|
170
189
|
return False
|
|
171
190
|
|
|
191
|
+
def _has_else_steps(self) -> bool:
|
|
192
|
+
"""Check if else_steps is provided and not empty."""
|
|
193
|
+
return self.else_steps is not None and len(self.else_steps) > 0
|
|
194
|
+
|
|
172
195
|
def execute(
|
|
173
196
|
self,
|
|
174
197
|
step_input: StepInput,
|
|
@@ -183,7 +206,12 @@ class Condition:
|
|
|
183
206
|
num_history_runs: int = 3,
|
|
184
207
|
background_tasks: Optional[Any] = None,
|
|
185
208
|
) -> StepOutput:
|
|
186
|
-
"""Execute the condition and its steps with sequential chaining
|
|
209
|
+
"""Execute the condition and its steps with sequential chaining.
|
|
210
|
+
|
|
211
|
+
If condition is True, executes `steps`.
|
|
212
|
+
If condition is False and `else_steps` is provided (and not empty), executes `else_steps`.
|
|
213
|
+
If condition is False and no `else_steps`, returns a "not met" message.
|
|
214
|
+
"""
|
|
187
215
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
188
216
|
|
|
189
217
|
conditional_step_id = str(uuid4())
|
|
@@ -198,7 +226,17 @@ class Condition:
|
|
|
198
226
|
|
|
199
227
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
200
228
|
|
|
201
|
-
|
|
229
|
+
# Determine which steps to execute
|
|
230
|
+
if condition_result:
|
|
231
|
+
steps_to_execute = self.steps
|
|
232
|
+
branch = CONDITION_BRANCH_IF
|
|
233
|
+
log_debug(f"Condition {self.name} met, executing {len(steps_to_execute)} steps (if branch)")
|
|
234
|
+
elif self._has_else_steps():
|
|
235
|
+
steps_to_execute = self.else_steps # type: ignore[assignment]
|
|
236
|
+
branch = CONDITION_BRANCH_ELSE
|
|
237
|
+
log_debug(f"Condition {self.name} not met, executing {len(steps_to_execute)} else_steps (else branch)")
|
|
238
|
+
else:
|
|
239
|
+
# No else_steps provided, return "not met" message
|
|
202
240
|
log_debug(f"Condition {self.name} not met, skipping {len(self.steps)} steps")
|
|
203
241
|
return StepOutput(
|
|
204
242
|
step_name=self.name,
|
|
@@ -208,12 +246,11 @@ class Condition:
|
|
|
208
246
|
success=True,
|
|
209
247
|
)
|
|
210
248
|
|
|
211
|
-
log_debug(f"Condition {self.name} met, executing {len(self.steps)} steps")
|
|
212
249
|
all_results: List[StepOutput] = []
|
|
213
250
|
current_step_input = step_input
|
|
214
|
-
condition_step_outputs = {}
|
|
251
|
+
condition_step_outputs: Dict[str, StepOutput] = {}
|
|
215
252
|
|
|
216
|
-
for i, step in enumerate(
|
|
253
|
+
for i, step in enumerate(steps_to_execute):
|
|
217
254
|
try:
|
|
218
255
|
step_output = step.execute( # type: ignore[union-attr]
|
|
219
256
|
current_step_input,
|
|
@@ -234,7 +271,7 @@ class Condition:
|
|
|
234
271
|
all_results.extend(step_output)
|
|
235
272
|
if step_output:
|
|
236
273
|
step_name = getattr(step, "name", f"step_{i}")
|
|
237
|
-
log_debug(f"Executing condition step {i + 1}/{len(
|
|
274
|
+
log_debug(f"Executing condition step {i + 1}/{len(steps_to_execute)}: {step_name}")
|
|
238
275
|
|
|
239
276
|
condition_step_outputs[step_name] = step_output[-1]
|
|
240
277
|
|
|
@@ -269,13 +306,13 @@ class Condition:
|
|
|
269
306
|
all_results.append(error_output)
|
|
270
307
|
break
|
|
271
308
|
|
|
272
|
-
log_debug(f"Condition End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
309
|
+
log_debug(f"Condition End: {self.name} ({len(all_results)} results, {branch} branch)", center=True, symbol="-")
|
|
273
310
|
|
|
274
311
|
return StepOutput(
|
|
275
312
|
step_name=self.name,
|
|
276
313
|
step_id=conditional_step_id,
|
|
277
314
|
step_type=StepType.CONDITION,
|
|
278
|
-
content=f"Condition {self.name} completed with {len(all_results)} results",
|
|
315
|
+
content=f"Condition {self.name} completed with {len(all_results)} results ({branch} branch)",
|
|
279
316
|
success=all(result.success for result in all_results) if all_results else True,
|
|
280
317
|
error=None,
|
|
281
318
|
stop=any(result.stop for result in all_results) if all_results else False,
|
|
@@ -300,7 +337,12 @@ class Condition:
|
|
|
300
337
|
num_history_runs: int = 3,
|
|
301
338
|
background_tasks: Optional[Any] = None,
|
|
302
339
|
) -> Iterator[Union[WorkflowRunOutputEvent, StepOutput]]:
|
|
303
|
-
"""Execute the condition with streaming support
|
|
340
|
+
"""Execute the condition with streaming support.
|
|
341
|
+
|
|
342
|
+
If condition is True, executes `steps`.
|
|
343
|
+
If condition is False and `else_steps` is provided (and not empty), executes `else_steps`.
|
|
344
|
+
If condition is False and no `else_steps`, yields completed event and returns.
|
|
345
|
+
"""
|
|
304
346
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
305
347
|
|
|
306
348
|
conditional_step_id = str(uuid4())
|
|
@@ -328,9 +370,18 @@ class Condition:
|
|
|
328
370
|
parent_step_id=parent_step_id,
|
|
329
371
|
)
|
|
330
372
|
|
|
331
|
-
|
|
373
|
+
# Determine which steps to execute
|
|
374
|
+
if condition_result:
|
|
375
|
+
steps_to_execute = self.steps
|
|
376
|
+
branch = CONDITION_BRANCH_IF
|
|
377
|
+
log_debug(f"Condition {self.name} met, executing {len(steps_to_execute)} steps (if branch)")
|
|
378
|
+
elif self._has_else_steps():
|
|
379
|
+
steps_to_execute = self.else_steps # type: ignore[assignment]
|
|
380
|
+
branch = CONDITION_BRANCH_ELSE
|
|
381
|
+
log_debug(f"Condition {self.name} not met, executing {len(steps_to_execute)} else_steps (else branch)")
|
|
382
|
+
else:
|
|
383
|
+
# No else_steps provided, yield completed event and return
|
|
332
384
|
if stream_events and workflow_run_response:
|
|
333
|
-
# Yield condition completed event for empty case
|
|
334
385
|
yield ConditionExecutionCompletedEvent(
|
|
335
386
|
run_id=workflow_run_response.run_id or "",
|
|
336
387
|
workflow_name=workflow_run_response.workflow_name or "",
|
|
@@ -340,20 +391,20 @@ class Condition:
|
|
|
340
391
|
step_index=step_index,
|
|
341
392
|
condition_result=False,
|
|
342
393
|
executed_steps=0,
|
|
394
|
+
branch=None,
|
|
343
395
|
step_results=[],
|
|
344
396
|
step_id=conditional_step_id,
|
|
345
397
|
parent_step_id=parent_step_id,
|
|
346
398
|
)
|
|
347
399
|
return
|
|
348
400
|
|
|
349
|
-
|
|
350
|
-
all_results = []
|
|
401
|
+
all_results: List[StepOutput] = []
|
|
351
402
|
current_step_input = step_input
|
|
352
|
-
condition_step_outputs = {}
|
|
403
|
+
condition_step_outputs: Dict[str, StepOutput] = {}
|
|
353
404
|
|
|
354
|
-
for i, step in enumerate(
|
|
405
|
+
for i, step in enumerate(steps_to_execute):
|
|
355
406
|
try:
|
|
356
|
-
step_outputs_for_step = []
|
|
407
|
+
step_outputs_for_step: List[StepOutput] = []
|
|
357
408
|
|
|
358
409
|
# Create child index for each step within condition
|
|
359
410
|
if step_index is None or isinstance(step_index, int):
|
|
@@ -426,7 +477,7 @@ class Condition:
|
|
|
426
477
|
all_results.append(error_output)
|
|
427
478
|
break
|
|
428
479
|
|
|
429
|
-
log_debug(f"Condition End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
480
|
+
log_debug(f"Condition End: {self.name} ({len(all_results)} results, {branch} branch)", center=True, symbol="-")
|
|
430
481
|
if stream_events and workflow_run_response:
|
|
431
482
|
# Yield condition completed event
|
|
432
483
|
yield ConditionExecutionCompletedEvent(
|
|
@@ -436,8 +487,9 @@ class Condition:
|
|
|
436
487
|
session_id=workflow_run_response.session_id or "",
|
|
437
488
|
step_name=self.name,
|
|
438
489
|
step_index=step_index,
|
|
439
|
-
condition_result=
|
|
440
|
-
executed_steps=len(
|
|
490
|
+
condition_result=condition_result,
|
|
491
|
+
executed_steps=len(steps_to_execute),
|
|
492
|
+
branch=branch,
|
|
441
493
|
step_results=all_results,
|
|
442
494
|
step_id=conditional_step_id,
|
|
443
495
|
parent_step_id=parent_step_id,
|
|
@@ -447,7 +499,7 @@ class Condition:
|
|
|
447
499
|
step_name=self.name,
|
|
448
500
|
step_id=conditional_step_id,
|
|
449
501
|
step_type=StepType.CONDITION,
|
|
450
|
-
content=f"Condition {self.name} completed with {len(all_results)} results",
|
|
502
|
+
content=f"Condition {self.name} completed with {len(all_results)} results ({branch} branch)",
|
|
451
503
|
success=all(result.success for result in all_results) if all_results else True,
|
|
452
504
|
stop=any(result.stop for result in all_results) if all_results else False,
|
|
453
505
|
steps=all_results,
|
|
@@ -467,7 +519,12 @@ class Condition:
|
|
|
467
519
|
num_history_runs: int = 3,
|
|
468
520
|
background_tasks: Optional[Any] = None,
|
|
469
521
|
) -> StepOutput:
|
|
470
|
-
"""Async execute the condition and its steps with sequential chaining
|
|
522
|
+
"""Async execute the condition and its steps with sequential chaining.
|
|
523
|
+
|
|
524
|
+
If condition is True, executes `steps`.
|
|
525
|
+
If condition is False and `else_steps` is provided (and not empty), executes `else_steps`.
|
|
526
|
+
If condition is False and no `else_steps`, returns a "not met" message.
|
|
527
|
+
"""
|
|
471
528
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
472
529
|
|
|
473
530
|
conditional_step_id = str(uuid4())
|
|
@@ -481,24 +538,32 @@ class Condition:
|
|
|
481
538
|
condition_result = await self._aevaluate_condition(step_input, session_state=session_state)
|
|
482
539
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
483
540
|
|
|
484
|
-
|
|
541
|
+
# Determine which steps to execute
|
|
542
|
+
if condition_result:
|
|
543
|
+
steps_to_execute = self.steps
|
|
544
|
+
branch = CONDITION_BRANCH_IF
|
|
545
|
+
log_debug(f"Condition {self.name} met, executing {len(steps_to_execute)} steps (if branch)")
|
|
546
|
+
elif self._has_else_steps():
|
|
547
|
+
steps_to_execute = self.else_steps # type: ignore[assignment]
|
|
548
|
+
branch = CONDITION_BRANCH_ELSE
|
|
549
|
+
log_debug(f"Condition {self.name} not met, executing {len(steps_to_execute)} else_steps (else branch)")
|
|
550
|
+
else:
|
|
551
|
+
# No else_steps provided, return "not met" message
|
|
485
552
|
log_debug(f"Condition {self.name} not met, skipping {len(self.steps)} steps")
|
|
486
553
|
return StepOutput(
|
|
487
554
|
step_name=self.name,
|
|
488
|
-
step_id=
|
|
555
|
+
step_id=conditional_step_id,
|
|
489
556
|
step_type=StepType.CONDITION,
|
|
490
557
|
content=f"Condition {self.name} not met - skipped {len(self.steps)} steps",
|
|
491
558
|
success=True,
|
|
492
559
|
)
|
|
493
560
|
|
|
494
|
-
log_debug(f"Condition {self.name} met, executing {len(self.steps)} steps")
|
|
495
|
-
|
|
496
561
|
# Chain steps sequentially like Loop does
|
|
497
562
|
all_results: List[StepOutput] = []
|
|
498
563
|
current_step_input = step_input
|
|
499
|
-
condition_step_outputs = {}
|
|
564
|
+
condition_step_outputs: Dict[str, StepOutput] = {}
|
|
500
565
|
|
|
501
|
-
for i, step in enumerate(
|
|
566
|
+
for i, step in enumerate(steps_to_execute):
|
|
502
567
|
try:
|
|
503
568
|
step_output = await step.aexecute( # type: ignore[union-attr]
|
|
504
569
|
current_step_input,
|
|
@@ -552,13 +617,13 @@ class Condition:
|
|
|
552
617
|
all_results.append(error_output)
|
|
553
618
|
break
|
|
554
619
|
|
|
555
|
-
log_debug(f"Condition End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
620
|
+
log_debug(f"Condition End: {self.name} ({len(all_results)} results, {branch} branch)", center=True, symbol="-")
|
|
556
621
|
|
|
557
622
|
return StepOutput(
|
|
558
623
|
step_name=self.name,
|
|
559
624
|
step_id=conditional_step_id,
|
|
560
625
|
step_type=StepType.CONDITION,
|
|
561
|
-
content=f"Condition {self.name} completed with {len(all_results)} results",
|
|
626
|
+
content=f"Condition {self.name} completed with {len(all_results)} results ({branch} branch)",
|
|
562
627
|
success=all(result.success for result in all_results) if all_results else True,
|
|
563
628
|
error=None,
|
|
564
629
|
stop=any(result.stop for result in all_results) if all_results else False,
|
|
@@ -583,7 +648,12 @@ class Condition:
|
|
|
583
648
|
num_history_runs: int = 3,
|
|
584
649
|
background_tasks: Optional[Any] = None,
|
|
585
650
|
) -> AsyncIterator[Union[WorkflowRunOutputEvent, TeamRunOutputEvent, RunOutputEvent, StepOutput]]:
|
|
586
|
-
"""Async execute the condition with streaming support
|
|
651
|
+
"""Async execute the condition with streaming support.
|
|
652
|
+
|
|
653
|
+
If condition is True, executes `steps`.
|
|
654
|
+
If condition is False and `else_steps` is provided (and not empty), executes `else_steps`.
|
|
655
|
+
If condition is False and no `else_steps`, yields completed event and returns.
|
|
656
|
+
"""
|
|
587
657
|
log_debug(f"Condition Start: {self.name}", center=True, symbol="-")
|
|
588
658
|
|
|
589
659
|
conditional_step_id = str(uuid4())
|
|
@@ -611,9 +681,18 @@ class Condition:
|
|
|
611
681
|
parent_step_id=parent_step_id,
|
|
612
682
|
)
|
|
613
683
|
|
|
614
|
-
|
|
684
|
+
# Determine which steps to execute
|
|
685
|
+
if condition_result:
|
|
686
|
+
steps_to_execute = self.steps
|
|
687
|
+
branch = CONDITION_BRANCH_IF
|
|
688
|
+
log_debug(f"Condition {self.name} met, executing {len(steps_to_execute)} steps (if branch)")
|
|
689
|
+
elif self._has_else_steps():
|
|
690
|
+
steps_to_execute = self.else_steps # type: ignore[assignment]
|
|
691
|
+
branch = CONDITION_BRANCH_ELSE
|
|
692
|
+
log_debug(f"Condition {self.name} not met, executing {len(steps_to_execute)} else_steps (else branch)")
|
|
693
|
+
else:
|
|
694
|
+
# No else_steps provided, yield completed event and return
|
|
615
695
|
if stream_events and workflow_run_response:
|
|
616
|
-
# Yield condition completed event for empty case
|
|
617
696
|
yield ConditionExecutionCompletedEvent(
|
|
618
697
|
run_id=workflow_run_response.run_id or "",
|
|
619
698
|
workflow_name=workflow_run_response.workflow_name or "",
|
|
@@ -623,22 +702,21 @@ class Condition:
|
|
|
623
702
|
step_index=step_index,
|
|
624
703
|
condition_result=False,
|
|
625
704
|
executed_steps=0,
|
|
705
|
+
branch=None,
|
|
626
706
|
step_results=[],
|
|
627
707
|
step_id=conditional_step_id,
|
|
628
708
|
parent_step_id=parent_step_id,
|
|
629
709
|
)
|
|
630
710
|
return
|
|
631
711
|
|
|
632
|
-
log_debug(f"Condition {self.name} met, executing {len(self.steps)} steps")
|
|
633
|
-
|
|
634
712
|
# Chain steps sequentially like Loop does
|
|
635
|
-
all_results = []
|
|
713
|
+
all_results: List[StepOutput] = []
|
|
636
714
|
current_step_input = step_input
|
|
637
|
-
condition_step_outputs = {}
|
|
715
|
+
condition_step_outputs: Dict[str, StepOutput] = {}
|
|
638
716
|
|
|
639
|
-
for i, step in enumerate(
|
|
717
|
+
for i, step in enumerate(steps_to_execute):
|
|
640
718
|
try:
|
|
641
|
-
step_outputs_for_step = []
|
|
719
|
+
step_outputs_for_step: List[StepOutput] = []
|
|
642
720
|
|
|
643
721
|
# Create child index for each step within condition
|
|
644
722
|
if step_index is None or isinstance(step_index, int):
|
|
@@ -711,7 +789,7 @@ class Condition:
|
|
|
711
789
|
all_results.append(error_output)
|
|
712
790
|
break
|
|
713
791
|
|
|
714
|
-
log_debug(f"Condition End: {self.name} ({len(all_results)} results)", center=True, symbol="-")
|
|
792
|
+
log_debug(f"Condition End: {self.name} ({len(all_results)} results, {branch} branch)", center=True, symbol="-")
|
|
715
793
|
|
|
716
794
|
if stream_events and workflow_run_response:
|
|
717
795
|
# Yield condition completed event
|
|
@@ -722,8 +800,9 @@ class Condition:
|
|
|
722
800
|
session_id=workflow_run_response.session_id or "",
|
|
723
801
|
step_name=self.name,
|
|
724
802
|
step_index=step_index,
|
|
725
|
-
condition_result=
|
|
726
|
-
executed_steps=len(
|
|
803
|
+
condition_result=condition_result,
|
|
804
|
+
executed_steps=len(steps_to_execute),
|
|
805
|
+
branch=branch,
|
|
727
806
|
step_results=all_results,
|
|
728
807
|
step_id=conditional_step_id,
|
|
729
808
|
parent_step_id=parent_step_id,
|
|
@@ -733,7 +812,7 @@ class Condition:
|
|
|
733
812
|
step_name=self.name,
|
|
734
813
|
step_id=conditional_step_id,
|
|
735
814
|
step_type=StepType.CONDITION,
|
|
736
|
-
content=f"Condition {self.name} completed with {len(all_results)} results",
|
|
815
|
+
content=f"Condition {self.name} completed with {len(all_results)} results ({branch} branch)",
|
|
737
816
|
success=all(result.success for result in all_results) if all_results else True,
|
|
738
817
|
stop=any(result.stop for result in all_results) if all_results else False,
|
|
739
818
|
steps=all_results,
|