camel-ai 0.2.15a0__py3-none-any.whl → 0.2.17__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.

Files changed (95) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +18 -4
  3. camel/agents/multi_hop_generator_agent.py +85 -0
  4. camel/agents/programmed_agent_instruction.py +148 -0
  5. camel/benchmarks/__init__.py +13 -1
  6. camel/benchmarks/apibank.py +565 -0
  7. camel/benchmarks/apibench.py +500 -0
  8. camel/benchmarks/gaia.py +4 -4
  9. camel/benchmarks/nexus.py +518 -0
  10. camel/benchmarks/ragbench.py +333 -0
  11. camel/bots/__init__.py +1 -1
  12. camel/bots/discord/__init__.py +26 -0
  13. camel/bots/discord/discord_app.py +384 -0
  14. camel/bots/discord/discord_installation.py +64 -0
  15. camel/bots/discord/discord_store.py +160 -0
  16. camel/configs/__init__.py +3 -0
  17. camel/configs/anthropic_config.py +17 -15
  18. camel/configs/internlm_config.py +60 -0
  19. camel/data_collector/base.py +5 -5
  20. camel/data_collector/sharegpt_collector.py +2 -2
  21. camel/datagen/__init__.py +6 -2
  22. camel/datagen/{o1datagen.py → cotdatagen.py} +19 -6
  23. camel/datagen/self_instruct/__init__.py +36 -0
  24. camel/datagen/self_instruct/filter/__init__.py +34 -0
  25. camel/datagen/self_instruct/filter/filter_function.py +216 -0
  26. camel/datagen/self_instruct/filter/filter_registry.py +56 -0
  27. camel/datagen/self_instruct/filter/instruction_filter.py +81 -0
  28. camel/datagen/self_instruct/self_instruct.py +393 -0
  29. camel/datagen/self_instruct/templates.py +382 -0
  30. camel/datahubs/huggingface.py +12 -2
  31. camel/datahubs/models.py +2 -3
  32. camel/embeddings/mistral_embedding.py +5 -1
  33. camel/embeddings/openai_compatible_embedding.py +6 -1
  34. camel/embeddings/openai_embedding.py +5 -1
  35. camel/interpreters/e2b_interpreter.py +5 -1
  36. camel/loaders/__init__.py +2 -0
  37. camel/loaders/apify_reader.py +5 -1
  38. camel/loaders/chunkr_reader.py +5 -1
  39. camel/loaders/firecrawl_reader.py +0 -30
  40. camel/loaders/panda_reader.py +337 -0
  41. camel/logger.py +11 -5
  42. camel/messages/__init__.py +10 -4
  43. camel/messages/conversion/conversation_models.py +5 -0
  44. camel/messages/func_message.py +30 -22
  45. camel/models/__init__.py +2 -0
  46. camel/models/anthropic_model.py +6 -23
  47. camel/models/azure_openai_model.py +1 -2
  48. camel/models/cohere_model.py +13 -1
  49. camel/models/deepseek_model.py +5 -1
  50. camel/models/gemini_model.py +15 -2
  51. camel/models/groq_model.py +5 -1
  52. camel/models/internlm_model.py +143 -0
  53. camel/models/mistral_model.py +19 -8
  54. camel/models/model_factory.py +3 -0
  55. camel/models/nemotron_model.py +5 -1
  56. camel/models/nvidia_model.py +5 -1
  57. camel/models/openai_model.py +5 -1
  58. camel/models/qwen_model.py +5 -1
  59. camel/models/reka_model.py +5 -1
  60. camel/models/reward/__init__.py +2 -0
  61. camel/models/reward/nemotron_model.py +5 -1
  62. camel/models/reward/skywork_model.py +88 -0
  63. camel/models/samba_model.py +5 -1
  64. camel/models/togetherai_model.py +5 -1
  65. camel/models/yi_model.py +5 -1
  66. camel/models/zhipuai_model.py +5 -1
  67. camel/schemas/openai_converter.py +5 -1
  68. camel/storages/graph_storages/nebula_graph.py +89 -20
  69. camel/storages/graph_storages/neo4j_graph.py +138 -0
  70. camel/synthetic_datagen/source2synth/data_processor.py +373 -0
  71. camel/synthetic_datagen/source2synth/models.py +68 -0
  72. camel/synthetic_datagen/source2synth/user_data_processor_config.py +73 -0
  73. camel/toolkits/__init__.py +4 -0
  74. camel/toolkits/arxiv_toolkit.py +20 -3
  75. camel/toolkits/dappier_toolkit.py +196 -0
  76. camel/toolkits/function_tool.py +61 -61
  77. camel/toolkits/google_scholar_toolkit.py +9 -0
  78. camel/toolkits/meshy_toolkit.py +5 -1
  79. camel/toolkits/notion_toolkit.py +1 -1
  80. camel/toolkits/openbb_toolkit.py +869 -0
  81. camel/toolkits/search_toolkit.py +91 -5
  82. camel/toolkits/stripe_toolkit.py +5 -1
  83. camel/toolkits/twitter_toolkit.py +24 -16
  84. camel/types/__init__.py +4 -2
  85. camel/types/enums.py +34 -1
  86. camel/types/openai_types.py +6 -4
  87. camel/types/unified_model_type.py +5 -0
  88. camel/utils/__init__.py +2 -0
  89. camel/utils/commons.py +104 -19
  90. camel/utils/token_counting.py +3 -3
  91. {camel_ai-0.2.15a0.dist-info → camel_ai-0.2.17.dist-info}/METADATA +160 -177
  92. {camel_ai-0.2.15a0.dist-info → camel_ai-0.2.17.dist-info}/RECORD +94 -69
  93. {camel_ai-0.2.15a0.dist-info → camel_ai-0.2.17.dist-info}/WHEEL +1 -1
  94. camel/bots/discord_app.py +0 -138
  95. {camel_ai-0.2.15a0.dist-info → camel_ai-0.2.17.dist-info}/LICENSE +0 -0
