fix(providers): MiniMax system prompt fix + live integration tests for 11 providers - #622
Conversation
MiniMax's /v1/chat/completions endpoint rejects role: "system" (error 2013) and silently ignores the non-standard top-level "system" JSON field that was used as a workaround. System prompts were completely lost for MiniMax users. Replace apply_top_level_system_prompt with apply_system_prompt_rewrite which prepends system content to the first user message wrapped in [System Instructions] markers. This is the only reliable way to deliver system prompts to MiniMax models. Add 12 live API integration tests (MINIMAX_API_KEY) covering system prompt delivery, tool calling with null optional params, streaming, multi-turn tool use, model catalog liveness, and new model detection. Fixes #578, #592 Entire-Checkpoint: 20fc5a401287
Merging this PR will degrade performance by 46.32%
Performance Changes
Comparing Footnotes
|
10 integration tests hitting the real Moonshot API (MOONSHOT_API_KEY): system prompt delivery, tool calling (streaming + non-streaming), multi-turn tool use, probe, model catalog liveness, and new model detection via both /models endpoint and speculative probing. Documents known limitation: Moonshot's thinking mode requires the original reasoning_content to be replayed in multi-turn tool use, but ChatMessage doesn't carry this field. The gateway works around this by preserving raw JSON across turns. Entire-Checkpoint: 38b6463f463f
Greptile SummaryThis PR delivers two targeted bug fixes — MiniMax system prompt delivery (now correctly inlined into the first user message, with multimodal content handled) and the GPT-5/reasoning-model probe rejecting
Confidence Score: 5/5Safe to merge — both bug fixes are correct and well-tested; the sole remaining finding is a P2 cleanup of dead catalog entries that don't block the fix. All P0/P1 concerns from prior review rounds (Secret for API keys, multimodal content drop, all-secrets-in-env) are resolved. The only open item is a P2 suggestion to remove dead Anthropic/Fireworks catalog entries that the tests discovered; this doesn't affect correctness of the fixes or the test infrastructure. crates/providers/src/lib.rs — ANTHROPIC_MODELS and FIREWORKS_MODELS contain confirmed-dead model IDs that should be pruned. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[OpenAiProvider::serialize_messages_for_request] --> B[build request body]
B --> C{apply_system_prompt_rewrite}
C -->|rejects_system_role = false| D[No-op: pass body through]
C -->|rejects_system_role = true| E[Extract & remove system messages]
E --> F{First user message content type?}
F -->|String| G[Prepend system block to string]
F -->|Array multimodal| H[Insert text element at index 0]
F -->|Missing / other| I[Replace with synthetic system block]
E --> J{No user message at all?}
J -->|true| K[Insert synthetic user message with system block]
G & H & I & K --> L[Send to MiniMax API]
Reviews (3): Last reviewed commit: "fix(providers): handle multimodal conten..." | Re-trigger Greptile |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
9 integration tests hitting the real Fireworks API (FIREWORKS_API_KEY): system prompt delivery, tool calling (streaming + non-streaming), multi-turn tool use, probe, streaming, model catalog liveness, and model discovery via /models endpoint. Catalog health check found 4 of 7 models are dead/undeployed, and 11 new fireworks-native models are available. Entire-Checkpoint: 3cab30b2bdf5
Add integration tests for OpenAI (9 tests, OPENAI_API_KEY) and Anthropic (9 tests, ANTHROPIC_API_KEY) following the same pattern: system prompt, tool calling, multi-turn, streaming, probe, model catalog liveness, and model discovery via /models endpoint. Also make keyword assertions case-insensitive across all provider integration tests — some models lowercase the injected keyword while still correctly following the system prompt instruction. GitHub Copilot integration tests deferred: the provider uses OAuth device flow, not a plain API key, requiring stored tokens. Findings: - Anthropic: claude-3-7-sonnet-20250219 is 404 (dead) - OpenAI: 102 new chat-capable models not in our catalog Entire-Checkpoint: d1c3e7e56c47
GPT-5 models reject max_completion_tokens: 1 with a 400 error in the probe path. Use streaming reachability check instead so probe and catalog health tests pass. All 9 OpenAI integration tests now green. Entire-Checkpoint: 233ed0399ecc
GPT-5 and reasoning models reject max_completion_tokens values below ~10 with a 400 error instead of truncating. Raise the probe cap from 1 to 16 tokens so provider reachability checks succeed. Closes moltis-6lt Entire-Checkpoint: caf68aaad1db
Runs live API integration tests for MiniMax, Moonshot, Fireworks, Anthropic, and OpenAI on a daily schedule (06:00 UTC) and on manual dispatch. Each provider runs as a separate matrix job with max-parallel: 1 to avoid rate limits. Jobs are continue-on-error so a single provider outage doesn't fail the whole workflow. Secrets are checked before running — missing keys emit a warning and skip. Entire-Checkpoint: 10ba5757cbc7
…ests Add live API integration tests for three more providers: - Mistral (9 tests, MISTRAL_API_KEY): mistral-large-latest - OpenRouter (8 tests, OPENROUTER_API_KEY): openai/gpt-4o-mini - Kimi Code (8 tests, KIMI_API_KEY): kimi-k2.5 All follow the same pattern: system prompt, tool calling, multi-turn, streaming, probe, and model catalog. Add all three to the daily CI workflow matrix. Results: OpenRouter 8/8 pass, Mistral has transient 503s (API instability), Kimi Code needs active membership (402). Entire-Checkpoint: 271d9be8e07a
9 integration tests hitting the real DeepSeek API (DEEPSEEK_API_KEY): system prompt, tool calling, multi-turn, streaming, probe, model catalog liveness, and model discovery. All 9/9 pass. Added to the daily CI workflow matrix. Entire-Checkpoint: 10261dbded0d
9 integration tests for Google Gemini (GEMINI_API_KEY): system prompt, tool calling, multi-turn, streaming, probe, model catalog liveness, and model discovery. Handles Gemini's "models/" prefix in API model IDs. Added to daily CI workflow matrix. Model discovery found 30 new Gemini models not in catalog, and 2 preview models (gemini-2.5-flash/pro) promoted to stable names. Functional tests need billing enabled on the Google AI project. Entire-Checkpoint: 01cbf097d0e9
Z.AI (9 tests, Z_API_KEY): 9/9 pass. Found glm-4.7-flash and glm-4.7-flashx return 500. Discovered 2 new models (glm-5-turbo, glm-5.1). Gemini (9 tests, GEMINI_API_KEY): 9/9 pass with gemini-3.1-flash- lite-preview. Handles models/ prefix in API IDs. Multi-turn gracefully handles thought_signature requirement (same pattern as Moonshot reasoning_content). Found 30 new Gemini models and 4 dead catalog entries (older preview models removed). Both added to daily CI. Entire-Checkpoint: c69e8b227ce5
Replace raw std::env::var reads with api_key().expose_secret() in all provider integration test model discovery functions. This keeps API keys wrapped in Secret<T> until the point of use, consistent with the codebase's secrecy policy. Resolves Greptile review comment. Entire-Checkpoint: 8978a5453e28
…write The system prompt rewrite for MiniMax used as_str() which silently dropped multimodal (array) content. Now handles three cases: - String content: prepend system text as before - Array content (text + images): insert system text block at index 0 - Missing content: set system text directly Also scope CI secrets to only the relevant provider per matrix job instead of exposing all 11 API keys to every job. Resolves Greptile review comments. Entire-Checkpoint: b46f56af8196
Summary
Bug fix: MiniMax silently ignores the top-level
"system"JSON field — system prompts were completely lost. Now prepends system content to the first user message wrapped in[System Instructions]markers. Fixes #578, #592.Bug fix: GPT-5/reasoning model probe failed with
max_completion_tokens: 1rejected as 400. Bumped to 16 tokens.Live API integration tests for 11 providers (all
#[ignore]d, run with-- --ignored):MINIMAX_API_KEYMOONSHOT_API_KEYANTHROPIC_API_KEYOPENAI_API_KEYDEEPSEEK_API_KEYZ_API_KEYGEMINI_API_KEYOPENROUTER_API_KEYFIREWORKS_API_KEYMISTRAL_API_KEYKIMI_API_KEYEach suite covers: system prompt delivery, tool calling (streaming + non-streaming), multi-turn tool use, probe, streaming, model catalog liveness, and model discovery.
Daily CI workflow (
provider-integration.yml): runs all 11 providers sequentially at 06:00 UTC withmax-parallel: 1to avoid rate limits. Each provider iscontinue-on-errorso one outage doesn't fail the whole run. Missing secrets emit a warning and skip.Findings from integration tests
systemfield silently ignored (fixed), all 7 catalog models alivereasoning_contentrequired for multi-turnclaude-3-7-sonnet-20250219returns 404glm-4.7-flashandglm-4.7-flashxreturn 500, 2 new models (glm-5-turbo,glm-5.1)thought_signaturerequired for multi-turnValidation
Completed
cargo +nightly-2025-11-30 fmt --all -- --checkcargo +nightly-2025-11-30 clippy -p moltis-providers --all-targets --features local-llm-metal -- -D warningscargo test --workspace(all 270 provider unit tests + full workspace pass)cargo test --test minimax_integration -- --ignored(12/12)cargo test --test moonshot_integration -- --ignored(10/10)cargo test --test anthropic_integration -- --ignored(9/9)cargo test --test openai_integration -- --ignored(9/9)cargo test --test deepseek_integration -- --ignored(9/9)cargo test --test zai_integration -- --ignored(9/9)cargo test --test gemini_integration -- --ignored(9/9)cargo test --test openrouter_integration -- --ignored(8/8)Remaining
./scripts/local-validate.shgh workflow run provider-integration.ymlManual QA
invalid message role: system (2013)errorsFixes #578, #592
🤖 Generated with Claude Code