camel-ai 0.2.73a4__py3-none-any.whl → 0.2.80a2__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.
Files changed (173) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_utils.py +38 -0
  3. camel/agents/chat_agent.py +2217 -519
  4. camel/agents/mcp_agent.py +30 -27
  5. camel/configs/__init__.py +15 -0
  6. camel/configs/aihubmix_config.py +88 -0
  7. camel/configs/amd_config.py +70 -0
  8. camel/configs/cometapi_config.py +104 -0
  9. camel/configs/minimax_config.py +93 -0
  10. camel/configs/nebius_config.py +103 -0
  11. camel/data_collectors/alpaca_collector.py +15 -6
  12. camel/datasets/base_generator.py +39 -10
  13. camel/environments/single_step.py +28 -3
  14. camel/environments/tic_tac_toe.py +1 -1
  15. camel/interpreters/__init__.py +2 -0
  16. camel/interpreters/docker/Dockerfile +3 -12
  17. camel/interpreters/e2b_interpreter.py +34 -1
  18. camel/interpreters/microsandbox_interpreter.py +395 -0
  19. camel/loaders/__init__.py +11 -2
  20. camel/loaders/chunkr_reader.py +9 -0
  21. camel/memories/agent_memories.py +48 -4
  22. camel/memories/base.py +26 -0
  23. camel/memories/blocks/chat_history_block.py +122 -4
  24. camel/memories/context_creators/score_based.py +25 -384
  25. camel/memories/records.py +88 -8
  26. camel/messages/base.py +153 -34
  27. camel/models/__init__.py +10 -0
  28. camel/models/aihubmix_model.py +83 -0
  29. camel/models/aiml_model.py +1 -16
  30. camel/models/amd_model.py +101 -0
  31. camel/models/anthropic_model.py +6 -19
  32. camel/models/aws_bedrock_model.py +2 -33
  33. camel/models/azure_openai_model.py +114 -89
  34. camel/models/base_audio_model.py +3 -1
  35. camel/models/base_model.py +32 -14
  36. camel/models/cohere_model.py +1 -16
  37. camel/models/cometapi_model.py +83 -0
  38. camel/models/crynux_model.py +1 -16
  39. camel/models/deepseek_model.py +1 -16
  40. camel/models/fish_audio_model.py +6 -0
  41. camel/models/gemini_model.py +36 -18
  42. camel/models/groq_model.py +1 -17
  43. camel/models/internlm_model.py +1 -16
  44. camel/models/litellm_model.py +1 -16
  45. camel/models/lmstudio_model.py +1 -17
  46. camel/models/minimax_model.py +83 -0
  47. camel/models/mistral_model.py +1 -16
  48. camel/models/model_factory.py +27 -1
  49. camel/models/modelscope_model.py +1 -16
  50. camel/models/moonshot_model.py +105 -24
  51. camel/models/nebius_model.py +83 -0
  52. camel/models/nemotron_model.py +0 -5
  53. camel/models/netmind_model.py +1 -16
  54. camel/models/novita_model.py +1 -16
  55. camel/models/nvidia_model.py +1 -16
  56. camel/models/ollama_model.py +4 -19
  57. camel/models/openai_compatible_model.py +62 -41
  58. camel/models/openai_model.py +62 -57
  59. camel/models/openrouter_model.py +1 -17
  60. camel/models/ppio_model.py +1 -16
  61. camel/models/qianfan_model.py +1 -16
  62. camel/models/qwen_model.py +1 -16
  63. camel/models/reka_model.py +1 -16
  64. camel/models/samba_model.py +34 -47
  65. camel/models/sglang_model.py +64 -31
  66. camel/models/siliconflow_model.py +1 -16
  67. camel/models/stub_model.py +0 -4
  68. camel/models/togetherai_model.py +1 -16
  69. camel/models/vllm_model.py +1 -16
  70. camel/models/volcano_model.py +0 -17
  71. camel/models/watsonx_model.py +1 -16
  72. camel/models/yi_model.py +1 -16
  73. camel/models/zhipuai_model.py +60 -16
  74. camel/parsers/__init__.py +18 -0
  75. camel/parsers/mcp_tool_call_parser.py +176 -0
  76. camel/retrievers/auto_retriever.py +1 -0
  77. camel/runtimes/daytona_runtime.py +11 -12
  78. camel/societies/__init__.py +2 -0
  79. camel/societies/workforce/__init__.py +2 -0
  80. camel/societies/workforce/events.py +122 -0
  81. camel/societies/workforce/prompts.py +146 -66
  82. camel/societies/workforce/role_playing_worker.py +15 -11
  83. camel/societies/workforce/single_agent_worker.py +302 -65
  84. camel/societies/workforce/structured_output_handler.py +30 -18
  85. camel/societies/workforce/task_channel.py +163 -27
  86. camel/societies/workforce/utils.py +107 -13
  87. camel/societies/workforce/workflow_memory_manager.py +772 -0
  88. camel/societies/workforce/workforce.py +1949 -579
  89. camel/societies/workforce/workforce_callback.py +74 -0
  90. camel/societies/workforce/workforce_logger.py +168 -145
  91. camel/societies/workforce/workforce_metrics.py +33 -0
  92. camel/storages/key_value_storages/json.py +15 -2
  93. camel/storages/key_value_storages/mem0_cloud.py +48 -47
  94. camel/storages/object_storages/google_cloud.py +1 -1
  95. camel/storages/vectordb_storages/oceanbase.py +13 -13
  96. camel/storages/vectordb_storages/qdrant.py +3 -3
  97. camel/storages/vectordb_storages/tidb.py +8 -6
  98. camel/tasks/task.py +4 -3
  99. camel/toolkits/__init__.py +20 -7
  100. camel/toolkits/aci_toolkit.py +45 -0
  101. camel/toolkits/base.py +6 -4
  102. camel/toolkits/code_execution.py +28 -1
  103. camel/toolkits/context_summarizer_toolkit.py +684 -0
  104. camel/toolkits/dappier_toolkit.py +5 -1
  105. camel/toolkits/dingtalk.py +1135 -0
  106. camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
  107. camel/toolkits/excel_toolkit.py +1 -1
  108. camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +430 -36
  109. camel/toolkits/function_tool.py +13 -3
  110. camel/toolkits/github_toolkit.py +104 -17
  111. camel/toolkits/gmail_toolkit.py +1839 -0
  112. camel/toolkits/google_calendar_toolkit.py +38 -4
  113. camel/toolkits/google_drive_mcp_toolkit.py +12 -31
  114. camel/toolkits/hybrid_browser_toolkit/config_loader.py +15 -0
  115. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +77 -8
  116. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +884 -88
  117. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  118. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +5 -612
  119. camel/toolkits/hybrid_browser_toolkit/ts/package.json +0 -1
  120. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +959 -89
  121. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +9 -2
  122. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +281 -213
  123. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  124. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  125. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  126. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +23 -3
  127. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +72 -7
  128. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +582 -132
  129. camel/toolkits/hybrid_browser_toolkit_py/actions.py +158 -0
  130. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +55 -8
  131. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +43 -0
  132. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +321 -8
  133. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +10 -4
  134. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +45 -4
  135. camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +151 -53
  136. camel/toolkits/klavis_toolkit.py +5 -1
  137. camel/toolkits/markitdown_toolkit.py +27 -1
  138. camel/toolkits/math_toolkit.py +64 -10
  139. camel/toolkits/mcp_toolkit.py +366 -71
  140. camel/toolkits/memory_toolkit.py +5 -1
  141. camel/toolkits/message_integration.py +18 -13
  142. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  143. camel/toolkits/note_taking_toolkit.py +19 -10
  144. camel/toolkits/notion_mcp_toolkit.py +16 -26
  145. camel/toolkits/openbb_toolkit.py +5 -1
  146. camel/toolkits/origene_mcp_toolkit.py +8 -49
  147. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  148. camel/toolkits/resend_toolkit.py +168 -0
  149. camel/toolkits/search_toolkit.py +264 -91
  150. camel/toolkits/slack_toolkit.py +64 -10
  151. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  152. camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
  153. camel/toolkits/terminal_toolkit/utils.py +532 -0
  154. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  155. camel/toolkits/video_analysis_toolkit.py +17 -11
  156. camel/toolkits/wechat_official_toolkit.py +483 -0
  157. camel/toolkits/zapier_toolkit.py +5 -1
  158. camel/types/__init__.py +2 -2
  159. camel/types/enums.py +274 -7
  160. camel/types/openai_types.py +2 -2
  161. camel/types/unified_model_type.py +15 -0
  162. camel/utils/commons.py +36 -5
  163. camel/utils/constants.py +3 -0
  164. camel/utils/context_utils.py +1003 -0
  165. camel/utils/mcp.py +138 -4
  166. camel/utils/token_counting.py +43 -20
  167. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +223 -83
  168. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +170 -141
  169. camel/loaders/pandas_reader.py +0 -368
  170. camel/toolkits/openai_agent_toolkit.py +0 -135
  171. camel/toolkits/terminal_toolkit.py +0 -1550
  172. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
  173. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
@@ -17,7 +17,7 @@ from typing import Any, Dict, List, Optional, Type, Union
17
17
  from openai import AsyncStream, Stream
18
18
  from pydantic import BaseModel
19
19
 
20
- from camel.configs import Gemini_API_PARAMS, GeminiConfig
20
+ from camel.configs import GeminiConfig
21
21
  from camel.messages import OpenAIMessage
22
22
  from camel.models.openai_compatible_model import OpenAICompatibleModel
23
23
  from camel.types import (
@@ -112,13 +112,46 @@ class GeminiModel(OpenAICompatibleModel):
112
112
 
113
113
  def _process_messages(self, messages) -> List[OpenAIMessage]:
114
114
  r"""Process the messages for Gemini API to ensure no empty content,
115
- which is not accepted by Gemini.
115
+ which is not accepted by Gemini. Also preserves thought signatures
116
+ required for Gemini 3 Pro function calling and adds fallback signatures
117
+ when they are missing.
116
118
  """
119
+ import copy
120
+
117
121
  processed_messages = []
118
122
  for msg in messages:
119
- msg_copy = msg.copy()
123
+ # Use deep copy to preserve all nested structures including
124
+ # thought signatures in extra_content
125
+ msg_copy = copy.deepcopy(msg)
120
126
  if 'content' in msg_copy and msg_copy['content'] == '':
121
127
  msg_copy['content'] = 'null'
128
+
129
+ # Handle missing thought signatures for function calls
130
+ # This is required for Gemini 3 Pro compatibility
131
+ # TODO: support multi round thought signatures
132
+ if (
133
+ msg_copy.get('role') == 'assistant'
134
+ and 'tool_calls' in msg_copy
135
+ and isinstance(msg_copy['tool_calls'], list)
136
+ ):
137
+ for i, tool_call in enumerate(msg_copy['tool_calls']):
138
+ # Check if this is the first tool call in a parallel set
139
+ # or any tool call that's missing a thought signature
140
+ if i == 0: # First tool call should have a signature
141
+ # Check if thought signature is missing
142
+ extra_content = tool_call.get('extra_content', {})
143
+ google_content = extra_content.get('google', {})
144
+
145
+ if 'thought_signature' not in google_content:
146
+ # Add fallback signature for missing signatures
147
+ if 'extra_content' not in tool_call:
148
+ tool_call['extra_content'] = {}
149
+ if 'google' not in tool_call['extra_content']:
150
+ tool_call['extra_content']['google'] = {}
151
+ tool_call['extra_content']['google'][
152
+ 'thought_signature'
153
+ ] = "skip_thought_signature_validator"
154
+
122
155
  processed_messages.append(msg_copy)
123
156
  return processed_messages
124
157
 
@@ -335,18 +368,3 @@ class GeminiModel(OpenAICompatibleModel):
335
368
  model=self.model_type,
336
369
  **request_config,
337
370
  )
