waldiez 0.5.1__py3-none-any.whl → 0.5.3__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 (36) hide show
  1. waldiez/_version.py +1 -1
  2. waldiez/cli.py +2 -0
  3. waldiez/exporting/agent/extras/group_manager_agent_extas.py +5 -1
  4. waldiez/exporting/chats/processor.py +4 -4
  5. waldiez/exporting/chats/utils/group.py +4 -4
  6. waldiez/exporting/chats/utils/single.py +3 -3
  7. waldiez/exporting/tools/exporter.py +1 -1
  8. waldiez/models/chat/chat_message.py +1 -1
  9. waldiez/models/tool/extra_requirements.py +5 -0
  10. waldiez/models/tool/predefined/__init__.py +24 -0
  11. waldiez/models/tool/predefined/_config.py +68 -0
  12. waldiez/models/tool/predefined/_google.py +166 -0
  13. waldiez/models/tool/predefined/_tavily.py +124 -0
  14. waldiez/models/tool/predefined/_wikipedia.py +130 -0
  15. waldiez/models/tool/predefined/_youtube.py +123 -0
  16. waldiez/models/tool/predefined/protocol.py +85 -0
  17. waldiez/models/tool/predefined/registry.py +79 -0
  18. waldiez/models/tool/tool.py +96 -13
  19. waldiez/models/tool/tool_data.py +12 -0
  20. waldiez/models/tool/tool_type.py +3 -1
  21. waldiez/runner.py +35 -2
  22. waldiez/running/base_runner.py +38 -8
  23. waldiez/running/environment.py +32 -12
  24. waldiez/running/import_runner.py +13 -0
  25. waldiez/running/post_run.py +71 -14
  26. waldiez/running/pre_run.py +42 -0
  27. waldiez/running/protocol.py +6 -0
  28. waldiez/running/subprocess_runner.py +4 -0
  29. waldiez/running/timeline_processor.py +1248 -0
  30. waldiez/utils/version.py +12 -1
  31. {waldiez-0.5.1.dist-info → waldiez-0.5.3.dist-info}/METADATA +39 -38
  32. {waldiez-0.5.1.dist-info → waldiez-0.5.3.dist-info}/RECORD +36 -27
  33. {waldiez-0.5.1.dist-info → waldiez-0.5.3.dist-info}/WHEEL +0 -0
  34. {waldiez-0.5.1.dist-info → waldiez-0.5.3.dist-info}/entry_points.txt +0 -0
  35. {waldiez-0.5.1.dist-info → waldiez-0.5.3.dist-info}/licenses/LICENSE +0 -0
  36. {waldiez-0.5.1.dist-info → waldiez-0.5.3.dist-info}/licenses/NOTICE.md +0 -0
@@ -20,7 +20,6 @@ from typing_extensions import Self
20
20
  from waldiez.exporter import WaldiezExporter
21
21
  from waldiez.logger import WaldiezLogger, get_logger
22
22
  from waldiez.models import Waldiez
23
- from waldiez.utils import get_waldiez_version
24
23
 
25
24
  from .environment import refresh_environment, reset_env_vars, set_env_vars
26
25
  from .post_run import after_run
@@ -149,6 +148,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
149
148
  output_file: Path,
150
149
  uploads_root: Path | None,
151
150
  skip_mmd: bool,
151
+ skip_timeline: bool,
152
152
  ) -> Union[
153
153
  "ChatResult",
154
154
  list["ChatResult"],
@@ -165,6 +165,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
165
165
  output_file: Path,
166
166
  uploads_root: Path | None,
167
167
  skip_mmd: bool,
168
+ skip_timeline: bool,
168
169
  ) -> Union[
169
170
  "ChatResult",
170
171
  list["ChatResult"],
@@ -181,6 +182,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
181
182
  output_file: Path,
182
183
  uploads_root: Path | None,
183
184
  skip_mmd: bool,
185
+ skip_timeline: bool,
184
186
  ) -> None:
185
187
  """Start running the Waldiez flow in a non-blocking way."""
186
188
  raise NotImplementedError(
@@ -193,6 +195,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
193
195
  output_file: Path,
194
196
  uploads_root: Path | None,
195
197
  skip_mmd: bool,
198
+ skip_timeline: bool,
196
199
  ) -> None:
