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/server.py CHANGED
@@ -1,10 +1,13 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+
3
4
  # pyright: reportMissingImports=false,reportUnknownVariableType=false
4
5
  # pyright: reportPossiblyUnboundVariable=false,reportUnknownMemberType=false
5
6
  # pyright: reportUnknownParameterType=false,reportUnknownArgumentType=false
6
- # pyright: reportAttributeAccessIssue=false
7
- # pylint: disable=import-error,line-too-long
7
+ # pyright: reportAttributeAccessIssue=false,reportAny=false
8
+ # pyright: reportConstantRedefinition=false,reportAssignmentType=false
9
+ # pyright: reportImportCycles=false,reportGeneralTypeIssues=false
10
+ # pylint: disable=import-error,line-too-long,invalid-name
8
11
  # flake8: noqa: E501
9
12
  """WebSocket server implementation for Waldiez."""
10
13
 
@@ -15,8 +18,9 @@ import signal
15
18
  import time
16
19
  import traceback
17
20
  import uuid
21
+ from collections.abc import Sequence
18
22
  from pathlib import Path
19
- from typing import Any, Sequence
23
+ from typing import Any, final
20
24
 
21
25
  from .client_manager import ClientManager
22
26
  from .errors import ErrorHandler, MessageParsingError, ServerOverloadError
@@ -26,14 +30,24 @@ from .utils import get_available_port, is_port_available
26
30
 
27
31
  HAS_WATCHDOG = False
28
32
  try:
29
- from .reloader import create_file_watcher
33
+ from .reloader import FileWatcher, create_file_watcher
30
34
 
31
- HAS_WATCHDOG = True # pyright: ignore
35
+ HAS_WATCHDOG = True
32
36
  except ImportError:
33
- # pylint: disable=unused-argument,missing-param-doc,missing-return-doc
34
- # noinspection PyUnusedLocal
35
- def create_file_watcher(*args: Any, **kwargs: Any) -> Any: # type: ignore
37
+
38
+ class FileWatcher: # type: ignore[no-redef]
39
+ """Mock fileWatcher for typing."""
40
+
41
+ def start(self) -> None:
42
+ """Start the watcher."""
43
+
44
+ def stop(self) -> None:
45
+ """Stop the watcher."""
46
+
47
+ # pylint: disable=missing-param-doc,missing-return-doc
48
+ def create_file_watcher(*args: Any, **kwargs: Any) -> FileWatcher: # type: ignore
36
49
  """No file watcher available."""
50
+ return FileWatcher(*args, **kwargs)
37
51
 
38
52
 
39
53
  HAS_WEBSOCKETS = False
@@ -44,7 +58,7 @@ try:
44
58
  WebSocketException,
45
59
  )
46
60
 
47
- HAS_WEBSOCKETS = True # pyright: ignore
61
+ HAS_WEBSOCKETS = True
48
62
  except ImportError:
