Skip to content

Commit 5af4aba

Browse files
authored
fix: Base model handle image type (camel-ai#1633)
1 parent d4225d0 commit 5af4aba

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

camel/models/base_model.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,26 +103,40 @@ def preprocess_messages(
103103
self, messages: List[OpenAIMessage]
104104
) -> List[OpenAIMessage]:
105105
r"""Preprocess messages before sending to model API.
106-
Removes thinking content and other model-specific preprocessing.
106+
Removes thinking content from assistant and user messages.
107107
108108
Args:
109109
messages (List[OpenAIMessage]): Original messages
110110
111111
Returns:
112112
List[OpenAIMessage]: Preprocessed messages
113113
"""
114-
# Remove thinking content from messages before sending to API
115-
# This ensures only the final response is sent, excluding
116-
# intermediate thought processes
117-
return [
118-
{ # type: ignore[misc]
119-
**msg,
120-
'content': re.sub(
114+
115+
def should_process_thinking(msg: OpenAIMessage) -> bool:
116+
# Only process thinking content for assistant and user messages
117+
return msg['role'] in ['assistant', 'user'] and isinstance(
118+
msg['content'], str
119+
)
120+
121+
def remove_thinking(content: str) -> str:
122+
# Only remove thinking content if the tags are present
123+
if '<think>' in content and '</think>' in content:
124+
return re.sub(
121125
r'<think>.*?</think>',
122126
'',
123-
msg['content'], # type: ignore[arg-type]
127+
content,
124128
flags=re.DOTALL,
125-
).strip(),
129+
).strip()
130+
return content
131+
132+
return [
133+
{ # type: ignore[misc]
134+
**msg,
135+
'content': (
136+
remove_thinking(msg['content']) # type: ignore[arg-type]
137+
if should_process_thinking(msg)
138+
else msg['content']
139+
),
126140
}
127141
for msg in messages
128142
]

camel/utils/commons.py

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -306,49 +306,51 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
306306
value = os.environ.get(env_var_name)
307307
if not value or value.strip() == "":
308308
missing_keys.append(env_var_name)
309-
309+
310310
key_way = "the official website"
311-
if env_var_name=='ANTHROPIC_API_KEY':
312-
key_way = "https://docs.anthropic.com/zh-CN/api/getting-started"
313-
elif env_var_name=='AIML_API_KEY':
311+
if env_var_name == 'ANTHROPIC_API_KEY':
312+
key_way = (
313+
"https://docs.anthropic.com/zh-CN/api/getting-started"
314+
)
315+
elif env_var_name == 'AIML_API_KEY':
314316
key_way = "https://aimlapi.com/"
315-
elif env_var_name=='COHERE_API_KEY':
317+
elif env_var_name == 'COHERE_API_KEY':
316318
key_way = "https://cohere.com/"
317-
elif env_var_name=='DEEPSEEK_API_KEY':
319+
elif env_var_name == 'DEEPSEEK_API_KEY':
318320
key_way = "https://www.deepseek.com/"
319-
elif env_var_name=='AZURE_OPENAI_API_KEY':
321+
elif env_var_name == 'AZURE_OPENAI_API_KEY':
320322
key_way = "https://portal.azure.com/"
321-
elif env_var_name=='OPENAI_API_KEY':
323+
elif env_var_name == 'OPENAI_API_KEY':
322324
key_way = "https://platform.openai.com/docs/overview"
323-
elif env_var_name=='FISHAUDIO_API_KEY':
325+
elif env_var_name == 'FISHAUDIO_API_KEY':
324326
key_way = "https://fish.audio/"
325-
elif env_var_name=='GEMINI_API_KEY':
327+
elif env_var_name == 'GEMINI_API_KEY':
326328
key_way = "https://gemini.google.com/"
327-
elif env_var_name=='INTERNLM_API_KEY':
329+
elif env_var_name == 'INTERNLM_API_KEY':
328330
key_way = "https://internlm-chat.intern-ai.org.cn/puyu/api/v1"
329-
elif env_var_name=='GROQ_API_KEY':
331+
elif env_var_name == 'GROQ_API_KEY':
330332
key_way = "https://api.groq.com/openai/v1"
331-
elif env_var_name=='MISTRAL_API_KEY':
333+
elif env_var_name == 'MISTRAL_API_KEY':
332334
key_way = "https://mistral.ai/"
333-
elif env_var_name=='MOONSHOT_API_KEY':
335+
elif env_var_name == 'MOONSHOT_API_KEY':
334336
key_way = "https://api.moonshot.cn/v1"
335-
elif env_var_name=='NVIDIA_API_KEY':
337+
elif env_var_name == 'NVIDIA_API_KEY':
336338
key_way = "https://integrate.api.nvidia.com/"
337-
elif env_var_name=='OPENAI_COMPATIBILIY_API_KEY':
339+
elif env_var_name == 'OPENAI_COMPATIBILIY_API_KEY':
338340
key_way = "https://platform.openai.com/docs/overview"
339-
elif env_var_name=='QWEN_API_KEY':
341+
elif env_var_name == 'QWEN_API_KEY':
340342
key_way = "https://tongyi.aliyun.com/"
341-
elif env_var_name=='REKA_API_KEY':
343+
elif env_var_name == 'REKA_API_KEY':
342344
key_way = "https://docs.reka.ai/quick-start"
343-
elif env_var_name=='SAMBA_API_KEY':
345+
elif env_var_name == 'SAMBA_API_KEY':
344346
key_way = "https://community.sambanova.ai/t/looking-for-api-key-and-url-for-sambanova/576"
345-
elif env_var_name=='TOGETHER_API_KEY':
347+
elif env_var_name == 'TOGETHER_API_KEY':
346348
key_way = "https://docs.together.ai/docs/quickstart"
347-
elif env_var_name=='YI_API_KEY':
349+
elif env_var_name == 'YI_API_KEY':
348350
key_way = "https://platform.lingyiwanwu.com/docs"
349-
elif env_var_name=='ZHIPUAI_API_KEY':
351+
elif env_var_name == 'ZHIPUAI_API_KEY':
350352
key_way = "https://www.zhipuai.cn/"
351-
353+
352354
if missing_keys:
353355
raise ValueError(
354356
"Missing or empty required API keys in "

test/models/test_base_model.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,32 @@ async def _arun(self, messages, response_format=None, tools=None):
6666
processed = model.preprocess_messages(messages)
6767
assert processed[0]['content'] == 'plain message'
6868

69+
# Test normal thinking sections
70+
messages = [
71+
{'role': 'user', 'content': 'Start <think>Think</think>End'}
72+
]
73+
processed = model.preprocess_messages(messages)
74+
assert processed[0]['content'] == 'Start End'
75+
76+
# Test system messages (should not be processed)
77+
messages = [
78+
{
79+
'role': 'system',
80+
'content': 'System <think>thinking</think> message',
81+
}
82+
]
83+
processed = model.preprocess_messages(messages)
84+
assert (
85+
processed[0]['content'] == 'System <think>thinking</think> message'
86+
)
87+
88+
# Test empty thinking tags
89+
messages = [
90+
{'role': 'assistant', 'content': 'Before<think></think>After'}
91+
]
92+
processed = model.preprocess_messages(messages)
93+
assert processed[0]['content'] == 'BeforeAfter'
94+
6995
def test_metaclass_preprocessing(self):
7096
r"""Test that metaclass automatically preprocesses messages in run
7197
method."""

0 commit comments

Comments
 (0)