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
waldiez/models/waldiez.py CHANGED
@@ -1,23 +1,33 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=too-many-public-methods
3
4
  """Waldiez data class.
4
5
 
5
- A Waldiez class contains all the information that is needed to generate
6
+ A Waldiez class contains all the information needed to generate
6
7
  and run an autogen workflow. It has the model/LLM configurations, the agent
7
- definitions and their optional additional skills to be used.
8
+ definitions and their optional additional tools to be used.
8
9
  """
9
10
 
10
11
  import json
11
12
  from dataclasses import dataclass
12
13
  from pathlib import Path
13
- from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
14
-
15
- from .agents import WaldiezAgent, get_retrievechat_extra_requirements
16
- from .chat import WaldiezChat
14
+ from typing import Any, Iterator, Optional
15
+
16
+ from .agents import (
17
+ WaldiezAgent,
18
+ WaldiezGroupManager,
19
+ get_captain_agent_extra_requirements,
20
+ get_retrievechat_extra_requirements,
21
+ )
17
22
  from .common import get_autogen_version
18
- from .flow import WaldiezFlow, get_flow_data
23
+ from .flow import (
24
+ WaldiezAgentConnection,
25
+ WaldiezFlow,
26
+ WaldiezFlowInfo,
27
+ get_flow_data,
28
+ )
19
29
  from .model import WaldiezModel, get_models_extra_requirements
20
- from .skill import WaldiezSkill, get_skills_extra_requirements
30
+ from .tool import WaldiezTool, get_tools_extra_requirements
21
31
 
22
32
 
23
33
  @dataclass(frozen=True, slots=True)
@@ -32,18 +42,18 @@ class Waldiez:
32
42
  @classmethod
33
43
  def from_dict(
34
44
  cls,
35
- data: Dict[str, Any],
45
+ data: dict[str, Any],
36
46
  flow_id: Optional[str] = None,
37
47
  name: Optional[str] = None,
38
48
  description: Optional[str] = None,
39
- tags: Optional[List[str]] = None,
40
- requirements: Optional[List[str]] = None,
49
+ tags: Optional[list[str]] = None,
50
+ requirements: Optional[list[str]] = None,
41
51
  ) -> "Waldiez":
42
52
  """Create a Waldiez from dict.
43
53
 
44
54
  Parameters
45
55
  ----------
46
- data : Dict[str, Any]
56
+ data : dict[str, Any]
47
57
  The data.
48
58
  flow_id : Optional[str], optional
49
59
  The flow id, by default None (retrieved from data or generated).
@@ -51,9 +61,9 @@ class Waldiez:
51
61
  The name, by default None (retrieved from data).
52
62
  description : Optional[str], optional
53
63
  The description, by default None (retrieved from data).
54
- tags : Optional[List[str]], optional
64
+ tags : Optional[list[str]], optional
55
65
  The tags, by default None (retrieved from data).
56
- requirements : Optional[List[str]], optional
66
+ requirements : Optional[list[str]], optional
57
67
  The requirements, by default None (retrieved from data).
58
68
 
59
69
  Returns
@@ -69,16 +79,17 @@ class Waldiez:
69
79
  tags=tags,
70
80
  requirements=requirements,
71
81
  )
72
- return cls(flow=WaldiezFlow.model_validate(flow))
82
+ validated = WaldiezFlow.model_validate(flow)
83
+ return cls(flow=validated) # pyright: ignore
73
84
 
74
85
  @classmethod
75
86
  def load(
76
87
  cls,
77
- waldiez_file: Union[str, Path],
88
+ waldiez_file: str | Path,
78
89
  name: Optional[str] = None,
79
90
  description: Optional[str] = None,
80
- tags: Optional[List[str]] = None,
81
- requirements: Optional[List[str]] = None,
91
+ tags: Optional[list[str]] = None,
92
+ requirements: Optional[list[str]] = None,
82
93
  ) -> "Waldiez":
83
94
  """Load a Waldiez from a file.
84
95
 
