77from typing import Any , AsyncGenerator
88
99from .context import Context
10- from .errors import WorkflowDone
10+ from .errors import WorkflowDone , WorkflowRuntimeError
1111from .events import Event , StopEvent
1212from .types import RunResultT
1313from .utils import BUSY_WAIT_DELAY
@@ -24,6 +24,7 @@ def __init__(
2424 super ().__init__ (* args , ** kwargs )
2525 self .run_id = run_id
2626 self ._ctx = ctx
27+ self ._all_events_consumed = False
2728
2829 @property
2930 def ctx (self ) -> Context | None :
@@ -36,15 +37,60 @@ def is_done(self) -> bool:
3637 return self .done ()
3738
3839 async def stream_events (self ) -> AsyncGenerator [Event , None ]:
40+ """
41+ Stream events from the workflow execution as they occur.
42+
43+ This method provides real-time access to events generated during workflow
44+ execution, allowing for monitoring and processing of intermediate results.
45+ Events are yielded in the order they are generated by the workflow.
46+
47+ The stream includes all events written to the context's streaming queue,
48+ and terminates when a StopEvent is encountered, indicating the workflow
49+ has completed.
50+
51+ Returns:
52+ AsyncGenerator[Event, None]: An async generator that yields Event objects
53+ as they are produced by the workflow.
54+
55+ Raises:
56+ ValueError: If the context is not set on the handler.
57+ WorkflowRuntimeError: If all events have already been consumed by a
58+ previous call to stream_events() on the same handler instance.
59+
60+ Examples:
61+ ```python
62+ handler = workflow.run()
63+
64+ # Stream and process events in real-time
65+ async for event in handler.stream_events():
66+ if isinstance(event, StopEvent):
67+ print(f"Workflow completed with result: {event.result}")
68+ else:
69+ print(f"Received event: {event}")
70+
71+ # Get final result
72+ result = await handler
73+ ```
74+
75+ Note:
76+ Events can only be streamed once per handler instance. Subsequent
77+ calls to stream_events() will raise a WorkflowRuntimeError.
78+ """
3979 if self .ctx is None :
4080 raise ValueError ("Context is not set!" )
4181
82+ # Check if we already consumed all the streamed events
83+ if self ._all_events_consumed :
84+ msg = "All the streamed events have already been consumed."
85+ raise WorkflowRuntimeError (msg )
86+
4287 while True :
4388 ev = await self .ctx .streaming_queue .get ()
4489
4590 yield ev
4691
4792 if isinstance (ev , StopEvent ):
93+ self ._all_events_consumed = True
4894 break
4995
5096 async def run_step (self ) -> list [Event ] | None :
0 commit comments