Skip to content

feat(models): add MiniMax OAuth provider flow #549

Merged
mrcfps merged 12 commits intomainfrom
feat/minimax-coding-plan
Mar 25, 2026
Merged

feat(models): add MiniMax OAuth provider flow #549
mrcfps merged 12 commits intomainfrom
feat/minimax-coding-plan

Conversation

@mrcfps
Copy link
Copy Markdown
Contributor

@mrcfps mrcfps commented Mar 25, 2026

Relates to #437

Summary

  • add MiniMax OAuth support across the controller and web models page, including provider state, OAuth status/login routes, OpenClaw sync updates, and model inventory handling
  • polish the MiniMax provider configuration UI by defaulting to OAuth login, improving reconnect/remove actions, and localizing the MiniMax-specific copy
  • remove the legacy custom BYOK provider path and tighten supported provider handling, plus a small home translation key fix

Summary by CodeRabbit

  • New Features

    • MiniMax OAuth: connect/login/cancel with region (Global/CN), status reporting; desktop and web provide start/status/cancel actions.
    • Provider auth modes: choose API Key or OAuth; UI shows OAuth flow and hides API-key inputs when OAuth selected.
  • Chores

    • Provider API and UI now surface OAuth state (hasOauthCredential, oauthRegion, oauthEmail).
    • Removed Custom provider option across UI/docs; BYOK/minimax defaults and compiled config updated for region-aware endpoints.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying nexu-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 69ecd38
Status: ✅  Deploy successful!
Preview URL: https://deb012d6.nexu-docs.pages.dev
Branch Preview URL: https://feat-minimax-coding-plan.nexu-docs.pages.dev

View logs

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds MiniMax OAuth endpoints and UI flows; extends provider schemas and stored provider records with authMode/oauth fields; removes the legacy "custom" provider flow; wires OAuth lifecycle into ModelProviderService, config store, auth-profile generation, desktop IPC, SDK/types, OpenClaw sync, and runtime restart handling.

Changes