49
63
  from ._mock import ( # type: ignore[no-redef, unused-ignore, unused-import, import-not-found, import-untyped]
50
64
  websockets,
@@ -60,6 +74,7 @@ CWD = Path.cwd()
60
74
 
61
75
 
62
76
  # pylint: disable=too-many-instance-attributes
77
+ @final
63
78
  class WaldiezWsServer:
64
79
  """WebSocket server for Waldiez."""
65
80
 
@@ -185,11 +200,13 @@ class WaldiezWsServer:
185
200
 
186
201
  # Message handling loop
187
202
  # noinspection PyTypeChecker
188
- async for raw_message in websocket: # pyright: ignore
203
+ async for raw_message in websocket:
189
204
  try:
190
205
  # Parse message
191
206
  if isinstance(raw_message, bytes):
192
- message_str = raw_message.decode("utf-8")
207
+ message_str = raw_message.decode(
208
+ "utf-8", errors="replace"
209
+ )
193
210
  else:
194
211
  # noinspection PyUnreachableCode
195
212
  message_str = (
@@ -411,6 +428,52 @@ class WaldiezWsServer:
411
428
  return successful
412
429
 
413
430
 
431
+ def _get_file_watcher(
432
+ auto_reload: bool, watch_dirs: set[Path] | None
433
+ ) -> FileWatcher | None:
434
+ file_watcher: FileWatcher | None = None
435
+ if auto_reload and HAS_WATCHDOG:
436
+ # pylint: disable=import-outside-toplevel,too-many-try-statements
437
+ try:
438
+ # Determine watch directories
439
+ if watch_dirs is None:
440
+ project_root = Path(__file__).parents[2]
441
+
442
+ # Watch the actual waldiez package directory
443
+ waldiez_dir = project_root / "waldiez"
444
+ if waldiez_dir.exists():
445
+ watch_dirs = {waldiez_dir}
446
+ logger.info(
447
+ "Auto-reload: watching waldiez package at %s",
448
+ waldiez_dir,
449
+ )
450
+ else:
451
+ # Fallback: watch current directory
452
+ watch_dirs = {Path.cwd()}
453
+ logger.warning(
454
+ "Auto-reload: fallback to current directory %s",
455
+ Path.cwd(),
456
+ )
457
+
458
+ # Create file watcher with restart callback
459
+ file_watcher = create_file_watcher(
460
+ root_dir=Path(__file__).parents[2],
461
+ additional_dirs=list(watch_dirs),
462
+ restart_callback=None,
463
+ )
464
+ file_watcher.start()
465
+ logger.info(
466
+ "Auto-reload enabled for directories: %s",
467
+ {str(dir_) for dir_ in watch_dirs},
468
+ )
469
+
470
+ except ImportError as e:
471
+ logger.warning("Auto-reload not available: %s", e)
472
+ except Exception as e: # pylint: disable=broad-exception-caught
473
+ logger.error("Failed to set up auto-reload: %s", e)
474
+ return file_watcher
475
+
476
+
414
477
  async def run_server(
415
478
  host: str = "localhost",
416
479
  port: int = 8765,
@@ -453,52 +516,19 @@ async def run_server(
453
516
 
454
517
  # Register signal handlers
455
518
  loop = asyncio.get_running_loop()
456
- for sig in (signal.SIGTERM, signal.SIGINT):
457
- # noinspection PyTypeChecker
458
- loop.add_signal_handler(sig, signal_handler)
519
+ try:
520
+ for sig in (signal.SIGTERM, signal.SIGINT):
521
+ # noinspection PyTypeChecker
522
+ loop.add_signal_handler(sig, signal_handler)
523
+ except NotImplementedError:
524
+ # Fallback for Windows
525
+ signal.signal(signal.SIGINT, lambda s, f: signal_handler())
526
+ signal.signal(signal.SIGTERM, lambda s, f: signal_handler())
459
527
 
460
528
  # Set up auto-reload if requested
461
- file_watcher = None
462
- if auto_reload and HAS_WATCHDOG:
463
- # pylint: disable=import-outside-toplevel,too-many-try-statements
464
- try:
465
- # Determine watch directories
466
- if watch_dirs is None:
467
- project_root = Path(__file__).parents[2]
468
-
469
- # Watch the actual waldiez package directory
470
- waldiez_dir = project_root / "waldiez"
471
- if waldiez_dir.exists():
472
- watch_dirs = {waldiez_dir}
473
- logger.info(
474
- "Auto-reload: watching waldiez package at %s",
475
- waldiez_dir,
476
- )
477
- else:
478
- # Fallback: watch current directory
479
- watch_dirs = {Path.cwd()}
480
- logger.warning(
481
- "Auto-reload: fallback to current directory %s",
482
- Path.cwd(),
483
- )
484
-
485
- # Create file watcher with restart callback
486
- file_watcher = create_file_watcher(
487
- root_dir=Path(__file__).parents[2],
488
- additional_dirs=list(watch_dirs),
489
- restart_callback=None,
490
- )
491
- file_watcher.start()
492
- logger.info(
493
- "Auto-reload enabled for directories: %s",
494
- {str(dir_) for dir_ in watch_dirs},
495
- )
496
-
497
- except ImportError as e:
498
- logger.warning("Auto-reload not available: %s", e)
499
- except Exception as e: # pylint: disable=broad-exception-caught
500
- logger.error("Failed to set up auto-reload: %s", e)
501
-
529
+ file_watcher = _get_file_watcher(
530
+ auto_reload=auto_reload, watch_dirs=watch_dirs
531
+ )
502
532
  try:
503
533
  # Start server
504
534
  await server.start()
@@ -7,13 +7,14 @@ import logging
7
7
  import time
8
8
  from collections import defaultdict
9
9
  from pathlib import Path
10
- from typing import Any
10
+ from typing import Any, final
11
11
 
12
12
  from .models import ExecutionMode, SessionState, WorkflowSession, WorkflowStatus
13
13
  from .session_stats import SessionStats
14
14
 
15
15
 
16
16
  # noinspection TryExceptPass,PyBroadException
17
+ @final
17
18
  class SessionManager:
18
19
  """Manage workflow sessions across WebSocket clients."""
19
20
 
@@ -67,7 +68,7 @@ class SessionManager:
67
68
  self,
68
69
  session_id: str,
69
70
  client_id: str,
70
- execution_mode: ExecutionMode,
71
+ mode: ExecutionMode,
71
72
  runner: Any = None,
72
73
  temp_file: Path | None = None,
73
74
  metadata: dict[str, Any] | None = None,
@@ -80,7 +81,7 @@ class SessionManager:
80
81
  The ID of the session to create
81
82
  client_id : str
82
83
  The ID of the client creating the session
83
- execution_mode : ExecutionMode
84
+ mode : ExecutionMode
84
85
  The execution mode for the session
85
86
  runner : Any, optional
86
87
  The runner to use for the session
@@ -103,7 +104,7 @@ class SessionManager:
103
104
  session_id=session_id,
104
105
  client_id=client_id,
105
106
  status=WorkflowStatus.IDLE,
106
- execution_mode=execution_mode,
107
+ mode=mode,
107
108
  metadata=metadata or {},
108
109
  )
109
110
  session = WorkflowSession(
@@ -180,9 +181,7 @@ class SessionManager:
180
181
  self._recompute_stats_locked()
181
182
  return True
182
183
 
183
- async def get_session_execution_mode(
184
- self, session_id: str
185
- ) -> ExecutionMode | None:
184
+ async def get_session_mode(self, session_id: str) -> ExecutionMode | None:
186
185
  """Get the execution mode of a workflow session.
187
186
 
188
187
  Parameters
@@ -196,8 +195,8 @@ class SessionManager:
196
195
  The execution mode of the session, or None if it does not exist
197
196
  """
198
197
  async with self._lock:
199
- s = self._sessions.get(session_id)
200
- return s.execution_mode if s else None
198
+ session = self._sessions.get(session_id)
199
+ return session.mode if session else None
201
200
 
202
201
  async def remove_session(self, session_id: str) -> bool:
203
202
  """Remove a workflow session by ID.
@@ -65,7 +65,7 @@ class SessionStats(BaseModel):
65
65
 
66
66
  client_count = self.sessions_by_client.get(state.client_id, 0)
67
67
  self.sessions_by_client[state.client_id] = client_count + 1
68
- mode_key = state.execution_mode.value
68
+ mode_key = state.mode.value
69
69
  mode_count = self.sessions_by_mode.get(mode_key, 0)
70
70
  self.sessions_by_mode[mode_key] = mode_count + 1
71
71
  status_key = state.status.value
waldiez/ws/utils.py CHANGED
@@ -3,6 +3,7 @@
3
3
  # pylint: disable=import-error,line-too-long
4
4
  # pyright: reportUnknownMemberType=false,reportUnknownVariableType=false
5
5
  # pyright: reportUnknownArgumentType=false,reportAttributeAccessIssue=false
6
+ # pyright: reportGeneralTypeIssues=false,reportAny=false
6
7
  # flake8: noqa: E501
7
8
  """Utilities for WebSocket server management."""
8
9
 
@@ -13,7 +14,7 @@ import socket
13
14
  import time
14
15
  from contextlib import closing
15
16
  from dataclasses import asdict, dataclass
16
- from typing import TYPE_CHECKING, Any
17
+ from typing import TYPE_CHECKING, Any, final
17
18
 
18
19
  try:
19
20
  import websockets # type: ignore[unused-ignore, unused-import, import-not-found, import-untyped] # noqa
@@ -82,6 +83,7 @@ class ServerHealth:
82
83
  return my_dict
83
84
 
84
85
 
86
+ @final
85
87
  class HealthChecker:
86
88
  """Health checker for WebSocket server."""
87
89
 
@@ -192,6 +194,7 @@ class HealthChecker:
192
194
 
193
195
 
194
196
  # noinspection PyBroadException
197
+ @final
195
198
  class ConnectionManager:
196
199
  """Manages WebSocket connections and provides utilities."""
197
200
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: waldiez
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Dynamic: Keywords
5
5
  Summary: Make AG2 Agents Collaborate: Drag, Drop, and Orchestrate with Waldiez.
6
6
  Project-URL: Homepage, https://waldiez.io
@@ -27,115 +27,103 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
27
27
  Classifier: Topic :: Software Development :: Code Generators
28
28
  Classifier: Typing :: Typed
29
29
  Requires-Python: <3.14,>=3.10
30
- Requires-Dist: ag2[openai]==0.9.9
31
- Requires-Dist: aiocsv==1.3.2
32
- Requires-Dist: aiofiles==24.1.0
30
+ Requires-Dist: ag2[openai]==0.9.10
31
+ Requires-Dist: aiocsv==1.4.0
32
+ Requires-Dist: aiofiles==25.1.0
33
33
  Requires-Dist: aiosqlite==0.21.0
34
34
  Requires-Dist: click<8.2
35
35
  Requires-Dist: graphviz<=0.21
36
36
  Requires-Dist: httpx<1
37
37
  Requires-Dist: jupytext
38
38
  Requires-Dist: nest-asyncio==1.6.0
39
- Requires-Dist: numpy<=2.3.3
39
+ Requires-Dist: numpy
40
40
  Requires-Dist: pandas>=2
41
41
  Requires-Dist: parso==0.8.5
42
42
  Requires-Dist: pillow
43
- Requires-Dist: pip>=25.1.1
44
- Requires-Dist: platformdirs==4.4.0
45
- Requires-Dist: psutil==7.0.0
43
+ Requires-Dist: pip>=25.1
44
+ Requires-Dist: platformdirs==4.5.0
45
+ Requires-Dist: psutil==7.1.0
46
46
  Requires-Dist: pydantic<3,>=2.10.2
47
47
  Requires-Dist: rpds-py==0.27.1
48
48
  Requires-Dist: typer<1,>=0.9.0
49
49
  Provides-Extra: ag2-extras
50
- Requires-Dist: ag2[anthropic]==0.9.9; extra == 'ag2-extras'
51
- Requires-Dist: ag2[autobuild]==0.9.9; extra == 'ag2-extras'
52
- Requires-Dist: ag2[bedrock]==0.9.9; extra == 'ag2-extras'
53
- Requires-Dist: ag2[blendsearch]==0.9.9; extra == 'ag2-extras'
54
- Requires-Dist: ag2[cohere]==0.9.9; extra == 'ag2-extras'
55
- Requires-Dist: ag2[commsagent-discord]==0.9.9; extra == 'ag2-extras'
56
- Requires-Dist: ag2[commsagent-slack]==0.9.9; extra == 'ag2-extras'
57
- Requires-Dist: ag2[commsagent-telegram]==0.9.9; extra == 'ag2-extras'
58
- Requires-Dist: ag2[crawl4ai]==0.9.9; extra == 'ag2-extras'
59
- Requires-Dist: ag2[duckduckgo]==0.9.9; extra == 'ag2-extras'
60
- Requires-Dist: ag2[google-api]==0.9.9; extra == 'ag2-extras'
61
- Requires-Dist: ag2[google-client]==0.9.9; extra == 'ag2-extras'
62
- Requires-Dist: ag2[google-search]==0.9.9; extra == 'ag2-extras'
63
- Requires-Dist: ag2[groq]==0.9.9; extra == 'ag2-extras'
64
- Requires-Dist: ag2[interop-crewai]==0.9.9; extra == 'ag2-extras'
65
- Requires-Dist: ag2[interop-langchain]==0.9.9; extra == 'ag2-extras'
66
- Requires-Dist: ag2[lmm]==0.9.9; extra == 'ag2-extras'
67
- Requires-Dist: ag2[mcp]==0.9.9; extra == 'ag2-extras'
68
- Requires-Dist: ag2[mistral]==0.9.9; extra == 'ag2-extras'
69
- Requires-Dist: ag2[neo4j]==0.9.9; (sys_platform != 'win32') and extra == 'ag2-extras'
70
- Requires-Dist: ag2[neo4j]==0.9.9; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
71
- Requires-Dist: ag2[ollama]==0.9.9; extra == 'ag2-extras'
72
- Requires-Dist: ag2[openai-realtime]==0.9.9; extra == 'ag2-extras'
73
- Requires-Dist: ag2[redis]==0.9.9; extra == 'ag2-extras'
74
- Requires-Dist: ag2[tavily]==0.9.9; extra == 'ag2-extras'
75
- Requires-Dist: ag2[together]==0.9.9; (sys_platform != 'win32') and extra == 'ag2-extras'
76
- Requires-Dist: ag2[together]==0.9.9; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
77
- Requires-Dist: ag2[twilio]==0.9.9; extra == 'ag2-extras'
78
- Requires-Dist: ag2[websockets]==0.9.9; extra == 'ag2-extras'
79
- Requires-Dist: ag2[websurfer]==0.9.9; extra == 'ag2-extras'
80
- Requires-Dist: ag2[wikipedia]==0.9.9; extra == 'ag2-extras'
81
- Requires-Dist: chromadb<2,>=0.5; extra == 'ag2-extras'
82
- Requires-Dist: chromadb>=0.5.10; (sys_platform != 'win32') and extra == 'ag2-extras'
83
- Requires-Dist: chromadb>=0.5.10; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
84
- Requires-Dist: couchbase>=4.4.0; extra == 'ag2-extras'
85
- Requires-Dist: docling<3,>=2.15.1; extra == 'ag2-extras'
86
- Requires-Dist: fastembed>=0.3.1; extra == 'ag2-extras'
87
- Requires-Dist: llama-index-embeddings-huggingface; extra == 'ag2-extras'
88
- Requires-Dist: llama-index-llms-langchain; extra == 'ag2-extras'
89
- Requires-Dist: llama-index-vector-stores-chroma; extra == 'ag2-extras'
90
- Requires-Dist: llama-index-vector-stores-mongodb; extra == 'ag2-extras'
91
- Requires-Dist: llama-index<1,>=0.12; extra == 'ag2-extras'
92
- Requires-Dist: pgvector>=0.4.0; extra == 'ag2-extras'
93
- Requires-Dist: psycopg>=3.2.9; (sys_platform == 'linux') and extra == 'ag2-extras'
94
- Requires-Dist: psycopg>=3.2.9; (sys_platform == 'win32' and platform_machine == 'AARCH64') and extra == 'ag2-extras'
95
- Requires-Dist: psycopg>=3.2.9; (sys_platform == 'win32' and platform_machine == 'ARM64') and extra == 'ag2-extras'
96
- Requires-Dist: psycopg>=3.2.9; (sys_platform == 'win32' and platform_machine == 'aarch64') and extra == 'ag2-extras'
97
- Requires-Dist: psycopg>=3.2.9; (sys_platform == 'win32' and platform_machine == 'arm64') and extra == 'ag2-extras'
98
- Requires-Dist: psycopg[binary]>=3.2.9; (sys_platform == 'darwin') and extra == 'ag2-extras'
99
- Requires-Dist: psycopg[binary]>=3.2.9; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'ARM64' and platform_machine != 'aarch64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
100
- Requires-Dist: pydantic-ai>=0.0.21; extra == 'ag2-extras'
101
- Requires-Dist: pymongo>=4.11; extra == 'ag2-extras'
102
- Requires-Dist: qdrant-client[fastembed]; (sys_platform != 'win32') and extra == 'ag2-extras'
103
- Requires-Dist: qdrant-client[fastembed]; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
104
- Requires-Dist: requests<3,>=2.32.3; extra == 'ag2-extras'
105
- Requires-Dist: selenium<5,>=4.28.1; extra == 'ag2-extras'
106
- Requires-Dist: webdriver-manager==4.0.2; extra == 'ag2-extras'
50
+ Requires-Dist: ag2[anthropic]==0.9.10; extra == 'ag2-extras'
51
+ Requires-Dist: ag2[autobuild]==0.9.10; extra == 'ag2-extras'
52
+ Requires-Dist: ag2[bedrock]==0.9.10; extra == 'ag2-extras'
53
+ Requires-Dist: ag2[blendsearch]==0.9.10; extra == 'ag2-extras'
54
+ Requires-Dist: ag2[cohere]==0.9.10; extra == 'ag2-extras'
55
+ Requires-Dist: ag2[commsagent-discord]==0.9.10; extra == 'ag2-extras'
56
+ Requires-Dist: ag2[commsagent-slack]==0.9.10; extra == 'ag2-extras'
57
+ Requires-Dist: ag2[commsagent-telegram]==0.9.10; extra == 'ag2-extras'
58
+ Requires-Dist: ag2[crawl4ai]==0.9.10; extra == 'ag2-extras'
59
+ Requires-Dist: ag2[duckduckgo]==0.9.10; extra == 'ag2-extras'
60
+ Requires-Dist: ag2[gemini-realtime]==0.9.10; (sys_platform != 'win32') and extra == 'ag2-extras'
61
+ Requires-Dist: ag2[gemini-realtime]==0.9.10; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
62
+ Requires-Dist: ag2[gemini]==0.9.10; (sys_platform != 'win32') and extra == 'ag2-extras'
63
+ Requires-Dist: ag2[gemini]==0.9.10; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
64
+ Requires-Dist: ag2[google-api]==0.9.10; extra == 'ag2-extras'
65
+ Requires-Dist: ag2[google-client]==0.9.10; extra == 'ag2-extras'
66
+ Requires-Dist: ag2[google-search]==0.9.10; extra == 'ag2-extras'
67
+ Requires-Dist: ag2[graph]==0.9.10; extra == 'ag2-extras'
68
+ Requires-Dist: ag2[groq]==0.9.10; extra == 'ag2-extras'
69
+ Requires-Dist: ag2[interop-crewai]==0.9.10; extra == 'ag2-extras'
70
+ Requires-Dist: ag2[interop-langchain]==0.9.10; extra == 'ag2-extras'
71
+ Requires-Dist: ag2[lmm]==0.9.10; extra == 'ag2-extras'
72
+ Requires-Dist: ag2[long-context]==0.9.10; extra == 'ag2-extras'
73
+ Requires-Dist: ag2[mcp]==0.9.10; extra == 'ag2-extras'
74
+ Requires-Dist: ag2[mistral]==0.9.10; extra == 'ag2-extras'
75
+ Requires-Dist: ag2[neo4j]==0.9.10; (sys_platform != 'win32') and extra == 'ag2-extras'
76
+ Requires-Dist: ag2[neo4j]==0.9.10; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
77
+ Requires-Dist: ag2[ollama]==0.9.10; extra == 'ag2-extras'
78
+ Requires-Dist: ag2[openai-realtime]==0.9.10; extra == 'ag2-extras'
79
+ Requires-Dist: ag2[rag]==0.9.10; extra == 'ag2-extras'
80
+ Requires-Dist: ag2[redis]==0.9.10; extra == 'ag2-extras'
81
+ Requires-Dist: ag2[retrievechat-couchbase]==0.9.10; extra == 'ag2-extras'
82
+ Requires-Dist: ag2[retrievechat-mongodb]==0.9.10; extra == 'ag2-extras'
83
+ Requires-Dist: ag2[retrievechat-pgvector]==0.9.10; extra == 'ag2-extras'
84
+ Requires-Dist: ag2[retrievechat-qdrant]==0.9.10; extra == 'ag2-extras'
85
+ Requires-Dist: ag2[retrievechat]==0.9.10; extra == 'ag2-extras'
86
+ Requires-Dist: ag2[tavily]==0.9.10; extra == 'ag2-extras'
87
+ Requires-Dist: ag2[together]==0.9.10; (sys_platform != 'win32') and extra == 'ag2-extras'
88
+ Requires-Dist: ag2[together]==0.9.10; (sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'ag2-extras'
89
+ Requires-Dist: ag2[twilio]==0.9.10; extra == 'ag2-extras'
90
+ Requires-Dist: ag2[websockets]==0.9.10; extra == 'ag2-extras'
91
+ Requires-Dist: ag2[websurfer]==0.9.10; extra == 'ag2-extras'
92
+ Requires-Dist: ag2[wikipedia]==0.9.10; extra == 'ag2-extras'
107
93
  Provides-Extra: dev
108
- Requires-Dist: ag2[redis]==0.9.9; extra == 'dev'
94
+ Requires-Dist: ag2[redis]==0.9.10; extra == 'dev'
109
95
  Requires-Dist: autoflake==2.3.1; extra == 'dev'
110
96
  Requires-Dist: bandit==1.8.6; extra == 'dev'
111
- Requires-Dist: black[jupyter]==25.1.0; extra == 'dev'
97
+ Requires-Dist: basedpyright==1.31.7; extra == 'dev'
98
+ Requires-Dist: black[jupyter]==25.9.0; extra == 'dev'
112
99
  Requires-Dist: build==1.3.0; extra == 'dev'
113
- Requires-Dist: fakeredis==2.31.1; extra == 'dev'
100
+ Requires-Dist: fakeredis==2.32.0; extra == 'dev'
114
101
  Requires-Dist: fastjsonschema>=2.21.2; extra == 'dev'
115
102
  Requires-Dist: flake8==7.3.0; extra == 'dev'
116
103
  Requires-Dist: hatchling==1.27.0; extra == 'dev'
117
104
  Requires-Dist: jsonschema==4.25.1; extra == 'dev'
118
105
  Requires-Dist: jupyter-server==2.17.0; extra == 'dev'
119
- Requires-Dist: jupyterlab==4.4.7; extra == 'dev'
106
+ Requires-Dist: jupyterlab==4.4.9; extra == 'dev'
120
107
  Requires-Dist: mypy-extensions>=1.1.0; extra == 'dev'
121
- Requires-Dist: mypy==1.18.1; extra == 'dev'
108
+ Requires-Dist: mypy==1.18.2; extra == 'dev'
122
109
  Requires-Dist: nbclient>=0.10.2; extra == 'dev'
123
110
  Requires-Dist: nbconvert>=7.16.6; extra == 'dev'
124
111
  Requires-Dist: nbformat>=5.10.4; extra == 'dev'
125
112
  Requires-Dist: nodeenv>=1.9.1; extra == 'dev'
126
113
  Requires-Dist: notebook-shim>=0.2.4; extra == 'dev'
127
114
  Requires-Dist: paho-mqtt<3.0,>=2.1.0; extra == 'dev'
128
- Requires-Dist: pandas-stubs==2.3.2.250827; extra == 'dev'
129
- Requires-Dist: pre-commit==4.3.0; extra == 'dev'
115
+ Requires-Dist: pandas-stubs==2.3.2.250926; extra == 'dev'
116
+ Requires-Dist: prek==0.2.9; extra == 'dev'
130
117
  Requires-Dist: pydocstyle==6.3.0; extra == 'dev'
131
- Requires-Dist: pylint==3.3.8; extra == 'dev'
118
+ Requires-Dist: pylint==4.0.1; extra == 'dev'
132
119
  Requires-Dist: python-dotenv>=1.1.1; extra == 'dev'
133
- Requires-Dist: ruff==0.13.0; extra == 'dev'
120
+ Requires-Dist: ruff==0.14.1; extra == 'dev'
134
121
  Requires-Dist: toml==0.10.2; (python_version <= '3.10') and extra == 'dev'
135
- Requires-Dist: types-aiofiles==24.1.0.20250822; extra == 'dev'
136
- Requires-Dist: types-jsonschema==4.25.1.20250822; extra == 'dev'
137
- Requires-Dist: types-psutil==7.0.0.20250822; extra == 'dev'
138
- Requires-Dist: types-pyyaml==6.0.12.20250822; extra == 'dev'
122
+ Requires-Dist: tox==4.31.0; extra == 'dev'
123
+ Requires-Dist: types-aiofiles==25.1.0.20251011; extra == 'dev'
124
+ Requires-Dist: types-jsonschema==4.25.1.20251009; extra == 'dev'
125
+ Requires-Dist: types-psutil==7.0.0.20251001; extra == 'dev'
126
+ Requires-Dist: types-pyyaml==6.0.12.20250915; extra == 'dev'
139
127
  Requires-Dist: types-redis==4.6.0.20241004; extra == 'dev'
140
128
  Requires-Dist: types-requests==2.32.4.20250913; extra == 'dev'
141
129
  Requires-Dist: types-toml==0.10.8.20240310; extra == 'dev'
@@ -149,49 +137,50 @@ Requires-Dist: mdx-truly-sane-lists==1.3; extra == 'docs'
149
137
  Requires-Dist: mkdocs-autorefs==1.4.3; extra == 'docs'
150
138
  Requires-Dist: mkdocs-awesome-nav==3.2.0; extra == 'docs'
151
139
  Requires-Dist: mkdocs-jupyter==0.25.1; extra == 'docs'
152
- Requires-Dist: mkdocs-macros-plugin==1.3.9; extra == 'docs'
153
- Requires-Dist: mkdocs-material==9.6.19; extra == 'docs'
140
+ Requires-Dist: mkdocs-macros-plugin==1.4.0; extra == 'docs'
141
+ Requires-Dist: mkdocs-material==9.6.22; extra == 'docs'
154
142
  Requires-Dist: mkdocs-minify-html-plugin; (python_version >= '3.13' and sys_platform == 'win32' and platform_machine == 'AARCH64') and extra == 'docs'
155
143
  Requires-Dist: mkdocs-minify-html-plugin; (python_version >= '3.13' and sys_platform == 'win32' and platform_machine == 'ARM64') and extra == 'docs'
156
144
  Requires-Dist: mkdocs-minify-html-plugin; (python_version >= '3.13' and sys_platform == 'win32' and platform_machine == 'aarch64') and extra == 'docs'
157
145
  Requires-Dist: mkdocs-minify-html-plugin; (python_version >= '3.13' and sys_platform == 'win32' and platform_machine == 'arm64') and extra == 'docs'
158
- Requires-Dist: mkdocs-minify-html-plugin==0.3.4; (python_version < '3.13') and extra == 'docs'
159
- Requires-Dist: mkdocs-minify-html-plugin==0.3.4; (python_version >= '3.13' and sys_platform != 'win32') and extra == 'docs'
160
- Requires-Dist: mkdocs-minify-html-plugin==0.3.4; (python_version >= '3.13' and sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'docs'
146
+ Requires-Dist: mkdocs-minify-html-plugin==0.3.5; (python_version < '3.13') and extra == 'docs'
147
+ Requires-Dist: mkdocs-minify-html-plugin==0.3.5; (python_version >= '3.13' and sys_platform != 'win32') and extra == 'docs'
148
+ Requires-Dist: mkdocs-minify-html-plugin==0.3.5; (python_version >= '3.13' and sys_platform == 'win32' and platform_machine != 'arm64' and platform_machine != 'aarch64' and platform_machine != 'ARM64' and platform_machine != 'AARCH64') and extra == 'docs'
161
149
  Requires-Dist: mkdocs-open-in-new-tab==1.0.8; extra == 'docs'
162
150
  Requires-Dist: mkdocs==1.6.1; extra == 'docs'
163
151
  Requires-Dist: mkdocstrings-crystal==0.3.7; extra == 'docs'
164
152
  Requires-Dist: mkdocstrings-python==1.18.2; extra == 'docs'
165
- Requires-Dist: mkdocstrings[crystal,python]==0.30.0; extra == 'docs'
153
+ Requires-Dist: mkdocstrings[crystal,python]==0.30.1; extra == 'docs'
166
154
  Requires-Dist: natsort==8.4.0; extra == 'docs'
167
155
  Provides-Extra: jupyter
168
156
  Requires-Dist: ipywidgets==8.1.7; extra == 'jupyter'
169
157
  Requires-Dist: jupyter-server==2.17.0; extra == 'jupyter'
170
- Requires-Dist: jupyterlab==4.4.7; extra == 'jupyter'
171
- Requires-Dist: waldiez-jupyter==0.6.0; extra == 'jupyter'
158
+ Requires-Dist: jupyterlab==4.4.9; extra == 'jupyter'
159
+ Requires-Dist: waldiez-jupyter==0.6.1; extra == 'jupyter'
172
160
  Provides-Extra: mqtt
173
161
  Requires-Dist: paho-mqtt<3.0,>=2.1.0; extra == 'mqtt'
174
162
  Provides-Extra: redis
175
- Requires-Dist: ag2[redis]==0.9.9; extra == 'redis'
163
+ Requires-Dist: ag2[redis]==0.9.10; extra == 'redis'
176
164
  Provides-Extra: reload
177
165
  Requires-Dist: watchdog>=5.0.0; extra == 'reload'
178
166
  Provides-Extra: runner
179
- Requires-Dist: waldiez-runner==0.6.0; (python_version >= '3.11') and extra == 'runner'
167
+ Requires-Dist: waldiez-runner==0.6.1; (python_version >= '3.11') and extra == 'runner'
180
168
  Provides-Extra: studio
181
- Requires-Dist: waldiez-studio==0.6.0; extra == 'studio'
169
+ Requires-Dist: waldiez-studio==0.6.1; extra == 'studio'
182
170
  Provides-Extra: test
183
- Requires-Dist: ag2[redis]==0.9.9; extra == 'test'
184
- Requires-Dist: ag2[websockets]==0.9.9; extra == 'test'
185
- Requires-Dist: fakeredis==2.31.1; extra == 'test'
171
+ Requires-Dist: ag2[redis]==0.9.10; extra == 'test'
172
+ Requires-Dist: ag2[websockets]==0.9.10; extra == 'test'
173
+ Requires-Dist: fakeredis==2.32.0; extra == 'test'
186
174
  Requires-Dist: paho-mqtt<3.0,>=2.1.0; extra == 'test'
187
175
  Requires-Dist: pytest-asyncio==1.2.0; extra == 'test'
188
176
  Requires-Dist: pytest-cov==7.0.0; extra == 'test'
189
- Requires-Dist: pytest-env==1.1.5; extra == 'test'
177
+ Requires-Dist: pytest-env==1.2.0; extra == 'test'
190
178
  Requires-Dist: pytest-html==4.1.1; extra == 'test'
191
179
  Requires-Dist: pytest-sugar==1.1.1; extra == 'test'
192
180
  Requires-Dist: pytest-timeout==2.4.0; extra == 'test'
193
181
  Requires-Dist: pytest-xdist==3.8.0; extra == 'test'
194
182
  Requires-Dist: pytest==8.4.2; extra == 'test'
183
+ Requires-Dist: tox==4.31.0; extra == 'test'
195
184
  Requires-Dist: watchdog>=5.0.0; extra == 'test'
196
185
  Requires-Dist: websockets<16,>=14.0; extra == 'test'
197
186
  Provides-Extra: websockets