Skip to content

fix(core): preserve declared MiniMax Messages effort levels - #56510

Open
rudycelekli wants to merge 2 commits into
anomalyco:devfrom
rudycelekli:minimax-effort
Open

rudycelekli wants to merge 2 commits into
anomalyco:devfrom
rudycelekli:minimax-effort

Conversation

@rudycelekli

@rudycelekli rudycelekli commented Oct 17, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #54801

Type of change

  • Bug fix

What does this PR do?

Map catalog-declared MiniMax Messages effort levels to body.output_config.effort. Preserve M3’s existing toggle and M2’s guard, without adding a disabled-thinking variant to the declared ladder. Follows the diagnosis recorded by @argszero and @drakeo338 in the issue.

How did you verify your code works?

  • Simplified the requested regression to one MiniMax coding-plan provider with low/max effort cases. It asserts resolved HTTP-body overlays and compileRequest model/thinking controls without a custom HTTP/SSE harness. Production behavior is unchanged by this review update.
  • The published related-suite baseline passed 68 tests; the reduced candidate passed 670 focused tests across ten repeats.
  • Current source-bound Linux qualification: Core 6,339 passed/345 skipped; AI 1,822 passed/28 skipped; both package typechecks and root check (34/34 tasks) passed. Initial/final full-index identity matched the reviewed patch. Owned-fork validation is separate from upstream CI authorization.
  • The original broader HTTP-request proof is retained in run 39063885150; that heavier test harness was removed in response to review. The current reduced test does not claim to exercise final transport overlays on the wire. No live provider calls.

Screenshots / recordings

No visual UI code changed; variant definitions and outgoing request bodies are asserted.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix works. On the base, Variant.resolve returns no variants for MiniMax-M3.1-Flash-Preview when the catalog declares an effort ladder. With this PR it returns low…max, each sending output_config.effort, and no none. MiniMax-M3 (toggle) and MiniMax-M2.7 behave as before. The issue's repro.sh couldn't run from source in either checkout because the standalone server stops before it's ready, so I checked by calling Variant.resolve directly. In packages/core, the variant and model-resolver tests pass (68/68). With your test files copied onto the base, the 3 new tests fail there. Typecheck passes.

The public API is unchanged.

The only thing I'd change is the new model-resolver test, which is heavier than it needs to be (see the inline comment).

@mradwankhalil

Copy link
Copy Markdown
Contributor

The released MiniMax-M3.1-Flash (not just the Preview) hits the same gap: on 2.2.5, minimax-coding-plan/MiniMax-M3.1-Flash resolves variants: [] although the catalog declares low…max. minimaxMessages on dev (14638b54d3) is still unchanged.

I confirmed the request shape this PR produces against the live API. With a config override that sends output_config.effort: "low" to https://api.minimax.io/anthropic/v1/messages for MiniMax-M3.1-Flash, the call succeeds. MiniMax's Anthropic API docs also say Flash always thinks and returns 400 for thinking: { type: "disabled" }, so leaving none out of the declared ladder, as this PR does, is required, not just tidier.

@benjaminkincses benjaminkincses left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checked this against #54801. the bug is real: a declared effort ladder hit configurable=false and returned []. this branch sits after the m2 guard and before the toggle fallback, so m2 still returns [] and m3 with no values still gets none/thinking. the resolver test covers the part that matters: no disabled thinking variant in the prepared body, since the api rejects it. looks right.

@isHeSatoshi

Copy link
Copy Markdown

Alternative implementation for the same branch, with the coverage this report names (the minimax minimax.io API provider and the minimax-coding-plan Token Plan provider, both serving MiniMax-M3.1-Flash): #62265.

The difference is the spelling. That PR uses settings: { effort }, so the Anthropic Messages protocol emits output_config.effort itself and a request-level providerOptions.effort still wins over the variant. A body: { output_config: { effort } } overlay is applied at the transport layer, so it overrides whatever the protocol produced for that model.

Both produce the same request body, and both keep MiniMax-M3's toggle and the M2.x guard. No rush to merge either — happy to close this one in favour of the other.

@isHeSatoshi isHeSatoshi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed from #62265, which touches the same branch. The mapping itself is right; this is about the spelling.

body: { output_config: { effort } } vs settings: { effort }

The overlay is applied at the transport layer, after the protocol has built the request body, so it wins over anything the protocol produced for that model. A request-level effort is therefore ignored:

// model variant -> body overlay
const model = MiniMax.model("MiniMax-M3.1-Flash", { apiKey: "k", body: { output_config: { effort: "low" } } })
// request -> providerOptions: { effort: "high" }
spelling wire body
body: { output_config: { effort: "low" } } output_config: {"effort":"low"} — the request's high is dropped
settings: { effort: "low" } output_config: {"effort":"high"} — the request wins

mergeProviderOptions() merges model options under request options, so the typed option keeps a per-request effort working; the overlay cannot, because it is merged last, on top of the protocol body.

Two more points for the typed spelling:

  • It is what the sibling Anthropic-compatible route already does. moonshotMessages maps its ladder to settings: { effort }, and MessagesOptionsInput there declares effort?: ReasoningEffort (packages/ai/src/providers/moonshot.ts). The MiniMax Messages route is the same kind of route, so the same spelling keeps one convention for Anthropic-compatible providers.
  • The MiniMax provider package then advertises the option instead of only the variant using it: MessagesOptionsInput.effort becomes part of the provider surface, and packages/ai/test/provider-options/minimax.types.ts can assert it the way the Moonshot one does.

Coverage this PR is missing

The test here uses minimax-coding-plan with MiniMax-M3.1-Flash-Preview. The catalog declares the same ladder for the shipping MiniMax-M3.1-Flash on all four hosts (minimax, minimax-coding-plan, minimax-cn, minimax-cn-coding-plan), and minimax (the minimax.io API) is the one most people use. A test that resolves a variant for both minimax and minimax-coding-plan and asserts the request body would cover the report in #62264.

One assertion worth adding either way

The current test asserts resolved.route.defaults.http?.body and prepared.body, but prepared.body is the protocol body — the overlay is merged later, at transport time. Asserting the prepared transport body (or the merged JSON) is what proves the effort reaches the wire.

@isHeSatoshi

isHeSatoshi commented Nov 6, 2026 •

Copy link
Copy Markdown

Concrete test for the coverage gap, adapted to the overlay spelling in this PR. It resolves a variant for both providers the report in #62264 names, on the shipping MiniMax-M3.1-Flash, and asserts the request body that goes out:

it.effect("sends declared MiniMax Messages effort levels", () =>
  Effect.gen(function* () {
    // The minimax.io API and the Token Plan both serve M3.1 Flash through the Messages route.
    for (const providerID of ["minimax", "minimax-coding-plan"]) {
      const base = model(Provider.aisdk("@ai-sdk/anthropic"), {
        providerID: Provider.ID.make(providerID),
        modelID: "MiniMax-M3.1-Flash",
      })
      const catalog = Info.make({
        ...base,
        variants: Variant.resolve(base, [{ type: "effort", values: ["low", "max"] }]),
      })
      const resolved = yield* ModelResolver.resolveModel(
        catalog,
        VariantID.make("low"),
        Credential.Key.make({ type: "key", key: "fixture" }),
      )
      const prepared = yield* compileRequest(ai.request({ model: resolved, prompt: "Hello" }))

      expect(resolved.route.id).toBe("minimax-messages")
      expect(resolved.options?.http?.body).toMatchObject({ output_config: { effort: "low" } })
      // Thinking cannot be turned off on this model, so no toggle is sent.
      expect(prepared.body.thinking).toBeUndefined()
    }
  }),
)

The catalog declares the same ladder for MiniMax-M3.1-Flash on all four hosts (minimax, minimax-coding-plan, minimax-cn, minimax-cn-coding-plan), so the loop above covers the shipping model on the two providers people actually use.

Verified locally on this branch: decoding the live catalog with the fix applied yields the five effort variants for MiniMax-M3.1-Flash on all four providers, while MiniMax-M3 keeps none/thinking and the M2.x models stay variant-free.

@isHeSatoshi

Copy link
Copy Markdown

Scope note on the review above: the report this follows up is about the shipping MiniMax-M3.1-Flash, not the preview build. The review body is fixed once submitted, so to be explicit — the coverage point stands as it is written for MiniMax-M3.1-Flash on the minimax and minimax-coding-plan providers, and the test in the following comment is scoped to that model only.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MiniMax M3.1 Flash Preview offers no thinking depth variants despite a catalog-declared effort ladder

4 participants