waldiez 0.2.1__py3-none-any.whl → 0.3.0__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 (138) hide show
  1. waldiez/__init__.py +2 -0
  2. waldiez/__main__.py +2 -0
  3. waldiez/_version.py +3 -1
  4. waldiez/cli.py +13 -3
  5. waldiez/cli_extras.py +25 -27
  6. waldiez/conflict_checker.py +4 -3
  7. waldiez/exporter.py +28 -105
  8. waldiez/exporting/__init__.py +8 -9
  9. waldiez/exporting/agent/__init__.py +7 -0
  10. waldiez/exporting/agent/agent_exporter.py +279 -0
  11. waldiez/exporting/agent/utils/__init__.py +23 -0
  12. waldiez/exporting/agent/utils/agent_class_name.py +34 -0
  13. waldiez/exporting/agent/utils/agent_imports.py +50 -0
  14. waldiez/exporting/{agents → agent/utils}/code_execution.py +9 -11
  15. waldiez/exporting/{agents → agent/utils}/group_manager.py +47 -35
  16. waldiez/exporting/{agents → agent/utils}/rag_user/__init__.py +2 -0
  17. waldiez/exporting/{agents → agent/utils}/rag_user/chroma_utils.py +22 -17
  18. waldiez/exporting/{agents → agent/utils}/rag_user/mongo_utils.py +14 -10
  19. waldiez/exporting/{agents → agent/utils}/rag_user/pgvector_utils.py +12 -8
  20. waldiez/exporting/{agents → agent/utils}/rag_user/qdrant_utils.py +11 -8
  21. waldiez/exporting/{agents → agent/utils}/rag_user/rag_user.py +78 -55
  22. waldiez/exporting/{agents → agent/utils}/rag_user/vector_db.py +10 -8
  23. waldiez/exporting/agent/utils/swarm_agent.py +463 -0
  24. waldiez/exporting/{agents → agent/utils}/teachability.py +10 -6
  25. waldiez/exporting/{agents → agent/utils}/termination_message.py +7 -8
  26. waldiez/exporting/base/__init__.py +25 -0
  27. waldiez/exporting/base/agent_position.py +75 -0
  28. waldiez/exporting/base/base_exporter.py +118 -0
  29. waldiez/exporting/base/export_position.py +48 -0
  30. waldiez/exporting/base/import_position.py +23 -0
  31. waldiez/exporting/base/mixin.py +134 -0
  32. waldiez/exporting/base/utils/__init__.py +18 -0
  33. waldiez/exporting/{utils → base/utils}/comments.py +12 -55
  34. waldiez/exporting/{utils → base/utils}/naming.py +14 -4
  35. waldiez/exporting/base/utils/path_check.py +68 -0
  36. waldiez/exporting/{utils/object_string.py → base/utils/to_string.py} +21 -20
  37. waldiez/exporting/chats/__init__.py +5 -12
  38. waldiez/exporting/chats/chats_exporter.py +240 -0
  39. waldiez/exporting/chats/utils/__init__.py +15 -0
  40. waldiez/exporting/chats/utils/common.py +81 -0
  41. waldiez/exporting/chats/{nested.py → utils/nested.py} +125 -86
  42. waldiez/exporting/chats/utils/sequential.py +244 -0
  43. waldiez/exporting/chats/utils/single_chat.py +313 -0
  44. waldiez/exporting/chats/utils/swarm.py +207 -0
  45. waldiez/exporting/flow/__init__.py +5 -3
  46. waldiez/exporting/flow/flow_exporter.py +503 -0
  47. waldiez/exporting/flow/utils/__init__.py +47 -0
  48. waldiez/exporting/flow/utils/agent_utils.py +204 -0
  49. waldiez/exporting/flow/utils/chat_utils.py +71 -0
  50. waldiez/exporting/flow/utils/def_main.py +62 -0
  51. waldiez/exporting/flow/utils/flow_content.py +112 -0
  52. waldiez/exporting/flow/utils/flow_names.py +115 -0
  53. waldiez/exporting/flow/utils/importing_utils.py +179 -0
  54. waldiez/exporting/{utils → flow/utils}/logging_utils.py +34 -31
  55. waldiez/exporting/models/__init__.py +7 -242
  56. waldiez/exporting/models/models_exporter.py +192 -0
  57. waldiez/exporting/models/utils.py +166 -0
  58. waldiez/exporting/skills/__init__.py +7 -161
  59. waldiez/exporting/skills/skills_exporter.py +169 -0
  60. waldiez/exporting/skills/utils.py +281 -0
  61. waldiez/models/__init__.py +25 -7
  62. waldiez/models/agents/__init__.py +70 -0
  63. waldiez/models/agents/agent/__init__.py +11 -1
  64. waldiez/models/agents/agent/agent.py +9 -4
  65. waldiez/models/agents/agent/agent_data.py +3 -1
  66. waldiez/models/agents/agent/code_execution.py +2 -0
  67. waldiez/models/agents/agent/linked_skill.py +2 -0
  68. waldiez/models/agents/agent/nested_chat.py +2 -0
  69. waldiez/models/agents/agent/teachability.py +2 -0
  70. waldiez/models/agents/agent/termination_message.py +49 -13
  71. waldiez/models/agents/agents.py +15 -3
  72. waldiez/models/agents/assistant/__init__.py +2 -0
  73. waldiez/models/agents/assistant/assistant.py +2 -0
  74. waldiez/models/agents/assistant/assistant_data.py +2 -0
  75. waldiez/models/agents/group_manager/__init__.py +9 -1
  76. waldiez/models/agents/group_manager/group_manager.py +2 -0
  77. waldiez/models/agents/group_manager/group_manager_data.py +2 -0
  78. waldiez/models/agents/group_manager/speakers.py +49 -13
  79. waldiez/models/agents/rag_user/__init__.py +21 -4
  80. waldiez/models/agents/rag_user/rag_user.py +3 -1
  81. waldiez/models/agents/rag_user/rag_user_data.py +2 -0
  82. waldiez/models/agents/rag_user/retrieve_config.py +268 -17
  83. waldiez/models/agents/rag_user/vector_db_config.py +5 -3
  84. waldiez/models/agents/swarm_agent/__init__.py +49 -0
  85. waldiez/models/agents/swarm_agent/after_work.py +178 -0
  86. waldiez/models/agents/swarm_agent/on_condition.py +103 -0
  87. waldiez/models/agents/swarm_agent/on_condition_available.py +140 -0
  88. waldiez/models/agents/swarm_agent/on_condition_target.py +40 -0
  89. waldiez/models/agents/swarm_agent/swarm_agent.py +107 -0
  90. waldiez/models/agents/swarm_agent/swarm_agent_data.py +125 -0
  91. waldiez/models/agents/swarm_agent/update_system_message.py +144 -0
  92. waldiez/models/agents/user_proxy/__init__.py +2 -0
  93. waldiez/models/agents/user_proxy/user_proxy.py +2 -0
  94. waldiez/models/agents/user_proxy/user_proxy_data.py +2 -0
  95. waldiez/models/chat/__init__.py +21 -3
  96. waldiez/models/chat/chat.py +241 -7
  97. waldiez/models/chat/chat_data.py +192 -48
  98. waldiez/models/chat/chat_message.py +153 -144
  99. waldiez/models/chat/chat_nested.py +33 -53
  100. waldiez/models/chat/chat_summary.py +2 -0
  101. waldiez/models/common/__init__.py +6 -6
  102. waldiez/models/common/base.py +4 -1
  103. waldiez/models/common/method_utils.py +163 -83
  104. waldiez/models/flow/__init__.py +2 -0
  105. waldiez/models/flow/flow.py +176 -40
  106. waldiez/models/flow/flow_data.py +63 -2
  107. waldiez/models/flow/utils.py +172 -0
  108. waldiez/models/model/__init__.py +2 -0
  109. waldiez/models/model/model.py +25 -6
  110. waldiez/models/model/model_data.py +3 -1
  111. waldiez/models/skill/__init__.py +4 -1
  112. waldiez/models/skill/skill.py +30 -2
  113. waldiez/models/skill/skill_data.py +2 -0
  114. waldiez/models/waldiez.py +28 -4
  115. waldiez/runner.py +142 -228
  116. waldiez/running/__init__.py +33 -0
  117. waldiez/running/environment.py +83 -0
  118. waldiez/running/gen_seq_diagram.py +185 -0
  119. waldiez/running/running.py +300 -0
  120. {waldiez-0.2.1.dist-info → waldiez-0.3.0.dist-info}/METADATA +36 -30
  121. waldiez-0.3.0.dist-info/RECORD +125 -0
  122. waldiez-0.3.0.dist-info/licenses/LICENSE +201 -0
  123. waldiez/exporting/agents/__init__.py +0 -5
  124. waldiez/exporting/agents/agent.py +0 -236
  125. waldiez/exporting/agents/agent_skills.py +0 -67
  126. waldiez/exporting/agents/llm_config.py +0 -53
  127. waldiez/exporting/chats/chats.py +0 -46
  128. waldiez/exporting/chats/helpers.py +0 -420
  129. waldiez/exporting/flow/def_main.py +0 -32
  130. waldiez/exporting/flow/flow.py +0 -189
  131. waldiez/exporting/utils/__init__.py +0 -36
  132. waldiez/exporting/utils/importing.py +0 -265
  133. waldiez/exporting/utils/method_utils.py +0 -35
  134. waldiez/exporting/utils/path_check.py +0 -51
  135. waldiez-0.2.1.dist-info/RECORD +0 -92
  136. waldiez-0.2.1.dist-info/licenses/LICENSE +0 -21
  137. {waldiez-0.2.1.dist-info → waldiez-0.3.0.dist-info}/WHEEL +0 -0
  138. {waldiez-0.2.1.dist-info → waldiez-0.3.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,463 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=unused-argument
4
+ """Get the extras for a swarm agent."""
5
+
6
+ from typing import Callable, Dict, List, Tuple
7
+
8
+ from waldiez.exporting.chats.utils.nested import get_nested_chat_queue
9
+ from waldiez.models import (
10
+ WaldiezAgent,
11
+ WaldiezChat,
12
+ WaldiezSwarmAfterWork,
13
+ WaldiezSwarmAgent,
14
+ WaldiezSwarmOnCondition,
15
+ WaldiezSwarmUpdateSystemMessage,
16
+ )
17
+
18
+ # SwarmAgent is a subclass of ConversableAgent.
19
+
20
+ # Additional args:
21
+ # functions (List[Callable]):
22
+ # -A list of functions to register with the agent.
23
+ # update_agent_state_before_reply (List[Callable]):
24
+ # - A list of functions, including UPDATE_SYSTEM_MESSAGEs,
25
+ # called to update the agent before it replies.
26
+
27
+ # Additional methods:
28
+ # register_hand_off(hand_offs: List[AfterWork|OnCondition]):
29
+
30
+
31
+ def get_swarm_extras(
32
+ agent: WaldiezAgent,
33
+ agent_names: Dict[str, str],
34
+ skill_names: Dict[str, str],
35
+ chats: Tuple[List[WaldiezChat], Dict[str, str]],
36
+ is_async: bool,
37
+ serializer: Callable[..., str],
38
+ string_escape: Callable[[str], str],
39
+ ) -> Tuple[str, str, str]:
40
+ """Get the extras of a swarm agent.
41
+
42
+ Parameters
43
+ ----------
44
+ agent : WaldiezAgent
45
+ The agent to get the extras for.
46
+ agent_names : Dict[str, str]
47
+ A mapping of agent IDs to agent names.
48
+ skill_names : Dict[str, str]
49
+ A mapping of skill IDs to skill names.
50
+ chats : Tuple[List[WaldiezChat], Dict[str, str]]
51
+ The list of all chats and the mapping of chat IDs to chat names.
52
+ is_async : bool
53
+ Whether the chat is asynchronous.
54
+ serializer : Callable[..., str]
55
+ The serializer to get the string representation of an object.
56
+ string_escape : Callable[[str], str]
57
+ The function to escape the string quotes and newlines.
58
+ Returns
59
+ -------
60
+ Tuple[str, str, str]
61
+ The extras of the swarm agent:
62
+ the content before the agent,
63
+ the extra argument(s) for the agent initialization,
64
+ and the content after the agent.
65
+ """
66
+ args_string = ""
67
+ before_agent = ""
68
+ after_agent = ""
69
+ if agent.agent_type != "swarm" or not isinstance(agent, WaldiezSwarmAgent):
70
+ return args_string, before_agent, after_agent
71
+ args_string = get_function_arg(agent, skill_names)
72
+ before_reply = get_update_agent_state_before_reply_arg(
73
+ agent=agent,
74
+ agent_names=agent_names,
75
+ skill_names=skill_names,
76
+ string_escape=string_escape,
77
+ )
78
+ args_string += before_reply[0]
79
+ before_agent += before_reply[1]
80
+ before_registration, after_agent = get_agent_handoff_registrations(
81
+ agent=agent,
82
+ agent_names=agent_names,
83
+ all_chats=chats[0],
84
+ chat_names=chats[1],
85
+ is_async=is_async,
86
+ serializer=serializer,
87
+ string_escape=string_escape,
88
+ )
89
+ before_agent += before_registration
90
+ return before_agent, args_string, after_agent
91
+
92
+
93
+ def get_function_arg(
94
+ agent: WaldiezSwarmAgent,
95
+ skill_names: Dict[str, str],
96
+ ) -> str:
97
+ """Get the function argument of a swarm agent.
98
+
99
+ Parameters
100
+ ----------
101
+ agent : WaldiezSwarmAgent
102
+ The swarm agent to get the function argument for.
103
+ skill_names : Dict[str, str]
104
+ A mapping of skill IDs to skill names.
105
+
106
+ Returns
107
+ -------
108
+ str
109
+ The function argument of the swarm agent.
110
+ """
111
+ tab = " "
112
+ arg_string = f"{tab}functions=["
113
+ added_skills = False
114
+ for function in agent.data.functions:
115
+ skill_name = skill_names.get(function, "")
116
+ if skill_name:
117
+ arg_string += "\n" + f"{tab}{tab}{skill_name},"
118
+ added_skills = True
119
+ if added_skills:
120
+ arg_string += "\n" + tab
121
+ arg_string += "],\n"
122
+ return arg_string
123
+
124
+
125
+ def get_update_agent_state_before_reply_arg(
126
+ agent: WaldiezSwarmAgent,
127
+ agent_names: Dict[str, str],
128
+ skill_names: Dict[str, str],
129
+ string_escape: Callable[[str], str],
130
+ ) -> Tuple[str, str]:
131
+ """Get the update_agent_state_before_reply argument of a swarm agent.
132
+
133
+ Parameters
134
+ ----------
135
+ agent : WaldiezSwarmAgent
136
+ The swarm agent to get the argument for.
137
+ agent_names : Dict[str, str]
138
+ A mapping of agent IDs to agent names.
139
+ skill_names : Dict[str, str]
140
+ A mapping of skill IDs to skill names.
141
+ string_escape : Callable[[str], str]
142
+ The function to escape the string quotes and newlines.
143
+
144
+ Returns
145
+ -------
146
+ Tuple[str, str]
147
+ The update_agent_state_before_reply argument of the swarm agent
148
+ and the content before the agent if any.
149
+ """
150
+ # update_function_type : Literal["string", "callable"]
151
+ # The type of the update function. Can be either a string or a callable.
152
+ # update_function : str
153
+ # "The string template or function definition to update "
154
+ # "the agent's system message. Can be a string or a Callable. "
155
+ # "If the function_type is 'string' it will be used as a "
156
+ # "template and substitute the context variables. "
157
+ # ag2 checks for: vars = re.findall(r"\{(\w+)\}", function)
158
+ # "If function_type is 'callable', it should have signature:
159
+ # "def custom_update_system_message("
160
+ # " agent: ConversableAgent, "
161
+ # " messages: List[Dict[str, Any]]
162
+ # ) -> str"
163
+ tab = " "
164
+ before_agent = ""
165
+ arg_string = f"{tab}update_agent_state_before_reply=["
166
+ added_functions = False
167
+ # pylint: disable=line-too-long
168
+ for function in agent.data.update_agent_state_before_reply:
169
+ if isinstance(function, WaldiezSwarmUpdateSystemMessage):
170
+ added_functions = True
171
+ if function.update_function_type == "callable":
172
+ function_content, function_name = function.get_update_function(
173
+ name_suffix=agent_names[agent.id],
174
+ )
175
+ arg_string += (
176
+ "\n" + f"{tab}{tab}UPDATE_SYSTEM_MESSAGE({function_name}),"
177
+ )
178
+ before_agent += "\n" + function_content + "\n"
179
+ else:
180
+ escaped_function = string_escape(function.update_function)
181
+ arg_string += (
182
+ "\n"
183
+ + f'{tab}{tab}UPDATE_SYSTEM_MESSAGE("{escaped_function}"),'
184
+ )
185
+ else:
186
+ skill_name = skill_names.get(function, "")
187
+ if skill_name:
188
+ added_functions = True
189
+ arg_string += "\n" + f"{tab}{tab}{skill_name},"
190
+ if added_functions:
191
+ arg_string = arg_string + "\n" + tab
192
+ arg_string += "],\n"
193
+ return arg_string, before_agent
194
+
195
+
196
+ def get_agent_handoff_registrations(
197
+ agent: WaldiezSwarmAgent,
198
+ agent_names: Dict[str, str],
199
+ all_chats: List[WaldiezChat],
200
+ chat_names: Dict[str, str],
201
+ is_async: bool,
202
+ serializer: Callable[..., str],
203
+ string_escape: Callable[[str], str],
204
+ ) -> Tuple[str, str]:
205
+ """Get the agent handoff registrations of a swarm agent.
206
+
207
+ Parameters
208
+ ----------
209
+ agent : WaldiezSwarmAgent
210
+ The swarm agent to get the agent handoff registrations for.
211
+ agent_names : Dict[str, str]
212
+ A mapping of agent IDs to agent names.
213
+ all_chats : List[WaldiezChat]
214
+ The list of all chats.
215
+ chat_names : Dict[str, str]
216
+ A mapping of chat IDs to chat names.
217
+ is_async : bool
218
+ Whether the chat is asynchronous.
219
+ serializer : Callable[..., str]
220
+ The serializer to get the string representation of an object.
221
+ string_escape : Callable[[str], str]
222
+ The function to escape the string quotes and newlines.
223
+
224
+ Returns
225
+ -------
226
+ Tuple[str, str]
227
+ the contents before and after the agent.
228
+ """
229
+ agent_name = agent_names[agent.id]
230
+ registrations = []
231
+ before_agent = ""
232
+ after_agent = ""
233
+ if not agent.handoffs:
234
+ return before_agent, after_agent
235
+ tab = " "
236
+ after_agent = f"{agent_name}.register_hand_off(" + "\n" + f"{tab}[" + "\n"
237
+ for hand_off in agent.handoffs:
238
+ if isinstance(hand_off, WaldiezSwarmOnCondition):
239
+ registration, before_handoff = get_agent_on_condition_handoff(
240
+ agent=agent,
241
+ hand_off=hand_off,
242
+ agent_names=agent_names,
243
+ all_chats=all_chats,
244
+ chat_names=chat_names,
245
+ is_async=is_async,
246
+ serializer=serializer,
247
+ string_escape=string_escape,
248
+ )
249
+ if registration:
250
+ registrations.append(registration)
251
+ before_agent += before_handoff
252
+ elif isinstance(hand_off, WaldiezSwarmAfterWork):
253
+ registration, before_handoff = get_agent_after_work_handoff(
254
+ hand_off=hand_off,
255
+ agent_names=agent_names,
256
+ agent_name=agent_name,
257
+ )
258
+ registrations.append(registration)
259
+ before_agent += before_handoff
260
+ after_agent += "\n".join(registrations) + "\n" + f"{tab}]" + "\n" + ")"
261
+ return before_agent, after_agent
262
+
263
+
264
+ def get_agent_after_work_handoff(
265
+ hand_off: WaldiezSwarmAfterWork,
266
+ agent_names: Dict[str, str],
267
+ agent_name: str,
268
+ ) -> Tuple[str, str]:
269
+ """Get the agent's after work hand off registration.
270
+
271
+ Parameters
272
+ ----------
273
+ hand_off : WaldiezSwarmAfterWork
274
+ The hand off to get the registration for.
275
+ agent_names : Dict[str, str]
276
+ A mapping of agent IDs to agent names.
277
+ agent_name : str
278
+ The name of the agent to register the hand off.
279
+
280
+ Returns
281
+ -------
282
+ Tuple[str, str]
283
+ The registration and the content before the agent.
284
+ """
285
+ before_agent = ""
286
+ tab = " "
287
+ recipient_type = hand_off.recipient_type
288
+ recipient, function_content = hand_off.get_recipient(
289
+ agent_names=agent_names,
290
+ name_suffix=agent_name,
291
+ )
292
+ registration = f"{tab}{tab}{recipient},"
293
+ if recipient_type == "callable" and function_content:
294
+ before_agent += "\n" + function_content + "\n"
295
+ return registration, before_agent
296
+
297
+
298
+ def get_agent_on_condition_handoff(
299
+ agent: WaldiezSwarmAgent,
300
+ hand_off: WaldiezSwarmOnCondition,
301
+ agent_names: Dict[str, str],
302
+ all_chats: List[WaldiezChat],
303
+ chat_names: Dict[str, str],
304
+ is_async: bool,
305
+ serializer: Callable[..., str],
306
+ string_escape: Callable[[str], str],
307
+ ) -> Tuple[str, str]:
308
+ """Get the agent's on condition hand off registration.
309
+
310
+ Parameters
311
+ ----------
312
+ agent : WaldiezSwarmAgent
313
+ The agent to get the registration for.
314
+ hand_off : WaldiezSwarmAfterWork
315
+ The hand off to get the registration for.
316
+ agent_names : Dict[str, str]
317
+ A mapping of agent IDs to agent names.
318
+ all_chats : List[WaldiezChat]
319
+ The list of all chats.
320
+ chat_names : Dict[str, str]
321
+ A mapping of chat IDs to chat names.
322
+ is_async : bool
323
+ Whether the chat is asynchronous.
324
+ serializer : Callable[..., str]
325
+ The serializer to get the string representation of an object.
326
+ string_escape : Callable[[str], str]
327
+ The function to escape the string quotes and newlines.
328
+
329
+ Returns
330
+ -------
331
+ Tuple[str, str]
332
+ The registration and the content before the agent.
333
+ """
334
+ before_agent = ""
335
+ registration = ""
336
+ available, available_function = hand_off.get_available(
337
+ name_suffix=agent_names[agent.id],
338
+ )
339
+ if available and not available_function:
340
+ available = f'"{string_escape(available)}"'
341
+ if hand_off.target_type == "agent":
342
+ recipient = agent_names[hand_off.target.id]
343
+ condition = (
344
+ string_escape(hand_off.condition) or f"Transfer to {recipient}"
345
+ )
346
+ results = _get_agent_on_condition_handoff_to_agent(
347
+ recipient=recipient,
348
+ available=available,
349
+ condition=condition,
350
+ available_function=available_function,
351
+ )
352
+ before_agent += results[0]
353
+ registration = results[1]
354
+ # else: # target_type == "nested_chat"
355
+ if hand_off.target_type == "nested_chat":
356
+ condition = _get_condition_string(
357
+ condition=hand_off.condition,
358
+ chat_id=hand_off.target.id,
359
+ all_chats=all_chats,
360
+ agent_names=agent_names,
361
+ )
362
+ results = _get_agent_on_condition_handoff_to_nested_chat(
363
+ agent=agent,
364
+ agent_names=agent_names,
365
+ condition=hand_off.condition,
366
+ available=available,
367
+ available_function=available_function,
368
+ all_chats=all_chats,
369
+ chat_names=chat_names,
370
+ is_async=is_async,
371
+ serializer=serializer,
372
+ string_escape=string_escape,
373
+ )
374
+ before_agent += results[0]
375
+ registration = results[1]
376
+ return registration, before_agent
377
+
378
+
379
+ def _get_agent_on_condition_handoff_to_agent(
380
+ recipient: str,
381
+ available: str,
382
+ condition: str,
383
+ available_function: str,
384
+ ) -> Tuple[str, str]:
385
+ before_agent = ""
386
+ tab = " "
387
+ on_condition = (
388
+ f"{tab}{tab}ON_CONDITION(" + "\n"
389
+ f"{tab}{tab}{tab}target={recipient}," + "\n"
390
+ f'{tab}{tab}{tab}condition="{condition}",' + "\n"
391
+ )
392
+ if available:
393
+ on_condition += f"{tab}{tab}{tab}available={available}," + "\n"
394
+ if available_function:
395
+ before_agent += "\n" + available_function + "\n"
396
+ on_condition += f"{tab}{tab}),"
397
+ return before_agent, on_condition
398
+
399
+
400
+ # pylint: disable=too-many-locals
401
+ def _get_agent_on_condition_handoff_to_nested_chat(
402
+ agent: WaldiezAgent,
403
+ agent_names: Dict[str, str],
404
+ condition: str,
405
+ available: str,
406
+ available_function: str,
407
+ all_chats: List[WaldiezChat],
408
+ chat_names: Dict[str, str],
409
+ is_async: bool,
410
+ serializer: Callable[..., str],
411
+ string_escape: Callable[[str], str],
412
+ ) -> Tuple[str, str]:
413
+ if not agent.data.nested_chats or not agent.data.nested_chats[0].messages:
414
+ return "", ""
415
+ chat_queue, extra_methods = get_nested_chat_queue(
416
+ nested_chat=agent.data.nested_chats[0],
417
+ agent=agent,
418
+ agent_names=agent_names,
419
+ chat_names=chat_names,
420
+ all_chats=all_chats,
421
+ serializer=serializer,
422
+ string_escape=string_escape,
423
+ )
424
+ if not chat_queue:
425
+ return "", ""
426
+ before_agent = ""
427
+ tab = " "
428
+ chat_queue_var_name = f"{agent_names[agent.id]}_handoff_nested_chat_queue"
429
+ if extra_methods:
430
+ before_agent += "\n".join(extra_methods) + "\n"
431
+ before_agent += f"{chat_queue_var_name} = {chat_queue} " + "\n"
432
+ condition_string = string_escape(condition)
433
+ on_condition = (
434
+ f"{tab}{tab}ON_CONDITION(" + "\n"
435
+ f"{tab}{tab}{tab}target=" + "{\n"
436
+ f'{tab}{tab}{tab}{tab}"chat_queue": {chat_queue_var_name},' + "\n"
437
+ f'{tab}{tab}{tab}{tab}"config": None,' + "\n"
438
+ f'{tab}{tab}{tab}{tab}"reply_func_from_nested_chats": None,' + "\n"
439
+ f'{tab}{tab}{tab}{tab}"use_async": {is_async},' + "\n"
440
+ f"{tab}{tab}{tab}" + "},\n"
441
+ f'{tab}{tab}{tab}condition="{condition_string}",' + "\n"
442
+ )
443
+ if available:
444
+ on_condition += f"{tab}{tab}{tab}available={available}," + "\n"
445
+ if available_function:
446
+ before_agent += "\n" + available_function + "\n"
447
+ on_condition += f"{tab}{tab}),"
448
+ return before_agent, on_condition
449
+
450
+
451
+ def _get_condition_string(
452
+ condition: str,
453
+ chat_id: str,
454
+ all_chats: List[WaldiezChat],
455
+ agent_names: Dict[str, str],
456
+ ) -> str:
457
+ if not condition:
458
+ chat = next((c for c in all_chats if c.id == chat_id), None)
459
+ if chat:
460
+ target_name = agent_names[chat.target]
461
+ return f"Transfer to {target_name}"
462
+ return "Transfer to the next agent"
463
+ return condition
@@ -1,3 +1,5 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
1
3
  """Exporting teachability data for agents."""
2
4
 
3
5
  from typing import Dict
@@ -23,15 +25,17 @@ def get_agent_teachability_string(
23
25
  str
24
26
  The teachability string
25
27
  """
26
- if not agent.data.teachability.enabled:
28
+ if not agent.data.teachability or not agent.data.teachability.enabled:
27
29
  return ""
28
30
  agent_name = agent_names[agent.id]
29
31
  teachability = agent.data.teachability
30
- content = f"{agent_name}_teachability = teachability.Teachability(\n"
31
- content += f" verbosity={teachability.verbosity},\n"
32
- content += f" reset_db={teachability.reset_db},\n"
33
- content += f" recall_threshold={teachability.recall_threshold},\n"
34
- content += f" max_num_retrievals={teachability.max_num_retrievals},\n"
32
+ content = f"{agent_name}_teachability = teachability.Teachability(" + "\n"
33
+ content += f" verbosity={teachability.verbosity}," + "\n"
34
+ content += f" reset_db={teachability.reset_db}," + "\n"
35
+ content += f" recall_threshold={teachability.recall_threshold}," + "\n"
36
+ content += (
37
+ f" max_num_retrievals={teachability.max_num_retrievals}," + "\n"
38
+ )
35
39
  content += ")\n\n\n"
36
40
  content += f"{agent_name}_teachability.add_to_agent({agent_name})"
37
41
  return content
@@ -1,3 +1,5 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
1
3
  """Get the `is_termination_message` check for the agent."""
2
4
 
3
5
  from typing import Tuple
@@ -33,13 +35,10 @@ def get_is_termination_message(
33
35
  if agent.data.termination.type == "keyword":
34
36
  return agent.data.termination.string, ""
35
37
  if agent.data.termination.type == "method":
36
- method_name = f"is_termination_message_{agent_name}"
37
- content = (
38
- "\n\n"
39
- + f"def is_termination_message_{agent_name}(message):"
40
- + "\n"
41
- + f"{agent.data.termination.string}"
42
- + "\n\n"
38
+ content, function_name = (
39
+ agent.data.termination.get_termination_function(
40
+ name_suffix=agent_name
41
+ )
43
42
  )
44
- return method_name, content
43
+ return function_name, "\n\n" + content + "\n"
45
44
  raise ValueError(f"Invalid termination type: {agent.data.termination.type}")
@@ -0,0 +1,25 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Base classes, mixins, and utilities for exporting data.
4
+
5
+ Each exporter should inherit from the `BaseExporter` class and implement the
6
+ `export` method. The `export` method should return the exported content as an
7
+ instance of the `ExporterReturnType` typed dictionary.
8
+ """
9
+
10
+ from .agent_position import AgentPosition, AgentPositions
11
+ from .base_exporter import BaseExporter, ExporterReturnType
12
+ from .export_position import ExportPosition, ExportPositions
13
+ from .import_position import ImportPosition
14
+ from .mixin import ExporterMixin
15
+
16
+ __all__ = [
17
+ "AgentPosition",
18
+ "AgentPositions",
19
+ "BaseExporter",
20
+ "ExporterMixin",
21
+ "ExportPosition",
22
+ "ExportPositions",
23
+ "ExporterReturnType",
24
+ "ImportPosition",
25
+ ]
@@ -0,0 +1,75 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Agent position generation."""
4
+
5
+ from dataclasses import dataclass
6
+ from enum import Enum
7
+ from typing import Optional
8
+
9
+ from waldiez.models import WaldiezAgent
10
+
11
+
12
+ class AgentPositions(Enum):
13
+ """Agent positions.
14
+
15
+ Attributes
16
+ ----------
17
+ BEFORE_ALL: int
18
+ Before all agents.
19
+ BEFORE: int
20
+ Before the agent.
21
+ AS_ARGUMENT: int
22
+ As an argument of the agent's initialization.
23
+ AFTER: int
24
+ After the agent.
25
+ AFTER_ALL: int
26
+ After all agents.
27
+ """
28
+
29
+ BEFORE_ALL = 0
30
+ BEFORE = 1
31
+ AS_ARGUMENT = 2
32
+ AFTER = 3
33
+ AFTER_ALL = 4
34
+
35
+
36
+ POSITIONS_WITHOUT_AGENT = [
37
+ AgentPositions.BEFORE_ALL,
38
+ AgentPositions.AFTER_ALL,
39
+ ]
40
+
41
+
42
+ @dataclass(order=True, frozen=True, slots=True)
43
+ class AgentPosition:
44
+ """Agent position.
45
+
46
+ Attributes
47
+ ----------
48
+ agent: Optional[WaldiezAgent]
49
+ The agent.
50
+ position: AgentPositions
51
+ The position.
52
+ order: int
53
+ The order of the agent position.
54
+
55
+ Raises
56
+ ------
57
+ ValueError
58
+ If the position is not "BEFORE_ALL" or "AFTER_ALL"
59
+ and the agent is not provided.
60
+ """
61
+
62
+ agent: Optional[WaldiezAgent]
63
+ position: AgentPositions
64
+ order: int = 0
65
+
66
+ def __post_init__(self) -> None:
67
+ """Post initialization.
68
+
69
+ Raises
70
+ ------
71
+ ValueError
72
+ If the agent is not provided for the given position.
73
+ """
74
+ if self.agent is None and self.position not in POSITIONS_WITHOUT_AGENT:
75
+ raise ValueError("Agent must be provided for the given position.")