waldiez 0.4.6__py3-none-any.whl → 0.4.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of waldiez might be problematic. Click here for more details.
- waldiez/__init__.py +5 -5
- waldiez/_version.py +1 -1
- waldiez/cli.py +112 -73
- waldiez/exporter.py +61 -19
- waldiez/exporting/__init__.py +25 -6
- waldiez/exporting/agent/__init__.py +7 -3
- waldiez/exporting/agent/code_execution.py +114 -0
- waldiez/exporting/agent/exporter.py +354 -0
- waldiez/exporting/agent/extras/__init__.py +15 -0
- waldiez/exporting/agent/extras/captain_agent_extras.py +315 -0
- waldiez/exporting/agent/extras/group/target.py +178 -0
- waldiez/exporting/agent/extras/group_manager_agent_extas.py +500 -0
- waldiez/exporting/agent/extras/group_member_extras.py +181 -0
- waldiez/exporting/agent/extras/handoffs/__init__.py +19 -0
- waldiez/exporting/agent/extras/handoffs/after_work.py +78 -0
- waldiez/exporting/agent/extras/handoffs/available.py +74 -0
- waldiez/exporting/agent/extras/handoffs/condition.py +158 -0
- waldiez/exporting/agent/extras/handoffs/handoff.py +171 -0
- waldiez/exporting/agent/extras/handoffs/target.py +189 -0
- waldiez/exporting/agent/extras/rag/__init__.py +10 -0
- waldiez/exporting/agent/{utils/rag_user/chroma_utils.py → extras/rag/chroma_extras.py} +16 -15
- waldiez/exporting/agent/{utils/rag_user/mongo_utils.py → extras/rag/mongo_extras.py} +10 -10
- waldiez/exporting/agent/{utils/rag_user/pgvector_utils.py → extras/rag/pgvector_extras.py} +13 -13
- waldiez/exporting/agent/{utils/rag_user/qdrant_utils.py → extras/rag/qdrant_extras.py} +13 -13
- waldiez/exporting/agent/{utils/rag_user/vector_db.py → extras/rag/vector_db_extras.py} +59 -46
- waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +245 -0
- waldiez/exporting/agent/extras/reasoning_agent_extras.py +88 -0
- waldiez/exporting/agent/factory.py +95 -0
- waldiez/exporting/agent/processor.py +150 -0
- waldiez/exporting/agent/system_message.py +36 -0
- waldiez/exporting/agent/termination.py +50 -0
- waldiez/exporting/chats/__init__.py +7 -3
- waldiez/exporting/chats/exporter.py +97 -0
- waldiez/exporting/chats/factory.py +65 -0
- waldiez/exporting/chats/processor.py +226 -0
- waldiez/exporting/chats/utils/__init__.py +6 -5
- waldiez/exporting/chats/utils/common.py +11 -45
- waldiez/exporting/chats/utils/group.py +55 -0
- waldiez/exporting/chats/utils/nested.py +37 -52
- waldiez/exporting/chats/utils/sequential.py +72 -61
- waldiez/exporting/chats/utils/{single_chat.py → single.py} +48 -50
- waldiez/exporting/core/__init__.py +196 -0
- waldiez/exporting/core/constants.py +17 -0
- waldiez/exporting/core/content.py +69 -0
- waldiez/exporting/core/context.py +244 -0
- waldiez/exporting/core/enums.py +89 -0
- waldiez/exporting/core/errors.py +19 -0
- waldiez/exporting/core/exporter.py +390 -0
- waldiez/exporting/core/exporters.py +67 -0
- waldiez/exporting/core/extras/__init__.py +39 -0
- waldiez/exporting/core/extras/agent_extras/__init__.py +27 -0
- waldiez/exporting/core/extras/agent_extras/captain_extras.py +57 -0
- waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +102 -0
- waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +53 -0
- waldiez/exporting/core/extras/agent_extras/reasoning_extras.py +68 -0
- waldiez/exporting/core/extras/agent_extras/standard_extras.py +263 -0
- waldiez/exporting/core/extras/base.py +241 -0
- waldiez/exporting/core/extras/chat_extras.py +118 -0
- waldiez/exporting/core/extras/flow_extras.py +70 -0
- waldiez/exporting/core/extras/model_extras.py +73 -0
- waldiez/exporting/core/extras/path_resolver.py +93 -0
- waldiez/exporting/core/extras/serializer.py +138 -0
- waldiez/exporting/core/extras/tool_extras.py +82 -0
- waldiez/exporting/core/protocols.py +259 -0
- waldiez/exporting/core/result.py +705 -0
- waldiez/exporting/core/types.py +329 -0
- waldiez/exporting/core/utils/__init__.py +11 -0
- waldiez/exporting/core/utils/comment.py +33 -0
- waldiez/exporting/core/utils/llm_config.py +117 -0
- waldiez/exporting/core/validation.py +96 -0
- waldiez/exporting/flow/__init__.py +6 -2
- waldiez/exporting/flow/execution_generator.py +193 -0
- waldiez/exporting/flow/exporter.py +107 -0
- waldiez/exporting/flow/factory.py +94 -0
- waldiez/exporting/flow/file_generator.py +214 -0
- waldiez/exporting/flow/merger.py +387 -0
- waldiez/exporting/flow/orchestrator.py +411 -0
- waldiez/exporting/flow/utils/__init__.py +9 -36
- waldiez/exporting/flow/utils/common.py +206 -0
- waldiez/exporting/flow/utils/importing.py +373 -0
- waldiez/exporting/flow/utils/linting.py +200 -0
- waldiez/exporting/flow/utils/{logging_utils.py → logging.py} +23 -9
- waldiez/exporting/models/__init__.py +3 -1
- waldiez/exporting/models/exporter.py +233 -0
- waldiez/exporting/models/factory.py +66 -0
- waldiez/exporting/models/processor.py +139 -0
- waldiez/exporting/tools/__init__.py +11 -0
- waldiez/exporting/tools/exporter.py +207 -0
- waldiez/exporting/tools/factory.py +57 -0
- waldiez/exporting/tools/processor.py +248 -0
- waldiez/exporting/tools/registration.py +133 -0
- waldiez/io/__init__.py +128 -0
- waldiez/io/_ws.py +199 -0
- waldiez/io/models/__init__.py +60 -0
- waldiez/io/models/base.py +66 -0
- waldiez/io/models/constants.py +78 -0
- waldiez/io/models/content/__init__.py +23 -0
- waldiez/io/models/content/audio.py +43 -0
- waldiez/io/models/content/base.py +45 -0
- waldiez/io/models/content/file.py +43 -0
- waldiez/io/models/content/image.py +96 -0
- waldiez/io/models/content/text.py +37 -0
- waldiez/io/models/content/video.py +43 -0
- waldiez/io/models/user_input.py +269 -0
- waldiez/io/models/user_response.py +215 -0
- waldiez/io/mqtt.py +681 -0
- waldiez/io/redis.py +782 -0
- waldiez/io/structured.py +419 -0
- waldiez/io/utils.py +184 -0
- waldiez/io/ws.py +298 -0
- waldiez/logger.py +481 -0
- waldiez/models/__init__.py +108 -51
- waldiez/models/agents/__init__.py +34 -70
- waldiez/models/agents/agent/__init__.py +10 -4
- waldiez/models/agents/agent/agent.py +466 -65
- waldiez/models/agents/agent/agent_data.py +119 -47
- waldiez/models/agents/agent/agent_type.py +13 -2
- waldiez/models/agents/agent/code_execution.py +12 -12
- waldiez/models/agents/agent/human_input_mode.py +8 -0
- waldiez/models/agents/agent/{linked_skill.py → linked_tool.py} +7 -7
- waldiez/models/agents/agent/nested_chat.py +35 -7
- waldiez/models/agents/agent/termination_message.py +30 -22
- waldiez/models/agents/{swarm_agent → agent}/update_system_message.py +22 -22
- waldiez/models/agents/agents.py +58 -63
- waldiez/models/agents/assistant/assistant.py +4 -4
- waldiez/models/agents/assistant/assistant_data.py +13 -1
- waldiez/models/agents/{captain_agent → captain}/captain_agent.py +5 -5
- waldiez/models/agents/{captain_agent → captain}/captain_agent_data.py +5 -5
- waldiez/models/agents/extra_requirements.py +11 -16
- waldiez/models/agents/group_manager/group_manager.py +103 -13
- waldiez/models/agents/group_manager/group_manager_data.py +36 -14
- waldiez/models/agents/group_manager/speakers.py +77 -24
- waldiez/models/agents/{rag_user → rag_user_proxy}/__init__.py +16 -16
- waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +64 -0
- waldiez/models/agents/{rag_user/rag_user_data.py → rag_user_proxy/rag_user_proxy_data.py} +6 -5
- waldiez/models/agents/{rag_user → rag_user_proxy}/retrieve_config.py +182 -114
- waldiez/models/agents/{rag_user → rag_user_proxy}/vector_db_config.py +13 -13
- waldiez/models/agents/reasoning/reasoning_agent.py +6 -6
- waldiez/models/agents/reasoning/reasoning_agent_data.py +110 -63
- waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +38 -10
- waldiez/models/agents/user_proxy/user_proxy.py +11 -7
- waldiez/models/agents/user_proxy/user_proxy_data.py +2 -2
- waldiez/models/chat/__init__.py +2 -1
- waldiez/models/chat/chat.py +166 -87
- waldiez/models/chat/chat_data.py +99 -136
- waldiez/models/chat/chat_message.py +33 -23
- waldiez/models/chat/chat_nested.py +31 -30
- waldiez/models/chat/chat_summary.py +10 -8
- waldiez/models/common/__init__.py +52 -2
- waldiez/models/common/ag2_version.py +1 -1
- waldiez/models/common/base.py +38 -7
- waldiez/models/common/dict_utils.py +42 -17
- waldiez/models/common/handoff.py +459 -0
- waldiez/models/common/id_generator.py +19 -0
- waldiez/models/common/method_utils.py +130 -68
- waldiez/{exporting/base/utils → models/common}/naming.py +38 -61
- waldiez/models/common/waldiez_version.py +37 -0
- waldiez/models/flow/__init__.py +9 -2
- waldiez/models/flow/connection.py +18 -0
- waldiez/models/flow/flow.py +311 -215
- waldiez/models/flow/flow_data.py +207 -40
- waldiez/models/flow/info.py +85 -0
- waldiez/models/flow/naming.py +131 -0
- waldiez/models/model/__init__.py +7 -1
- waldiez/models/model/extra_requirements.py +3 -12
- waldiez/models/model/model.py +76 -21
- waldiez/models/model/model_data.py +108 -20
- waldiez/models/tool/__init__.py +16 -0
- waldiez/models/tool/extra_requirements.py +36 -0
- waldiez/models/{skill/skill.py → tool/tool.py} +88 -88
- waldiez/models/tool/tool_data.py +51 -0
- waldiez/models/tool/tool_type.py +8 -0
- waldiez/models/waldiez.py +97 -80
- waldiez/runner.py +114 -49
- waldiez/running/__init__.py +1 -1
- waldiez/running/environment.py +49 -68
- waldiez/running/gen_seq_diagram.py +16 -14
- waldiez/running/running.py +53 -34
- waldiez/utils/__init__.py +0 -4
- waldiez/utils/cli_extras/jupyter.py +5 -3
- waldiez/utils/cli_extras/runner.py +6 -4
- waldiez/utils/cli_extras/studio.py +6 -4
- waldiez/utils/conflict_checker.py +15 -9
- waldiez/utils/flaml_warnings.py +5 -5
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/METADATA +235 -91
- waldiez-0.4.8.dist-info/RECORD +200 -0
- waldiez/exporting/agent/agent_exporter.py +0 -297
- waldiez/exporting/agent/utils/__init__.py +0 -23
- waldiez/exporting/agent/utils/captain_agent.py +0 -263
- waldiez/exporting/agent/utils/code_execution.py +0 -65
- waldiez/exporting/agent/utils/group_manager.py +0 -220
- waldiez/exporting/agent/utils/rag_user/__init__.py +0 -7
- waldiez/exporting/agent/utils/rag_user/rag_user.py +0 -209
- waldiez/exporting/agent/utils/reasoning.py +0 -36
- waldiez/exporting/agent/utils/swarm_agent.py +0 -469
- waldiez/exporting/agent/utils/teachability.py +0 -41
- waldiez/exporting/agent/utils/termination_message.py +0 -44
- waldiez/exporting/base/__init__.py +0 -25
- waldiez/exporting/base/agent_position.py +0 -75
- waldiez/exporting/base/base_exporter.py +0 -118
- waldiez/exporting/base/export_position.py +0 -48
- waldiez/exporting/base/import_position.py +0 -23
- waldiez/exporting/base/mixin.py +0 -137
- waldiez/exporting/base/utils/__init__.py +0 -18
- waldiez/exporting/base/utils/comments.py +0 -96
- waldiez/exporting/base/utils/path_check.py +0 -68
- waldiez/exporting/base/utils/to_string.py +0 -84
- waldiez/exporting/chats/chats_exporter.py +0 -240
- waldiez/exporting/chats/utils/swarm.py +0 -210
- waldiez/exporting/flow/flow_exporter.py +0 -528
- waldiez/exporting/flow/utils/agent_utils.py +0 -204
- waldiez/exporting/flow/utils/chat_utils.py +0 -71
- waldiez/exporting/flow/utils/def_main.py +0 -77
- waldiez/exporting/flow/utils/flow_content.py +0 -202
- waldiez/exporting/flow/utils/flow_names.py +0 -116
- waldiez/exporting/flow/utils/importing_utils.py +0 -227
- waldiez/exporting/models/models_exporter.py +0 -199
- waldiez/exporting/models/utils.py +0 -174
- waldiez/exporting/skills/__init__.py +0 -9
- waldiez/exporting/skills/skills_exporter.py +0 -176
- waldiez/exporting/skills/utils.py +0 -369
- waldiez/models/agents/agent/teachability.py +0 -70
- waldiez/models/agents/rag_user/rag_user.py +0 -60
- waldiez/models/agents/swarm_agent/__init__.py +0 -50
- waldiez/models/agents/swarm_agent/after_work.py +0 -179
- waldiez/models/agents/swarm_agent/on_condition.py +0 -105
- waldiez/models/agents/swarm_agent/on_condition_available.py +0 -142
- waldiez/models/agents/swarm_agent/on_condition_target.py +0 -40
- waldiez/models/agents/swarm_agent/swarm_agent.py +0 -107
- waldiez/models/agents/swarm_agent/swarm_agent_data.py +0 -124
- waldiez/models/flow/utils.py +0 -232
- waldiez/models/skill/__init__.py +0 -16
- waldiez/models/skill/extra_requirements.py +0 -36
- waldiez/models/skill/skill_data.py +0 -53
- waldiez/models/skill/skill_type.py +0 -8
- waldiez/utils/pysqlite3_checker.py +0 -308
- waldiez/utils/rdps_checker.py +0 -122
- waldiez-0.4.6.dist-info/RECORD +0 -149
- /waldiez/models/agents/{captain_agent → captain}/__init__.py +0 -0
- /waldiez/models/agents/{captain_agent → captain}/captain_agent_lib_entry.py +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/WHEEL +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/entry_points.txt +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0.
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# pyright: reportUnknownMemberType=false,reportUnknownVariableType=false
|
|
4
|
+
# pyright: reportUnknownArgumentType=false
|
|
3
5
|
"""Function related utilities."""
|
|
4
6
|
|
|
5
7
|
import ast
|
|
@@ -7,15 +9,25 @@ import importlib.util
|
|
|
7
9
|
import sys
|
|
8
10
|
import sysconfig
|
|
9
11
|
from pathlib import Path
|
|
10
|
-
from typing import
|
|
12
|
+
from typing import NamedTuple, Optional
|
|
11
13
|
|
|
14
|
+
# parso for extracting function bodies
|
|
15
|
+
# (keeps comments, docstrings and formatting as-is)
|
|
12
16
|
import parso
|
|
13
|
-
import parso.python
|
|
14
|
-
import parso.tree
|
|
17
|
+
import parso.python # pyright: ignore
|
|
18
|
+
import parso.tree # pyright: ignore
|
|
15
19
|
|
|
20
|
+
# let's limit the variable name length
|
|
16
21
|
MAX_VAR_NAME_LENGTH = 64
|
|
17
22
|
|
|
18
23
|
|
|
24
|
+
class ParseResult(NamedTuple):
|
|
25
|
+
"""Result of parsing a code string."""
|
|
26
|
+
|
|
27
|
+
error: Optional[str]
|
|
28
|
+
tree: Optional[ast.Module]
|
|
29
|
+
|
|
30
|
+
|
|
19
31
|
def is_standard_library(module_name: str) -> bool:
|
|
20
32
|
"""Check if the module is part of the standard library.
|
|
21
33
|
|
|
@@ -33,21 +45,21 @@ def is_standard_library(module_name: str) -> bool:
|
|
|
33
45
|
return True
|
|
34
46
|
try:
|
|
35
47
|
spec = importlib.util.find_spec(module_name)
|
|
36
|
-
except
|
|
48
|
+
except (ImportError, ValueError, ModuleNotFoundError): # pragma: no cover
|
|
37
49
|
return False
|
|
38
|
-
if spec is None or not spec.origin:
|
|
50
|
+
if spec is None or not spec.origin: # pragma: no cover
|
|
39
51
|
return False
|
|
40
52
|
if "site-packages" in spec.origin:
|
|
41
53
|
return False
|
|
42
|
-
if spec.origin
|
|
54
|
+
if spec.origin == "frozen":
|
|
43
55
|
return True
|
|
44
|
-
stdlib_path =
|
|
45
|
-
return spec.origin.
|
|
56
|
+
stdlib_path = Path(sysconfig.get_path("stdlib")).resolve()
|
|
57
|
+
return Path(spec.origin).resolve().is_relative_to(stdlib_path)
|
|
46
58
|
|
|
47
59
|
|
|
48
60
|
def parse_code_string(
|
|
49
61
|
code_string: str,
|
|
50
|
-
) ->
|
|
62
|
+
) -> ParseResult:
|
|
51
63
|
"""Parse the code string.
|
|
52
64
|
|
|
53
65
|
Parameters
|
|
@@ -57,7 +69,7 @@ def parse_code_string(
|
|
|
57
69
|
|
|
58
70
|
Returns
|
|
59
71
|
-------
|
|
60
|
-
|
|
72
|
+
ParseResult
|
|
61
73
|
If valid, None and the ast module.
|
|
62
74
|
If invalid, the error message and None.
|
|
63
75
|
"""
|
|
@@ -65,16 +77,95 @@ def parse_code_string(
|
|
|
65
77
|
try:
|
|
66
78
|
tree = ast.parse(code_string)
|
|
67
79
|
except SyntaxError as e:
|
|
68
|
-
return
|
|
80
|
+
return ParseResult(
|
|
81
|
+
f"SyntaxError: {e}, in " + "\n" + f"{code_string}", None
|
|
82
|
+
)
|
|
69
83
|
except BaseException as e: # pragma: no cover
|
|
70
|
-
return
|
|
71
|
-
|
|
84
|
+
return ParseResult(
|
|
85
|
+
f"Invalid code: {e}, in " + "\n" + f"{code_string}", None
|
|
86
|
+
)
|
|
87
|
+
return ParseResult(None, tree)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _extract_module_name(node: ast.AST) -> Optional[str]:
|
|
91
|
+
"""Extract the root module name from an import node."""
|
|
92
|
+
if isinstance(node, ast.Import):
|
|
93
|
+
return node.names[0].name.split(".")[0]
|
|
94
|
+
if isinstance(node, ast.ImportFrom):
|
|
95
|
+
if node.module:
|
|
96
|
+
# Handle relative imports
|
|
97
|
+
if node.module.startswith("."): # pragma: no cover
|
|
98
|
+
return None # Skip relative imports for stdlib check
|
|
99
|
+
return node.module.split(".")[0]
|
|
100
|
+
return None # pragma: no cover
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _extract_imports_from_ast(code_string: str) -> tuple[list[str], list[str]]:
|
|
104
|
+
"""Extract import statements from code using AST.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
code_string : str
|
|
109
|
+
The code string to parse.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
tuple[list[str], list[str]]
|
|
114
|
+
Standard library imports and third party imports (unsorted).
|
|
115
|
+
"""
|
|
116
|
+
standard_lib_imports: list[str] = []
|
|
117
|
+
third_party_imports: list[str] = []
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
tree = ast.parse(code_string)
|
|
121
|
+
except SyntaxError: # pragma: no cover
|
|
122
|
+
return [], []
|
|
123
|
+
|
|
124
|
+
for node in ast.walk(tree):
|
|
125
|
+
if isinstance(node, (ast.Import, ast.ImportFrom)):
|
|
126
|
+
full_import_statement = ast.get_source_segment(code_string, node)
|
|
127
|
+
if not full_import_statement: # pragma: no cover
|
|
128
|
+
continue
|
|
129
|
+
full_import_statement = full_import_statement.strip()
|
|
130
|
+
|
|
131
|
+
module_name = _extract_module_name(node)
|
|
132
|
+
if not module_name: # pragma: no cover
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
if is_standard_library(module_name):
|
|
136
|
+
standard_lib_imports.append(full_import_statement)
|
|
137
|
+
else:
|
|
138
|
+
third_party_imports.append(full_import_statement)
|
|
139
|
+
|
|
140
|
+
return standard_lib_imports, third_party_imports
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _sort_imports(imports: list[str]) -> list[str]:
|
|
144
|
+
"""Sort import statements with 'import' statements before 'from' statements.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
imports : list[str]
|
|
149
|
+
List of import statements to sort.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
list[str]
|
|
154
|
+
Sorted import statements.
|
|
155
|
+
"""
|
|
156
|
+
import_statements = sorted(
|
|
157
|
+
[stmt for stmt in imports if stmt.startswith("import ")]
|
|
158
|
+
)
|
|
159
|
+
from_statements = sorted(
|
|
160
|
+
[stmt for stmt in imports if stmt.startswith("from ")]
|
|
161
|
+
)
|
|
162
|
+
return import_statements + from_statements
|
|
72
163
|
|
|
73
164
|
|
|
74
165
|
def gather_code_imports(
|
|
75
166
|
code_string: str,
|
|
76
167
|
is_interop: bool,
|
|
77
|
-
) ->
|
|
168
|
+
) -> tuple[list[str], list[str]]:
|
|
78
169
|
"""Gather the imports from the code string.
|
|
79
170
|
|
|
80
171
|
Parameters
|
|
@@ -86,35 +177,13 @@ def gather_code_imports(
|
|
|
86
177
|
|
|
87
178
|
Returns
|
|
88
179
|
-------
|
|
89
|
-
|
|
180
|
+
tuple[list[str], list[str]]
|
|
90
181
|
The standard library imports and the third party imports.
|
|
91
182
|
"""
|
|
92
|
-
standard_lib_imports
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if node.type == "import_name":
|
|
97
|
-
full_import_statement = node.get_code().strip()
|
|
98
|
-
module_name = (
|
|
99
|
-
node.get_code().replace("import", "").strip().split(" ")[0]
|
|
100
|
-
)
|
|
101
|
-
if not module_name:
|
|
102
|
-
continue
|
|
103
|
-
if is_standard_library(module_name):
|
|
104
|
-
standard_lib_imports.append(full_import_statement)
|
|
105
|
-
else:
|
|
106
|
-
third_party_imports.append(full_import_statement)
|
|
107
|
-
elif node.type == "import_from":
|
|
108
|
-
full_import_statement = node.get_code().strip()
|
|
109
|
-
module_name = (
|
|
110
|
-
node.get_code().replace("from", "").strip().split(" ")[0]
|
|
111
|
-
)
|
|
112
|
-
if not module_name:
|
|
113
|
-
continue
|
|
114
|
-
if is_standard_library(module_name):
|
|
115
|
-
standard_lib_imports.append(full_import_statement)
|
|
116
|
-
else:
|
|
117
|
-
third_party_imports.append(full_import_statement)
|
|
183
|
+
standard_lib_imports, third_party_imports = _extract_imports_from_ast(
|
|
184
|
+
code_string
|
|
185
|
+
)
|
|
186
|
+
|
|
118
187
|
if is_interop and (
|
|
119
188
|
"from autogen.interop import Interoperability"
|
|
120
189
|
not in third_party_imports
|
|
@@ -122,25 +191,18 @@ def gather_code_imports(
|
|
|
122
191
|
third_party_imports.append(
|
|
123
192
|
"from autogen.interop import Interoperability"
|
|
124
193
|
)
|
|
125
|
-
|
|
126
|
-
sorted_standard_lib_imports =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
[stmt for stmt in standard_lib_imports if stmt.startswith("from ")]
|
|
130
|
-
)
|
|
131
|
-
sorted_third_party_imports = sorted(
|
|
132
|
-
[stmt for stmt in third_party_imports if stmt.startswith("import ")]
|
|
133
|
-
) + sorted(
|
|
134
|
-
[stmt for stmt in third_party_imports if stmt.startswith("from ")]
|
|
135
|
-
)
|
|
194
|
+
|
|
195
|
+
sorted_standard_lib_imports = _sort_imports(standard_lib_imports)
|
|
196
|
+
sorted_third_party_imports = _sort_imports(third_party_imports)
|
|
197
|
+
|
|
136
198
|
return sorted_standard_lib_imports, sorted_third_party_imports
|
|
137
199
|
|
|
138
200
|
|
|
139
201
|
def check_function(
|
|
140
202
|
code_string: str,
|
|
141
203
|
function_name: str,
|
|
142
|
-
function_args:
|
|
143
|
-
) ->
|
|
204
|
+
function_args: list[str],
|
|
205
|
+
) -> tuple[bool, str]:
|
|
144
206
|
"""Check the function.
|
|
145
207
|
|
|
146
208
|
Parameters
|
|
@@ -149,12 +211,12 @@ def check_function(
|
|
|
149
211
|
The code string to check.
|
|
150
212
|
function_name : str
|
|
151
213
|
The expected method name.
|
|
152
|
-
function_args :
|
|
214
|
+
function_args : list[str]
|
|
153
215
|
The expected method arguments.
|
|
154
216
|
|
|
155
217
|
Returns
|
|
156
218
|
-------
|
|
157
|
-
|
|
219
|
+
tuple[bool, str]
|
|
158
220
|
If valid, True and the function body (only), no extra lines.
|
|
159
221
|
If invalid, False and the error message.
|
|
160
222
|
"""
|
|
@@ -173,24 +235,24 @@ def _validate_function_body(
|
|
|
173
235
|
tree: ast.Module,
|
|
174
236
|
code_string: str,
|
|
175
237
|
function_name: str,
|
|
176
|
-
function_args:
|
|
177
|
-
) ->
|
|
238
|
+
function_args: list[str],
|
|
239
|
+
) -> tuple[bool, str]:
|
|
178
240
|
"""Get the function body.
|
|
179
241
|
|
|
180
242
|
Parameters
|
|
181
243
|
----------
|
|
182
244
|
tree : ast.Module
|
|
183
245
|
The ast module.
|
|
184
|
-
|
|
246
|
+
code_string : str
|
|
185
247
|
The function body.
|
|
186
248
|
function_name : str
|
|
187
249
|
The expected method name.
|
|
188
|
-
function_args :
|
|
250
|
+
function_args : list[str]
|
|
189
251
|
The expected method arguments.
|
|
190
252
|
|
|
191
253
|
Returns
|
|
192
254
|
-------
|
|
193
|
-
|
|
255
|
+
tuple[bool, str]
|
|
194
256
|
If valid, True and the function body (only), no extra lines.
|
|
195
257
|
If invalid, False and the error message.
|
|
196
258
|
"""
|
|
@@ -277,13 +339,13 @@ def _get_function_body(
|
|
|
277
339
|
Raises
|
|
278
340
|
------
|
|
279
341
|
ValueError
|
|
280
|
-
If
|
|
342
|
+
If the function's body is empty.
|
|
281
343
|
"""
|
|
282
344
|
lines = code_string.splitlines()
|
|
283
345
|
signature_start_line = node.lineno - 1
|
|
284
346
|
body_start_line = node.body[0].lineno - 1
|
|
285
347
|
signature_end_line = signature_start_line
|
|
286
|
-
for i in range(signature_start_line, body_start_line):
|
|
348
|
+
for i in range(signature_start_line, body_start_line): # pragma: no branch
|
|
287
349
|
if ")" in lines[i]:
|
|
288
350
|
signature_end_line = i
|
|
289
351
|
break
|
|
@@ -301,8 +363,8 @@ def _get_function_body(
|
|
|
301
363
|
|
|
302
364
|
def generate_function(
|
|
303
365
|
function_name: str,
|
|
304
|
-
function_args:
|
|
305
|
-
function_types:
|
|
366
|
+
function_args: list[str],
|
|
367
|
+
function_types: tuple[list[str], str],
|
|
306
368
|
function_body: str,
|
|
307
369
|
types_as_comments: bool = False,
|
|
308
370
|
) -> str:
|
|
@@ -312,9 +374,9 @@ def generate_function(
|
|
|
312
374
|
----------
|
|
313
375
|
function_name : str
|
|
314
376
|
The function name.
|
|
315
|
-
function_args :
|
|
377
|
+
function_args : list[str]
|
|
316
378
|
The function arguments.
|
|
317
|
-
function_types :
|
|
379
|
+
function_types : tuple[list[str], str]
|
|
318
380
|
The function types.
|
|
319
381
|
function_body : str
|
|
320
382
|
The function body.
|
|
@@ -349,6 +411,6 @@ def generate_function(
|
|
|
349
411
|
function_string += " -> " + function_types[1] + ":"
|
|
350
412
|
function_string += "\n" if not function_body.startswith("\n") else ""
|
|
351
413
|
function_string += f"{function_body}"
|
|
352
|
-
if not function_string.endswith("\n"):
|
|
414
|
+
if not function_string.endswith("\n"): # pragma: no branch
|
|
353
415
|
function_string += "\n"
|
|
354
416
|
return function_string
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0.
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
Functions
|
|
6
|
-
---------
|
|
7
|
-
get_valid_python_variable_name
|
|
8
|
-
Make sure a string is a valid Python variable name.
|
|
9
|
-
get_valid_instance_name
|
|
10
|
-
Get a valid instance name.
|
|
11
|
-
get_escaped_string
|
|
12
|
-
Get a string with escaped quotes and newlines.
|
|
13
|
-
"""
|
|
3
|
+
"""Ensure unique names for agents, models, tools, and chats."""
|
|
14
4
|
|
|
15
5
|
import re
|
|
16
|
-
from typing import Dict, Tuple
|
|
17
6
|
|
|
18
7
|
MAX_VARIABLE_LENGTH = 46
|
|
19
8
|
|
|
@@ -29,10 +18,8 @@ def get_valid_python_variable_name(
|
|
|
29
18
|
----------
|
|
30
19
|
possible : str
|
|
31
20
|
The possible name.
|
|
32
|
-
|
|
33
21
|
prefix : str, optional
|
|
34
22
|
The prefix to use if the name starts with a digit or special character
|
|
35
|
-
|
|
36
23
|
max_length : int, optional
|
|
37
24
|
The maximum length of the variable name.
|
|
38
25
|
|
|
@@ -41,47 +28,48 @@ def get_valid_python_variable_name(
|
|
|
41
28
|
str
|
|
42
29
|
The valid Python variable name.
|
|
43
30
|
"""
|
|
31
|
+
if not possible or not possible.strip():
|
|
32
|
+
return prefix + "_"
|
|
33
|
+
|
|
34
|
+
# First handle arrow operators specifically
|
|
35
|
+
possible = possible.replace("->", "to")
|
|
36
|
+
possible = possible.replace("=>", "to")
|
|
37
|
+
possible = possible.replace("<-", "from")
|
|
38
|
+
possible = possible.replace("<=", "from")
|
|
39
|
+
|
|
40
|
+
# Replace non-ASCII characters and non-word characters with underscores
|
|
41
|
+
# \W matches any non-word character, but in Python's re module,
|
|
42
|
+
# \w includes Unicode letters by default, so we need to be more explicit
|
|
43
|
+
# to replace Unicode letters with underscores for valid Python identifiers
|
|
44
|
+
possible = re.sub(r"[^\w]", "_", possible) # Replace non-word chars
|
|
45
|
+
possible = re.sub(r"[^\x00-\x7F]", "_", possible) # Replace non-ASCII chars
|
|
46
|
+
|
|
47
|
+
# Convert to lowercase and truncate
|
|
48
|
+
possible = possible.lower()[:max_length]
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Parameters
|
|
49
|
-
----------
|
|
50
|
-
match : re.Match[str]
|
|
51
|
-
The match.
|
|
52
|
-
|
|
53
|
-
Returns
|
|
54
|
-
-------
|
|
55
|
-
str
|
|
56
|
-
The replacement
|
|
57
|
-
"""
|
|
58
|
-
if match.group(0) in ["->", "=>"]:
|
|
59
|
-
return "to"
|
|
60
|
-
if match.group(0) in ["<-", "<="]:
|
|
61
|
-
return "from"
|
|
62
|
-
if re.match(r"\W|^(?=\d)", match.group(0)):
|
|
63
|
-
return "_"
|
|
64
|
-
return match.group(0)
|
|
65
|
-
|
|
66
|
-
possible = re.sub(r"->|=>|<-|<=|\W|^(?=\d)", replacement, possible)[
|
|
67
|
-
:max_length
|
|
68
|
-
].lower()
|
|
50
|
+
# Remove trailing underscores from truncation
|
|
51
|
+
possible = possible.rstrip("_")
|
|
69
52
|
|
|
70
53
|
if not possible:
|
|
71
54
|
return prefix + "_"
|
|
55
|
+
|
|
56
|
+
# Handle names starting with underscore
|
|
72
57
|
if possible.startswith("_"):
|
|
73
58
|
return f"{prefix}{possible}"
|
|
59
|
+
|
|
60
|
+
# Handle names starting with digit
|
|
74
61
|
if possible[0].isdigit():
|
|
75
62
|
return f"{prefix}_{possible}"
|
|
63
|
+
|
|
76
64
|
return possible
|
|
77
65
|
|
|
78
66
|
|
|
79
67
|
def get_valid_instance_name(
|
|
80
|
-
instance:
|
|
81
|
-
current_names:
|
|
68
|
+
instance: tuple[str, str],
|
|
69
|
+
current_names: dict[str, str],
|
|
82
70
|
prefix: str = "w",
|
|
83
71
|
max_length: int = MAX_VARIABLE_LENGTH,
|
|
84
|
-
) ->
|
|
72
|
+
) -> dict[str, str]:
|
|
85
73
|
"""Get a valid instance name.
|
|
86
74
|
|
|
87
75
|
If the instance id is already in the current names nothing is done.
|
|
@@ -90,9 +78,9 @@ def get_valid_instance_name(
|
|
|
90
78
|
|
|
91
79
|
Parameters
|
|
92
80
|
----------
|
|
93
|
-
instance :
|
|
81
|
+
instance : tuple[str, str]
|
|
94
82
|
The instance id and possible name.
|
|
95
|
-
current_names :
|
|
83
|
+
current_names : dict[str, str]
|
|
96
84
|
The current names.
|
|
97
85
|
prefix : str, optional
|
|
98
86
|
The prefix to use if the name starts with a digit,
|
|
@@ -103,39 +91,28 @@ def get_valid_instance_name(
|
|
|
103
91
|
|
|
104
92
|
Returns
|
|
105
93
|
-------
|
|
106
|
-
|
|
94
|
+
dict[str, str]
|
|
107
95
|
The updated names.
|
|
108
96
|
"""
|
|
109
97
|
instance_id, possible_name = instance[0], instance[1][:max_length]
|
|
98
|
+
|
|
110
99
|
if instance_id in current_names:
|
|
111
|
-
# already in the current names (
|
|
100
|
+
# already in the current names (by its id)
|
|
112
101
|
return current_names
|
|
102
|
+
|
|
113
103
|
new_names = current_names.copy()
|
|
114
104
|
name = get_valid_python_variable_name(
|
|
115
105
|
possible_name, prefix=prefix, max_length=max_length
|
|
116
106
|
)
|
|
107
|
+
|
|
117
108
|
if name in current_names.values():
|
|
118
109
|
name = f"{prefix}_{name}"
|
|
110
|
+
|
|
119
111
|
if name in current_names.values():
|
|
120
112
|
index = 1
|
|
121
113
|
while f"{name}_{index}" in current_names.values():
|
|
122
114
|
index += 1
|
|
123
115
|
name = f"{name}_{index}"
|
|
116
|
+
|
|
124
117
|
new_names[instance_id] = name
|
|
125
118
|
return new_names
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def get_escaped_string(string: str) -> str:
|
|
129
|
-
"""Get a string with escaped quotes and newlines.
|
|
130
|
-
|
|
131
|
-
Parameters
|
|
132
|
-
----------
|
|
133
|
-
string : str
|
|
134
|
-
The original string.
|
|
135
|
-
|
|
136
|
-
Returns
|
|
137
|
-
-------
|
|
138
|
-
str
|
|
139
|
-
The escaped string.
|
|
140
|
-
"""
|
|
141
|
-
return string.replace('"', '\\"').replace("\n", "\\n")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
|
|
4
|
+
"""Read the version from the version file."""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_waldiez_version() -> (
|
|
10
|
+
str
|
|
11
|
+
): # pragma: no cover # depends on file existence
|
|
12
|
+
"""Read the version from the version file.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
str
|
|
17
|
+
The version.
|
|
18
|
+
"""
|
|
19
|
+
here = Path(__file__).parent # waldiez/models/common
|
|
20
|
+
package_dir = here.parent.parent # waldiez/models -> waldiez
|
|
21
|
+
version_file = package_dir / "_version.py"
|
|
22
|
+
if not version_file.exists():
|
|
23
|
+
return "0.0.0" # dev / ignored
|
|
24
|
+
with version_file.open() as f:
|
|
25
|
+
for line in f:
|
|
26
|
+
if line.startswith("__version__"):
|
|
27
|
+
version = line.split("=")[1].strip().strip('"').strip("'")
|
|
28
|
+
# send version without "v" prefix
|
|
29
|
+
if version.startswith("v"):
|
|
30
|
+
version = version[1:]
|
|
31
|
+
# make sure it is a valid semver
|
|
32
|
+
if not version or not all(
|
|
33
|
+
part.isdigit() for part in version.split(".")
|
|
34
|
+
):
|
|
35
|
+
return "0.0.0"
|
|
36
|
+
return version
|
|
37
|
+
return "0.0.0" # fallback if not found
|
waldiez/models/flow/__init__.py
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
"""Waldiez flow related models."""
|
|
4
4
|
|
|
5
|
+
from .connection import WaldiezAgentConnection
|
|
5
6
|
from .flow import WaldiezFlow
|
|
6
|
-
from .flow_data import WaldiezFlowData
|
|
7
|
-
from .
|
|
7
|
+
from .flow_data import WaldiezFlowData, get_flow_data
|
|
8
|
+
from .info import WaldiezAgentInfo, WaldiezFlowInfo
|
|
9
|
+
from .naming import WaldiezUniqueNames, ensure_unique_names
|
|
8
10
|
|
|
9
11
|
__all__ = [
|
|
10
12
|
"get_flow_data",
|
|
13
|
+
"ensure_unique_names",
|
|
14
|
+
"WaldiezAgentConnection",
|
|
15
|
+
"WaldiezAgentInfo",
|
|
11
16
|
"WaldiezFlow",
|
|
17
|
+
"WaldiezFlowInfo",
|
|
12
18
|
"WaldiezFlowData",
|
|
19
|
+
"WaldiezUniqueNames",
|
|
13
20
|
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Waldiez agent connection model."""
|
|
4
|
+
|
|
5
|
+
from typing import TypedDict
|
|
6
|
+
|
|
7
|
+
from ..agents import (
|
|
8
|
+
WaldiezAgent,
|
|
9
|
+
)
|
|
10
|
+
from ..chat import WaldiezChat
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class WaldiezAgentConnection(TypedDict):
|
|
14
|
+
"""Agent connection."""
|
|
15
|
+
|
|
16
|
+
source: WaldiezAgent
|
|
17
|
+
target: WaldiezAgent
|
|
18
|
+
chat: WaldiezChat
|