Skip to content

Add MiniMax LLM adapter#2156

Open
octo-patch wants to merge 2 commits into
Zipstack:mainfrom
octo-patch:octo/20260706-provider-add-recvozNE1fKYRA
Open

Add MiniMax LLM adapter#2156
octo-patch wants to merge 2 commits into
Zipstack:mainfrom
octo-patch:octo/20260706-provider-add-recvozNE1fKYRA

Conversation

@octo-patch

Copy link
Copy Markdown

Reason: 仿 nvidia_build/openrouter 品牌化 OpenAI 兼容 adapter:在 adapters/llm1 加 MiniMax.py + static/MiniMax.json,base1.py 加 MiniMaxLLMParameters 固定默认 api_base,__...

Summary

  • Add a branded MiniMax LLM adapter backed by the OpenAI-compatible validation path and the default MiniMax API base.
  • Register the adapter, expose its schema and icon, and extend branded adapter tests for defaults and registration.

Checks

  • Secret scan: git add -A -N && git diff HEAD | grep -E "$SECRET_RE" (passed)
  • uv --directory unstract/sdk1 run ruff check src/unstract/sdk1/adapters/base1.py src/unstract/sdk1/adapters/llm1/minimax.py src/unstract/sdk1/adapters/llm1/__init__.py tests/test_branded_openai_adapters.py
  • uv --directory unstract/sdk1 run pytest tests/test_branded_openai_adapters.py -k 'not embedding_strips_embed_batch_size_before_litellm and not nvidia_embedding_batch_sends_passage_input_type and not compatible_embedding_omits_input_type'

Note: Full tests/test_branded_openai_adapters.py was attempted but three existing embedding tests could not import magic because system libmagic is not installed in this environment.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 15a7a70e-0cfa-4293-beac-bc93383bfdb1

📥 Commits

Reviewing files that changed from the base of the PR and between 913bb6a and f996449.

⛔ Files ignored due to path filters (1)
  • frontend/public/icons/adapter-icons/MiniMax.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • unstract/sdk1/src/unstract/sdk1/adapters/base1.py
  • unstract/sdk1/src/unstract/sdk1/adapters/llm1/__init__.py
  • unstract/sdk1/src/unstract/sdk1/adapters/llm1/minimax.py
  • unstract/sdk1/src/unstract/sdk1/adapters/llm1/static/minimax.json
  • unstract/sdk1/tests/test_branded_openai_adapters.py

Summary by CodeRabbit

  • New Features

    • Added support for a new MiniMax LLM provider.
    • Introduced a new configuration option set, including reasoning controls and a default endpoint.
  • Bug Fixes

    • Improved branded provider validation to ensure MiniMax settings use the correct default API base.
    • Confirmed model names are normalized consistently for MiniMax configurations.

Walkthrough

This PR adds a new MiniMax branded OpenAI-compatible LLM adapter to the Unstract SDK, including a MiniMaxLLMParameters validation class, MiniMaxLLMAdapter implementation, a JSON configuration schema, package export wiring, and corresponding test coverage.

Changes

MiniMax LLM Adapter

Layer / File(s) Summary
Parameter validation
unstract/sdk1/src/unstract/sdk1/adapters/base1.py
Adds _MINIMAX_API_BASE constant and MiniMaxLLMParameters class validating metadata against the branded OpenAI-compatible endpoint.
Adapter class and registration
unstract/sdk1/src/unstract/sdk1/adapters/llm1/minimax.py, unstract/sdk1/src/unstract/sdk1/adapters/llm1/__init__.py
Adds MiniMaxLLMAdapter with identity, metadata, and UI descriptor methods, and exports it from the package.
Configuration schema
unstract/sdk1/src/unstract/sdk1/adapters/llm1/static/minimax.json
Defines required fields, configuration properties, and conditional reasoning_effort validation based on enable_reasoning.
Test coverage
unstract/sdk1/tests/test_branded_openai_adapters.py
Extends branded adapter tests to include MiniMax for model prefixing, api_base fallback/override, and schema default checks.

