waldiez 0.5.10__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.

Files changed (192) hide show
  1. waldiez/__init__.py +1 -1
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +19 -7
  4. waldiez/cli_extras/jupyter.py +3 -0
  5. waldiez/cli_extras/runner.py +3 -1
  6. waldiez/cli_extras/studio.py +3 -1
  7. waldiez/exporter.py +9 -3
  8. waldiez/exporting/agent/exporter.py +15 -16
  9. waldiez/exporting/agent/extras/captain_agent_extras.py +6 -6
  10. waldiez/exporting/agent/extras/doc_agent_extras.py +6 -6
  11. waldiez/exporting/agent/extras/group_manager_agent_extas.py +40 -24
  12. waldiez/exporting/agent/extras/group_member_extras.py +6 -5
  13. waldiez/exporting/agent/extras/handoffs/after_work.py +2 -1
  14. waldiez/exporting/agent/extras/handoffs/available.py +2 -1
  15. waldiez/exporting/agent/extras/handoffs/condition.py +3 -2
  16. waldiez/exporting/agent/extras/handoffs/handoff.py +2 -1
  17. waldiez/exporting/agent/extras/handoffs/target.py +7 -4
  18. waldiez/exporting/agent/extras/rag/chroma_extras.py +27 -19
  19. waldiez/exporting/agent/extras/rag/mongo_extras.py +8 -8
  20. waldiez/exporting/agent/extras/rag/pgvector_extras.py +5 -5
  21. waldiez/exporting/agent/extras/rag/qdrant_extras.py +5 -4
  22. waldiez/exporting/agent/extras/rag/vector_db_extras.py +1 -1
  23. waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +5 -7
  24. waldiez/exporting/agent/extras/reasoning_agent_extras.py +3 -5
  25. waldiez/exporting/agent/termination.py +1 -0
  26. waldiez/exporting/chats/exporter.py +4 -4
  27. waldiez/exporting/chats/processor.py +1 -2
  28. waldiez/exporting/chats/utils/common.py +89 -48
  29. waldiez/exporting/chats/utils/group.py +9 -9
  30. waldiez/exporting/chats/utils/nested.py +7 -7
  31. waldiez/exporting/chats/utils/sequential.py +1 -1
  32. waldiez/exporting/chats/utils/single.py +2 -2
  33. waldiez/exporting/core/constants.py +3 -1
  34. waldiez/exporting/core/content.py +7 -7
  35. waldiez/exporting/core/context.py +5 -3
  36. waldiez/exporting/core/exporter.py +5 -3
  37. waldiez/exporting/core/exporters.py +2 -2
  38. waldiez/exporting/core/extras/agent_extras/captain_extras.py +2 -2
  39. waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +2 -2
  40. waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +2 -2
  41. waldiez/exporting/core/extras/agent_extras/standard_extras.py +3 -8
  42. waldiez/exporting/core/extras/base.py +7 -5
  43. waldiez/exporting/core/extras/flow_extras.py +4 -5
  44. waldiez/exporting/core/extras/model_extras.py +2 -2
  45. waldiez/exporting/core/extras/path_resolver.py +1 -2
  46. waldiez/exporting/core/extras/serializer.py +13 -11
  47. waldiez/exporting/core/protocols.py +6 -5
  48. waldiez/exporting/core/result.py +25 -28
  49. waldiez/exporting/core/types.py +11 -10
  50. waldiez/exporting/core/utils/llm_config.py +4 -4
  51. waldiez/exporting/core/validation.py +10 -11
  52. waldiez/exporting/flow/execution_generator.py +99 -10
  53. waldiez/exporting/flow/exporter.py +2 -2
  54. waldiez/exporting/flow/factory.py +2 -2
  55. waldiez/exporting/flow/file_generator.py +4 -2
  56. waldiez/exporting/flow/merger.py +5 -3
  57. waldiez/exporting/flow/orchestrator.py +72 -2
  58. waldiez/exporting/flow/utils/common.py +6 -6
  59. waldiez/exporting/flow/utils/importing.py +7 -8
  60. waldiez/exporting/flow/utils/linting.py +25 -9
  61. waldiez/exporting/flow/utils/logging.py +5 -77
  62. waldiez/exporting/models/exporter.py +8 -8
  63. waldiez/exporting/models/processor.py +5 -5
  64. waldiez/exporting/tools/exporter.py +2 -2
  65. waldiez/exporting/tools/processor.py +7 -4
  66. waldiez/io/__init__.py +11 -5
  67. waldiez/io/_ws.py +12 -6
  68. waldiez/io/models/constants.py +10 -10
  69. waldiez/io/models/content/audio.py +1 -0
  70. waldiez/io/models/content/base.py +20 -18
  71. waldiez/io/models/content/file.py +1 -0
  72. waldiez/io/models/content/image.py +1 -0
  73. waldiez/io/models/content/text.py +1 -0
  74. waldiez/io/models/content/video.py +1 -0
  75. waldiez/io/models/user_input.py +10 -5
  76. waldiez/io/models/user_response.py +17 -16
  77. waldiez/io/mqtt.py +18 -31
  78. waldiez/io/redis.py +18 -22
  79. waldiez/io/structured.py +122 -70
  80. waldiez/io/utils.py +19 -10
  81. waldiez/io/ws.py +7 -3
  82. waldiez/logger.py +16 -3
  83. waldiez/models/agents/__init__.py +3 -0
  84. waldiez/models/agents/agent/agent.py +25 -17
  85. waldiez/models/agents/agent/agent_data.py +25 -22
  86. waldiez/models/agents/agent/code_execution.py +9 -11
  87. waldiez/models/agents/agent/termination_message.py +10 -12
  88. waldiez/models/agents/agent/update_system_message.py +2 -4
  89. waldiez/models/agents/agents.py +8 -8
  90. waldiez/models/agents/assistant/assistant.py +6 -3
  91. waldiez/models/agents/assistant/assistant_data.py +2 -2
  92. waldiez/models/agents/captain/captain_agent.py +7 -4
  93. waldiez/models/agents/captain/captain_agent_data.py +5 -7
  94. waldiez/models/agents/doc_agent/doc_agent.py +7 -4
  95. waldiez/models/agents/doc_agent/doc_agent_data.py +9 -10
  96. waldiez/models/agents/doc_agent/rag_query_engine.py +10 -12
  97. waldiez/models/agents/extra_requirements.py +3 -3
  98. waldiez/models/agents/group_manager/group_manager.py +12 -7
  99. waldiez/models/agents/group_manager/group_manager_data.py +13 -12
  100. waldiez/models/agents/group_manager/speakers.py +17 -19
  101. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +7 -4
  102. waldiez/models/agents/rag_user_proxy/rag_user_proxy_data.py +4 -1
  103. waldiez/models/agents/rag_user_proxy/retrieve_config.py +69 -63
  104. waldiez/models/agents/rag_user_proxy/vector_db_config.py +19 -19
  105. waldiez/models/agents/reasoning/reasoning_agent.py +7 -4
  106. waldiez/models/agents/reasoning/reasoning_agent_data.py +3 -2
  107. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +8 -8
  108. waldiez/models/agents/user_proxy/user_proxy.py +6 -3
  109. waldiez/models/agents/user_proxy/user_proxy_data.py +1 -1
  110. waldiez/models/chat/chat.py +28 -20
  111. waldiez/models/chat/chat_data.py +22 -21
  112. waldiez/models/chat/chat_message.py +9 -9
  113. waldiez/models/chat/chat_nested.py +9 -9
  114. waldiez/models/chat/chat_summary.py +6 -6
  115. waldiez/models/common/__init__.py +2 -0
  116. waldiez/models/common/ag2_version.py +2 -0
  117. waldiez/models/common/base.py +2 -0
  118. waldiez/models/common/dict_utils.py +8 -6
  119. waldiez/models/common/handoff.py +20 -17
  120. waldiez/models/common/method_utils.py +9 -7
  121. waldiez/models/common/naming.py +49 -0
  122. waldiez/models/flow/flow.py +11 -6
  123. waldiez/models/flow/flow_data.py +23 -17
  124. waldiez/models/flow/info.py +3 -3
  125. waldiez/models/flow/naming.py +2 -1
  126. waldiez/models/model/_aws.py +11 -13
  127. waldiez/models/model/_llm.py +8 -0
  128. waldiez/models/model/_price.py +2 -4
  129. waldiez/models/model/extra_requirements.py +1 -3
  130. waldiez/models/model/model.py +2 -2
  131. waldiez/models/model/model_data.py +21 -21
  132. waldiez/models/tool/extra_requirements.py +2 -4
  133. waldiez/models/tool/predefined/_duckduckgo.py +1 -0
  134. waldiez/models/tool/predefined/_email.py +4 -0
  135. waldiez/models/tool/predefined/_google.py +1 -0
  136. waldiez/models/tool/predefined/_perplexity.py +2 -1
  137. waldiez/models/tool/predefined/_searxng.py +2 -1
  138. waldiez/models/tool/predefined/_tavily.py +1 -0
  139. waldiez/models/tool/predefined/_wikipedia.py +2 -1
  140. waldiez/models/tool/predefined/_youtube.py +1 -0
  141. waldiez/models/tool/tool.py +8 -5
  142. waldiez/models/tool/tool_data.py +2 -2
  143. waldiez/models/waldiez.py +152 -4
  144. waldiez/runner.py +11 -5
  145. waldiez/running/async_utils.py +192 -0
  146. waldiez/running/base_runner.py +155 -241
  147. waldiez/running/dir_utils.py +52 -0
  148. waldiez/running/environment.py +10 -44
  149. waldiez/running/events_mixin.py +252 -0
  150. waldiez/running/exceptions.py +20 -0
  151. waldiez/running/gen_seq_diagram.py +18 -15
  152. waldiez/running/io_utils.py +216 -0
  153. waldiez/running/protocol.py +11 -5
  154. waldiez/running/requirements_mixin.py +65 -0
  155. waldiez/running/results_mixin.py +926 -0
  156. waldiez/running/standard_runner.py +24 -27
  157. waldiez/running/step_by_step/breakpoints_mixin.py +503 -47
  158. waldiez/running/step_by_step/command_handler.py +154 -0
  159. waldiez/running/step_by_step/events_processor.py +379 -0
  160. waldiez/running/step_by_step/step_by_step_models.py +425 -41
  161. waldiez/running/step_by_step/step_by_step_runner.py +437 -382
  162. waldiez/running/subprocess_runner/__base__.py +13 -8
  163. waldiez/running/subprocess_runner/_async_runner.py +6 -4
  164. waldiez/running/subprocess_runner/_sync_runner.py +11 -6
  165. waldiez/running/subprocess_runner/runner.py +48 -23
  166. waldiez/running/timeline_processor.py +1 -1
  167. waldiez/utils/__init__.py +2 -0
  168. waldiez/utils/conflict_checker.py +4 -4
  169. waldiez/utils/python_manager.py +415 -0
  170. waldiez/ws/__init__.py +8 -7
  171. waldiez/ws/_file_handler.py +18 -20
  172. waldiez/ws/_mock.py +75 -0
  173. waldiez/ws/cli.py +58 -10
  174. waldiez/ws/client_manager.py +77 -53
  175. waldiez/ws/errors.py +3 -0
  176. waldiez/ws/models.py +61 -53
  177. waldiez/ws/reloader.py +33 -4
  178. waldiez/ws/server.py +121 -52
  179. waldiez/ws/session_manager.py +8 -9
  180. waldiez/ws/session_stats.py +1 -1
  181. waldiez/ws/utils.py +33 -5
  182. {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/METADATA +107 -109
  183. waldiez-0.6.1.dist-info/RECORD +254 -0
  184. waldiez/running/post_run.py +0 -180
  185. waldiez/running/pre_run.py +0 -159
  186. waldiez/running/run_results.py +0 -14
  187. waldiez/running/utils.py +0 -511
  188. waldiez-0.5.10.dist-info/RECORD +0 -248
  189. {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/WHEEL +0 -0
  190. {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/entry_points.txt +0 -0
  191. {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/licenses/LICENSE +0 -0
  192. {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/licenses/NOTICE.md +0 -0
@@ -50,6 +50,10 @@ class BaseSubprocessRunner:
50
50
  self.dot_env = dot_env
51
51
  self.logger = logger or logging.getLogger(self.__class__.__name__)
52
52
  self.waiting_for_input = False
53
+ breakpoints = kwargs.get("breakpoints", [])
54
+ if not isinstance(breakpoints, list):
55
+ breakpoints = []
56
+ self.breakpoints: list[str] = breakpoints
53
57
 
54
58
  def build_command(
55
59
  self,
@@ -110,6 +114,10 @@ class BaseSubprocessRunner:
110
114
  if self.dot_env:
111
115
  cmd.extend(["--dot-env", str(self.dot_env)])
112
116
 
117
+ if self.breakpoints:
118
+ for entry in self.breakpoints:
119
+ cmd.extend(["--breakpoints", entry])
120
+ self.logger.debug("Runner command: %s", " ".join(cmd))
113
121
  return cmd
114
122
 
115
123
  def parse_output(
@@ -138,7 +146,7 @@ class BaseSubprocessRunner:
138
146
  try:
139
147
  data = json.loads(line)
140
148
  if isinstance(data, dict):
141
- return data # pyright: ignore
149
+ return data # pyright: ignore[reportUnknownVariableType]
142
150
  except json.JSONDecodeError:
143
151
  return self.create_output_message(stream=stream, content=line)
144
152
  return self.create_output_message(
@@ -195,7 +203,7 @@ class BaseSubprocessRunner:
195
203
  def create_input_response(
196
204
  self,
197
205
  response_type: str,
198
- user_input: str,
206
+ user_input: Any,
199
207
  request_id: str | None = None,
200
208
  ) -> str:
201
209
  """Create input response for subprocess.
@@ -204,7 +212,7 @@ class BaseSubprocessRunner:
204
212
  ----------
205
213
  response_type : str
206
214
  Type of the response
207
- user_input : str
215
+ user_input : Any
208
216
  User's input response
209
217
  request_id : str | None
210
218
  Request ID from the input request
@@ -214,15 +222,12 @@ class BaseSubprocessRunner:
214
222
  str
215
223
  JSON-formatted response
216
224
  """
217
- response = {
218
- "type": response_type,
219
- "data": user_input,
220
- }
225
+ response: dict[str, Any] = {"type": response_type, "data": user_input}
221
226
 
222
227
  if request_id:
223
228
  response["request_id"] = request_id
224
229
 
225
- return json.dumps(response) + "\n"
230
+ return json.dumps(response, default=str, ensure_ascii=False) + "\n"
226
231
 
227
232
  def create_output_message(
228
233
  self, content: str, stream: str = "stdout", msg_type: str = "output"
@@ -10,8 +10,9 @@ import logging
10
10
 
11
11
  # noinspection PyProtectedMember
12
12
  from asyncio.subprocess import Process as AsyncProcess
13
+ from collections.abc import Coroutine
13
14
  from pathlib import Path
14
- from typing import Any, Callable, Coroutine, Literal, Optional
15
+ from typing import Any, Callable, Literal
15
16
 
16
17
  from .__base__ import BaseSubprocessRunner
17
18
 
@@ -57,7 +58,7 @@ class AsyncSubprocessRunner(BaseSubprocessRunner):
57
58
  )
58
59
  self.on_output = on_output
59
60
  self.on_input_request = on_input_request
60
- self.process: Optional[AsyncProcess] = None
61
+ self.process: AsyncProcess | None = None
61
62
  self.input_queue: asyncio.Queue[str] = asyncio.Queue()
62
63
  self.output_queue: asyncio.Queue[dict[str, Any]] = asyncio.Queue()
63
64
  self._monitor_tasks: list[asyncio.Task[Any]] = []
@@ -158,7 +159,8 @@ class AsyncSubprocessRunner(BaseSubprocessRunner):
158
159
  await self.process.wait()
159
160
 
160
161
  except Exception as e:
161
- self.logger.error(f"Error stopping subprocess: {e}")
162
+ if not isinstance(e, AttributeError):
163
+ self.logger.error(f"Error stopping subprocess: {e}")
162
164
  self.process = None
163
165
 
164
166
  async def _start_monitoring(self) -> None:
@@ -311,7 +313,7 @@ class AsyncSubprocessRunner(BaseSubprocessRunner):
311
313
  self.process.stdin.write(response.encode())
312
314
  await self.process.stdin.drain()
313
315
 
314
- self.logger.debug(f"Sent input response: {user_input}")
316
+ self.logger.debug(f"Sent {response_type}: {user_input}")
315
317
 
316
318
  except asyncio.TimeoutError:
317
319
  self.logger.warning("Input request timed out")
@@ -93,6 +93,7 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
93
93
  stdin=subprocess.PIPE,
94
94
  stdout=subprocess.PIPE,
95
95
  stderr=subprocess.PIPE,
96
+ encoding="utf-8",
96
97
  text=True,
97
98
  bufsize=1, # Line buffered
98
99
  )
@@ -175,7 +176,6 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
175
176
  # Use readline with timeout simulation
176
177
  if self.process.stdout.readable(): # pragma: no branch
177
178
  line = self.process.stdout.readline()
178
-
179
179
  if not line: # pragma: no cover
180
180
  time.sleep(0.1)
181
181
  continue
@@ -209,7 +209,7 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
209
209
  # Use readline with timeout simulation
210
210
  if self.process.stderr.readable(): # pragma: no branch
211
211
  line = self.process.stderr.readline()
212
-
212
+ self.logger.debug("Stderr line: %s", line)
213
213
  if not line:
214
214
  time.sleep(0.1)
215
215
  continue
@@ -272,9 +272,11 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
272
272
  line : str
273
273
  Decoded line from stdout
274
274
  """
275
- # Try to parse as structured JSON first
275
+ self.logger.debug(f"Stdout line: {line}")
276
276
  parsed_data = self.parse_output(line, stream="stdout")
277
277
  if not parsed_data:
278
+ self.logger.debug("Non-structured output, forwarding as is")
279
+ self.output_queue.put({"type": "print", "data": line}, timeout=1.0)
278
280
  return
279
281
  if parsed_data.get("type") in ("input_request", "debug_input_request"):
280
282
  prompt = parsed_data.get("prompt", "> ")
@@ -317,7 +319,7 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
317
319
  self.process.stdin.write(response)
318
320
  self.process.stdin.flush()
319
321
 
320
- self.logger.debug(f"Sent input response: {user_input}")
322
+ self.logger.debug(f"Sent {response_type}: {user_input}")
321
323
 
322
324
  except queue.Empty:
323
325
  self.logger.warning("Input request timed out")
@@ -350,8 +352,9 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
350
352
  f"Thread {thread.name} did not stop gracefully"
351
353
  )
352
354
 
355
+ # pylint: disable=too-complex
353
356
  # noinspection TryExceptPass,PyBroadException
354
- def _cleanup_process(self) -> None:
357
+ def _cleanup_process(self) -> None: # noqa: C901
355
358
  """Cleanup process resources."""
356
359
  if self.process:
357
360
  if self.process.stdin:
@@ -380,7 +383,9 @@ class SyncSubprocessRunner(BaseSubprocessRunner):
380
383
  self.process.kill()
381
384
  self.process.wait()
382
385
  except BaseException as e:
383
- self.logger.error(f"Error stopping subprocess: {e}")
386
+ if not isinstance(e, AttributeError):
387
+ # already "None"
388
+ self.logger.error(f"Error stopping subprocess: {e}")
384
389
  finally:
385
390
  self.process = None
386
391
 
@@ -1,5 +1,7 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+
4
+ # pyright: reportAttributeAccessIssue=false,reportUnknownArgumentType=false
3
5
  # flake8: noqa: G004
4
6
  """Waldiez subprocess runner that inherits from BaseRunner."""
5
7
 
@@ -8,16 +10,17 @@ import re
8
10
  from pathlib import Path
9
11
  from typing import Any, Callable, Literal
10
12
 
13
+ from typing_extensions import override
14
+
11
15
  from waldiez.models import Waldiez
12
16
 
13
17
  from ..base_runner import WaldiezBaseRunner
18
+ from ..step_by_step.breakpoints_mixin import BreakpointsMixin
14
19
  from ._async_runner import AsyncSubprocessRunner
15
20
  from ._sync_runner import SyncSubprocessRunner
16
21
 
17
- # TODO: check output directory and return the results from the JSON logs
18
- # in self._run and self._a_run
19
-
20
22
 
23
+ # noinspection PyUnusedLocal
21
24
  class WaldiezSubprocessRunner(WaldiezBaseRunner):
22
25
  """Waldiez runner that uses subprocess execution via standalone runners."""
23
26
 
@@ -70,6 +73,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
70
73
  dot_env=dot_env,
71
74
  **kwargs,
72
75
  )
76
+ self.breakpoints = self._parse_breakpoints(**kwargs)
73
77
 
74
78
  # Store callbacks
75
79
  self.sync_on_output = on_output or self._default_sync_output
@@ -89,6 +93,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
89
93
  mode = kwargs.get("mode", "run")
90
94
  if mode not in ["run", "debug"]:
91
95
  raise ValueError(f"Invalid mode: {mode}")
96
+ # noinspection PyTypeChecker
92
97
  self.mode: Literal["run", "debug"] = mode
93
98
  waldiez_file = kwargs.get("waldiez_file")
94
99
  self._waldiez_file = self._ensure_waldiez_file(waldiez_file)
@@ -101,19 +106,30 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
101
106
  return waldiez_file.resolve()
102
107
  file_name = self.waldiez.name
103
108
  # sanitize file name
109
+ # noinspection RegExpRedundantEscape
104
110
  file_name = re.sub(r"[^a-zA-Z0-9_\-\.]", "_", file_name)[:30]
105
111
  file_name = f"{file_name}.waldiez"
106
- with open(file_name, "w", encoding="utf-8") as f:
112
+ with open(file_name, "w", encoding="utf-8", newline="\n") as f:
107
113
  f.write(self.waldiez.model_dump_json())
108
114
  return Path(file_name).resolve()
109
115
 
116
+ @staticmethod
117
+ def _parse_breakpoints(**kwargs: Any) -> list[str]:
118
+ initial_breakpoints = kwargs.get("breakpoints")
119
+ if isinstance(initial_breakpoints, (list, set, tuple)):
120
+ breakpoints = BreakpointsMixin.get_initial_breakpoints(
121
+ initial_breakpoints
122
+ )
123
+ return [str(item) for item in breakpoints]
124
+ return []
125
+
110
126
  def _default_sync_output(self, data: dict[str, Any]) -> None:
111
127
  """Get the default sync output handler."""
112
128
  if data.get("type") == "error":
113
129
  self.log.error(data.get("data", ""))
114
130
  else:
115
131
  content = data.get("data", data)
116
- self._print(content)
132
+ self.print(content)
117
133
 
118
134
  def _default_sync_input_request(self, prompt: str) -> None:
119
135
  """Get the default sync input request handler."""
@@ -138,6 +154,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
138
154
  uploads_root=self.uploads_root,
139
155
  dot_env=self.dot_env_path,
140
156
  logger=self.log,
157
+ breakpoints=self.breakpoints,
141
158
  )
142
159
  return self.async_runner
143
160
 
@@ -150,9 +167,11 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
150
167
  uploads_root=self.uploads_root,
151
168
  dot_env=self.dot_env_path,
152
169
  logger=self.log,
170
+ breakpoints=self.breakpoints,
153
171
  )
154
172
  return self.sync_runner
155
173
 
174
+ @override
156
175
  def run(
157
176
  self,
158
177
  output_path: str | Path | None = None,
@@ -217,6 +236,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
217
236
  return _output_path / f"{filename}.py"
218
237
  return self._waldiez_file.with_suffix(".py")
219
238
 
239
+ @override
220
240
  def _run(
221
241
  self,
222
242
  temp_dir: Path,
@@ -239,14 +259,8 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
239
259
  runner = self._create_sync_subprocess_runner()
240
260
 
241
261
  # Run subprocess
242
- success = runner.run_subprocess(self._waldiez_file, mode=self.mode)
243
- return [
244
- {
245
- "success": success,
246
- "runner": "sync_subprocess",
247
- "mode": self.mode,
248
- }
249
- ]
262
+ runner.run_subprocess(self._waldiez_file, mode=self.mode)
263
+ return self.read_from_output(output_file.parent)
250
264
 
251
265
  except Exception as e:
252
266
  self.log.error("Error in sync subprocess execution: %s", e)
@@ -258,6 +272,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
258
272
  }
259
273
  ]
260
274
 
275
+ @override
261
276
  async def a_run(
262
277
  self,
263
278
  output_path: str | Path | None = None,
@@ -308,6 +323,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
308
323
  **kwargs,
309
324
  )
310
325
 
326
+ @override
311
327
  async def _a_run(
312
328
  self,
313
329
  temp_dir: Path,
@@ -353,17 +369,11 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
353
369
  runner = self._create_async_subprocess_runner()
354
370
 
355
371
  # Run subprocess
356
- success = await runner.run_subprocess(
372
+ await runner.run_subprocess(
357
373
  self._waldiez_file,
358
374
  mode=self.mode,
359
375
  )
360
- return [
361
- {
362
- "success": success,
363
- "runner": "async_subprocess",
364
- "mode": self.mode,
365
- }
366
- ]
376
+ return await self.a_read_from_output(output_file.parent)
367
377
 
368
378
  except Exception as e:
369
379
  self.log.error("Error in async subprocess execution: %s", e)
@@ -405,6 +415,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
405
415
  self.sync_runner.provide_user_input, user_input
406
416
  )
407
417
 
418
+ @override
408
419
  def stop(self) -> None:
409
420
  """Stop the workflow execution."""
410
421
  super().stop() # Set the base runner stop flag
@@ -458,10 +469,13 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
458
469
  self.sync_runner.stop()
459
470
  self.sync_runner = None
460
471
 
472
+ @override
461
473
  def _after_run(
462
474
  self,
463
475
  results: list[dict[str, Any]],
476
+ error: BaseException | None,
464
477
  output_file: Path,
478
+ waldiez_file: Path,
465
479
  uploads_root: Path | None,
466
480
  temp_dir: Path,
467
481
  skip_mmd: bool,
@@ -472,9 +486,13 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
472
486
  Parameters
473
487
  ----------
474
488
  results : list[dict[str, Any]]
475
- Results from the workflow execution
489
+ Results from the workflow execution.
490
+ error : BaseException | None
491
+ Optional error during the run.
476
492
  output_file : Path
477
493
  Output file path
494
+ waldiez_file : Path
495
+ The waldiez file used/dumped for the run.
478
496
  uploads_root : Path | None
479
497
  Uploads root directory
480
498
  temp_dir : Path
@@ -487,10 +505,13 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
487
505
  # Cleanup subprocess runners
488
506
  self._cleanup_subprocess_runners()
489
507
 
508
+ @override
490
509
  async def _a_after_run(
491
510
  self,
492
511
  results: list[dict[str, Any]],
512
+ error: BaseException | None,
493
513
  output_file: Path,
514
+ waldiez_file: Path,
494
515
  uploads_root: Path | None,
495
516
  temp_dir: Path,
496
517
  skip_mmd: bool,
@@ -501,9 +522,13 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
501
522
  Parameters
502
523
  ----------
503
524
  results : list[dict[str, Any]]
504
- Results from the workflow execution
525
+ Results from the workflow execution.
526
+ error : BaseException | None
527
+ Optional error during the run.
505
528
  output_file : Path
506
529
  Output file path
530
+ waldiez_file : Path
531
+ The waldiez file used/dumped for the run.
507
532
  uploads_root : Path | None
508
533
  Uploads root directory
509
534
  temp_dir : Path
@@ -93,7 +93,7 @@ class TimelineProcessor:
93
93
  bool
94
94
  True if the value is missing, NaN, or empty; False otherwise.
95
95
  """
96
- if pd.isna(value): # pyright: ignore
96
+ if pd.isna(value):
97
97
  return True
98
98
  if isinstance(value, str) and (
99
99
  value.strip() == "" or value.lower() == "nan"
waldiez/utils/__init__.py CHANGED
@@ -3,9 +3,11 @@
3
3
  """Utils to call on init."""
4
4
 
5
5
  from .conflict_checker import check_conflicts
6
+ from .python_manager import PythonManager
6
7
  from .version import get_waldiez_version
7
8
 
8
9
  __all__ = [
9
10
  "check_conflicts",
10
11
  "get_waldiez_version",
12
+ "PythonManager",
11
13
  ]
@@ -15,16 +15,16 @@ __waldiez_checked_conflicts = False
15
15
  def _check_autogen_agentchat() -> None: # pragma: no cover
16
16
  try:
17
17
  version("autogen-agentchat")
18
- print(
18
+ msg = (
19
19
  "Conflict detected: 'autogen-agentchat' is installed "
20
20
  "in the current environment, \n"
21
21
  "which conflicts with 'ag2'.\n"
22
22
  "Please uninstall 'autogen-agentchat': \n"
23
- f"{sys.executable} -m pip uninstall -y autogen-agentchat" + "\n"
23
+ f"{sys.executable} -m pip uninstall -y autogen-agentchat\n"
24
24
  "And install 'ag2' (and/or 'waldiez') again: \n"
25
- f"{sys.executable} -m pip install --force ag2 waldiez",
26
- file=sys.stderr,
25
+ f"{sys.executable} -m pip install --force ag2 waldiez"
27
26
  )
27
+ print(msg, file=sys.stderr)
28
28
  sys.exit(1)
29
29
  except PackageNotFoundError:
30
30
  pass