feat(media): add MiniMax music generation - #1242
Conversation
📝 WalkthroughWalkthroughThe pull request adds a MiniMax music-generation plugin. It supports regional endpoints, configurable audio settings, URL and hexadecimal audio responses, validation, plugin registration, and Vitest coverage. ChangesMiniMax music generation
Estimated code review effort: 3 (Moderate) | ~25 minutes Mergeability Score: 🟡 Moderate · up to The new music-generation path can reject default requests, wait indefinitely on an unresponsive provider, and accept malformed audio response data. These are bounded but concrete correctness and availability risks, so the PR is not merge-ready until they are fixed or explicitly accepted by the owner. Sequence Diagram(s)sequenceDiagram
participant generateMiniMaxMusic
participant MiniMaxAPI
participant parseMiniMaxMusicResponse
generateMiniMaxMusic->>MiniMaxAPI: Submit regional music-generation request
MiniMaxAPI-->>generateMiniMaxMusic: Return generation response
generateMiniMaxMusic->>parseMiniMaxMusicResponse: Parse completed audio
parseMiniMaxMusicResponse-->>generateMiniMaxMusic: Return secure URL or WAV data URL
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/plugins/media-generators/minimax.ts`:
- Around line 141-148: Add an AbortController and configured timeout around the
MiniMax fetch request, pass its signal to fetch, and abort when the deadline
expires. Ensure the timeout is cleared in a finally block after the request
completes or fails.
- Around line 77-90: Validate that result.data.audio is a string immediately
after confirming completed audio and before the outputFormat URL branch or
hexadecimal checks. Reject arrays and all other non-string values, while
preserving secure URL validation and hex decoding for valid strings; add a
regression test covering a truthy array input.
- Around line 122-136: Update the MiniMax payload construction around the
lyrics, lyricsOptimizer, and isInstrumental variables so every request has a
valid lyric mode: preserve lyrics when provided, otherwise enable
lyrics_optimizer or is_instrumental, or reject the configuration before the
provider request. Keep the existing valid .env.example values at .env.example
lines 72-74 unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 0b58fd63-341f-48fa-bd25-d697790f58c8
📒 Files selected for processing (4)
.env.examplesrc/__tests__/lib/plugins/media-generators/minimax.test.tssrc/lib/plugins/media-generators/index.tssrc/lib/plugins/media-generators/minimax.ts
| if (result.data?.status !== 2 || !result.data.audio) { | ||
| throw new Error("MiniMax music generation did not return completed audio"); | ||
| } | ||
| if (outputFormat === "url") { | ||
| return assertSecureAudioUrl(result.data.audio); | ||
| } | ||
| if ( | ||
| result.data.audio.length % 2 !== 0 || | ||
| !/^[0-9a-f]+$/i.test(result.data.audio) | ||
| ) { | ||
| throw new Error("MiniMax music generation returned invalid hex audio"); | ||
| } | ||
| const mediaType = audioFormat === "mp3" ? "mpeg" : audioFormat; | ||
| return `data:audio/${mediaType};base64,${Buffer.from(result.data.audio, "hex").toString("base64")}`; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file="src/lib/plugins/media-generators/minimax.ts"
if [ -f "$file" ]; then
wc -l "$file"
ast-grep outline "$file" --view compact || true
sed -n '1,220p' "$file"
fi
printf '\n--- related symbols ---\n'
rg -n --glob '*.{ts,tsx}' 'assertSecureAudioUrl|parseMiniMaxMusicResponse|MiniMax music generation|audioFormat|outputFormat' src tests 2>/dev/null | head -200 || true
printf '\n--- candidate test files ---\n'
git ls-files | rg '(^|/)(test|tests|__tests__)/|minimax|media-generators' | head -200Repository: f/prompts.chat
Length of output: 17177
🏁 Script executed:
#!/bin/bash
set -eu
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'assertSecureAudioUrl|parseMiniMaxMusicResponse|MiniMax' . | head -250Repository: f/prompts.chat
Length of output: 4770
🏁 Script executed:
#!/bin/bash
set -eu
sed -n '1,220p' src/lib/plugins/media-generators/minimax.ts
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'function assertSecureAudioUrl|const assertSecureAudioUrl|assertSecureAudioUrl' .Repository: f/prompts.chat
Length of output: 6493
🏁 Script executed:
#!/bin/bash
set -eu
sed -n '1,190p' src/__tests__/lib/plugins/media-generators/minimax.test.ts
node - <<'JS'
function assertSecureAudioUrl(audio) {
let url;
try {
url = new URL(audio);
} catch {
throw new Error("invalid");
}
if (url.protocol !== "https:") throw new Error("insecure");
return audio;
}
const audio = ["https://cdn.example/audio.mp3"];
const returned = assertSecureAudioUrl(audio);
console.log(JSON.stringify({
inputType: typeof audio,
coercedUrl: new URL(audio).href,
returnedIsSameArray: returned === audio,
returnedType: typeof returned,
returnedValue: returned,
}));
JSRepository: f/prompts.chat
Length of output: 4735
Validate data.audio as a string before parsing it.
A truthy array containing an HTTPS URL passes new URL() coercion, then assertSecureAudioUrl returns the array as a value declared string. Reject non-string values before URL or hexadecimal processing, and add a regression test.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/plugins/media-generators/minimax.ts` around lines 77 - 90, Validate
that result.data.audio is a string immediately after confirming completed audio
and before the outputFormat URL branch or hexadecimal checks. Reject arrays and
all other non-string values, while preserving secure URL validation and hex
decoding for valid strings; add a regression test covering a truthy array input.
| const lyrics = process.env.MINIMAX_LYRICS?.trim(); | ||
| const lyricsOptimizer = readBoolean(process.env.MINIMAX_LYRICS_OPTIMIZER); | ||
| const isInstrumental = readBoolean(process.env.MINIMAX_IS_INSTRUMENTAL); | ||
| const aigcWatermark = readBoolean(process.env.MINIMAX_AIGC_WATERMARK); | ||
|
|
||
| const payload: Record<string, unknown> = { | ||
| model: request.model, | ||
| prompt: request.prompt, | ||
| stream: false, | ||
| output_format: "url", | ||
| audio_setting: audioSetting, | ||
| }; | ||
| if (lyrics) payload.lyrics = lyrics; | ||
| if (lyricsOptimizer !== undefined) payload.lyrics_optimizer = lyricsOptimizer; | ||
| if (isInstrumental !== undefined) payload.is_instrumental = isInstrumental; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- minimax implementation ---'
sed -n '1,220p' src/lib/plugins/media-generators/minimax.ts
printf '%s\n' '--- environment documentation ---'
sed -n '55,85p' .env.example
printf '%s\n' '--- related request types and call sites ---'
rg -n -S 'GenerationRequest|MINIMAX_LYRICS|lyrics_optimizer|is_instrumental|MiniMax' src .env.exampleRepository: f/prompts.chat
Length of output: 13377
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- GenerationRequest definition ---'
sed -n '1,55p' src/lib/plugins/media-generators/types.ts
printf '%s\n' '--- MiniMax tests ---'
sed -n '1,115p' src/__tests__/lib/plugins/media-generators/minimax.test.ts
printf '%s\n' '--- all MiniMax environment references ---'
rg -n -S 'MINIMAX_' --glob '!src/lib/plugins/media-generators/minimax.ts' --glob '!*minimax.test.ts' .Repository: f/prompts.chat
Length of output: 6903
🌐 Web query:
MiniMax music generation API music_generation lyrics lyrics_optimizer is_instrumental required parameters
💡 Result:
For the MiniMax music generation API, the lyrics, lyrics_optimizer, and is_instrumental parameters work together to determine how a song's content and vocals are generated [1][2][3]. The prompt parameter (describing style, mood, instrumentation, etc.) is generally required for all requests [4][3]. The requirements for the other parameters are as follows: 1. is_instrumental (boolean): When set to true, the model generates instrumental-only music without vocals [4][5][3]. In this mode, lyrics should be omitted, and lyrics_optimizer should generally not be enabled [4][2][3]. 2. lyrics_optimizer (boolean): When set to true and the lyrics field is left empty, the model will automatically generate lyrics based on the provided prompt [1][4][5]. 3. lyrics (string): This field provides specific lyrics for the song [1][2]. - It is required if both is_instrumental and lyrics_optimizer are set to false [2][3]. - It is optional or can be omitted if either is_instrumental is true (for instrumental tracks) or lyrics_optimizer is true (to trigger auto-generation) [1][4][2][3]. In summary, you must provide either specific lyrics, enable lyrics_optimizer for auto-generated lyrics, or set is_instrumental to true to create a track without vocals [4][2][3].
Citations:
- 1: https://platform.minimax.io/docs/api-reference/music-generation
- 2: https://apidot.ai/docs/minimax-music-2-6
- 3: https://minimax-ai.chat/models/minimax-music-3-0/
- 4: https://docs.poyo.ai/api-manual/music-series/minimax-music-2.6
- 5: https://developers.cloudflare.com/ai/models/minimax/music-2.6/
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
import json
def read_boolean(value):
if value is None:
return None
if value == "true":
return True
if value == "false":
return False
return None
def build_payload(env):
payload = {
"model": "music-3.0",
"prompt": "test prompt",
"stream": False,
"output_format": "url",
"audio_setting": {"format": "mp3"},
}
lyrics = env.get("MINIMAX_LYRICS", "").strip()
lyrics_optimizer = read_boolean(env.get("MINIMAX_LYRICS_OPTIMIZER"))
is_instrumental = read_boolean(env.get("MINIMAX_IS_INSTRUMENTAL"))
if lyrics:
payload["lyrics"] = lyrics
if lyrics_optimizer is not None:
payload["lyrics_optimizer"] = lyrics_optimizer
if is_instrumental is not None:
payload["is_instrumental"] = is_instrumental
return payload
cases = {
"all variables unset": {},
"documented example": {
"MINIMAX_LYRICS": "",
"MINIMAX_LYRICS_OPTIMIZER": "false",
"MINIMAX_IS_INSTRUMENTAL": "true",
},
"automatic lyrics": {
"MINIMAX_LYRICS_OPTIMIZER": "true",
"MINIMAX_IS_INSTRUMENTAL": "false",
},
"explicit lyrics": {
"MINIMAX_LYRICS": "[Verse] test",
"MINIMAX_LYRICS_OPTIMIZER": "false",
"MINIMAX_IS_INSTRUMENTAL": "false",
},
}
for name, env in cases.items():
print(name + ": " + json.dumps(build_payload(env), sort_keys=True))
PYRepository: f/prompts.chat
Length of output: 911
Set a valid MiniMax lyric mode before sending the request.
When all three lyric variables are unset, the payload contains neither lyrics nor a mode selector. MiniMax requires lyrics, lyrics_optimizer: true, or is_instrumental: true; a default GenerationRequest.prompt request therefore fails. Enable lyrics_optimizer or is_instrumental when lyrics are absent, or reject the configuration before the provider request. The .env.example values are valid when enabled.
📍 Affects 2 files
src/lib/plugins/media-generators/minimax.ts#L122-L136(this comment).env.example#L72-L74
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/plugins/media-generators/minimax.ts` around lines 122 - 136, Update
the MiniMax payload construction around the lyrics, lyricsOptimizer, and
isInstrumental variables so every request has a valid lyric mode: preserve
lyrics when provided, otherwise enable lyrics_optimizer or is_instrumental, or
reject the configuration before the provider request. Keep the existing valid
.env.example values at .env.example lines 72-74 unchanged.
| const response = await fetch(MINIMAX_MUSIC_CONFIG.endpoints[region], { | ||
| method: "POST", | ||
| headers: { | ||
| Authorization: `Bearer ${apiKey}`, | ||
| "Content-Type": "application/json", | ||
| }, | ||
| body: JSON.stringify(payload), | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file="src/lib/plugins/media-generators/minimax.ts"
printf '%s\n' "== outline =="
ast-grep outline "$file" --lang typescript || true
printf '%s\n' "== relevant source =="
cat -n "$file" | sed -n '1,230p'
printf '%s\n' "== related symbols and config =="
rg -n --glob '*.ts' --glob '*.tsx' 'parseMiniMaxMusicResponse|MINIMAX_MUSIC_CONFIG|startGeneration|lyrics_optimizer|instrumental|MiniMax' srcRepository: f/prompts.chat
Length of output: 15737
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '== media generation route =='
cat -n src/app/api/media-generate/route.ts | sed -n '80,135p'
printf '%s\n' '== fetch timeout patterns =='
rg -n --glob '*.ts' --glob '*.tsx' 'AbortController|AbortSignal|setTimeout\(|signal:' src
printf '%s\n' '== MiniMax tests =='
cat -n src/__tests__/lib/plugins/media-generators/minimax.test.ts | sed -n '1,180p'Repository: f/prompts.chat
Length of output: 14673
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
plugin = Path("src/lib/plugins/media-generators/minimax.ts").read_text()
route = Path("src/app/api/media-generate/route.ts").read_text()
fetch_start = plugin.index("const response = await fetch(")
fetch_end = plugin.index("\n });", fetch_start) + len("\n });")
fetch_call = plugin[fetch_start:fetch_end]
assert "signal:" not in fetch_call
assert "AbortController" not in fetch_call
assert "setTimeout" not in fetch_call
assert "await plugin.startGeneration" in route
assert "await db.user.update" in route
print("MiniMax fetch options have no signal, AbortController, or timeout.")
print("The API route awaits startGeneration before the credit update and response.")
PY
printf '%s\n' '== route configuration =='
sed -n '1,82p' src/app/api/media-generate/route.tsRepository: f/prompts.chat
Length of output: 2468
Add an application timeout to the MiniMax request.
This fetch call has no application-controlled deadline or abort signal. An unresponsive MiniMax endpoint can keep the POST request pending before credit deduction and response. Use an AbortController with a configured timeout, and clear the timer in finally.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/plugins/media-generators/minimax.ts` around lines 141 - 148, Add an
AbortController and configured timeout around the MiniMax fetch request, pass
its signal to fetch, and abort when the deadline expires. Ensure the timeout is
cleared in a finally block after the request completes or fails.
Reason: Add MiniMax music generation to the existing media generator registry.
Checks:
npm test -- src/__tests__/lib/plugins/media-generators/minimax.test.tsnpm run lint -- src/lib/plugins/media-generators/minimax.ts src/lib/plugins/media-generators/index.ts src/__tests__/lib/plugins/media-generators/minimax.test.tsgit diff --checkSummary