agno 2.1.10__py3-none-any.whl → 2.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. agno/agent/agent.py +1594 -1248
  2. agno/knowledge/knowledge.py +11 -0
  3. agno/knowledge/reader/pptx_reader.py +101 -0
  4. agno/knowledge/reader/reader_factory.py +14 -0
  5. agno/knowledge/types.py +1 -0
  6. agno/models/anthropic/claude.py +2 -2
  7. agno/models/base.py +4 -4
  8. agno/models/ollama/chat.py +7 -2
  9. agno/os/app.py +1 -1
  10. agno/os/interfaces/a2a/router.py +2 -2
  11. agno/os/interfaces/agui/router.py +2 -2
  12. agno/os/router.py +7 -7
  13. agno/os/routers/evals/schemas.py +31 -31
  14. agno/os/routers/health.py +6 -2
  15. agno/os/routers/knowledge/schemas.py +49 -47
  16. agno/os/routers/memory/schemas.py +16 -16
  17. agno/os/routers/metrics/schemas.py +16 -16
  18. agno/os/routers/session/session.py +382 -7
  19. agno/os/schema.py +254 -231
  20. agno/os/utils.py +1 -1
  21. agno/run/agent.py +54 -1
  22. agno/run/team.py +48 -0
  23. agno/run/workflow.py +15 -5
  24. agno/session/summary.py +45 -13
  25. agno/session/team.py +90 -5
  26. agno/team/team.py +1130 -849
  27. agno/utils/agent.py +372 -0
  28. agno/utils/events.py +144 -2
  29. agno/utils/message.py +60 -0
  30. agno/utils/print_response/agent.py +10 -6
  31. agno/utils/print_response/team.py +6 -4
  32. agno/utils/print_response/workflow.py +7 -5
  33. agno/utils/team.py +9 -8
  34. agno/workflow/condition.py +17 -9
  35. agno/workflow/loop.py +18 -10
  36. agno/workflow/parallel.py +14 -6
  37. agno/workflow/router.py +16 -8
  38. agno/workflow/step.py +14 -6
  39. agno/workflow/steps.py +14 -6
  40. agno/workflow/workflow.py +331 -123
  41. {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/METADATA +63 -23
  42. {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/RECORD +45 -43
  43. {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/WHEEL +0 -0
  44. {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/licenses/LICENSE +0 -0
  45. {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/top_level.txt +0 -0
agno/workflow/workflow.py CHANGED
@@ -29,7 +29,7 @@ from agno.exceptions import InputCheckError, OutputCheckError, RunCancelledExcep
29
29
  from agno.media import Audio, File, Image, Video
30
30
  from agno.models.message import Message
31
31
  from agno.models.metrics import Metrics
32
- from agno.run.agent import RunEvent
32
+ from agno.run.agent import RunContentEvent, RunEvent
33
33
  from agno.run.base import RunStatus
34
34
  from agno.run.cancel import (
35
35
  cancel_run as cancel_run_global,
@@ -39,6 +39,7 @@ from agno.run.cancel import (
39
39
  raise_if_cancelled,
40
40
  register_run,
41
41
  )
42
+ from agno.run.team import RunContentEvent as TeamRunContentEvent
42
43
  from agno.run.team import TeamRunEvent
43
44
  from agno.run.workflow import (
44
45
  StepOutputEvent,
@@ -147,6 +148,8 @@ class Workflow:
147
148
  # Stream the response from the Workflow
148
149
  stream: Optional[bool] = None
149
150
  # Stream the intermediate steps from the Workflow
151
+ stream_events: bool = False
152
+ # [Deprecated] Stream the intermediate steps from the Workflow
150
153
  stream_intermediate_steps: bool = False
151
154
  # Stream events from executors (agents/teams/functions) within steps
152
155
  stream_executor_events: bool = True
@@ -190,6 +193,7 @@ class Workflow:
190
193
  user_id: Optional[str] = None,
191
194
  debug_mode: Optional[bool] = False,
192
195
  stream: Optional[bool] = None,
196
+ stream_events: bool = False,
193
197
  stream_intermediate_steps: bool = False,
194
198
  stream_executor_events: bool = True,
195
199
  store_events: bool = False,
@@ -214,6 +218,7 @@ class Workflow:
214
218
  self.store_events = store_events
215
219
  self.events_to_skip = events_to_skip or []
216
220
  self.stream = stream
221
+ self.stream_events = stream_events
217
222
  self.stream_intermediate_steps = stream_intermediate_steps
218
223
  self.stream_executor_events = stream_executor_events
219
224
  self.store_executor_outputs = store_executor_outputs
@@ -344,10 +349,8 @@ class Workflow:
344
349
  self,
345
350
  session_id: Optional[str] = None,
346
351
  user_id: Optional[str] = None,
347
- session_state: Optional[Dict[str, Any]] = None,
348
- run_id: Optional[str] = None,
349
- ) -> Tuple[str, Optional[str], Dict[str, Any]]:
350
- """Initialize the session for the agent."""
352
+ ) -> Tuple[str, Optional[str]]:
353
+ """Initialize the session for the workflow."""
351
354
 
352
355
  if session_id is None:
353
356
  if self.session_id:
@@ -360,27 +363,25 @@ class Workflow:
360
363
  log_debug(f"Session ID: {session_id}", center=True)
361
364
 
362
365
  # Use the default user_id when necessary
363
- if user_id is None:
366
+ if user_id is None or user_id == "":
364
367
  user_id = self.user_id
365
368
 
366
- # Determine the session_state with proper precedence
367
- if session_state is None:
368
- session_state = self.session_state or {}
369
- else:
370
- # If run session_state is provided, merge agent defaults under it
371
- # This ensures run state takes precedence over agent defaults
372
- if self.session_state:
373
- from agno.utils.merge_dict import merge_dictionaries
374
-
375
- base_state = self.session_state.copy()
376
- merge_dictionaries(base_state, session_state)
377
- session_state.clear()
378
- session_state.update(base_state)
369
+ return session_id, user_id
379
370
 
380
- if user_id is not None:
371
+ def _initialize_session_state(
372
+ self,
373
+ session_state: Dict[str, Any],
374
+ user_id: Optional[str] = None,
375
+ session_id: Optional[str] = None,
376
+ run_id: Optional[str] = None,
377
+ ) -> Dict[str, Any]:
378
+ """Initialize the session state for the workflow."""
379
+ if user_id:
381
380
  session_state["current_user_id"] = user_id
382
381
  if session_id is not None:
383
382
  session_state["current_session_id"] = session_id
383
+ if run_id is not None:
384
+ session_state["current_run_id"] = run_id
384
385
 
385
386
  session_state.update(
386
387
  {
@@ -392,7 +393,7 @@ class Workflow:
392
393
  if self.name:
393
394
  session_state["workflow_name"] = self.name
394
395
 
395
- return session_id, user_id, session_state # type: ignore
396
+ return session_state
396
397
 
397
398
  def _generate_workflow_session_name(self) -> str:
398
399
  """Generate a name for the workflow session"""
@@ -502,6 +503,62 @@ class Workflow:
502
503
  raise Exception("Session not found")
503
504
  return session.session_data.get("session_state", {}) if session.session_data else {}
504
505
 
506
+ def update_session_state(
507
+ self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None
508
+ ) -> Dict[str, Any]:
509
+ """
510
+ Update the session state for the given session ID.
511
+ Args:
512
+ session_state_updates: The updates to apply to the session state. Should be a dictionary of key-value pairs.
513
+ session_id: The session ID to update. If not provided, the current cached session ID is used.
514
+ Returns:
515
+ dict: The updated session state.
516
+ """
517
+ session_id = session_id or self.session_id
518
+ if session_id is None:
519
+ raise Exception("Session ID is not set")
520
+ session = self.get_session(session_id=session_id) # type: ignore
521
+ if session is None:
522
+ raise Exception("Session not found")
523
+
524
+ if session.session_data is not None and "session_state" not in session.session_data:
525
+ session.session_data["session_state"] = {}
526
+
527
+ for key, value in session_state_updates.items():
528
+ session.session_data["session_state"][key] = value # type: ignore
529
+
530
+ self.save_session(session=session)
531
+
532
+ return session.session_data["session_state"] # type: ignore
533
+
534
+ async def aupdate_session_state(
535
+ self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None
536
+ ) -> Dict[str, Any]:
537
+ """
538
+ Update the session state for the given session ID (async).
539
+ Args:
540
+ session_state_updates: The updates to apply to the session state. Should be a dictionary of key-value pairs.
541
+ session_id: The session ID to update. If not provided, the current cached session ID is used.
542
+ Returns:
543
+ dict: The updated session state.
544
+ """
545
+ session_id = session_id or self.session_id
546
+ if session_id is None:
547
+ raise Exception("Session ID is not set")
548
+ session = await self.aget_session(session_id=session_id) # type: ignore
549
+ if session is None:
550
+ raise Exception("Session not found")
551
+
552
+ if session.session_data is not None and "session_state" not in session.session_data:
553
+ session.session_data["session_state"] = {} # type: ignore
554
+
555
+ for key, value in session_state_updates.items():
556
+ session.session_data["session_state"][key] = value # type: ignore
557
+
558
+ await self.asave_session(session=session)
559
+
560
+ return session.session_data["session_state"] # type: ignore
561
+
505
562
  async def adelete_session(self, session_id: str):
506
563
  """Delete the current session and save to storage"""
507
564
  if self.db is None:
@@ -615,12 +672,17 @@ class Workflow:
615
672
  if workflow_session is None:
616
673
  # Creating new session if none found
617
674
  log_debug(f"Creating new WorkflowSession: {session_id}")
675
+ session_data = {}
676
+ if self.session_state is not None:
677
+ from copy import deepcopy
678
+
679
+ session_data["session_state"] = deepcopy(self.session_state)
618
680
  workflow_session = WorkflowSession(
619
681
  session_id=session_id,
620
682
  workflow_id=self.id,
621
683
  user_id=user_id,
622
684
  workflow_data=self._get_workflow_data(),
623
- session_data={},
685
+ session_data=session_data,
624
686
  metadata=self.metadata,
625
687
  created_at=int(time()),
626
688
  )
@@ -859,7 +921,7 @@ class Workflow:
859
921
  else:
860
922
  step_type = STEP_TYPE_MAPPING[type(step)]
861
923
  step_dict = {
862
- "name": step.name if hasattr(step, "name") else step.__name__,
924
+ "name": step.name if hasattr(step, "name") else step.__name__, # type: ignore
863
925
  "description": step.description if hasattr(step, "description") else "User-defined callable step",
864
926
  "type": step_type.value,
865
927
  }
@@ -1116,6 +1178,15 @@ class Workflow:
1116
1178
  logger.error(f"Function signature inspection failed: {e}. Falling back to original calling convention.")
1117
1179
  return func(**kwargs)
1118
1180
 
1181
+ def _accumulate_partial_step_data(
1182
+ self, event: Union[RunContentEvent, TeamRunContentEvent], partial_step_content: str
1183
+ ) -> str:
1184
+ """Accumulate partial step data from streaming events"""
1185
+ if isinstance(event, (RunContentEvent, TeamRunContentEvent)) and event.content:
1186
+ if isinstance(event.content, str):
1187
+ partial_step_content += event.content
1188
+ return partial_step_content
1189
+
1119
1190
  def _execute(
1120
1191
  self,
1121
1192
  session: WorkflowSession,
@@ -1283,7 +1354,7 @@ class Workflow:
1283
1354
  execution_input: WorkflowExecutionInput,
1284
1355
  workflow_run_response: WorkflowRunOutput,
1285
1356
  session_state: Optional[Dict[str, Any]] = None,
1286
- stream_intermediate_steps: bool = False,
1357
+ stream_events: bool = False,
1287
1358
  **kwargs: Any,
1288
1359
  ) -> Iterator[WorkflowRunOutputEvent]:
1289
1360
  """Execute a specific pipeline by name with event streaming"""
@@ -1339,11 +1410,22 @@ class Workflow:
1339
1410
 
1340
1411
  early_termination = False
1341
1412
 
1413
+ # Track partial step data in case of cancellation
1414
+ current_step_name = ""
1415
+ current_step = None
1416
+ partial_step_content = ""
1417
+
1342
1418
  for i, step in enumerate(self.steps): # type: ignore[arg-type]
1343
1419
  raise_if_cancelled(workflow_run_response.run_id) # type: ignore
1344
1420
  step_name = getattr(step, "name", f"step_{i + 1}")
1345
1421
  log_debug(f"Streaming step {i + 1}/{self._get_step_count()}: {step_name}")
1346
1422
 
1423
+ # Track current step for cancellation handler
1424
+ current_step_name = step_name
1425
+ current_step = step
1426
+ # Reset partial data for this step
1427
+ partial_step_content = ""
1428
+
1347
1429
  # Create enhanced StepInput
1348
1430
  step_input = self._create_step_input(
1349
1431
  execution_input=execution_input,
@@ -1359,7 +1441,7 @@ class Workflow:
1359
1441
  step_input,
1360
1442
  session_id=session.session_id,
1361
1443
  user_id=self.user_id,
1362
- stream_intermediate_steps=stream_intermediate_steps,
1444
+ stream_events=stream_events,
1363
1445
  stream_executor_events=self.stream_executor_events,
1364
1446
  workflow_run_response=workflow_run_response,
1365
1447
  session_state=session_state,
@@ -1372,6 +1454,10 @@ class Workflow:
1372
1454
  num_history_runs=self.num_history_runs,
1373
1455
  ):
1374
1456
  raise_if_cancelled(workflow_run_response.run_id) # type: ignore
1457
+
1458
+ # Accumulate partial data from streaming events
1459
+ partial_step_content = self._accumulate_partial_step_data(event, partial_step_content) # type: ignore
1460
+
1375
1461
  # Handle events
1376
1462
  if isinstance(event, StepOutput):
1377
1463
  step_output = event
@@ -1486,6 +1572,29 @@ class Workflow:
1486
1572
  logger.info(f"Workflow run {workflow_run_response.run_id} was cancelled during streaming")
1487
1573
  workflow_run_response.status = RunStatus.cancelled
1488
1574
  workflow_run_response.content = str(e)
1575
+
1576
+ # Capture partial progress from the step that was cancelled mid-stream
1577
+ if partial_step_content:
1578
+ logger.info(
1579
+ f"Step with name '{current_step_name}' was cancelled. Setting its partial progress as step output."
1580
+ )
1581
+ partial_step_output = StepOutput(
1582
+ step_name=current_step_name,
1583
+ step_id=getattr(current_step, "step_id", None) if current_step else None,
1584
+ step_type=StepType.STEP,
1585
+ executor_type=getattr(current_step, "executor_type", None) if current_step else None,
1586
+ executor_name=getattr(current_step, "executor_name", None) if current_step else None,
1587
+ content=partial_step_content,
1588
+ success=False,
1589
+ error="Cancelled during execution",
1590
+ )
1591
+ collected_step_outputs.append(partial_step_output)
1592
+
1593
+ # Preserve all progress (completed steps + partial step) before cancellation
1594
+ if collected_step_outputs:
1595
+ workflow_run_response.step_results = collected_step_outputs
1596
+ workflow_run_response.metrics = self._aggregate_workflow_metrics(collected_step_outputs)
1597
+
1489
1598
  cancelled_event = WorkflowCancelledEvent(
1490
1599
  run_id=workflow_run_response.run_id or "",
1491
1600
  workflow_id=self.id,
@@ -1588,9 +1697,31 @@ class Workflow:
1588
1697
  # For regular async functions, use the same signature inspection logic in fallback
1589
1698
  return await func(**call_kwargs) # type: ignore
1590
1699
 
1700
+ async def _aload_or_create_session(
1701
+ self, session_id: str, user_id: Optional[str], session_state: Optional[Dict[str, Any]]
1702
+ ) -> Tuple[WorkflowSession, Dict[str, Any]]:
1703
+ """Load or create session from database, update metadata, and prepare session state.
1704
+
1705
+ Returns:
1706
+ Tuple of (workflow_session, prepared_session_state)
1707
+ """
1708
+ # Read existing session from database
1709
+ if self._has_async_db():
1710
+ workflow_session = await self.aread_or_create_session(session_id=session_id, user_id=user_id)
1711
+ else:
1712
+ workflow_session = self.read_or_create_session(session_id=session_id, user_id=user_id)
1713
+ self._update_metadata(session=workflow_session)
1714
+
1715
+ # Update session state from DB
1716
+ _session_state = session_state or {}
1717
+ _session_state = self._load_session_state(session=workflow_session, session_state=_session_state)
1718
+
1719
+ return workflow_session, _session_state
1720
+
1591
1721
  async def _aexecute(
1592
1722
  self,
1593
- session: WorkflowSession,
1723
+ session_id: str,
1724
+ user_id: Optional[str],
1594
1725
  execution_input: WorkflowExecutionInput,
1595
1726
  workflow_run_response: WorkflowRunOutput,
1596
1727
  session_state: Optional[Dict[str, Any]] = None,
@@ -1599,6 +1730,11 @@ class Workflow:
1599
1730
  """Execute a specific pipeline by name asynchronously"""
1600
1731
  from inspect import isasyncgenfunction, iscoroutinefunction, isgeneratorfunction
1601
1732
 
1733
+ # Read existing session from database
1734
+ workflow_session, session_state = await self._aload_or_create_session(
1735
+ session_id=session_id, user_id=user_id, session_state=session_state
1736
+ )
1737
+
1602
1738
  workflow_run_response.status = RunStatus.running
1603
1739
 
1604
1740
  # Register run for cancellation tracking
@@ -1667,12 +1803,12 @@ class Workflow:
1667
1803
 
1668
1804
  step_output = await step.aexecute( # type: ignore[union-attr]
1669
1805
  step_input,
1670
- session_id=session.session_id,
1806
+ session_id=session_id,
1671
1807
  user_id=self.user_id,
1672
1808
  workflow_run_response=workflow_run_response,
1673
1809
  session_state=session_state,
1674
1810
  store_executor_outputs=self.store_executor_outputs,
1675
- workflow_session=session,
1811
+ workflow_session=workflow_session,
1676
1812
  add_workflow_history_to_steps=self.add_workflow_history_to_steps
1677
1813
  if self.add_workflow_history_to_steps
1678
1814
  else None,
@@ -1742,34 +1878,40 @@ class Workflow:
1742
1878
  workflow_run_response.content = f"Workflow execution failed: {e}"
1743
1879
  raise e
1744
1880
 
1745
- self._update_session_metrics(session=session, workflow_run_response=workflow_run_response)
1746
- session.upsert_run(run=workflow_run_response)
1881
+ self._update_session_metrics(session=workflow_session, workflow_run_response=workflow_run_response)
1882
+ workflow_session.upsert_run(run=workflow_run_response)
1747
1883
  if self._has_async_db():
1748
- await self.asave_session(session=session)
1884
+ await self.asave_session(session=workflow_session)
1749
1885
  else:
1750
- self.save_session(session=session)
1886
+ self.save_session(session=workflow_session)
1751
1887
  # Always clean up the run tracking
1752
1888
  cleanup_run(workflow_run_response.run_id) # type: ignore
1753
1889
 
1754
1890
  # Log Workflow Telemetry
1755
1891
  if self.telemetry:
1756
- await self._alog_workflow_telemetry(session_id=session.session_id, run_id=workflow_run_response.run_id)
1892
+ await self._alog_workflow_telemetry(session_id=session_id, run_id=workflow_run_response.run_id)
1757
1893
 
1758
1894
  return workflow_run_response
1759
1895
 
1760
1896
  async def _aexecute_stream(
1761
1897
  self,
1762
- session: WorkflowSession,
1898
+ session_id: str,
1899
+ user_id: Optional[str],
1763
1900
  execution_input: WorkflowExecutionInput,
1764
1901
  workflow_run_response: WorkflowRunOutput,
1765
1902
  session_state: Optional[Dict[str, Any]] = None,
1766
- stream_intermediate_steps: bool = False,
1903
+ stream_events: bool = False,
1767
1904
  websocket_handler: Optional[WebSocketHandler] = None,
1768
1905
  **kwargs: Any,
1769
1906
  ) -> AsyncIterator[WorkflowRunOutputEvent]:
1770
1907
  """Execute a specific pipeline by name with event streaming"""
1771
1908
  from inspect import isasyncgenfunction, iscoroutinefunction, isgeneratorfunction
1772
1909
 
1910
+ # Read existing session from database
1911
+ workflow_session, session_state = await self._aload_or_create_session(
1912
+ session_id=session_id, user_id=user_id, session_state=session_state
1913
+ )
1914
+
1773
1915
  workflow_run_response.status = RunStatus.running
1774
1916
 
1775
1917
  # Register run for cancellation tracking
@@ -1828,12 +1970,22 @@ class Workflow:
1828
1970
 
1829
1971
  early_termination = False
1830
1972
 
1973
+ # Track partial step data in case of cancellation
1974
+ current_step_name = ""
1975
+ current_step = None
1976
+ partial_step_content = ""
1977
+
1831
1978
  for i, step in enumerate(self.steps): # type: ignore[arg-type]
1832
1979
  if workflow_run_response.run_id:
1833
1980
  raise_if_cancelled(workflow_run_response.run_id)
1834
1981
  step_name = getattr(step, "name", f"step_{i + 1}")
1835
1982
  log_debug(f"Async streaming step {i + 1}/{self._get_step_count()}: {step_name}")
1836
1983
 
1984
+ current_step_name = step_name
1985
+ current_step = step
1986
+ # Reset partial data for this step
1987
+ partial_step_content = ""
1988
+
1837
1989
  # Create enhanced StepInput
1838
1990
  step_input = self._create_step_input(
1839
1991
  execution_input=execution_input,
@@ -1847,15 +1999,15 @@ class Workflow:
1847
1999
  # Execute step with streaming and yield all events
1848
2000
  async for event in step.aexecute_stream( # type: ignore[union-attr]
1849
2001
  step_input,
1850
- session_id=session.session_id,
2002
+ session_id=session_id,
1851
2003
  user_id=self.user_id,
1852
- stream_intermediate_steps=stream_intermediate_steps,
2004
+ stream_events=stream_events,
1853
2005
  stream_executor_events=self.stream_executor_events,
1854
2006
  workflow_run_response=workflow_run_response,
1855
2007
  session_state=session_state,
1856
2008
  step_index=i,
1857
2009
  store_executor_outputs=self.store_executor_outputs,
1858
- workflow_session=session,
2010
+ workflow_session=workflow_session,
1859
2011
  add_workflow_history_to_steps=self.add_workflow_history_to_steps
1860
2012
  if self.add_workflow_history_to_steps
1861
2013
  else None,
@@ -1863,6 +2015,10 @@ class Workflow:
1863
2015
  ):
1864
2016
  if workflow_run_response.run_id:
1865
2017
  raise_if_cancelled(workflow_run_response.run_id)
2018
+
2019
+ # Accumulate partial data from streaming events
2020
+ partial_step_content = self._accumulate_partial_step_data(event, partial_step_content) # type: ignore
2021
+
1866
2022
  if isinstance(event, StepOutput):
1867
2023
  step_output = event
1868
2024
  collected_step_outputs.append(step_output)
@@ -1965,7 +2121,7 @@ class Workflow:
1965
2121
  run_id=workflow_run_response.run_id or "",
1966
2122
  workflow_id=self.id,
1967
2123
  workflow_name=self.name,
1968
- session_id=session.session_id,
2124
+ session_id=session_id,
1969
2125
  error=str(e),
1970
2126
  )
1971
2127
 
@@ -1979,11 +2135,34 @@ class Workflow:
1979
2135
  logger.info(f"Workflow run {workflow_run_response.run_id} was cancelled during streaming")
1980
2136
  workflow_run_response.status = RunStatus.cancelled
1981
2137
  workflow_run_response.content = str(e)
2138
+
2139
+ # Capture partial progress from the step that was cancelled mid-stream
2140
+ if partial_step_content:
2141
+ logger.info(
2142
+ f"Step with name '{current_step_name}' was cancelled. Setting its partial progress as step output."
2143
+ )
2144
+ partial_step_output = StepOutput(
2145
+ step_name=current_step_name,
2146
+ step_id=getattr(current_step, "step_id", None) if current_step else None,
2147
+ step_type=StepType.STEP,
2148
+ executor_type=getattr(current_step, "executor_type", None) if current_step else None,
2149
+ executor_name=getattr(current_step, "executor_name", None) if current_step else None,
2150
+ content=partial_step_content,
2151
+ success=False,
2152
+ error="Cancelled during execution",
2153
+ )
2154
+ collected_step_outputs.append(partial_step_output)
2155
+
2156
+ # Preserve all progress (completed steps + partial step) before cancellation
2157
+ if collected_step_outputs:
2158
+ workflow_run_response.step_results = collected_step_outputs
2159
+ workflow_run_response.metrics = self._aggregate_workflow_metrics(collected_step_outputs)
2160
+
1982
2161
  cancelled_event = WorkflowCancelledEvent(
1983
2162
  run_id=workflow_run_response.run_id or "",
1984
2163
  workflow_id=self.id,
1985
2164
  workflow_name=self.name,
1986
- session_id=session.session_id,
2165
+ session_id=session_id,
1987
2166
  reason=str(e),
1988
2167
  )
1989
2168
  yield self._handle_event(
@@ -2000,7 +2179,7 @@ class Workflow:
2000
2179
  run_id=workflow_run_response.run_id or "",
2001
2180
  workflow_id=self.id,
2002
2181
  workflow_name=self.name,
2003
- session_id=session.session_id,
2182
+ session_id=session_id,
2004
2183
  error=str(e),
2005
2184
  )
2006
2185
 
@@ -2024,16 +2203,16 @@ class Workflow:
2024
2203
  yield self._handle_event(workflow_completed_event, workflow_run_response, websocket_handler=websocket_handler)
2025
2204
 
2026
2205
  # Store the completed workflow response
2027
- self._update_session_metrics(session=session, workflow_run_response=workflow_run_response)
2028
- session.upsert_run(run=workflow_run_response)
2206
+ self._update_session_metrics(session=workflow_session, workflow_run_response=workflow_run_response)
2207
+ workflow_session.upsert_run(run=workflow_run_response)
2029
2208
  if self._has_async_db():
2030
- await self.asave_session(session=session)
2209
+ await self.asave_session(session=workflow_session)
2031
2210
  else:
2032
- self.save_session(session=session)
2211
+ self.save_session(session=workflow_session)
2033
2212
 
2034
2213
  # Log Workflow Telemetry
2035
2214
  if self.telemetry:
2036
- await self._alog_workflow_telemetry(session_id=session.session_id, run_id=workflow_run_response.run_id)
2215
+ await self._alog_workflow_telemetry(session_id=session_id, run_id=workflow_run_response.run_id)
2037
2216
 
2038
2217
  # Always clean up the run tracking
2039
2218
  cleanup_run(workflow_run_response.run_id) # type: ignore
@@ -2057,19 +2236,12 @@ class Workflow:
2057
2236
 
2058
2237
  self.initialize_workflow()
2059
2238
 
2060
- session_id, user_id, session_state = self._initialize_session(
2061
- session_id=session_id, user_id=user_id, session_state=session_state, run_id=run_id
2062
- )
2239
+ session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
2063
2240
 
2064
2241
  # Read existing session from database
2065
- if self._has_async_db():
2066
- workflow_session = await self.aread_or_create_session(session_id=session_id, user_id=user_id)
2067
- else:
2068
- workflow_session = self.read_or_create_session(session_id=session_id, user_id=user_id)
2069
- self._update_metadata(session=workflow_session)
2070
-
2071
- # Update session state from DB
2072
- session_state = self._load_session_state(session=workflow_session, session_state=session_state)
2242
+ workflow_session, session_state = await self._aload_or_create_session(
2243
+ session_id=session_id, user_id=user_id, session_state=session_state
2244
+ )
2073
2245
 
2074
2246
  self._prepare_steps()
2075
2247
 
@@ -2114,7 +2286,8 @@ class Workflow:
2114
2286
  self.save_session(session=workflow_session)
2115
2287
 
2116
2288
  await self._aexecute(
2117
- session=workflow_session,
2289
+ session_id=session_id,
2290
+ user_id=user_id,
2118
2291
  execution_input=inputs,
2119
2292
  workflow_run_response=workflow_run_response,
2120
2293
  session_state=session_state,
@@ -2150,7 +2323,7 @@ class Workflow:
2150
2323
  images: Optional[List[Image]] = None,
2151
2324
  videos: Optional[List[Video]] = None,
2152
2325
  files: Optional[List[File]] = None,
2153
- stream_intermediate_steps: bool = False,
2326
+ stream_events: bool = False,
2154
2327
  websocket_handler: Optional[WebSocketHandler] = None,
2155
2328
  **kwargs: Any,
2156
2329
  ) -> WorkflowRunOutput:
@@ -2160,19 +2333,12 @@ class Workflow:
2160
2333
 
2161
2334
  self.initialize_workflow()
2162
2335
 
2163
- session_id, user_id, session_state = self._initialize_session(
2164
- session_id=session_id, user_id=user_id, session_state=session_state, run_id=run_id
2165
- )
2336
+ session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
2166
2337
 
2167
2338
  # Read existing session from database
2168
- if self._has_async_db():
2169
- workflow_session = await self.aread_or_create_session(session_id=session_id, user_id=user_id)
2170
- else:
2171
- workflow_session = self.read_or_create_session(session_id=session_id, user_id=user_id)
2172
- self._update_metadata(session=workflow_session)
2173
-
2174
- # Update session state from DB
2175
- session_state = self._load_session_state(session=workflow_session, session_state=session_state)
2339
+ workflow_session, session_state = await self._aload_or_create_session(
2340
+ session_id=session_id, user_id=user_id, session_state=session_state
2341
+ )
2176
2342
 
2177
2343
  self._prepare_steps()
2178
2344
 
@@ -2218,10 +2384,11 @@ class Workflow:
2218
2384
 
2219
2385
  # Execute with streaming - consume all events (they're auto-broadcast via _handle_event)
2220
2386
  async for event in self._aexecute_stream(
2387
+ session_id=session_id,
2388
+ user_id=user_id,
2221
2389
  execution_input=inputs,
2222
- session=workflow_session,
2223
2390
  workflow_run_response=workflow_run_response,
2224
- stream_intermediate_steps=stream_intermediate_steps,
2391
+ stream_events=stream_events,
2225
2392
  session_state=session_state,
2226
2393
  websocket_handler=websocket_handler,
2227
2394
  **kwargs,
@@ -2296,6 +2463,7 @@ class Workflow:
2296
2463
  videos: Optional[List[Video]] = None,
2297
2464
  files: Optional[List[File]] = None,
2298
2465
  stream: Literal[False] = False,
2466
+ stream_events: Optional[bool] = None,
2299
2467
  stream_intermediate_steps: Optional[bool] = None,
2300
2468
  background: Optional[bool] = False,
2301
2469
  ) -> WorkflowRunOutput: ...
@@ -2313,6 +2481,7 @@ class Workflow:
2313
2481
  videos: Optional[List[Video]] = None,
2314
2482
  files: Optional[List[File]] = None,
2315
2483
  stream: Literal[True] = True,
2484
+ stream_events: Optional[bool] = None,
2316
2485
  stream_intermediate_steps: Optional[bool] = None,
2317
2486
  background: Optional[bool] = False,
2318
2487
  ) -> Iterator[WorkflowRunOutputEvent]: ...
@@ -2329,6 +2498,7 @@ class Workflow:
2329
2498
  videos: Optional[List[Video]] = None,
2330
2499
  files: Optional[List[File]] = None,
2331
2500
  stream: bool = False,
2501
+ stream_events: Optional[bool] = None,
2332
2502
  stream_intermediate_steps: Optional[bool] = None,
2333
2503
  background: Optional[bool] = False,
2334
2504
  **kwargs: Any,
@@ -2346,14 +2516,16 @@ class Workflow:
2346
2516
  run_id = str(uuid4())
2347
2517
 
2348
2518
  self.initialize_workflow()
2349
- session_id, user_id, session_state = self._initialize_session(
2350
- session_id=session_id, user_id=user_id, session_state=session_state, run_id=run_id
2351
- )
2519
+ session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
2352
2520
 
2353
2521
  # Read existing session from database
2354
2522
  workflow_session = self.read_or_create_session(session_id=session_id, user_id=user_id)
2355
2523
  self._update_metadata(session=workflow_session)
2356
2524
 
2525
+ # Initialize session state
2526
+ session_state = self._initialize_session_state(
2527
+ session_state=session_state or {}, user_id=user_id, session_id=session_id, run_id=run_id
2528
+ )
2357
2529
  # Update session state from DB
2358
2530
  session_state = self._load_session_state(session=workflow_session, session_state=session_state)
2359
2531
 
@@ -2361,11 +2533,13 @@ class Workflow:
2361
2533
 
2362
2534
  # Use simple defaults
2363
2535
  stream = stream or self.stream or False
2364
- stream_intermediate_steps = stream_intermediate_steps or self.stream_intermediate_steps or False
2536
+ stream_events = (stream_events or stream_intermediate_steps) or (
2537
+ self.stream_events or self.stream_intermediate_steps
2538
+ )
2365
2539
 
2366
- # Can't have stream_intermediate_steps if stream is False
2367
- if not stream:
2368
- stream_intermediate_steps = False
2540
+ # Can't stream events if streaming is disabled
2541
+ if stream is False:
2542
+ stream_events = False
2369
2543
 
2370
2544
  log_debug(f"Stream: {stream}")
2371
2545
  log_debug(f"Total steps: {self._get_step_count()}")
@@ -2402,7 +2576,7 @@ class Workflow:
2402
2576
  session=workflow_session,
2403
2577
  execution_input=inputs, # type: ignore[arg-type]
2404
2578
  workflow_run_response=workflow_run_response,
2405
- stream_intermediate_steps=stream_intermediate_steps,
2579
+ stream_events=stream_events,
2406
2580
  session_state=session_state,
2407
2581
  **kwargs,
2408
2582
  )
@@ -2428,13 +2602,14 @@ class Workflow:
2428
2602
  videos: Optional[List[Video]] = None,
2429
2603
  files: Optional[List[File]] = None,
2430
2604
  stream: Literal[False] = False,
2605
+ stream_events: Optional[bool] = None,
2431
2606
  stream_intermediate_steps: Optional[bool] = None,
2432
2607
  background: Optional[bool] = False,
2433
2608
  websocket: Optional[WebSocket] = None,
2434
2609
  ) -> WorkflowRunOutput: ...
2435
2610
 
2436
2611
  @overload
2437
- async def arun(
2612
+ def arun(
2438
2613
  self,
2439
2614
  input: Optional[Union[str, Dict[str, Any], List[Any], BaseModel, List[Message]]] = None,
2440
2615
  additional_data: Optional[Dict[str, Any]] = None,
@@ -2446,12 +2621,13 @@ class Workflow:
2446
2621
  videos: Optional[List[Video]] = None,
2447
2622
  files: Optional[List[File]] = None,
2448
2623
  stream: Literal[True] = True,
2624
+ stream_events: Optional[bool] = None,
2449
2625
  stream_intermediate_steps: Optional[bool] = None,
2450
2626
  background: Optional[bool] = False,
2451
2627
  websocket: Optional[WebSocket] = None,
2452
2628
  ) -> AsyncIterator[WorkflowRunOutputEvent]: ...
2453
2629
 
2454
- async def arun(
2630
+ def arun( # type: ignore
2455
2631
  self,
2456
2632
  input: Optional[Union[str, Dict[str, Any], List[Any], BaseModel, List[Message]]] = None,
2457
2633
  additional_data: Optional[Dict[str, Any]] = None,
@@ -2463,6 +2639,7 @@ class Workflow:
2463
2639
  videos: Optional[List[Video]] = None,
2464
2640
  files: Optional[List[File]] = None,
2465
2641
  stream: bool = False,
2642
+ stream_events: Optional[bool] = None,
2466
2643
  stream_intermediate_steps: Optional[bool] = False,
2467
2644
  background: Optional[bool] = False,
2468
2645
  websocket: Optional[WebSocket] = None,
@@ -2480,8 +2657,11 @@ class Workflow:
2480
2657
 
2481
2658
  if background:
2482
2659
  if stream and websocket:
2660
+ # Consider both stream_events and stream_intermediate_steps (deprecated)
2661
+ stream_events = stream_events or stream_intermediate_steps or False
2662
+
2483
2663
  # Background + Streaming + WebSocket = Real-time events
2484
- return await self._arun_background_stream(
2664
+ return self._arun_background_stream( # type: ignore
2485
2665
  input=input,
2486
2666
  additional_data=additional_data,
2487
2667
  user_id=user_id,
@@ -2491,7 +2671,7 @@ class Workflow:
2491
2671
  images=images,
2492
2672
  videos=videos,
2493
2673
  files=files,
2494
- stream_intermediate_steps=stream_intermediate_steps or False,
2674
+ stream_events=stream_events,
2495
2675
  websocket_handler=websocket_handler,
2496
2676
  **kwargs,
2497
2677
  )
@@ -2500,7 +2680,7 @@ class Workflow:
2500
2680
  raise ValueError("Background streaming execution requires a WebSocket for real-time events")
2501
2681
  else:
2502
2682
  # Background + Non-streaming = Polling (existing)
2503
- return await self._arun_background(
2683
+ return self._arun_background( # type: ignore
2504
2684
  input=input,
2505
2685
  additional_data=additional_data,
2506
2686
  user_id=user_id,
@@ -2518,29 +2698,19 @@ class Workflow:
2518
2698
  run_id = str(uuid4())
2519
2699
 
2520
2700
  self.initialize_workflow()
2521
- session_id, user_id, session_state = self._initialize_session(
2522
- session_id=session_id, user_id=user_id, session_state=session_state, run_id=run_id
2523
- )
2524
-
2525
- # Read existing session from database
2526
- if self._has_async_db():
2527
- workflow_session = await self.aread_or_create_session(session_id=session_id, user_id=user_id)
2528
- else:
2529
- workflow_session = self.read_or_create_session(session_id=session_id, user_id=user_id)
2530
- self._update_metadata(session=workflow_session)
2531
-
2532
- # Update session state from DB
2533
- session_state = self._load_session_state(session=workflow_session, session_state=session_state)
2701
+ session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
2534
2702
 
2535
2703
  log_debug(f"Async Workflow Run Start: {self.name}", center=True)
2536
2704
 
2537
2705
  # Use simple defaults
2538
2706
  stream = stream or self.stream or False
2539
- stream_intermediate_steps = stream_intermediate_steps or self.stream_intermediate_steps or False
2707
+ stream_events = (stream_events or stream_intermediate_steps) or (
2708
+ self.stream_events or self.stream_intermediate_steps
2709
+ )
2540
2710
 
2541
- # Can't have stream_intermediate_steps if stream is False
2542
- if not stream:
2543
- stream_intermediate_steps = False
2711
+ # Can't stream events if streaming is disabled
2712
+ if stream is False:
2713
+ stream_events = False
2544
2714
 
2545
2715
  log_debug(f"Stream: {stream}")
2546
2716
 
@@ -2572,21 +2742,23 @@ class Workflow:
2572
2742
  self.update_agents_and_teams_session_info()
2573
2743
 
2574
2744
  if stream:
2575
- return self._aexecute_stream(
2745
+ return self._aexecute_stream( # type: ignore
2576
2746
  execution_input=inputs,
2577
2747
  workflow_run_response=workflow_run_response,
2578
- session=workflow_session,
2579
- stream_intermediate_steps=stream_intermediate_steps,
2748
+ session_id=session_id,
2749
+ user_id=user_id,
2750
+ stream_events=stream_events,
2580
2751
  websocket=websocket,
2581
2752
  files=files,
2582
2753
  session_state=session_state,
2583
2754
  **kwargs,
2584
2755
  )
2585
2756
  else:
2586
- return await self._aexecute(
2757
+ return self._aexecute( # type: ignore
2587
2758
  execution_input=inputs,
2588
2759
  workflow_run_response=workflow_run_response,
2589
- session=workflow_session,
2760
+ session_id=session_id,
2761
+ user_id=user_id,
2590
2762
  websocket=websocket,
2591
2763
  files=files,
2592
2764
  session_state=session_state,
@@ -2601,7 +2773,7 @@ class Workflow:
2601
2773
  if callable(step) and hasattr(step, "__name__"):
2602
2774
  step_name = step.__name__
2603
2775
  log_debug(f"Step {i + 1}: Wrapping callable function '{step_name}'")
2604
- prepared_steps.append(Step(name=step_name, description="User-defined callable step", executor=step))
2776
+ prepared_steps.append(Step(name=step_name, description="User-defined callable step", executor=step)) # type: ignore
2605
2777
  elif isinstance(step, Agent):
2606
2778
  step_name = step.name or f"step_{i + 1}"
2607
2779
  log_debug(f"Step {i + 1}: Agent '{step_name}'")
@@ -2632,6 +2804,7 @@ class Workflow:
2632
2804
  videos: Optional[List[Video]] = None,
2633
2805
  files: Optional[List[File]] = None,
2634
2806
  stream: Optional[bool] = None,
2807
+ stream_events: Optional[bool] = None,
2635
2808
  stream_intermediate_steps: Optional[bool] = None,
2636
2809
  markdown: bool = True,
2637
2810
  show_time: bool = True,
@@ -2650,11 +2823,12 @@ class Workflow:
2650
2823
  images: Image input
2651
2824
  videos: Video input
2652
2825
  stream: Whether to stream the response content
2653
- stream_intermediate_steps: Whether to stream intermediate steps
2826
+ stream_events: Whether to stream intermediate steps
2654
2827
  markdown: Whether to render content as markdown
2655
2828
  show_time: Whether to show execution time
2656
2829
  show_step_details: Whether to show individual step outputs
2657
2830
  console: Rich console instance (optional)
2831
+ (deprecated) stream_intermediate_steps: Whether to stream intermediate step outputs. If None, uses workflow default.
2658
2832
  """
2659
2833
  if self._has_async_db():
2660
2834
  raise Exception("`print_response()` is not supported with an async DB. Please use `aprint_response()`.")
@@ -2662,8 +2836,19 @@ class Workflow:
2662
2836
  if stream is None:
2663
2837
  stream = self.stream or False
2664
2838
 
2665
- if stream_intermediate_steps is None:
2666
- stream_intermediate_steps = self.stream_intermediate_steps or False
2839
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
2840
+ stream_events = stream_events or stream_intermediate_steps
2841
+
2842
+ # Can't stream events if streaming is disabled
2843
+ if stream is False:
2844
+ stream_events = False
2845
+
2846
+ if stream_events is None:
2847
+ stream_events = (
2848
+ False
2849
+ if (self.stream_events is None and self.stream_intermediate_steps is None)
2850
+ else (self.stream_intermediate_steps or self.stream_events)
2851
+ )
2667
2852
 
2668
2853
  if stream:
2669
2854
  print_response_stream(
@@ -2676,7 +2861,7 @@ class Workflow:
2676
2861
  images=images,
2677
2862
  videos=videos,
2678
2863
  files=files,
2679
- stream_intermediate_steps=stream_intermediate_steps,
2864
+ stream_events=stream_events,
2680
2865
  markdown=markdown,
2681
2866
  show_time=show_time,
2682
2867
  show_step_details=show_step_details,
@@ -2712,6 +2897,7 @@ class Workflow:
2712
2897
  videos: Optional[List[Video]] = None,
2713
2898
  files: Optional[List[File]] = None,
2714
2899
  stream: Optional[bool] = None,
2900
+ stream_events: Optional[bool] = None,
2715
2901
  stream_intermediate_steps: Optional[bool] = None,
2716
2902
  markdown: bool = True,
2717
2903
  show_time: bool = True,
@@ -2729,18 +2915,30 @@ class Workflow:
2729
2915
  audio: Audio input
2730
2916
  images: Image input
2731
2917
  videos: Video input
2732
- stream_intermediate_steps: Whether to stream intermediate steps
2733
2918
  stream: Whether to stream the response content
2919
+ stream_events: Whether to stream intermediate steps
2734
2920
  markdown: Whether to render content as markdown
2735
2921
  show_time: Whether to show execution time
2736
2922
  show_step_details: Whether to show individual step outputs
2737
2923
  console: Rich console instance (optional)
2924
+ (deprecated) stream_intermediate_steps: Whether to stream intermediate step outputs. If None, uses workflow default.
2738
2925
  """
2739
2926
  if stream is None:
2740
2927
  stream = self.stream or False
2741
2928
 
2742
- if stream_intermediate_steps is None:
2743
- stream_intermediate_steps = self.stream_intermediate_steps or False
2929
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
2930
+ stream_events = stream_events or stream_intermediate_steps
2931
+
2932
+ # Can't stream events if streaming is disabled
2933
+ if stream is False:
2934
+ stream_events = False
2935
+
2936
+ if stream_events is None:
2937
+ stream_events = (
2938
+ False
2939
+ if (self.stream_events is None and self.stream_intermediate_steps is None)
2940
+ else (self.stream_intermediate_steps or self.stream_events)
2941
+ )
2744
2942
 
2745
2943
  if stream:
2746
2944
  await aprint_response_stream(
@@ -2753,7 +2951,7 @@ class Workflow:
2753
2951
  images=images,
2754
2952
  videos=videos,
2755
2953
  files=files,
2756
- stream_intermediate_steps=stream_intermediate_steps,
2954
+ stream_events=stream_events,
2757
2955
  markdown=markdown,
2758
2956
  show_time=show_time,
2759
2957
  show_step_details=show_step_details,
@@ -2930,7 +3128,7 @@ class Workflow:
2930
3128
 
2931
3129
  # If it's a team, update all members
2932
3130
  if hasattr(active_executor, "members"):
2933
- for member in active_executor.members:
3131
+ for member in active_executor.members: # type: ignore
2934
3132
  if hasattr(member, "workflow_id"):
2935
3133
  member.workflow_id = self.id
2936
3134
 
@@ -2986,6 +3184,7 @@ class Workflow:
2986
3184
  user: str = "User",
2987
3185
  emoji: str = ":technologist:",
2988
3186
  stream: Optional[bool] = None,
3187
+ stream_events: Optional[bool] = None,
2989
3188
  stream_intermediate_steps: Optional[bool] = None,
2990
3189
  markdown: bool = True,
2991
3190
  show_time: bool = True,
@@ -3006,11 +3205,12 @@ class Workflow:
3006
3205
  user: Display name for the user in the CLI prompt. Defaults to "User".
3007
3206
  emoji: Emoji to display next to the user name in prompts. Defaults to ":technologist:".
3008
3207
  stream: Whether to stream the workflow response. If None, uses workflow default.
3009
- stream_intermediate_steps: Whether to stream intermediate step outputs. If None, uses workflow default.
3208
+ stream_events: Whether to stream intermediate step outputs. If None, uses workflow default.
3010
3209
  markdown: Whether to render output as markdown. Defaults to True.
3011
3210
  show_time: Whether to display timestamps in the output. Defaults to True.
3012
3211
  show_step_details: Whether to show detailed step information. Defaults to True.
3013
3212
  exit_on: List of commands that will exit the CLI. Defaults to ["exit", "quit", "bye", "stop"].
3213
+ (deprecated) stream_intermediate_steps: Whether to stream intermediate step outputs. If None, uses workflow default.
3014
3214
  **kwargs: Additional keyword arguments passed to the workflow's print_response method.
3015
3215
 
3016
3216
  Returns:
@@ -3019,11 +3219,14 @@ class Workflow:
3019
3219
 
3020
3220
  from rich.prompt import Prompt
3021
3221
 
3222
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
3223
+ stream_events = stream_events or stream_intermediate_steps or False
3224
+
3022
3225
  if input:
3023
3226
  self.print_response(
3024
3227
  input=input,
3025
3228
  stream=stream,
3026
- stream_intermediate_steps=stream_intermediate_steps,
3229
+ stream_events=stream_events,
3027
3230
  markdown=markdown,
3028
3231
  show_time=show_time,
3029
3232
  show_step_details=show_step_details,
@@ -3041,7 +3244,7 @@ class Workflow:
3041
3244
  self.print_response(
3042
3245
  input=message,
3043
3246
  stream=stream,
3044
- stream_intermediate_steps=stream_intermediate_steps,
3247
+ stream_events=stream_events,
3045
3248
  markdown=markdown,
3046
3249
  show_time=show_time,
3047
3250
  show_step_details=show_step_details,
@@ -3058,6 +3261,7 @@ class Workflow:
3058
3261
  user: str = "User",
3059
3262
  emoji: str = ":technologist:",
3060
3263
  stream: Optional[bool] = None,
3264
+ stream_events: Optional[bool] = None,
3061
3265
  stream_intermediate_steps: Optional[bool] = None,
3062
3266
  markdown: bool = True,
3063
3267
  show_time: bool = True,
@@ -3078,11 +3282,12 @@ class Workflow:
3078
3282
  user: Display name for the user in the CLI prompt. Defaults to "User".
3079
3283
  emoji: Emoji to display next to the user name in prompts. Defaults to ":technologist:".
3080
3284
  stream: Whether to stream the workflow response. If None, uses workflow default.
3081
- stream_intermediate_steps: Whether to stream intermediate step outputs. If None, uses workflow default.
3285
+ stream_events: Whether to stream events from the workflow. If None, uses workflow default.
3082
3286
  markdown: Whether to render output as markdown. Defaults to True.
3083
3287
  show_time: Whether to display timestamps in the output. Defaults to True.
3084
3288
  show_step_details: Whether to show detailed step information. Defaults to True.
3085
3289
  exit_on: List of commands that will exit the CLI. Defaults to ["exit", "quit", "bye", "stop"].
3290
+ (deprecated) stream_intermediate_steps: Whether to stream intermediate step outputs. If None, uses workflow default.
3086
3291
  **kwargs: Additional keyword arguments passed to the workflow's print_response method.
3087
3292
 
3088
3293
  Returns:
@@ -3091,11 +3296,14 @@ class Workflow:
3091
3296
 
3092
3297
  from rich.prompt import Prompt
3093
3298
 
3299
+ # Considering both stream_events and stream_intermediate_steps (deprecated)
3300
+ stream_events = stream_events or stream_intermediate_steps or False
3301
+
3094
3302
  if input:
3095
3303
  await self.aprint_response(
3096
3304
  input=input,
3097
3305
  stream=stream,
3098
- stream_intermediate_steps=stream_intermediate_steps,
3306
+ stream_events=stream_events,
3099
3307
  markdown=markdown,
3100
3308
  show_time=show_time,
3101
3309
  show_step_details=show_step_details,
@@ -3113,7 +3321,7 @@ class Workflow:
3113
3321
  await self.aprint_response(
3114
3322
  input=message,
3115
3323
  stream=stream,
3116
- stream_intermediate_steps=stream_intermediate_steps,
3324
+ stream_events=stream_events,
3117
3325
  markdown=markdown,
3118
3326
  show_time=show_time,
3119
3327
  show_step_details=show_step_details,