mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-03 04:49:26 +00:00
composer: drop the hardcoded model fallback
Until /v1/settings supplies the list the picker is a disabled "Loading models…" chip. The baked-in list had gone stale and offered phantom ids during the boot race.
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import { test, expect } from "./fixtures";
|
||||
|
||||
// The composer must never advertise models the backend didn't confirm: before the
|
||||
// /v1/settings list arrives (cold app boot races the sidecar), the picker is a
|
||||
// disabled "Loading models…" chip — NOT a hardcoded fallback list, which went stale
|
||||
// and offered phantom ids (caught by owner, 2026-07-21).
|
||||
test("picker shows a disabled Loading-models chip until the list arrives", async ({ page }) => {
|
||||
await page.route("**/v1/settings", (r) =>
|
||||
r.fulfill({
|
||||
json: { model: "gpt-5.5", models: [], model_labels: {}, has_key: true, model_ready: true, onboarded: true, nav_layout: "flat" },
|
||||
}),
|
||||
);
|
||||
await page.goto("/");
|
||||
const chip = page.getByTestId("models-loading");
|
||||
await expect(chip).toBeVisible();
|
||||
await expect(chip).toBeDisabled();
|
||||
await expect(chip).toContainText("Loading models…");
|
||||
});
|
||||
@@ -23,9 +23,9 @@ const PERMISSION_OPTIONS: Option[] = [
|
||||
{ value: "custom", label: "Custom", description: "Use auto-allow rules from config.toml" },
|
||||
];
|
||||
|
||||
// Fallback list when the server hasn't supplied one yet; the live list (incl. detected Ollama
|
||||
// models) arrives via the `models` prop.
|
||||
const MODEL_VALUES = ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.5"];
|
||||
// No hardcoded model fallback: until the server supplies the list (a few seconds after a
|
||||
// cold app boot), the picker renders a disabled "Loading models…" chip. A baked-in list
|
||||
// goes stale and silently offers ids the backend never confirmed (caught 2026-07-21).
|
||||
|
||||
// Drop the provider prefix for display (anthropic:claude-opus-4-8 → claude-opus-4-8); full id on hover.
|
||||
const shortModel = (m: string) => (m.includes(":") ? m.split(":").slice(1).join(":") : m);
|
||||
@@ -319,8 +319,10 @@ export function Composer(props: Props) {
|
||||
}
|
||||
};
|
||||
|
||||
const available = props.models && props.models.length ? props.models : MODEL_VALUES;
|
||||
const modelOptions: Option[] = Array.from(new Set([props.model, ...available])).map((m) => ({
|
||||
const modelsLoaded = !!(props.models && props.models.length);
|
||||
const modelOptions: Option[] = Array.from(
|
||||
new Set([props.model, ...(props.models || [])]),
|
||||
).map((m) => ({
|
||||
value: m,
|
||||
label: props.modelLabels?.[m] || shortModel(m),
|
||||
}));
|
||||
@@ -472,9 +474,19 @@ export function Composer(props: Props) {
|
||||
<span className="model-warn-ico" aria-hidden>⚠</span>
|
||||
</button>
|
||||
) : (
|
||||
!props.modelLocked && (
|
||||
<Dropdown value={props.model} options={modelOptions} onChange={props.onModelChange} align="right" />
|
||||
)
|
||||
!props.modelLocked &&
|
||||
(modelsLoaded ? (
|
||||
<Dropdown value={props.model} options={modelOptions} onChange={props.onModelChange} align="right" />
|
||||
) : (
|
||||
<button
|
||||
className="pill chip text-faint cursor-default"
|
||||
disabled
|
||||
data-testid="models-loading"
|
||||
title="Fetching the model list from the server"
|
||||
>
|
||||
<span className="pill-label">Loading models…</span>
|
||||
</button>
|
||||
))
|
||||
))}
|
||||
|
||||
{/* mic — immediately before send (owner call, DMG #28 walkthrough) */}
|
||||
|
||||
Reference in New Issue
Block a user