waldiez 0.6.0__py3-none-any.whl → 0.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of waldiez might be problematic. Click here for more details.

Files changed (188) hide show
  1. waldiez/__init__.py +1 -1
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +18 -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 +9 -10
  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 +34 -23
  12. waldiez/exporting/agent/extras/group_member_extras.py +6 -5
  13. waldiez/exporting/agent/extras/handoffs/after_work.py +1 -1
  14. waldiez/exporting/agent/extras/handoffs/available.py +1 -1
  15. waldiez/exporting/agent/extras/handoffs/condition.py +3 -2
  16. waldiez/exporting/agent/extras/handoffs/handoff.py +1 -1
  17. waldiez/exporting/agent/extras/handoffs/target.py +6 -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/chats/exporter.py +4 -4
  26. waldiez/exporting/chats/processor.py +1 -2
  27. waldiez/exporting/chats/utils/common.py +89 -48
  28. waldiez/exporting/chats/utils/group.py +9 -9
  29. waldiez/exporting/chats/utils/nested.py +7 -7
  30. waldiez/exporting/chats/utils/sequential.py +1 -1
  31. waldiez/exporting/chats/utils/single.py +2 -2
  32. waldiez/exporting/core/content.py +7 -7
  33. waldiez/exporting/core/context.py +5 -3
  34. waldiez/exporting/core/exporter.py +5 -3
  35. waldiez/exporting/core/exporters.py +2 -2
  36. waldiez/exporting/core/extras/agent_extras/captain_extras.py +2 -2
  37. waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +2 -2
  38. waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +2 -2
  39. waldiez/exporting/core/extras/agent_extras/standard_extras.py +3 -8
  40. waldiez/exporting/core/extras/base.py +7 -5
  41. waldiez/exporting/core/extras/flow_extras.py +4 -5
  42. waldiez/exporting/core/extras/model_extras.py +2 -2
  43. waldiez/exporting/core/extras/path_resolver.py +1 -2
  44. waldiez/exporting/core/extras/serializer.py +2 -2
  45. waldiez/exporting/core/protocols.py +6 -5
  46. waldiez/exporting/core/result.py +25 -28
  47. waldiez/exporting/core/types.py +10 -10
  48. waldiez/exporting/core/utils/llm_config.py +2 -2
  49. waldiez/exporting/core/validation.py +10 -11
  50. waldiez/exporting/flow/execution_generator.py +98 -10
  51. waldiez/exporting/flow/exporter.py +2 -2
  52. waldiez/exporting/flow/factory.py +2 -2
  53. waldiez/exporting/flow/file_generator.py +4 -2
  54. waldiez/exporting/flow/merger.py +5 -3
  55. waldiez/exporting/flow/orchestrator.py +72 -2
  56. waldiez/exporting/flow/utils/common.py +5 -5
  57. waldiez/exporting/flow/utils/importing.py +6 -7
  58. waldiez/exporting/flow/utils/linting.py +25 -9
  59. waldiez/exporting/flow/utils/logging.py +2 -2
  60. waldiez/exporting/models/exporter.py +8 -8
  61. waldiez/exporting/models/processor.py +5 -5
  62. waldiez/exporting/tools/exporter.py +2 -2
  63. waldiez/exporting/tools/processor.py +7 -4
  64. waldiez/io/__init__.py +8 -4
  65. waldiez/io/_ws.py +10 -6
  66. waldiez/io/models/constants.py +10 -10
  67. waldiez/io/models/content/audio.py +1 -0
  68. waldiez/io/models/content/base.py +20 -18
  69. waldiez/io/models/content/file.py +1 -0
  70. waldiez/io/models/content/image.py +1 -0
  71. waldiez/io/models/content/text.py +1 -0
  72. waldiez/io/models/content/video.py +1 -0
  73. waldiez/io/models/user_input.py +10 -5
  74. waldiez/io/models/user_response.py +17 -16
  75. waldiez/io/mqtt.py +18 -31
  76. waldiez/io/redis.py +18 -22
  77. waldiez/io/structured.py +52 -53
  78. waldiez/io/utils.py +3 -0
  79. waldiez/io/ws.py +5 -1
  80. waldiez/logger.py +16 -3
  81. waldiez/models/agents/__init__.py +3 -0
  82. waldiez/models/agents/agent/agent.py +23 -16
  83. waldiez/models/agents/agent/agent_data.py +25 -22
  84. waldiez/models/agents/agent/code_execution.py +9 -11
  85. waldiez/models/agents/agent/termination_message.py +10 -12
  86. waldiez/models/agents/agent/update_system_message.py +2 -4
  87. waldiez/models/agents/agents.py +8 -8
  88. waldiez/models/agents/assistant/assistant.py +6 -3
  89. waldiez/models/agents/assistant/assistant_data.py +2 -2
  90. waldiez/models/agents/captain/captain_agent.py +7 -4
  91. waldiez/models/agents/captain/captain_agent_data.py +5 -7
  92. waldiez/models/agents/doc_agent/doc_agent.py +7 -4
  93. waldiez/models/agents/doc_agent/doc_agent_data.py +9 -10
  94. waldiez/models/agents/doc_agent/rag_query_engine.py +10 -12
  95. waldiez/models/agents/extra_requirements.py +3 -3
  96. waldiez/models/agents/group_manager/group_manager.py +12 -7
  97. waldiez/models/agents/group_manager/group_manager_data.py +13 -12
  98. waldiez/models/agents/group_manager/speakers.py +17 -19
  99. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +7 -4
  100. waldiez/models/agents/rag_user_proxy/rag_user_proxy_data.py +4 -1
  101. waldiez/models/agents/rag_user_proxy/retrieve_config.py +69 -63
  102. waldiez/models/agents/rag_user_proxy/vector_db_config.py +19 -19
  103. waldiez/models/agents/reasoning/reasoning_agent.py +7 -4
  104. waldiez/models/agents/reasoning/reasoning_agent_data.py +3 -2
  105. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +8 -8
  106. waldiez/models/agents/user_proxy/user_proxy.py +6 -3
  107. waldiez/models/agents/user_proxy/user_proxy_data.py +1 -1
  108. waldiez/models/chat/chat.py +27 -20
  109. waldiez/models/chat/chat_data.py +22 -19
  110. waldiez/models/chat/chat_message.py +9 -9
  111. waldiez/models/chat/chat_nested.py +9 -9
  112. waldiez/models/chat/chat_summary.py +6 -6
  113. waldiez/models/common/__init__.py +2 -0
  114. waldiez/models/common/ag2_version.py +2 -0
  115. waldiez/models/common/dict_utils.py +8 -6
  116. waldiez/models/common/handoff.py +18 -17
  117. waldiez/models/common/method_utils.py +7 -7
  118. waldiez/models/common/naming.py +49 -0
  119. waldiez/models/flow/flow.py +11 -6
  120. waldiez/models/flow/flow_data.py +23 -17
  121. waldiez/models/flow/info.py +3 -3
  122. waldiez/models/flow/naming.py +2 -1
  123. waldiez/models/model/_aws.py +11 -13
  124. waldiez/models/model/_llm.py +5 -0
  125. waldiez/models/model/_price.py +2 -4
  126. waldiez/models/model/extra_requirements.py +1 -3
  127. waldiez/models/model/model.py +2 -2
  128. waldiez/models/model/model_data.py +21 -21
  129. waldiez/models/tool/extra_requirements.py +2 -4
  130. waldiez/models/tool/predefined/_duckduckgo.py +1 -0
  131. waldiez/models/tool/predefined/_email.py +1 -0
  132. waldiez/models/tool/predefined/_google.py +1 -0
  133. waldiez/models/tool/predefined/_perplexity.py +1 -0
  134. waldiez/models/tool/predefined/_searxng.py +1 -0
  135. waldiez/models/tool/predefined/_tavily.py +1 -0
  136. waldiez/models/tool/predefined/_wikipedia.py +1 -0
  137. waldiez/models/tool/predefined/_youtube.py +1 -0
  138. waldiez/models/tool/tool.py +8 -5
  139. waldiez/models/tool/tool_data.py +2 -2
  140. waldiez/models/waldiez.py +152 -4
  141. waldiez/runner.py +11 -5
  142. waldiez/running/async_utils.py +192 -0
  143. waldiez/running/base_runner.py +117 -264
  144. waldiez/running/dir_utils.py +52 -0
  145. waldiez/running/environment.py +10 -44
  146. waldiez/running/events_mixin.py +252 -0
  147. waldiez/running/exceptions.py +20 -0
  148. waldiez/running/gen_seq_diagram.py +18 -15
  149. waldiez/running/io_utils.py +216 -0
  150. waldiez/running/protocol.py +11 -5
  151. waldiez/running/requirements_mixin.py +65 -0
  152. waldiez/running/results_mixin.py +926 -0
  153. waldiez/running/standard_runner.py +22 -25
  154. waldiez/running/step_by_step/breakpoints_mixin.py +192 -60
  155. waldiez/running/step_by_step/command_handler.py +3 -0
  156. waldiez/running/step_by_step/events_processor.py +194 -14
  157. waldiez/running/step_by_step/step_by_step_models.py +110 -43
  158. waldiez/running/step_by_step/step_by_step_runner.py +107 -57
  159. waldiez/running/subprocess_runner/__base__.py +9 -1
  160. waldiez/running/subprocess_runner/_async_runner.py +5 -3
  161. waldiez/running/subprocess_runner/_sync_runner.py +6 -2
  162. waldiez/running/subprocess_runner/runner.py +39 -23
  163. waldiez/running/timeline_processor.py +1 -1
  164. waldiez/utils/__init__.py +2 -0
  165. waldiez/utils/conflict_checker.py +4 -4
  166. waldiez/utils/python_manager.py +415 -0
  167. waldiez/ws/_file_handler.py +18 -18
  168. waldiez/ws/_mock.py +2 -1
  169. waldiez/ws/cli.py +36 -12
  170. waldiez/ws/client_manager.py +35 -27
  171. waldiez/ws/errors.py +3 -0
  172. waldiez/ws/models.py +43 -52
  173. waldiez/ws/reloader.py +12 -4
  174. waldiez/ws/server.py +85 -55
  175. waldiez/ws/session_manager.py +8 -9
  176. waldiez/ws/session_stats.py +1 -1
  177. waldiez/ws/utils.py +4 -1
  178. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/METADATA +82 -93
  179. waldiez-0.6.1.dist-info/RECORD +254 -0
  180. waldiez/running/post_run.py +0 -186
  181. waldiez/running/pre_run.py +0 -281
  182. waldiez/running/run_results.py +0 -14
  183. waldiez/running/utils.py +0 -625
  184. waldiez-0.6.0.dist-info/RECORD +0 -251
  185. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/WHEEL +0 -0
  186. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/entry_points.txt +0 -0
  187. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/LICENSE +0 -0
  188. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/NOTICE.md +0 -0
waldiez/ws/cli.py CHANGED
@@ -1,22 +1,28 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- # pylint: disable=too-many-locals,unused-import
3
+
4
+ # pylint: disable=too-many-locals,unused-import,invalid-name
5
+ # pyright: reportUnusedImport=false,reportConstantRedefinition=false
6
+ # pyright: reportUnusedParameter=false, reportCallInDefaultInitializer=false
7
+
4
8
  """CLI interface for Waldiez WebSocket server."""
5
9
 
6
10
  import asyncio
7
11
  import logging
12
+ import os
8
13
  import re
9
14
  import sys
15
+ import traceback
10
16
  from pathlib import Path
11
- from typing import Annotated, Any, Optional, Set
17
+ from typing import Annotated, Any
12
18
 
13
19
  import typer
14
20
 
15
21
  HAS_WATCHDOG = False
16
22
  try:
17
- from .reloader import FileWatcher # pyright: ignore # noqa: F401
23
+ from .reloader import FileWatcher # noqa: F401
18
24
 
19
- HAS_WATCHDOG = True # pyright: ignore
25
+ HAS_WATCHDOG = True
20
26
  except ImportError:
21
27
  pass
22
28
 
@@ -24,7 +30,7 @@ HAS_WEBSOCKETS = False
24
30
  try:
25
31
  from .server import run_server
26
32
 
27
- HAS_WEBSOCKETS = True # pyright: ignore
33
+ HAS_WEBSOCKETS = True
28
34
  except ImportError:
29
35
  # pylint: disable=missing-param-doc,missing-raises-doc
30
36
  # noinspection PyUnusedLocal
@@ -34,6 +40,7 @@ except ImportError:
34
40
 
35
41
 
36
42
  DEFAULT_WORKSPACE_DIR = Path.cwd()
43
+ DEFAULT_WS_PORT = 8765
37
44
 
38
45
 
39
46
  def setup_logging(verbose: bool = False) -> None:
@@ -69,12 +76,27 @@ app = typer.Typer(
69
76
  )
70
77
 
71
78
 
79
+ def _get_ws_port() -> int:
80
+ """Get the default ws server port to use."""
81
+ vite_ws_config = os.environ.get("VITE_DEV_WS_URL", "")
82
+ if not vite_ws_config:
83
+ return DEFAULT_WS_PORT
84
+ # VITE_DEV_WS_URL=ws://localhost:8765
85
+ server_parts = vite_ws_config.rsplit(":", maxsplit=1)
86
+ if not server_parts:
87
+ return DEFAULT_WS_PORT
88
+ try:
89
+ return int(server_parts[-1])
90
+ except Exception: # pylint: disable=broad-exception-caught
91
+ return DEFAULT_WS_PORT
92
+
93
+
72
94
  @app.command()
