Repository navigation
Conversation
yetone
left a comment
There was a problem hiding this comment.
Thanks for this. The search hook and the video routes match magpie's plugin contract on main (e6fe481b3), but two things don't work the way magpie actually calls the plugin, so I'm requesting changes. Reviewed head: 4cc171a.
What I checked against magpie main:
- Search:
host.jssearchesOf/runSearchtakes{search: {<id>: {name, auth, execute}}}.authhas to name a provider this plugin's auth hook signs in to (searchAuthOf), andctx.getAuth()/ctx.abortare what the hook gets. This PR matches that. - Image:
draw.go:396lists a plugin model as a drawer when its output is images only and its npm is@ai-sdk/openai-compatible(PluginOpenAICompatible). Generations go as JSON toplugin://<id>/v1/images/generations(draw.go:1652). YourmediaPathcatches that afterpluginFetchrewrites the URL onto the chat base. This matches too. - Video:
video.gocustomVideomakersOftreats a plugin model whosecapabilities.outputhas video as a video model, sends the OpenAI-shaped body (remoteVideoBody) tovideoBase(p)+"/videos", and polls/videos/{id}and/videos/{id}/content. This matches.
Blocking
1. /images/edits never works through magpie (native.mjs:472-484, native.mjs:374-381)
The edit request for a plugin drawer that isn't Codex or SenseNova goes down the multipart branch in draw.go:1686-1720. magpie sends multipart/form-data with the image bytes, and it downloads an https reference into bytes first (fetchPicture). jsonBody only parses JSON, so every edit and every reference-image drawing comes back 400. Probe: I fed handleMediaFetch the body magpie builds (model, prompt, n, and an image file part):
PROBE edits multipart -> 400 {"error":{"message":"request body must be a JSON object","type":"invalid_request_error"}}
native.test.mjs:121 passes only because it posts a JSON {prompt} that magpie never sends. Meanwhile MiniMax-Image declares input: ["text","image"], so magpie offers it for edits and references.
Video has the same gap. magpie keeps an http(s) input_reference as a URL, but a local file or an uploaded image reaches the plugin as a data: URL (video.go:967, picture.dataURL), which mediaUrl refuses.
The README's "reference images must already be HTTPS URLs" is also not shown to work. The live Matrix schema describes reference_images[].url / input_image.url as "temp_url from a completed upload_temp_url upload ... or an existing upload URL from this environment", and submit_video_generation says "upload first and pass the URL". Nothing here tries an arbitrary external https URL.
Either of these would be fine:
- (a) Declare the image model
input: ["text"]and drop the edits route, so magpie doesn't offer what can't work. Text-to-image and text-to-video stay. - (b) Parse the multipart body and upload the bytes through MiniMax's upload flow before calling
generate_image, with a test that posts the multipart body magpie actually builds.
2. A 401 on the media path is never renewed (index.mjs:1123-1127, index.mjs:1279)
postTool throws a plain Error("... HTTP 401") with no status, and handleMediaFetch turns any throw without a status into 502. So res?.status === 401 is never true and the renewal branch can't run. Probe through auth.loader().fetch with the connector list answering 401:
PROBE 401 -> 502 kept {"error":{"message":"MiniMax Code tool API: HTTP 401","type":"api_error"}} list asks: 1
The chat path and the named tools (createToolRequest) both renew on 401. Please carry the status on the error, or reuse createToolRequest's send and renew, and add a test where the first ask is 401 and the second is 200.
Non-blocking (fix while you're here)
postTool(index.mjs:1270-1302) is a copy ofcreateToolRequest's envelope checks without its secret redaction. One function for both would keep them from drifting.- #974: the native image path calls
get_asset_urlright aftergenerate_image, which is exactly when #974 says MiniMax answers with the watermarked/visible/rendition. magpie then saves whatever that URL serves. So unless #974 is wrong, every native image can come back watermarked. At least say so on #974. Better, add a short bounded wait while the URL has/visible/. - The search hook's errors carry no
status. host.js rests an account for search only when the hook throws with a numeric status (401/402/403/429, see the comment oversearchesOf). As it is, a 429 keeps being retried on the same account. - With no
quality,areais left out, and the vendor's default is 4K. magpie's usual 1024x1024 then comes out as a 4K image. Consider mappingsizetoarea. mediaUrlaccepts any scheme (http:,ftp:…), though the docs say HTTPS.
Related issues
- #955: not affected. The native path validates against the live catalog through
callMatrixTool. - #985: not affected. The chat models' input modalities are unchanged.
- #974: see item 4.
What ran (mica, Bun 1.4.2, temp HOME)
bun test packages/minimax: 176 pass, 0 fail.bun scripts/check.mjs: ok.- Broken by hand, and a test went red each time: dropping the
searchhook, skipping the media answer in the loader fetch, leaving the media models out of the live list, and allowingdata:URIs. - The two probes above.
- Root
bun testwith origin/main (1e5b1c8) merged in, underlockf ~/suite.lock: 8387 pass, 20 skip, 0 fail. - No real MiniMax calls were made.
Register MiniMax Code as a backend for Magpie's built-in image generation, video generation, and web search, so agents can use /mcp/magpie/image, the videos API, and /mcp/magpie/web-search and drop the separate MiniMax named tools if they only need those capabilities. The named tools stay; this is additive. Search uses the plugin search hook, signed in as minimax-code or minimax-code-global, and MiniMax Code's web_search API. Image and video use Magpie's plugin fetch contract: MiniMax-Image is listed as an images-only @ai-sdk/openai-compatible model, and H3 / H3 Max / Hailuo 2.3 as models that give video. The fetch answers the OpenAI-shaped images and videos routes by calling the same Matrix connector tools (generate_image, submit_video_generation, query_video_generation, get_asset_url). No new MiniMax endpoints.
Parse the multipart /images/edits body Magpie actually sends, and upload those bytes (and video data: references) through the live catalog's upload_temp_url signed-form flow before generate_image / submit_video_generation. HTTPS URLs stay as they are. postTool and createToolRequest now share one envelope reader; HTTP errors carry their status, so a 401 on the media path can be renewed the way chat already is, and the search hook can rest an account on 401/402/403/429. Also: a short wait while get_asset_url still answers a /visible/ URL (magpie-community#974), map size to area so 1024x1024 is 1K rather than the 4K default, and accept only https and data: media URLs. Tests: the multipart body Magpie builds, a video data: reference, a media 401 then 200, a /visible/ retry, search status, and size→area.
4cc171a to
2a7303b
Compare
|
Thanks for the review. Kept edits and reference images (option b), and addressed the rest in 2a7303b. Rebased onto current main. Version stays 0.2.7 (still unreleased). 1. Tests: 2–3. Media 401 renewal, and one envelope for Test: 4. Test: 5. Search hook status (non-blocking) Test: 6. Map Test: covered in 7.
|
yetone
left a comment
There was a problem hiding this comment.
Thanks for the second round. I checked each item from the last review against the code at 2a7303b. Most of them are done. Two problems are still blocking, and both come from the new code. One quietly sends the wrong image to MiniMax, and the other can charge the user for a generation twice.
The items from the last review
| # | Claim | At 2a7303b |
|---|---|---|
| 1 | Multipart edits are parsed and uploaded through upload_temp_url |
Done. One gap: the mask (blocking A below) |
| 1 | Video data: refs are uploaded, and https refs pass through |
Done |
| 2 | A media 401 is renewed | It renews, but it runs the whole request again (blocking B) |
| 3 | postTool and createToolRequest share one envelope and keep the redaction |
Done |
| 4 | #974 /visible/ gets a bounded retry |
Done (8s, in 1s steps) |
| 5 | The search status is a number | Done for HTTP refusals. A refusal in base_resp still throws with no status (see below) |
| 6 | size maps to area |
Done |
| 7 | mediaRef takes https and data: only |
Done |
Blocking
A. The mask is uploaded as a reference image (packages/minimax/native.mjs:403)
referenceImages uploads every part whose field is image, image[], mask or markup, and puts all of them in reference_images. magpie's multipart branch (internal/gateway/draw.go, the else after drawsCodex) adds d.Mask as a part named mask. generate_image takes no mask, so MiniMax gets the black-and-white mask as one more picture to draw from. The edit comes back wrong, and the user is still charged. Probe: the multipart body magpie builds, with one image part and one mask part:
PROBE mask -> 200 [{"url":"https://temp.example/image0.png",...},{"url":"https://temp.example/image1.png",...}]
Please refuse a mask part with a 400, as magpie does for OpenRouter ("does not support mask edits"), and add a test for it. Drop markup too, unless something sends it.
B. A 401 after generate_image runs the paid generation again (packages/minimax/index.mjs:1124-1129, packages/minimax/native.mjs:270-277)
The renewal wraps the whole of handleMediaFetch. In one image request, generate_image runs first, for up to GEN_MS (10 minutes), and get_asset_url runs after it. If the token is turned away on get_asset_url, handleMediaFetch answers 401. The loader then renews and calls media() again from the start, so generate_image runs a second time and is charged twice. The first image is lost. A long generation makes this more likely, because the token can expire or be rotated while it runs. Probe through auth.loader().fetch: generate_image succeeds on tok, get_asset_url answers 401 on tok, and the renewal gives tok-2:
PROBE 401-after-generate -> 200 generate_image calls: 2
createToolRequest doesn't have this problem, because it renews per HTTP call and repeats only the call that got the 401. Please do the same on the media path: renew inside the transport that makeTokenRequest returns (or reuse createToolRequest's send-and-renew), and drop the retry around media(). Then add a test where get_asset_url gets the 401 and generate_image runs exactly once.
Non-blocking
allowedUploadHost(packages/minimax/native.mjs:576-581) acceptshttp://127.0.0.1,localhostand::1, so that the tests'Bun.serveupload host works. In production, it means anupload_hostfrom the vendor's answer makes the plugin POST the user's image to a service on this computer, and magpie's own gateway is on loopback too. Please accept only https in the code, and point the tests at a fakefetchinstead.parseToolEnvelope: a refusal insidebase_resp(code !== 0) throws with nostatus. If MiniMax reports quota or rate limits there, rather than as an HTTP status, magpie keeps sending searches to that account. If you know which codes those are, map them to 402 or 429.videoContent(native.mjs:349-353) copies all of the download's headers. If the CDN ever setscontent-encoding, Bun has already decoded the body, and the client decodes it a second time. Droppingcontent-encodingandcontent-lengththere would avoid that.
Version and rebase
#1014 has merged as 2b87fad and published @magpie-community/opencode-minimax-auth 0.2.7. This PR conflicts with it in packages/minimax/package.json and connector-tools.mjs. Please rebase onto main, bump to 0.2.8, and keep both native.mjs and the new magpie.options in package.json. As it stands, publish.yml would find 0.2.7 already on npm, and this change would never ship.
What ran (mote, Bun, temp HOME, fake fetch only)
bun test packages/minimax: 182 pass, 0 fail.bun scripts/check.mjs: exit 0.- I broke the code by hand four times and restored it after each, and a test went red every time:
- Multipart not parsed: the edits multipart test went red.
toolHttpErrorwith no status: the media-401 and search-status tests went red.- The media 401 retry removed: the media-401 test went red.
mediaRefallowinghttp:: the scheme tests went red.
- The two probes above.
git merge-treeagainst main dba2406: clean. Against #1014's head: conflict.- No real MiniMax calls were made.
Summary
@magpie-community/opencode-minimax-auth0.2.7 registers MiniMax Code as a backend for Magpie's built-in image generation, video generation, and web search. Agents can use Magpie's native/mcp/magpie/image, videos API, and/mcp/magpie/web-search, and drop the separate MiniMax named tools if they only need those capabilities. The named tools stay; this is additive.This does not change #1005 (opt-in compact/progressive MiniMax tools), which still awaits maintainers.
How it hooks in
Magpie core already has plugin extension points for this; no Magpie core change is required.
searchhook ({search: {<id>: {name, auth, execute}}}), listed beside Tavily and the rest, signed in asminimax-codeorminimax-code-global. Calls MiniMax Code's existing/mavis/api/v1/mcp/web_searchAPI (same as theweb_searchtool). No separate search API key. A refusal from that API carries a numericstatus(401/402/403/429) so Magpie can rest the account for search.@ai-sdk/openai-compatible. The plugin answersplugin://<id>/v1/images/generationsand/images/editsin its fetch by calling the Matrixgenerate_imagetool, thenget_asset_url. The livegenerate_imagecatalog has no model enum, so the listed model is MiniMax Image (MiniMax-Image). Magpie's non-Codex/SenseNova edit path sendsmultipart/form-datawith the image bytes; those bytes (and anydata:URL) are uploaded through the account's liveupload_temp_urlsigned-form flow, then passed togenerate_imageas atemp_url. HTTPS URLs are passed through. A size such as1024x1024is mapped to MiniMax'sarea(1K/2K/4K) so it does not fall through to the vendor's 4K default. Right after a generation,get_asset_urlis asked again for a few seconds while the URL still has/visible/(the watermarked rendition reported in minimax: get_asset_url answers a watermarked /visible/ URL right after a generation #974); if the wait runs out, the last URL is returned as-is.capabilities.outputincludesvideo. The plugin answers the OpenAI-shaped/videosAPI in its fetch withsubmit_video_generation,query_video_generation, andget_asset_url, using the real model ids MiniMax-H3, MiniMax-H3-Max, and MiniMax-Hailuo-2.3. A first or last frame given as adata:URL is uploaded the same way; an HTTPS URL is passed through.Resource library
MiniMax Code as a Library agent target (the icon row used to give skills to the MiniMax Code app) already lives in Magpie core, not in this plugin. Magpie shows it when it detects the MiniMax Code app (its data folder). This plugin cannot add that column.
After updating the plugin
Sign in to MiniMax Code (China) or MiniMax Code (Global), then:
The image and video models also appear on the MiniMax Code provider's model list; leave chat on M3 / M2.7.
Tests
bun test packages/minimax: 182 pass, includingnative.test.mjs.bun scripts/check.mjspasses. Rebased onto currentmain.