waldiez 0.5.10__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 +19 -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 +15 -16
- 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 +40 -24
- waldiez/exporting/agent/extras/group_member_extras.py +6 -5
- waldiez/exporting/agent/extras/handoffs/after_work.py +2 -1
- waldiez/exporting/agent/extras/handoffs/available.py +2 -1
- waldiez/exporting/agent/extras/handoffs/condition.py +3 -2
- waldiez/exporting/agent/extras/handoffs/handoff.py +2 -1
- waldiez/exporting/agent/extras/handoffs/target.py +7 -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/agent/termination.py +1 -0
- 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/constants.py +3 -1
- 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 +13 -11
- waldiez/exporting/core/protocols.py +6 -5
- waldiez/exporting/core/result.py +25 -28
- waldiez/exporting/core/types.py +11 -10
- waldiez/exporting/core/utils/llm_config.py +4 -4
- waldiez/exporting/core/validation.py +10 -11
- waldiez/exporting/flow/execution_generator.py +99 -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 +6 -6
- waldiez/exporting/flow/utils/importing.py +7 -8
- waldiez/exporting/flow/utils/linting.py +25 -9
- waldiez/exporting/flow/utils/logging.py +5 -77
- 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 +11 -5
- waldiez/io/_ws.py +12 -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 +122 -70
- waldiez/io/utils.py +19 -10
- waldiez/io/ws.py +7 -3
- waldiez/logger.py +16 -3
- waldiez/models/agents/__init__.py +3 -0
- waldiez/models/agents/agent/agent.py +25 -17
- 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 +28 -20
- waldiez/models/chat/chat_data.py +22 -21
- 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/base.py +2 -0
- waldiez/models/common/dict_utils.py +8 -6
- waldiez/models/common/handoff.py +20 -17
- waldiez/models/common/method_utils.py +9 -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 +8 -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 +4 -0
- waldiez/models/tool/predefined/_google.py +1 -0
- waldiez/models/tool/predefined/_perplexity.py +2 -1
- waldiez/models/tool/predefined/_searxng.py +2 -1
- waldiez/models/tool/predefined/_tavily.py +1 -0
- waldiez/models/tool/predefined/_wikipedia.py +2 -1
- 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 +155 -241
- 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 +24 -27
- waldiez/running/step_by_step/breakpoints_mixin.py +503 -47
- waldiez/running/step_by_step/command_handler.py +154 -0
- waldiez/running/step_by_step/events_processor.py +379 -0
- waldiez/running/step_by_step/step_by_step_models.py +425 -41
- waldiez/running/step_by_step/step_by_step_runner.py +437 -382
- waldiez/running/subprocess_runner/__base__.py +13 -8
- waldiez/running/subprocess_runner/_async_runner.py +6 -4
- waldiez/running/subprocess_runner/_sync_runner.py +11 -6
- waldiez/running/subprocess_runner/runner.py +48 -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/__init__.py +8 -7
- waldiez/ws/_file_handler.py +18 -20
- waldiez/ws/_mock.py +75 -0
- waldiez/ws/cli.py +58 -10
- waldiez/ws/client_manager.py +77 -53
- waldiez/ws/errors.py +3 -0
- waldiez/ws/models.py +61 -53
- waldiez/ws/reloader.py +33 -4
- waldiez/ws/server.py +121 -52
- waldiez/ws/session_manager.py +8 -9
- waldiez/ws/session_stats.py +1 -1
- waldiez/ws/utils.py +33 -5
- {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/METADATA +107 -109
- waldiez-0.6.1.dist-info/RECORD +254 -0
- waldiez/running/post_run.py +0 -180
- waldiez/running/pre_run.py +0 -159
- waldiez/running/run_results.py +0 -14
- waldiez/running/utils.py +0 -511
- waldiez-0.5.10.dist-info/RECORD +0 -248
- {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/WHEEL +0 -0
- {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/entry_points.txt +0 -0
- {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.5.10.dist-info → waldiez-0.6.1.dist-info}/licenses/NOTICE.md +0 -0
waldiez/exporting/core/types.py
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
from dataclasses import dataclass, field, fields
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any,
|
|
8
|
+
from typing import Any, TypeVar
|
|
9
9
|
|
|
10
10
|
from .enums import (
|
|
11
11
|
ImportPosition,
|
|
@@ -25,7 +25,7 @@ class _NoExtrasType:
|
|
|
25
25
|
return "<NoExtras>"
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
NoExtras = _NoExtrasType()
|
|
28
|
+
NoExtras = _NoExtrasType() # pylint: disable=invalid-name
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
# Core Data Structures
|
|
@@ -35,7 +35,7 @@ class ImportStatement:
|
|
|
35
35
|
|
|
36
36
|
statement: str
|
|
37
37
|
position: ImportPosition = ImportPosition.THIRD_PARTY
|
|
38
|
-
metadata:
|
|
38
|
+
metadata: dict[str, Any] | None = None
|
|
39
39
|
|
|
40
40
|
def __hash__(self) -> int:
|
|
41
41
|
"""Hash based on the import statement.
|
|
@@ -89,7 +89,7 @@ class EnvironmentVariable:
|
|
|
89
89
|
|
|
90
90
|
name: str
|
|
91
91
|
value: str
|
|
92
|
-
description:
|
|
92
|
+
description: str | None = None
|
|
93
93
|
required: bool = True
|
|
94
94
|
|
|
95
95
|
def __post_init__(self) -> None:
|
|
@@ -151,7 +151,7 @@ class InstanceArgument:
|
|
|
151
151
|
with_new_line_if_empty: bool = False
|
|
152
152
|
skip_if_empty_string: bool = True
|
|
153
153
|
skip_trailing_comma: bool = False
|
|
154
|
-
comment:
|
|
154
|
+
comment: str | None = None
|
|
155
155
|
|
|
156
156
|
def has_content(self) -> bool:
|
|
157
157
|
"""Check if the instance argument has content.
|
|
@@ -266,13 +266,13 @@ class ExportConfig:
|
|
|
266
266
|
description: str = (
|
|
267
267
|
"Make AG2 Agents Collaborate: Drag, Drop, and Orchestrate with Waldiez"
|
|
268
268
|
)
|
|
269
|
-
requirements: list[str] = field(default_factory=list
|
|
270
|
-
tags: list[str] = field(default_factory=list
|
|
269
|
+
requirements: list[str] = field(default_factory=list)
|
|
270
|
+
tags: list[str] = field(default_factory=list)
|
|
271
271
|
output_extension: str = "py"
|
|
272
272
|
is_async: bool = False
|
|
273
|
-
output_directory:
|
|
274
|
-
uploads_root:
|
|
275
|
-
cache_seed:
|
|
273
|
+
output_directory: str | Path | None = None
|
|
274
|
+
uploads_root: Path | None = None
|
|
275
|
+
cache_seed: int | None = None
|
|
276
276
|
|
|
277
277
|
@property
|
|
278
278
|
def for_notebook(self) -> bool:
|
|
@@ -314,6 +314,7 @@ class ExportConfig:
|
|
|
314
314
|
if for_notebook:
|
|
315
315
|
output_extension = "ipynb"
|
|
316
316
|
cache_seed = kwargs.pop("cache_seed", None)
|
|
317
|
+
# noinspection PyUnreachableCode
|
|
317
318
|
if cache_seed is not None and not isinstance(cache_seed, int):
|
|
318
319
|
cache_seed = None
|
|
319
320
|
return cls(
|
|
@@ -64,7 +64,7 @@ def _get_agent_llm_config_arg_as_arg(
|
|
|
64
64
|
tab = " " * tab_leng * tabs if tabs > 0 else ""
|
|
65
65
|
# tab = " " * tabs if tabs > 0 else ""
|
|
66
66
|
if not agent.data.model_ids:
|
|
67
|
-
return f"{tab}llm_config=False,
|
|
67
|
+
return f"{tab}llm_config=False," + "\n"
|
|
68
68
|
content = f"{tab}llm_config=autogen.LLMConfig(" + "\n"
|
|
69
69
|
content += f"{tab} config_list=["
|
|
70
70
|
got_at_least_one_model = False
|
|
@@ -77,7 +77,7 @@ def _get_agent_llm_config_arg_as_arg(
|
|
|
77
77
|
content += "\n" + f"{tab} {model_name}_llm_config,"
|
|
78
78
|
got_at_least_one_model = True
|
|
79
79
|
if not got_at_least_one_model: # pragma: no cover
|
|
80
|
-
return f"{tab}llm_config=False,
|
|
80
|
+
return f"{tab}llm_config=False," + "\n"
|
|
81
81
|
content += "\n" + f"{tab} ]," + "\n"
|
|
82
82
|
content += f"{tab} cache_seed={cache_seed}," + "\n"
|
|
83
83
|
if temperature is not None:
|
|
@@ -97,7 +97,7 @@ def _get_agent_llm_config_arg_as_dict(
|
|
|
97
97
|
) -> str:
|
|
98
98
|
tab = " " * tab_leng * tabs if tabs > 0 else ""
|
|
99
99
|
if not agent.data.model_ids:
|
|
100
|
-
return f'{tab}"llm_config": False' + "\n"
|
|
100
|
+
return f'{tab}"llm_config": False,' + "\n"
|
|
101
101
|
content = f'{tab}"llm_config": autogen.LLMConfig(' + "\n"
|
|
102
102
|
content += f"{tab} config_list=["
|
|
103
103
|
got_at_least_one_model = False
|
|
@@ -110,7 +110,7 @@ def _get_agent_llm_config_arg_as_dict(
|
|
|
110
110
|
content += "\n" + f"{tab} {model_name}_llm_config,"
|
|
111
111
|
got_at_least_one_model = True
|
|
112
112
|
if not got_at_least_one_model: # pragma: no cover
|
|
113
|
-
return f'{tab}"llm_config": False' + "\n"
|
|
113
|
+
return f'{tab}"llm_config": False,' + "\n"
|
|
114
114
|
content += "\n" + f"{tab} ]," + "\n"
|
|
115
115
|
content += f"{tab} cache_seed={cache_seed}," + "\n"
|
|
116
116
|
if temperature is not None:
|
|
@@ -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"
|
|
@@ -125,25 +198,41 @@ class ExecutionGenerator:
|
|
|
125
198
|
flow_content += " result_dicts: list[dict[str, Any]] = []\n"
|
|
126
199
|
space = " "
|
|
127
200
|
if cache_seed is not None:
|
|
201
|
+
# noinspection SqlDialectInspection
|
|
128
202
|
flow_content += (
|
|
129
|
-
f" with Cache.disk(cache_seed={cache_seed}"
|
|
130
|
-
") as cache: # pyright: ignore\n"
|
|
203
|
+
f" with Cache.disk(cache_seed={cache_seed}) as cache:\n"
|
|
131
204
|
)
|
|
132
205
|
space = f"{space} "
|
|
133
206
|
flow_content += f"{content}" + "\n"
|
|
134
207
|
if not skip_logging:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
flow_content += f"{space}stop_logging()"
|
|
208
|
+
flow_content += ExecutionGenerator._get_stop_logging_call(
|
|
209
|
+
space, is_async
|
|
210
|
+
)
|
|
139
211
|
flow_content += "\n"
|
|
140
212
|
if after_run:
|
|
141
213
|
flow_content += after_run + "\n"
|
|
142
214
|
if cache_seed is not None:
|
|
143
215
|
space = space[4:]
|
|
216
|
+
flow_content += ExecutionGenerator._get_store_results_call(
|
|
217
|
+
space, is_async
|
|
218
|
+
)
|
|
144
219
|
flow_content += f"{space}return result_dicts\n"
|
|
145
220
|
return flow_content
|
|
146
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
|
+
|
|
147
236
|
@staticmethod
|
|
148
237
|
def generate_call_main_function(is_async: bool, for_notebook: bool) -> str:
|
|
149
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:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
# pylint: disable=line-too-long
|
|
4
4
|
# flake8: noqa: E501
|
|
5
|
-
"""Common utils for the final
|
|
5
|
+
"""Common utils for the final flow generation."""
|
|
6
6
|
|
|
7
7
|
from waldiez.models import Waldiez
|
|
8
8
|
|
|
@@ -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,17 +2,17 @@
|
|
|
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 = [
|
|
8
|
+
"import asyncio",
|
|
10
9
|
"import csv",
|
|
11
10
|
"import importlib",
|
|
12
11
|
"import json",
|
|
13
12
|
"import os",
|
|
14
13
|
"import sqlite3",
|
|
15
14
|
"import sys",
|
|
15
|
+
"import traceback",
|
|
16
16
|
"from dataclasses import asdict",
|
|
17
17
|
"from pprint import pprint",
|
|
18
18
|
"from types import ModuleType",
|
|
@@ -208,7 +208,6 @@ def get_the_imports_string(
|
|
|
208
208
|
final_string += "\n"
|
|
209
209
|
|
|
210
210
|
if is_async:
|
|
211
|
-
builtin_imports.insert(0, "import asyncio")
|
|
212
211
|
final_string += (
|
|
213
212
|
"\nimport aiofiles"
|
|
214
213
|
"\nimport aiosqlite"
|
|
@@ -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
|
|