diff options
| author | Adam Malczewski <[email protected]> | 2026-08-12 22:01:59 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-08-12 22:01:59 +0900 |
| commit | 5f10a40b26dbfdc10b2c02cdf23ec3a7edfa9443 (patch) | |
| tree | 2f1d5ee2674d1dcc9909e89f06a82a7b10b4191a /src/features/chat/ui | |
| parent | 774519e052fd869952cc5e05aca159e4bf978fa1 (diff) | |
| download | dispatch-web-5f10a40b26dbfdc10b2c02cdf23ec3a7edfa9443.tar.gz dispatch-web-5f10a40b26dbfdc10b2c02cdf23ec3a7edfa9443.zip | |
feat(models): numbered OpenCode credential selection, labels, migration
Adopt the numbered OPENCODE_API_KEY_N scheme in the model picker and
concurrency surfaces.
- model-select: numeric sort of opencode-<n> keys (#2 before #10); friendly
OpenCode #N labels (raw opencode-N/<model> value still selected/persisted);
migrateLegacyModelName rewrites opencode/<model> -> opencode-1/<model>.
- ModelSelector: renders friendly key labels; surfaces a disappeared saved
credential as UNAVAILABLE (disabled option + notice) without silently
switching to another model.
- app store: DEFAULT_MODEL -> opencode-1/...; catalogs no longer auto-fallback
the active model when the selected credential is absent; boot restore
migrates persisted legacy opencode/<model> tab models idempotently.
- concurrency: providerLabel renders opencode-<n> as OpenCode #<n> in the
limit rows and Add dropdown (raw provider id preserved on the wire).
- Tests: parsing/sorting/labels/migration, unavailable-state selector behavior,
no-silent-fallback, and concurrency provider label; fixtures updated to the
numbered scheme.
Verification: bun install, bun run typecheck (0 errors), bun run test
(1179 passed), bun run check (clean, exit 0), bun run build (vite OK).
Diffstat (limited to 'src/features/chat/ui')
| -rw-r--r-- | src/features/chat/ui/ModelSelector.svelte | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/src/features/chat/ui/ModelSelector.svelte b/src/features/chat/ui/ModelSelector.svelte index 11b9feb..1d06848 100644 --- a/src/features/chat/ui/ModelSelector.svelte +++ b/src/features/chat/ui/ModelSelector.svelte @@ -1,6 +1,13 @@ <script lang="ts"> import type { ModelMetadata } from "@dispatch/transport-contract"; - import { isVisionModel, joinModelName, modelKeys, modelsForKey, splitModelName } from "../model-select"; + import { + isVisionModel, + joinModelName, + modelKeyLabel, + modelKeys, + modelsForKey, + splitModelName, + } from "../model-select"; let { models, @@ -27,8 +34,17 @@ // Whether the currently-selected full model name is vision-capable. const selectedVision = $derived(isVisionModel(modelInfo, selected)); + // Whether the currently-selected full name is PRESENT in the catalog. When a + // saved credential/model disappears, we show it as unavailable rather than + // silently switching to something else. + const selectedUnavailable = $derived(selected !== "" && !models.includes(selected)); + // The key part is itself missing from the catalog (e.g. a whole numbered + // OpenCode credential was removed). + const keyUnavailable = $derived(selected !== "" && !keys.includes(current.key)); + // Switching key jumps to the first model available under it. function selectKey(key: string): void { + if (key === current.key) return; const first = modelsForKey(models, key)[0] ?? ""; onSelect(joinModelName(key, first)); } @@ -50,8 +66,11 @@ onchange={(e) => selectKey(e.currentTarget.value)} aria-label="Key selector" > + {#if keyUnavailable} + <option value={current.key} disabled>{modelKeyLabel(current.key)} (unavailable)</option> + {/if} {#each keys as key (key)} - <option value={key}>{key}</option> + <option value={key}>{modelKeyLabel(key)}</option> {/each} </select> <select @@ -65,7 +84,15 @@ {model}{#if isVisionModel(modelInfo, fullNameFor(model))} ยท vision{/if} </option> {/each} + {#if selectedUnavailable && !keyUnavailable} + <option value={current.model} disabled>{current.model} (unavailable)</option> + {/if} </select> + {#if selectedUnavailable} + <div class="text-xs text-warning" role="status"> + Selected model โ{selected}โ is unavailable โ choose another credential. + </div> + {/if} {#if selectedVision} <div class="flex items-center gap-1 text-xs text-base-content/60"> <svg |
