waldiez 0.5.8__py3-none-any.whl → 0.5.10__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.
Potentially problematic release.
This version of waldiez might be problematic. Click here for more details.
- waldiez/_version.py +1 -1
- waldiez/cli.py +112 -24
- waldiez/exporting/agent/exporter.py +3 -0
- waldiez/exporting/agent/extras/captain_agent_extras.py +44 -7
- waldiez/exporting/agent/extras/handoffs/condition.py +3 -1
- waldiez/exporting/chats/utils/common.py +25 -23
- waldiez/exporting/core/__init__.py +0 -2
- waldiez/exporting/core/context.py +13 -13
- waldiez/exporting/core/protocols.py +0 -141
- waldiez/exporting/core/result.py +5 -5
- waldiez/exporting/flow/merger.py +2 -2
- waldiez/exporting/flow/orchestrator.py +1 -0
- waldiez/exporting/flow/utils/common.py +2 -2
- waldiez/exporting/flow/utils/importing.py +1 -0
- waldiez/exporting/flow/utils/logging.py +6 -7
- waldiez/exporting/tools/exporter.py +5 -0
- waldiez/exporting/tools/factory.py +4 -0
- waldiez/exporting/tools/processor.py +5 -1
- waldiez/io/_ws.py +13 -5
- waldiez/io/models/content/image.py +1 -0
- waldiez/io/models/user_input.py +4 -4
- waldiez/io/models/user_response.py +1 -0
- waldiez/io/mqtt.py +1 -1
- waldiez/io/structured.py +17 -17
- waldiez/io/utils.py +1 -1
- waldiez/io/ws.py +9 -11
- waldiez/logger.py +180 -63
- waldiez/models/agents/agent/update_system_message.py +0 -2
- waldiez/models/agents/doc_agent/doc_agent.py +8 -1
- waldiez/models/common/dict_utils.py +169 -40
- waldiez/models/flow/flow.py +6 -6
- waldiez/models/flow/info.py +5 -1
- waldiez/models/model/_llm.py +28 -14
- waldiez/models/model/model.py +4 -1
- waldiez/models/model/model_data.py +18 -5
- waldiez/models/tool/predefined/_config.py +5 -1
- waldiez/models/tool/predefined/_duckduckgo.py +4 -0
- waldiez/models/tool/predefined/_email.py +474 -0
- waldiez/models/tool/predefined/_google.py +8 -6
- waldiez/models/tool/predefined/_perplexity.py +3 -0
- waldiez/models/tool/predefined/_searxng.py +3 -0
- waldiez/models/tool/predefined/_tavily.py +4 -1
- waldiez/models/tool/predefined/_wikipedia.py +4 -1
- waldiez/models/tool/predefined/_youtube.py +4 -1
- waldiez/models/tool/predefined/protocol.py +3 -0
- waldiez/models/tool/tool.py +22 -4
- waldiez/models/waldiez.py +12 -0
- waldiez/runner.py +37 -54
- waldiez/running/__init__.py +6 -0
- waldiez/running/base_runner.py +310 -353
- waldiez/running/environment.py +1 -0
- waldiez/running/exceptions.py +9 -0
- waldiez/running/post_run.py +4 -4
- waldiez/running/pre_run.py +51 -40
- waldiez/running/protocol.py +21 -101
- waldiez/running/run_results.py +1 -1
- waldiez/running/standard_runner.py +84 -277
- waldiez/running/step_by_step/__init__.py +46 -0
- waldiez/running/step_by_step/breakpoints_mixin.py +188 -0
- waldiez/running/step_by_step/step_by_step_models.py +224 -0
- waldiez/running/step_by_step/step_by_step_runner.py +745 -0
- waldiez/running/subprocess_runner/__base__.py +282 -0
- waldiez/running/subprocess_runner/__init__.py +16 -0
- waldiez/running/subprocess_runner/_async_runner.py +362 -0
- waldiez/running/subprocess_runner/_sync_runner.py +455 -0
- waldiez/running/subprocess_runner/runner.py +561 -0
- waldiez/running/timeline_processor.py +1 -1
- waldiez/running/utils.py +376 -1
- waldiez/utils/version.py +2 -6
- waldiez/ws/__init__.py +70 -0
- waldiez/ws/__main__.py +15 -0
- waldiez/ws/_file_handler.py +201 -0
- waldiez/ws/cli.py +211 -0
- waldiez/ws/client_manager.py +835 -0
- waldiez/ws/errors.py +416 -0
- waldiez/ws/models.py +971 -0
- waldiez/ws/reloader.py +342 -0
- waldiez/ws/server.py +469 -0
- waldiez/ws/session_manager.py +393 -0
- waldiez/ws/session_stats.py +83 -0
- waldiez/ws/utils.py +385 -0
- {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/METADATA +74 -74
- {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/RECORD +87 -65
- waldiez/running/patch_io_stream.py +0 -210
- {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/WHEEL +0 -0
- {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/entry_points.txt +0 -0
- {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/licenses/NOTICE.md +0 -0
waldiez/running/base_runner.py
CHANGED
|
@@ -1,26 +1,19 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0.
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# pylint: disable=too-many-public-methods,too-many-locals
|
|
7
|
-
|
|
4
|
+
# pyright: reportUnknownMemberType=false, reportAttributeAccessIssue=false
|
|
5
|
+
# pyright: reportUnknownArgumentType=false
|
|
8
6
|
"""Base runner for Waldiez workflows."""
|
|
9
7
|
|
|
8
|
+
import importlib.util
|
|
9
|
+
import inspect
|
|
10
10
|
import shutil
|
|
11
11
|
import sys
|
|
12
12
|
import tempfile
|
|
13
13
|
import threading
|
|
14
14
|
from pathlib import Path
|
|
15
|
-
from types import TracebackType
|
|
16
|
-
from typing import
|
|
17
|
-
TYPE_CHECKING,
|
|
18
|
-
Any,
|
|
19
|
-
Callable,
|
|
20
|
-
Coroutine,
|
|
21
|
-
Optional,
|
|
22
|
-
Type,
|
|
23
|
-
)
|
|
15
|
+
from types import ModuleType, TracebackType
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Type, Union
|
|
24
17
|
|
|
25
18
|
from aiofiles.os import wrap
|
|
26
19
|
from anyio.from_thread import start_blocking_portal
|
|
@@ -31,22 +24,26 @@ from waldiez.logger import WaldiezLogger, get_logger
|
|
|
31
24
|
from waldiez.models import Waldiez
|
|
32
25
|
|
|
33
26
|
from .environment import refresh_environment, reset_env_vars, set_env_vars
|
|
27
|
+
from .exceptions import StopRunningException
|
|
34
28
|
from .post_run import after_run
|
|
35
|
-
from .pre_run import
|
|
36
|
-
a_install_requirements,
|
|
37
|
-
install_requirements,
|
|
38
|
-
)
|
|
29
|
+
from .pre_run import RequirementsMixin
|
|
39
30
|
from .protocol import WaldiezRunnerProtocol
|
|
40
31
|
from .utils import (
|
|
41
32
|
a_chdir,
|
|
42
33
|
chdir,
|
|
34
|
+
input_async,
|
|
35
|
+
input_sync,
|
|
36
|
+
is_async_callable,
|
|
37
|
+
syncify,
|
|
43
38
|
)
|
|
44
39
|
|
|
45
40
|
if TYPE_CHECKING:
|
|
46
41
|
from autogen.events import BaseEvent # type: ignore[import-untyped]
|
|
42
|
+
from autogen.messages import BaseMessage # type: ignore[import-untyped]
|
|
47
43
|
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
# pylint: disable=too-many-public-methods
|
|
46
|
+
class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
50
47
|
"""Base runner for Waldiez.
|
|
51
48
|
|
|
52
49
|
Initialization parameters:
|
|
@@ -57,17 +54,15 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
57
54
|
- skip_patch_io: Whether to skip patching I/O functions.
|
|
58
55
|
- dot_env: Path to a .env file for environment variables.
|
|
59
56
|
|
|
60
|
-
Methods to override:
|
|
57
|
+
Methods to possibly override:
|
|
58
|
+
- prepare: Prepare the environment and paths for running the flow.
|
|
61
59
|
- _before_run: Actions to perform before running the flow.
|
|
60
|
+
- a_prepare: Async version of the prepare method.
|
|
62
61
|
- _a_before_run: Async actions to perform before running the flow.
|
|
63
62
|
- _run: Actual implementation of the run logic.
|
|
64
63
|
- _a_run: Async implementation of the run logic.
|
|
65
64
|
- _after_run: Actions to perform after running the flow.
|
|
66
65
|
- _a_after_run: Async actions to perform after running the flow.
|
|
67
|
-
- _start: Implementation of non-blocking start logic.
|
|
68
|
-
- _a_start: Async implementation of non-blocking start logic.
|
|
69
|
-
- _stop: Actions to perform when stopping the flow.
|
|
70
|
-
- _a_stop: Async actions to perform when stopping the flow.
|
|
71
66
|
"""
|
|
72
67
|
|
|
73
68
|
_structured_io: bool
|
|
@@ -76,6 +71,10 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
76
71
|
_dot_env_path: str | Path | None
|
|
77
72
|
_skip_patch_io: bool
|
|
78
73
|
_running: bool
|
|
74
|
+
_is_async: bool
|
|
75
|
+
_input: Callable[..., str] | Callable[..., Coroutine[Any, Any, str]]
|
|
76
|
+
_print: Callable[..., None]
|
|
77
|
+
_send: Callable[[Union["BaseEvent", "BaseMessage"]], None]
|
|
79
78
|
|
|
80
79
|
def __init__(
|
|
81
80
|
self,
|
|
@@ -85,28 +84,32 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
85
84
|
structured_io: bool,
|
|
86
85
|
skip_patch_io: bool = False,
|
|
87
86
|
dot_env: str | Path | None = None,
|
|
87
|
+
**kwargs: Any,
|
|
88
88
|
) -> None:
|
|
89
89
|
"""Initialize the Waldiez manager."""
|
|
90
|
-
self._waldiez = waldiez
|
|
91
90
|
WaldiezBaseRunner._running = False
|
|
92
91
|
WaldiezBaseRunner._structured_io = structured_io
|
|
93
92
|
WaldiezBaseRunner._output_path = output_path
|
|
94
93
|
WaldiezBaseRunner._uploads_root = uploads_root
|
|
95
94
|
WaldiezBaseRunner._skip_patch_io = skip_patch_io
|
|
96
95
|
WaldiezBaseRunner._dot_env_path = dot_env
|
|
96
|
+
WaldiezBaseRunner._input = input
|
|
97
|
+
WaldiezBaseRunner._print = print
|
|
98
|
+
WaldiezBaseRunner._send = print
|
|
99
|
+
WaldiezBaseRunner._is_async = waldiez.is_async
|
|
100
|
+
self._waldiez = waldiez
|
|
97
101
|
self._called_install_requirements = False
|
|
98
102
|
self._exporter = WaldiezExporter(waldiez)
|
|
99
103
|
self._stop_requested = threading.Event()
|
|
100
|
-
self._logger = get_logger()
|
|
101
|
-
self._print: Callable[..., None] = print
|
|
102
|
-
self._send: Callable[["BaseEvent"], None] = self._print
|
|
103
|
-
self._input: (
|
|
104
|
-
Callable[..., str] | Callable[..., Coroutine[Any, Any, str]]
|
|
105
|
-
) = input
|
|
106
104
|
self._last_results: list[dict[str, Any]] = []
|
|
107
105
|
self._last_exception: Exception | None = None
|
|
108
|
-
self.
|
|
109
|
-
self.
|
|
106
|
+
self._running_lock = threading.Lock()
|
|
107
|
+
self._loaded_module: ModuleType | None = None
|
|
108
|
+
logger = kwargs.get("logger")
|
|
109
|
+
if isinstance(logger, WaldiezLogger):
|
|
110
|
+
self._logger = logger
|
|
111
|
+
else:
|
|
112
|
+
self._logger = get_logger()
|
|
110
113
|
|
|
111
114
|
def is_running(self) -> bool:
|
|
112
115
|
"""Check if the workflow is currently running.
|
|
@@ -116,65 +119,109 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
116
119
|
bool
|
|
117
120
|
True if the workflow is running, False otherwise.
|
|
118
121
|
"""
|
|
119
|
-
|
|
122
|
+
with self._running_lock:
|
|
123
|
+
return WaldiezBaseRunner._running
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def get_input_function() -> (
|
|
127
|
+
Callable[..., str] | Callable[..., Coroutine[Any, Any, str]]
|
|
128
|
+
):
|
|
129
|
+
"""Get the input function for user interaction.
|
|
120
130
|
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
Callable[[str, bool], str]
|
|
134
|
+
A function that takes a prompt and a password flag,
|
|
135
|
+
returning user input.
|
|
136
|
+
"""
|
|
137
|
+
if hasattr(WaldiezBaseRunner, "_input") and callable(
|
|
138
|
+
WaldiezBaseRunner._input
|
|
139
|
+
):
|
|
140
|
+
return WaldiezBaseRunner._input
|
|
141
|
+
if WaldiezBaseRunner._is_async:
|
|
142
|
+
return input_async
|
|
143
|
+
return input_sync
|
|
123
144
|
|
|
124
|
-
|
|
145
|
+
@staticmethod
|
|
146
|
+
async def a_get_user_input(prompt: str, *, password: bool = False) -> str:
|
|
147
|
+
"""Get user input with an optional password prompt.
|
|
125
148
|
|
|
126
149
|
Parameters
|
|
127
150
|
----------
|
|
128
|
-
|
|
129
|
-
The
|
|
130
|
-
|
|
151
|
+
prompt : str
|
|
152
|
+
The prompt to display to the user.
|
|
153
|
+
password : bool, optional
|
|
154
|
+
If True, the input will be hidden (default is False).
|
|
131
155
|
|
|
132
156
|
Returns
|
|
133
157
|
-------
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
str
|
|
159
|
+
The user input.
|
|
136
160
|
"""
|
|
137
|
-
|
|
138
|
-
if
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
161
|
+
input_function = WaldiezBaseRunner.get_input_function()
|
|
162
|
+
if is_async_callable(input_function):
|
|
163
|
+
try:
|
|
164
|
+
result = await input_function( # type: ignore
|
|
165
|
+
prompt,
|
|
166
|
+
password=password,
|
|
167
|
+
)
|
|
168
|
+
except TypeError:
|
|
169
|
+
result = await input_function(prompt) # type: ignore
|
|
170
|
+
else:
|
|
171
|
+
try:
|
|
172
|
+
result = input_function(prompt, password=password)
|
|
173
|
+
except TypeError:
|
|
174
|
+
result = input_function(prompt)
|
|
175
|
+
return result # pyright: ignore
|
|
144
176
|
|
|
145
|
-
|
|
177
|
+
@staticmethod
|
|
178
|
+
def get_user_input(
|
|
179
|
+
prompt: str,
|
|
180
|
+
*,
|
|
181
|
+
password: bool = False,
|
|
182
|
+
) -> str:
|
|
183
|
+
"""Get user input with an optional password prompt.
|
|
146
184
|
|
|
147
|
-
|
|
148
|
-
|
|
185
|
+
Parameters
|
|
186
|
+
----------
|
|
187
|
+
prompt : str
|
|
188
|
+
The prompt to display to the user.
|
|
189
|
+
password : bool, optional
|
|
190
|
+
If True, the input will be hidden (default is False).
|
|
149
191
|
|
|
150
192
|
Returns
|
|
151
193
|
-------
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
- is_running: Whether the runner is currently running.
|
|
155
|
-
- has_thread: Whether there is an execution thread.
|
|
156
|
-
- thread_alive: Whether the execution thread is alive.
|
|
157
|
-
- has_error: Whether there was an error during execution.
|
|
194
|
+
str
|
|
195
|
+
The user input.
|
|
158
196
|
"""
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
197
|
+
input_function = WaldiezBaseRunner.get_input_function()
|
|
198
|
+
if inspect.iscoroutinefunction(input_function):
|
|
199
|
+
try:
|
|
200
|
+
return syncify(input_function)(prompt, password=password)
|
|
201
|
+
except TypeError:
|
|
202
|
+
return syncify(input_function)(prompt)
|
|
203
|
+
try:
|
|
204
|
+
return str(input_function(prompt, password=password))
|
|
205
|
+
except TypeError:
|
|
206
|
+
return str(input_function(prompt))
|
|
207
|
+
|
|
208
|
+
def _load_module(self, output_file: Path, temp_dir: Path) -> ModuleType:
|
|
209
|
+
"""Load the module from the waldiez file."""
|
|
210
|
+
file_name = output_file.name
|
|
211
|
+
module_name = file_name.replace(".py", "")
|
|
212
|
+
spec = importlib.util.spec_from_file_location(
|
|
213
|
+
module_name, temp_dir / file_name
|
|
214
|
+
)
|
|
215
|
+
if not spec or not spec.loader:
|
|
216
|
+
raise ImportError("Could not import the flow")
|
|
217
|
+
module = importlib.util.module_from_spec(spec)
|
|
218
|
+
spec.loader.exec_module(module)
|
|
219
|
+
if not hasattr(module, "main"):
|
|
220
|
+
raise ImportError(
|
|
221
|
+
"The waldiez file does not contain a main() function"
|
|
222
|
+
)
|
|
223
|
+
self._loaded_module = module
|
|
224
|
+
return module
|
|
178
225
|
|
|
179
226
|
def _before_run(
|
|
180
227
|
self,
|
|
@@ -250,44 +297,6 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
250
297
|
"The _a_run method must be implemented in the subclass."
|
|
251
298
|
)
|
|
252
299
|
|
|
253
|
-
def _start(
|
|
254
|
-
self,
|
|
255
|
-
temp_dir: Path,
|
|
256
|
-
output_file: Path,
|
|
257
|
-
uploads_root: Path | None,
|
|
258
|
-
skip_mmd: bool,
|
|
259
|
-
skip_timeline: bool,
|
|
260
|
-
) -> None:
|
|
261
|
-
"""Start running the Waldiez flow in a non-blocking way."""
|
|
262
|
-
raise NotImplementedError(
|
|
263
|
-
"The _start method must be implemented in the subclass."
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
async def _a_start(
|
|
267
|
-
self,
|
|
268
|
-
temp_dir: Path,
|
|
269
|
-
output_file: Path,
|
|
270
|
-
uploads_root: Path | None,
|
|
271
|
-
skip_mmd: bool,
|
|
272
|
-
skip_timeline: bool,
|
|
273
|
-
) -> None:
|
|
274
|
-
"""Start running the Waldiez flow in a non-blocking way asynchronously.
|
|
275
|
-
|
|
276
|
-
Parameters
|
|
277
|
-
----------
|
|
278
|
-
temp_dir : Path
|
|
279
|
-
The path to the temporary directory created for the run.
|
|
280
|
-
output_file : Path
|
|
281
|
-
The path to the output file.
|
|
282
|
-
uploads_root : Path | None
|
|
283
|
-
The root path for uploads, if any.
|
|
284
|
-
skip_mmd : bool
|
|
285
|
-
Whether to skip generating the mermaid diagram.
|
|
286
|
-
"""
|
|
287
|
-
raise NotImplementedError(
|
|
288
|
-
"The _a_start method must be implemented in the subclass."
|
|
289
|
-
)
|
|
290
|
-
|
|
291
300
|
def _after_run(
|
|
292
301
|
self,
|
|
293
302
|
results: list[dict[str, Any]],
|
|
@@ -303,14 +312,18 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
303
312
|
|
|
304
313
|
# Reset stop flag for next run
|
|
305
314
|
self._stop_requested.clear()
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
315
|
+
# pylint: disable=broad-exception-caught
|
|
316
|
+
try:
|
|
317
|
+
after_run(
|
|
318
|
+
temp_dir=temp_dir,
|
|
319
|
+
output_file=output_file,
|
|
320
|
+
flow_name=self._waldiez.name,
|
|
321
|
+
uploads_root=uploads_root,
|
|
322
|
+
skip_mmd=skip_mmd,
|
|
323
|
+
skip_timeline=skip_timeline,
|
|
324
|
+
)
|
|
325
|
+
except BaseException as exc: # pragma: no cover
|
|
326
|
+
self.log.warning("Error occurred during after_run: %s", exc)
|
|
314
327
|
self.log.info("Cleanup completed")
|
|
315
328
|
|
|
316
329
|
async def _a_after_run(
|
|
@@ -332,21 +345,6 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
332
345
|
skip_timeline=skip_timeline,
|
|
333
346
|
)
|
|
334
347
|
|
|
335
|
-
def _stop(self) -> None:
|
|
336
|
-
"""Actions to perform when stopping the flow."""
|
|
337
|
-
raise NotImplementedError(
|
|
338
|
-
"The _stop method must be implemented in the subclass."
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
async def _a_stop(self) -> None:
|
|
342
|
-
"""Asynchronously perform actions when stopping the flow."""
|
|
343
|
-
raise NotImplementedError(
|
|
344
|
-
"The _a_stop method must be implemented in the subclass."
|
|
345
|
-
)
|
|
346
|
-
|
|
347
|
-
# ===================================================================
|
|
348
|
-
# HELPER METHODS
|
|
349
|
-
# ===================================================================
|
|
350
348
|
@staticmethod
|
|
351
349
|
def _prepare_paths(
|
|
352
350
|
output_path: str | Path | None = None,
|
|
@@ -366,43 +364,57 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
366
364
|
output_file: Path = Path(WaldiezBaseRunner._output_path)
|
|
367
365
|
return output_file, uploads_root_path
|
|
368
366
|
|
|
369
|
-
|
|
370
|
-
|
|
367
|
+
@staticmethod
|
|
368
|
+
async def a_process_event(event: Union["BaseEvent", "BaseMessage"]) -> None:
|
|
369
|
+
"""Process an event or message asynchronously.
|
|
371
370
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
371
|
+
Parameters
|
|
372
|
+
----------
|
|
373
|
+
event : Union[BaseEvent, BaseMessage]
|
|
374
|
+
The event or message to process.
|
|
375
|
+
"""
|
|
376
|
+
if hasattr(event, "type"): # pragma: no branch
|
|
377
|
+
if event.type == "input_request":
|
|
378
|
+
prompt = getattr(
|
|
379
|
+
event, "prompt", getattr(event.content, "prompt", "> ")
|
|
380
|
+
)
|
|
381
|
+
password = getattr(
|
|
382
|
+
event,
|
|
383
|
+
"password",
|
|
384
|
+
getattr(event.content, "password", False),
|
|
385
|
+
)
|
|
386
|
+
user_input = await WaldiezBaseRunner.a_get_user_input(
|
|
387
|
+
prompt, password=password
|
|
388
|
+
)
|
|
389
|
+
await event.content.respond(user_input)
|
|
390
|
+
else:
|
|
391
|
+
WaldiezBaseRunner._send(event)
|
|
392
|
+
|
|
393
|
+
@staticmethod
|
|
394
|
+
def process_event(event: Union["BaseEvent", "BaseMessage"]) -> None:
|
|
395
|
+
"""Process an event or message synchronously.
|
|
396
|
+
|
|
397
|
+
Parameters
|
|
398
|
+
----------
|
|
399
|
+
event : Union[BaseEvent, BaseMessage]
|
|
400
|
+
The event or message to process.
|
|
377
401
|
"""
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
async def a_install_requirements(self) -> None:
|
|
396
|
-
"""Install the requirements for the flow asynchronously."""
|
|
397
|
-
if not self._called_install_requirements:
|
|
398
|
-
self._called_install_requirements = True
|
|
399
|
-
extra_requirements = self.gather_requirements()
|
|
400
|
-
if extra_requirements:
|
|
401
|
-
await a_install_requirements(extra_requirements)
|
|
402
|
-
|
|
403
|
-
# ===================================================================
|
|
404
|
-
# PUBLIC PROTOCOL IMPLEMENTATION
|
|
405
|
-
# ===================================================================
|
|
402
|
+
if hasattr(event, "type"): # pragma: no branch
|
|
403
|
+
if event.type == "input_request":
|
|
404
|
+
prompt = getattr(
|
|
405
|
+
event, "prompt", getattr(event.content, "prompt", "> ")
|
|
406
|
+
)
|
|
407
|
+
password = getattr(
|
|
408
|
+
event,
|
|
409
|
+
"password",
|
|
410
|
+
getattr(event.content, "password", False),
|
|
411
|
+
)
|
|
412
|
+
user_input = WaldiezBaseRunner.get_user_input(
|
|
413
|
+
prompt, password=password
|
|
414
|
+
)
|
|
415
|
+
event.content.respond(user_input)
|
|
416
|
+
else:
|
|
417
|
+
WaldiezBaseRunner._send(event)
|
|
406
418
|
|
|
407
419
|
def before_run(
|
|
408
420
|
self,
|
|
@@ -452,6 +464,42 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
452
464
|
uploads_root=uploads_root,
|
|
453
465
|
)
|
|
454
466
|
|
|
467
|
+
def prepare(
|
|
468
|
+
self,
|
|
469
|
+
output_path: str | Path | None,
|
|
470
|
+
uploads_root: str | Path | None,
|
|
471
|
+
) -> tuple[Path, Path, Path | None]:
|
|
472
|
+
"""Prepare the paths and environment for running the flow.
|
|
473
|
+
|
|
474
|
+
Parameters
|
|
475
|
+
----------
|
|
476
|
+
output_path : str | Path | None
|
|
477
|
+
The output path for the flow, by default None.
|
|
478
|
+
uploads_root : str | Path | None
|
|
479
|
+
The root path for uploads, by default None.
|
|
480
|
+
|
|
481
|
+
Returns
|
|
482
|
+
-------
|
|
483
|
+
tuple[Path, Path, Path | None]
|
|
484
|
+
A tuple containing:
|
|
485
|
+
- The path to the output file.
|
|
486
|
+
- The path to the temporary directory created for the run.
|
|
487
|
+
- The root path for uploads, if specified, otherwise None.
|
|
488
|
+
"""
|
|
489
|
+
output_file, uploads_root_path = self._prepare_paths(
|
|
490
|
+
output_path=output_path,
|
|
491
|
+
uploads_root=uploads_root,
|
|
492
|
+
)
|
|
493
|
+
temp_dir = self.before_run(
|
|
494
|
+
output_file=output_file,
|
|
495
|
+
uploads_root=uploads_root_path,
|
|
496
|
+
)
|
|
497
|
+
self.install_requirements()
|
|
498
|
+
refresh_environment()
|
|
499
|
+
return temp_dir, output_file, uploads_root_path
|
|
500
|
+
|
|
501
|
+
# noinspection PyProtocol
|
|
502
|
+
# pylint: disable=too-many-locals,unused-argument
|
|
455
503
|
def run(
|
|
456
504
|
self,
|
|
457
505
|
output_path: str | Path | None = None,
|
|
@@ -462,7 +510,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
462
510
|
dot_env: str | Path | None = None,
|
|
463
511
|
**kwargs: Any,
|
|
464
512
|
) -> list[dict[str, Any]]:
|
|
465
|
-
"""Run the Waldiez flow
|
|
513
|
+
"""Run the Waldiez flow.
|
|
466
514
|
|
|
467
515
|
Parameters
|
|
468
516
|
----------
|
|
@@ -471,10 +519,9 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
471
519
|
uploads_root : str | Path | None
|
|
472
520
|
The runtime uploads root, by default None.
|
|
473
521
|
structured_io : bool
|
|
474
|
-
Whether to use structured IO instead of the default 'input/print'
|
|
475
|
-
by default False.
|
|
522
|
+
Whether to use structured IO instead of the default 'input/print'.
|
|
476
523
|
skip_mmd : bool
|
|
477
|
-
Whether to skip generating the mermaid diagram
|
|
524
|
+
Whether to skip generating the mermaid diagram.
|
|
478
525
|
skip_timeline : bool
|
|
479
526
|
Whether to skip generating the timeline JSON.
|
|
480
527
|
dot_env : str | Path | None
|
|
@@ -485,12 +532,15 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
485
532
|
Returns
|
|
486
533
|
-------
|
|
487
534
|
list[dict[str, Any]]
|
|
488
|
-
The
|
|
535
|
+
The results of the run.
|
|
489
536
|
|
|
490
537
|
Raises
|
|
491
538
|
------
|
|
492
539
|
RuntimeError
|
|
493
|
-
If the runner is already running
|
|
540
|
+
If the runner is already running, the workflow is not async,
|
|
541
|
+
or an error occurs during the run.
|
|
542
|
+
StopRunningException
|
|
543
|
+
If the run is stopped by the user.
|
|
494
544
|
"""
|
|
495
545
|
if dot_env is not None:
|
|
496
546
|
resolved = Path(dot_env).resolve()
|
|
@@ -500,7 +550,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
500
550
|
WaldiezBaseRunner._structured_io = structured_io
|
|
501
551
|
if self.is_running():
|
|
502
552
|
raise RuntimeError("Workflow already running")
|
|
503
|
-
if self.
|
|
553
|
+
if self.is_async:
|
|
504
554
|
with start_blocking_portal(backend="asyncio") as portal:
|
|
505
555
|
return portal.call(
|
|
506
556
|
self.a_run,
|
|
@@ -509,19 +559,13 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
509
559
|
structured_io,
|
|
510
560
|
skip_mmd,
|
|
511
561
|
)
|
|
512
|
-
output_file, uploads_root_path = self.
|
|
562
|
+
temp_dir, output_file, uploads_root_path = self.prepare(
|
|
513
563
|
output_path=output_path,
|
|
514
564
|
uploads_root=uploads_root,
|
|
515
565
|
)
|
|
516
|
-
temp_dir = self.before_run(
|
|
517
|
-
output_file=output_file,
|
|
518
|
-
uploads_root=uploads_root_path,
|
|
519
|
-
)
|
|
520
|
-
self.install_requirements()
|
|
521
|
-
refresh_environment()
|
|
522
566
|
WaldiezBaseRunner._running = True
|
|
523
|
-
results: list[dict[str, Any]]
|
|
524
|
-
old_env_vars = set_env_vars(self.
|
|
567
|
+
results: list[dict[str, Any]]
|
|
568
|
+
old_env_vars = set_env_vars(self._waldiez.get_flow_env_vars())
|
|
525
569
|
try:
|
|
526
570
|
with chdir(to=temp_dir):
|
|
527
571
|
sys.path.insert(0, str(temp_dir))
|
|
@@ -532,6 +576,11 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
532
576
|
skip_mmd=skip_mmd,
|
|
533
577
|
skip_timeline=skip_timeline,
|
|
534
578
|
)
|
|
579
|
+
except (SystemExit, StopRunningException, KeyboardInterrupt) as exc:
|
|
580
|
+
raise StopRunningException(StopRunningException.reason) from exc
|
|
581
|
+
except BaseException as exc: # pylint: disable=broad-exception-caught
|
|
582
|
+
self.log.error("Error occurred while running workflow: %s", exc)
|
|
583
|
+
results = [{"error": str(exc)}]
|
|
535
584
|
finally:
|
|
536
585
|
WaldiezBaseRunner._running = False
|
|
537
586
|
reset_env_vars(old_env_vars)
|
|
@@ -548,7 +597,39 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
548
597
|
sys.path.pop(0)
|
|
549
598
|
return results
|
|
550
599
|
|
|
600
|
+
async def a_prepare(
|
|
601
|
+
self,
|
|
602
|
+
output_path: str | Path | None,
|
|
603
|
+
uploads_root: str | Path | None,
|
|
604
|
+
) -> tuple[Path, Path, Path | None]:
|
|
605
|
+
"""Prepare the paths for the async run.
|
|
606
|
+
|
|
607
|
+
Parameters
|
|
608
|
+
----------
|
|
609
|
+
output_path : str | Path | None
|
|
610
|
+
The output path, by default None.
|
|
611
|
+
uploads_root : str | Path | None
|
|
612
|
+
The uploads root path, by default None.
|
|
613
|
+
|
|
614
|
+
Returns
|
|
615
|
+
-------
|
|
616
|
+
tuple[Path, Path, Path | None]
|
|
617
|
+
The temporary directory, output file, and uploads root path.
|
|
618
|
+
"""
|
|
619
|
+
output_file, uploads_root_path = self._prepare_paths(
|
|
620
|
+
output_path=output_path,
|
|
621
|
+
uploads_root=uploads_root,
|
|
622
|
+
)
|
|
623
|
+
temp_dir = await self._a_before_run(
|
|
624
|
+
output_file=output_file,
|
|
625
|
+
uploads_root=uploads_root_path,
|
|
626
|
+
)
|
|
627
|
+
await self.a_install_requirements()
|
|
628
|
+
refresh_environment()
|
|
629
|
+
return temp_dir, output_file, uploads_root_path
|
|
630
|
+
|
|
551
631
|
# noinspection DuplicatedCode
|
|
632
|
+
# noinspection PyProtocol
|
|
552
633
|
async def a_run(
|
|
553
634
|
self,
|
|
554
635
|
output_path: str | Path | None = None,
|
|
@@ -566,28 +647,30 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
566
647
|
output_path : str | Path | None
|
|
567
648
|
The output path, by default None.
|
|
568
649
|
uploads_root : str | Path | None
|
|
569
|
-
The runtime uploads root
|
|
650
|
+
The runtime uploads root.
|
|
570
651
|
structured_io : bool
|
|
571
|
-
Whether to use structured IO instead of the default 'input/print'
|
|
572
|
-
by default False.
|
|
652
|
+
Whether to use structured IO instead of the default 'input/print'.
|
|
573
653
|
skip_mmd : bool
|
|
574
|
-
Whether to skip generating the mermaid diagram
|
|
654
|
+
Whether to skip generating the mermaid diagram.
|
|
575
655
|
skip_timeline : bool
|
|
576
|
-
Whether to skip generating the timeline JSON
|
|
656
|
+
Whether to skip generating the timeline JSON.
|
|
577
657
|
dot_env : str | Path | None
|
|
578
658
|
The path to the .env file, if any.
|
|
579
659
|
**kwargs : Any
|
|
580
|
-
Additional keyword arguments for the
|
|
660
|
+
Additional keyword arguments for the a_run method.
|
|
581
661
|
|
|
582
662
|
Returns
|
|
583
663
|
-------
|
|
584
664
|
list[dict[str, Any]]
|
|
585
|
-
The
|
|
665
|
+
The results of the run.
|
|
586
666
|
|
|
587
667
|
Raises
|
|
588
668
|
------
|
|
589
669
|
RuntimeError
|
|
590
|
-
If the runner is already running
|
|
670
|
+
If the runner is already running, the workflow is not async
|
|
671
|
+
or an error occurs during the run.
|
|
672
|
+
StopRunningException
|
|
673
|
+
If the run is stopped by the user.
|
|
591
674
|
"""
|
|
592
675
|
if dot_env is not None:
|
|
593
676
|
resolved = Path(dot_env).resolve()
|
|
@@ -597,19 +680,13 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
597
680
|
WaldiezBaseRunner._structured_io = structured_io
|
|
598
681
|
if self.is_running():
|
|
599
682
|
raise RuntimeError("Workflow already running")
|
|
600
|
-
output_file, uploads_root_path = self.
|
|
683
|
+
temp_dir, output_file, uploads_root_path = await self.a_prepare(
|
|
601
684
|
output_path=output_path,
|
|
602
685
|
uploads_root=uploads_root,
|
|
603
686
|
)
|
|
604
|
-
temp_dir = await self._a_before_run(
|
|
605
|
-
output_file=output_file,
|
|
606
|
-
uploads_root=uploads_root_path,
|
|
607
|
-
)
|
|
608
|
-
await self.a_install_requirements()
|
|
609
|
-
refresh_environment()
|
|
610
687
|
WaldiezBaseRunner._running = True
|
|
611
|
-
results: list[dict[str, Any]]
|
|
612
|
-
old_env_vars = set_env_vars(self.
|
|
688
|
+
results: list[dict[str, Any]]
|
|
689
|
+
old_env_vars = set_env_vars(self._waldiez.get_flow_env_vars())
|
|
613
690
|
try:
|
|
614
691
|
async with a_chdir(to=temp_dir):
|
|
615
692
|
sys.path.insert(0, str(temp_dir))
|
|
@@ -620,6 +697,10 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
620
697
|
skip_mmd=skip_mmd,
|
|
621
698
|
skip_timeline=skip_timeline,
|
|
622
699
|
)
|
|
700
|
+
except (SystemExit, StopRunningException, KeyboardInterrupt) as exc:
|
|
701
|
+
raise StopRunningException(StopRunningException.reason) from exc
|
|
702
|
+
except BaseException as exc: # pylint: disable=broad-exception-caught
|
|
703
|
+
results = [{"error": str(exc)}]
|
|
623
704
|
finally:
|
|
624
705
|
WaldiezBaseRunner._running = False
|
|
625
706
|
reset_env_vars(old_env_vars)
|
|
@@ -635,129 +716,6 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
635
716
|
sys.path.pop(0)
|
|
636
717
|
return results
|
|
637
718
|
|
|
638
|
-
def start(
|
|
639
|
-
self,
|
|
640
|
-
output_path: str | Path | None,
|
|
641
|
-
uploads_root: str | Path | None,
|
|
642
|
-
structured_io: bool | None = None,
|
|
643
|
-
skip_mmd: bool = False,
|
|
644
|
-
skip_timeline: bool = False,
|
|
645
|
-
dot_env: str | Path | None = None,
|
|
646
|
-
**kwargs: Any,
|
|
647
|
-
) -> None:
|
|
648
|
-
"""Start running the Waldiez flow in a non-blocking way.
|
|
649
|
-
|
|
650
|
-
Parameters
|
|
651
|
-
----------
|
|
652
|
-
output_path : str | Path | None
|
|
653
|
-
The output path.
|
|
654
|
-
uploads_root : str | Path | None
|
|
655
|
-
The runtime uploads root.
|
|
656
|
-
structured_io : bool | None
|
|
657
|
-
Whether to use structured IO instead of the default 'input/print'.
|
|
658
|
-
skip_mmd : bool
|
|
659
|
-
Whether to skip generating the mermaid diagram, by default False.
|
|
660
|
-
skip_timeline : bool
|
|
661
|
-
Whether to skip generating the timeline JSON, by default False.
|
|
662
|
-
dot_env : str | Path | None
|
|
663
|
-
The path to the .env file, if any.
|
|
664
|
-
**kwargs : Any
|
|
665
|
-
Additional keyword arguments for the start method.
|
|
666
|
-
|
|
667
|
-
Raises
|
|
668
|
-
------
|
|
669
|
-
RuntimeError
|
|
670
|
-
If the runner is already running.
|
|
671
|
-
"""
|
|
672
|
-
if dot_env is not None:
|
|
673
|
-
resolved = Path(dot_env).resolve()
|
|
674
|
-
if resolved.is_file():
|
|
675
|
-
WaldiezBaseRunner._dot_env_path = resolved
|
|
676
|
-
if structured_io is not None:
|
|
677
|
-
WaldiezBaseRunner._structured_io = structured_io
|
|
678
|
-
if self.is_running():
|
|
679
|
-
raise RuntimeError("Workflow already running")
|
|
680
|
-
output_file, uploads_root_path = self._prepare_paths(
|
|
681
|
-
output_path=output_path,
|
|
682
|
-
uploads_root=uploads_root,
|
|
683
|
-
)
|
|
684
|
-
temp_dir = self.before_run(
|
|
685
|
-
output_file=output_file,
|
|
686
|
-
uploads_root=uploads_root_path,
|
|
687
|
-
)
|
|
688
|
-
self.install_requirements()
|
|
689
|
-
refresh_environment()
|
|
690
|
-
WaldiezBaseRunner._running = True
|
|
691
|
-
self._start(
|
|
692
|
-
temp_dir=temp_dir,
|
|
693
|
-
output_file=output_file,
|
|
694
|
-
uploads_root=uploads_root_path,
|
|
695
|
-
skip_mmd=skip_mmd,
|
|
696
|
-
skip_timeline=skip_timeline,
|
|
697
|
-
)
|
|
698
|
-
|
|
699
|
-
# noinspection DuplicatedCode
|
|
700
|
-
async def a_start(
|
|
701
|
-
self,
|
|
702
|
-
output_path: str | Path | None,
|
|
703
|
-
uploads_root: str | Path | None,
|
|
704
|
-
structured_io: bool | None = None,
|
|
705
|
-
skip_mmd: bool = False,
|
|
706
|
-
skip_timeline: bool = False,
|
|
707
|
-
dot_env: str | Path | None = None,
|
|
708
|
-
**kwargs: Any,
|
|
709
|
-
) -> None:
|
|
710
|
-
"""Asynchronously start running the Waldiez flow in a non-blocking way.
|
|
711
|
-
|
|
712
|
-
Parameters
|
|
713
|
-
----------
|
|
714
|
-
output_path : str | Path | None
|
|
715
|
-
The output path.
|
|
716
|
-
uploads_root : str | Path | None
|
|
717
|
-
The runtime uploads root.
|
|
718
|
-
structured_io : bool | None = None
|
|
719
|
-
Whether to use structured IO instead of the default 'input/print'.
|
|
720
|
-
skip_mmd : bool = False
|
|
721
|
-
Whether to skip generating the mermaid diagram, by default False.
|
|
722
|
-
skip_timeline : bool = False
|
|
723
|
-
Whether to skip generating the timeline JSON, by default False.
|
|
724
|
-
dot_env : str | Path | None = None
|
|
725
|
-
The path to the .env file, if any.
|
|
726
|
-
**kwargs : Any
|
|
727
|
-
Additional keyword arguments for the start method.
|
|
728
|
-
|
|
729
|
-
Raises
|
|
730
|
-
------
|
|
731
|
-
RuntimeError
|
|
732
|
-
If the runner is already running.
|
|
733
|
-
"""
|
|
734
|
-
if dot_env is not None:
|
|
735
|
-
resolved = Path(dot_env).resolve()
|
|
736
|
-
if resolved.is_file():
|
|
737
|
-
WaldiezBaseRunner._dot_env_path = resolved
|
|
738
|
-
if structured_io is not None:
|
|
739
|
-
WaldiezBaseRunner._structured_io = structured_io
|
|
740
|
-
if self.is_running():
|
|
741
|
-
raise RuntimeError("Workflow already running")
|
|
742
|
-
output_file, uploads_root_path = self._prepare_paths(
|
|
743
|
-
output_path=output_path,
|
|
744
|
-
uploads_root=uploads_root,
|
|
745
|
-
)
|
|
746
|
-
temp_dir = await self._a_before_run(
|
|
747
|
-
output_file=output_file,
|
|
748
|
-
uploads_root=uploads_root_path,
|
|
749
|
-
)
|
|
750
|
-
await self.a_install_requirements()
|
|
751
|
-
refresh_environment()
|
|
752
|
-
WaldiezBaseRunner._running = True
|
|
753
|
-
await self._a_start(
|
|
754
|
-
temp_dir=temp_dir,
|
|
755
|
-
output_file=output_file,
|
|
756
|
-
uploads_root=uploads_root_path,
|
|
757
|
-
skip_mmd=skip_mmd,
|
|
758
|
-
skip_timeline=skip_timeline,
|
|
759
|
-
)
|
|
760
|
-
|
|
761
719
|
def after_run(
|
|
762
720
|
self,
|
|
763
721
|
results: list[dict[str, Any]],
|
|
@@ -828,28 +786,6 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
828
786
|
skip_timeline=skip_timeline,
|
|
829
787
|
)
|
|
830
788
|
|
|
831
|
-
def stop(self) -> None:
|
|
832
|
-
"""Stop the runner if it is running."""
|
|
833
|
-
if not self.is_running():
|
|
834
|
-
return
|
|
835
|
-
try:
|
|
836
|
-
self._stop()
|
|
837
|
-
finally:
|
|
838
|
-
WaldiezBaseRunner._running = False
|
|
839
|
-
|
|
840
|
-
async def a_stop(self) -> None:
|
|
841
|
-
"""Asynchronously stop the runner if it is running."""
|
|
842
|
-
if not self.is_running():
|
|
843
|
-
return
|
|
844
|
-
try:
|
|
845
|
-
await self._a_stop()
|
|
846
|
-
finally:
|
|
847
|
-
WaldiezBaseRunner._running = False
|
|
848
|
-
|
|
849
|
-
# ===================================================================
|
|
850
|
-
# PROPERTIES AND CONTEXT MANAGERS
|
|
851
|
-
# ===================================================================
|
|
852
|
-
|
|
853
789
|
@property
|
|
854
790
|
def waldiez(self) -> Waldiez:
|
|
855
791
|
"""Get the Waldiez instance."""
|
|
@@ -858,7 +794,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
858
794
|
@property
|
|
859
795
|
def is_async(self) -> bool:
|
|
860
796
|
"""Check if the workflow is async."""
|
|
861
|
-
return self.
|
|
797
|
+
return self._waldiez.is_async
|
|
862
798
|
|
|
863
799
|
@property
|
|
864
800
|
def running(self) -> bool:
|
|
@@ -952,6 +888,27 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
952
888
|
dot_env=dot_env,
|
|
953
889
|
)
|
|
954
890
|
|
|
891
|
+
def stop(self) -> None:
|
|
892
|
+
"""Stop the workflow execution.
|
|
893
|
+
|
|
894
|
+
This method sets the stop flag that will be checked by the event
|
|
895
|
+
handlers and other parts of the workflow execution to gracefully
|
|
896
|
+
terminate the workflow execution.
|
|
897
|
+
Note: Stopping will occur at the "next" AutoGen event, not immediately.
|
|
898
|
+
"""
|
|
899
|
+
self.log.info("Stop requested - setting stop flag")
|
|
900
|
+
self._stop_requested.set()
|
|
901
|
+
|
|
902
|
+
def is_stop_requested(self) -> bool:
|
|
903
|
+
"""Check if a stop has been requested.
|
|
904
|
+
|
|
905
|
+
Returns
|
|
906
|
+
-------
|
|
907
|
+
bool
|
|
908
|
+
True if stop has been requested, False otherwise.
|
|
909
|
+
"""
|
|
910
|
+
return self._stop_requested.is_set()
|
|
911
|
+
|
|
955
912
|
def __enter__(self) -> Self:
|
|
956
913
|
"""Enter the context manager."""
|
|
957
914
|
return self
|
|
@@ -968,7 +925,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
968
925
|
) -> None:
|
|
969
926
|
"""Exit the context manager."""
|
|
970
927
|
if self.is_running():
|
|
971
|
-
self.
|
|
928
|
+
self._stop_requested.set()
|
|
972
929
|
|
|
973
930
|
async def __aexit__(
|
|
974
931
|
self,
|
|
@@ -978,4 +935,4 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
|
|
|
978
935
|
) -> None:
|
|
979
936
|
"""Exit the context manager asynchronously."""
|
|
980
937
|
if self.is_running():
|
|
981
|
-
|
|
938
|
+
self._stop_requested.set()
|