Skip to content

Add MiniMax runner to the semantic-comparison factory - #682

Open
octo-patch wants to merge 1 commit into
Gentleman-Programming:mainfrom
octo-patch:octo/20260729-provider-add-recvq9LEXlx7Ts
Open

Add MiniMax runner to the semantic-comparison factory#682
octo-patch wants to merge 1 commit into
Gentleman-Programming:mainfrom
octo-patch:octo/20260729-provider-add-recvq9LEXlx7Ts

Conversation

@octo-patch

@octo-patch octo-patch commented Jul 29, 2026

Copy link
Copy Markdown

Reason: The semantic-comparison runner factory had no MiniMax runner or configuration for MiniMax-M3 and MiniMax-M2.7.

What changed

  • Add a MiniMaxRunner (internal/llm/minimax.go) that implements the existing AgentRunner interface by calling the MiniMax hosted chat completions API directly over HTTP. It sends the locked canonical comparison prompt as a single user message and parses the returned single-line Verdict JSON (markdown code fences are stripped), reusing the package's shared innerVerdict, validRelations, and fenceRE helpers.
  • Register the "minimax" identifier in the runner factory (internal/llm/factory.go) alongside the existing runners, and extend the ENGRAM_AGENT_CLI guidance in the CLI error message and --help output.
  • Configuration is read from the environment:
    • MINIMAX_API_KEY — bearer token (required at compare time; a missing key returns the existing auth-missing sentinel).
    • ENGRAM_MINIMAX_MODEL — text model id; defaults to MiniMax-M3. The configured ids are MiniMax-M3 and MiniMax-M2.7.
    • ENGRAM_MINIMAX_REGIONglobal_en (default, https://api.minimax.io/v1) or cn_zh (https://api.minimaxi.com/v1).
    • ENGRAM_MINIMAX_BASE_URL — optional explicit base URL override.
  • Application-level errors are surfaced clearly: a non-zero base_resp.status_code, a non-200 HTTP status, an empty choices list, malformed verdict JSON, and relations outside the locked vocabulary all return errors, reusing the package error sentinels where applicable.

Tests

  • New internal/llm/minimax_test.go covers golden parsing, fence stripping, request shape (method, path, authorization header, body), missing key, application and HTTP error paths, unknown relation, transport and timeout errors, and base-URL/model resolution. The HTTP round-trip is injected through a seam, so the tests make no network calls.
  • New factory test asserts NewRunner("minimax") returns a *MiniMaxRunner.

Checks

  • go build ./...
  • go vet ./internal/llm/ ./cmd/engram/
  • go test ./internal/llm/ ./cmd/engram/
  • gofmt -l on the changed files (clean)

Summary by CodeRabbit

  • New Features

    • Added MiniMax as a supported semantic scanning provider.
    • Added support for MiniMax M3 and M2.7 models.
    • Added configurable MiniMax region, endpoint, model, and API authentication settings.
    • Updated command-line help and error messages to document MiniMax support.
  • Tests

    • Added coverage for successful requests, configuration, response parsing, authentication, timeouts, and API errors.

Introduce a direct MiniMax HTTP runner that implements the AgentRunner
interface, register it under the "minimax" identifier in the runner
factory, and configure its text models and regional endpoints through
environment variables. Update the ENGRAM_AGENT_CLI guidance accordingly.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a MiniMax LLM runner with environment-based configuration, chat-completions requests, response parsing, error handling, factory registration, CLI help updates, and unit tests.

Changes

MiniMax runner integration

Layer / File(s) Summary
MiniMax runner implementation and validation
internal/llm/minimax.go, internal/llm/minimax_test.go
Adds MiniMax models, regional and environment-based endpoint resolution, authenticated request handling, verdict parsing, error mapping, and comprehensive HTTP/configuration tests.
Runner registration and CLI documentation
internal/llm/factory.go, internal/llm/factory_test.go, cmd/engram/llm.go, cmd/engram/main.go
Registers minimax with NewRunner, updates supported-value errors and comments, adds factory coverage, and documents the option in CLI messages and usage text.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested reviewers: gentleman-programming, alan-thegentleman

Sequence Diagram(s)

sequenceDiagram
  participant MiniMaxRunner
  participant MiniMaxAPI
  participant parseMiniMaxResponse
  participant Verdict
  MiniMaxRunner->>MiniMaxAPI: POST chat-completions request
  MiniMaxAPI-->>MiniMaxRunner: HTTP response body
  MiniMaxRunner->>parseMiniMaxResponse: Parse response envelope and inner verdict
  parseMiniMaxResponse-->>Verdict: Return structured verdict
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a MiniMax runner to the semantic-comparison factory.
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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/llm/minimax_test.go`:
- Around line 55-56: Remove the redundant package-level AgentRunner compile-time
assertion named TestMiniMaxRunner_CompileTimeCheck from minimax_test.go. Retain
the identical interface assertion already present in minimax.go, and do not
replace it with a runnable test.
- Around line 201-245: Extend the MiniMax runner tests with coverage for both
untested branches in parseMiniMaxResponse: add a malformed outer-envelope case
using invalid response JSON and assert ErrInvalidJSON, and add a response whose
envelope Model is empty but inner result Model is populated, then assert Compare
returns the inner model. Place these alongside the existing MiniMax runner tests
and preserve current fakeDo/http response patterns.

In `@internal/llm/minimax.go`:
- Around line 92-111: Validate configuration in miniMaxResolveModel and
miniMaxResolveBaseURL before returning values: accept only model identifiers
present in MiniMaxModelIDs, and accept only recognized region constants,
reporting invalid non-empty values through the existing configuration-error
mechanism instead of silently using defaults. Preserve the current default
model, global fallback for an unset region, and base-URL override behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ab21f643-0fca-4f37-8942-9cae3983f500

📥 Commits

Reviewing files that changed from the base of the PR and between 763a6ba and 570fe26.

📒 Files selected for processing (6)
  • cmd/engram/llm.go
  • cmd/engram/main.go
  • internal/llm/factory.go
  • internal/llm/factory_test.go
  • internal/llm/minimax.go
  • internal/llm/minimax_test.go

Comment on lines +55 to +56
// TestMiniMaxRunner_CompileTimeCheck verifies MiniMaxRunner satisfies AgentRunner.
var _ AgentRunner = (*MiniMaxRunner)(nil)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Misleading "Test" naming on a non-runnable compile-time check.

TestMiniMaxRunner_CompileTimeCheck is just a package-level var declaration, not an actual func Test...(t *testing.T), so it never appears in go test output despite the name suggesting a test. It also duplicates the identical check already present in minimax.go (line 169).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/llm/minimax_test.go` around lines 55 - 56, Remove the redundant
package-level AgentRunner compile-time assertion named
TestMiniMaxRunner_CompileTimeCheck from minimax_test.go. Retain the identical
interface assertion already present in minimax.go, and do not replace it with a
runnable test.

Comment on lines +201 to +245
timeoutErr := fmt.Errorf("Post: %w", context.DeadlineExceeded)
r := newTestRunner(fakeDo(nil, timeoutErr))
_, err := r.Compare(context.Background(), "compare")
if !errors.Is(err, ErrTimeout) {
t.Errorf("expected ErrTimeout; got %v", err)
}
}

