waldiez 0.5.2__py3-none-any.whl → 0.5.4__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 (79) hide show
  1. waldiez/_version.py +1 -1
  2. waldiez/cli.py +5 -27
  3. waldiez/exporter.py +0 -13
  4. waldiez/exporting/agent/exporter.py +38 -0
  5. waldiez/exporting/agent/extras/__init__.py +2 -0
  6. waldiez/exporting/agent/extras/doc_agent_extras.py +366 -0
  7. waldiez/exporting/agent/extras/group_member_extras.py +3 -2
  8. waldiez/exporting/agent/processor.py +113 -15
  9. waldiez/exporting/chats/processor.py +2 -21
  10. waldiez/exporting/chats/utils/common.py +66 -1
  11. waldiez/exporting/chats/utils/group.py +6 -3
  12. waldiez/exporting/chats/utils/nested.py +1 -1
  13. waldiez/exporting/chats/utils/sequential.py +25 -9
  14. waldiez/exporting/chats/utils/single.py +8 -6
  15. waldiez/exporting/core/context.py +0 -12
  16. waldiez/exporting/core/extras/agent_extras/standard_extras.py +3 -1
  17. waldiez/exporting/core/extras/base.py +20 -17
  18. waldiez/exporting/core/extras/path_resolver.py +39 -41
  19. waldiez/exporting/core/extras/serializer.py +16 -1
  20. waldiez/exporting/core/protocols.py +17 -0
  21. waldiez/exporting/core/types.py +6 -9
  22. waldiez/exporting/flow/execution_generator.py +56 -21
  23. waldiez/exporting/flow/exporter.py +1 -4
  24. waldiez/exporting/flow/factory.py +0 -9
  25. waldiez/exporting/flow/file_generator.py +6 -0
  26. waldiez/exporting/flow/orchestrator.py +27 -21
  27. waldiez/exporting/flow/utils/__init__.py +0 -2
  28. waldiez/exporting/flow/utils/common.py +15 -96
  29. waldiez/exporting/flow/utils/importing.py +4 -0
  30. waldiez/io/mqtt.py +33 -14
  31. waldiez/io/redis.py +18 -13
  32. waldiez/io/structured.py +9 -4
  33. waldiez/io/utils.py +32 -0
  34. waldiez/io/ws.py +8 -2
  35. waldiez/models/__init__.py +6 -0
  36. waldiez/models/agents/__init__.py +8 -0
  37. waldiez/models/agents/agent/agent.py +136 -38
  38. waldiez/models/agents/agent/agent_type.py +3 -2
  39. waldiez/models/agents/agents.py +10 -0
  40. waldiez/models/agents/doc_agent/__init__.py +13 -0
  41. waldiez/models/agents/doc_agent/doc_agent.py +126 -0
  42. waldiez/models/agents/doc_agent/doc_agent_data.py +149 -0
  43. waldiez/models/agents/doc_agent/rag_query_engine.py +127 -0
  44. waldiez/models/chat/chat_message.py +1 -1
  45. waldiez/models/flow/flow.py +13 -2
  46. waldiez/models/model/__init__.py +2 -2
  47. waldiez/models/model/_aws.py +75 -0
  48. waldiez/models/model/_llm.py +516 -0
  49. waldiez/models/model/_price.py +30 -0
  50. waldiez/models/model/model.py +45 -2
  51. waldiez/models/model/model_data.py +2 -83
  52. waldiez/models/tool/predefined/_duckduckgo.py +123 -0
  53. waldiez/models/tool/predefined/_google.py +31 -9
  54. waldiez/models/tool/predefined/_perplexity.py +161 -0
  55. waldiez/models/tool/predefined/_searxng.py +152 -0
  56. waldiez/models/tool/predefined/_tavily.py +46 -9
  57. waldiez/models/tool/predefined/_wikipedia.py +26 -6
  58. waldiez/models/tool/predefined/_youtube.py +36 -8
  59. waldiez/models/tool/predefined/registry.py +6 -0
  60. waldiez/models/waldiez.py +12 -0
  61. waldiez/runner.py +184 -382
  62. waldiez/running/__init__.py +2 -4
  63. waldiez/running/base_runner.py +136 -118
  64. waldiez/running/environment.py +61 -17
  65. waldiez/running/post_run.py +70 -14
  66. waldiez/running/pre_run.py +42 -0
  67. waldiez/running/protocol.py +42 -48
  68. waldiez/running/run_results.py +5 -5
  69. waldiez/running/standard_runner.py +429 -0
  70. waldiez/running/timeline_processor.py +1166 -0
  71. waldiez/utils/version.py +12 -1
  72. {waldiez-0.5.2.dist-info → waldiez-0.5.4.dist-info}/METADATA +61 -63
  73. {waldiez-0.5.2.dist-info → waldiez-0.5.4.dist-info}/RECORD +77 -66
  74. waldiez/running/import_runner.py +0 -424
  75. waldiez/running/subprocess_runner.py +0 -100
  76. {waldiez-0.5.2.dist-info → waldiez-0.5.4.dist-info}/WHEEL +0 -0
  77. {waldiez-0.5.2.dist-info → waldiez-0.5.4.dist-info}/entry_points.txt +0 -0
  78. {waldiez-0.5.2.dist-info → waldiez-0.5.4.dist-info}/licenses/LICENSE +0 -0
  79. {waldiez-0.5.2.dist-info → waldiez-0.5.4.dist-info}/licenses/NOTICE.md +0 -0
@@ -1,424 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0.
2
- # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
-
4
- # flake8: noqa: C901
5
- # pylint: disable=too-many-try-statements,import-outside-toplevel,
6
- # pylint: disable=too-complex,unused-argument
7
- """Run a waldiez flow.
8
-
9
- The flow is first converted to an autogen flow with agents, chats, and tools.
10
- We then chown to temporary directory, call the flow's `main()` and
11
- return the results. Before running the flow, any additional environment
12
- variables specified in the waldiez file are set.
13
- """
14
-
15
- import asyncio
16
- import importlib.util
17
- import threading
18
- import time
19
- from pathlib import Path
20
- from types import ModuleType
21
- from typing import TYPE_CHECKING, Callable, Union
22
-
23
- from waldiez.models.waldiez import Waldiez
24
- from waldiez.running.patch_io_stream import patch_io_stream
25
-
26
- from .base_runner import WaldiezBaseRunner
27
- from .run_results import WaldiezRunResults
28
-
29
- if TYPE_CHECKING:
30
- from autogen import ChatResult # type: ignore
31
-
32
-
33
- class WaldiezImportRunner(WaldiezBaseRunner):
34
- """Waldiez runner class."""
35
-
36
- def __init__(
37
- self,
38
- waldiez: Waldiez,
39
- output_path: str | Path | None = None,
40
- uploads_root: str | Path | None = None,
41
- structured_io: bool = False,
42
- isolated: bool = False,
43
- threaded: bool = True,
44
- skip_patch_io: bool = False,
45
- ) -> None:
46
- """Initialize the Waldiez manager."""
47
- super().__init__(
48
- waldiez,
49
- output_path=output_path,
50
- uploads_root=uploads_root,
51
- structured_io=structured_io,
52
- isolated=isolated,
53
- threaded=threaded,
54
- skip_patch_io=skip_patch_io,
55
- )
56
- self._execution_thread: threading.Thread | None = None
57
- self._execution_loop: asyncio.AbstractEventLoop | None = None
58
- self._loaded_module: ModuleType | None = None
59
-
60
- def _run(
61
- self,
62
- temp_dir: Path,
63
- output_file: Path,
64
- uploads_root: Path | None,
65
- skip_mmd: bool,
66
- ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
67
- """Run the Waldiez workflow."""
68
- if self.threaded:
69
- return self._run_threaded(
70
- temp_dir=temp_dir,
71
- output_file=output_file,
72
- uploads_root=uploads_root,
73
- skip_mmd=skip_mmd,
74
- )
75
-
76
- return self._run_not_threaded(
77
- temp_dir=temp_dir,
78
- output_file=output_file,
79
- uploads_root=uploads_root,
80
- skip_mmd=skip_mmd,
81
- )
82
-
83
- def _run_not_threaded(
84
- self,
85
- temp_dir: Path,
86
- output_file: Path,
87
- uploads_root: Path | None,
88
- skip_mmd: bool,
89
- ) -> Union[
90
- "ChatResult",
91
- list["ChatResult"],
92
- dict[int, "ChatResult"],
93
- ]:
94
- """Run the Waldiez workflow in a blocking manner."""
95
- from autogen.io import IOStream # type: ignore
96
-
97
- from waldiez.io import StructuredIOStream
98
-
99
- results_container: WaldiezRunResults = {
100
- "results": None,
101
- "exception": None,
102
- "completed": False,
103
- }
104
- if not self.structured_io and not self.skip_patch_io:
105
- patch_io_stream(self.waldiez.is_async)
106
- printer: Callable[..., None] = print
107
- try:
108
- file_name = output_file.name
109
- module_name = file_name.replace(".py", "")
110
- spec = importlib.util.spec_from_file_location(
111
- module_name, temp_dir / file_name
112
- )
113
- if not spec or not spec.loader:
114
- raise ImportError("Could not import the flow")
115
- if self.structured_io:
116
- stream = StructuredIOStream(
117
- uploads_root=uploads_root, is_async=False
118
- )
119
- printer = stream.print
120
- with IOStream.set_default(stream):
121
- self._loaded_module = importlib.util.module_from_spec(spec)
122
- spec.loader.exec_module(self._loaded_module)
123
- printer("<Waldiez> - Starting workflow...")
124
- printer(self.waldiez.info.model_dump_json())
125
- results = self._loaded_module.main()
126
- else:
127
- printer = IOStream.get_default().print
128
- self._loaded_module = importlib.util.module_from_spec(spec)
129
- spec.loader.exec_module(self._loaded_module)
130
- printer("<Waldiez> - Starting workflow...")
131
- printer(self.waldiez.info.model_dump_json())
132
- results = self._loaded_module.main()
133
- results_container["results"] = results
134
- printer("<Waldiez> - Workflow finished")
135
- except SystemExit:
136
- printer("<Waldiez> - Workflow stopped by user")
137
- results_container["results"] = []
138
- except Exception as e: # pylint: disable=broad-exception-caught
139
- results_container["exception"] = e
140
- printer("<Waldiez> - Workflow execution failed: %s", e)
141
- finally:
142
- results_container["completed"] = True
143
- return results_container["results"] or []
144
-
145
- # pylint: disable=too-many-statements,duplicate-code
146
- def _run_threaded(
147
- self,
148
- temp_dir: Path,
149
- output_file: Path,
150
- uploads_root: Path | None,
151
- skip_mmd: bool,
152
- ) -> Union[
153
- "ChatResult",
154
- list["ChatResult"],
155
- dict[int, "ChatResult"],
156
- ]:
157
- """Run the Waldiez workflow."""
158
- results_container: WaldiezRunResults = {
159
- "results": None,
160
- "exception": None,
161
- "completed": False,
162
- }
163
-
164
- def _execute_workflow() -> None:
165
- """Execute the workflow in a separate thread."""
166
- from autogen.io import IOStream # pyright: ignore
167
-
168
- from waldiez.io import StructuredIOStream
169
-
170
- if not self.structured_io and not self.skip_patch_io:
171
- patch_io_stream(self.waldiez.is_async)
172
- printer: Callable[..., None] = print
173
- try:
174
- file_name = output_file.name
175
- module_name = file_name.replace(".py", "")
176
- spec = importlib.util.spec_from_file_location(
177
- module_name, temp_dir / file_name
178
- )
179
- if not spec or not spec.loader:
180
- raise ImportError("Could not import the flow")
181
- if self.structured_io:
182
- stream = StructuredIOStream(
183
- uploads_root=uploads_root, is_async=False
184
- )
185
- printer = stream.print
186
- with IOStream.set_default(stream):
187
- self._loaded_module = importlib.util.module_from_spec(
188
- spec
189
- )
190
- spec.loader.exec_module(self._loaded_module)
191
- printer("<Waldiez> - Starting workflow...")
192
- printer(self.waldiez.info.model_dump_json())
193
- results = self._loaded_module.main()
194
- else:
195
- printer = IOStream.get_default().print
196
- self._loaded_module = importlib.util.module_from_spec(spec)
197
- spec.loader.exec_module(self._loaded_module)
198
- printer("<Waldiez> - Starting workflow...")
199
- printer(self.waldiez.info.model_dump_json())
200
- results = self._loaded_module.main()
201
- results_container["results"] = results
202
- printer("<Waldiez> - Workflow finished")
203
- except SystemExit:
204
- printer("<Waldiez> - Workflow stopped by user")
205
- results_container["results"] = []
206
- except Exception as e: # pylint: disable=broad-exception-caught
207
- results_container["exception"] = e
208
- printer("<Waldiez> - Workflow execution failed: %s", e)
209
- finally:
210
- results_container["completed"] = True
211
- self._execution_loop = None
212
- self._execution_thread = None
213
-
214
- # Execute in a separate thread for responsive stopping
215
- self._execution_thread = threading.Thread(
216
- target=_execute_workflow, daemon=True
217
- )
218
- self._execution_thread.start()
219
-
220
- # Wait for completion while checking for stop requests
221
- while self._execution_thread and self._execution_thread.is_alive():
222
- if self._stop_requested.is_set():
223
- self.log.info(
224
- "Stop requested, waiting for graceful shutdown..."
225
- )
226
- self._execution_thread.join(timeout=5.0)
227
- if self._execution_thread.is_alive():
228
- self.log.warning("Workflow did not stop gracefully")
229
- break
230
- if results_container["completed"] is True:
231
- break
232
- time.sleep(0.1)
233
-
234
- # Handle results
235
- exception = results_container["exception"]
236
- if exception is not None:
237
- self._last_exception = exception
238
- raise exception
239
-
240
- self._last_results = results_container["results"] or []
241
- return self._last_results
242
-
243
- async def _a_run(
244
- self,
245
- temp_dir: Path,
246
- output_file: Path,
247
- uploads_root: Path | None,
248
- skip_mmd: bool,
249
- ) -> Union[
250
- "ChatResult",
251
- list["ChatResult"],
252
- dict[int, "ChatResult"],
253
- ]:
254
- """Async execution using asyncio tasks."""
255
-
256
- async def _execute_workflow() -> Union[
257
- "ChatResult",
258
- list["ChatResult"],
259
- dict[int, "ChatResult"],
260
- ]:
261
- """Execute the workflow in an async context."""
262
- from autogen.io import IOStream # pyright: ignore
263
-
264
- from waldiez.io import StructuredIOStream
265
-
266
- printer: Callable[..., None] = print
267
- if not self.structured_io and not self.skip_patch_io:
268
- patch_io_stream(self.waldiez.is_async)
269
- try:
270
- file_name = output_file.name
271
- module_name = file_name.replace(".py", "")
272
- spec = importlib.util.spec_from_file_location(
273
- module_name, temp_dir / file_name
274
- )
275
- if not spec or not spec.loader:
276
- raise ImportError("Could not import the flow")
277
- if self.structured_io:
278
- stream = StructuredIOStream(
279
- uploads_root=uploads_root, is_async=True
280
- )
281
- printer = stream.print
282
- with IOStream.set_default(stream):
283
- printer("<Waldiez> - Starting workflow...")
284
- printer(self.waldiez.info.model_dump_json())
285
- self._loaded_module = importlib.util.module_from_spec(
286
- spec
287
- )
288
- spec.loader.exec_module(self._loaded_module)
289
- results = await self._loaded_module.main()
290
- self._last_results = results
291
- else:
292
- printer = IOStream.get_default().print
293
- printer("<Waldiez> - Starting workflow...")
294
- printer(self.waldiez.info.model_dump_json())
295
- self._loaded_module = importlib.util.module_from_spec(spec)
296
- spec.loader.exec_module(self._loaded_module)
297
- results = await self._loaded_module.main()
298
- self._last_results = results
299
- printer("<Waldiez> - Workflow finished")
300
- return results
301
-
302
- except SystemExit:
303
- printer("Workflow stopped by user")
304
- return []
305
- except Exception as e:
306
- self._last_exception = e
307
- printer("Workflow execution failed: %s", e)
308
- raise
309
-
310
- # Create cancellable task
311
- task = asyncio.create_task(_execute_workflow())
312
-
313
- # Monitor for stop requests
314
- try:
315
- while not task.done():
316
- if self._stop_requested.is_set():
317
- self.log.info("Stop requested, cancelling task...")
318
- task.cancel()
319
- break
320
- await asyncio.sleep(0.1)
321
-
322
- return await task
323
-
324
- except asyncio.CancelledError:
325
- self.log.info("Workflow cancelled")
326
- return []
327
-
328
- def _after_run(
329
- self,
330
- results: Union[
331
- "ChatResult",
332
- list["ChatResult"],
333
- dict[int, "ChatResult"],
334
- ],
335
- output_file: Path,
336
- uploads_root: Path | None,
337
- temp_dir: Path,
338
- skip_mmd: bool,
339
- ) -> None:
340
- super()._after_run(
341
- results=results,
342
- output_file=output_file,
343
- uploads_root=uploads_root,
344
- temp_dir=temp_dir,
345
- skip_mmd=skip_mmd,
346
- )
347
-
348
- # Clean up module reference
349
- self._loaded_module = None
350
-
351
- def _start(
352
- self,
353
- temp_dir: Path,
354
- output_file: Path,
355
- uploads_root: Path | None,
356
- skip_mmd: bool = False,
357
- ) -> None:
358
- """Start the Waldiez workflow."""
359
-
360
- def run_in_background() -> None:
361
- """Run the workflow in a background thread."""
362
- try:
363
- # Reuse the blocking run logic but in a background thread
364
- self._run_threaded(
365
- temp_dir=temp_dir,
366
- output_file=output_file,
367
- uploads_root=uploads_root,
368
- skip_mmd=skip_mmd,
369
- )
370
- except Exception as e: # pylint: disable=broad-exception-caught
371
- self._last_exception = e
372
- self.log.error("Background workflow failed: %s", e)
373
-
374
- # Start background execution
375
- background_thread = threading.Thread(
376
- target=run_in_background, daemon=True
377
- )
378
- background_thread.start()
379
-
380
- async def _a_start(
381
- self,
382
- temp_dir: Path,
383
- output_file: Path,
384
- uploads_root: Path | None,
385
- skip_mmd: bool = False,
386
- ) -> None:
387
- """Start the Waldiez workflow asynchronously."""
388
-
389
- async def run_in_background() -> None:
390
- """Run the workflow in an async context."""
391
- try:
392
- await self._a_run(
393
- temp_dir=temp_dir,
394
- output_file=output_file,
395
- uploads_root=uploads_root,
396
- skip_mmd=skip_mmd,
397
- )
398
- except Exception as e: # pylint: disable=broad-exception-caught
399
- self._last_exception = e
400
- self.log.error("Background workflow failed: %s", e)
401
-
402
- # Start background task
403
- asyncio.create_task(run_in_background())
404
-
405
- def _stop(self) -> None:
406
- """Stop the Waldiez workflow."""
407
- self.log.info("Stopping workflow execution...")
408
- self._stop_requested.set()
409
-
410
- # Wait for graceful shutdown
411
- if self._execution_thread and self._execution_thread.is_alive():
412
- self._execution_thread.join(timeout=5.0)
413
-
414
- if self._execution_thread and self._execution_thread.is_alive():
415
- self.log.warning("Workflow thread did not stop gracefully")
416
-
417
- async def _a_stop(self) -> None:
418
- """Stop the Waldiez workflow asynchronously."""
419
- self.log.info("Stopping workflow execution (async)...")
420
- self._stop_requested.set()
421
-
422
- # For async, we rely on the task cancellation in _a_run
423
- # Let's give it a moment to respond
424
- await asyncio.sleep(0.5)
@@ -1,100 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0.
2
- # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- """Run a waldiez flow.
4
-
5
- The flow is first converted to an autogen flow with agents, chats, and tools.
6
- We then chown to temporary directory, call the flow's `main()` and
7
- return the results. Before running the flow, any additional environment
8
- variables specified in the waldiez file are set.
9
- """
10
-
11
- from pathlib import Path
12
- from typing import TYPE_CHECKING, Union
13
-
14
- from waldiez.models.waldiez import Waldiez
15
-
16
- from .base_runner import WaldiezBaseRunner
17
-
18
- if TYPE_CHECKING:
19
- from autogen import ChatResult # type: ignore[import-untyped]
20
-
21
-
22
- class WaldiezSubprocessRunner(WaldiezBaseRunner):
23
- """Waldiez runner class."""
24
-
25
- def __init__(
26
- self,
27
- waldiez: Waldiez,
28
- output_path: str | Path | None = None,
29
- uploads_root: str | Path | None = None,
30
- structured_io: bool = True,
31
- isolated: bool = True,
32
- threaded: bool = False,
33
- skip_patch_io: bool = True,
34
- ) -> None:
35
- """Initialize the Waldiez manager."""
36
- super().__init__(
37
- waldiez,
38
- output_path=output_path,
39
- uploads_root=uploads_root,
40
- structured_io=structured_io,
41
- isolated=isolated,
42
- threaded=threaded,
43
- skip_patch_io=skip_patch_io,
44
- )
45
-
46
- def _run(
47
- self,
48
- temp_dir: Path,
49
- output_file: Path,
50
- uploads_root: Path | None,
51
- skip_mmd: bool,
52
- ) -> Union[
53
- "ChatResult",
54
- list["ChatResult"],
55
- dict[int, "ChatResult"],
56
- ]:
57
- """Run the Waldiez workflow."""
58
- return []
59
-
60
- async def _a_run(
61
- self,
62
- temp_dir: Path,
63
- output_file: Path,
64
- uploads_root: Path | None,
65
- skip_mmd: bool,
66
- ) -> Union[
67
- "ChatResult",
68
- list["ChatResult"],
69
- dict[int, "ChatResult"],
70
- ]:
71
- """Run the Waldiez workflow asynchronously."""
72
- return []
73
-
74
- def _start(
75
- self,
76
- temp_dir: Path,
77
- output_file: Path,
78
- uploads_root: Path | None,
79
- skip_mmd: bool,
80
- ) -> None:
81
- """Start the Waldiez workflow."""
82
- # This method should be implemented to start the workflow
83
- # For now, it is a placeholder
84
-
85
- async def _a_start(
86
- self,
87
- temp_dir: Path,
88
- output_file: Path,
89
- uploads_root: Path | None,
90
- skip_mmd: bool,
91
- ) -> None:
92
- """Start the Waldiez workflow asynchronously."""
93
- # This method should be implemented to start the workflow asynchronously
94
- # For now, it is a placeholder
95
-
96
- def _stop(self) -> None:
97
- """Stop the Waldiez workflow."""
98
-
99
- async def _a_stop(self) -> None:
100
- """Stop the Waldiez workflow asynchronously."""