feat(code-queue): register minimax-m3 alongside minimax-m2.7

Add minimax-m3 as a sibling model on the same path as the existing
minimax-m2.7 support. M3 is the new PROD default; M2.7 remains available
as a one-line rollback target via MINIMAX_MODEL.

Changes:
- code-agent/common.ts: add minimaxM3Model constant, include in
  defaultCodeModels, normalize aliases (minimax-m3 / m3), route to
  opencode port, sibling entry in codeModelProviderSourceContract.
- code-agent/opencode.ts: add M3 branch in openCodeModelId, register
  both M2.7 and M3 in openCodeConfigContent, inject MINIMAX_M3_MODEL
  in local/remote env, M3 branch in missingOpenCodeCredentialMessage.
- index.ts + types.ts: add minimaxM3Model to RuntimeConfig, read
  MINIMAX_M3_MODEL env, propagate to remoteCodexEnvKeys.
- queue-api.ts: include minimaxM3Model in Pick for
  codeModelProviderSourceContract callers.
- scripts/src/code-queue.ts: add minimaxM3SubmitModel, normalize/port
  routing, default route recommendation now points to M3, M2.7 kept
  as minimaxM2FallbackCandidate.
- scripts/src/docker.ts: default UNIDESK_CODE_QUEUE_MINIMAX_M3_MODEL
  to MiniMax-M3.
- k8s yaml (D601 + G14): CODE_QUEUE_MODELS gains minimax-m3, three
  deployments each set MINIMAX_MODEL=MiniMax-M3 and
  MINIMAX_M3_MODEL=MiniMax-M3.
- docker-compose.d601.yml: same env defaults for local compose.
- docs/reference/{code-queue-supervision,microservices,
  windows-passthrough}.md: update model contracts to M3 default +
  M2.7 fallback.
- scripts/code-queue-submit-routing-contract-test.ts: low-risk
  recommendation now asserts minimax-m3; registry asserts both M3
  and M2.7 fallback in modelPorts/opencodeModels; provider source
  contract test passes minimaxM3Model.

Refs: #189
This commit is contained in:
Codex
2026-06-01 06:51:28 +00:00
parent 0b1c012ba5
commit 201a8c8af2
14 changed files with 102 additions and 33 deletions
@@ -44,7 +44,7 @@ export function runCodeQueueSubmitRoutingContract(): JsonRecord {
const lowRisk = codexSubmitRoutingRecommendationForTest(lowRiskPrompt);
assertCondition(lowRisk.route === "minimax-opencode", "low-risk self-contained prompt should be a MiniMax candidate", lowRisk);
assertCondition(lowRisk.recommendedRunner === "opencode", "MiniMax candidate should recommend OpenCode", lowRisk);
assertCondition(lowRisk.recommendedModel === "minimax-m2.7", "MiniMax candidate should recommend minimax-m2.7", lowRisk);
assertCondition(lowRisk.recommendedModel === "minimax-m3", "MiniMax candidate should recommend minimax-m3 as new default", lowRisk);
assertCondition(asRecord(lowRisk.riskControls).promptSelfContained === true, "low-risk prompt should be self-contained", lowRisk);
assertCondition(asRecord(lowRisk.riskControls).issueIsNotOnlySource === true, "issue must not be the only source", lowRisk);
@@ -73,22 +73,25 @@ export function runCodeQueueSubmitRoutingContract(): JsonRecord {
assertCondition(externalProvider429.commanderAction === "wait-while-exponential-backoff-is-healthy", "429 policy should tell commander to wait on healthy backoff", policyContract);
assertCondition(Array.isArray(externalProvider429.interveneWhen), "429 policy should expose intervention conditions", policyContract);
const registry = codexSubmitModelRegistryForTest(["gpt-5.5", "deepseek", "minimax-m2.7"]);
const registry = codexSubmitModelRegistryForTest(["gpt-5.5", "deepseek", "minimax-m3", "minimax-m2.7"]);
const modelPorts = asRecord(registry.modelPorts);
assertCondition(modelPorts["deepseek-chat"] === "opencode", "modelPorts should route deepseek-chat to OpenCode", registry);
assertCondition(modelPorts["minimax-m2.7"] === "opencode", "modelPorts should keep MiniMax on OpenCode", registry);
assertCondition(modelPorts["minimax-m3"] === "opencode", "modelPorts should keep minimax-m3 on OpenCode", registry);
assertCondition(modelPorts["minimax-m2.7"] === "opencode", "modelPorts should keep minimax-m2.7 on OpenCode as fallback", registry);
assertCondition(modelPorts["gpt-5.5"] === "codex", "modelPorts should keep default GPT on Codex", registry);
assertCondition(registry.opencodeModels.includes("deepseek-chat"), "opencodeModels should include deepseek-chat", registry);
assertCondition(registry.opencodeModels.includes("minimax-m2.7"), "opencodeModels should include MiniMax", registry);
assertCondition(registry.opencodeModels.includes("minimax-m3"), "opencodeModels should include minimax-m3", registry);
assertCondition(registry.opencodeModels.includes("minimax-m2.7"), "opencodeModels should include minimax-m2.7 as fallback", registry);
assertCondition(registry.codexModels.includes("gpt-5.5"), "codexModels should include default GPT", registry);
const providerSource = codeModelProviderSourceContract({
codeModels: ["gpt-5.5", "deepseek", "minimax-m2.7"],
codeModels: ["gpt-5.5", "deepseek", "minimax-m3", "minimax-m2.7"],
deepseekApiBase: "https://api.deepseek.example",
deepseekApiKey: "ds-secret-must-not-print",
deepseekModel: "deepseek-chat",
minimaxApiBase: "https://api.minimax.example",
minimaxApiKey: "",
minimaxModel: "MiniMax-M2.7",
minimaxM3Model: "MiniMax-M3",
}, {
DEEPSEEK_API_KEY: "ds-secret-must-not-print",
DEEPSEEK_API_BASE: "https://api.deepseek.example",
@@ -121,10 +124,10 @@ export function runCodeQueueSubmitRoutingContract(): JsonRecord {
return {
ok: true,
checks: [
"low-risk self-contained prompts recommend minimax-m2.7/OpenCode",
"low-risk self-contained prompts recommend minimax-m3/OpenCode (new default)",
"runtime/core work recommends GPT-5.5/Codex",
"medium bounded frontend work recommends deepseek-chat/OpenCode",
"model registry maps deepseek-chat and minimax-m2.7 to OpenCode and GPT-5.5 to Codex",
"model registry maps deepseek-chat, minimax-m3, and minimax-m2.7 fallback to OpenCode and GPT-5.5 to Codex",
"model provider source contract exposes DeepSeek refs/presence without secret values",
"dry-run policy contract exposes model-tier concurrency",
"prod/restart/secret/DB work is commander-only",