waldiez 0.6.0__py3-none-any.whl → 0.6.1__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.
- waldiez/__init__.py +1 -1
- waldiez/_version.py +1 -1
- waldiez/cli.py +18 -7
- waldiez/cli_extras/jupyter.py +3 -0
- waldiez/cli_extras/runner.py +3 -1
- waldiez/cli_extras/studio.py +3 -1
- waldiez/exporter.py +9 -3
- waldiez/exporting/agent/exporter.py +9 -10
- waldiez/exporting/agent/extras/captain_agent_extras.py +6 -6
- waldiez/exporting/agent/extras/doc_agent_extras.py +6 -6
- waldiez/exporting/agent/extras/group_manager_agent_extas.py +34 -23
- waldiez/exporting/agent/extras/group_member_extras.py +6 -5
- waldiez/exporting/agent/extras/handoffs/after_work.py +1 -1
- waldiez/exporting/agent/extras/handoffs/available.py +1 -1
- waldiez/exporting/agent/extras/handoffs/condition.py +3 -2
- waldiez/exporting/agent/extras/handoffs/handoff.py +1 -1
- waldiez/exporting/agent/extras/handoffs/target.py +6 -4
- waldiez/exporting/agent/extras/rag/chroma_extras.py +27 -19
- waldiez/exporting/agent/extras/rag/mongo_extras.py +8 -8
- waldiez/exporting/agent/extras/rag/pgvector_extras.py +5 -5
- waldiez/exporting/agent/extras/rag/qdrant_extras.py +5 -4
- waldiez/exporting/agent/extras/rag/vector_db_extras.py +1 -1
- waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +5 -7
- waldiez/exporting/agent/extras/reasoning_agent_extras.py +3 -5
- waldiez/exporting/chats/exporter.py +4 -4
- waldiez/exporting/chats/processor.py +1 -2
- waldiez/exporting/chats/utils/common.py +89 -48
- waldiez/exporting/chats/utils/group.py +9 -9
- waldiez/exporting/chats/utils/nested.py +7 -7
- waldiez/exporting/chats/utils/sequential.py +1 -1
- waldiez/exporting/chats/utils/single.py +2 -2
- waldiez/exporting/core/content.py +7 -7
- waldiez/exporting/core/context.py +5 -3
- waldiez/exporting/core/exporter.py +5 -3
- waldiez/exporting/core/exporters.py +2 -2
- waldiez/exporting/core/extras/agent_extras/captain_extras.py +2 -2
- waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +2 -2
- waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +2 -2
- waldiez/exporting/core/extras/agent_extras/standard_extras.py +3 -8
- waldiez/exporting/core/extras/base.py +7 -5
- waldiez/exporting/core/extras/flow_extras.py +4 -5
- waldiez/exporting/core/extras/model_extras.py +2 -2
- waldiez/exporting/core/extras/path_resolver.py +1 -2
- waldiez/exporting/core/extras/serializer.py +2 -2
- waldiez/exporting/core/protocols.py +6 -5
- waldiez/exporting/core/result.py +25 -28
- waldiez/exporting/core/types.py +10 -10
- waldiez/exporting/core/utils/llm_config.py +2 -2
- waldiez/exporting/core/validation.py +10 -11
- waldiez/exporting/flow/execution_generator.py +98 -10
- waldiez/exporting/flow/exporter.py +2 -2
- waldiez/exporting/flow/factory.py +2 -2
- waldiez/exporting/flow/file_generator.py +4 -2
- waldiez/exporting/flow/merger.py +5 -3
- waldiez/exporting/flow/orchestrator.py +72 -2
- waldiez/exporting/flow/utils/common.py +5 -5
- waldiez/exporting/flow/utils/importing.py +6 -7
- waldiez/exporting/flow/utils/linting.py +25 -9
- waldiez/exporting/flow/utils/logging.py +2 -2
- waldiez/exporting/models/exporter.py +8 -8
- waldiez/exporting/models/processor.py +5 -5
- waldiez/exporting/tools/exporter.py +2 -2
- waldiez/exporting/tools/processor.py +7 -4
- waldiez/io/__init__.py +8 -4
- waldiez/io/_ws.py +10 -6
- waldiez/io/models/constants.py +10 -10
- waldiez/io/models/content/audio.py +1 -0
- waldiez/io/models/content/base.py +20 -18
- waldiez/io/models/content/file.py +1 -0
- waldiez/io/models/content/image.py +1 -0
- waldiez/io/models/content/text.py +1 -0
- waldiez/io/models/content/video.py +1 -0
- waldiez/io/models/user_input.py +10 -5
- waldiez/io/models/user_response.py +17 -16
- waldiez/io/mqtt.py +18 -31
- waldiez/io/redis.py +18 -22
- waldiez/io/structured.py +52 -53
- waldiez/io/utils.py +3 -0
- waldiez/io/ws.py +5 -1
- waldiez/logger.py +16 -3
- waldiez/models/agents/__init__.py +3 -0
- waldiez/models/agents/agent/agent.py +23 -16
- waldiez/models/agents/agent/agent_data.py +25 -22
- waldiez/models/agents/agent/code_execution.py +9 -11
- waldiez/models/agents/agent/termination_message.py +10 -12
- waldiez/models/agents/agent/update_system_message.py +2 -4
- waldiez/models/agents/agents.py +8 -8
- waldiez/models/agents/assistant/assistant.py +6 -3
- waldiez/models/agents/assistant/assistant_data.py +2 -2
- waldiez/models/agents/captain/captain_agent.py +7 -4
- waldiez/models/agents/captain/captain_agent_data.py +5 -7
- waldiez/models/agents/doc_agent/doc_agent.py +7 -4
- waldiez/models/agents/doc_agent/doc_agent_data.py +9 -10
- waldiez/models/agents/doc_agent/rag_query_engine.py +10 -12
- waldiez/models/agents/extra_requirements.py +3 -3
- waldiez/models/agents/group_manager/group_manager.py +12 -7
- waldiez/models/agents/group_manager/group_manager_data.py +13 -12
- waldiez/models/agents/group_manager/speakers.py +17 -19
- waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +7 -4
- waldiez/models/agents/rag_user_proxy/rag_user_proxy_data.py +4 -1
- waldiez/models/agents/rag_user_proxy/retrieve_config.py +69 -63
- waldiez/models/agents/rag_user_proxy/vector_db_config.py +19 -19
- waldiez/models/agents/reasoning/reasoning_agent.py +7 -4
- waldiez/models/agents/reasoning/reasoning_agent_data.py +3 -2
- waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +8 -8
- waldiez/models/agents/user_proxy/user_proxy.py +6 -3
- waldiez/models/agents/user_proxy/user_proxy_data.py +1 -1
- waldiez/models/chat/chat.py +27 -20
- waldiez/models/chat/chat_data.py +22 -19
- waldiez/models/chat/chat_message.py +9 -9
- waldiez/models/chat/chat_nested.py +9 -9
- waldiez/models/chat/chat_summary.py +6 -6
- waldiez/models/common/__init__.py +2 -0
- waldiez/models/common/ag2_version.py +2 -0
- waldiez/models/common/dict_utils.py +8 -6
- waldiez/models/common/handoff.py +18 -17
- waldiez/models/common/method_utils.py +7 -7
- waldiez/models/common/naming.py +49 -0
- waldiez/models/flow/flow.py +11 -6
- waldiez/models/flow/flow_data.py +23 -17
- waldiez/models/flow/info.py +3 -3
- waldiez/models/flow/naming.py +2 -1
- waldiez/models/model/_aws.py +11 -13
- waldiez/models/model/_llm.py +5 -0
- waldiez/models/model/_price.py +2 -4
- waldiez/models/model/extra_requirements.py +1 -3
- waldiez/models/model/model.py +2 -2
- waldiez/models/model/model_data.py +21 -21
- waldiez/models/tool/extra_requirements.py +2 -4
- waldiez/models/tool/predefined/_duckduckgo.py +1 -0
- waldiez/models/tool/predefined/_email.py +1 -0
- waldiez/models/tool/predefined/_google.py +1 -0
- waldiez/models/tool/predefined/_perplexity.py +1 -0
- waldiez/models/tool/predefined/_searxng.py +1 -0
- waldiez/models/tool/predefined/_tavily.py +1 -0
- waldiez/models/tool/predefined/_wikipedia.py +1 -0
- waldiez/models/tool/predefined/_youtube.py +1 -0
- waldiez/models/tool/tool.py +8 -5
- waldiez/models/tool/tool_data.py +2 -2
- waldiez/models/waldiez.py +152 -4
- waldiez/runner.py +11 -5
- waldiez/running/async_utils.py +192 -0
- waldiez/running/base_runner.py +117 -264
- waldiez/running/dir_utils.py +52 -0
- waldiez/running/environment.py +10 -44
- waldiez/running/events_mixin.py +252 -0
- waldiez/running/exceptions.py +20 -0
- waldiez/running/gen_seq_diagram.py +18 -15
- waldiez/running/io_utils.py +216 -0
- waldiez/running/protocol.py +11 -5
- waldiez/running/requirements_mixin.py +65 -0
- waldiez/running/results_mixin.py +926 -0
- waldiez/running/standard_runner.py +22 -25
- waldiez/running/step_by_step/breakpoints_mixin.py +192 -60
- waldiez/running/step_by_step/command_handler.py +3 -0
- waldiez/running/step_by_step/events_processor.py +194 -14
- waldiez/running/step_by_step/step_by_step_models.py +110 -43
- waldiez/running/step_by_step/step_by_step_runner.py +107 -57
- waldiez/running/subprocess_runner/__base__.py +9 -1
- waldiez/running/subprocess_runner/_async_runner.py +5 -3
- waldiez/running/subprocess_runner/_sync_runner.py +6 -2
- waldiez/running/subprocess_runner/runner.py +39 -23
- waldiez/running/timeline_processor.py +1 -1
- waldiez/utils/__init__.py +2 -0
- waldiez/utils/conflict_checker.py +4 -4
- waldiez/utils/python_manager.py +415 -0
- waldiez/ws/_file_handler.py +18 -18
- waldiez/ws/_mock.py +2 -1
- waldiez/ws/cli.py +36 -12
- waldiez/ws/client_manager.py +35 -27
- waldiez/ws/errors.py +3 -0
- waldiez/ws/models.py +43 -52
- waldiez/ws/reloader.py +12 -4
- waldiez/ws/server.py +85 -55
- waldiez/ws/session_manager.py +8 -9
- waldiez/ws/session_stats.py +1 -1
- waldiez/ws/utils.py +4 -1
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/METADATA +82 -93
- waldiez-0.6.1.dist-info/RECORD +254 -0
- waldiez/running/post_run.py +0 -186
- waldiez/running/pre_run.py +0 -281
- waldiez/running/run_results.py +0 -14
- waldiez/running/utils.py +0 -625
- waldiez-0.6.0.dist-info/RECORD +0 -251
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/WHEEL +0 -0
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/entry_points.txt +0 -0
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
"""Validation types and results for Waldiez exporting core."""
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
|
-
from typing import Optional
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
# Validation Types
|
|
@@ -13,8 +12,8 @@ class ValidationError:
|
|
|
13
12
|
|
|
14
13
|
message: str
|
|
15
14
|
severity: str = "error" # error, warning, info
|
|
16
|
-
location:
|
|
17
|
-
suggestion:
|
|
15
|
+
location: str | None = None
|
|
16
|
+
suggestion: str | None = None
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
@dataclass
|
|
@@ -23,17 +22,17 @@ class ValidationResult:
|
|
|
23
22
|
|
|
24
23
|
is_valid: bool
|
|
25
24
|
errors: list[ValidationError] = field(
|
|
26
|
-
default_factory=list
|
|
25
|
+
default_factory=list,
|
|
27
26
|
)
|
|
28
27
|
warnings: list[ValidationError] = field(
|
|
29
|
-
default_factory=list
|
|
28
|
+
default_factory=list,
|
|
30
29
|
)
|
|
31
30
|
|
|
32
31
|
def add_error(
|
|
33
32
|
self,
|
|
34
33
|
message: str,
|
|
35
|
-
location:
|
|
36
|
-
suggestion:
|
|
34
|
+
location: str | None = None,
|
|
35
|
+
suggestion: str | None = None,
|
|
37
36
|
) -> None:
|
|
38
37
|
"""Add a validation error.
|
|
39
38
|
|
|
@@ -41,9 +40,9 @@ class ValidationResult:
|
|
|
41
40
|
----------
|
|
42
41
|
message : str
|
|
43
42
|
The error message to add.
|
|
44
|
-
location :
|
|
43
|
+
location : str | None, optional
|
|
45
44
|
The location in the code where the error occurred, by default None
|
|
46
|
-
suggestion :
|
|
45
|
+
suggestion : str | None, optional
|
|
47
46
|
A suggestion for fixing the error, by default None
|
|
48
47
|
"""
|
|
49
48
|
self.errors.append(
|
|
@@ -51,14 +50,14 @@ class ValidationResult:
|
|
|
51
50
|
)
|
|
52
51
|
self.is_valid = False
|
|
53
52
|
|
|
54
|
-
def add_warning(self, message: str, location:
|
|
53
|
+
def add_warning(self, message: str, location: str | None = None) -> None:
|
|
55
54
|
"""Add a validation warning.
|
|
56
55
|
|
|
57
56
|
Parameters
|
|
58
57
|
----------
|
|
59
58
|
message : str
|
|
60
59
|
The warning message to add.
|
|
61
|
-
location :
|
|
60
|
+
location : str | None, optional
|
|
62
61
|
The location in the code where the warning occurred, by default None
|
|
63
62
|
"""
|
|
64
63
|
self.warnings.append(ValidationError(message, "warning", location))
|
|
@@ -67,6 +67,79 @@ class ExecutionGenerator:
|
|
|
67
67
|
+ "\n"
|
|
68
68
|
)
|
|
69
69
|
|
|
70
|
+
@staticmethod
|
|
71
|
+
def generate_store_results(is_async: bool) -> str:
|
|
72
|
+
"""Generate the part that writes the results to results.json.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
is_async : bool
|
|
77
|
+
Whether the flow is async or not.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
str
|
|
82
|
+
The part that generates the code to store the results.
|
|
83
|
+
"""
|
|
84
|
+
content: str = "async " if is_async else ""
|
|
85
|
+
tab = " "
|
|
86
|
+
content += (
|
|
87
|
+
"def store_results(result_dicts: list[dict[str, Any]]) -> None:\n"
|
|
88
|
+
)
|
|
89
|
+
content += f'{tab}"""Store the results to results.json.\n'
|
|
90
|
+
content += f"{tab}Parameters\n"
|
|
91
|
+
content += f"{tab}----------\n"
|
|
92
|
+
content += f"{tab}result_dicts : list[dict[str, Any]]\n"
|
|
93
|
+
content += f"{tab}{tab}The list of the results.\n"
|
|
94
|
+
content += f'{tab}"""\n'
|
|
95
|
+
if is_async:
|
|
96
|
+
content += f'{tab}async with aiofiles.open("results.json", "w", encoding="utf-8", newline="\\n") as file:\n'
|
|
97
|
+
content += f"{tab}{tab}await file.write(json.dumps({{'results': result_dicts}}, indent=4, ensure_ascii=False))\n"
|
|
98
|
+
else:
|
|
99
|
+
content += f'{tab}with open("results.json", "w", encoding="utf-8", newline="\\n") as file:\n'
|
|
100
|
+
content += f"{tab}{tab}file.write(json.dumps({{'results': result_dicts}}, indent=4, ensure_ascii=False))\n"
|
|
101
|
+
return content
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def generate_store_error(is_async: bool) -> str:
|
|
105
|
+
"""Generate the part that writes an error to error.json.
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
is_async : bool
|
|
110
|
+
Whether the flow is async or not.
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
str
|
|
115
|
+
The content for writing the error to file.
|
|
116
|
+
"""
|
|
117
|
+
content = "\nasync " if is_async else "\n"
|
|
118
|
+
content += '''def store_error(exc: BaseException | None = None) -> None:
|
|
119
|
+
"""Store the error in error.json.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
exc : BaseException | None
|
|
124
|
+
The exception we got if any.
|
|
125
|
+
"""
|
|
126
|
+
reason = "Event handler stopped processing" if not exc else traceback.format_exc()
|
|
127
|
+
try:'''
|
|
128
|
+
if is_async:
|
|
129
|
+
content += """
|
|
130
|
+
async with aiofiles.open("error.json", "w", encoding="utf-8", newline="\\n") as file:
|
|
131
|
+
await file.write(json.dumps({"error": reason}))"""
|
|
132
|
+
else:
|
|
133
|
+
content += """
|
|
134
|
+
with open("error.json", "w", encoding="utf-8", newline="\\n") as file:
|
|
135
|
+
file.write(json.dumps({"error": reason}))"""
|
|
136
|
+
content += """
|
|
137
|
+
except BaseException: # pylint: disable=broad-exception-caught
|
|
138
|
+
pass
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
return content
|
|
142
|
+
|
|
70
143
|
@staticmethod
|
|
71
144
|
def generate_main_function(
|
|
72
145
|
content: str,
|
|
@@ -108,12 +181,12 @@ class ExecutionGenerator:
|
|
|
108
181
|
flow_content += f"{comment}\n"
|
|
109
182
|
if is_async:
|
|
110
183
|
flow_content += "async "
|
|
111
|
-
on_event_arg = "on_event:
|
|
184
|
+
on_event_arg = "on_event: Callable[[BaseEvent, list[ConversableAgent]], bool] | None = None"
|
|
112
185
|
if is_async:
|
|
113
186
|
on_event_arg = (
|
|
114
|
-
"on_event:
|
|
115
|
-
"Callable[[BaseEvent], Coroutine[None, None, bool]]"
|
|
116
|
-
"
|
|
187
|
+
"on_event: "
|
|
188
|
+
"Callable[[BaseEvent, list[ConversableAgent]], Coroutine[None, None, bool]]"
|
|
189
|
+
" | None = None"
|
|
117
190
|
)
|
|
118
191
|
return_type_hint = "list[dict[str, Any]]"
|
|
119
192
|
flow_content += f"def main({on_event_arg}) -> {return_type_hint}:\n"
|
|
@@ -127,24 +200,39 @@ class ExecutionGenerator:
|
|
|
127
200
|
if cache_seed is not None:
|
|
128
201
|
# noinspection SqlDialectInspection
|
|
129
202
|
flow_content += (
|
|
130
|
-
f" with Cache.disk(cache_seed={cache_seed}"
|
|
131
|
-
") as cache: # pyright: ignore\n"
|
|
203
|
+
f" with Cache.disk(cache_seed={cache_seed}) as cache:\n"
|
|
132
204
|
)
|
|
133
205
|
space = f"{space} "
|
|
134
206
|
flow_content += f"{content}" + "\n"
|
|
135
207
|
if not skip_logging:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
flow_content += f"{space}stop_logging()"
|
|
208
|
+
flow_content += ExecutionGenerator._get_stop_logging_call(
|
|
209
|
+
space, is_async
|
|
210
|
+
)
|
|
140
211
|
flow_content += "\n"
|
|
141
212
|
if after_run:
|
|
142
213
|
flow_content += after_run + "\n"
|
|
143
214
|
if cache_seed is not None:
|
|
144
215
|
space = space[4:]
|
|
216
|
+
flow_content += ExecutionGenerator._get_store_results_call(
|
|
217
|
+
space, is_async
|
|
218
|
+
)
|
|
145
219
|
flow_content += f"{space}return result_dicts\n"
|
|
146
220
|
return flow_content
|
|
147
221
|
|
|
222
|
+
@staticmethod
|
|
223
|
+
def _get_stop_logging_call(space: str, is_async: bool) -> str:
|
|
224
|
+
"""Get stop logging call."""
|
|
225
|
+
if is_async:
|
|
226
|
+
return f"{space}await stop_logging()"
|
|
227
|
+
return f"{space}stop_logging()"
|
|
228
|
+
|
|
229
|
+
@staticmethod
|
|
230
|
+
def _get_store_results_call(space: str, is_async: bool) -> str:
|
|
231
|
+
"""Get store results call."""
|
|
232
|
+
if is_async:
|
|
233
|
+
return f"{space}await store_results(result_dicts)\n"
|
|
234
|
+
return f"{space}store_results(result_dicts)\n"
|
|
235
|
+
|
|
148
236
|
@staticmethod
|
|
149
237
|
def generate_call_main_function(is_async: bool, for_notebook: bool) -> str:
|
|
150
238
|
"""Generate the call_main function for the flow script.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""Flow exporter."""
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
from waldiez.models import Waldiez
|
|
9
9
|
|
|
@@ -21,7 +21,7 @@ class FlowExporter(Exporter[FlowExtras]):
|
|
|
21
21
|
waldiez: Waldiez,
|
|
22
22
|
output_dir: Path | None,
|
|
23
23
|
for_notebook: bool,
|
|
24
|
-
context:
|
|
24
|
+
context: ExporterContext | None = None,
|
|
25
25
|
**kwargs: Any,
|
|
26
26
|
) -> None:
|
|
27
27
|
"""Initialize the chats exporter.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""Factory function for creating a FlowExporter instance."""
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
from waldiez.logger import WaldiezLogger
|
|
9
9
|
from waldiez.models import Waldiez
|
|
@@ -22,7 +22,7 @@ def create_flow_exporter(
|
|
|
22
22
|
output_dir: Path | None,
|
|
23
23
|
uploads_root: Path | None,
|
|
24
24
|
for_notebook: bool,
|
|
25
|
-
context:
|
|
25
|
+
context: ExporterContext | None = None,
|
|
26
26
|
**kwargs: Any,
|
|
27
27
|
) -> FlowExporter:
|
|
28
28
|
"""Create a flow exporter.
|
|
@@ -43,7 +43,7 @@ class FileGenerator(ContentGenerator):
|
|
|
43
43
|
after_run: str,
|
|
44
44
|
skip_logging: bool,
|
|
45
45
|
**kwargs: Any,
|
|
46
|
-
) -> str:
|
|
46
|
+
) -> str:
|
|
47
47
|
"""Generate content based on provided parameters.
|
|
48
48
|
|
|
49
49
|
Parameters
|
|
@@ -172,7 +172,9 @@ class FileGenerator(ContentGenerator):
|
|
|
172
172
|
)
|
|
173
173
|
execution_gen = ExecutionGenerator()
|
|
174
174
|
chat_contents = "\n".join(chat.content for chat in chats_content)
|
|
175
|
-
|
|
175
|
+
before_main = execution_gen.generate_store_error(is_async) + "\n\n"
|
|
176
|
+
before_main += execution_gen.generate_store_results(is_async) + "\n\n"
|
|
177
|
+
main = before_main + execution_gen.generate_main_function(
|
|
176
178
|
content=chat_contents,
|
|
177
179
|
is_async=is_async,
|
|
178
180
|
for_notebook=for_notebook,
|
waldiez/exporting/flow/merger.py
CHANGED
|
@@ -27,7 +27,7 @@ class MergeStatistics:
|
|
|
27
27
|
total_content_items: int = 0
|
|
28
28
|
total_env_vars: int = 0
|
|
29
29
|
deduplicated_env_vars: int = 0
|
|
30
|
-
conflicts_found: list[str] = field(default_factory=list
|
|
30
|
+
conflicts_found: list[str] = field(default_factory=list)
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class ContentMerger:
|
|
@@ -156,10 +156,11 @@ class ContentMerger:
|
|
|
156
156
|
elif imp.position.value == existing.position.value:
|
|
157
157
|
# Same position - check for conflicts
|
|
158
158
|
if imp.metadata != existing.metadata:
|
|
159
|
-
|
|
159
|
+
conflict = (
|
|
160
160
|
f"Import '{key}' has conflicting metadata: "
|
|
161
161
|
f"{existing.metadata} vs {imp.metadata}"
|
|
162
162
|
)
|
|
163
|
+
conflicts.append(conflict)
|
|
163
164
|
# Keep existing (first wins for same priority)
|
|
164
165
|
|
|
165
166
|
if conflicts:
|
|
@@ -292,10 +293,11 @@ class ContentMerger:
|
|
|
292
293
|
|
|
293
294
|
# Check for value conflicts
|
|
294
295
|
if existing.value != env_var.value:
|
|
295
|
-
|
|
296
|
+
conflict = (
|
|
296
297
|
f"Environment variable '{key}' has conflicting "
|
|
297
298
|
f"values: '{existing.value}' vs '{env_var.value}'"
|
|
298
299
|
)
|
|
300
|
+
conflicts.append(conflict)
|
|
299
301
|
# Keep first occurrence
|
|
300
302
|
# (tools/models take precedence over agents)
|
|
301
303
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from typing import Any, Callable
|
|
6
6
|
|
|
7
|
-
from waldiez.models import Waldiez, WaldiezAgent
|
|
7
|
+
from waldiez.models import Waldiez, WaldiezAgent, WaldiezGroupManager
|
|
8
8
|
|
|
9
9
|
from ..agent import AgentExporter, create_agent_exporter
|
|
10
10
|
from ..chats import ChatsExporter, create_chats_exporter
|
|
@@ -167,7 +167,7 @@ class ExportOrchestrator:
|
|
|
167
167
|
tags=self.waldiez.tags,
|
|
168
168
|
for_notebook=self.config.for_notebook,
|
|
169
169
|
),
|
|
170
|
-
position=ExportPosition.TOP, #
|
|
170
|
+
position=ExportPosition.TOP, # before everything
|
|
171
171
|
order=ContentOrder.EARLY_SETUP,
|
|
172
172
|
)
|
|
173
173
|
merged_result.add_content(
|
|
@@ -224,6 +224,12 @@ class ExportOrchestrator:
|
|
|
224
224
|
position=ExportPosition.IMPORTS, # imports section
|
|
225
225
|
order=ContentOrder.EARLY_SETUP, # top position
|
|
226
226
|
)
|
|
227
|
+
known_agents_string = self._get_the_known_agents_string()
|
|
228
|
+
merged_result.add_content(
|
|
229
|
+
known_agents_string,
|
|
230
|
+
position=ExportPosition.AGENTS,
|
|
231
|
+
order=ContentOrder.POST_CONTENT.value + 100,
|
|
232
|
+
)
|
|
227
233
|
return merged_result
|
|
228
234
|
|
|
229
235
|
def get_after_run_content(self) -> str:
|
|
@@ -240,6 +246,70 @@ class ExportOrchestrator:
|
|
|
240
246
|
tabs=1,
|
|
241
247
|
)
|
|
242
248
|
|
|
249
|
+
def _get_the_known_agents_string(self) -> str:
|
|
250
|
+
"""Get the _get_known_agents method."""
|
|
251
|
+
content: str = """
|
|
252
|
+
|
|
253
|
+
def _check_for_extra_agents(agent: ConversableAgent) -> list[ConversableAgent]:
|
|
254
|
+
_extra_agents: list[ConversableAgent] = []
|
|
255
|
+
_agent_cls_name = agent.__class__.__name__
|
|
256
|
+
if _agent_cls_name == "CaptainAgent":
|
|
257
|
+
_assistant_agent = getattr(agent, "assistant", None)
|
|
258
|
+
if _assistant_agent and _assistant_agent not in _extra_agents:
|
|
259
|
+
_extra_agents.append(_assistant_agent)
|
|
260
|
+
_executor_agent = getattr(agent, "executor", None)
|
|
261
|
+
if _executor_agent and _executor_agent not in _extra_agents:
|
|
262
|
+
_extra_agents.append(_executor_agent)
|
|
263
|
+
return _extra_agents
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _check_for_group_members(agent: ConversableAgent) -> list[ConversableAgent]:
|
|
267
|
+
_extra_agents: list[ConversableAgent] = []
|
|
268
|
+
_group_chat = getattr(agent, "_groupchat", None)
|
|
269
|
+
if _group_chat:
|
|
270
|
+
_chat_agents = getattr(_group_chat, "agents", [])
|
|
271
|
+
if isinstance(_chat_agents, list):
|
|
272
|
+
for _group_member in _chat_agents:
|
|
273
|
+
if _group_member not in _extra_agents:
|
|
274
|
+
_extra_agents.append(_group_member)
|
|
275
|
+
_manager = getattr(agent, "_group_manager", None)
|
|
276
|
+
if _manager:
|
|
277
|
+
if _manager not in _extra_agents:
|
|
278
|
+
_extra_agents.append(_manager)
|
|
279
|
+
for _group_member in _check_for_group_members(_manager):
|
|
280
|
+
if _group_member not in _extra_agents:
|
|
281
|
+
_extra_agents.append(_group_member)
|
|
282
|
+
return _extra_agents
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _get_known_agents() -> list[ConversableAgent]:
|
|
286
|
+
_known_agents: list[ConversableAgent] = []"""
|
|
287
|
+
# group_manager: WaldiezGroupManager | None = None
|
|
288
|
+
for agent in self.waldiez.agents:
|
|
289
|
+
if (
|
|
290
|
+
isinstance(agent, WaldiezGroupManager)
|
|
291
|
+
and self.waldiez.is_group_pattern_based
|
|
292
|
+
):
|
|
293
|
+
# not defined in agents
|
|
294
|
+
# we'll get it from "._group_manager"
|
|
295
|
+
# if found in the rest of the agents.
|
|
296
|
+
continue
|
|
297
|
+
agent_name = self.agent_names.get(agent.id)
|
|
298
|
+
if agent_name:
|
|
299
|
+
content += f"""
|
|
300
|
+
if {agent_name} not in _known_agents:
|
|
301
|
+
_known_agents.append({agent_name})
|
|
302
|
+
_known_agents.append({agent_name})
|
|
303
|
+
for _group_member in _check_for_group_members({agent_name}):
|
|
304
|
+
if _group_member not in _known_agents:
|
|
305
|
+
_known_agents.append(_group_member)
|
|
306
|
+
for _extra_agent in _check_for_extra_agents({agent_name}):
|
|
307
|
+
if _extra_agent not in _known_agents:
|
|
308
|
+
_known_agents.append(_extra_agent)
|
|
309
|
+
"""
|
|
310
|
+
content += " return _known_agents\n\n"
|
|
311
|
+
return content
|
|
312
|
+
|
|
243
313
|
def _get_tools_exporter(self) -> ToolsExporter:
|
|
244
314
|
"""Get or create tools exporter."""
|
|
245
315
|
if self._tools_exporter is None:
|
|
@@ -51,7 +51,7 @@ def generate_header(
|
|
|
51
51
|
requirements=requirements,
|
|
52
52
|
tags=tags,
|
|
53
53
|
)
|
|
54
|
-
return
|
|
54
|
+
return _get_ipynb_header(
|
|
55
55
|
name=name,
|
|
56
56
|
description=description,
|
|
57
57
|
requirements=requirements,
|
|
@@ -59,7 +59,7 @@ def generate_header(
|
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
def
|
|
62
|
+
def _get_ipynb_header(
|
|
63
63
|
name: str,
|
|
64
64
|
description: str,
|
|
65
65
|
requirements: list[str],
|
|
@@ -73,7 +73,7 @@ def _get_ipynb_heeader(
|
|
|
73
73
|
content += f"### Tags: {tags_str}\n\n"
|
|
74
74
|
content += f"####{GENERATED_WITH}\n\n"
|
|
75
75
|
content += "#### Requirements\n\n# %%\n"
|
|
76
|
-
content += "import sys
|
|
76
|
+
content += "import sys\n"
|
|
77
77
|
# fmt: off
|
|
78
78
|
content += "# # " + f"!{{sys.executable}} -m pip install -q {requirements_str}" + "\n"
|
|
79
79
|
# fmt: on
|
|
@@ -166,8 +166,8 @@ def get_after_run_content(
|
|
|
166
166
|
{space}# save the tree to json
|
|
167
167
|
{space}# pylint: disable=protected-access
|
|
168
168
|
{space}try:
|
|
169
|
-
{space}{tab}data = {agent_name}._root.to_dict() # pyright: ignore
|
|
170
|
-
{space}{tab}with open("{agent_name}_reasoning_tree.json", "w", encoding="utf-8") as f:
|
|
169
|
+
{space}{tab}data = {agent_name}._root.to_dict() # pyright: ignore[reportPrivateUsage]
|
|
170
|
+
{space}{tab}with open("{agent_name}_reasoning_tree.json", "w", encoding="utf-8", newline="\\n") as f:
|
|
171
171
|
{space}{tab}{tab}json.dump(data, f)
|
|
172
172
|
{space}except BaseException:
|
|
173
173
|
{space}{tab}pass
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
"""Get the standard imports for the flow exporter."""
|
|
4
4
|
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
5
|
from waldiez.exporting.core import ImportPosition
|
|
8
6
|
|
|
9
7
|
BUILTIN_IMPORTS = [
|
|
@@ -14,6 +12,7 @@ BUILTIN_IMPORTS = [
|
|
|
14
12
|
"import os",
|
|
15
13
|
"import sqlite3",
|
|
16
14
|
"import sys",
|
|
15
|
+
"import traceback",
|
|
17
16
|
"from dataclasses import asdict",
|
|
18
17
|
"from pprint import pprint",
|
|
19
18
|
"from types import ModuleType",
|
|
@@ -239,7 +238,7 @@ def get_the_imports_string(
|
|
|
239
238
|
final_string += (
|
|
240
239
|
"# pylint: disable=broad-exception-caught\n"
|
|
241
240
|
"try:\n"
|
|
242
|
-
" nest_asyncio.apply()
|
|
241
|
+
" nest_asyncio.apply()\n"
|
|
243
242
|
"except BaseException:\n"
|
|
244
243
|
" pass # maybe on uvloop?\n"
|
|
245
244
|
)
|
|
@@ -269,10 +268,10 @@ def ensure_np_import(third_party_imports: list[str]) -> list[str]:
|
|
|
269
268
|
|
|
270
269
|
|
|
271
270
|
def gather_imports(
|
|
272
|
-
model_imports:
|
|
273
|
-
tool_imports:
|
|
274
|
-
chat_imports:
|
|
275
|
-
agent_imports:
|
|
271
|
+
model_imports: list[tuple[str, ImportPosition]] | None = None,
|
|
272
|
+
tool_imports: list[tuple[str, ImportPosition]] | None = None,
|
|
273
|
+
chat_imports: list[tuple[str, ImportPosition]] | None = None,
|
|
274
|
+
agent_imports: list[tuple[str, ImportPosition]] | None = None,
|
|
276
275
|
) -> list[tuple[str, ImportPosition]]:
|
|
277
276
|
"""Gather all the imports.
|
|
278
277
|
|
|
@@ -37,32 +37,48 @@ def split_linter_comment(
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
PYLINT_RULES = [
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"unused-argument",
|
|
43
|
-
"unused-import",
|
|
44
|
-
"unused-variable",
|
|
40
|
+
"broad-exception-caught",
|
|
41
|
+
"f-string-without-interpolation",
|
|
45
42
|
"invalid-name",
|
|
46
43
|
"import-error",
|
|
47
44
|
"import-outside-toplevel",
|
|
48
45
|
"inconsistent-quotes",
|
|
46
|
+
"line-too-long",
|
|
49
47
|
"missing-function-docstring",
|
|
50
48
|
"missing-param-doc",
|
|
51
49
|
"missing-return-doc",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
50
|
+
"no-member",
|
|
51
|
+
"pointless-string-statement",
|
|
52
|
+
"too-complex",
|
|
54
53
|
"too-many-arguments",
|
|
55
54
|
"too-many-locals",
|
|
56
55
|
"too-many-try-statements",
|
|
57
|
-
"
|
|
56
|
+
"ungrouped-imports",
|
|
57
|
+
"unnecessary-lambda-assignment",
|
|
58
|
+
"unknown-option-value",
|
|
59
|
+
"unused-argument",
|
|
60
|
+
"unused-import",
|
|
61
|
+
"unused-variable",
|
|
58
62
|
]
|
|
63
|
+
# including basedpyright specific (not pyright only) rules
|
|
59
64
|
PYRIGHT_RULES = [
|
|
60
|
-
"
|
|
65
|
+
"reportArgumentType",
|
|
66
|
+
"reportAttributeAccessIssue",
|
|
67
|
+
"reportCallInDefaultInitializer",
|
|
68
|
+
"reportDeprecated",
|
|
69
|
+
"reportDuplicateImport",
|
|
61
70
|
"reportMissingTypeStubs",
|
|
71
|
+
"reportOperatorIssue",
|
|
72
|
+
"reportOptionalMemberAccess",
|
|
73
|
+
"reportPossiblyUnboundVariable",
|
|
74
|
+
"reportUnreachable",
|
|
75
|
+
"reportUnusedImport",
|
|
62
76
|
"reportUnknownArgumentType",
|
|
63
77
|
"reportUnknownMemberType",
|
|
64
78
|
"reportUnknownLambdaType",
|
|
65
79
|
"reportUnnecessaryIsInstance",
|
|
80
|
+
"reportUnusedParameter",
|
|
81
|
+
"reportUnusedVariable",
|
|
66
82
|
"reportUnknownVariableType",
|
|
67
83
|
]
|
|
68
84
|
|
|
@@ -126,7 +126,7 @@ def get_sync_sqlite_out() -> str:
|
|
|
126
126
|
content += " csv_writer.writeheader()\n"
|
|
127
127
|
content += " csv_writer.writerows(data)\n"
|
|
128
128
|
content += ' json_file = csv_file.replace(".csv", ".json")\n'
|
|
129
|
-
content += ' with open(json_file, "w", encoding="utf-8") as file:\n'
|
|
129
|
+
content += ' with open(json_file, "w", encoding="utf-8", newline="\\n") as file:\n'
|
|
130
130
|
content += " json.dump(data, file, indent=4, ensure_ascii=False)\n"
|
|
131
131
|
content += "\n"
|
|
132
132
|
return content
|
|
@@ -172,7 +172,7 @@ def get_async_sqlite_out() -> str:
|
|
|
172
172
|
content += " await csv_writer.writeheader()\n"
|
|
173
173
|
content += " await csv_writer.writerows(data)\n"
|
|
174
174
|
content += ' json_file = csv_file.replace(".csv", ".json")\n'
|
|
175
|
-
content += ' async with aiofiles.open(json_file, "w", encoding="utf-8") as file:\n'
|
|
175
|
+
content += ' async with aiofiles.open(json_file, "w", encoding="utf-8", newline="\\n") as file:\n'
|
|
176
176
|
content += " await file.write(json.dumps(data, indent=4, ensure_ascii=False))\n"
|
|
177
177
|
content += "\n"
|
|
178
178
|
# fmt: on
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""Models exporter module."""
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
from waldiez.models import WaldiezAgent, WaldiezModel
|
|
9
9
|
|
|
@@ -31,9 +31,9 @@ class ModelsExporter(Exporter[ModelExtras]):
|
|
|
31
31
|
models: list[WaldiezModel],
|
|
32
32
|
model_names: dict[str, str],
|
|
33
33
|
for_notebook: bool = False,
|
|
34
|
-
cache_seed:
|
|
35
|
-
output_dir:
|
|
36
|
-
context:
|
|
34
|
+
cache_seed: int | None = None,
|
|
35
|
+
output_dir: str | Path | None = None,
|
|
36
|
+
context: ExporterContext | None = None,
|
|
37
37
|
**kwargs: Any,
|
|
38
38
|
):
|
|
39
39
|
"""Initialize the models exporter."""
|
|
@@ -94,7 +94,7 @@ class ModelsExporter(Exporter[ModelExtras]):
|
|
|
94
94
|
|
|
95
95
|
return extras
|
|
96
96
|
|
|
97
|
-
def generate_main_content(self) ->
|
|
97
|
+
def generate_main_content(self) -> str | None:
|
|
98
98
|
"""Generate the main models content (LLM configs).
|
|
99
99
|
|
|
100
100
|
Returns
|
|
@@ -146,7 +146,7 @@ class ModelsExporter(Exporter[ModelExtras]):
|
|
|
146
146
|
or "llm_config=False" if no models are configured.
|
|
147
147
|
"""
|
|
148
148
|
if not agent.data.model_ids:
|
|
149
|
-
return " llm_config=False
|
|
149
|
+
return " llm_config=False,\n"
|
|
150
150
|
|
|
151
151
|
# Get model configs for this agent
|
|
152
152
|
model_configs: list[str] = []
|
|
@@ -154,9 +154,9 @@ class ModelsExporter(Exporter[ModelExtras]):
|
|
|
154
154
|
model_name = self.model_names.get(model_id)
|
|
155
155
|
if model_name:
|
|
156
156
|
model_configs.append(f"{model_name}_llm_config")
|
|
157
|
-
tab = " " * 4
|
|
157
|
+
tab: str = " " * 4
|
|
158
158
|
if not model_configs:
|
|
159
|
-
return f"{tab}llm_config=False
|
|
159
|
+
return f"{tab}llm_config=False,\n"
|
|
160
160
|
|
|
161
161
|
config_list = f",\n{tab}{tab}{tab}".join(model_configs)
|
|
162
162
|
llm_config = f"""{tab}llm_config=autogen.LLMConfig(
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
from waldiez.models import WaldiezModel
|
|
11
10
|
|
|
@@ -20,7 +19,7 @@ class ModelProcessingResult:
|
|
|
20
19
|
"""Result from processing models."""
|
|
21
20
|
|
|
22
21
|
llm_configs_content: str = ""
|
|
23
|
-
api_keys_file:
|
|
22
|
+
api_keys_file: Path | None = None
|
|
24
23
|
needs_api_key_loader: bool = False
|
|
25
24
|
|
|
26
25
|
|
|
@@ -32,8 +31,8 @@ class ModelProcessor:
|
|
|
32
31
|
flow_name: str,
|
|
33
32
|
models: list[WaldiezModel],
|
|
34
33
|
model_names: dict[str, str],
|
|
35
|
-
serializer:
|
|
36
|
-
output_dir:
|
|
34
|
+
serializer: Serializer | None = None,
|
|
35
|
+
output_dir: Path | None = None,
|
|
37
36
|
):
|
|
38
37
|
self.flow_name = flow_name
|
|
39
38
|
self.models = models
|
|
@@ -93,8 +92,9 @@ __{flow_name_upper}_MODEL_API_KEYS__ = {{'''
|
|
|
93
92
|
for model in self.models:
|
|
94
93
|
model_name = self.model_names[model.id]
|
|
95
94
|
key_env = model.api_key_env_key
|
|
95
|
+
api_keys_content += "\n"
|
|
96
96
|
api_keys_content += (
|
|
97
|
-
|
|
97
|
+
f' "{model_name}": '
|
|
98
98
|
f'{{"key": "{model.api_key}", "env_key": "{key_env}"}},'
|
|
99
99
|
)
|
|
100
100
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"""Tools exporter."""
|
|
5
5
|
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
8
8
|
|
|
9
9
|
from waldiez.models import WaldiezAgent, WaldiezTool
|
|
10
10
|
|
|
@@ -148,7 +148,7 @@ class ToolsExporter(Exporter[ToolExtras]):
|
|
|
148
148
|
)
|
|
149
149
|
return extras
|
|
150
150
|
|
|
151
|
-
def generate_main_content(self) ->
|
|
151
|
+
def generate_main_content(self) -> str | None:
|
|
152
152
|
"""Generate the main tools content."""
|
|
153
153
|
# handled as positioned content
|
|
154
154
|
return None
|