waldiez 0.4.7__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.7.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.7.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.7.dist-info → waldiez-0.4.8.dist-info}/WHEEL +0 -0
  242. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/entry_points.txt +0 -0
  243. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/licenses/LICENSE +0 -0
  244. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,373 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Get the standard imports for the flow exporter."""
4
+
5
+ from typing import Optional
6
+
7
+ from waldiez.exporting.core import ImportPosition
8
+
9
+ BUILTIN_IMPORTS = [
10
+ "import csv",
11
+ "import importlib",
12
+ "import json",
13
+ "import os",
14
+ "import sqlite3",
15
+ "import sys",
16
+ "from dataclasses import asdict",
17
+ "from pprint import pprint",
18
+ "from types import ModuleType",
19
+ ]
20
+ TYPING_IMPORT_NAMES = [
21
+ "Annotated",
22
+ "Any",
23
+ "Callable",
24
+ "Dict",
25
+ "List",
26
+ "Optional",
27
+ "Set",
28
+ "Tuple",
29
+ "Union",
30
+ ]
31
+ # pylint: disable=inconsistent-quotes
32
+ TYPING_IMPORTS = [f"from typing import {', '.join(TYPING_IMPORT_NAMES)}"]
33
+ COMMON_AUTOGEN_IMPORTS = [
34
+ "from autogen import Agent",
35
+ "from autogen import Cache",
36
+ "from autogen import ConversableAgent",
37
+ "from autogen import ChatResult",
38
+ "from autogen import GroupChat",
39
+ "from autogen import runtime_logging",
40
+ ]
41
+
42
+
43
+ def get_sorted_imports(collected_imports: list[str]) -> list[str]:
44
+ """Get the sorted imports.
45
+
46
+ Parameters
47
+ ----------
48
+ collected_imports : list[str]
49
+ The collected imports.
50
+
51
+ Returns
52
+ -------
53
+ list[str]
54
+ The sorted imports.
55
+ """
56
+ # Remove duplicates while preserving order by converting to dict
57
+ unique_imports = list(dict.fromkeys(collected_imports))
58
+
59
+ sorted_imports = sorted(
60
+ [imp for imp in unique_imports if imp.startswith("import ")]
61
+ ) + sorted([imp for imp in unique_imports if imp.startswith("from ")])
62
+ return sorted_imports
63
+
64
+
65
+ def sort_imports(
66
+ all_imports: list[tuple[str, ImportPosition]],
67
+ ) -> tuple[list[str], list[str], list[str], list[str], bool]:
68
+ """Sort the imports.
69
+
70
+ Parameters
71
+ ----------
72
+ all_imports : list[tuple[str, ImportPosition]]
73
+ All the imports.
74
+
75
+ Returns
76
+ -------
77
+ tuple[list[str], list[str], list[str], list[str], bool]
78
+ The sorted imports and a flag if we got `import autogen`.
79
+ """
80
+ builtin_imports: list[str] = BUILTIN_IMPORTS.copy() + TYPING_IMPORTS.copy()
81
+ third_party_imports: list[str] = []
82
+ local_imports: list[str] = []
83
+ autogen_imports: list[str] = COMMON_AUTOGEN_IMPORTS.copy()
84
+ got_import_autogen = False
85
+
86
+ for import_string, position in all_imports:
87
+ if "import autogen" in import_string:
88
+ got_import_autogen = True
89
+ continue
90
+ if import_string.startswith("from autogen"):
91
+ autogen_imports.append(import_string)
92
+ continue
93
+ if position == ImportPosition.BUILTINS:
94
+ builtin_imports.append(import_string)
95
+ elif position == ImportPosition.THIRD_PARTY:
96
+ third_party_imports.append(import_string)
97
+ elif position == ImportPosition.LOCAL: # pragma: no branch
98
+ local_imports.append(import_string)
99
+
100
+ autogen_imports = clean_and_group_autogen_imports(autogen_imports)
101
+ third_party_imports = ensure_np_import(third_party_imports)
102
+ sorted_builtins = get_sorted_imports(builtin_imports)
103
+ sorted_third_party = get_sorted_imports(third_party_imports)
104
+ sorted_locals = get_sorted_imports(local_imports)
105
+
106
+ return (
107
+ sorted_builtins,
108
+ sorted(autogen_imports),
109
+ sorted_third_party,
110
+ sorted_locals,
111
+ got_import_autogen,
112
+ )
113
+
114
+
115
+ def clean_and_group_autogen_imports(autogen_imports: list[str]) -> list[str]:
116
+ """Cleanup and group autogen imports.
117
+
118
+ Parameters
119
+ ----------
120
+ autogen_imports : list[str]
121
+ List of autogen import statements
122
+
123
+ Returns
124
+ -------
125
+ list[str]
126
+ Cleaned and grouped autogen imports
127
+ """
128
+ # Group imports by module path
129
+ import_groups: dict[str, set[str]] = {}
130
+ direct_imports: set[str] = set()
131
+
132
+ for imp in autogen_imports:
133
+ imp = imp.strip()
134
+ if not imp:
135
+ continue
136
+
137
+ if imp.startswith("import autogen"):
138
+ direct_imports.add(imp)
139
+ continue
140
+
141
+ # Parse "from autogen.module import items"
142
+ if imp.startswith("from autogen"): # pragma: no branch
143
+ parts = imp.split(" import ")
144
+ if len(parts) == 2: # pragma: no branch
145
+ module_path = parts[0] # "from autogen.module"
146
+ items = parts[1].strip()
147
+
148
+ if module_path not in import_groups:
149
+ import_groups[module_path] = set()
150
+
151
+ # Handle multiple imports in one line
152
+ for item in items.split(","):
153
+ import_groups[module_path].add(item.strip())
154
+
155
+ # Build cleaned import list
156
+ cleaned_imports: list[str] = []
157
+
158
+ # Add direct imports first
159
+ cleaned_imports.extend(sorted(direct_imports))
160
+
161
+ # Add grouped imports, sorted by module path
162
+ for module_path in sorted(import_groups.keys()):
163
+ sorted_items = sorted(import_groups[module_path])
164
+ items_str = ", ".join(sorted_items)
165
+ import_statement = f"{module_path} import {items_str}"
166
+ cleaned_imports.append(import_statement)
167
+
168
+ return cleaned_imports
169
+
170
+
171
+ def get_the_imports_string(
172
+ all_imports: list[tuple[str, ImportPosition]],
173
+ is_async: bool,
174
+ ) -> str:
175
+ """Get the final imports string.
176
+
177
+ Parameters
178
+ ----------
179
+ all_imports : list[tuple[str, ImportPosition]]
180
+ All the imports.
181
+ is_async : bool
182
+ If the flow is async.
183
+
184
+ Returns
185
+ -------
186
+ str
187
+ The final imports string.
188
+ """
189
+ (
190
+ builtin_imports,
191
+ autogen_imports,
192
+ third_party_imports,
193
+ local_imports,
194
+ got_import_autogen,
195
+ ) = sort_imports(all_imports)
196
+
197
+ # Get the final imports string.
198
+ # Making sure that there are two lines
199
+ # after each import section
200
+ # (builtin, third party, local)
201
+ final_string = "\n".join(builtin_imports) + "\n"
202
+ while not final_string.endswith("\n\n"):
203
+ final_string += "\n"
204
+
205
+ if is_async:
206
+ final_string += (
207
+ "\nimport aiofiles"
208
+ "\nimport aiosqlite"
209
+ "\nimport anyio"
210
+ "\nimport nest_asyncio"
211
+ "\nfrom aiocsv import AsyncDictWriter\n"
212
+ )
213
+
214
+ if got_import_autogen:
215
+ final_string += "\nimport autogen # type: ignore\n"
216
+
217
+ if autogen_imports: # pragma: no branch
218
+ final_string += "\n".join(autogen_imports) + "\n"
219
+
220
+ if third_party_imports: # pragma: no branch
221
+ final_string += "\n".join(third_party_imports) + "\n"
222
+
223
+ while not final_string.endswith("\n\n"):
224
+ final_string += "\n"
225
+
226
+ if local_imports:
227
+ final_string += "\n".join(local_imports) + "\n"
228
+
229
+ while not final_string.endswith("\n\n"):
230
+ final_string += "\n"
231
+
232
+ if is_async:
233
+ final_string += (
234
+ "# pylint: disable=broad-exception-caught\n"
235
+ "try:\n"
236
+ " nest_asyncio.apply() # pyright: ignore\n"
237
+ "except BaseException:\n"
238
+ " pass # maybe on uvloop?\n"
239
+ )
240
+
241
+ return final_string.replace("\n\n\n", "\n\n") # avoid too many newlines
242
+
243
+
244
+ def ensure_np_import(third_party_imports: list[str]) -> list[str]:
245
+ """Ensure numpy is imported.
246
+
247
+ Parameters
248
+ ----------
249
+ third_party_imports : list[str]
250
+ The third party imports.
251
+
252
+ Returns
253
+ -------
254
+ list[str]
255
+ The third party imports with numpy.
256
+ """
257
+ if (
258
+ not third_party_imports
259
+ or "import numpy as np" not in third_party_imports
260
+ ):
261
+ third_party_imports.append("import numpy as np")
262
+ return third_party_imports
263
+
264
+
265
+ def gather_imports(
266
+ model_imports: Optional[list[tuple[str, ImportPosition]]] = None,
267
+ tool_imports: Optional[list[tuple[str, ImportPosition]]] = None,
268
+ chat_imports: Optional[list[tuple[str, ImportPosition]]] = None,
269
+ agent_imports: Optional[list[tuple[str, ImportPosition]]] = None,
270
+ ) -> list[tuple[str, ImportPosition]]:
271
+ """Gather all the imports.
272
+
273
+ Parameters
274
+ ----------
275
+ model_imports : tuple[str, ImportPosition]
276
+ The model imports.
277
+ tool_imports : tuple[str, ImportPosition]
278
+ The tool imports.
279
+ chat_imports : tuple[str, ImportPosition]
280
+ The chat imports.
281
+ agent_imports : tuple[str, ImportPosition]
282
+ The agent imports.
283
+
284
+ Returns
285
+ -------
286
+ tuple[str, ImportPosition]
287
+ The gathered imports.
288
+ """
289
+ all_imports: list[tuple[str, ImportPosition]] = []
290
+ for import_statement in BUILTIN_IMPORTS:
291
+ all_imports.append(
292
+ (
293
+ import_statement,
294
+ ImportPosition.BUILTINS,
295
+ )
296
+ )
297
+ if model_imports:
298
+ all_imports.extend(model_imports)
299
+ if tool_imports:
300
+ all_imports.extend(tool_imports)
301
+ if chat_imports:
302
+ all_imports.extend(chat_imports)
303
+ if agent_imports:
304
+ all_imports.extend(agent_imports)
305
+ all_imports = deduplicate_imports(all_imports)
306
+ one_line_typing_imports: list[tuple[str, ImportPosition]] = []
307
+ final_imports: list[tuple[str, ImportPosition]] = []
308
+ for import_tuple in all_imports:
309
+ if import_tuple[0].startswith("from typing import "):
310
+ one_line_typing_imports.append(import_tuple)
311
+ else:
312
+ final_imports.append(import_tuple)
313
+ final_typing_imports = get_the_typing_imports(one_line_typing_imports)
314
+ final_imports.insert(1, (final_typing_imports, ImportPosition.BUILTINS))
315
+ return final_imports
316
+
317
+
318
+ def get_the_typing_imports(
319
+ one_line_typing_imports: list[tuple[str, ImportPosition]],
320
+ ) -> str:
321
+ """Get the typing imports as a single line.
322
+
323
+ Parameters
324
+ ----------
325
+ one_line_typing_imports : list[tuple[str, ImportPosition]]
326
+ The one line typing imports.
327
+
328
+ Returns
329
+ -------
330
+ str
331
+ The final typing imports string.
332
+ """
333
+ # merge the ones found in the imports
334
+ # with the default ones
335
+ typing_imports: set[str] = set(TYPING_IMPORT_NAMES)
336
+ for import_tuple in one_line_typing_imports:
337
+ if import_tuple[0].startswith(
338
+ "from typing import "
339
+ ): # pragma: no branch
340
+ # extract the names from the import statement
341
+ names = import_tuple[0].split("from typing import ")[1]
342
+ for name in names.split(","):
343
+ typing_imports.add(name.strip())
344
+ # create the final import statement
345
+ final_typing_imports = (
346
+ f"from typing import {', '.join(sorted(typing_imports))}"
347
+ )
348
+ return final_typing_imports.strip()
349
+
350
+
351
+ def deduplicate_imports(
352
+ imports: list[tuple[str, ImportPosition]],
353
+ ) -> list[tuple[str, ImportPosition]]:
354
+ """Deduplicate imports while preserving order.
355
+
356
+ Parameters
357
+ ----------
358
+ imports : list[tuple[str, ImportPosition]]
359
+ The imports to deduplicate.
360
+
361
+ Returns
362
+ -------
363
+ list[tuple[str, ImportPosition]]
364
+ The deduplicated imports.
365
+ """
366
+ # Remove duplicates while preserving order
367
+ seen: set[tuple[str, ImportPosition]] = set()
368
+ deduplicated_imports: list[tuple[str, ImportPosition]] = []
369
+ for import_tuple in imports:
370
+ if import_tuple not in seen:
371
+ seen.add(import_tuple)
372
+ deduplicated_imports.append(import_tuple)
373
+ return deduplicated_imports
@@ -0,0 +1,200 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Linting comments to include in the generated code."""
4
+
5
+ import math
6
+
7
+
8
+ def split_linter_comment(
9
+ prefix: str,
10
+ rules: list[str],
11
+ max_lines: int = 3,
12
+ ) -> str:
13
+ """Split linter comment.
14
+
15
+ Parameters
16
+ ----------
17
+ prefix : str
18
+ The prefix for the comment, e.g., "# pylint: disable=" or "# pyright: ".
19
+ rules : list[str]
20
+ The list of linter rules to include in the comment.
21
+ max_lines : int, optional
22
+ The maximum number of lines to split the comment into, by default 3.
23
+
24
+ Returns
25
+ -------
26
+ str
27
+ The formatted comment string with the rules split into lines.
28
+ """
29
+ # Calculate minimum number of rules per line to not exceed max_lines
30
+ rules_per_line = max(1, math.ceil(len(rules) / max_lines))
31
+ # pylint: disable=inconsistent-quotes
32
+ lines = [
33
+ f"{prefix}{','.join(rules[i : i + rules_per_line])}"
34
+ for i in range(0, len(rules), rules_per_line)
35
+ ]
36
+ return "\n".join(lines) + "\n"
37
+
38
+
39
+ PYLINT_RULES = [
40
+ "line-too-long",
41
+ "unknown-option-value",
42
+ "unused-argument",
43
+ "unused-import",
44
+ "unused-variable",
45
+ "invalid-name",
46
+ "import-error",
47
+ "import-outside-toplevel",
48
+ "inconsistent-quotes",
49
+ "missing-function-docstring",
50
+ "missing-param-doc",
51
+ "missing-return-doc",
52
+ "ungrouped-imports",
53
+ "unnecessary-lambda-assignment",
54
+ "too-many-arguments",
55
+ "too-many-locals",
56
+ "too-many-try-statements",
57
+ "broad-exception-caught",
58
+ ]
59
+ PYRIGHT_RULES = [
60
+ "reportUnusedImport",
61
+ "reportMissingTypeStubs",
62
+ "reportUnknownArgumentType",
63
+ "reportUnknownMemberType",
64
+ "reportUnknownLambdaType",
65
+ "reportUnnecessaryIsInstance",
66
+ "reportUnknownVariableType",
67
+ ]
68
+
69
+ MYPY_RULES = [
70
+ "import-untyped",
71
+ "no-redef",
72
+ "unused-ignore",
73
+ "import-not-found",
74
+ ]
75
+
76
+ FLAKE8_RULES = ["E501"]
77
+
78
+
79
+ def get_flake8_ignore_comment(rules: list[str] | None = None) -> str:
80
+ """Get the flake8 ignore comment string.
81
+
82
+ Parameters
83
+ ----------
84
+ rules : Optional[list[str]], optional
85
+ The flake8 rules to ignore, by default None.
86
+
87
+ Returns
88
+ -------
89
+ str
90
+ The flake8 ignore comment string.
91
+
92
+ Example
93
+ -------
94
+ ```python
95
+ >>> get_flake8_ignore_comment(["E501", "F401"])
96
+
97
+ # flake8: noqa: E501, F401
98
+ ```
99
+ """
100
+ if not rules:
101
+ rules = FLAKE8_RULES
102
+ prefix = "# flake8: noqa: "
103
+ output = ", ".join(rules)
104
+ return prefix + output + "\n"
105
+
106
+
107
+ def get_pylint_ignore_comment(rules: list[str] | None = None) -> str:
108
+ """Get the pylint ignore comment string.
109
+
110
+ Parameters
111
+ ----------
112
+ rules : Optional[list[str]], optional
113
+ The pylint rules to ignore, by default None.
114
+
115
+ Returns
116
+ -------
117
+ str
118
+ The pylint ignore comment string.
119
+
120
+ Example
121
+ -------
122
+ ```python
123
+ >>> get_pylint_ignore_comment(True, ["invalid-name", "line-too-long"])
124
+
125
+ # pylint: disable=invalid-name, line-too-long
126
+ ```
127
+ """
128
+ if not rules:
129
+ rules = PYLINT_RULES
130
+ prefix = "# pylint: disable="
131
+ return split_linter_comment(
132
+ prefix,
133
+ rules,
134
+ max_lines=3,
135
+ )
136
+
137
+
138
+ def get_pyright_ignore_comment(rules: list[str] | None = None) -> str:
139
+ """Get the pyright ignore comment string.
140
+
141
+ Parameters
142
+ ----------
143
+ rules : Optional[list[str]], optional
144
+ The pyright rules to ignore, by default None.
145
+
146
+ Returns
147
+ -------
148
+ str
149
+ The pyright ignore comment string.
150
+
151
+ Example
152
+ -------
153
+ ```python
154
+ >>> get_pyright_ignore_comment(
155
+ ... True,
156
+ ... ["reportUnusedImport", "reportMissingTypeStubs"]
157
+ ... )
158
+
159
+ # pyright: reportUnusedImport=false, reportMissingTypeStubs=false
160
+ ```
161
+ """
162
+ if not rules:
163
+ rules = PYRIGHT_RULES
164
+ prefix = "# pyright: "
165
+ output = split_linter_comment(
166
+ prefix,
167
+ [f"{rule}=false" for rule in rules],
168
+ max_lines=3,
169
+ )
170
+ return output
171
+
172
+
173
+ def get_mypy_ignore_comment(rules: list[str] | None = None) -> str:
174
+ """Get the mypy ignore comment string.
175
+
176
+ Parameters
177
+ ----------
178
+ rules : Optional[list[str]], optional
179
+ The mypy rules to ignore, by default None.
180
+
181
+ Returns
182
+ -------
183
+ str
184
+ The mypy ignore comment string.
185
+
186
+ Example
187
+ -------
188
+ ```python
189
+ >>> get_mypy_ignore_comment(["import-untyped", "no-redef"])
190
+
191
+ # mypy: disable-error-code="import-untyped,no-redef"
192
+ ```
193
+ """
194
+ if rules is None:
195
+ rules = MYPY_RULES
196
+ if not rules:
197
+ return "# type: ignore\n"
198
+ prefix = "# mypy: disable-error-code="
199
+ content = ", ".join(rules)
200
+ return prefix + f'"{content}"\n'
@@ -15,16 +15,18 @@ get_sqlite_to_csv_call_string
15
15
  Get the string to call the sqlite to csv conversion.
