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
@@ -2,19 +2,29 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Base agent class to be inherited by all agents."""
4
4
 
5
- from typing import List, Set
5
+ import warnings
6
+ from typing import TYPE_CHECKING
6
7
 
7
- from pydantic import Field
8
+ from pydantic import Field, field_validator
8
9
  from typing_extensions import Annotated, Literal
9
10
 
10
- from ...common import WaldiezBase, now
11
+ from ...common import (
12
+ WaldiezBase,
13
+ WaldiezGroupOrNestedTarget,
14
+ WaldiezHandoff,
15
+ now,
16
+ )
11
17
  from .agent_data import WaldiezAgentData
12
18
  from .agent_type import WaldiezAgentType
13
19
  from .code_execution import WaldiezAgentCodeExecutionConfig
20
+ from .nested_chat import WaldiezAgentNestedChat, WaldiezAgentNestedChatMessage
21
+
22
+ if TYPE_CHECKING:
23
+ from ...chat import WaldiezChat
14
24
 
15
25
 
16
26
  class WaldiezAgent(WaldiezBase):
17
- """Waldiez Agent.
27
+ """Waldiez Agent to be inherited by all other agents.
18
28
 
19
29
  Attributes
20
30
  ----------
@@ -28,9 +38,9 @@ class WaldiezAgent(WaldiezBase):
28
38
  The name of the agent.
29
39
  description : str
30
40
  The description of the agent.
31
- tags : List[str]
41
+ tags : list[str]
32
42
  Tags for this agent.
33
- requirements : List[str]
43
+ requirements : list[str]
34
44
  Python requirements for the agent.
35
45
  created_at : str
36
46
  The date and time when the agent was created.
@@ -42,9 +52,9 @@ class WaldiezAgent(WaldiezBase):
42
52
 
43
53
  Functions
44
54
  ---------
45
- validate_linked_skills(skill_ids: List[str], agent_ids: List[str])
46
- Validate the skills linked to the agent.
47
- validate_linked_models(model_ids: List[str])
55
+ validate_linked_tools(tool_ids: list[str], agent_ids: list[str])
56
+ Validate the tools linked to the agent.
57
+ validate_linked_models(model_ids: list[str])
48
58
  Validate the models linked to the agent.
49
59
  """
50
60
 
@@ -58,15 +68,15 @@ class WaldiezAgent(WaldiezBase):
58
68
  title="Type",
59
69
  description="The type of the 'node' in a graph.",
60
70
  ),
61
- ]
71
+ ] = "agent"
62
72
  agent_type: Annotated[
63
73
  WaldiezAgentType,
64
74
  Field(
65
75
  ...,
66
76
  title="Agent type",
67
77
  description=(
68
- "The type of the agent: user, assistant, group manager, "
69
- "rag_user, swarm or reasoning"
78
+ "The type of the agent: user_proxy, assistant, group_manager, "
79
+ "rag_user_proxy or reasoning"
70
80
  ),
71
81
  ),
72
82
  ]
