import { type ProviderKind, type ServerProvider } from "@t3tools/contracts";import { EnvironmentId } from "@t3tools/contracts";import { createModelCapabilities } from "@t3tools/shared/model";import { page, userEvent } from "vitest/browser";import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";import { render } from "vitest-browser-react"; import { ProviderModelPicker } from "./ProviderModelPicker";import { getCustomModelOptionsByProvider } from "../../modelSelection";import { DEFAULT_CLIENT_SETTINGS, DEFAULT_UNIFIED_SETTINGS } from "@t3tools/contracts/settings";import { __resetLocalApiForTests } from "../../localApi"; // Mock the environments/runtime module to provide a mock primary environment connectionvi.mock("../../environments/runtime", () => { const primaryConnection = { kind: "primary" as const, knownEnvironment: { id: "environment-local", label: "Local environment", source: "manual" as const, environmentId: EnvironmentId.make("environment-local"), target: { httpBaseUrl: "http://localhost:3000", wsBaseUrl: "ws://localhost:3000", }, }, environmentId: EnvironmentId.make("environment-local"), client: { server: { getConfig: vi.fn(), updateSettings: vi.fn(), }, }, ensureBootstrapped: async () => undefined, reconnect: async () => undefined, dispose: async () => undefined, }; return { getEnvironmentHttpBaseUrl: () => "http://localhost:3000", getSavedEnvironmentRecord: () => null, getSavedEnvironmentRuntimeState: () => null, hasSavedEnvironmentRegistryHydrated: () => true, listSavedEnvironmentRecords: () => [], resetSavedEnvironmentRegistryStoreForTests: vi.fn(), resetSavedEnvironmentRuntimeStoreForTests: vi.fn(), resolveEnvironmentHttpUrl: (_environmentId: unknown, path: string) => new URL(path, "http://localhost:3000").toString(), waitForSavedEnvironmentRegistryHydration: async () => undefined, addSavedEnvironment: vi.fn(), disconnectSavedEnvironment: vi.fn(), ensureEnvironmentConnectionBootstrapped: async () => undefined, getPrimaryEnvironmentConnection: () => primaryConnection, readEnvironmentConnection: () => primaryConnection, reconnectSavedEnvironment: vi.fn(), removeSavedEnvironment: vi.fn(), requireEnvironmentConnection: () => primaryConnection, resetEnvironmentServiceForTests: vi.fn(), startEnvironmentConnectionService: vi.fn(), subscribeEnvironmentConnections: () => () => {}, useSavedEnvironmentRegistryStore: ( selector: (state: { byId: Record<string, never> }) => unknown, ) => selector({ byId: {} }), useSavedEnvironmentRuntimeStore: ( selector: (state: { byId: Record<string, never> }) => unknown, ) => selector({ byId: {} }), };}); function selectDescriptor( id: string, label: string, options: ReadonlyArray<{ id: string; label: string; isDefault?: boolean }>,) { return { id, label, type: "select" as const, options: [...options], ...(options.find((option) => option.isDefault)?.id ? { currentValue: options.find((option) => option.isDefault)?.id } : {}), };} function booleanDescriptor(id: string, label: string) { return { id, label, type: "boolean" as const, };} const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [ { provider: "codex", displayName: "Codex", enabled: true, installed: true, version: "0.116.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), slashCommands: [], skills: [], models: [ { slug: "gpt-5-codex", name: "GPT-5 Codex", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("reasoningEffort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]), booleanDescriptor("fastMode", "Fast Mode"), ], }), }, { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("reasoningEffort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]), booleanDescriptor("fastMode", "Fast Mode"), ], }), }, ], }, { provider: "claudeAgent", displayName: "Claude", enabled: true, installed: true, version: "1.0.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), slashCommands: [], skills: [], models: [ { slug: "claude-opus-4-6", name: "Claude Opus 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, { id: "max", label: "max" }, ]), booleanDescriptor("thinking", "Thinking"), ], }), }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, { id: "max", label: "max" }, ]), booleanDescriptor("thinking", "Thinking"), ], }), }, { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]), booleanDescriptor("thinking", "Thinking"), ], }), }, ], },]; function buildCodexProvider(models: ServerProvider["models"]): ServerProvider { return { provider: "codex", displayName: "Codex", enabled: true, installed: true, version: "0.116.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), models, slashCommands: [], skills: [], };} function buildOpenCodeProvider(models: ServerProvider["models"]): ServerProvider { return { provider: "opencode", enabled: true, installed: true, version: "1.0.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), models, slashCommands: [], skills: [], };} async function mountPicker(props: { provider: ProviderKind; model: string; lockedProvider: ProviderKind | null; providers?: ReadonlyArray<ServerProvider>; triggerVariant?: "ghost" | "outline";}) { const host = document.createElement("div"); document.body.append(host); const onProviderModelChange = vi.fn(); const providers = props.providers ?? TEST_PROVIDERS; const modelOptionsByProvider = getCustomModelOptionsByProvider( DEFAULT_UNIFIED_SETTINGS, providers, props.provider, props.model, ); const screen = await render( <ProviderModelPicker provider={props.provider} model={props.model} lockedProvider={props.lockedProvider} providers={providers} modelOptionsByProvider={modelOptionsByProvider} triggerVariant={props.triggerVariant} onProviderModelChange={onProviderModelChange} />, { container: host }, ); return { onProviderModelChange, cleanup: async () => { await screen.unmount(); host.remove(); }, };} function getModelPickerListElement() { const modelPickerList = document.querySelector<HTMLElement>(".model-picker-list"); expect(modelPickerList).not.toBeNull(); return modelPickerList!;} function getModelPickerListText() { return getModelPickerListElement().textContent ?? "";} function getVisibleModelNames() { return Array.from(getModelPickerListElement().querySelectorAll<HTMLDivElement>("div.font-medium")) .map((element) => element.textContent?.replace(/New$/u, "").trim() ?? "") .filter((text) => text.length > 0);} function getSidebarProviderOrder() { return Array.from(document.querySelectorAll<HTMLElement>("[data-model-picker-provider]")).map( (element) => element.dataset.modelPickerProvider ?? "", );} describe("ProviderModelPicker", () => { beforeEach(async () => { // Reset test environment before each test await __resetLocalApiForTests(); }); afterEach(async () => { document.body.innerHTML = ""; await __resetLocalApiForTests(); }); it("shows provider sidebar in unlocked mode", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); await vi.waitFor(() => { const text = document.body.textContent ?? ""; expect(text).not.toContain("Codex"); expect(text).toContain("Claude"); expect(text).toContain("Claude Opus 4.6"); }); } finally { await mounted.cleanup(); } }); it("shows favorites first in the provider sidebar", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); await vi.waitFor(() => { expect(getSidebarProviderOrder().slice(0, 3)).toEqual([ "favorites", "codex", "claudeAgent", ]); }); } finally { await mounted.cleanup(); } }); it("filters models by selected provider in sidebar", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); // Start with Claude models visible await vi.waitFor(() => { const text = document.body.textContent ?? ""; expect(text).not.toContain("GPT-5 Codex"); expect(text).toContain("Claude Opus 4.6"); }); // Click on Codex provider in sidebar await vi.waitFor(() => { expect(document.querySelector('[data-model-picker-provider="codex"]')).not.toBeNull(); }); await page.getByRole("button", { name: "Codex", exact: true }).click(); // Now should only show Codex models await vi.waitFor(() => { const listText = getModelPickerListText(); expect(listText).toContain("GPT-5 Codex"); expect(listText).not.toContain("Claude Opus 4.6"); }); } finally { await mounted.cleanup(); } }); it("focuses the search input after selecting a sidebar provider", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); await vi.waitFor(() => { expect(document.querySelector('[data-model-picker-provider="codex"]')).not.toBeNull(); }); await page.getByRole("button", { name: "Codex", exact: true }).click(); await vi.waitFor(() => { const searchInput = document.querySelector<HTMLInputElement>( 'input[placeholder="Search models..."]', ); expect(searchInput).not.toBeNull(); expect(document.activeElement).toBe(searchInput); }); } finally { await mounted.cleanup(); } }); it("shows locked provider header and only its models in locked mode", async () => { localStorage.setItem( "t3code:client-settings:v1", JSON.stringify({ ...DEFAULT_CLIENT_SETTINGS, favorites: [ { provider: "codex", model: "gpt-5-codex" }, { provider: "claudeAgent", model: "claude-sonnet-4-6" }, ], }), ); const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: "claudeAgent", }); try { await page.getByRole("button").click(); await vi.waitFor(() => { const text = document.body.textContent ?? ""; // Should show locked provider label expect(text).toContain("Claude"); expect(getVisibleModelNames()).toEqual([ "Claude Sonnet 4.6", "Claude Opus 4.6", "Claude Haiku 4.5", ]); }); } finally { localStorage.removeItem("t3code:client-settings:v1"); await mounted.cleanup(); } }); it("falls back to the active provider's first model when props.model belongs to another provider (#1982)", async () => { const host = document.createElement("div"); document.body.append(host); const onProviderModelChange = vi.fn(); const modelOptionsByProvider = { claudeAgent: [ { slug: "claude-opus-4-6", name: "Claude Opus 4.6" }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, ], codex: [{ slug: "gpt-5-codex", name: "GPT-5 Codex" }], cursor: [], opencode: [], } as const; const screen = await render( <ProviderModelPicker provider="claudeAgent" model="gpt-5-codex" lockedProvider={null} providers={TEST_PROVIDERS} modelOptionsByProvider={modelOptionsByProvider} onProviderModelChange={onProviderModelChange} />, { container: host }, ); try { const trigger = document.querySelector<HTMLElement>( '[data-chat-provider-model-picker="true"]', ); expect(trigger).not.toBeNull(); const label = trigger?.textContent ?? ""; expect(label).not.toContain("gpt-5-codex"); expect(label).toContain("Claude Opus 4.6"); } finally { await screen.unmount(); host.remove(); } }); it("uses the trigger label for locked opencode rows", async () => { const providers: ReadonlyArray<ServerProvider> = [ buildOpenCodeProvider([ { slug: "github-copilot/claude-opus-4.5", name: "Claude Opus 4.5", subProvider: "GitHub Copilot", shortName: "Opus 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("reasoningEffort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]),Lines 1–500 of 1088. Load more
import { type ProviderKind, type ServerProvider } from "@t3tools/contracts"; import { EnvironmentId } from "@t3tools/contracts"; import { createModelCapabilities } from "@t3tools/shared/model"; import { page, userEvent } from "vitest/browser"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { render } from "vitest-browser-react"; import { ProviderModelPicker } from "./ProviderModelPicker"; import { getCustomModelOptionsByProvider } from "../../modelSelection"; import { DEFAULT_CLIENT_SETTINGS, DEFAULT_UNIFIED_SETTINGS } from "@t3tools/contracts/settings"; import { __resetLocalApiForTests } from "../../localApi"; // Mock the environments/runtime module to provide a mock primary environment connection vi.mock("../../environments/runtime", () => { const primaryConnection = { kind: "primary" as const, knownEnvironment: { id: "environment-local", label: "Local environment", source: "manual" as const, environmentId: EnvironmentId.make("environment-local"), target: { httpBaseUrl: "http://localhost:3000", wsBaseUrl: "ws://localhost:3000", }, }, environmentId: EnvironmentId.make("environment-local"), client: { server: { getConfig: vi.fn(), updateSettings: vi.fn(), }, }, ensureBootstrapped: async () => undefined, reconnect: async () => undefined, dispose: async () => undefined, }; return { getEnvironmentHttpBaseUrl: () => "http://localhost:3000", getSavedEnvironmentRecord: () => null, getSavedEnvironmentRuntimeState: () => null, hasSavedEnvironmentRegistryHydrated: () => true, listSavedEnvironmentRecords: () => [], resetSavedEnvironmentRegistryStoreForTests: vi.fn(), resetSavedEnvironmentRuntimeStoreForTests: vi.fn(), resolveEnvironmentHttpUrl: (_environmentId: unknown, path: string) => new URL(path, "http://localhost:3000").toString(), waitForSavedEnvironmentRegistryHydration: async () => undefined, addSavedEnvironment: vi.fn(), disconnectSavedEnvironment: vi.fn(), ensureEnvironmentConnectionBootstrapped: async () => undefined, getPrimaryEnvironmentConnection: () => primaryConnection, readEnvironmentConnection: () => primaryConnection, reconnectSavedEnvironment: vi.fn(), removeSavedEnvironment: vi.fn(), requireEnvironmentConnection: () => primaryConnection, resetEnvironmentServiceForTests: vi.fn(), startEnvironmentConnectionService: vi.fn(), subscribeEnvironmentConnections: () => () => {}, useSavedEnvironmentRegistryStore: ( selector: (state: { byId: Record<string, never> }) => unknown, ) => selector({ byId: {} }), useSavedEnvironmentRuntimeStore: ( selector: (state: { byId: Record<string, never> }) => unknown, ) => selector({ byId: {} }), }; }); function selectDescriptor( id: string, label: string, options: ReadonlyArray<{ id: string; label: string; isDefault?: boolean }>, ) { return { id, label, type: "select" as const, options: [...options], ...(options.find((option) => option.isDefault)?.id ? { currentValue: options.find((option) => option.isDefault)?.id } : {}), }; } function booleanDescriptor(id: string, label: string) { return { id, label, type: "boolean" as const, }; } const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [ { provider: "codex", displayName: "Codex", enabled: true, installed: true, version: "0.116.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), slashCommands: [], skills: [], models: [ { slug: "gpt-5-codex", name: "GPT-5 Codex", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("reasoningEffort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]), booleanDescriptor("fastMode", "Fast Mode"), ], }), }, { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("reasoningEffort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]), booleanDescriptor("fastMode", "Fast Mode"), ], }), }, ], }, { provider: "claudeAgent", displayName: "Claude", enabled: true, installed: true, version: "1.0.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), slashCommands: [], skills: [], models: [ { slug: "claude-opus-4-6", name: "Claude Opus 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, { id: "max", label: "max" }, ]), booleanDescriptor("thinking", "Thinking"), ], }), }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, { id: "max", label: "max" }, ]), booleanDescriptor("thinking", "Thinking"), ], }), }, { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]), booleanDescriptor("thinking", "Thinking"), ], }), }, ], }, ]; function buildCodexProvider(models: ServerProvider["models"]): ServerProvider { return { provider: "codex", displayName: "Codex", enabled: true, installed: true, version: "0.116.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), models, slashCommands: [], skills: [], }; } function buildOpenCodeProvider(models: ServerProvider["models"]): ServerProvider { return { provider: "opencode", enabled: true, installed: true, version: "1.0.0", status: "ready", auth: { status: "authenticated" }, checkedAt: new Date().toISOString(), models, slashCommands: [], skills: [], }; } async function mountPicker(props: { provider: ProviderKind; model: string; lockedProvider: ProviderKind | null; providers?: ReadonlyArray<ServerProvider>; triggerVariant?: "ghost" | "outline"; }) { const host = document.createElement("div"); document.body.append(host); const onProviderModelChange = vi.fn(); const providers = props.providers ?? TEST_PROVIDERS; const modelOptionsByProvider = getCustomModelOptionsByProvider( DEFAULT_UNIFIED_SETTINGS, providers, props.provider, props.model, ); const screen = await render( <ProviderModelPicker provider={props.provider} model={props.model} lockedProvider={props.lockedProvider} providers={providers} modelOptionsByProvider={modelOptionsByProvider} triggerVariant={props.triggerVariant} onProviderModelChange={onProviderModelChange} />, { container: host }, ); return { onProviderModelChange, cleanup: async () => { await screen.unmount(); host.remove(); }, }; } function getModelPickerListElement() { const modelPickerList = document.querySelector<HTMLElement>(".model-picker-list"); expect(modelPickerList).not.toBeNull(); return modelPickerList!; } function getModelPickerListText() { return getModelPickerListElement().textContent ?? ""; } function getVisibleModelNames() { return Array.from(getModelPickerListElement().querySelectorAll<HTMLDivElement>("div.font-medium")) .map((element) => element.textContent?.replace(/New$/u, "").trim() ?? "") .filter((text) => text.length > 0); } function getSidebarProviderOrder() { return Array.from(document.querySelectorAll<HTMLElement>("[data-model-picker-provider]")).map( (element) => element.dataset.modelPickerProvider ?? "", ); } describe("ProviderModelPicker", () => { beforeEach(async () => { // Reset test environment before each test await __resetLocalApiForTests(); }); afterEach(async () => { document.body.innerHTML = ""; await __resetLocalApiForTests(); }); it("shows provider sidebar in unlocked mode", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); await vi.waitFor(() => { const text = document.body.textContent ?? ""; expect(text).not.toContain("Codex"); expect(text).toContain("Claude"); expect(text).toContain("Claude Opus 4.6"); }); } finally { await mounted.cleanup(); } }); it("shows favorites first in the provider sidebar", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); await vi.waitFor(() => { expect(getSidebarProviderOrder().slice(0, 3)).toEqual([ "favorites", "codex", "claudeAgent", ]); }); } finally { await mounted.cleanup(); } }); it("filters models by selected provider in sidebar", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); // Start with Claude models visible await vi.waitFor(() => { const text = document.body.textContent ?? ""; expect(text).not.toContain("GPT-5 Codex"); expect(text).toContain("Claude Opus 4.6"); }); // Click on Codex provider in sidebar await vi.waitFor(() => { expect(document.querySelector('[data-model-picker-provider="codex"]')).not.toBeNull(); }); await page.getByRole("button", { name: "Codex", exact: true }).click(); // Now should only show Codex models await vi.waitFor(() => { const listText = getModelPickerListText(); expect(listText).toContain("GPT-5 Codex"); expect(listText).not.toContain("Claude Opus 4.6"); }); } finally { await mounted.cleanup(); } }); it("focuses the search input after selecting a sidebar provider", async () => { const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: null, }); try { await page.getByRole("button").click(); await vi.waitFor(() => { expect(document.querySelector('[data-model-picker-provider="codex"]')).not.toBeNull(); }); await page.getByRole("button", { name: "Codex", exact: true }).click(); await vi.waitFor(() => { const searchInput = document.querySelector<HTMLInputElement>( 'input[placeholder="Search models..."]', ); expect(searchInput).not.toBeNull(); expect(document.activeElement).toBe(searchInput); }); } finally { await mounted.cleanup(); } }); it("shows locked provider header and only its models in locked mode", async () => { localStorage.setItem( "t3code:client-settings:v1", JSON.stringify({ ...DEFAULT_CLIENT_SETTINGS, favorites: [ { provider: "codex", model: "gpt-5-codex" }, { provider: "claudeAgent", model: "claude-sonnet-4-6" }, ], }), ); const mounted = await mountPicker({ provider: "claudeAgent", model: "claude-opus-4-6", lockedProvider: "claudeAgent", }); try { await page.getByRole("button").click(); await vi.waitFor(() => { const text = document.body.textContent ?? ""; // Should show locked provider label expect(text).toContain("Claude"); expect(getVisibleModelNames()).toEqual([ "Claude Sonnet 4.6", "Claude Opus 4.6", "Claude Haiku 4.5", ]); }); } finally { localStorage.removeItem("t3code:client-settings:v1"); await mounted.cleanup(); } }); it("falls back to the active provider's first model when props.model belongs to another provider (#1982)", async () => { const host = document.createElement("div"); document.body.append(host); const onProviderModelChange = vi.fn(); const modelOptionsByProvider = { claudeAgent: [ { slug: "claude-opus-4-6", name: "Claude Opus 4.6" }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, ], codex: [{ slug: "gpt-5-codex", name: "GPT-5 Codex" }], cursor: [], opencode: [], } as const; const screen = await render( <ProviderModelPicker provider="claudeAgent" model="gpt-5-codex" lockedProvider={null} providers={TEST_PROVIDERS} modelOptionsByProvider={modelOptionsByProvider} onProviderModelChange={onProviderModelChange} />, { container: host }, ); try { const trigger = document.querySelector<HTMLElement>( '[data-chat-provider-model-picker="true"]', ); expect(trigger).not.toBeNull(); const label = trigger?.textContent ?? ""; expect(label).not.toContain("gpt-5-codex"); expect(label).toContain("Claude Opus 4.6"); } finally { await screen.unmount(); host.remove(); } }); it("uses the trigger label for locked opencode rows", async () => { const providers: ReadonlyArray<ServerProvider> = [ buildOpenCodeProvider([ { slug: "github-copilot/claude-opus-4.5", name: "Claude Opus 4.5", subProvider: "GitHub Copilot", shortName: "Opus 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ selectDescriptor("reasoningEffort", "Reasoning", [ { id: "low", label: "low" }, { id: "medium", label: "medium", isDefault: true }, { id: "high", label: "high" }, ]),