338
-
339
- def check_model_config(self):
340
- r"""Check whether the model configuration contains any
341
- unexpected arguments to Gemini API.
342
-
343
- Raises:
344
- ValueError: If the model configuration dictionary contains any
345
- unexpected arguments to Gemini API.
346
- """
347
- for param in self.model_config_dict:
348
- if param not in Gemini_API_PARAMS:
349
- raise ValueError(
350
- f"Unexpected argument `{param}` is "
351
- "input into Gemini model backend."
352
- )
@@ -14,7 +14,7 @@
14
14
  import os
15
15
  from typing import Any, Dict, Optional, Union
16
16
 
17
- from camel.configs import GROQ_API_PARAMS, GroqConfig
17
+ from camel.configs import GroqConfig
18
18
  from camel.models.openai_compatible_model import OpenAICompatibleModel
19
19
  from camel.types import ModelType
20
20
  from camel.utils import (
@@ -80,19 +80,3 @@ class GroqModel(OpenAICompatibleModel):
80
80
  max_retries=max_retries,
81
81
  **kwargs,
82
82
  )
83
-
84
- def check_model_config(self):
85
- r"""Check whether the model configuration contains any unexpected
86
- arguments to Groq API. But Groq API does not have any additional
87
- arguments to check.
88
-
89
- Raises:
90
- ValueError: If the model configuration dictionary contains any
91
- unexpected arguments to Groq API.
92
- """
93
- for param in self.model_config_dict:
94
- if param not in GROQ_API_PARAMS:
95
- raise ValueError(
96
- f"Unexpected argument `{param}` is "
97
- "input into Groq model backend."
98
- )
@@ -18,7 +18,7 @@ from typing import Any, Dict, List, Optional, Type, Union
18
18
  from openai import AsyncStream
