/** * MiMo (Xiaomi) Provider Adapter * * 基于 OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、流式输出。 * 模型: mimo-v2.5-pro(1M 上下文 / 131072 max_tokens)/ mimo-v2.5(1M 上下文 / 32768 max_tokens) * * v0.6.4 P3-1: 继承 OpenAICompatibleAdapter —— 传输/组装/回退链收敛到共享基类, * 本文件只保留 MiMo 差异点:max_completion_tokens 字段名、tool_choice 强制 "auto"、 * 思考模式与 temperature/top_p 互斥、无 /models 端点(本地元数据列表)。 * * @see apis/mimo-api-docs-20260715.html */ import type { MetonaRequest } from '../types'; import type { MetonaModelInfo } from '../types/metona-adapter'; import { buildOpenAICompatibleMessages, buildOpenAICompatibleTools } from './shared/openai-format'; import { OpenAICompatibleAdapter } from './shared/openai-compatible-base'; export class MimoAdapter extends OpenAICompatibleAdapter { override readonly providerId: string = 'mimo'; readonly supportedModels = ['mimo-v2.5-pro', 'mimo-v2.5']; readonly supportsToolCalling = true; readonly supportsThinking = true; // MiMo 模型元信息 // mimo-v2.5-pro: 1M 上下文 / 131072 max_tokens;mimo-v2.5: 1M 上下文 / 32768 max_tokens private static readonly MODEL_INFO: Record = { 'mimo-v2.5-pro': { id: 'mimo-v2.5-pro', name: 'MiMo V2.5 Pro', contextWindow: 1_000_000, maxOutputTokens: 131_072, supportsToolCalling: true, supportsThinking: true, description: '小米 MiMo 旗舰模型,支持深度思考与工具调用', }, 'mimo-v2.5': { id: 'mimo-v2.5', name: 'MiMo V2.5', contextWindow: 1_000_000, maxOutputTokens: 32_768, supportsToolCalling: true, supportsThinking: true, description: '小米 MiMo 标准模型,低延迟推理', }, }; // ===== 共享基类差异声明 ===== protected override chatCompletionsUrl(): string { return `${this.config.baseURL}/chat/completions`; } protected override sendTimeoutMs(): number { return 120_000; } protected override modelInfoTable(): Record { return MimoAdapter.MODEL_INFO; } protected override providerLabel(): string { return 'MiMo'; } /** * MiMo 官方未提供 /models 端点,直接返回本地元数据。 */ override async listModels(): Promise { return this.supportedModels.map((id) => MimoAdapter.MODEL_INFO[id] ?? { id }); } // ========== 协议参数映射(MiMo 差异点) ========== protected override toNativeRequest(request: MetonaRequest, stream: boolean): Record { // v0.6.2: images 处理收敛至共享层(原索引对齐循环在孤立 tool 过滤后会错位) const messages = buildOpenAICompatibleMessages(request, true); const tools = buildOpenAICompatibleTools(request.tools); // MiMo 使用 max_completion_tokens(非 max_tokens) // #41 修复: thinking 模式下未配置时兜底 32768(thinking 占用 token 配额,API 默认值过小会截断输出) // v0.5.3: 按模型上限钳制(pro 131072 / standard 32768)— // 引擎默认 63488 超过 standard 上限时 API 直接 400 const mimoMaxOutput = MimoAdapter.MODEL_INFO[this.config.defaultModel]?.maxOutputTokens ?? 131_072; const mimoDefault = request.params.thinkingEnabled !== false ? 32_768 : mimoMaxOutput; const body: Record = { model: this.config.defaultModel, messages, max_completion_tokens: Math.min(request.params.maxTokens ?? mimoDefault, mimoMaxOutput), stream, }; if (stream) { body.stream_options = { include_usage: true }; } if (tools) { body.tools = tools; // MiMo 仅支持 tool_choice: "auto" body.tool_choice = 'auto'; } // v0.6.4 P4-3: MiMo 服务端内置工具透出 —— config.providerOptions.enableWebSearch // 开启后附加 {type:'web_search'} 服务端搜索工具(annotations 引用随响应返回, // 由上层归并为文本内容展示)。与客户端 tools 定义互不影响。 const providerOptions = this.config.providerOptions as Record | undefined; if (providerOptions?.['enableWebSearch'] === true) { const serverTools = body.tools ? [...(body.tools as Array>), { type: 'web_search' }] : [{ type: 'web_search' }]; body.tools = serverTools; if (!body.tool_choice) body.tool_choice = 'auto'; } // v0.6.4 P4-3: strict JSON 响应格式开关(response_format: json_object)—— // 供结构化抽取类任务使用;与流式模式兼容性由服务端保证(文档标注支持子集) if (providerOptions?.['responseFormatJson'] === true) { body.response_format = { type: 'json_object' }; } // Thinking 模式(与 DeepSeek 参数结构一致) // MiMo API 默认 thinking.type = "enabled",必须显式发送 disabled 才能关闭 if (request.params.thinkingEnabled === false) { // 显式禁用思考:传 disabled + temperature/top_p(非思考模式下这两个参数有效) body.thinking = { type: 'disabled' }; body.temperature = request.params.temperature; body.top_p = request.params.topP; } else { // 启用思考(包括 undefined,因为 MiMo 默认 enabled) // 思考模式下 temperature/top_p 被 API 强制覆盖为 1.0/0.95,不传 body.thinking = { type: 'enabled' }; } // 停止序列 if (request.params.stopSequences?.length) { body.stop = request.params.stopSequences; } return body; } }