Skip to content

feat(providers): formalize model discovery modes - #422

Open
Lxr-max wants to merge 2 commits into
OpenCoworkAI:mainfrom
Lxr-max:cursor/provider-model-discovery-modes-2c48
Open

Lxr-max wants to merge 2 commits into
OpenCoworkAI:mainfrom
Lxr-max:cursor/provider-model-discovery-modes-2c48

Conversation

@Lxr-max

@Lxr-max Lxr-max commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Provider model discovery still mostly assumed a listing endpoint, even though real providers split into GET /models, a static catalog, manual IDs, inference-only gateways, and imports with a single known default. This adds a formal modelDiscoveryMode and drives listing, Settings pickers, import defaults, connection tests, and diagnostics from it so “no /models” is no longer a uniform hard failure.

Fixes #210

Mode enum: models | static-hint | manual | infer-only

Mode models:v1:list-for-provider Settings picker Connection test
models GET /models remote select probe /models; 404 + working inference stays degraded
static-hint local modelsHint + defaultModel local select skip /models (ChatGPT Codex OAuth still uses its existing token check)
manual [defaultModel] locally text input skip /models, probe inference → compatible
infer-only same as manual text input skip /models; missing listing is expected, not degraded

Built-in / import defaults:

  • Anthropic, OpenAI, OpenRouter, Ollama → models
  • ChatGPT Codex OAuth → static-hint
  • Claude Code official api.anthropic.com → models; custom/proxy base → infer-only
  • Gemini CLI / OpenCode official maps → models
  • Codex config import → infer-only
  • Custom add form: discovered list → models; listing failed → infer-only; user chose manual → manual

Independent of sibling PRs #419 / #420 / #421; additive types only.

Type of change

  • New feature

Linked issue

Fixes #210

Checklist

  • I checked the linked issue / relevant context before starting
  • pnpm lint && pnpm typecheck && pnpm test passes locally
  • Added/updated tests for the change
  • Added a changeset (pnpm changeset) if user-visible
  • Updated i18n strings for Settings picker + diagnostics copy

Principles 5b

  • Compatible: existing supportsModelsEndpoint / modelsHint still work; modelDiscoveryMode is optional on disk and older configs derive a mode
  • Upgradeable: schemaVersion unchanged; Zod accepts the new optional capability field and locksteps it with listing
  • Lean: no new dependencies; one shared helper module consumed by IPC, Settings, imports, and diagnostics
  • Elegant: listing, picker UX, connection tests, and 404 wording all key off the same mode instead of per-provider fallbacks

Tests

Cover mode helpers, list-for-provider plans, infer-only/manual connection tests (skip /models, success is compatible), Settings picker state, parser payloads, builtin/import stamps, and diagnostics that treat listing 404 as info when the mode does not expect /models.

Screenshots / recordings (UI changes)

Settings picker and custom-provider test copy changed. This environment cannot drive the Electron Settings UI, so those flows were verified with unit tests rather than a live click-through.

@github-actions github-actions Bot added docs Documentation area:desktop apps/desktop (Electron shell, renderer) labels Sep 14, 2026
@cursor
cursor Bot force-pushed the cursor/provider-model-discovery-modes-2c48 branch from c77991e to 28f5b17 Compare September 23, 2026 15:55
@Lxr-max

Lxr-max commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (26c8498). Head is 28f5b17; mergeable_state is clean again.

Conflict resolution kept modelDiscoveryMode (models | static-hint | manual | infer-only) and the keyless-provider work that landed on main:

  • Provider rows now carry both requiresApiKey and modelDiscoveryMode / modelsHint.
  • Custom-provider discovery still passes keyRequired into the keyless probe, and a real discovery run sets discoveryTouched so the saved mode follows that result.
  • The connection test keeps the stale-response guard and the success path that fills the model dropdown, and still treats not-a-model-endpoint as listing-unavailable.
  • Atlas Cloud, added on main, is stamped modelDiscoveryMode: "models" like the other listing builtins.

Checks on 28f5b17:

  • pnpm lint — pass
  • pnpm typecheck — pass
  • pnpm test — pass

@Lxr-max

Lxr-max commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

Hi, a gentle ping on this one when you have time.

It still merges cleanly into current main (5bc24f0). On that merge, pnpm typecheck, biome check, and the shared/providers/desktop provider tests all pass locally.

I know ~1.2k lines is a lot to review in one go. If it helps, I can split it into three smaller PRs:

  1. packages/shared: model-discovery.ts helpers + config schema/derivation + tests
  2. main process: list-for-provider / connection test honoring the mode + built-in and import defaults
  3. renderer: Settings model picker (select vs manual) + diagnostics copy + i18n