@@ -90,9 +101,9 @@ class Waldiez:
90
101
  The name, by default None.
91
102
  description : Optional[str], optional
92
103
  The description, by default None.
93
- tags : Optional[List[str]], optional
104
+ tags : Optional[list[str]], optional
94
105
  The tags, by default None.
95
- requirements : Optional[List[str]], optional
106
+ requirements : Optional[list[str]], optional
96
107
  The requirements, by default None.
97
108
 
98
109
  Returns
@@ -105,7 +116,7 @@ class Waldiez:
105
116
  ValueError
106
117
  If the file is not found or invalid JSON.
107
118
  """
108
- data: Dict[str, Any] = {}
119
+ data: dict[str, Any] = {}
109
120
  if not Path(waldiez_file).exists():
110
121
  raise ValueError(f"File not found: {waldiez_file}")
111
122
  with open(waldiez_file, "r", encoding="utf-8") as file:
@@ -142,23 +153,33 @@ class Waldiez:
142
153
  """
143
154
  return self.flow.model_dump_json(by_alias=by_alias, indent=indent)
144
155
 
156
+ @property
157
+ def id(self) -> str:
158
+ """Get the flow id."""
159
+ return self.flow.id
160
+
145
161
  @property
146
162
  def has_rag_agents(self) -> bool:
147
163
  """Check if the flow has RAG agents."""
148
- return any(agent.agent_type == "rag_user" for agent in self.agents)
164
+ return any(agent.is_rag_user for agent in self.agents)
149
165
 
150
166
  @property
151
167
  def has_multimodal_agents(self) -> bool:
152
168
  """Check if the flow has multimodal agents."""
153
- return any(agent.data.is_multimodal for agent in self.agents)
169
+ return any(
170
+ agent.data.is_multimodal
171
+ for agent in self.flow.data.agents.assistantAgents
172
+ )
154
173
 
155
174
  @property
156
175
  def has_captain_agents(self) -> bool:
157
176
  """Check if the flow has captain agents."""
158
- return any(agent.agent_type == "captain" for agent in self.agents)
177
+ return any(agent.is_captain for agent in self.agents)
159
178
 
160
179
  @property
161
- def chats(self) -> List[Tuple[WaldiezChat, WaldiezAgent, WaldiezAgent]]:
180
+ def initial_chats(
181
+ self,
182
+ ) -> list[WaldiezAgentConnection]:
162
183
  """Get the chats."""
163
184
  return self.flow.ordered_flow
164
185
 
@@ -174,15 +195,15 @@ class Waldiez:
174
195
  yield from self.flow.data.agents.members
175
196
 
176
197
  @property
177
- def skills(self) -> Iterator[WaldiezSkill]:
178
- """Get the flow skills.
198
+ def tools(self) -> Iterator[WaldiezTool]:
199
+ """Get the flow tools.
179
200
 
180
201
  Yields
181
202
  ------
182
- WaldiezSkill
183
- The skills.
203
+ WaldiezTool
204
+ The tools.
184
205
  """
185
- yield from self.flow.data.skills
206
+ yield from self.flow.data.tools
186
207
 
187
208
  @property
188
209
  def models(self) -> Iterator[WaldiezModel]:
@@ -195,6 +216,14 @@ class Waldiez:
195
216
  """
196
217
  yield from self.flow.data.models
197
218
 
219
+ @property
220
+ def info(self) -> WaldiezFlowInfo:
221
+ """Get the flow info."""
222
+ return WaldiezFlowInfo.create(
223
+ agents=self.agents,
224
+ agent_names=self.flow.unique_names["agent_names"],
225
+ )
226
+
198
227
  @property
199
228
  def name(self) -> str:
200
229
  """Get the flow name."""
@@ -206,7 +235,7 @@ class Waldiez:
206
235
  return self.flow.description or "Waldiez Flow description"
207
236
 
208
237
  @property
209
- def tags(self) -> List[str]:
238
+ def tags(self) -> list[str]:
210
239
  """Get the flow tags."""
211
240
  return self.flow.tags
212
241
 
@@ -226,14 +255,13 @@ class Waldiez:
226
255
  return self.flow.is_single_agent_mode
227
256
 
228
257
  @property
229
- def requirements(self) -> List[str]:
258
+ def requirements(self) -> list[str]:
230
259
  """Get the flow requirements."""
231
260
  autogen_version = get_autogen_version()
232
261
  requirements_list = filter(
233
262
  # we use the fixed "ag2=={autogen_version}" below
234
263
  lambda requirement: not (
235
- # cspell:disable-next-line
236
- requirement.startswith("pyautogen")
264
+ requirement.startswith("ag2")
237
265
  or requirement.startswith("ag2")
238
266
  or requirement.startswith("autogen")
239
267
  ),
@@ -241,29 +269,13 @@ class Waldiez:
241
269
  )
242
270
  requirements = set(requirements_list)
243
271
  requirements.add(f"ag2[openai]=={autogen_version}")
244
- if self.has_rag_agents:
272
+ if self.has_rag_agents: # pragma: no branch
245
273
  rag_extras = get_retrievechat_extra_requirements(self.agents)
246
274
  requirements.update(rag_extras)
247
- if self.has_multimodal_agents:
275
+ if self.has_multimodal_agents: # pragma: no branch
248
276
  requirements.add(f"ag2[lmm]=={autogen_version}")
249
- if self.has_captain_agents:
250
- # pysqlite3-binary might not get installed on windows
251
- captain_extras = [
252
- "chromadb",
253
- "sentence-transformers",
254
- "huggingface-hub",
255
- # tools:
256
- "pillow",
257
- "markdownify",
258
- "arxiv",
259
- "pymupdf",
260
- "wikipedia-api",
261
- "easyocr",
262
- "python-pptx",
263
- "openai-whisper",
264
- "pandas",
265
- "scipy",
266
- ]
277
+ if self.has_captain_agents: # pragma: no branch
278
+ captain_extras = get_captain_agent_extra_requirements()
267
279
  requirements.update(captain_extras)
268
280
  requirements.update(
269
281
  get_models_extra_requirements(
@@ -272,28 +284,50 @@ class Waldiez:
272
284
  )
273
285
  )
274
286
  requirements.update(
275
- get_skills_extra_requirements(
276
- self.skills,
287
+ get_tools_extra_requirements(
288
+ self.tools,
277
289
  autogen_version=autogen_version,
278
290
  )
279
291
  )
280
292
  return sorted(requirements)
281
293
 
282
- def get_flow_env_vars(self) -> List[Tuple[str, str]]:
294
+ # def get_flow_chat_info(self) ->
295
+
296
+ def get_flow_env_vars(self) -> list[tuple[str, str]]:
283
297
  """Get the flow environment variables.
284
298
 
285
299
  Returns
286
300
  -------
287
- List[Tuple[str, str]]
301
+ list[tuple[str, str]]
288
302
  The environment variables for the flow.
289
303
  """
290
- env_vars: List[Tuple[str, str]] = []
291
- for skill in self.skills:
292
- for secret_key, secret_value in skill.secrets.items():
304
+ env_vars: list[tuple[str, str]] = []
305
+ for tool in self.tools:
306
+ for secret_key, secret_value in tool.secrets.items():
293
307
  env_vars.append((secret_key, secret_value))
308
+ for model in self.models:
309
+ api_env_key = model.api_key_env_key
310
+ api_key = model.api_key
311
+ if api_env_key and api_key: # pragma: no branch
312
+ env_vars.append((api_env_key, api_key))
294
313
  return env_vars
295
314
 
296
- def get_group_chat_members(self, agent: WaldiezAgent) -> List[WaldiezAgent]:
315
+ def get_root_group_manager(self) -> WaldiezGroupManager:
316
+ """Get the root group manager agent.
317
+
318
+ Returns
319
+ -------
320
+ WaldiezGroupManager
321
+ The root group manager agent.
322
+
323
+ Raises
324
+ ------
325
+ ValueError
326
+ If the root group manager agent is not found.
327
+ """
328
+ return self.flow.get_root_group_manager()
329
+
330
+ def get_group_chat_members(self, agent: WaldiezAgent) -> list[WaldiezAgent]:
297
331
  """Get the chat members that connect to a group chat manager agent.
298
332
 
299
333
  Parameters
@@ -306,23 +340,6 @@ class Waldiez:
306
340
  List[WaldiezAgent]
307
341
  The group chat members.
308
342
  """
309
- if agent.agent_type != "manager":
343
+ if not agent.is_group_manager:
310
344
  return []
311
345
  return self.flow.get_group_chat_members(agent.id)
312
-
313
- def get_swarm_members(
314
- self, initial_agent: WaldiezAgent
315
- ) -> Tuple[List[WaldiezAgent], Optional[WaldiezAgent]]:
316
- """Get the chat members that connect to a swarm agent.
317
-
318
- Parameters
319
- ----------
320
- initial_agent : WaldiezAgent
321
- The initial agent.
322
-
323
- Returns
324
- -------
325
- Tuple[List[WaldiezAgent], Optional[WaldiezAgent]]
326
- The swarm agents and the user agent.
327
- """
328
- return self.flow.get_swarm_chat_members(initial_agent)
waldiez/runner.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Run a waldiez flow.
4
4
 
5
- The flow is first converted to an autogen flow with agents, chats and skills.
5
+ The flow is first converted to an autogen flow with agents, chats, and tools.
6
6
  We then chown to temporary directory, call the flow's `main()` and
7
7
  return the results. Before running the flow, any additional environment
8
8
  variables specified in the waldiez file are set.
@@ -10,14 +10,23 @@ variables specified in the waldiez file are set.
10
10
 
11
11
  # pylint: disable=import-outside-toplevel,reimported
12
12
 
13
+ import gc
13
14
  import importlib.util
14
15
  import sys
15
16
  import tempfile
16
17
  from pathlib import Path
17
- from types import TracebackType
18
- from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union
18
+ from types import ModuleType, TracebackType
19
+ from typing import (
20
+ TYPE_CHECKING,
21
+ Callable,
22
+ Optional,
23
+ Set,
24
+ Type,
25
+ Union,
26
+ )
19
27
 
20
28
  from .exporter import WaldiezExporter
29
+ from .io import StructuredIOStream
21
30
  from .models.waldiez import Waldiez
22
31
  from .running import (
23
32
  a_chdir,
@@ -31,7 +40,6 @@ from .running import (
31
40
  reset_env_vars,
32
41
  set_env_vars,
33
42
  )
34
- from .utils import check_pysqlite3
35
43
 
36
44
  if TYPE_CHECKING:
37
45
  from autogen import ChatResult # type: ignore
@@ -56,8 +64,8 @@ class WaldiezRunner:
56
64
  waldiez_file: Union[str, Path],
57
65
  name: Optional[str] = None,
58
66
  description: Optional[str] = None,
59
- tags: Optional[List[str]] = None,
60
- requirements: Optional[List[str]] = None,
67
+ tags: Optional[list[str]] = None,
68
+ requirements: Optional[list[str]] = None,
61
69
  ) -> "WaldiezRunner":
62
70
  """Create a WaldiezRunner instance from a file.
63
71
 
@@ -69,9 +77,9 @@ class WaldiezRunner:
69
77
  The name of the Waldiez, by default None.
70
78
  description : Optional[str], optional
71
79
  The description of the Waldiez, by default None.
72
- tags : Optional[List[str]], optional
80
+ tags : Optional[list[str]], optional
73
81
  The tags of the Waldiez, by default None.
74
- requirements : Optional[List[str]], optional
82
+ requirements : Optional[list[str]], optional
75
83
  The requirements of the Waldiez, by default None.
76
84
 
77
85
  Returns
@@ -132,6 +140,11 @@ class WaldiezRunner:
132
140
  """Get the Waldiez instance."""
133
141
  return self._waldiez
134
142
 
143
+ @property
144
+ def is_async(self) -> bool:
145
+ """Check if the workflow is async."""
146
+ return self.waldiez.is_async
147
+
135
148
  @property
136
149
  def running(self) -> bool:
137
150
  """Get the running status."""
@@ -148,8 +161,6 @@ class WaldiezRunner:
148
161
  extra_requirements = {
149
162
  req for req in self.waldiez.requirements if req not in sys.modules
150
163
  }
151
- if self.waldiez.has_captain_agents:
152
- check_pysqlite3()
153
164
  return extra_requirements
154
165
 
155
166
  def install_requirements(self) -> None:
@@ -159,7 +170,6 @@ class WaldiezRunner:
159
170
  extra_requirements = self.gather_requirements()
160
171
  if extra_requirements:
161
172
  install_requirements(extra_requirements, printer)
162
- refresh_environment()
163
173
 
164
174
  async def a_install_requirements(self) -> None:
165
175
  """Install the requirements for the flow asynchronously."""
@@ -168,14 +178,36 @@ class WaldiezRunner:
168
178
  extra_requirements = self.gather_requirements()
169
179
  if extra_requirements:
170
180
  await a_install_requirements(extra_requirements, printer)
171
- refresh_environment()
181
+
182
+ def _before_run(
183
+ self,
184
+ temp_dir: Path,
185
+ file_name: str,
186
+ module_name: str,
187
+ printer: Callable[..., None],
188
+ ) -> tuple[ModuleType, dict[str, str]]:
189
+ self._exporter.export(Path(file_name))
190
+ # unique_names = self._exporter.context.get_unique_names()
191
+ spec = importlib.util.spec_from_file_location(
192
+ module_name, temp_dir / file_name
193
+ )
194
+ if not spec or not spec.loader:
195
+ raise ImportError("Could not import the flow")
196
+ sys.path.insert(0, str(temp_dir))
197
+ old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
198
+ module = importlib.util.module_from_spec(spec)
199
+ spec.loader.exec_module(module)
200
+ printer("<Waldiez> - Starting workflow...")
201
+ printer(self.waldiez.info.model_dump_json())
202
+ return module, old_vars
172
203
 
173
204
  def _run(
174
205
  self,
175
206
  output_path: Optional[Union[str, Path]],
176
207
  uploads_root: Optional[Union[str, Path]],
208
+ use_structured_io: bool = False,
177
209
  skip_mmd: bool = False,
178
- ) -> Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]:
210
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
179
211
  """Run the Waldiez workflow.
180
212
 
181
213
  Parameters
@@ -184,12 +216,14 @@ class WaldiezRunner:
184
216
  The output path.
185
217
  uploads_root : Optional[Union[str, Path]]
186
218
  The runtime uploads root.
219
+ use_structured_io : bool
220
+ Whether to use structured IO instead of the default 'input/print'.
187
221
  skip_mmd : bool
188
222
  Whether to skip the Mermaid diagram generation.
189
223
 
190
224
  Returns
191
225
  -------
192
- Union[ChatResult, List[ChatResult]]
226
+ Union[ChatResult, list[ChatResult]]
193
227
  The result(s) of the chat(s).
194
228
  """
195
229
  temp_dir = Path(tempfile.mkdtemp())
@@ -197,8 +231,7 @@ class WaldiezRunner:
197
231
  module_name = file_name.replace(".py", "")
198
232
  if not self._called_install_requirements:
199
233
  self.install_requirements()
200
- else:
201
- refresh_environment()
234
+ refresh_environment()
202
235
  printer = get_printer()
203
236
  printer(
204
237
  "Requirements installed.\n"
@@ -206,21 +239,24 @@ class WaldiezRunner:
206
239
  "you might need to restart the kernel."
207
240
  )
208
241
  results: Union[
209
- "ChatResult", List["ChatResult"], Dict[int, "ChatResult"]
242
+ "ChatResult", list["ChatResult"], dict[int, "ChatResult"]
210
243
  ] = []
211
244
  with chdir(to=temp_dir):
212
- self._exporter.export(Path(file_name))
213
- spec = importlib.util.spec_from_file_location(
214
- module_name, temp_dir / file_name
245
+ module, old_vars = self._before_run(
246
+ temp_dir=temp_dir,
247
+ file_name=file_name,
248
+ module_name=module_name,
249
+ printer=printer,
215
250
  )
216
- if not spec or not spec.loader:
217
- raise ImportError("Could not import the flow")
218
- sys.path.insert(0, str(temp_dir))
219
- old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
220
- module = importlib.util.module_from_spec(spec)
221
- spec.loader.exec_module(module)
222
- printer("<Waldiez> - Starting workflow...")
223
- results = module.main()
251
+ if use_structured_io:
252
+ stream = StructuredIOStream(
253
+ timeout=120, # 2 minutes
254
+ uploads_root=uploads_root,
255
+ )
256
+ with StructuredIOStream.set_default(stream):
257
+ results = module.main()
258
+ else:
259
+ results = module.main()
224
260
  printer("<Waldiez> - Workflow finished")
225
261
  sys.path.pop(0)
226
262
  reset_env_vars(old_vars)
@@ -231,22 +267,24 @@ class WaldiezRunner:
231
267
  flow_name=self.waldiez.name,
232
268
  skip_mmd=skip_mmd,
233
269
  )
270
+ gc.collect()
271
+ refresh_environment()
234
272
  return results
235
273
 
236
274
  async def _a_run(
237
275
  self,
238
276
  output_path: Optional[Union[str, Path]],
239
277
  uploads_root: Optional[Union[str, Path]],
278
+ use_structured_io: bool = False,
240
279
  skip_mmd: bool = False,
241
- ) -> Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]:
280
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
242
281
  """Run the Waldiez workflow asynchronously."""
243
282
  temp_dir = Path(tempfile.mkdtemp())
244
283
  file_name = before_run(output_path, uploads_root)
245
284
  module_name = file_name.replace(".py", "")
246
285
  if not self._called_install_requirements:
247
286
  await self.a_install_requirements()
248
- else:
249
- refresh_environment()
287
+ refresh_environment()
250
288
  printer = get_printer()
251
289
  printer(
252
290
  "Requirements installed.\n"
@@ -254,21 +292,24 @@ class WaldiezRunner:
254
292
  "you might need to restart the kernel."
255
293
  )
256
294
  results: Union[
257
- "ChatResult", List["ChatResult"], Dict[int, "ChatResult"]
295
+ "ChatResult", list["ChatResult"], dict[int, "ChatResult"]
258
296
  ] = []
259
297
  async with a_chdir(to=temp_dir):
260
- self._exporter.export(Path(file_name))
261
- spec = importlib.util.spec_from_file_location(
262
- module_name, temp_dir / file_name
298
+ module, old_vars = self._before_run(
299
+ temp_dir=temp_dir,
300
+ file_name=file_name,
301
+ module_name=module_name,
302
+ printer=printer,
263
303
  )
264
- if not spec or not spec.loader:
265
- raise ImportError("Could not import the flow")
266
- sys.path.insert(0, str(temp_dir))
267
- old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
268
- module = importlib.util.module_from_spec(spec)
269
- spec.loader.exec_module(module)
270
- printer("<Waldiez> - Starting workflow...")
271
- results = await module.main()
304
+ if use_structured_io:
305
+ stream = StructuredIOStream(
306
+ timeout=120, # 2 minutes
307
+ uploads_root=uploads_root,
308
+ )
309
+ with StructuredIOStream.set_default(stream):
310
+ results = await module.main()
311
+ else:
312
+ results = await module.main()
272
313
  sys.path.pop(0)
273
314
  reset_env_vars(old_vars)
274
315
  after_run(
@@ -278,14 +319,17 @@ class WaldiezRunner:
278
319
  flow_name=self.waldiez.name,
279
320
  skip_mmd=skip_mmd,
280
321
  )
322
+ gc.collect()
323
+ refresh_environment()
281
324
  return results
282
325
 
283
326
  def run(
284
327
  self,
285
328
  output_path: Optional[Union[str, Path]] = None,
286
329
  uploads_root: Optional[Union[str, Path]] = None,
330
+ use_structured_io: bool = False,
287
331
  skip_mmd: bool = False,
288
- ) -> Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]:
332
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
289
333
  """Run the Waldiez workflow.
290
334
 
291
335
  Parameters
@@ -294,12 +338,15 @@ class WaldiezRunner:
294
338
  The output path, by default None.
295
339
  uploads_root : Optional[Union[str, Path]], optional
296
340
  The uploads root, to get user-uploaded files, by default None.
341
+ use_structured_io : bool, optional
342
+ Whether to use structured IO instead of the default 'input/print',
343
+ by default False.
297
344
  skip_mmd : bool, optional
298
345
  Whether to skip the Mermaid diagram generation, by default False.
299
346
 
300
347
  Returns
301
348
  -------
302
- Union["ChatResult", List["ChatResult"], Dict[int, "ChatResult"]]
349
+ Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]
303
350
  The result(s) of the chat(s).