Cohort / File(s) Summary
OpenAPI & Generated API
apps/controller/openapi.json, apps/web/lib/api/types.gen.ts, apps/web/lib/api/sdk.gen.ts
Tightened providerId to a fixed enum, added authMode/OAuth fields to provider shapes, and introduced MiniMax OAuth endpoints/types/SDK functions.
Shared Schemas
packages/shared/src/schemas/provider.ts
Added provider authMode and minimax region enums; added oauthCredential and MiniMax OAuth request/response schemas.
Controller Store & Schemas
apps/controller/src/store/schemas.ts, apps/controller/src/store/nexu-config-store.ts
Persisted provider records now include authMode, hasOauthCredential, oauthRegion, oauthEmail; added setProviderOauthCredentials() and upsert logic to clear OAuth on API-key mode.
Model Provider Service
apps/controller/src/services/model-provider-service.ts
Added MiniMax OAuth orchestration (PKCE, polling, token exchange), public APIs (getMiniMaxOauthStatus, startMiniMaxOauth, cancelMiniMaxOauth), and constructor now accepts full env, OpenClawSyncService, and OpenClawProcessManager; filters BYOK providers to supported set.
BYOK Provider List
apps/controller/src/lib/byok-providers.ts
New module exporting supportedByokProviderIds, SupportedByokProviderId type, and isSupportedByokProviderId() type guard.
OpenClaw Config Compiler
apps/controller/src/lib/openclaw-config-compiler.ts
Removed custom_ special-casing, added region-specific Minimax base URL selection, restricts compiled BYOK providers to supported IDs and to providers with API key or OAuth, and derives compiled apiKey from OAuth access when applicable.
Auth Profiles & Sync
apps/controller/src/runtime/openclaw-auth-profiles-writer.ts, apps/controller/src/services/openclaw-sync-service.ts
Auth profiles writer now emits oauth profiles and derived api_key entries from controller providers; OpenClawSyncService passes controller providers into the writer.
Routes
apps/controller/src/routes/model-routes.ts
Added MiniMax OAuth routes (GET /.../status, POST /.../login, DELETE /.../login); route param validation restricted to supported BYOK provider IDs.
Desktop IPC & Host Bridge
apps/desktop/main/ipc.ts, apps/desktop/shared/host.ts, apps/desktop/src/lib/host-api.ts
Added IPC handlers and host-invoke channels for MiniMax OAuth status/start/cancel; host API wrappers to call new channels.
Web UI — Models / Welcome
apps/web/src/pages/models.tsx, apps/web/src/pages/welcome.tsx
Added MiniMax OAuth UI (region selection, connect/cancel/reconnect flows); provider considered configured if API key or OAuth credential exists; removed custom provider option and related UI.
Model Picker & Runtime Plugin
apps/web/src/components/model-picker-dropdown.tsx, apps/controller/static/runtime-plugins/nexu-runtime-model/index.js
Removed custom provider grouping/handling and simplified runtime-plugin return (no custom_ early return).
Desktop Links Helper
apps/web/src/lib/desktop-links.ts
Added openExternalUrl() util that prefers host bridge shell:open-external with fallback to window.open.
I18n & Docs
apps/web/src/i18n/locales/en.ts, apps/web/src/i18n/locales/zh-CN.ts, docs/en/guide/models.md
Added MiniMax BYOK/OAuth localization keys; removed custom provider strings and docs.
Container / DI
apps/controller/src/app/container.ts
ModelProviderService instantiation now receives full env, openclawSyncService, and openclawProcess.
Tests & Minor UX
apps/controller/tests/openclaw-config-compiler.test.ts, tests/desktop/*, apps/desktop/src/components/surface-frame.tsx
Tests updated for removal of custom provider and new compiler behavior; added MiniMax OAuth tests; minor linting/unused var adjustments.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Desktop as Desktop UI
    participant Controller as Controller API
    participant MiniMax as MiniMax OAuth
    participant Store as Config Store
    participant Sync as OpenClaw Sync
    participant Runtime as OpenClaw Runtime

    User->>Desktop: Click "Connect MiniMax" (region)
    Desktop->>Controller: POST /api/v1/providers/minimax/oauth/login { region }
    Controller->>MiniMax: Create auth request (PKCE/state) → returns browserUrl
    Controller-->>Desktop: 200 { browserUrl, started: true }
    Desktop->>MiniMax: User authorizes in browser
    Note over Controller,MiniMax: Controller polls token endpoint until token received or aborted
    MiniMax-->>Controller: Returns access token & metadata
    Controller->>Store: setProviderOauthCredentials(minimax, oauthCredential)
    Store-->>Controller: Persisted provider record
    Controller->>Sync: openclawSyncService.syncAll()
    Sync->>Runtime: write auth-profiles (derived api_key + oauth profile)
    Controller->>Runtime: restart runtime if required
    Desktop-->>User: Show connected status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • nettee
  • lefarcen

Poem

🐰 I hopped into code with a tiny cheer,
MiniMax tokens now cozy and near.
Custom roots pruned with a tidy thump,
OAuth hop, profiles hum—no bump. ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description lacks required sections from the template: missing 'What', 'Why', 'How', 'Affected areas' checklist, 'Checklist' items, and 'Notes for reviewers'. Only 'Summary' is provided. Fill in all required template sections: clarify what MiniMax OAuth flow adds, explain the problem it solves, describe key design decisions, check affected areas, verify checklist items, and add reviewer notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 10.20% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(models): add MiniMax OAuth provider flow' clearly summarizes the main change: adding MiniMax OAuth support to the models system.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/minimax-coding-plan

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 and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69ecd38953

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/controller/src/services/model-provider-service.ts Outdated
Comment thread apps/controller/src/runtime/openclaw-auth-profiles-writer.ts Outdated
Comment thread apps/controller/src/runtime/openclaw-auth-profiles-writer.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/shared/src/schemas/provider.ts (1)

28-34: ⚠️ Potential issue | 🟠 Major

Don't expose OAuth on every provider update contract.

upsertProviderBodySchema backs the generic /providers/{providerId} update route, so this makes the SDK/OpenAPI advertise authMode: "oauth" for every provider even though this PR only implements MiniMax OAuth. Split out a MiniMax-specific body schema, or add a route-level refinement keyed by providerId, so unsupported providers cannot accept an impossible auth mode.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared/src/schemas/provider.ts` around lines 28 - 34, The generic
upsertProviderBodySchema currently exposes providerAuthModeSchema (which
includes "oauth") for every provider and thus advertises OAuth support on the
generic /providers/{providerId} update route; fix by removing OAuth from the
generic contract and scoping OAuth to MiniMax-specific updates: create a new
minimaxUpsertProviderBodySchema that mirrors upsertProviderBodySchema but allows
authMode: providerAuthModeSchema (including "oauth"), keep the existing
upsertProviderBodySchema but constrain its authMode to the non-OAuth subset (or
make authMode optional without "oauth"), and update the route handlers to use
minimaxUpsertProviderBodySchema only for the MiniMax providerId (or add a
route-level refinement that validates providerId === "minimax" before accepting
authMode "oauth").
🧹 Nitpick comments (5)
apps/controller/src/store/nexu-config-store.ts (1)

977-980: Redundant OAuth field clearing.

Lines 952-955 already conditionally set oauthRegion and oauthCredential to null when input.authMode === "apiKey". The clearing at lines 977-980 duplicates this for the same condition. Consider removing this redundant block.

♻️ Proposed fix
-      if (nextProvider.authMode === "apiKey") {
-        nextProvider.oauthRegion = null;
-        nextProvider.oauthCredential = null;
-      }
-
       created = existing === undefined;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/store/nexu-config-store.ts` around lines 977 - 980,
Remove the duplicate OAuth-clearing block by deleting the redundant conditional
that sets nextProvider.oauthRegion = null and nextProvider.oauthCredential =
null for nextProvider.authMode === "apiKey"; keep the original conditional that
handles input.authMode === "apiKey" (which already clears these fields) so OAuth
fields are cleared in one place only (refer to nextProvider and input.authMode
to locate the duplicates).
apps/controller/src/runtime/openclaw-auth-profiles-writer.ts (1)

195-213: Verify necessity of dual auth profile writes.

This writes auth profiles to both the workspace path and ~/.openclaw/agents/{agentId}/agent/auth-profiles.json. The condition defaultUserAgentAuthProfilesPath !== authProfilesPath will almost always be true since they're derived from different base paths.

Is the dual write intentional to support different OpenClaw resolution paths? If so, consider adding a brief comment explaining why both locations are needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/runtime/openclaw-auth-profiles-writer.ts` around lines
195 - 213, The code is writing auth profiles to two locations via
defaultUserAgentAuthProfilesPath and authProfilesPath and the condition
defaultUserAgentAuthProfilesPath !== authProfilesPath will almost always be
true; either add a short clarifying comment above the block explaining that the
dual write to ~/.openclaw/agents/{agent.id}/agent/auth-profiles.json is
intentional to support alternate OpenClaw resolution paths (referencing
defaultUserAgentAuthProfilesPath, authProfilesPath, and agent.id), or if the
duplicate write is not required remove the mkdir/writeFile block (the mkdir,
writeFile calls and the defaultUserAgentAuthProfilesPath variable) so we only
write to authProfilesPath.
apps/controller/src/services/model-provider-service.ts (2)

766-766: Unbounded poll interval growth could delay final attempts.

The interval grows via pollIntervalMs * 1.5 up to 10 seconds. While capped, if the user completes authorization just before expiry, the long interval could cause a missed window. Consider whether a tighter cap (e.g., 5 seconds) would improve UX.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/services/model-provider-service.ts` at line 766, The poll
interval growth currently caps at 10000ms causing potentially long waits; change
the cap to a tighter value (e.g., 5000ms) or make it configurable to improve UX
by replacing the hardcoded 10000 with a new constant or config (e.g.,
POLL_INTERVAL_MAX_MS = 5000) where pollIntervalMs is updated (the line using
pollIntervalMs = Math.min(pollIntervalMs * 1.5, 10000)); update any related
docs/comments and tests to reflect the new cap or config parameter.

174-235: Consider simplifying OpenClaw command resolution.

The getOpenClawCommandSpec function has complex path resolution logic with multiple fallbacks (Electron executable, workspace root detection, various entry points). While functional, this could be fragile if directory structures change.

Consider documenting the expected directory layouts or consolidating the resolution paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/services/model-provider-service.ts` around lines 174 -
235, getOpenClawCommandSpec: simplify and harden OpenClaw resolution by
consolidating fallbacks and adding clear expectations: update
getOpenClawCommandSpec to first check OPENCLAW_ELECTRON_EXECUTABLE and return
electronExec with ELECTRON_RUN_AS_NODE, then if env.openclawBin appears to be a
path (absolute or contains path.sep) return it directly; if not, attempt
workspace-based resolution by computing workspaceRoot via NEXU_WORKSPACE_ROOT or
findWorkspaceRoot(process.cwd()) and then check for a single canonical runtime
entry (runtimeEntryPath) and a single canonical wrapper (wrapperPath) in a clear
priority order (runtimeEntryPath -> wrapperPath), and finally fall back to
returning env.openclawBin; document expected directory layout for
runtimeEntryPath and wrapperPath in a short comment inside the function and
remove any duplicate/fragile path constructions to keep paths deterministic.
apps/web/src/pages/models.tsx (1)

119-142: Host bridge helper duplicates pattern from desktop-links.ts.

This helper duplicates the pattern from apps/web/src/lib/desktop-links.ts. Consider extracting a shared getHostInvokeBridge utility to avoid duplication, though this is a minor refactor opportunity.

♻️ Optional: Extract shared host bridge helper

The getModelsHostInvokeBridge could be consolidated with the similar pattern in desktop-links.ts into a shared utility in apps/web/src/lib/ that returns a properly typed bridge based on the channels needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/pages/models.tsx` around lines 119 - 142, The function
getModelsHostInvokeBridge duplicates the host-invoke detection logic; extract a
shared utility (e.g. getHostInvokeBridge) that encapsulates the window check,
candidate retrieval, Reflect.get("invoke") validation, and typed invoke wrapper,
then replace getModelsHostInvokeBridge with a thin wrapper that calls
getHostInvokeBridge and narrows the returned bridge to ModelsHostInvokeBridge
(preserving the same invoke signature); update the other duplicating
implementation (desktop-links' equivalent) to reuse getHostInvokeBridge as well
so both callers share the single implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/controller/src/lib/byok-providers.ts`:
- Around line 1-11: The allowlist supportedByokProviderIds is missing "moonshot"
and "zai", which breaks validation (z.enum(supportedByokProviderIds)) and
runtime checks (isSupportedByokProviderId()) while those providers remain
configured elsewhere (model-provider-service.ts, openclaw-config-compiler.ts,
apps/web pages). Fix by adding "moonshot" and "zai" to the exported
supportedByokProviderIds const so the enum and checks accept them, or
alternatively implement a migration in model-provider-service (or config
compiler) to map existing "moonshot" -> "kimi" and "zai" -> "glm" before
validation; update references to isSupportedByokProviderId() and any validation
sites to use the chosen approach so existing configs are preserved.

In `@apps/controller/src/routes/model-routes.ts`:
- Around line 18-20: providerIdParamSchema was tightened to
z.enum(supportedByokProviderIds) removing "custom", so update the tests that
still expect providerId="custom" (tests named openclaw-config-compiler.test and
openclaw-auth-service.test) to use one of the supported provider IDs from
supportedByokProviderIds or adjust the tests to expect a 422 validation error;
locate occurrences of "custom" in those test files and replace with a valid
provider constant or change assertions accordingly to match
providerIdParamSchema behavior.

In `@apps/controller/src/services/model-provider-service.ts`:
- Around line 571-586: The code passes OAuth's expired_in (a relative duration
in seconds) directly to pollMiniMaxOAuthToken causing an immediate timeout;
update finishMiniMaxOauthLogin to convert auth.expired_in into an absolute
expiration timestamp in milliseconds (e.g., Date.now() + auth.expired_in * 1000)
before passing it as the expiresAt argument so pollMiniMaxOAuthToken receives a
proper epoch-ms expiry value.

In `@apps/desktop/src/components/surface-frame.tsx`:
- Around line 97-98: Replace the `void title; void description;` pattern by
renaming the unused props in the SurfaceFrame component signature to use an
underscore prefix (e.g. _title and _description) and remove those void
statements; update any references accordingly so the props are clearly marked
unused (or optionally used for aria-label) while avoiding the void statements.

In `@packages/shared/src/schemas/provider.ts`:
- Around line 73-75: The minimaxOauthStartBodySchema currently allows region:
"cn" but downstream code (the minimax sync path used in
openclaw-config-compiler.ts) is hard-coded to the global endpoint; update
minimaxOauthStartBodySchema (which uses minimaxOauthRegionSchema) to prevent
acceptance of region === "cn" until a region-aware sync path is implemented,
e.g., add a schema refinement that throws a validation error when region ===
"cn" (or alternately require an explicit region-specific syncPath field and
validate it) so CN OAuth logins cannot proceed with the wrong sync endpoint.

---

Outside diff comments:
In `@packages/shared/src/schemas/provider.ts`:
- Around line 28-34: The generic upsertProviderBodySchema currently exposes
providerAuthModeSchema (which includes "oauth") for every provider and thus
advertises OAuth support on the generic /providers/{providerId} update route;
fix by removing OAuth from the generic contract and scoping OAuth to
MiniMax-specific updates: create a new minimaxUpsertProviderBodySchema that
mirrors upsertProviderBodySchema but allows authMode: providerAuthModeSchema
(including "oauth"), keep the existing upsertProviderBodySchema but constrain
its authMode to the non-OAuth subset (or make authMode optional without
"oauth"), and update the route handlers to use minimaxUpsertProviderBodySchema
only for the MiniMax providerId (or add a route-level refinement that validates
providerId === "minimax" before accepting authMode "oauth").

---

Nitpick comments:
In `@apps/controller/src/runtime/openclaw-auth-profiles-writer.ts`:
- Around line 195-213: The code is writing auth profiles to two locations via
defaultUserAgentAuthProfilesPath and authProfilesPath and the condition
defaultUserAgentAuthProfilesPath !== authProfilesPath will almost always be
true; either add a short clarifying comment above the block explaining that the
dual write to ~/.openclaw/agents/{agent.id}/agent/auth-profiles.json is
intentional to support alternate OpenClaw resolution paths (referencing
defaultUserAgentAuthProfilesPath, authProfilesPath, and agent.id), or if the
duplicate write is not required remove the mkdir/writeFile block (the mkdir,
writeFile calls and the defaultUserAgentAuthProfilesPath variable) so we only
write to authProfilesPath.

In `@apps/controller/src/services/model-provider-service.ts`:
- Line 766: The poll interval growth currently caps at 10000ms causing
potentially long waits; change the cap to a tighter value (e.g., 5000ms) or make
it configurable to improve UX by replacing the hardcoded 10000 with a new
constant or config (e.g., POLL_INTERVAL_MAX_MS = 5000) where pollIntervalMs is
updated (the line using pollIntervalMs = Math.min(pollIntervalMs * 1.5, 10000));
update any related docs/comments and tests to reflect the new cap or config
parameter.
- Around line 174-235: getOpenClawCommandSpec: simplify and harden OpenClaw
resolution by consolidating fallbacks and adding clear expectations: update
getOpenClawCommandSpec to first check OPENCLAW_ELECTRON_EXECUTABLE and return
electronExec with ELECTRON_RUN_AS_NODE, then if env.openclawBin appears to be a
path (absolute or contains path.sep) return it directly; if not, attempt
workspace-based resolution by computing workspaceRoot via NEXU_WORKSPACE_ROOT or
findWorkspaceRoot(process.cwd()) and then check for a single canonical runtime
entry (runtimeEntryPath) and a single canonical wrapper (wrapperPath) in a clear
priority order (runtimeEntryPath -> wrapperPath), and finally fall back to
returning env.openclawBin; document expected directory layout for
runtimeEntryPath and wrapperPath in a short comment inside the function and
remove any duplicate/fragile path constructions to keep paths deterministic.

In `@apps/controller/src/store/nexu-config-store.ts`:
- Around line 977-980: Remove the duplicate OAuth-clearing block by deleting the
redundant conditional that sets nextProvider.oauthRegion = null and
nextProvider.oauthCredential = null for nextProvider.authMode === "apiKey"; keep
the original conditional that handles input.authMode === "apiKey" (which already
clears these fields) so OAuth fields are cleared in one place only (refer to
nextProvider and input.authMode to locate the duplicates).

In `@apps/web/src/pages/models.tsx`:
- Around line 119-142: The function getModelsHostInvokeBridge duplicates the
host-invoke detection logic; extract a shared utility (e.g. getHostInvokeBridge)
that encapsulates the window check, candidate retrieval, Reflect.get("invoke")
validation, and typed invoke wrapper, then replace getModelsHostInvokeBridge
with a thin wrapper that calls getHostInvokeBridge and narrows the returned
bridge to ModelsHostInvokeBridge (preserving the same invoke signature); update
the other duplicating implementation (desktop-links' equivalent) to reuse
getHostInvokeBridge as well so both callers share the single implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32884e05-63ad-4f57-8b06-c2489ab4f55d

📥 Commits

Reviewing files that changed from the base of the PR and between 8129ff5 and 69ecd38.

⛔ Files ignored due to path filters (2)
  • apps/controller/static/runtime-plugins/openclaw-weixin/package-lock.json is excluded by !**/package-lock.json
  • openclaw-runtime/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (28)
  • apps/controller/openapi.json
  • apps/controller/src/app/container.ts
  • apps/controller/src/lib/byok-providers.ts
  • apps/controller/src/lib/openclaw-config-compiler.ts
  • apps/controller/src/routes/model-routes.ts
  • apps/controller/src/runtime/openclaw-auth-profiles-writer.ts
  • apps/controller/src/services/model-provider-service.ts
  • apps/controller/src/services/openclaw-sync-service.ts
  • apps/controller/src/store/nexu-config-store.ts
  • apps/controller/src/store/schemas.ts
  • apps/controller/static/runtime-plugins/nexu-runtime-model/index.js
  • apps/controller/tests/openclaw-config-compiler.test.ts
  • apps/desktop/main/ipc.ts
  • apps/desktop/shared/host.ts
  • apps/desktop/src/components/surface-frame.tsx
  • apps/desktop/src/lib/host-api.ts
  • apps/web/lib/api/sdk.gen.ts
  • apps/web/lib/api/types.gen.ts
  • apps/web/src/components/model-picker-dropdown.tsx
  • apps/web/src/i18n/locales/en.ts
  • apps/web/src/i18n/locales/zh-CN.ts
  • apps/web/src/lib/desktop-links.ts
  • apps/web/src/pages/home.tsx
  • apps/web/src/pages/models.tsx
  • apps/web/src/pages/welcome.tsx
  • docs/en/guide/models.md
  • packages/shared/src/schemas/provider.ts
  • tests/desktop/nexu-runtime-model-plugin.test.ts