16
16
  """
17
17
 
18
+ from ...core import get_comment
18
19
 
19
- def get_start_logging(is_async: bool, tabs: int = 0) -> str:
20
+
21
+ def get_start_logging(is_async: bool, for_notebook: bool) -> str:
20
22
  r"""Get the logging start call string.
21
23
 
22
24
  Parameters
23
25
  ----------
24
26
  is_async : bool
25
27
  Whether to use async mode.
26
- tabs : int, optional
27
- The number of tabs to use for indentation, by default 0
28
+ for_notebook : bool
29
+ Whether the logging is for a notebook or a script.
28
30
 
29
31
  Returns
30
32
  -------
@@ -42,17 +44,26 @@ def get_start_logging(is_async: bool, tabs: int = 0) -> str:
42
44
  config={"dbname": "flow.db"},
43
45
  )
44
46
  """
45
- tab = " " * tabs
47
+ tab = ""
48
+ comment = get_comment(
49
+ "Start logging.",
50
+ for_notebook=for_notebook,
51
+ )
46
52
  if is_async is False:
47
53
  return f'''
54
+ {tab}{comment}
48
55
  {tab}def start_logging() -> None:
49
56
  {tab} """Start logging."""
50
57
  {tab} runtime_logging.start(
51
58
  {tab} logger_type="sqlite",
52
59
  {tab} config={{"dbname": "flow.db"}},
53
60
  {tab} )
61
+ {tab}
62
+ {tab}
63
+ {tab}start_logging()
54
64
  '''
55
65
  return f'''
66
+ {tab}{comment}
56
67
  {tab}def start_logging() -> None:
57
68
  {tab} """Start logging."""
58
69
  {tab} # pylint: disable=import-outside-toplevel
@@ -65,6 +76,9 @@ def get_start_logging(is_async: bool, tabs: int = 0) -> str:
65
76
  {tab} "sqlite",
66
77
  {tab} {{"dbname": "flow.db"}},
67
78
  {tab} )
79
+ {tab}
80
+ {tab}
81
+ {tab}start_logging()
68
82
  '''
69
83
 
70
84
 
@@ -146,7 +160,7 @@ def get_sync_sqlite_out() -> str:
146
160
  content += ' json_file = csv_file.replace(".csv", ".json")\n'
147
161
  content += ' with open(json_file, "w", encoding="utf-8") as file:\n'
148
162
  content += " json.dump(data, file, indent=4, ensure_ascii=False)\n"
149
- content += "\n\n"
163
+ content += "\n"
150
164
  return content
151
165
 
152
166
 
@@ -231,7 +245,7 @@ def get_async_sqlite_out() -> str:
231
245
  content += ' json_file = csv_file.replace(".csv", ".json")\n'
232
246
  content += ' async with aiofiles.open(json_file, "w", encoding="utf-8") as file:\n'
233
247
  content += " await file.write(json.dumps(data, indent=4, ensure_ascii=False))\n"
234
- content += "\n\n"
248
+ content += "\n"
235
249
  return content
236
250
 
237
251
 
@@ -312,15 +326,15 @@ def get_sqlite_out_call(tabs: int, is_async: bool) -> str:
312
326
  return content
313
327
 
314
328
 
315
- def get_stop_logging(tabs: int, is_async: bool) -> str:
329
+ def get_stop_logging(is_async: bool, tabs: int = 0) -> str:
316
330
  r"""Get the function to stop logging and gather logs.
317
331
 
318
332
  Parameters
319
333
  ----------
320
- tabs : int
321
- The number of tabs to use for indentation
322
334
  is_async : bool
323
335
  Whether to use async mode
336
+ tabs : int, optional
337
+ The number of tabs to use for indentation, by default 0
324
338
 
325
339
  Returns
326
340
  -------
@@ -2,8 +2,10 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Models (llm_configs) exporter."""
4
4
 
5
- from .models_exporter import ModelsExporter
5
+ from .exporter import ModelsExporter
6
+ from .factory import create_models_exporter
6
7
 
7
8
  __all__ = [
8
9
  "ModelsExporter",
10
+ "create_models_exporter",
9
11
  ]