19
19
  from pydantic import BaseModel
20
20
 
21
- from camel.configs import INTERNLM_API_PARAMS, InternLMConfig
21
+ from camel.configs import InternLMConfig
22
22
  from camel.messages import OpenAIMessage
23
23
  from camel.models.openai_compatible_model import OpenAICompatibleModel
24
24
  from camel.types import (
@@ -101,18 +101,3 @@ class InternLMModel(OpenAICompatibleModel):
101
101
  tools: Optional[List[Dict[str, Any]]] = None,
102
102
  ) -> Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
103
103
  raise NotImplementedError("InternLM does not support async inference.")
104
-
105
- def check_model_config(self):
106
- r"""Check whether the model configuration contains any
107
- unexpected arguments to InternLM API.
108
-
109
- Raises:
110
- ValueError: If the model configuration dictionary contains any
111
- unexpected arguments to InternLM API.
112
- """
113
- for param in self.model_config_dict:
114
- if param not in INTERNLM_API_PARAMS:
115
- raise ValueError(
116
- f"Unexpected argument `{param}` is "
117
- "input into InternLM model backend."
118
- )
@@ -17,7 +17,7 @@ from typing import Any, Dict, List, Optional, Type, Union
17
17
 
18
18
  from pydantic import BaseModel
19
19
 
20
- from camel.configs import LITELLM_API_PARAMS, LiteLLMConfig
20
+ from camel.configs import LiteLLMConfig
21
21
  from camel.messages import OpenAIMessage
22
22
  from camel.models import BaseModelBackend
23
23
  from camel.types import ChatCompletion, ModelType
@@ -217,18 +217,3 @@ class LiteLLMModel(BaseModelBackend):
217
217
  usage=response.usage,
218
218
  )
219
219
  return response
220
-
221
- def check_model_config(self):
222
- r"""Check whether the model configuration contains any unexpected
223
- arguments to LiteLLM API.
224
-
225
- Raises:
226
- ValueError: If the model configuration dictionary contains any
227
- unexpected arguments.
228
- """
229
- for param in self.model_config_dict:
230
- if param not in LITELLM_API_PARAMS:
231
- raise ValueError(
232
- f"Unexpected argument `{param}` is "
233
- "input into LiteLLM model backend."
234
- )
@@ -14,7 +14,7 @@
14
14
  import os
15
15
  from typing import Any, Dict, Optional, Union
16
16
 
17
- from camel.configs import LMSTUDIO_API_PARAMS, LMStudioConfig
17
+ from camel.configs import LMStudioConfig
18
18
  from camel.models.openai_compatible_model import OpenAICompatibleModel
19
19
  from camel.types import ModelType
20
20
  from camel.utils import BaseTokenCounter
@@ -77,19 +77,3 @@ class LMStudioModel(OpenAICompatibleModel):
77
77
  max_retries=max_retries,
78
78
  **kwargs,
79
79
  )
