带工具调用支持的 MiMo API 调用 (供 agent 集成使用)。 处理逻辑: - Claude 格式 → OpenAI 格式 转换(含 reasoning_content 全量回传) - System prompt 注入 - SSE 流式响应(包含 tool_calls 与 reasoning_content 增量) - 思考模式开关传递
(self, messages, tools=None, stream: bool = False, **kwargs)
| 209 | # ==================== Agent mode support ==================== |
| 210 | |
| 211 | def call_with_tools(self, messages, tools=None, stream: bool = False, **kwargs): |
| 212 | """ |
| 213 | 带工具调用支持的 MiMo API 调用 (供 agent 集成使用)。 |
| 214 | |
| 215 | 处理逻辑: |
| 216 | - Claude 格式 → OpenAI 格式 转换(含 reasoning_content 全量回传) |
| 217 | - System prompt 注入 |
| 218 | - SSE 流式响应(包含 tool_calls 与 reasoning_content 增量) |
| 219 | - 思考模式开关传递 |
| 220 | """ |
| 221 | try: |
| 222 | converted_messages = self._convert_messages_to_openai_format(messages) |
| 223 | |
| 224 | system_prompt = kwargs.pop("system", None) |
| 225 | if system_prompt: |
| 226 | if not converted_messages or converted_messages[0].get("role") != "system": |
| 227 | converted_messages.insert(0, {"role": "system", "content": system_prompt}) |
| 228 | else: |
| 229 | converted_messages[0] = {"role": "system", "content": system_prompt} |
| 230 | |
| 231 | converted_tools = None |
| 232 | if tools: |
| 233 | converted_tools = self._convert_tools_to_openai_format(tools) |
| 234 | |
| 235 | model = kwargs.pop("model", None) or self.args["model"] |
| 236 | max_tokens = kwargs.pop("max_tokens", None) |
| 237 | |
| 238 | request_body = { |
| 239 | "model": model, |
| 240 | "messages": converted_messages, |
| 241 | "stream": stream, |
| 242 | } |
| 243 | if max_tokens is not None: |
| 244 | # MiMo 使用 max_completion_tokens 命名(含可见输出 + 推理 token) |
| 245 | request_body["max_completion_tokens"] = max_tokens |
| 246 | |
| 247 | if converted_tools: |
| 248 | request_body["tools"] = converted_tools |
| 249 | request_body["tool_choice"] = kwargs.pop("tool_choice", "auto") |
| 250 | |
| 251 | # 思考模式:默认遵循各模型的官方默认值;caller 可显式覆盖 |
| 252 | thinking_param = kwargs.pop("thinking", None) |
| 253 | thinking_active = False |
| 254 | |
| 255 | if self._model_supports_thinking(model): |
| 256 | if thinking_param is None: |
| 257 | default_on = self._thinking_default_enabled(model) |
| 258 | thinking_param = {"type": "enabled" if default_on else "disabled"} |
| 259 | request_body["thinking"] = thinking_param |
| 260 | thinking_active = thinking_param.get("type") == "enabled" |
| 261 | |
| 262 | # 思考模式下 v2.5-pro / v2.5 不支持自定义 temperature;干脆全部剥离避免被静默忽略 |
| 263 | if thinking_active: |
| 264 | for k in ("temperature", "top_p", "presence_penalty", "frequency_penalty"): |
| 265 | request_body.pop(k, None) |
| 266 | kwargs.pop(k, None) |
| 267 | else: |
| 268 | temperature = kwargs.pop("temperature", None) |
no test coverage detected