@@ -76,27 +86,27 @@ class WaldiezAgent(WaldiezBase):
76
86
  description: Annotated[
77
87
  str,
78
88
  Field(
79
- "Agent's description",
89
+ default="Agent's description",
80
90
  title="Description",
81
91
  description="The description of the agent",
82
92
  ),
83
- ]
93
+ ] = "Agent's description"
84
94
  tags: Annotated[
85
- List[str],
95
+ list[str],
86
96
  Field(
87
97
  title="Tags",
88
98
  description="Tags of the agent",
89
99
  default_factory=list,
90
100
  ),
91
- ]
101
+ ] = []
92
102
  requirements: Annotated[
93
- List[str],
103
+ list[str],
94
104
  Field(
95
105
  title="Requirements",
96
106
  description="Python requirements for the agent",
97
107
  default_factory=list,
98
108
  ),
99
- ]
109
+ ] = []
100
110
  created_at: Annotated[
101
111
  str,
102
112
  Field(
@@ -118,34 +128,195 @@ class WaldiezAgent(WaldiezBase):
118
128
  Field(
119
129
  title="Data",
120
130
  description="The data (properties) of the agent",
121
- default_factory=WaldiezAgentData,
131
+ default_factory=WaldiezAgentData, # pyright: ignore
122
132
  ),
123
133
  ]
124
134
 
135
+ _handoffs: Annotated[
136
+ list[WaldiezHandoff],
137
+ Field(
138
+ init=False, # this is not a field in the constructor
139
+ default_factory=list[WaldiezHandoff],
140
+ title="Handoffs",
141
+ description=(
142
+ "A list of handoffs (target ids) to register. "
143
+ "These are used to transfer control to another agent or chat."
144
+ ),
145
+ ),
146
+ ] = []
147
+
148
+ _checked_nested_chats: Annotated[bool, Field(init=False, default=False)] = (
149
+ False
150
+ )
151
+ _checked_handoffs: Annotated[bool, Field(init=False, default=False)] = False
152
+
153
+ @property
154
+ def handoffs(self) -> list[WaldiezHandoff]:
155
+ """Get the handoffs for this agent.
156
+
157
+ Returns
158
+ -------
159
+ list[WaldiezHandoff]
160
+ The list of handoffs for this agent.
161
+
162
+ Raises
163
+ ------
164
+ RuntimeError
165
+ If handoffs have not been gathered yet.
166
+ """
167
+ if not self._checked_handoffs:
168
+ raise RuntimeError(
169
+ "Handoffs have not been gathered yet. "
170
+ "Call gather_handoffs() first."
171
+ )
172
+ return self._handoffs
173
+
174
+ @field_validator("agent_type")
175
+ @classmethod
176
+ def validate_agent_type(cls, v: WaldiezAgentType) -> WaldiezAgentType:
177
+ """Validate the agent type.
178
+
179
+ Parameters
180
+ ----------
181
+ v : WaldiezAgentType
182
+ The agent type.
183
+
184
+ Returns
185
+ -------
186
+ WaldiezAgentType
187
+ The validated agent type.
188
+
189
+ Raises
190
+ ------
191
+ ValueError
192
+ If the agent type is not valid.
193
+ """
194
+
195
+ def _get_warning_message(old_type: str, new_type: str) -> str:
196
+ return (
197
+ f"The agent type '{old_type}' is deprecated. "
198
+ f"Use '{new_type}' instead."
199
+ )
200
+
201
+ if v == "user":
202
+ warnings.warn(
203
+ _get_warning_message("user", "user_proxy"),
204
+ DeprecationWarning,
205
+ stacklevel=2,
206
+ )
207
+ return "user_proxy"
208
+ if v == "rag_user":
209
+ warnings.warn(
210
+ _get_warning_message("rag_user", "rag_user_proxy"),
211
+ DeprecationWarning,
212
+ stacklevel=2,
213
+ )
214
+ return "rag_user_proxy"
215
+ return v
216
+
217
+ @property
218
+ def is_group_member(self) -> bool:
219
+ """Check if the agent is a group member.
220
+
221
+ Returns
222
+ -------
223
+ bool
224
+ True if the agent is a group member, False otherwise.
225
+ """
226
+ return (
227
+ self.agent_type not in ("group_manager", "manager")
228
+ and self.data.parent_id is not None
229
+ )
230
+
231
+ @property
232
+ def is_captain(self) -> bool:
233
+ """Check if the agent is a captain.
234
+
235
+ Returns
236
+ -------
237
+ bool
238
+ True if the agent is a captain, False otherwise.
239
+ """
240
+ return self.agent_type == "captain"
241
+
242
+ @property
243
+ def is_reasoning(self) -> bool:
244
+ """Check if the agent is a reasoning agent.
245
+
246
+ Returns
247
+ -------
248
+ bool
249
+ True if the agent is a reasoning agent, False otherwise.
250
+ """
251
+ return self.agent_type == "reasoning"
252
+
253
+ @property
254
+ def is_user(self) -> bool:
255
+ """Check if the agent is a user.
256
+
257
+ Returns
258
+ -------
259
+ bool
260
+ True if the agent is a user, False otherwise.
261
+ """
262
+ return self.agent_type in (
263
+ "user",
264
+ "user_proxy",
265
+ "rag_user",
266
+ "rag_user_proxy",
267
+ )
268
+
269
+ @property
270
+ def is_rag_user(self) -> bool:
271
+ """Check if the agent is a RAG user.
272
+
273
+ Returns
274
+ -------
275
+ bool
276
+ True if the agent is a RAG user, False otherwise.
277
+ """
278
+ return self.agent_type in ("rag_user", "rag_user_proxy")
279
+
280
+ @property
281
+ def is_group_manager(self) -> bool:
282
+ """Check if the agent is a group manager.
283
+
284
+ Returns
285
+ -------
286
+ bool
287
+ True if the agent is a group manager, False otherwise.
288
+ """
289
+ return self.agent_type in ("group_manager", "manager")
290
+
125
291
  @property
126
292
  def ag2_class(self) -> str:
127
293
  """Return the AG2 class of the agent."""
128
294
  class_name = "ConversableAgent"
129
- if self.data.is_multimodal:
130
- return "MultimodalConversableAgent"
295
+ if self.is_group_member:
296
+ if (
297
+ getattr(self.data, "is_multimodal", False) is True
298
+ ): # pragma: no branch
299
+ class_name = "MultimodalConversableAgent"
300
+ return class_name
131
301
  if self.agent_type == "assistant":
132
- class_name = "AssistantAgent"
133
- if self.agent_type == "user":
302
+ if getattr(self.data, "is_multimodal", False) is True:
303
+ class_name = "MultimodalConversableAgent"
304
+ else:
305
+ class_name = "AssistantAgent"
306
+ if self.is_user:
134
307
  class_name = "UserProxyAgent"
135
- if self.agent_type == "manager":
136
- class_name = "GroupChatManager"
137
- if self.agent_type == "rag_user":
308
+ if self.is_rag_user:
138
309
  class_name = "RetrieveUserProxyAgent"
139
- if self.agent_type == "swarm":
140
- class_name = "SwarmAgent"
141
- if self.agent_type == "reasoning":
310
+ if self.is_reasoning:
142
311
  class_name = "ReasoningAgent"
143
- if self.agent_type == "captain":
312
+ if self.is_captain:
144
313
  class_name = "CaptainAgent"
145
- return class_name
314
+ if self.is_group_manager:
315
+ class_name = "GroupChatManager"
316
+ return class_name # pragma: no cover
146
317
 
147
318
  @property
148
- def ag2_imports(self) -> Set[str]:
319
+ def ag2_imports(self) -> set[str]:
149
320
  """Return the AG2 imports of the agent."""
150
321
  agent_class = self.ag2_class
151
322
  imports = {"import autogen"}
@@ -153,8 +324,6 @@ class WaldiezAgent(WaldiezBase):
153
324
  imports.add("from autogen import AssistantAgent")
154
325
  elif agent_class == "UserProxyAgent":
155
326
  imports.add("from autogen import UserProxyAgent")
156
- elif agent_class == "GroupChatManager":
157
- imports.add("from autogen import GroupChatManager")
158
327
  elif agent_class == "RetrieveUserProxyAgent":
159
328
  imports.add(
160
329
  "from autogen.agentchat.contrib.retrieve_user_proxy_agent "
@@ -165,16 +334,6 @@ class WaldiezAgent(WaldiezBase):
165
334
  "from autogen.agentchat.contrib.multimodal_conversable_agent "
166
335
  "import MultimodalConversableAgent"
167
336
  )
168
- elif agent_class == "SwarmAgent":
169
- imports.add(
170
- "from autogen import "
171
- "register_hand_off, "
172
- "AfterWork, "
173
- "OnCondition, "
174
- "UpdateSystemMessage, "
175
- "AfterWorkOption, "
176
- "SwarmResult"
177
- )
178
337
  elif agent_class == "ReasoningAgent":
179
338
  imports.add(
180
339
  "from autogen.agents.experimental import ReasoningAgent"
@@ -184,39 +343,41 @@ class WaldiezAgent(WaldiezBase):
184
343
  "from autogen.agentchat.contrib.captainagent "
185
344
  "import CaptainAgent"
186
345
  )
187
- else: # pragma: no cover
188
- imports.add("import ConversableAgent")
346
+ elif agent_class == "GroupChatManager": # pragma: no branch
347
+ imports.add("from autogen import GroupChat")
348
+ imports.add("from autogen.agentchat import GroupChatManager")
349
+ imports.add("from autogen.agentchat.group import ContextVariables")
189
350
  return imports
190
351
 
191
- def validate_linked_skills(
192
- self, skill_ids: List[str], agent_ids: List[str]
352
+ def validate_linked_tools(
353
+ self, tool_ids: list[str], agent_ids: list[str]
193
354
  ) -> None:
194
- """Validate the skills.
355
+ """Validate the tools.
195
356
 
196
357
  Parameters
197
358
  ----------
198
- skill_ids : List[str]
199
- The list of skill IDs.
200
- agent_ids : List[str]
359
+ tool_ids : list[str]
360
+ The list of tool IDs.
361
+ agent_ids : list[str]
201
362
  The list of agent IDs.
202
363
 
203
364
  Raises
204
365
  ------
205
366
  ValueError
206
- If a skill or agent is not found
367
+ If a tool or agent is not found
207
368
  """
208
- # if the config dict has skills, make sure they can be found
209
- for skill in self.data.skills:
210
- if skill.id not in skill_ids:
369
+ # if the config dict has tools, make sure they can be found
370
+ for tool in self.data.tools:
371
+ if tool.id not in tool_ids:
211
372
  raise ValueError(
212
- f"Skill '{skill.id}' not found in agent's {self.id} skills"
373
+ f"Tool '{tool.id}' not found in agent's {self.id} tools"
213
374
  )
214
- if skill.executor_id not in agent_ids:
375
+ if tool.executor_id not in agent_ids:
215
376
  raise ValueError(
216
- f"Agent '{skill.executor_id}' not found in agents"
377
+ f"Agent '{tool.executor_id}' not found in agents"
217
378
  )
218
379
 
219
- def validate_linked_models(self, model_ids: List[str]) -> None:
380
+ def validate_linked_models(self, model_ids: list[str]) -> None:
220
381
  """Validate the models.
221
382
 
222
383
  Parameters
@@ -236,13 +397,13 @@ class WaldiezAgent(WaldiezBase):
236
397
  f"Model '{model}' not found in agent's {self.id} models"
237
398
  )
238
399
 
239
- def validate_code_execution(self, skill_ids: List[str]) -> None:
400
+ def validate_code_execution(self, tool_ids: list[str]) -> None:
240
401
  """Validate the code execution config.
241
402
 
242
403
  Parameters
243
404
  ----------
244
- skill_ids : List[str]
245
- The list of skill IDs.
405
+ tool_ids : list[str]
406
+ The list of tool IDs.
246
407
 
247
408
  Raises
248
409
  ------
@@ -254,7 +415,247 @@ class WaldiezAgent(WaldiezBase):
254
415
  self.data.code_execution_config, WaldiezAgentCodeExecutionConfig
255
416
  ):
256
417
  for function in self.data.code_execution_config.functions:
257
- if function not in skill_ids:
418
+ if function not in tool_ids:
258
419
  raise ValueError(
259
- f"Function '{function}' not found in skills"
420
+ f"Function '{function}' not found in tools"
260
421
  )
422
+
423
+ def gather_nested_chats(
424
+ self,
425
+ all_agents: list["WaldiezAgent"],
426
+ all_chats: list["WaldiezChat"],
427
+ ) -> None:
428
+ """Gather the nested chats for the agent.
429
+
430
+ Parameters
431
+ ----------
432
+ all_agents : list["WaldiezAgent"]
433
+ All the agents in the flow.
434
+ all_chats : list["WaldiezChat"]
435
+ All the chats in the flow.
436
+ """
437
+ if self._checked_nested_chats:
438
+ return
439
+ self._checked_nested_chats = True
440
+ all_chat_ids = {chat.id for chat in all_chats}
441
+ all_agent_ids = {agent.id for agent in all_agents}
442
+ # only use chats that do have messages and "triggered_by"
443
+ nested_chats: list[WaldiezAgentNestedChat] = []
444
+ for chat in self.data.nested_chats:
445
+ if not chat.messages or not chat.triggered_by: # pragma: no cover
446
+ continue
447
+ # make sure the ids exist
448
+ chat.messages = [
449
+ message
450
+ for message in chat.messages
451
+ if message.id in all_chat_ids
452
+ ]
453
+ chat.triggered_by = [
454
+ agent_id
455
+ for agent_id in chat.triggered_by
456
+ if agent_id in all_agent_ids
457
+ ]
458
+ if chat.messages and chat.triggered_by: # pragma: no branch
459
+ nested_chats.append(chat)
460
+ self.data.nested_chats = nested_chats
461
+
462
+ def gather_handoff_ids(
463
+ self,
464
+ group_chats: list["WaldiezChat"],
465
+ nested_chat_id: str,
466
+ ) -> None:
467
+ """Gather all the handoff IDs for this agent.
468
+
469
+ This method will gather all the handoff IDs from the agent's data,
470
+ including those that might not be passed in data.handoffs.
471
+
472
+ Parameters
473
+ ----------
474
+ group_chats : list["WaldiezChat"]
475
+ The list of group chats that this agent is part of.
476
+ nested_chat_id : str
477
+ The ID of the nested chat to include in handoffs if it exists.
478
+
479
+ """
480
+ existing_handoffs = set(self.data.handoffs)
481
+ has_nested_chat = len(self.data.nested_chats) > 0 and any(
482
+ chat.messages for chat in self.data.nested_chats
483
+ )
484
+ # Step 1: Add missing group chat handoffs
485
+ # These are chats between group members (equivalent to groupEdges)
486
+ for chat in group_chats:
487
+ if chat.id not in existing_handoffs:
488
+ self.data.handoffs.append(chat.id)
489
+ existing_handoffs.add(chat.id)
490
+
491
+ # Step 2: Add nested chat if it exists and is not already in handoffs
492
+ if (
493
+ has_nested_chat and nested_chat_id not in existing_handoffs
494
+ ): # pragma: no branch
495
+ self.data.handoffs.append(nested_chat_id)
496
+ existing_handoffs.add(nested_chat_id)
497
+
498
+ # Step 3: Validate all handoffs still exist
499
+ # Remove any handoffs that reference non-existent chats
500
+ valid_chat_ids = {chat.id for chat in group_chats}
501
+ if has_nested_chat: # pragma: no branch
502
+ valid_chat_ids.add(nested_chat_id)
503
+
504
+ # Filter out invalid handoffs
505
+ self.data.handoffs = [
506
+ handoff
507
+ for handoff in self.data.handoffs
508
+ if handoff in valid_chat_ids
509
+ ]
510
+
511
+ def gather_handoffs(
512
+ self,
513
+ all_agents: list["WaldiezAgent"],
514
+ all_chats: list["WaldiezChat"],
515
+ ) -> None:
516
+ """Gather all the handoffs including.
517
+
518
+ Including ones that might not be passed in data.handoffs.
519
+
520
+ Parameters
521
+ ----------
522
+ all_agents : list["WaldiezAgent"]
523
+ The list of all agents in the flow.
524
+ all_chats : list["WaldiezChat"]
525
+ The list of all chats in the flow.
526
+
527
+ """
528
+ self.gather_nested_chats(all_agents, all_chats)
529
+ if not self.is_group_member or self._checked_handoffs:
530
+ return
531
+ nested_chat_id = "nested-chat"
532
+ self._checked_handoffs = True
533
+ group_chats, group_nested_chats = self._get_agent_chats(
534
+ all_agents, all_chats
535
+ )
536
+ if group_nested_chats: # pragma: no branch
537
+ self._ensure_one_nested_chat(group_nested_chats)
538
+ self.gather_handoff_ids(
539
+ group_chats=group_chats, nested_chat_id=nested_chat_id
540
+ )
541
+ # generate the actual handoff instances
542
+ for handoff_id in self.data.handoffs:
543
+ if handoff_id == nested_chat_id:
544
+ nested_chat_handoff = self._generate_handoff_from_nested(
545
+ group_nested_chats
546
+ )
547
+ if nested_chat_handoff: # pragma: no branch
548
+ self._handoffs.append(nested_chat_handoff)
549
+ else:
550
+ chat = next(
551
+ (chat for chat in group_chats if chat.id == handoff_id),
552
+ None,
553
+ )
554
+ if chat: # pragma: no branch
555
+ self._handoffs.append(chat.as_handoff())
556
+
557
+ def _ensure_one_nested_chat(
558
+ self,
559
+ group_nested_chats: list["WaldiezChat"],
560
+ ) -> None:
561
+ """Ensure that there is at least one nested chat."""
562
+ if not self.data.nested_chats: # pragma: no branch
563
+ # create one from the group chats.
564
+ triggered_by = [self.id]
565
+ messages = [
566
+ WaldiezAgentNestedChatMessage(id=chat.id, is_reply=False)
567
+ for chat in group_nested_chats
568
+ ]
569
+ chats_with_condition = [
570
+ chat
571
+ for chat in group_nested_chats
572
+ if chat.condition.is_not_empty()
573
+ ]
574
+ if not chats_with_condition:
575
+ chat_with_condition = group_nested_chats[0]
576
+ else:
577
+ chat_with_condition = chats_with_condition[0]
578
+ nested_chat = WaldiezAgentNestedChat(
579
+ triggered_by=triggered_by,
580
+ messages=messages,
581
+ condition=chat_with_condition.condition, # pyright: ignore
582
+ available=chat_with_condition.available, # pyright: ignore
583
+ )
584
+ self.data.nested_chats.append(nested_chat)
585
+
586
+ def _generate_handoff_from_nested(
587
+ self,
588
+ group_nested_chats: list["WaldiezChat"],
589
+ ) -> WaldiezHandoff | None:
590
+ """Generate a handoff from a nested chat.
591
+
592
+ Parameters
593
+ ----------
594
+ group_nested_chats : list["WaldiezChat"]
595
+ The list of nested (out of the group) chats
596
+ that this agent is part of.
597
+
598
+ Returns
599
+ -------
600
+ WaldiezHandoff | None
601
+ A handoff instance if a nested chat with messages exists,
602
+ otherwise None.
603
+ """
604
+ if not group_nested_chats:
605
+ return None
606
+ # Check if we have any nested chats with messages
607
+ if not self.data.nested_chats or not any(
608
+ chat.messages for chat in self.data.nested_chats
609
+ ):
610
+ return None
611
+ # get the first (and probably only) nested chat
612
+ nested_chat = self.data.nested_chats[0]
613
+ target = WaldiezGroupOrNestedTarget(
614
+ target_type="NestedChatTarget",
615
+ value=[message.id for message in nested_chat.messages],
616
+ )
617
+ return WaldiezHandoff(
618
+ target=target,
619
+ available=nested_chat.available,
620
+ condition=nested_chat.condition,
621
+ )
622
+
623
+ def _get_agent_chats(
624
+ self,
625
+ all_agents: list["WaldiezAgent"],
626
+ all_chats: list["WaldiezChat"],
627
+ ) -> tuple[list["WaldiezChat"], list["WaldiezChat"]]:
628
+ """Get all chats originating from this agent.
629
+
630
+ Parameters
631
+ ----------
632
+ all_agents : list["WaldiezAgent"]
633
+ The list of all agents.
634
+ all_chats : list["WaldiezChat"]
635
+ The list of all chats if the flow.
636
+
637
+ Returns
638
+ -------
639
+ tuple[list["WaldiezChat"], list["WaldiezChat"]]
640
+ A tuple containing two lists:
641
+ - group_chats: Chats that are between group members.
642
+ - group_nested_chats: Chats that are from this agent to an agent
643
+ that is not a group member.
644
+ """
645
+ agent_chats: list["WaldiezChat"] = [
646
+ chat for chat in all_chats if chat.source == self.id
647
+ ]
648
+ group_chats: list["WaldiezChat"] = []
649
+ group_nested_chats: list["WaldiezChat"] = []
650
+ # make sure we have prepared the nested chats
651
+ for chat in agent_chats:
652
+ target_agent = next(
653
+ (agent for agent in all_agents if agent.id == chat.target),
654
+ None,
655
+ )
656
+ if target_agent: # pragma: no branch
657
+ if target_agent.is_group_member:
658
+ group_chats.append(chat)
659
+ else:
660
+ group_nested_chats.append(chat)
661
+ return group_chats, group_nested_chats