@@ -0,0 +1,337 @@
1
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+ import os
15
+ from functools import wraps
16
+ from pathlib import Path
17
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
18
+
19
+ import pandas as pd
20
+
21
+ if TYPE_CHECKING:
22
+ from pandas import DataFrame
23
+ from pandasai import SmartDataframe
24
+
25
+
26
+ def check_suffix(valid_suffixs: List[str]) -> Callable:
27
+ r"""A decorator to check the file suffix of a given file path.
28
+
29
+ Args:
30
+ valid_suffix (str): The required file suffix.
31
+
32
+ Returns:
33
+ Callable: The decorator function.
34
+ """
35
+
36
+ def decorator(func: Callable):
37
+ @wraps(func)
38
+ def wrapper(
39
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
40
+ ) -> "DataFrame":
41
+ suffix = Path(file_path).suffix
42
+ if suffix not in valid_suffixs:
43
+ raise ValueError(
44
+ f"Only {', '.join(valid_suffixs)} files are supported"
45
+ )
46
+ return func(self, file_path, *args, **kwargs)
47
+
48
+ return wrapper
49
+
50
+ return decorator
51
+
52
+
53
+ class PandaReader:
54
+ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
55
+ r"""Initializes the PandaReader class.
56
+
57
+ Args:
58
+ config (Optional[Dict[str, Any]], optional): The configuration
59
+ dictionary that can include LLM API settings for LLM-based
60
+ processing. If not provided, it will use OpenAI with the API
61
+ key from the OPENAI_API_KEY environment variable. You can
62
+ customize the LLM configuration by providing a 'llm' key in
63
+ the config dictionary. (default: :obj:`None`)
64
+ """
65
+ from pandasai.llm import OpenAI # type: ignore[import-untyped]
66
+
67
+ self.config = config or {}
68
+ if "llm" not in self.config:
69
+ self.config["llm"] = OpenAI(
70
+ api_token=os.getenv("OPENAI_API_KEY"),
71
+ )
72
+
73
+ self.__LOADER = {
74
+ ".csv": self.read_csv,
75
+ ".xlsx": self.read_excel,
76
+ ".xls": self.read_excel,
77
+ ".json": self.read_json,
78
+ ".parquet": self.read_parquet,
79
+ ".sql": self.read_sql,
80
+ ".html": self.read_html,
81
+ ".feather": self.read_feather,
82
+ ".dta": self.read_stata,
83
+ ".sas": self.read_sas,
84
+ ".pkl": self.read_pickle,
85
+ ".h5": self.read_hdf,
86
+ ".orc": self.read_orc,
87
+ }
88
+
89
+ def load(
90
+ self,
91
+ data: Union["DataFrame", str],
92
+ *args: Any,
93
+ **kwargs: Dict[str, Any],
94
+ ) -> "SmartDataframe":
95
+ r"""Loads a file or DataFrame and returns a SmartDataframe object.
96
+
97
+ args:
98
+ data (Union[DataFrame, str]): The data to load.
99
+ *args (Any): Additional positional arguments.
100
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
101
+
102
+ Returns:
103
+ SmartDataframe: The SmartDataframe object.
104
+ """
105
+ from pandas import DataFrame
106
+ from pandasai import SmartDataframe
107
+
108
+ if isinstance(data, DataFrame):
109
+ return SmartDataframe(data, config=self.config)
110
+ file_path = str(data)
111
+ path = Path(file_path)
112
+ if not file_path.startswith("http") and not path.exists():
113
+ raise FileNotFoundError(f"File {file_path} not found")
114
+ if path.suffix in self.__LOADER:
115
+ return SmartDataframe(
116
+ self.__LOADER[path.suffix](file_path, *args, **kwargs), # type: ignore[operator]
117
+ config=self.config,
118
+ )
119
+ else:
120
+ raise ValueError(f"Unsupported file format: {path.suffix}")
121
+
122
+ @check_suffix([".csv"])
123
+ def read_csv(
124
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
125
+ ) -> "DataFrame":
126
+ r"""Reads a CSV file and returns a DataFrame.
127
+
128
+ Args:
129
+ file_path (str): The path to the CSV file.
130
+ *args (Any): Additional positional arguments.
131
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
132
+
133
+ Returns:
134
+ DataFrame: The DataFrame object.
135
+ """
136
+ return pd.read_csv(file_path, *args, **kwargs)
137
+
138
+ @check_suffix([".xlsx", ".xls"])
139
+ def read_excel(
140
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
141
+ ) -> "DataFrame":
142
+ r"""Reads an Excel file and returns a DataFrame.
143
+
144
+ Args:
145
+ file_path (str): The path to the Excel file.
146
+ *args (Any): Additional positional arguments.
147
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
148
+
149
+ Returns:
150
+ DataFrame: The DataFrame object.
151
+ """
152
+ return pd.read_excel(file_path, *args, **kwargs)
153
+
154
+ @check_suffix([".json"])
155
+ def read_json(
156
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
157
+ ) -> "DataFrame":
158
+ r"""Reads a JSON file and returns a DataFrame.
159
+
160
+ Args:
161
+ file_path (str): The path to the JSON file.
162
+ *args (Any): Additional positional arguments.
163
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
164
+
165
+ Returns:
166
+ DataFrame: The DataFrame object.
167
+ """
168
+ return pd.read_json(file_path, *args, **kwargs)
169
+
170
+ @check_suffix([".parquet"])
171
+ def read_parquet(
172
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
173
+ ) -> "DataFrame":
174
+ r"""Reads a Parquet file and returns a DataFrame.
175
+
176
+ Args:
177
+ file_path (str): The path to the Parquet file.
178
+ *args (Any): Additional positional arguments.
179
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
180
+
181
+ Returns:
182
+ DataFrame: The DataFrame object.
183
+ """
184
+ return pd.read_parquet(file_path, *args, **kwargs)
185
+
186
+ def read_sql(self, *args: Any, **kwargs: Dict[str, Any]) -> "DataFrame":
187
+ r"""Reads a SQL file and returns a DataFrame.
188
+
189
+ Args:
190
+ *args (Any): Additional positional arguments.
191
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
192
+
193
+ Returns:
194
+ DataFrame: The DataFrame object.
195
+ """
196
+ return pd.read_sql(*args, **kwargs)
197
+
198
+ def read_table(
199
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
200
+ ) -> "DataFrame":
201
+ r"""Reads a table and returns a DataFrame.
202
+
203
+ Args:
204
+ file_path (str): The path to the table.
205
+ *args (Any): Additional positional arguments.
206
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
207
+
208
+ Returns:
209
+ DataFrame: The DataFrame object.
210
+ """
211
+ return pd.read_table(file_path, *args, **kwargs)
212
+
213
+ def read_clipboard(
214
+ self, *args: Any, **kwargs: Dict[str, Any]
215
+ ) -> "DataFrame":
216
+ r"""Reads a clipboard and returns a DataFrame.
217
+
218
+ Args:
219
+ *args (Any): Additional positional arguments.
220
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
221
+
222
+ Returns:
223
+ DataFrame: The DataFrame object.
224
+ """
225
+ return pd.read_clipboard(*args, **kwargs)
226
+
227
+ @check_suffix([".html"])
228
+ def read_html(
229
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
230
+ ) -> "DataFrame":
231
+ r"""Reads an HTML file and returns a DataFrame.
232
+
233
+ Args:
234
+ file_path (str): The path to the HTML file.
235
+ *args (Any): Additional positional arguments.
236
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
237
+
238
+ Returns:
239
+ DataFrame: The DataFrame object.
240
+ """
241
+ return pd.read_html(file_path, *args, **kwargs)
242
+
243
+ @check_suffix([".feather"])
244
+ def read_feather(
245
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
246
+ ) -> "DataFrame":
247
+ r"""Reads a Feather file and returns a DataFrame.
248
+
249
+ Args:
250
+ file_path (str): The path to the Feather file.
251
+ *args (Any): Additional positional arguments.
252
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
253
+
254
+ Returns:
255
+ DataFrame: The DataFrame object.
256
+ """
257
+ return pd.read_feather(file_path, *args, **kwargs)
258
+
259
+ @check_suffix([".dta"])
260
+ def read_stata(
261
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
262
+ ) -> "DataFrame":
263
+ r"""Reads a Stata file and returns a DataFrame.
264
+
265
+ Args:
266
+ file_path (str): The path to the Stata file.
267
+ *args (Any): Additional positional arguments.
268
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
269
+
270
+ Returns:
271
+ DataFrame: The DataFrame object.
272
+ """
273
+ return pd.read_stata(file_path, *args, **kwargs)
274
+
275
+ @check_suffix([".sas"])
276
+ def read_sas(
277
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
278
+ ) -> "DataFrame":
279
+ r"""Reads a SAS file and returns a DataFrame.
280
+
281
+ Args:
282
+ file_path (str): The path to the SAS file.
283
+ *args (Any): Additional positional arguments.
284
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
285
+
286
+ Returns:
287
+ DataFrame: The DataFrame object.
288
+ """
289
+ return pd.read_sas(file_path, *args, **kwargs)
290
+
291
+ @check_suffix([".pkl"])
292
+ def read_pickle(
293
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
294
+ ) -> "DataFrame":
295
+ r"""Reads a Pickle file and returns a DataFrame.
296
+
297
+ Args:
298
+ file_path (str): The path to the Pickle file.
299
+ *args (Any): Additional positional arguments.
300
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
301
+
302
+ Returns:
303
+ DataFrame: The DataFrame object.
304
+ """
305
+ return pd.read_pickle(file_path, *args, **kwargs)
306
+
307
+ @check_suffix([".h5"])
308
+ def read_hdf(
309
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
310
+ ) -> "DataFrame":
311
+ r"""Reads an HDF file and returns a DataFrame.
312
+
313
+ Args:
314
+ file_path (str): The path to the HDF file.
315
+ *args (Any): Additional positional arguments.
316
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
317
+
318
+ Returns:
319
+ DataFrame: The DataFrame object.
320
+ """
321
+ return pd.read_hdf(file_path, *args, **kwargs)
322
+
323
+ @check_suffix([".orc"])
324
+ def read_orc(
325
+ self, file_path: str, *args: Any, **kwargs: Dict[str, Any]
326
+ ) -> "DataFrame":
327
+ r"""Reads an ORC file and returns a DataFrame.
328
+
329
+ Args:
330
+ file_path (str): The path to the ORC file.
331
+ *args (Any): Additional positional arguments.
332
+ **kwargs (Dict[str, Any]): Additional keyword arguments.
333
+
334
+ Returns:
335
+ DataFrame: The DataFrame object.
336
+ """
337
+ return pd.read_orc(file_path, *args, **kwargs)
camel/logger.py CHANGED
@@ -26,18 +26,24 @@ def _configure_library_logging():
26
26
 
