waldiez 0.6.0__py3-none-any.whl → 0.6.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.
Potentially problematic release.
This version of waldiez might be problematic. Click here for more details.
- waldiez/__init__.py +1 -1
- waldiez/_version.py +1 -1
- waldiez/cli.py +18 -7
- waldiez/cli_extras/jupyter.py +3 -0
- waldiez/cli_extras/runner.py +3 -1
- waldiez/cli_extras/studio.py +3 -1
- waldiez/exporter.py +9 -3
- waldiez/exporting/agent/exporter.py +9 -10
- waldiez/exporting/agent/extras/captain_agent_extras.py +6 -6
- waldiez/exporting/agent/extras/doc_agent_extras.py +6 -6
- waldiez/exporting/agent/extras/group_manager_agent_extas.py +34 -23
- waldiez/exporting/agent/extras/group_member_extras.py +6 -5
- waldiez/exporting/agent/extras/handoffs/after_work.py +1 -1
- waldiez/exporting/agent/extras/handoffs/available.py +1 -1
- waldiez/exporting/agent/extras/handoffs/condition.py +3 -2
- waldiez/exporting/agent/extras/handoffs/handoff.py +1 -1
- waldiez/exporting/agent/extras/handoffs/target.py +6 -4
- waldiez/exporting/agent/extras/rag/chroma_extras.py +27 -19
- waldiez/exporting/agent/extras/rag/mongo_extras.py +8 -8
- waldiez/exporting/agent/extras/rag/pgvector_extras.py +5 -5
- waldiez/exporting/agent/extras/rag/qdrant_extras.py +5 -4
- waldiez/exporting/agent/extras/rag/vector_db_extras.py +1 -1
- waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +5 -7
- waldiez/exporting/agent/extras/reasoning_agent_extras.py +3 -5
- waldiez/exporting/chats/exporter.py +4 -4
- waldiez/exporting/chats/processor.py +1 -2
- waldiez/exporting/chats/utils/common.py +89 -48
- waldiez/exporting/chats/utils/group.py +9 -9
- waldiez/exporting/chats/utils/nested.py +7 -7
- waldiez/exporting/chats/utils/sequential.py +1 -1
- waldiez/exporting/chats/utils/single.py +2 -2
- waldiez/exporting/core/content.py +7 -7
- waldiez/exporting/core/context.py +5 -3
- waldiez/exporting/core/exporter.py +5 -3
- waldiez/exporting/core/exporters.py +2 -2
- waldiez/exporting/core/extras/agent_extras/captain_extras.py +2 -2
- waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +2 -2
- waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +2 -2
- waldiez/exporting/core/extras/agent_extras/standard_extras.py +3 -8
- waldiez/exporting/core/extras/base.py +7 -5
- waldiez/exporting/core/extras/flow_extras.py +4 -5
- waldiez/exporting/core/extras/model_extras.py +2 -2
- waldiez/exporting/core/extras/path_resolver.py +1 -2
- waldiez/exporting/core/extras/serializer.py +2 -2
- waldiez/exporting/core/protocols.py +6 -5
- waldiez/exporting/core/result.py +25 -28
- waldiez/exporting/core/types.py +10 -10
- waldiez/exporting/core/utils/llm_config.py +2 -2
- waldiez/exporting/core/validation.py +10 -11
- waldiez/exporting/flow/execution_generator.py +98 -10
- waldiez/exporting/flow/exporter.py +2 -2
- waldiez/exporting/flow/factory.py +2 -2
- waldiez/exporting/flow/file_generator.py +4 -2
- waldiez/exporting/flow/merger.py +5 -3
- waldiez/exporting/flow/orchestrator.py +72 -2
- waldiez/exporting/flow/utils/common.py +5 -5
- waldiez/exporting/flow/utils/importing.py +6 -7
- waldiez/exporting/flow/utils/linting.py +25 -9
- waldiez/exporting/flow/utils/logging.py +2 -2
- waldiez/exporting/models/exporter.py +8 -8
- waldiez/exporting/models/processor.py +5 -5
- waldiez/exporting/tools/exporter.py +2 -2
- waldiez/exporting/tools/processor.py +7 -4
- waldiez/io/__init__.py +8 -4
- waldiez/io/_ws.py +10 -6
- waldiez/io/models/constants.py +10 -10
- waldiez/io/models/content/audio.py +1 -0
- waldiez/io/models/content/base.py +20 -18
- waldiez/io/models/content/file.py +1 -0
- waldiez/io/models/content/image.py +1 -0
- waldiez/io/models/content/text.py +1 -0
- waldiez/io/models/content/video.py +1 -0
- waldiez/io/models/user_input.py +10 -5
- waldiez/io/models/user_response.py +17 -16
- waldiez/io/mqtt.py +18 -31
- waldiez/io/redis.py +18 -22
- waldiez/io/structured.py +52 -53
- waldiez/io/utils.py +3 -0
- waldiez/io/ws.py +5 -1
- waldiez/logger.py +16 -3
- waldiez/models/agents/__init__.py +3 -0
- waldiez/models/agents/agent/agent.py +23 -16
- waldiez/models/agents/agent/agent_data.py +25 -22
- waldiez/models/agents/agent/code_execution.py +9 -11
- waldiez/models/agents/agent/termination_message.py +10 -12
- waldiez/models/agents/agent/update_system_message.py +2 -4
- waldiez/models/agents/agents.py +8 -8
- waldiez/models/agents/assistant/assistant.py +6 -3
- waldiez/models/agents/assistant/assistant_data.py +2 -2
- waldiez/models/agents/captain/captain_agent.py +7 -4
- waldiez/models/agents/captain/captain_agent_data.py +5 -7
- waldiez/models/agents/doc_agent/doc_agent.py +7 -4
- waldiez/models/agents/doc_agent/doc_agent_data.py +9 -10
- waldiez/models/agents/doc_agent/rag_query_engine.py +10 -12
- waldiez/models/agents/extra_requirements.py +3 -3
- waldiez/models/agents/group_manager/group_manager.py +12 -7
- waldiez/models/agents/group_manager/group_manager_data.py +13 -12
- waldiez/models/agents/group_manager/speakers.py +17 -19
- waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +7 -4
- waldiez/models/agents/rag_user_proxy/rag_user_proxy_data.py +4 -1
- waldiez/models/agents/rag_user_proxy/retrieve_config.py +69 -63
- waldiez/models/agents/rag_user_proxy/vector_db_config.py +19 -19
- waldiez/models/agents/reasoning/reasoning_agent.py +7 -4
- waldiez/models/agents/reasoning/reasoning_agent_data.py +3 -2
- waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +8 -8
- waldiez/models/agents/user_proxy/user_proxy.py +6 -3
- waldiez/models/agents/user_proxy/user_proxy_data.py +1 -1
- waldiez/models/chat/chat.py +27 -20
- waldiez/models/chat/chat_data.py +22 -19
- waldiez/models/chat/chat_message.py +9 -9
- waldiez/models/chat/chat_nested.py +9 -9
- waldiez/models/chat/chat_summary.py +6 -6
- waldiez/models/common/__init__.py +2 -0
- waldiez/models/common/ag2_version.py +2 -0
- waldiez/models/common/dict_utils.py +8 -6
- waldiez/models/common/handoff.py +18 -17
- waldiez/models/common/method_utils.py +7 -7
- waldiez/models/common/naming.py +49 -0
- waldiez/models/flow/flow.py +11 -6
- waldiez/models/flow/flow_data.py +23 -17
- waldiez/models/flow/info.py +3 -3
- waldiez/models/flow/naming.py +2 -1
- waldiez/models/model/_aws.py +11 -13
- waldiez/models/model/_llm.py +5 -0
- waldiez/models/model/_price.py +2 -4
- waldiez/models/model/extra_requirements.py +1 -3
- waldiez/models/model/model.py +2 -2
- waldiez/models/model/model_data.py +21 -21
- waldiez/models/tool/extra_requirements.py +2 -4
- waldiez/models/tool/predefined/_duckduckgo.py +1 -0
- waldiez/models/tool/predefined/_email.py +1 -0
- waldiez/models/tool/predefined/_google.py +1 -0
- waldiez/models/tool/predefined/_perplexity.py +1 -0
- waldiez/models/tool/predefined/_searxng.py +1 -0
- waldiez/models/tool/predefined/_tavily.py +1 -0
- waldiez/models/tool/predefined/_wikipedia.py +1 -0
- waldiez/models/tool/predefined/_youtube.py +1 -0
- waldiez/models/tool/tool.py +8 -5
- waldiez/models/tool/tool_data.py +2 -2
- waldiez/models/waldiez.py +152 -4
- waldiez/runner.py +11 -5
- waldiez/running/async_utils.py +192 -0
- waldiez/running/base_runner.py +117 -264
- waldiez/running/dir_utils.py +52 -0
- waldiez/running/environment.py +10 -44
- waldiez/running/events_mixin.py +252 -0
- waldiez/running/exceptions.py +20 -0
- waldiez/running/gen_seq_diagram.py +18 -15
- waldiez/running/io_utils.py +216 -0
- waldiez/running/protocol.py +11 -5
- waldiez/running/requirements_mixin.py +65 -0
- waldiez/running/results_mixin.py +926 -0
- waldiez/running/standard_runner.py +22 -25
- waldiez/running/step_by_step/breakpoints_mixin.py +192 -60
- waldiez/running/step_by_step/command_handler.py +3 -0
- waldiez/running/step_by_step/events_processor.py +194 -14
- waldiez/running/step_by_step/step_by_step_models.py +110 -43
- waldiez/running/step_by_step/step_by_step_runner.py +107 -57
- waldiez/running/subprocess_runner/__base__.py +9 -1
- waldiez/running/subprocess_runner/_async_runner.py +5 -3
- waldiez/running/subprocess_runner/_sync_runner.py +6 -2
- waldiez/running/subprocess_runner/runner.py +39 -23
- waldiez/running/timeline_processor.py +1 -1
- waldiez/utils/__init__.py +2 -0
- waldiez/utils/conflict_checker.py +4 -4
- waldiez/utils/python_manager.py +415 -0
- waldiez/ws/_file_handler.py +18 -18
- waldiez/ws/_mock.py +2 -1
- waldiez/ws/cli.py +36 -12
- waldiez/ws/client_manager.py +35 -27
- waldiez/ws/errors.py +3 -0
- waldiez/ws/models.py +43 -52
- waldiez/ws/reloader.py +12 -4
- waldiez/ws/server.py +85 -55
- waldiez/ws/session_manager.py +8 -9
- waldiez/ws/session_stats.py +1 -1
- waldiez/ws/utils.py +4 -1
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/METADATA +82 -93
- waldiez-0.6.1.dist-info/RECORD +254 -0
- waldiez/running/post_run.py +0 -186
- waldiez/running/pre_run.py +0 -281
- waldiez/running/run_results.py +0 -14
- waldiez/running/utils.py +0 -625
- waldiez-0.6.0.dist-info/RECORD +0 -251
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/WHEEL +0 -0
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/entry_points.txt +0 -0
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/NOTICE.md +0 -0
waldiez/running/base_runner.py
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
|
|
4
4
|
# pyright: reportUnknownMemberType=false, reportAttributeAccessIssue=false
|
|
5
|
-
# pyright: reportUnknownArgumentType=false
|
|
5
|
+
# pyright: reportUnknownArgumentType=false, reportUnusedParameter=false
|
|
6
6
|
"""Base runner for Waldiez workflows."""
|
|
7
7
|
|
|
8
8
|
import importlib.util
|
|
9
|
-
import inspect
|
|
10
9
|
import json
|
|
11
10
|
import shutil
|
|
12
11
|
import sys
|
|
@@ -14,72 +13,35 @@ import tempfile
|
|
|
14
13
|
import threading
|
|
15
14
|
from pathlib import Path
|
|
16
15
|
from types import ModuleType, TracebackType
|
|
17
|
-
from typing import
|
|
16
|
+
from typing import Any
|
|
18
17
|
|
|
19
18
|
from aiofiles.os import wrap
|
|
20
19
|
from anyio.from_thread import start_blocking_portal
|
|
21
|
-
from typing_extensions import Self
|
|
20
|
+
from typing_extensions import Self, override
|
|
22
21
|
|
|
23
22
|
from waldiez.exporter import WaldiezExporter
|
|
24
23
|
from waldiez.logger import WaldiezLogger, get_logger
|
|
25
24
|
from waldiez.models import Waldiez
|
|
26
25
|
|
|
27
|
-
from .
|
|
26
|
+
from .dir_utils import a_chdir, chdir
|
|
27
|
+
from .environment import reset_env_vars, set_env_vars
|
|
28
|
+
from .events_mixin import EventsMixin
|
|
28
29
|
from .exceptions import StopRunningException
|
|
29
|
-
from .post_run import after_run
|
|
30
|
-
from .pre_run import RequirementsMixin, dump_waldiez
|
|
31
30
|
from .protocol import WaldiezRunnerProtocol
|
|
32
|
-
from .
|
|
33
|
-
|
|
34
|
-
chdir,
|
|
35
|
-
input_async,
|
|
36
|
-
input_sync,
|
|
37
|
-
is_async_callable,
|
|
38
|
-
syncify,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
if TYPE_CHECKING:
|
|
42
|
-
# pylint: disable=line-too-long
|
|
43
|
-
from autogen.events import ( # type: ignore[import-untyped,import-not-found,unused-ignore] # noqa: E501
|
|
44
|
-
BaseEvent,
|
|
45
|
-
)
|
|
46
|
-
from autogen.messages import ( # type: ignore[import-untyped,import-not-found,unused-ignore] # noqa: E501
|
|
47
|
-
BaseMessage,
|
|
48
|
-
)
|
|
31
|
+
from .requirements_mixin import RequirementsMixin
|
|
32
|
+
from .results_mixin import ResultsMixin
|
|
49
33
|
|
|
50
34
|
|
|
51
35
|
# pylint: disable=too-many-public-methods
|
|
52
|
-
class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
53
|
-
"""Base runner for Waldiez.
|
|
54
|
-
|
|
55
|
-
Initialization parameters:
|
|
56
|
-
- waldiez: The Waldiez flow to run.
|
|
57
|
-
- output_path: Path to save the output file.
|
|
58
|
-
- uploads_root: Root directory for uploads.
|
|
59
|
-
- structured_io: Whether to use structured I/O.
|
|
60
|
-
- dot_env: Path to a .env file for environment variables.
|
|
61
|
-
|
|
62
|
-
Methods to possibly override:
|
|
63
|
-
- prepare: Prepare the environment and paths for running the flow.
|
|
64
|
-
- _before_run: Actions to perform before running the flow.
|
|
65
|
-
- a_prepare: Async version of the prepare method.
|
|
66
|
-
- _a_before_run: Async actions to perform before running the flow.
|
|
67
|
-
- _run: Actual implementation of the run logic.
|
|
68
|
-
- _a_run: Async implementation of the run logic.
|
|
69
|
-
- _after_run: Actions to perform after running the flow.
|
|
70
|
-
- _a_after_run: Async actions to perform after running the flow.
|
|
71
|
-
"""
|
|
36
|
+
class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin, ResultsMixin):
|
|
37
|
+
"""Base runner for Waldiez."""
|
|
72
38
|
|
|
73
39
|
_structured_io: bool
|
|
74
40
|
_output_path: str | Path | None
|
|
75
41
|
_uploads_root: str | Path | None
|
|
76
42
|
_dot_env_path: str | Path | None
|
|
77
43
|
_running: bool
|
|
78
|
-
_is_async: bool
|
|
79
44
|
_waldiez_file: Path
|
|
80
|
-
_input: Callable[..., str] | Callable[..., Coroutine[Any, Any, str]]
|
|
81
|
-
_print: Callable[..., None]
|
|
82
|
-
_send: Callable[[Union["BaseEvent", "BaseMessage"]], None]
|
|
83
45
|
|
|
84
46
|
def __init__(
|
|
85
47
|
self,
|
|
@@ -96,10 +58,11 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
96
58
|
WaldiezBaseRunner._output_path = output_path
|
|
97
59
|
WaldiezBaseRunner._uploads_root = uploads_root
|
|
98
60
|
WaldiezBaseRunner._dot_env_path = dot_env
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
61
|
+
EventsMixin.set_input_function(input)
|
|
62
|
+
EventsMixin.set_print_function(print)
|
|
63
|
+
EventsMixin.set_send_function(print)
|
|
64
|
+
EventsMixin.set_async(waldiez.is_async)
|
|
65
|
+
RequirementsMixin.__init__(self)
|
|
103
66
|
self._waldiez = waldiez
|
|
104
67
|
self._called_install_requirements = False
|
|
105
68
|
self._exporter = WaldiezExporter(waldiez)
|
|
@@ -119,14 +82,15 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
119
82
|
elif isinstance(waldiez_file, Path):
|
|
120
83
|
waldiez_file_path = waldiez_file.resolve()
|
|
121
84
|
else:
|
|
122
|
-
waldiez_file_path =
|
|
85
|
+
waldiez_file_path = waldiez.dump(to=output_path)
|
|
123
86
|
if not waldiez_file_path or not waldiez_file_path.is_file():
|
|
124
87
|
raise ValueError("Could not resolve a waldiez file path")
|
|
125
88
|
WaldiezBaseRunner._waldiez_file = waldiez_file_path
|
|
126
89
|
|
|
90
|
+
@override
|
|
127
91
|
@staticmethod
|
|
128
92
|
def print(*args: Any, **kwargs: Any) -> None:
|
|
129
|
-
"""Print a message to the
|
|
93
|
+
"""Print a message to the output stream.
|
|
130
94
|
|
|
131
95
|
Parameters
|
|
132
96
|
----------
|
|
@@ -137,10 +101,11 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
137
101
|
"""
|
|
138
102
|
if len(args) == 1 and isinstance(args[0], dict):
|
|
139
103
|
arg = json.dumps(args[0], default=str, ensure_ascii=False)
|
|
140
|
-
|
|
104
|
+
EventsMixin.do_print(arg, **kwargs)
|
|
141
105
|
else:
|
|
142
|
-
|
|
106
|
+
EventsMixin.do_print(*args, **kwargs)
|
|
143
107
|
|
|
108
|
+
@override
|
|
144
109
|
def is_running(self) -> bool:
|
|
145
110
|
"""Check if the workflow is currently running.
|
|
146
111
|
|
|
@@ -152,99 +117,6 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
152
117
|
with self._running_lock:
|
|
153
118
|
return WaldiezBaseRunner._running
|
|
154
119
|
|
|
155
|
-
@staticmethod
|
|
156
|
-
def get_input_function() -> (
|
|
157
|
-
Callable[..., str] | Callable[..., Coroutine[Any, Any, str]]
|
|
158
|
-
):
|
|
159
|
-
"""Get the input function for user interaction.
|
|
160
|
-
|
|
161
|
-
Returns
|
|
162
|
-
-------
|
|
163
|
-
Callable[[str, bool], str]
|
|
164
|
-
A function that takes a prompt and a password flag,
|
|
165
|
-
returning user input.
|
|
166
|
-
"""
|
|
167
|
-
if hasattr(WaldiezBaseRunner, "_input") and callable(
|
|
168
|
-
WaldiezBaseRunner._input
|
|
169
|
-
):
|
|
170
|
-
return WaldiezBaseRunner._input
|
|
171
|
-
if WaldiezBaseRunner._is_async:
|
|
172
|
-
return input_async
|
|
173
|
-
return input_sync
|
|
174
|
-
|
|
175
|
-
@staticmethod
|
|
176
|
-
async def a_get_user_input(
|
|
177
|
-
prompt: str, *, password: bool = False, **kwargs: Any
|
|
178
|
-
) -> str:
|
|
179
|
-
"""Get user input with an optional password prompt.
|
|
180
|
-
|
|
181
|
-
Parameters
|
|
182
|
-
----------
|
|
183
|
-
prompt : str
|
|
184
|
-
The prompt to display to the user.
|
|
185
|
-
password : bool, optional
|
|
186
|
-
If True, the input will be hidden (default is False).
|
|
187
|
-
**kwargs : Any
|
|
188
|
-
Additional keyword arguments to pass to the input function.
|
|
189
|
-
|
|
190
|
-
Returns
|
|
191
|
-
-------
|
|
192
|
-
str
|
|
193
|
-
The user input.
|
|
194
|
-
"""
|
|
195
|
-
input_function = WaldiezBaseRunner.get_input_function()
|
|
196
|
-
if is_async_callable(input_function):
|
|
197
|
-
try:
|
|
198
|
-
result = await input_function( # type: ignore
|
|
199
|
-
prompt,
|
|
200
|
-
password=password,
|
|
201
|
-
**kwargs,
|
|
202
|
-
)
|
|
203
|
-
except TypeError:
|
|
204
|
-
result = await input_function(prompt) # type: ignore
|
|
205
|
-
else:
|
|
206
|
-
try:
|
|
207
|
-
result = input_function(prompt, password=password, **kwargs)
|
|
208
|
-
except TypeError:
|
|
209
|
-
result = input_function(prompt)
|
|
210
|
-
return result # pyright: ignore
|
|
211
|
-
|
|
212
|
-
@staticmethod
|
|
213
|
-
def get_user_input(
|
|
214
|
-
prompt: str,
|
|
215
|
-
*,
|
|
216
|
-
password: bool = False,
|
|
217
|
-
**kwargs: Any,
|
|
218
|
-
) -> str:
|
|
219
|
-
"""Get user input with an optional password prompt.
|
|
220
|
-
|
|
221
|
-
Parameters
|
|
222
|
-
----------
|
|
223
|
-
prompt : str
|
|
224
|
-
The prompt to display to the user.
|
|
225
|
-
password : bool, optional
|
|
226
|
-
If True, the input will be hidden (default is False).
|
|
227
|
-
**kwargs : Any
|
|
228
|
-
Additional keyword arguments to pass to the input function.
|
|
229
|
-
|
|
230
|
-
Returns
|
|
231
|
-
-------
|
|
232
|
-
str
|
|
233
|
-
The user input.
|
|
234
|
-
"""
|
|
235
|
-
input_function = WaldiezBaseRunner.get_input_function()
|
|
236
|
-
if inspect.iscoroutinefunction(input_function):
|
|
237
|
-
try:
|
|
238
|
-
return syncify(input_function)(
|
|
239
|
-
prompt, password=password, **kwargs
|
|
240
|
-
)
|
|
241
|
-
except TypeError:
|
|
242
|
-
return syncify(input_function)(prompt)
|
|
243
|
-
try:
|
|
244
|
-
return str(input_function(prompt, password=password, **kwargs))
|
|
245
|
-
except TypeError:
|
|
246
|
-
return str(input_function(prompt))
|
|
247
|
-
|
|
248
120
|
def _load_module(self, output_file: Path, temp_dir: Path) -> ModuleType:
|
|
249
121
|
"""Load the module from the waldiez file."""
|
|
250
122
|
file_name = output_file.name
|
|
@@ -270,7 +142,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
270
142
|
) -> Path:
|
|
271
143
|
"""Run before the flow execution."""
|
|
272
144
|
self.log.info("Preparing workflow file: %s", output_file)
|
|
273
|
-
temp_dir = Path(tempfile.mkdtemp())
|
|
145
|
+
temp_dir = Path(tempfile.mkdtemp(prefix="wlz-"))
|
|
274
146
|
file_name = output_file.name
|
|
275
147
|
with chdir(to=temp_dir):
|
|
276
148
|
self._exporter.export(
|
|
@@ -340,13 +212,14 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
340
212
|
def _after_run(
|
|
341
213
|
self,
|
|
342
214
|
results: list[dict[str, Any]],
|
|
215
|
+
error: BaseException | None,
|
|
343
216
|
output_file: Path,
|
|
344
217
|
waldiez_file: Path,
|
|
345
218
|
uploads_root: Path | None,
|
|
346
219
|
temp_dir: Path,
|
|
347
220
|
skip_mmd: bool,
|
|
348
221
|
skip_timeline: bool,
|
|
349
|
-
) -> None:
|
|
222
|
+
) -> Path | None:
|
|
350
223
|
"""Run after the flow execution."""
|
|
351
224
|
# Save results
|
|
352
225
|
self._last_results = results
|
|
@@ -355,7 +228,9 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
355
228
|
self._stop_requested.clear()
|
|
356
229
|
# pylint: disable=broad-exception-caught
|
|
357
230
|
try:
|
|
358
|
-
|
|
231
|
+
return ResultsMixin.post_run(
|
|
232
|
+
results=results,
|
|
233
|
+
error=error,
|
|
359
234
|
temp_dir=temp_dir,
|
|
360
235
|
output_file=output_file,
|
|
361
236
|
flow_name=self._waldiez.name,
|
|
@@ -367,27 +242,39 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
367
242
|
except BaseException as exc: # pragma: no cover
|
|
368
243
|
self.log.warning("Error occurred during after_run: %s", exc)
|
|
369
244
|
self.log.info("Cleanup completed")
|
|
245
|
+
return None
|
|
370
246
|
|
|
371
247
|
async def _a_after_run(
|
|
372
248
|
self,
|
|
373
249
|
results: list[dict[str, Any]],
|
|
250
|
+
error: BaseException | None,
|
|
374
251
|
output_file: Path,
|
|
375
252
|
waldiez_file: Path,
|
|
376
253
|
uploads_root: Path | None,
|
|
377
254
|
temp_dir: Path,
|
|
378
255
|
skip_mmd: bool,
|
|
379
256
|
skip_timeline: bool,
|
|
380
|
-
) -> None:
|
|
257
|
+
) -> Path | None:
|
|
381
258
|
"""Run after the flow execution asynchronously."""
|
|
382
|
-
self.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
259
|
+
self._last_results = results
|
|
260
|
+
self._stop_requested.clear()
|
|
261
|
+
# pylint: disable=broad-exception-caught
|
|
262
|
+
try:
|
|
263
|
+
return await ResultsMixin.a_post_run(
|
|
264
|
+
results=results,
|
|
265
|
+
error=error,
|
|
266
|
+
temp_dir=temp_dir,
|
|
267
|
+
output_file=output_file,
|
|
268
|
+
flow_name=self._waldiez.name,
|
|
269
|
+
waldiez_file=waldiez_file,
|
|
270
|
+
uploads_root=uploads_root,
|
|
271
|
+
skip_mmd=skip_mmd,
|
|
272
|
+
skip_timeline=skip_timeline,
|
|
273
|
+
)
|
|
274
|
+
except BaseException as exc: # pragma: no cover
|
|
275
|
+
self.log.warning("Error occurred during a_after_run: %s", exc)
|
|
276
|
+
self.log.info("Cleanup completed")
|
|
277
|
+
return None
|
|
391
278
|
|
|
392
279
|
@staticmethod
|
|
393
280
|
def _prepare_paths(
|
|
@@ -408,68 +295,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
408
295
|
output_file: Path = Path(WaldiezBaseRunner._output_path)
|
|
409
296
|
return output_file, uploads_root_path
|
|
410
297
|
|
|
411
|
-
@
|
|
412
|
-
async def a_process_event(
|
|
413
|
-
event: Union["BaseEvent", "BaseMessage"],
|
|
414
|
-
skip_send: bool = False,
|
|
415
|
-
) -> None:
|
|
416
|
-
"""Process an event or message asynchronously.
|
|
417
|
-
|
|
418
|
-
Parameters
|
|
419
|
-
----------
|
|
420
|
-
event : Union[BaseEvent, BaseMessage]
|
|
421
|
-
The event or message to process.
|
|
422
|
-
skip_send : bool
|
|
423
|
-
Skip sending the event.
|
|
424
|
-
"""
|
|
425
|
-
if hasattr(event, "type"): # pragma: no branch
|
|
426
|
-
if event.type == "input_request":
|
|
427
|
-
prompt = getattr(
|
|
428
|
-
event, "prompt", getattr(event.content, "prompt", "> ")
|
|
429
|
-
)
|
|
430
|
-
password = getattr(
|
|
431
|
-
event,
|
|
432
|
-
"password",
|
|
433
|
-
getattr(event.content, "password", False),
|
|
434
|
-
)
|
|
435
|
-
user_input = await WaldiezBaseRunner.a_get_user_input(
|
|
436
|
-
prompt, password=password
|
|
437
|
-
)
|
|
438
|
-
await event.content.respond(user_input)
|
|
439
|
-
elif not skip_send:
|
|
440
|
-
WaldiezBaseRunner._send(event)
|
|
441
|
-
|
|
442
|
-
@staticmethod
|
|
443
|
-
def process_event(
|
|
444
|
-
event: Union["BaseEvent", "BaseMessage"],
|
|
445
|
-
skip_send: bool = False,
|
|
446
|
-
) -> None:
|
|
447
|
-
"""Process an event or message synchronously.
|
|
448
|
-
|
|
449
|
-
Parameters
|
|
450
|
-
----------
|
|
451
|
-
event : Union[BaseEvent, BaseMessage]
|
|
452
|
-
The event or message to process.
|
|
453
|
-
skip_send : bool
|
|
454
|
-
Skip sending the event.
|
|
455
|
-
"""
|
|
456
|
-
if hasattr(event, "type"): # pragma: no branch
|
|
457
|
-
if event.type == "input_request":
|
|
458
|
-
prompt = getattr(
|
|
459
|
-
event, "prompt", getattr(event.content, "prompt", "> ")
|
|
460
|
-
)
|
|
461
|
-
password = getattr(
|
|
462
|
-
event,
|
|
463
|
-
"password",
|
|
464
|
-
getattr(event.content, "password", False),
|
|
465
|
-
)
|
|
466
|
-
user_input = WaldiezBaseRunner.get_user_input(
|
|
467
|
-
prompt, password=password
|
|
468
|
-
)
|
|
469
|
-
event.content.respond(user_input)
|
|
470
|
-
elif not skip_send:
|
|
471
|
-
WaldiezBaseRunner._send(event)
|
|
472
|
-
|
|
298
|
+
@override
|
|
473
299
|
def before_run(
|
|
474
300
|
self,
|
|
475
301
|
output_file: Path,
|
|
@@ -494,6 +320,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
494
320
|
uploads_root=uploads_root,
|
|
495
321
|
)
|
|
496
322
|
|
|
323
|
+
@override
|
|
497
324
|
async def a_before_run(
|
|
498
325
|
self,
|
|
499
326
|
output_file: Path,
|
|
@@ -549,11 +376,11 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
549
376
|
uploads_root=uploads_root_path,
|
|
550
377
|
)
|
|
551
378
|
self.install_requirements()
|
|
552
|
-
refresh_environment()
|
|
553
379
|
return temp_dir, output_file, uploads_root_path
|
|
554
380
|
|
|
555
381
|
# noinspection PyProtocol
|
|
556
382
|
# pylint: disable=too-many-locals,unused-argument
|
|
383
|
+
@override
|
|
557
384
|
def run(
|
|
558
385
|
self,
|
|
559
386
|
output_path: str | Path | None = None,
|
|
@@ -618,8 +445,10 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
618
445
|
uploads_root=uploads_root,
|
|
619
446
|
)
|
|
620
447
|
WaldiezBaseRunner._running = True
|
|
621
|
-
results: list[dict[str, Any]]
|
|
448
|
+
results: list[dict[str, Any]] = []
|
|
449
|
+
error: BaseException | None = None
|
|
622
450
|
old_env_vars = set_env_vars(self._waldiez.get_flow_env_vars())
|
|
451
|
+
output_dir = output_file.parent
|
|
623
452
|
try:
|
|
624
453
|
with chdir(to=temp_dir):
|
|
625
454
|
sys.path.insert(0, str(temp_dir))
|
|
@@ -631,25 +460,30 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
631
460
|
skip_timeline=skip_timeline,
|
|
632
461
|
)
|
|
633
462
|
except (SystemExit, StopRunningException, KeyboardInterrupt) as exc:
|
|
463
|
+
error = exc
|
|
464
|
+
self.log.warning("Execution stopped: %s", exc)
|
|
634
465
|
raise StopRunningException(StopRunningException.reason) from exc
|
|
635
466
|
except BaseException as exc: # pylint: disable=broad-exception-caught
|
|
636
467
|
self.log.error("Error occurred while running workflow: %s", exc)
|
|
637
|
-
|
|
468
|
+
error = exc
|
|
638
469
|
finally:
|
|
639
470
|
WaldiezBaseRunner._running = False
|
|
640
471
|
reset_env_vars(old_env_vars)
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
472
|
+
output = self.after_run(
|
|
473
|
+
results=results,
|
|
474
|
+
error=error,
|
|
475
|
+
output_file=output_file,
|
|
476
|
+
uploads_root=uploads_root_path,
|
|
477
|
+
temp_dir=temp_dir,
|
|
478
|
+
skip_mmd=skip_mmd,
|
|
479
|
+
skip_timeline=skip_timeline,
|
|
480
|
+
)
|
|
481
|
+
if output:
|
|
482
|
+
output_dir = output
|
|
483
|
+
EventsMixin.do_print("<Waldiez> - Done running the flow.")
|
|
650
484
|
if sys.path[0] == str(temp_dir):
|
|
651
485
|
sys.path.pop(0)
|
|
652
|
-
return results
|
|
486
|
+
return self.get_results(results, output_dir)
|
|
653
487
|
|
|
654
488
|
async def a_prepare(
|
|
655
489
|
self,
|
|
@@ -679,11 +513,11 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
679
513
|
uploads_root=uploads_root_path,
|
|
680
514
|
)
|
|
681
515
|
await self.a_install_requirements()
|
|
682
|
-
refresh_environment()
|
|
683
516
|
return temp_dir, output_file, uploads_root_path
|
|
684
517
|
|
|
685
518
|
# noinspection DuplicatedCode
|
|
686
519
|
# noinspection PyProtocol
|
|
520
|
+
@override
|
|
687
521
|
async def a_run(
|
|
688
522
|
self,
|
|
689
523
|
output_path: str | Path | None = None,
|
|
@@ -739,7 +573,9 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
739
573
|
uploads_root=uploads_root,
|
|
740
574
|
)
|
|
741
575
|
WaldiezBaseRunner._running = True
|
|
742
|
-
results: list[dict[str, Any]]
|
|
576
|
+
results: list[dict[str, Any]] = []
|
|
577
|
+
error: BaseException | None = None
|
|
578
|
+
output_dir = output_file.parent
|
|
743
579
|
old_env_vars = set_env_vars(self._waldiez.get_flow_env_vars())
|
|
744
580
|
try:
|
|
745
581
|
async with a_chdir(to=temp_dir):
|
|
@@ -752,40 +588,49 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
752
588
|
skip_timeline=skip_timeline,
|
|
753
589
|
)
|
|
754
590
|
except (SystemExit, StopRunningException, KeyboardInterrupt) as exc:
|
|
591
|
+
self.log.warning("Execution stopped: %s", exc)
|
|
592
|
+
error = exc
|
|
755
593
|
raise StopRunningException(StopRunningException.reason) from exc
|
|
756
594
|
except BaseException as exc: # pylint: disable=broad-exception-caught
|
|
757
|
-
|
|
595
|
+
self.log.error("Error occurred while running workflow: %s", exc)
|
|
596
|
+
error = exc
|
|
758
597
|
finally:
|
|
759
598
|
WaldiezBaseRunner._running = False
|
|
760
599
|
reset_env_vars(old_env_vars)
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
600
|
+
output = await self.a_after_run(
|
|
601
|
+
results=results,
|
|
602
|
+
error=error,
|
|
603
|
+
output_file=output_file,
|
|
604
|
+
uploads_root=uploads_root_path,
|
|
605
|
+
temp_dir=temp_dir,
|
|
606
|
+
skip_mmd=skip_mmd,
|
|
607
|
+
skip_timeline=skip_timeline,
|
|
608
|
+
)
|
|
609
|
+
if output:
|
|
610
|
+
output_dir = output
|
|
770
611
|
if sys.path[0] == str(temp_dir):
|
|
771
612
|
sys.path.pop(0)
|
|
772
|
-
return results
|
|
613
|
+
return await self.a_get_results(results, output_dir)
|
|
773
614
|
|
|
615
|
+
@override
|
|
774
616
|
def after_run(
|
|
775
617
|
self,
|
|
776
618
|
results: list[dict[str, Any]],
|
|
619
|
+
error: BaseException | None,
|
|
777
620
|
output_file: Path,
|
|
778
621
|
uploads_root: Path | None,
|
|
779
622
|
temp_dir: Path,
|
|
780
623
|
skip_mmd: bool,
|
|
781
624
|
skip_timeline: bool,
|
|
782
|
-
) -> None:
|
|
625
|
+
) -> Path | None:
|
|
783
626
|
"""Actions to perform after running the flow.
|
|
784
627
|
|
|
785
628
|
Parameters
|
|
786
629
|
----------
|
|
787
630
|
results : list[dict[str, Any]]
|
|
788
631
|
The results of the flow run.
|
|
632
|
+
error : BaseException | None
|
|
633
|
+
Optional error during the run.
|
|
789
634
|
output_file : Path
|
|
790
635
|
The path to the output file.
|
|
791
636
|
uploads_root : Path | None
|
|
@@ -796,9 +641,15 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
796
641
|
Whether to skip generating the mermaid diagram.
|
|
797
642
|
skip_timeline : bool
|
|
798
643
|
Whether to skip generating the timeline JSON.
|
|
644
|
+
|
|
645
|
+
Returns
|
|
646
|
+
-------
|
|
647
|
+
Path | None
|
|
648
|
+
The destination directory if output file, else None
|
|
799
649
|
"""
|
|
800
|
-
self._after_run(
|
|
650
|
+
return self._after_run(
|
|
801
651
|
results=results,
|
|
652
|
+
error=error,
|
|
802
653
|
output_file=output_file,
|
|
803
654
|
waldiez_file=WaldiezBaseRunner._waldiez_file,
|
|
804
655
|
uploads_root=uploads_root,
|
|
@@ -807,21 +658,25 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
807
658
|
skip_timeline=skip_timeline,
|
|
808
659
|
)
|
|
809
660
|
|
|
661
|
+
@override
|
|
810
662
|
async def a_after_run(
|
|
811
663
|
self,
|
|
812
664
|
results: list[dict[str, Any]],
|
|
665
|
+
error: BaseException | None,
|
|
813
666
|
output_file: Path,
|
|
814
667
|
uploads_root: Path | None,
|
|
815
668
|
temp_dir: Path,
|
|
816
669
|
skip_mmd: bool,
|
|
817
670
|
skip_timeline: bool,
|
|
818
|
-
) -> None:
|
|
671
|
+
) -> Path | None:
|
|
819
672
|
"""Asynchronously perform actions after running the flow.
|
|
820
673
|
|
|
821
674
|
Parameters
|
|
822
675
|
----------
|
|
823
676
|
results : list[dict[str, Any]]
|
|
824
677
|
The results of the flow run.
|
|
678
|
+
error : BaseException | None
|
|
679
|
+
Optional error during the run.
|
|
825
680
|
output_file : Path
|
|
826
681
|
The path to the output file.
|
|
827
682
|
uploads_root : Path | None
|
|
@@ -832,9 +687,14 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
832
687
|
Whether to skip generating the mermaid diagram.
|
|
833
688
|
skip_timeline : bool
|
|
834
689
|
|
|
690
|
+
Returns
|
|
691
|
+
-------
|
|
692
|
+
Path | None
|
|
693
|
+
The destination directory if output file, else None
|
|
835
694
|
"""
|
|
836
|
-
await self._a_after_run(
|
|
695
|
+
return await self._a_after_run(
|
|
837
696
|
results=results,
|
|
697
|
+
error=error,
|
|
838
698
|
output_file=output_file,
|
|
839
699
|
uploads_root=uploads_root,
|
|
840
700
|
temp_dir=temp_dir,
|
|
@@ -946,14 +806,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
946
806
|
)
|
|
947
807
|
|
|
948
808
|
def stop(self) -> None:
|
|
949
|
-
"""Stop the workflow execution.
|
|
950
|
-
|
|
951
|
-
This method sets the stop flag that will be checked by the event
|
|
952
|
-
handlers and other parts of the workflow execution to gracefully
|
|
953
|
-
terminate the workflow execution.
|
|
954
|
-
Note: Stopping will occur at the "next" AutoGen event, not immediately.
|
|
955
|
-
"""
|
|
956
|
-
self.log.info("Stop requested - setting stop flag")
|
|
809
|
+
"""Stop the workflow execution."""
|
|
957
810
|
self._stop_requested.set()
|
|
958
811
|
|
|
959
812
|
def is_stop_requested(self) -> bool:
|
|
@@ -980,7 +833,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
980
833
|
|
|
981
834
|
def __exit__(
|
|
982
835
|
self,
|
|
983
|
-
exc_type:
|
|
836
|
+
exc_type: type[BaseException],
|
|
984
837
|
exc_value: BaseException,
|
|
985
838
|
traceback: TracebackType,
|
|
986
839
|
) -> None:
|
|
@@ -990,7 +843,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol, RequirementsMixin):
|
|
|
990
843
|
|
|
991
844
|
async def __aexit__(
|
|
992
845
|
self,
|
|
993
|
-
exc_type:
|
|
846
|
+
exc_type: type[BaseException],
|
|
994
847
|
exc_value: BaseException,
|
|
995
848
|
traceback: TracebackType,
|
|
996
849
|
) -> None:
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Dir related utilities for the waldiez runner."""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from collections.abc import AsyncIterator, Iterator
|
|
7
|
+
from contextlib import asynccontextmanager, contextmanager
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@contextmanager
|
|
12
|
+
def chdir(to: str | Path) -> Iterator[None]:
|
|
13
|
+
"""Change the current working directory in a context.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
to : str | Path
|
|
18
|
+
The directory to change to.
|
|
19
|
+
|
|
20
|
+
Yields
|
|
21
|
+
------
|
|
22
|
+
Iterator[None]
|
|
23
|
+
The context manager.
|
|
24
|
+
"""
|
|
25
|
+
old_cwd = str(os.getcwd())
|
|
26
|
+
try:
|
|
27
|
+
os.chdir(to)
|
|
28
|
+
yield
|
|
29
|
+
finally:
|
|
30
|
+
os.chdir(old_cwd)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@asynccontextmanager
|
|
34
|
+
async def a_chdir(to: str | Path) -> AsyncIterator[None]:
|
|
35
|
+
"""Asynchronously change the current working directory in a context.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
to : str | Path
|
|
40
|
+
The directory to change to.
|
|
41
|
+
|
|
42
|
+
Yields
|
|
43
|
+
------
|
|
44
|
+
AsyncIterator[None]
|
|
45
|
+
The async context manager.
|
|
46
|
+
"""
|
|
47
|
+
old_cwd = str(os.getcwd())
|
|
48
|
+
try:
|
|
49
|
+
os.chdir(to)
|
|
50
|
+
yield
|
|
51
|
+
finally:
|
|
52
|
+
os.chdir(old_cwd)
|