197
200
  """Start running the Waldiez flow in a non-blocking way asynchronously.
198
201
 
@@ -224,6 +227,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
224
227
  uploads_root: Path | None,
225
228
  temp_dir: Path,
226
229
  skip_mmd: bool,
230
+ skip_timeline: bool,
227
231
  ) -> None:
228
232
  """Run after the flow execution."""
229
233
  # Save results
@@ -237,6 +241,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
237
241
  flow_name=self.waldiez.name,
238
242
  uploads_root=uploads_root,
239
243
  skip_mmd=skip_mmd,
244
+ skip_timeline=skip_timeline,
240
245
  )
241
246
  self.log.info("Cleanup completed")
242
247
 
@@ -251,6 +256,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
251
256
  uploads_root: Path | None,
252
257
  temp_dir: Path,
253
258
  skip_mmd: bool,
259
+ skip_timeline: bool,
254
260
  ) -> None:
255
261
  """Run after the flow execution asynchronously."""
256
262
  self._after_run(
@@ -259,6 +265,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
259
265
  uploads_root=uploads_root,
260
266
  temp_dir=temp_dir,
261
267
  skip_mmd=skip_mmd,
268
+ skip_timeline=skip_timeline,
262
269
  )
263
270
 
264
271
  def _stop(self) -> None:
@@ -309,9 +316,6 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
309
316
  for req in self.waldiez.requirements
310
317
  if req not in sys.modules and "waldiez" not in req
311
318
  }
312
- waldiez_version = get_waldiez_version()
313
- if "waldiez" not in sys.modules:
314
- extra_requirements.add(f"waldiez=={waldiez_version}")
315
319
  return extra_requirements
316
320
 
317
321
  def install_requirements(self) -> None:
@@ -390,6 +394,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
390
394
  threaded: bool | None = None,
391
395
  skip_patch_io: bool | None = None,
392
396
  skip_mmd: bool = False,
397
+ skip_timeline: bool = False,
393
398
  ) -> Union[
394
399
  "ChatResult",
395
400
  list["ChatResult"],
@@ -408,10 +413,12 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
408
413
  by default False.
409
414
  threaded : bool | None
410
415
  Whether to run the flow in a threaded environment, by default None.
411
- skip_mmd : bool
412
- Whether to skip generating the mermaid diagram, by default False.
413
416
  skip_patch_io : bool | None
414
417
  Whether to skip patching the IO streams, by default None.
418
+ skip_mmd : bool
419
+ Whether to skip generating the mermaid diagram, by default False.
420
+ skip_timeline : bool
421
+ Whether to skip generating the timeline JSON.
415
422
 
416
423
  Returns
417
424
  -------
@@ -468,6 +475,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
468
475
  output_file=output_file,
469
476
  uploads_root=uploads_root_path,
470
477
  skip_mmd=skip_mmd,
478
+ skip_timeline=skip_timeline,
471
479
  )
472
480
  finally:
473
481
  WaldiezBaseRunner._running = False
@@ -478,6 +486,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
478
486
  uploads_root=uploads_root_path,
479
487
  temp_dir=temp_dir,
480
488
  skip_mmd=skip_mmd,
489
+ skip_timeline=skip_timeline,
481
490
  )
482
491
  if sys.path[0] == str(temp_dir):
483
492
  sys.path.pop(0)
@@ -490,6 +499,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
490
499
  structured_io: bool | None = None,
491
500
  skip_patch_io: bool | None = None,
492
501
  skip_mmd: bool = False,
502
+ skip_timeline: bool = False,
493
503
  ) -> Union[
494
504
  "ChatResult",
495
505
  list["ChatResult"],
@@ -510,6 +520,8 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
510
520
  Whether to skip patching I/O, by default None.
511
521
  skip_mmd : bool
512
522
  Whether to skip generating the mermaid diagram, by default False.
523
+ skip_timeline : bool
524
+ Whether to skip generating the timeline JSON, by default False.
513
525
 
514
526
  Returns
515
527
  -------
@@ -553,6 +565,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
553
565
  output_file=output_file,
554
566
  uploads_root=uploads_root_path,
555
567
  skip_mmd=skip_mmd,
568
+ skip_timeline=skip_timeline,
556
569
  )
557
570
  finally:
558
571
  WaldiezBaseRunner._running = False
@@ -562,6 +575,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
562
575
  uploads_root=uploads_root_path,
563
576
  temp_dir=temp_dir,
564
577
  skip_mmd=skip_mmd,
578
+ skip_timeline=skip_timeline,
565
579
  )
566
580
  if sys.path[0] == str(temp_dir):
567
581
  sys.path.pop(0)
@@ -574,6 +588,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
574
588
  structured_io: bool | None = None,
575
589
  skip_patch_io: bool | None = None,
576
590
  skip_mmd: bool = False,
591
+ skip_timeline: bool = False,
577
592
  ) -> None:
578
593
  """Start running the Waldiez flow in a non-blocking way.