304
351
 
305
352
  Raises
@@ -316,6 +363,7 @@ class WaldiezRunner:
316
363
  self._a_run,
317
364
  output_path,
318
365
  uploads_root,
366
+ use_structured_io,
319
367
  skip_mmd,
320
368
  )
321
369
  if self._running is True:
@@ -323,7 +371,12 @@ class WaldiezRunner:
323
371
  self._running = True
324
372
  file_path = output_path or self._file_path
325
373
  try:
326
- return self._run(file_path, uploads_root, skip_mmd)
374
+ return self._run(
375
+ file_path,
376
+ uploads_root=uploads_root,
377
+ use_structured_io=use_structured_io,
378
+ skip_mmd=skip_mmd,
379
+ )
327
380
  finally:
328
381
  self._running = False
329
382
 
@@ -331,7 +384,9 @@ class WaldiezRunner:
331
384
  self,
332
385
  output_path: Optional[Union[str, Path]] = None,
333
386
  uploads_root: Optional[Union[str, Path]] = None,
334
- ) -> Union["ChatResult", List["ChatResult"]]:
387
+ use_structured_io: bool = False,
388
+ skip_mmd: bool = False,
389
+ ) -> Union["ChatResult", list["ChatResult"], dict[int, "ChatResult"]]:
335
390
  """Run the Waldiez workflow asynchronously.
336
391
 
337
392
  Parameters
@@ -340,10 +395,15 @@ class WaldiezRunner:
340
395
  The output path, by default None.
341
396
  uploads_root : Optional[Union[str, Path]], optional
342
397
  The uploads root, to get user-uploaded files, by default None.
398
+ use_structured_io : bool, optional
399
+ Whether to use structured IO instead of the default 'input/print',
400
+ by default False.
401
+ skip_mmd : bool, optional
402
+ Whether to skip the Mermaid diagram generation, by default False.
343
403
 
344
404
  Returns
345
405
  -------
346
- Union[ChatResult, List[ChatResult]]
406
+ Union[ChatResult, list[ChatResult]], dict[int, ChatResult]
347
407
  The result(s) of the chat(s).
348
408
 
349
409
  Raises
@@ -356,6 +416,11 @@ class WaldiezRunner:
356
416
  self._running = True
357
417
  file_path = output_path or self._file_path
358
418
  try:
359
- return await self._a_run(file_path, uploads_root)
419
+ return await self._a_run(
420
+ file_path,
421
+ uploads_root=uploads_root,
422
+ use_structured_io=use_structured_io,
423
+ skip_mmd=skip_mmd,
424
+ )
360
425
  finally:
361
426
  self._running = False