Skip to content
Source
Sign inSign up

providerStatusCache.test.ts

211 lines5.6 KB

1import * as NodeServices from "@effect/platform-node/NodeServices";
2import {
3 defaultInstanceIdForDriver,
4 ProviderDriverKind,
5 ProviderInstanceId,
6 type ServerProvider,
7} from "@t3tools/contracts";
8import { createModelCapabilities } from "@t3tools/shared/model";
9import { assert, it } from "@effect/vitest";
10​
11import { hydrateCachedProvider, isCachedProviderCorrelated } from "./providerStatusCache.ts";
12​
13const emptyCapabilities = createModelCapabilities({ optionDescriptors: [] });
14const CODEX_DRIVER = ProviderDriverKind.make("codex");
15​
16const makeProvider = (
17 provider: ProviderDriverKind,
18 overrides?: Partial<ServerProvider>,
19): ServerProvider => ({
20 instanceId: defaultInstanceIdForDriver(provider),
21 driver: provider,
22 enabled: true,
23 installed: true,
24 version: "1.0.0",
25 status: "ready",
26 auth: { status: "authenticated" },
27 checkedAt: "2026-04-11T00:00:00.000Z",
28 models: [],
29 slashCommands: [],
30 skills: [],
31 ...overrides,
32});
33​
34it.layer(NodeServices.layer)("providerStatusCache", (it) => {
35 it("hydrates cached provider status while preserving current settings-derived models", () => {
36 const cachedCodex = makeProvider(CODEX_DRIVER, {
37 checkedAt: "2026-04-10T12:00:00.000Z",
38 models: [
39 {
40 slug: "gpt-5-mini",
41 name: "GPT-5 Mini",
42 isCustom: false,
43 capabilities: emptyCapabilities,
44 },
45 ],
46 message: "Cached message",
47 skills: [
48 {
49 name: "github:gh-fix-ci",
50 path: "/tmp/skills/gh-fix-ci/SKILL.md",
51 enabled: true,
52 displayName: "CI Debug",
53 },
54 ],
55 });
56 const fallbackCodex = makeProvider(CODEX_DRIVER, {
57 models: [
58 {
59 slug: "gpt-5.4",
60 name: "GPT-5.4",
61 isCustom: false,
62 capabilities: emptyCapabilities,
63 },
64 ],
65 message: "Pending refresh",
66 });
67​
68 assert.deepStrictEqual(
69 hydrateCachedProvider({
70 cachedProvider: cachedCodex,
71 fallbackProvider: fallbackCodex,
72 }),
73 {
74 ...fallbackCodex,
75 models: [
76 ...fallbackCodex.models,
77 {
78 slug: "gpt-5-mini",
79 name: "GPT-5 Mini",
80 isCustom: false,
81 capabilities: emptyCapabilities,
82 },
83 ],
84 installed: cachedCodex.installed,
85 version: cachedCodex.version,
86 status: cachedCodex.status,
87 auth: cachedCodex.auth,
88 checkedAt: cachedCodex.checkedAt,
89 slashCommands: cachedCodex.slashCommands,
90 skills: cachedCodex.skills,
91 message: cachedCodex.message,
92 },
93 );
94 });
95​
96 it("does not resurrect cached custom models that settings no longer declare", () => {
97 const builtIn = {
98 slug: "gpt-5.4",
99 name: "GPT-5.4",
100 isCustom: false,
101 capabilities: emptyCapabilities,
102 } as const;
103 const cachedCodex = makeProvider(CODEX_DRIVER, {
104 models: [
105 builtIn,
106 {
107 slug: "removed-custom",
108 name: "removed-custom",
109 isCustom: true,
110 capabilities: emptyCapabilities,
111 },
112 ],
113 });
114 const fallbackCodex = makeProvider(CODEX_DRIVER, { models: [builtIn] });
115​
116 assert.deepStrictEqual(
117 hydrateCachedProvider({
118 cachedProvider: cachedCodex,
119 fallbackProvider: fallbackCodex,
120 }).models,
121 [builtIn],
122 );
123 });
124​
125 it("ignores stale cached enabled state when the provider is now disabled", () => {
126 const cachedCodex = makeProvider(CODEX_DRIVER, {
127 checkedAt: "2026-04-10T12:00:00.000Z",
128 message: "Cached ready status",
129 });
130 const disabledFallback = makeProvider(CODEX_DRIVER, {
131 enabled: false,
132 installed: false,
133 version: null,
134 status: "disabled",
135 auth: { status: "unknown" },
136 message: "Codex is disabled in T3 Code settings.",
137 });
138​
139 assert.deepStrictEqual(
140 hydrateCachedProvider({
141 cachedProvider: cachedCodex,
142 fallbackProvider: disabledFallback,
143 }),
144 disabledFallback,
145 );
146 });
147​
148 it("rejects cached snapshots that are not correlated to the fallback instance", () => {
149 const fallbackCodex = makeProvider(CODEX_DRIVER, {
150 models: [
151 {
152 slug: "gpt-5.4",
153 name: "GPT-5.4",
154 isCustom: false,
155 capabilities: emptyCapabilities,
156 },
157 ],
158 });
159 const legacyCachedCodex = {
160 provider: ProviderDriverKind.make("codex"),
161 enabled: true,
162 installed: true,
163 version: "1.0.0",
164 status: "ready",
165 auth: { status: "authenticated" },
166 checkedAt: "2026-04-10T12:00:00.000Z",
167 models: [
168 {
169 slug: "cached-legacy-model",
170 name: "Cached Legacy Model",
171 isCustom: false,
172 capabilities: emptyCapabilities,
173 },
174 ],
175 slashCommands: [],
176 skills: [],
177 } as unknown as ServerProvider;
178 const mismatchedCachedCodex = makeProvider(CODEX_DRIVER, {
179 instanceId: ProviderInstanceId.make("codex_personal"),
180 });
181​
182 assert.strictEqual(
183 isCachedProviderCorrelated({
184 cachedProvider: legacyCachedCodex,
185 fallbackProvider: fallbackCodex,
186 }),
187 false,
188 );
189 assert.deepStrictEqual(
190 hydrateCachedProvider({
191 cachedProvider: legacyCachedCodex,
192 fallbackProvider: fallbackCodex,
193 }),
194 fallbackCodex,
195 );
196 assert.strictEqual(
197 isCachedProviderCorrelated({
198 cachedProvider: mismatchedCachedCodex,
199 fallbackProvider: fallbackCodex,
200 }),
201 false,
202 );
203 assert.deepStrictEqual(
204 hydrateCachedProvider({
205 cachedProvider: mismatchedCachedCodex,
206 fallbackProvider: fallbackCodex,
207 }),
208 fallbackCodex,
209 );
210 });
211});