579
594
 
@@ -589,6 +604,8 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
589
604
  Whether to skip patching I/O, by default None.
590
605
  skip_mmd : bool
591
606
  Whether to skip generating the mermaid diagram, by default False.
607
+ skip_timeline : bool
608
+ Whether to skip generating the timeline JSON, by default False.
592
609
 
593
610
  Raises
594
611
  ------
@@ -617,6 +634,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
617
634
  output_file=output_file,
618
635
  uploads_root=uploads_root_path,
619
636
  skip_mmd=skip_mmd,
637
+ skip_timeline=skip_timeline,
620
638
  )
621
639
 
622
640
  async def a_start(
@@ -626,6 +644,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
626
644
  structured_io: bool | None = None,
627
645
  skip_patch_io: bool | None = None,
628
646
  skip_mmd: bool = False,
647
+ skip_timeline: bool = False,
629
648
  ) -> None:
630
649
  """Asynchronously start running the Waldiez flow in a non-blocking way.
631
650
 
@@ -639,8 +658,10 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
639
658
  Whether to use structured IO instead of the default 'input/print'.
640
659
  skip_patch_io : bool | None = None
641
660
  Whether to skip patching I/O, by default None.
642
- skip_mmd : bool | None = None
643
- Whether to skip generating the mermaid diagram, by default None.
661
+ skip_mmd : bool = False
662
+ Whether to skip generating the mermaid diagram, by default False.
663
+ skip_timeline : bool = False
664
+ Whether to skip generating the timeline JSON, by default False.
644
665
 
645
666
  Raises
646
667
  ------
@@ -669,6 +690,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
669
690
  output_file=output_file,
670
691
  uploads_root=uploads_root_path,
671
692
  skip_mmd=skip_mmd,
693
+ skip_timeline=skip_timeline,
672
694
  )
673
695
 
674
696
  def after_run(
@@ -682,6 +704,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
682
704
  uploads_root: Path | None,
683
705
  temp_dir: Path,
684
706
  skip_mmd: bool,
707
+ skip_timeline: bool,
685
708
  ) -> None:
686
709
  """Actions to perform after running the flow.
687
710
 
@@ -697,6 +720,8 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
697
720
  The path to the temporary directory used during the run.
698
721
  skip_mmd : bool
699
722
  Whether to skip generating the mermaid diagram.
723
+ skip_timeline : bool
724
+ Whether to skip generating the timeline JSON.
700
725
  """
701
726
  self._after_run(
702
727
  results=results,
@@ -704,6 +729,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
704
729
  uploads_root=uploads_root,
705
730
  temp_dir=temp_dir,
706
731
  skip_mmd=skip_mmd,
732
+ skip_timeline=skip_timeline,
707
733
  )
708
734
 
709
735
  async def a_after_run(
@@ -717,6 +743,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
717
743
  uploads_root: Path | None,
718
744
  temp_dir: Path,
719
745
  skip_mmd: bool,
746
+ skip_timeline: bool,
720
747
  ) -> None:
721
748
  """Asynchronously perform actions after running the flow.
722
749
 
@@ -732,6 +759,8 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
732
759
  The path to the temporary directory used during the run.
733
760
  skip_mmd : bool
734
761
  Whether to skip generating the mermaid diagram.
