waldiez 0.3.11__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of waldiez might be problematic. Click here for more details.
- waldiez/_version.py +1 -1
- waldiez/cli.py +1 -3
- waldiez/exporting/agent/agent_exporter.py +26 -15
- waldiez/exporting/agent/utils/__init__.py +2 -4
- waldiez/exporting/agent/utils/captain_agent.py +250 -0
- waldiez/exporting/agent/utils/swarm_agent.py +12 -7
- waldiez/exporting/base/utils/comments.py +1 -0
- waldiez/exporting/chats/utils/swarm.py +1 -1
- waldiez/exporting/flow/flow_exporter.py +5 -6
- waldiez/exporting/flow/utils/__init__.py +3 -6
- waldiez/exporting/flow/utils/def_main.py +5 -4
- waldiez/exporting/flow/utils/flow_content.py +38 -0
- waldiez/exporting/flow/utils/importing_utils.py +64 -29
- waldiez/exporting/skills/skills_exporter.py +13 -6
- waldiez/exporting/skills/utils.py +92 -6
- waldiez/models/__init__.py +6 -0
- waldiez/models/agents/__init__.py +14 -0
- waldiez/models/agents/agent/__init__.py +2 -1
- waldiez/models/agents/agent/agent.py +71 -11
- waldiez/models/agents/agent/agent_type.py +11 -0
- waldiez/models/agents/agents.py +11 -1
- waldiez/models/agents/captain_agent/__init__.py +15 -0
- waldiez/models/agents/captain_agent/captain_agent.py +45 -0
- waldiez/models/agents/captain_agent/captain_agent_data.py +62 -0
- waldiez/models/agents/captain_agent/captain_agent_lib_entry.py +38 -0
- waldiez/models/agents/extra_requirements.py +88 -0
- waldiez/models/agents/group_manager/speakers.py +3 -0
- waldiez/models/agents/rag_user/retrieve_config.py +3 -0
- waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +1 -0
- waldiez/models/agents/swarm_agent/after_work.py +13 -11
- waldiez/models/agents/swarm_agent/on_condition.py +3 -2
- waldiez/models/agents/swarm_agent/on_condition_available.py +1 -0
- waldiez/models/agents/swarm_agent/swarm_agent_data.py +3 -3
- waldiez/models/agents/swarm_agent/update_system_message.py +1 -0
- waldiez/models/chat/chat_message.py +1 -0
- waldiez/models/chat/chat_summary.py +1 -0
- waldiez/models/common/__init__.py +4 -0
- waldiez/models/common/ag2_version.py +30 -0
- waldiez/models/common/base.py +1 -1
- waldiez/models/common/date_utils.py +2 -0
- waldiez/models/common/dict_utils.py +2 -0
- waldiez/models/common/method_utils.py +98 -0
- waldiez/models/flow/__init__.py +2 -0
- waldiez/models/flow/utils.py +61 -1
- waldiez/models/model/__init__.py +2 -0
- waldiez/models/model/extra_requirements.py +57 -0
- waldiez/models/model/model.py +5 -2
- waldiez/models/model/model_data.py +3 -1
- waldiez/models/skill/__init__.py +4 -0
- waldiez/models/skill/extra_requirements.py +39 -0
- waldiez/models/skill/skill.py +157 -13
- waldiez/models/skill/skill_data.py +14 -0
- waldiez/models/skill/skill_type.py +8 -0
- waldiez/models/waldiez.py +47 -76
- waldiez/runner.py +19 -7
- waldiez/running/environment.py +30 -1
- waldiez/running/running.py +0 -6
- waldiez/utils/pysqlite3_checker.py +18 -5
- {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/METADATA +42 -30
- {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/RECORD +64 -55
- waldiez/exporting/agent/utils/agent_class_name.py +0 -36
- waldiez/exporting/agent/utils/agent_imports.py +0 -55
- {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/WHEEL +0 -0
- {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/entry_points.txt +0 -0
- {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Waldiez model extra requirements."""
|
|
4
|
+
|
|
5
|
+
from typing import Iterator, Set
|
|
6
|
+
|
|
7
|
+
from .model import WaldiezModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_models_extra_requirements(
|
|
11
|
+
models: Iterator[WaldiezModel], autogen_version: str
|
|
12
|
+
) -> Set[str]:
|
|
13
|
+
"""Get the models extra requirements.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
models : List[WaldiezModel]
|
|
18
|
+
The models.
|
|
19
|
+
autogen_version : str
|
|
20
|
+
The autogen version.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
List[str]
|
|
25
|
+
The models extra requirements.
|
|
26
|
+
"""
|
|
27
|
+
model_requirements: Set[str] = set()
|
|
28
|
+
# ref: https://github.com/ag2ai/ag2/blob/main/pyproject.toml
|
|
29
|
+
models_with_additional_requirements = [
|
|
30
|
+
"together",
|
|
31
|
+
"gemini",
|
|
32
|
+
"mistral",
|
|
33
|
+
"groq",
|
|
34
|
+
"anthropic",
|
|
35
|
+
"cohere",
|
|
36
|
+
"bedrock", # we might add this later
|
|
37
|
+
]
|
|
38
|
+
for model in models:
|
|
39
|
+
for requirement in model.requirements:
|
|
40
|
+
model_requirements.add(requirement)
|
|
41
|
+
if model.data.api_type == "google":
|
|
42
|
+
model_requirements.add(f"pyautogen[gemini]=={autogen_version}")
|
|
43
|
+
continue
|
|
44
|
+
if model.data.api_type in models_with_additional_requirements:
|
|
45
|
+
model_requirements.add(
|
|
46
|
+
f"pyautogen[{model.data.api_type}]=={autogen_version}"
|
|
47
|
+
)
|
|
48
|
+
return model_requirements
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# for bedrock, there are some additional params needed
|
|
52
|
+
# (both here and on the ui part):
|
|
53
|
+
# aws_region (mandatory)
|
|
54
|
+
# aws_access_key (or environment variable: AWS_ACCESS_KEY)
|
|
55
|
+
# aws_secret_key (or environment variable: AWS_SECRET_KEY)
|
|
56
|
+
# aws_session_token (or environment variable: AWS_SESSION_TOKEN)
|
|
57
|
+
# aws_profile_name
|
waldiez/models/model/model.py
CHANGED
|
@@ -19,6 +19,7 @@ DEFAULT_BASE_URLS: Dict[WaldiezModelAPIType, str] = {
|
|
|
19
19
|
"groq": "https://api.groq.com/openai/v1",
|
|
20
20
|
"together": "https://api.together.xyz/v1",
|
|
21
21
|
"nim": "https://integrate.api.nvidia.com/v1",
|
|
22
|
+
"cohere": "https://api.cohere.com",
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
|
|
@@ -63,7 +64,7 @@ class WaldiezModel(WaldiezBase):
|
|
|
63
64
|
description: Annotated[
|
|
64
65
|
str,
|
|
65
66
|
Field(
|
|
66
|
-
|
|
67
|
+
"Model's Description",
|
|
67
68
|
title="Description",
|
|
68
69
|
description="The description of the model.",
|
|
69
70
|
),
|
|
@@ -118,6 +119,7 @@ class WaldiezModel(WaldiezBase):
|
|
|
118
119
|
- groq: 'GROQ_API_KEY',
|
|
119
120
|
- together: 'TOGETHER_API_KEY',
|
|
120
121
|
- nim: 'NIM_API_KEY',
|
|
122
|
+
- cohere: 'COHERE_API_KEY',
|
|
121
123
|
- other: 'OPENAI_API_KEY'
|
|
122
124
|
"""
|
|
123
125
|
env_key = "OPENAI_API_KEY"
|
|
@@ -142,6 +144,7 @@ class WaldiezModel(WaldiezBase):
|
|
|
142
144
|
- groq: 'GROQ_API_KEY',
|
|
143
145
|
- together: 'TOGETHER_API_KEY',
|
|
144
146
|
- nim: 'NIM_API_KEY',
|
|
147
|
+
- cohere: 'COHERE_API_KEY',
|
|
145
148
|
- other: 'OPENAI_API_KEY'
|
|
146
149
|
"""
|
|
147
150
|
if self.data.api_key and self.data.api_key != "REPLACE_ME":
|
|
@@ -222,7 +225,7 @@ def set_default_base_url(
|
|
|
222
225
|
Dict[str, Any]
|
|
223
226
|
The llm config dictionary with the default base url set.
|
|
224
227
|
"""
|
|
225
|
-
if api_type in ("openai", "other", "azure"):
|
|
228
|
+
if api_type in ("openai", "other", "azure", "cohere"):
|
|
226
229
|
return llm_config
|
|
227
230
|
if "base_url" not in llm_config or not llm_config["base_url"]:
|
|
228
231
|
dict_copy = llm_config.copy()
|
|
@@ -20,8 +20,10 @@ WaldiezModelAPIType = Literal[
|
|
|
20
20
|
"groq",
|
|
21
21
|
"together",
|
|
22
22
|
"nim",
|
|
23
|
+
"cohere",
|
|
23
24
|
"other",
|
|
24
25
|
]
|
|
26
|
+
"""Possible API types for the model."""
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class WaldiezModelPrice(WaldiezBase):
|
|
@@ -53,7 +55,7 @@ class WaldiezModelData(WaldiezBase):
|
|
|
53
55
|
The base url of the model, by default None.
|
|
54
56
|
api_key : Optional[str]
|
|
55
57
|
The api key to use with the model, by default None.
|
|
56
|
-
api_type :
|
|
58
|
+
api_type : WaldiezModelAPIType
|
|
57
59
|
The api type of the model.
|
|
58
60
|
api_version : Optional[str]
|
|
59
61
|
The api version of the model, by default None.
|
waldiez/models/skill/__init__.py
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
"""Waldiez Skill related models."""
|
|
4
4
|
|
|
5
|
+
from .extra_requirements import get_skills_extra_requirements
|
|
5
6
|
from .skill import SHARED_SKILL_NAME, WaldiezSkill
|
|
6
7
|
from .skill_data import WaldiezSkillData
|
|
8
|
+
from .skill_type import WaldiezSkillType
|
|
7
9
|
|
|
8
10
|
__all__ = [
|
|
9
11
|
"SHARED_SKILL_NAME",
|
|
10
12
|
"WaldiezSkill",
|
|
11
13
|
"WaldiezSkillData",
|
|
14
|
+
"WaldiezSkillType",
|
|
15
|
+
"get_skills_extra_requirements",
|
|
12
16
|
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Waldiez skill extra requirements."""
|
|
4
|
+
|
|
5
|
+
from typing import Iterator, Set
|
|
6
|
+
|
|
7
|
+
from .skill import WaldiezSkill
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_skills_extra_requirements(
|
|
11
|
+
skills: Iterator[WaldiezSkill],
|
|
12
|
+
autogen_version: str,
|
|
13
|
+
) -> Set[str]:
|
|
14
|
+
"""Get the skills extra requirements.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
skills : List[WaldiezSkill]
|
|
19
|
+
The skills.
|
|
20
|
+
autogen_version : str
|
|
21
|
+
The ag2 version.
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
List[str]
|
|
25
|
+
The skills extra requirements.
|
|
26
|
+
"""
|
|
27
|
+
skill_requirements: Set[str] = set()
|
|
28
|
+
for skill in skills:
|
|
29
|
+
if skill.skill_type == "langchain":
|
|
30
|
+
skill_requirements.add(
|
|
31
|
+
f"pyautogen[interop-langchain]=={autogen_version}"
|
|
32
|
+
)
|
|
33
|
+
if skill.skill_type == "crewai":
|
|
34
|
+
skill_requirements.add(
|
|
35
|
+
f"pyautogen[interop-crewai]=={autogen_version}"
|
|
36
|
+
)
|
|
37
|
+
for requirement in skill.requirements:
|
|
38
|
+
skill_requirements.add(requirement)
|
|
39
|
+
return skill_requirements
|
waldiez/models/skill/skill.py
CHANGED
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
"""Waldiez Skill model."""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, List, Tuple, Union
|
|
6
9
|
|
|
7
10
|
from pydantic import Field, model_validator
|
|
8
11
|
from typing_extensions import Annotated, Literal, Self
|
|
9
12
|
|
|
10
|
-
from ..common import
|
|
13
|
+
from ..common import (
|
|
14
|
+
WaldiezBase,
|
|
15
|
+
gather_code_imports,
|
|
16
|
+
get_function,
|
|
17
|
+
now,
|
|
18
|
+
parse_code_string,
|
|
19
|
+
)
|
|
11
20
|
from .skill_data import WaldiezSkillData
|
|
21
|
+
from .skill_type import WaldiezSkillType
|
|
12
22
|
|
|
13
23
|
SHARED_SKILL_NAME = "waldiez_shared"
|
|
14
24
|
|
|
@@ -97,6 +107,66 @@ class WaldiezSkill(WaldiezBase):
|
|
|
97
107
|
),
|
|
98
108
|
]
|
|
99
109
|
|
|
110
|
+
@staticmethod
|
|
111
|
+
def load(data_or_path: Union[str, Path, Dict[str, Any]]) -> "WaldiezSkill":
|
|
112
|
+
"""Load a skill from a read-only file.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
data_or_path : Union[str, Path, Dict[str, Any]]
|
|
117
|
+
The path to the read-only file or the loaded data.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
WaldiezSkill
|
|
122
|
+
The skill.
|
|
123
|
+
|
|
124
|
+
Raises
|
|
125
|
+
------
|
|
126
|
+
FileNotFoundError
|
|
127
|
+
If the file is not found.
|
|
128
|
+
ValueError
|
|
129
|
+
If the JSON is invalid or the data is invalid.
|
|
130
|
+
"""
|
|
131
|
+
if isinstance(data_or_path, dict):
|
|
132
|
+
return WaldiezSkill.model_validate(data_or_path)
|
|
133
|
+
if not isinstance(data_or_path, Path):
|
|
134
|
+
data_or_path = Path(data_or_path)
|
|
135
|
+
resolved = data_or_path.resolve()
|
|
136
|
+
if not resolved.is_file():
|
|
137
|
+
raise FileNotFoundError(f"File not found: {resolved}")
|
|
138
|
+
with resolved.open("r", encoding="utf-8") as file:
|
|
139
|
+
data_string = file.read()
|
|
140
|
+
try:
|
|
141
|
+
data_dict = json.loads(data_string)
|
|
142
|
+
except BaseException as exc: # pylint: disable=broad-except
|
|
143
|
+
raise ValueError(f"Invalid WaldiezSkill/JSON: {exc}") from exc
|
|
144
|
+
return WaldiezSkill.model_validate(data_dict)
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def skill_type(self) -> WaldiezSkillType:
|
|
148
|
+
"""Get the skill type.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
WaldiezSkillType
|
|
153
|
+
The type of the skill:
|
|
154
|
+
[shared, custom, langchain, crewai].
|
|
155
|
+
"""
|
|
156
|
+
return self.data.skill_type
|
|
157
|
+
|
|
158
|
+
_skill_imports: Tuple[List[str], List[str]] = ([], [])
|
|
159
|
+
|
|
160
|
+
def get_imports(self) -> Tuple[List[str], List[str]]:
|
|
161
|
+
"""Get the skill imports.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
Tuple[List[str], List[str]]
|
|
166
|
+
The builtin and external imports.
|
|
167
|
+
"""
|
|
168
|
+
return self._skill_imports
|
|
169
|
+
|
|
100
170
|
@property
|
|
101
171
|
def is_shared(self) -> bool:
|
|
102
172
|
"""Check if the skill is shared.
|
|
@@ -106,7 +176,18 @@ class WaldiezSkill(WaldiezBase):
|
|
|
106
176
|
bool
|
|
107
177
|
True if the skill is shared, False otherwise.
|
|
108
178
|
"""
|
|
109
|
-
return self.name == SHARED_SKILL_NAME
|
|
179
|
+
return self.skill_type == "shared" or self.name == SHARED_SKILL_NAME
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def is_interop(self) -> bool:
|
|
183
|
+
"""Check if the skill is interoperability.
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
bool
|
|
188
|
+
True if the skill is interoperability, False otherwise.
|
|
189
|
+
"""
|
|
190
|
+
return self.skill_type in ("langchain", "crewai")
|
|
110
191
|
|
|
111
192
|
def get_content(self) -> str:
|
|
112
193
|
"""Get the content of the skill.
|
|
@@ -116,11 +197,61 @@ class WaldiezSkill(WaldiezBase):
|
|
|
116
197
|
str
|
|
117
198
|
The content of the skill.
|
|
118
199
|
"""
|
|
119
|
-
if self.
|
|
120
|
-
# the whole content (globals)
|
|
200
|
+
if self.is_shared or self.is_interop:
|
|
121
201
|
return self.data.content
|
|
202
|
+
# if custom, only the function content
|
|
122
203
|
return get_function(self.data.content, self.name)
|
|
123
204
|
|
|
205
|
+
def _validate_interop_skill(self) -> None:
|
|
206
|
+
"""Validate the interoperability skill.
|
|
207
|
+
|
|
208
|
+
Raises
|
|
209
|
+
------
|
|
210
|
+
ValueError
|
|
211
|
+
If the skill name is not in the content.
|
|
212
|
+
"""
|
|
213
|
+
if self.is_interop:
|
|
214
|
+
# we expect sth like:
|
|
215
|
+
# with single or double quotes for type={skill_type}
|
|
216
|
+
# {skill_name} = *.convert_tool(..., type="{skill_type}", ...)
|
|
217
|
+
if f"{self.name} = " not in self.data.content:
|
|
218
|
+
raise ValueError(
|
|
219
|
+
f"The skill name '{self.name}' is not in the content."
|
|
220
|
+
)
|
|
221
|
+
# we don't want the conversion to ag2 tool (we do it internally)
|
|
222
|
+
# or the skill registration (we do it after having the agent names)
|
|
223
|
+
# so no" .convert_tool(... type="...")
|
|
224
|
+
# or .register_for_llm(...), .register_for_execution(...)
|
|
225
|
+
to_exclude = [
|
|
226
|
+
r".convert_tool\(.+?type=",
|
|
227
|
+
rf"{self.name}.register_for_llm\(",
|
|
228
|
+
rf"{self.name}.register_for_execution\(",
|
|
229
|
+
]
|
|
230
|
+
for exclude in to_exclude:
|
|
231
|
+
if re.search(exclude, self.data.content):
|
|
232
|
+
raise ValueError(
|
|
233
|
+
f"Invalid skill content: '{exclude}' is not allowed."
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
def _validate_custom_skill(self) -> None:
|
|
237
|
+
"""Validate a custom skill.
|
|
238
|
+
|
|
239
|
+
Raises
|
|
240
|
+
------
|
|
241
|
+
ValueError
|
|
242
|
+
If the skill name is not in the content.
|
|
243
|
+
If the skill content is invalid.
|
|
244
|
+
"""
|
|
245
|
+
search = f"def {self.name}("
|
|
246
|
+
if self.skill_type == "custom" and not self.is_shared:
|
|
247
|
+
if search not in self.data.content:
|
|
248
|
+
raise ValueError(
|
|
249
|
+
f"The skill name '{self.name}' is not in the content."
|
|
250
|
+
)
|
|
251
|
+
error, tree = parse_code_string(self.data.content)
|
|
252
|
+
if error is not None or tree is None:
|
|
253
|
+
raise ValueError(f"Invalid skill content: {error}")
|
|
254
|
+
|
|
124
255
|
@model_validator(mode="after")
|
|
125
256
|
def validate_data(self) -> Self:
|
|
126
257
|
"""Validate the data.
|
|
@@ -136,14 +267,27 @@ class WaldiezSkill(WaldiezBase):
|
|
|
136
267
|
If the skill name is not in the content.
|
|
137
268
|
If the skill content is invalid.
|
|
138
269
|
"""
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
270
|
+
self._validate_custom_skill()
|
|
271
|
+
self._validate_interop_skill()
|
|
272
|
+
self._skill_imports = gather_code_imports(
|
|
273
|
+
self.data.content, self.is_interop
|
|
274
|
+
)
|
|
275
|
+
# remove the imports from the content
|
|
276
|
+
# we 'll place them at the top of the file
|
|
277
|
+
all_imports = self._skill_imports[0] + self._skill_imports[1]
|
|
278
|
+
code_lines = self.data.content.splitlines()
|
|
279
|
+
valid_lines = [
|
|
280
|
+
line
|
|
281
|
+
for line in code_lines
|
|
282
|
+
if not any(line.startswith(imp) for imp in all_imports)
|
|
283
|
+
]
|
|
284
|
+
# remove empty lines at the beginning and end
|
|
285
|
+
# of the content
|
|
286
|
+
while valid_lines and not valid_lines[0].strip():
|
|
287
|
+
valid_lines.pop(0)
|
|
288
|
+
while valid_lines and not valid_lines[-1].strip():
|
|
289
|
+
valid_lines.pop()
|
|
290
|
+
self.data.content = "\n".join(valid_lines)
|
|
147
291
|
return self
|
|
148
292
|
|
|
149
293
|
@property
|
|
@@ -8,6 +8,7 @@ from pydantic import Field
|
|
|
8
8
|
from typing_extensions import Annotated
|
|
9
9
|
|
|
10
10
|
from ..common import WaldiezBase
|
|
11
|
+
from .skill_type import WaldiezSkillType
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class WaldiezSkillData(WaldiezBase):
|
|
@@ -15,12 +16,25 @@ class WaldiezSkillData(WaldiezBase):
|
|
|
15
16
|
|
|
16
17
|
Attributes
|
|
17
18
|
----------
|
|
19
|
+
skill_type : WaldiezSkillType
|
|
20
|
+
The type of the skill: shared, custom, langchain, crewai.
|
|
18
21
|
content : str
|
|
19
22
|
The content (source code) of the skill.
|
|
20
23
|
secrets : Dict[str, str]
|
|
21
24
|
The secrets (environment variables) of the skill.
|
|
22
25
|
"""
|
|
23
26
|
|
|
27
|
+
skill_type: Annotated[
|
|
28
|
+
WaldiezSkillType,
|
|
29
|
+
Field(
|
|
30
|
+
"custom",
|
|
31
|
+
alias="skillType",
|
|
32
|
+
title="Skill Type",
|
|
33
|
+
description=(
|
|
34
|
+
"The type of the skill: shared, custom, langchain, crewai."
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
] = "custom"
|
|
24
38
|
content: Annotated[
|
|
25
39
|
str,
|
|
26
40
|
Field(
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Waldiez Skill types."""
|
|
4
|
+
|
|
5
|
+
from typing_extensions import Literal
|
|
6
|
+
|
|
7
|
+
WaldiezSkillType = Literal["shared", "custom", "langchain", "crewai"]
|
|
8
|
+
"""Possible types of a Waldiez Skill."""
|
waldiez/models/waldiez.py
CHANGED
|
@@ -8,17 +8,16 @@ definitions and their optional additional skills to be used.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
-
import warnings
|
|
12
11
|
from dataclasses import dataclass
|
|
13
|
-
from functools import cache
|
|
14
12
|
from pathlib import Path
|
|
15
13
|
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
|
|
16
14
|
|
|
17
|
-
from .agents import WaldiezAgent
|
|
15
|
+
from .agents import WaldiezAgent, get_retrievechat_extra_requirements
|
|
18
16
|
from .chat import WaldiezChat
|
|
19
|
-
from .
|
|
20
|
-
from .
|
|
21
|
-
from .
|
|
17
|
+
from .common import get_autogen_version
|
|
18
|
+
from .flow import WaldiezFlow, get_flow_data
|
|
19
|
+
from .model import WaldiezModel, get_models_extra_requirements
|
|
20
|
+
from .skill import WaldiezSkill, get_skills_extra_requirements
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
@dataclass(frozen=True, slots=True)
|
|
@@ -62,7 +61,7 @@ class Waldiez:
|
|
|
62
61
|
Waldiez
|
|
63
62
|
The Waldiez.
|
|
64
63
|
"""
|
|
65
|
-
flow =
|
|
64
|
+
flow = get_flow_data(
|
|
66
65
|
data,
|
|
67
66
|
flow_id=flow_id,
|
|
68
67
|
name=name,
|
|
@@ -153,6 +152,11 @@ class Waldiez:
|
|
|
153
152
|
"""Check if the flow has multimodal agents."""
|
|
154
153
|
return any(agent.data.is_multimodal for agent in self.agents)
|
|
155
154
|
|
|
155
|
+
@property
|
|
156
|
+
def has_captain_agents(self) -> bool:
|
|
157
|
+
"""Check if the flow has captain agents."""
|
|
158
|
+
return any(agent.agent_type == "captain" for agent in self.agents)
|
|
159
|
+
|
|
156
160
|
@property
|
|
157
161
|
def chats(self) -> List[Tuple[WaldiezChat, WaldiezAgent, WaldiezAgent]]:
|
|
158
162
|
"""Get the chats."""
|
|
@@ -224,8 +228,9 @@ class Waldiez:
|
|
|
224
228
|
@property
|
|
225
229
|
def requirements(self) -> List[str]:
|
|
226
230
|
"""Get the flow requirements."""
|
|
227
|
-
autogen_version =
|
|
231
|
+
autogen_version = get_autogen_version()
|
|
228
232
|
requirements_list = filter(
|
|
233
|
+
# we use the fixed "pyautogen=={autogen_version}" below
|
|
229
234
|
lambda requirement: not (
|
|
230
235
|
requirement.startswith("pyautogen")
|
|
231
236
|
or requirement.startswith("ag2")
|
|
@@ -234,30 +239,43 @@ class Waldiez:
|
|
|
234
239
|
self.flow.requirements,
|
|
235
240
|
)
|
|
236
241
|
requirements = set(requirements_list)
|
|
242
|
+
requirements.add(f"pyautogen=={autogen_version}")
|
|
237
243
|
if self.has_rag_agents:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
requirements.add(f"pyautogen=={autogen_version}")
|
|
244
|
+
rag_extras = get_retrievechat_extra_requirements(self.agents)
|
|
245
|
+
requirements.update(rag_extras)
|
|
241
246
|
if self.has_multimodal_agents:
|
|
242
247
|
requirements.add(f"pyautogen[lmm]=={autogen_version}")
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
248
|
+
if self.has_captain_agents:
|
|
249
|
+
# pysqlite3-binary might not get installed on windows
|
|
250
|
+
captain_extras = [
|
|
251
|
+
"chromadb",
|
|
252
|
+
"sentence-transformers",
|
|
253
|
+
"huggingface-hub",
|
|
254
|
+
# tools:
|
|
255
|
+
"pillow",
|
|
256
|
+
"markdownify",
|
|
257
|
+
"arxiv",
|
|
258
|
+
"pymupdf",
|
|
259
|
+
"wikipedia-api",
|
|
260
|
+
"easyocr",
|
|
261
|
+
"python-pptx",
|
|
262
|
+
"openai-whisper",
|
|
263
|
+
"pandas",
|
|
264
|
+
"scipy",
|
|
265
|
+
]
|
|
266
|
+
requirements.update(captain_extras)
|
|
267
|
+
requirements.update(
|
|
268
|
+
get_models_extra_requirements(
|
|
269
|
+
self.models,
|
|
270
|
+
autogen_version=autogen_version,
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
requirements.update(
|
|
274
|
+
get_skills_extra_requirements(
|
|
275
|
+
self.skills,
|
|
276
|
+
autogen_version=autogen_version,
|
|
277
|
+
)
|
|
278
|
+
)
|
|
261
279
|
return sorted(list(requirements))
|
|
262
280
|
|
|
263
281
|
def get_flow_env_vars(self) -> List[Tuple[str, str]]:
|
|
@@ -307,50 +325,3 @@ class Waldiez:
|
|
|
307
325
|
The swarm agents and the user agent.
|
|
308
326
|
"""
|
|
309
327
|
return self.flow.get_swarm_chat_members(initial_agent)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
def _get_flow(
|
|
313
|
-
data: Dict[str, Any],
|
|
314
|
-
flow_id: Optional[str] = None,
|
|
315
|
-
name: Optional[str] = None,
|
|
316
|
-
description: Optional[str] = None,
|
|
317
|
-
tags: Optional[List[str]] = None,
|
|
318
|
-
requirements: Optional[List[str]] = None,
|
|
319
|
-
) -> Dict[str, Any]:
|
|
320
|
-
"""Get the flow."""
|
|
321
|
-
item_type = data.get("type", "flow")
|
|
322
|
-
if item_type != "flow":
|
|
323
|
-
# empty flow (from exported model/skill ?)
|
|
324
|
-
raise ValueError(f"Invalid flow type: {item_type}")
|
|
325
|
-
from_args = {
|
|
326
|
-
"id": flow_id,
|
|
327
|
-
"name": name,
|
|
328
|
-
"description": description,
|
|
329
|
-
"tags": tags,
|
|
330
|
-
"requirements": requirements,
|
|
331
|
-
}
|
|
332
|
-
for key, value in from_args.items():
|
|
333
|
-
if value:
|
|
334
|
-
data[key] = value
|
|
335
|
-
if "name" not in data:
|
|
336
|
-
data["name"] = "Waldiez Flow"
|
|
337
|
-
if "description" not in data:
|
|
338
|
-
data["description"] = "Waldiez Flow description"
|
|
339
|
-
if "tags" not in data:
|
|
340
|
-
data["tags"] = []
|
|
341
|
-
if "requirements" not in data:
|
|
342
|
-
data["requirements"] = []
|
|
343
|
-
return data
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
@cache
|
|
347
|
-
def _get_autogen_version() -> str:
|
|
348
|
-
"""Get the autogen version."""
|
|
349
|
-
# pylint: disable=import-outside-toplevel
|
|
350
|
-
with warnings.catch_warnings():
|
|
351
|
-
warnings.simplefilter("ignore")
|
|
352
|
-
try:
|
|
353
|
-
from autogen.version import __version__ as ag2 # type: ignore
|
|
354
|
-
except ImportError as error: # pragma: no cover
|
|
355
|
-
raise ValueError("pyautogen is not installed.") from error
|
|
356
|
-
return ag2
|
waldiez/runner.py
CHANGED
|
@@ -14,7 +14,7 @@ import sys
|
|
|
14
14
|
import tempfile
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
from types import TracebackType
|
|
17
|
-
from typing import TYPE_CHECKING, Dict, List, Optional, Type, Union
|
|
17
|
+
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union
|
|
18
18
|
|
|
19
19
|
from .exporter import WaldiezExporter
|
|
20
20
|
from .models.waldiez import Waldiez
|
|
@@ -30,6 +30,7 @@ from .running import (
|
|
|
30
30
|
reset_env_vars,
|
|
31
31
|
set_env_vars,
|
|
32
32
|
)
|
|
33
|
+
from .utils import check_pysqlite3
|
|
33
34
|
|
|
34
35
|
if TYPE_CHECKING:
|
|
35
36
|
from autogen import ChatResult # type: ignore
|
|
@@ -135,13 +136,26 @@ class WaldiezRunner:
|
|
|
135
136
|
"""Get the running status."""
|
|
136
137
|
return self._running
|
|
137
138
|
|
|
139
|
+
def gather_requirements(self) -> Set[str]:
|
|
140
|
+
"""Gather extra requirements to install before running the flow.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
Set[str]
|
|
145
|
+
The extra requirements.
|
|
146
|
+
"""
|
|
147
|
+
extra_requirements = set(
|
|
148
|
+
req for req in self.waldiez.requirements if req not in sys.modules
|
|
149
|
+
)
|
|
150
|
+
if self.waldiez.has_captain_agents:
|
|
151
|
+
check_pysqlite3()
|
|
152
|
+
return extra_requirements
|
|
153
|
+
|
|
138
154
|
def install_requirements(self) -> None:
|
|
139
155
|
"""Install the requirements for the flow."""
|
|
140
156
|
self._called_install_requirements = True
|
|
141
157
|
printer = get_printer()
|
|
142
|
-
extra_requirements =
|
|
143
|
-
req for req in self.waldiez.requirements if req not in sys.modules
|
|
144
|
-
)
|
|
158
|
+
extra_requirements = self.gather_requirements()
|
|
145
159
|
if extra_requirements:
|
|
146
160
|
install_requirements(extra_requirements, printer)
|
|
147
161
|
refresh_environment()
|
|
@@ -150,9 +164,7 @@ class WaldiezRunner:
|
|
|
150
164
|
"""Install the requirements for the flow asynchronously."""
|
|
151
165
|
self._called_install_requirements = True
|
|
152
166
|
printer = get_printer()
|
|
153
|
-
extra_requirements =
|
|
154
|
-
req for req in self.waldiez.requirements if req not in sys.modules
|
|
155
|
-
)
|
|
167
|
+
extra_requirements = self.gather_requirements()
|
|
156
168
|
if extra_requirements:
|
|
157
169
|
await a_install_requirements(extra_requirements, printer)
|
|
158
170
|
refresh_environment()
|