Open History to see the last commit
1import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";
2import { DEFAULT_UNIFIED_SETTINGS, type UnifiedSettings } from "@t3tools/contracts/settings";
3import { createModelSelection } from "@t3tools/shared/model";
4import { describe, expect, it } from "vite-plus/test";
5
6import { providerInstanceEntriesFor } from "../../providerInstances";
7import { resolveDefaultModelSettingsPresentation } from "./ProjectDefaultsSettings.logic";
8
9const claudeId = ProviderInstanceId.make("claudeAgent");
10const high = [{ id: "effort", value: "high" }];
11const savedClaude = createModelSelection(claudeId, "claude-opus-4-8", high);
12function provider(input: {
13 instanceId: string;
14 driver: string;
15 enabled?: boolean;
16 availability?: ServerProvider["availability"];
17 models: ReadonlyArray<string>;
18}): ServerProvider {
19 return {
20 instanceId: ProviderInstanceId.make(input.instanceId),
21 driver: ProviderDriverKind.make(input.driver),
22 enabled: input.enabled ?? true,
23 installed: true,
24 version: null,
25 status: "ready",
26 ...(input.availability ? { availability: input.availability } : {}),
27 auth: { status: "authenticated" },
28 checkedAt: "2026-01-01T00:00:00.000Z",
29 models: input.models.map((slug, index) => ({
30 slug,
31 name: slug,
32 isCustom: false,
33 ...(index === 0 ? { isDefault: true } : {}),
34 capabilities: {},
35 })),
36 slashCommands: [],
37 skills: [],
38 };
39}
40
41const claudeAndCodex = [
42 provider({ instanceId: "codex", driver: "codex", models: ["gpt-5.6"] }),
43 provider({ instanceId: "claudeAgent", driver: "claudeAgent", models: ["claude-opus-4-8"] }),
44];
45
46function present(
47 providers: ReadonlyArray<ServerProvider>,
48 overrides: Partial<UnifiedSettings> = {},
49) {
50 const settings = {
51 ...DEFAULT_UNIFIED_SETTINGS,
52 defaultModelSelection: savedClaude,
53 ...overrides,
54 };
55 return resolveDefaultModelSettingsPresentation({
56 entries: providerInstanceEntriesFor(providers, settings, null),
57 providers,
58 settings,
59 projectId: null,
60 });
61}
62
63const claudeOff: Partial<UnifiedSettings> = {
64 providerInstances: {
65 [claudeId]: { driver: ProviderDriverKind.make("claudeAgent"), enabled: false },
66 },
67};
68
69describe("resolveDefaultModelSettingsPresentation", () => {
70 it("keeps the saved model and explains why when its provider cannot run", () => {
71 const withoutClaude = claudeAndCodex.filter((entry) => entry.instanceId !== claudeId);
72 const claudeUnavailable = claudeAndCodex.map((entry) =>
73 entry.instanceId === claudeId ? { ...entry, availability: "unavailable" as const } : entry,
74 );
75 // Settings turn Claude off before the server snapshot reflects it.
76 expect(present(claudeAndCodex, claudeOff)).toEqual({
77 selection: savedClaude,
78 providerNote: "Claude is turned off.",
79 });
80 expect(present(claudeUnavailable)).toEqual({
81 selection: savedClaude,
82 providerNote: "Claude is unavailable.",
83 });
84 expect(present(withoutClaude)).toEqual({
85 selection: savedClaude,
86 providerNote: "This provider is not available on this environment.",
87 });
88 });
89
90 it("leaves effort editable when the saved provider can run", () => {
91 expect(present(claudeAndCodex)).toEqual({ selection: savedClaude, providerNote: null });
92 });
93
94 it("still follows a hidden model on the same provider", () => {
95 const row = present(
96 [
97 provider({
98 instanceId: "claudeAgent",
99 driver: "claudeAgent",
100 models: ["claude-sonnet-5", "claude-opus-4-8"],
101 }),
102 ],
103 {
104 providerModelPreferences: {
105 [claudeId]: { hiddenModels: ["claude-opus-4-8"], modelOrder: [] },
106 },
107 },
108 );
109 expect(row.providerNote).toBeNull();
110 expect(row.selection).toMatchObject({ instanceId: claudeId, model: "claude-sonnet-5" });
111 });
112});