Skip to content

config: no-auth custom providers (e.g. lmstudio) dropped when env is undefined #37144

Description

@eruizc-dev

Summary

Custom (no-auth) providers declared in V2 config under providers.<id> — such as a local
LM Studio server — are silently dropped if they do not define env and are not otherwise
registered as integrations. The /connect flow then offers only the three built-in hardcoded
LM Studio models instead of the user's configured server/models.

Environment

  • opencode version: v1.17.20+ded9f87 (V2, via nix run .#opencode2 - custom nix flake to run v2 binary)
  • OS: Linux 7.1.3 (NixOS, x86_64)
  • Terminal: TERM_PROGRAM=kgx, TERM=xterm-256color, COLORTERM=truecolor
  • Shell: /run/current-system/sw/bin/zsh
  • Install/channel: nix (local dev build from dev)
  • Active plugins: None configured

Reproduction

  1. Configure a local LM Studio provider in ~/.config/opencode/opencode.jsonc:

    {
      "providers": {
        "lmstudio": {
          "npm": "@ai-sdk/openai-compatible",
          "name": "Lm-Studio",
          "settings": { "baseURL": "http://localhost:1234/v1" },
          "models": {
            "qwen/qwen3.6-27b": { "name": "QWEN 3.6 27b", "modelID": "qwen3.6-27b" },
            "google/gemma-4-26b-a4b-qat": { "name": "Gemma 4 26B-A4B", "modelID": "gemma4-26b-a4b-qat" }
          }
        }
      }
    }

    (No env key — LM Studio is a local server and needs no API key.)

  2. Launch opencode2 and run /connect.

  3. Select LM Studio from the list.

  4. Observe it only offers the three built-in models (openai/gpt-oss-20b,
    qwen/qwen3-30b-a3b-2507, qwen/qwen3-coder-30b) pulled from ModelsDev — NOT the
    qwen/qwen3.6-27b and google/gemma-4-26b-a4b-qat models defined in the user config.

Expected Behavior

  • The user's providers.lmstudio config (base URL, custom model list) should be picked up and
    the configured models should appear in the model picker.
  • /connect for a no-auth local provider should surface the configured server rather than
    silently ignoring it.

Actual Behavior

The configured lmstudio provider is discarded. Root cause appears to be the integration/catalog
transform in packages/core/src/config/plugin/provider.ts:

const configuredIntegrations = new Set(
  files.flatMap((file) =>
    Object.entries(file.info.providers ?? {}).flatMap(([id, provider]) =>
      provider.env === undefined ? [] : [id],
    ),
  ),
)
for (const file of files) {
  for (const [id, item] of Object.entries(file.info.providers ?? {})) {
    const integrationID = id
    if (!configuredIntegrations.has(id) && !integrations.get(integrationID)) continue  // <-- drops no-auth providers
    integrations.update(integrationID, ...)
    ...
    catalog.provider.update(providerID, ...)  // this never runs for lmstudio
    ...
  }
}

Because lmstudio has no env, it is never added to configuredIntegrations, and there is no
pre-existing integration with that id, so the entire loop iteration is skipped — including the
catalog.provider.update(...) that would apply the config. Local/open-weight providers that need
no credential therefore cannot be configured through providers.<id>.

Additionally, the /connect provider-selection list (packages/opencode/src/cli/cmd/providers.ts)
is built only from ModelsDev + plugin providers and has no entry for user-configured custom
providers, so there is no path to authenticate/discover a locally-defined provider either.

Additional Context

  • The V1→V2 config migration (packages/core/src/v1/config/migrate.ts) correctly maps
    provider.lmstudio → V2 providers.lmstudio (with package from npm and settings.baseURL
    from api/options). The migrated config is loaded; the drop happens later in the
    integration/catalog transform.
  • The catalog available() logic in packages/core/src/catalog.ts does support no-auth providers
    (provider.integrationID === undefined && !integration → available), so the only blocker is the
    env-gated continue.
  • Workaround attempted: none effective. Adding a dummy env array to the provider config makes it
    appear in the integration list, but LM Studio does not use an API key, so this is not a real fix.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions