pi-freeflow 1.4.2 → 1.4.4

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/src/models.ts CHANGED
@@ -1,399 +1,355 @@
1
- /**
2
- * Static model definitions and upstream routing catalogs for pi-freeflow
3
- *
4
- * Defines the 23 verified free models:
5
- * - 9 OpenCode Zen models (2 Responses API + 7 Chat Completions)
6
- * - 14 KiloCode Keyless Gateway models (11 OpenRouter format + 3 Standard format)
7
- */
8
-
9
- import type { ModelDef, Upstream } from "./types.ts";
10
-
11
- /**
12
- * OpenCode Zen free models verified against the live catalog and inference APIs.
13
- * Endpoint: https://opencode.ai/zen/v1
14
- */
15
- export const OPENCODE_MODELS: ModelDef[] = [
16
- {
17
- id: "deepseek-v4-flash-free",
18
- name: "DeepSeek V4 Flash (1M)",
19
- reasoning: true,
20
- contextWindow: 1_000_000,
21
- maxTokens: 384_000,
22
- input: ["text"],
23
- thinkingLevelMap: {
24
- off: null,
25
- minimal: "low",
26
- low: "low",
27
- medium: "high",
28
- high: "high",
29
- xhigh: "max",
30
- max: "max",
31
- },
32
- },
33
- {
34
- id: "x-preview-f-free",
35
- name: "Ox Alpha (1M)",
36
- reasoning: true,
37
- contextWindow: 1_048_576,
38
- maxTokens: 131_072,
39
- input: ["text", "image"],
40
- thinkingLevelMap: {
41
- off: null,
42
- minimal: "low",
43
- low: "low",
44
- medium: "high",
45
- high: "high",
46
- xhigh: "max",
47
- max: "max",
48
- },
49
- },
50
- {
51
- id: "muse-spark-1.2-contributor-free",
52
- name: "Muse Spark 1.2 (1M)",
53
- reasoning: true,
54
- contextWindow: 1_048_576,
55
- maxTokens: 131_072,
56
- api: "openai-responses",
57
- input: ["text", "image"],
58
- thinkingLevelMap: {
59
- off: null,
60
- minimal: "minimal",
61
- low: "low",
62
- medium: "medium",
63
- high: "high",
64
- xhigh: "xhigh",
65
- max: "max",
66
- },
67
- },
68
- {
69
- id: "mimo-v2.5-free",
70
- name: "MiMo V2.5 (1M)",
71
- reasoning: true,
72
- contextWindow: 1_048_576,
73
- maxTokens: 131_072,
74
- input: ["text", "image"],
75
- thinkingLevelMap: {
76
- off: null,
77
- minimal: "low",
78
- low: "low",
79
- medium: "medium",
80
- high: "high",
81
- xhigh: "high",
82
- max: "high",
83
- },
84
- },
85
- {
86
- id: "hy3-free",
87
- name: "Hy3 (262K)",
88
- reasoning: true,
89
- contextWindow: 262_144,
90
- maxTokens: 262_144,
91
- input: ["text"],
92
- thinkingLevelMap: {
93
- off: null,
94
- minimal: "low",
95
- low: "low",
96
- medium: "high",
97
- high: "high",
98
- xhigh: "max",
99
- max: "max",
100
- },
101
- },
102
- {
103
- id: "nemotron-3-ultra-free",
104
- name: "Nemotron 3 Ultra (1M)",
105
- reasoning: true,
106
- contextWindow: 1_000_000,
107
- maxTokens: 128_000,
108
- input: ["text"],
109
- thinkingLevelMap: {
110
- off: null,
111
- minimal: "low",
112
- low: "low",
113
- medium: "high",
114
- high: "high",
115
- xhigh: "max",
116
- max: "max",
117
- },
118
- },
119
- {
120
- id: "nemotron-3.5-lightning-free",
121
- name: "Nemotron 3.5 Lightning (1M)",
122
- reasoning: true,
123
- contextWindow: 1_000_000,
124
- maxTokens: 262_144,
125
- input: ["text"],
126
- thinkingLevelMap: {
127
- off: null,
128
- minimal: "low",
129
- low: "low",
130
- medium: "high",
131
- high: "high",
132
- xhigh: "max",
133
- max: "max",
134
- },
135
- },
136
- {
137
- id: "big-pickle",
138
- name: "Big Pickle",
139
- reasoning: true,
140
- contextWindow: 200_000,
141
- maxTokens: 32_000,
142
- input: ["text"],
143
- thinkingLevelMap: {
144
- off: null,
145
- minimal: "high",
146
- low: "high",
147
- medium: "high",
148
- high: "high",
149
- xhigh: "max",
150
- max: "max",
151
- },
152
- },
153
- {
154
- id: "laguna-s-2.1-free",
155
- name: "Laguna S 2.1 (1M)",
156
- reasoning: true,
157
- contextWindow: 1_048_576,
158
- maxTokens: 131_072,
159
- input: ["text"],
160
- thinkingLevelMap: {
161
- off: null,
162
- minimal: "low",
163
- low: "low",
164
- medium: "high",
165
- high: "high",
166
- xhigh: "max",
167
- max: "max",
168
- },
169
- },
170
- ];
171
-
172
- /**
173
- * Backward compatibility alias for OPENCODE_MODELS
174
- */
175
- export const KNOWN_MODELS = OPENCODE_MODELS;
176
-
177
- /**
178
- * KiloCode Gateway free models (keyless — https://kilo.ai/docs/gateway).
179
- * Endpoint: https://api.kilo.ai/api/gateway/chat/completions
180
- */
181
- export const KILO_MODELS: ModelDef[] = [
182
- {
183
- id: "dots-studio/dots-3-note-preview:free",
184
- name: "Dots3-Note Preview (512K)",
185
- reasoning: true,
186
- contextWindow: 512_000,
187
- maxTokens: 512_000,
188
- input: ["text", "image"],
189
- thinkingFormat: "openrouter",
190
- },
191
- {
192
- id: "stepfun/step-3.7-flash:free",
193
- name: "Step 3.7 Flash",
194
- reasoning: true,
195
- contextWindow: 262_144,
196
- maxTokens: 262_144,
197
- input: ["text", "image"],
198
- thinkingFormat: "openrouter",
199
- },
200
- {
201
- id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
202
- name: "Nemotron 3 Nano Omni",
203
- reasoning: true,
204
- contextWindow: 256_000,
205
- maxTokens: 65_536,
206
- input: ["text", "image"],
207
- thinkingFormat: "openrouter",
208
- },
209
- {
210
- id: "nvidia/nemotron-3-ultra-550b-a55b:free",
211
- name: "Nemotron 3 Ultra 550B (1M)",
212
- reasoning: true,
213
- contextWindow: 1_000_000,
214
- maxTokens: 65_536,
215
- input: ["text"],
216
- thinkingFormat: "openrouter",
217
- },
218
- {
219
- id: "nvidia/nemotron-3.5-lightning:free",
220
- name: "Nemotron 3.5 Lightning (Kilo)",
221
- reasoning: true,
222
- contextWindow: 1_000_000,
223
- maxTokens: 131_072,
224
- input: ["text"],
225
- thinkingFormat: "openrouter",
226
- },
227
- {
228
- id: "nvidia/nemotron-3-super-120b-a12b:free",
229
- name: "Nemotron 3 Super 120B",
230
- reasoning: true,
231
- contextWindow: 262_144,
232
- maxTokens: 262_144,
233
- input: ["text"],
234
- thinkingFormat: "openrouter",
235
- },
236
- {
237
- id: "tencent/hy3:free",
238
- name: "Tencent Hy3 (Kilo)",
239
- reasoning: true,
240
- contextWindow: 262_144,
241
- maxTokens: 262_144,
242
- input: ["text"],
243
- },
244
- {
245
- id: "cohere/north-mini-code:free",
246
- name: "North Mini Code",
247
- reasoning: true,
248
- contextWindow: 256_000,
249
- maxTokens: 64_000,
250
- input: ["text"],
251
- thinkingFormat: "openrouter",
252
- },
253
- {
254
- id: "poolside/laguna-s-2.1:free",
255
- name: "Laguna S 2.1 (Kilo)",
256
- reasoning: true,
257
- contextWindow: 1_048_576,
258
- maxTokens: 131_072,
259
- input: ["text"],
260
- thinkingFormat: "openrouter",
261
- },
262
- {
263
- id: "poolside/laguna-xs-2.1:free",
264
- name: "Laguna XS 2.1",
265
- reasoning: true,
266
- contextWindow: 262_144,
267
- maxTokens: 32_768,
268
- input: ["text"],
269
- thinkingFormat: "openrouter",
270
- },
271
- {
272
- id: "liquid/lfm-2.5-2.6b:free",
273
- name: "Liquid LFM 2.5",
274
- reasoning: true,
275
- contextWindow: 128_000,
276
- maxTokens: 32_768,
277
- input: ["text"],
278
- thinkingFormat: "openrouter",
279
- },
280
- {
281
- id: "kilo-auto/free",
282
- name: "Kilo Auto",
283
- reasoning: false,
284
- contextWindow: 256_000,
285
- maxTokens: 10_000,
286
- input: ["text"],
287
- },
288
- {
289
- id: "openrouter/free",
290
- name: "OpenRouter Auto",
291
- reasoning: false,
292
- contextWindow: 200_000,
293
- maxTokens: 65_536,
294
- input: ["text", "image"],
295
- },
296
- {
297
- id: "nvidia/nemotron-3.5-content-safety:free",
298
- name: "Nemotron Content Safety",
299
- reasoning: false,
300
- contextWindow: 128_000,
301
- maxTokens: 8_192,
302
- input: ["text", "image"],
303
- },
304
- ];
305
-
306
- /**
307
- * Model ID Aliases — maps user-friendly / slash-free CLI IDs to canonical upstream model IDs.
308
- */
309
- export const MODEL_ALIASES: Record<string, string> = {
310
- // Kilo Gateway slash-free & colon-free CLI aliases
311
- "dots-3-note-preview": "dots-studio/dots-3-note-preview:free",
312
- "dots-3-note-preview:free": "dots-studio/dots-3-note-preview:free",
313
- "step-3.7-flash": "stepfun/step-3.7-flash:free",
314
- "step-3.7-flash:free": "stepfun/step-3.7-flash:free",
315
- "nemotron-3-nano-omni": "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
316
- "nemotron-3-nano-omni:free": "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
317
- "nemotron-3-ultra-550b": "nvidia/nemotron-3-ultra-550b-a55b:free",
318
- "nemotron-3-ultra-550b:free": "nvidia/nemotron-3-ultra-550b-a55b:free",
319
- "nemotron-3-super": "nvidia/nemotron-3-super-120b-a12b:free",
320
- "nemotron-3-super:free": "nvidia/nemotron-3-super-120b-a12b:free",
321
- "hy3:free": "tencent/hy3:free",
322
- "north-mini-code": "cohere/north-mini-code:free",
323
- "north-mini-code:free": "cohere/north-mini-code:free",
324
- "laguna-s-2.1:free": "poolside/laguna-s-2.1:free",
325
- "laguna-xs-2.1:free": "poolside/laguna-xs-2.1:free",
326
- "lfm-2.5": "liquid/lfm-2.5-2.6b:free",
327
- "lfm-2.5:free": "liquid/lfm-2.5-2.6b:free",
328
- "content-safety": "nvidia/nemotron-3.5-content-safety:free",
329
- "content-safety:free": "nvidia/nemotron-3.5-content-safety:free",
330
- "kilo-auto": "kilo-auto/free",
331
- "openrouter": "openrouter/free",
332
-
333
- // OpenCode Zen aliases
334
- "claude-sonnet-4.5-free": "muse-spark-1.2-contributor-free",
335
- "claude-sonnet-4.5-contributor-free": "muse-spark-1.2-contributor-free",
336
- "grok-code-fast-1-preview-f-free": "x-preview-f-free",
337
- "minimax-m2.1-free": "laguna-s-2.1-free",
338
- "qwen3-coder-480b-free": "hy3-free",
339
- };
340
-
341
- /**
342
- * Resolve any model alias to its canonical upstream model ID.
343
- */
344
- export function resolveCanonicalModelId(id: string): string {
345
- const clean = (id || "").trim();
346
- return MODEL_ALIASES[clean] || clean;
347
- }
348
-
349
- /**
350
- * Set of all KiloCode model IDs (including aliases) for fast lookup
351
- */
352
- export const KILO_MODEL_IDS = new Set<string>([
353
- ...KILO_MODELS.map((m) => m.id),
354
- ...Object.entries(MODEL_ALIASES)
355
- .filter(([_, target]) => KILO_MODELS.some((km) => km.id === target))
356
- .map(([alias]) => alias),
357
- ]);
358
-
359
- /**
360
- * Combined list of all 23 static free models (canonical)
361
- */
362
- export const ALL_MODELS: ModelDef[] = [...OPENCODE_MODELS, ...KILO_MODELS];
363
-
364
- /**
365
- * Map of model ID -> ModelDef
366
- */
367
- export const MODEL_MAP = new Map<string, ModelDef>(
368
- ALL_MODELS.map((m): [string, ModelDef] => [m.id, m]),
369
- );
370
-
371
- /**
372
- * Get full list of registered canonical models for Pi/OMP provider registration
373
- */
374
- export function getAllRegisteredModels(): ModelDef[] {
375
- return ALL_MODELS;
376
- }
377
-
378
- /**
379
- * Lookup a model definition by ID (supporting alias fallback)
380
- */
381
- export function getModelDef(id: string): ModelDef | undefined {
382
- return MODEL_MAP.get(id) || MODEL_MAP.get(resolveCanonicalModelId(id));
383
- }
384
-
385
-
386
- /**
387
- * Check if a model ID belongs to KiloCode Gateway
388
- */
389
- export function isKiloModel(id: string): boolean {
390
- const canonical = resolveCanonicalModelId(id);
391
- return KILO_MODEL_IDS.has(id) || KILO_MODEL_IDS.has(canonical);
392
- }
393
-
394
- /**
395
- * Determine the upstream provider for a given model ID
396
- */
397
- export function getModelUpstream(id: string): Upstream {
398
- return isKiloModel(id) ? "kilo" : "opencode";
399
- }
1
+ /**
2
+ * Static model definitions and upstream routing catalogs for pi-freeflow
3
+ *
4
+ * Defines the 21 verified free models:
5
+ * - 7 OpenCode Zen models (1 Responses API + 6 Chat Completions)
6
+ * - 14 KiloCode Keyless Gateway models (10 OpenRouter format + 4 Standard format)
7
+ */
8
+
9
+ import type { ModelDef, Upstream } from "./types.ts";
10
+
11
+ /**
12
+ * OpenCode Zen free models verified against the live catalog and inference APIs.
13
+ * Endpoint: https://opencode.ai/zen/v1
14
+ */
15
+ export const OPENCODE_MODELS: ModelDef[] = [
16
+ {
17
+ id: "muse-spark-1.2-contributor-free",
18
+ name: "Muse Spark 1.2 (1M)",
19
+ reasoning: true,
20
+ contextWindow: 1_048_576,
21
+ maxTokens: 131_072,
22
+ api: "openai-responses",
23
+ input: ["text", "image"],
24
+ thinkingLevelMap: {
25
+ off: null,
26
+ minimal: "minimal",
27
+ low: "low",
28
+ medium: "medium",
29
+ high: "high",
30
+ xhigh: "xhigh",
31
+ max: "max",
32
+ },
33
+ },
34
+ {
35
+ id: "mimo-v2.5-free",
36
+ name: "MiMo V2.5 (1M)",
37
+ reasoning: true,
38
+ contextWindow: 1_048_576,
39
+ maxTokens: 131_072,
40
+ input: ["text", "image"],
41
+ thinkingLevelMap: {
42
+ off: null,
43
+ minimal: "low",
44
+ low: "low",
45
+ medium: "medium",
46
+ high: "high",
47
+ xhigh: "high",
48
+ max: "high",
49
+ },
50
+ },
51
+ {
52
+ id: "hy3-free",
53
+ name: "Hy3 (262K)",
54
+ reasoning: true,
55
+ contextWindow: 262_144,
56
+ maxTokens: 262_144,
57
+ input: ["text"],
58
+ thinkingLevelMap: {
59
+ off: null,
60
+ minimal: "low",
61
+ low: "low",
62
+ medium: "high",
63
+ high: "high",
64
+ xhigh: "max",
65
+ max: "max",
66
+ },
67
+ },
68
+ {
69
+ id: "nemotron-3-ultra-free",
70
+ name: "Nemotron 3 Ultra (1M)",
71
+ reasoning: true,
72
+ contextWindow: 1_000_000,
73
+ maxTokens: 128_000,
74
+ input: ["text"],
75
+ thinkingLevelMap: {
76
+ off: null,
77
+ minimal: "low",
78
+ low: "low",
79
+ medium: "high",
80
+ high: "high",
81
+ xhigh: "max",
82
+ max: "max",
83
+ },
84
+ },
85
+ {
86
+ id: "nemotron-3.5-lightning-free",
87
+ name: "Nemotron 3.5 Lightning (1M)",
88
+ reasoning: true,
89
+ contextWindow: 1_000_000,
90
+ maxTokens: 262_144,
91
+ input: ["text"],
92
+ thinkingLevelMap: {
93
+ off: null,
94
+ minimal: "low",
95
+ low: "low",
96
+ medium: "high",
97
+ high: "high",
98
+ xhigh: "max",
99
+ max: "max",
100
+ },
101
+ },
102
+ {
103
+ id: "big-pickle",
104
+ name: "Big Pickle",
105
+ reasoning: true,
106
+ contextWindow: 200_000,
107
+ maxTokens: 32_000,
108
+ input: ["text"],
109
+ thinkingLevelMap: {
110
+ off: null,
111
+ minimal: "high",
112
+ low: "high",
113
+ medium: "high",
114
+ high: "high",
115
+ xhigh: "max",
116
+ max: "max",
117
+ },
118
+ },
119
+ {
120
+ id: "laguna-s-2.1-free",
121
+ name: "Laguna S 2.1 (1M)",
122
+ reasoning: true,
123
+ contextWindow: 1_048_576,
124
+ maxTokens: 131_072,
125
+ input: ["text"],
126
+ thinkingLevelMap: {
127
+ off: null,
128
+ minimal: "low",
129
+ low: "low",
130
+ medium: "high",
131
+ high: "high",
132
+ xhigh: "max",
133
+ max: "max",
134
+ },
135
+ },
136
+ ];
137
+
138
+ /**
139
+ * Backward compatibility alias for OPENCODE_MODELS
140
+ */
141
+ export const KNOWN_MODELS = OPENCODE_MODELS;
142
+
143
+ /**
144
+ * KiloCode Gateway free models (keyless — https://kilo.ai/docs/gateway).
145
+ * Endpoint: https://api.kilo.ai/api/gateway/chat/completions
146
+ */
147
+ export const KILO_MODELS: ModelDef[] = [
148
+ {
149
+ id: "dots-studio/dots-3-note-preview:free",
150
+ name: "Dots3-Note Preview (512K)",
151
+ reasoning: true,
152
+ contextWindow: 512_000,
153
+ maxTokens: 512_000,
154
+ input: ["text", "image"],
155
+ thinkingFormat: "openrouter",
156
+ },
157
+ {
158
+ id: "stepfun/step-3.7-flash:free",
159
+ name: "Step 3.7 Flash",
160
+ reasoning: true,
161
+ contextWindow: 262_144,
162
+ maxTokens: 262_144,
163
+ input: ["text", "image"],
164
+ thinkingFormat: "openrouter",
165
+ },
166
+ {
167
+ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
168
+ name: "Nemotron 3 Nano Omni",
169
+ reasoning: true,
170
+ contextWindow: 256_000,
171
+ maxTokens: 65_536,
172
+ input: ["text", "image"],
173
+ thinkingFormat: "openrouter",
174
+ },
175
+ {
176
+ id: "nvidia/nemotron-3-ultra-550b-a55b:free",
177
+ name: "Nemotron 3 Ultra 550B (1M)",
178
+ reasoning: true,
179
+ contextWindow: 1_000_000,
180
+ maxTokens: 65_536,
181
+ input: ["text"],
182
+ thinkingFormat: "openrouter",
183
+ },
184
+ {
185
+ id: "nvidia/nemotron-3.5-lightning:free",
186
+ name: "Nemotron 3.5 Lightning (Kilo)",
187
+ reasoning: true,
188
+ contextWindow: 1_000_000,
189
+ maxTokens: 131_072,
190
+ input: ["text"],
191
+ thinkingFormat: "openrouter",
192
+ },
193
+ {
194
+ id: "nvidia/nemotron-3-super-120b-a12b:free",
195
+ name: "Nemotron 3 Super 120B",
196
+ reasoning: true,
197
+ contextWindow: 262_144,
198
+ maxTokens: 262_144,
199
+ input: ["text"],
200
+ thinkingFormat: "openrouter",
201
+ },
202
+ {
203
+ id: "tencent/hy3:free",
204
+ name: "Tencent Hy3 (Kilo)",
205
+ reasoning: true,
206
+ contextWindow: 262_144,
207
+ maxTokens: 262_144,
208
+ input: ["text"],
209
+ },
210
+ {
211
+ id: "cohere/north-mini-code:free",
212
+ name: "North Mini Code",
213
+ reasoning: true,
214
+ contextWindow: 256_000,
215
+ maxTokens: 64_000,
216
+ input: ["text"],
217
+ thinkingFormat: "openrouter",
218
+ },
219
+ {
220
+ id: "poolside/laguna-s-2.1:free",
221
+ name: "Laguna S 2.1 (Kilo)",
222
+ reasoning: true,
223
+ contextWindow: 1_048_576,
224
+ maxTokens: 131_072,
225
+ input: ["text"],
226
+ thinkingFormat: "openrouter",
227
+ },
228
+ {
229
+ id: "poolside/laguna-xs-2.1:free",
230
+ name: "Laguna XS 2.1",
231
+ reasoning: true,
232
+ contextWindow: 262_144,
233
+ maxTokens: 32_768,
234
+ input: ["text"],
235
+ thinkingFormat: "openrouter",
236
+ },
237
+ {
238
+ id: "liquid/lfm-2.5-2.6b:free",
239
+ name: "Liquid LFM 2.5",
240
+ reasoning: true,
241
+ contextWindow: 128_000,
242
+ maxTokens: 32_768,
243
+ input: ["text"],
244
+ thinkingFormat: "openrouter",
245
+ },
246
+ {
247
+ id: "kilo-auto/free",
248
+ name: "Kilo Auto",
249
+ reasoning: false,
250
+ contextWindow: 256_000,
251
+ maxTokens: 10_000,
252
+ input: ["text"],
253
+ },
254
+ {
255
+ id: "openrouter/free",
256
+ name: "OpenRouter Auto",
257
+ reasoning: false,
258
+ contextWindow: 200_000,
259
+ maxTokens: 65_536,
260
+ input: ["text", "image"],
261
+ },
262
+ {
263
+ id: "nvidia/nemotron-3.5-content-safety:free",
264
+ name: "Nemotron Content Safety",
265
+ reasoning: false,
266
+ contextWindow: 128_000,
267
+ maxTokens: 8_192,
268
+ input: ["text", "image"],
269
+ },
270
+ ];
271
+
272
+ /**
273
+ * Model ID Aliases — maps user-friendly / slash-free CLI IDs to canonical upstream model IDs.
274
+ * Single clean alias per model (no :free duplicates). Wrong cross-lab aliases removed:
275
+ * - Muse Spark 1.2 = Meta Superintelligence Labs (not Anthropic Claude) → removed claude-sonnet aliases
276
+ * - Laguna S 2.1 = Poolside (not MiniMax) → removed minimax-m2.1 alias
277
+ * - Hy3 = Tencent Hunyuan (not Alibaba Qwen) → removed qwen3-coder alias
278
+ */
279
+ export const MODEL_ALIASES: Record<string, string> = {
280
+ // Kilo Gateway — slash-free & colon-free clean aliases (one per model)
281
+ "dots-3-note-preview": "dots-studio/dots-3-note-preview:free",
282
+ "step-3.7-flash": "stepfun/step-3.7-flash:free",
283
+ "nemotron-3-nano-omni": "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
284
+ "nemotron-3-ultra-550b": "nvidia/nemotron-3-ultra-550b-a55b:free",
285
+ "nemotron-3-super": "nvidia/nemotron-3-super-120b-a12b:free",
286
+ "north-mini-code": "cohere/north-mini-code:free",
287
+ "lfm-2.5": "liquid/lfm-2.5-2.6b:free",
288
+ "content-safety": "nvidia/nemotron-3.5-content-safety:free",
289
+ // provider-prefixed short aliases (slash-normalized)
290
+ "hy3:free": "tencent/hy3:free",
291
+ "laguna-s-2.1:free": "poolside/laguna-s-2.1:free",
292
+ "laguna-xs-2.1:free": "poolside/laguna-xs-2.1:free",
293
+ "kilo-auto": "kilo-auto/free",
294
+ "openrouter": "openrouter/free",
295
+ };
296
+
297
+ /**
298
+ * Resolve any model alias to its canonical upstream model ID.
299
+ */
300
+ export function resolveCanonicalModelId(id: string): string {
301
+ const clean = (id || "").trim();
302
+ return MODEL_ALIASES[clean] || clean;
303
+ }
304
+
305
+ /**
306
+ * Set of all KiloCode model IDs (including aliases) for fast lookup
307
+ */
308
+ export const KILO_MODEL_IDS = new Set<string>([
309
+ ...KILO_MODELS.map((m) => m.id),
310
+ ...Object.entries(MODEL_ALIASES)
311
+ .filter(([_, target]) => KILO_MODELS.some((km) => km.id === target))
312
+ .map(([alias]) => alias),
313
+ ]);
314
+
315
+ /**
316
+ * Combined list of all 21 static free models (canonical)
317
+ */
318
+ export const ALL_MODELS: ModelDef[] = [...OPENCODE_MODELS, ...KILO_MODELS];
319
+
320
+ /**
321
+ * Map of model ID -> ModelDef
322
+ */
323
+ export const MODEL_MAP = new Map<string, ModelDef>(
324
+ ALL_MODELS.map((m): [string, ModelDef] => [m.id, m]),
325
+ );
326
+
327
+ /**
328
+ * Get full list of registered canonical models for Pi/OMP provider registration
329
+ */
330
+ export function getAllRegisteredModels(): ModelDef[] {
331
+ return ALL_MODELS;
332
+ }
333
+
334
+ /**
335
+ * Lookup a model definition by ID (supporting alias fallback)
336
+ */
337
+ export function getModelDef(id: string): ModelDef | undefined {
338
+ return MODEL_MAP.get(id) || MODEL_MAP.get(resolveCanonicalModelId(id));
339
+ }
340
+
341
+
342
+ /**
343
+ * Check if a model ID belongs to KiloCode Gateway
344
+ */
345
+ export function isKiloModel(id: string): boolean {
346
+ const canonical = resolveCanonicalModelId(id);
347
+ return KILO_MODEL_IDS.has(id) || KILO_MODEL_IDS.has(canonical);
348
+ }
349
+
350
+ /**
351
+ * Determine the upstream provider for a given model ID
352
+ */
353
+ export function getModelUpstream(id: string): Upstream {
354
+ return isKiloModel(id) ? "kilo" : "opencode";
355
+ }