Estimated code review effort: 2 (Simple) | ~15 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers intent, summary, and testing, but misses most required template sections like Why/How, breakage, migrations, env config, issues, and checklist. Rewrite the PR description using the repository template and fill every required section, especially breakage, testing, checklist, and any related issues.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: adding a MiniMax LLM adapter.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a MiniMax LLM adapter following the established branded OpenAI-compatible pattern (NvidiaBuild, OpenRouter), with a fixed default API base of https://api.minimax.io/v1, a JSON schema, a frontend icon, and parametrized tests covering registration, default base, and base override.

  • minimax.py + base1.py: MiniMaxLLMParameters delegates to _validate_branded_openai_compatible, which prefixes model names with custom_openai/ and routes calls through LiteLLM's generic OpenAI-compatible provider — the same path used by NvidiaBuild.
  • minimax.json: The schema copies the enable_reasoning / reasoning_effort conditional block from openrouter.json, but MiniMax's API uses a thinking: {type: \"adaptive\"} field for reasoning rather than reasoning_effort, so that toggle will have no effect at runtime while silently stripping temperature.
  • Tests: Parametrized suites are extended correctly for registration, blank-base fallback, and base override; the reasoning path for MiniMax is not tested.

Confidence Score: 4/5

Safe to merge for the basic MiniMax completion path; the enable_reasoning toggle in the schema will silently have no effect and should be fixed or removed before users rely on it.

The core adapter — model prefixing, API base defaulting, registration, icon, and tests — is correctly implemented and mirrors the battle-tested NvidiaBuild pattern. The one defect is the enable_reasoning UI toggle: MiniMax's OpenAI-compatible endpoint uses a thinking field for reasoning rather than reasoning_effort, so toggling it on strips temperature without activating reasoning. That's a real functional mismatch introduced by this PR, but it only affects users who explicitly enable the reasoning toggle; all standard completions are unaffected.

unstract/sdk1/src/unstract/sdk1/adapters/llm1/static/minimax.json — the enable_reasoning / reasoning_effort block should be updated to match MiniMax's actual reasoning API or removed.

Important Files Changed

Filename Overview
unstract/sdk1/src/unstract/sdk1/adapters/llm1/minimax.py New MiniMaxLLMAdapter class that faithfully mirrors the NvidiaBuild pattern; all static methods present, correct provider string and icon path.
unstract/sdk1/src/unstract/sdk1/adapters/base1.py Adds MiniMaxLLMParameters with the correct API base and delegates validation to _validate_branded_openai_compatible; consistent with NvidiaBuildLLMParameters.
unstract/sdk1/src/unstract/sdk1/adapters/llm1/static/minimax.json Schema exposes an enable_reasoning toggle that sends reasoning_effort via extra_body, but MiniMax's API uses a thinking field for reasoning — the toggle will silently have no effect while stripping temperature.
unstract/sdk1/src/unstract/sdk1/adapters/llm1/init.py Registers MiniMaxLLMAdapter in both the import list and all; alphabetical ordering maintained.
unstract/sdk1/tests/test_branded_openai_adapters.py Good parametrized coverage of registration, default API base, and base-override; no test covers enable_reasoning for MiniMax where the mismatch would surface.
frontend/public/icons/adapter-icons/MiniMax.png New icon file added; path matches the string returned by MiniMaxLLMAdapter.get_icon().

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Frontend UI
    participant Adapter as MiniMaxLLMAdapter
    participant Params as MiniMaxLLMParameters
    participant Base as _validate_branded_openai_compatible
    participant OAICompat as OpenAICompatibleLLMParameters.validate
    participant LiteLLM as LiteLLM (custom_openai/)
    participant API as api.minimax.io/v1

    UI->>Adapter: get_json_schema()
    Adapter-->>UI: minimax.json (model, api_key, api_base, enable_reasoning...)

    UI->>Params: validate(adapter_metadata)
    Params->>Base: _validate_branded_openai_compatible(metadata, _MINIMAX_API_BASE)
    Base->>Base: fill api_base if blank
    Base->>OAICompat: validate(metadata)
    OAICompat->>OAICompat: prepend custom_openai/ to model
    OAICompat->>OAICompat: "handle enable_reasoning → extra_body{reasoning_effort}"
    OAICompat-->>Base: validated dict
    Base-->>Params: validated dict

    Params-->>UI: "{model: custom_openai/MiniMax-M3, api_base: https://api.minimax.io/v1, ...}"

    UI->>LiteLLM: "completion(model=custom_openai/MiniMax-M3, api_base=...)"
    LiteLLM->>API: POST /v1/chat/completions
    API-->>LiteLLM: response
    LiteLLM-->>UI: LLM response
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Frontend UI
    participant Adapter as MiniMaxLLMAdapter
    participant Params as MiniMaxLLMParameters
    participant Base as _validate_branded_openai_compatible
    participant OAICompat as OpenAICompatibleLLMParameters.validate
    participant LiteLLM as LiteLLM (custom_openai/)
    participant API as api.minimax.io/v1

    UI->>Adapter: get_json_schema()
    Adapter-->>UI: minimax.json (model, api_key, api_base, enable_reasoning...)

    UI->>Params: validate(adapter_metadata)
    Params->>Base: _validate_branded_openai_compatible(metadata, _MINIMAX_API_BASE)
    Base->>Base: fill api_base if blank
    Base->>OAICompat: validate(metadata)
    OAICompat->>OAICompat: prepend custom_openai/ to model
    OAICompat->>OAICompat: "handle enable_reasoning → extra_body{reasoning_effort}"
    OAICompat-->>Base: validated dict
    Base-->>Params: validated dict

    Params-->>UI: "{model: custom_openai/MiniMax-M3, api_base: https://api.minimax.io/v1, ...}"

    UI->>LiteLLM: "completion(model=custom_openai/MiniMax-M3, api_base=...)"
    LiteLLM->>API: POST /v1/chat/completions
    API-->>LiteLLM: response
    LiteLLM-->>UI: LLM response
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
unstract/sdk1/src/unstract/sdk1/adapters/llm1/static/minimax.json:59-64
**`enable_reasoning` toggle silently has no effect on MiniMax**

