Skip to content

Add NVIDIA NIM API provider support#1012

Merged
PeterDaveHello merged 1 commit into
ChatGPTBox-dev:masterfrom
PeterDaveHello:add-nvidia-nim-provider
Jul 19, 2026
Merged

Add NVIDIA NIM API provider support#1012
PeterDaveHello merged 1 commit into
ChatGPTBox-dev:masterfrom
PeterDaveHello:add-nvidia-nim-provider

Conversation

@PeterDaveHello

@PeterDaveHello PeterDaveHello commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Add NVIDIA NIM as a built-in OpenAI-compatible API provider.
  • Add selected NVIDIA-hosted model presets in a consistent order, with Nemotron 3 Super enabled by default.
  • Wire API-key setup, request routing, legacy preset mapping, and focused provider coverage.

Validation

  • npm test (795 tests passed)
  • npm run lint
  • npm run build

Manual browser smoke testing was not run because a browser extension runtime is not available in this environment.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds NVIDIA NIM models, configuration, provider registration, API-key setup, legacy model resolution, OpenAI-compatible session routing, and unit coverage for classification, provider resolution, endpoint selection, and authorization.

Changes

NVIDIA NIM provider support

Layer / File(s) Summary
NVIDIA NIM model and configuration contracts
src/config/index.mjs, src/config/openai-provider-mappings.mjs
Adds NVIDIA NIM model keys, model metadata, API-key defaults, active mode defaults, model detection, and provider mappings.
Provider registration and session routing
src/services/apis/provider-registry.mjs, src/background/index.mjs, src/popup/sections/GeneralPart.jsx
Registers the nvidia-nim provider, resolves legacy NVIDIA NIM model names, routes sessions through the OpenAI-compatible path, and adds the NVIDIA API-key setup URL.
NVIDIA NIM integration validation
tests/unit/config/config-predicates.test.mjs, tests/unit/services/apis/provider-registry.test.mjs, tests/unit/services/apis/thin-adapters.test.mjs
Tests model classification, legacy provider resolution, chat-completions routing, and authorization headers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Session
  participant Background
  participant ProviderRegistry
  participant NVIDIA_NIM_API
  Session->>Background: Select NVIDIA NIM model
  Background->>ProviderRegistry: Resolve nvidia-nim provider
  ProviderRegistry-->>Background: Return endpoint and API key
  Background->>NVIDIA_NIM_API: Send chat completions request
Loading

Possibly related PRs

Suggested reviewers: josstorer

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding NVIDIA NIM as a built-in API provider with routing and model support.
✨ 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.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Add NVIDIA NIM as built-in OpenAI-compatible provider with model presets

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Register NVIDIA NIM as a built-in OpenAI-compatible chat provider.
• Add featured NVIDIA-hosted model presets and persist an NVIDIA-specific API key.
• Extend routing and unit tests for provider resolution and request wiring.
Diagram

graph TD
  UI["Popup settings"] --> CFG[("Config & secrets")] --> REG["Provider registry"] --> API["OpenAI compat client"] --> NIM[/"NVIDIA NIM endpoint"/]
  BG["Background executor"] --> REG
  subgraph Legend
    direction LR
    _cfg[("Storage") ] ~~~ _svc["Module/Service"] ~~~ _ext[/"External API"/]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Ship NVIDIA NIM only as a preconfigured custom provider
  • ➕ Less built-in surface area (no new providerId/mappings)
  • ➕ Leverages existing custom provider UI and persistence fully
  • ➖ Worse UX: harder discovery and less consistent model presets
  • ➖ Harder to support legacy modelName migrations/predicates cleanly
  • ➖ Less testable as a first-class provider with stable IDs
2. Expose NIM models via an aggregator provider (e.g., OpenRouter) instead of direct NIM
  • ➕ Single API key/provider integration point
  • ➕ Potentially simplifies maintenance across multiple upstreams
  • ➖ Requires users to rely on a third-party routing layer
  • ➖ May not provide parity with NVIDIA’s hosted catalog or pricing/features
  • ➖ Doesn’t satisfy “use NVIDIA API key directly” requirement

Recommendation: Keep the PR’s approach: making NVIDIA NIM a first-class built-in OpenAI-compatible provider best matches the existing provider registry architecture, enables clean API-key routing, and supports stable model presets with focused unit coverage.

Files changed (8) +84 / -0

Enhancement (5) +42 / -0
index.mjsRoute NVIDIA NIM sessions through OpenAI-compatible API execution +2/-0

Route NVIDIA NIM sessions through OpenAI-compatible API execution

• Extends the OpenAI-compatible session predicate to treat NVIDIA NIM API-mode sessions as compatible, ensuring they use the shared OpenAI-compatible execution path in the background script.

src/background/index.mjs

index.mjsAdd NVIDIA NIM model group, presets, config key, and predicate +27/-0

Add NVIDIA NIM model group, presets, config key, and predicate

• Introduces the NVIDIA NIM API model key group and adds three featured model presets. Adds a dedicated nvidiaNimApiKey field to the default config and exposes an isUsingNvidiaNimApiModel predicate for consistent routing.

src/config/index.mjs

openai-provider-mappings.mjsMap NVIDIA NIM providerId to legacy API-key field and apiMode group +2/-0

Map NVIDIA NIM providerId to legacy API-key field and apiMode group

• Registers providerId-to-legacy-key-field mapping for 'nvidia-nim' and wires the nvidiaNimApiModelKeys group to the NVIDIA providerId for OpenAI-compatible request resolution.

src/config/openai-provider-mappings.mjs

GeneralPart.jsxAdd NVIDIA NIM API-key setup link in the provider UI +2/-0

Add NVIDIA NIM API-key setup link in the provider UI

• Adds a provider-specific API key setup URL for 'nvidia-nim' to direct users to NVIDIA’s API key management page from the existing settings UI.

src/popup/sections/GeneralPart.jsx

provider-registry.mjsRegister NVIDIA NIM as a built-in provider and support legacy preset resolution +9/-0

Register NVIDIA NIM as a built-in provider and support legacy preset resolution

• Adds NVIDIA NIM to the built-in provider list with the integrate.api.nvidia.com base URL and chat completions path. Extends legacy modelName parsing to resolve NVIDIA NIM provider IDs from preset keys/groups.

src/services/apis/provider-registry.mjs

Tests (3) +42 / -0
config-predicates.test.mjsAdd predicate coverage for NVIDIA NIM API models +9/-0

Add predicate coverage for NVIDIA NIM API models

• Adds unit tests verifying isUsingNvidiaNimApiModel matches all exported NVIDIA NIM model keys and does not match unrelated models.

tests/unit/config/config-predicates.test.mjs

