waldiez 0.2.2__py3-none-any.whl → 0.3.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 +2 -0
- waldiez/__main__.py +2 -0
- waldiez/_version.py +3 -1
- waldiez/cli.py +13 -3
- waldiez/cli_extras.py +4 -3
- waldiez/conflict_checker.py +4 -3
- waldiez/exporter.py +28 -105
- waldiez/exporting/__init__.py +8 -9
- waldiez/exporting/agent/__init__.py +7 -0
- waldiez/exporting/agent/agent_exporter.py +279 -0
- waldiez/exporting/agent/utils/__init__.py +23 -0
- waldiez/exporting/agent/utils/agent_class_name.py +34 -0
- waldiez/exporting/agent/utils/agent_imports.py +50 -0
- waldiez/exporting/{agents → agent/utils}/code_execution.py +9 -11
- waldiez/exporting/{agents → agent/utils}/group_manager.py +47 -35
- waldiez/exporting/{agents → agent/utils}/rag_user/__init__.py +2 -0
- waldiez/exporting/{agents → agent/utils}/rag_user/chroma_utils.py +22 -17
- waldiez/exporting/{agents → agent/utils}/rag_user/mongo_utils.py +14 -10
- waldiez/exporting/{agents → agent/utils}/rag_user/pgvector_utils.py +12 -8
- waldiez/exporting/{agents → agent/utils}/rag_user/qdrant_utils.py +11 -8
- waldiez/exporting/{agents → agent/utils}/rag_user/rag_user.py +78 -55
- waldiez/exporting/{agents → agent/utils}/rag_user/vector_db.py +10 -8
- waldiez/exporting/agent/utils/swarm_agent.py +463 -0
- waldiez/exporting/{agents → agent/utils}/teachability.py +10 -6
- waldiez/exporting/{agents → agent/utils}/termination_message.py +7 -8
- waldiez/exporting/base/__init__.py +25 -0
- waldiez/exporting/base/agent_position.py +75 -0
- waldiez/exporting/base/base_exporter.py +118 -0
- waldiez/exporting/base/export_position.py +48 -0
- waldiez/exporting/base/import_position.py +23 -0
- waldiez/exporting/base/mixin.py +134 -0
- waldiez/exporting/base/utils/__init__.py +18 -0
- waldiez/exporting/{utils → base/utils}/comments.py +12 -55
- waldiez/exporting/{utils → base/utils}/naming.py +14 -4
- waldiez/exporting/base/utils/path_check.py +68 -0
- waldiez/exporting/{utils/object_string.py → base/utils/to_string.py} +21 -20
- waldiez/exporting/chats/__init__.py +5 -12
- waldiez/exporting/chats/chats_exporter.py +240 -0
- waldiez/exporting/chats/utils/__init__.py +15 -0
- waldiez/exporting/chats/utils/common.py +81 -0
- waldiez/exporting/chats/{nested.py → utils/nested.py} +125 -86
- waldiez/exporting/chats/utils/sequential.py +244 -0
- waldiez/exporting/chats/utils/single_chat.py +313 -0
- waldiez/exporting/chats/utils/swarm.py +207 -0
- waldiez/exporting/flow/__init__.py +5 -3
- waldiez/exporting/flow/flow_exporter.py +503 -0
- waldiez/exporting/flow/utils/__init__.py +47 -0
- waldiez/exporting/flow/utils/agent_utils.py +204 -0
- waldiez/exporting/flow/utils/chat_utils.py +71 -0
- waldiez/exporting/flow/utils/def_main.py +62 -0
- waldiez/exporting/flow/utils/flow_content.py +112 -0
- waldiez/exporting/flow/utils/flow_names.py +115 -0
- waldiez/exporting/flow/utils/importing_utils.py +182 -0
- waldiez/exporting/{utils → flow/utils}/logging_utils.py +34 -31
- waldiez/exporting/models/__init__.py +7 -242
- waldiez/exporting/models/models_exporter.py +192 -0
- waldiez/exporting/models/utils.py +166 -0
- waldiez/exporting/skills/__init__.py +7 -161
- waldiez/exporting/skills/skills_exporter.py +169 -0
- waldiez/exporting/skills/utils.py +281 -0
- waldiez/models/__init__.py +25 -7
- waldiez/models/agents/__init__.py +70 -0
- waldiez/models/agents/agent/__init__.py +11 -1
- waldiez/models/agents/agent/agent.py +9 -4
- waldiez/models/agents/agent/agent_data.py +3 -1
- waldiez/models/agents/agent/code_execution.py +2 -0
- waldiez/models/agents/agent/linked_skill.py +2 -0
- waldiez/models/agents/agent/nested_chat.py +2 -0
- waldiez/models/agents/agent/teachability.py +2 -0
- waldiez/models/agents/agent/termination_message.py +49 -13
- waldiez/models/agents/agents.py +15 -3
- waldiez/models/agents/assistant/__init__.py +2 -0
- waldiez/models/agents/assistant/assistant.py +2 -0
- waldiez/models/agents/assistant/assistant_data.py +2 -0
- waldiez/models/agents/group_manager/__init__.py +9 -1
- waldiez/models/agents/group_manager/group_manager.py +2 -0
- waldiez/models/agents/group_manager/group_manager_data.py +2 -0
- waldiez/models/agents/group_manager/speakers.py +49 -13
- waldiez/models/agents/rag_user/__init__.py +21 -4
- waldiez/models/agents/rag_user/rag_user.py +3 -1
- waldiez/models/agents/rag_user/rag_user_data.py +2 -0
- waldiez/models/agents/rag_user/retrieve_config.py +268 -17
- waldiez/models/agents/rag_user/vector_db_config.py +5 -3
- waldiez/models/agents/swarm_agent/__init__.py +49 -0
- waldiez/models/agents/swarm_agent/after_work.py +178 -0
- waldiez/models/agents/swarm_agent/on_condition.py +103 -0
- waldiez/models/agents/swarm_agent/on_condition_available.py +140 -0
- waldiez/models/agents/swarm_agent/on_condition_target.py +40 -0
- waldiez/models/agents/swarm_agent/swarm_agent.py +107 -0
- waldiez/models/agents/swarm_agent/swarm_agent_data.py +125 -0
- waldiez/models/agents/swarm_agent/update_system_message.py +144 -0
- waldiez/models/agents/user_proxy/__init__.py +2 -0
- waldiez/models/agents/user_proxy/user_proxy.py +2 -0
- waldiez/models/agents/user_proxy/user_proxy_data.py +2 -0
- waldiez/models/chat/__init__.py +21 -3
- waldiez/models/chat/chat.py +241 -7
- waldiez/models/chat/chat_data.py +192 -48
- waldiez/models/chat/chat_message.py +153 -144
- waldiez/models/chat/chat_nested.py +33 -53
- waldiez/models/chat/chat_summary.py +2 -0
- waldiez/models/common/__init__.py +6 -6
- waldiez/models/common/base.py +4 -1
- waldiez/models/common/method_utils.py +163 -83
- waldiez/models/flow/__init__.py +2 -0
- waldiez/models/flow/flow.py +176 -40
- waldiez/models/flow/flow_data.py +63 -2
- waldiez/models/flow/utils.py +172 -0
- waldiez/models/model/__init__.py +2 -0
- waldiez/models/model/model.py +30 -9
- waldiez/models/model/model_data.py +3 -1
- waldiez/models/skill/__init__.py +4 -1
- waldiez/models/skill/skill.py +30 -2
- waldiez/models/skill/skill_data.py +2 -0
- waldiez/models/waldiez.py +28 -4
- waldiez/runner.py +142 -228
- waldiez/running/__init__.py +33 -0
- waldiez/running/environment.py +83 -0
- waldiez/running/gen_seq_diagram.py +185 -0
- waldiez/running/running.py +300 -0
- {waldiez-0.2.2.dist-info → waldiez-0.3.1.dist-info}/METADATA +35 -28
- waldiez-0.3.1.dist-info/RECORD +125 -0
- waldiez-0.3.1.dist-info/licenses/LICENSE +201 -0
- waldiez/exporting/agents/__init__.py +0 -5
- waldiez/exporting/agents/agent.py +0 -236
- waldiez/exporting/agents/agent_skills.py +0 -67
- waldiez/exporting/agents/llm_config.py +0 -53
- waldiez/exporting/chats/chats.py +0 -46
- waldiez/exporting/chats/helpers.py +0 -420
- waldiez/exporting/flow/def_main.py +0 -32
- waldiez/exporting/flow/flow.py +0 -189
- waldiez/exporting/utils/__init__.py +0 -36
- waldiez/exporting/utils/importing.py +0 -265
- waldiez/exporting/utils/method_utils.py +0 -35
- waldiez/exporting/utils/path_check.py +0 -51
- waldiez-0.2.2.dist-info/RECORD +0 -92
- waldiez-0.2.2.dist-info/licenses/LICENSE +0 -21
- {waldiez-0.2.2.dist-info → waldiez-0.3.1.dist-info}/WHEEL +0 -0
- {waldiez-0.2.2.dist-info → waldiez-0.3.1.dist-info}/entry_points.txt +0 -0
waldiez/models/waldiez.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Waldiez
|
|
2
4
|
|
|
3
5
|
A Waldiez class contains all the information that is needed to generate
|
|
4
6
|
and run an autogen workflow. It has the model/LLM configurations, the agent
|
|
@@ -204,6 +206,11 @@ class Waldiez:
|
|
|
204
206
|
"""Get the flow tags."""
|
|
205
207
|
return self.flow.tags
|
|
206
208
|
|
|
209
|
+
@property
|
|
210
|
+
def is_async(self) -> bool:
|
|
211
|
+
"""Check if the flow is asynchronous."""
|
|
212
|
+
return self.flow.is_async
|
|
213
|
+
|
|
207
214
|
@property
|
|
208
215
|
def requirements(self) -> List[str]:
|
|
209
216
|
"""Get the flow requirements."""
|
|
@@ -236,9 +243,9 @@ class Waldiez:
|
|
|
236
243
|
for model in self.models:
|
|
237
244
|
if model.data.api_type in models_with_additional_requirements:
|
|
238
245
|
requirements.add(
|
|
239
|
-
f"pyautogen[{model.data.api_type}]==
|
|
246
|
+
f"pyautogen[{model.data.api_type}]=={autogen_version}"
|
|
240
247
|
)
|
|
241
|
-
return list(requirements)
|
|
248
|
+
return sorted(list(requirements))
|
|
242
249
|
|
|
243
250
|
def get_flow_env_vars(self) -> List[Tuple[str, str]]:
|
|
244
251
|
"""Get the flow environment variables.
|
|
@@ -255,7 +262,7 @@ class Waldiez:
|
|
|
255
262
|
return env_vars
|
|
256
263
|
|
|
257
264
|
def get_group_chat_members(self, agent: WaldiezAgent) -> List[WaldiezAgent]:
|
|
258
|
-
"""Get the chat members that connect to a group chat
|
|
265
|
+
"""Get the chat members that connect to a group chat manager agent.
|
|
259
266
|
|
|
260
267
|
Parameters
|
|
261
268
|
----------
|
|
@@ -271,6 +278,23 @@ class Waldiez:
|
|
|
271
278
|
return []
|
|
272
279
|
return self.flow.get_group_chat_members(agent.id)
|
|
273
280
|
|
|
281
|
+
def get_swarm_members(
|
|
282
|
+
self, initial_agent: WaldiezAgent
|
|
283
|
+
) -> Tuple[List[WaldiezAgent], Optional[WaldiezAgent]]:
|
|
284
|
+
"""Get the chat members that connect to a swarm agent.
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
----------
|
|
288
|
+
initial_agent : WaldiezAgent
|
|
289
|
+
The initial agent.
|
|
290
|
+
|
|
291
|
+
Returns
|
|
292
|
+
-------
|
|
293
|
+
Tuple[List[WaldiezAgent], Optional[WaldiezAgent]]
|
|
294
|
+
The swarm agents and the user agent.
|
|
295
|
+
"""
|
|
296
|
+
return self.flow.get_swarm_chat_members(initial_agent)
|
|
297
|
+
|
|
274
298
|
|
|
275
299
|
def _get_flow(
|
|
276
300
|
data: Dict[str, Any],
|
waldiez/runner.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Run a waldiez flow.
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Run a waldiez flow.
|
|
4
4
|
The flow is first converted to an autogen flow with agents, chats and skills.
|
|
5
5
|
We then chown to temporary directory, call the flow's `main()` and
|
|
6
6
|
return the results. Before running the flow, any additional environment
|
|
@@ -9,60 +9,34 @@ variables specified in the waldiez file are set.
|
|
|
9
9
|
|
|
10
10
|
# pylint: disable=import-outside-toplevel,reimported
|
|
11
11
|
|
|
12
|
-
import datetime
|
|
13
12
|
import importlib.util
|
|
14
|
-
import io
|
|
15
|
-
import os
|
|
16
|
-
import shutil
|
|
17
|
-
import site
|
|
18
|
-
import subprocess # nosemgrep # nosec
|
|
19
13
|
import sys
|
|
20
14
|
import tempfile
|
|
21
|
-
import warnings
|
|
22
|
-
from contextlib import contextmanager
|
|
23
15
|
from pathlib import Path
|
|
24
16
|
from types import TracebackType
|
|
25
|
-
from typing import
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Dict,
|
|
29
|
-
Iterator,
|
|
30
|
-
List,
|
|
31
|
-
Optional,
|
|
32
|
-
Tuple,
|
|
33
|
-
Type,
|
|
34
|
-
Union,
|
|
35
|
-
)
|
|
17
|
+
from typing import TYPE_CHECKING, List, Optional, Type, Union
|
|
18
|
+
|
|
19
|
+
from asyncer import syncify
|
|
36
20
|
|
|
37
21
|
from .exporter import WaldiezExporter
|
|
38
22
|
from .models.waldiez import Waldiez
|
|
23
|
+
from .running import (
|
|
24
|
+
a_chdir,
|
|
25
|
+
a_install_requirements,
|
|
26
|
+
after_run,
|
|
27
|
+
before_run,
|
|
28
|
+
chdir,
|
|
29
|
+
get_printer,
|
|
30
|
+
install_requirements,
|
|
31
|
+
refresh_environment,
|
|
32
|
+
reset_env_vars,
|
|
33
|
+
set_env_vars,
|
|
34
|
+
)
|
|
39
35
|
|
|
40
36
|
if TYPE_CHECKING:
|
|
41
37
|
from autogen import ChatResult # type: ignore
|
|
42
38
|
|
|
43
39
|
|
|
44
|
-
@contextmanager
|
|
45
|
-
def _chdir(to: Union[str, Path]) -> Iterator[None]:
|
|
46
|
-
"""Change the current working directory in a context.
|
|
47
|
-
|
|
48
|
-
Parameters
|
|
49
|
-
----------
|
|
50
|
-
to : Union[str, Path]
|
|
51
|
-
The directory to change to.
|
|
52
|
-
|
|
53
|
-
Yields
|
|
54
|
-
------
|
|
55
|
-
Iterator[None]
|
|
56
|
-
The context manager.
|
|
57
|
-
"""
|
|
58
|
-
old_cwd = str(os.getcwd())
|
|
59
|
-
os.chdir(to)
|
|
60
|
-
try:
|
|
61
|
-
yield
|
|
62
|
-
finally:
|
|
63
|
-
os.chdir(old_cwd)
|
|
64
|
-
|
|
65
|
-
|
|
66
40
|
class WaldiezRunner:
|
|
67
41
|
"""Waldiez runner class."""
|
|
68
42
|
|
|
@@ -127,6 +101,12 @@ class WaldiezRunner:
|
|
|
127
101
|
"""Enter the context manager."""
|
|
128
102
|
return self
|
|
129
103
|
|
|
104
|
+
async def __aenter__(
|
|
105
|
+
self,
|
|
106
|
+
) -> "WaldiezRunner":
|
|
107
|
+
"""Enter the context manager asynchronously."""
|
|
108
|
+
return self
|
|
109
|
+
|
|
130
110
|
def __exit__(
|
|
131
111
|
self,
|
|
132
112
|
exc_type: Type[BaseException],
|
|
@@ -137,6 +117,16 @@ class WaldiezRunner:
|
|
|
137
117
|
if self._running:
|
|
138
118
|
self._running = False
|
|
139
119
|
|
|
120
|
+
async def __aexit__(
|
|
121
|
+
self,
|
|
122
|
+
exc_type: Type[BaseException],
|
|
123
|
+
exc_value: BaseException,
|
|
124
|
+
traceback: TracebackType,
|
|
125
|
+
) -> None:
|
|
126
|
+
"""Exit the context manager asynchronously."""
|
|
127
|
+
if self._running:
|
|
128
|
+
self._running = False
|
|
129
|
+
|
|
140
130
|
@property
|
|
141
131
|
def waldiez(self) -> Waldiez:
|
|
142
132
|
"""Get the Waldiez instance."""
|
|
@@ -155,78 +145,25 @@ class WaldiezRunner:
|
|
|
155
145
|
req for req in self.waldiez.requirements if req not in sys.modules
|
|
156
146
|
)
|
|
157
147
|
if extra_requirements:
|
|
158
|
-
|
|
159
|
-
printer(f"Installing requirements: {requirements_string}")
|
|
160
|
-
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
161
|
-
if not in_virtualenv():
|
|
162
|
-
pip_install.append("--user")
|
|
163
|
-
pip_install.extend(extra_requirements)
|
|
164
|
-
with subprocess.Popen(
|
|
165
|
-
pip_install,
|
|
166
|
-
stdout=subprocess.PIPE,
|
|
167
|
-
stderr=subprocess.PIPE,
|
|
168
|
-
) as proc:
|
|
169
|
-
if proc.stdout:
|
|
170
|
-
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
|
|
171
|
-
printer(line.strip())
|
|
172
|
-
if proc.stderr:
|
|
173
|
-
for line in io.TextIOWrapper(proc.stderr, encoding="utf-8"):
|
|
174
|
-
printer(line.strip())
|
|
148
|
+
install_requirements(extra_requirements, printer)
|
|
175
149
|
refresh_environment()
|
|
176
150
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
/ "waldiez_out"
|
|
188
|
-
/ datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
|
189
|
-
)
|
|
190
|
-
destination_dir.mkdir(parents=True, exist_ok=True)
|
|
191
|
-
# copy the contents of the temp dir to the destination dir
|
|
192
|
-
printer(f"Copying the results to {destination_dir}")
|
|
193
|
-
for item in temp_dir.iterdir():
|
|
194
|
-
# skip cache files
|
|
195
|
-
if (
|
|
196
|
-
item.name.startswith("__pycache__")
|
|
197
|
-
or item.name.endswith(".pyc")
|
|
198
|
-
or item == ".cache"
|
|
199
|
-
):
|
|
200
|
-
continue
|
|
201
|
-
if item.is_file():
|
|
202
|
-
shutil.copy(item, destination_dir)
|
|
203
|
-
else:
|
|
204
|
-
shutil.copytree(item, destination_dir / item.name)
|
|
205
|
-
shutil.rmtree(temp_dir)
|
|
206
|
-
|
|
207
|
-
def _set_env_vars(self) -> Dict[str, str]:
|
|
208
|
-
"""Set environment variables and return the old ones (if any)."""
|
|
209
|
-
old_vars: Dict[str, str] = {}
|
|
210
|
-
for var_key, var_value in self.waldiez.get_flow_env_vars():
|
|
211
|
-
if var_key:
|
|
212
|
-
current = os.environ.get(var_key, "")
|
|
213
|
-
old_vars[var_key] = current
|
|
214
|
-
os.environ[var_key] = var_value
|
|
215
|
-
return old_vars
|
|
216
|
-
|
|
217
|
-
@staticmethod
|
|
218
|
-
def _reset_env_vars(old_vars: Dict[str, str]) -> None:
|
|
219
|
-
"""Reset the environment variables."""
|
|
220
|
-
for var_key, var_value in old_vars.items():
|
|
221
|
-
if not var_value:
|
|
222
|
-
os.environ.pop(var_key, "")
|
|
223
|
-
else:
|
|
224
|
-
os.environ[var_key] = var_value
|
|
151
|
+
async def a_install_requirements(self) -> None:
|
|
152
|
+
"""Install the requirements for the flow asynchronously."""
|
|
153
|
+
self._called_install_requirements = True
|
|
154
|
+
printer = get_printer()
|
|
155
|
+
extra_requirements = set(
|
|
156
|
+
req for req in self.waldiez.requirements if req not in sys.modules
|
|
157
|
+
)
|
|
158
|
+
if extra_requirements:
|
|
159
|
+
await a_install_requirements(extra_requirements, printer)
|
|
160
|
+
refresh_environment()
|
|
225
161
|
|
|
226
|
-
def
|
|
162
|
+
def _run(
|
|
227
163
|
self,
|
|
228
164
|
output_path: Optional[Union[str, Path]],
|
|
229
165
|
uploads_root: Optional[Union[str, Path]],
|
|
166
|
+
skip_mmd: bool = False,
|
|
230
167
|
) -> Union["ChatResult", List["ChatResult"]]:
|
|
231
168
|
"""Run the Waldiez workflow.
|
|
232
169
|
|
|
@@ -236,12 +173,16 @@ class WaldiezRunner:
|
|
|
236
173
|
The output path.
|
|
237
174
|
uploads_root : Optional[Union[str, Path]]
|
|
238
175
|
The runtime uploads root.
|
|
239
|
-
|
|
176
|
+
skip_mmd : bool
|
|
177
|
+
Whether to skip the Mermaid diagram generation.
|
|
240
178
|
Returns
|
|
241
179
|
-------
|
|
242
180
|
Union[ChatResult, List[ChatResult]]
|
|
243
181
|
The result(s) of the chat(s).
|
|
244
182
|
"""
|
|
183
|
+
temp_dir = Path(tempfile.mkdtemp())
|
|
184
|
+
file_name = before_run(output_path, uploads_root)
|
|
185
|
+
module_name = file_name.replace(".py", "")
|
|
245
186
|
if not self._called_install_requirements:
|
|
246
187
|
self.install_requirements()
|
|
247
188
|
else:
|
|
@@ -253,22 +194,52 @@ class WaldiezRunner:
|
|
|
253
194
|
"you might need to restart the kernel."
|
|
254
195
|
)
|
|
255
196
|
results: Union["ChatResult", List["ChatResult"]] = []
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if not uploads_root.exists():
|
|
261
|
-
uploads_root.mkdir(parents=True)
|
|
262
|
-
temp_dir = Path(tempfile.mkdtemp())
|
|
263
|
-
file_name = "flow.py" if not output_path else Path(output_path).name
|
|
264
|
-
if file_name.endswith((".json", ".waldiez")):
|
|
265
|
-
file_name = file_name.replace(".json", ".py").replace(
|
|
266
|
-
".waldiez", ".py"
|
|
197
|
+
with chdir(to=temp_dir):
|
|
198
|
+
self._exporter.export(Path(file_name))
|
|
199
|
+
spec = importlib.util.spec_from_file_location(
|
|
200
|
+
module_name, temp_dir / file_name
|
|
267
201
|
)
|
|
268
|
-
|
|
269
|
-
|
|
202
|
+
if not spec or not spec.loader:
|
|
203
|
+
raise ImportError("Could not import the flow")
|
|
204
|
+
sys.path.insert(0, str(temp_dir))
|
|
205
|
+
old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
|
|
206
|
+
module = importlib.util.module_from_spec(spec)
|
|
207
|
+
spec.loader.exec_module(module)
|
|
208
|
+
printer("<Waldiez> - Starting workflow...")
|
|
209
|
+
results = module.main()
|
|
210
|
+
sys.path.pop(0)
|
|
211
|
+
reset_env_vars(old_vars)
|
|
212
|
+
after_run(
|
|
213
|
+
temp_dir=temp_dir,
|
|
214
|
+
output_path=output_path,
|
|
215
|
+
printer=printer,
|
|
216
|
+
flow_name=self.waldiez.name,
|
|
217
|
+
skip_mmd=skip_mmd,
|
|
218
|
+
)
|
|
219
|
+
return results
|
|
220
|
+
|
|
221
|
+
async def _a_run(
|
|
222
|
+
self,
|
|
223
|
+
output_path: Optional[Union[str, Path]],
|
|
224
|
+
uploads_root: Optional[Union[str, Path]],
|
|
225
|
+
skip_mmd: bool = False,
|
|
226
|
+
) -> Union["ChatResult", List["ChatResult"]]:
|
|
227
|
+
"""Run the Waldiez workflow asynchronously."""
|
|
228
|
+
temp_dir = Path(tempfile.mkdtemp())
|
|
229
|
+
file_name = before_run(output_path, uploads_root)
|
|
270
230
|
module_name = file_name.replace(".py", "")
|
|
271
|
-
|
|
231
|
+
if not self._called_install_requirements:
|
|
232
|
+
await self.a_install_requirements()
|
|
233
|
+
else:
|
|
234
|
+
refresh_environment()
|
|
235
|
+
printer = get_printer()
|
|
236
|
+
printer(
|
|
237
|
+
"Requirements installed.\n"
|
|
238
|
+
"NOTE: If new packages were added and you are using Jupyter, "
|
|
239
|
+
"you might need to restart the kernel."
|
|
240
|
+
)
|
|
241
|
+
results: Union["ChatResult", List["ChatResult"]] = []
|
|
242
|
+
async with a_chdir(to=temp_dir):
|
|
272
243
|
self._exporter.export(Path(file_name))
|
|
273
244
|
spec = importlib.util.spec_from_file_location(
|
|
274
245
|
module_name, temp_dir / file_name
|
|
@@ -276,20 +247,27 @@ class WaldiezRunner:
|
|
|
276
247
|
if not spec or not spec.loader:
|
|
277
248
|
raise ImportError("Could not import the flow")
|
|
278
249
|
sys.path.insert(0, str(temp_dir))
|
|
279
|
-
old_vars = self.
|
|
250
|
+
old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
|
|
280
251
|
module = importlib.util.module_from_spec(spec)
|
|
281
252
|
spec.loader.exec_module(module)
|
|
282
253
|
printer("<Waldiez> - Starting workflow...")
|
|
283
|
-
results = module.main()
|
|
254
|
+
results = await module.main()
|
|
284
255
|
sys.path.pop(0)
|
|
285
|
-
|
|
286
|
-
|
|
256
|
+
reset_env_vars(old_vars)
|
|
257
|
+
after_run(
|
|
258
|
+
temp_dir=temp_dir,
|
|
259
|
+
output_path=output_path,
|
|
260
|
+
printer=printer,
|
|
261
|
+
flow_name=self.waldiez.name,
|
|
262
|
+
skip_mmd=skip_mmd,
|
|
263
|
+
)
|
|
287
264
|
return results
|
|
288
265
|
|
|
289
266
|
def run(
|
|
290
267
|
self,
|
|
291
268
|
output_path: Optional[Union[str, Path]] = None,
|
|
292
269
|
uploads_root: Optional[Union[str, Path]] = None,
|
|
270
|
+
skip_mmd: bool = False,
|
|
293
271
|
) -> Union["ChatResult", List["ChatResult"]]:
|
|
294
272
|
"""Run the Waldiez workflow.
|
|
295
273
|
|
|
@@ -299,6 +277,8 @@ class WaldiezRunner:
|
|
|
299
277
|
The output path, by default None.
|
|
300
278
|
uploads_root : Optional[Union[str, Path]], optional
|
|
301
279
|
The uploads root, to get user-uploaded files, by default None.
|
|
280
|
+
skip_mmd : bool, optional
|
|
281
|
+
Whether to skip the Mermaid diagram generation, by default False.
|
|
302
282
|
|
|
303
283
|
Returns
|
|
304
284
|
-------
|
|
@@ -310,114 +290,48 @@ class WaldiezRunner:
|
|
|
310
290
|
RuntimeError
|
|
311
291
|
If the workflow is already running.
|
|
312
292
|
"""
|
|
293
|
+
if self.waldiez.is_async:
|
|
294
|
+
return syncify(self.a_run, raise_sync_error=False)(
|
|
295
|
+
output_path, uploads_root
|
|
296
|
+
)
|
|
313
297
|
if self._running is True:
|
|
314
298
|
raise RuntimeError("Workflow already running")
|
|
315
299
|
self._running = True
|
|
316
300
|
file_path = output_path or self._file_path
|
|
317
301
|
try:
|
|
318
|
-
return self.
|
|
302
|
+
return self._run(file_path, uploads_root, skip_mmd)
|
|
319
303
|
finally:
|
|
320
304
|
self._running = False
|
|
321
305
|
|
|
306
|
+
async def a_run(
|
|
307
|
+
self,
|
|
308
|
+
output_path: Optional[Union[str, Path]] = None,
|
|
309
|
+
uploads_root: Optional[Union[str, Path]] = None,
|
|
310
|
+
) -> Union["ChatResult", List["ChatResult"]]:
|
|
311
|
+
"""Run the Waldiez workflow asynchronously.
|
|
322
312
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
True if inside a virtualenv, False otherwise.
|
|
330
|
-
"""
|
|
331
|
-
return hasattr(sys, "real_prefix") or (
|
|
332
|
-
hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def refresh_environment() -> None:
|
|
337
|
-
"""Refresh the environment."""
|
|
338
|
-
# backup the default IOStream
|
|
339
|
-
from autogen.io import IOStream # type: ignore
|
|
340
|
-
|
|
341
|
-
default_io_stream = IOStream.get_default()
|
|
342
|
-
site.main()
|
|
343
|
-
# pylint: disable=import-outside-toplevel
|
|
344
|
-
modules_to_reload = [
|
|
345
|
-
mod for mod in sys.modules if mod.startswith("autogen")
|
|
346
|
-
]
|
|
347
|
-
for mod in modules_to_reload:
|
|
348
|
-
del sys.modules[mod]
|
|
349
|
-
warnings.filterwarnings(
|
|
350
|
-
"ignore", module="flaml", message="^.*flaml.automl is not available.*$"
|
|
351
|
-
)
|
|
352
|
-
import autogen
|
|
353
|
-
from autogen.io import IOStream
|
|
354
|
-
|
|
355
|
-
importlib.reload(autogen)
|
|
356
|
-
# restore the default IOStream
|
|
357
|
-
IOStream.set_global_default(default_io_stream)
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
def get_printer() -> Callable[..., None]:
|
|
361
|
-
"""Get the printer function.
|
|
362
|
-
|
|
363
|
-
Returns
|
|
364
|
-
-------
|
|
365
|
-
Callable[..., None]
|
|
366
|
-
The printer function.
|
|
367
|
-
"""
|
|
368
|
-
from autogen.io import IOStream
|
|
313
|
+
Parameters
|
|
314
|
+
----------
|
|
315
|
+
output_path : Optional[Union[str, Path]], optional
|
|
316
|
+
The output path, by default None.
|
|
317
|
+
uploads_root : Optional[Union[str, Path]], optional
|
|
318
|
+
The uploads root, to get user-uploaded files, by default None.
|
|
369
319
|
|
|
370
|
-
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
Union[ChatResult, List[ChatResult]]
|
|
323
|
+
The result(s) of the chat(s).
|
|
371
324
|
|
|
372
|
-
|
|
325
|
+
Raises
|
|
326
|
+
------
|
|
327
|
+
RuntimeError
|
|
328
|
+
If the workflow is already running.
|
|
329
|
+
"""
|
|
330
|
+
if self._running is True:
|
|
331
|
+
raise RuntimeError("Workflow already running")
|
|
332
|
+
self._running = True
|
|
333
|
+
file_path = output_path or self._file_path
|
|
373
334
|
try:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
try:
|
|
378
|
-
msg, flush = get_what_to_print(*args, **kwargs)
|
|
379
|
-
printer(msg, end="", flush=flush)
|
|
380
|
-
except UnicodeEncodeError:
|
|
381
|
-
sys.stdout = io.TextIOWrapper(
|
|
382
|
-
sys.stdout.buffer, encoding="utf-8"
|
|
383
|
-
)
|
|
384
|
-
sys.stderr = io.TextIOWrapper(
|
|
385
|
-
sys.stderr.buffer, encoding="utf-8"
|
|
386
|
-
)
|
|
387
|
-
try:
|
|
388
|
-
printer(*args, **kwargs)
|
|
389
|
-
except UnicodeEncodeError:
|
|
390
|
-
sys.stderr.write(
|
|
391
|
-
"Could not print the message due to encoding issues.\n"
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
return safe_printer
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
def get_what_to_print(*args: object, **kwargs: object) -> Tuple[str, bool]:
|
|
398
|
-
"""Get what to print.
|
|
399
|
-
|
|
400
|
-
Parameters
|
|
401
|
-
----------
|
|
402
|
-
args : object
|
|
403
|
-
The arguments.
|
|
404
|
-
kwargs : object
|
|
405
|
-
The keyword arguments.
|
|
406
|
-
|
|
407
|
-
Returns
|
|
408
|
-
-------
|
|
409
|
-
Tuple[str, bool]
|
|
410
|
-
The message and whether to flush.
|
|
411
|
-
"""
|
|
412
|
-
sep = kwargs.get("sep", " ")
|
|
413
|
-
if not isinstance(sep, str):
|
|
414
|
-
sep = " "
|
|
415
|
-
end = kwargs.get("end", "\n")
|
|
416
|
-
if not isinstance(end, str):
|
|
417
|
-
end = "\n"
|
|
418
|
-
flush = kwargs.get("flush", False)
|
|
419
|
-
if not isinstance(flush, bool):
|
|
420
|
-
flush = False
|
|
421
|
-
msg = sep.join(str(arg) for arg in args) + end
|
|
422
|
-
utf8_msg = msg.encode("utf-8", errors="replace").decode("utf-8")
|
|
423
|
-
return utf8_msg, flush
|
|
335
|
+
return await self._a_run(file_path, uploads_root)
|
|
336
|
+
finally:
|
|
337
|
+
self._running = False
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Common utility functions."""
|
|
4
|
+
|
|
5
|
+
from .environment import (
|
|
6
|
+
in_virtualenv,
|
|
7
|
+
refresh_environment,
|
|
8
|
+
reset_env_vars,
|
|
9
|
+
set_env_vars,
|
|
10
|
+
)
|
|
11
|
+
from .running import (
|
|
12
|
+
a_chdir,
|
|
13
|
+
a_install_requirements,
|
|
14
|
+
after_run,
|
|
15
|
+
before_run,
|
|
16
|
+
chdir,
|
|
17
|
+
get_printer,
|
|
18
|
+
install_requirements,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"a_chdir",
|
|
23
|
+
"a_install_requirements",
|
|
24
|
+
"after_run",
|
|
25
|
+
"before_run",
|
|
26
|
+
"chdir",
|
|
27
|
+
"get_printer",
|
|
28
|
+
"in_virtualenv",
|
|
29
|
+
"install_requirements",
|
|
30
|
+
"refresh_environment",
|
|
31
|
+
"reset_env_vars",
|
|
32
|
+
"set_env_vars",
|
|
33
|
+
]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# pylint: disable=import-outside-toplevel,reimported
|
|
4
|
+
"""Environment related utilities."""
|
|
5
|
+
|
|
6
|
+
import importlib.util
|
|
7
|
+
import os
|
|
8
|
+
import site
|
|
9
|
+
import sys
|
|
10
|
+
import warnings
|
|
11
|
+
from typing import Dict, List, Tuple
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def in_virtualenv() -> bool:
|
|
15
|
+
"""Check if we are inside a virtualenv.
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
bool
|
|
20
|
+
True if inside a virtualenv, False otherwise.
|
|
21
|
+
"""
|
|
22
|
+
return hasattr(sys, "real_prefix") or (
|
|
23
|
+
hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def refresh_environment() -> None:
|
|
28
|
+
"""Refresh the environment."""
|
|
29
|
+
# backup the default IOStream
|
|
30
|
+
from autogen.io import IOStream # type: ignore
|
|
31
|
+
|
|
32
|
+
default_io_stream = IOStream.get_default()
|
|
33
|
+
site.main()
|
|
34
|
+
# pylint: disable=import-outside-toplevel
|
|
35
|
+
modules_to_reload = [mod for mod in sys.modules if "autogen" in mod]
|
|
36
|
+
for mod in modules_to_reload:
|
|
37
|
+
del sys.modules[mod]
|
|
38
|
+
warnings.filterwarnings(
|
|
39
|
+
"ignore", module="flaml", message="^.*flaml.automl is not available.*$"
|
|
40
|
+
)
|
|
41
|
+
import autogen # type: ignore
|
|
42
|
+
from autogen.io import IOStream
|
|
43
|
+
|
|
44
|
+
importlib.reload(autogen)
|
|
45
|
+
# restore the default IOStream
|
|
46
|
+
IOStream.set_global_default(default_io_stream)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def set_env_vars(flow_env_vars: List[Tuple[str, str]]) -> Dict[str, str]:
|
|
50
|
+
"""Set environment variables and return the old ones (if any).
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
flow_env_vars : List[Tuple[str, str]]
|
|
55
|
+
The environment variables to set.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
Dict[str, str]
|
|
60
|
+
The old environment variables.
|
|
61
|
+
"""
|
|
62
|
+
old_vars: Dict[str, str] = {}
|
|
63
|
+
for var_key, var_value in flow_env_vars:
|
|
64
|
+
if var_key:
|
|
65
|
+
current = os.environ.get(var_key, "")
|
|
66
|
+
old_vars[var_key] = current
|
|
67
|
+
os.environ[var_key] = var_value
|
|
68
|
+
return old_vars
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def reset_env_vars(old_vars: Dict[str, str]) -> None:
|
|
72
|
+
"""Reset the environment variables.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
old_vars : Dict[str, str]
|
|
77
|
+
The old environment variables.
|
|
78
|
+
"""
|
|
79
|
+
for var_key, var_value in old_vars.items():
|
|
80
|
+
if not var_value:
|
|
81
|
+
os.environ.pop(var_key, "")
|
|
82
|
+
else:
|
|
83
|
+
os.environ[var_key] = var_value
|