27
27
  if not logging.root.handlers and not _logger.handlers:
28
28
  logging.basicConfig(
29
- level=os.environ.get('LOGLEVEL', 'INFO').upper(),
29
+ level=os.environ.get('CAMEL_LOGGING_LEVEL', 'WARNING').upper(),
30
30
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
31
31
  stream=sys.stdout,
32
32
  )
33
33
  logging.setLoggerClass(logging.Logger)
34
- _logger.info("Camel library logging has been configured.")
34
+ _logger.info(
35
+ f"CAMEL library logging has been configured "
36
+ f"(level: {_logger.getEffectiveLevel()}). "
37
+ f"To change level, use set_log_level() or "
38
+ "set CAMEL_LOGGING_LEVEL env var. To disable logging, "
39
+ "set CAMEL_LOGGING_DISABLED=true or use disable_logging()"
40
+ )
35
41
  else:
36
42
  _logger.debug("Existing logger configuration found, using that.")
37
43
 
38
44
 
39
45
  def disable_logging():
40
- r"""Disable all logging for the Camel library.
46
+ r"""Disable all logging for the CAMEL library.
41
47
 
42
48
  This function sets the log level to a value higher than CRITICAL,
43
49
  effectively disabling all log messages, and adds a NullHandler to
@@ -55,7 +61,7 @@ def disable_logging():
55
61
 