The adapter routes reasoning through `OpenAICompatibleLLMParameters.validate()`, which sends `reasoning_effort` in `extra_body`. MiniMax's OpenAI-compatible API does not recognise `reasoning_effort`; it exposes deep thinking via a `thinking: {type: "adaptive"}` field instead ([MiniMax docs](https://platform.minimax.io/docs/guides/text-generation)). A user who turns this toggle on will have their `temperature` stripped from the request (potentially changing generation behaviour) while MiniMax silently ignores the unknown `reasoning_effort` key — no actual reasoning is activated.

Reviews (1): Last reviewed commit: "[pre-commit.ci] auto fixes from pre-comm..." | Re-trigger Greptile

Comment on lines +59 to +64
"enable_reasoning": {
"type": "boolean",
"title": "Enable Reasoning",
"default": false,
"description": "Toggle on for reasoning models to route reasoning_effort via the OpenAI-compatible request body."
}

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.

P1 enable_reasoning toggle silently has no effect on MiniMax

The adapter routes reasoning through OpenAICompatibleLLMParameters.validate(), which sends reasoning_effort in extra_body. MiniMax's OpenAI-compatible API does not recognise reasoning_effort; it exposes deep thinking via a thinking: {type: "adaptive"} field instead (MiniMax docs). A user who turns this toggle on will have their temperature stripped from the request (potentially changing generation behaviour) while MiniMax silently ignores the unknown reasoning_effort key — no actual reasoning is activated. Is there a plan to map enable_reasoningthinking: {type: "adaptive"} in MiniMax's request body, or should the enable_reasoning section be removed from minimax.json until that mapping is implemented?

Prompt To Fix With AI
This is a comment left during a code review.
Path: unstract/sdk1/src/unstract/sdk1/adapters/llm1/static/minimax.json
Line: 59-64

Comment:
**`enable_reasoning` toggle silently has no effect on MiniMax**