80
-
81
- def check_model_config(self):
82
- r"""Check whether the model configuration contains any unexpected
83
- arguments to LMStudio API. But LMStudio API does not have any
84
- additional arguments to check.
85
-
86
- Raises:
87
- ValueError: If the model configuration dictionary contains any
88
- unexpected arguments to LMStudio API.
89
- """
90
- for param in self.model_config_dict:
91
- if param not in LMSTUDIO_API_PARAMS:
92
- raise ValueError(
93
- f"Unexpected argument `{param}` is "
94
- "input into LMStudio model backend."
95
- )
@@ -0,0 +1,83 @@
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 typing import Any, Dict, Optional, Union
16
+
17
+ from camel.configs import MinimaxConfig
18
+ from camel.models.openai_compatible_model import OpenAICompatibleModel
19
+ from camel.types import ModelType
20
+ from camel.utils import (
21
+ BaseTokenCounter,
22
+ api_keys_required,
23
+ )
24
+
25
+
26
+ class MinimaxModel(OpenAICompatibleModel):
27
+ r"""LLM API served by Minimax in a unified OpenAICompatibleModel
28
+ interface.
29
+
30
+ Args:
31
+ model_type (Union[ModelType, str]): Model for which a backend is
32
+ created.
33
+ model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
34
+ that will be fed into:obj:`openai.ChatCompletion.create()`.
35
+ If:obj:`None`, :obj:`MinimaxConfig().as_dict()` will be used.
36
+ (default: :obj:`None`)
37
+ api_key (Optional[str], optional): The API key for authenticating
38
+ with the Minimax service. (default: :obj:`None`).
39
+ url (Optional[str], optional): The url to the Minimax M2 service.
40
+ (default: :obj:`None`)
41
+ token_counter (Optional[BaseTokenCounter], optional): Token counter to
42
+ use for the model. If not provided, :obj:`OpenAITokenCounter(
43
+ ModelType.GPT_4O_MINI)` will be used.
44
+ (default: :obj:`None`)
45
+ timeout (Optional[float], optional): The timeout value in seconds for
46
+ API calls. If not provided, will fall back to the MODEL_TIMEOUT
47
+ environment variable or default to 180 seconds.
48
+ (default: :obj:`None`)
49
+ max_retries (int, optional): Maximum number of retries for API calls.
50
+ (default: :obj:`3`)
51
+ **kwargs (Any): Additional arguments to pass to the client
52
+ initialization.
53
+ """
54
+
55
+ @api_keys_required([("api_key", "MINIMAX_API_KEY")])
56
+ def __init__(
57
+ self,
58
+ model_type: Union[ModelType, str],
59
+ model_config_dict: Optional[Dict[str, Any]] = None,
60
+ api_key: Optional[str] = None,
61
+ url: Optional[str] = None,
62
+ token_counter: Optional[BaseTokenCounter] = None,
63
+ timeout: Optional[float] = None,
64
+ max_retries: int = 3,
65
+ **kwargs: Any,
66
+ ) -> None:
67
+ if model_config_dict is None:
68
+ model_config_dict = MinimaxConfig().as_dict()
69
+ api_key = api_key or os.environ.get("MINIMAX_API_KEY")
70
+ url = url or os.environ.get(
71
+ "MINIMAX_API_BASE_URL", "https://api.minimaxi.com/v1"
72
+ )
73
+ timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
74
+ super().__init__(
75
+ model_type=model_type,
76
+ model_config_dict=model_config_dict,
77
+ api_key=api_key,
78
+ url=url,
79
+ token_counter=token_counter,
80
+ timeout=timeout,
81
+ max_retries=max_retries,
82
+ **kwargs,
83
+ )
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
24
24
 
25
25
  from openai import AsyncStream
26
26
 
27
- from camel.configs import MISTRAL_API_PARAMS, MistralConfig
27
+ from camel.configs import MistralConfig
28
28
  from camel.logger import get_logger
29
29
  from camel.messages import OpenAIMessage
30
30
  from camel.models import BaseModelBackend
@@ -414,21 +414,6 @@ class MistralModel(BaseModelBackend):
414
414
 
415
415
  return request_config
416
416
 
417
- def check_model_config(self):
418
- r"""Check whether the model configuration contains any
419
- unexpected arguments to Mistral API.
420
-
421
- Raises:
422
- ValueError: If the model configuration dictionary contains any
423
- unexpected arguments to Mistral API.
424
- """
425
- for param in self.model_config_dict:
426
- if param not in MISTRAL_API_PARAMS:
427
- raise ValueError(
428
- f"Unexpected argument `{param}` is "
429
- "input into Mistral model backend."
430
- )
431
-
432
417
  @property
433
418
  def stream(self) -> bool:
434
419
  r"""Returns whether the model is in stream mode, which sends partial
@@ -13,14 +13,17 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
  import json
15
15
  import os
16
- from typing import ClassVar, Dict, Optional, Type, Union
16
+ from typing import Any, ClassVar, Dict, Optional, Type, Union
17
17
 
18
+ from camel.models.aihubmix_model import AihubMixModel
18
19
  from camel.models.aiml_model import AIMLModel
20
+ from camel.models.amd_model import AMDModel
19
21
  from camel.models.anthropic_model import AnthropicModel
20
22
  from camel.models.aws_bedrock_model import AWSBedrockModel
21
23
  from camel.models.azure_openai_model import AzureOpenAIModel
22
24
  from camel.models.base_model import BaseModelBackend
23
25
  from camel.models.cohere_model import CohereModel
26
+ from camel.models.cometapi_model import CometAPIModel
24
27
  from camel.models.crynux_model import CrynuxModel
25
28
  from camel.models.deepseek_model import DeepSeekModel
26
29
  from camel.models.gemini_model import GeminiModel
@@ -28,9 +31,11 @@ from camel.models.groq_model import GroqModel
28
31
  from camel.models.internlm_model import InternLMModel
29
32
  from camel.models.litellm_model import LiteLLMModel
30
33
  from camel.models.lmstudio_model import LMStudioModel
34
+ from camel.models.minimax_model import MinimaxModel
31
35
  from camel.models.mistral_model import MistralModel
32
36
  from camel.models.modelscope_model import ModelScopeModel
33
37
  from camel.models.moonshot_model import MoonshotModel
38
+ from camel.models.nebius_model import NebiusModel
34
39
  from camel.models.netmind_model import NetmindModel
35
40
  from camel.models.novita_model import NovitaModel
36
41
  from camel.models.nvidia_model import NvidiaModel
@@ -76,6 +81,7 @@ class ModelFactory:
76
81
  ModelPlatformType.AWS_BEDROCK: AWSBedrockModel,
77
82
  ModelPlatformType.NVIDIA: NvidiaModel,
78
83
  ModelPlatformType.SILICONFLOW: SiliconFlowModel,
84
+ ModelPlatformType.AMD: AMDModel,
79
85
  ModelPlatformType.AIML: AIMLModel,
80
86
  ModelPlatformType.VOLCANO: VolcanoModel,
81
87
  ModelPlatformType.NETMIND: NetmindModel,
@@ -83,7 +89,10 @@ class ModelFactory:
83
89
  ModelPlatformType.AZURE: AzureOpenAIModel,
84
90
  ModelPlatformType.ANTHROPIC: AnthropicModel,
85
91
  ModelPlatformType.GROQ: GroqModel,
92
+ ModelPlatformType.COMETAPI: CometAPIModel,
93
+ ModelPlatformType.NEBIUS: NebiusModel,
86
94
  ModelPlatformType.LMSTUDIO: LMStudioModel,
95
+ ModelPlatformType.MINIMAX: MinimaxModel,
87
96
  ModelPlatformType.OPENROUTER: OpenRouterModel,
88
97
  ModelPlatformType.ZHIPU: ZhipuAIModel,
89
98
  ModelPlatformType.GEMINI: GeminiModel,
@@ -101,6 +110,7 @@ class ModelFactory:
101
110
  ModelPlatformType.WATSONX: WatsonXModel,
102
111
  ModelPlatformType.QIANFAN: QianfanModel,
103
112
  ModelPlatformType.CRYNUX: CrynuxModel,
113
+ ModelPlatformType.AIHUBMIX: AihubMixModel,
104
114
  }
105
115
 
106
116
  @staticmethod
@@ -113,6 +123,8 @@ class ModelFactory:
113
123
  url: Optional[str] = None,
114
124
  timeout: Optional[float] = None,
115
125
  max_retries: int = 3,
126
+ client: Optional[Any] = None,
127
+ async_client: Optional[Any] = None,
116
128
  **kwargs,
117
129
  ) -> BaseModelBackend:
118
130
  r"""Creates an instance of `BaseModelBackend` of the specified type.
@@ -139,6 +151,14 @@ class ModelFactory:
139
151
  for API calls. (default: :obj:`None`)
140
152
  max_retries (int, optional): Maximum number of retries
141
153
  for API calls. (default: :obj:`3`)
154
+ client (Optional[Any], optional): A custom synchronous client
155
+ instance. Supported by models that use OpenAI-compatible APIs
156
+ . The client should implement the appropriate client interface
157
+ for the platform. (default: :obj:`None`)
158
+ async_client (Optional[Any], optional): A custom asynchronous
159
+ client instance. Supported by models that use OpenAI-compatible
160
+ APIs. The client should implement the appropriate async client
161
+ interface for the platform. (default: :obj:`None`)
142
162
  **kwargs: Additional model-specific parameters that will be passed
143
163
  to the model constructor. For example, Azure OpenAI models may
144
164
  require `api_version`, `azure_deployment_name`,
@@ -184,6 +204,12 @@ class ModelFactory:
184
204
  if model_class is None:
185
205
  raise ValueError(f"Unknown model platform `{model_platform}`")
186
206
 
