camel-ai 0.2.13__py3-none-any.whl → 0.2.15__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/agents/chat_agent.py +362 -237
- camel/benchmarks/__init__.py +11 -1
- camel/benchmarks/apibank.py +560 -0
- camel/benchmarks/apibench.py +496 -0
- camel/benchmarks/gaia.py +2 -2
- camel/benchmarks/nexus.py +518 -0
- camel/datagen/__init__.py +21 -0
- camel/datagen/cotdatagen.py +448 -0
- camel/datagen/self_instruct/__init__.py +36 -0
- camel/datagen/self_instruct/filter/__init__.py +34 -0
- camel/datagen/self_instruct/filter/filter_function.py +208 -0
- camel/datagen/self_instruct/filter/filter_registry.py +56 -0
- camel/datagen/self_instruct/filter/instruction_filter.py +76 -0
- camel/datagen/self_instruct/self_instruct.py +393 -0
- camel/datagen/self_instruct/templates.py +384 -0
- camel/datahubs/huggingface.py +12 -2
- camel/datahubs/models.py +4 -2
- camel/embeddings/mistral_embedding.py +5 -1
- camel/embeddings/openai_compatible_embedding.py +6 -1
- camel/embeddings/openai_embedding.py +5 -1
- camel/interpreters/e2b_interpreter.py +5 -1
- camel/loaders/apify_reader.py +5 -1
- camel/loaders/chunkr_reader.py +5 -1
- camel/loaders/firecrawl_reader.py +0 -30
- camel/logger.py +11 -5
- camel/messages/conversion/sharegpt/hermes/hermes_function_formatter.py +4 -1
- camel/models/anthropic_model.py +5 -1
- camel/models/azure_openai_model.py +1 -2
- camel/models/cohere_model.py +5 -1
- camel/models/deepseek_model.py +5 -1
- camel/models/gemini_model.py +5 -1
- camel/models/groq_model.py +5 -1
- camel/models/mistral_model.py +5 -1
- camel/models/nemotron_model.py +5 -1
- camel/models/nvidia_model.py +5 -1
- camel/models/openai_model.py +28 -12
- camel/models/qwen_model.py +5 -1
- camel/models/reka_model.py +5 -1
- camel/models/reward/nemotron_model.py +5 -1
- camel/models/samba_model.py +5 -1
- camel/models/togetherai_model.py +5 -1
- camel/models/yi_model.py +5 -1
- camel/models/zhipuai_model.py +5 -1
- camel/retrievers/auto_retriever.py +8 -0
- camel/retrievers/vector_retriever.py +6 -3
- camel/schemas/__init__.py +2 -1
- camel/schemas/base.py +2 -4
- camel/schemas/openai_converter.py +5 -1
- camel/schemas/outlines_converter.py +249 -0
- camel/societies/role_playing.py +4 -4
- camel/societies/workforce/workforce.py +2 -2
- camel/storages/graph_storages/nebula_graph.py +119 -27
- camel/storages/graph_storages/neo4j_graph.py +138 -0
- camel/toolkits/__init__.py +2 -0
- camel/toolkits/arxiv_toolkit.py +20 -3
- camel/toolkits/function_tool.py +61 -61
- camel/toolkits/meshy_toolkit.py +5 -1
- camel/toolkits/notion_toolkit.py +1 -1
- camel/toolkits/openbb_toolkit.py +869 -0
- camel/toolkits/search_toolkit.py +91 -5
- camel/toolkits/stripe_toolkit.py +5 -1
- camel/toolkits/twitter_toolkit.py +24 -16
- camel/types/enums.py +10 -1
- camel/types/unified_model_type.py +5 -0
- camel/utils/__init__.py +4 -0
- camel/utils/commons.py +146 -42
- camel/utils/token_counting.py +1 -0
- {camel_ai-0.2.13.dist-info → camel_ai-0.2.15.dist-info}/METADATA +18 -7
- {camel_ai-0.2.13.dist-info → camel_ai-0.2.15.dist-info}/RECORD +72 -58
- {camel_ai-0.2.13.dist-info → camel_ai-0.2.15.dist-info}/LICENSE +0 -0
- {camel_ai-0.2.13.dist-info → camel_ai-0.2.15.dist-info}/WHEEL +0 -0
camel/toolkits/search_toolkit.py
CHANGED
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import os
|
|
15
15
|
import xml.etree.ElementTree as ET
|
|
16
|
-
from typing import Any, Dict, List, Optional, TypeAlias, Union
|
|
16
|
+
from typing import Any, Dict, List, Literal, Optional, Type, TypeAlias, Union
|
|
17
17
|
|
|
18
18
|
import requests
|
|
19
|
+
from pydantic import BaseModel
|
|
19
20
|
|
|
20
21
|
from camel.toolkits.base import BaseToolkit
|
|
21
22
|
from camel.toolkits.function_tool import FunctionTool
|
|
@@ -63,6 +64,82 @@ class SearchToolkit(BaseToolkit):
|
|
|
63
64
|
|
|
64
65
|
return result
|
|
65
66
|
|
|
67
|
+
@dependencies_required("linkup")
|
|
68
|
+
@api_keys_required(
|
|
69
|
+
[
|
|
70
|
+
(None, "LINKUP_API_KEY"),
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
def search_linkup(
|
|
74
|
+
self,
|
|
75
|
+
query: str,
|
|
76
|
+
depth: Literal["standard", "deep"] = "standard",
|
|
77
|
+
output_type: Literal[
|
|
78
|
+
"searchResults", "sourcedAnswer", "structured"
|
|
79
|
+
] = "searchResults",
|
|
80
|
+
structured_output_schema: Union[Type[BaseModel], str, None] = None,
|
|
81
|
+
) -> Dict[str, Any]:
|
|
82
|
+
r"""Search for a query in the Linkup API and return results in various
|
|
83
|
+
formats.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
query (str): The search query.
|
|
87
|
+
depth (Literal["standard", "deep"]): The depth of the search.
|
|
88
|
+
"standard" for a straightforward search, "deep" for a more
|
|
89
|
+
comprehensive search.
|
|
90
|
+
output_type (Literal["searchResults", "sourcedAnswer",
|
|
91
|
+
"structured"]): The type of output:
|
|
92
|
+
- "searchResults" for raw search results,
|
|
93
|
+
- "sourcedAnswer" for an answer with supporting sources,
|
|
94
|
+
- "structured" for output based on a provided schema.
|
|
95
|
+
structured_output_schema (Union[Type[BaseModel], str, None]): If
|
|
96
|
+
`output_type` is "structured",specify the schema of the
|
|
97
|
+
output. Can be a Pydantic BaseModel or a JSON schema string.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Dict[str, Any]: A dictionary representing the search result. The
|
|
101
|
+
structure depends on the `output_type`. If an error occurs,
|
|
102
|
+
returns an error message.
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
from linkup import LinkupClient
|
|
106
|
+
|
|
107
|
+
# Initialize the Linkup client with the API key
|
|
108
|
+
LINKUP_API_KEY = os.getenv("LINKUP_API_KEY")
|
|
109
|
+
client = LinkupClient(api_key=LINKUP_API_KEY)
|
|
110
|
+
|
|
111
|
+
# Perform the search using the specified output_type
|
|
112
|
+
response = client.search(
|
|
113
|
+
query=query,
|
|
114
|
+
depth=depth,
|
|
115
|
+
output_type=output_type,
|
|
116
|
+
structured_output_schema=structured_output_schema,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if output_type == "searchResults":
|
|
120
|
+
results = [
|
|
121
|
+
item.__dict__
|
|
122
|
+
for item in response.__dict__.get('results', [])
|
|
123
|
+
]
|
|
124
|
+
return {"results": results}
|
|
125
|
+
|
|
126
|
+
elif output_type == "sourcedAnswer":
|
|
127
|
+
answer = response.__dict__.get('answer', '')
|
|
128
|
+
sources = [
|
|
129
|
+
item.__dict__
|
|
130
|
+
for item in response.__dict__.get('sources', [])
|
|
131
|
+
]
|
|
132
|
+
return {"answer": answer, "sources": sources}
|
|
133
|
+
|
|
134
|
+
elif output_type == "structured" and structured_output_schema:
|
|
135
|
+
return response.__dict__
|
|
136
|
+
|
|
137
|
+
else:
|
|
138
|
+
return {"error": f"Invalid output_type: {output_type}"}
|
|
139
|
+
|
|
140
|
+
except Exception as e:
|
|
141
|
+
return {"error": f"An unexpected error occurred: {e!s}"}
|
|
142
|
+
|
|
66
143
|
@dependencies_required("duckduckgo_search")
|
|
67
144
|
def search_duckduckgo(
|
|
68
145
|
self, query: str, source: str = "text", max_results: int = 5
|
|
@@ -151,7 +228,11 @@ class SearchToolkit(BaseToolkit):
|
|
|
151
228
|
# If no answer found, return an empty list
|
|
152
229
|
return responses
|
|
153
230
|
|
|
154
|
-
@api_keys_required(
|
|
231
|
+
@api_keys_required(
|
|
232
|
+
[
|
|
233
|
+
(None, 'BRAVE_API_KEY'),
|
|
234
|
+
]
|
|
235
|
+
)
|
|
155
236
|
def search_brave(
|
|
156
237
|
self,
|
|
157
238
|
q: str,
|
|
@@ -297,7 +378,12 @@ class SearchToolkit(BaseToolkit):
|
|
|
297
378
|
data = response.json()["web"]
|
|
298
379
|
return data
|
|
299
380
|
|
|
300
|
-
@api_keys_required(
|
|
381
|
+
@api_keys_required(
|
|
382
|
+
[
|
|
383
|
+
(None, 'GOOGLE_API_KEY'),
|
|
384
|
+
(None, 'SEARCH_ENGINE_ID'),
|
|
385
|
+
]
|
|
386
|
+
)
|
|
301
387
|
def search_google(
|
|
302
388
|
self, query: str, num_result_pages: int = 5
|
|
303
389
|
) -> List[Dict[str, Any]]:
|
|
@@ -429,8 +515,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
429
515
|
if not WOLFRAMALPHA_APP_ID:
|
|
430
516
|
raise ValueError(
|
|
431
517
|
"`WOLFRAMALPHA_APP_ID` not found in environment "
|
|
432
|
-
"variables. Get `WOLFRAMALPHA_APP_ID` here: "
|
|
433
|
-
"`https://products.wolframalpha.com/api/`."
|
|
518
|
+
"variables. Get `WOLFRAMALPHA_APP_ID` here: `https://products.wolframalpha.com/api/`."
|
|
434
519
|
)
|
|
435
520
|
|
|
436
521
|
try:
|
|
@@ -618,6 +703,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
618
703
|
"""
|
|
619
704
|
return [
|
|
620
705
|
FunctionTool(self.search_wiki),
|
|
706
|
+
FunctionTool(self.search_linkup),
|
|
621
707
|
FunctionTool(self.search_google),
|
|
622
708
|
FunctionTool(self.search_duckduckgo),
|
|
623
709
|
FunctionTool(self.query_wolfram_alpha),
|
camel/toolkits/stripe_toolkit.py
CHANGED
|
@@ -36,7 +36,11 @@ class StripeToolkit(BaseToolkit):
|
|
|
36
36
|
logger (Logger): a logger to write logs.
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
-
@api_keys_required(
|
|
39
|
+
@api_keys_required(
|
|
40
|
+
[
|
|
41
|
+
(None, "STRIPE_API_KEY"),
|
|
42
|
+
]
|
|
43
|
+
)
|
|
40
44
|
def __init__(self, retries: int = 3):
|
|
41
45
|
r"""Initializes the StripeToolkit with the specified number of
|
|
42
46
|
retries.
|
|
@@ -31,10 +31,12 @@ logger = get_logger(__name__)
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@api_keys_required(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
[
|
|
35
|
+
(None, "TWITTER_CONSUMER_KEY"),
|
|
36
|
+
(None, "TWITTER_CONSUMER_SECRET"),
|
|
37
|
+
(None, "TWITTER_ACCESS_TOKEN"),
|
|
38
|
+
(None, "TWITTER_ACCESS_TOKEN_SECRET"),
|
|
39
|
+
]
|
|
38
40
|
)
|
|
39
41
|
def create_tweet(
|
|
40
42
|
text: str,
|
|
@@ -132,10 +134,12 @@ def create_tweet(
|
|
|
132
134
|
|
|
133
135
|
|
|
134
136
|
@api_keys_required(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
[
|
|
138
|
+
(None, "TWITTER_CONSUMER_KEY"),
|
|
139
|
+
(None, "TWITTER_CONSUMER_SECRET"),
|
|
140
|
+
(None, "TWITTER_ACCESS_TOKEN"),
|
|
141
|
+
(None, "TWITTER_ACCESS_TOKEN_SECRET"),
|
|
142
|
+
]
|
|
139
143
|
)
|
|
140
144
|
def delete_tweet(tweet_id: str) -> str:
|
|
141
145
|
r"""Deletes a tweet with the specified ID for an authorized user.
|
|
@@ -187,10 +191,12 @@ def delete_tweet(tweet_id: str) -> str:
|
|
|
187
191
|
|
|
188
192
|
|
|
189
193
|
@api_keys_required(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
[
|
|
195
|
+
(None, "TWITTER_CONSUMER_KEY"),
|
|
196
|
+
(None, "TWITTER_CONSUMER_SECRET"),
|
|
197
|
+
(None, "TWITTER_ACCESS_TOKEN"),
|
|
198
|
+
(None, "TWITTER_ACCESS_TOKEN_SECRET"),
|
|
199
|
+
]
|
|
194
200
|
)
|
|
195
201
|
def get_my_user_profile() -> str:
|
|
196
202
|
r"""Retrieves the authenticated user's Twitter profile info.
|
|
@@ -214,10 +220,12 @@ def get_my_user_profile() -> str:
|
|
|
214
220
|
|
|
215
221
|
|
|
216
222
|
@api_keys_required(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
[
|
|
224
|
+
(None, "TWITTER_CONSUMER_KEY"),
|
|
225
|
+
(None, "TWITTER_CONSUMER_SECRET"),
|
|
226
|
+
(None, "TWITTER_ACCESS_TOKEN"),
|
|
227
|
+
(None, "TWITTER_ACCESS_TOKEN_SECRET"),
|
|
228
|
+
]
|
|
221
229
|
)
|
|
222
230
|
def get_user_by_username(username: str) -> str:
|
|
223
231
|
r"""Retrieves one user's Twitter profile info by username (handle).
|
camel/types/enums.py
CHANGED
|
@@ -34,6 +34,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
34
34
|
GPT_4_TURBO = "gpt-4-turbo"
|
|
35
35
|
GPT_4O = "gpt-4o"
|
|
36
36
|
GPT_4O_MINI = "gpt-4o-mini"
|
|
37
|
+
O1 = "o1"
|
|
37
38
|
O1_PREVIEW = "o1-preview"
|
|
38
39
|
O1_MINI = "o1-mini"
|
|
39
40
|
|
|
@@ -153,9 +154,15 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
153
154
|
return self.value
|
|
154
155
|
return "gpt-4o-mini"
|
|
155
156
|
|
|
157
|
+
@property
|
|
158
|
+
def support_native_structured_output(self) -> bool:
|
|
159
|
+
return self.is_openai
|
|
160
|
+
|
|
156
161
|
@property
|
|
157
162
|
def support_native_tool_calling(self) -> bool:
|
|
158
|
-
return any(
|
|
163
|
+
return any(
|
|
164
|
+
[self.is_openai, self.is_gemini, self.is_mistral, self.is_qwen]
|
|
165
|
+
)
|
|
159
166
|
|
|
160
167
|
@property
|
|
161
168
|
def is_openai(self) -> bool:
|
|
@@ -166,6 +173,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
166
173
|
ModelType.GPT_4_TURBO,
|
|
167
174
|
ModelType.GPT_4O,
|
|
168
175
|
ModelType.GPT_4O_MINI,
|
|
176
|
+
ModelType.O1,
|
|
169
177
|
ModelType.O1_PREVIEW,
|
|
170
178
|
ModelType.O1_MINI,
|
|
171
179
|
}
|
|
@@ -452,6 +460,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
452
460
|
}:
|
|
453
461
|
return 131_072
|
|
454
462
|
elif self in {
|
|
463
|
+
ModelType.O1,
|
|
455
464
|
ModelType.CLAUDE_2_1,
|
|
456
465
|
ModelType.CLAUDE_3_OPUS,
|
|
457
466
|
ModelType.CLAUDE_3_SONNET,
|
|
@@ -113,6 +113,11 @@ class UnifiedModelType(str):
|
|
|
113
113
|
r"""Returns whether the model is a Qwen model."""
|
|
114
114
|
return True
|
|
115
115
|
|
|
116
|
+
@property
|
|
117
|
+
def support_native_structured_output(self) -> bool:
|
|
118
|
+
r"""Returns whether the model supports native structured output."""
|
|
119
|
+
return False
|
|
120
|
+
|
|
116
121
|
@property
|
|
117
122
|
def support_native_tool_calling(self) -> bool:
|
|
118
123
|
r"""Returns whether the model supports native tool calling."""
|
camel/utils/__init__.py
CHANGED
|
@@ -19,8 +19,10 @@ from .commons import (
|
|
|
19
19
|
check_server_running,
|
|
20
20
|
create_chunks,
|
|
21
21
|
dependencies_required,
|
|
22
|
+
download_github_subdirectory,
|
|
22
23
|
download_tasks,
|
|
23
24
|
func_string_to_callable,
|
|
25
|
+
generate_prompt_for_structured_output,
|
|
24
26
|
get_first_int,
|
|
25
27
|
get_prompt_template_key_words,
|
|
26
28
|
get_pydantic_major_version,
|
|
@@ -78,4 +80,6 @@ __all__ = [
|
|
|
78
80
|
"track_agent",
|
|
79
81
|
"handle_http_error",
|
|
80
82
|
"get_pydantic_model",
|
|
83
|
+
"download_github_subdirectory",
|
|
84
|
+
"generate_prompt_for_structured_output",
|
|
81
85
|
]
|
camel/utils/commons.py
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import importlib
|
|
15
|
-
import logging
|
|
16
15
|
import os
|
|
17
16
|
import platform
|
|
18
17
|
import re
|
|
@@ -22,6 +21,7 @@ import time
|
|
|
22
21
|
import zipfile
|
|
23
22
|
from functools import wraps
|
|
24
23
|
from http import HTTPStatus
|
|
24
|
+
from pathlib import Path
|
|
25
25
|
from typing import (
|
|
26
26
|
Any,
|
|
27
27
|
Callable,
|
|
@@ -30,6 +30,7 @@ from typing import (
|
|
|
30
30
|
Mapping,
|
|
31
31
|
Optional,
|
|
32
32
|
Set,
|
|
33
|
+
Tuple,
|
|
33
34
|
Type,
|
|
34
35
|
TypeVar,
|
|
35
36
|
cast,
|
|
@@ -40,19 +41,14 @@ import pydantic
|
|
|
40
41
|
import requests
|
|
41
42
|
from pydantic import BaseModel
|
|
42
43
|
|
|
43
|
-
from camel.logger import get_logger
|
|
44
44
|
from camel.types import TaskType
|
|
45
45
|
|
|
46
46
|
from .constants import Constants
|
|
47
47
|
|
|
48
48
|
F = TypeVar('F', bound=Callable[..., Any])
|
|
49
49
|
|
|
50
|
-
logger = get_logger(__name__)
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
def print_text_animated(
|
|
54
|
-
text, delay: float = 0.02, end: str = "", log_level: int = logging.INFO
|
|
55
|
-
):
|
|
51
|
+
def print_text_animated(text, delay: float = 0.02, end: str = ""):
|
|
56
52
|
r"""Prints the given text with an animated effect.
|
|
57
53
|
|
|
58
54
|
Args:
|
|
@@ -61,22 +57,10 @@ def print_text_animated(
|
|
|
61
57
|
(default: :obj:`0.02`)
|
|
62
58
|
end (str, optional): The end character to print after each
|
|
63
59
|
character of text. (default: :obj:`""`)
|
|
64
|
-
log_level (int, optional): The log level to use.
|
|
65
|
-
See https://docs.python.org/3/library/logging.html#levels
|
|
66
|
-
(default: :obj:`logging.INFO`)
|
|
67
60
|
"""
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
for char in text:
|
|
73
|
-
print(char, end=end, flush=True)
|
|
74
|
-
time.sleep(delay)
|
|
75
|
-
# Close the log entry
|
|
76
|
-
logger.log(log_level, '')
|
|
77
|
-
else:
|
|
78
|
-
# This may be relevant for logging frameworks
|
|
79
|
-
logger.log(log_level, text)
|
|
61
|
+
for char in text:
|
|
62
|
+
print(char, end=end, flush=True)
|
|
63
|
+
time.sleep(delay)
|
|
80
64
|
|
|
81
65
|
|
|
82
66
|
def get_prompt_template_key_words(template: str) -> Set[str]:
|
|
@@ -249,41 +233,79 @@ def is_module_available(module_name: str) -> bool:
|
|
|
249
233
|
return False
|
|
250
234
|
|
|
251
235
|
|
|
252
|
-
def api_keys_required(
|
|
253
|
-
|
|
254
|
-
|
|
236
|
+
def api_keys_required(
|
|
237
|
+
param_env_list: List[Tuple[Optional[str], str]],
|
|
238
|
+
) -> Callable[[F], F]:
|
|
239
|
+
r"""A decorator to check if the required API keys are provided in the
|
|
240
|
+
environment variables or as function arguments.
|
|
255
241
|
|
|
256
242
|
Args:
|
|
257
|
-
|
|
243
|
+
param_env_list (List[Tuple[Optional[str], str]]): A list of tuples
|
|
244
|
+
where each tuple contains a function argument name (as the first
|
|
245
|
+
element, or None) and the corresponding environment variable name
|
|
246
|
+
(as the second element) that holds the API key.
|
|
258
247
|
|
|
259
248
|
Returns:
|
|
260
|
-
Callable[[F], F]: The original function with the added check
|
|
261
|
-
for required API keys.
|
|
249
|
+
Callable[[F], F]: The original function wrapped with the added check
|
|
250
|
+
for the required API keys.
|
|
262
251
|
|
|
263
252
|
Raises:
|
|
264
|
-
ValueError: If any of the required API keys are missing
|
|
265
|
-
|
|
253
|
+
ValueError: If any of the required API keys are missing, either
|
|
254
|
+
from the function arguments or environment variables.
|
|
266
255
|
|
|
267
256
|
Example:
|
|
268
257
|
::
|
|
269
258
|
|
|
270
|
-
@api_keys_required(
|
|
271
|
-
|
|
272
|
-
|
|
259
|
+
@api_keys_required([
|
|
260
|
+
('api_key_arg', 'API_KEY_1'),
|
|
261
|
+
('another_key_arg', 'API_KEY_2'),
|
|
262
|
+
(None, 'API_KEY_3'),
|
|
263
|
+
])
|
|
264
|
+
def some_api_function(api_key_arg=None, another_key_arg=None):
|
|
265
|
+
# Function implementation that requires API keys
|
|
273
266
|
"""
|
|
267
|
+
import inspect
|
|
274
268
|
|
|
275
269
|
def decorator(func: F) -> F:
|
|
276
270
|
@wraps(func)
|
|
277
271
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
272
|
+
signature = inspect.signature(func)
|
|
273
|
+
bound_arguments = signature.bind(*args, **kwargs)
|
|
274
|
+
bound_arguments.apply_defaults()
|
|
275
|
+
arguments = bound_arguments.arguments
|
|
276
|
+
|
|
277
|
+
missing_keys = []
|
|
278
|
+
for param_name, env_var_name in param_env_list:
|
|
279
|
+
if not isinstance(env_var_name, str):
|
|
280
|
+
raise TypeError(
|
|
281
|
+
f"Environment variable name must be a string, got"
|
|
282
|
+
f" {type(env_var_name)}"
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
value = None
|
|
286
|
+
if (
|
|
287
|
+
param_name
|
|
288
|
+
): # If param_name is provided, check function argument first
|
|
289
|
+
if not isinstance(param_name, str):
|
|
290
|
+
raise TypeError(
|
|
291
|
+
f"Parameter name must be a string, "
|
|
292
|
+
f"got {type(param_name)}"
|
|
293
|
+
)
|
|
294
|
+
value = arguments.get(param_name)
|
|
295
|
+
# If we found a valid value in arguments, continue to next
|
|
296
|
+
# item
|
|
297
|
+
if value:
|
|
298
|
+
continue
|
|
299
|
+
|
|
300
|
+
# Check environment variable if no valid value found yet
|
|
301
|
+
value = os.environ.get(env_var_name)
|
|
302
|
+
if not value or value.strip() == "":
|
|
303
|
+
missing_keys.append(env_var_name)
|
|
304
|
+
|
|
305
|
+
if missing_keys:
|
|
285
306
|
raise ValueError(
|
|
286
|
-
|
|
307
|
+
"Missing or empty required API keys in "
|
|
308
|
+
f"environment variables: {', '.join(missing_keys)}"
|
|
287
309
|
)
|
|
288
310
|
return func(*args, **kwargs)
|
|
289
311
|
|
|
@@ -406,7 +428,8 @@ def json_to_function_code(json_obj: Dict) -> str:
|
|
|
406
428
|
}
|
|
407
429
|
|
|
408
430
|
for prop in required:
|
|
409
|
-
description
|
|
431
|
+
# if no description, return empty string
|
|
432
|
+
description = properties[prop].get('description', "")
|
|
410
433
|
prop_type = properties[prop]['type']
|
|
411
434
|
python_type = prop_to_python.get(prop_type, prop_type)
|
|
412
435
|
args.append(f"{prop}: {python_type}")
|
|
@@ -624,3 +647,84 @@ def retry_request(
|
|
|
624
647
|
time.sleep(delay)
|
|
625
648
|
else:
|
|
626
649
|
raise
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
def download_github_subdirectory(
|
|
653
|
+
repo: str, subdir: str, data_dir: Path, branch="main"
|
|
654
|
+
):
|
|
655
|
+
r"""Download subdirectory of the Github repo of
|
|
656
|
+
the benchmark.
|
|
657
|
+
|
|
658
|
+
This function downloads all files and subdirectories from a
|
|
659
|
+
specified subdirectory of a GitHub repository and
|
|
660
|
+
saves them to a local directory.
|
|
661
|
+
|
|
662
|
+
Args:
|
|
663
|
+
repo (str): The name of the GitHub repository
|
|
664
|
+
in the format "owner/repo".
|
|
665
|
+
subdir (str): The path to the subdirectory
|
|
666
|
+
within the repository to download.
|
|
667
|
+
data_dir (Path): The local directory where
|
|
668
|
+
the files will be saved.
|
|
669
|
+
branch (str, optional): The branch of the repository to use.
|
|
670
|
+
Defaults to "main".
|
|
671
|
+
"""
|
|
672
|
+
from tqdm import tqdm
|
|
673
|
+
|
|
674
|
+
api_url = (
|
|
675
|
+
f"https://api.github.com/repos/{repo}/contents/{subdir}?ref={branch}"
|
|
676
|
+
)
|
|
677
|
+
headers = {"Accept": "application/vnd.github.v3+json"}
|
|
678
|
+
response = requests.get(api_url, headers=headers)
|
|
679
|
+
response.raise_for_status()
|
|
680
|
+
files = response.json()
|
|
681
|
+
os.makedirs(data_dir, exist_ok=True)
|
|
682
|
+
|
|
683
|
+
for file in tqdm(files, desc="Downloading"):
|
|
684
|
+
file_path = data_dir / file["name"]
|
|
685
|
+
|
|
686
|
+
if file["type"] == "file":
|
|
687
|
+
file_url = file["download_url"]
|
|
688
|
+
file_response = requests.get(file_url)
|
|
689
|
+
with open(file_path, "wb") as f:
|
|
690
|
+
f.write(file_response.content)
|
|
691
|
+
elif file["type"] == "dir":
|
|
692
|
+
download_github_subdirectory(
|
|
693
|
+
repo, f'{subdir}/{file["name"]}', file_path, branch
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
def generate_prompt_for_structured_output(
|
|
698
|
+
response_format: Optional[Type[BaseModel]],
|
|
699
|
+
user_message: str,
|
|
700
|
+
) -> str:
|
|
701
|
+
"""
|
|
702
|
+
This function generates a prompt based on the provided Pydantic model and
|
|
703
|
+
user message.
|
|
704
|
+
|
|
705
|
+
Args:
|
|
706
|
+
response_format (Type[BaseModel]): The Pydantic model class.
|
|
707
|
+
user_message (str): The user message to be used in the prompt.
|
|
708
|
+
|
|
709
|
+
Returns:
|
|
710
|
+
str: A prompt string for the LLM.
|
|
711
|
+
"""
|
|
712
|
+
if response_format is None:
|
|
713
|
+
return user_message
|
|
714
|
+
|
|
715
|
+
json_schema = response_format.model_json_schema()
|
|
716
|
+
sys_prompt = (
|
|
717
|
+
"Given the user message, please generate a JSON response adhering "
|
|
718
|
+
"to the following JSON schema:\n"
|
|
719
|
+
f"{json_schema}\n"
|
|
720
|
+
"Make sure the JSON response is valid and matches the EXACT structure "
|
|
721
|
+
"defined in the schema. Your result should only be a valid json "
|
|
722
|
+
"object, without any other text or comments.\n"
|
|
723
|
+
)
|
|
724
|
+
user_prompt = f"User message: {user_message}\n"
|
|
725
|
+
|
|
726
|
+
final_prompt = f"""
|
|
727
|
+
{sys_prompt}
|
|
728
|
+
{user_prompt}
|
|
729
|
+
"""
|
|
730
|
+
return final_prompt
|
camel/utils/token_counting.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: camel-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.15
|
|
4
4
|
Summary: Communicative Agents for AI Society Study
|
|
5
5
|
Home-page: https://www.camel-ai.org/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -42,13 +42,13 @@ Requires-Dist: colorama (>=0,<1)
|
|
|
42
42
|
Requires-Dist: curl_cffi (==0.6.2)
|
|
43
43
|
Requires-Dist: datacommons (>=1.4.3,<2.0.0) ; extra == "tools" or extra == "all"
|
|
44
44
|
Requires-Dist: datacommons_pandas (>=0.0.3,<0.0.4) ; extra == "tools" or extra == "all"
|
|
45
|
-
Requires-Dist: datasets (>=
|
|
45
|
+
Requires-Dist: datasets (>=3,<4) ; extra == "huggingface-agent" or extra == "all"
|
|
46
46
|
Requires-Dist: diffusers (>=0,<1) ; extra == "huggingface-agent" or extra == "all"
|
|
47
47
|
Requires-Dist: discord.py (>=2.3.2,<3.0.0) ; extra == "tools" or extra == "all"
|
|
48
48
|
Requires-Dist: docker (>=7.1.0,<8.0.0) ; extra == "tools" or extra == "runtime" or extra == "all"
|
|
49
49
|
Requires-Dist: docstring-parser (>=0.15,<0.16)
|
|
50
50
|
Requires-Dist: docx2txt (>=0.8,<0.9) ; extra == "tools" or extra == "all"
|
|
51
|
-
Requires-Dist: duckduckgo-search (>=6.
|
|
51
|
+
Requires-Dist: duckduckgo-search (>=6.3.5,<7.0.0) ; extra == "search-tools" or extra == "tools" or extra == "all"
|
|
52
52
|
Requires-Dist: e2b-code-interpreter (>=1.0.3,<2.0.0) ; extra == "tools" or extra == "all"
|
|
53
53
|
Requires-Dist: eval-type-backport (==0.2.0)
|
|
54
54
|
Requires-Dist: ffmpeg-python (>=0.2.0,<0.3.0) ; extra == "tools" or extra == "all"
|
|
@@ -62,18 +62,21 @@ Requires-Dist: imageio[pyav] (>=2.34.2,<3.0.0) ; extra == "tools" or extra == "a
|
|
|
62
62
|
Requires-Dist: ipykernel (>=6.0.0,<7.0.0) ; extra == "tools" or extra == "all"
|
|
63
63
|
Requires-Dist: jsonschema (>=4,<5)
|
|
64
64
|
Requires-Dist: jupyter_client (>=8.6.2,<9.0.0) ; extra == "tools" or extra == "all"
|
|
65
|
+
Requires-Dist: linkup-sdk (>=0.2.1,<0.3.0) ; extra == "search-tools" or extra == "tools" or extra == "all"
|
|
65
66
|
Requires-Dist: litellm (>=1.38.1,<2.0.0) ; extra == "model-platforms" or extra == "all"
|
|
66
67
|
Requires-Dist: mistralai (>=1.1.0,<2.0.0) ; extra == "model-platforms" or extra == "all"
|
|
67
68
|
Requires-Dist: mock (>=5,<6) ; extra == "test"
|
|
68
69
|
Requires-Dist: nebula3-python (==3.8.2) ; extra == "rag" or extra == "graph-storages" or extra == "all"
|
|
69
70
|
Requires-Dist: neo4j (>=5.18.0,<6.0.0) ; extra == "rag" or extra == "graph-storages" or extra == "all"
|
|
70
71
|
Requires-Dist: newspaper3k (>=0.2.8,<0.3.0) ; extra == "tools" or extra == "all"
|
|
71
|
-
Requires-Dist: nltk (==3.9.1) ; extra == "tools" or extra == "all"
|
|
72
72
|
Requires-Dist: notion-client (>=2.2.1,<3.0.0) ; extra == "tools" or extra == "all"
|
|
73
73
|
Requires-Dist: numpy (>=1,<2)
|
|
74
|
-
Requires-Dist: openai (>=1.
|
|
74
|
+
Requires-Dist: openai (>=1.58.1,<2.0.0)
|
|
75
75
|
Requires-Dist: openapi-spec-validator (>=0.7.1,<0.8.0) ; extra == "tools" or extra == "all"
|
|
76
|
+
Requires-Dist: openbb (>=4.3.5,<5.0.0) ; extra == "tools" or extra == "all"
|
|
76
77
|
Requires-Dist: opencv-python (>=4,<5) ; extra == "huggingface-agent" or extra == "all"
|
|
78
|
+
Requires-Dist: outlines (>=0.1.7,<0.2.0) ; extra == "tools" or extra == "all"
|
|
79
|
+
Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "tools" or extra == "all"
|
|
77
80
|
Requires-Dist: pandoc
|
|
78
81
|
Requires-Dist: pathlib (>=1.0.1,<2.0.0)
|
|
79
82
|
Requires-Dist: pdfplumber (>=0.11.0,<0.12.0) ; extra == "tools" or extra == "all"
|
|
@@ -95,6 +98,7 @@ Requires-Dist: rank-bm25 (>=0.2.2,<0.3.0) ; extra == "rag" or extra == "retrieve
|
|
|
95
98
|
Requires-Dist: redis (>=5.0.6,<6.0.0) ; extra == "kv-stroages" or extra == "all"
|
|
96
99
|
Requires-Dist: reka-api (>=3.0.8,<4.0.0) ; extra == "model-platforms" or extra == "all"
|
|
97
100
|
Requires-Dist: requests_oauthlib (>=1.3.1,<2.0.0) ; extra == "tools" or extra == "all"
|
|
101
|
+
Requires-Dist: rouge (>=1.0.1,<2.0.0) ; extra == "tools" or extra == "all"
|
|
98
102
|
Requires-Dist: scholarly[tor] (==1.7.11) ; extra == "tools" or extra == "all"
|
|
99
103
|
Requires-Dist: sentence-transformers (>=3.0.1,<4.0.0) ; extra == "rag" or extra == "encoders" or extra == "all"
|
|
100
104
|
Requires-Dist: sentencepiece (>=0,<1) ; extra == "huggingface-agent" or extra == "all"
|
|
@@ -109,7 +113,9 @@ Requires-Dist: tiktoken (>=0.7.0,<0.8.0)
|
|
|
109
113
|
Requires-Dist: torch (==2.2.1) ; (platform_system == "Darwin" and platform_machine != "arm64") and (extra == "huggingface-agent" or extra == "all")
|
|
110
114
|
Requires-Dist: torch (>=2,<3) ; (platform_system != "Darwin" or platform_machine == "arm64") and (extra == "huggingface-agent" or extra == "all")
|
|
111
115
|
Requires-Dist: transformers (>=4,<5) ; extra == "huggingface-agent" or extra == "all"
|
|
112
|
-
Requires-Dist:
|
|
116
|
+
Requires-Dist: tree-sitter (>=0.23.2,<0.24.0) ; extra == "tools" or extra == "all"
|
|
117
|
+
Requires-Dist: tree-sitter-python (>=0.23.6,<0.24.0) ; extra == "tools" or extra == "all"
|
|
118
|
+
Requires-Dist: unstructured[all-docs] (==0.16.11) ; extra == "rag" or extra == "tools" or extra == "all"
|
|
113
119
|
Requires-Dist: wikipedia (>=1,<2) ; extra == "search-tools" or extra == "tools" or extra == "all"
|
|
114
120
|
Requires-Dist: wolframalpha (>=5.0.0,<6.0.0) ; extra == "search-tools" or extra == "tools" or extra == "all"
|
|
115
121
|
Requires-Dist: yt-dlp (>=2024.11.4,<2025.0.0) ; extra == "tools" or extra == "all"
|
|
@@ -263,7 +269,7 @@ conda create --name camel python=3.10
|
|
|
263
269
|
conda activate camel
|
|
264
270
|
|
|
265
271
|
# Clone github repo
|
|
266
|
-
git clone -b v0.2.
|
|
272
|
+
git clone -b v0.2.15 https://github.com/camel-ai/camel.git
|
|
267
273
|
|
|
268
274
|
# Change directory into project directory
|
|
269
275
|
cd camel
|
|
@@ -444,6 +450,9 @@ Practical guides and tutorials for implementing specific functionalities in CAME
|
|
|
444
450
|
| **[Customer Service Discord Bot with Agentic RAG](https://docs.camel-ai.org/cookbooks/customer_service_Discord_bot_with_agentic_RAG.html)** | Learn how to build a robust customer service bot for Discord using Agentic RAG. |
|
|
445
451
|
| **[Create AI Agents that work with your PDFs using Chunkr & Mistral AI](https://docs.camel-ai.org/cookbooks/agent_with_chunkr_for_pdf_parsing.html)** | Learn how to create AI agents that work with your PDFs using Chunkr and Mistral AI. |
|
|
446
452
|
| **[Data Gen with Real Function Calls and Hermes Format](https://docs.camel-ai.org/cookbooks/data_gen_with_real_function_calls_and_hermes_format.html)** | Explore how to generate data with real function calls and the Hermes format. |
|
|
453
|
+
| **[CoT Data Generation and Upload Data to Huggingface](https://docs.camel-ai.org/cookbooks/cot_data_gen_upload_to_huggingface.html)** | Uncover how to generate CoT data with CAMEL and seamlessly upload it to Huggingface. |
|
|
454
|
+
| **[CoT Data Generation and SFT Qwen with Unsolth, Uploading Data and Model to Hugging Face](https://docs.camel-ai.org/cookbooks/cot_data_gen_sft_qwen_unsolth_upload_huggingface.html)** | Discover how to generate CoT data using CAMEL and SFT Qwen with Unsolth, and seamlessly upload your data and model to Huggingface. |
|
|
455
|
+
| **[Customer Service Discord Bot with Agentic RAG supports local model deployment](https://docs.camel-ai.org/cookbooks/customer_service_Discord_bot_using_local_model_with_agentic_RAG.html)** | Learn how to build a robust customer service bot for Discord using Agentic RAG which supports local deployment. |
|
|
447
456
|
|
|
448
457
|
## Utilize Various LLMs as Backends
|
|
449
458
|
|
|
@@ -473,6 +482,8 @@ We implemented amazing research ideas from other works for you to build, compare
|
|
|
473
482
|
|
|
474
483
|
- `PersonaHub` from *Tao Ge et al.*: [Scaling Synthetic Data Creation with 1,000,000,000 Personas](https://arxiv.org/pdf/2406.20094). [[Example](https://github.com/camel-ai/camel/blob/master/examples/personas/personas_generation.py)]
|
|
475
484
|
|
|
485
|
+
- `Self-Instruct` from *Yizhong Wang et al.*: [SELF-INSTRUCT: Aligning Language Models with Self-Generated Instructions](https://arxiv.org/pdf/2212.10560). [[Example](https://github.com/camel-ai/camel/blob/master/examples/datagen/self_instruct/self_instruct.py)]
|
|
486
|
+
|
|
476
487
|
## Other Research Works Based on Camel
|
|
477
488
|
- [Agent Trust](http://agent-trust.camel-ai.org/): Can Large Language Model Agents Simulate Human Trust Behavior?
|
|
478
489
|
|