73
95
  def serve(
74
96
  host: Annotated[
75
97
  str, typer.Option(help="Server host address")
76
98
  ] = "localhost",
77
- port: Annotated[int, typer.Option(help="Server port")] = 8765,
99
+ port: Annotated[int, typer.Option(help="Server port")] = _get_ws_port(),
78
100
  max_clients: Annotated[
79
101
  int,
80
102
  typer.Option(
@@ -82,7 +104,7 @@ def serve(
82
104
  ),
83
105
  ] = 1,
84
106
  allowed_origins: Annotated[
85
- Optional[list[str]],
107
+ list[str] | None,
86
108
  typer.Option(
87
109
  "--allowed-origin",
88
110
  help=(
@@ -103,7 +125,7 @@ def serve(
103
125
  ),
104
126
  ] = False,
105
127
  watch_dir: Annotated[
106
- Optional[list[Path]],
128
+ list[Path] | None,
107
129
  typer.Option(
108
130
  "--watch-dir",
109
131
  help=(
@@ -173,7 +195,7 @@ def serve(
173
195
  logger = logging.getLogger(__name__)
174
196
 
175
197
  # Convert watch directories to set
176
- watch_dirs: Optional[Set[Path]] = None
198
+ watch_dirs: set[Path] | None = None
177
199
  if watch_dir:
178
200
  watch_dirs = set(watch_dir)
179
201
 
@@ -196,10 +218,11 @@ def serve(
196
218
  "max_size": max_size,
197
219
  }
198
220
  if not HAS_WATCHDOG and auto_reload:
199
- typer.echo(
221
+ msg = (
200
222
  "Auto-reload requires the 'watchdog' package. "
201
223
  "Please install it with: pip install watchdog"
202
224
  )
225
+ typer.echo(msg)
203
226
  auto_reload = False
204
227
  logger.info("Starting Waldiez WebSocket server...")
205
228
  logger.info("Configuration:")
@@ -226,8 +249,9 @@ def serve(
226
249
  )
227
250
  except KeyboardInterrupt:
228
251
  logger.info("Server stopped by user")
229
- except Exception as e: # pylint: disable=broad-exception-caught
230
- logger.error("Server error: %s", e)
252
+ except Exception: # pylint: disable=broad-exception-caught
253
+ tb = traceback.format_exc()
254
+ logger.error("Server error: %s", tb)
231
255
  sys.exit(1)
232
256
 
233
257
 
@@ -5,6 +5,7 @@
5
5
  # pyright: reportUnknownMemberType=false,reportAttributeAccessIssue=false
6
6
  # pyright: reportUnknownVariableType=false,reportUnknownArgumentType=false
7
7
  # pyright: reportAssignmentType=false,reportUnknownParameterType=false
8
+ # pyright: reportArgumentType=false
8
9
  # flake8: noqa: C901
9
10
  """WebSocket client manager: bridges WS <-> subprocess runner."""
10
11
 
@@ -71,7 +72,7 @@ class ClientManager:
71
72
 
72
73
  def __init__(
73
74
  self,
74
- websocket: websockets.ServerConnection, # pyright: ignore
75
+ websocket: websockets.ServerConnection,
75
76
  client_id: str,
76
77
  session_manager: SessionManager,
77
78
  workspace_dir: Path = CWD,
@@ -148,7 +149,7 @@ class ClientManager:
148
149
  except (
149
150
  websockets.ConnectionClosed,
150
151
  ConnectionResetError,
151
- ) as e: # pyright: ignore
152
+ ) as e:
152
153
  self.logger.info("Client %s disconnected: %s", self.client_id, e)
153
154
  await self.cleanup()
154
155
  return False
@@ -280,8 +281,8 @@ class ClientManager:
280
281
  server_status = await self.session_manager.get_status()
281
282
  wf_status = None
282
283
  if msg.session_id:
283
- sess = await self.session_manager.get_session(msg.session_id)
284
- wf_status = sess.status if sess else None
284
+ session = await self.session_manager.get_session(msg.session_id)
285
+ wf_status = session.status if session else None
285
286
  return StatusResponse.ok(
286
287
  server_status=server_status,
287
288
  workflow_status=wf_status,
@@ -289,7 +290,7 @@ class ClientManager:
289
290
  ).model_dump(mode="json")
290
291
 
291
292
  if isinstance(msg, SaveFlowRequest):
292
- return FileRequestHandler.handle_save_flow_request(
293
+ return FileRequestHandler.handle_save_request(
293
294
  msg=msg,
294
295
  workspace_dir=self.workspace_dir,
295
296
  client_id=self.client_id,
@@ -297,7 +298,7 @@ class ClientManager:
297
298
  )
298
299
 
299
300
  if isinstance(msg, ConvertWorkflowRequest):
300
- return FileRequestHandler.handle_convert_workflow_request(
301
+ return FileRequestHandler.handle_convert_request(
301
302
  msg=msg,
302
303
  client_id=self.client_id,
303
304
  workspace_dir=self.workspace_dir,
@@ -306,11 +307,11 @@ class ClientManager:
306
307
 
307
308
  # Start workflow (STANDARD)
308
309
  if isinstance(msg, RunWorkflowRequest):
309
- return await self._handle_run_workflow(msg)
310
+ return await self._handle_run(msg)
310
311
 
311
312
  # Start workflow (STEP-BY-STEP / DEBUG)
312
313
  if isinstance(msg, StepRunWorkflowRequest):
313
- return await self._handle_step_run_workflow(msg)
314
+ return await self._handle_step_run(msg)
314
315
 
315
316
  # Step controls
316
317
  if isinstance(msg, StepControlRequest):
@@ -325,24 +326,21 @@ class ClientManager:
325
326
  return await self._handle_user_input(msg)
326
327
 
327
328
  # Stop workflow
328
- if hasattr(msg, "type") and msg.type == "stop_workflow":
329
- return await self._handle_stop_workflow(msg)
329
+ if hasattr(msg, "type") and msg.type == "stop":
330
+ return await self.handle_stop(msg)
330
331
 
331
332
  # Unknown
332
333
  return self._error_to_response(
333
334
  UnsupportedActionError(getattr(msg, "type", "unknown"))
334
335
  )
335
336
 
336
- async def _handle_run_workflow(
337
- self, msg: RunWorkflowRequest
338
- ) -> dict[str, Any]:
337
+ async def _handle_run(self, msg: RunWorkflowRequest) -> dict[str, Any]:
339
338
  try:
340
- data_dict = json.loads(msg.flow_data)
339
+ data_dict = json.loads(msg.data)
341
340
  waldiez = Waldiez.from_dict(data_dict)
342
341
  except Exception as e:
343
342
  return RunWorkflowResponse.fail(
344
343
  error=f"Invalid flow_data: {e}",
345
- execution_mode=msg.execution_mode,
346
344
  session_id="",
347
345
  ).model_dump(mode="json")
348
346
  # structured path preferred
@@ -361,20 +359,19 @@ class ClientManager:
361
359
  asyncio.create_task(self._run_runner(session_id, runner))
362
360
 
363
361
  return RunWorkflowResponse.ok(
364
- session_id=session_id, execution_mode=ExecutionMode.STANDARD
362
+ session_id=session_id, mode=ExecutionMode.STANDARD
365
363
  ).model_dump(mode="json")
366
364
 
367
- async def _handle_step_run_workflow(
365
+ async def _handle_step_run(
368
366
  self, msg: StepRunWorkflowRequest
369
367
  ) -> dict[str, Any]:
370
368
  try:
371
- data_dict = json.loads(msg.flow_data)
369
+ data_dict = json.loads(msg.data)
372
370
  waldiez = Waldiez.from_dict(data_dict)
373
371
  except Exception as e:
374
372
  return StepRunWorkflowResponse.fail(
375
373
  error=f"Invalid flow_data: {e}",
376
374
  session_id="",
377
- auto_continue=msg.auto_continue,
378
375
  breakpoints=msg.breakpoints,
379
376
  ).model_dump(mode="json")
380
377
  session_id = self._next_session_id()
@@ -383,6 +380,7 @@ class ClientManager:
383
380
  on_output=self._mk_on_output(session_id),
384
381
  on_input_request=self._mk_on_input_request(session_id),
385
382
  mode="debug", # step-by-step via CLI
383
+ breakpoints=msg.breakpoints,
386
384
  )
387
385
 
388
386
  await self._create_session_for_runner(
@@ -390,11 +388,10 @@ class ClientManager:
390
388
  ExecutionMode.STEP_BY_STEP,
391
389
  session_id=session_id,
392
390
  )
393
- sess = await self.session_manager.get_session(session_id)
394
- if sess:
395
- sess.state.metadata.update(
391
+ session = await self.session_manager.get_session(session_id)
392
+ if session:
393
+ session.state.metadata.update(
396
394
  {
397
- "auto_continue": msg.auto_continue,
398
395
  "breakpoints": list(msg.breakpoints),
399
396
  }
400
397
  )
@@ -403,7 +400,6 @@ class ClientManager:
403
400
 
404
401
  return StepRunWorkflowResponse.ok(
405
402
  session_id=session_id,
406
- auto_continue=msg.auto_continue,
407
403
  breakpoints=list(msg.breakpoints),
408
404
  ).model_dump(mode="json")
409
405
 
@@ -416,7 +412,7 @@ class ClientManager:
416
412
  await self.session_manager.create_session(
417
413
  session_id=session_id,
418
414
  client_id=self.client_id,
419
- execution_mode=mode,
415
+ mode=mode,
420
416
  runner=runner,
421
417
  temp_file=None,
422
418
  metadata={},
@@ -560,7 +556,19 @@ class ClientManager:
560
556
  runner.provide_user_input(msg.data)
561
557
  return {"type": "ok", "success": True}
562
558
 
563
- async def _handle_stop_workflow(self, msg: Any) -> dict[str, Any]:
559
+ async def handle_stop(self, msg: Any) -> dict[str, Any]:
560
+ """Handle stop request.
561
+
562
+ Parameters
563
+ ----------
564
+ msg : Any
565
+ The stop request.
566
+
567
+ Returns
568
+ -------
569
+ dict[str, Any]
570
+ The processing result to respond with.
571
+ """
564
572
  session_id = getattr(msg, "session_id", "")
565
573
  runner = self._runners.get(session_id)
566
574
  if not runner:
@@ -574,7 +582,7 @@ class ClientManager:
574
582
  session_id, WorkflowStatus.STOPPING
575
583
  )
576
584
  return {
577
- "type": "stop_workflow_response",
585
+ "type": "stop_response",
578
586
  "session_id": session_id,
579
587
  "success": True,
580
588
  "forced": getattr(msg, "force", False),
waldiez/ws/errors.py CHANGED
@@ -1,6 +1,9 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+
3
4
  # pylint: disable=unused-argument
5
+ # pyright: reportUnusedParameter=false
6
+
4
7
  """Error handling and exceptions for Waldiez WebSocket server."""
5
8
 
6
9
  import logging
waldiez/ws/models.py CHANGED
@@ -1,7 +1,8 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- # pylint: disable=broad-exception-caught,no-member
4
- # pyright: reportUnknownVariableType=false
3
+ # pylint: disable=broad-exception-caught,no-member,invalid-name
4
+ # pyright: reportUnknownVariableType=false,reportAny=false
5
+ # pyright: reportDeprecated=false, reportUnannotatedClassAttribute=false
5
6
  """Session management models for WebSocket workflow execution."""
6
7
 
7
8
  import json
@@ -119,35 +120,27 @@ class BaseNotification(BaseWaldiezMessage):
119
120
  class SaveFlowRequest(BaseRequest):
120
121
  """Request to save a workflow."""
121
122
 
122
- type: Literal["save_flow"] = "save_flow"
123
- flow_data: str # JSON string of workflow
124
- filename: str | None = None
125
- force_overwrite: bool = False
123
+ type: Literal["save"] = "save"
124
+ data: str # JSON string of workflow
125
+ path: str | None = None
126
+ force: bool = False
126
127
 
127
128
 
128
129
  class RunWorkflowRequest(BaseRequest):
129
130
  """Request to run a workflow in standard mode."""
130
131
 
131
- type: Literal["run_workflow"] = "run_workflow"
132
- flow_data: str # JSON string of workflow
133
- execution_mode: ExecutionMode = ExecutionMode.STANDARD
134
- structured_io: bool = True
135
- uploads_root: str | None = None
136
- dot_env_path: str | None = None
137
- output_path: str | None = None
132
+ type: Literal["run"] = "run"
133
+ data: str # JSON string of workflow
134
+ path: str | None = None
138
135
 
139
136
 
140
137
  class StepRunWorkflowRequest(BaseRequest):
141
138
  """Request to run a workflow in step-by-step mode."""
142
139
 
143
- type: Literal["step_run_workflow"] = "step_run_workflow"
144
- flow_data: str # JSON string of workflow
145
- auto_continue: bool = False
140
+ type: Literal["step_run"] = "step_run"
141
+ data: str # JSON string of workflow
146
142
  breakpoints: list[str] = Field(default_factory=list)
147
- structured_io: bool = True
148
- uploads_root: str | None = None
149
- dot_env_path: str | None = None
150
- output_path: str | None = None
143
+ path: str | None = None
151
144
 
152
145
 
153
146
  class StepControlRequest(BaseRequest):
@@ -207,7 +200,7 @@ class UserInputResponse(BaseRequest):
207
200
  class StopWorkflowRequest(BaseRequest):
208
201
  """Request to stop workflow execution."""
209
202
 
210
- type: Literal["stop_workflow"] = "stop_workflow"
203
+ type: Literal["stop"] = "stop"
211
204
  session_id: str
212
205
  force: bool = False
213
206
 
@@ -216,7 +209,7 @@ class StopWorkflowResponse(BaseResponse):
216
209
  """Response to stop workflow request."""
217
210
 
218
211
  session_id: str
219
- type: Literal["stop_workflow_response"] = "stop_workflow_response"
212
+ type: Literal["stop_response"] = "stop_response"
220
213
  error: str | None = None
221
214
  forced: bool = False
222
215
 
@@ -224,10 +217,10 @@ class StopWorkflowResponse(BaseResponse):
224
217
  class ConvertWorkflowRequest(BaseRequest):
225
218
  """Request to convert workflow to different format."""
226
219
 
227
- type: Literal["convert_workflow"] = "convert_workflow"
228
- flow_data: str
229
- target_format: Literal["py", "ipynb"]
230
- output_path: str | None = None
220
+ type: Literal["convert"] = "convert"
221
+ data: str
222
+ format: Literal["py", "ipynb"]
223
+ path: str | None = None
231
224
 
232
225
 
233
226
  class UploadFileRequest(BaseRequest):
@@ -262,26 +255,24 @@ class GetStatusRequest(BaseRequest):
262
255
  class SaveFlowResponse(BaseResponse):
263
256
  """Response to save flow request."""
264
257
 
265
- type: Literal["save_flow_response"] = "save_flow_response"
266
- file_path: str | None = None
258
+ type: Literal["save_response"] = "save_response"
259
+ path: str | None = None
267
260
  error: str | None = None
268
261
 
269
262
 
270
263
  class RunWorkflowResponse(BaseResponse):
271
264
  """Response to run workflow request."""
272
265
 
273
- type: Literal["run_workflow_response"] = "run_workflow_response"
266
+ type: Literal["run_response"] = "run_response"
274
267
  session_id: str
275
- execution_mode: ExecutionMode
276
268
  error: str | None = None
277
269
 
278
270
 
279
271
  class StepRunWorkflowResponse(BaseResponse):
280
272
  """Response to step run workflow request."""
281
273
 
282
- type: Literal["step_run_workflow_response"] = "step_run_workflow_response"
274
+ type: Literal["step_run_response"] = "step_run_response"
283
275
  session_id: str
284
- auto_continue: bool
285
276
  breakpoints: list[str]
286
277
  error: str | None = None
287
278
 
@@ -308,9 +299,9 @@ class BreakpointResponse(BaseResponse):
308
299
  class ConvertWorkflowResponse(BaseResponse):
309
300
  """Response to convert workflow request."""
310
301
 
311
- type: Literal["convert_workflow_response"] = "convert_workflow_response"
312
- target_format: str
313
- output_path: str | None = None
302
+ type: Literal["convert_response"] = "convert_response"
303
+ format: str
304
+ path: str | None = None
314
305
  error: str | None = None
315
306
 
316
307
 
@@ -318,8 +309,8 @@ class UploadFileResponse(BaseResponse):
318
309
  """Response to file upload."""
319
310
 
320
311
  type: Literal["upload_file_response"] = "upload_file_response"
321
- file_path: str | None = None
322
- file_size: int | None = None
312
+ path: str | None = None
313
+ size: int | None = None
323
314
  error: str | None = None
324
315
 
325
316
 
@@ -361,7 +352,7 @@ class WorkflowStatusNotification(BaseNotification):
361
352
  type: Literal["workflow_status"] = "workflow_status"
362
353
  session_id: str
363
354
  status: WorkflowStatus
364
- execution_mode: ExecutionMode
355
+ mode: ExecutionMode
365
356
  details: str | None = None
366
357
 
367
358
  @classmethod
@@ -393,7 +384,7 @@ class WorkflowStatusNotification(BaseNotification):
393
384
  return cls(
394
385
  session_id=session_id,
395
386
  status=status,
396
- execution_mode=mode,
387
+ mode=mode,
397
388
  details=details,
398
389
  )
399
390
 
@@ -738,14 +729,14 @@ def create_session_id() -> str:
738
729
  # ========================================
739
730
 
740
731
  CLIENT_MESSAGE_TYPES = {
741
- "save_flow",
742
- "run_workflow",
743
- "step_run_workflow",
732
+ "save",
733
+ "run",
734
+ "step_run",
744
735
  "step_control",
745
736
  "breakpoint_control",
746
737
  "user_input",
747
- "stop_workflow",
748
- "convert_workflow",
738
+ "stop",
739
+ "convert",
749
740
  "upload_file",
750
741
  "ping",
751
742
  "get_status",
@@ -753,12 +744,12 @@ CLIENT_MESSAGE_TYPES = {
753
744
 
754
745
  SERVER_MESSAGE_TYPES = {
755
746
  # Responses
756
- "save_flow_response",
757
- "run_workflow_response",
758
- "step_run_workflow_response",
747
+ "save_response",
748
+ "run_response",
749
+ "step_run_response",
759
750
  "step_control_response",
760
751
  "breakpoint_response",
761
- "convert_workflow_response",
752
+ "convert_response",
762
753
  "upload_file_response",
763
754
  "pong",
764
755
  "status_response",
@@ -786,7 +777,7 @@ class SessionState(BaseModel):
786
777
  session_id: str
787
778
  client_id: str
788
779
  status: WorkflowStatus
789
- execution_mode: ExecutionMode
780
+ mode: ExecutionMode
790
781
  start_time: int = Field(default_factory=time.monotonic_ns)
791
782
  end_time: int | None = None
792
783
  metadata: dict[str, Any] = Field(default_factory=dict)
@@ -845,7 +836,7 @@ class SessionState(BaseModel):
845
836
  "session_id": self.session_id,
846
837
  "client_id": self.client_id,
847
838
  "status": self.status.value,
848
- "execution_mode": self.execution_mode.value,
839
+ "mode": self.mode.value,
849
840
  "duration_seconds": self.duration,
850
841
  "start_time": self.start_time,
851
842
  "end_time": self.end_time,
@@ -915,9 +906,9 @@ class WorkflowSession:
915
906
  return self._state.status
916
907
 
917
908
  @property
918
- def execution_mode(self) -> ExecutionMode:
909
+ def mode(self) -> ExecutionMode:
919
910
  """Get execution mode."""
920
- return self._state.execution_mode
911
+ return self._state.mode
921
912
 
922
913
  @property
923
914
  def temp_file(self) -> Path | None:
waldiez/ws/reloader.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- # pylint: disable=line-too-long
3
+ # pylint: disable=line-too-long,invalid-name
4
4
  # pyright: reportUnknownVariableType=false,reportConstantRedefinition=false
5
5
  # pyright: reportUntypedBaseClass=false,reportUnknownMemberType=false
6
6
  # pyright: reportUnknownParameterType=false,reportUnknownArgumentType=false
@@ -14,7 +14,9 @@ import threading
14
14
  import time
15
15
  from pathlib import Path
16
16
  from types import TracebackType
17
- from typing import Any, Callable
17
+ from typing import Any, Callable, final
18
+
19
+ from typing_extensions import override
18
20
 
19
21
  HAS_WATCHDOG = False
20
22
  try:
@@ -28,16 +30,18 @@ try:
28
30
 
29
31
  HAS_WATCHDOG = True
30
32
  except ImportError as exc:
31
- raise ImportError(
33
+ _msg = ( # pylint: disable=invalid-name
32
34
  "The 'watchdog' package is required for auto-reload functionality. "
33
35
  "Please install it using 'pip install watchdog'."
34
- ) from exc
36
+ )
37
+ raise ImportError(_msg) from exc
35
38
 
36
39
  logger = logging.getLogger(__name__)
37
40
  fsevents_logger = logging.getLogger("fsevents")
38
41
  fsevents_logger.setLevel(logging.WARNING) # Reduce noise from fsevents
39
42
 
40
43
 
44
+ @final
41
45
  class ReloadHandler(FileSystemEventHandler):
42
46
  """Handler for file system events that triggers server reload."""
43
47
 
@@ -134,6 +138,7 @@ class ReloadHandler(FileSystemEventHandler):
134
138
  else str(event.src_path)
135
139
  )
136
140
 
141
+ @override
137
142
  def on_modified(self, event: FileSystemEvent) -> None:
138
143
  """Handle file modification events.
139
144
 
@@ -150,6 +155,7 @@ class ReloadHandler(FileSystemEventHandler):
150
155
  logger.info("File changed: %s", src_path)
151
156
  self._schedule_restart()
152
157
 
158
+ @override
153
159
  def on_created(self, event: FileSystemEvent) -> None:
154
160
  """Handle file creation events.
155
161
 
@@ -163,6 +169,7 @@ class ReloadHandler(FileSystemEventHandler):
163
169
  logger.info("File created: %s", src_path)
164
170
  self._schedule_restart()
165
171
 
172
+ @override
166
173
  def on_deleted(self, event: FileSystemEvent) -> None:
167
174
  """Handle file deletion events.
168
175
 
@@ -235,6 +242,7 @@ class ReloadHandler(FileSystemEventHandler):
235
242
  os._exit(1) # nosec
236
243
 
237
244
 
245
+ @final
238
246
  class FileWatcher:
239
247
  """File watcher with auto-reload functionality."""
240
248