feat(models): resolve active session models through provider adapters

The model inventory command was showing a mix of catalog defaults and
composer-local state instead of the model that is actually active for a
real provider session. That made /models, /cost, and /status
misleading once a session had already started, especially for providers
whose effective runtime model can differ from the optimistic model value
held in the UI.

Introduce an explicit getCurrentActiveModel() contract on
IProviderModels so model resolution lives next to each provider's
catalog logic and uses the provider-native source of truth:

- Claude reads the init event from a resumed stream-json run
- Codex reads model from ~/.codex/config.toml
- Cursor reads lastUsedModel from the chat store.db
- OpenCode reads the persisted session model from opencode.db
- Gemini intentionally returns its default because the CLI does not
  provide a reliable active-session lookup

Keep the returned shape intentionally minimal ({ model }). The goal is
to expose only what downstream command consumers need and avoid leaking
provider-specific metadata into a shared transport shape that would
create extra UI coupling and future cleanup cost.

Also make command behavior session-aware: when there is no concrete
session id, do not spawn provider processes or inspect provider session
storage just to answer /models, /cost, or /status. In a new-session
view the correct answer is simply the provider default, and doing more
work there adds latency and unnecessary side effects for no user value.

As part of this, centralize two supporting concerns:

- add a shared helper for building the default current-model result from
  a provider catalog so fallbacks stay aligned with DEFAULT
- move leaf-directory validation into shared utils so Cursor session
  readers and model lookup code enforce the same path-safety rule

Tests were expanded to cover both the new service delegation path and
the sessionless command behavior, while keeping cache-sensitive tests
isolated from persisted host cache state.

Why this change:
- command output should reflect the model actually driving a session
- new-session views should stay fast and side-effect free
- provider-specific active-model lookup should not be scattered across
  routes or UI code
- fallback behavior should be explicit, consistent, and limited to the
  provider default when no true active model can be resolved
This commit is contained in:
Haileyesus
2026-05-18 14:54:32 +03:00
parent 556cbd1a03
commit bc5e768579
13 changed files with 537 additions and 52 deletions

View File

@@ -109,6 +109,20 @@ export type ProviderModelsResult = {
cache: ProviderModelsCacheInfo;
};
// ---------------------------
//----------------- PROVIDER ACTIVE MODEL TYPES ------------
/**
* Provider-neutral result for the model that is actively driving a session or
* provider runtime at the time of lookup.
*
* `model` must always be populated. Provider adapters should use the
* provider-specific lookup method requested by the caller, and only fall back
* to the provider catalog `DEFAULT` value when the active model cannot be read.
*/
export type ProviderCurrentActiveModel = {
model: string;
};
/**
* Message/event variants emitted by provider adapters and normalized transports.
*