56
62
 
57
63
  def enable_logging():
58
- r"""Enable logging for the Camel library.
64
+ r"""Enable logging for the CAMEL library.
59
65
 
60
66
  This function re-enables logging if it was previously disabled,
61
67
  and configures the library logging using the default settings.
@@ -67,7 +73,7 @@ def enable_logging():
67
73
 
68
74
 
69
75
  def set_log_level(level):
70
- r"""Set the logging level for the Camel library.
76
+ r"""Set the logging level for the CAMEL library.
71
77
 
72
78
  Args:
73
79
  level (Union[str, int]): The logging level to set. This can be a string
@@ -11,11 +11,13 @@
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+ from typing import Union
15
+
14
16
  from camel.types import (
15
17
  ChatCompletionAssistantMessageParam,
16
- ChatCompletionFunctionMessageParam,
17
18
  ChatCompletionMessageParam,
18
19
  ChatCompletionSystemMessageParam,
20
+ ChatCompletionToolMessageParam,
19
21
  ChatCompletionUserMessageParam,
20
22
  )
21
23
 
@@ -32,9 +34,13 @@ from .conversion.sharegpt.function_call_formatter import (
32
34
  )
33
35
 
34
36
  OpenAISystemMessage = ChatCompletionSystemMessageParam
35
- OpenAIAssistantMessage = ChatCompletionAssistantMessageParam
37
+ OpenAIAssistantMessage = Union[
38
+ ChatCompletionAssistantMessageParam,
39
+ ChatCompletionToolMessageParam,
40
+ ]
36
41
  OpenAIUserMessage = ChatCompletionUserMessageParam
