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