Skip to content

fix(tui): keep model selection stable across catalog refresh #35967

Description

@kitlangton

Summary

After a managed-service restart and catalog refresh, the V2 model picker exposed 189 active entries across four providers. Large overlapping model sets from connection-backed providers made the picker difficult to use, and an existing session durably switched from its previous model to an unintended provider/model.

The server correctly persisted the selected value, so this was not only stale rendering. It is not yet clear whether reconnect state, picker interaction, or catalog reordering initiated the selection.

Environment

  • Channel: next
  • Version: 0.0.0-next-15145
  • macOS arm64
  • origin/v2: 212c9f99ee2d082082a00f7074df950974747a2a
  • Multiple connection-backed providers from one integration

Observed catalog

GET /api/model for the affected Location returned 189 active models:

primary hosted provider       76
connection-backed provider A 54
connection-backed provider B 52
direct provider               7
total                       189

Many model names and IDs appeared under more than one provider. The picker renders all non-deprecated models, grouped by provider, after favorites and recents. The full overlapping sets therefore remain visible and selectable.

No credentials, organization identifiers, connection identifiers, or model request payloads are included here.

Session behavior

Before the restart, the session's last successful step used its established connection-backed model.

Several minutes after the restart, the durable history recorded:

session.model.selected  direct-provider / alternate-model / high
session.prompt.admitted
session.execution.started
session.prompt.promoted
session.step.started     direct-provider / alternate-model / high
session.step.failed      provider.unknown
session.execution.failed provider.unknown

The same provider/model failed again on the next prompt. The session API also returned that alternate model as current, confirming the wrong selection had been persisted rather than merely displayed.

Switching the model back through POST /api/session/:id/model immediately restored the expected durable selection.

Expected behavior

  • Reconnect and catalog refresh must preserve the current session model unless the user explicitly selects another model.
  • The model picker should remain usable when several connection-backed providers expose overlapping catalogs.
  • Identical model names/IDs from related providers should either be collapsed, filtered to the connection's actual scope, or clearly differentiated without presenting hundreds of near-duplicate rows.
  • Catalog reordering should not make an existing keyboard selection resolve to a different provider/model.

Relevant UI behavior

packages/tui/src/component/dialog-model.tsx renders every non-deprecated item returned by data.location.model.list(). Favorites and recents are promoted into sections, but all remaining provider models are still appended. Selection is represented by { providerID, modelID }.

The provider plugin also registers each remote provider's complete returned model map independently. If several connection-backed providers return overlapping maps, the API and picker preserve every provider/model pair.

Questions to investigate

  • Did catalog refresh reorder an open picker while retaining a positional selection?
  • Can reconnect restore local picker/model state by list index rather than stable { providerID, modelID } identity?
  • Should connection-backed providers expose the entire remote catalog or only models valid for that connection?
  • Should the picker default to favorites/recents and require search or provider expansion for the full catalog?
  • Can identical model IDs across providers be visually collapsed while preserving explicit provider selection?

Suggested coverage

  • Open the picker, refresh/reorder the model catalog, and verify the highlighted/selected stable model identity does not change.
  • Reconnect a session with a persisted model while multiple overlapping providers initialize concurrently.
  • Feed the picker several providers with large overlapping model sets and verify a bounded, comprehensible default view.
  • Verify no session.model.selected event is written solely because the catalog refreshed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    2.0bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)tui

    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