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
@@ -1,369 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0.
2
- # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- """Utilities for running code."""
4
-
5
- import asyncio
6
- import datetime
7
- import io
8
- import os
9
- import shutil
10
- import subprocess
11
- import sys
12
- import tempfile
13
- import warnings
14
- from contextlib import asynccontextmanager, contextmanager
15
- from pathlib import Path
16
- from typing import (
17
- AsyncIterator,
18
- Callable,
19
- Iterator,
20
- Optional,
21
- Set,
22
- Tuple,
23
- Union,
24
- )
25
-
26
- from .environment import in_virtualenv, is_root
27
- from .gen_seq_diagram import generate_sequence_diagram
28
-
29
- # pylint: disable=import-outside-toplevel
30
-
31
-
32
- @contextmanager
33
- def chdir(to: Union[str, Path]) -> Iterator[None]:
34
- """Change the current working directory in a context.
35
-
36
- Parameters
37
- ----------
38
- to : Union[str, Path]
39
- The directory to change to.
40
-
41
- Yields
42
- ------
43
- Iterator[None]
44
- The context manager.
45
- """
46
- old_cwd = str(os.getcwd())
47
- os.chdir(to)
48
- try:
49
- yield
50
- finally:
51
- os.chdir(old_cwd)
52
-
53
-
54
- @asynccontextmanager
55
- async def a_chdir(to: Union[str, Path]) -> AsyncIterator[None]:
56
- """Asynchronously change the current working directory in a context.
57
-
58
- Parameters
59
- ----------
60
- to : Union[str, Path]
61
- The directory to change to.
62
-
63
- Yields
64
- ------
65
- AsyncIterator[None]
66
- The async context manager.
67
- """
68
- old_cwd = str(os.getcwd())
69
- os.chdir(to)
70
- try:
71
- yield
72
- finally:
73
- os.chdir(old_cwd)
74
-
75
-
76
- def before_run(
77
- output_path: Optional[Union[str, Path]],
78
- uploads_root: Optional[Union[str, Path]],
79
- ) -> str:
80
- """Actions to perform before running the flow.
81
-
82
- Parameters
83
- ----------
84
- output_path : Optional[Union[str, Path]]
85
- The output path.
86
- uploads_root : Optional[Union[str, Path]]
87
- The runtime uploads root.
88
-
89
- Returns
90
- -------
91
- str
92
- The file name.
93
- """
94
- if not uploads_root:
95
- uploads_root = Path(tempfile.mkdtemp())
96
- else:
97
- uploads_root = Path(uploads_root)
98
- if not uploads_root.exists():
99
- uploads_root.mkdir(parents=True)
100
- file_name = "waldiez_flow.py" if not output_path else Path(output_path).name
101
- if file_name.endswith((".json", ".waldiez")):
102
- file_name = file_name.replace(".json", ".py").replace(".waldiez", ".py")
103
- if not file_name.endswith(".py"):
104
- file_name += ".py"
105
- return file_name
106
-
107
-
108
- def install_requirements(
109
- extra_requirements: Set[str], printer: Callable[..., None]
110
- ) -> None:
111
- """Install the requirements.
112
-
113
- Parameters
114
- ----------
115
- extra_requirements : Set[str]
116
- The extra requirements.
117
- printer : Callable[..., None]
118
- The printer function.
119
- """
120
- requirements_string = ", ".join(extra_requirements)
121
- printer(f"Installing requirements: {requirements_string}")
122
- pip_install = [sys.executable, "-m", "pip", "install"]
123
- if not in_virtualenv(): # it should
124
- # if not, let's try to install as user
125
- # not sure if --break-system-packages is safe
126
- # but it might fail if we don't
127
- break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
128
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
129
- if not is_root():
130
- pip_install.append("--user")
131
- pip_install.extend(extra_requirements)
132
- # pylint: disable=too-many-try-statements
133
- try:
134
- with subprocess.Popen(
135
- pip_install,
136
- stdout=subprocess.PIPE,
137
- stderr=subprocess.PIPE,
138
- ) as proc:
139
- if proc.stdout:
140
- for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
141
- printer(line.strip())
142
- if proc.stderr:
143
- for line in io.TextIOWrapper(proc.stderr, encoding="utf-8"):
144
- printer(line.strip())
145
- finally:
146
- if not in_virtualenv():
147
- # restore the old env var
148
- if break_system_packages:
149
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
150
- else:
151
- del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
152
-
153
-
154
- async def a_install_requirements(
155
- extra_requirements: Set[str], printer: Callable[..., None]
156
- ) -> None:
157
- """Install the requirements asynchronously.
158
-
159
- Parameters
160
- ----------
161
- extra_requirements : Set[str]
162
- The extra requirements.
163
- printer : Callable[..., None]
164
- The printer function.
165
- """
166
- requirements_string = ", ".join(extra_requirements)
167
- printer(f"Installing requirements: {requirements_string}")
168
- pip_install = [sys.executable, "-m", "pip", "install"]
169
- if not in_virtualenv():
170
- break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
171
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
172
- pip_install.extend(["--user"])
173
- pip_install.extend(extra_requirements)
174
- # pylint: disable=too-many-try-statements
175
- try:
176
- proc = await asyncio.create_subprocess_exec(
177
- *pip_install,
178
- stdout=asyncio.subprocess.PIPE,
179
- stderr=asyncio.subprocess.PIPE,
180
- )
181
- if proc.stdout:
182
- async for line in proc.stdout:
183
- printer(line.decode().strip())
184
- if proc.stderr:
185
- async for line in proc.stderr:
186
- printer(line.decode().strip())
187
- finally:
188
- if not in_virtualenv():
189
- if break_system_packages:
190
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
191
- else:
192
- del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
193
-
194
-
195
- def after_run(
196
- temp_dir: Path,
197
- output_path: Optional[Union[str, Path]],
198
- printer: Callable[..., None],
199
- flow_name: str,
200
- skip_mmd: bool = False,
201
- ) -> None:
202
- """Actions to perform after running the flow.
203
-
204
- Parameters
205
- ----------
206
- temp_dir : Path
207
- The temporary directory.
208
- output_path : Optional[Union[str, Path]]
209
- The output path.
210
- printer : Callable[..., None]
211
- The printer function.
212
- flow_name : str
213
- The flow name.
214
- skip_mmd : bool, optional
215
- Whether to skip the mermaid sequence diagram generation,
216
- by default False
217
- """
218
- if isinstance(output_path, str):
219
- output_path = Path(output_path)
220
- output_dir = output_path.parent if output_path else Path.cwd()
221
- if skip_mmd is False:
222
- events_csv_path = temp_dir / "logs" / "events.csv"
223
- if events_csv_path.exists():
224
- printer("Generating mermaid sequence diagram...")
225
- mmd_path = temp_dir / f"{flow_name}.mmd"
226
- generate_sequence_diagram(events_csv_path, mmd_path)
227
- if mmd_path.exists():
228
- shutil.copyfile(mmd_path, output_dir / f"{flow_name}.mmd")
229
- if output_path:
230
- destination_dir = output_path.parent
231
- destination_dir = (
232
- destination_dir
233
- / "waldiez_out"
234
- / datetime.datetime.now().strftime("%Y%m%d%H%M%S")
235
- )
236
- destination_dir.mkdir(parents=True, exist_ok=True)
237
- # copy the contents of the temp dir to the destination dir
238
- printer(f"Copying the results to {destination_dir}")
239
- copy_results(
240
- temp_dir=temp_dir,
241
- output_path=output_path,
242
- output_dir=output_dir,
243
- destination_dir=destination_dir,
244
- )
245
- shutil.rmtree(temp_dir)
246
-
247
-
248
- def copy_results(
249
- temp_dir: Path,
250
- output_path: Path,
251
- output_dir: Path,
252
- destination_dir: Path,
253
- ) -> None:
254
- """Copy the results to the output directory.
255
-
256
- Parameters
257
- ----------
258
- temp_dir : Path
259
- The temporary directory.
260
- output_path : Path
261
- The output path.
262
- output_dir : Path
263
- The output directory.
264
- destination_dir : Path
265
- The destination directory.
266
- """
267
- temp_dir.mkdir(parents=True, exist_ok=True)
268
- for item in temp_dir.iterdir():
269
- # skip cache files
270
- if (
271
- item.name.startswith("__pycache__")
272
- or item.name.endswith(".pyc")
273
- or item.name.endswith(".pyo")
274
- or item.name.endswith(".pyd")
275
- or item.name == ".cache"
276
- ):
277
- continue
278
- if item.is_file():
279
- # let's also copy the tree of thoughts image
280
- # to the output directory
281
- if item.name.endswith("tree_of_thoughts.png") or item.name.endswith(
282
- "reasoning_tree.json"
283
- ):
284
- shutil.copy(item, output_dir / item.name)
285
- shutil.copy(item, destination_dir)
286
- else:
287
- shutil.copytree(item, destination_dir / item.name)
288
- if output_path.is_file():
289
- if output_path.suffix == ".waldiez":
290
- output_path = output_path.with_suffix(".py")
291
- if output_path.suffix == ".py":
292
- src = temp_dir / output_path.name
293
- if src.exists():
294
- dst = destination_dir / output_path.name
295
- if dst.exists():
296
- dst.unlink()
297
- shutil.copyfile(src, output_dir / output_path.name)
298
-
299
-
300
- def get_printer() -> Callable[..., None]:
301
- """Get the printer function.
302
-
303
- Returns
304
- -------
305
- Callable[..., None]
306
- The printer function.
307
- """
308
- with warnings.catch_warnings():
309
- warnings.filterwarnings(
310
- "ignore",
311
- module="flaml",
312
- message="^.*flaml.automl is not available.*$",
313
- )
314
- from autogen.io import IOStream # type: ignore
315
-
316
- printer = IOStream.get_default().print
317
-
318
- def safe_printer(*args: object, **kwargs: object) -> None:
319
- try:
320
- printer(*args, **kwargs)
321
- except UnicodeEncodeError:
322
- # pylint: disable=too-many-try-statements
323
- try:
324
- msg, flush = get_what_to_print(*args, **kwargs)
325
- printer(msg, end="", flush=flush)
326
- except UnicodeEncodeError:
327
- sys.stdout = io.TextIOWrapper(
328
- sys.stdout.buffer, encoding="utf-8"
329
- )
330
- sys.stderr = io.TextIOWrapper(
331
- sys.stderr.buffer, encoding="utf-8"
332
- )
333
- try:
334
- printer(*args, **kwargs)
335
- except UnicodeEncodeError:
336
- sys.stderr.write(
337
- "Could not print the message due to encoding issues.\n"
338
- )
339
-
340
- return safe_printer
341
-
342
-
343
- def get_what_to_print(*args: object, **kwargs: object) -> Tuple[str, bool]:
344
- """Get what to print.
345
-
346
- Parameters
347
- ----------
348
- args : object
349
- The arguments.
350
- kwargs : object
351
- The keyword arguments.
352
-
353
- Returns
354
- -------
355
- Tuple[str, bool]
356
- The message and whether to flush.
357
- """
358
- sep = kwargs.get("sep", " ")
359
- if not isinstance(sep, str):
360
- sep = " "
361
- end = kwargs.get("end", "\n")
362
- if not isinstance(end, str):
363
- end = "\n"
364
- flush = kwargs.get("flush", False)
365
- if not isinstance(flush, bool):
366
- flush = False
367
- msg = sep.join(str(arg) for arg in args) + end
368
- utf8_msg = msg.encode("utf-8", errors="replace").decode("utf-8")
369
- return utf8_msg, flush
@@ -1,308 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0.
2
- # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- # pylint: disable=import-error
4
- # flake8: noqa: E501
5
- """Try to install pysqlite3-binary.
6
-
7
- Highly recommended to be run in a virtual environment.
8
- 'setuptools' and 'wheel' will also be installed if not already installed.
9
- """
10
-
11
- import contextlib
12
- import os
13
- import platform
14
- import shutil
15
- import site
16
- import subprocess
17
- import sys
18
- import tempfile
19
- import urllib.request
20
- import zipfile
21
-
22
- PYSQLITE3_VERSION = "0.5.4"
23
- SQLITE_URL = "https://www.sqlite.org/2025/sqlite-amalgamation-3480000.zip"
24
- PYSQLITE3_URL = f"https://github.com/coleifer/pysqlite3/archive/refs/tags/{PYSQLITE3_VERSION}.zip" # pylint: disable=line-too-long
25
-
26
- PIP = [sys.executable, "-m", "pip"]
27
-
28
-
29
- def run_command(command: list[str], cwd: str = ".") -> None:
30
- """Run a command.
31
-
32
- Parameters
33
- ----------
34
- command : str
35
- The command to run.
36
- cwd : str
37
- The current working directory.
38
- """
39
- if cwd == ".":
40
- cwd = os.getcwd()
41
- try:
42
- subprocess.run( # nosemgrep # nosec
43
- command,
44
- check=True,
45
- cwd=cwd,
46
- env=os.environ,
47
- encoding="utf-8",
48
- )
49
- except subprocess.CalledProcessError as e:
50
- print(f"Error running command: {e}")
51
- sys.exit(1)
52
-
53
-
54
- def in_virtualenv() -> bool:
55
- """Check if the script is running in a virtual environment.
56
-
57
- Returns
58
- -------
59
- bool
60
- True if in a virtual environment, False otherwise.
61
- """
62
- return hasattr(sys, "real_prefix") or (
63
- hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
64
- )
65
-
66
-
67
- def is_root() -> bool:
68
- """Check if the script is running as root/administrator.
69
-
70
- Returns
71
- -------
72
- bool
73
- True if running as root/administrator, False otherwise.
74
- """
75
- # pylint: disable=import-outside-toplevel,line-too-long
76
- if os.name == "nt":
77
- try:
78
- import ctypes
79
-
80
- return ctypes.windll.shell32.IsUserAnAdmin() != 0 # type: ignore[unused-ignore,attr-defined] # noqa: E501
81
- except Exception: # pylint: disable=broad-exception-caught
82
- return False
83
- else:
84
- return os.getuid() == 0
85
-
86
-
87
- def pip_install(*package_names: str, cwd: str = ".") -> None:
88
- """Install packages using pip.
89
-
90
- Parameters
91
- ----------
92
- *package_names : tuple[str, ...]
93
- The package names or paths to install.
94
- cwd : str
95
- The current working directory.
96
- """
97
- args = ["install", "-qq"]
98
- break_system_packages = ""
99
- if not in_virtualenv():
100
- break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
101
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
102
- if not is_root():
103
- args.append("--user")
104
- run_command(PIP + args + list(package_names), cwd)
105
- if not in_virtualenv():
106
- if break_system_packages:
107
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
108
- else:
109
- os.environ.pop("PIP_BREAK_SYSTEM_PACKAGES", None)
110
-
111
-
112
- def pip_uninstall(*package_names: str, cwd: str = ".") -> None:
113
- """Uninstall packages using pip.
114
-
115
- Parameters
116
- ----------
117
- *package_names : tuple[str, ...]
118
- The package names to uninstall.
119
- cwd : str
120
- The current working directory.
121
- """
122
- args = ["uninstall", "-qq", "--yes"]
123
- break_system_packages = ""
124
- if not in_virtualenv():
125
- break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
126
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
127
- run_command(PIP + args + list(package_names), cwd)
128
- if not in_virtualenv():
129
- if break_system_packages:
130
- os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
131
- else:
132
- os.environ.pop("PIP_BREAK_SYSTEM_PACKAGES", None)
133
-
134
-
135
- def download_sqlite_amalgamation() -> str:
136
- """Download the SQLite amalgamation source code.
137
-
138
- Returns
139
- -------
140
- str
141
- The path to the extracted SQLite source code.
142
- """
143
- zip_path = "sqlite_amalgamation.zip"
144
- extract_path = "sqlite_amalgamation"
145
-
146
- # Download the SQLite source code
147
- print("Downloading SQLite amalgamation source code...")
148
- urllib.request.urlretrieve(SQLITE_URL, zip_path) # nosec
149
-
150
- # Extract the SQLite source code
151
- print("Extracting SQLite source code...")
152
- with zipfile.ZipFile(zip_path, "r") as zip_ref:
153
- zip_ref.extractall(extract_path)
154
-
155
- # Clean up the zip file
156
- os.remove(zip_path)
157
-
158
- # Return the path to the extracted source code
159
- folder_name = SQLITE_URL.rsplit("/", 1)[-1].split(".")[0]
160
- return os.path.join(extract_path, folder_name)
161
-
162
-
163
- def rename_package_name(pysqlite3_dir: str) -> None:
164
- """Rename the package name in the setup.py file.
165
-
166
- Parameters
167
- ----------
168
- pysqlite3_dir : str
169
- The path to the pysqlite3 directory.
170
- """
171
- setup_file = os.path.join(pysqlite3_dir, "setup.py")
172
- with open(setup_file, "r", encoding="utf-8") as file:
173
- setup_py = file.read()
174
- # sed -i "s|name='pysqlite3-binary'|name=PACKAGE_NAME|g" setup.py
175
- setup_py = setup_py.replace(
176
- "name='pysqlite3'", "name='pysqlite3-binary'"
177
- ).replace("name=PACKAGE_NAME,", "name='pysqlite3-binary',")
178
- with open(setup_file, "w", encoding="utf-8", newline="\n") as file:
179
- file.write(setup_py)
180
-
181
-
182
- def prepare_pysqlite3(sqlite_amalgamation_path: str) -> str:
183
- """Prepare pysqlite3 using the SQLite amalgamation source code.
184
-
185
- Parameters
186
- ----------
187
- sqlite_amalgamation_path : str
188
- The path to the SQLite amalgamation source code.
189
-
190
- Returns
191
- -------
192
- str
193
- The path to the pysqlite3 directory.
194
- """
195
- pysqlite3_zip = "pysqlite3.zip"
196
- pysqlite3_extract = "pysqlite3"
197
- urllib.request.urlretrieve(PYSQLITE3_URL, pysqlite3_zip) # nosec
198
- with zipfile.ZipFile(pysqlite3_zip, "r") as zip_ref:
199
- zip_ref.extractall(pysqlite3_extract)
200
- os.remove(pysqlite3_zip)
201
- sqlite3_c = os.path.join(sqlite_amalgamation_path, "sqlite3.c")
202
- sqlite3_h = os.path.join(sqlite_amalgamation_path, "sqlite3.h")
203
- pysqlite3_dir = os.path.join(
204
- pysqlite3_extract, f"pysqlite3-{PYSQLITE3_VERSION}"
205
- )
206
- shutil.copy(sqlite3_c, pysqlite3_dir)
207
- shutil.copy(sqlite3_h, pysqlite3_dir)
208
- rename_package_name(pysqlite3_dir)
209
- return pysqlite3_dir
210
-
211
-
212
- def install_pysqlite3(sqlite_amalgamation_path: str) -> None:
213
- """Install pysqlite3 using the SQLite amalgamation source code.
214
-
215
- Parameters
216
- ----------
217
- sqlite_amalgamation_path : str
218
- The path to the SQLite amalgamation source code.
219
- """
220
- # pylint: disable=too-many-try-statements
221
- try:
222
- pysqlite3_dir = prepare_pysqlite3(sqlite_amalgamation_path)
223
- pip_install("setuptools")
224
- # let's suppress logs
225
- with open(os.devnull, "w", encoding="utf-8") as devnull:
226
- with (
227
- contextlib.redirect_stdout(devnull),
228
- contextlib.redirect_stderr(devnull),
229
- ):
230
- run_command(
231
- [sys.executable, "setup.py", "build_static"], pysqlite3_dir
232
- )
233
- pip_install("wheel")
234
- run_command(
235
- PIP + ["wheel", ".", "-w", "dist"],
236
- pysqlite3_dir,
237
- )
238
- wheel_file = os.listdir(os.path.join(pysqlite3_dir, "dist"))[0]
239
- wheel_path = os.path.join("dist", wheel_file)
240
- pip_install(wheel_path, cwd=pysqlite3_dir)
241
- except BaseException as e: # pylint: disable=broad-except
242
- print(f"Failed to install pysqlite3: {e}")
243
- sys.exit(1)
244
-
245
-
246
- def check_pysqlite3() -> None:
247
- """Check the installation of pysqlite3."""
248
- # pylint: disable=unused-import, import-outside-toplevel, line-too-long
249
- try:
250
- import pysqlite3 # type: ignore[unused-ignore, import-untyped, import-not-found] # noqa
251
- except ImportError:
252
- print("pysqlite3 not found or cannot be imported.")
253
- # and not arm64
254
- is_arm = "arm" in platform.machine().lower()
255
- if not is_arm and platform.system() == "Linux":
256
- pip_install("pysqlite3-binary")
257
- else:
258
- # Uninstall pysqlite3-binary if it is already installed
259
- pip_uninstall("pysqlite3", "pysqlite3-binary")
260
- cwd = os.getcwd()
261
- tmpdir = tempfile.mkdtemp()
262
- os.chdir(tmpdir)
263
- source_path = download_sqlite_amalgamation()
264
- install_pysqlite3(source_path)
265
- os.chdir(cwd)
266
- shutil.rmtree(tmpdir)
267
- site.main()
268
- # Re-import pysqlite3 as sqlite3
269
- import pysqlite3 # type: ignore[unused-ignore, import-untyped, import-not-found] # noqa
270
-
271
- sys.modules["sqlite3"] = sys.modules["pysqlite3"]
272
-
273
-
274
- def test_sqlite_usage() -> None:
275
- """Test the usage of the sqlite3 module."""
276
- # pylint: disable=import-outside-toplevel, unused-import, line-too-long
277
- import pysqlite3 # type: ignore[unused-ignore, import-untyped, import-not-found] # noqa
278
-
279
- sys.modules["sqlite3"] = sys.modules.pop("pysqlite3")
280
- import sqlite3 # noqa
281
-
282
- print(sqlite3.__file__)
283
- # it should be sth like: /path/to/site-packages/pysqlite3/__init__.py
284
- conn = sqlite3.connect(":memory:")
285
- cursor = conn.cursor()
286
- cursor.execute("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)")
287
- cursor.execute("INSERT INTO test (name) VALUES ('test')")
288
- cursor.execute("SELECT * FROM test")
289
- rows = cursor.fetchall()
290
- print(rows)
291
- conn.close()
292
-
293
-
294
- def main() -> None:
295
- """Run the check."""
296
- if "--force" in sys.argv:
297
- pip_uninstall("pysqlite3", "pysqlite3-binary")
298
- cwd = os.getcwd()
299
- tmpdir = tempfile.mkdtemp()
300
- os.chdir(tmpdir)
301
- check_pysqlite3()
302
- os.chdir(cwd)
303
- shutil.rmtree(tmpdir)
304
- test_sqlite_usage()
305
-
306
-
307
- if __name__ == "__main__":
308
- main()