waldiez 0.4.7__py3-none-any.whl → 0.4.9__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 (248) hide show
  1. waldiez/__init__.py +5 -5
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +97 -102
  4. waldiez/exporter.py +61 -19
  5. waldiez/exporting/__init__.py +25 -6
  6. waldiez/exporting/agent/__init__.py +7 -3
  7. waldiez/exporting/agent/code_execution.py +114 -0
  8. waldiez/exporting/agent/exporter.py +354 -0
  9. waldiez/exporting/agent/extras/__init__.py +15 -0
  10. waldiez/exporting/agent/extras/captain_agent_extras.py +315 -0
  11. waldiez/exporting/agent/extras/group/target.py +178 -0
  12. waldiez/exporting/agent/extras/group_manager_agent_extas.py +500 -0
  13. waldiez/exporting/agent/extras/group_member_extras.py +181 -0
  14. waldiez/exporting/agent/extras/handoffs/__init__.py +19 -0
  15. waldiez/exporting/agent/extras/handoffs/after_work.py +78 -0
  16. waldiez/exporting/agent/extras/handoffs/available.py +74 -0
  17. waldiez/exporting/agent/extras/handoffs/condition.py +158 -0
  18. waldiez/exporting/agent/extras/handoffs/handoff.py +171 -0
  19. waldiez/exporting/agent/extras/handoffs/target.py +189 -0
  20. waldiez/exporting/agent/extras/rag/__init__.py +10 -0
  21. waldiez/exporting/agent/{utils/rag_user/chroma_utils.py → extras/rag/chroma_extras.py} +37 -24
  22. waldiez/exporting/agent/{utils/rag_user/mongo_utils.py → extras/rag/mongo_extras.py} +10 -10
  23. waldiez/exporting/agent/{utils/rag_user/pgvector_utils.py → extras/rag/pgvector_extras.py} +13 -13
  24. waldiez/exporting/agent/{utils/rag_user/qdrant_utils.py → extras/rag/qdrant_extras.py} +13 -13
  25. waldiez/exporting/agent/{utils/rag_user/vector_db.py → extras/rag/vector_db_extras.py} +59 -46
  26. waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +245 -0
  27. waldiez/exporting/agent/extras/reasoning_agent_extras.py +88 -0
  28. waldiez/exporting/agent/factory.py +95 -0
  29. waldiez/exporting/agent/processor.py +150 -0
  30. waldiez/exporting/agent/system_message.py +36 -0
  31. waldiez/exporting/agent/termination.py +50 -0
  32. waldiez/exporting/chats/__init__.py +7 -3
  33. waldiez/exporting/chats/exporter.py +97 -0
  34. waldiez/exporting/chats/factory.py +65 -0
  35. waldiez/exporting/chats/processor.py +226 -0
  36. waldiez/exporting/chats/utils/__init__.py +6 -5
  37. waldiez/exporting/chats/utils/common.py +11 -45
  38. waldiez/exporting/chats/utils/group.py +55 -0
  39. waldiez/exporting/chats/utils/nested.py +37 -52
  40. waldiez/exporting/chats/utils/sequential.py +72 -61
  41. waldiez/exporting/chats/utils/{single_chat.py → single.py} +48 -50
  42. waldiez/exporting/core/__init__.py +196 -0
  43. waldiez/exporting/core/constants.py +17 -0
  44. waldiez/exporting/core/content.py +69 -0
  45. waldiez/exporting/core/context.py +244 -0
  46. waldiez/exporting/core/enums.py +89 -0
  47. waldiez/exporting/core/errors.py +19 -0
  48. waldiez/exporting/core/exporter.py +390 -0
  49. waldiez/exporting/core/exporters.py +67 -0
  50. waldiez/exporting/core/extras/__init__.py +39 -0
  51. waldiez/exporting/core/extras/agent_extras/__init__.py +27 -0
  52. waldiez/exporting/core/extras/agent_extras/captain_extras.py +57 -0
  53. waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +102 -0
  54. waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +53 -0
  55. waldiez/exporting/core/extras/agent_extras/reasoning_extras.py +68 -0
  56. waldiez/exporting/core/extras/agent_extras/standard_extras.py +263 -0
  57. waldiez/exporting/core/extras/base.py +241 -0
  58. waldiez/exporting/core/extras/chat_extras.py +118 -0
  59. waldiez/exporting/core/extras/flow_extras.py +70 -0
  60. waldiez/exporting/core/extras/model_extras.py +73 -0
  61. waldiez/exporting/core/extras/path_resolver.py +93 -0
  62. waldiez/exporting/core/extras/serializer.py +138 -0
  63. waldiez/exporting/core/extras/tool_extras.py +82 -0
  64. waldiez/exporting/core/protocols.py +259 -0
  65. waldiez/exporting/core/result.py +705 -0
  66. waldiez/exporting/core/types.py +329 -0
  67. waldiez/exporting/core/utils/__init__.py +11 -0
  68. waldiez/exporting/core/utils/comment.py +33 -0
  69. waldiez/exporting/core/utils/llm_config.py +117 -0
  70. waldiez/exporting/core/validation.py +96 -0
  71. waldiez/exporting/flow/__init__.py +6 -2
  72. waldiez/exporting/flow/execution_generator.py +193 -0
  73. waldiez/exporting/flow/exporter.py +107 -0
  74. waldiez/exporting/flow/factory.py +94 -0
  75. waldiez/exporting/flow/file_generator.py +214 -0
  76. waldiez/exporting/flow/merger.py +387 -0
  77. waldiez/exporting/flow/orchestrator.py +411 -0
  78. waldiez/exporting/flow/utils/__init__.py +9 -36
  79. waldiez/exporting/flow/utils/common.py +206 -0
  80. waldiez/exporting/flow/utils/importing.py +373 -0
  81. waldiez/exporting/flow/utils/linting.py +200 -0
  82. waldiez/exporting/flow/utils/{logging_utils.py → logging.py} +23 -9
  83. waldiez/exporting/models/__init__.py +3 -1
  84. waldiez/exporting/models/exporter.py +233 -0
  85. waldiez/exporting/models/factory.py +66 -0
  86. waldiez/exporting/models/processor.py +139 -0
  87. waldiez/exporting/tools/__init__.py +11 -0
  88. waldiez/exporting/tools/exporter.py +207 -0
  89. waldiez/exporting/tools/factory.py +57 -0
  90. waldiez/exporting/tools/processor.py +248 -0
  91. waldiez/exporting/tools/registration.py +133 -0
  92. waldiez/io/__init__.py +128 -0
  93. waldiez/io/_ws.py +199 -0
  94. waldiez/io/models/__init__.py +60 -0
  95. waldiez/io/models/base.py +66 -0
  96. waldiez/io/models/constants.py +78 -0
  97. waldiez/io/models/content/__init__.py +23 -0
  98. waldiez/io/models/content/audio.py +43 -0
  99. waldiez/io/models/content/base.py +45 -0
  100. waldiez/io/models/content/file.py +43 -0
  101. waldiez/io/models/content/image.py +96 -0
  102. waldiez/io/models/content/text.py +37 -0
  103. waldiez/io/models/content/video.py +43 -0
  104. waldiez/io/models/user_input.py +269 -0
  105. waldiez/io/models/user_response.py +215 -0
  106. waldiez/io/mqtt.py +681 -0
  107. waldiez/io/redis.py +782 -0
  108. waldiez/io/structured.py +439 -0
  109. waldiez/io/utils.py +184 -0
  110. waldiez/io/ws.py +298 -0
  111. waldiez/logger.py +481 -0
  112. waldiez/models/__init__.py +108 -51
  113. waldiez/models/agents/__init__.py +34 -70
  114. waldiez/models/agents/agent/__init__.py +10 -4
  115. waldiez/models/agents/agent/agent.py +466 -65
  116. waldiez/models/agents/agent/agent_data.py +119 -47
  117. waldiez/models/agents/agent/agent_type.py +13 -2
  118. waldiez/models/agents/agent/code_execution.py +12 -12
  119. waldiez/models/agents/agent/human_input_mode.py +8 -0
  120. waldiez/models/agents/agent/{linked_skill.py → linked_tool.py} +7 -7
  121. waldiez/models/agents/agent/nested_chat.py +35 -7
  122. waldiez/models/agents/agent/termination_message.py +30 -22
  123. waldiez/models/agents/{swarm_agent → agent}/update_system_message.py +22 -22
  124. waldiez/models/agents/agents.py +58 -63
  125. waldiez/models/agents/assistant/assistant.py +4 -4
  126. waldiez/models/agents/assistant/assistant_data.py +13 -1
  127. waldiez/models/agents/{captain_agent → captain}/captain_agent.py +5 -5
  128. waldiez/models/agents/{captain_agent → captain}/captain_agent_data.py +5 -5
  129. waldiez/models/agents/extra_requirements.py +11 -16
  130. waldiez/models/agents/group_manager/group_manager.py +103 -13
  131. waldiez/models/agents/group_manager/group_manager_data.py +36 -14
  132. waldiez/models/agents/group_manager/speakers.py +77 -24
  133. waldiez/models/agents/{rag_user → rag_user_proxy}/__init__.py +16 -16
  134. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +64 -0
  135. waldiez/models/agents/{rag_user/rag_user_data.py → rag_user_proxy/rag_user_proxy_data.py} +6 -5
  136. waldiez/models/agents/{rag_user → rag_user_proxy}/retrieve_config.py +182 -114
  137. waldiez/models/agents/{rag_user → rag_user_proxy}/vector_db_config.py +13 -13
  138. waldiez/models/agents/reasoning/reasoning_agent.py +6 -6
  139. waldiez/models/agents/reasoning/reasoning_agent_data.py +110 -63
  140. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +38 -10
  141. waldiez/models/agents/user_proxy/user_proxy.py +11 -7
  142. waldiez/models/agents/user_proxy/user_proxy_data.py +2 -2
  143. waldiez/models/chat/__init__.py +2 -1
  144. waldiez/models/chat/chat.py +166 -87
  145. waldiez/models/chat/chat_data.py +99 -136
  146. waldiez/models/chat/chat_message.py +33 -23
  147. waldiez/models/chat/chat_nested.py +31 -30
  148. waldiez/models/chat/chat_summary.py +10 -8
  149. waldiez/models/common/__init__.py +52 -2
  150. waldiez/models/common/ag2_version.py +1 -1
  151. waldiez/models/common/base.py +38 -7
  152. waldiez/models/common/dict_utils.py +42 -17
  153. waldiez/models/common/handoff.py +459 -0
  154. waldiez/models/common/id_generator.py +19 -0
  155. waldiez/models/common/method_utils.py +130 -68
  156. waldiez/{exporting/base/utils → models/common}/naming.py +38 -61
  157. waldiez/models/common/waldiez_version.py +37 -0
  158. waldiez/models/flow/__init__.py +9 -2
  159. waldiez/models/flow/connection.py +18 -0
  160. waldiez/models/flow/flow.py +311 -215
  161. waldiez/models/flow/flow_data.py +207 -40
  162. waldiez/models/flow/info.py +85 -0
  163. waldiez/models/flow/naming.py +131 -0
  164. waldiez/models/model/__init__.py +7 -1
  165. waldiez/models/model/extra_requirements.py +3 -12
  166. waldiez/models/model/model.py +76 -21
  167. waldiez/models/model/model_data.py +108 -20
  168. waldiez/models/tool/__init__.py +16 -0
  169. waldiez/models/tool/extra_requirements.py +36 -0
  170. waldiez/models/{skill/skill.py → tool/tool.py} +88 -88
  171. waldiez/models/tool/tool_data.py +51 -0
  172. waldiez/models/tool/tool_type.py +8 -0
  173. waldiez/models/waldiez.py +97 -80
  174. waldiez/runner.py +115 -61
  175. waldiez/running/__init__.py +13 -7
  176. waldiez/running/environment.py +49 -68
  177. waldiez/running/gen_seq_diagram.py +16 -14
  178. waldiez/running/post_run.py +119 -0
  179. waldiez/running/pre_run.py +149 -0
  180. waldiez/running/util.py +134 -0
  181. waldiez/utils/__init__.py +2 -4
  182. waldiez/utils/cli_extras/jupyter.py +5 -3
  183. waldiez/utils/cli_extras/runner.py +6 -4
  184. waldiez/utils/cli_extras/studio.py +6 -4
  185. waldiez/utils/conflict_checker.py +15 -9
  186. waldiez/utils/flaml_warnings.py +5 -5
  187. waldiez/utils/version.py +47 -0
  188. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/METADATA +235 -91
  189. waldiez-0.4.9.dist-info/RECORD +203 -0
  190. waldiez/exporting/agent/agent_exporter.py +0 -297
  191. waldiez/exporting/agent/utils/__init__.py +0 -23
  192. waldiez/exporting/agent/utils/captain_agent.py +0 -263
  193. waldiez/exporting/agent/utils/code_execution.py +0 -65
  194. waldiez/exporting/agent/utils/group_manager.py +0 -220
  195. waldiez/exporting/agent/utils/rag_user/__init__.py +0 -7
  196. waldiez/exporting/agent/utils/rag_user/rag_user.py +0 -209
  197. waldiez/exporting/agent/utils/reasoning.py +0 -36
  198. waldiez/exporting/agent/utils/swarm_agent.py +0 -469
  199. waldiez/exporting/agent/utils/teachability.py +0 -41
  200. waldiez/exporting/agent/utils/termination_message.py +0 -44
  201. waldiez/exporting/base/__init__.py +0 -25
  202. waldiez/exporting/base/agent_position.py +0 -75
  203. waldiez/exporting/base/base_exporter.py +0 -118
  204. waldiez/exporting/base/export_position.py +0 -48
  205. waldiez/exporting/base/import_position.py +0 -23
  206. waldiez/exporting/base/mixin.py +0 -137
  207. waldiez/exporting/base/utils/__init__.py +0 -18
  208. waldiez/exporting/base/utils/comments.py +0 -96
  209. waldiez/exporting/base/utils/path_check.py +0 -68
  210. waldiez/exporting/base/utils/to_string.py +0 -84
  211. waldiez/exporting/chats/chats_exporter.py +0 -240
  212. waldiez/exporting/chats/utils/swarm.py +0 -210
  213. waldiez/exporting/flow/flow_exporter.py +0 -528
  214. waldiez/exporting/flow/utils/agent_utils.py +0 -204
  215. waldiez/exporting/flow/utils/chat_utils.py +0 -71
  216. waldiez/exporting/flow/utils/def_main.py +0 -77
  217. waldiez/exporting/flow/utils/flow_content.py +0 -202
  218. waldiez/exporting/flow/utils/flow_names.py +0 -116
  219. waldiez/exporting/flow/utils/importing_utils.py +0 -227
  220. waldiez/exporting/models/models_exporter.py +0 -199
  221. waldiez/exporting/models/utils.py +0 -174
  222. waldiez/exporting/skills/__init__.py +0 -9
  223. waldiez/exporting/skills/skills_exporter.py +0 -176
  224. waldiez/exporting/skills/utils.py +0 -369
  225. waldiez/models/agents/agent/teachability.py +0 -70
  226. waldiez/models/agents/rag_user/rag_user.py +0 -60
  227. waldiez/models/agents/swarm_agent/__init__.py +0 -50
  228. waldiez/models/agents/swarm_agent/after_work.py +0 -179
  229. waldiez/models/agents/swarm_agent/on_condition.py +0 -105
  230. waldiez/models/agents/swarm_agent/on_condition_available.py +0 -142
  231. waldiez/models/agents/swarm_agent/on_condition_target.py +0 -40
  232. waldiez/models/agents/swarm_agent/swarm_agent.py +0 -107
  233. waldiez/models/agents/swarm_agent/swarm_agent_data.py +0 -124
  234. waldiez/models/flow/utils.py +0 -232
  235. waldiez/models/skill/__init__.py +0 -16
  236. waldiez/models/skill/extra_requirements.py +0 -36
  237. waldiez/models/skill/skill_data.py +0 -53
  238. waldiez/models/skill/skill_type.py +0 -8
  239. waldiez/running/running.py +0 -369
  240. waldiez/utils/pysqlite3_checker.py +0 -308
  241. waldiez/utils/rdps_checker.py +0 -122
  242. waldiez-0.4.7.dist-info/RECORD +0 -149
  243. /waldiez/models/agents/{captain_agent → captain}/__init__.py +0 -0
  244. /waldiez/models/agents/{captain_agent → captain}/captain_agent_lib_entry.py +0 -0
  245. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/WHEEL +0 -0
  246. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/entry_points.txt +0 -0
  247. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/licenses/LICENSE +0 -0
  248. {waldiez-0.4.7.dist-info → waldiez-0.4.9.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,193 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Generates the main() and call_main() functions."""
4
+
5
+ # pylint: disable=no-self-use,unused-argument
6
+
7
+ from ..core import get_comment
8
+ from .utils.common import RETURN_TYPE_HINT, main_doc_string
9
+
10
+
11
+ class ExecutionGenerator:
12
+ """Generate the main function and its calling block for flow exporter."""
13
+
14
+ @staticmethod
15
+ def generate(
16
+ content: str,
17
+ is_async: bool,
18
+ for_notebook: bool,
19
+ cache_seed: int | None,
20
+ after_run: str,
21
+ ) -> str:
22
+ """Generate the complete flow script content.
23
+
24
+ Parameters
25
+ ----------
26
+ content : str
27
+ The content of the chats to be included in the main function.
28
+ is_async : bool
29
+ Whether to generate async content.
30
+ for_notebook : bool
31
+ Whether the export is intended for a notebook environment.
32
+ cache_seed : str | int | None
33
+ The cache seed to use for flow chat if any.
34
+ after_run : str, optional
35
+ Additional content to add after the main chat execution,
36
+ by default ""
37
+
38
+ Returns
39
+ -------
40
+ str
41
+ The complete flow script content.
42
+ """
43
+ main_function = ExecutionGenerator.generate_main_function(
44
+ content=content,
45
+ is_async=is_async,
46
+ cache_seed=cache_seed,
47
+ after_run=after_run,
48
+ for_notebook=for_notebook,
49
+ )
50
+ call_main_function = ExecutionGenerator.generate_call_main_function(
51
+ is_async=is_async,
52
+ for_notebook=for_notebook,
53
+ )
54
+ if not for_notebook:
55
+ execution_block = ExecutionGenerator.generate_execution_block(
56
+ is_async=is_async,
57
+ )
58
+ else:
59
+ execution_block = ""
60
+ return (
61
+ "\n".join([main_function, call_main_function, execution_block])
62
+ + "\n"
63
+ )
64
+
65
+ @staticmethod
66
+ def generate_main_function(
67
+ content: str,
68
+ is_async: bool,
69
+ cache_seed: int | None,
70
+ after_run: str,
71
+ for_notebook: bool,
72
+ ) -> str:
73
+ """Generate the main function for the flow script.
74
+
75
+ Parameters
76
+ ----------
77
+ content : str
78
+ The content of the chats to be included in the main function.
79
+ is_async : bool
80
+ Whether to generate async content
81
+ cache_seed : str | int | None
82
+ The cache seed to use for flow chat if any
83
+ after_run : str
84
+ Additional content to add after the main chat execution.
85
+ for_notebook : bool
86
+ Whether the export is intended for a notebook environment.
87
+
88
+ Returns
89
+ -------
90
+ str
91
+ The complete main function content.
92
+ """
93
+ if content.startswith("\n"):
94
+ content = content[1:]
95
+ flow_content = "\n\n"
96
+ comment = get_comment(
97
+ "Start chatting",
98
+ for_notebook=for_notebook,
99
+ )
100
+ flow_content += f"{comment}\n"
101
+ if is_async:
102
+ flow_content += "async "
103
+
104
+ flow_content += f"def main() -> {RETURN_TYPE_HINT}:\n"
105
+ flow_content += f" {main_doc_string()}\n"
106
+ space = " "
107
+ if cache_seed is not None:
108
+ flow_content += (
109
+ f" with Cache.disk(cache_seed={cache_seed}"
110
+ ") as cache: # pyright: ignore\n"
111
+ )
112
+ space = f"{space} "
113
+ flow_content += f"{content}" + "\n"
114
+ if is_async:
115
+ flow_content += f"{space}await stop_logging()"
116
+ else:
117
+ flow_content += f"{space}stop_logging()"
118
+ flow_content += "\n"
119
+ if after_run:
120
+ flow_content += after_run + "\n"
121
+ if cache_seed is not None:
122
+ space = space[4:]
123
+ flow_content += f"{space}return results\n"
124
+ return flow_content
125
+
126
+ @staticmethod
127
+ def generate_call_main_function(is_async: bool, for_notebook: bool) -> str:
128
+ """Generate the call_main function for the flow script.
129
+
130
+ Parameters
131
+ ----------
132
+ is_async : bool
133
+ Whether to generate async content
134
+ for_notebook : bool
135
+ Whether the export is intended for a notebook environment.
136
+
137
+ Returns
138
+ -------
139
+ str
140
+ The complete call_main function content.
141
+ """
142
+ content = "\n"
143
+ if for_notebook:
144
+ if is_async:
145
+ return "# %%\nawait main()\n"
146
+ return "# %%\nmain()\n"
147
+ if is_async:
148
+ content += "async def call_main() -> None:\n"
149
+ else:
150
+ content += "def call_main() -> None:\n"
151
+ content += ' """Run the main function and print the results."""\n'
152
+ content += f" results: {RETURN_TYPE_HINT} = "
153
+ if is_async:
154
+ content += "await "
155
+ content += "main()\n"
156
+ content += " if isinstance(results, dict):\n"
157
+ content += " # order by key\n"
158
+ content += " ordered_results = dict(sorted(results.items()))\n"
159
+ content += " for _, result in ordered_results.items():\n"
160
+ content += " pprint(asdict(result))\n"
161
+ content += " else:\n"
162
+ content += " if not isinstance(results, list):\n"
163
+ content += " results = [results]\n"
164
+ content += " for result in results:\n"
165
+ content += " pprint(asdict(result))\n"
166
+ content += "\n"
167
+ return content
168
+
169
+ @staticmethod
170
+ def generate_execution_block(is_async: bool) -> str:
171
+ """Generate the execution block for the main function.
172
+
173
+ Parameters
174
+ ----------
175
+ is_async : bool
176
+ Whether to generate async content
177
+
178
+ Returns
179
+ -------
180
+ str
181
+ The complete if __name__ == "__main__": block content
182
+ """
183
+ comment = get_comment(
184
+ "Let's go!",
185
+ for_notebook=False,
186
+ )
187
+ content = 'if __name__ == "__main__":\n'
188
+ content += f" {comment}"
189
+ if is_async:
190
+ content += " anyio.run(call_main)\n"
191
+ else:
192
+ content += " call_main()\n"
193
+ return content
@@ -0,0 +1,107 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Flow exporter."""
4
+
5
+ from pathlib import Path
6
+ from typing import Any, Optional
7
+
8
+ from waldiez.models import Waldiez
9
+
10
+ from ..core import Exporter, ExporterContext
11
+ from ..core.extras import FlowExtras
12
+ from .file_generator import FileGenerator
13
+ from .orchestrator import ExportOrchestrator
14
+
15
+
16
+ class FlowExporter(Exporter[FlowExtras]):
17
+ """Flow exporter."""
18
+
19
+ def __init__(
20
+ self,
21
+ waldiez: Waldiez,
22
+ output_dir: Path | None,
23
+ for_notebook: bool,
24
+ context: Optional[ExporterContext] = None,
25
+ **kwargs: Any,
26
+ ) -> None:
27
+ """Initialize the chats exporter.
28
+
29
+ Parameters
30
+ ----------
31
+ waldiez : Waldiez
32
+ The Waldiez instance containing the flow data.
33
+ output_dir : Path
34
+ The directory where the exported flow will be saved.
35
+ for_notebook : bool
36
+ Whether the export is intended for a notebook environment.
37
+ context : Optional[ExporterContext], optional
38
+ Exporter context with dependencies, by default None
39
+ **kwargs : Any
40
+ Additional keyword arguments for the exporter.
41
+ """
42
+ super().__init__(context, **kwargs)
43
+
44
+ self.waldiez = waldiez
45
+ self.output_dir = Path(output_dir) if output_dir is not None else None
46
+ self.flow_config = self.context.get_config(
47
+ name=waldiez.name,
48
+ description=waldiez.description,
49
+ requirements=waldiez.requirements or [],
50
+ tags=waldiez.tags or [],
51
+ output_extension="ipynb" if for_notebook else "py",
52
+ is_async=waldiez.is_async,
53
+ output_directory=str(self.output_dir) if self.output_dir else None,
54
+ cache_seed=waldiez.cache_seed,
55
+ )
56
+ self._extras = self._generate_extras()
57
+
58
+ @property
59
+ def extras(self) -> FlowExtras:
60
+ """Get the flow exporter extras.
61
+
62
+ Returns
63
+ -------
64
+ dict[str, Any]
65
+ The extras dictionary containing additional
66
+ information for the flow exporter.
67
+ """
68
+ return self._extras
69
+
70
+ def _generate_extras(self) -> FlowExtras:
71
+ """Generate the extras for the flow exporter.
72
+
73
+ Returns
74
+ -------
75
+ BaseExtras
76
+ An instance of BaseExtras containing the generated content.
77
+ """
78
+ extras = FlowExtras(
79
+ instance_id=self.waldiez.id,
80
+ flow_name=self.waldiez.name,
81
+ description=self.waldiez.description or "",
82
+ config=self.flow_config,
83
+ )
84
+ return extras
85
+
86
+ def generate_main_content(self) -> str:
87
+ """Generate the main content of the export.
88
+
89
+ Returns
90
+ -------
91
+ str
92
+ The final executable script or notebook content.
93
+ """
94
+ orchestrator = ExportOrchestrator(
95
+ waldiez=self.waldiez,
96
+ context=self.context,
97
+ )
98
+ merged_result = orchestrator.orchestrate()
99
+ after_run = orchestrator.get_after_run_content()
100
+ generator = FileGenerator(
101
+ context=self.context,
102
+ )
103
+ return generator.generate(
104
+ merged_result=merged_result,
105
+ is_async=self.waldiez.is_async,
106
+ after_run=after_run,
107
+ )
@@ -0,0 +1,94 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Factory function for creating a FlowExporter instance."""
4
+
5
+ from pathlib import Path
6
+ from typing import Any, Optional
7
+
8
+ from waldiez.logger import WaldiezLogger
9
+ from waldiez.models import Waldiez
10
+
11
+ from ..core import (
12
+ DefaultPathResolver,
13
+ DefaultSerializer,
14
+ ExportConfig,
15
+ ExporterContext,
16
+ )
17
+ from .exporter import FlowExporter
18
+
19
+
20
+ def create_flow_exporter(
21
+ waldiez: Waldiez,
22
+ output_dir: Path | None,
23
+ for_notebook: bool,
24
+ context: Optional[ExporterContext] = None,
25
+ **kwargs: Any,
26
+ ) -> FlowExporter:
27
+ """Create a flow exporter.
28
+
29
+ Parameters
30
+ ----------
31
+ waldiez : Waldiez
32
+ The Waldiez instance containing the flow data.
33
+ output_dir : Path
34
+ The directory where the exported flow will be saved.
35
+ for_notebook : bool
36
+ Whether the export is intended for a notebook environment.
37
+ context : Optional[ExporterContext], optional
38
+ Exporter context with dependencies, by default None
39
+ **kwargs : Any
40
+ Additional keyword arguments for the exporter.
41
+
42
+ Returns
43
+ -------
44
+ ChatsExporter
45
+ The created chats exporter.
46
+ """
47
+ if context is None:
48
+ config = ExportConfig(
49
+ name=waldiez.name,
50
+ description=waldiez.description or "",
51
+ tags=waldiez.tags or [],
52
+ requirements=waldiez.requirements or [],
53
+ output_extension="ipynb" if for_notebook else "py",
54
+ is_async=waldiez.is_async,
55
+ output_directory=output_dir,
56
+ cache_seed=waldiez.cache_seed,
57
+ )
58
+ context = ExporterContext(
59
+ config=config,
60
+ serializer=DefaultSerializer(),
61
+ path_resolver=DefaultPathResolver(),
62
+ logger=WaldiezLogger(),
63
+ )
64
+ else:
65
+ if not context.config: # pragma: no cover
66
+ context.config = ExportConfig(
67
+ name=waldiez.name,
68
+ description=waldiez.description or "",
69
+ tags=waldiez.tags or [],
70
+ requirements=waldiez.requirements or [],
71
+ output_extension="ipynb" if for_notebook else "py",
72
+ is_async=waldiez.is_async,
73
+ output_directory=output_dir,
74
+ cache_seed=waldiez.cache_seed,
75
+ )
76
+ else:
77
+ context.config.update(
78
+ name=waldiez.name,
79
+ description=waldiez.description or "",
80
+ tags=waldiez.tags or [],
81
+ requirements=waldiez.requirements or [],
82
+ output_extension="ipynb" if for_notebook else "py",
83
+ is_async=waldiez.is_async,
84
+ output_directory=output_dir,
85
+ cache_seed=waldiez.cache_seed,
86
+ )
87
+
88
+ return FlowExporter(
89
+ waldiez=waldiez,
90
+ output_dir=output_dir,
91
+ for_notebook=for_notebook,
92
+ context=context,
93
+ **kwargs,
94
+ )
@@ -0,0 +1,214 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Generate the whole folw content."""
4
+
5
+ from typing import Any
6
+
7
+ from ..core import (
8
+ ContentGenerator,
9
+ ExporterContentError,
10
+ ExporterContext,
11
+ ExportPosition,
12
+ ExportResult,
13
+ PositionedContent,
14
+ get_comment,
15
+ )
16
+ from .execution_generator import ExecutionGenerator
17
+ from .utils.common import generate_header
18
+
19
+
20
+ class FileGenerator(ContentGenerator):
21
+ """Generate the complete flow notebook content."""
22
+
23
+ def __init__(
24
+ self,
25
+ context: ExporterContext,
26
+ ) -> None:
27
+ """Initialize the notebook generator.
28
+
29
+ Parameters
30
+ ----------
31
+ context : ExporterContext
32
+ The exporter context containing dependencies.
33
+ """
34
+ self.context = context
35
+ self.config = context.get_config()
36
+
37
+ # pylint: disable=too-many-locals
38
+ def generate(
39
+ self,
40
+ merged_result: ExportResult,
41
+ is_async: bool,
42
+ after_run: str,
43
+ **kwargs: Any,
44
+ ) -> str:
45
+ """Generate the complete flow notebook content.
46
+
47
+ Parameters
48
+ ----------
49
+ merged_result : ExportResult
50
+ The merged export result containing all content.
51
+ is_async : bool
52
+ Whether to generate async conten
53
+ after_run : str
54
+ Additional content to add after the main flow execution.
55
+ **kwargs : Any
56
+ Additional keyword arguments for the generator.
57
+
58
+ Returns
59
+ -------
60
+ str
61
+ The complete flow notebook content.
62
+
63
+ Raises
64
+ ------
65
+ ExporterContentError
66
+ If there is no content to export.
67
+ """
68
+ # 1. Generate header
69
+ header = self.get_header(merged_result)
70
+
71
+ # 2. Generate imports
72
+ imports_section = merged_result.get_content_by_position(
73
+ ExportPosition.IMPORTS
74
+ )
75
+
76
+ # 3. Generate content sections
77
+ tools_section = merged_result.get_content_by_position(
78
+ ExportPosition.TOOLS
79
+ )
80
+ models_section = merged_result.get_content_by_position(
81
+ ExportPosition.MODELS
82
+ )
83
+ agents_section = merged_result.get_content_by_position(
84
+ ExportPosition.AGENTS,
85
+ # Skip agent arguments (should already be there)
86
+ skip_agent_arguments=True,
87
+ )
88
+ chats_content = merged_result.get_content_by_position(
89
+ ExportPosition.CHATS
90
+ )
91
+ if not chats_content:
92
+ raise ExporterContentError(
93
+ "No content to export. Please ensure that the flow has chats."
94
+ )
95
+ after_chats = merged_result.get_content_by_position(
96
+ ExportPosition.BOTTOM
97
+ )
98
+
99
+ main, call_main, execution_block = self._get_execution_content(
100
+ chats_content=chats_content,
101
+ is_async=is_async,
102
+ after_run=after_run,
103
+ for_notebook=self.config.for_notebook,
104
+ )
105
+
106
+ # 5. Combine everything
107
+ everything: list[str] = [header]
108
+ if imports_section:
109
+ comment = get_comment(
110
+ "Imports",
111
+ for_notebook=self.config.for_notebook,
112
+ )
113
+ everything.append(comment)
114
+ everything.append(
115
+ "\n".join([entry.content for entry in imports_section])
116
+ )
117
+ if tools_section:
118
+ comment = get_comment(
119
+ "Tools",
120
+ for_notebook=self.config.for_notebook,
121
+ )
122
+ everything.append(comment)
123
+ everything.append(
124
+ "\n".join([entry.content for entry in tools_section]) + "\n"
125
+ )
126
+ if models_section:
127
+ comment = get_comment(
128
+ "Models",
129
+ for_notebook=self.config.for_notebook,
130
+ )
131
+ everything.append(comment)
132
+ everything.append(
133
+ "\n\n".join([entry.content for entry in models_section]) + "\n"
134
+ )
135
+ if agents_section:
136
+ comment = get_comment(
137
+ "Agents",
138
+ for_notebook=self.config.for_notebook,
139
+ )
140
+ if self.config.for_notebook:
141
+ comment += "# pyright: reportUnnecessaryIsInstance=false\n"
142
+ everything.append(comment)
143
+ everything.append(
144
+ "\n\n".join([entry.content for entry in agents_section]) + "\n"
145
+ )
146
+ everything.append(main)
147
+ if after_chats:
148
+ everything.append(
149
+ "\n".join([entry.content for entry in after_chats])
150
+ )
151
+ everything.append(call_main)
152
+ if execution_block:
153
+ everything.append(execution_block)
154
+
155
+ return "\n".join(everything)
156
+
157
+ def _get_execution_content(
158
+ self,
159
+ chats_content: list[PositionedContent],
160
+ is_async: bool,
161
+ for_notebook: bool,
162
+ after_run: str,
163
+ ) -> tuple[str, str, str]:
164
+ cache_seed = (
165
+ self.context.config.cache_seed if self.context.config else None
166
+ )
167
+ execution_gen = ExecutionGenerator()
168
+ chat_contents = "\n".join(chat.content for chat in chats_content)
169
+ main = execution_gen.generate_main_function(
170
+ content=chat_contents,
171
+ is_async=is_async,
172
+ for_notebook=for_notebook,
173
+ cache_seed=cache_seed,
174
+ after_run=after_run,
175
+ )
176
+ call_main = execution_gen.generate_call_main_function(
177
+ is_async=is_async,
178
+ for_notebook=for_notebook,
179
+ )
180
+ execution_block = (
181
+ execution_gen.generate_execution_block(
182
+ is_async=is_async,
183
+ )
184
+ if not for_notebook
185
+ else ""
186
+ )
187
+ return main, call_main, execution_block
188
+
189
+ def get_header(self, merged_result: ExportResult) -> str:
190
+ """Get or generate the header for the script.
191
+
192
+ Parameters
193
+ ----------
194
+ merged_result : ExportResult
195
+ The merged export result containing all content.
196
+
197
+ Returns
198
+ -------
199
+ str
200
+ The header content.
201
+ """
202
+ from_result = merged_result.get_content_by_position(ExportPosition.TOP)
203
+ if not from_result:
204
+ return generate_header(
205
+ name=self.config.name,
206
+ description=self.config.description,
207
+ requirements=self.config.requirements,
208
+ tags=self.config.tags,
209
+ for_notebook=self.config.for_notebook,
210
+ )
211
+ header_string = "\n".join(content.content for content in from_result)
212
+ while not header_string.endswith("\n\n"):
213
+ header_string += "\n"
214
+ return header_string