The adapter routes reasoning through `OpenAICompatibleLLMParameters.validate()`, which sends `reasoning_effort` in `extra_body`. MiniMax's OpenAI-compatible API does not recognise `reasoning_effort`; it exposes deep thinking via a `thinking: {type: "adaptive"}` field instead ([MiniMax docs](https://platform.minimax.io/docs/guides/text-generation)). A user who turns this toggle on will have their `temperature` stripped from the request (potentially changing generation behaviour) while MiniMax silently ignores the unknown `reasoning_effort` key — no actual reasoning is activated. Is there a plan to map `enable_reasoning``thinking: {type: "adaptive"}` in MiniMax's request body, or should the `enable_reasoning` section be removed from `minimax.json` until that mapping is implemented?

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

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.

Confirmed — this is a real issue, not just a doc mismatch.

The reasoning path in OpenAICompatibleLLMParameters.validate() (base1.py) does two things when enable_reasoning is on: it puts reasoning_effort into extra_body and pops temperature (validated.pop("temperature", None)). MiniMax's OpenAI-compatible endpoint doesn't recognise reasoning_effort — it gates deep thinking via thinking: {type: "adaptive"} — so the key is silently ignored while the user's temperature is stripped. The toggle activates no reasoning but changes generation behaviour.

Severity is bounded to the opt-in case: it only fires if a user flips the toggle. It won't auto-enable, since _is_openai_reasoning_model matches only o1|o3|o4|gpt-5, not MiniMax-M3.

Fix: dropping the enable_reasoning block (and its allOf conditional) from minimax.json for now, since the shared OpenAI-compatible validate path has no way to emit MiniMax's thinking field. A proper enable_reasoning → thinking:{type:"adaptive"} mapping would be a follow-up in the validate layer.

)


class MiniMaxLLMParameters(OpenAICompatibleLLMParameters):

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.

Routing through custom_openai/ silently zeroes out cost tracking for MiniMax.

_validate_branded_openai_compatible delegates to OpenAICompatibleLLMParameters.validate(), whose validate_model() unconditionally prepends custom_openai/. cost_model is only populated when the endpoint is OpenAI's own (base1.py:483), so it stays unset here, and audit.py:98 ends up calling cost_per_token(model="custom_openai/MiniMax-M3") — which raises, gets swallowed by the bare except, and records cost_in_dollars = 0.0 at debug level.

LiteLLM already ships a native MiniMax provider, and it prices M3:

litellm.get_llm_provider("minimax/MiniMax-M3")  -> ('MiniMax-M3', 'minimax', None, None)

cost_per_token("custom_openai/MiniMax-M3") -> raises        => cost = 0.0
cost_per_token("minimax/MiniMax-M3")       -> $0.30 / $1.20 per 1M tokens

So every MiniMax token would bill as $0 in usage tracking, silently.

This is why OpenRouterLLMParameters extends BaseChatCompletionParameters instead of OpenAICompatibleLLMParameters — its own docstring says so: "Routed through LiteLLM's native openrouter/ provider so per-token costs resolve and reasoning params map without provider-specific workarounds." MiniMax should follow OpenRouter's template, not NVIDIA Build's.

Worth noting NVIDIA Build's custom_openai/ routing is correct for NVIDIA — LiteLLM prices zero nvidia_nim/ chat models (3 entries, all rerankers, all $0.0), so there's nothing to forfeit there. That reason doesn't carry over to MiniMax.

Bonus: MinimaxChatConfig.get_api_base() already returns https://api.minimax.io/v1, so going native lets you drop the hardcoded _MINIMAX_API_BASE constant entirely.


@staticmethod
def get_icon() -> str:
return "/icons/adapter-icons/MiniMax.png"

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 shipped MiniMax.png is the OpenRouter logo.

frontend/public/icons/adapter-icons/MiniMax.png is byte-for-byte identical to OpenRouter.png:

0980b0d3102c84da9d332862c563c44f  MiniMax.png
0980b0d3102c84da9d332862c563c44f  OpenRouter.png
676be9d2fc5cec78d5be80af03eb9fd4  NvidiaBuild.png

Both 29953 bytes. Rendering it confirms it's the OpenRouter fork-arrow mark. NvidiaBuild.png differs, so this isn't a shared-placeholder convention — it looks like the icon was copied along with the adapter template and never swapped.

Users would see OpenRouter's branding on the MiniMax card in the adapter picker. Needs the real MiniMax logo.

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.

4 participants