provider-registry.test.mjsTest NVIDIA NIM providerId resolution and request URL/key selection +26/-0

Test NVIDIA NIM providerId resolution and request URL/key selection

• Adds coverage for resolving providerId from legacy NVIDIA preset keys and for resolving an OpenAI-compatible request (providerId, requestUrl, apiKey) from nvidiaNimApiModelKeys apiMode.

tests/unit/services/apis/provider-registry.test.mjs

thin-adapters.test.mjsVerify OpenAI-compatible adapter uses NVIDIA NIM base URL and auth header +7/-0

Verify OpenAI-compatible adapter uses NVIDIA NIM base URL and auth header

• Adds NVIDIA NIM to the shared adapter test matrix to confirm correct base URL selection and that the provider secret is passed through the Authorization header.

tests/unit/services/apis/thin-adapters.test.mjs

@kilo-code-bot

kilo-code-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Incremental review of PR #1012 (Add NVIDIA NIM API provider support) over 54f8a3ac..9aa53a65. No new high-confidence defects were found in the changed lines.

Notes

The incremental change registers NVIDIA NIM as a built-in OpenAI-compatible provider and is fully additive:

  • src/config/index.mjs: adds nvidiaNimApiModelKeys, ModelGroups.nvidiaNimApiModelKeys, seven Models entries, the nvidiaNimApiKey config field, includes nvidiaNim_nemotron_3_super in defaultConfig.activeApiModes (addressing the earlier CodeRabbit "activate a preset" suggestion), and the isUsingNvidiaNimApiModel predicate.
  • src/services/apis/provider-registry.mjs: registers the nvidia-nim builtin provider (https://integrate.api.nvidia.com, /v1/chat/completions) and legacy preset resolution (nvidiaNim_ prefix / nvidiaNimApiModelKeys).
  • src/config/openai-provider-mappings.mjs, src/popup/sections/GeneralPart.jsx, src/background/index.mjs: API-key field mapping, setup URL, and OpenAI-compatible session routing, all mirroring existing provider patterns.
  • Tests added/extended for predicates, provider resolution, and thin-adapter routing; PR reports 839 tests passing.

All prior active review comments on this PR target files outside the current incremental diff (api-modes-provider-utils.mjs, model-name-convert.mjs, broader config/index.mjs migration logic) and were addressed in earlier commits. No new blocking or warning-level issue remains in the changed lines.

Files Reviewed (incremental, 8 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs
Previous Review Summaries (12 snapshots, latest commit 54f8a3a)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 54f8a3a)

Status: No Issues Found | Recommendation: Merge

Incremental review of PR #1012 (Add NVIDIA NIM API provider support) over 366c25f0..54f8a3ac. No new high-confidence defects were found in the changed lines.

Notes

The incremental change is a small, focused fix to src/popup/sections/api-modes-provider-utils.mjs:

  • isProviderReferencedByApiModes now uses the shared areProviderIdsEquivalent helper instead of a strict normalizeText equality check when matching apiMode.providerId against the queried provider ID.
  • This brings the reference check in line with the canonical-ID matching used elsewhere in the file (e.g. sanitizeApiModeForSave, getReferencedCustomProviderIdsFromSessions) and correctly avoids treating a stored legacyProviderIds entry as a current match — legacy-proxy will not match proxy-v1.
  • A new unit test confirms the canonical match (proxy-v1 → true), the non-match on legacy IDs (legacy-proxy → false), and the non-match on unrelated providers (other-provider → false).

All prior active review comments on the changed files are either confirmed fixed in earlier commits or are optional maintainability suggestions explicitly excluded by the author. No new blocking or warning-level issue remains.

Files Reviewed (incremental, 2 files)
  • src/popup/sections/api-modes-provider-utils.mjs
  • tests/unit/popup/api-modes-provider-utils.test.mjs

Previous review (commit 366c25f)

Status: No Issues Found | Recommendation: Merge

Incremental review of PR #1012 (Add NVIDIA NIM API provider support) over eab051b0..366c25f0. No new high-confidence defects were found in the changed lines.

Notes

The incremental changes are focused provider-registration and test-coverage work, consistent with the previously reviewed fixes:

  • src/config/openai-provider-mappings.mjs / src/config/index.mjs — registers nvidia-nim as a built-in OpenAI-compatible provider, maps the nvidiaNimApiModelKeys group, wires nvidiaNimApiKey plus the LEGACY_API_KEY_FIELD_BY_PROVIDER_ID entry, and adds the featured preset model keys (Nemotron-3-Super enabled by default in activeApiModes).
  • src/services/apis/provider-registry.mjs — adds the built-in nvidia-nim template (https://integrate.api.nvidia.com) and legacy preset resolution; diagnostic/legacy-id matching now uses the shared hasNormalizedProviderIdMatch.
  • src/popup/sections/areProviderIdsEquivalent is applied in ApiModes.jsx and getApiModeDisplayLabel/getConversationAiName honor legacy provider IDs and disabled matches; import-data-cleanup.mjs seeds completedBuiltinProviderIdMigrations when provider state is imported.
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs (new, 585 lines) plus additions to existing unit tests cover NIM detection, request resolution, and builtin-secret migration.

All prior active review comments on the changed files are either confirmed fixed in earlier commits (provider-ID canonicalization, legacy-ID retention, disabled-provider reference handling, renamed-ID URL disambiguation) or are optional maintainability suggestions explicitly excluded by the author. No new blocking or warning-level issue remains.

Files Reviewed (incremental, 17 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/ApiModes.jsx
  • src/popup/sections/GeneralPart.jsx
  • src/popup/sections/api-modes-provider-utils.mjs
  • src/popup/sections/import-data-cleanup.mjs
  • src/services/apis/provider-registry.mjs
  • src/utils/model-name-convert.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs
  • tests/unit/config/migrate-user-config.test.mjs
  • tests/unit/popup/api-modes-provider-utils.test.mjs
  • tests/unit/popup/import-data-cleanup.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs
  • tests/unit/utils/model-name-convert.test.mjs

Previous review (commit eab051b)

Status: No Issues Found | Recommendation: Merge

Incremental review of PR #1012 (Add NVIDIA NIM API provider support) over 1248673..eab051b. No new high-confidence defects were found in the changed lines.

Notes

The incremental changes are focused, consistent bug fixes with accompanying test coverage:

  • src/config/index.mjs — migration hardening: normalizes provider IDs used as providerSecrets keys, and safely recovers/relocates "malformed provider secret" API keys (secrets keyed by a non-normalizable providerId) into the migrated provider before deleting the orphaned key. Deletion is guarded by migratedProviderSecret === malformedProviderSecret, preventing data loss.
  • src/popup/sections/import-data-cleanup.mjsimportsProviderState now triggers on customOpenAIProviders or providerSecrets (was and), so migration bookkeeping is initialized when only one is imported.
  • src/services/apis/provider-registry.mjs — diagnostic matching now recognizes providers matched via legacyProviderIds via hasNormalizedProviderIdMatch, consistent with the rest of the codebase.
  • src/popup/sections/api-modes-provider-utils.mjsgetReferencedCustomProviderIdsFromSessions now falls through to URL-based recovery for a single disabled/non-current-ID match instead of skipping it.

Existing platform-bot and maintainer comments were reviewed and left in place; none correspond to a new defect in the incremental diff.

Files Reviewed (incremental, 8 files)
  • src/config/index.mjs
  • src/popup/sections/api-modes-provider-utils.mjs
  • src/popup/sections/import-data-cleanup.mjs
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/migrate-user-config.test.mjs
  • tests/unit/popup/api-modes-provider-utils.test.mjs
  • tests/unit/popup/import-data-cleanup.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs

Previous review (commit 1248673)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (16 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/ApiModes.jsx
  • src/popup/sections/GeneralPart.jsx
  • src/popup/sections/api-modes-provider-utils.mjs
  • src/popup/sections/import-data-cleanup.mjs
  • src/services/apis/provider-registry.mjs
  • src/utils/model-name-convert.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs
  • tests/unit/popup/api-modes-provider-utils.test.mjs
  • tests/unit/popup/import-data-cleanup.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs
  • tests/unit/utils/model-name-convert.test.mjs

Notes

Full review of PR #1012 (Add NVIDIA NIM API provider support) over 2419486..1248673. No new high-confidence defects were found in the changed lines.

Verified previously-raised items against current HEAD 1248673:

  • src/config/index.mjs:139 (Codex: NVIDIA preset in default selector) — resolved: nvidiaNim_nemotron_3_super is now in defaultConfig.activeApiModes.
  • src/utils/model-name-convert.mjs:312 / src/popup/sections/api-modes-provider-utils.mjs:324 (canonical provider-ID comparison; legacyProviderIds cleanup) — resolved: areProviderIdsEquivalent is used consistently and legacyProviderIds is cleared on canonical provider change and on non-custom save.
  • CodeRabbit #Data Integrity findings (config/index.mjs lines 1227/1863) — no longer applicable: the remapSessionProviderIds / sessionProviderIdRenameLookup / sessions read-modify-write path was removed entirely from getUserConfig.
  • qodo #1038 (slashless paths) — false positive: getProviderChatCompletionsUrlForCompare already wraps chatCompletionsPath/completionsPath in ensureLeadingSlash before comparison.

Outstanding items previously raised by platform bots remain (not re-raised here to avoid duplicates): qodo #716 (disabled providerIdCandidates can narrow URL recovery in resolveOpenAICompatibleRequest) and Copilot #588 (disabled providers still treated as unreferenced in getReferencedCustomProviderIdsFromSessions).

Previous review (commit 421fc0d)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (incremental over 9d24d5e..421fc0d)

Incremental scope: the only changes since the prior review commit are two fixes the author already verified as fixed in 421fc0d:

  • src/utils/model-name-convert.mjs - isApiModeSelected now compares provider IDs canonically via areProviderIdsEquivalent and consults legacyProviderIds; malformed/empty-normalizing IDs fall back to trimmed exact comparison. Fix verified present and correct.
  • src/popup/sections/api-modes-provider-utils.mjs - sanitizeApiModeForSave now removes legacyProviderIds for non-custom-provider-backed modes. Fix verified present and correct.
  • src/popup/sections/ApiModes.jsx - uses areProviderIdsEquivalent to gate clearing provider-derived fields; consistent with the helper added elsewhere.

Notes

Incremental review of HEAD 421fc0d9 over prior review commit 9d24d5e. The previously-raised platform findings (CodeRabbit/qodo/copilot) concern pre-existing or already-addressed areas outside the incremental changed lines and were not re-raised. No new high-confidence defects (security, runtime, logic, typos, breaking changes) were found in the changed lines.

Previous review (commit 9d24d5e)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (16 files, incremental over 3fb39ff)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/ApiModes.jsx
  • src/popup/sections/GeneralPart.jsx
  • src/popup/sections/api-modes-provider-utils.mjs
  • src/popup/sections/import-data-cleanup.mjs
  • src/services/apis/provider-registry.mjs
  • src/utils/model-name-convert.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs
  • tests/unit/popup/api-modes-provider-utils.test.mjs
  • tests/unit/popup/import-data-cleanup.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs
  • tests/unit/utils/model-name-convert.test.mjs

Notes

Incremental review of HEAD 9d24d5e over prior review commit 3fb39ff. The NVIDIA NIM provider work (registration, presets, shared-key storage, request routing, setup links, and provider-resolution hardening) was re-examined line-by-line.

Previously-flagged platform findings are confirmed addressed in the current code:

  • getProviderChatCompletionsUrlForCompare (src/config/index.mjs) now normalizes chatCompletionsPath/completionsPath via ensureLeadingSlash, fixing the slashless-path URL disambiguation gap.
  • applySelectedProviderToApiMode (api-modes-provider-utils.mjs) uses areProviderIdsEquivalent before clearing legacyProviderIds, preserving legacy aliases for canonical-equivalent IDs.
  • isApiModeSelected (model-name-convert.mjs) uses areProviderIdsEquivalent plus legacyProviderIds matching, resolving the strict-equality false-mismatch.

No new high-confidence defects (security, runtime, logic, typos) were found in the changed lines. The secret-migration flow was traced against the new test suite and the builtin-key sync at the top of migrateUserConfig keeps assertions consistent with no secret-loss path identified. The remaining active platform comments concern pre-existing, unchanged code paths outside this PR's scope and were not duplicated.

Previous review (commit 3fb39ff)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (40 files, incremental since d02d04a)
  • src/config/index.mjs
  • src/services/apis/provider-registry.mjs
  • src/utils/model-name-convert.mjs
  • src/popup/sections/api-modes-provider-utils.mjs
  • src/components/ConversationCard/index.jsx
  • src/components/MarkdownRender/markdown.jsx
  • src/components/MarkdownRender/markdown-without-katex.jsx
  • src/content-script/index.jsx
  • src/content-script/port-error.mjs
  • src/services/clients/bing/index.mjs
  • src/services/wrappers.mjs
  • src/utils/abort-error.mjs
  • src/utils/error-text.mjs
  • src/utils/fetch-sse.mjs
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs
  • tests/unit/services/clients/bing.test.mjs
  • tests/unit/services/wrappers-register.test.mjs
  • tests/unit/services/handle-port-error.test.mjs
  • tests/unit/utils/fetch-sse.test.mjs
  • tests/unit/utils/error-text.test.mjs
  • tests/unit/popup/api-modes-provider-utils.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/utils/model-name-convert.test.mjs
  • plus locale/_locales and other unit test files

Notes

Incremental review of HEAD 3fb39ff over prior review commit d02d04a.

The expanded PR now also introduces provider-resolution hardening and a new transport-error reporting layer beyond the original NVIDIA NIM provider work:

  • Config migration (src/config/index.mjs): legacyProviderIds tracking added to custom providers and apiModes so that sessions referencing a pre-migration provider id still resolve after rename. migrateUserConfig secret-migration branches were extended to also handle empty normalized secrets paired with a non-empty raw secret. Verified against the 169-line expanded migrate-nvidia-nim-provider.test.mjs suite.
  • Provider resolution (provider-registry.mjs): resolveOpenAICompatibleRequest now matches by exact id, legacy legacyProviderIds, and normalized id, with candidate-scoped URL/label recovery and disabled-provider detection covering legacy ids. findConfiguredCustomApiModeBySessionLabel and normalizeCustomProvider propagate legacyProviderIds.
  • Selection helpers (model-name-convert.mjs): isApiModeSelected matches legacy ids; getUniquelySelectedApiModeIndex disambiguates multiple matches by customUrl under sessionCompat.
  • Popup utils (api-modes-provider-utils.mjs): legacy-id aware matching and disabled-provider inclusion (includeDisabled) added throughout; getApiModeDisplayLabel/getConversationAiName resolve via the new matcher.
  • Transport error reporting: new fetch-sse.mjs error codes (FETCH_REQUEST_FAILED, FETCH_RESPONSE_STREAM_FAILED, INVALID_API_ENDPOINT), abort-error.mjs, error-text.mjs, port-error.mjs, and a refactored handlePortError in wrappers.mjs with localized summaries and sec_access_token redaction in bing/index.mjs.

No new high-confidence defects found in the changed lines. The 5 active inline comments from other review bots on src/config/index.mjs are not duplicated here.

Previous review (commit d02d04a)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (11 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/popup/sections/import-data-cleanup.mjs
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs
  • tests/unit/popup/import-data-cleanup.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs

Notes

Incremental review of commit d02d04a over the prior review commit d48fe61. The NVIDIA NIM provider integration is consistent end-to-end: builtin registry entry (baseUrl https://integrate.api.nvidia.com, /v1/chat/completions), OpenAI-compatible group mapping, legacy key field nvidiaNimApiKey, shared API-key storage, background isUsingOpenAICompatibleApiSession branch, popup setup URL, and a default active mode (nvidiaNim_nemotron_3_super).

The expanded migration logic in src/config/index.mjs was verified against its new 486-line test suite:

  • providerSecretSnapshot correctly isolates reads of pre-migration secrets from in-loop providerSecrets mutations.
  • resolveRenamedProviderId is derived from the final providerIdRenames (built after provider promotion), resolving the prior cross-bot sessionProviderIdRenameLookup staleness concern.
  • completedBuiltinProviderIdMigrations is computed from NEWLY_RESERVED_BUILTIN_PROVIDER_IDS and persisted via both migrateUserConfig and the import-data-cleanup.mjs reset, so colliding custom-provider secrets are migrated exactly once.
  • remapSessionProviderIds only rewrites customApiModelKeys-group sessions, leaving builtin-group sessions untouched.

No new high-confidence defects found in the changed lines. The four active inline comments from other review bots (chatgpt-codex-connector, coderabbit, qodo) are not duplicated here. The prior recommendation to activate an NVIDIA NIM preset by default is now satisfied by defaultConfig.activeApiModes.

Previous review (commit d48fe61)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (8 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs

Notes

The PR was expanded beyond the prior incremental review into a full provider integration. The prior finding about NVIDIA NIM not being selectable by default (line 135 of src/config/index.mjs) is now resolved: nvidiaNim_nemotron_3_super is added to defaultConfig.activeApiModes. All new keys are consistent across nvidiaNimApiModelKeys, the Models map, the provider registry (nvidia-nim builtin with baseUrl https://integrate.api.nvidia.com), the OpenAI-compatible group mapping, the API-key storage field (nvidiaNimApiKey), the popup setup URL, and the background isUsingOpenAICompatibleApiSession branch. Request URL construction yields https://integrate.api.nvidia.com/v1/chat/completions, matching the new unit tests. No new defects found in the changed lines.

Previous review (commit 27c6770)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (8 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs

Notes

The PR was expanded beyond the prior incremental review into a full provider integration. The prior finding about NVIDIA NIM not being selectable by default (line 135 of src/config/index.mjs) is now resolved: nvidiaNim_nemotron_3_super is added to defaultConfig.activeApiModes. All new keys are consistent across nvidiaNimApiModelKeys, the Models map, the provider registry (nvidia-nim builtin with baseUrl https://integrate.api.nvidia.com), the OpenAI-compatible group mapping, the API-key storage field (nvidiaNimApiKey), the popup setup URL, and the background isUsingOpenAICompatibleApiSession branch. Request URL construction yields https://integrate.api.nvidia.com/v1/chat/completions, matching the new unit tests. No new defects found in the changed lines.

Previous review (commit 589b988)

Status: No Issues Found | Recommendation: Merge

The incremental changes add four new NVIDIA NIM model presets (nvidiaNim_minimax_m3, nvidiaNim_deepseek_v4_flash, nvidiaNim_inkling, nvidiaNim_nemotron_3_super) to nvidiaNimApiModelKeys and the Models map, enable nvidiaNim_nemotron_3_super in defaultConfig.activeApiModes, and add matching unit tests. The new keys are consistent across the keys list, Models entries, and tests; the provider registry resolves them automatically via the nvidiaNim_ prefix, so no additional registration is required. No bugs, security issues, or logic errors found in the changed lines.

Files Reviewed (2 files)
  • src/config/index.mjs
  • tests/unit/config/config-predicates.test.mjs

Previous review (commit 7cb9c9e)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (8 files)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs

Reviewed by hy3:free · Input: 73.4K · Output: 6K · Cached: 606K

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cb9c9e027

ℹ️ 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 src/config/index.mjs Outdated
@qodo-code-review

qodo-code-review Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Disabled candidate blocks URL recovery ✗ Dismissed 🐞 Bug ≡ Correctness ⭐ New
Description
In resolveOpenAICompatibleRequest(), URL-based recovery is restricted to providerIdCandidates
whenever any providerId/legacy-ID match exists; if those candidates are disabled, enabled providers
that match the session’s customUrl are never considered and the request can fail closed (return
null). This is a regression because the URL recovery path can be suppressed by an unrelated disabled
ID match.
Code

src/services/apis/provider-registry.mjs[R685-716]

+    let matchedByProviderId = []
+    let matchedByLegacyProviderId = []
+    let providerIdCandidates = []
+    if (normalizedProviderId) {
+      matchedByProviderId = customProviders.filter((item) => item.id === providerId)
+      matchedByLegacyProviderId = customProviders.filter(
+        (item) =>
+          Array.isArray(item.legacyProviderIds) &&
+          item.legacyProviderIds.includes(normalizedProviderId),
      )
-      if (matchedByNormalizedProviderId) {
-        provider = matchedByNormalizedProviderId
-        resolvedProviderId = matchedByNormalizedProviderId.id
+      providerIdCandidates = Array.from(
+        new Map(
+          [...matchedByProviderId, ...matchedByLegacyProviderId].map((item) => [item.id, item]),
+        ).values(),
+      )
+      if (providerIdCandidates.length === 0) {
+        providerIdCandidates = customProviders.filter(
+          (item) => normalizeProviderId(item.id) === normalizedProviderId,
+        )
+      }
+      if (providerIdCandidates.length === 1 && providerIdCandidates[0].enabled !== false) {
+        provider = providerIdCandidates[0]
+        resolvedProviderId = provider.id
      }
    }
+    const recoveryProviders =
+      providerIdCandidates.length > 0 ? providerIdCandidates : customProviders
+    const hasAmbiguousLegacyCustomUrlMatch = hasAmbiguousCustomProviderMatchByLegacySessionUrl(
+      recoveryProviders,
+      config,
+      session,
+    )
Evidence
The code collects providerIdCandidates without filtering out disabled providers, then uses those
candidates as the exclusive set for legacy URL recovery. However, legacy URL matching explicitly
skips disabled providers, so a candidates-only search can miss enabled URL matches that exist in the
full provider list and lead to a null resolution.

src/services/apis/provider-registry.mjs[675-813]
src/services/apis/provider-registry.mjs[501-517]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`resolveOpenAICompatibleRequest()` narrows `recoveryProviders` to `providerIdCandidates` whenever that array is non-empty. Because `providerIdCandidates` may be populated solely by **disabled** providers (candidate collection does not filter them), the subsequent legacy-URL matching logic (which only considers enabled providers) cannot recover to another enabled provider that matches the session’s `customUrl`, causing `resolveOpenAICompatibleRequest()` to return `null`.

### Issue Context
This manifests for custom sessions (`groupName === 'customApiModelKeys'`) when the session’s stored `providerId` collides with (or was renamed into) a disabled provider ID/legacy alias, but the session URL still matches an enabled provider.

### Fix Focus Areas
- src/services/apis/provider-registry.mjs[675-813]

### Implementation notes
- When choosing `recoveryProviders`, consider using:
 - all `customProviders` when `providerIdCandidates` contains **no enabled** providers, or
 - only **enabled** candidates when narrowing is needed for disambiguation.
- Alternatively, only narrow when `providerIdCandidates.length > 1` (true ambiguity), not merely `> 0`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Slashless paths break remap ✓ Resolved 🐞 Bug ≡ Correctness
Description
getProviderChatCompletionsUrlForCompare() compares chatCompletionsPath/completionsPath against
hard-coded "/v1/..." strings without normalizing leading slashes, so stored paths like
"v1/chat/completions" can yield mismatched derived URLs (e.g., "/v1/v1/..."), causing
resolveRenamedProviderId() to fail URL-based disambiguation. In those ambiguous-rename cases,
sessions/customApiModes may not be remapped to the new provider IDs, breaking request resolution for
affected legacy sessions.
Code

src/config/index.mjs[R1018-1032]

+function getProviderChatCompletionsUrlForCompare(provider) {
+  const directUrl = normalizeEndpointUrlForCompare(provider?.chatCompletionsUrl)
+  if (directUrl) return directUrl
+
+  let baseUrl = normalizeEndpointUrlForCompare(provider?.baseUrl)
+  const path = normalizeText(provider?.chatCompletionsPath)
+  if (!baseUrl || !path) return ''
+  const usesDefaultV1Paths =
+    path === '/v1/chat/completions' &&
+    normalizeText(provider?.completionsPath) === '/v1/completions'
+  if (!normalizeText(provider?.completionsUrl) && usesDefaultV1Paths) {
+    baseUrl = baseUrl.replace(/\/v1$/i, '')
+  }
+  return normalizeEndpointUrlForCompare(`${baseUrl}/${path.replace(/^\/+/, '')}`)
+}
Evidence
The new migration-time comparison helper relies on exact '/v1/...' path matches but the storage
normalization path does not enforce leading slashes, while runtime URL building does; this
discrepancy can cause the migration’s URL matching to compute different URLs than the runtime
resolver uses, preventing providerId remapping in ambiguous-rename scenarios.

src/config/index.mjs[1018-1032]
src/config/index.mjs[1109-1116]
src/services/apis/provider-registry.mjs[259-268]
src/services/apis/provider-registry.mjs[304-333]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getProviderChatCompletionsUrlForCompare()` uses strict string equality against `'/v1/chat/completions'` and `'/v1/completions'` without normalizing leading slashes. If legacy stored providers have paths like `'v1/chat/completions'` and a baseUrl ending in `/v1`, the computed comparison URL can become `.../v1/v1/chat/completions`, which won’t match the session’s `customUrl`. This prevents `resolveRenamedProviderId()` from disambiguating duplicate providerId renames by URL, leaving some sessions/customApiModes pointing at now-renamed provider IDs.

### Issue Context
Runtime URL building in `provider-registry.mjs` *does* normalize leading slashes via `ensureLeadingSlash()`, so migration-time URL comparisons can diverge from runtime request URLs.

### Fix Focus Areas
- src/config/index.mjs[1018-1032]
- src/config/index.mjs[1109-1116]

### Suggested fix
1) In `getProviderChatCompletionsUrlForCompare()`, normalize `chatCompletionsPath` and `completionsPath` with a small local `ensureLeadingSlash()` helper (or equivalent) before:
  - performing the `usesDefaultV1Paths` equality checks
  - constructing the final `${baseUrl}/${path...}` URL
2) (Optional but safer) Also normalize stored provider `chatCompletionsPath`/`completionsPath` in `normalizeCustomProviderForStorage()` to always include a leading `/`, aligning storage/migration behavior with runtime behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Session migration overwrites updates ✓ Resolved 🐞 Bug ☼ Reliability
Description
getUserConfig() now reads Browser.storage.local.sessions, remaps provider IDs, then writes the
entire sessions array back, which can clobber concurrent writers that also set the full sessions
array (lost-update race). This can silently lose newly created/updated sessions when config
migration runs near session persistence operations.
Code

src/config/index.mjs[R1857-1866]

+  const { migrated, dirty, sessionProviderIdRenameLookup } = migrateUserConfig(options)
+  let sessionMigration = { sessions: undefined, dirty: false }
+  if (sessionProviderIdRenameLookup.size > 0) {
+    const { sessions } = await Browser.storage.local.get('sessions')
+    sessionMigration = remapSessionProviderIds(sessions, sessionProviderIdRenameLookup)
+  }
+  if (dirty || sessionMigration.dirty) {
    const payload = {}
    if (JSON.stringify(options.customApiModes) !== JSON.stringify(migrated.customApiModes)) {
      payload.customApiModes = migrated.customApiModes
Evidence
The diff introduces a new sessions read/write path inside getUserConfig(). The codebase already
has multiple whole-array writers of sessions, so the added read-modify-write can overwrite
concurrent updates if they occur between the migration read and subsequent storage.local.set().

src/config/index.mjs[1857-1894]
src/services/local-session.mjs[17-33]
src/services/local-session.mjs[55-62]
src/services/local-session.mjs[71-78]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getUserConfig()` performs a read→transform→write of the full `sessions` array during provider-ID migration. Because other parts of the app also write the full `sessions` array, this introduces a timing-dependent lost-update race where the migration write can overwrite newer session changes.

### Issue Context
- `getUserConfig()` is called broadly (including during session flows), and now conditionally writes `sessions` when provider IDs are renamed.
- Session persistence paths (`createSession`, `updateSession`, etc.) also write the full `sessions` array, so concurrent writes are plausible.

### Fix Focus Areas
- src/config/index.mjs[1857-1894]

### Suggested fix approach
1. When `sessionMigration.dirty` is true, re-read the latest `sessions` *immediately before* persisting and re-run `remapSessionProviderIds()` on that latest value (do not persist the earlier snapshot).
2. Optionally, if a write fails or if you want extra safety, add a small retry loop: re-read latest sessions, re-apply remap, and attempt `set` again.
3. Keep the remap transformation minimal (only update `apiMode.providerId` for affected custom sessions) so that unrelated session fields are preserved.

This doesn’t make the operation fully atomic, but it significantly reduces the likelihood of overwriting newer session updates and ensures you always migrate the most recent session state you can see.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Normalization helpers duplicated ✗ Dismissed 🐞 Bug ⚙ Maintainability ⭐ New
Description
Provider ID and endpoint URL normalization/equivalence logic is duplicated in multiple modules,
increasing drift risk and making future fixes to provider-ID matching easy to apply inconsistently.
This PR adds another copy in model-name-convert.mjs alongside existing logic in
api-modes-provider-utils.mjs.
Code

src/utils/model-name-convert.mjs[R1-25]

import { AlwaysCustomGroups, ModelGroups, ModelMode, Models } from '../config/index.mjs'

+function normalizeProviderId(value) {
+  return String(value || '')
+    .trim()
+    .toLowerCase()
+    .replace(/[^a-z0-9]+/g, '-')
+    .replace(/^-+|-+$/g, '')
+}
+
+function areProviderIdsEquivalent(firstProviderId, secondProviderId) {
+  const normalizedFirstProviderId = normalizeProviderId(firstProviderId)
+  const normalizedSecondProviderId = normalizeProviderId(secondProviderId)
+  if (!normalizedFirstProviderId || !normalizedSecondProviderId) {
+    return String(firstProviderId || '').trim() === String(secondProviderId || '').trim()
+  }
+  return normalizedFirstProviderId === normalizedSecondProviderId
+}
+
+function normalizeProviderEndpointUrl(value) {
+  return String(value || '')
+    .trim()
+    .replace(/\/+$/, '')
+}
+
Evidence
Both files define their own provider ID normalization/equivalence and endpoint URL normalization
helpers, which are logically the same concern but implemented separately.

src/utils/model-name-convert.mjs[1-24]
src/popup/sections/api-modes-provider-utils.mjs[17-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The PR introduces a new set of helper functions in `src/utils/model-name-convert.mjs` (`normalizeProviderId`, `areProviderIdsEquivalent`, `normalizeProviderEndpointUrl`) that overlap with equivalent helpers already present in `src/popup/sections/api-modes-provider-utils.mjs`. This duplication increases the probability of future behavior drift between selection logic and popup/provider logic.

### Issue Context
Both modules implement near-identical canonicalization rules. A later bugfix (e.g., changing normalization rules) could easily be applied to only one place, creating subtle mismatches.

### Fix Focus Areas
- src/utils/model-name-convert.mjs[1-24]
- src/popup/sections/api-modes-provider-utils.mjs[17-39]

### Suggested direction
- Create a small shared utility module (e.g., `src/utils/provider-id.mjs`) exporting these helpers.
- Update both call sites to import from that module, taking care to avoid circular dependencies.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Legacy IDs not cleared ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
applySelectedProviderToApiMode only deletes legacyProviderIds when providerId changes, so
legacyProviderIds can persist as stale metadata when the apiMode is later saved as a non-custom
group. This increases the chance of unintended legacy matching behavior over time and makes stored
apiMode state harder to reason about.
Code

src/popup/sections/api-modes-provider-utils.mjs[R310-315]

  const currentProviderId = normalizeText(nextApiMode.providerId)
  const nextProviderId = normalizeText(selectedProviderId)
  nextApiMode.providerId = nextProviderId
+  if (currentProviderId !== nextProviderId) {
+    delete nextApiMode.legacyProviderIds
+  }
Evidence
The PR adds explicit clearing of legacyProviderIds only when providerId changes, but the save
sanitizer for non-custom modes does not delete the field. Separately, session-compat selection now
checks legacyProviderIds, so persisting stale values is unnecessary and can influence matching if
data shapes drift over time.

src/popup/sections/api-modes-provider-utils.mjs[303-339]
src/utils/model-name-convert.mjs[269-301]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`legacyProviderIds` is a compatibility/migration field intended for custom provider-backed modes, but it is only cleared on providerId changes. When an apiMode is saved as a non-custom group, `sanitizeApiModeForSave` clears provider-related fields but leaves `legacyProviderIds`, persisting stale lineage metadata.

### Issue Context
This PR adds session-compat logic that consults `legacyProviderIds`, so leaving stale arrays around is unnecessary risk and complicates future migrations/debugging.

### Fix Focus Areas
- src/popup/sections/api-modes-provider-utils.mjs[303-339]

### Suggested fix
In `sanitizeApiModeForSave`, when `groupName !== 'customApiModelKeys'`, also `delete nextApiMode.legacyProviderIds` (and consider doing the same in any other non-custom sanitization paths).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit 9aa53a6

Results up to commit d48fe61


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Session migration overwrites updates ✓ Resolved 🐞 Bug ☼ Reliability
Description
getUserConfig() now reads Browser.storage.local.sessions, remaps provider IDs, then writes the
entire sessions array back, which can clobber concurrent writers that also set the full sessions
array (lost-update race). This can silently lose newly created/updated sessions when config
migration runs near session persistence operations.
Code

src/config/index.mjs[R1857-1866]

+  const { migrated, dirty, sessionProviderIdRenameLookup } = migrateUserConfig(options)
+  let sessionMigration = { sessions: undefined, dirty: false }
+  if (sessionProviderIdRenameLookup.size > 0) {
+    const { sessions } = await Browser.storage.local.get('sessions')
+    sessionMigration = remapSessionProviderIds(sessions, sessionProviderIdRenameLookup)
+  }
+  if (dirty || sessionMigration.dirty) {
    const payload = {}
    if (JSON.stringify(options.customApiModes) !== JSON.stringify(migrated.customApiModes)) {
      payload.customApiModes = migrated.customApiModes
Evidence
The diff introduces a new sessions read/write path inside getUserConfig(). The codebase already
has multiple whole-array writers of sessions, so the added read-modify-write can overwrite
concurrent updates if they occur between the migration read and subsequent storage.local.set().

src/config/index.mjs[1857-1894]
src/services/local-session.mjs[17-33]
src/services/local-session.mjs[55-62]
src/services/local-session.mjs[71-78]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getUserConfig()` performs a read→transform→write of the full `sessions` array during provider-ID migration. Because other parts of the app also write the full `sessions` array, this introduces a timing-dependent lost-update race where the migration write can overwrite newer session changes.

### Issue Context
- `getUserConfig()` is called broadly (including during session flows), and now conditionally writes `sessions` when provider IDs are renamed.
- Session persistence paths (`createSession`, `updateSession`, etc.) also write the full `sessions` array, so concurrent writes are plausible.

### Fix Focus Areas
- src/config/index.mjs[1857-1894]

### Suggested fix approach
1. When `sessionMigration.dirty` is true, re-read the latest `sessions` *immediately before* persisting and re-run `remapSessionProviderIds()` on that latest value (do not persist the earlier snapshot).
2. Optionally, if a write fails or if you want extra safety, add a small retry loop: re-read latest sessions, re-apply remap, and attempt `set` again.
3. Keep the remap transformation minimal (only update `apiMode.providerId` for affected custom sessions) so that unrelated session fields are preserved.

This doesn’t make the operation fully atomic, but it significantly reduces the likelihood of overwriting newer session updates and ensures you always migrate the most recent session state you can see.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit d02d04a


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Slashless paths break remap ✓ Resolved 🐞 Bug ≡ Correctness
Description
getProviderChatCompletionsUrlForCompare() compares chatCompletionsPath/completionsPath against
hard-coded "/v1/..." strings without normalizing leading slashes, so stored paths like
"v1/chat/completions" can yield mismatched derived URLs (e.g., "/v1/v1/..."), causing
resolveRenamedProviderId() to fail URL-based disambiguation. In those ambiguous-rename cases,
sessions/customApiModes may not be remapped to the new provider IDs, breaking request resolution for
affected legacy sessions.
Code

src/config/index.mjs[R1018-1032]

+function getProviderChatCompletionsUrlForCompare(provider) {
+  const directUrl = normalizeEndpointUrlForCompare(provider?.chatCompletionsUrl)
+  if (directUrl) return directUrl
+
+  let baseUrl = normalizeEndpointUrlForCompare(provider?.baseUrl)
+  const path = normalizeText(provider?.chatCompletionsPath)
+  if (!baseUrl || !path) return ''
+  const usesDefaultV1Paths =
+    path === '/v1/chat/completions' &&
+    normalizeText(provider?.completionsPath) === '/v1/completions'
+  if (!normalizeText(provider?.completionsUrl) && usesDefaultV1Paths) {
+    baseUrl = baseUrl.replace(/\/v1$/i, '')
+  }
+  return normalizeEndpointUrlForCompare(`${baseUrl}/${path.replace(/^\/+/, '')}`)
+}
Evidence
The new migration-time comparison helper relies on exact '/v1/...' path matches but the storage
normalization path does not enforce leading slashes, while runtime URL building does; this
discrepancy can cause the migration’s URL matching to compute different URLs than the runtime
resolver uses, preventing providerId remapping in ambiguous-rename scenarios.

src/config/index.mjs[1018-1032]
src/config/index.mjs[1109-1116]
src/services/apis/provider-registry.mjs[259-268]
src/services/apis/provider-registry.mjs[304-333]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getProviderChatCompletionsUrlForCompare()` uses strict string equality against `'/v1/chat/completions'` and `'/v1/completions'` without normalizing leading slashes. If legacy stored providers have paths like `'v1/chat/completions'` and a baseUrl ending in `/v1`, the computed comparison URL can become `.../v1/v1/chat/completions`, which won’t match the session’s `customUrl`. This prevents `resolveRenamedProviderId()` from disambiguating duplicate providerId renames by URL, leaving some sessions/customApiModes pointing at now-renamed provider IDs.

### Issue Context
Runtime URL building in `provider-registry.mjs` *does* normalize leading slashes via `ensureLeadingSlash()`, so migration-time URL comparisons can diverge from runtime request URLs.

### Fix Focus Areas
- src/config/index.mjs[1018-1032]
- src/config/index.mjs[1109-1116]

### Suggested fix
1) In `getProviderChatCompletionsUrlForCompare()`, normalize `chatCompletionsPath` and `completionsPath` with a small local `ensureLeadingSlash()` helper (or equivalent) before:
  - performing the `usesDefaultV1Paths` equality checks
  - constructing the final `${baseUrl}/${path...}` URL
2) (Optional but safer) Also normalize stored provider `chatCompletionsPath`/`completionsPath` in `normalizeCustomProviderForStorage()` to always include a leading `/`, aligning storage/migration behavior with runtime behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 3fb39ff


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Informational
1. Legacy IDs not cleared ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
applySelectedProviderToApiMode only deletes legacyProviderIds when providerId changes, so
legacyProviderIds can persist as stale metadata when the apiMode is later saved as a non-custom
group. This increases the chance of unintended legacy matching behavior over time and makes stored
apiMode state harder to reason about.
Code

src/popup/sections/api-modes-provider-utils.mjs[R310-315]

  const currentProviderId = normalizeText(nextApiMode.providerId)
  const nextProviderId = normalizeText(selectedProviderId)
  nextApiMode.providerId = nextProviderId
+  if (currentProviderId !== nextProviderId) {
+    delete nextApiMode.legacyProviderIds
+  }
Evidence
The PR adds explicit clearing of legacyProviderIds only when providerId changes, but the save
sanitizer for non-custom modes does not delete the field. Separately, session-compat selection now
checks legacyProviderIds, so persisting stale values is unnecessary and can influence matching if
data shapes drift over time.

src/popup/sections/api-modes-provider-utils.mjs[303-339]
src/utils/model-name-convert.mjs[269-301]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`legacyProviderIds` is a compatibility/migration field intended for custom provider-backed modes, but it is only cleared on providerId changes. When an apiMode is saved as a non-custom group, `sanitizeApiModeForSave` clears provider-related fields but leaves `legacyProviderIds`, persisting stale lineage metadata.

### Issue Context
This PR adds session-compat logic that consults `legacyProviderIds`, so leaving stale arrays around is unnecessary risk and complicates future migrations/debugging.

### Fix Focus Areas
- src/popup/sections/api-modes-provider-utils.mjs[303-339]

### Suggested fix
In `sanitizeApiModeForSave`, when `groupName !== 'customApiModelKeys'`, also `delete nextApiMode.legacyProviderIds` (and consider doing the same in any other non-custom sanitization paths).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

Copilot AI 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.

Pull request overview

Adds NVIDIA NIM as a first-class OpenAI-compatible API provider in the extension’s provider registry/config, including model presets and unit coverage to ensure provider resolution and routing work end-to-end with the existing OpenAI-compatible infrastructure.

Changes:

  • Register nvidia-nim as a built-in OpenAI-compatible provider (base URL + chat completions path) and add legacy preset/provider resolution.
  • Add NVIDIA NIM model group + presets (GLM-5.2, Nemotron-3-Ultra, DeepSeek V4 Pro) and wire the API-key field into config/mappings.
  • Extend unit tests to cover provider-id resolution, request resolution, and thin adapter routing for NVIDIA NIM.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/unit/services/apis/thin-adapters.test.mjs Adds thin-adapter coverage ensuring NVIDIA NIM requests use the expected base URL and provider secret.
tests/unit/services/apis/provider-registry.test.mjs Adds tests for legacy preset resolution and OpenAI-compatible request resolution for NVIDIA NIM.
tests/unit/config/config-predicates.test.mjs Adds predicate coverage for detecting NVIDIA NIM API model usage.
src/services/apis/provider-registry.mjs Registers NVIDIA NIM as a built-in provider and supports resolving it from legacy model names.
src/popup/sections/GeneralPart.jsx Adds the NVIDIA API key setup link for the nvidia-nim provider.
src/config/openai-provider-mappings.mjs Maps NVIDIA NIM API mode group to provider id and wires its legacy API-key field mapping.
src/config/index.mjs Adds NVIDIA NIM model group/presets and the nvidiaNimApiKey config field + predicate.
src/background/index.mjs Treats NVIDIA NIM sessions as OpenAI-compatible API sessions for routing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 589b988

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 27c6770

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@src/config/index.mjs`:
- Around line 1222-1227: Update the session remap flow around
sessionProviderIdRenameLookup so it is derived from the final provider IDs after
all promoteCustomModeApiKeyToProvider operations complete, rather than from the
intermediate providerIdRenameLookup state. Ensure every subsequent session
persistence path, including the related logic at the other referenced locations,
uses the refreshed mapping when promotion reassigns a mode.
- Around line 1857-1863: Update the session migration flow around
migrateUserConfig and remapSessionProviderIds to run the sessions read,
provider-ID remapping, and storage.local.set write through the existing session
persistence lock/queue. Keep the entire read-modify-write sequence serialized,
including the related migration path near the second session update, so
concurrent session saves are not overwritten.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 136a53c2-9bef-4714-b2dd-f4e3bf0d8a7b

📥 Commits

Reviewing files that changed from the base of the PR and between 27c6770 and d48fe61.

📒 Files selected for processing (11)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/popup/sections/import-data-cleanup.mjs
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/config/migrate-nvidia-nim-provider.test.mjs
  • tests/unit/popup/import-data-cleanup.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs
🚧 Files skipped from review as they are similar to previous changes (7)
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs
  • tests/unit/services/apis/provider-registry.test.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/services/apis/provider-registry.mjs
  • src/background/index.mjs

Comment thread src/config/index.mjs Outdated
Comment thread src/config/index.mjs Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Comment thread src/config/index.mjs Outdated
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit d48fe61

@PeterDaveHello
PeterDaveHello force-pushed the add-nvidia-nim-provider branch from d48fe61 to d02d04a Compare July 18, 2026 22:08
@PeterDaveHello
PeterDaveHello force-pushed the add-nvidia-nim-provider branch from 9d24d5e to 421fc0d Compare July 19, 2026 00:31

Copy link
Copy Markdown
Member Author

Reviewed the outside-diff suggestion about disabled-provider URL recovery. No code change is needed: getCustomProvidersMatchedByLegacySessionUrl filters entries with enabled === false before calling resolveCustomProviderByLegacySessionUrl, and the disabled-provider URL/legacy-ID regression tests verify fail-closed behavior.

Copilot AI 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.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comment thread src/popup/sections/api-modes-provider-utils.mjs Outdated
Comment thread src/services/apis/provider-registry.mjs Outdated
Comment thread src/utils/model-name-convert.mjs Outdated
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 421fc0d

Copilot AI 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.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 1248673

Copilot AI 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.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit eab051b

@PeterDaveHello
PeterDaveHello force-pushed the add-nvidia-nim-provider branch from eab051b to 366c25f Compare July 19, 2026 02:16
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 366c25f

@PeterDaveHello
PeterDaveHello force-pushed the add-nvidia-nim-provider branch from 366c25f to 54f8a3a Compare July 19, 2026 02:42
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 54f8a3a

Register NVIDIA NIM as a built-in OpenAI-compatible chat provider and expose selected featured model presets.

Wire shared API-key storage, request routing, setup links, and focused coverage for the NVIDIA hosted endpoint.
@PeterDaveHello
PeterDaveHello force-pushed the add-nvidia-nim-provider branch from 54f8a3a to 9aa53a6 Compare July 19, 2026 08:27
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 9aa53a6

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@PeterDaveHello
PeterDaveHello merged commit b325ce7 into ChatGPTBox-dev:master Jul 19, 2026
4 checks passed
@PeterDaveHello
PeterDaveHello deleted the add-nvidia-nim-provider branch July 19, 2026 17:46
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