💤 Files with no reviewable changes (4)
  • docs/en/guide/models.md
  • apps/controller/static/runtime-plugins/nexu-runtime-model/index.js
  • tests/desktop/nexu-runtime-model-plugin.test.ts
  • apps/web/src/pages/welcome.tsx

Comment thread apps/controller/src/lib/byok-providers.ts
Comment thread apps/controller/src/routes/model-routes.ts
Comment thread apps/controller/src/services/model-provider-service.ts
Comment thread apps/desktop/src/components/surface-frame.tsx Outdated
Comment thread packages/shared/src/schemas/provider.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd53715b86

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/controller/src/lib/openclaw-config-compiler.ts
Comment thread apps/controller/src/services/model-provider-service.ts
@mrcfps mrcfps changed the title feat(models): add MiniMax OAuth provider flow fix: add MiniMax OAuth support and align provider/runtime integrations Mar 25, 2026
@mrcfps mrcfps changed the title fix: add MiniMax OAuth support and align provider/runtime integrations feat(models): add MiniMax OAuth provider flow Mar 25, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/controller/src/services/model-provider-service.ts (3)

738-741: Consider wrapping JSON.parse for clearer error messages.

JSON.parse(text) will throw a generic syntax error if the server returns malformed JSON (e.g., HTML error page). While the outer try-catch in finishMiniMaxOauthLogin handles this, wrapping the parse would provide a more descriptive error.