762
+ skip_timeline : bool
763
+
735
764
  """
736
765
  await self._a_after_run(
737
766
  results=results,
@@ -739,6 +768,7 @@ class WaldiezBaseRunner(WaldiezRunnerProtocol):
739
768
  uploads_root=uploads_root,
740
769
  temp_dir=temp_dir,
741
770
  skip_mmd=skip_mmd,
771
+ skip_timeline=skip_timeline,
742
772
  )
743
773
 
744
774
  def stop(self) -> None:
@@ -3,6 +3,7 @@
3
3
  # pylint: disable=import-outside-toplevel,reimported
4
4
  """Environment related utilities."""
5
5
 
6
+ import importlib
6
7
  import os
7
8
  import site
8
9
  import sys
@@ -86,19 +87,19 @@ def reload_autogen() -> None: # noqa: C901
86
87
  default_io_stream = IOStream.get_default()
87
88
  except (ImportError, AttributeError):
88
89
  pass
89
-
90
+ autogen_modules = sorted(
91
+ [
92
+ name
93
+ for name in sys.modules
94
+ if name.startswith("autogen.")
95
+ and not name.startswith("autogen.io")
96
+ and not name.startswith("autogen.tools")
97
+ ],
98
+ key=len,
99
+ reverse=True, # Longer names (deeper modules) first
100
+ )
90
101
  try:
91
102
  # Remove autogen modules in reverse dependency order
92
- autogen_modules = sorted(
93
- [
94
- name
95
- for name in sys.modules
96
- if name.startswith("autogen.")
97
- and not name.startswith("autogen.io")
98
- ],
99
- key=len,
100
- reverse=True, # Longer names (deeper modules) first
101
- )
102
103
  for mod_name in autogen_modules:
103
104
  if mod_name in sys.modules:
104
105
  del sys.modules[mod_name]
@@ -110,6 +111,14 @@ def reload_autogen() -> None: # noqa: C901
110
111
  # pylint: disable=unused-import
111
112
  import autogen # pyright: ignore
112
113
 
114
+ for mod_name in sorted(autogen_modules, key=len, reverse=False):
115
+ # Re-import each module
116
+ try:
117
+ importlib.import_module(mod_name)
118
+ except ImportError as e:
119
+ # If a module fails to import, we can log it or handle it
120
+ print(f"Failed to re-import {mod_name}: {e}", file=sys.stderr)
121
+
113
122
  # Restore IOStream state if we had it
114
123
  if default_io_stream is not None:
115
124
  try:
@@ -124,7 +133,18 @@ def reload_autogen() -> None: # noqa: C901
124
133
  # If reload fails, at least try to re-import autogen
125
134
  try:
126
135
  import autogen # type: ignore # noqa: F401
127
- except ImportError:
136
+
137
+ for mod_name in sorted(autogen_modules, key=len, reverse=False):
138
+ # Re-import each module
139
+ try:
140
+ importlib.import_module(mod_name)
141
+ except ImportError as err:
142
+ # If a module fails to import, we can log it or handle it
143
+ print(
144
+ f"Failed to re-import {mod_name}: {err}",
145
+ file=sys.stderr,
146
+ )
147
+ except Exception: # pylint: disable=broad-exception-caught
128
148
  pass
129
149
  raise e
130
150
 
@@ -63,6 +63,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
63
63
  output_file: Path,
64
64
  uploads_root: Path | None,
65
65
  skip_mmd: bool,
66
+ skip_timeline: bool,
66
67
  ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
67
68
  """Run the Waldiez workflow."""
68
69
  if self.threaded:
@@ -71,6 +72,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
71
72
  output_file=output_file,
72
73
  uploads_root=uploads_root,
73
74
  skip_mmd=skip_mmd,
75
+ skip_timeline=skip_timeline,
74
76
  )
75
77
 
76
78
  return self._run_not_threaded(
@@ -78,14 +80,17 @@ class WaldiezImportRunner(WaldiezBaseRunner):
78
80
  output_file=output_file,
79
81
  uploads_root=uploads_root,
80
82
  skip_mmd=skip_mmd,
83
+ skip_timeline=skip_timeline,
81
84
  )
82
85
 
86
+ # pylint: disable=too-many-locals
83
87
  def _run_not_threaded(
84
88
  self,
85
89
  temp_dir: Path,
86
90
  output_file: Path,
87
91
  uploads_root: Path | None,
88
92
  skip_mmd: bool,
93
+ skip_timeline: bool,
89
94
  ) -> Union[
90
95
  "ChatResult",
91
96
  list["ChatResult"],
@@ -149,6 +154,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
149
154
  output_file: Path,
150
155
  uploads_root: Path | None,
151
156
  skip_mmd: bool,
157
+ skip_timeline: bool,
152
158
  ) -> Union[
153
159
  "ChatResult",
154
160
  list["ChatResult"],
@@ -246,6 +252,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
246
252
  output_file: Path,
247
253
  uploads_root: Path | None,
248
254
  skip_mmd: bool,
255
+ skip_timeline: bool,
249
256
  ) -> Union[
250
257
  "ChatResult",
251
258
  list["ChatResult"],
@@ -336,6 +343,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
336
343
  uploads_root: Path | None,
337
344
  temp_dir: Path,
338
345
  skip_mmd: bool,
346
+ skip_timeline: bool,
339
347
  ) -> None:
340
348
  super()._after_run(
341
349
  results=results,
@@ -343,6 +351,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
343
351
  uploads_root=uploads_root,
344
352
  temp_dir=temp_dir,
345
353
  skip_mmd=skip_mmd,
354
+ skip_timeline=skip_timeline,
346
355
  )
347
356
 
348
357
  # Clean up module reference
@@ -354,6 +363,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
354
363
  output_file: Path,
355
364
  uploads_root: Path | None,
356
365
  skip_mmd: bool = False,
366
+ skip_timeline: bool = False,
357
367
  ) -> None:
358
368
  """Start the Waldiez workflow."""
359
369
 
@@ -366,6 +376,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
366
376
  output_file=output_file,
367
377
  uploads_root=uploads_root,
368
378
  skip_mmd=skip_mmd,
379
+ skip_timeline=skip_timeline,
369
380
  )
370
381
  except Exception as e: # pylint: disable=broad-exception-caught
371
382
  self._last_exception = e
@@ -383,6 +394,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
383
394
  output_file: Path,
384
395
  uploads_root: Path | None,
385
396
  skip_mmd: bool = False,
397
+ skip_timeline: bool = False,
386
398
  ) -> None:
387
399
  """Start the Waldiez workflow asynchronously."""
388
400
 
@@ -394,6 +406,7 @@ class WaldiezImportRunner(WaldiezBaseRunner):
394
406
  output_file=output_file,
395
407
  uploads_root=uploads_root,
396
408
  skip_mmd=skip_mmd,
409
+ skip_timeline=skip_timeline,
397
410
  )
398
411
  except Exception as e: # pylint: disable=broad-exception-caught
399
412
  self._last_exception = e
@@ -5,11 +5,14 @@
5
5
  """Utilities for running code."""
6
6
 
7
7
  import datetime
8
+ import json
8
9
  import shutil
9
10
  from pathlib import Path
10
11
  from typing import Optional, Union
11
12
 
12
13
  from .gen_seq_diagram import generate_sequence_diagram
14
+ from .patch_io_stream import get_printer
15
+ from .timeline_processor import TimelineProcessor
13
16
 
14
17
 
15
18
  def after_run(
@@ -18,6 +21,7 @@ def after_run(
18
21
  flow_name: str,
19
22
  uploads_root: Optional[Path] = None,
20
23
  skip_mmd: bool = False,
24
+ skip_timeline: bool = False,
21
25
  ) -> None:
22
26
  """Actions to perform after running the flow.
23
27
 
@@ -34,25 +38,21 @@ def after_run(
34
38
  skip_mmd : bool, optional
35
39
  Whether to skip the mermaid sequence diagram generation,
36
40
  by default, False
41
+ skip_timeline : bool, optional
42
+ Whether to skip the timeline processing, by default False
37
43
  """
38
44
  if isinstance(output_file, str):
39
45
  output_file = Path(output_file)
40
46
  mmd_dir = output_file.parent if output_file else Path.cwd()
41
47
  if skip_mmd is False:
42
- events_csv_path = temp_dir / "logs" / "events.csv"
43
- if events_csv_path.exists():
44
- print("Generating mermaid sequence diagram...")
45
- mmd_path = temp_dir / f"{flow_name}.mmd"
46
- generate_sequence_diagram(events_csv_path, mmd_path)
47
- if (
48
- not output_file
49
- and mmd_path.exists()
50
- and mmd_path != mmd_dir / f"{flow_name}.mmd"
51
- ):
52
- try:
53
- shutil.copyfile(mmd_path, mmd_dir / f"{flow_name}.mmd")
54
- except BaseException: # pylint: disable=broad-exception-caught
55
- pass
48
+ _make_mermaid_diagram(
49
+ temp_dir=temp_dir,
50
+ output_file=output_file,
51
+ flow_name=flow_name,
52
+ mmd_dir=mmd_dir,
53
+ )
54
+ if skip_timeline is False:
55
+ _make_timeline_json(temp_dir=temp_dir)
56
56
  if output_file:
57
57
  destination_dir = output_file.parent
58
58
  destination_dir = (
@@ -71,6 +71,63 @@ def after_run(
71
71
  shutil.rmtree(temp_dir)
72
72
 
73
73
 
74
+ def _make_mermaid_diagram(
75
+ temp_dir: Path,
76
+ output_file: Optional[Union[str, Path]],
77
+ flow_name: str,
78
+ mmd_dir: Path,
79
+ ) -> None:
80
+ events_csv_path = temp_dir / "logs" / "events.csv"
81
+ if events_csv_path.exists():
82
+ print("Generating mermaid sequence diagram...")
83
+ mmd_path = temp_dir / f"{flow_name}.mmd"
84
+ generate_sequence_diagram(events_csv_path, mmd_path)
85
+ if (
86
+ not output_file
87
+ and mmd_path.exists()
88
+ and mmd_path != mmd_dir / f"{flow_name}.mmd"
89
+ ):
90
+ try:
91
+ shutil.copyfile(mmd_path, mmd_dir / f"{flow_name}.mmd")
92
+ except BaseException: # pylint: disable=broad-exception-caught
93
+ pass
94
+
95
+
96
+ def _make_timeline_json(
97
+ temp_dir: Path,
98
+ ) -> None:
99
+ """Make the timeline JSON file."""
100
+ events_csv_path = temp_dir / "logs" / "events.csv"
101
+ if events_csv_path.exists():
102
+ print("Processing timeline...")
103
+ log_files = TimelineProcessor.get_files(temp_dir / "logs")
104
+ if any(log_files.values()):
105
+ output_file = temp_dir / "timeline.json"
106
+ # pylint: disable=too-many-try-statements
107
+ try:
108
+ processor = TimelineProcessor()
109
+ processor.load_csv_files(
110
+ agents_file=log_files["agents"],
111
+ chat_file=log_files["chat"],
112
+ events_file=log_files["events"],
113
+ functions_file=log_files["functions"],
114
+ )
115
+ results = processor.process_timeline()
116
+ with open(output_file, "w", encoding="utf-8") as f:
117
+ json.dump(results, f, indent=2, default=str)
118
+ short_results = TimelineProcessor.get_short_results(results)
119
+ printer = get_printer()
120
+ printer(
121
+ json.dumps(
122
+ {"type": "timeline", "content": short_results},
123
+ default=str,
124
+ ),
125
+ flush=True,
126
+ )
127
+ except BaseException: # pylint: disable=broad-exception-caught
128
+ pass
129
+
130
+
74
131
  def copy_results(
75
132
  temp_dir: Path,
76
133
  output_file: Path,
@@ -15,6 +15,7 @@ from .utils import strip_ansi
15
15
 
16
16
  def install_requirements(
17
17
  extra_requirements: set[str],
18
+ upgrade: bool = False,
18
19
  printer: Callable[..., None] = print,
19
20
  ) -> None:
20
21
  """Install the requirements.
@@ -23,6 +24,8 @@ def install_requirements(
23
24
  ----------
24
25
  extra_requirements : set[str]
25
26
  The extra requirements.
27
+ upgrade : bool, optional
28
+ Whether to upgrade the requirements, by default False.
26
29
  printer : Callable[..., None]
27
30
  The printer function to use, defaults to print.
28
31
  """
@@ -38,6 +41,8 @@ def install_requirements(
38
41
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
39
42
  if not is_root():
40
43
  pip_install.append("--user")
44
+ if upgrade:
45
+ pip_install.append("--upgrade")
41
46
  pip_install.extend(extra_requirements)
42
47
  # pylint: disable=too-many-try-statements
43
48
  try:
@@ -63,6 +68,7 @@ def install_requirements(
63
68
 
64
69
  async def a_install_requirements(
65
70
  extra_requirements: set[str],
71
+ upgrade: bool = False,
66
72
  printer: Callable[..., None] = print,
67
73
  ) -> None:
68
74
  """Install the requirements asynchronously.
@@ -71,6 +77,8 @@ async def a_install_requirements(
71
77
  ----------
72
78
  extra_requirements : set[str]
73
79
  The extra requirements.
80
+ upgrade : bool, optional
81
+ Whether to upgrade the requirements, by default False.
74
82
  printer : Callable[..., None]
75
83
  The printer function to use, defaults to print.
76
84
  """
@@ -83,6 +91,8 @@ async def a_install_requirements(
83
91
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
84
92
  if not is_root():
85
93
  pip_install.extend(["--user"])
94
+ if upgrade:
95
+ pip_install.append("--upgrade")
86
96
  pip_install.extend(extra_requirements)
87
97
  # pylint: disable=too-many-try-statements
88
98
  try:
@@ -103,3 +113,35 @@ async def a_install_requirements(
103
113
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
104
114
  else:
105
115
  del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
116
+
117
+
118
+ def install_waldiez(
119
+ upgrade: bool = True,
120
+ printer: Callable[..., None] = print,
121
+ ) -> None:
122
+ """Install Waldiez.
123
+
124
+ Parameters
125
+ ----------
126
+ upgrade : bool, optional
127
+ Whether to upgrade Waldiez, by default True.
128
+ printer : Callable[..., None]
129
+ The printer function to use, defaults to print.
130
+ """
131
+ install_requirements({"waldiez"}, upgrade, printer)
132
+
133
+
134
+ async def a_install_waldiez(
135
+ upgrade: bool = True,
136
+ printer: Callable[..., None] = print,
137
+ ) -> None:
138
+ """Install Waldiez asynchronously.
139
+
140
+ Parameters
141
+ ----------
142
+ upgrade : bool, optional
143
+ Whether to upgrade Waldiez, by default True.
144
+ printer : Callable[..., None]
145
+ The printer function to use, defaults to print.
146
+ """
147
+ await a_install_requirements({"waldiez"}, upgrade, printer)
@@ -204,6 +204,7 @@ class WaldiezRunnerProtocol(Protocol):
204
204
  uploads_root: Path | None,
205
205
  temp_dir: Path,
206
206
  skip_mmd: bool,
207
+ skip_timeline: bool,
207
208
  ) -> None:
208
209
  """Actions to perform after running the flow.
209
210
 
@@ -221,6 +222,8 @@ class WaldiezRunnerProtocol(Protocol):
221
222
  The path to the temporary directory.
222
223
  skip_mmd : bool
223
224
  Whether to skip generating the mermaid diagram.
225
+ skip_timeline : bool
226
+ Whether to skip generating the timeline JSON.
224
227
  """
225
228
 
226
229
  async def a_after_run(
@@ -234,6 +237,7 @@ class WaldiezRunnerProtocol(Protocol):
234
237
  uploads_root: Path | None,
235
238
  temp_dir: Path,
236
239
  skip_mmd: bool,
240
+ skip_timeline: bool,
237
241
  ) -> None:
238
242
  """Asynchronously perform actions after running the flow.
239
243
 
@@ -251,6 +255,8 @@ class WaldiezRunnerProtocol(Protocol):
251
255
  The path to the temporary directory.
252
256
  skip_mmd : bool
253
257
  Whether to skip generating the mermaid diagram.
258
+ skip_timeline : bool
259
+ Whether to skip generating the timeline JSON.
254
260
  """
255
261
 
256
262
  def is_running(self) -> bool: # pyright: ignore
@@ -49,6 +49,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
49
49
  output_file: Path,
50
50
  uploads_root: Path | None,
51
51
  skip_mmd: bool,
52
+ skip_timeline: bool,
52
53
  ) -> Union[
53
54
  "ChatResult",
54
55
  list["ChatResult"],
@@ -63,6 +64,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
63
64
  output_file: Path,
64
65
  uploads_root: Path | None,
65
66
  skip_mmd: bool,
67
+ skip_timeline: bool,
66
68
  ) -> Union[
67
69
  "ChatResult",
68
70
  list["ChatResult"],
@@ -77,6 +79,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
77
79
  output_file: Path,
78
80
  uploads_root: Path | None,
79
81
  skip_mmd: bool,
82
+ skip_timeline: bool,
80
83
  ) -> None:
81
84
  """Start the Waldiez workflow."""
82
85
  # This method should be implemented to start the workflow
@@ -88,6 +91,7 @@ class WaldiezSubprocessRunner(WaldiezBaseRunner):
88
91
  output_file: Path,
89
92
  uploads_root: Path | None,
90
93
  skip_mmd: bool,
94
+ skip_timeline: bool,
91
95
  ) -> None:
92
96
  """Start the Waldiez workflow asynchronously."""
93
97
  # This method should be implemented to start the workflow asynchronously