pi-windsurf-beta 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/metadata.ts ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * `exa.codeium_common_pb.Metadata` proto builder.
3
+ */
4
+ import { encodeMessage, encodeString, encodeTimestampBody, encodeVarintField } from "./wire";
5
+
6
+ const WINDSURF_VERSION_STRING = "2.0.0";
7
+
8
+ export interface MetadataInput {
9
+ apiKey: string;
10
+ userJwt?: string;
11
+ sessionId: string;
12
+ requestId: bigint;
13
+ triggerId: string;
14
+ windsurfVersion?: string;
15
+ osName?: string;
16
+ }
17
+
18
+ function osString(): string {
19
+ switch (process.platform) {
20
+ case "darwin": return "darwin";
21
+ case "linux": return "linux";
22
+ case "win32": return "windows";
23
+ default: return String(process.platform);
24
+ }
25
+ }
26
+
27
+ export function buildMetadata(input: MetadataInput): Buffer {
28
+ const version = input.windsurfVersion ?? WINDSURF_VERSION_STRING;
29
+ const os = input.osName ?? osString();
30
+ const parts: Buffer[] = [
31
+ encodeString(1, "windsurf"),
32
+ encodeString(2, version),
33
+ encodeString(3, input.apiKey),
34
+ encodeString(4, "en"),
35
+ encodeString(5, os),
36
+ encodeString(7, version),
37
+ encodeVarintField(9, input.requestId),
38
+ encodeString(10, input.sessionId),
39
+ encodeString(12, "windsurf"),
40
+ encodeMessage(16, encodeTimestampBody()),
41
+ encodeString(25, input.triggerId),
42
+ encodeString(26, "Unset"),
43
+ encodeString(28, "windsurf"),
44
+ ];
45
+ if (input.userJwt) parts.push(encodeString(21, input.userJwt));
46
+ return Buffer.concat(parts);
47
+ }
package/models.ts ADDED
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Windsurf model catalog — variant resolution + model_uid mapping.
3
+ */
4
+
5
+ export const ModelEnum = {
6
+ MODEL_UNSPECIFIED: 0,
7
+ CLAUDE_3_OPUS_20240229: 63,
8
+ CLAUDE_3_SONNET_20240229: 64,
9
+ CLAUDE_3_HAIKU_20240307: 172,
10
+ CLAUDE_3_5_SONNET_20241022: 166,
11
+ CLAUDE_3_5_HAIKU_20241022: 171,
12
+ CLAUDE_3_7_SONNET_20250219: 226,
13
+ CLAUDE_3_7_SONNET_20250219_THINKING: 227,
14
+ CLAUDE_4_OPUS: 290,
15
+ CLAUDE_4_OPUS_THINKING: 291,
16
+ CLAUDE_4_SONNET: 281,
17
+ CLAUDE_4_SONNET_THINKING: 282,
18
+ CLAUDE_4_1_OPUS: 328,
19
+ CLAUDE_4_1_OPUS_THINKING: 329,
20
+ CLAUDE_4_5_SONNET: 353,
21
+ CLAUDE_4_5_SONNET_THINKING: 354,
22
+ CLAUDE_4_5_OPUS: 391,
23
+ CLAUDE_4_5_OPUS_THINKING: 392,
24
+ CLAUDE_CODE: 344,
25
+ GPT_4: 30,
26
+ GPT_4O_2024_08_06: 109,
27
+ GPT_4O_MINI_2024_07_18: 113,
28
+ GPT_4_1_2025_04_14: 259,
29
+ GPT_4_1_MINI_2025_04_14: 260,
30
+ GPT_4_1_NANO_2025_04_14: 261,
31
+ GPT_5: 340,
32
+ GPT_5_NANO: 337,
33
+ GPT_5_LOW: 339,
34
+ GPT_5_HIGH: 341,
35
+ GPT_5_CODEX: 346,
36
+ GPT_5_1_CODEX_MINI_LOW: 385,
37
+ GPT_5_1_CODEX_MINI_MEDIUM: 386,
38
+ GPT_5_1_CODEX_MINI_HIGH: 387,
39
+ GPT_5_1_CODEX_LOW: 388,
40
+ GPT_5_1_CODEX_MEDIUM: 389,
41
+ GPT_5_1_CODEX_HIGH: 390,
42
+ GPT_5_1_CODEX_MAX_LOW: 395,
43
+ GPT_5_1_CODEX_MAX_MEDIUM: 396,
44
+ GPT_5_1_CODEX_MAX_HIGH: 397,
45
+ GPT_5_2_NONE: 399, GPT_5_2_LOW: 400, GPT_5_2_MEDIUM: 401, GPT_5_2_HIGH: 402, GPT_5_2_XHIGH: 403,
46
+ GPT_5_2_NONE_PRIORITY: 404, GPT_5_2_LOW_PRIORITY: 405, GPT_5_2_MEDIUM_PRIORITY: 406, GPT_5_2_HIGH_PRIORITY: 407, GPT_5_2_XHIGH_PRIORITY: 408,
47
+ O3: 218, O3_MINI: 207, O3_LOW: 262, O3_HIGH: 263, O3_PRO: 294, O3_PRO_LOW: 295, O3_PRO_HIGH: 296,
48
+ O4_MINI: 264, O4_MINI_LOW: 265, O4_MINI_HIGH: 266,
49
+ GEMINI_2_0_FLASH: 184, GEMINI_2_5_PRO: 246, GEMINI_2_5_FLASH: 312,
50
+ GEMINI_2_5_FLASH_THINKING: 313, GEMINI_2_5_FLASH_LITE: 343,
51
+ GEMINI_3_0_PRO_MINIMAL: 411, GEMINI_3_0_PRO_LOW: 378, GEMINI_3_0_PRO_MEDIUM: 412, GEMINI_3_0_PRO_HIGH: 379,
52
+ GEMINI_3_0_FLASH_MINIMAL: 413, GEMINI_3_0_FLASH_LOW: 414, GEMINI_3_0_FLASH_MEDIUM: 415, GEMINI_3_0_FLASH_HIGH: 416,
53
+ DEEPSEEK_V3: 205, DEEPSEEK_V3_2: 409, DEEPSEEK_R1: 206, DEEPSEEK_R1_FAST: 216, DEEPSEEK_R1_SLOW: 215,
54
+ LLAMA_3_1_8B_INSTRUCT: 106, LLAMA_3_1_70B_INSTRUCT: 107, LLAMA_3_1_405B_INSTRUCT: 105,
55
+ LLAMA_3_3_70B_INSTRUCT: 208, LLAMA_3_3_70B_INSTRUCT_R1: 209,
56
+ QWEN_2_5_7B_INSTRUCT: 178, QWEN_2_5_32B_INSTRUCT: 179, QWEN_2_5_72B_INSTRUCT: 180,
57
+ QWEN_2_5_32B_INSTRUCT_R1: 224, QWEN_3_235B_INSTRUCT: 324,
58
+ QWEN_3_CODER_480B_INSTRUCT: 325, QWEN_3_CODER_480B_INSTRUCT_FAST: 327,
59
+ GROK_2: 212, GROK_3: 217, GROK_3_MINI_REASONING: 234, GROK_CODE_FAST: 345,
60
+ MISTRAL_7B: 77, KIMI_K2: 323, KIMI_K2_THINKING: 394,
61
+ GLM_4_5: 342, GLM_4_5_FAST: 352, GLM_4_6: 356, GLM_4_6_FAST: 357, GLM_4_7: 417, GLM_4_7_FAST: 418,
62
+ MINIMAX_M2: 368, MINIMAX_M2_1: 419,
63
+ SWE_1_5: 359, SWE_1_5_THINKING: 369, SWE_1_5_SLOW: 377,
64
+ SWE_1_6: 420, SWE_1_6_FAST: 421,
65
+ GPT_OSS_120B: 326,
66
+ GPT_5_2_CODEX_LOW: 422, GPT_5_2_CODEX_MEDIUM: 423, GPT_5_2_CODEX_HIGH: 424, GPT_5_2_CODEX_XHIGH: 425,
67
+ GPT_5_2_CODEX_LOW_PRIORITY: 426, GPT_5_2_CODEX_MEDIUM_PRIORITY: 427, GPT_5_2_CODEX_HIGH_PRIORITY: 428, GPT_5_2_CODEX_XHIGH_PRIORITY: 429,
68
+ PRIVATE_1: 219, PRIVATE_2: 220, PRIVATE_3: 221, PRIVATE_4: 222, PRIVATE_5: 223,
69
+ PRIVATE_6: 314, PRIVATE_7: 315, PRIVATE_8: 316, PRIVATE_9: 317, PRIVATE_10: 318,
70
+ PRIVATE_11: 347, PRIVATE_12: 348, PRIVATE_13: 349, PRIVATE_14: 350, PRIVATE_15: 351,
71
+ PRIVATE_16: 363, PRIVATE_17: 364, PRIVATE_18: 365, PRIVATE_19: 366, PRIVATE_20: 367,
72
+ PRIVATE_21: 372, PRIVATE_22: 373, PRIVATE_23: 374, PRIVATE_24: 375, PRIVATE_25: 376,
73
+ PRIVATE_26: 380, PRIVATE_27: 381, PRIVATE_28: 382, PRIVATE_29: 383, PRIVATE_30: 384,
74
+ } as const;
75
+
76
+ export type ModelEnumValue = (typeof ModelEnum)[keyof typeof ModelEnum];
77
+
78
+ // ----------------------------------------------------------------------------
79
+ // Enum → cloud uid mapping
80
+ // ----------------------------------------------------------------------------
81
+
82
+ const ENUM_PREFIX_OVERRIDES: Array<{ enumPrefix: string; uidPrefix: string }> = [
83
+ { enumPrefix: "GPT_4_1_2025_04_14", uidPrefix: "MODEL_CHAT_GPT_4_1_2025_04_14" },
84
+ { enumPrefix: "GPT_4O_2024_08_06", uidPrefix: "MODEL_CHAT_GPT_4O_2024_08_06" },
85
+ { enumPrefix: "GPT_5_CODEX", uidPrefix: "MODEL_CHAT_GPT_5_CODEX" },
86
+ { enumPrefix: "O3_HIGH", uidPrefix: "MODEL_CHAT_O3_HIGH" },
87
+ { enumPrefix: "O3", uidPrefix: "MODEL_CHAT_O3" },
88
+ { enumPrefix: "GEMINI_3_0_FLASH", uidPrefix: "MODEL_GOOGLE_GEMINI_3_0_FLASH" },
89
+ { enumPrefix: "GEMINI_2_5_PRO", uidPrefix: "MODEL_GOOGLE_GEMINI_2_5_PRO" },
90
+ { enumPrefix: "GROK_3_MINI_REASONING", uidPrefix: "MODEL_XAI_GROK_3_MINI_REASONING" },
91
+ { enumPrefix: "GROK_3", uidPrefix: "MODEL_XAI_GROK_3" },
92
+ ];
93
+
94
+ function enumKeyToCloudUid(key: string): string {
95
+ const sorted = [...ENUM_PREFIX_OVERRIDES].sort((a, b) => b.enumPrefix.length - a.enumPrefix.length);
96
+ for (const { enumPrefix, uidPrefix } of sorted) {
97
+ if (key === enumPrefix) return uidPrefix;
98
+ if (key.startsWith(enumPrefix + "_")) return uidPrefix + key.slice(enumPrefix.length);
99
+ }
100
+ return `MODEL_${key}`;
101
+ }
102
+
103
+ const ENUM_VALUE_TO_NAME: Map<number, string> = (() => {
104
+ const map = new Map<number, string>();
105
+ for (const [key, value] of Object.entries(ModelEnum)) {
106
+ if (typeof value === "number") map.set(value, enumKeyToCloudUid(key));
107
+ }
108
+ return map;
109
+ })();
110
+
111
+ // ----------------------------------------------------------------------------
112
+ // Variant catalog
113
+ // ----------------------------------------------------------------------------
114
+
115
+ type VariantMeta = { description?: string; modelUid?: string; enumValue?: ModelEnumValue; };
116
+ type VariantName = string;
117
+
118
+ interface ModelCatalogEntry {
119
+ id: string;
120
+ defaultEnum?: ModelEnumValue;
121
+ defaultUid?: string;
122
+ variants?: Record<VariantName, VariantMeta>;
123
+ aliases?: string[];
124
+ }
125
+
126
+ const VARIANT_CATALOG: Record<string, ModelCatalogEntry> = {
127
+ "claude-opus-4.8": { id: "claude-opus-4.8", defaultUid: "claude-opus-4-8-medium",
128
+ variants: {
129
+ "low": { modelUid: "claude-opus-4-8-low" }, "medium": { modelUid: "claude-opus-4-8-medium" },
130
+ "high": { modelUid: "claude-opus-4-8-high" }, "xhigh": { modelUid: "claude-opus-4-8-xhigh" },
131
+ "max": { modelUid: "claude-opus-4-8-max" },
132
+ "low-fast": { modelUid: "claude-opus-4-8-low-fast" }, "medium-fast": { modelUid: "claude-opus-4-8-medium-fast" },
133
+ "high-fast": { modelUid: "claude-opus-4-8-high-fast" }, "xhigh-fast": { modelUid: "claude-opus-4-8-xhigh-fast" },
134
+ "max-fast": { modelUid: "claude-opus-4-8-max-fast" },
135
+ }, aliases: ["claude-opus-4-8"],
136
+ },
137
+ "claude-opus-4.7": { id: "claude-opus-4.7", defaultUid: "claude-opus-4-7-medium",
138
+ variants: {
139
+ "low": { modelUid: "claude-opus-4-7-low" }, "medium": { modelUid: "claude-opus-4-7-medium" },
140
+ "high": { modelUid: "claude-opus-4-7-high" }, "xhigh": { modelUid: "claude-opus-4-7-xhigh" },
141
+ "max": { modelUid: "claude-opus-4-7-max" },
142
+ "low-fast": { modelUid: "claude-opus-4-7-low-fast" }, "medium-fast": { modelUid: "claude-opus-4-7-medium-fast" },
143
+ "high-fast": { modelUid: "claude-opus-4-7-high-fast" }, "xhigh-fast": { modelUid: "claude-opus-4-7-xhigh-fast" },
144
+ "max-fast": { modelUid: "claude-opus-4-7-max-fast" },
145
+ }, aliases: ["claude-opus-4-7"],
146
+ },
147
+ "claude-opus-4.6": { id: "claude-opus-4.6", defaultUid: "claude-opus-4-6-thinking",
148
+ variants: {
149
+ "thinking": { modelUid: "claude-opus-4-6-thinking" }, "base": { modelUid: "claude-opus-4-6" },
150
+ "1m": { modelUid: "claude-opus-4-6-1m" }, "thinking-1m": { modelUid: "claude-opus-4-6-thinking-1m" },
151
+ "fast": { modelUid: "claude-opus-4-6-fast" }, "thinking-fast": { modelUid: "claude-opus-4-6-thinking-fast" },
152
+ }, aliases: ["claude-opus-4-6"],
153
+ },
154
+ "gemini-3.5-flash": { id: "gemini-3.5-flash", defaultUid: "gemini-3-5-flash-medium",
155
+ variants: {
156
+ "minimal": { modelUid: "gemini-3-5-flash-minimal" }, "low": { modelUid: "gemini-3-5-flash-low" },
157
+ "medium": { modelUid: "gemini-3-5-flash-medium" }, "high": { modelUid: "gemini-3-5-flash-high" },
158
+ }, aliases: ["gemini-3-5-flash"],
159
+ },
160
+ "gpt-5.5": { id: "gpt-5.5", defaultUid: "gpt-5-5-low",
161
+ variants: {
162
+ "none": { modelUid: "gpt-5-5-none" }, "low": { modelUid: "gpt-5-5-low" },
163
+ "medium": { modelUid: "gpt-5-5-medium" }, "high": { modelUid: "gpt-5-5-high" }, "xhigh": { modelUid: "gpt-5-5-xhigh" },
164
+ "none-priority": { modelUid: "gpt-5-5-none-priority" }, "low-priority": { modelUid: "gpt-5-5-low-priority" },
165
+ "medium-priority": { modelUid: "gpt-5-5-medium-priority" }, "high-priority": { modelUid: "gpt-5-5-high-priority" },
166
+ "xhigh-priority": { modelUid: "gpt-5-5-xhigh-priority" },
167
+ }, aliases: ["gpt-5-5"],
168
+ },
169
+ "gpt-5.4": { id: "gpt-5.4", defaultUid: "gpt-5-4-none",
170
+ variants: {
171
+ "none": { modelUid: "gpt-5-4-none" }, "low": { modelUid: "gpt-5-4-low" },
172
+ "medium": { modelUid: "gpt-5-4-medium" }, "high": { modelUid: "gpt-5-4-high" }, "xhigh": { modelUid: "gpt-5-4-xhigh" },
173
+ "none-priority": { modelUid: "gpt-5-4-none-priority" }, "low-priority": { modelUid: "gpt-5-4-low-priority" },
174
+ "medium-priority": { modelUid: "gpt-5-4-medium-priority" }, "high-priority": { modelUid: "gpt-5-4-high-priority" },
175
+ "xhigh-priority": { modelUid: "gpt-5-4-xhigh-priority" },
176
+ }, aliases: ["gpt-5-4"],
177
+ },
178
+ "gpt-5.3-codex": { id: "gpt-5.3-codex", defaultUid: "gpt-5-3-codex-medium",
179
+ variants: {
180
+ "low": { modelUid: "gpt-5-3-codex-low" }, "medium": { modelUid: "gpt-5-3-codex-medium" },
181
+ "high": { modelUid: "gpt-5-3-codex-high" }, "xhigh": { modelUid: "gpt-5-3-codex-xhigh" },
182
+ "low-priority": { modelUid: "gpt-5-3-codex-low-priority" }, "medium-priority": { modelUid: "gpt-5-3-codex-medium-priority" },
183
+ "high-priority": { modelUid: "gpt-5-3-codex-high-priority" }, "xhigh-priority": { modelUid: "gpt-5-3-codex-xhigh-priority" },
184
+ }, aliases: ["gpt-5-3-codex"],
185
+ },
186
+ "gpt-5.2": { id: "gpt-5.2", defaultUid: "MODEL_GPT_5_2_LOW",
187
+ variants: {
188
+ "low": { modelUid: "MODEL_GPT_5_2_LOW" }, "medium": { modelUid: "MODEL_GPT_5_2_MEDIUM" },
189
+ "high": { modelUid: "MODEL_GPT_5_2_HIGH" }, "xhigh": { modelUid: "MODEL_GPT_5_2_XHIGH" },
190
+ "none": { modelUid: "MODEL_GPT_5_2_NONE" },
191
+ "low-priority": { modelUid: "MODEL_GPT_5_2_LOW_PRIORITY" }, "medium-priority": { modelUid: "MODEL_GPT_5_2_MEDIUM_PRIORITY" },
192
+ "high-priority": { modelUid: "MODEL_GPT_5_2_HIGH_PRIORITY" }, "xhigh-priority": { modelUid: "MODEL_GPT_5_2_XHIGH_PRIORITY" },
193
+ "none-priority": { modelUid: "MODEL_GPT_5_2_NONE_PRIORITY" },
194
+ }, aliases: ["gpt-5-2"],
195
+ },
196
+ "gpt-5.2-codex": { id: "gpt-5.2-codex", defaultUid: "MODEL_GPT_5_2_CODEX_LOW",
197
+ variants: {
198
+ "low": { modelUid: "MODEL_GPT_5_2_CODEX_LOW" }, "medium": { modelUid: "MODEL_GPT_5_2_CODEX_MEDIUM" },
199
+ "high": { modelUid: "MODEL_GPT_5_2_CODEX_HIGH" }, "xhigh": { modelUid: "MODEL_GPT_5_2_CODEX_XHIGH" },
200
+ "low-priority": { modelUid: "MODEL_GPT_5_2_CODEX_LOW_PRIORITY" }, "medium-priority": { modelUid: "MODEL_GPT_5_2_CODEX_MEDIUM_PRIORITY" },
201
+ "high-priority": { modelUid: "MODEL_GPT_5_2_CODEX_HIGH_PRIORITY" }, "xhigh-priority": { modelUid: "MODEL_GPT_5_2_CODEX_XHIGH_PRIORITY" },
202
+ }, aliases: ["gpt-5-2-codex"],
203
+ },
204
+ "kimi-k2.6": { id: "kimi-k2.6", defaultUid: "kimi-k2-6", aliases: ["kimi-k2-6"] },
205
+ "kimi-k2.7": { id: "kimi-k2.7", defaultUid: "kimi-k2-7", aliases: ["kimi-k2-7"] },
206
+ "glm-5.2": { id: "glm-5.2", defaultUid: "glm-5-2", aliases: ["glm-5-2"] },
207
+ "swe-1.6": { id: "swe-1.6", defaultUid: "swe-1-6",
208
+ variants: {
209
+ "base": { modelUid: "swe-1-6" }, "fast": { modelUid: "swe-1-6-fast" },
210
+ }, aliases: ["swe-1-6"],
211
+ },
212
+ "deepseek-v4": { id: "deepseek-v4", defaultUid: "deepseek-v4" },
213
+ "gemini-3.1-pro": { id: "gemini-3.1-pro", defaultUid: "gemini-3-1-pro-low",
214
+ variants: { "low": { modelUid: "gemini-3-1-pro-low" }, "high": { modelUid: "gemini-3-1-pro-high" } }, aliases: ["gemini-3-1-pro"],
215
+ },
216
+ "gpt-5.4-mini": { id: "gpt-5.4-mini", defaultUid: "gpt-5-4-mini-low",
217
+ variants: {
218
+ "low": { modelUid: "gpt-5-4-mini-low" }, "medium": { modelUid: "gpt-5-4-mini-medium" },
219
+ "high": { modelUid: "gpt-5-4-mini-high" }, "xhigh": { modelUid: "gpt-5-4-mini-xhigh" },
220
+ }, aliases: ["gpt-5-4-mini"],
221
+ },
222
+ };
223
+
224
+ const ALIAS_TO_ID: Record<string, string> = Object.values(VARIANT_CATALOG).reduce((acc, entry) => {
225
+ acc[entry.id] = entry.id;
226
+ for (const alias of entry.aliases || []) acc[alias] = entry.id;
227
+ return acc;
228
+ }, {} as Record<string, string>);
229
+
230
+ // ----------------------------------------------------------------------------
231
+ // Model resolution
232
+ // ----------------------------------------------------------------------------
233
+
234
+ export interface ResolvedModel {
235
+ modelId: string;
236
+ modelUid: string;
237
+ variant?: string;
238
+ enumValue?: ModelEnumValue;
239
+ }
240
+
241
+ function splitModelAndVariant(raw: string): { base: string; variant?: string } {
242
+ const normalized = raw.toLowerCase().trim();
243
+ const colonIdx = normalized.indexOf(":");
244
+ if (colonIdx !== -1) {
245
+ return { base: normalized.slice(0, colonIdx), variant: normalized.slice(colonIdx + 1).trim() || undefined };
246
+ }
247
+ const parts = normalized.split("-");
248
+ for (let cut = 1; cut < parts.length; cut++) {
249
+ const base = parts.slice(0, parts.length - cut).join("-");
250
+ const maybeVariant = parts.slice(parts.length - cut).join("-");
251
+ const entry = VARIANT_CATALOG[ALIAS_TO_ID[base] || base];
252
+ if (entry?.variants?.[maybeVariant]) return { base, variant: maybeVariant };
253
+ }
254
+ return { base: normalized };
255
+ }
256
+
257
+ export function resolveModel(modelName: string): ResolvedModel {
258
+ const { base, variant } = splitModelAndVariant(modelName);
259
+ const baseId = ALIAS_TO_ID[base] || base;
260
+ const entry = VARIANT_CATALOG[baseId];
261
+
262
+ if (entry) {
263
+ const effectiveVariant = (variant || "").trim().toLowerCase();
264
+ if (effectiveVariant && entry.variants?.[effectiveVariant]) {
265
+ const v = entry.variants[effectiveVariant]!;
266
+ return {
267
+ modelId: entry.id,
268
+ modelUid: v.modelUid ?? (v.enumValue !== undefined ? ENUM_VALUE_TO_NAME.get(v.enumValue as number) ?? "" : uidForEntry(entry)),
269
+ enumValue: v.enumValue,
270
+ variant: effectiveVariant,
271
+ };
272
+ }
273
+ return { modelId: entry.id, modelUid: uidForEntry(entry), enumValue: entry.defaultEnum };
274
+ }
275
+
276
+ // Legacy enum fallback
277
+ const enumKey = base.toUpperCase().replace(/\./g, "_").replace(/-/g, "_");
278
+ const enumValue = (ModelEnum as Record<string, number>)[enumKey];
279
+ if (enumValue !== undefined) {
280
+ const uid = ENUM_VALUE_TO_NAME.get(enumValue);
281
+ if (uid) return { modelId: base, modelUid: uid, enumValue: enumValue as ModelEnumValue };
282
+ }
283
+
284
+ throw new Error(`Unknown Windsurf model: "${modelName}".`);
285
+ }
286
+
287
+ // Resolve model but accept raw model_uid passthrough for catalog-discovered models
288
+ export function resolveModelOrPassthrough(modelName: string): ResolvedModel {
289
+ try {
290
+ return resolveModel(modelName);
291
+ } catch {
292
+ // Unknown model — pass through the raw name as the UID
293
+ return { modelId: modelName, modelUid: modelName };
294
+ }
295
+ }
296
+
297
+ function uidForEntry(entry: ModelCatalogEntry): string {
298
+ if (entry.defaultUid) return entry.defaultUid;
299
+ if (entry.defaultEnum !== undefined) {
300
+ const uid = ENUM_VALUE_TO_NAME.get(entry.defaultEnum as number);
301
+ if (uid) return uid;
302
+ }
303
+ throw new Error(`Catalog entry "${entry.id}" has no defaultUid or defaultEnum`);
304
+ }
305
+
306
+ export function getDefaultModel(): string { return "claude-opus-4.8:medium"; }
307
+
308
+ export function getCanonicalModels(): string[] {
309
+ return Object.keys(VARIANT_CATALOG);
310
+ }
311
+
312
+ // Build reverse lookup: model_uid → user-facing model ID
313
+ const UID_TO_MODEL_ID: Map<string, string> = (() => {
314
+ const map = new Map<string, string>();
315
+ for (const [id, entry] of Object.entries(VARIANT_CATALOG)) {
316
+ // Default UID
317
+ try {
318
+ const defaultUid = entry.defaultUid ?? (entry.defaultEnum !== undefined ? ENUM_VALUE_TO_NAME.get(entry.defaultEnum as number) : undefined);
319
+ if (defaultUid) map.set(defaultUid, id);
320
+ } catch {}
321
+ // Variant UIDs
322
+ if (entry.variants) {
323
+ for (const [variantKey, variantMeta] of Object.entries(entry.variants)) {
324
+ const vUid = variantMeta.modelUid ?? (variantMeta.enumValue !== undefined ? ENUM_VALUE_TO_NAME.get(variantMeta.enumValue as number) : undefined);
325
+ if (vUid) map.set(vUid, `${id}:${variantKey}`);
326
+ }
327
+ }
328
+ }
329
+ // Also map legacy enum names
330
+ for (const [key, value] of Object.entries(ModelEnum)) {
331
+ if (typeof value === "number") {
332
+ const uid = ENUM_VALUE_TO_NAME.get(value);
333
+ if (uid && !map.has(uid)) {
334
+ const id = key.toLowerCase().replace(/_/g, "-");
335
+ map.set(uid, id);
336
+ }
337
+ }
338
+ }
339
+ return map;
340
+ })();
341
+
342
+ export function lookupModelId(uid: string): string | null {
343
+ // Direct lookup
344
+ const direct = UID_TO_MODEL_ID.get(uid);
345
+ if (direct) return direct;
346
+ // Strip _BYOK suffix (Bring Your Own Key variants)
347
+ const withoutByok = uid.replace(/_BYOK$/, "");
348
+ if (withoutByok !== uid) {
349
+ const byokMatch = UID_TO_MODEL_ID.get(withoutByok);
350
+ if (byokMatch) return byokMatch;
351
+ }
352
+ return null;
353
+ }