waldiez 0.5.8__py3-none-any.whl → 0.5.10__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 (88) hide show
  1. waldiez/_version.py +1 -1
  2. waldiez/cli.py +112 -24
  3. waldiez/exporting/agent/exporter.py +3 -0
  4. waldiez/exporting/agent/extras/captain_agent_extras.py +44 -7
  5. waldiez/exporting/agent/extras/handoffs/condition.py +3 -1
  6. waldiez/exporting/chats/utils/common.py +25 -23
  7. waldiez/exporting/core/__init__.py +0 -2
  8. waldiez/exporting/core/context.py +13 -13
  9. waldiez/exporting/core/protocols.py +0 -141
  10. waldiez/exporting/core/result.py +5 -5
  11. waldiez/exporting/flow/merger.py +2 -2
  12. waldiez/exporting/flow/orchestrator.py +1 -0
  13. waldiez/exporting/flow/utils/common.py +2 -2
  14. waldiez/exporting/flow/utils/importing.py +1 -0
  15. waldiez/exporting/flow/utils/logging.py +6 -7
  16. waldiez/exporting/tools/exporter.py +5 -0
  17. waldiez/exporting/tools/factory.py +4 -0
  18. waldiez/exporting/tools/processor.py +5 -1
  19. waldiez/io/_ws.py +13 -5
  20. waldiez/io/models/content/image.py +1 -0
  21. waldiez/io/models/user_input.py +4 -4
  22. waldiez/io/models/user_response.py +1 -0
  23. waldiez/io/mqtt.py +1 -1
  24. waldiez/io/structured.py +17 -17
  25. waldiez/io/utils.py +1 -1
  26. waldiez/io/ws.py +9 -11
  27. waldiez/logger.py +180 -63
  28. waldiez/models/agents/agent/update_system_message.py +0 -2
  29. waldiez/models/agents/doc_agent/doc_agent.py +8 -1
  30. waldiez/models/common/dict_utils.py +169 -40
  31. waldiez/models/flow/flow.py +6 -6
  32. waldiez/models/flow/info.py +5 -1
  33. waldiez/models/model/_llm.py +28 -14
  34. waldiez/models/model/model.py +4 -1
  35. waldiez/models/model/model_data.py +18 -5
  36. waldiez/models/tool/predefined/_config.py +5 -1
  37. waldiez/models/tool/predefined/_duckduckgo.py +4 -0
  38. waldiez/models/tool/predefined/_email.py +474 -0
  39. waldiez/models/tool/predefined/_google.py +8 -6
  40. waldiez/models/tool/predefined/_perplexity.py +3 -0
  41. waldiez/models/tool/predefined/_searxng.py +3 -0
  42. waldiez/models/tool/predefined/_tavily.py +4 -1
  43. waldiez/models/tool/predefined/_wikipedia.py +4 -1
  44. waldiez/models/tool/predefined/_youtube.py +4 -1
  45. waldiez/models/tool/predefined/protocol.py +3 -0
  46. waldiez/models/tool/tool.py +22 -4
  47. waldiez/models/waldiez.py +12 -0
  48. waldiez/runner.py +37 -54
  49. waldiez/running/__init__.py +6 -0
  50. waldiez/running/base_runner.py +310 -353
  51. waldiez/running/environment.py +1 -0
  52. waldiez/running/exceptions.py +9 -0
  53. waldiez/running/post_run.py +4 -4
  54. waldiez/running/pre_run.py +51 -40
  55. waldiez/running/protocol.py +21 -101
  56. waldiez/running/run_results.py +1 -1
  57. waldiez/running/standard_runner.py +84 -277
  58. waldiez/running/step_by_step/__init__.py +46 -0
  59. waldiez/running/step_by_step/breakpoints_mixin.py +188 -0
  60. waldiez/running/step_by_step/step_by_step_models.py +224 -0
  61. waldiez/running/step_by_step/step_by_step_runner.py +745 -0
  62. waldiez/running/subprocess_runner/__base__.py +282 -0
  63. waldiez/running/subprocess_runner/__init__.py +16 -0
  64. waldiez/running/subprocess_runner/_async_runner.py +362 -0
  65. waldiez/running/subprocess_runner/_sync_runner.py +455 -0
  66. waldiez/running/subprocess_runner/runner.py +561 -0
  67. waldiez/running/timeline_processor.py +1 -1
  68. waldiez/running/utils.py +376 -1
  69. waldiez/utils/version.py +2 -6
  70. waldiez/ws/__init__.py +70 -0
  71. waldiez/ws/__main__.py +15 -0
  72. waldiez/ws/_file_handler.py +201 -0
  73. waldiez/ws/cli.py +211 -0
  74. waldiez/ws/client_manager.py +835 -0
  75. waldiez/ws/errors.py +416 -0
  76. waldiez/ws/models.py +971 -0
  77. waldiez/ws/reloader.py +342 -0
  78. waldiez/ws/server.py +469 -0
  79. waldiez/ws/session_manager.py +393 -0
  80. waldiez/ws/session_stats.py +83 -0
  81. waldiez/ws/utils.py +385 -0
  82. {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/METADATA +74 -74
  83. {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/RECORD +87 -65
  84. waldiez/running/patch_io_stream.py +0 -210
  85. {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/WHEEL +0 -0
  86. {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/entry_points.txt +0 -0
  87. {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/licenses/LICENSE +0 -0
  88. {waldiez-0.5.8.dist-info → waldiez-0.5.10.dist-info}/licenses/NOTICE.md +0 -0
@@ -63,6 +63,7 @@ def refresh_environment() -> None:
63
63
 
64
64
 
65
65
  # pylint: disable=too-complex,too-many-try-statements,unused-import
66
+ # noinspection TryExceptPass
66
67
  def reload_autogen() -> None: # noqa: C901 # pragma: no cover
67
68
  """Reload the autogen package.
68
69
 
@@ -0,0 +1,9 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Custom exceptions for Waldiez runners."""
4
+
5
+
6
+ class StopRunningException(Exception):
7
+ """Exception to stop the running process."""
8
+
9
+ reason: str = "Execution stopped by user"
@@ -11,8 +11,8 @@ from pathlib import Path
11
11
  from typing import Optional, Union
12
12
 
13
13
  from .gen_seq_diagram import generate_sequence_diagram
14
- from .patch_io_stream import get_printer
15
14
  from .timeline_processor import TimelineProcessor
15
+ from .utils import get_printer
16
16
 
17
17
 
18
18
  # noinspection PyUnusedLocal
@@ -52,7 +52,7 @@ def after_run(
52
52
  flow_name=flow_name,
53
53
  mmd_dir=mmd_dir,
54
54
  )
55
- if skip_timeline is False:
55
+ if skip_timeline is False: # pragma: no branch
56
56
  _make_timeline_json(temp_dir=temp_dir)
57
57
  if output_file:
58
58
  destination_dir = output_file.parent
@@ -103,7 +103,7 @@ def _make_timeline_json(
103
103
  events_csv_path = temp_dir / "logs" / "events.csv"
104
104
  if events_csv_path.exists():
105
105
  log_files = TimelineProcessor.get_files(temp_dir / "logs")
106
- if any(log_files.values()):
106
+ if any(log_files.values()): # pragma: no branch
107
107
  output_file = temp_dir / "timeline.json"
108
108
  # pylint: disable=too-many-try-statements
109
109
  try:
@@ -171,7 +171,7 @@ def copy_results(
171
171
  if output_file.is_file():
172
172
  if output_file.suffix == ".waldiez":
173
173
  output_file = output_file.with_suffix(".py")
174
- if output_file.suffix == ".py":
174
+ if output_file.suffix == ".py": # pragma: no branch
175
175
  src = temp_dir / output_file.name
176
176
  if src.exists():
177
177
  dst = destination_dir / output_file.name
@@ -9,10 +9,53 @@ import subprocess
9
9
  import sys
10
10
  from typing import Callable
11
11
 
12
+ from waldiez.models import Waldiez
13
+
12
14
  from .environment import in_virtualenv, is_root
13
15
  from .utils import strip_ansi
14
16
 
15
17
 
18
+ class RequirementsMixin:
19
+ """Mixin class to handle requirements installation."""
20
+
21
+ _waldiez: Waldiez
22
+ _called_install_requirements: bool
23
+
24
+ def gather_requirements(self) -> set[str]:
25
+ """Gather extra requirements to install before running the flow.
26
+
27
+ Returns
28
+ -------
29
+ set[str]
30
+ A set of requirements that are not already installed and do not
31
+ include 'waldiez' in their name.
32
+ """
33
+ extra_requirements = {
34
+ req
35
+ for req in self._waldiez.requirements
36
+ if req not in sys.modules and "waldiez" not in req
37
+ }
38
+ if "python-dotenv" not in extra_requirements: # pragma: no branch
39
+ extra_requirements.add("python-dotenv")
40
+ return extra_requirements
41
+
42
+ def install_requirements(self) -> None:
43
+ """Install the requirements for the flow."""
44
+ if not self._called_install_requirements: # pragma: no branch
45
+ self._called_install_requirements = True
46
+ extra_requirements = self.gather_requirements()
47
+ if extra_requirements: # pragma: no branch
48
+ install_requirements(extra_requirements)
49
+
50
+ async def a_install_requirements(self) -> None:
51
+ """Install the requirements for the flow asynchronously."""
52
+ if not self._called_install_requirements: # pragma: no branch
53
+ self._called_install_requirements = True
54
+ extra_requirements = self.gather_requirements()
55
+ if extra_requirements: # pragma: no branch
56
+ await a_install_requirements(extra_requirements)
57
+
58
+
16
59
  # noinspection PyUnresolvedReferences
17
60
  def install_requirements(
18
61
  extra_requirements: set[str],
@@ -34,7 +77,7 @@ def install_requirements(
34
77
  printer(f"Installing requirements: {requirements_string}")
35
78
  pip_install = [sys.executable, "-m", "pip", "install"]
36
79
  break_system_packages = ""
37
- if not in_virtualenv(): # it should
80
+ if not in_virtualenv(): # it should # pragma: no cover
38
81
  # if not, let's try to install as user
39
82
  # not sure if --break-system-packages is safe,
40
83
  # but it might fail if we don't
@@ -42,7 +85,7 @@ def install_requirements(
42
85
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
43
86
  if not is_root():
44
87
  pip_install.append("--user")
45
- if upgrade:
88
+ if upgrade: # pragma: no cover
46
89
  pip_install.append("--upgrade")
47
90
  pip_install.extend(extra_requirements)
48
91
  # pylint: disable=too-many-try-statements
@@ -52,14 +95,14 @@ def install_requirements(
52
95
  stdout=subprocess.PIPE,
53
96
  stderr=subprocess.PIPE,
54
97
  ) as proc:
55
- if proc.stdout:
98
+ if proc.stdout: # pragma: no branch
56
99
  for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
57
100
  printer(strip_ansi(line.strip()))
58
- if proc.stderr:
101
+ if proc.stderr: # pragma: no branch
59
102
  for line in io.TextIOWrapper(proc.stderr, encoding="utf-8"):
60
103
  printer(strip_ansi(line.strip()))
61
104
  finally:
62
- if not in_virtualenv():
105
+ if not in_virtualenv(): # pragma: no cover
63
106
  # restore the old env var
64
107
  if break_system_packages:
65
108
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
@@ -87,12 +130,12 @@ async def a_install_requirements(
87
130
  printer(f"Installing requirements: {requirements_string}")
88
131
  pip_install = [sys.executable, "-m", "pip", "install"]
89
132
  break_system_packages = ""
90
- if not in_virtualenv():
133
+ if not in_virtualenv(): # pragma: no cover
91
134
  break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
92
135
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
93
136
  if not is_root():
94
137
  pip_install.extend(["--user"])
95
- if upgrade:
138
+ if upgrade: # pragma: no cover
96
139
  pip_install.append("--upgrade")
97
140
  pip_install.extend(extra_requirements)
98
141
  # pylint: disable=too-many-try-statements
@@ -109,40 +152,8 @@ async def a_install_requirements(
109
152
  async for line in proc.stderr:
110
153
  printer(strip_ansi(line.decode().strip()))
111
154
  finally:
112
- if not in_virtualenv():
155
+ if not in_virtualenv(): # pragma: no cover
113
156
  if break_system_packages:
114
157
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
115
158
  else:
116
159
  del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
117
-
118
-
119
- def install_waldiez(
120
- upgrade: bool = True,
121
- printer: Callable[..., None] = print,
122
- ) -> None:
123
- """Install Waldiez.
124
-
125
- Parameters
126
- ----------
127
- upgrade : bool, optional
128
- Whether to upgrade Waldiez, by default True.
129
- printer : Callable[..., None]
130
- The printer function to use, defaults to print.
131
- """
132
- install_requirements({"waldiez"}, upgrade, printer)
133
-
134
-
135
- async def a_install_waldiez(
136
- upgrade: bool = True,
137
- printer: Callable[..., None] = print,
138
- ) -> None:
139
- """Install Waldiez asynchronously.
140
-
141
- Parameters
142
- ----------
143
- upgrade : bool, optional
144
- Whether to upgrade Waldiez, by default True.
145
- printer : Callable[..., None]
146
- The printer function to use, defaults to print.
147
- """
148
- await a_install_requirements({"waldiez"}, upgrade, printer)
@@ -51,98 +51,24 @@ class WaldiezRunnerProtocol(Protocol):
51
51
  The path to the temporary directory created for the run.
52
52
  """
53
53
 
54
- def start(
55
- self,
56
- output_path: str | Path | None,
57
- uploads_root: str | Path | None,
58
- structured_io: bool | None = None,
59
- skip_mmd: bool = False,
60
- skip_timeline: bool = False,
61
- dot_env: str | Path | None = None,
62
- **kwargs: Any,
63
- ) -> None:
64
- """Start running the Waldiez flow in a non-blocking way.
65
-
66
- To allow "stoping" it later.
67
-
68
- Parameters
69
- ----------
70
- output_path : str | Path | None
71
- The output path.
72
- uploads_root : str | Path | None
73
- The runtime uploads root.
74
- structured_io : bool
75
- Whether to use structured IO instead of the default 'input/print'.
76
- skip_mmd : bool
77
- Whether to skip generating the mermaid diagram.
78
- skip_timeline : bool
79
- Whether to skip generating the timeline JSON.
80
- dot_env : str | Path | None
81
- The path to the .env file, if any.
82
- **kwargs : Any
83
- Additional keyword arguments for the start method.
84
-
85
- Raises
86
- ------
87
- RuntimeError
88
- If the runner is already running.
89
- """
90
-
91
- async def a_start(
92
- self,
93
- output_path: str | Path | None,
94
- uploads_root: str | Path | None,
95
- structured_io: bool | None = None,
96
- skip_mmd: bool = False,
97
- skip_timeline: bool = False,
98
- dot_env: str | Path | None = None,
99
- **kwargs: Any,
100
- ) -> None:
101
- """Asynchronously start running the Waldiez flow in a non-blocking way.
102
-
103
- To allow "stoping" it later.
104
-
105
- Parameters
106
- ----------
107
- output_path : str | Path | None
108
- The output path.
109
- uploads_root : str | Path | None
110
- The runtime uploads root.
111
- structured_io : bool
112
- Whether to use structured IO instead of the default 'input/print'.
113
- skip_mmd : bool
114
- Whether to skip generating the mermaid diagram.
115
- skip_timeline : bool
116
- Whether to skip generating the timeline JSON.
117
- dot_env : str | Path | None
118
- The path to the .env file, if any.
119
- **kwargs : Any
120
- Additional keyword arguments for the start method.
121
-
122
- Raises
123
- ------
124
- RuntimeError
125
- If the runner is already running.
126
- """
127
-
128
54
  def run(
129
55
  self,
130
- output_path: str | Path | None,
131
- uploads_root: str | Path | None,
56
+ output_path: str | Path | None = None,
57
+ uploads_root: str | Path | None = None,
132
58
  structured_io: bool | None = None,
133
59
  skip_mmd: bool = False,
134
60
  skip_timeline: bool = False,
135
61
  dot_env: str | Path | None = None,
136
62
  **kwargs: Any,
137
63
  ) -> list[dict[str, Any]]:
138
- """Run the Waldiez flow in a blocking way.
64
+ """Run the Waldiez flow.
139
65
 
140
66
  Parameters
141
67
  ----------
142
68
  output_path : str | Path | None
143
69
  The output path, by default None.
144
70
  uploads_root : str | Path | None
145
- The runtime uploads root.
71
+ The runtime uploads root, by default None.
146
72
  structured_io : bool
147
73
  Whether to use structured IO instead of the default 'input/print'.
148
74
  skip_mmd : bool
@@ -157,20 +83,26 @@ class WaldiezRunnerProtocol(Protocol):
157
83
  Returns
158
84
  -------
159
85
  list[dict[str, Any]]
160
- The result of the run.
86
+ The results of the run.
87
+
88
+ Raises
89
+ ------
90
+ RuntimeError
91
+ If the runner is already running
92
+ or an error occurs during the run.
161
93
  """
162
94
 
163
95
  async def a_run(
164
96
  self,
165
- output_path: str | Path | None,
166
- uploads_root: str | Path | None,
97
+ output_path: str | Path | None = None,
98
+ uploads_root: str | Path | None = None,
167
99
  structured_io: bool | None = None,
168
100
  skip_mmd: bool = False,
169
101
  skip_timeline: bool = False,
170
102
  dot_env: str | Path | None = None,
171
103
  **kwargs: Any,
172
104
  ) -> list[dict[str, Any]]:
173
- """Run the Waldiez flow.
105
+ """Run the Waldiez flow asynchronously.
174
106
 
175
107
  Parameters
176
108
  ----------
@@ -192,7 +124,13 @@ class WaldiezRunnerProtocol(Protocol):
192
124
  Returns
193
125
  -------
194
126
  list[dict[str, Any]]
195
- The result of the run.
127
+ The results of the run.
128
+
129
+ Raises
130
+ ------
131
+ RuntimeError
132
+ If the runner is already running, the workflow is not async
133
+ or an error occurs during the run.
196
134
  """
197
135
 
198
136
  def after_run(
@@ -257,21 +195,3 @@ class WaldiezRunnerProtocol(Protocol):
257
195
  bool
258
196
  True if the runner is running, False otherwise.
259
197
  """
260
-
261
- def stop(self) -> None:
262
- """Stop the runner if it is running.
263
-
264
- Raises
265
- ------
266
- RuntimeError
267
- If the runner is not running.
268
- """
269
-
270
- async def a_stop(self) -> None:
271
- """Asynchronously stop the runner if it is running.
272
-
273
- Raises
274
- ------
275
- RuntimeError
276
- If the runner is not running.
277
- """
@@ -10,5 +10,5 @@ class WaldiezRunResults(TypedDict):
10
10
  """Results of the Waldiez run."""
11
11
 
12
12
  results: list[dict[str, Any]]
13
- exception: Exception | None
13
+ exception: BaseException | None
14
14
  completed: bool