Happy to do either. Also, #421 touches the same connection-test path, so I'd suggest landing this one first. I'll rebase #421 on top of it.

Declare modelDiscoveryMode on provider capabilities so listing, Settings
pickers, imports, and diagnostics stop treating GET /models as universal.

Fixes OpenCoworkAI#210
@Lxr-max
Lxr-max force-pushed the cursor/provider-model-discovery-modes-2c48 branch from 28f5b17 to 1e2f3c8 Compare October 4, 2026 16:46

@github-actions github-actions 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.

Findings

  • [Minor] Every Codex config import is blanket-stamped infer-only, which drops model listing for OpenAI-compatible endpoints that do expose GET /models — packages/shared/src/model-discovery.ts (discoveryModeForImport: if (source === 'codex') return 'infer-only'), applied at apps/desktop/src/main/imports/codex-config.ts:241. Before this PR these entries carried no capabilities, so resolveProviderCapabilities derived models and the Settings picker fetched /models. Endpoints in the Codex import allowlist (DEEPSEEK_API_KEY, GROQ_API_KEY, MISTRAL_API_KEY, XAI_API_KEY, OPENAI_API_KEY, …) are standard OpenAI-compatible hosts where listing works, so this is a user-visible downgrade: the picker now forces manual ID entry and the connection test skips /models even though listing is available. The Claude Code path already handles this correctly by branching on host (isDefaultAnthropicApiHost).
    Suggested fix / next action: narrow this the same way — for source === 'codex', return models when entry.baseUrl resolves to a known listing-capable host (e.g. api.openai.com, api.deepseek.com, api.groq.com, api.mistral.ai, api.x.ai), and only fall back to infer-only for unknown/proxy hosts. If the blanket choice is deliberate, please note the rationale (and the lost listing) in the PR body.

Questions

  • ConnectionDiagnosticPanel gained an optional modelDiscoveryMode prop (apps/desktop/src/renderer/src/components/ConnectionDiagnosticPanel.tsx), but I could not find a render site passing it. Because it is optional, TypeScript will not flag a missing pass-through, and if it is not wired the new diagnose('404', …) branch (packages/shared/src/diagnostics.ts, the model-discovery-degraded early return) only fires in unit tests, not in the real UI. Can you confirm the caller passes modelDiscoveryMode={row.modelDiscoveryMode} (or equivalent)?

Summary

Review mode: initial

The change direction is sound and additive: modelDiscoveryMode is an optional on-disk field, schemaVersion is unchanged, ProviderModelDiscoveryModeSchema only gains infer-only (old configs still parse), supportsModelsEndpoint is now derived in lockstep with the mode instead of drifting from it, and no new dependencies or direct provider-SDK imports are introduced. Test coverage is strong for the new paths (helpers, list-for-provider plans, connection-test modes, parsers, imports, picker state, diagnostics). The one substantive concern is the blanket Codex-import stamp above.

Residual observations (non-blocking):

  • discoveryModeForImport treats opencode and gemini as always models regardless of base URL, whereas claude-code branches on host. If an OpenCode/Gemini entry can point at a local/custom proxy, it will keep probing /models; worth confirming the mappings are official-only.
  • infer-only and manual are near-duplicates for picker/connection-test behavior (settingsModelPickerKind, connectionTestProbesModelsEndpoint, resolveListForProviderPlan); the distinction is semantic only. Acceptable, but consider documenting it so future call sites do not assume behavioral differences.
  • I could not independently fetch the body/acceptance criteria of the linked issue #210 in this run; the diff is on-topic for “/models is not universal,” but verify the specific acceptance criteria against the mode matrix before treating Fixes #210 as satisfied.

Testing

Not run (automation). Coverage added: packages/shared/src/model-discovery.test.ts, packages/shared/src/config.test.ts, packages/shared/src/diagnostics.test.ts, apps/desktop/src/main/connection-ipc.test.ts, apps/desktop/src/main/onboarding/provider-parsers.test.ts, apps/desktop/src/main/provider-settings.test.ts, and import/Settings suites. The PR acknowledges no live Electron click-through for the Settings picker; an E2E walk of the manual-vs-select flows would close that gap but is not required to merge.

Open-CoDesign Bot

Codex imports no longer stamp every provider infer-only. Official hosts
that expose GET /models keep listing; custom and proxy hosts stay
infer-only, matching the Claude Code host split.

Settings connection failures now render ConnectionDiagnosticPanel with
the row's modelDiscoveryMode so a /models 404 follows the declared mode.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:desktop apps/desktop (Electron shell, renderer) docs Documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: 正式建模模型发现模式 / Formalize provider model discovery modes

3 participants