Skip to content

tui: model picker hides provider grouping unless an integration connection exists #55288

Closed as duplicate

Description

@Ivony

Summary

In the TUI model picker (/models, or Ctrl+X then M), provider grouping and provider names are only shown when at least one integration has a saved connection. Providers declared in opencode.json (providers.<id>), which is the documented way to configure a custom gateway, never create a connection, so anyone using that path gets a flat, ungrouped, unlabeled model list. Combined with "free models first" sorting, this makes the picker look like it does not contain the configured provider at all.

Environment

  • opencode version: 2.0.28 (installed CLI; background service still reported 2.0.27 while reproducing)
  • OS: Windows_NT 10.0.26300 (win32 x64)
  • Terminal: Windows Terminal (WT_SESSION set), TERM=xterm-256color, TERM_PROGRAM unset
  • Shell: C:\WINDOWS\system32\cmd.exe; the agent shell used for the commands below is PowerShell 7.6.6
  • Install/channel: latest, installed via bun global (~/.bun/install/global/node_modules/@opencode/cli/bin/opencode.exe)
  • Active plugins: git-ai (local, ~/.config/opencode/plugins/git-ai.ts), utf8-encoding (local, ~/.config/opencode/plugins/utf8-encoding.ts)

Reproduction

  1. Start from a config with no saved integration connections (opencode auth list prints No authenticated integrations, opencode api get /api/credential returns {"data":[]}).

  2. Declare a custom provider using the documented recipe (Providers -> Custom / Gateways, Models -> Compatible) instead of /connect:

    {
      "model": "acme/coder",
      "providers": {
        "acme": {
          "name": "Acme Gateway",
          "package": "@opencode/ai/providers/openai-compatible",
          "settings": { "baseURL": "https://gateway.example.com/v1", "apiKey": "sk-***" },
          "models": { "coder": { "name": "Coder" } }
        }
      }
    }

    Migrating a V1 config instead (provider.acme.npm + provider.acme.options -> providers.acme.package + providers.acme.settings) has the same effect.

  3. Reload, then confirm the models resolve server-side:

    opencode reload
    opencode models                       # lists acme/coder
    opencode api get /api/model           # includes providerID "acme"
  4. Open the model picker (type /models, or press Ctrl+X then M).

  5. Observe the list.

Expected Behavior

Because the provider is enabled and its models resolve (steps 2-3), the picker should present those models the same way it presents any other provider: grouped by provider, with the provider name visible (and Favorites / Recent sections available).

Actual Behavior

The picker renders one flat list with:

  • no provider grouping, and no provider name anywhere in the rows,
  • no Favorites and no Recent sections,
  • ordering that puts free models first and then newest-first, so built-in free models occupy the top of the list.

There is no error. The configured provider's own models are present, but they are unlabeled and pushed below the fold, so the picker appears to contain "none of my models" and "only unfamiliar models".

Connecting any single catalog provider makes grouping appear globally, which confirms the gate below. Repro is consistent, not intermittent.

Additional Context

Cause

The model dialog's list builder computes one global boolean from the integration list and uses it to gate grouping, provider names, and the Favorites/Recent sections:

// 2.0.27: ej(t)   2.0.28: aj(t)
function aj(t) { return t.some((r) => r.connections.length > 0) }

and in the model dialog itself:

category:    w() ? provider.name ?? provider.id : undefined   // grouping + label
description: w() ? provider.name ?? provider.id : undefined   // provider name
M = w() ? favorite : []                                       // Favorites section
q = w() && filter === ""                                      // Recent section
// and when a query is typed, grouping is skipped entirely:
if (j) return ...fuzzysort(...)   // keys: ["title", "category"]

So "does the user have any provider" is implemented as "has the user ever connected an integration". Providers that come from configuration are explicitly present in the integration list, but with an empty connections array, so they do not satisfy the gate. Example from /api/integration on this machine (custom provider declared in opencode.json):

{
  "id": "acme",
  "name": "Acme Gateway",
  "methods": [{ "type": "key" }],
  "connections": []
}

Why this affects documented usage

The docs route custom gateways through configuration, not /connect:

  • Providers -> Custom: define providers.<id> with package, settings, models.
  • Providers -> Gateways: "For a gateway that exposes an OpenAI-compatible API but has its own model inventory, define a custom provider instead."
  • Models -> Compatible: same recipe for any OpenAI-compatible server.

None of those mention /connect, and providers.<id> produces no connection. /connect (and auth) manage integration accounts against catalog providers. A provider that is not in models.dev cannot be connected at all, so a self-hosted or internal gateway can never satisfy the gate.

Note /api/integration is not equivalent to models.dev: it is models.dev entries + built-in websearch integrations + any provider declared in config.

Workaround

Connect any provider that exists in the catalog, which flips the boolean globally:

opencode service set env DEEPSEEK_API_KEY sk-***
# or: /connect in the TUI

This is only a workaround; it requires storing an unrelated credential purely to change picker rendering.

Related issue

A second, independent defect in the same dialog: a model configured with "name": "" renders as a blank row and is unsearchable, because the display-name fallback uses ?? and therefore keeps the empty string instead of falling back to the model ID. Reported separately.

Activity

  1. Ivony commented on Oct 14, 2026

    @Ivony
    Author

    Related: #55289 (independent defect in the same dialog - empty configured name renders blank and is unsearchable).

  2. opencode-agent commented on Oct 14, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed write-up and root-cause analysis. I think this is a duplicate of #49309, which reports the same thing: the model picker drops provider names and grouping for providers declared in config, because the check only looks for saved integration connections.

    Possible duplicates and related items, ordered by likelihood:

    Your notes on the Favorites/Recent sections, the search path and the free-first ordering would be useful on #49309. The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.

  3. Ivony commented on Oct 14, 2026

    @Ivony
    Author

    Agreed, this is a duplicate of #49309 — same root cause (provider names/grouping gated on saved integration connections rather than configured providers), and #49309 plus #50322 cover it more thoroughly.

    Closing this one proactively rather than waiting for the automatic duplicate close.

    Two notes carried over so nothing is lost:

    Thanks for the triage.

  4. opencode-agent commented on Oct 14, 2026

    @opencode-agent
    Contributor

    Thanks for confirming, and for moving the configured-vs-connected point over to #49309. That keeps everything in one place. #55289 still covers the blank-row problem separately.

  5. opencode-agent commented on Oct 15, 2026

    @opencode-agent
    Contributor

    Closing this as a duplicate of #49309, as agreed above. Please follow #49309 (and #50322) for the provider grouping and names in the model picker, and #55289 for the blank-row problem with "name": "". Thanks again for the detailed report.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions