waldiez 0.4.7__py3-none-any.whl → 0.4.9__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.

Files changed (248) hide show
  1. waldiez/__init__.py +5 -5
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +97 -102
  4. waldiez/exporter.py +61 -19
  5. waldiez/exporting/__init__.py +25 -6
  6. waldiez/exporting/agent/__init__.py +7 -3
  7. waldiez/exporting/agent/code_execution.py +114 -0
  8. waldiez/exporting/agent/exporter.py +354 -0
  9. waldiez/exporting/agent/extras/__init__.py +15 -0
  10. waldiez/exporting/agent/extras/captain_agent_extras.py +315 -0
  11. waldiez/exporting/agent/extras/group/target.py +178 -0
  12. waldiez/exporting/agent/extras/group_manager_agent_extas.py +500 -0
  13. waldiez/exporting/agent/extras/group_member_extras.py +181 -0
  14. waldiez/exporting/agent/extras/handoffs/__init__.py +19 -0
  15. waldiez/exporting/agent/extras/handoffs/after_work.py +78 -0
  16. waldiez/exporting/agent/extras/handoffs/available.py +74 -0
  17. waldiez/exporting/agent/extras/handoffs/condition.py +158 -0
  18. waldiez/exporting/agent/extras/handoffs/handoff.py +171 -0
  19. waldiez/exporting/agent/extras/handoffs/target.py +189 -0
  20. waldiez/exporting/agent/extras/rag/__init__.py +10 -0
  21. waldiez/exporting/agent/{utils/rag_user/chroma_utils.py → extras/rag/chroma_extras.py} +37 -24
  22. waldiez/exporting/agent/{utils/rag_user/mongo_utils.py → extras/rag/mongo_extras.py} +10 -10
  23. waldiez/exporting/agent/{utils/rag_user/pgvector_utils.py → extras/rag/pgvector_extras.py} +13 -13
  24. waldiez/exporting/agent/{utils/rag_user/qdrant_utils.py → extras/rag/qdrant_extras.py} +13 -13
  25. waldiez/exporting/agent/{utils/rag_user/vector_db.py → extras/rag/vector_db_extras.py} +59 -46
  26. waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +245 -0
  27. waldiez/exporting/agent/extras/reasoning_agent_extras.py +88 -0
  28. waldiez/exporting/agent/factory.py +95 -0
  29. waldiez/exporting/agent/processor.py +150 -0
  30. waldiez/exporting/agent/system_message.py +36 -0
  31. waldiez/exporting/agent/termination.py +50 -0
  32. waldiez/exporting/chats/__init__.py +7 -3
  33. waldiez/exporting/chats/exporter.py +97 -0
  34. waldiez/exporting/chats/factory.py +65 -0
  35. waldiez/exporting/chats/processor.py +226 -0
  36. waldiez/exporting/chats/utils/__init__.py +6 -5
  37. waldiez/exporting/chats/utils/common.py +11 -45
  38. waldiez/exporting/chats/utils/group.py +55 -0
  39. waldiez/exporting/chats/utils/nested.py +37 -52
  40. waldiez/exporting/chats/utils/sequential.py +72 -61
  41. waldiez/exporting/chats/utils/{single_chat.py → single.py} +48 -50
  42. waldiez/exporting/core/__init__.py +196 -0
  43. waldiez/exporting/core/constants.py +17 -0
  44. waldiez/exporting/core/content.py +69 -0
  45. waldiez/exporting/core/context.py +244 -0
  46. waldiez/exporting/core/enums.py +89 -0
  47. waldiez/exporting/core/errors.py +19 -0
  48. waldiez/exporting/core/exporter.py +390 -0
  49. waldiez/exporting/core/exporters.py +67 -0
  50. waldiez/exporting/core/extras/__init__.py +39 -0
  51. waldiez/exporting/core/extras/agent_extras/__init__.py +27 -0
  52. waldiez/exporting/core/extras/agent_extras/captain_extras.py +57 -0
  53. waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +102 -0
  54. waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +53 -0
  55. waldiez/exporting/core/extras/agent_extras/reasoning_extras.py +68 -0
  56. waldiez/exporting/core/extras/agent_extras/standard_extras.py +263 -0
  57. waldiez/exporting/core/extras/base.py +241 -0
  58. waldiez/exporting/core/extras/chat_extras.py +118 -0
  59. waldiez/exporting/core/extras/flow_extras.py +70 -0
  60. waldiez/exporting/core/extras/model_extras.py +73 -0
  61. waldiez/exporting/core/extras/path_resolver.py +93 -0
  62. waldiez/exporting/core/extras/serializer.py +138 -0
  63. waldiez/exporting/core/extras/tool_extras.py +82 -0
  64. waldiez/exporting/core/protocols.py +259 -0
  65. waldiez/exporting/core/result.py +705 -0
  66. waldiez/exporting/core/types.py +329 -0
  67. waldiez/exporting/core/utils/__init__.py +11 -0
  68. waldiez/exporting/core/utils/comment.py +33 -0
  69. waldiez/exporting/core/utils/llm_config.py +117 -0
  70. waldiez/exporting/core/validation.py +96 -0
  71. waldiez/exporting/flow/__init__.py +6 -2
  72. waldiez/exporting/flow/execution_generator.py +193 -0
  73. waldiez/exporting/flow/exporter.py +107 -0
  74. waldiez/exporting/flow/factory.py +94 -0
  75. waldiez/exporting/flow/file_generator.py +214 -0
  76. waldiez/exporting/flow/merger.py +387 -0
  77. waldiez/exporting/flow/orchestrator.py +411 -0
  78. waldiez/exporting/flow/utils/__init__.py +9 -36
  79. waldiez/exporting/flow/utils/common.py +206 -0
  80. waldiez/exporting/flow/utils/importing.py +373 -0
  81. waldiez/exporting/flow/utils/linting.py +200 -0
  82. waldiez/exporting/flow/utils/{logging_utils.py → logging.py} +23 -9
  83. waldiez/exporting/models/__init__.py +3 -1
  84. waldiez/exporting/models/exporter.py +233 -0
  85. waldiez/exporting/models/factory.py +66 -0
  86. waldiez/exporting/models/processor.py +139 -0
  87. waldiez/exporting/tools/__init__.py +11 -0
  88. waldiez/exporting/tools/exporter.py +207 -0
  89. waldiez/exporting/tools/factory.py +57 -0
  90. waldiez/exporting/tools/processor.py +248 -0
  91. waldiez/exporting/tools/registration.py +133 -0
  92. waldiez/io/__init__.py +128 -0
  93. waldiez/io/_ws.py +199 -0
  94. waldiez/io/models/__init__.py +60 -0
  95. waldiez/io/models/base.py +66 -0
  96. waldiez/io/models/constants.py +78 -0
  97. waldiez/io/models/content/__init__.py +23 -0
  98. waldiez/io/models/content/audio.py +43 -0
  99. waldiez/io/models/content/base.py +45 -0
  100. waldiez/io/models/content/file.py +43 -0
  101. waldiez/io/models/content/image.py +96 -0
  102. waldiez/io/models/content/text.py +37 -0
  103. waldiez/io/models/content/video.py +43 -0
  104. waldiez/io/models/user_input.py +269 -0
  105. waldiez/io/models/user_response.py +215 -0
  106. waldiez/io/mqtt.py +681 -0
  107. waldiez/io/redis.py +782 -0
  108. waldiez/io/structured.py +439 -0
  109. waldiez/io/utils.py +184 -0
  110. waldiez/io/ws.py +298 -0
  111. waldiez/logger.py +481 -0
  112. waldiez/models/__init__.py +108 -51
  113. waldiez/models/agents/__init__.py +34 -70
  114. waldiez/models/agents/agent/__init__.py +10 -4
  115. waldiez/models/agents/agent/agent.py +466 -65
  116. waldiez/models/agents/agent/agent_data.py +119 -47
  117. waldiez/models/agents/agent/agent_type.py +13 -2
  118. waldiez/models/agents/agent/code_execution.py +12 -12
  119. waldiez/models/agents/agent/human_input_mode.py +8 -0
  120. waldiez/models/agents/agent/{linked_skill.py → linked_tool.py} +7 -7
  121. waldiez/models/agents/agent/nested_chat.py +35 -7
  122. waldiez/models/agents/agent/termination_message.py +30 -22
  123. waldiez/models/agents/{swarm_agent → agent}/update_system_message.py +22 -22
  124. waldiez/models/agents/agents.py +58 -63
  125. waldiez/models/agents/assistant/assistant.py +4 -4
  126. waldiez/models/agents/assistant/assistant_data.py +13 -1
  127. waldiez/models/agents/{captain_agent → captain}/captain_agent.py +5 -5
  128. waldiez/models/agents/{captain_agent → captain}/captain_agent_data.py +5 -5
  129. waldiez/models/agents/extra_requirements.py +11 -16
  130. waldiez/models/agents/group_manager/group_manager.py +103 -13
  131. waldiez/models/agents/group_manager/group_manager_data.py +36 -14
  132. waldiez/models/agents/group_manager/speakers.py +77 -24
  133. waldiez/models/agents/{rag_user → rag_user_proxy}/__init__.py +16 -16
  134. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +64 -0
  135. waldiez/models/agents/{rag_user/rag_user_data.py → rag_user_proxy/rag_user_proxy_data.py} +6 -5
  136. waldiez/models/agents/{rag_user → rag_user_proxy}/retrieve_config.py +182 -114
  137. waldiez/models/agents/{rag_user → rag_user_proxy}/vector_db_config.py +13 -13
  138. waldiez/models/agents/reasoning/reasoning_agent.py +6 -6
  139. waldiez/models/agents/reasoning/reasoning_agent_data.py +110 -63
  140. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +38 -10
  141. waldiez/models/agents/user_proxy/user_proxy.py +11 -7
  142. waldiez/models/agents/user_proxy/user_proxy_data.py +2 -2
  143. waldiez/models/chat/__init__.py +2 -1
  144. waldiez/models/chat/chat.py +166 -87
  145. waldiez/models/chat/chat_data.py +99 -136
  146. waldiez/models/chat/chat_message.py +33 -23
  147. waldiez/models/chat/chat_nested.py +31 -30
  148. waldiez/models/chat/chat_summary.py +10 -8
  149. waldiez/models/common/__init__.py +52 -2
  150. waldiez/models/common/ag2_version.py +1 -1
  151. waldiez/models/common/base.py +38 -7
  152. waldiez/models/common/dict_utils.py +42 -17
  153. waldiez/models/common/handoff.py +459 -0
  154. waldiez/models/common/id_generator.py +19 -0
  155. waldiez/models/common/method_utils.py +130 -68
  156. waldiez/{exporting/base/utils → models/common}/naming.py +38 -61
  157. waldiez/models/common/waldiez_version.py +37 -0
  158. waldiez/models/flow/__init__.py +9 -2
  159. waldiez/models/flow/connection.py +18 -0
  160. waldiez/models/flow/flow.py +311 -215
  161. waldiez/models/flow/flow_data.py +207 -40
  162. waldiez/models/flow/info.py +85 -0
  163. waldiez/models/flow/naming.py +131 -0
  164. waldiez/models/model/__init__.py +7 -1
  165. waldiez/models/model/extra_requirements.py +3 -12
  166. waldiez/models/model/model.py +76 -21
  167. waldiez/models/model/model_data.py +108 -20
  168. waldiez/models/tool/__init__.py +16 -0
  169. waldiez/models/tool/extra_requirements.py +36 -0
  170. waldiez/models/{skill/skill.py → tool/tool.py} +88 -88
  171. waldiez/models/tool/tool_data.py +51 -0
  172. waldiez/models/tool/tool_type.py +8 -0
  173. waldiez/models/waldiez.py +97 -80
  174. waldiez/runner.py +115 -61
  175. waldiez/running/__init__.py +13 -7
  176. waldiez/running/environment.py +49 -68
  177. waldiez/running/gen_seq_diagram.py +16 -14
  178. waldiez/running/post_run.py +119 -0
  179. waldiez/running/pre_run.py +149 -0
  180. waldiez/running/util.py +134 -0
  181. waldiez/utils/__init__.py +2 -4
  182. waldiez/utils/cli_extras/jupyter.py +5 -3
  183. waldiez/utils/cli_extras/runner.py +6 -4
  184. waldiez/utils/cli_extras/studio.py +6 -4
  185. waldiez/utils/conflict_checker.py +15 -9
  186. waldiez/utils/flaml_warnings.py +5 -5
  187. waldiez/utils/version.py +47 -0
  188. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/METADATA +235 -91
  189. waldiez-0.4.9.dist-info/RECORD +203 -0
  190. waldiez/exporting/agent/agent_exporter.py +0 -297
  191. waldiez/exporting/agent/utils/__init__.py +0 -23
  192. waldiez/exporting/agent/utils/captain_agent.py +0 -263
  193. waldiez/exporting/agent/utils/code_execution.py +0 -65
  194. waldiez/exporting/agent/utils/group_manager.py +0 -220
  195. waldiez/exporting/agent/utils/rag_user/__init__.py +0 -7
  196. waldiez/exporting/agent/utils/rag_user/rag_user.py +0 -209
  197. waldiez/exporting/agent/utils/reasoning.py +0 -36
  198. waldiez/exporting/agent/utils/swarm_agent.py +0 -469
  199. waldiez/exporting/agent/utils/teachability.py +0 -41
  200. waldiez/exporting/agent/utils/termination_message.py +0 -44
  201. waldiez/exporting/base/__init__.py +0 -25
  202. waldiez/exporting/base/agent_position.py +0 -75
  203. waldiez/exporting/base/base_exporter.py +0 -118
  204. waldiez/exporting/base/export_position.py +0 -48
  205. waldiez/exporting/base/import_position.py +0 -23
  206. waldiez/exporting/base/mixin.py +0 -137
  207. waldiez/exporting/base/utils/__init__.py +0 -18
  208. waldiez/exporting/base/utils/comments.py +0 -96
  209. waldiez/exporting/base/utils/path_check.py +0 -68
  210. waldiez/exporting/base/utils/to_string.py +0 -84
  211. waldiez/exporting/chats/chats_exporter.py +0 -240
  212. waldiez/exporting/chats/utils/swarm.py +0 -210
  213. waldiez/exporting/flow/flow_exporter.py +0 -528
  214. waldiez/exporting/flow/utils/agent_utils.py +0 -204
  215. waldiez/exporting/flow/utils/chat_utils.py +0 -71
  216. waldiez/exporting/flow/utils/def_main.py +0 -77
  217. waldiez/exporting/flow/utils/flow_content.py +0 -202
  218. waldiez/exporting/flow/utils/flow_names.py +0 -116
  219. waldiez/exporting/flow/utils/importing_utils.py +0 -227
  220. waldiez/exporting/models/models_exporter.py +0 -199
  221. waldiez/exporting/models/utils.py +0 -174
  222. waldiez/exporting/skills/__init__.py +0 -9
  223. waldiez/exporting/skills/skills_exporter.py +0 -176
  224. waldiez/exporting/skills/utils.py +0 -369
  225. waldiez/models/agents/agent/teachability.py +0 -70
  226. waldiez/models/agents/rag_user/rag_user.py +0 -60
  227. waldiez/models/agents/swarm_agent/__init__.py +0 -50
  228. waldiez/models/agents/swarm_agent/after_work.py +0 -179
  229. waldiez/models/agents/swarm_agent/on_condition.py +0 -105
  230. waldiez/models/agents/swarm_agent/on_condition_available.py +0 -142
  231. waldiez/models/agents/swarm_agent/on_condition_target.py +0 -40
  232. waldiez/models/agents/swarm_agent/swarm_agent.py +0 -107
  233. waldiez/models/agents/swarm_agent/swarm_agent_data.py +0 -124
  234. waldiez/models/flow/utils.py +0 -232
  235. waldiez/models/skill/__init__.py +0 -16
  236. waldiez/models/skill/extra_requirements.py +0 -36
  237. waldiez/models/skill/skill_data.py +0 -53
  238. waldiez/models/skill/skill_type.py +0 -8
  239. waldiez/running/running.py +0 -369
  240. waldiez/utils/pysqlite3_checker.py +0 -308
  241. waldiez/utils/rdps_checker.py +0 -122
  242. waldiez-0.4.7.dist-info/RECORD +0 -149
  243. /waldiez/models/agents/{captain_agent → captain}/__init__.py +0 -0
  244. /waldiez/models/agents/{captain_agent → captain}/captain_agent_lib_entry.py +0 -0
  245. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/WHEEL +0 -0
  246. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/entry_points.txt +0 -0
  247. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/licenses/LICENSE +0 -0
  248. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/licenses/NOTICE.md +0 -0
waldiez/runner.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Run a waldiez flow.
4
4
 
5
- The flow is first converted to an autogen flow with agents, chats and skills.
5
+ The flow is first converted to an autogen flow with agents, chats, and tools.
6
6
  We then chown to temporary directory, call the flow's `main()` and
7
7
  return the results. Before running the flow, any additional environment
8
8
  variables specified in the waldiez file are set.
@@ -10,14 +10,22 @@ variables specified in the waldiez file are set.
10
10
 
11
11
  # pylint: disable=import-outside-toplevel,reimported
12
12
 
13
+ import gc
13
14
  import importlib.util
14
15
  import sys
15
16
  import tempfile
16
17
  from pathlib import Path
17
- from types import TracebackType
18
- from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union
18
+ from types import ModuleType, TracebackType
19
+ from typing import (
20
+ TYPE_CHECKING,
21
+ Optional,
22
+ Set,
23
+ Type,
24
+ Union,
25
+ )
19
26
 
20
27
  from .exporter import WaldiezExporter
28
+ from .io import StructuredIOStream
21
29
  from .models.waldiez import Waldiez
22
30
  from .running import (
23
31
  a_chdir,
@@ -25,13 +33,11 @@ from .running import (
25
33
  after_run,
26
34
  before_run,
27
35
  chdir,
28
- get_printer,
29
36
  install_requirements,
30
37
  refresh_environment,
31
38
  reset_env_vars,
32
39
  set_env_vars,
33
40
  )
34
- from .utils import check_pysqlite3
35
41
 
36
42
  if TYPE_CHECKING:
37
43
  from autogen import ChatResult # type: ignore
@@ -56,8 +62,8 @@ class WaldiezRunner:
56
62
  waldiez_file: Union[str, Path],
57
63
  name: Optional[str] = None,
58
64
  description: Optional[str] = None,
59
- tags: Optional[List[str]] = None,
60
- requirements: Optional[List[str]] = None,
65
+ tags: Optional[list[str]] = None,
66
+ requirements: Optional[list[str]] = None,
61
67
  ) -> "WaldiezRunner":
62
68
  """Create a WaldiezRunner instance from a file.
63
69
 
@@ -69,9 +75,9 @@ class WaldiezRunner:
69
75
  The name of the Waldiez, by default None.
70
76
  description : Optional[str], optional
71
77
  The description of the Waldiez, by default None.
72
- tags : Optional[List[str]], optional
78
+ tags : Optional[list[str]], optional
73
79
  The tags of the Waldiez, by default None.
74
- requirements : Optional[List[str]], optional
80
+ requirements : Optional[list[str]], optional
75
81
  The requirements of the Waldiez, by default None.
76
82
 
77
83
  Returns
@@ -132,6 +138,11 @@ class WaldiezRunner:
132
138
  """Get the Waldiez instance."""
133
139
  return self._waldiez
134
140
 
141
+ @property
142
+ def is_async(self) -> bool:
143
+ """Check if the workflow is async."""
144
+ return self.waldiez.is_async
145
+
135
146
  @property
136
147
  def running(self) -> bool:
137
148
  """Get the running status."""
@@ -148,34 +159,50 @@ class WaldiezRunner:
148
159
  extra_requirements = {
149
160
  req for req in self.waldiez.requirements if req not in sys.modules
150
161
  }
151
- if self.waldiez.has_captain_agents:
152
- check_pysqlite3()
153
162
  return extra_requirements
154
163
 
155
164
  def install_requirements(self) -> None:
156
165
  """Install the requirements for the flow."""
157
166
  self._called_install_requirements = True
158
- printer = get_printer()
159
167
  extra_requirements = self.gather_requirements()
160
168
  if extra_requirements:
161
- install_requirements(extra_requirements, printer)
162
- refresh_environment()
169
+ install_requirements(extra_requirements)
163
170
 
164
171
  async def a_install_requirements(self) -> None:
165
172
  """Install the requirements for the flow asynchronously."""
166
173
  self._called_install_requirements = True
167
- printer = get_printer()
168
174
  extra_requirements = self.gather_requirements()
169
175
  if extra_requirements:
170
- await a_install_requirements(extra_requirements, printer)
171
- refresh_environment()
176
+ await a_install_requirements(extra_requirements)
177
+
178
+ def _before_run(
179
+ self,
180
+ temp_dir: Path,
181
+ file_name: str,
182
+ module_name: str,
183
+ ) -> tuple[ModuleType, dict[str, str]]:
184
+ self._exporter.export(Path(file_name))
185
+ # unique_names = self._exporter.context.get_unique_names()
186
+ spec = importlib.util.spec_from_file_location(
187
+ module_name, temp_dir / file_name
188
+ )
189
+ if not spec or not spec.loader:
190
+ raise ImportError("Could not import the flow")
191
+ sys.path.insert(0, str(temp_dir))
192
+ old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
193
+ module = importlib.util.module_from_spec(spec)
194
+ spec.loader.exec_module(module)
195
+ print("<Waldiez> - Starting workflow...")
196
+ print(self.waldiez.info.model_dump_json())
197
+ return module, old_vars
172
198
 
173
199
  def _run(
174
200
  self,
175
201
  output_path: Optional[Union[str, Path]],
176
202
  uploads_root: Optional[Union[str, Path]],
203
+ use_structured_io: bool = False,
177
204
  skip_mmd: bool = False,
178
- ) -> Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]:
205
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
179
206
  """Run the Waldiez workflow.
180
207
 
181
208
  Parameters
@@ -184,12 +211,14 @@ class WaldiezRunner:
184
211
  The output path.
185
212
  uploads_root : Optional[Union[str, Path]]
186
213
  The runtime uploads root.
214
+ use_structured_io : bool
215
+ Whether to use structured IO instead of the default 'input/print'.
187
216
  skip_mmd : bool
188
217
  Whether to skip the Mermaid diagram generation.
189
218
 
190
219
  Returns
191
220
  -------
192
- Union[ChatResult, List[ChatResult]]
221
+ Union[ChatResult, list[ChatResult]]
193
222
  The result(s) of the chat(s).
194
223
  """
195
224
  temp_dir = Path(tempfile.mkdtemp())
@@ -197,95 +226,99 @@ class WaldiezRunner:
197
226
  module_name = file_name.replace(".py", "")
198
227
  if not self._called_install_requirements:
199
228
  self.install_requirements()
200
- else:
201
- refresh_environment()
202
- printer = get_printer()
203
- printer(
229
+ refresh_environment()
230
+ print(
204
231
  "Requirements installed.\n"
205
232
  "NOTE: If new packages were added and you are using Jupyter, "
206
233
  "you might need to restart the kernel."
207
234
  )
208
235
  results: Union[
209
- "ChatResult", List["ChatResult"], Dict[int, "ChatResult"]
236
+ "ChatResult", list["ChatResult"], dict[int, "ChatResult"]
210
237
  ] = []
211
238
  with chdir(to=temp_dir):
212
- self._exporter.export(Path(file_name))
213
- spec = importlib.util.spec_from_file_location(
214
- module_name, temp_dir / file_name
239
+ module, old_vars = self._before_run(
240
+ temp_dir=temp_dir,
241
+ file_name=file_name,
242
+ module_name=module_name,
215
243
  )
216
- if not spec or not spec.loader:
217
- raise ImportError("Could not import the flow")
218
- sys.path.insert(0, str(temp_dir))
219
- old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
220
- module = importlib.util.module_from_spec(spec)
221
- spec.loader.exec_module(module)
222
- printer("<Waldiez> - Starting workflow...")
223
- results = module.main()
224
- printer("<Waldiez> - Workflow finished")
244
+ if use_structured_io:
245
+ stream = StructuredIOStream(
246
+ timeout=120, # 2 minutes
247
+ uploads_root=uploads_root,
248
+ )
249
+ with StructuredIOStream.set_default(stream):
250
+ results = module.main()
251
+ else:
252
+ results = module.main()
253
+ print("<Waldiez> - Workflow finished")
225
254
  sys.path.pop(0)
226
255
  reset_env_vars(old_vars)
227
256
  after_run(
228
257
  temp_dir=temp_dir,
229
258
  output_path=output_path,
230
- printer=printer,
231
259
  flow_name=self.waldiez.name,
232
260
  skip_mmd=skip_mmd,
233
261
  )
262
+ gc.collect()
263
+ refresh_environment()
234
264
  return results
235
265
 
236
266
  async def _a_run(
237
267
  self,
238
268
  output_path: Optional[Union[str, Path]],
239
269
  uploads_root: Optional[Union[str, Path]],
270
+ use_structured_io: bool = False,
240
271
  skip_mmd: bool = False,
241
- ) -> Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]:
272
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
242
273
  """Run the Waldiez workflow asynchronously."""
243
274
  temp_dir = Path(tempfile.mkdtemp())
244
275
  file_name = before_run(output_path, uploads_root)
245
276
  module_name = file_name.replace(".py", "")
246
277
  if not self._called_install_requirements:
247
278
  await self.a_install_requirements()
248
- else:
249
- refresh_environment()
250
- printer = get_printer()
251
- printer(
279
+ refresh_environment()
280
+ print(
252
281
  "Requirements installed.\n"
253
282
  "NOTE: If new packages were added and you are using Jupyter, "
254
283
  "you might need to restart the kernel."
255
284
  )
256
285
  results: Union[
257
- "ChatResult", List["ChatResult"], Dict[int, "ChatResult"]
286
+ "ChatResult", list["ChatResult"], dict[int, "ChatResult"]
258
287
  ] = []
259
288
  async with a_chdir(to=temp_dir):
260
- self._exporter.export(Path(file_name))
261
- spec = importlib.util.spec_from_file_location(
262
- module_name, temp_dir / file_name
289
+ module, old_vars = self._before_run(
290
+ temp_dir=temp_dir,
291
+ file_name=file_name,
292
+ module_name=module_name,
263
293
  )
264
- if not spec or not spec.loader:
265
- raise ImportError("Could not import the flow")
266
- sys.path.insert(0, str(temp_dir))
267
- old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
268
- module = importlib.util.module_from_spec(spec)
269
- spec.loader.exec_module(module)
270
- printer("<Waldiez> - Starting workflow...")
271
- results = await module.main()
294
+ if use_structured_io:
295
+ stream = StructuredIOStream(
296
+ timeout=120, # 2 minutes
297
+ uploads_root=uploads_root,
298
+ )
299
+ with StructuredIOStream.set_default(stream):
300
+ results = await module.main()
301
+ else:
302
+ results = await module.main()
272
303
  sys.path.pop(0)
273
304
  reset_env_vars(old_vars)
274
305
  after_run(
275
306
  temp_dir=temp_dir,
276
307
  output_path=output_path,
277
- printer=printer,
278
308
  flow_name=self.waldiez.name,
279
309
  skip_mmd=skip_mmd,
280
310
  )
311
+ gc.collect()
312
+ refresh_environment()
281
313
  return results
282
314
 
283
315
  def run(
284
316
  self,
285
317
  output_path: Optional[Union[str, Path]] = None,
286
318
  uploads_root: Optional[Union[str, Path]] = None,
319
+ use_structured_io: bool = False,
287
320
  skip_mmd: bool = False,
288
- ) -> Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]:
321
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
289
322
  """Run the Waldiez workflow.
290
323
 
291
324
  Parameters
@@ -294,12 +327,15 @@ class WaldiezRunner:
294
327
  The output path, by default None.
295
328
  uploads_root : Optional[Union[str, Path]], optional
296
329
  The uploads root, to get user-uploaded files, by default None.
330
+ use_structured_io : bool, optional
331
+ Whether to use structured IO instead of the default 'input/print',
332
+ by default False.
297
333
  skip_mmd : bool, optional
298
334
  Whether to skip the Mermaid diagram generation, by default False.
299
335
 
300
336
  Returns
301
337
  -------
302
- Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]
338
+ Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]
303
339
  The result(s) of the chat(s).
304
340
 
305
341
  Raises
@@ -316,6 +352,7 @@ class WaldiezRunner:
316
352
  self._a_run,
317
353
  output_path,
318
354
  uploads_root,
355
+ use_structured_io,
319
356
  skip_mmd,
320
357
  )
321
358
  if self._running is True:
@@ -323,7 +360,12 @@ class WaldiezRunner:
323
360
  self._running = True
324
361
  file_path = output_path or self._file_path
325
362
  try:
326
- return self._run(file_path, uploads_root, skip_mmd)
363
+ return self._run(
364
+ file_path,
365
+ uploads_root=uploads_root,
366
+ use_structured_io=use_structured_io,
367
+ skip_mmd=skip_mmd,
368
+ )
327
369
  finally:
328
370
  self._running = False
329
371
 
@@ -331,7 +373,9 @@ class WaldiezRunner:
331
373
  self,
332
374
  output_path: Optional[Union[str, Path]] = None,
333
375
  uploads_root: Optional[Union[str, Path]] = None,
334
- ) -> Union["ChatResult", List["ChatResult"]]:
376
+ use_structured_io: bool = False,
377
+ skip_mmd: bool = False,
378
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
335
379
  """Run the Waldiez workflow asynchronously.
336
380
 
337
381
  Parameters
@@ -340,10 +384,15 @@ class WaldiezRunner:
340
384
  The output path, by default None.
341
385
  uploads_root : Optional[Union[str, Path]], optional
342
386
  The uploads root, to get user-uploaded files, by default None.
387
+ use_structured_io : bool, optional
388
+ Whether to use structured IO instead of the default 'input/print',
389
+ by default False.
390
+ skip_mmd : bool, optional
391
+ Whether to skip the Mermaid diagram generation, by default False.
343
392
 
344
393
  Returns
345
394
  -------
346
- Union[ChatResult, List[ChatResult]]
395
+ Union[ChatResult, list[ChatResult]], dict[int, ChatResult]
347
396
  The result(s) of the chat(s).
348
397
 
349
398
  Raises
@@ -356,6 +405,11 @@ class WaldiezRunner:
356
405
  self._running = True
357
406
  file_path = output_path or self._file_path
358
407
  try:
359
- return await self._a_run(file_path, uploads_root)
408
+ return await self._a_run(
409
+ file_path,
410
+ uploads_root=uploads_root,
411
+ use_structured_io=use_structured_io,
412
+ skip_mmd=skip_mmd,
413
+ )
360
414
  finally:
361
415
  self._running = False
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- """Common utility functions."""
3
+ """Running related functions."""
4
4
 
5
5
  from .environment import (
6
6
  in_virtualenv,
@@ -9,23 +9,29 @@ from .environment import (
9
9
  reset_env_vars,
10
10
  set_env_vars,
11
11
  )
12
- from .running import (
13
- a_chdir,
12
+ from .post_run import after_run
13
+ from .pre_run import (
14
14
  a_install_requirements,
15
- after_run,
16
15
  before_run,
17
- chdir,
18
- get_printer,
19
16
  install_requirements,
20
17
  )
18
+ from .util import (
19
+ a_chdir,
20
+ chdir,
21
+ create_async_subprocess,
22
+ create_sync_subprocess,
23
+ strip_ansi,
24
+ )
21
25
 
22
26
  __all__ = [
23
27
  "a_chdir",
24
28
  "a_install_requirements",
25
29
  "after_run",
26
30
  "before_run",
31
+ "create_async_subprocess",
32
+ "create_sync_subprocess",
33
+ "strip_ansi",
27
34
  "chdir",
28
- "get_printer",
29
35
  "in_virtualenv",
30
36
  "is_root",
31
37
  "install_requirements",
@@ -3,12 +3,9 @@
3
3
  # pylint: disable=import-outside-toplevel,reimported
4
4
  """Environment related utilities."""
5
5
 
6
- import importlib
7
6
  import os
8
- import site
9
7
  import sys
10
- import warnings
11
- from typing import Dict, Generator, List, Tuple
8
+ from typing import Generator
12
9
 
13
10
 
14
11
  def in_virtualenv() -> bool:
@@ -25,7 +22,7 @@ def in_virtualenv() -> bool:
25
22
  )
26
23
 
27
24
 
28
- def is_root() -> bool:
25
+ def is_root() -> bool: # pragma: no cover # os specific
29
26
  """Check if the script is running as root/administrator.
30
27
 
31
28
  Returns
@@ -33,13 +30,15 @@ def is_root() -> bool:
33
30
  bool
34
31
  True if running as root/administrator, False otherwise.
35
32
  """
36
- # pylint: disable=import-outside-toplevel,line-too-long
33
+ # pylint: disable=import-outside-toplevel,line-too-long,no-member
37
34
  if os.name == "nt":
35
+ # noinspection PyBroadException
36
+ # pylint: disable=broad-exception-caught
38
37
  try:
39
38
  import ctypes
40
39
 
41
40
  return ctypes.windll.shell32.IsUserAnAdmin() != 0 # type: ignore[unused-ignore,attr-defined] # noqa: E501
42
- except Exception: # pylint: disable=broad-exception-caught
41
+ except Exception:
43
42
  return False
44
43
  else:
45
44
  return os.getuid() == 0
@@ -47,75 +46,57 @@ def is_root() -> bool:
47
46
 
48
47
  def refresh_environment() -> None:
49
48
  """Refresh the environment."""
50
- with warnings.catch_warnings():
51
- warnings.filterwarnings(
52
- "ignore",
53
- module="flaml",
54
- message="^.*flaml.automl is not available.*$",
55
- )
56
- from autogen.io import IOStream # type: ignore
57
-
58
- default_io_stream = IOStream.get_default()
59
- site.main()
60
- # pylint: disable=import-outside-toplevel
61
- modules_to_reload = [mod for mod in sys.modules if "autogen" in mod]
62
- for mod in modules_to_reload:
63
- del sys.modules[mod]
64
- import autogen # type: ignore
65
- from autogen.io import IOStream
66
-
67
- importlib.reload(autogen)
68
- # restore the default IOStream
69
- IOStream.set_global_default(default_io_stream)
70
- # reload any other modules that may have been affected
71
- for mod in modules_to_reload:
72
- if mod not in sys.modules:
73
- importlib.import_module(mod)
74
- # a swarm chat without a user agent
75
- # creates a new user (this has a default code execution with docker)
76
- # captain also generates new agents that also have
77
- # default code execution with docker
78
- # temp (until we handle/detect docker setup)
79
- os.environ["AUTOGEN_USE_DOCKER"] = "0"
80
- # we might get:
81
- # module 'numpy' has no attribute '_no_nep50_warning'
82
- # in autogen/agentchat/contrib/captainagent/tool_retriever.py
83
- os.environ["NEP50_DEPRECATION_WARNING"] = "0"
84
- os.environ["NEP50_DISABLE_WARNING"] = "1"
85
- os.environ["NPY_PROMOTION_STATE"] = "weak"
86
- import numpy as np
87
-
88
- if not hasattr(np, "_no_pep50_warning"):
89
- import contextlib
90
-
91
- @contextlib.contextmanager
92
- def _np_no_nep50_warning() -> Generator[None, None, None]:
93
- """Avoid no_nep50 warning.
94
-
95
- Yields
96
- ------
97
- None
98
- Dummy value.
99
- """
100
- yield
101
-
102
- setattr(np, "_no_pep50_warning", _np_no_nep50_warning) # noqa
103
-
104
-
105
- def set_env_vars(flow_env_vars: List[Tuple[str, str]]) -> Dict[str, str]:
49
+ # a group chat without a user agent
50
+ # creates a new user (this has a default code execution with docker)
51
+ # captain also generates new agents that also have
52
+ # default code execution with docker
53
+ # temp (until we handle/detect docker setup)
54
+ os.environ["AUTOGEN_USE_DOCKER"] = "0"
55
+ try_handle_the_np_thing()
56
+
57
+
58
+ def try_handle_the_np_thing() -> None:
59
+ """Try to handle the numpy deprecation warning."""
60
+ # we might get:
61
+ # module 'numpy' has no attribute '_no_nep50_warning'
62
+ # (sentnence_transformers?)
63
+ # in autogen/agentchat/contrib/captainagent/tool_retriever.py
64
+ os.environ["NEP50_DEPRECATION_WARNING"] = "0"
65
+ os.environ["NEP50_DISABLE_WARNING"] = "1"
66
+ os.environ["NPY_PROMOTION_STATE"] = "weak"
67
+ import numpy as np
68
+
69
+ if not hasattr(np, "_no_pep50_warning"):
70
+ import contextlib
71
+
72
+ @contextlib.contextmanager
73
+ def _np_no_nep50_warning() -> Generator[None, None, None]:
74
+ """Avoid no_nep50 warning.
75
+
76
+ Yields
77
+ ------
78
+ None
79
+ Nothing.
80
+ """
81
+ yield # pragma: no cover
82
+
83
+ setattr(np, "_no_pep50_warning", _np_no_nep50_warning) # noqa
84
+
85
+
86
+ def set_env_vars(flow_env_vars: list[tuple[str, str]]) -> dict[str, str]:
106
87
  """Set environment variables and return the old ones (if any).
107
88
 
108
89
  Parameters
109
90
  ----------
110
- flow_env_vars : List[Tuple[str, str]]
91
+ flow_env_vars : list[tuple[str, str]]
111
92
  The environment variables to set.
112
93
 
113
94
  Returns
114
95
  -------
115
- Dict[str, str]
96
+ dict[str, str]
116
97
  The old environment variables.
117
98
  """
118
- old_vars: Dict[str, str] = {}
99
+ old_vars: dict[str, str] = {}
119
100
  for var_key, var_value in flow_env_vars:
120
101
  if var_key:
121
102
  current = os.environ.get(var_key, "")
@@ -124,12 +105,12 @@ def set_env_vars(flow_env_vars: List[Tuple[str, str]]) -> Dict[str, str]:
124
105
  return old_vars
125
106
 
126
107
 
127
- def reset_env_vars(old_vars: Dict[str, str]) -> None:
108
+ def reset_env_vars(old_vars: dict[str, str]) -> None:
128
109
  """Reset the environment variables.
129
110
 
130
111
  Parameters
131
112
  ----------
132
- old_vars : Dict[str, str]
113
+ old_vars : dict[str, str]
133
114
  The old environment variables.
134
115
  """
135
116
  for var_key, var_value in old_vars.items():