camel-ai 0.2.71a9__py3-none-any.whl → 0.2.71a11__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 camel-ai might be problematic. Click here for more details.
- camel/__init__.py +1 -1
- camel/models/cohere_model.py +4 -1
- camel/models/moonshot_model.py +54 -1
- camel/societies/workforce/prompts.py +40 -16
- camel/societies/workforce/worker.py +1 -7
- camel/societies/workforce/workforce.py +2 -2
- camel/toolkits/function_tool.py +13 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +165 -218
- camel/toolkits/hybrid_browser_toolkit/unified_analyzer.js +3 -3
- camel/toolkits/search_toolkit.py +44 -14
- camel/toolkits/slack_toolkit.py +10 -0
- camel/types/enums.py +3 -0
- {camel_ai-0.2.71a9.dist-info → camel_ai-0.2.71a11.dist-info}/METADATA +3 -3
- {camel_ai-0.2.71a9.dist-info → camel_ai-0.2.71a11.dist-info}/RECORD +16 -16
- {camel_ai-0.2.71a9.dist-info → camel_ai-0.2.71a11.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.71a9.dist-info → camel_ai-0.2.71a11.dist-info}/licenses/LICENSE +0 -0
camel/__init__.py
CHANGED
camel/models/cohere_model.py
CHANGED
|
@@ -21,7 +21,10 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union
|
|
|
21
21
|
from pydantic import BaseModel
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
|
-
from cohere.types import
|
|
24
|
+
from cohere.types import ( # type: ignore[attr-defined]
|
|
25
|
+
ChatMessageV2,
|
|
26
|
+
ChatResponse,
|
|
27
|
+
)
|
|
25
28
|
|
|
26
29
|
from camel.configs import COHERE_API_PARAMS, CohereConfig
|
|
27
30
|
from camel.messages import OpenAIMessage
|
camel/models/moonshot_model.py
CHANGED
|
@@ -29,8 +29,23 @@ from camel.types import (
|
|
|
29
29
|
from camel.utils import (
|
|
30
30
|
BaseTokenCounter,
|
|
31
31
|
api_keys_required,
|
|
32
|
+
get_current_agent_session_id,
|
|
33
|
+
update_langfuse_trace,
|
|
32
34
|
)
|
|
33
35
|
|
|
36
|
+
if os.environ.get("LANGFUSE_ENABLED", "False").lower() == "true":
|
|
37
|
+
try:
|
|
38
|
+
from langfuse.decorators import observe
|
|
39
|
+
except ImportError:
|
|
40
|
+
from camel.utils import observe
|
|
41
|
+
elif os.environ.get("TRACEROOT_ENABLED", "False").lower() == "true":
|
|
42
|
+
try:
|
|
43
|
+
from traceroot import trace as observe # type: ignore[import]
|
|
44
|
+
except ImportError:
|
|
45
|
+
from camel.utils import observe
|
|
46
|
+
else:
|
|
47
|
+
from camel.utils import observe
|
|
48
|
+
|
|
34
49
|
|
|
35
50
|
class MoonshotModel(OpenAICompatibleModel):
|
|
36
51
|
r"""Moonshot API in a unified OpenAICompatibleModel interface.
|
|
@@ -91,13 +106,51 @@ class MoonshotModel(OpenAICompatibleModel):
|
|
|
91
106
|
**kwargs,
|
|
92
107
|
)
|
|
93
108
|
|
|
109
|
+
@observe()
|
|
94
110
|
async def _arun(
|
|
95
111
|
self,
|
|
96
112
|
messages: List[OpenAIMessage],
|
|
97
113
|
response_format: Optional[Type[BaseModel]] = None,
|
|
98
114
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
99
115
|
) -> Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
|
|
100
|
-
|
|
116
|
+
r"""Runs inference of Moonshot chat completion asynchronously.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
messages (List[OpenAIMessage]): Message list with the chat history
|
|
120
|
+
in OpenAI API format.
|
|
121
|
+
response_format (Optional[Type[BaseModel]]): The format of the
|
|
122
|
+
response.
|
|
123
|
+
tools (Optional[List[Dict[str, Any]]]): The schema of the tools to
|
|
124
|
+
use for the request.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
|
|
128
|
+
`ChatCompletion` in the non-stream mode, or
|
|
129
|
+
`AsyncStream[ChatCompletionChunk]` in the stream mode.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
# Update Langfuse trace with current agent session and metadata
|
|
133
|
+
agent_session_id = get_current_agent_session_id()
|
|
134
|
+
if agent_session_id:
|
|
135
|
+
update_langfuse_trace(
|
|
136
|
+
session_id=agent_session_id,
|
|
137
|
+
metadata={
|
|
138
|
+
"agent_id": agent_session_id,
|
|
139
|
+
"model_type": str(self.model_type),
|
|
140
|
+
},
|
|
141
|
+
tags=["CAMEL-AI", str(self.model_type)],
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
request_config = self.model_config_dict.copy()
|
|
145
|
+
|
|
146
|
+
if tools:
|
|
147
|
+
request_config["tools"] = tools
|
|
148
|
+
|
|
149
|
+
return await self._async_client.chat.completions.create(
|
|
150
|
+
messages=messages,
|
|
151
|
+
model=self.model_type,
|
|
152
|
+
**request_config,
|
|
153
|
+
)
|
|
101
154
|
|
|
102
155
|
def check_model_config(self):
|
|
103
156
|
r"""Check whether the model configuration contains any
|
|
@@ -196,7 +196,11 @@ Now you should summarize the scenario and return the result of the task.
|
|
|
196
196
|
"""
|
|
197
197
|
)
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
TASK_DECOMPOSE_PROMPT = r"""You need to decompose the given task into subtasks according to the workers available in the group, following these important principles to maximize efficiency, parallelism, and clarity for the executing agents:
|
|
200
|
+
|
|
201
|
+
1. **Self-Contained Subtasks**: This is critical principle. Each subtask's description **must be fully self-sufficient and independently understandable**. The agent executing the subtask has **no knowledge** of the parent task, other subtasks, or the overall workflow.
|
|
202
|
+
* **DO NOT** use relative references like "the first task," "the paper mentioned above," or "the result from the previous step."
|
|
203
|
+
* **DO** write explicit instructions. For example, instead of "Analyze the document," write "Analyze the document titled 'The Future of AI'." The system will automatically provide the necessary inputs (like the document itself) from previous steps.
|
|
200
204
|
|
|
201
205
|
1. **Strategic Grouping for Sequential Work**:
|
|
202
206
|
* If a series of steps must be done in order *and* can be handled by the same worker type, group them into a single subtask to maintain flow and minimize handoffs.
|
|
@@ -216,23 +220,42 @@ These principles aim to reduce overall completion time by maximizing concurrent
|
|
|
216
220
|
|
|
217
221
|
**EXAMPLE FORMAT ONLY** (DO NOT use this example content for actual task decomposition):
|
|
218
222
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
* Poor decomposition (monolithic):
|
|
222
|
-
`<tasks><task>Do all research, analysis, and write final report.</task></tasks>`
|
|
223
|
+
***
|
|
224
|
+
**Example 1: Sequential Task for a Single Worker**
|
|
223
225
|
|
|
224
|
-
*
|
|
226
|
+
* **Overall Task**: "Create a short blog post about the benefits of Python. First, research the key benefits. Then, write a 300-word article. Finally, find a suitable image to go with it."
|
|
227
|
+
* **Available Workers**:
|
|
228
|
+
* `Document Agent`: A worker that can research topics, write articles, and find images.
|
|
229
|
+
* **Correct Decomposition**:
|
|
230
|
+
```xml
|
|
231
|
+
<tasks>
|
|
232
|
+
<task>Create a short blog post about the benefits of Python by researching key benefits, writing a 300-word article, and finding a suitable image.</task>
|
|
233
|
+
</tasks>
|
|
225
234
|
```
|
|
235
|
+
* **Reasoning**: All steps are sequential and can be handled by the same worker type (`Document Agent`). Grouping them into one subtask is efficient and maintains the workflow, following the "Strategic Grouping" principle.
|
|
236
|
+
|
|
237
|
+
***
|
|
238
|
+
**Example 2: Parallel Task Across Different Workers**
|
|
239
|
+
|
|
240
|
+
* **Overall Task**: "Write a report on the Q2 performance of Apple (AAPL) and Google (GOOGL). The report needs a financial summary and a market sentiment analysis for each company."
|
|
241
|
+
* **Available Workers**:
|
|
242
|
+
* `financial_analyst_1`: A worker that can analyze financial data and create summaries.
|
|
243
|
+
* `market_researcher_1`: A worker that can perform market sentiment analysis.
|
|
244
|
+
* `report_writer_1`: A worker that compiles information into a final report.
|
|
245
|
+
* **Correct Decomposition**:
|
|
246
|
+
```xml
|
|
226
247
|
<tasks>
|
|
227
|
-
<task>
|
|
228
|
-
<task>
|
|
229
|
-
<task>
|
|
230
|
-
<task>
|
|
231
|
-
<task>
|
|
248
|
+
<task>Create a financial summary for Apple (AAPL) for Q2.</task>
|
|
249
|
+
<task>Create a financial summary for Google (GOOGL) for Q2.</task>
|
|
250
|
+
<task>Perform market sentiment analysis for Apple (AAPL) for Q2.</task>
|
|
251
|
+
<task>Perform market sentiment analysis for Google (GOOGL) for Q2.</task>
|
|
252
|
+
<task>Compile the provided financial summaries and market sentiment analyses for Apple (AAPL) and Google (GOOGL) into a single Q2 performance report.</task>
|
|
232
253
|
</tasks>
|
|
233
254
|
```
|
|
255
|
+
* **Reasoning**: The financial analysis and market research can be done in parallel for both companies. The final report depends on all previous steps. This decomposition leverages worker specialization and parallelism, following the "Aggressive Parallelization" principle.
|
|
256
|
+
***
|
|
234
257
|
|
|
235
|
-
**END OF
|
|
258
|
+
**END OF EXAMPLES** - Now, apply these principles and examples to decompose the following task.
|
|
236
259
|
|
|
237
260
|
The content of the task is:
|
|
238
261
|
|
|
@@ -261,10 +284,11 @@ You must return the subtasks as a list of individual subtasks within <tasks> tag
|
|
|
261
284
|
</tasks>
|
|
262
285
|
|
|
263
286
|
Each subtask should be:
|
|
264
|
-
-
|
|
265
|
-
-
|
|
266
|
-
-
|
|
267
|
-
-
|
|
287
|
+
- **Self-contained and independently understandable.**
|
|
288
|
+
- Clear and concise.
|
|
289
|
+
- Achievable by a single worker.
|
|
290
|
+
- Containing all sequential steps that should be performed by the same worker type.
|
|
291
|
+
- Written without any relative references (e.g., "the previous task").
|
|
268
292
|
"""
|
|
269
293
|
|
|
270
294
|
FAILURE_ANALYSIS_PROMPT = TextPrompt(
|
|
@@ -87,15 +87,9 @@ class Worker(BaseNode, ABC):
|
|
|
87
87
|
f"{Fore.YELLOW}{self} get task {task.id}: {task.content}"
|
|
88
88
|
f"{Fore.RESET}"
|
|
89
89
|
)
|
|
90
|
-
# Get the Task instance of dependencies
|
|
91
|
-
dependency_ids = await self._channel.get_dependency_ids()
|
|
92
|
-
task_dependencies = [
|
|
93
|
-
await self._channel.get_task_by_id(dep_id)
|
|
94
|
-
for dep_id in dependency_ids
|
|
95
|
-
]
|
|
96
90
|
|
|
97
91
|
# Process the task
|
|
98
|
-
task_state = await self._process_task(task,
|
|
92
|
+
task_state = await self._process_task(task, [])
|
|
99
93
|
|
|
100
94
|
# Update the result and status of the task
|
|
101
95
|
task.set_state(task_state)
|
|
@@ -44,7 +44,7 @@ from camel.societies.workforce.prompts import (
|
|
|
44
44
|
ASSIGN_TASK_PROMPT,
|
|
45
45
|
CREATE_NODE_PROMPT,
|
|
46
46
|
FAILURE_ANALYSIS_PROMPT,
|
|
47
|
-
|
|
47
|
+
TASK_DECOMPOSE_PROMPT,
|
|
48
48
|
)
|
|
49
49
|
from camel.societies.workforce.role_playing_worker import RolePlayingWorker
|
|
50
50
|
from camel.societies.workforce.single_agent_worker import SingleAgentWorker
|
|
@@ -730,7 +730,7 @@ class Workforce(BaseNode):
|
|
|
730
730
|
Union[List[Task], Generator[List[Task], None, None]]:
|
|
731
731
|
The subtasks or generator of subtasks.
|
|
732
732
|
"""
|
|
733
|
-
decompose_prompt =
|
|
733
|
+
decompose_prompt = TASK_DECOMPOSE_PROMPT.format(
|
|
734
734
|
content=task.content,
|
|
735
735
|
child_nodes_info=self._get_child_nodes_info(),
|
|
736
736
|
additional_info=task.additional_info,
|
camel/toolkits/function_tool.py
CHANGED
|
@@ -256,11 +256,24 @@ def sanitize_and_enforce_required(parameters_dict):
|
|
|
256
256
|
# This field is optional - add null to its type
|
|
257
257
|
current_type = field_schema.get('type')
|
|
258
258
|
has_ref = '$ref' in field_schema
|
|
259
|
+
has_any_of = 'anyOf' in field_schema
|
|
259
260
|
|
|
260
261
|
if has_ref:
|
|
261
262
|
# Fields with $ref shouldn't have additional type field
|
|
262
263
|
# The $ref itself defines the type structure
|
|
263
264
|
pass
|
|
265
|
+
elif has_any_of:
|
|
266
|
+
# Field already has anyOf
|
|
267
|
+
any_of_types = field_schema['anyOf']
|
|
268
|
+
has_null_type = any(
|
|
269
|
+
item.get('type') == 'null' for item in any_of_types
|
|
270
|
+
)
|
|
271
|
+
if not has_null_type:
|
|
272
|
+
# Add null type to anyOf
|
|
273
|
+
field_schema['anyOf'].append({'type': 'null'})
|
|
274
|
+
# Remove conflicting type field if it exists
|
|
275
|
+
if 'type' in field_schema:
|
|
276
|
+
del field_schema['type']
|
|
264
277
|
elif current_type:
|
|
265
278
|
if isinstance(current_type, str):
|
|
266
279
|
# Single type - convert to array with null
|
|
@@ -1094,25 +1094,19 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1094
1094
|
# Public API Methods
|
|
1095
1095
|
|
|
1096
1096
|
async def open_browser(self) -> Dict[str, Any]:
|
|
1097
|
-
r"""
|
|
1098
|
-
|
|
1097
|
+
r"""Starts a new browser session. This must be the first browser
|
|
1098
|
+
action.
|
|
1099
1099
|
|
|
1100
|
-
This method initializes the
|
|
1101
|
-
|
|
1102
|
-
during toolkit initialization in the first tab. Agents cannot specify
|
|
1103
|
-
a custom URL - they must use the visit_page tool to open new tabs
|
|
1104
|
-
with other URLs.
|
|
1100
|
+
This method initializes the browser and navigates to a default start
|
|
1101
|
+
page. To visit a specific URL, use `visit_page` after this.
|
|
1105
1102
|
|
|
1106
1103
|
Returns:
|
|
1107
|
-
Dict[str, Any]: A dictionary
|
|
1108
|
-
- "result":
|
|
1109
|
-
|
|
1110
|
-
- "
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
- "tabs": List of all open tabs with their information.
|
|
1114
|
-
- "current_tab": Index of the currently active tab.
|
|
1115
|
-
- "total_tabs": Total number of open tabs.
|
|
1104
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1105
|
+
- "result" (str): Confirmation of the action.
|
|
1106
|
+
- "snapshot" (str): A textual snapshot of interactive elements.
|
|
1107
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1108
|
+
- "current_tab" (int): Index of the active tab.
|
|
1109
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1116
1110
|
"""
|
|
1117
1111
|
# Add logging if enabled
|
|
1118
1112
|
action_start = time.time()
|
|
@@ -1163,14 +1157,12 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1163
1157
|
|
|
1164
1158
|
@action_logger
|
|
1165
1159
|
async def close_browser(self) -> str:
|
|
1166
|
-
r"""Closes the
|
|
1167
|
-
resources.
|
|
1160
|
+
r"""Closes the browser session, releasing all resources.
|
|
1168
1161
|
|
|
1169
|
-
This should be called at the end of a
|
|
1170
|
-
clean shutdown of the browser instance.
|
|
1162
|
+
This should be called at the end of a task for cleanup.
|
|
1171
1163
|
|
|
1172
1164
|
Returns:
|
|
1173
|
-
str: A confirmation message
|
|
1165
|
+
str: A confirmation message.
|
|
1174
1166
|
"""
|
|
1175
1167
|
if self._agent is not None:
|
|
1176
1168
|
try:
|
|
@@ -1184,17 +1176,19 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1184
1176
|
|
|
1185
1177
|
@action_logger
|
|
1186
1178
|
async def visit_page(self, url: str) -> Dict[str, Any]:
|
|
1187
|
-
r"""
|
|
1188
|
-
|
|
1189
|
-
This method creates a new tab for the URL instead of navigating
|
|
1190
|
-
in the current tab, allowing better multi-tab management.
|
|
1179
|
+
r"""Opens a URL in a new browser tab and switches to it.
|
|
1191
1180
|
|
|
1192
1181
|
Args:
|
|
1193
|
-
url (str): The web address to load
|
|
1182
|
+
url (str): The web address to load. This should be a valid and
|
|
1183
|
+
existing URL.
|
|
1194
1184
|
|
|
1195
1185
|
Returns:
|
|
1196
|
-
Dict[str, Any]: A dictionary
|
|
1197
|
-
|
|
1186
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1187
|
+
- "result" (str): Confirmation of the action.
|
|
1188
|
+
- "snapshot" (str): A textual snapshot of the new page.
|
|
1189
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1190
|
+
- "current_tab" (int): Index of the new active tab.
|
|
1191
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1198
1192
|
"""
|
|
1199
1193
|
if not url or not isinstance(url, str):
|
|
1200
1194
|
return {
|
|
@@ -1260,23 +1254,18 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1260
1254
|
|
|
1261
1255
|
@action_logger
|
|
1262
1256
|
async def back(self) -> Dict[str, Any]:
|
|
1263
|
-
r"""
|
|
1257
|
+
r"""Goes back to the previous page in the browser history.
|
|
1264
1258
|
|
|
1265
|
-
This
|
|
1266
|
-
|
|
1267
|
-
history.
|
|
1259
|
+
This action simulates using the browser's "back" button in the
|
|
1260
|
+
currently active tab.
|
|
1268
1261
|
|
|
1269
1262
|
Returns:
|
|
1270
|
-
Dict[str, Any]: A dictionary
|
|
1271
|
-
- "result":
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
- "
|
|
1275
|
-
|
|
1276
|
-
string "snapshot not changed".
|
|
1277
|
-
- "tabs": List of all open tabs with their information.
|
|
1278
|
-
- "current_tab": Index of the currently active tab.
|
|
1279
|
-
- "total_tabs": Total number of open tabs.
|
|
1263
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1264
|
+
- "result" (str): Confirmation of the action.
|
|
1265
|
+
- "snapshot" (str): A textual snapshot of the previous page.
|
|
1266
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1267
|
+
- "current_tab" (int): Index of the active tab.
|
|
1268
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1280
1269
|
"""
|
|
1281
1270
|
page = await self._require_page()
|
|
1282
1271
|
|
|
@@ -1329,23 +1318,18 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1329
1318
|
|
|
1330
1319
|
@action_logger
|
|
1331
1320
|
async def forward(self) -> Dict[str, Any]:
|
|
1332
|
-
r"""
|
|
1321
|
+
r"""Goes forward to the next page in the browser history.
|
|
1333
1322
|
|
|
1334
|
-
This
|
|
1335
|
-
|
|
1336
|
-
if you have previously navigated back).
|
|
1323
|
+
This action simulates using the browser's "forward" button in the
|
|
1324
|
+
currently active tab.
|
|
1337
1325
|
|
|
1338
1326
|
Returns:
|
|
1339
|
-
Dict[str, Any]: A dictionary
|
|
1340
|
-
- "result":
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
- "
|
|
1344
|
-
|
|
1345
|
-
string "snapshot not changed".
|
|
1346
|
-
- "tabs": List of all open tabs with their information.
|
|
1347
|
-
- "current_tab": Index of the currently active tab.
|
|
1348
|
-
- "total_tabs": Total number of open tabs.
|
|
1327
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1328
|
+
- "result" (str): Confirmation of the action.
|
|
1329
|
+
- "snapshot" (str): A textual snapshot of the next page.
|
|
1330
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1331
|
+
- "current_tab" (int): Index of the active tab.
|
|
1332
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1349
1333
|
"""
|
|
1350
1334
|
page = await self._require_page()
|
|
1351
1335
|
|
|
@@ -1399,20 +1383,16 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1399
1383
|
|
|
1400
1384
|
@action_logger
|
|
1401
1385
|
async def get_page_snapshot(self) -> str:
|
|
1402
|
-
r"""
|
|
1386
|
+
r"""Gets a textual snapshot of the page's interactive elements.
|
|
1403
1387
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
The snapshot is useful for understanding the page structure and
|
|
1410
|
-
identifying elements to interact with without needing to parse raw
|
|
1411
|
-
HTML. A new snapshot is generated on each call.
|
|
1388
|
+
The snapshot lists elements like buttons, links, and inputs, each with
|
|
1389
|
+
a unique `ref` ID. This ID is used by other tools (e.g., `click`,
|
|
1390
|
+
`type`) to interact with a specific element. This tool provides no
|
|
1391
|
+
visual information.
|
|
1412
1392
|
|
|
1413
1393
|
Returns:
|
|
1414
|
-
str: A formatted string representing the interactive elements
|
|
1415
|
-
|
|
1394
|
+
str: A formatted string representing the interactive elements and
|
|
1395
|
+
their `ref` IDs. For example:
|
|
1416
1396
|
'- link "Sign In" [ref=1]'
|
|
1417
1397
|
'- textbox "Username" [ref=2]'
|
|
1418
1398
|
"""
|
|
@@ -1435,32 +1415,25 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1435
1415
|
@dependencies_required('PIL')
|
|
1436
1416
|
@action_logger
|
|
1437
1417
|
async def get_som_screenshot(self):
|
|
1438
|
-
r"""Captures a screenshot
|
|
1439
|
-
interactive elements. "SoM" stands for "Set of Marks".
|
|
1440
|
-
|
|
1441
|
-
This method is essential for tasks requiring visual understanding of
|
|
1442
|
-
the page layout. It works by:
|
|
1443
|
-
1. Taking a full-page screenshot.
|
|
1444
|
-
2. Identifying all interactive elements (buttons, links, inputs, etc.).
|
|
1445
|
-
3. Drawing colored boxes and reference IDs (`ref`) over these elements
|
|
1446
|
-
on the screenshot.
|
|
1447
|
-
4. Saving the annotated image to a cache directory.
|
|
1448
|
-
5. Returning the image as a base64-encoded string along with a summary.
|
|
1418
|
+
r"""Captures a screenshot with interactive elements highlighted.
|
|
1449
1419
|
|
|
1450
|
-
|
|
1451
|
-
|
|
1420
|
+
"SoM" stands for "Set of Marks". This tool takes a screenshot and draws
|
|
1421
|
+
boxes around clickable elements, overlaying a `ref` ID on each. Use
|
|
1422
|
+
this for a visual understanding of the page, especially when the
|
|
1423
|
+
textual snapshot is not enough.
|
|
1452
1424
|
|
|
1453
1425
|
Returns:
|
|
1454
1426
|
ToolResult: An object containing:
|
|
1455
|
-
- `text
|
|
1427
|
+
- `text` (str): A summary, e.g., "Visual webpage screenshot
|
|
1456
1428
|
captured with 42 interactive elements".
|
|
1457
|
-
- `images
|
|
1458
|
-
|
|
1429
|
+
- `images` (List[str]): A list containing one base64-encoded
|
|
1430
|
+
PNG image data URL.
|
|
1459
1431
|
"""
|
|
1460
1432
|
from PIL import Image
|
|
1461
1433
|
|
|
1462
1434
|
from camel.utils.tool_result import ToolResult
|
|
1463
1435
|
|
|
1436
|
+
os.makedirs(self._cache_dir, exist_ok=True)
|
|
1464
1437
|
# Get screenshot and analysis
|
|
1465
1438
|
page = await self._require_page()
|
|
1466
1439
|
|
|
@@ -1516,37 +1489,33 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1516
1489
|
return ToolResult(text=text_result, images=[img_data_url])
|
|
1517
1490
|
|
|
1518
1491
|
async def click(self, *, ref: str) -> Dict[str, Any]:
|
|
1519
|
-
r"""
|
|
1492
|
+
r"""Performs a click on an element on the page.
|
|
1520
1493
|
|
|
1521
1494
|
Args:
|
|
1522
|
-
ref (str): The
|
|
1523
|
-
obtained from
|
|
1495
|
+
ref (str): The `ref` ID of the element to click. This ID is
|
|
1496
|
+
obtained from a page snapshot (`get_page_snapshot` or
|
|
1524
1497
|
`get_som_screenshot`).
|
|
1525
1498
|
|
|
1526
1499
|
Returns:
|
|
1527
|
-
Dict[str, Any]: A dictionary
|
|
1528
|
-
- "result":
|
|
1529
|
-
- "snapshot": A
|
|
1530
|
-
click
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
- "
|
|
1534
|
-
- "current_tab": Index of the currently active tab.
|
|
1535
|
-
- "total_tabs": Total number of open tabs.
|
|
1500
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1501
|
+
- "result" (str): Confirmation of the action.
|
|
1502
|
+
- "snapshot" (str): A textual snapshot of the page after the
|
|
1503
|
+
click.
|
|
1504
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1505
|
+
- "current_tab" (int): Index of the active tab.
|
|
1506
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1536
1507
|
"""
|
|
1537
1508
|
self._validate_ref(ref, "click")
|
|
1538
1509
|
|
|
1539
1510
|
analysis = await self._get_unified_analysis()
|
|
1540
1511
|
elements = analysis.get("elements", {})
|
|
1541
1512
|
if ref not in elements:
|
|
1542
|
-
available_refs = list(elements.keys())
|
|
1543
1513
|
logger.error(f"Error: Element reference '{ref}' not found. ")
|
|
1544
1514
|
# Added snapshot to give more context on failure
|
|
1545
1515
|
snapshot = self._format_snapshot_from_analysis(analysis)
|
|
1546
1516
|
tab_info = await self._get_tab_info_for_output()
|
|
1547
1517
|
return {
|
|
1548
|
-
"result": f"Error: Element reference '{ref}' not found. "
|
|
1549
|
-
f"Available refs: {available_refs}",
|
|
1518
|
+
"result": f"Error: Element reference '{ref}' not found. ",
|
|
1550
1519
|
"snapshot": snapshot,
|
|
1551
1520
|
**tab_info,
|
|
1552
1521
|
}
|
|
@@ -1564,20 +1533,20 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1564
1533
|
return result
|
|
1565
1534
|
|
|
1566
1535
|
async def type(self, *, ref: str, text: str) -> Dict[str, Any]:
|
|
1567
|
-
r"""Types text into an input
|
|
1536
|
+
r"""Types text into an input element on the page.
|
|
1568
1537
|
|
|
1569
1538
|
Args:
|
|
1570
|
-
ref (str): The
|
|
1571
|
-
text (str): The text to
|
|
1539
|
+
ref (str): The `ref` ID of the input element, from a snapshot.
|
|
1540
|
+
text (str): The text to type into the element.
|
|
1572
1541
|
|
|
1573
1542
|
Returns:
|
|
1574
|
-
Dict[str, Any]: A dictionary
|
|
1575
|
-
- "result":
|
|
1576
|
-
- "snapshot": A
|
|
1577
|
-
|
|
1578
|
-
- "tabs"
|
|
1579
|
-
- "current_tab": Index of the
|
|
1580
|
-
- "total_tabs": Total number of open tabs.
|
|
1543
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1544
|
+
- "result" (str): Confirmation of the action.
|
|
1545
|
+
- "snapshot" (str): A textual snapshot of the page after
|
|
1546
|
+
typing.
|
|
1547
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1548
|
+
- "current_tab" (int): Index of the active tab.
|
|
1549
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1581
1550
|
"""
|
|
1582
1551
|
self._validate_ref(ref, "type")
|
|
1583
1552
|
await self._get_unified_analysis() # Ensure aria-ref attributes
|
|
@@ -1592,21 +1561,21 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1592
1561
|
return result
|
|
1593
1562
|
|
|
1594
1563
|
async def select(self, *, ref: str, value: str) -> Dict[str, Any]:
|
|
1595
|
-
r"""Selects an option
|
|
1564
|
+
r"""Selects an option in a dropdown (`<select>`) element.
|
|
1596
1565
|
|
|
1597
1566
|
Args:
|
|
1598
|
-
ref (str): The
|
|
1599
|
-
value (str): The value of the `<option>` to
|
|
1600
|
-
|
|
1601
|
-
visible text.
|
|
1567
|
+
ref (str): The `ref` ID of the `<select>` element.
|
|
1568
|
+
value (str): The `value` attribute of the `<option>` to select,
|
|
1569
|
+
not its visible text.
|
|
1602
1570
|
|
|
1603
1571
|
Returns:
|
|
1604
|
-
Dict[str, Any]: A dictionary
|
|
1605
|
-
- "result":
|
|
1606
|
-
- "snapshot": A
|
|
1607
|
-
|
|
1608
|
-
- "
|
|
1609
|
-
- "
|
|
1572
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1573
|
+
- "result" (str): Confirmation of the action.
|
|
1574
|
+
- "snapshot" (str): A snapshot of the page after the
|
|
1575
|
+
selection.
|
|
1576
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1577
|
+
- "current_tab" (int): Index of the active tab.
|
|
1578
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1610
1579
|
"""
|
|
1611
1580
|
self._validate_ref(ref, "select")
|
|
1612
1581
|
await self._get_unified_analysis()
|
|
@@ -1621,20 +1590,19 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1621
1590
|
return result
|
|
1622
1591
|
|
|
1623
1592
|
async def scroll(self, *, direction: str, amount: int) -> Dict[str, Any]:
|
|
1624
|
-
r"""Scrolls the page window
|
|
1593
|
+
r"""Scrolls the current page window.
|
|
1625
1594
|
|
|
1626
1595
|
Args:
|
|
1627
|
-
direction (str): The direction to scroll
|
|
1628
|
-
'down'.
|
|
1596
|
+
direction (str): The direction to scroll: 'up' or 'down'.
|
|
1629
1597
|
amount (int): The number of pixels to scroll.
|
|
1630
1598
|
|
|
1631
1599
|
Returns:
|
|
1632
|
-
Dict[str, Any]: A dictionary
|
|
1633
|
-
- "result":
|
|
1634
|
-
- "snapshot": A
|
|
1635
|
-
- "tabs"
|
|
1636
|
-
- "current_tab": Index of the
|
|
1637
|
-
- "total_tabs": Total number of open tabs.
|
|
1600
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1601
|
+
- "result" (str): Confirmation of the action.
|
|
1602
|
+
- "snapshot" (str): A snapshot of the page after scrolling.
|
|
1603
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1604
|
+
- "current_tab" (int): Index of the active tab.
|
|
1605
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1638
1606
|
"""
|
|
1639
1607
|
if direction not in ("up", "down"):
|
|
1640
1608
|
tab_info = await self._get_tab_info_for_output()
|
|
@@ -1656,25 +1624,17 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1656
1624
|
async def enter(self) -> Dict[str, Any]:
|
|
1657
1625
|
r"""Simulates pressing the Enter key on the currently focused element.
|
|
1658
1626
|
|
|
1659
|
-
This
|
|
1660
|
-
|
|
1661
|
-
an element, such as:
|
|
1662
|
-
- Submitting a search query after typing in a search box.
|
|
1663
|
-
- Confirming a form submission.
|
|
1664
|
-
- Executing a command in a text input field.
|
|
1665
|
-
|
|
1666
|
-
The common usage pattern is to first use the 'type' tool to input
|
|
1667
|
-
text, which sets the focus, and then call 'enter' without any
|
|
1668
|
-
parameters to trigger the action.
|
|
1627
|
+
This is useful for submitting forms or search queries after using the
|
|
1628
|
+
`type` tool.
|
|
1669
1629
|
|
|
1670
1630
|
Returns:
|
|
1671
|
-
Dict[str, Any]: A dictionary
|
|
1672
|
-
- "result":
|
|
1673
|
-
- "snapshot": A new page snapshot, as this action often
|
|
1674
|
-
triggers navigation
|
|
1675
|
-
- "tabs"
|
|
1676
|
-
- "current_tab": Index of the
|
|
1677
|
-
- "total_tabs": Total number of open tabs.
|
|
1631
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1632
|
+
- "result" (str): Confirmation of the action.
|
|
1633
|
+
- "snapshot" (str): A new page snapshot, as this action often
|
|
1634
|
+
triggers navigation.
|
|
1635
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1636
|
+
- "current_tab" (int): Index of the active tab.
|
|
1637
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1678
1638
|
"""
|
|
1679
1639
|
# Always press Enter on the currently focused element
|
|
1680
1640
|
action = {"type": "enter"}
|
|
@@ -1691,25 +1651,22 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1691
1651
|
async def wait_user(
|
|
1692
1652
|
self, timeout_sec: Optional[float] = None
|
|
1693
1653
|
) -> Dict[str, Any]:
|
|
1694
|
-
r"""Pauses
|
|
1654
|
+
r"""Pauses execution and waits for human input from the console.
|
|
1695
1655
|
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
until the user presses the Enter key.
|
|
1656
|
+
Use this for tasks requiring manual steps, like solving a CAPTCHA. The
|
|
1657
|
+
agent will resume after the user presses Enter in the console.
|
|
1699
1658
|
|
|
1700
1659
|
Args:
|
|
1701
|
-
timeout_sec (Optional[float]):
|
|
1702
|
-
|
|
1703
|
-
automatically. If `None`, it will wait indefinitely.
|
|
1660
|
+
timeout_sec (Optional[float]): Max time to wait in seconds. If
|
|
1661
|
+
`None`, it will wait indefinitely.
|
|
1704
1662
|
|
|
1705
1663
|
Returns:
|
|
1706
|
-
Dict[str, Any]: A dictionary
|
|
1707
|
-
- "result": A message indicating how the wait ended
|
|
1708
|
-
|
|
1709
|
-
- "
|
|
1710
|
-
- "
|
|
1711
|
-
- "
|
|
1712
|
-
- "total_tabs": Total number of open tabs.
|
|
1664
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1665
|
+
- "result" (str): A message indicating how the wait ended.
|
|
1666
|
+
- "snapshot" (str): The page snapshot after the wait.
|
|
1667
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1668
|
+
- "current_tab" (int): Index of the active tab.
|
|
1669
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1713
1670
|
"""
|
|
1714
1671
|
import asyncio
|
|
1715
1672
|
|
|
@@ -1756,20 +1713,18 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1756
1713
|
|
|
1757
1714
|
@action_logger
|
|
1758
1715
|
async def get_page_links(self, *, ref: List[str]) -> Dict[str, Any]:
|
|
1759
|
-
r"""
|
|
1716
|
+
r"""Gets the destination URLs for a list of link elements.
|
|
1760
1717
|
|
|
1761
|
-
This is useful
|
|
1762
|
-
clicking it.
|
|
1718
|
+
This is useful to know where a link goes before clicking it.
|
|
1763
1719
|
|
|
1764
1720
|
Args:
|
|
1765
|
-
ref (List[str]): A list of
|
|
1766
|
-
|
|
1721
|
+
ref (List[str]): A list of `ref` IDs for link elements, obtained
|
|
1722
|
+
from a page snapshot.
|
|
1767
1723
|
|
|
1768
1724
|
Returns:
|
|
1769
1725
|
Dict[str, Any]: A dictionary containing:
|
|
1770
|
-
- "links": A list of
|
|
1771
|
-
|
|
1772
|
-
keys.
|
|
1726
|
+
- "links" (List[Dict]): A list of found links, where each
|
|
1727
|
+
link has "text", "ref", and "url" keys.
|
|
1773
1728
|
"""
|
|
1774
1729
|
if not ref or not isinstance(ref, list):
|
|
1775
1730
|
return {"links": []}
|
|
@@ -1790,26 +1745,25 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1790
1745
|
async def solve_task(
|
|
1791
1746
|
self, task_prompt: str, start_url: str, max_steps: int = 15
|
|
1792
1747
|
) -> str:
|
|
1793
|
-
r"""
|
|
1748
|
+
r"""Delegates a complex, high-level task to a specialized web agent.
|
|
1794
1749
|
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1750
|
+
Use this for multi-step tasks that can be described in a single prompt
|
|
1751
|
+
(e.g., "log into my account and check for new messages"). The agent
|
|
1752
|
+
will autonomously perform the necessary browser actions.
|
|
1798
1753
|
|
|
1799
|
-
|
|
1800
|
-
|
|
1754
|
+
NOTE: This is a high-level action; for simple interactions, use tools
|
|
1755
|
+
like `click` and `type`. `web_agent_model` must be provided during
|
|
1756
|
+
toolkit initialization.
|
|
1801
1757
|
|
|
1802
1758
|
Args:
|
|
1803
|
-
task_prompt (str): A natural language description of the task
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1759
|
+
task_prompt (str): A natural language description of the task.
|
|
1760
|
+
start_url (str): The URL to start the task from. This should be a
|
|
1761
|
+
valid and existing URL, as agents may generate non-existent
|
|
1762
|
+
ones.
|
|
1763
|
+
max_steps (int): The maximum number of steps the agent can take.
|
|
1808
1764
|
|
|
1809
1765
|
Returns:
|
|
1810
|
-
str: A summary message indicating
|
|
1811
|
-
finished. The detailed trace of the agent's actions will be
|
|
1812
|
-
printed to the standard output.
|
|
1766
|
+
str: A summary message indicating the task has finished.
|
|
1813
1767
|
"""
|
|
1814
1768
|
agent = self._ensure_agent()
|
|
1815
1769
|
await agent.navigate(start_url)
|
|
@@ -1944,25 +1898,21 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1944
1898
|
|
|
1945
1899
|
@action_logger
|
|
1946
1900
|
async def switch_tab(self, *, tab_index: int) -> Dict[str, Any]:
|
|
1947
|
-
r"""Switches to a
|
|
1901
|
+
r"""Switches to a different browser tab using its index.
|
|
1948
1902
|
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
selected tab.
|
|
1903
|
+
After switching, all actions will apply to the new tab. Use
|
|
1904
|
+
`get_tab_info` to find the index of the tab you want to switch to.
|
|
1952
1905
|
|
|
1953
1906
|
Args:
|
|
1954
|
-
tab_index (int): The zero-based index of the tab to
|
|
1955
|
-
Use `get_tab_info` to see available tabs and their indices.
|
|
1907
|
+
tab_index (int): The zero-based index of the tab to activate.
|
|
1956
1908
|
|
|
1957
1909
|
Returns:
|
|
1958
|
-
Dict[str, Any]: A dictionary
|
|
1959
|
-
- "result":
|
|
1960
|
-
|
|
1961
|
-
- "
|
|
1962
|
-
|
|
1963
|
-
- "
|
|
1964
|
-
- "current_tab": Index of the currently active tab.
|
|
1965
|
-
- "total_tabs": Total number of open tabs.
|
|
1910
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1911
|
+
- "result" (str): Confirmation of the action.
|
|
1912
|
+
- "snapshot" (str): A snapshot of the newly active tab.
|
|
1913
|
+
- "tabs" (List[Dict]): Information about all open tabs.
|
|
1914
|
+
- "current_tab" (int): Index of the new active tab.
|
|
1915
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
1966
1916
|
"""
|
|
1967
1917
|
await self._ensure_browser()
|
|
1968
1918
|
session = await self._get_session()
|
|
@@ -1993,24 +1943,21 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
1993
1943
|
|
|
1994
1944
|
@action_logger
|
|
1995
1945
|
async def close_tab(self, *, tab_index: int) -> Dict[str, Any]:
|
|
1996
|
-
r"""Closes a
|
|
1946
|
+
r"""Closes a browser tab using its index.
|
|
1997
1947
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
session will remain active but without any pages.
|
|
1948
|
+
Use `get_tab_info` to find the index of the tab to close. After
|
|
1949
|
+
closing, the browser will switch to another tab if available.
|
|
2001
1950
|
|
|
2002
1951
|
Args:
|
|
2003
1952
|
tab_index (int): The zero-based index of the tab to close.
|
|
2004
1953
|
|
|
2005
1954
|
Returns:
|
|
2006
|
-
Dict[str, Any]: A dictionary
|
|
2007
|
-
- "result":
|
|
2008
|
-
|
|
2009
|
-
- "
|
|
2010
|
-
|
|
2011
|
-
- "
|
|
2012
|
-
- "current_tab": Index of the currently active tab.
|
|
2013
|
-
- "total_tabs": Total number of remaining open tabs.
|
|
1955
|
+
Dict[str, Any]: A dictionary with the result of the action:
|
|
1956
|
+
- "result" (str): Confirmation of the action.
|
|
1957
|
+
- "snapshot" (str): A snapshot of the active tab after closure.
|
|
1958
|
+
- "tabs" (List[Dict]): Information about remaining tabs.
|
|
1959
|
+
- "current_tab" (int): Index of the new active tab.
|
|
1960
|
+
- "total_tabs" (int): Total number of remaining tabs.
|
|
2014
1961
|
"""
|
|
2015
1962
|
await self._ensure_browser()
|
|
2016
1963
|
session = await self._get_session()
|
|
@@ -2046,20 +1993,20 @@ class HybridBrowserToolkit(BaseToolkit):
|
|
|
2046
1993
|
|
|
2047
1994
|
@action_logger
|
|
2048
1995
|
async def get_tab_info(self) -> Dict[str, Any]:
|
|
2049
|
-
r"""
|
|
1996
|
+
r"""Gets a list of all open browser tabs and their information.
|
|
2050
1997
|
|
|
2051
|
-
This
|
|
2052
|
-
|
|
1998
|
+
This includes each tab's index, title, and URL, and indicates which
|
|
1999
|
+
tab is currently active. Use this to manage multiple tabs.
|
|
2053
2000
|
|
|
2054
2001
|
Returns:
|
|
2055
|
-
Dict[str, Any]: A dictionary
|
|
2056
|
-
- "tabs": A list of
|
|
2057
|
-
- "index": The zero-based index
|
|
2058
|
-
- "title": The page title
|
|
2059
|
-
- "url": The current URL
|
|
2060
|
-
- "is_current":
|
|
2061
|
-
- "current_tab": Index of the
|
|
2062
|
-
- "total_tabs": Total number of open tabs
|
|
2002
|
+
Dict[str, Any]: A dictionary with tab information:
|
|
2003
|
+
- "tabs" (List[Dict]): A list of open tabs, each with:
|
|
2004
|
+
- "index" (int): The tab's zero-based index.
|
|
2005
|
+
- "title" (str): The page title.
|
|
2006
|
+
- "url" (str): The current URL.
|
|
2007
|
+
- "is_current" (bool): True if the tab is active.
|
|
2008
|
+
- "current_tab" (int): Index of the active tab.
|
|
2009
|
+
- "total_tabs" (int): Total number of open tabs.
|
|
2063
2010
|
"""
|
|
2064
2011
|
await self._ensure_browser()
|
|
2065
2012
|
return await self._get_tab_info_for_output()
|
|
@@ -735,11 +735,11 @@
|
|
|
735
735
|
function renderTree(node, indent = '') {
|
|
736
736
|
const lines = [];
|
|
737
737
|
let meaningfulProps = '';
|
|
738
|
-
if (node.disabled) meaningfulProps += ' disabled';
|
|
739
|
-
if (node.occluded) meaningfulProps += ' occluded';
|
|
738
|
+
if (node.disabled) meaningfulProps += ' [disabled]';
|
|
739
|
+
if (node.occluded) meaningfulProps += ' [occluded]';
|
|
740
740
|
if (node.checked !== undefined) meaningfulProps += ` checked=${node.checked}`;
|
|
741
741
|
if (node.expanded !== undefined) meaningfulProps += ` expanded=${node.expanded}`;
|
|
742
|
-
if (node.selected) meaningfulProps += ' selected';
|
|
742
|
+
if (node.selected) meaningfulProps += ' [selected]';
|
|
743
743
|
|
|
744
744
|
// Add level attribute following Playwright's format
|
|
745
745
|
if (node.level !== undefined) meaningfulProps += ` [level=${node.level}]`;
|
camel/toolkits/search_toolkit.py
CHANGED
|
@@ -89,8 +89,8 @@ class SearchToolkit(BaseToolkit):
|
|
|
89
89
|
depth (Literal["standard", "deep"]): The depth of the search.
|
|
90
90
|
"standard" for a straightforward search, "deep" for a more
|
|
91
91
|
comprehensive search.
|
|
92
|
-
output_type (Literal["searchResults", "sourcedAnswer",
|
|
93
|
-
|
|
92
|
+
output_type (Literal["searchResults", "sourcedAnswer", "structured"]):
|
|
93
|
+
The type of output:
|
|
94
94
|
- "searchResults" for raw search results,
|
|
95
95
|
- "sourcedAnswer" for an answer with supporting sources,
|
|
96
96
|
- "structured" for output based on a provided schema.
|
|
@@ -265,13 +265,18 @@ class SearchToolkit(BaseToolkit):
|
|
|
265
265
|
The country string is limited to 2 character country codes of
|
|
266
266
|
supported countries. For a list of supported values, see
|
|
267
267
|
Country Codes. (default: :obj:`US `)
|
|
268
|
-
search_lang (str): The search language preference.
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
search_lang (str): The search language preference.
|
|
269
|
+
Use ONLY these exact values, NOT standard ISO codes:
|
|
270
|
+
'ar', 'eu', 'bn', 'bg', 'ca', 'zh-hans', 'zh-hant', 'hr',
|
|
271
|
+
'cs', 'da', 'nl', 'en', 'en-gb', 'et', 'fi', 'fr', 'gl', 'de',
|
|
272
|
+
'gu', 'he', 'hi', 'hu', 'is', 'it', 'jp', 'kn', 'ko', 'lv',
|
|
273
|
+
'lt', 'ms', 'ml', 'mr', 'nb', 'pl', 'pt-br', 'pt-pt', 'pa',
|
|
274
|
+
'ro', 'ru', 'sr', 'sk', 'sl', 'es', 'sv', 'ta', 'te', 'th',
|
|
275
|
+
'tr', 'uk', 'vi'.
|
|
271
276
|
ui_lang (str): User interface language preferred in response.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
277
|
+
Format: '<language_code>-<country_code>'. Common examples:
|
|
278
|
+
'en-US', 'en-GB', 'jp-JP', 'zh-hans-CN', 'zh-hant-TW',
|
|
279
|
+
'de-DE', 'fr-FR', 'es-ES', 'pt-BR', 'ru-RU', 'ko-KR'.
|
|
275
280
|
count (int): The number of search results returned in response.
|
|
276
281
|
The maximum is 20. The actual number delivered may be less than
|
|
277
282
|
requested. Combine this parameter with offset to paginate
|
|
@@ -375,10 +380,36 @@ class SearchToolkit(BaseToolkit):
|
|
|
375
380
|
"extra_snippets": extra_snippets,
|
|
376
381
|
"summary": summary,
|
|
377
382
|
}
|
|
383
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
378
384
|
|
|
379
385
|
response = requests.get(url, headers=headers, params=params)
|
|
380
|
-
|
|
381
|
-
|
|
386
|
+
try:
|
|
387
|
+
response.raise_for_status()
|
|
388
|
+
except requests.HTTPError as e:
|
|
389
|
+
raise RuntimeError(
|
|
390
|
+
f"Brave API HTTP error: {e}, body={response.text!r}"
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
json_data = response.json()
|
|
394
|
+
# Check if response has search results
|
|
395
|
+
content_keys = [
|
|
396
|
+
'web',
|
|
397
|
+
'news',
|
|
398
|
+
'videos',
|
|
399
|
+
'images',
|
|
400
|
+
'locations',
|
|
401
|
+
'discussions',
|
|
402
|
+
'faq',
|
|
403
|
+
'infobox',
|
|
404
|
+
]
|
|
405
|
+
has_results = any(key in json_data for key in content_keys)
|
|
406
|
+
|
|
407
|
+
if not has_results:
|
|
408
|
+
# Return empty results structure if no content found
|
|
409
|
+
json_data['web'] = {'results': []}
|
|
410
|
+
json_data['message'] = 'No search results found for the query'
|
|
411
|
+
|
|
412
|
+
return json_data
|
|
382
413
|
|
|
383
414
|
@api_keys_required(
|
|
384
415
|
[
|
|
@@ -941,11 +972,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
941
972
|
|
|
942
973
|
Args:
|
|
943
974
|
query (str): The search query string (length >= 1 and <= 100).
|
|
944
|
-
time_range (Literal["OneDay", "OneWeek", "OneMonth", "OneYear",
|
|
945
|
-
|
|
975
|
+
time_range (Literal["OneDay", "OneWeek", "OneMonth", "OneYear", "NoLimit"]):
|
|
976
|
+
Time frame filter for search results.
|
|
946
977
|
(default: :obj:`"NoLimit"`)
|
|
947
|
-
industry (Optional[Literal["finance", "law", "medical",
|
|
948
|
-
"internet", "tax", "news_province", "news_center"]]):
|
|
978
|
+
industry (Optional[Literal["finance", "law", "medical", "internet", "tax", "news_province", "news_center"]]):
|
|
949
979
|
Industry-specific search filter. When specified, only returns
|
|
950
980
|
results from sites in the specified industries. Multiple
|
|
951
981
|
industries can be comma-separated.
|
camel/toolkits/slack_toolkit.py
CHANGED
|
@@ -239,6 +239,7 @@ class SlackToolkit(BaseToolkit):
|
|
|
239
239
|
self,
|
|
240
240
|
message: str,
|
|
241
241
|
channel_id: str,
|
|
242
|
+
file_path: Optional[str] = None,
|
|
242
243
|
user: Optional[str] = None,
|
|
243
244
|
) -> str:
|
|
244
245
|
r"""Send a message to a Slack channel.
|
|
@@ -246,6 +247,8 @@ class SlackToolkit(BaseToolkit):
|
|
|
246
247
|
Args:
|
|
247
248
|
message (str): The message to send.
|
|
248
249
|
channel_id (str): The ID of the Slack channel to send message.
|
|
250
|
+
file_path (Optional[str]): The path of the file to send.
|
|
251
|
+
Defaults to `None`.
|
|
249
252
|
user (Optional[str]): The user ID of the recipient.
|
|
250
253
|
Defaults to `None`.
|
|
251
254
|
|
|
@@ -257,6 +260,13 @@ class SlackToolkit(BaseToolkit):
|
|
|
257
260
|
|
|
258
261
|
try:
|
|
259
262
|
slack_client = self._login_slack()
|
|
263
|
+
if file_path:
|
|
264
|
+
response = slack_client.files_upload_v2(
|
|
265
|
+
channel=channel_id,
|
|
266
|
+
file=file_path,
|
|
267
|
+
initial_comment=message,
|
|
268
|
+
)
|
|
269
|
+
return f"File sent successfully, got response: {response}"
|
|
260
270
|
if user:
|
|
261
271
|
response = slack_client.chat_postEphemeral(
|
|
262
272
|
channel=channel_id, text=message, user=user
|
camel/types/enums.py
CHANGED
|
@@ -270,6 +270,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
270
270
|
MOONSHOT_V1_8K = "moonshot-v1-8k"
|
|
271
271
|
MOONSHOT_V1_32K = "moonshot-v1-32k"
|
|
272
272
|
MOONSHOT_V1_128K = "moonshot-v1-128k"
|
|
273
|
+
MOONSHOT_KIMI_K2 = "kimi-k2-0711-preview"
|
|
273
274
|
|
|
274
275
|
# SiliconFlow models support tool calling
|
|
275
276
|
SILICONFLOW_DEEPSEEK_V2_5 = "deepseek-ai/DeepSeek-V2.5"
|
|
@@ -833,6 +834,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
833
834
|
ModelType.MOONSHOT_V1_8K,
|
|
834
835
|
ModelType.MOONSHOT_V1_32K,
|
|
835
836
|
ModelType.MOONSHOT_V1_128K,
|
|
837
|
+
ModelType.MOONSHOT_KIMI_K2,
|
|
836
838
|
}
|
|
837
839
|
|
|
838
840
|
@property
|
|
@@ -1205,6 +1207,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
1205
1207
|
ModelType.MISTRAL_MEDIUM_3,
|
|
1206
1208
|
ModelType.ERNIE_4_5_TURBO_128K,
|
|
1207
1209
|
ModelType.DEEPSEEK_V3,
|
|
1210
|
+
ModelType.MOONSHOT_KIMI_K2,
|
|
1208
1211
|
}:
|
|
1209
1212
|
return 128_000
|
|
1210
1213
|
elif self in {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camel-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.71a11
|
|
4
4
|
Summary: Communicative Agents for AI Society Study
|
|
5
5
|
Project-URL: Homepage, https://www.camel-ai.org/
|
|
6
6
|
Project-URL: Repository, https://github.com/camel-ai/camel
|
|
@@ -127,7 +127,7 @@ Requires-Dist: sympy<2,>=1.13.3; extra == 'all'
|
|
|
127
127
|
Requires-Dist: tabulate>=0.9.0; extra == 'all'
|
|
128
128
|
Requires-Dist: tavily-python<0.6,>=0.5.0; extra == 'all'
|
|
129
129
|
Requires-Dist: textblob<0.18,>=0.17.1; extra == 'all'
|
|
130
|
-
Requires-Dist: traceroot==0.0.
|
|
130
|
+
Requires-Dist: traceroot==0.0.3; extra == 'all'
|
|
131
131
|
Requires-Dist: transformers<5,>=4; extra == 'all'
|
|
132
132
|
Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'all'
|
|
133
133
|
Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'all'
|
|
@@ -191,7 +191,7 @@ Requires-Dist: ipykernel<7,>=6.0.0; extra == 'dev-tools'
|
|
|
191
191
|
Requires-Dist: jupyter-client<9,>=8.6.2; extra == 'dev-tools'
|
|
192
192
|
Requires-Dist: langfuse>=2.60.5; extra == 'dev-tools'
|
|
193
193
|
Requires-Dist: mcp>=1.3.0; extra == 'dev-tools'
|
|
194
|
-
Requires-Dist: traceroot==0.0.
|
|
194
|
+
Requires-Dist: traceroot==0.0.3; extra == 'dev-tools'
|
|
195
195
|
Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'dev-tools'
|
|
196
196
|
Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'dev-tools'
|
|
197
197
|
Requires-Dist: typer>=0.15.2; extra == 'dev-tools'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
camel/__init__.py,sha256=
|
|
1
|
+
camel/__init__.py,sha256=0_Amq6sz_Pgv__ZMtKiptsrQ5gIku0jlCc0G6Bc1qac,902
|
|
2
2
|
camel/generators.py,sha256=JRqj9_m1PF4qT6UtybzTQ-KBT9MJQt18OAAYvQ_fr2o,13844
|
|
3
3
|
camel/human.py,sha256=Xg8x1cS5KK4bQ1SDByiHZnzsRpvRP-KZViNvmu38xo4,5475
|
|
4
4
|
camel/logger.py,sha256=WgEwael_eT6D-lVAKHpKIpwXSTjvLbny5jbV1Ab8lnA,5760
|
|
@@ -180,7 +180,7 @@ camel/models/aws_bedrock_model.py,sha256=bcQBiHVdVuJXyPEkSdymQlGx2zHIVj5d4ouFuF8
|
|
|
180
180
|
camel/models/azure_openai_model.py,sha256=-hnzGlV8NJAzR9wVfhe-YDazbGU43ECtw6_uFICKnPU,18393
|
|
181
181
|
camel/models/base_audio_model.py,sha256=_VUWh1L3rh8mldNvM5R6jBOKtvmTeBKJyRxAdPJmPlY,3324
|
|
182
182
|
camel/models/base_model.py,sha256=NouoYjMPo2K6KmKCIeU7smyEFnDkqnLL71Dh9SyJoa4,19486
|
|
183
|
-
camel/models/cohere_model.py,sha256=
|
|
183
|
+
camel/models/cohere_model.py,sha256=6KvYnYxoBZ8kLMmRp5wcJisY65KhCTl6kiG1W3xOkJQ,17292
|
|
184
184
|
camel/models/crynux_model.py,sha256=leEiFz1RcRtVJLJvYt_Ydyg5jkSk3VEJphgmHFz67bw,4118
|
|
185
185
|
camel/models/deepseek_model.py,sha256=MXOdmpFQFbxpgh5DiTETzx3qDFUkKiFjnEjTMDeWk2k,11015
|
|
186
186
|
camel/models/fish_audio_model.py,sha256=RCwORRIdCbjZXWWjjctpksPI2DnS0b68JjxunHBQ1xk,5981
|
|
@@ -193,7 +193,7 @@ camel/models/mistral_model.py,sha256=ipOVPk2boGqyGAypgKeQ9syaP0znKFQQSOqeVtockjk
|
|
|
193
193
|
camel/models/model_factory.py,sha256=8b-LEXovPnpmD3GFKOdbtcgjCwpa91IPCJxikPxhdMs,12114
|
|
194
194
|
camel/models/model_manager.py,sha256=ln3bCV_QWM3V5BrwKwjmxIeRN8ojIvPEBMMHun0MliU,9942
|
|
195
195
|
camel/models/modelscope_model.py,sha256=meO7KCAwZtHpUVgwtuKe0j4jYh0IWsxa8e3mwyhGLvg,10804
|
|
196
|
-
camel/models/moonshot_model.py,sha256=
|
|
196
|
+
camel/models/moonshot_model.py,sha256=BNkKcEPMieMZwClRT4w-D4crZ5Ovs8tLdK5Kxm41hWg,6465
|
|
197
197
|
camel/models/nemotron_model.py,sha256=PzRuQoAEmBRZ2wcotQ8-MRz5wYachKa_CUNenMQg-3U,3091
|
|
198
198
|
camel/models/netmind_model.py,sha256=YKHfntqsKqBxfh6qryn4L7CzHOIAYtyPXwJNK6NxNi4,4276
|
|
199
199
|
camel/models/novita_model.py,sha256=V-g0Wrf1Zh1il6oPKh1LVy_U0nveOwJq9YBVzGp4GOI,4238
|
|
@@ -273,14 +273,14 @@ camel/societies/babyagi_playing.py,sha256=KbTdpHfZ2V8AripVck0bNTOyF-RSaMPCRARz3D
|
|
|
273
273
|
camel/societies/role_playing.py,sha256=0XScr3WfxX1QOC71RhBLmrcS5y2c7DMQB_mAFOHU34M,31421
|
|
274
274
|
camel/societies/workforce/__init__.py,sha256=bkTI-PE-MSK9AQ2V2gR6cR2WY-R7Jqy_NmXRtAoqo8o,920
|
|
275
275
|
camel/societies/workforce/base.py,sha256=z2DmbTP5LL5-aCAAqglznQqCLfPmnyM5zD3w6jjtsb8,2175
|
|
276
|
-
camel/societies/workforce/prompts.py,sha256=
|
|
276
|
+
camel/societies/workforce/prompts.py,sha256=AxsznORYV6E31Hcf6CcDbuV4iuUY7EFsu9MTV42P144,16517
|
|
277
277
|
camel/societies/workforce/role_playing_worker.py,sha256=z5-OcNiaNEaoC206_3HD7xeonuUkD-XTxYbD3AqoNC8,10319
|
|
278
278
|
camel/societies/workforce/single_agent_worker.py,sha256=fXgAEkDMhvTd-nbwy5Gw3BOaRAiPsL8mf3AW1aaNqKU,19342
|
|
279
279
|
camel/societies/workforce/structured_output_handler.py,sha256=xr8szFN86hg3jQ825aEkJTjkSFQnTlbinVg4j1vZJVI,17870
|
|
280
280
|
camel/societies/workforce/task_channel.py,sha256=GWHaGQBpjTzdKbWoBYAQzzAiLKRKRXa6beqtc4cg-Is,7611
|
|
281
281
|
camel/societies/workforce/utils.py,sha256=THgNHSeZsNVnjTzQTur3qCJhi72MrDS8X2gPET174cI,8434
|
|
282
|
-
camel/societies/workforce/worker.py,sha256=
|
|
283
|
-
camel/societies/workforce/workforce.py,sha256=
|
|
282
|
+
camel/societies/workforce/worker.py,sha256=wImTK95gXBfnfzEaInUKJyyRSPlHJUyV9dONjofbVu8,6233
|
|
283
|
+
camel/societies/workforce/workforce.py,sha256=yiKEULgeNl5Red3LGhDZzY63tFZpcEkCKFivVKTfIKg,138300
|
|
284
284
|
camel/societies/workforce/workforce_logger.py,sha256=0YT__ys48Bgn0IICKIZBmSWhON-eA1KShebjCdn5ppE,24525
|
|
285
285
|
camel/storages/__init__.py,sha256=RwpEyvxpMbJzVDZJJygeBg4AzyYMkTjjkfB53hTuqGo,2141
|
|
286
286
|
camel/storages/graph_storages/__init__.py,sha256=G29BNn651C0WTOpjCl4QnVM-4B9tcNh8DdmsCiONH8Y,948
|
|
@@ -333,7 +333,7 @@ camel/toolkits/data_commons_toolkit.py,sha256=aHZUSL1ACpnYGaf1rE2csVKTmXTmN8lMGR
|
|
|
333
333
|
camel/toolkits/edgeone_pages_mcp_toolkit.py,sha256=1TFpAGHUNLggFQeN1OEw7P5laijwnlrCkfxBtgxFuUY,2331
|
|
334
334
|
camel/toolkits/excel_toolkit.py,sha256=9Uk5GLWl719c4W-NcGPJTNMtodAbEE5gUgLsFkIInbk,32564
|
|
335
335
|
camel/toolkits/file_write_toolkit.py,sha256=d8N8FfmK1fS13sY58PPhJh6M0vq6yh-s1-ltCZQJObg,37044
|
|
336
|
-
camel/toolkits/function_tool.py,sha256=
|
|
336
|
+
camel/toolkits/function_tool.py,sha256=3_hE-Khqf556CeebchsPpjIDCynC6vKmUJLdh1EO_js,34295
|
|
337
337
|
camel/toolkits/github_toolkit.py,sha256=iUyRrjWGAW_iljZVfNyfkm1Vi55wJxK6PsDAQs9pOag,13099
|
|
338
338
|
camel/toolkits/google_calendar_toolkit.py,sha256=E-sdgdbtNBs_CXbhht9t1dsVr4DsTr5NguHkx4fvSmc,15410
|
|
339
339
|
camel/toolkits/google_drive_mcp_toolkit.py,sha256=NubrRdPV8_t8bM4vP-7eKSVMuVwSEBXLfubWR_Hba7k,2583
|
|
@@ -366,10 +366,10 @@ camel/toolkits/pulse_mcp_search_toolkit.py,sha256=uLUpm19uC_4xLJow0gGVS9f-5T5EW2
|
|
|
366
366
|
camel/toolkits/pyautogui_toolkit.py,sha256=Q810fm8cFvElRory7B74aqS2YV6BOpdRE6jkewoM8xc,16093
|
|
367
367
|
camel/toolkits/reddit_toolkit.py,sha256=x0XAT1zQJVNHUr1R1HwWCgIlkamU-kPmbfb_H1WIv-w,8036
|
|
368
368
|
camel/toolkits/retrieval_toolkit.py,sha256=BKjEyOqW3cGEPTS5yHPYb-Qg795iNNPIs1wjowfuq3U,3825
|
|
369
|
-
camel/toolkits/search_toolkit.py,sha256=
|
|
369
|
+
camel/toolkits/search_toolkit.py,sha256=qt-g6c563p2pw0I8arXY3K45nvzu8QSKOBRMghdltuI,45161
|
|
370
370
|
camel/toolkits/searxng_toolkit.py,sha256=a2GtE4FGSrmaIVvX6Yide-abBYD1wsHqitnDlx9fdVg,7664
|
|
371
371
|
camel/toolkits/semantic_scholar_toolkit.py,sha256=Rh7eA_YPxV5pvPIzhjjvpr3vtlaCniJicrqzkPWW9_I,11634
|
|
372
|
-
camel/toolkits/slack_toolkit.py,sha256=
|
|
372
|
+
camel/toolkits/slack_toolkit.py,sha256=ZT6Ndlce2qjGsyZaNMfQ54nSEi7DOC9Ro7YqtK-u5O4,11651
|
|
373
373
|
camel/toolkits/stripe_toolkit.py,sha256=07swo5znGTnorafC1uYLKB4NRcJIOPOx19J7tkpLYWk,10102
|
|
374
374
|
camel/toolkits/sympy_toolkit.py,sha256=BAQnI8EFJydNUpKQWXBdleQ1Cm-srDBhFlqp9V9pbPQ,33757
|
|
375
375
|
camel/toolkits/task_planning_toolkit.py,sha256=Ttw9fHae4omGC1SA-6uaeXVHJ1YkwiVloz_hO-fm1gw,4855
|
|
@@ -387,10 +387,10 @@ camel/toolkits/hybrid_browser_toolkit/actions.py,sha256=x6X-kEdQx3K1ID-BBwdQEciX
|
|
|
387
387
|
camel/toolkits/hybrid_browser_toolkit/agent.py,sha256=0ifwhYUDJ5GLxfdpC5KquPaW1a0QBAutp2Y9y0YFujw,11685
|
|
388
388
|
camel/toolkits/hybrid_browser_toolkit/browser_session.py,sha256=LdXjF4eBFuqoRnbPU0ErBtR5wtbcv3cv-hBXtiDkgMg,27102
|
|
389
389
|
camel/toolkits/hybrid_browser_toolkit/config_loader.py,sha256=0zpDq3aFKEva2jc38kgLHnyxypIDk9SOcMjoP26tozo,15414
|
|
390
|
-
camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py,sha256=
|
|
390
|
+
camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py,sha256=5rrwj7H3qKoSUaDBPozWxcGqbdCInUrhhDTPZ6O7ZBU,77550
|
|
391
391
|
camel/toolkits/hybrid_browser_toolkit/snapshot.py,sha256=3vQaFK5C1P8WnkK2eDMaFOizrZf4uUAW0LxdeoF4F2w,8539
|
|
392
392
|
camel/toolkits/hybrid_browser_toolkit/stealth_script.js,sha256=z4XRSVUpAS87Sj36s3bY8XXhvRcHBlgsUOyMxV2HI80,27650
|
|
393
|
-
camel/toolkits/hybrid_browser_toolkit/unified_analyzer.js,sha256=
|
|
393
|
+
camel/toolkits/hybrid_browser_toolkit/unified_analyzer.js,sha256=VnzIn0KcEtxuncJi-OPZzdWbLSeSHCH-7sviFAGNM8g,40823
|
|
394
394
|
camel/toolkits/open_api_specs/security_config.py,sha256=ZVnBa_zEifaE_ao2xsvV5majuJHpn2Tn7feMDOnj-eo,898
|
|
395
395
|
camel/toolkits/open_api_specs/biztoc/__init__.py,sha256=OKCZrQCDwaWtXIN_2rA9FSqEvgpQRieRoHh7Ek6N16A,702
|
|
396
396
|
camel/toolkits/open_api_specs/biztoc/ai-plugin.json,sha256=IJinQbLv5MFPGFwdN7PbOhwArFVExSEZdJspe-mOBIo,866
|
|
@@ -417,7 +417,7 @@ camel/toolkits/open_api_specs/web_scraper/openapi.yaml,sha256=u_WalQ01e8W1D27VnZ
|
|
|
417
417
|
camel/toolkits/open_api_specs/web_scraper/paths/__init__.py,sha256=OKCZrQCDwaWtXIN_2rA9FSqEvgpQRieRoHh7Ek6N16A,702
|
|
418
418
|
camel/toolkits/open_api_specs/web_scraper/paths/scraper.py,sha256=aWy1_ppV4NVVEZfnbN3tu9XA9yAPAC9bRStJ5JuXMRU,1117
|
|
419
419
|
camel/types/__init__.py,sha256=pFTg3CWGSCfwFdoxPDTf4dKV8DdJS1x-bBPuEOmtdf0,2549
|
|
420
|
-
camel/types/enums.py,sha256=
|
|
420
|
+
camel/types/enums.py,sha256=qEPE2r4Np7JgJqSsZmM0SNQ8_hy19aeCn5da3pK93so,62948
|
|
421
421
|
camel/types/mcp_registries.py,sha256=dl4LgYtSaUhsqAKpz28k_SA9La11qxqBvDLaEuyzrFE,4971
|
|
422
422
|
camel/types/openai_types.py,sha256=8ZFzLe-zGmKNPfuVZFzxlxAX98lGf18gtrPhOgMmzus,2104
|
|
423
423
|
camel/types/unified_model_type.py,sha256=ZweHiS4MQ1QbDEX3a3oUc-pvgueYP27Zt0SlAPcYg_4,5623
|
|
@@ -446,7 +446,7 @@ camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo
|
|
|
446
446
|
camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
|
|
447
447
|
camel/verifiers/physics_verifier.py,sha256=c1grrRddcrVN7szkxhv2QirwY9viIRSITWeWFF5HmLs,30187
|
|
448
448
|
camel/verifiers/python_verifier.py,sha256=ogTz77wODfEcDN4tMVtiSkRQyoiZbHPY2fKybn59lHw,20558
|
|
449
|
-
camel_ai-0.2.
|
|
450
|
-
camel_ai-0.2.
|
|
451
|
-
camel_ai-0.2.
|
|
452
|
-
camel_ai-0.2.
|
|
449
|
+
camel_ai-0.2.71a11.dist-info/METADATA,sha256=n_79KNQG4fYZKxJoJxX6E9J1CyXY3pny6PpBLnOZ9lk,49999
|
|
450
|
+
camel_ai-0.2.71a11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
451
|
+
camel_ai-0.2.71a11.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
|
|
452
|
+
camel_ai-0.2.71a11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|