* Streams a chat completion from MiMo's OpenAI-compatible API. * * Uses convertToR1Format (shared with DeepSeek/Z.ai) for message conversion * with mergeToolResultText and normalizeToolCallId options enabled. * MiMo-specific: enables thinking mode via extra_body.thinking. * * supportsPro
( systemPrompt: string, messages: any[], metadata?: ApiHandlerCreateMessageMetadata, )
| 67 | * definitions are correct for cost calculation. |
| 68 | */ |
| 69 | override async *createMessage( |
| 70 | systemPrompt: string, |
| 71 | messages: any[], |
| 72 | metadata?: ApiHandlerCreateMessageMetadata, |
| 73 | ): ApiStream { |
| 74 | const { id: modelId, info: modelInfo } = this.getModel() |
| 75 | |
| 76 | // Use shared R1-format conversion with tool ID sanitization and text merging |
| 77 | const convertedMessages = convertToR1Format(messages, { |
| 78 | mergeToolResultText: true, |
| 79 | normalizeToolCallId: sanitizeOpenAiCallId, |
| 80 | }) |
| 81 | |
| 82 | const tools = metadata?.tools |
| 83 | |
| 84 | // Build request per MiMo's OpenAI-compatible API |
| 85 | // https://developer.puter.com/ai/xiaomi/mimo-v2.5-pro/ |
| 86 | // Note: temperature is omitted because MiMo forces it to 1.0 when thinking mode |
| 87 | // is enabled, regardless of what is passed (see model-hyperparameters docs). |
| 88 | const params: Record<string, any> = { |
| 89 | model: modelId, |
| 90 | messages: [{ role: "system", content: systemPrompt }, ...convertedMessages], |
| 91 | stream: true, |
| 92 | stream_options: { include_usage: true }, |
| 93 | // MiMo requires thinking to be enabled via extra_body |
| 94 | extra_body: { thinking: { type: "enabled" } }, |
| 95 | } |
| 96 | |
| 97 | if (tools && tools.length > 0) { |
| 98 | params.tools = tools |
| 99 | } |
| 100 | |
| 101 | let stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk> |
| 102 | try { |
| 103 | stream = (await this.client.chat.completions.create(params as any)) as any |
| 104 | } catch (error) { |
| 105 | throw handleProviderError(error, "MiMo") |
| 106 | } |
| 107 | |
| 108 | let lastUsage: OpenAI.CompletionUsage | undefined |
| 109 | const activeToolCallIds = new Set<string>() |
| 110 | |
| 111 | for await (const chunk of stream) { |
| 112 | const delta = chunk.choices?.[0]?.delta ?? {} |
| 113 | const finishReason = chunk.choices?.[0]?.finish_reason |
| 114 | const sanitizedDelta = delta.tool_calls |
| 115 | ? { |
| 116 | ...delta, |
| 117 | tool_calls: delta.tool_calls.map((toolCall) => ({ |
| 118 | ...toolCall, |
| 119 | id: toolCall.id ? sanitizeOpenAiCallId(toolCall.id) : toolCall.id, |
| 120 | })), |
| 121 | } |
| 122 | : delta |
| 123 | |
| 124 | if (delta.content) { |
| 125 | yield { |
| 126 | type: "text", |
nothing calls this directly
no test coverage detected