feat: upgrade MiniMax default model to M3 - #6468
octo-patch wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for MiniMax services, including a new ChatMiniMax model node, MiniMax API credentials, and MiniMax Text-to-Speech (TTS) integration. Feedback on the changes highlights a critical bug in the TTS stream processing where the loop does not fully terminate and the stream reader is not cancelled on error or abort, leading to potential resource leaks. Additionally, the falsy checks for temperature and topP in the ChatMiniMax node should be updated to safe nullish checks to allow valid values of 0.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const processMinimaxStream = async () => { | ||
| for (;;) { | ||
| if (abortController.signal.aborted) { | ||
| reader.cancel() | ||
| streamDestroyed = true | ||
| reject(new Error('TTS generation aborted')) | ||
| return | ||
| } | ||
|
|
||
| const { done, value } = await reader.read() | ||
| if (done) break | ||
|
|
||
| sseBuffer += decoder.decode(value, { stream: true }) | ||
| const lines = sseBuffer.split('\n') | ||
| sseBuffer = lines.pop() || '' | ||
|
|
||
| for (const line of lines) { | ||
| const trimmedLine = line.trim() | ||
| if (!trimmedLine || trimmedLine.startsWith(':')) { | ||
| continue | ||
| } | ||
|
|
||
| if (trimmedLine.startsWith('data:')) { | ||
| const jsonStr = trimmedLine.slice(5).trim() | ||
| if (!jsonStr) continue | ||
|
|
||
| try { | ||
| const eventData = JSON.parse(jsonStr) | ||
|
|
||
| if (eventData.base_resp?.status_code !== 0) { | ||
| const errorMsg = eventData.base_resp?.status_msg || 'Unknown error' | ||
| reject(new Error(`MiniMax TTS error: ${errorMsg}`)) | ||
| return | ||
| } | ||
|
|
||
| if (eventData.data?.audio) { | ||
| const audioChunk = Buffer.from(eventData.data.audio, 'hex') | ||
| onChunk(audioChunk) | ||
| } | ||
|
|
||
| if (eventData.data?.status === 2) { | ||
| break | ||
| } | ||
| } catch { | ||
| // Skip malformed JSON | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| onEnd() | ||
| resolve() | ||
| } |
There was a problem hiding this comment.
There are two critical issues in processMinimaxStream:
- The
breakstatement on line 200 only exits the innerfor (const line of lines)loop. The outerfor (;;)loop continues to run and callreader.read(), causing unnecessary processing and potential hangs. - If an error occurs (
status_code !== 0) or the stream is aborted, the stream reader is not properly cancelled, leading to resource/connection leaks.
Using a labeled loop (outerLoop) and ensuring reader.cancel() is called on all exit paths resolves these issues. Additionally, throwing an error when the API returns an invalid status code promotes fail-fast behavior.
const processMinimaxStream = async () => {
try {
outerLoop: for (;;) {
if (abortController.signal.aborted) {
await reader.cancel();
streamDestroyed = true;
reject(new Error("TTS generation aborted"));
return;
}
const { done, value } = await reader.read();
if (done) break;
sseBuffer += decoder.decode(value, { stream: true });
const lines = sseBuffer.split("\n");
sseBuffer = lines.pop() || "";
for (const line of lines) {
const trimmedLine = line.trim();
if (!trimmedLine || trimmedLine.startsWith(":")) {
continue;
}
if (trimmedLine.startsWith("data:")) {
const jsonStr = trimmedLine.slice(5).trim();
if (!jsonStr) continue;
try {
const eventData = JSON.parse(jsonStr);
if (eventData.base_resp?.status_code !== 0) {
const errorMsg = eventData.base_resp?.status_msg || "Unknown error";
await reader.cancel();
reject(new Error("MiniMax TTS error: " + errorMsg));
return;
}
if (eventData.data?.audio) {
const audioChunk = Buffer.from(eventData.data.audio, "hex");
onChunk(audioChunk);
}
if (eventData.data?.status === 2) {
await reader.cancel();
break outerLoop;
}
} catch {
// Skip malformed JSON
}
}
}
}
onEnd();
resolve();
} catch (err) {
await reader.cancel().catch(() => {});
reject(err);
}
}References
- When handling potentially invalid data from external sources (like an API response), prefer throwing an error for invalid input types rather than silently returning a default or empty value. This promotes fail-fast behavior.
| if (temperature) obj.temperature = parseFloat(temperature) | ||
| if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) | ||
| if (topP) obj.topP = parseFloat(topP) | ||
| if (cache) obj.cache = cache |
There was a problem hiding this comment.
Checking if (temperature) can fail when temperature is resolved as the number 0 (which is falsy in JavaScript), preventing users from setting a deterministic temperature of 0. It is safer to check temperature != null && temperature !== '' to allow 0 as a valid value. Similarly, topP should be checked safely. Use loose equality (!= null) as a standard idiom for nullish checks.
| if (temperature) obj.temperature = parseFloat(temperature) | |
| if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) | |
| if (topP) obj.topP = parseFloat(topP) | |
| if (cache) obj.cache = cache | |
| if (temperature != null && temperature !== '') obj.temperature = parseFloat(temperature) | |
| if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) | |
| if (topP != null && topP !== '') obj.topP = parseFloat(topP) | |
| if (cache) obj.cache = cache |
References
- In JavaScript/TypeScript, use loose equality (
== null) as a standard idiom for a 'nullish' check that covers bothnullandundefined.
- Add ChatMiniMax node with FlowiseChatMiniMax integration - Add MiniMaxApi credential definition - Update models.json with MiniMax model list (M3, M2.7, M2.7-highspeed) - Set MiniMax-M3 as the default model - Add MiniMax TTS support in textToSpeech.ts
ec0c559 to
a331603
Compare
Reason: Refresh the existing MiniMax integration with current model parameters and China-region TTS endpoint parity.
Changes
Checks
pnpm install --frozen-lockfile./.husky/pre-commitpnpm --filter flowise-components exec jest --runInBand src/minimaxParameters.test.tspnpm --filter flowise-components buildgit diff --checkgit diff --cached --check