♻️ Suggested improvement
       const text = await response.text();
-      const payload =
-        text.length > 0 ? (JSON.parse(text) as Record<string, unknown>) : {};
+      let payload: Record<string, unknown> = {};
+      if (text.length > 0) {
+        try {
+          payload = JSON.parse(text) as Record<string, unknown>;
+        } catch {
+          throw new Error("MiniMax OAuth returned invalid JSON response");
+        }
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/services/model-provider-service.ts` around lines 738 -
741, Wrap the JSON.parse call that builds payload in a small try-catch to
provide a clearer error message that includes the raw response body; inside
finishMiniMaxOauthLogin (where const text = await response.text() and const
payload = ... JSON.parse(text) ... are used) replace the direct JSON.parse with
a guarded parse that catches SyntaxError and throws/returns a new error
describing "failed to parse JSON response" and include the text (or attach it)
so callers can see the malformed server response.

786-810: Consider adding a timeout to prevent indefinite hangs.

execOpenClawCommand has no timeout. If the OpenClaw process hangs (e.g., waiting for input or encountering a deadlock), this promise will never resolve, potentially blocking the OAuth flow indefinitely.

♻️ Suggested improvement
+const OPENCLAW_COMMAND_TIMEOUT_MS = 30_000;
+
 private async execOpenClawCommand(args: string[]): Promise<void> {
   const spec = getOpenClawCommandSpec(this.env);
   await new Promise<void>((resolve, reject) => {
-    execFile(
+    const child = execFile(
       spec.command,
       [...spec.argsPrefix, ...args],
       {
         cwd: this.env.openclawStateDir,
         env: {
           ...process.env,
           ...spec.extraEnv,
           OPENCLAW_CONFIG_PATH: this.env.openclawConfigPath,
           OPENCLAW_STATE_DIR: this.env.openclawStateDir,
         },
+        timeout: OPENCLAW_COMMAND_TIMEOUT_MS,
       },
       (error) => {
         if (error) {
           reject(error);
           return;
         }
         resolve();
       },
     );
   });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/services/model-provider-service.ts` around lines 786 -
810, The execOpenClawCommand function can hang because execFile is called
without a timeout; modify execOpenClawCommand to enforce a configurable timeout
(e.g., from this.env or a constant) and reject when exceeded, ensuring the child
process is killed: use execFile's options.timeout or switch to spawn to track
the ChildProcess, set a timer that calls child.kill() and rejects with a clear
TimeoutError, and clear the timer on normal exit; update any call-sites if you
add a timeout parameter and keep references to getOpenClawCommandSpec and
execOpenClawCommand when locating the code.

90-95: Order-sensitive comparison may be fragile.

hasSameModels compares arrays by index, which will return false if the same models appear in different order. This works currently since it compares against constant arrays (MINI_MAX_OAUTH_MODELS), but could cause unexpected refresh loops if the stored model order ever diverges.

♻️ Alternative using sets for order-insensitive comparison
 function hasSameModels(current: string[], expected: string[]): boolean {
-  return (
-    current.length === expected.length &&
-    current.every((model, index) => model === expected[index])
-  );
+  if (current.length !== expected.length) {
+    return false;
+  }
+  const expectedSet = new Set(expected);
+  return current.every((model) => expectedSet.has(model));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/services/model-provider-service.ts` around lines 90 - 95,
The hasSameModels function is currently order-sensitive and can falsely return
false if the same model names are shuffled; update hasSameModels to perform an
order-insensitive comparison by comparing either sets or by sorting both arrays
before comparison (e.g., convert current and expected to sets and check sizes
and membership, or sort and then compare lengths and elements). Change the
implementation inside hasSameModels (used when comparing against constants like
MINI_MAX_OAUTH_MODELS) so it first normalizes order (or uses a Set) and then
compares equality to avoid refresh loops when stored model order differs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/desktop/openclaw-auth-profiles-writer.test.ts`:
- Around line 58-59: The test mock for ControllerEnv is missing the
analyticsStatePath property used by createEnv; update the test env object used
in openclaw-auth-profiles-writer.test (the mock passed to createEnv) to include
analyticsStatePath (e.g., a string path or undefined if allowed) so the mock
conforms to the ControllerEnv shape and satisfies pnpm typecheck.

---

Nitpick comments:
In `@apps/controller/src/services/model-provider-service.ts`:
- Around line 738-741: Wrap the JSON.parse call that builds payload in a small
try-catch to provide a clearer error message that includes the raw response
body; inside finishMiniMaxOauthLogin (where const text = await response.text()
and const payload = ... JSON.parse(text) ... are used) replace the direct
JSON.parse with a guarded parse that catches SyntaxError and throws/returns a
new error describing "failed to parse JSON response" and include the text (or
attach it) so callers can see the malformed server response.
- Around line 786-810: The execOpenClawCommand function can hang because
execFile is called without a timeout; modify execOpenClawCommand to enforce a
configurable timeout (e.g., from this.env or a constant) and reject when
exceeded, ensuring the child process is killed: use execFile's options.timeout
or switch to spawn to track the ChildProcess, set a timer that calls
child.kill() and rejects with a clear TimeoutError, and clear the timer on
normal exit; update any call-sites if you add a timeout parameter and keep
references to getOpenClawCommandSpec and execOpenClawCommand when locating the
code.
- Around line 90-95: The hasSameModels function is currently order-sensitive and
can falsely return false if the same model names are shuffled; update
hasSameModels to perform an order-insensitive comparison by comparing either
sets or by sorting both arrays before comparison (e.g., convert current and
expected to sets and check sizes and membership, or sort and then compare
lengths and elements). Change the implementation inside hasSameModels (used when
comparing against constants like MINI_MAX_OAUTH_MODELS) so it first normalizes
order (or uses a Set) and then compares equality to avoid refresh loops when
stored model order differs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1d45c9ea-1b7c-4659-8b39-7b6caafc3f00

📥 Commits

Reviewing files that changed from the base of the PR and between bd53715 and 41c4554.

📒 Files selected for processing (6)
  • apps/controller/src/lib/byok-providers.ts
  • apps/controller/src/lib/openclaw-config-compiler.ts
  • apps/controller/src/runtime/openclaw-auth-profiles-writer.ts
  • apps/controller/src/services/model-provider-service.ts
  • apps/controller/tests/openclaw-config-compiler.test.ts
  • tests/desktop/openclaw-auth-profiles-writer.test.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/controller/src/lib/byok-providers.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/controller/src/runtime/openclaw-auth-profiles-writer.ts

Comment thread tests/desktop/openclaw-auth-profiles-writer.test.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41c455416a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/controller/src/runtime/openclaw-auth-profiles-writer.ts
Comment thread apps/desktop/main/ipc.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/controller/src/services/model-provider-service.ts (1)

419-435: ⚠️ Potential issue | 🟠 Major

Don't mark arbitrary MiniMax /models failures as valid.

Line 420 promotes any 404 to valid: true, and Lines 433-435 do the same for any 200 response without a data array. A mistyped or custom base URL can therefore pass verification and only fail later at runtime. Restrict the static-model fallback to the canonical MiniMax hosts, or to some other positive MiniMax-specific probe.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/controller/src/services/model-provider-service.ts` around lines 419 -
435, The current verification in model-provider-service.ts incorrectly treats
any MiniMax 404 or missing-data 200 as valid; update the validation in the code
paths around the fetch response handling (the block that returns { valid: true,
models: MINI_MAX_API_MODELS } and the payload.data fallback) to only allow the
static MINI_MAX_API_MODELS fallback when the request is actually against a
canonical MiniMax host (e.g., inspect response.url or the provider's configured
baseUrl for an authorized MiniMax hostname) or after a dedicated
MiniMax-specific probe succeeds; otherwise return valid: false with the HTTP
error or an explicit invalid-provider error to avoid accepting mistyped/custom
endpoints. Ensure the checks are applied both in the !response.ok branch and the
payload.data absence branch (the logic that currently maps payload.data or falls
back to MINI_MAX_API_MODELS).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/controller/src/services/model-provider-service.ts`:
- Around line 463-517: Concurrent startMiniMaxOauth calls can race when earlier
attempts clear shared fields; fix by tagging each attempt and validating before
any mutation: in startMiniMaxOauth create a unique attempt id (e.g., const
attemptId = Symbol() or timestamp) and store it on the instance
(this.currentMiniMaxAttemptId = attemptId) right after setting
this.miniMaxOauthAbortController, then pass/close-over that id when calling
requestMiniMaxOAuthCode and finishMiniMaxOauthLogin; inside the catch/finally of
startMiniMaxOauth and inside finishMiniMaxOauthLogin (the code referenced around
633-662), check that this.currentMiniMaxAttemptId === attemptId (or that
this.miniMaxOauthAbortController === abortController) before clearing or
updating this.miniMaxOauthAbortController, this.miniMaxOauthBrowserUrl, or
this.miniMaxOauthState so a newer attempt cannot be overwritten by an older one.
- Around line 573-588: In refreshMiniMaxOauthModelsIfNeeded, only backfill
MINI_MAX_OAUTH_MODELS when the provider is not just authMode: "oauth" but also
actually has stored OAuth credentials; after fetching provider via
this.configStore.getProvider("minimax") add a guard that returns unless the
provider contains the expected credential fields (e.g., provider.clientId &&
provider.clientSecret or provider.credentials?.accessToken — match your actual
provider shape), keeping the rest of the logic and the upsertProvider call
unchanged; reference finishMiniMaxOauthLogin for the canonical place where
credentials are saved so the helper only mirrors that successful state.
- Around line 665-686: Add hard timeouts to the new MiniMax/OpenClaw I/O by
combining an AbortSignal.timeout(timeoutMs) with the existing signal for each
external call: wrap the fetch in requestMiniMaxOAuthCode (the POST to
`${getMiniMaxOauthHost(region)}/oauth/code`) with a merged signal (e.g.,
AbortSignal.any or manual race) that enforces a reasonable timeout, do the same
for the fetch in the MiniMax OAuth token polling loop (the polling request that
checks for access_token), and apply a timeout to execOpenClawCommand's execFile
call so the child process is killed if it hangs; update the calls to use the
combined signal (or abort the child) and ensure proper cleanup of timers/abort
controllers.

In `@tests/desktop/model-provider-service.test.ts`:
- Around line 141-155: The test still calls the removed two-argument
ModelProviderService constructor; update the old call sites (the ones using
ModelProviderService(store, env.nodeEnv) at the earlier specs) to the new
four-argument signature used later in this file: pass the NexuConfigStore
instance and the env returned from createEnv, plus a mock openclawSyncService
(implement syncAll: async () => ({ configPushed: false }) or similar) and a mock
openclawProcess (implement stop/start/enableAutoRestart stubs). Mirror the shape
of the mocks used in the existing four-arg instantiation in this file so the
constructor and types align with ModelProviderService.

---

Outside diff comments:
In `@apps/controller/src/services/model-provider-service.ts`:
- Around line 419-435: The current verification in model-provider-service.ts
incorrectly treats any MiniMax 404 or missing-data 200 as valid; update the
validation in the code paths around the fetch response handling (the block that
returns { valid: true, models: MINI_MAX_API_MODELS } and the payload.data
fallback) to only allow the static MINI_MAX_API_MODELS fallback when the request
is actually against a canonical MiniMax host (e.g., inspect response.url or the
provider's configured baseUrl for an authorized MiniMax hostname) or after a
dedicated MiniMax-specific probe succeeds; otherwise return valid: false with
the HTTP error or an explicit invalid-provider error to avoid accepting
mistyped/custom endpoints. Ensure the checks are applied both in the
!response.ok branch and the payload.data absence branch (the logic that
currently maps payload.data or falls back to MINI_MAX_API_MODELS).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 667b8164-75b1-4a77-b1c0-67684ded22ec

📥 Commits

Reviewing files that changed from the base of the PR and between 41c4554 and f4bff2c.

📒 Files selected for processing (2)
  • apps/controller/src/services/model-provider-service.ts
  • tests/desktop/model-provider-service.test.ts

Comment thread apps/controller/src/services/model-provider-service.ts
Comment thread apps/controller/src/services/model-provider-service.ts
Comment thread apps/controller/src/services/model-provider-service.ts
Comment thread tests/desktop/model-provider-service.test.ts Outdated
Copy link
Copy Markdown
Collaborator

@lefarcen lefarcen left a comment

Choose a reason for hiding this comment

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

Code Review

几个需要修复的问题:

1. home.starnexu 翻译 key 错误 — UI 会显示 raw key

apps/web/src/pages/home.tsxt("home.starNexu") 被改成了 t("home.starnexu"),但 locale 文件里没有对应更新,会导致首页按钮显示未翻译的原始 key。

2. OpenAPI spec 未完全重新生成

supportedByokProviderIds 包含 moonshotzai(共 11 个),但生成的 openapi.json / types.gen.ts 只有 9 个 provider。需要重新 pnpm generate-types

3. browserUrl 打开前未校验 URL scheme — XSS 风险

models.tsxwindow.open(browserUrl, "_blank", "noopener,noreferrer")browserUrl 来自 MiniMax API 响应。如果被篡改为 javascript: URL 会产生 XSS。建议加个前缀校验:

if (browserUrl && /^https?:\/\//.test(browserUrl)) {
  window.open(browserUrl, "_blank", "noopener,noreferrer");
}

4. custom provider 移除无迁移路径

现有配置了 custom provider 的用户升级后会被静默过滤掉,无警告。需要考虑迁移策略或至少 log 一条 warning。

5. API title 意外改名

openapi.json"Nexu Controller API""nexu Controller API",看起来是无意的。

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e39b2ee52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/controller/src/lib/openclaw-config-compiler.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/pages/models.tsx (1)

415-427: ⚠️ Potential issue | 🟠 Major

Keep moonshot and zai reachable until they are migrated.

The sidebar/type union now excludes moonshot and zai, but the controller still accepts both provider IDs and this file still has metadata/default models for them. Existing saved configs for those providers will disappear from the UI and become impossible to edit or remove.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/pages/models.tsx` around lines 415 - 427, The BYOK_PROVIDER_IDS
constant and resulting ByokProviderId union currently omit "moonshot" and "zai",
which hides existing saved configs; restore those providers by adding "moonshot"
and "zai" back into the BYOK_PROVIDER_IDS array so the ByokProviderId type and
sidebar/type union include them, and verify any related metadata/default model
entries for moonshot and zai remain referenced (e.g., in the same file's
metadata/defaults) so existing configs remain editable/removable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/pages/models.tsx`:
- Around line 1798-1808: The dismiss button for the MiniMax OAuth error uses a
hard-coded aria-label ("Dismiss error") which bypasses localization; update the
button to use the i18n translation function (the same t(...) used elsewhere) for
its aria-label so screen readers get locale-specific text, e.g., replace the
static aria-label on the element associated with visibleMiniMaxOauthError and
setDismissedMiniMaxOauthError to a translated string via t('...') consistent
with other MiniMax copy.
- Around line 1284-1288: The current defaulting logic for authMode and
oauthRegion uses providerId === "minimax" to pick "oauth", which misclassifies
legacy MiniMax entries; instead, update the initialization of authMode (used
with setAuthMode) and oauthRegion (used with setOauthRegion) to first inspect
saved credential flags on dbProvider (e.g., whether an API key or OAuth token is
present) and derive the fallback from those flags when dbProvider.authMode is
missing; apply the same change at the other occurrence (around the other
authMode/oauthRegion initialization) so legacy API-key-only MiniMax configs open
the API-key panel and avoid exposing OAuth-only UI.
- Around line 1546-1570: Add onError handlers to the existing
minimaxOauthMutation (and the equivalent cancel mutation) so HTTP/IPC failures
are surfaced to the UI: in minimaxOauthMutation (which calls hostBridge.invoke
or postApiV1ProvidersMinimaxOauthLogin) add an onError callback that takes the
error, invalidates the ["minimax-oauth-status"] query via
queryClient.invalidateQueries, and write the error message into the status cache
(e.g. queryClient.setQueryData(["minimax-oauth-status"], prev => ({
...(prev||{}), error: error?.message || String(error) }))) so
minimaxOauthStatus.error is populated; apply the same pattern to the cancel
mutation.
- Around line 1451-1460: The effect that loads stored MiniMax models should also
clear verifiedModels when switching away from the OAuth MiniMax path; inside the
useEffect that currently returns early when (!isMiniMax || authMode !==
"oauth"), call setVerifiedModels([]) before returning so the API-key
verifiedModels do not persist into the OAuth panel. Update the effect that reads
dbProvider?.modelsJson to only setVerifiedModels(stored) when stored.length > 0
and ensure the early-return branch clears the state via setVerifiedModels([]).

---

Outside diff comments:
In `@apps/web/src/pages/models.tsx`:
- Around line 415-427: The BYOK_PROVIDER_IDS constant and resulting
ByokProviderId union currently omit "moonshot" and "zai", which hides existing
saved configs; restore those providers by adding "moonshot" and "zai" back into
the BYOK_PROVIDER_IDS array so the ByokProviderId type and sidebar/type union
include them, and verify any related metadata/default model entries for moonshot
and zai remain referenced (e.g., in the same file's metadata/defaults) so
existing configs remain editable/removable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d12fb44-a34f-4494-841a-d804d8288039

📥 Commits

Reviewing files that changed from the base of the PR and between f4bff2c and 9e39b2e.

📒 Files selected for processing (1)
  • apps/web/src/pages/models.tsx

Comment thread apps/web/src/pages/models.tsx
Comment thread apps/web/src/pages/models.tsx
Comment thread apps/web/src/pages/models.tsx
Comment thread apps/web/src/pages/models.tsx
Copy link
Copy Markdown
Collaborator

@lefarcen lefarcen left a comment

Choose a reason for hiding this comment

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

Code Review (updated)

三个需要修复的问题:

1. home.starnexu 翻译 key 错误 — UI 会显示 raw key

apps/web/src/pages/home.tsxt("home.starNexu") 被改成了 t("home.starnexu"),但 locale 文件里没有对应更新,会导致首页按钮显示未翻译的原始 key。

2. OpenAPI spec 未完全重新生成

supportedByokProviderIds 包含 moonshotzai(共 11 个),但生成的 openapi.json / types.gen.ts 只有 9 个 provider。需要重新 pnpm generate-types

3. browserUrl 打开前未校验 URL scheme — XSS 风险

models.tsxwindow.open(browserUrl, "_blank", "noopener,noreferrer")browserUrl 来自 MiniMax API 响应。如果被篡改为 javascript: URL 会产生 XSS。建议加个前缀校验:

if (browserUrl && /^https?:\/\//.test(browserUrl)) {
  window.open(browserUrl, "_blank", "noopener,noreferrer");
}

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0268870058

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/controller/src/runtime/openclaw-auth-profiles-writer.ts
@mrcfps mrcfps merged commit 1c368ed into main Mar 25, 2026
7 checks passed
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.

2 participants