// ─── configuration resolution ──────────────────────────────────────────────────

func TestMiniMaxResolveBaseURL(t *testing.T) {
t.Run("default is global", func(t *testing.T) {
t.Setenv("ENGRAM_MINIMAX_BASE_URL", "")
t.Setenv("ENGRAM_MINIMAX_REGION", "")
if got := miniMaxResolveBaseURL(); got != miniMaxBaseURLGlobal {
t.Errorf("baseURL = %q; want %q", got, miniMaxBaseURLGlobal)
}
})
t.Run("china region", func(t *testing.T) {
t.Setenv("ENGRAM_MINIMAX_BASE_URL", "")
t.Setenv("ENGRAM_MINIMAX_REGION", MiniMaxRegionChina)
if got := miniMaxResolveBaseURL(); got != miniMaxBaseURLChina {
t.Errorf("baseURL = %q; want %q", got, miniMaxBaseURLChina)
}
})
t.Run("explicit override wins", func(t *testing.T) {
t.Setenv("ENGRAM_MINIMAX_REGION", MiniMaxRegionChina)
t.Setenv("ENGRAM_MINIMAX_BASE_URL", "https://example.test/api/")
if got := miniMaxResolveBaseURL(); got != "https://example.test/api" {
t.Errorf("baseURL = %q; want trimmed override", got)
}
})
}

