fix(minimax): add region selector for international and China API endpoints#128
Conversation
📝 WalkthroughWalkthroughAdds MiniMax region support (international/china), surfaces region in settings UI, standardizes identifier names from "minimaxi" → "minimax", and makes provider/probe URLs region-aware while updating persistence and tests accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant SettingsView as SettingsView(UI)
participant Repo as ProviderSettingsRepository
participant Provider as MiniMaxProvider
participant Probe as MiniMaxUsageProbe
participant Net as Network
User->>SettingsView: Select region / Save & Test
SettingsView->>Repo: setMinimaxRegion(region)
SettingsView->>Repo: setMinimaxAuthEnvVar(envVar)
SettingsView->>Provider: request dashboard/api URLs
Provider->>Repo: minimaxRegion()
SettingsView->>Probe: run probe()
Probe->>Repo: minimaxAuthEnvVar()
Probe->>Repo: getMinimaxApiKey()
Probe->>Provider: request api base URL
Provider->>Repo: minimaxRegion()
Probe->>Net: HTTP request to region-specific API URL
Net-->>Probe: HTTP response
Probe-->>SettingsView: probe result
SettingsView-->>User: display result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
Tests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift (1)
30-39: Cover the “region not configured” path explicitly in tests.
makeProbealways sets a region (default.china), so fallback behavior for missingproviderConfig.minimaxRegionis never exercised.🧪 Suggested test-helper tweak
private func makeProbe( apiKey: String? = nil, envVar: String = "", - region: MiniMaxRegion = .china, + region: MiniMaxRegion? = nil, networkClient: any NetworkClient = MockNetworkClient() ) -> MiniMaxUsageProbe { let defaults = UserDefaults(suiteName: "MiniMaxProbeTests.\(UUID().uuidString)")! let settingsRepository = UserDefaultsProviderSettingsRepository(userDefaults: defaults) - settingsRepository.setMinimaxRegion(region) + if let region { + settingsRepository.setMinimaxRegion(region) + } settingsRepository.setMinimaxAuthEnvVar(envVar) if let apiKey { settingsRepository.saveMinimaxApiKey(apiKey) }`@Test` func `apiURL handles missing region configuration`() { let probe = makeProbe(apiKey: "test-key", region: nil) // Assert repository contract for absent region key. }Also applies to: 155-161
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Tests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift` around lines 30 - 39, makeProbe currently forces a region by using parameter region: MiniMaxRegion = .china and always calls settingsRepository.setMinimaxRegion(region), which prevents testing the "region not configured" path; change the makeProbe signature to accept an optional region (region: MiniMaxRegion? = .china) and update the body to only call settingsRepository.setMinimaxRegion(...) when region is non-nil (otherwise leave the repo unset or call the repo's removal/clear method), so tests can pass nil (e.g., makeProbe(region: nil)) to exercise MiniMaxUsageProbe behavior when providerConfig.minimaxRegion is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swift`:
- Around line 254-259: The current minimaxRegion() always returns .international
when the stored string is missing, which breaks legacy users; change the logic
in minimaxRegion() to detect a genuinely missing key by using
userDefaults.object(forKey: Keys.minimaxRegion) == nil and if the key is missing
return the legacy .minimaxi value, otherwise read the string
(userDefaults.string(forKey: Keys.minimaxRegion)) and map it via
MiniMaxRegion(rawValue: ...) falling back to .international only when a value
exists but is unrecognized; reference Keys.minimaxRegion, minimaxRegion(),
userDefaults, and MiniMaxRegion.
---
Nitpick comments:
In `@Tests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift`:
- Around line 30-39: makeProbe currently forces a region by using parameter
region: MiniMaxRegion = .china and always calls
settingsRepository.setMinimaxRegion(region), which prevents testing the "region
not configured" path; change the makeProbe signature to accept an optional
region (region: MiniMaxRegion? = .china) and update the body to only call
settingsRepository.setMinimaxRegion(...) when region is non-nil (otherwise leave
the repo unset or call the repo's removal/clear method), so tests can pass nil
(e.g., makeProbe(region: nil)) to exercise MiniMaxUsageProbe behavior when
providerConfig.minimaxRegion is missing.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
Sources/App/Views/SettingsView.swiftSources/Domain/Provider/MiniMax/MiniMaxProvider.swiftSources/Domain/Provider/MiniMax/MiniMaxRegion.swiftSources/Domain/Provider/ProviderSettingsRepository.swiftSources/Infrastructure/MiniMax/MiniMaxUsageProbe.swiftSources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swiftTests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift
| public func minimaxRegion() -> MiniMaxRegion { | ||
| guard let rawValue = userDefaults.string(forKey: Keys.minimaxRegion) else { | ||
| return .international // Default to international (默认国际版) | ||
| } | ||
| return MiniMaxRegion(rawValue: rawValue) ?? .international | ||
| } |
There was a problem hiding this comment.
Preserve legacy MiniMax behavior when region is unset.
When providerConfig.minimaxRegion is missing (typical on upgrade), defaulting directly to .international can break existing users who were previously on minimaxi.com only.
💡 Suggested migration-safe fallback
public func minimaxRegion() -> MiniMaxRegion {
- guard let rawValue = userDefaults.string(forKey: Keys.minimaxRegion) else {
- return .international // Default to international (默认国际版)
- }
- return MiniMaxRegion(rawValue: rawValue) ?? .international
+ if let rawValue = userDefaults.string(forKey: Keys.minimaxRegion),
+ let region = MiniMaxRegion(rawValue: rawValue) {
+ return region
+ }
+
+ // One-time inference for pre-region installs (legacy behavior was China endpoints).
+ let inferred: MiniMaxRegion =
+ (userDefaults.object(forKey: Keys.minimaxiApiKey) != nil ||
+ userDefaults.object(forKey: Keys.minimaxiAuthEnvVar) != nil)
+ ? .china : .international
+
+ userDefaults.set(inferred.rawValue, forKey: Keys.minimaxRegion)
+ return inferred
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public func minimaxRegion() -> MiniMaxRegion { | |
| guard let rawValue = userDefaults.string(forKey: Keys.minimaxRegion) else { | |
| return .international // Default to international (默认国际版) | |
| } | |
| return MiniMaxRegion(rawValue: rawValue) ?? .international | |
| } | |
| public func minimaxRegion() -> MiniMaxRegion { | |
| if let rawValue = userDefaults.string(forKey: Keys.minimaxRegion), | |
| let region = MiniMaxRegion(rawValue: rawValue) { | |
| return region | |
| } | |
| // One-time inference for pre-region installs (legacy behavior was China endpoints). | |
| let inferred: MiniMaxRegion = | |
| (userDefaults.object(forKey: Keys.minimaxiApiKey) != nil || | |
| userDefaults.object(forKey: Keys.minimaxiAuthEnvVar) != nil) | |
| ? .china : .international | |
| userDefaults.set(inferred.rawValue, forKey: Keys.minimaxRegion) | |
| return inferred | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Sources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swift`
around lines 254 - 259, The current minimaxRegion() always returns
.international when the stored string is missing, which breaks legacy users;
change the logic in minimaxRegion() to detect a genuinely missing key by using
userDefaults.object(forKey: Keys.minimaxRegion) == nil and if the key is missing
return the legacy .minimaxi value, otherwise read the string
(userDefaults.string(forKey: Keys.minimaxRegion)) and map it via
MiniMaxRegion(rawValue: ...) falling back to .international only when a value
exists but is unrecognized; reference Keys.minimaxRegion, minimaxRegion(),
userDefaults, and MiniMaxRegion.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #128 +/- ##
==========================================
+ Coverage 77.71% 78.10% +0.39%
==========================================
Files 78 79 +1
Lines 6013 6084 +71
==========================================
+ Hits 4673 4752 +79
+ Misses 1340 1332 -8
🚀 New features to boost your workflow:
|
8535b87 to
93abd26
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
Tests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift (1)
184-207: Consider asserting the request URL to fully validate region routing.This test verifies response parsing but not that
probe()actually sends the request tohttps://api.minimax.io/.... Since.request(.any)matches unconditionally, the international URL is never confirmed end-to-end. A captured-URL assertion would make the test a true integration check for region routing.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Tests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift` around lines 184 - 207, The test currently stubs network with given(mockNetwork).request(.any) so it never verifies which endpoint was called; change the stub to capture the actual URL request from the MockNetworkClient and assert it equals the international API URL. Concretely: in the test for probe uses international API URL when region is international replace the .request(.any) matcher with a capture/matcher that records the Request/URL argument (for example capture requestArg in the mock setup for MockNetworkClient.request), keep returning (responseData, httpResponse), then after calling let snapshot = try await probe.probe() add an assertion that the capturedRequest.url?.absoluteString (or capturedRequest.url) equals "https://api.minimax.io/v1/api/openplatform/coding_plan/remains" (or contains that host/path). Use existing helpers makeProbe(apiKey:region:networkClient:) and probe.probe() to locate where to add the capture and assertion.Sources/App/Views/SettingsView.swift (1)
1111-1113: Region change doesn't trigger a provider refresh, unlike other mode pickers.
codexProbeMode,kimiProbeMode, andclaudeProbeModeall callmonitor.refresh(providerId:)in theironChangehandlers. TheminiMaxRegionpicker persists the region but doesn't refresh, so the displayed quota data may reflect the old region's endpoint until the next background sync or manual "Save & Test". Consider adding a refresh here for consistency.📝 Proposed fix
.onChange(of: miniMaxRegion) { _, newValue in UserDefaultsProviderSettingsRepository.shared.setMinimaxRegion(newValue) + Task { + await monitor.refresh(providerId: ProviderID.minimax) + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/App/Views/SettingsView.swift` around lines 1111 - 1113, The miniMaxRegion onChange only persists the new region but doesn't refresh the provider; update the handler in SettingsView so after calling UserDefaultsProviderSettingsRepository.shared.setMinimaxRegion(newValue) it also calls monitor.refresh(providerId: <Minimax provider id constant>) to trigger an immediate refresh (use the same Minimax provider id constant used elsewhere in the repo, e.g., the one referenced when updating codexProbeMode/kimiProbeMode/claudeProbeMode).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/App/Views/SettingsView.swift`:
- Line 68: The `@State` default for miniMaxRegion is wrong for legacy users:
change the initial value of miniMaxRegion (declared as `@State` private var
miniMaxRegion: MiniMaxRegion) from .international to .china so the view does not
briefly show the incorrect selection before the value loaded in minimaxRegion()
is applied in .onAppear; update the initializer only (not the persisted logic)
to match the legacy default.
In `@Sources/Domain/Provider/ProviderSettingsRepository.swift`:
- Around line 198-199: Update the documentation for minimaxRegion() to reflect
the actual persisted default (.china) rather than “default: international”;
change the doc comment in ProviderSettingsRepository.swift for the
minimaxRegion() method to state that legacy/persisted default is .china (and
mention that SettingsView.swift currently uses an `@State` provisional
.international until onAppear corrects it) so the protocol contract matches the
concrete behavior.
---
Nitpick comments:
In `@Sources/App/Views/SettingsView.swift`:
- Around line 1111-1113: The miniMaxRegion onChange only persists the new region
but doesn't refresh the provider; update the handler in SettingsView so after
calling UserDefaultsProviderSettingsRepository.shared.setMinimaxRegion(newValue)
it also calls monitor.refresh(providerId: <Minimax provider id constant>) to
trigger an immediate refresh (use the same Minimax provider id constant used
elsewhere in the repo, e.g., the one referenced when updating
codexProbeMode/kimiProbeMode/claudeProbeMode).
In `@Tests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift`:
- Around line 184-207: The test currently stubs network with
given(mockNetwork).request(.any) so it never verifies which endpoint was called;
change the stub to capture the actual URL request from the MockNetworkClient and
assert it equals the international API URL. Concretely: in the test for probe
uses international API URL when region is international replace the
.request(.any) matcher with a capture/matcher that records the Request/URL
argument (for example capture requestArg in the mock setup for
MockNetworkClient.request), keep returning (responseData, httpResponse), then
after calling let snapshot = try await probe.probe() add an assertion that the
capturedRequest.url?.absoluteString (or capturedRequest.url) equals
"https://api.minimax.io/v1/api/openplatform/coding_plan/remains" (or contains
that host/path). Use existing helpers makeProbe(apiKey:region:networkClient:)
and probe.probe() to locate where to add the capture and assertion.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
Sources/App/Views/SettingsView.swiftSources/Domain/Provider/MiniMax/MiniMaxProvider.swiftSources/Domain/Provider/MiniMax/MiniMaxRegion.swiftSources/Domain/Provider/ProviderSettingsRepository.swiftSources/Infrastructure/MiniMax/MiniMaxUsageProbe.swiftSources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swiftTests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift
🚧 Files skipped from review as they are similar to previous changes (2)
- Sources/Domain/Provider/MiniMax/MiniMaxRegion.swift
- Sources/Domain/Provider/MiniMax/MiniMaxProvider.swift
|
Thanks @BryanQQYue, but can we add some uts for MiniMaxRegion which's missing? |
…API endpoints (tddworks#125) MiniMax provider previously hardcoded minimaxi.com URLs, which only works for China region users. This adds a MiniMaxRegion enum with international (minimax.io) and china (minimaxi.com) options, a region picker in Settings, and dynamic URL resolution throughout the probe and provider layers. - Add MiniMaxRegion enum with region-specific URLs - Add region selector (segmented picker) in MiniMax settings UI - Rename minimaxiXxx methods to minimaxXxx for consistent naming - Update MiniMaxUsageProbe to resolve API URL from configured region - Update MiniMaxProvider.dashboardURL to use region-aware URL - Add region-specific tests for API URL resolution Closes tddworks#125
93abd26 to
e3dd249
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (3)
Sources/Domain/Provider/ProviderSettingsRepository.swift (1)
197-222: LGTM — past doc-comment mismatch resolved, protocol surface is consistent.The
minimaxRegion()doc comment now correctly documents.chinaas the legacy default, the sub-protocol pattern is correctly applied, and all renamed methods align with the implementation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/Domain/Provider/ProviderSettingsRepository.swift` around lines 197 - 222, No code changes needed: the MiniMaxSettingsRepository protocol (methods minimaxRegion(), setMinimaxRegion(_:), minimaxAuthEnvVar(), setMinimaxAuthEnvVar(_:), saveMinimaxApiKey(_:), getMinimaxApiKey(), deleteMinimaxApiKey(), hasMinimaxApiKey()) is consistent with implementation and the doc comment correctly documents .china as the legacy default, so leave these declarations as-is.Sources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swift (1)
254-261: LGTM — legacy default correctly returns.chinain both fallback paths.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swift` around lines 254 - 261, No change required: the minimaxRegion() method correctly handles legacy defaults by returning .china when Keys.minimaxRegion is missing or when rawValue fails to initialize a MiniMaxRegion; leave the function minimaxRegion() and its use of userDefaults.string(forKey: Keys.minimaxRegion) and MiniMaxRegion(rawValue:) as-is.Sources/App/Views/SettingsView.swift (1)
68-68: LGTM —@Statedefault.chinanow matches the persisted legacy default.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/App/Views/SettingsView.swift` at line 68, No change required—the `@State` property miniMaxRegion should keep its default set to .china to match the persisted legacy default; verify that the declaration "@State private var miniMaxRegion: MiniMaxRegion = .china" remains as-is and ensure no other initializers override this default (check any init() or onAppear code that might set miniMaxRegion).
🧹 Nitpick comments (1)
Sources/App/Views/SettingsView.swift (1)
1111-1116: Add anAppLogcall for region changes to match observability of other picker changes.
copilotProbeMode(Line 1512) andclaudeProbeMode(Line 669) both emitAppLogon change; the region picker has no log, making it harder to diagnose region-related issues in the field.🔍 Proposed addition
.onChange(of: miniMaxRegion) { _, newValue in + AppLog.providers.info("MiniMax region changed to \(newValue.rawValue)") UserDefaultsProviderSettingsRepository.shared.setMinimaxRegion(newValue) Task { await monitor.refresh(providerId: ProviderID.minimax) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/App/Views/SettingsView.swift` around lines 1111 - 1116, Add an AppLog call inside the miniMaxRegion onChange handler to mirror other pickers: when miniMaxRegion changes (inside the closure that calls UserDefaultsProviderSettingsRepository.shared.setMinimaxRegion(newValue) and Task { await monitor.refresh(providerId: ProviderID.minimax) }), emit an AppLog entry including the newValue and a short context string like "minimax region changed" so region changes are observable in logs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@Sources/App/Views/SettingsView.swift`:
- Line 68: No change required—the `@State` property miniMaxRegion should keep its
default set to .china to match the persisted legacy default; verify that the
declaration "@State private var miniMaxRegion: MiniMaxRegion = .china" remains
as-is and ensure no other initializers override this default (check any init()
or onAppear code that might set miniMaxRegion).
In `@Sources/Domain/Provider/ProviderSettingsRepository.swift`:
- Around line 197-222: No code changes needed: the MiniMaxSettingsRepository
protocol (methods minimaxRegion(), setMinimaxRegion(_:), minimaxAuthEnvVar(),
setMinimaxAuthEnvVar(_:), saveMinimaxApiKey(_:), getMinimaxApiKey(),
deleteMinimaxApiKey(), hasMinimaxApiKey()) is consistent with implementation and
the doc comment correctly documents .china as the legacy default, so leave these
declarations as-is.
In `@Sources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swift`:
- Around line 254-261: No change required: the minimaxRegion() method correctly
handles legacy defaults by returning .china when Keys.minimaxRegion is missing
or when rawValue fails to initialize a MiniMaxRegion; leave the function
minimaxRegion() and its use of userDefaults.string(forKey: Keys.minimaxRegion)
and MiniMaxRegion(rawValue:) as-is.
---
Nitpick comments:
In `@Sources/App/Views/SettingsView.swift`:
- Around line 1111-1116: Add an AppLog call inside the miniMaxRegion onChange
handler to mirror other pickers: when miniMaxRegion changes (inside the closure
that calls
UserDefaultsProviderSettingsRepository.shared.setMinimaxRegion(newValue) and
Task { await monitor.refresh(providerId: ProviderID.minimax) }), emit an AppLog
entry including the newValue and a short context string like "minimax region
changed" so region changes are observable in logs.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
Sources/App/Views/SettingsView.swiftSources/Domain/Provider/MiniMax/MiniMaxProvider.swiftSources/Domain/Provider/MiniMax/MiniMaxRegion.swiftSources/Domain/Provider/ProviderSettingsRepository.swiftSources/Infrastructure/MiniMax/MiniMaxUsageProbe.swiftSources/Infrastructure/Storage/UserDefaultsProviderSettingsRepository.swiftTests/DomainTests/Provider/MiniMax/MiniMaxRegionTests.swiftTests/InfrastructureTests/MiniMax/MiniMaxUsageProbeTests.swift
🚧 Files skipped from review as they are similar to previous changes (2)
- Sources/Infrastructure/MiniMax/MiniMaxUsageProbe.swift
- Sources/Domain/Provider/MiniMax/MiniMaxRegion.swift
Summary
MiniMaxRegionenum supporting international (minimax.io) and China (minimaxi.com) API endpointsMiniMaxUsageProbeandMiniMaxProviderto dynamically resolve URLs based on configured regionminimaxiXxxmethods tominimaxXxxfor consistent naming conventionContext
MiniMax provider previously hardcoded
minimaxi.comURLs, which only works for China region users. International users atminimax.iocould not configure the provider properly. See MiniMax docs for the two region endpoints.Closes #125
Test plan
tuist build)tuist test), including new region-specific testsapi.minimax.ioapi.minimaxi.com🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes / UX
Tests