waldiez 0.4.6__py3-none-any.whl → 0.4.8__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 (244) hide show
  1. waldiez/__init__.py +5 -5
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +112 -73
  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} +16 -15
  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 +419 -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 +114 -49
  175. waldiez/running/__init__.py +1 -1
  176. waldiez/running/environment.py +49 -68
  177. waldiez/running/gen_seq_diagram.py +16 -14
  178. waldiez/running/running.py +53 -34
  179. waldiez/utils/__init__.py +0 -4
  180. waldiez/utils/cli_extras/jupyter.py +5 -3
  181. waldiez/utils/cli_extras/runner.py +6 -4
  182. waldiez/utils/cli_extras/studio.py +6 -4
  183. waldiez/utils/conflict_checker.py +15 -9
  184. waldiez/utils/flaml_warnings.py +5 -5
  185. {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/METADATA +235 -91
  186. waldiez-0.4.8.dist-info/RECORD +200 -0
  187. waldiez/exporting/agent/agent_exporter.py +0 -297
  188. waldiez/exporting/agent/utils/__init__.py +0 -23
  189. waldiez/exporting/agent/utils/captain_agent.py +0 -263
  190. waldiez/exporting/agent/utils/code_execution.py +0 -65
  191. waldiez/exporting/agent/utils/group_manager.py +0 -220
  192. waldiez/exporting/agent/utils/rag_user/__init__.py +0 -7
  193. waldiez/exporting/agent/utils/rag_user/rag_user.py +0 -209
  194. waldiez/exporting/agent/utils/reasoning.py +0 -36
  195. waldiez/exporting/agent/utils/swarm_agent.py +0 -469
  196. waldiez/exporting/agent/utils/teachability.py +0 -41
  197. waldiez/exporting/agent/utils/termination_message.py +0 -44
  198. waldiez/exporting/base/__init__.py +0 -25
  199. waldiez/exporting/base/agent_position.py +0 -75
  200. waldiez/exporting/base/base_exporter.py +0 -118
  201. waldiez/exporting/base/export_position.py +0 -48
  202. waldiez/exporting/base/import_position.py +0 -23
  203. waldiez/exporting/base/mixin.py +0 -137
  204. waldiez/exporting/base/utils/__init__.py +0 -18
  205. waldiez/exporting/base/utils/comments.py +0 -96
  206. waldiez/exporting/base/utils/path_check.py +0 -68
  207. waldiez/exporting/base/utils/to_string.py +0 -84
  208. waldiez/exporting/chats/chats_exporter.py +0 -240
  209. waldiez/exporting/chats/utils/swarm.py +0 -210
  210. waldiez/exporting/flow/flow_exporter.py +0 -528
  211. waldiez/exporting/flow/utils/agent_utils.py +0 -204
  212. waldiez/exporting/flow/utils/chat_utils.py +0 -71
  213. waldiez/exporting/flow/utils/def_main.py +0 -77
  214. waldiez/exporting/flow/utils/flow_content.py +0 -202
  215. waldiez/exporting/flow/utils/flow_names.py +0 -116
  216. waldiez/exporting/flow/utils/importing_utils.py +0 -227
  217. waldiez/exporting/models/models_exporter.py +0 -199
  218. waldiez/exporting/models/utils.py +0 -174
  219. waldiez/exporting/skills/__init__.py +0 -9
  220. waldiez/exporting/skills/skills_exporter.py +0 -176
  221. waldiez/exporting/skills/utils.py +0 -369
  222. waldiez/models/agents/agent/teachability.py +0 -70
  223. waldiez/models/agents/rag_user/rag_user.py +0 -60
  224. waldiez/models/agents/swarm_agent/__init__.py +0 -50
  225. waldiez/models/agents/swarm_agent/after_work.py +0 -179
  226. waldiez/models/agents/swarm_agent/on_condition.py +0 -105
  227. waldiez/models/agents/swarm_agent/on_condition_available.py +0 -142
  228. waldiez/models/agents/swarm_agent/on_condition_target.py +0 -40
  229. waldiez/models/agents/swarm_agent/swarm_agent.py +0 -107
  230. waldiez/models/agents/swarm_agent/swarm_agent_data.py +0 -124
  231. waldiez/models/flow/utils.py +0 -232
  232. waldiez/models/skill/__init__.py +0 -16
  233. waldiez/models/skill/extra_requirements.py +0 -36
  234. waldiez/models/skill/skill_data.py +0 -53
  235. waldiez/models/skill/skill_type.py +0 -8
  236. waldiez/utils/pysqlite3_checker.py +0 -308
  237. waldiez/utils/rdps_checker.py +0 -122
  238. waldiez-0.4.6.dist-info/RECORD +0 -149
  239. /waldiez/models/agents/{captain_agent → captain}/__init__.py +0 -0
  240. /waldiez/models/agents/{captain_agent → captain}/captain_agent_lib_entry.py +0 -0
  241. {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/WHEEL +0 -0
  242. {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/entry_points.txt +0 -0
  243. {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/licenses/LICENSE +0 -0
  244. {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,411 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Flow export orchestrator."""
4
+
5
+ from typing import Any, Callable
6
+
7
+ from waldiez.models import Waldiez, WaldiezAgent
8
+
9
+ from ..agent import AgentExporter, create_agent_exporter
10
+ from ..chats import ChatsExporter, create_chats_exporter
11
+ from ..core import (
12
+ AgentPosition,
13
+ ContentOrder,
14
+ ExporterContext,
15
+ ExportPosition,
16
+ ExportResult,
17
+ ImportPosition,
18
+ )
19
+ from ..models import ModelsExporter, create_models_exporter
20
+ from ..tools import ToolsExporter, create_tools_exporter
21
+ from .merger import ContentMerger
22
+ from .utils import (
23
+ generate_header,
24
+ get_after_run_content,
25
+ get_np_no_nep50_handle,
26
+ get_sqlite_out,
27
+ get_start_logging,
28
+ get_stop_logging,
29
+ get_the_imports_string,
30
+ )
31
+
32
+
33
+ # pylint: disable=no-self-use,too-many-instance-attributes
34
+ class ExportOrchestrator:
35
+ """Coordinates the export process."""
36
+
37
+ def __init__(
38
+ self,
39
+ waldiez: Waldiez,
40
+ context: ExporterContext,
41
+ ) -> None:
42
+ """Initialize the export orchestrator.
43
+
44
+ Parameters
45
+ ----------
46
+ waldiez : Waldiez
47
+ The Waldiez instance containing the flow to export.
48
+ context : ExporterContext
49
+ The exporter context containing dependencies and configuration.
50
+ """
51
+ self.waldiez = waldiez
52
+ self.context = context
53
+ self.config = context.get_config()
54
+ self._tools_exporter: ToolsExporter | None = None
55
+ self._models_exporter: ModelsExporter | None = None
56
+ self._chats_exporter: ChatsExporter | None = None
57
+ self.logger = context.get_logger()
58
+ self._initialize()
59
+
60
+ def _initialize(self) -> None:
61
+ """Initialize the orchestrator with necessary configurations."""
62
+ unique_names = self.waldiez.flow.unique_names
63
+ self.flow_name = unique_names["flow_name"]
64
+ self.agents = unique_names["agents"]
65
+ self.models = unique_names["models"]
66
+ self.tools = unique_names["tools"]
67
+ self.chats = unique_names["chats"]
68
+ self.agent_names = unique_names["agent_names"]
69
+ self.model_names = unique_names["model_names"]
70
+ self.tool_names = unique_names["tool_names"]
71
+ self.chat_names = unique_names["chat_names"]
72
+
73
+ def orchestrate(self) -> ExportResult:
74
+ """Orchestrate the export process.
75
+
76
+ Returns
77
+ -------
78
+ ExportResult
79
+ The result of the export process,
80
+ containing the generated script and any additional metadata.
81
+ """
82
+ results: list[ExportResult] = []
83
+ agent_arguments: dict[str, list[str]] = {}
84
+
85
+ # 1. Tools first (needed by agents)
86
+ if self.waldiez.tools:
87
+ self.logger.info("Exporting tools ...")
88
+ tools_result = self._get_tools_exporter().export()
89
+ # Extract tool arguments for agents
90
+ tool_arguments = self._extract_agent_arguments_from_result(
91
+ tools_result
92
+ )
93
+ # Merge tool arguments into agent arguments
94
+ self._merge_agent_arguments(
95
+ source=tool_arguments,
96
+ target=agent_arguments,
97
+ )
98
+ results.append(tools_result)
99
+ self.logger.debug("Exported %s", tools_result)
100
+
101
+ # 2. Models second (needed by agents)
102
+ if self.waldiez.models:
103
+ self.logger.info("Exporting models ...")
104
+ models_result = self._get_models_exporter().export()
105
+ # Extract model arguments for agents
106
+ model_arguments = self._extract_agent_arguments_from_result(
107
+ models_result
108
+ )
109
+ # Merge model arguments into agent arguments
110
+ self._merge_agent_arguments(
111
+ source=model_arguments,
112
+ target=agent_arguments,
113
+ )
114
+ results.append(models_result)
115
+ self.logger.debug("Exported %s", models_result)
116
+ # 3. Chats third (agents might need agent chat registrations)
117
+ # we always have at least one chat (already validated in Waldiez init)
118
+ self.logger.info("Exporting chats ...")
119
+ chats_result = self._get_chats_exporter().export()
120
+ self.logger.debug("Exported %s", chats_result)
121
+ # Extract chat arguments for agents
122
+ chat_arguments = self._extract_agent_arguments_from_result(chats_result)
123
+ # Merge chat arguments into agent arguments
124
+ self._merge_agent_arguments(
125
+ source=chat_arguments,
126
+ target=agent_arguments,
127
+ )
128
+ results.append(chats_result)
129
+
130
+ # 4. Agents last
131
+ # we always have at least one agent (already validated in Waldiez init)
132
+ agent_results = self._export_all_agents(agent_arguments)
133
+ results.extend(agent_results)
134
+
135
+ # 5. Merge everything
136
+ merger = ContentMerger(self.context)
137
+ merged_result = merger.merge_results(results)
138
+ # Check for issues
139
+ stats = merger.get_merge_statistics()
140
+ if stats.conflicts_found:
141
+ self.logger.info(
142
+ "Resolved %d merge conflicts", len(stats.conflicts_found)
143
+ )
144
+ self.logger.debug("Merged result: %s", merged_result)
145
+ return self._finalize_export(merged_result)
146
+
147
+ def _finalize_export(self, merged_result: ExportResult) -> ExportResult:
148
+ """Finalize the export result with additional content.
149
+
150
+ Parameters
151
+ ----------
152
+ merged_result : ExportResult
153
+ The merged export result containing all content.
154
+
155
+ Returns
156
+ -------
157
+ ExportResult
158
+ The finalized export result with additional content.
159
+ """
160
+ merged_result.add_content(
161
+ generate_header(
162
+ name=self.waldiez.name,
163
+ description=self.waldiez.description,
164
+ requirements=self.waldiez.requirements,
165
+ tags=self.waldiez.tags,
166
+ for_notebook=self.config.for_notebook,
167
+ ),
168
+ position=ExportPosition.TOP, # befoe everything
169
+ order=ContentOrder.EARLY_SETUP,
170
+ )
171
+ merged_result.add_content(
172
+ get_np_no_nep50_handle(),
173
+ position=ExportPosition.IMPORTS, # after imports (need np)
174
+ order=ContentOrder.CLEANUP,
175
+ )
176
+ merged_result.add_content(
177
+ get_start_logging(
178
+ is_async=self.waldiez.is_async,
179
+ for_notebook=self.config.for_notebook,
180
+ ),
181
+ position=ExportPosition.IMPORTS, # after imports, before models
182
+ order=ContentOrder.CLEANUP.value + 1, # after imports
183
+ skip_strip=True, # keep newlines
184
+ )
185
+ merged_result.add_content(
186
+ get_sqlite_out(is_async=self.waldiez.is_async),
187
+ position=ExportPosition.AGENTS,
188
+ order=ContentOrder.LATE_CLEANUP.value + 1, # after all agents
189
+ )
190
+ merged_result.add_content(
191
+ get_stop_logging(is_async=self.waldiez.is_async),
192
+ position=ExportPosition.AGENTS,
193
+ order=ContentOrder.LATE_CLEANUP.value
194
+ + 2, # before def main (chats)
195
+ )
196
+ all_imports: list[tuple[str, ImportPosition]] = [
197
+ (item.statement, item.position)
198
+ for item in merged_result.get_sorted_imports()
199
+ ]
200
+ import_string = get_the_imports_string(
201
+ all_imports=all_imports,
202
+ is_async=self.waldiez.is_async,
203
+ )
204
+ if self.config.for_notebook:
205
+ cell_ignore_comment = (
206
+ "# pyright: "
207
+ "reportUnusedImport=false,"
208
+ "reportMissingTypeStubs=false"
209
+ "\n"
210
+ )
211
+ import_string = cell_ignore_comment + import_string
212
+ merged_result.add_content(
213
+ import_string,
214
+ position=ExportPosition.IMPORTS, # imports section
215
+ order=ContentOrder.EARLY_SETUP, # top position
216
+ )
217
+ return merged_result
218
+
219
+ def get_after_run_content(self) -> str:
220
+ """Get the content to be executed after the main flow run.
221
+
222
+ Returns
223
+ -------
224
+ str
225
+ The content to be executed after the main flow run.
226
+ """
227
+ return get_after_run_content(
228
+ waldiez=self.waldiez,
229
+ agent_names=self.agent_names,
230
+ tabs=1,
231
+ )
232
+
233
+ def _get_tools_exporter(self) -> ToolsExporter:
234
+ """Get or create tools exporter."""
235
+ if self._tools_exporter is None:
236
+ self._tools_exporter = create_tools_exporter(
237
+ flow_name=self.flow_name,
238
+ agents=self.agents,
239
+ agent_names=self.agent_names,
240
+ tools=self.tools,
241
+ tool_names=self.tool_names,
242
+ output_dir=self.config.output_directory,
243
+ context=self.context,
244
+ )
245
+ return self._tools_exporter
246
+
247
+ def _get_models_exporter(self) -> ModelsExporter:
248
+ """Get or create models exporter."""
249
+ if self._models_exporter is None:
250
+ self._models_exporter = create_models_exporter(
251
+ flow_name=self.flow_name,
252
+ agents=self.agents,
253
+ agent_names=self.agent_names,
254
+ models=self.models,
255
+ model_names=self.model_names,
256
+ for_notebook=self.config.for_notebook,
257
+ cache_seed=self.config.cache_seed,
258
+ output_dir=self.config.output_directory,
259
+ context=self.context,
260
+ )
261
+ return self._models_exporter
262
+
263
+ def _get_chats_exporter(self) -> ChatsExporter:
264
+ """Get or create chats exporter."""
265
+ if self._chats_exporter is None:
266
+ self._chats_exporter = create_chats_exporter(
267
+ waldiez=self.waldiez,
268
+ all_agents=self.agents,
269
+ agent_names=self.agent_names,
270
+ models=self.models,
271
+ model_names=self.model_names,
272
+ tools=self.tools,
273
+ tool_names=self.tool_names,
274
+ all_chats=self.chats,
275
+ main_chats=self.waldiez.initial_chats,
276
+ chat_names=self.chat_names,
277
+ output_dir=self.config.output_directory,
278
+ context=self.context,
279
+ )
280
+ return self._chats_exporter
281
+
282
+ # pylint: disable=no-self-use
283
+ def _create_agent_arguments_resolver(
284
+ self, exported_arguments: dict[str, Any]
285
+ ) -> Callable[[WaldiezAgent], list[str]]:
286
+ """Create an arguments resolver function for a specific agent.
287
+
288
+ Parameters
289
+ ----------
290
+ exported_arguments : dict[str, Any]
291
+ A dictionary containing exported arguments for agents,
292
+ models, and tools.
293
+
294
+ Returns
295
+ -------
296
+ Callable[[WaldiezAgent], list[str]]
297
+ A function that takes a WaldiezAgent and returns a list of
298
+ arguments to be used for that agent.
299
+ """
300
+
301
+ def arguments_resolver(target_agent: WaldiezAgent) -> list[str]:
302
+ """Resolve arguments for the target agent.
303
+
304
+ Parameters
305
+ ----------
306
+ target_agent : WaldiezAgent
307
+ The agent for which to resolve arguments.
308
+
309
+ Returns
310
+ -------
311
+ list[str]
312
+ A list of arguments to be used for the agent.
313
+ """
314
+ # Extract arguments from exported_arguments
315
+ return exported_arguments.get(target_agent.id, [])
316
+
317
+ return arguments_resolver
318
+
319
+ def _create_agent_exporter(
320
+ self,
321
+ agent: WaldiezAgent,
322
+ agent_arguments: dict[str, list[str]],
323
+ ) -> AgentExporter:
324
+ """Create an exporter for a specific agent."""
325
+ return create_agent_exporter(
326
+ agent=agent,
327
+ agent_names=self.agent_names,
328
+ models=(self.models, self.model_names),
329
+ chats=(self.chats, self.chat_names),
330
+ initial_chats=self.waldiez.initial_chats,
331
+ tool_names=self.tool_names,
332
+ cache_seed=self.waldiez.cache_seed,
333
+ is_async=self.waldiez.is_async,
334
+ for_notebook=self.config.for_notebook,
335
+ output_dir=self.config.output_directory,
336
+ context=self.context,
337
+ group_chat_members=self.waldiez.get_group_chat_members(agent),
338
+ arguments_resolver=self._create_agent_arguments_resolver(
339
+ exported_arguments=agent_arguments,
340
+ ),
341
+ )
342
+
343
+ def _extract_agent_arguments_from_result(
344
+ self, result: ExportResult
345
+ ) -> dict[str, list[str]]:
346
+ """Extract agent-specific arguments from an export result."""
347
+ agent_args: dict[str, list[str]] = {}
348
+
349
+ for content in result.positioned_content:
350
+ # Look for content positioned as agent arguments
351
+ if (
352
+ content.position == ExportPosition.AGENTS
353
+ and content.agent_position == AgentPosition.AS_ARGUMENT
354
+ and content.agent_id
355
+ ):
356
+ if content.agent_id not in agent_args:
357
+ agent_args[content.agent_id] = []
358
+
359
+ # The content itself is the argument string
360
+ strip_content = content.content.strip()
361
+ if strip_content:
362
+ # Add the content as an argument for the agent
363
+ agent_args[content.agent_id].append(f" {strip_content}")
364
+
365
+ return agent_args
366
+
367
+ def _merge_agent_arguments(
368
+ self, target: dict[str, list[str]], source: dict[str, list[str]]
369
+ ) -> None:
370
+ """Merge agent arguments from source into target."""
371
+ for agent_id, args in source.items():
372
+ if agent_id not in target:
373
+ target[agent_id] = []
374
+ target[agent_id].extend(args)
375
+
376
+ def _gather_agent_arguments(self) -> dict[str, Any]:
377
+ """Gather exported arguments from all agents, models, and tools.
378
+
379
+ Returns
380
+ -------
381
+ dict[str, Any]
382
+ A dictionary containing exported arguments for agents,
383
+ models, and tools.
384
+ """
385
+ exported_arguments: dict[str, Any] = {}
386
+ return exported_arguments
387
+
388
+ def _export_all_agents(
389
+ self, exported_arguments: dict[str, Any]
390
+ ) -> list[ExportResult]:
391
+ """Export all agents in dependency order.
392
+
393
+ Parameters
394
+ ----------
395
+ exported_arguments : dict[str, Any]
396
+ A dictionary containing exported arguments for agents,
397
+ models, and tools.
398
+
399
+ Returns
400
+ -------
401
+ list[ExportResult]
402
+ A list of export results for each agent.
403
+ """
404
+ results: list[ExportResult] = []
405
+ for agent in self.waldiez.agents:
406
+ agent_exporter = self._create_agent_exporter(
407
+ agent, exported_arguments
408
+ )
409
+ agent_result = agent_exporter.export()
410
+ results.append(agent_result)
411
+ return results
@@ -1,49 +1,22 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- """Utility functions for exporting waldiez to different formats."""
3
+ """Flow exporter utils."""
4
4
 
5
- from .agent_utils import (
6
- add_after_agent_content,
7
- add_after_all_agents_content,
8
- add_before_agent_content,
9
- add_before_all_agents_content,
10
- gather_agent_outputs,
11
- )
12
- from .chat_utils import add_after_chat_content, add_before_chat_content
13
- from .def_main import get_def_main
14
- from .flow_content import (
5
+ from .common import (
6
+ generate_header,
15
7
  get_after_run_content,
16
- get_ipynb_content_start,
17
8
  get_np_no_nep50_handle,
18
- get_py_content_start,
19
- )
20
- from .flow_names import ensure_unique_names
21
- from .importing_utils import gather_imports, get_the_imports_string
22
- from .logging_utils import (
23
- get_sqlite_out,
24
- get_sqlite_out_call,
25
- get_start_logging,
26
- get_stop_logging,
27
9
  )
10
+ from .importing import get_sorted_imports, get_the_imports_string
11
+ from .logging import get_sqlite_out, get_start_logging, get_stop_logging
28
12
 
29
13
  __all__ = [
30
- "add_after_agent_content",
31
- "add_after_all_agents_content",
32
- "add_before_agent_content",
33
- "add_before_all_agents_content",
34
- "add_after_chat_content",
35
- "add_before_chat_content",
36
- "ensure_unique_names",
37
- "gather_agent_outputs",
38
- "gather_imports",
39
- "get_after_run_content",
40
- "get_def_main",
14
+ "generate_header",
41
15
  "get_np_no_nep50_handle",
42
- "get_py_content_start",
43
- "get_ipynb_content_start",
16
+ "get_after_run_content",
17
+ "get_the_imports_string",
18
+ "get_sorted_imports",
44
19
  "get_start_logging",
45
20
  "get_stop_logging",
46
21
  "get_sqlite_out",
47
- "get_sqlite_out_call",
48
- "get_the_imports_string",
49
22
  ]
@@ -0,0 +1,206 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=line-too-long
4
+ # flake8: noqa: E501
5
+ """Common utils for the final generatio."""
6
+
7
+ from waldiez.models import Waldiez
8
+
9
+ from ...core import FILE_HEADER
10
+ from .linting import (
11
+ get_flake8_ignore_comment,
12
+ get_mypy_ignore_comment,
13
+ get_pylint_ignore_comment,
14
+ get_pyright_ignore_comment,
15
+ )
16
+
17
+ RETURN_TYPE_HINT = "Union[ChatResult, list[ChatResult], dict[int, ChatResult]]"
18
+ GENERATED_WITH = "🧩 generated with ❤️ by Waldiez."
19
+
20
+
21
+ def generate_header(
22
+ name: str,
23
+ description: str,
24
+ requirements: list[str],
25
+ tags: list[str],
26
+ for_notebook: bool,
27
+ ) -> str:
28
+ """Generate the header for the script or notebook.
29
+
30
+ Parameters
31
+ ----------
32
+ name : str
33
+ The name of the flow.
34
+ description : str
35
+ A brief description of the flow.
36
+ requirements : list[str]
37
+ A list of requirements for the flow.
38
+ tags : list[str]
39
+ A list of tags associated with the flow.
40
+ for_notebook : bool
41
+ Whether the header is for a notebook or a script.
42
+
43
+ Returns
44
+ -------
45
+ str
46
+ The header content.
47
+ """
48
+ if not for_notebook:
49
+ return _get_py_header(
50
+ name=name,
51
+ description=description,
52
+ requirements=requirements,
53
+ tags=tags,
54
+ )
55
+ return _get_ipynb_heeader(
56
+ name=name,
57
+ description=description,
58
+ requirements=requirements,
59
+ tags=tags,
60
+ )
61
+
62
+
63
+ def _get_ipynb_heeader(
64
+ name: str,
65
+ description: str,
66
+ requirements: list[str],
67
+ tags: list[str],
68
+ ) -> str:
69
+ requirements_str = " ".join(requirements)
70
+ tags_str = ", ".join(tags)
71
+ content = "# %% [markdown]\n"
72
+ content += f"## Name: {name}\n\n"
73
+ content += f"### Description: {description}\n\n"
74
+ content += f"### Tags: {tags_str}\n\n"
75
+ content += f"####{GENERATED_WITH}\n\n"
76
+ content += "#### Requirements\n\n# %%\n"
77
+ content += "import sys # pyright: ignore\n"
78
+ # fmt: off
79
+ content += "# # " + f"!{{sys.executable}} -m pip install -q {requirements_str}" + "\n"
80
+ # fmt: on
81
+ return content
82
+
83
+
84
+ def _get_py_header(
85
+ name: str,
86
+ description: str,
87
+ requirements: list[str],
88
+ tags: list[str],
89
+ ) -> str:
90
+ return f'''#!/usr/bin/env python
91
+ {FILE_HEADER}
92
+ {get_flake8_ignore_comment()}
93
+ {get_pylint_ignore_comment()}
94
+ {get_mypy_ignore_comment([])}
95
+ {get_pyright_ignore_comment()}
96
+ """{name}.
97
+
98
+ {description}
99
+
100
+ Requirements: {", ".join(requirements)}
101
+ Tags: {", ".join(tags)}
102
+ {GENERATED_WITH}
103
+ """'''
104
+
105
+
106
+ def main_doc_string() -> str:
107
+ """Generate the docstring for the main function.
108
+
109
+ Returns
110
+ -------
111
+ str
112
+ The docstring for the main function.
113
+ """
114
+ return f'''"""Start chatting.
115
+
116
+ Returns
117
+ -------
118
+ {RETURN_TYPE_HINT}
119
+ The result of the chat session, which can be a single ChatResult,
120
+ a list of ChatResults, or a dictionary mapping integers to ChatResults.
121
+ """'''
122
+
123
+
124
+ def get_after_run_content(
125
+ waldiez: Waldiez,
126
+ agent_names: dict[str, str],
127
+ tabs: int,
128
+ ) -> str:
129
+ """Get content to add after the flow is run.
130
+
131
+ Parameters
132
+ ----------
133
+ waldiez : Waldiez
134
+ The waldiez object.
135
+ agent_names : dict[str, str]
136
+ The dictionary of agent names and their corresponding ids
137
+ tabs : int
138
+ The number of tabs to add before the content.
139
+
140
+ Returns
141
+ -------
142
+ str
143
+ The content to add after the flow is run.
144
+ """
145
+ # if the flow has a reasoning agents, we add
146
+ # agent.visualize_tree() for each agent
147
+ content = ""
148
+ tab = " "
149
+ space = tab * tabs
150
+ for agent in waldiez.agents:
151
+ if agent.is_reasoning:
152
+ agent_name = agent_names[agent.id]
153
+ content += f"""
154
+ {space}# pylint: disable=broad-except,too-many-try-statements
155
+ {space}try:
156
+ {space}{tab}{agent_name}.visualize_tree()
157
+ {space}{tab}if os.path.exists("tree_of_thoughts.png"):
158
+ {space}{tab}{tab}new_name = "{agent_name}_tree_of_thoughts.png"
159
+ {space}{tab}{tab}os.rename("tree_of_thoughts.png", new_name)
160
+ {space}except BaseException:
161
+ {space}{tab}pass
162
+ {space}# save the tree to json
163
+ {space}try:
164
+ {space}{tab}data = {agent_name}._root.to_dict() # pylint: disable=protected-access # pyright: ignore
165
+ {space}{tab}with open("{agent_name}_reasoning_tree.json", "w", encoding="utf-8") as f:
166
+ {space}{tab}{tab}json.dump(data, f)
167
+ {space}except BaseException:
168
+ {space}{tab}pass
169
+ """
170
+ return content
171
+
172
+
173
+ def get_np_no_nep50_handle() -> str:
174
+ """Handle the "module numpy has no attribute _no_pep50_warning" error.
175
+
176
+ Returns
177
+ -------
178
+ str
179
+ The content to handle the error.
180
+ """
181
+ content = '''
182
+ #
183
+ # let's try to avoid:
184
+ # module 'numpy' has no attribute '_no_nep50_warning'"
185
+ # ref: https://github.com/numpy/numpy/blob/v2.2.2/doc/source/release/2.2.0-notes.rst#nep-50-promotion-state-option-removed
186
+ os.environ["NEP50_DEPRECATION_WARNING"] = "0"
187
+ os.environ["NEP50_DISABLE_WARNING"] = "1"
188
+ os.environ["NPY_PROMOTION_STATE"] = "weak"
189
+ if not hasattr(np, "_no_pep50_warning"):
190
+
191
+ import contextlib
192
+ from typing import Generator
193
+
194
+ @contextlib.contextmanager
195
+ def _np_no_nep50_warning() -> Generator[None, None, None]:
196
+ """Dummy function to avoid the warning.
197
+
198
+ Yields
199
+ ------
200
+ None
201
+ Nothing.
202
+ """
203
+ yield
204
+ setattr(np, "_no_pep50_warning", _np_no_nep50_warning) # noqa
205
+ '''
206
+ return content