func TestMiniMaxResolveModel(t *testing.T) {
t.Run("default", func(t *testing.T) {
t.Setenv("ENGRAM_MINIMAX_MODEL", "")
if got := miniMaxResolveModel(); got != MiniMaxDefaultModel {
t.Errorf("model = %q; want %q", got, MiniMaxDefaultModel)
}
})
t.Run("override", func(t *testing.T) {
t.Setenv("ENGRAM_MINIMAX_MODEL", MiniMaxModelM27)
if got := miniMaxResolveModel(); got != MiniMaxModelM27 {
t.Errorf("model = %q; want %q", got, MiniMaxModelM27)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing test coverage for the outer-envelope decode-failure and model-fallback branches.

parseMiniMaxResponse in minimax.go has two untested branches: (1) the top-level json.Unmarshal(raw, &env) failure at line 203-205 of minimax.go — only the inner JSON invalid case (TestMiniMaxRunner_InvalidInnerJSON) is covered, not a malformed outer envelope; and (2) the Model fallback to iv.Model when env.Model == "" (minimax.go lines 233-236) is never exercised. Both are edge cases directly reachable from this runner.

🧪 Suggested additions
func TestMiniMaxRunner_MalformedEnvelope(t *testing.T) {
	r := newTestRunner(fakeDo(fakeHTTPResponse(http.StatusOK, "not json"), nil))
	_, err := r.Compare(context.Background(), "compare")
	if !errors.Is(err, ErrInvalidJSON) {
		t.Errorf("expected ErrInvalidJSON; got %v", err)
	}
}

func TestMiniMaxRunner_ModelFallbackToInner(t *testing.T) {
	inner := `{"Relation":"related","Confidence":0.5,"Reasoning":"x","Model":"MiniMax-M2.7"}`
	body := fmt.Sprintf(`{"choices":[{"message":{"content":%q}}],"base_resp":{"status_code":0}}`, inner)
	r := newTestRunner(fakeDo(fakeHTTPResponse(http.StatusOK, body), nil))
	v, err := r.Compare(context.Background(), "compare")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if v.Model != "MiniMax-M2.7" {
		t.Errorf("Model = %q; want fallback to inner Model", v.Model)
	}
}
As per path instructions, `**/*_test.go` files must "Verify coverage of happy path, error paths, and edge cases."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/llm/minimax_test.go` around lines 201 - 245, Extend the MiniMax
runner tests with coverage for both untested branches in parseMiniMaxResponse:
add a malformed outer-envelope case using invalid response JSON and assert
ErrInvalidJSON, and add a response whose envelope Model is empty but inner
result Model is populated, then assert Compare returns the inner model. Place
these alongside the existing MiniMax runner tests and preserve current
fakeDo/http response patterns.

Source: Path instructions

Comment thread internal/llm/minimax.go
Comment on lines +92 to +111
// miniMaxResolveBaseURL selects the base URL from the environment.
func miniMaxResolveBaseURL() string {
if v := strings.TrimSpace(os.Getenv("ENGRAM_MINIMAX_BASE_URL")); v != "" {
return strings.TrimRight(v, "/")
}
switch strings.TrimSpace(os.Getenv("ENGRAM_MINIMAX_REGION")) {
case MiniMaxRegionChina:
return miniMaxBaseURLChina
default:
return miniMaxBaseURLGlobal
}
}

// miniMaxResolveModel selects the model id from the environment.
func miniMaxResolveModel() string {
if v := strings.TrimSpace(os.Getenv("ENGRAM_MINIMAX_MODEL")); v != "" {
return v
}
return MiniMaxDefaultModel
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

No validation of resolved model/region against known constants.

miniMaxResolveModel accepts any ENGRAM_MINIMAX_MODEL value without validating it against MiniMaxModelIDs, and miniMaxResolveBaseURL's region switch silently falls back to the global endpoint on an unrecognized ENGRAM_MINIMAX_REGION value (e.g. a typo). Misconfiguration will only surface as an opaque API error at request time rather than a clear startup/config error.

♻️ Suggested validation
 func miniMaxResolveModel() string {
 	if v := strings.TrimSpace(os.Getenv("ENGRAM_MINIMAX_MODEL")); v != "" {
+		for _, id := range MiniMaxModelIDs {
+			if v == id {
+				return v
+			}
+		}
+		// fall through with a clear signal that the override isn't a known model
 		return v
 	}
 	return MiniMaxDefaultModel
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/llm/minimax.go` around lines 92 - 111, Validate configuration in
miniMaxResolveModel and miniMaxResolveBaseURL before returning values: accept
only model identifiers present in MiniMaxModelIDs, and accept only recognized
region constants, reporting invalid non-empty values through the existing
configuration-error mechanism instead of silently using defaults. Preserve the
current default model, global fallback for an unset region, and base-URL
override behavior.

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.

1 participant