207
+ # Pass client and async_client via kwargs if provided
208
+ if client is not None:
209
+ kwargs['client'] = client
210
+ if async_client is not None:
211
+ kwargs['async_client'] = async_client
212
+
187
213
  return model_class(
188
214
  model_type=model_type,
189
215
  model_config_dict=model_config_dict,
@@ -18,7 +18,7 @@ from typing import Any, Dict, List, Optional, Union
18
18
 
19
19
  from openai import AsyncStream, Stream
20
20
 
21
- from camel.configs import MODELSCOPE_API_PARAMS, ModelScopeConfig
21
+ from camel.configs import ModelScopeConfig
22
22
  from camel.messages import OpenAIMessage
23
23
  from camel.models.openai_compatible_model import OpenAICompatibleModel
24
24
  from camel.types import (
@@ -261,18 +261,3 @@ class ModelScopeModel(OpenAICompatibleModel):
261
261
  **request_config,
262
262
  )
263
263
  return self._post_handle_response(response)
264
-
265
- def check_model_config(self):
266
- r"""Check whether the model configuration contains any
267
- unexpected arguments to ModelScope API.
268
-
269
- Raises:
270
- ValueError: If the model configuration dictionary contains any
271
- unexpected arguments to ModelScope API.
272
- """
273
- for param in self.model_config_dict:
274
- if param not in MODELSCOPE_API_PARAMS:
275
- raise ValueError(
276
- f"Unexpected argument `{param}` is "
277
- "input into ModelScope model backend."
278
- )
@@ -12,13 +12,15 @@
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
+ import copy
15
16
  import os
16
17
  from typing import Any, Dict, List, Optional, Type, Union
17
18
 
18
19
  from openai import AsyncStream
19
20
  from pydantic import BaseModel
20
21
 
21
- from camel.configs import MOONSHOT_API_PARAMS, MoonshotConfig
22
+ from camel.configs import MoonshotConfig
23
+ from camel.logger import get_logger
22
24
  from camel.messages import OpenAIMessage
23
25
  from camel.models._utils import try_modify_message_with_format
24
26
  from camel.models.openai_compatible_model import OpenAICompatibleModel
@@ -34,6 +36,8 @@ from camel.utils import (
34
36
  update_langfuse_trace,
35
37
  )
36
38
 
39
+ logger = get_logger(__name__)
40
+
37
41
  if os.environ.get("LANGFUSE_ENABLED", "False").lower() == "true":
38
42
  try:
39
43
  from langfuse.decorators import observe
@@ -61,7 +65,9 @@ class MoonshotModel(OpenAICompatibleModel):
61
65
  api_key (Optional[str], optional): The API key for authenticating with
62
66
  the Moonshot service. (default: :obj:`None`)
63
67
  url (Optional[str], optional): The url to the Moonshot service.
64
- (default: :obj:`https://api.moonshot.cn/v1`)
68
+ For Chinese users, use :obj:`https://api.moonshot.cn/v1`.
69
+ For overseas users, the default endpoint will be used.
70
+ (default: :obj:`https://api.moonshot.ai/v1`)
65
71
  token_counter (Optional[BaseTokenCounter], optional): Token counter to
66
72
  use for the model. If not provided, :obj:`OpenAITokenCounter(
67
73
  ModelType.GPT_4)` will be used.
@@ -91,10 +97,12 @@ class MoonshotModel(OpenAICompatibleModel):
91
97
  if model_config_dict is None:
92
98
  model_config_dict = MoonshotConfig().as_dict()
93
99
  api_key = api_key or os.environ.get("MOONSHOT_API_KEY")
94
- url = url or os.environ.get(
95
- "MOONSHOT_API_BASE_URL",
96
- "https://api.moonshot.cn/v1",
97
- )
100
+ # Preserve default URL if not provided
101
+ if url is None:
102
+ url = (
103
+ os.environ.get("MOONSHOT_API_BASE_URL")
104
+ or "https://api.moonshot.ai/v1"
105
+ )
98
106
  timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
99
107
  super().__init__(
100
108
  model_type=model_type,
@@ -126,12 +134,12 @@ class MoonshotModel(OpenAICompatibleModel):
126
134
  Returns:
127
135
  Dict[str, Any]: The prepared request configuration.
128
136
  """
129
- import copy
130
-
131
137
  request_config = copy.deepcopy(self.model_config_dict)
132
138
 
133
139
  if tools:
134
- request_config["tools"] = tools
140
+ # Clean tools to remove null types (Moonshot API incompatibility)
141
+ cleaned_tools = self._clean_tool_schemas(tools)
142
+ request_config["tools"] = cleaned_tools
135
143
  elif response_format:
136
144
  # Use the same approach as DeepSeek for structured output
137
145
  try_modify_message_with_format(messages[-1], response_format)
@@ -139,6 +147,94 @@ class MoonshotModel(OpenAICompatibleModel):
139
147
 
140
148
  return request_config
141
149
 
150
+ def _clean_tool_schemas(
151
+ self, tools: List[Dict[str, Any]]
152
+ ) -> List[Dict[str, Any]]:
153
+ r"""Clean tool schemas to remove null types for Moonshot compatibility.
154
+
155
+ Moonshot API doesn't accept {"type": "null"} in anyOf schemas.
156
+ This method removes null type definitions from parameters.
157
+
158
+ Args:
159
+ tools (List[Dict[str, Any]]): Original tool schemas.
160
+
161
+ Returns:
162
+ List[Dict[str, Any]]: Cleaned tool schemas.
163
+ """
164
+
165
+ def remove_null_from_schema(schema: Any) -> Any:
166
+ """Recursively remove null types from schema."""
167
+ if isinstance(schema, dict):
168
+ # Create a copy to avoid modifying the original
169
+ result = {}
170
+
171
+ for key, value in schema.items():
172
+ if key == 'type' and isinstance(value, list):
173
+ # Handle type arrays like ["string", "null"]
174
+ filtered_types = [t for t in value if t != 'null']
175
+ if len(filtered_types) == 1:
176
+ # Single type remains, convert to string
177
+ result[key] = filtered_types[0]
178
+ elif len(filtered_types) > 1:
179
+ # Multiple types remain, keep as array
180
+ result[key] = filtered_types
181
+ else:
182
+ # All were null, use string as fallback
183
+ logger.warning(
184
+ "All types in tool schema type array "
185
+ "were null, falling back to 'string' "
186
+ "type for Moonshot API compatibility. "
187
+ "Original tool schema may need review."
188
+ )
189
+ result[key] = 'string'
190
+ elif key == 'anyOf':
191
+ # Handle anyOf with null types
192
+ filtered = [
193
+ item
194
+ for item in value
195
+ if not (
196
+ isinstance(item, dict)
197
+ and item.get('type') == 'null'
198
+ )
199
+ ]
200
+ if len(filtered) == 1:
201
+ # If only one type remains, flatten it
202
+ return remove_null_from_schema(filtered[0])
203
+ elif len(filtered) > 1:
204
+ result[key] = [
205
+ remove_null_from_schema(item)
206
+ for item in filtered
207
+ ]
208
+ else:
209
+ # All were null, return string type as fallback
210
+ logger.warning(
211
+ "All types in tool schema anyOf were null, "
212
+ "falling back to 'string' type for "
213
+ "Moonshot API compatibility. Original "
214
+ "tool schema may need review."
215
+ )
216
+ return {"type": "string"}
217
+ else:
218
+ # Recursively process other values
219
+ result[key] = remove_null_from_schema(value)
220
+
221
+ return result
222
+ elif isinstance(schema, list):
223
+ return [remove_null_from_schema(item) for item in schema]
224
+ else:
225
+ return schema
226
+
227
+ cleaned_tools = copy.deepcopy(tools)
228
+ for tool in cleaned_tools:
229
+ if 'function' in tool and 'parameters' in tool['function']:
230
+ params = tool['function']['parameters']
231
+ if 'properties' in params:
232
+ params['properties'] = remove_null_from_schema(
233
+ params['properties']
234
+ )
235
+
236
+ return cleaned_tools
237
+
142
238
  @observe()
143
239
  async def _arun(
144
240
  self,
@@ -183,18 +279,3 @@ class MoonshotModel(OpenAICompatibleModel):
183
279
  model=self.model_type,
184
280
  **request_config,
185
281
  )
186
-
187
- def check_model_config(self):
188
- r"""Check whether the model configuration contains any
189
- unexpected arguments to Moonshot API.
190
-
191
- Raises:
192
- ValueError: If the model configuration dictionary contains any
193
- unexpected arguments to Moonshot API.
194
- """
195
- for param in self.model_config_dict:
196
- if param not in MOONSHOT_API_PARAMS:
197
- raise ValueError(
198
- f"Unexpected argument `{param}` is "
199
- "input into Moonshot model backend."
200
- )