waldiez 0.4.7__py3-none-any.whl → 0.4.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of waldiez might be problematic. Click here for more details.

Files changed (244) hide show
  1. waldiez/__init__.py +5 -5
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +112 -73
  4. waldiez/exporter.py +61 -19
  5. waldiez/exporting/__init__.py +25 -6
  6. waldiez/exporting/agent/__init__.py +7 -3
  7. waldiez/exporting/agent/code_execution.py +114 -0
  8. waldiez/exporting/agent/exporter.py +354 -0
  9. waldiez/exporting/agent/extras/__init__.py +15 -0
  10. waldiez/exporting/agent/extras/captain_agent_extras.py +315 -0
  11. waldiez/exporting/agent/extras/group/target.py +178 -0
  12. waldiez/exporting/agent/extras/group_manager_agent_extas.py +500 -0
  13. waldiez/exporting/agent/extras/group_member_extras.py +181 -0
  14. waldiez/exporting/agent/extras/handoffs/__init__.py +19 -0
  15. waldiez/exporting/agent/extras/handoffs/after_work.py +78 -0
  16. waldiez/exporting/agent/extras/handoffs/available.py +74 -0
  17. waldiez/exporting/agent/extras/handoffs/condition.py +158 -0
  18. waldiez/exporting/agent/extras/handoffs/handoff.py +171 -0
  19. waldiez/exporting/agent/extras/handoffs/target.py +189 -0
  20. waldiez/exporting/agent/extras/rag/__init__.py +10 -0
  21. waldiez/exporting/agent/{utils/rag_user/chroma_utils.py → extras/rag/chroma_extras.py} +16 -15
  22. waldiez/exporting/agent/{utils/rag_user/mongo_utils.py → extras/rag/mongo_extras.py} +10 -10
  23. waldiez/exporting/agent/{utils/rag_user/pgvector_utils.py → extras/rag/pgvector_extras.py} +13 -13
  24. waldiez/exporting/agent/{utils/rag_user/qdrant_utils.py → extras/rag/qdrant_extras.py} +13 -13
  25. waldiez/exporting/agent/{utils/rag_user/vector_db.py → extras/rag/vector_db_extras.py} +59 -46
  26. waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +245 -0
  27. waldiez/exporting/agent/extras/reasoning_agent_extras.py +88 -0
  28. waldiez/exporting/agent/factory.py +95 -0
  29. waldiez/exporting/agent/processor.py +150 -0
  30. waldiez/exporting/agent/system_message.py +36 -0
  31. waldiez/exporting/agent/termination.py +50 -0
  32. waldiez/exporting/chats/__init__.py +7 -3
  33. waldiez/exporting/chats/exporter.py +97 -0
  34. waldiez/exporting/chats/factory.py +65 -0
  35. waldiez/exporting/chats/processor.py +226 -0
  36. waldiez/exporting/chats/utils/__init__.py +6 -5
  37. waldiez/exporting/chats/utils/common.py +11 -45
  38. waldiez/exporting/chats/utils/group.py +55 -0
  39. waldiez/exporting/chats/utils/nested.py +37 -52
  40. waldiez/exporting/chats/utils/sequential.py +72 -61
  41. waldiez/exporting/chats/utils/{single_chat.py → single.py} +48 -50
  42. waldiez/exporting/core/__init__.py +196 -0
  43. waldiez/exporting/core/constants.py +17 -0
  44. waldiez/exporting/core/content.py +69 -0
  45. waldiez/exporting/core/context.py +244 -0
  46. waldiez/exporting/core/enums.py +89 -0
  47. waldiez/exporting/core/errors.py +19 -0
  48. waldiez/exporting/core/exporter.py +390 -0
  49. waldiez/exporting/core/exporters.py +67 -0
  50. waldiez/exporting/core/extras/__init__.py +39 -0
  51. waldiez/exporting/core/extras/agent_extras/__init__.py +27 -0
  52. waldiez/exporting/core/extras/agent_extras/captain_extras.py +57 -0
  53. waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +102 -0
  54. waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +53 -0
  55. waldiez/exporting/core/extras/agent_extras/reasoning_extras.py +68 -0
  56. waldiez/exporting/core/extras/agent_extras/standard_extras.py +263 -0
  57. waldiez/exporting/core/extras/base.py +241 -0
  58. waldiez/exporting/core/extras/chat_extras.py +118 -0
  59. waldiez/exporting/core/extras/flow_extras.py +70 -0
  60. waldiez/exporting/core/extras/model_extras.py +73 -0
  61. waldiez/exporting/core/extras/path_resolver.py +93 -0
  62. waldiez/exporting/core/extras/serializer.py +138 -0
  63. waldiez/exporting/core/extras/tool_extras.py +82 -0
  64. waldiez/exporting/core/protocols.py +259 -0
  65. waldiez/exporting/core/result.py +705 -0
  66. waldiez/exporting/core/types.py +329 -0
  67. waldiez/exporting/core/utils/__init__.py +11 -0
  68. waldiez/exporting/core/utils/comment.py +33 -0
  69. waldiez/exporting/core/utils/llm_config.py +117 -0
  70. waldiez/exporting/core/validation.py +96 -0
  71. waldiez/exporting/flow/__init__.py +6 -2
  72. waldiez/exporting/flow/execution_generator.py +193 -0
  73. waldiez/exporting/flow/exporter.py +107 -0
  74. waldiez/exporting/flow/factory.py +94 -0
  75. waldiez/exporting/flow/file_generator.py +214 -0
  76. waldiez/exporting/flow/merger.py +387 -0
  77. waldiez/exporting/flow/orchestrator.py +411 -0
  78. waldiez/exporting/flow/utils/__init__.py +9 -36
  79. waldiez/exporting/flow/utils/common.py +206 -0
  80. waldiez/exporting/flow/utils/importing.py +373 -0
  81. waldiez/exporting/flow/utils/linting.py +200 -0
  82. waldiez/exporting/flow/utils/{logging_utils.py → logging.py} +23 -9
  83. waldiez/exporting/models/__init__.py +3 -1
  84. waldiez/exporting/models/exporter.py +233 -0
  85. waldiez/exporting/models/factory.py +66 -0
  86. waldiez/exporting/models/processor.py +139 -0
  87. waldiez/exporting/tools/__init__.py +11 -0
  88. waldiez/exporting/tools/exporter.py +207 -0
  89. waldiez/exporting/tools/factory.py +57 -0
  90. waldiez/exporting/tools/processor.py +248 -0
  91. waldiez/exporting/tools/registration.py +133 -0
  92. waldiez/io/__init__.py +128 -0
  93. waldiez/io/_ws.py +199 -0
  94. waldiez/io/models/__init__.py +60 -0
  95. waldiez/io/models/base.py +66 -0
  96. waldiez/io/models/constants.py +78 -0
  97. waldiez/io/models/content/__init__.py +23 -0
  98. waldiez/io/models/content/audio.py +43 -0
  99. waldiez/io/models/content/base.py +45 -0
  100. waldiez/io/models/content/file.py +43 -0
  101. waldiez/io/models/content/image.py +96 -0
  102. waldiez/io/models/content/text.py +37 -0
  103. waldiez/io/models/content/video.py +43 -0
  104. waldiez/io/models/user_input.py +269 -0
  105. waldiez/io/models/user_response.py +215 -0
  106. waldiez/io/mqtt.py +681 -0
  107. waldiez/io/redis.py +782 -0
  108. waldiez/io/structured.py +419 -0
  109. waldiez/io/utils.py +184 -0
  110. waldiez/io/ws.py +298 -0
  111. waldiez/logger.py +481 -0
  112. waldiez/models/__init__.py +108 -51
  113. waldiez/models/agents/__init__.py +34 -70
  114. waldiez/models/agents/agent/__init__.py +10 -4
  115. waldiez/models/agents/agent/agent.py +466 -65
  116. waldiez/models/agents/agent/agent_data.py +119 -47
  117. waldiez/models/agents/agent/agent_type.py +13 -2
  118. waldiez/models/agents/agent/code_execution.py +12 -12
  119. waldiez/models/agents/agent/human_input_mode.py +8 -0
  120. waldiez/models/agents/agent/{linked_skill.py → linked_tool.py} +7 -7
  121. waldiez/models/agents/agent/nested_chat.py +35 -7
  122. waldiez/models/agents/agent/termination_message.py +30 -22
  123. waldiez/models/agents/{swarm_agent → agent}/update_system_message.py +22 -22
  124. waldiez/models/agents/agents.py +58 -63
  125. waldiez/models/agents/assistant/assistant.py +4 -4
  126. waldiez/models/agents/assistant/assistant_data.py +13 -1
  127. waldiez/models/agents/{captain_agent → captain}/captain_agent.py +5 -5
  128. waldiez/models/agents/{captain_agent → captain}/captain_agent_data.py +5 -5
  129. waldiez/models/agents/extra_requirements.py +11 -16
  130. waldiez/models/agents/group_manager/group_manager.py +103 -13
  131. waldiez/models/agents/group_manager/group_manager_data.py +36 -14
  132. waldiez/models/agents/group_manager/speakers.py +77 -24
  133. waldiez/models/agents/{rag_user → rag_user_proxy}/__init__.py +16 -16
  134. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +64 -0
  135. waldiez/models/agents/{rag_user/rag_user_data.py → rag_user_proxy/rag_user_proxy_data.py} +6 -5
  136. waldiez/models/agents/{rag_user → rag_user_proxy}/retrieve_config.py +182 -114
  137. waldiez/models/agents/{rag_user → rag_user_proxy}/vector_db_config.py +13 -13
  138. waldiez/models/agents/reasoning/reasoning_agent.py +6 -6
  139. waldiez/models/agents/reasoning/reasoning_agent_data.py +110 -63
  140. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +38 -10
  141. waldiez/models/agents/user_proxy/user_proxy.py +11 -7
  142. waldiez/models/agents/user_proxy/user_proxy_data.py +2 -2
  143. waldiez/models/chat/__init__.py +2 -1
  144. waldiez/models/chat/chat.py +166 -87
  145. waldiez/models/chat/chat_data.py +99 -136
  146. waldiez/models/chat/chat_message.py +33 -23
  147. waldiez/models/chat/chat_nested.py +31 -30
  148. waldiez/models/chat/chat_summary.py +10 -8
  149. waldiez/models/common/__init__.py +52 -2
  150. waldiez/models/common/ag2_version.py +1 -1
  151. waldiez/models/common/base.py +38 -7
  152. waldiez/models/common/dict_utils.py +42 -17
  153. waldiez/models/common/handoff.py +459 -0
  154. waldiez/models/common/id_generator.py +19 -0
  155. waldiez/models/common/method_utils.py +130 -68
  156. waldiez/{exporting/base/utils → models/common}/naming.py +38 -61
  157. waldiez/models/common/waldiez_version.py +37 -0
  158. waldiez/models/flow/__init__.py +9 -2
  159. waldiez/models/flow/connection.py +18 -0
  160. waldiez/models/flow/flow.py +311 -215
  161. waldiez/models/flow/flow_data.py +207 -40
  162. waldiez/models/flow/info.py +85 -0
  163. waldiez/models/flow/naming.py +131 -0
  164. waldiez/models/model/__init__.py +7 -1
  165. waldiez/models/model/extra_requirements.py +3 -12
  166. waldiez/models/model/model.py +76 -21
  167. waldiez/models/model/model_data.py +108 -20
  168. waldiez/models/tool/__init__.py +16 -0
  169. waldiez/models/tool/extra_requirements.py +36 -0
  170. waldiez/models/{skill/skill.py → tool/tool.py} +88 -88
  171. waldiez/models/tool/tool_data.py +51 -0
  172. waldiez/models/tool/tool_type.py +8 -0
  173. waldiez/models/waldiez.py +97 -80
  174. waldiez/runner.py +114 -49
  175. waldiez/running/__init__.py +1 -1
  176. waldiez/running/environment.py +49 -68
  177. waldiez/running/gen_seq_diagram.py +16 -14
  178. waldiez/running/running.py +53 -34
  179. waldiez/utils/__init__.py +0 -4
  180. waldiez/utils/cli_extras/jupyter.py +5 -3
  181. waldiez/utils/cli_extras/runner.py +6 -4
  182. waldiez/utils/cli_extras/studio.py +6 -4
  183. waldiez/utils/conflict_checker.py +15 -9
  184. waldiez/utils/flaml_warnings.py +5 -5
  185. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/METADATA +235 -91
  186. waldiez-0.4.8.dist-info/RECORD +200 -0
  187. waldiez/exporting/agent/agent_exporter.py +0 -297
  188. waldiez/exporting/agent/utils/__init__.py +0 -23
  189. waldiez/exporting/agent/utils/captain_agent.py +0 -263
  190. waldiez/exporting/agent/utils/code_execution.py +0 -65
  191. waldiez/exporting/agent/utils/group_manager.py +0 -220
  192. waldiez/exporting/agent/utils/rag_user/__init__.py +0 -7
  193. waldiez/exporting/agent/utils/rag_user/rag_user.py +0 -209
  194. waldiez/exporting/agent/utils/reasoning.py +0 -36
  195. waldiez/exporting/agent/utils/swarm_agent.py +0 -469
  196. waldiez/exporting/agent/utils/teachability.py +0 -41
  197. waldiez/exporting/agent/utils/termination_message.py +0 -44
  198. waldiez/exporting/base/__init__.py +0 -25
  199. waldiez/exporting/base/agent_position.py +0 -75
  200. waldiez/exporting/base/base_exporter.py +0 -118
  201. waldiez/exporting/base/export_position.py +0 -48
  202. waldiez/exporting/base/import_position.py +0 -23
  203. waldiez/exporting/base/mixin.py +0 -137
  204. waldiez/exporting/base/utils/__init__.py +0 -18
  205. waldiez/exporting/base/utils/comments.py +0 -96
  206. waldiez/exporting/base/utils/path_check.py +0 -68
  207. waldiez/exporting/base/utils/to_string.py +0 -84
  208. waldiez/exporting/chats/chats_exporter.py +0 -240
  209. waldiez/exporting/chats/utils/swarm.py +0 -210
  210. waldiez/exporting/flow/flow_exporter.py +0 -528
  211. waldiez/exporting/flow/utils/agent_utils.py +0 -204
  212. waldiez/exporting/flow/utils/chat_utils.py +0 -71
  213. waldiez/exporting/flow/utils/def_main.py +0 -77
  214. waldiez/exporting/flow/utils/flow_content.py +0 -202
  215. waldiez/exporting/flow/utils/flow_names.py +0 -116
  216. waldiez/exporting/flow/utils/importing_utils.py +0 -227
  217. waldiez/exporting/models/models_exporter.py +0 -199
  218. waldiez/exporting/models/utils.py +0 -174
  219. waldiez/exporting/skills/__init__.py +0 -9
  220. waldiez/exporting/skills/skills_exporter.py +0 -176
  221. waldiez/exporting/skills/utils.py +0 -369
  222. waldiez/models/agents/agent/teachability.py +0 -70
  223. waldiez/models/agents/rag_user/rag_user.py +0 -60
  224. waldiez/models/agents/swarm_agent/__init__.py +0 -50
  225. waldiez/models/agents/swarm_agent/after_work.py +0 -179
  226. waldiez/models/agents/swarm_agent/on_condition.py +0 -105
  227. waldiez/models/agents/swarm_agent/on_condition_available.py +0 -142
  228. waldiez/models/agents/swarm_agent/on_condition_target.py +0 -40
  229. waldiez/models/agents/swarm_agent/swarm_agent.py +0 -107
  230. waldiez/models/agents/swarm_agent/swarm_agent_data.py +0 -124
  231. waldiez/models/flow/utils.py +0 -232
  232. waldiez/models/skill/__init__.py +0 -16
  233. waldiez/models/skill/extra_requirements.py +0 -36
  234. waldiez/models/skill/skill_data.py +0 -53
  235. waldiez/models/skill/skill_type.py +0 -8
  236. waldiez/utils/pysqlite3_checker.py +0 -308
  237. waldiez/utils/rdps_checker.py +0 -122
  238. waldiez-0.4.7.dist-info/RECORD +0 -149
  239. /waldiez/models/agents/{captain_agent → captain}/__init__.py +0 -0
  240. /waldiez/models/agents/{captain_agent → captain}/captain_agent_lib_entry.py +0 -0
  241. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/WHEEL +0 -0
  242. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/entry_points.txt +0 -0
  243. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/licenses/LICENSE +0 -0
  244. {waldiez-0.4.7.dist-info → waldiez-0.4.8.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,178 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=too-few-public-methods
4
+ """Transition target processor for Waldiez agents."""
5
+
6
+ from dataclasses import dataclass, field
7
+ from typing import Callable, Set
8
+
9
+ from waldiez.exporting.chats.utils.nested import get_nested_chat_queue
10
+ from waldiez.models import (
11
+ WaldiezAgent,
12
+ WaldiezAgentTarget,
13
+ WaldiezChat,
14
+ WaldiezGroupOrNestedTarget,
15
+ WaldiezRandomAgentTarget,
16
+ WaldiezTransitionTarget,
17
+ )
18
+
19
+
20
+ @dataclass
21
+ class TargetResult:
22
+ """Result from processing a transition target."""
23
+
24
+ target_string: str = ""
25
+ after_agent: str = ""
26
+ extra_imports: Set[str] = field(default_factory=set) # pyright: ignore
27
+
28
+
29
+ class TransitionTargetProcessor:
30
+ """Processor for transition targets."""
31
+
32
+ def __init__(
33
+ self,
34
+ agent: WaldiezAgent,
35
+ agent_names: dict[str, str],
36
+ chat_names: dict[str, str],
37
+ all_chats: list[WaldiezChat],
38
+ serializer: Callable[..., str],
39
+ ) -> None:
40
+ """Initialize the processor with agent names and context.
41
+
42
+ Parameters
43
+ ----------
44
+ agent_names : dict[str, str]
45
+ Mapping of agent IDs to their names.
46
+ """
47
+ self.agent_names = agent_names
48
+ self.chat_names = chat_names
49
+ self.agent = agent
50
+ self.agent_name = agent_names[agent.id]
51
+ self.all_chats = all_chats
52
+ self.serializer = serializer
53
+
54
+ def process(self, target: WaldiezTransitionTarget) -> TargetResult:
55
+ """Process transition target based on its type.
56
+
57
+ Parameters
58
+ ----------
59
+ target : WaldiezTransitionTarget
60
+ The transition target to process.
61
+
62
+ Returns
63
+ -------
64
+ TargetResult
65
+ The processed result containing the target string,
66
+ after_agent code, and extra imports.
67
+
68
+ Raises
69
+ ------
70
+ ValueError
71
+ If the target type is unknown.
72
+ """
73
+ result = TargetResult()
74
+ where = "autogen.agentchat.group"
75
+ if target.target_type == "GroupManagerTarget":
76
+ where += ".targets.group_manager_target"
77
+ result.extra_imports.add(f"from {where} import {target.target_type}")
78
+
79
+ processors: dict[str, Callable[[WaldiezTransitionTarget], str]] = {
80
+ "AgentTarget": self._process_agent_target,
81
+ "RandomAgentTarget": self._process_random_agent_target,
82
+ "GroupChatTarget": self._process_group_chat_target,
83
+ "NestedChatTarget": self._process_nested_chat_target,
84
+ "AskUserTarget": self._process_simple_target,
85
+ "GroupManagerTarget": self._process_simple_target,
86
+ "RevertToUserTarget": self._process_simple_target,
87
+ "StayTarget": self._process_simple_target,
88
+ "TerminateTarget": self._process_simple_target,
89
+ }
90
+
91
+ processor = processors.get(target.target_type)
92
+ if not processor:
93
+ raise ValueError(f"Unknown target type: {target.target_type}")
94
+
95
+ result.target_string = processor(target)
96
+
97
+ # Special handling for nested chat targets
98
+ if target.target_type == "NestedChatTarget":
99
+ nested_result = self._process_nested_chat_target_full(target)
100
+ result.after_agent = nested_result.after_agent
101
+
102
+ return result
103
+
104
+ def _process_agent_target(self, target: WaldiezTransitionTarget) -> str:
105
+ """Process agent target."""
106
+ if not isinstance(target, WaldiezAgentTarget):
107
+ raise ValueError(
108
+ "Expected WaldiezAgentTarget for agent target processing."
109
+ )
110
+ agent_name = self.agent_names[target.value[0]]
111
+ return f"AgentTarget({agent_name})"
112
+
113
+ def _process_random_agent_target(
114
+ self, target: WaldiezTransitionTarget
115
+ ) -> str:
116
+ """Process random agent target."""
117
+ if not isinstance(target, WaldiezRandomAgentTarget):
118
+ raise ValueError(
119
+ "Expected WaldiezRandomAgentTarget"
120
+ " for random agent target processing."
121
+ )
122
+ agent_vars = [self.agent_names[agent_id] for agent_id in target.value]
123
+ agents_str = ", ".join(agent_vars)
124
+ return f"RandomAgentTarget([{agents_str}])"
125
+
126
+ def _process_group_chat_target(
127
+ self, target: WaldiezTransitionTarget
128
+ ) -> str:
129
+ """Process group chat target."""
130
+ if not isinstance(target, WaldiezGroupOrNestedTarget):
131
+ raise ValueError(
132
+ "Expected WaldiezGroupOrNestedTarget for group chat target "
133
+ "processing."
134
+ )
135
+ chat_name = self.chat_names[target.value[0]]
136
+ return f"GroupChatTarget({chat_name})"
137
+
138
+ def _process_nested_chat_target(self, _: WaldiezTransitionTarget) -> str:
139
+ """Process nested chat target (simple string only)."""
140
+ chat_name = f"{self.agent_name}_handoff_nested_chat_queue"
141
+ target_arg = f'nested_chat_config={{"chat_queue": {chat_name}}}'
142
+ return f"NestedChatTarget({target_arg})"
143
+
144
+ def _process_nested_chat_target_full(
145
+ self, _: WaldiezTransitionTarget
146
+ ) -> TargetResult:
147
+ """Process nested chat target with full configuration."""
148
+ result = TargetResult()
149
+
150
+ chat_queue, extra_methods = get_nested_chat_queue(
151
+ nested_chat=self.agent.data.nested_chats[0],
152
+ agent=self.agent,
153
+ agent_names=self.agent_names,
154
+ chat_names=self.chat_names,
155
+ all_chats=self.all_chats,
156
+ serializer=self.serializer,
157
+ )
158
+
159
+ chat_name = f"{self.agent_name}_handoff_nested_chat_queue"
160
+
161
+ if extra_methods:
162
+ result.after_agent += "\n".join(extra_methods) + "\n"
163
+
164
+ result.after_agent += (
165
+ f"{chat_name}: list[dict[str, Any]] = {chat_queue}\n\n"
166
+ )
167
+ return result
168
+
169
+ # pylint: disable=no-self-use
170
+ def _process_simple_target(self, target: WaldiezTransitionTarget) -> str:
171
+ """Process simple targets that don't need parameters.
172
+
173
+ Parameters
174
+ ----------
175
+ target : WaldiezTransitionTarget
176
+ The target to process.
177
+ """
178
+ return f"{target.target_type}()"
@@ -0,0 +1,500 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=no-self-use,too-few-public-methods
4
+ """Group manager agent configuration processor."""
5
+
6
+ from typing import Callable, Optional
7
+
8
+ from waldiez.models import (
9
+ WaldiezAgent,
10
+ WaldiezAgentConnection,
11
+ WaldiezGroupManager,
12
+ WaldiezModel,
13
+ WaldiezTransitionTarget,
14
+ )
15
+
16
+ from ...core import (
17
+ CodeExecutionConfig,
18
+ GroupManagerExtras,
19
+ GroupManagerStrategy,
20
+ SystemMessageConfig,
21
+ TerminationConfig,
22
+ get_agent_llm_config_arg,
23
+ )
24
+
25
+
26
+ class GroupManagerProcessor:
27
+ """Processes group manager configurations."""
28
+
29
+ def __init__(
30
+ self,
31
+ agent: WaldiezAgent,
32
+ initial_chats: list[WaldiezAgentConnection],
33
+ group_chat_members: list[WaldiezAgent],
34
+ agent_names: dict[str, str],
35
+ model_names: dict[str, str],
36
+ all_models: list[WaldiezModel],
37
+ serializer: Callable[..., str],
38
+ cache_seed: Optional[int] = None,
39
+ ):
40
+ """Initialize the group manager processor.
41
+
42
+ Parameters
43
+ ----------
44
+ agent : WaldiezAgent
45
+ The group manager agent to process.
46
+ initial_chats : list[WaldiezAgentConnection]
47
+ The initial chats to process for the group manager.
48
+ group_chat_members : list[WaldiezAgent]
49
+ The members of the group chat.
50
+ agent_names : dict[str, str]
51
+ Mapping of agent IDs to their names.
52
+ model_names : dict[str, str]
53
+ Mapping of model IDs to their names.
54
+ all_models : list[WaldiezModel]
55
+ List of all models available for the agent.
56
+ serializer : Callable[..., str]
57
+ Function to serialize data into a string format.
58
+ cache_seed : Optional[int], optional
59
+ Seed for caching purposes, by default None.
60
+ """
61
+ self.agent = agent
62
+ self.initial_chats = initial_chats
63
+ self.group_chat_members = group_chat_members
64
+ self.agent_names = agent_names
65
+ self.model_names = model_names
66
+ self.all_models = all_models
67
+ self.serializer = serializer
68
+ self.cache_seed = cache_seed
69
+
70
+ def process(
71
+ self,
72
+ code_execution_config: Optional[CodeExecutionConfig] = None,
73
+ termination_config: Optional[TerminationConfig] = None,
74
+ system_message_config: Optional[SystemMessageConfig] = None,
75
+ ) -> GroupManagerExtras:
76
+ """Process group manager and return extras.
77
+
78
+ Parameters
79
+ ----------
80
+ code_execution_config : CodeExecutionConfig, optional
81
+ Configuration for code execution, by default None.
82
+ termination_config : TerminationConfig, optional
83
+ Configuration for termination, by default None.
84
+ system_message_config : SystemMessageConfig, optional
85
+ Configuration for system messages, by default None.
86
+
87
+ Returns
88
+ -------
89
+ GroupManagerExtras
90
+ The processed group manager extras containing configuration.
91
+ """
92
+ extras = GroupManagerExtras(
93
+ instance_id=self.agent.id,
94
+ code_execution_config=code_execution_config,
95
+ termination_config=termination_config,
96
+ system_message_config=system_message_config,
97
+ )
98
+
99
+ # Determine strategy based on initial chats and message types
100
+ extras.strategy = self._determine_strategy()
101
+
102
+ if extras.strategy == GroupManagerStrategy.PATTERN:
103
+ self._process_pattern_strategy(extras)
104
+ else:
105
+ self._process_traditional_strategy(extras)
106
+
107
+ return extras
108
+
109
+ @staticmethod
110
+ def is_pattern_strategy(
111
+ initial_chats: list[WaldiezAgentConnection],
112
+ ) -> bool:
113
+ """Check if the group manager should use pattern strategy.
114
+
115
+ Parameters
116
+ ----------
117
+ initial_chats : list[WaldiezAgentConnection]
118
+ The initial chats to determine the strategy.
119
+
120
+ Returns
121
+ -------
122
+ bool
123
+ True if pattern strategy should be used, False otherwise.
124
+ """
125
+ if not initial_chats:
126
+ return True
127
+
128
+ first_chat = initial_chats[0]["chat"]
129
+ return (
130
+ isinstance(first_chat.data.message, str)
131
+ or not first_chat.data.message.is_method()
132
+ )
133
+
134
+ def _determine_strategy(self) -> GroupManagerStrategy:
135
+ """Determine which strategy to use for this group manager."""
136
+ if self.is_pattern_strategy(self.initial_chats):
137
+ # Use AG2 Pattern system
138
+ return GroupManagerStrategy.PATTERN
139
+
140
+ # Method call - must use traditional approach
141
+ return GroupManagerStrategy.TRADITIONAL
142
+
143
+ def _process_pattern_strategy(self, extras: GroupManagerExtras) -> None:
144
+ """Process using AG2 Pattern system."""
145
+ extras.pattern_class_name = self._get_pattern_class_name()
146
+
147
+ # Add required imports
148
+ extras.pattern_imports.add(
149
+ "from autogen.agentchat.group.patterns import "
150
+ f"{extras.pattern_class_name}"
151
+ )
152
+
153
+ # Get user agent if applicable
154
+ user_agent = None
155
+ if self.initial_chats:
156
+ user_agent = self.initial_chats[0]["source"]
157
+
158
+ # Generate pattern definition
159
+ extras.pattern_definition = self._generate_pattern_definition(
160
+ extras.pattern_class_name, user_agent
161
+ )
162
+
163
+ # Add context variables if present
164
+ if self.agent.data.context_variables:
165
+ ctx_lines = self._generate_context_variables()
166
+ if ctx_lines:
167
+ extras.context_variables_content = (
168
+ " context_variables=ContextVariables(data={\n"
169
+ + "\n".join(ctx_lines)
170
+ + "\n })"
171
+ )
172
+ extras.pattern_imports.add(
173
+ "from autogen.agentchat.group import ContextVariables"
174
+ )
175
+
176
+ # Add after work configuration if needed
177
+ if self._should_check_for_after_work(extras.pattern_class_name):
178
+ after_work_arg, extra_import = self._get_after_work_configuration()
179
+ if after_work_arg:
180
+ extras.after_work_content = after_work_arg
181
+ if extra_import:
182
+ extras.pattern_imports.add(extra_import)
183
+
184
+ def _process_traditional_strategy(self, extras: GroupManagerExtras) -> None:
185
+ """Process using traditional GroupChat + GroupChatManager."""
186
+ if not self.initial_chats:
187
+ return
188
+
189
+ user_agent = self.initial_chats[0]["source"]
190
+ group_members = self.group_chat_members
191
+ if user_agent not in group_members:
192
+ group_members.append(user_agent)
193
+ admin_name = self.agent_names[user_agent.id]
194
+
195
+ # Generate group chat definition
196
+ group_chat_content = self._generate_group_chat_definition(
197
+ group_members, admin_name
198
+ )
199
+
200
+ extras.group_chat_definition = group_chat_content["definition"]
201
+ extras.group_chat_name = group_chat_content["name"]
202
+ extras.custom_speaker_selection = group_chat_content["custom_selection"]
203
+
204
+ # Generate group chat argument for agent constructor
205
+ if extras.group_chat_name:
206
+ extras.group_chat_argument = f"groupchat={extras.group_chat_name}"
207
+
208
+ def _get_pattern_class_name(self) -> str:
209
+ """Get the appropriate pattern class name."""
210
+ if not isinstance(self.agent, WaldiezGroupManager):
211
+ return "AutoPattern"
212
+ selection_method = self.agent.data.speakers.selection_method
213
+
214
+ pattern_map = {
215
+ "auto": "AutoPattern",
216
+ "manual": "ManualPattern",
217
+ "round_robin": "RoundRobinPattern",
218
+ "random": "RandomPattern",
219
+ "default": "DefaultPattern",
220
+ }
221
+
222
+ return pattern_map.get(selection_method, "AutoPattern")
223
+
224
+ def _generate_pattern_definition(
225
+ self, pattern_class: str, user_agent: Optional[WaldiezAgent]
226
+ ) -> str:
227
+ """Generate the pattern definition string."""
228
+ if not isinstance(self.agent, WaldiezGroupManager):
229
+ return ""
230
+ manager_name = self.agent_names[self.agent.id]
231
+ initial_agent_name = self.agent_names[self.agent.data.initial_agent_id]
232
+ agents_string = ", ".join(
233
+ self.agent_names[agent.id] for agent in self.group_chat_members
234
+ )
235
+
236
+ pattern_lines = [
237
+ f"{manager_name}_pattern = {pattern_class}(",
238
+ f" initial_agent={initial_agent_name},",
239
+ f" agents=[{agents_string}],",
240
+ ]
241
+
242
+ if user_agent:
243
+ pattern_lines.append(
244
+ f" user_agent={self.agent_names[user_agent.id]},"
245
+ )
246
+
247
+ # Add LLM config
248
+ llm_config_arg = get_agent_llm_config_arg(
249
+ agent=self.agent,
250
+ all_models=self.all_models,
251
+ model_names=self.model_names,
252
+ cache_seed=self.cache_seed,
253
+ as_dict=True,
254
+ )
255
+ pattern_lines.append(
256
+ f" group_manager_args={{\n{llm_config_arg} }},"
257
+ )
258
+
259
+ # Add context variables if present
260
+ if self.agent.data.context_variables:
261
+ # Generate context variables lines
262
+ ctx_lines = self._generate_context_variables()
263
+ if ctx_lines:
264
+ pattern_lines.extend(
265
+ [
266
+ " context_variables=ContextVariables(data={",
267
+ *ctx_lines,
268
+ " }),",
269
+ ]
270
+ )
271
+
272
+ # Add after work if applicable
273
+ if self._should_check_for_after_work(pattern_class):
274
+ after_work_arg, _ = self._get_after_work_configuration()
275
+ if after_work_arg:
276
+ pattern_lines.append(f" group_after_work={after_work_arg},")
277
+
278
+ pattern_lines.append(")")
279
+
280
+ return "\n" + "\n".join(pattern_lines)
281
+
282
+ def _generate_group_chat_definition(
283
+ self, group_members: list[WaldiezAgent], admin_name: str
284
+ ) -> dict[str, str]:
285
+ """Generate traditional group chat definition."""
286
+ if not isinstance(self.agent, WaldiezGroupManager):
287
+ return {}
288
+ agent_name = self.agent_names[self.agent.id]
289
+ group_chat_name = f"{agent_name}_group_chat"
290
+
291
+ group_members_str = ", ".join(
292
+ self.agent_names[member.id] for member in group_members
293
+ )
294
+
295
+ lines = [
296
+ f"{group_chat_name} = GroupChat(",
297
+ f" agents=[{group_members_str}],",
298
+ f" enable_clear_history={self.agent.data.enable_clear_history},",
299
+ f" send_introductions={self.agent.data.send_introductions},",
300
+ " messages=[],",
301
+ ]
302
+
303
+ if self.agent.data.max_round > 0:
304
+ lines.append(f" max_round={self.agent.data.max_round},")
305
+
306
+ # Add admin name
307
+ admin = self.agent.data.admin_name or admin_name
308
+ lines.append(f' admin_name="{admin}",')
309
+
310
+ # Add speakers configuration
311
+ speakers_config, custom_selection = (
312
+ self._generate_speakers_configuration()
313
+ )
314
+ lines.extend(speakers_config)
315
+
316
+ lines.append(")")
317
+
318
+ return {
319
+ "definition": "\n" + "\n".join(lines) + "\n",
320
+ "name": group_chat_name,
321
+ "custom_selection": custom_selection or "",
322
+ }
323
+
324
+ def _generate_context_variables(
325
+ self,
326
+ ) -> list[str]:
327
+ """Generate context variables for the group manager agent."""
328
+ ctx_lines: list[str] = []
329
+ for key, value in self.agent.data.context_variables.items():
330
+ if isinstance(value, str):
331
+ ctx_lines.append(f' "{key}": "{value}",')
332
+ else:
333
+ ctx_lines.append(f' "{key}": {value},')
334
+ return ctx_lines
335
+
336
+ def _generate_speakers_configuration(
337
+ self,
338
+ ) -> tuple[list[str], Optional[str]]:
339
+ """Generate speakers configuration for traditional group chat."""
340
+ if not isinstance(self.agent, WaldiezGroupManager):
341
+ return [], None
342
+ config_lines: list[str] = []
343
+ custom_function = None
344
+
345
+ speakers = self.agent.data.speakers
346
+
347
+ # Max retries
348
+ if speakers.max_retries_for_selecting is not None:
349
+ config_lines.append(
350
+ " max_retries_for_selecting_speaker="
351
+ f"{speakers.max_retries_for_selecting},"
352
+ )
353
+
354
+ # Selection method
355
+ if speakers.selection_method != "custom":
356
+ config_lines.append(
357
+ f' speaker_selection_method="{speakers.selection_method}",'
358
+ )
359
+ else:
360
+ # Custom selection method
361
+ agent_name = self.agent_names[self.agent.id]
362
+ custom_function, function_name = (
363
+ speakers.get_custom_method_function(name_suffix=agent_name)
364
+ )
365
+ config_lines.append(
366
+ f" speaker_selection_method={function_name},"
367
+ )
368
+
369
+ # Selection mode configurations
370
+ if speakers.selection_mode == "repeat":
371
+ config_lines.extend(self._generate_repeat_configuration())
372
+ elif speakers.selection_mode == "transition":
373
+ config_lines.extend(self._generate_transition_configuration())
374
+
375
+ # Clean up None values
376
+ config_lines = [line.replace('"None"', "None") for line in config_lines]
377
+
378
+ return config_lines, custom_function
379
+
380
+ def _generate_repeat_configuration(self) -> list[str]:
381
+ """Generate repeat selection configuration."""
382
+ if not isinstance(self.agent, WaldiezGroupManager):
383
+ return []
384
+ lines: list[str] = []
385
+ allow_repeat = self.agent.data.speakers.allow_repeat
386
+
387
+ if isinstance(allow_repeat, bool):
388
+ lines.append(f" allow_repeat_speaker={allow_repeat},")
389
+ else:
390
+ # List of agent names
391
+ agent_names = ", ".join(
392
+ self.agent_names[agent_id] for agent_id in allow_repeat
393
+ )
394
+ lines.append(f" allow_repeat=[{agent_names}],")
395
+
396
+ return lines
397
+
398
+ def _generate_transition_configuration(self) -> list[str]:
399
+ """Generate transition selection configuration."""
400
+ if not isinstance(self.agent, WaldiezGroupManager):
401
+ return []
402
+ lines: list[str] = []
403
+
404
+ if not self.agent.data.speakers.allowed_or_disallowed_transitions:
405
+ return lines
406
+
407
+ # Convert agent IDs to names in transitions
408
+ transitions_dict = {}
409
+ for (
410
+ agent_id,
411
+ transitions,
412
+ ) in self.agent.data.speakers.allowed_or_disallowed_transitions.items():
413
+ agent_name = self.agent_names[agent_id]
414
+ transition_names = [self.agent_names[tid] for tid in transitions]
415
+ transitions_dict[agent_name] = transition_names
416
+
417
+ # Serialize transitions
418
+ transitions_str = self.serializer(transitions_dict, 1)
419
+ transitions_str = transitions_str.replace('"', "").replace("'", "")
420
+
421
+ lines.extend(
422
+ [
423
+ " allowed_or_disallowed_speaker_transitions="
424
+ f"{transitions_str},",
425
+ ' speaker_transitions_type="'
426
+ f'"{self.agent.data.speakers.transitions_type}",',
427
+ ]
428
+ )
429
+
430
+ return lines
431
+
432
+ def _should_check_for_after_work(self, pattern_class: str) -> bool:
433
+ """Check if pattern should have after work configuration."""
434
+ return pattern_class not in ["ManualPattern", "AutoPattern"]
435
+
436
+ def _get_after_work_configuration(self) -> tuple[str, str]:
437
+ """Get after work target configuration."""
438
+ if not self.agent.data.after_work:
439
+ return "", ""
440
+
441
+ return self._get_transition_target(self.agent.data.after_work)
442
+
443
+ def _get_transition_target(
444
+ self, target: WaldiezTransitionTarget
445
+ ) -> tuple[str, str]:
446
+ """Get transition target configuration and import."""
447
+ import_prefix = "from autogen.agentchat.group"
448
+
449
+ target_map = {
450
+ "TerminateTarget": (
451
+ "TerminateTarget()",
452
+ f"{import_prefix} import TerminateTarget",
453
+ ),
454
+ "AskUserTarget": (
455
+ "AskUserTarget()",
456
+ f"{import_prefix} import AskUserTarget",
457
+ ),
458
+ "RevertToUserTarget": (
459
+ "RevertToUserTarget()",
460
+ f"{import_prefix} import RevertToUserTarget",
461
+ ),
462
+ "StayTarget": (
463
+ "StayTarget()",
464
+ f"{import_prefix} import StayTarget",
465
+ ),
466
+ "GroupManagerTarget": (
467
+ "GroupManagerTarget()",
468
+ f"{import_prefix}.targets.group_manager_target "
469
+ "import GroupManagerTarget",
470
+ ),
471
+ }
472
+
473
+ if target.target_type in target_map:
474
+ return target_map[target.target_type]
475
+
476
+ # Special cases
477
+ if target.target_type == "AgentTarget":
478
+ target_name = self.agent_names[target.value[0]]
479
+ return (
480
+ f"AgentTarget(agent={target_name})",
481
+ f"{import_prefix} import AgentTarget",
482
+ )
483
+
484
+ if target.target_type == "RandomAgentTarget":
485
+ target_names = [
486
+ self.agent_names[agent_id] for agent_id in target.value
487
+ ]
488
+ if not target_names:
489
+ target_names = [
490
+ self.agent_names[agent.id]
491
+ for agent in self.group_chat_members
492
+ ]
493
+ target_names_str = ", ".join(target_names)
494
+ return (
495
+ f"RandomAgentTarget(agents=[{target_names_str}])",
496
+ f"{import_prefix}.targets.transition_target "
497
+ "import RandomAgentTarget",
498
+ )
499
+
500
+ return "", ""