feat(inference): add MiniMax native embedding adapter - #1653
Open
AlexStocks wants to merge 4 commits into
Open
AlexStocks wants to merge 4 commits into
AlexStocks wants to merge 4 commits into
Conversation
MiniMax's /v1/embeddings endpoint is not OpenAI-compatible: it takes {"model","texts","type":"db"} and returns {"vectors","total_tokens","base_resp":{"status_code"}}; on business errors it still answers HTTP 200 with a non-zero base_resp.status_code. PowerContext's default OpenAI embedder cannot parse this shape, so embedding over MiniMax failed.
Add MiniMaxEmbeddingModel, a self-contained adapter that issues the native request, validates the returned vector count, and raises InferenceUnavailableError on HTTP or business-level errors. Route MiniMax endpoints to it from the runtime composition layer via host/model detection (is_minimax_embedding) without altering the OpenAI path.
See oceanbase#1642.
AI assistance: code
Human verification: read the full diff and ran pytest / ruff / ty
Lore: MiniMax requires document embeddings for stored content and query embeddings for retrieval queries. Constraint: Preserve existing EmbeddingModel fallback and recall-gate query-vector reuse; only providers that expose embed_query take the provider-specific path. Tested: uv run pytest tests/builtin/inference/test_minimax_embedding.py tests/builtin/inference/test_pydantic_ai.py tests/builtin/artifacts/memory/test_service.py tests/builtin/runtime/test_composition_embedding.py tests/builtin/runtime/test_topic_memory_processing.py -q; uv run ty check changed files; uv run ruff check changed files. Not-tested: full uv run ty check and uv run ruff check . were polluted by untracked local .worktrees/.workbuddy directories in this workspace. Co-authored-by: OmX <[email protected]>
AlexStocks
force-pushed
the
feat/minimax-embedding-adapter
branch
from
September 18, 2026 10:59
44e51b8 to
8f3678d
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
MiniMax detection and error handling need tightening to avoid misrouting and loss or misclassification of actionable provider and response errors.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds native MiniMax embedding support, provider routing, query embedding dispatch, and regression coverage.
Changes:
- Implements and validates MiniMax embedding requests and responses.
- Routes MiniMax hosts and models through the native adapter.
- Adds query-aware embedding support across memory workflows.
- Adds adapter, routing, and retrieval tests.
File summaries
| File | Summary |
|---|---|
tests/builtin/runtime/test_topic_memory_processing.py |
Topic-memory query embedding tests |
tests/builtin/runtime/test_composition_embedding.py |
MiniMax routing tests |
tests/builtin/inference/test_pydantic_ai.py |
Query embedding forwarding tests |
tests/builtin/inference/test_minimax_embedding.py |
MiniMax adapter tests |
tests/builtin/artifacts/memory/test_service.py |
Memory query-path tests |
src/powercontext/builtin/runtime/topic_memory_processing.py |
Topic-memory query embeddings |
src/powercontext/builtin/runtime/composition.py |
MiniMax detection and construction |
src/powercontext/builtin/runtime/application.py |
Query embedding integration |
src/powercontext/builtin/inference/usage.py |
Query usage reporting |
src/powercontext/builtin/inference/pydantic_ai.py |
Query input propagation |
src/powercontext/builtin/inference/protocols.py |
Query embedding protocol |
src/powercontext/builtin/inference/minimax.py |
Native MiniMax adapter and detection |
src/powercontext/builtin/inference/__init__.py |
Query embedding exports |
src/powercontext/builtin/artifacts/memory/service.py |
Memory query embeddings |
Review details
Suppressed comments (2)
src/powercontext/builtin/inference/minimax.py:115
- The catch-all converts every unexpected exception, including adapter programming errors and unexpected response-shape bugs, into a transient
InferenceUnavailableError. This hides actionable defects and can cause callers to retry failures that are not transient; restrict this branch to expected JSON/transport failures and let unexpected exceptions propagate (as the Pydantic AI adapter does via_map_error).
except Exception as error:
raise InferenceUnavailableError("embed") from error
src/powercontext/builtin/inference/minimax.py:139
- A malformed JSON response raises
ValueErrorhere and is then caught by_embed's broad exception handler asInferenceUnavailableError. That misclassifies a provider-output contract violation (and can trigger the caller's transient fallback) instead of theInvalidInferenceOutputErrorused for other malformed MiniMax responses; catch JSON decoding errors and map them explicitly.
data = response.json()
- Files reviewed: 14/14 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Lore: MiniMax malformed provider output should remain distinguishable from transient availability failures. Constraint: Keep transport and provider business errors mapped to unavailable while letting adapter programming errors propagate. Tested: uv run pytest tests/builtin/inference/test_minimax_embedding.py tests/builtin/inference/test_pydantic_ai.py tests/builtin/artifacts/memory/test_service.py tests/builtin/runtime/test_composition_embedding.py tests/builtin/runtime/test_topic_memory_processing.py -q; uv run ruff check src/powercontext/builtin/inference/minimax.py tests/builtin/inference/test_minimax_embedding.py; uv run ty check src/powercontext/builtin/inference/minimax.py tests/builtin/inference/test_minimax_embedding.py; git diff --check. Co-authored-by: OmX <[email protected]>
Lore: MiniMax embeds return provider-specific business errors inside base_resp even when HTTP status is 200. Constraint: Keep the existing unavailable error category for retry/fallback behavior while preserving provider code/message for operators. Tested: uv run pytest tests/builtin/inference/test_minimax_embedding.py tests/builtin/runtime/test_composition_embedding.py -q; uv run pytest tests/builtin/inference/test_minimax_embedding.py tests/builtin/inference/test_pydantic_ai.py tests/builtin/artifacts/memory/test_service.py tests/builtin/runtime/test_composition_embedding.py tests/builtin/runtime/test_topic_memory_processing.py tests/builtin/runtime/test_topic_memory_application.py -q; uv run ruff check src/powercontext/builtin/inference/errors.py src/powercontext/builtin/inference/minimax.py tests/builtin/inference/test_minimax_embedding.py tests/builtin/runtime/test_composition_embedding.py; uv run ty check src/powercontext/builtin/inference/errors.py src/powercontext/builtin/inference/minimax.py tests/builtin/inference/test_minimax_embedding.py tests/builtin/runtime/test_composition_embedding.py; git diff --check. Co-authored-by: OmX <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue or RFC does this PR close?
Closes #1642.
Rationale for this change
MiniMax exposes
/v1/embeddingsunder an OpenAI-looking path but speaks a different dialect, so it cannot be used as an "OpenAI-compatible" embedding endpoint. PowerContext's only embedding path goes through Pydantic AI's OpenAI client, which sends{"model","input","dimensions"}and parses OpenAI's{data:[{embedding}]}. MiniMax requires{"model","texts","type"}and answers{"vectors","total_tokens","base_resp"}— returning HTTP 200 with a non-zerobase_resp.status_codeon business errors. The OpenAI client therefore fails while parsing, and the operator only sees a generic "provider rejected" message that does not point at the real cause.The result was that users who already run generation on
openai-chat:MiniMax-M3could not complete their inference configuration. This PR adds the missing adapter, which is the solution proposed in the issue.What changes are included in this PR?
New adapter —
src/powercontext/builtin/inference/minimax.pyMiniMaxEmbeddingModelis a self-containedEmbeddingModelimplementation that:texts+type: "db", with the provider prefix stripped frommodel);vectorsand validates the returned vector count against the number of inputs;InferenceUnavailableError, and a non-zerobase_resp.status_code(including the2013envelope from the issue) toInferenceUnavailableError/InvalidInferenceOutputError— so a null or partial vector is never handed to the index;httpx.AsyncClientregistered on the runtime exit stack, so it is closed with the rest of the resources;is_minimax_embedding()for host/prefix detection.Routing —
src/powercontext/builtin/runtime/composition.py_embedding_models()detects a MiniMax endpoint —api.minimaxi.com/api.minimax.iohost, or an explicitminimaxmodel prefix — and routes to the new adapter via a small_minimax_embedding_models()helper that mirrors the existing provider path (operational + readiness instances,EmbeddingProfile, batch size, timeout). The existing OpenAI/Anthropic path is untouched, and no new configuration knob is introduced. The existing base-URL guard in the helper was widened to also require the embedding model, which narrows the type for the profile construction.Tests
tests/builtin/inference/test_minimax_embedding.py(new) — request body shape, response parsing, thebase_respbusiness-error envelope, HTTP errors, and vector-count validation.tests/builtin/runtime/test_composition_embedding.py— routing test asserting that a MiniMax host selectsMiniMaxEmbeddingModeland that the request actually reaching the transport is the native shape.No change to the OpenAI embedding path, to any persisted format, or to the
EmbeddingProfilecontract.Are there any user-facing changes?
Yes, one — MiniMax can now be configured as an embedding backend using the existing generic variables:
Notes for reviewers:
openai:— selection is by base-URL host / model prefix, so no new provider name is needed and existing configs keep working.MODEL+PROFILE_ID+DIMENSIONremain a three-way contract, exactly as for every other embedding provider.docs/. A note listing MiniMax among supported embedding backends may be worth a follow-up.How was this change tested?
Beyond the unit tests, the change was validated end to end against the live MiniMax endpoint, on a personal server built from this branch:
/health/readyreportsinference.embedding: ready;POST /v1/memory/searchwithmode: "vector"using a query that shares no meaningful literal overlap with the stored text;"matched_by": ["vector"].Because retrieval only matched through the vector channel, this confirms that both the write-side and the query-side embeddings were really produced by MiniMax (1536 dimensions) rather than by any keyword path. The failing behaviour described in #1642 no longer reproduces.
AI usage statement
AI assistance: code. The adapter, the runtime routing, and the tests were drafted with an AI coding agent (WorkBuddy). The full diff was reviewed, and every command listed above was executed locally against the commit in this PR before submission.