waldiez 0.1.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/__init__.py +15 -0
- waldiez/__main__.py +6 -0
- waldiez/_version.py +3 -0
- waldiez/cli.py +162 -0
- waldiez/exporter.py +293 -0
- waldiez/exporting/__init__.py +14 -0
- waldiez/exporting/agents/__init__.py +5 -0
- waldiez/exporting/agents/agent.py +229 -0
- waldiez/exporting/agents/agent_skills.py +67 -0
- waldiez/exporting/agents/code_execution.py +67 -0
- waldiez/exporting/agents/group_manager.py +209 -0
- waldiez/exporting/agents/llm_config.py +53 -0
- waldiez/exporting/agents/rag_user/__init__.py +5 -0
- waldiez/exporting/agents/rag_user/chroma_utils.py +134 -0
- waldiez/exporting/agents/rag_user/mongo_utils.py +83 -0
- waldiez/exporting/agents/rag_user/pgvector_utils.py +93 -0
- waldiez/exporting/agents/rag_user/qdrant_utils.py +112 -0
- waldiez/exporting/agents/rag_user/rag_user.py +165 -0
- waldiez/exporting/agents/rag_user/vector_db.py +119 -0
- waldiez/exporting/agents/teachability.py +37 -0
- waldiez/exporting/agents/termination_message.py +45 -0
- waldiez/exporting/chats/__init__.py +14 -0
- waldiez/exporting/chats/chats.py +46 -0
- waldiez/exporting/chats/helpers.py +395 -0
- waldiez/exporting/chats/nested.py +264 -0
- waldiez/exporting/flow/__init__.py +5 -0
- waldiez/exporting/flow/def_main.py +37 -0
- waldiez/exporting/flow/flow.py +185 -0
- waldiez/exporting/models/__init__.py +193 -0
- waldiez/exporting/skills/__init__.py +128 -0
- waldiez/exporting/utils/__init__.py +34 -0
- waldiez/exporting/utils/comments.py +136 -0
- waldiez/exporting/utils/importing.py +267 -0
- waldiez/exporting/utils/logging_utils.py +203 -0
- waldiez/exporting/utils/method_utils.py +35 -0
- waldiez/exporting/utils/naming.py +127 -0
- waldiez/exporting/utils/object_string.py +81 -0
- waldiez/io_stream.py +181 -0
- waldiez/models/__init__.py +107 -0
- waldiez/models/agents/__init__.py +65 -0
- waldiez/models/agents/agent/__init__.py +21 -0
- waldiez/models/agents/agent/agent.py +190 -0
- waldiez/models/agents/agent/agent_data.py +162 -0
- waldiez/models/agents/agent/code_execution.py +71 -0
- waldiez/models/agents/agent/linked_skill.py +30 -0
- waldiez/models/agents/agent/nested_chat.py +73 -0
- waldiez/models/agents/agent/teachability.py +68 -0
- waldiez/models/agents/agent/termination_message.py +167 -0
- waldiez/models/agents/agents.py +129 -0
- waldiez/models/agents/assistant/__init__.py +6 -0
- waldiez/models/agents/assistant/assistant.py +41 -0
- waldiez/models/agents/assistant/assistant_data.py +29 -0
- waldiez/models/agents/group_manager/__init__.py +19 -0
- waldiez/models/agents/group_manager/group_manager.py +87 -0
- waldiez/models/agents/group_manager/group_manager_data.py +91 -0
- waldiez/models/agents/group_manager/speakers.py +211 -0
- waldiez/models/agents/rag_user/__init__.py +26 -0
- waldiez/models/agents/rag_user/rag_user.py +58 -0
- waldiez/models/agents/rag_user/rag_user_data.py +32 -0
- waldiez/models/agents/rag_user/retrieve_config.py +592 -0
- waldiez/models/agents/rag_user/vector_db_config.py +162 -0
- waldiez/models/agents/user_proxy/__init__.py +6 -0
- waldiez/models/agents/user_proxy/user_proxy.py +41 -0
- waldiez/models/agents/user_proxy/user_proxy_data.py +30 -0
- waldiez/models/chat/__init__.py +22 -0
- waldiez/models/chat/chat.py +129 -0
- waldiez/models/chat/chat_data.py +326 -0
- waldiez/models/chat/chat_message.py +304 -0
- waldiez/models/chat/chat_nested.py +160 -0
- waldiez/models/chat/chat_summary.py +110 -0
- waldiez/models/common/__init__.py +38 -0
- waldiez/models/common/base.py +63 -0
- waldiez/models/common/method_utils.py +165 -0
- waldiez/models/flow/__init__.py +9 -0
- waldiez/models/flow/flow.py +302 -0
- waldiez/models/flow/flow_data.py +87 -0
- waldiez/models/model/__init__.py +11 -0
- waldiez/models/model/model.py +169 -0
- waldiez/models/model/model_data.py +86 -0
- waldiez/models/skill/__init__.py +9 -0
- waldiez/models/skill/skill.py +129 -0
- waldiez/models/skill/skill_data.py +37 -0
- waldiez/models/waldiez.py +301 -0
- waldiez/py.typed +0 -0
- waldiez/runner.py +304 -0
- waldiez/stream/__init__.py +7 -0
- waldiez/stream/consumer.py +139 -0
- waldiez/stream/provider.py +339 -0
- waldiez/stream/server.py +412 -0
- waldiez-0.1.0.dist-info/METADATA +181 -0
- waldiez-0.1.0.dist-info/RECORD +94 -0
- waldiez-0.1.0.dist-info/WHEEL +4 -0
- waldiez-0.1.0.dist-info/entry_points.txt +2 -0
- waldiez-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Nested chat model."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import (
|
|
6
|
+
ConfigDict,
|
|
7
|
+
Field,
|
|
8
|
+
ValidationInfo,
|
|
9
|
+
field_validator,
|
|
10
|
+
model_validator,
|
|
11
|
+
)
|
|
12
|
+
from pydantic.alias_generators import to_camel
|
|
13
|
+
from typing_extensions import Annotated, Self
|
|
14
|
+
|
|
15
|
+
from ..common import WaldiezBase, WaldiezMethodName
|
|
16
|
+
from .chat_message import WaldiezChatMessage, validate_message_dict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class WaldiezChatNested(WaldiezBase):
|
|
20
|
+
"""Nested chat class.
|
|
21
|
+
|
|
22
|
+
Attributes
|
|
23
|
+
----------
|
|
24
|
+
message : WaldiezChatMessage
|
|
25
|
+
The message in a nested chat (sender -> recipient).
|
|
26
|
+
reply : WaldiezChatMessage
|
|
27
|
+
The reply in a nested chat (recipient -> sender).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
model_config = ConfigDict(
|
|
31
|
+
extra="forbid",
|
|
32
|
+
alias_generator=to_camel,
|
|
33
|
+
populate_by_name=True,
|
|
34
|
+
frozen=False,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
message: Annotated[
|
|
38
|
+
Optional[WaldiezChatMessage],
|
|
39
|
+
Field(
|
|
40
|
+
None,
|
|
41
|
+
title="Message",
|
|
42
|
+
description="The message in a nested chat (sender -> recipient).",
|
|
43
|
+
),
|
|
44
|
+
]
|
|
45
|
+
reply: Annotated[
|
|
46
|
+
Optional[WaldiezChatMessage],
|
|
47
|
+
Field(
|
|
48
|
+
None,
|
|
49
|
+
title="Reply",
|
|
50
|
+
description="The reply in a nested chat (recipient -> sender).",
|
|
51
|
+
),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
_message_content: Optional[str] = None
|
|
55
|
+
_reply_content: Optional[str] = None
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def message_content(self) -> Optional[str]:
|
|
59
|
+
"""Get the message content."""
|
|
60
|
+
return self._message_content
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def reply_content(self) -> Optional[str]:
|
|
64
|
+
"""Get the reply content."""
|
|
65
|
+
return self._reply_content
|
|
66
|
+
|
|
67
|
+
@field_validator("message", "reply", mode="before")
|
|
68
|
+
@classmethod
|
|
69
|
+
def validate_message(
|
|
70
|
+
cls, value: Any, info: ValidationInfo
|
|
71
|
+
) -> WaldiezChatMessage:
|
|
72
|
+
"""Validate the message.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
value : Any
|
|
77
|
+
The value.
|
|
78
|
+
info : ValidationInfo
|
|
79
|
+
The validation info.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
WaldiezChatMessage
|
|
84
|
+
The validated message.
|
|
85
|
+
|
|
86
|
+
Raises
|
|
87
|
+
------
|
|
88
|
+
ValueError
|
|
89
|
+
If the validation fails.
|
|
90
|
+
"""
|
|
91
|
+
function_name: WaldiezMethodName = (
|
|
92
|
+
"nested_chat_message"
|
|
93
|
+
if info.field_name == "message"
|
|
94
|
+
else "nested_chat_reply"
|
|
95
|
+
)
|
|
96
|
+
if not value:
|
|
97
|
+
return WaldiezChatMessage(
|
|
98
|
+
type="none", use_carryover=False, content=None, context={}
|
|
99
|
+
)
|
|
100
|
+
if isinstance(value, str):
|
|
101
|
+
return WaldiezChatMessage(
|
|
102
|
+
type="string", use_carryover=False, content=value, context={}
|
|
103
|
+
)
|
|
104
|
+
if isinstance(value, dict):
|
|
105
|
+
return validate_message_dict(value, function_name=function_name)
|
|
106
|
+
if isinstance(value, WaldiezChatMessage):
|
|
107
|
+
return validate_message_dict(
|
|
108
|
+
{
|
|
109
|
+
"type": value.type,
|
|
110
|
+
"use_carryover": False,
|
|
111
|
+
"content": value.content,
|
|
112
|
+
"context": value.context,
|
|
113
|
+
},
|
|
114
|
+
function_name=function_name,
|
|
115
|
+
)
|
|
116
|
+
raise ValueError(f"Invalid message type: {type(value)}")
|
|
117
|
+
|
|
118
|
+
@model_validator(mode="after")
|
|
119
|
+
def validate_nested_chat(self) -> Self:
|
|
120
|
+
"""Validate the nested chat.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
WaldiezChatNested
|
|
125
|
+
The validated nested chat.
|
|
126
|
+
|
|
127
|
+
Raises
|
|
128
|
+
------
|
|
129
|
+
ValueError
|
|
130
|
+
If the validation fails.
|
|
131
|
+
"""
|
|
132
|
+
if self.message is not None:
|
|
133
|
+
if self.message.type == "none":
|
|
134
|
+
self._message_content = ""
|
|
135
|
+
elif self.message.type == "string":
|
|
136
|
+
self._message_content = self.message.content
|
|
137
|
+
else:
|
|
138
|
+
self._message_content = validate_message_dict(
|
|
139
|
+
value={
|
|
140
|
+
"type": "method",
|
|
141
|
+
"content": self.message.content,
|
|
142
|
+
},
|
|
143
|
+
function_name="nested_chat_message",
|
|
144
|
+
skip_definition=True,
|
|
145
|
+
).content
|
|
146
|
+
if self.reply is not None:
|
|
147
|
+
if self.reply.type == "none":
|
|
148
|
+
self._reply_content = ""
|
|
149
|
+
elif self.reply.type == "string":
|
|
150
|
+
self._reply_content = self.reply.content
|
|
151
|
+
else:
|
|
152
|
+
self._reply_content = validate_message_dict(
|
|
153
|
+
value={
|
|
154
|
+
"type": "method",
|
|
155
|
+
"content": self.reply.content,
|
|
156
|
+
},
|
|
157
|
+
function_name="nested_chat_reply",
|
|
158
|
+
skip_definition=True,
|
|
159
|
+
).content
|
|
160
|
+
return self
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Waldiez chat summary options."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import (
|
|
6
|
+
Field,
|
|
7
|
+
FieldSerializationInfo,
|
|
8
|
+
field_serializer,
|
|
9
|
+
field_validator,
|
|
10
|
+
)
|
|
11
|
+
from typing_extensions import Annotated, Literal
|
|
12
|
+
|
|
13
|
+
from ..common import WaldiezBase
|
|
14
|
+
|
|
15
|
+
WaldiezChatSummaryMethod = Literal[
|
|
16
|
+
"reflectionWithLlm",
|
|
17
|
+
"lastMsg",
|
|
18
|
+
"reflection_with_llm",
|
|
19
|
+
"last_msg",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class WaldiezChatSummary(WaldiezBase):
|
|
24
|
+
"""Llm summary method options.
|
|
25
|
+
|
|
26
|
+
Attributes
|
|
27
|
+
----------
|
|
28
|
+
method : Optional[WaldiezChatSummaryMethod]
|
|
29
|
+
The method to use for the LLM summary. Defaults to "last_msg".
|
|
30
|
+
prompt : str
|
|
31
|
+
The prompt for the LLM summary method.
|
|
32
|
+
args : Optional[Dict[str, Any]]
|
|
33
|
+
The additional arguments for the LLM summary method, by default None.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
method: Annotated[
|
|
37
|
+
Optional[WaldiezChatSummaryMethod],
|
|
38
|
+
Field(
|
|
39
|
+
"last_msg",
|
|
40
|
+
title="Method",
|
|
41
|
+
description="The method to use for the LLM summary.",
|
|
42
|
+
),
|
|
43
|
+
]
|
|
44
|
+
prompt: Annotated[
|
|
45
|
+
str,
|
|
46
|
+
Field(
|
|
47
|
+
"",
|
|
48
|
+
title="Prompt",
|
|
49
|
+
description="The prompt for the LLM summary method.",
|
|
50
|
+
),
|
|
51
|
+
]
|
|
52
|
+
args: Annotated[
|
|
53
|
+
Dict[str, str],
|
|
54
|
+
Field(
|
|
55
|
+
title="Arguments",
|
|
56
|
+
description="The additional arguments for the LLM summary method.",
|
|
57
|
+
default_factory=dict,
|
|
58
|
+
),
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
@field_validator("method", mode="before")
|
|
62
|
+
@classmethod
|
|
63
|
+
def validate_summary_method(
|
|
64
|
+
cls, value: Optional[WaldiezChatSummaryMethod]
|
|
65
|
+
) -> Optional[WaldiezChatSummaryMethod]:
|
|
66
|
+
"""Validate the summary method.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
value : Optional[WaldiezChatSummaryMethod]
|
|
71
|
+
The passed WaldiezChatSummaryMethod
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
Optional[WaldiezChatSummaryMethod]
|
|
76
|
+
The validated message summary method
|
|
77
|
+
"""
|
|
78
|
+
if str(value).lower() == "none":
|
|
79
|
+
return None
|
|
80
|
+
if value == "lastMsg":
|
|
81
|
+
return "last_msg"
|
|
82
|
+
if value == "reflectionWithLlm":
|
|
83
|
+
return "reflection_with_llm"
|
|
84
|
+
return value
|
|
85
|
+
|
|
86
|
+
@field_serializer("method")
|
|
87
|
+
@classmethod
|
|
88
|
+
def serialize_summary_method(
|
|
89
|
+
cls, value: Any, info: FieldSerializationInfo
|
|
90
|
+
) -> Any:
|
|
91
|
+
"""Serialize summary method.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
value : Any
|
|
96
|
+
The value to serialize.
|
|
97
|
+
info : FieldSerializationInfo
|
|
98
|
+
The serialization info.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
Any
|
|
103
|
+
The serialized value.
|
|
104
|
+
"""
|
|
105
|
+
if info.by_alias is True:
|
|
106
|
+
if value == "reflection_with_llm":
|
|
107
|
+
return "reflectionWithLlm"
|
|
108
|
+
if value == "last_msg":
|
|
109
|
+
return "lastMsg"
|
|
110
|
+
return value
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Common utils for all models."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
|
|
5
|
+
from .base import WaldiezBase
|
|
6
|
+
from .method_utils import (
|
|
7
|
+
METHOD_ARGS,
|
|
8
|
+
METHOD_TYPE_HINTS,
|
|
9
|
+
WaldiezMethodName,
|
|
10
|
+
check_function,
|
|
11
|
+
parse_code_string,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def now() -> str:
|
|
16
|
+
"""Get the current date and time in UTC.
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
str
|
|
21
|
+
The current date and time in UTC.
|
|
22
|
+
"""
|
|
23
|
+
return (
|
|
24
|
+
datetime.now(tz=timezone.utc)
|
|
25
|
+
.isoformat(timespec="milliseconds")
|
|
26
|
+
.replace("+00:00", "Z")
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"WaldiezBase",
|
|
32
|
+
"METHOD_ARGS",
|
|
33
|
+
"METHOD_TYPE_HINTS",
|
|
34
|
+
"WaldiezMethodName",
|
|
35
|
+
"now",
|
|
36
|
+
"check_function",
|
|
37
|
+
"parse_code_string",
|
|
38
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Base class to inherit from."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict
|
|
6
|
+
from pydantic.alias_generators import to_camel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WaldiezBase(BaseModel):
|
|
10
|
+
"""Base model class to inherit from.
|
|
11
|
+
|
|
12
|
+
It contains the default configuration for all models.
|
|
13
|
+
It also `model_dumps` by alias by default.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
model_config = ConfigDict(
|
|
17
|
+
extra="forbid",
|
|
18
|
+
# treat `skillId` as `skill_id`
|
|
19
|
+
alias_generator=to_camel,
|
|
20
|
+
# allow passing either `skill_id` or `skillId`
|
|
21
|
+
populate_by_name=True,
|
|
22
|
+
frozen=True,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def model_dump(self, **kwargs: Any) -> Dict[str, Any]:
|
|
26
|
+
"""Dump the model to a dictionary.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
**kwargs : Any
|
|
31
|
+
Additional keyword arguments.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
Dict[str, Any]
|
|
36
|
+
The dictionary representation of the model.
|
|
37
|
+
"""
|
|
38
|
+
by_alias = kwargs.pop("by_alias", None)
|
|
39
|
+
if by_alias is None:
|
|
40
|
+
by_alias = True
|
|
41
|
+
if not isinstance(by_alias, bool):
|
|
42
|
+
by_alias = True
|
|
43
|
+
return super().model_dump(by_alias=by_alias, **kwargs)
|
|
44
|
+
|
|
45
|
+
def model_dump_json(self, **kwargs: Any) -> str:
|
|
46
|
+
"""Dump the model to a JSON string.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
**kwargs : Any
|
|
51
|
+
Additional keyword arguments.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
str
|
|
56
|
+
The JSON string.
|
|
57
|
+
"""
|
|
58
|
+
by_alias = kwargs.pop("by_alias", None)
|
|
59
|
+
if by_alias is None:
|
|
60
|
+
by_alias = True
|
|
61
|
+
if not isinstance(by_alias, bool):
|
|
62
|
+
by_alias = True
|
|
63
|
+
return super().model_dump_json(by_alias=by_alias, **kwargs)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Function related utilities."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from typing import Dict, List, Literal, Optional, Tuple
|
|
5
|
+
|
|
6
|
+
WaldiezMethodName = Literal[
|
|
7
|
+
"callable_message", # Chat
|
|
8
|
+
"is_termination_message", # Agent
|
|
9
|
+
"nested_chat_message", # Agents' NestedChat
|
|
10
|
+
"nested_chat_reply", # Agents' NestedChat
|
|
11
|
+
"custom_speaker_selection", # GroupChat
|
|
12
|
+
"custom_embedding_function", # RAG
|
|
13
|
+
"custom_token_count_function", # RAG
|
|
14
|
+
"custom_text_split_function", # RAG
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
METHOD_ARGS: Dict[WaldiezMethodName, List[str]] = {
|
|
18
|
+
"callable_message": ["sender", "recipient", "context"],
|
|
19
|
+
"is_termination_message": ["message"],
|
|
20
|
+
"nested_chat_message": ["recipient", "messages", "sender", "config"],
|
|
21
|
+
"nested_chat_reply": ["recipient", "messages", "sender", "config"],
|
|
22
|
+
"custom_speaker_selection": ["last_speaker", "groupchat"],
|
|
23
|
+
"custom_embedding_function": [],
|
|
24
|
+
"custom_token_count_function": ["text", "model"],
|
|
25
|
+
"custom_text_split_function": [
|
|
26
|
+
"text",
|
|
27
|
+
"max_tokens",
|
|
28
|
+
"chunk_mode",
|
|
29
|
+
"must_break_at_empty_line",
|
|
30
|
+
"overlap",
|
|
31
|
+
],
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# pylint: disable=line-too-long
|
|
35
|
+
METHOD_TYPE_HINTS: Dict[WaldiezMethodName, str] = {
|
|
36
|
+
"callable_message": "# type: (ConversableAgent, ConversableAgent, dict) -> Union[dict, str]",
|
|
37
|
+
"is_termination_message": "# type: (dict) -> bool",
|
|
38
|
+
"nested_chat_message": "# type: (ConversableAgent, list[dict], ConversableAgent, dict) -> Union[dict, str]",
|
|
39
|
+
"nested_chat_reply": "# type: (ConversableAgent, list[dict], ConversableAgent, dict) -> Union[dict, str]",
|
|
40
|
+
"custom_speaker_selection": "# type: (ConversableAgent, GroupChat) -> Union[Agent, str, None]",
|
|
41
|
+
"custom_embedding_function": "# type: () -> Callable[..., Any]",
|
|
42
|
+
"custom_token_count_function": "# type: (str, str) -> int",
|
|
43
|
+
"custom_text_split_function": "# type: (str, int, str, bool, int) -> List[str]",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def parse_code_string(
|
|
48
|
+
code_string: str,
|
|
49
|
+
) -> Tuple[Optional[str], Optional[ast.Module]]:
|
|
50
|
+
"""Parse the code string.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
code_string : str
|
|
55
|
+
The code string.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
Tuple[Optional[str], Optional[ast.Module]]
|
|
60
|
+
If valid, None and the ast module.
|
|
61
|
+
If invalid, the error message and None.
|
|
62
|
+
"""
|
|
63
|
+
# pylint: disable=broad-except
|
|
64
|
+
try:
|
|
65
|
+
tree = ast.parse(code_string)
|
|
66
|
+
except SyntaxError as e:
|
|
67
|
+
return f"SyntaxError: {e}, in \n{code_string}", None
|
|
68
|
+
except BaseException as e: # pragma: no cover
|
|
69
|
+
return f"Invalid code: {e}, in \n{code_string}", None
|
|
70
|
+
return None, tree
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def check_function(
|
|
74
|
+
code_string: str,
|
|
75
|
+
function_name: WaldiezMethodName,
|
|
76
|
+
skip_type_hints: bool = False,
|
|
77
|
+
) -> Tuple[bool, str]:
|
|
78
|
+
"""Check the function.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
code_string : str
|
|
83
|
+
The code string.
|
|
84
|
+
function_name : WaldiezMethodName
|
|
85
|
+
The expected function name.
|
|
86
|
+
skip_type_hints : bool, optional
|
|
87
|
+
Whether to skip type hints in the function body, by default False.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
Tuple[bool, str]
|
|
92
|
+
If valid, True and the function body (only), no extra lines.
|
|
93
|
+
If invalid, False and the error message.
|
|
94
|
+
"""
|
|
95
|
+
error, tree = parse_code_string(code_string)
|
|
96
|
+
if error is not None or tree is None:
|
|
97
|
+
return False, error or "Invalid code"
|
|
98
|
+
if function_name not in METHOD_ARGS:
|
|
99
|
+
return False, f"Invalid function name: {function_name}"
|
|
100
|
+
expected_method_args = METHOD_ARGS[function_name]
|
|
101
|
+
return _get_function_body(
|
|
102
|
+
tree,
|
|
103
|
+
code_string,
|
|
104
|
+
function_name,
|
|
105
|
+
expected_method_args,
|
|
106
|
+
skip_type_hints=skip_type_hints,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _get_function_body(
|
|
111
|
+
tree: ast.Module,
|
|
112
|
+
code_string: str,
|
|
113
|
+
function_name: WaldiezMethodName,
|
|
114
|
+
method_args: List[str],
|
|
115
|
+
skip_type_hints: bool = False,
|
|
116
|
+
) -> Tuple[bool, str]:
|
|
117
|
+
"""Get the function body.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
tree : ast.Module
|
|
122
|
+
The ast module.
|
|
123
|
+
code_string : str
|
|
124
|
+
The code string.
|
|
125
|
+
function_name : WaldiezMethodName
|
|
126
|
+
The expected function name.
|
|
127
|
+
method_args : List[str]
|
|
128
|
+
The expected method arguments.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
Tuple[bool, str]
|
|
133
|
+
If valid, True and the function body (only), no extra lines.
|
|
134
|
+
If invalid, False and the error message.
|
|
135
|
+
"""
|
|
136
|
+
for node in ast.walk(tree):
|
|
137
|
+
if isinstance(node, ast.FunctionDef):
|
|
138
|
+
if node.name != function_name:
|
|
139
|
+
continue
|
|
140
|
+
if len(node.args.args) != len(method_args):
|
|
141
|
+
return (
|
|
142
|
+
False,
|
|
143
|
+
f"Invalid number of arguments in function {node.name}",
|
|
144
|
+
)
|
|
145
|
+
for arg, expected_arg in zip(node.args.args, method_args):
|
|
146
|
+
if arg.arg != expected_arg:
|
|
147
|
+
return (
|
|
148
|
+
False,
|
|
149
|
+
f"Invalid argument name in function {node.name}",
|
|
150
|
+
)
|
|
151
|
+
function_body_lines = code_string.splitlines()[
|
|
152
|
+
node.lineno - 1 : node.end_lineno
|
|
153
|
+
]
|
|
154
|
+
function_body = "\n".join(function_body_lines[1:])
|
|
155
|
+
if not skip_type_hints:
|
|
156
|
+
# add type hints after the function definition
|
|
157
|
+
function_body = (
|
|
158
|
+
f" {METHOD_TYPE_HINTS[function_name]}\n{function_body}"
|
|
159
|
+
)
|
|
160
|
+
return True, function_body
|
|
161
|
+
error_msg = (
|
|
162
|
+
f"No function with name `{function_name}`"
|
|
163
|
+
f" and arguments `{method_args}` found"
|
|
164
|
+
)
|
|
165
|
+
return False, error_msg
|