37
- OpenAIFunctionMessage = ChatCompletionFunctionMessageParam
42
+ OpenAIToolMessageParam = ChatCompletionToolMessageParam
43
+
38
44
  OpenAIMessage = ChatCompletionMessageParam
39
45
 
40
46
 
@@ -45,7 +51,7 @@ __all__ = [
45
51
  'OpenAISystemMessage',
46
52
  'OpenAIAssistantMessage',
47
53
  'OpenAIUserMessage',
48
- 'OpenAIFunctionMessage',
54
+ 'OpenAIToolMessageParam',
49
55
  'OpenAIMessage',
50
56
  'FunctionCallFormatter',
51
57
  'HermesFunctionFormatter',
@@ -69,6 +69,11 @@ class ShareGPTConversation(RootModel):
69
69
  for i in range(1, len(messages)):
70
70
  curr, prev = messages[i], messages[i - 1]
71
71
 
72
+ print("@@@@")
73
+ print(curr)
74
+ print(prev)
75
+ print("@@@@")
76
+
72
77
  if curr.from_ == "tool":
73
78
  if prev.from_ != "gpt" or "<tool_call>" not in prev.value:
74
79
  raise ValueError(
@@ -11,6 +11,7 @@
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+ import json
14
15
  from dataclasses import dataclass
15
16
  from typing import Any, Dict, Optional
16
17
 
@@ -18,8 +19,8 @@ from camel.messages import (
18
19
  BaseMessage,
19
20
  HermesFunctionFormatter,
20
21
  OpenAIAssistantMessage,
21
- OpenAIFunctionMessage,
22
22
  OpenAIMessage,
23
+ OpenAIToolMessageParam,
23
24
  )
24
25
  from camel.messages.conversion import (
25
26
  ShareGPTMessage,
@@ -44,11 +45,14 @@ class FunctionCallingMessage(BaseMessage):
44
45
  function. (default: :obj:`None`)
45
46
  result (Optional[Any]): The result of function execution.
46
47
  (default: :obj:`None`)
48
+ tool_call_id (Optional[str]): The ID of the tool call, if available.
49
+ (default: :obj:`None`)
47
50
  """
48
51
 
49
52
  func_name: Optional[str] = None
50
53
  args: Optional[Dict] = None
51
54
  result: Optional[Any] = None
55
+ tool_call_id: Optional[str] = None
52
56
 
53
57
  def to_openai_message(
54
58
  self,
@@ -66,7 +70,7 @@ class FunctionCallingMessage(BaseMessage):
66
70
  if role_at_backend == OpenAIBackendRole.ASSISTANT:
67
71
  return self.to_openai_assistant_message()
68
72
  elif role_at_backend == OpenAIBackendRole.FUNCTION:
69
- return self.to_openai_function_message()
73
+ return self.to_openai_tool_message()
70
74
  else:
71
75
  raise ValueError(f"Unsupported role: {role_at_backend}.")
72
76
 
@@ -120,24 +124,29 @@ class FunctionCallingMessage(BaseMessage):
120
124
  " due to missing function name or arguments."
121
125
  )
122
126
 
123
- msg_dict: OpenAIAssistantMessage = {
127
+ return {
124
128
  "role": "assistant",
125
- "content": self.content,
126
- "function_call": {
127
- "name": self.func_name,
128
- "arguments": str(self.args),
129
- },
129
+ "content": self.content or "",
130
+ "tool_calls": [
131
+ {
132
+ "id": self.tool_call_id or "null",
133
+ "type": "function",
134
+ "function": {
135
+ "name": self.func_name,
136
+ "arguments": json.dumps(self.args),
137
+ },
138
+ }
139
+ ],
130
140
  }
131
141
 
132
- return msg_dict
133
-
134
- def to_openai_function_message(self) -> OpenAIFunctionMessage:
135
- r"""Converts the message to an :obj:`OpenAIMessage` object
136
- with the role being "function".
142
+ def to_openai_tool_message(self) -> OpenAIToolMessageParam:
143
+ r"""Converts the message to an :obj:`OpenAIToolMessageParam` object
144
+ with the role being "tool".
137
145
 
138
146
  Returns:
139
- OpenAIMessage: The converted :obj:`OpenAIMessage` object
140
- with its role being "function".
147
+ OpenAIToolMessageParam: The converted
148
+ :obj:`OpenAIToolMessageParam` object with its role being
149
+ "tool".
141
150
  """
142
151
  if not self.func_name:
143
152
  raise ValueError(
@@ -145,11 +154,10 @@ class FunctionCallingMessage(BaseMessage):
145
154
  " due to missing function name."
146
155
  )
147
156
 
148
- result_content = {"result": {str(self.result)}}
149
- msg_dict: OpenAIFunctionMessage = {
150
- "role": "function",
151
- "name": self.func_name,
152
- "content": f'{result_content}',
153
- }
157
+ result_content = json.dumps(self.result)
154
158
 
155
- return msg_dict
159
+ return {
160
+ "role": "tool",
161
+ "content": result_content,
162
+ "tool_call_id": self.tool_call_id or "null",
163
+ }
camel/models/__init__.py CHANGED
@@ -19,6 +19,7 @@ from .deepseek_model import DeepSeekModel
19
19
  from .fish_audio_model import FishAudioModel
20
20
  from .gemini_model import GeminiModel
21
21
  from .groq_model import GroqModel
22
+ from .internlm_model import InternLMModel
22
23
  from .litellm_model import LiteLLMModel
23
24
  from .mistral_model import MistralModel
24
25
  from .model_factory import ModelFactory
@@ -68,4 +69,5 @@ __all__ = [
68
69
  'ModelProcessingError',
69
70
  'DeepSeekModel',
70
71
  'FishAudioModel',
72
+ 'InternLMModel',
71
73
  ]
@@ -12,7 +12,7 @@
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
  import os
15
- from typing import Any, Dict, List, Literal, Optional, Union
15
+ from typing import Any, Dict, List, Optional, Union
16
16
 
17
17
  from camel.configs import ANTHROPIC_API_PARAMS, AnthropicConfig
18
18
  from camel.messages import OpenAIMessage
@@ -45,6 +45,11 @@ class AnthropicModel(BaseModelBackend):
45
45
  will be used. (default: :obj:`None`)
46
46
  """
47
47
 
48
+ @api_keys_required(
49
+ [
50
+ ("api_key", "ANTHROPIC_API_KEY"),
51
+ ]
52
+ )
48
53
  @dependencies_required('anthropic')
49
54
  def __init__(
50
55
  self,
@@ -97,28 +102,6 @@ class AnthropicModel(BaseModelBackend):
97
102
  self._token_counter = AnthropicTokenCounter(self.model_type)
98
103
  return self._token_counter
99
104
 
100
- @dependencies_required('anthropic')
101
- def count_tokens_from_prompt(
102
- self, prompt: str, role: Literal["user", "assistant"]
103
- ) -> int:
104
- r"""Count the number of tokens from a prompt.
105
-
106
- Args:
107
- prompt (str): The prompt string.
108
- role (Literal["user", "assistant"]): The role of the message
109
- sender, either "user" or "assistant".
110
-
111
- Returns:
112
- int: The number of tokens in the prompt.
113
- """
114
- from anthropic.types.beta import BetaMessageParam
115
-
116
- return self.client.beta.messages.count_tokens(
117
- messages=[BetaMessageParam(content=prompt, role=role)],
118
- model=self.model_type,
119
- ).input_tokens
120
-
121
- @api_keys_required("ANTHROPIC_API_KEY")
122
105
  def run(
123
106
  self,
124
107
  messages: List[OpenAIMessage],
@@ -24,7 +24,7 @@ from camel.types import (
24
24
  ChatCompletionChunk,
25
25
  ModelType,
26
26
  )
27
- from camel.utils import BaseTokenCounter, OpenAITokenCounter, api_keys_required
27
+ from camel.utils import BaseTokenCounter, OpenAITokenCounter
28
28
 
29
29
 
30
30
  class AzureOpenAIModel(BaseModelBackend):
@@ -107,7 +107,6 @@ class AzureOpenAIModel(BaseModelBackend):
107
107
  self._token_counter = OpenAITokenCounter(self.model_type)
108
108
  return self._token_counter
109
109
 
110
- @api_keys_required("AZURE_OPENAI_API_KEY", "AZURE_API_VERSION")
111
110
  def run(
112
111
  self,
113
112
  messages: List[OpenAIMessage],
@@ -43,6 +43,11 @@ except (ImportError, AttributeError):
43
43
  class CohereModel(BaseModelBackend):
44
44
  r"""Cohere API in a unified BaseModelBackend interface."""
45
45
 
46
+ @api_keys_required(
47
+ [
48
+ ("api_key", 'COHERE_API_KEY'),
49
+ ]
50
+ )
46
51
  def __init__(
47
52
  self,
48
53
  model_type: Union[ModelType, str],
@@ -210,7 +215,6 @@ class CohereModel(BaseModelBackend):
210
215
  )
211
216
  return self._token_counter
212
217
 
213
- @api_keys_required("COHERE_API_KEY")
214
218
  def run(self, messages: List[OpenAIMessage]) -> ChatCompletion:
215
219
  r"""Runs inference of Cohere chat completion.
216
220
 
@@ -224,6 +228,14 @@ class CohereModel(BaseModelBackend):
224
228
 
225
229
  cohere_messages = self._to_cohere_chatmessage(messages)
226
230
 
231
+ # Removing 'strict': True from the dictionary for
232
+ # cohere client
233
+ if self.model_config_dict.get('tools') is not None:
234
+ for tool in self.model_config_dict.get('tools', []):
235
+ function_dict = tool.get('function', {})
236
+ if 'strict' in function_dict:
237
+ del function_dict['strict']
238
+
227
239
  try:
228
240
  response = self._client.chat(
229
241
  messages=cohere_messages,
@@ -50,6 +50,11 @@ class DeepSeekModel(BaseModelBackend):
50
50
  https://api-docs.deepseek.com/
51
51
  """
52
52
 
53
+ @api_keys_required(
54
+ [
55
+ ("api_key", "DEEPSEEK_API_KEY"),
56
+ ]
57
+ )
53
58
  def __init__(
54
59
  self,
55
60
  model_type: Union[ModelType, str],
@@ -90,7 +95,6 @@ class DeepSeekModel(BaseModelBackend):
90
95
  )
91
96
  return self._token_counter
92
97
 
93
- @api_keys_required("DEEPSEEK_API_KEY")
94
98
  def run(
95
99
  self,
96
100
  messages: List[OpenAIMessage],