@wenathlan/getry 2.0.165 → 2.0.166

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/gateway.ts ADDED
@@ -0,0 +1,1306 @@
1
+ /**
2
+ * gateway — consolidated gateway logics of the getry family
3
+ * @module gateway
4
+ * @family wave/logicfold3
5
+ * One keyed file per family: the former variant arms (gatewayconfig, gatewayviewconfig)
6
+ * retired into this seat with every export preserved under the same name.
7
+ */
8
+
9
+ import type { gatewaydefinition, modeldef, thinkinglevel } from "./types.ts";
10
+ import { listlevels, providerchain, type thinkingproviderrow } from "@wenathlan/getry/thinking";
11
+
12
+ /**
13
+ * gateway.ts — the gateway versions domain of getry (root layer).
14
+ *
15
+ * the five provider gateways the app serves (v1 through v5), the seven
16
+ * OpenAI-compatible route kinds each one answers, and the canonical
17
+ * parser pattern the streaming routes follow. the rows below are the
18
+ * in-memory catalog of the route map: the self-hosted gateway answers
19
+ * the real traffic over HTTPS, the static build falls back to this
20
+ * catalog without ever touching the visitor machine.
21
+ */
22
+
23
+ /** the seven OpenAI-compatible route kinds every gateway version carries. */
24
+ export const GATEWAYROUTES = [
25
+ "chat/completions",
26
+ "completions",
27
+ "embeddings",
28
+ "keys",
29
+ "messages",
30
+ "models",
31
+ "responses",
32
+ ] as const;
33
+
34
+ /** one route kind of the gateway surface. */
35
+ export type GatewayRoute = (typeof GATEWAYROUTES)[number];
36
+
37
+ /** the lifecycle badge a gateway version carries. */
38
+ export type GatewayBadge = "live" | "paused";
39
+
40
+ /** one provider gateway of the family (v1 through v5). */
41
+ export type GatewayVersion = {
42
+ v: string;
43
+ provider: string;
44
+ pattern: string;
45
+ badge: GatewayBadge;
46
+ models: string;
47
+ routes: GatewayRoute[];
48
+ note: string;
49
+ };
50
+
51
+ /** the in-memory catalog the DB layer persists on first run. */
52
+ export const GATEWAYVERSIONS: GatewayVersion[] = [
53
+ {
54
+ v: "v1",
55
+ provider: "zai",
56
+ pattern: "passthrough retransmit via z ai web dev sdk",
57
+ badge: "live",
58
+ models:
59
+ "glm-5.3 glm-5.3-flash glm-5.3-fast glm-5.3-air glm-5.2 glm-5.1 glm-5 glm-5v glm-5-turbo glm-4-plus glm-4-flash devthink",
60
+ routes: [...GATEWAYROUTES],
61
+ note: "no token chat id required — sdk has internal config — individual model calling plus devthink meta over glm-5.3",
62
+ },
63
+ {
64
+ v: "v2",
65
+ provider: "babel town",
66
+ pattern: "rebuild plus byte tee passthrough paused fallback v1",
67
+ badge: "paused",
68
+ models: "babel-glm-5.2 devthink",
69
+ routes: [...GATEWAYROUTES],
70
+ note: "service is paused returns 503 fallback to v1 zai — glm-5.2 only",
71
+ },
72
+ {
73
+ v: "v3",
74
+ provider: "nvidia nim",
75
+ pattern: "rebuild per family reasoning control pure byte passthrough",
76
+ badge: "live",
77
+ models: "17 chat models kimi-k3 deepseek-v4 nemotron-3 muse-glimmer laguna gpt-oss gemma-4 mistral llama-3.2",
78
+ routes: [...GATEWAYROUTES],
79
+ note: "22 keys round robin devthink meta model rotates every 6 messages",
80
+ },
81
+ {
82
+ v: "v4",
83
+ provider: "opencode zen plus kilo",
84
+ pattern: "dynamic free discovery anonymous no key",
85
+ badge: "live",
86
+ models: "discovered live -free and :free tagged models from opencode zen plus kilo",
87
+ routes: [...GATEWAYROUTES],
88
+ note: "zero hardcoded model names — universal free-tag filter plus devthink context-window math",
89
+ },
90
+ {
91
+ v: "v5",
92
+ provider: "openrouter",
93
+ pattern: "dynamic free discovery openrouter :free tagged",
94
+ badge: "live",
95
+ models: "discovered live :free tagged models from openrouter",
96
+ routes: [...GATEWAYROUTES],
97
+ note: "requires free openrouter api key — zero hardcoded model names plus devthink context-window math",
98
+ },
99
+ ];
100
+
101
+ /** the canonical parser pattern of the streaming routes, in order. */
102
+ export const PARSERSTEPS: string[] = [
103
+ "readablestream with safeenqueue safeclose plus closed flag",
104
+ "setinterval keepalive 200ms only when silent greater than 1 second",
105
+ "upstream call fetch with abortsignal timeout 2147483647 for stream",
106
+ "parse sse parsesseframes split on double newline never partial frame",
107
+ "discard heartbeat lines starting with colon or event ping",
108
+ "mask model name to devthink via regex no json parse",
109
+ "re-emit normalized chunks delta reasoning content before content",
110
+ "finally emit finish reason stop plus single done plus savemsg",
111
+ ];
112
+
113
+ /**
114
+ * lists the gateway versions in serve order (v1 first).
115
+ *
116
+ * @returns the version rows.
117
+ */
118
+ export function listversions(): GatewayVersion[] {
119
+ return GATEWAYVERSIONS;
120
+ }
121
+
122
+ /**
123
+ * finds one gateway version by its version tag.
124
+ *
125
+ * @param v the version tag (v1 through v5).
126
+ * @returns the version row or null.
127
+ */
128
+ export function findversion(v: string): GatewayVersion | null {
129
+ return GATEWAYVERSIONS.find((version) => version.v === v) ?? null;
130
+ }
131
+
132
+ /**
133
+ * counts the routes the whole gateway serves (versions times route kinds).
134
+ *
135
+ * @returns the total route count.
136
+ */
137
+ export function totalroutes(): number {
138
+ return GATEWAYVERSIONS.reduce((sum, version) => sum + version.routes.length, 0);
139
+ }
140
+
141
+ /**
142
+ * lists the versions that answer live traffic right now.
143
+ *
144
+ * @returns the live version rows.
145
+ */
146
+ export function liveversions(): GatewayVersion[] {
147
+ return GATEWAYVERSIONS.filter((version) => version.badge === "live");
148
+ }
149
+
150
+ /**
151
+ * builds the cross-provider thinking chain for one level over the catalog
152
+ * this module owns: every gateway version's provider row (the
153
+ * GATEWAYVERSIONS lifecycle badges) wired with the model rows of the
154
+ * matching gatewayViewConfig version, routed through the thinking seat's
155
+ * providerchain — the tier routing (the level selects the model tier), the
156
+ * budget fit and the live-first order all answer from the seat (the one
157
+ * owner of the routing math), the rows from this catalog (the one owner of
158
+ * the data). the family consumers (devthink and siblings) call this
159
+ * through the @wenathlan/getry/gatewayconfig face and never rebuild the
160
+ * chain themselves.
161
+ *
162
+ * @law the level routes the chain — the data rides the catalog rows, the
163
+ * math rides the thinking seat, nothing duplicates
164
+ * @param level the thinking level to route.
165
+ * @returns the ordered provider/model candidates (live providers first,
166
+ * tier-exact models first within each provider).
167
+ */
168
+ export function thinkingchain(level: thinkinglevel): { provider: string; model: modeldef }[] {
169
+ const catalog: thinkingproviderrow[] = GATEWAYVERSIONS.map((version) => ({
170
+ provider: version.provider,
171
+ badge: version.badge,
172
+ models: gatewayViewConfig.versions[version.v]?.models ?? [],
173
+ }));
174
+ return providerchain(catalog, level).map((candidate) => ({
175
+ provider: candidate.provider,
176
+ model: candidate.model as modeldef,
177
+ }));
178
+ }
179
+
180
+ /* ===== block: gatewayconfig ===== */
181
+ /**
182
+ * gatewayconfig.ts — the gateway definition of the devthink app (root layer).
183
+ *
184
+ * The embedded gateway serves the OpenAI-compatible contract the chat speaks:
185
+ * `/v1/chat/completions` + `/v1/models` (and the legacy `/api/v1/*` prefix the
186
+ * server always carried). The v1 row rides the z.ai SDK transport — keyless,
187
+ * the SDK authenticates itself — exactly the family doctrine: the chat talks to
188
+ * the gateway, the gateway talks to the model, and no side-service ever ships.
189
+ */
190
+
191
+
192
+ export const gatewayConfig: gatewaydefinition = {
193
+ name: "devthink gateway",
194
+ description: "the embedded gateway of the devthink app — v1 zai sdk keyless",
195
+ versions: {
196
+ v1: {
197
+ id: "v1",
198
+ name: "zai sdk",
199
+ providername: "zai",
200
+ note: "passthrough retransmit via z ai web dev sdk — no token chat id required",
201
+ transport: { type: "zai-sdk" },
202
+ upstreams: [],
203
+ auth: { mode: "keylesssdk" },
204
+ defaultmodel: "devthink",
205
+ models: [
206
+ { id: "devthink", context: 200000, maxoutput: 32768, reasoning: true },
207
+ { id: "glm-5.3", context: 200000, maxoutput: 32768, reasoning: true, family: "glm" },
208
+ { id: "glm-5.3-flash", context: 128000, maxoutput: 16384, reasoning: true, family: "glm", free: true },
209
+ { id: "glm-5.3-fast", context: 128000, maxoutput: 16384, reasoning: true, family: "glm" },
210
+ { id: "glm-5.3-air", context: 128000, maxoutput: 16384, reasoning: true, family: "glm", free: true },
211
+ { id: "glm-5.2", context: 200000, maxoutput: 32768, reasoning: true, family: "glm" },
212
+ { id: "glm-5.1", context: 128000, maxoutput: 32768, reasoning: true, family: "glm" },
213
+ { id: "glm-5", context: 128000, maxoutput: 32768, reasoning: true, family: "glm" },
214
+ { id: "glm-5v", context: 128000, maxoutput: 16384, reasoning: false, vision: true, family: "glm" },
215
+ { id: "glm-5-turbo", context: 128000, maxoutput: 16384, reasoning: false, family: "glm", free: true },
216
+ { id: "glm-4-plus", context: 128000, maxoutput: 16384, reasoning: false, family: "glm" },
217
+ { id: "glm-4-flash", context: 128000, maxoutput: 8192, reasoning: false, family: "glm", free: true },
218
+ ],
219
+ defaults: {
220
+ primary: "devthink",
221
+ maxtokens: 8192,
222
+ temperature: [0, 2, 0.7],
223
+ },
224
+ thinking: {
225
+ defaultlevel: "high",
226
+ param: "thinking",
227
+ twocalls: { threshold: 98304, freshresponseguarantee: true },
228
+ },
229
+ metamodel: {
230
+ id: "devthink",
231
+ contextoverride: 200000,
232
+ maxoutput: 32768,
233
+ maskupstreammodel: true,
234
+ alwaysdisplay: true,
235
+ listedcreated: 1700000000,
236
+ pattern: "fusion meta model over the zai sdk transport",
237
+ },
238
+ context: {
239
+ restoresessionhistory: false,
240
+ truncate: true,
241
+ historylimit: 40,
242
+ truncatemargin: 4096,
243
+ },
244
+ },
245
+ },
246
+ };
247
+
248
+ /* (the gatewayconfig arm once answered a dual default export beside this
249
+ * named seat — the logicfold3 fold converted it to the named export alone,
250
+ * the default retired with the variant file.) */
251
+
252
+ /* ===== block: gatewayviewconfig ===== */
253
+ /**
254
+ * gatewayviewconfig — the user customization layer of the embedded gateway
255
+ * one file one responsibility — only version definitions live here
256
+ * this is the hardcoded v1 v5 configuration the gateway ships with
257
+ *
258
+ * the catalog lives at the repository root beside the engine modules it
259
+ * configures (the family law: page folders carry only the page anchor and
260
+ * the visual components beside it — engine config is root module matter)
261
+ *
262
+ * the library engine at root is universal and dry — it reads a config file
263
+ * every value here is what the user customizes:
264
+ * baseurls — which upstream apis to call
265
+ * models — which models to expose
266
+ * auth — how keys are resolved per method
267
+ * rotation — model rotation strategies
268
+ * retry — backoff and status handling
269
+ * context — session history and truncation
270
+ * thinking — two-calls pattern and budgets
271
+ *
272
+ * create as many versions as you want — v1 through v9 and beyond
273
+ * each version gets all 7 routes generated automatically:
274
+ * chat/completions completions messages responses embeddings keys models
275
+ *
276
+ * the engine config loader (gateway-configloader.ts) probes the standard
277
+ * sol/config.mjs|ts|js locations of the working directory for the definition
278
+ * a deployment loads; this catalog is the shipped example the gateway
279
+ * console page renders — copy it to the location your serve reads, or
280
+ * use the cli to scaffold a fresh config (gateway init) and edit the values
281
+ */
282
+
283
+ /* the gatewaydefinition family moved to the gateway types with the
284
+ * wave/ownership.getry split: the catalog imports the kind from the engine
285
+ * owner (types.ts of this app root) — the os gateway lane keeps its own
286
+ * web-check projection and never leaks into the engine import graph. */
287
+
288
+
289
+ /** the live thinking budgets consumed from the getry engine (pr16): the
290
+ * ladder is owned by getry and every budget map of this catalog derives
291
+ * from the owner's registered rungs — never a second literal copy, never a
292
+ * fixed 7. */
293
+ const ladderbudgets = Object.fromEntries(listlevels().map((rung) => [rung.level, rung.budget])) as Record<
294
+ thinkinglevel,
295
+ number
296
+ >;
297
+
298
+ export const gatewayViewConfig: gatewaydefinition = {
299
+ name: "DevThink Gateway",
300
+ description: "multi provider ai gateway v1 v5 with thinking rotation retry and fusion context",
301
+
302
+ versions: {
303
+ // -----------------------------------------------------------------------
304
+ // v1 — zai sdk keyless transport with 2-calls thinking pattern
305
+ // -----------------------------------------------------------------------
306
+ v1: {
307
+ id: "v1",
308
+ name: "V1 ZAI",
309
+ providername: "zai",
310
+ note: "v1 replica retains token plus chat id functionality calls internal api z ai directly",
311
+ transport: {
312
+ type: "zai-sdk",
313
+ },
314
+ upstreams: [{ name: "zai", baseurl: "https://internal-api.z.ai/v1" }],
315
+ auth: {
316
+ mode: "keylesssdk",
317
+ required: false,
318
+ },
319
+ models: [
320
+ {
321
+ id: "glm-5.3",
322
+ context: 1048576,
323
+ maxoutput: 131072,
324
+ vision: false,
325
+ reasoning: true,
326
+ free: false,
327
+ rank: { score: 56, tier: 1 },
328
+ },
329
+ {
330
+ id: "glm-5.3-flash",
331
+ context: 1048576,
332
+ maxoutput: 131072,
333
+ vision: true,
334
+ reasoning: true,
335
+ free: false,
336
+ rank: { score: 55, tier: 1 },
337
+ },
338
+ {
339
+ id: "glm-5.2",
340
+ context: 1048576,
341
+ maxoutput: 131072,
342
+ vision: false,
343
+ reasoning: true,
344
+ free: true,
345
+ rank: { score: 53, tier: 1 },
346
+ },
347
+ {
348
+ id: "glm-5.1",
349
+ context: 131072,
350
+ maxoutput: 16384,
351
+ vision: false,
352
+ reasoning: true,
353
+ free: true,
354
+ rank: { score: 40, tier: 2 },
355
+ },
356
+ {
357
+ id: "glm-5v",
358
+ context: 131072,
359
+ maxoutput: 16384,
360
+ vision: true,
361
+ reasoning: true,
362
+ free: true,
363
+ rank: { score: 38, tier: 2 },
364
+ },
365
+ {
366
+ id: "glm-4-plus",
367
+ context: 131072,
368
+ maxoutput: 4096,
369
+ vision: false,
370
+ reasoning: true,
371
+ free: true,
372
+ rank: { score: 25, tier: 3 },
373
+ },
374
+ {
375
+ id: "glm-4-flash",
376
+ context: 131072,
377
+ maxoutput: 4096,
378
+ vision: false,
379
+ reasoning: false,
380
+ free: true,
381
+ rank: { score: 15, tier: 4 },
382
+ },
383
+ ],
384
+ defaultmodel: "glm-5.3",
385
+ metamodel: {
386
+ id: "devthink",
387
+ contextoverride: 2300000,
388
+ fallbackcontext: 1048576,
389
+ maxoutput: 98304,
390
+ maskupstreammodel: false,
391
+ alwaysdisplay: false,
392
+ pattern: "2-calls thinking over glm-5.2 backend",
393
+ },
394
+ thinking: {
395
+ defaultlevel: "high",
396
+ budgets: ladderbudgets,
397
+ twocalls: {
398
+ threshold: 98304,
399
+ freshresponseguarantee: true,
400
+ },
401
+ param: "thinking",
402
+ },
403
+ bodybuild: {
404
+ optionalparamspolicy: "always",
405
+ clampmaxtokens: true,
406
+ },
407
+ routes: {
408
+ embeddings: "disabled",
409
+ embeddingsmessage: "zai has no embeddings endpoint",
410
+ },
411
+ headers: {
412
+ useragent: "DevThink-Gateway/1.0",
413
+ },
414
+ },
415
+
416
+ // -----------------------------------------------------------------------
417
+ // v2 — babel town paused with fallback to v1
418
+ // -----------------------------------------------------------------------
419
+ v2: {
420
+ id: "v2",
421
+ name: "V2 Babel",
422
+ providername: "babel",
423
+ note: "service is paused returns 503 fallback to v1 zai",
424
+ paused: true,
425
+ upstreams: [{ name: "babel", baseurl: "https://api.babel.town/v1" }],
426
+ auth: {
427
+ mode: "apikeyheader",
428
+ headername: "x-token",
429
+ keysources: ["ephemeralurl"],
430
+ keyurl: "https://glm.babel.town/api/get_api_key",
431
+ keyexpiryminutes: 60,
432
+ ipbound: true,
433
+ required: false,
434
+ },
435
+ models: [
436
+ {
437
+ id: "babel-glm-5.3",
438
+ upstream: "glm-5.3",
439
+ context: 1048576,
440
+ maxoutput: 131072,
441
+ free: true,
442
+ },
443
+ {
444
+ id: "babel-glm-5.3-flash",
445
+ upstream: "glm-5.3-flash",
446
+ context: 1048576,
447
+ maxoutput: 131072,
448
+ free: true,
449
+ },
450
+ {
451
+ id: "babel-glm-5.2",
452
+ upstream: "glm-5.2",
453
+ context: 1048576,
454
+ maxoutput: 131072,
455
+ free: true,
456
+ },
457
+ {
458
+ id: "babel-devthink",
459
+ upstream: "devthink",
460
+ context: 1048576,
461
+ maxoutput: 131072,
462
+ free: true,
463
+ },
464
+ ],
465
+ defaultmodel: "babel-glm-5.3",
466
+ metamodel: {
467
+ id: "babel-devthink",
468
+ fallbackcontext: 1048576,
469
+ maxoutput: 131072,
470
+ maskupstreammodel: false,
471
+ alwaysdisplay: false,
472
+ },
473
+ routes: {
474
+ embeddings: "disabled",
475
+ embeddingsmessage: "babel has no embeddings endpoint",
476
+ pausedstatus: 503,
477
+ pausedmessage: "babel town is paused — use v1 zai instead",
478
+ fallbackroute: "/v1/chat/completions",
479
+ },
480
+ },
481
+
482
+ // -----------------------------------------------------------------------
483
+ // v3 — nvidia nim with 4-backend rotation db keys retry backoff
484
+ // -----------------------------------------------------------------------
485
+ v3: {
486
+ id: "v3",
487
+ name: "V3 NVIDIA",
488
+ providername: "nvidia",
489
+ note: "nvidia keys round robin devthink meta model rotates",
490
+ upstreams: [{ name: "nvidia", baseurl: "https://integrate.api.nvidia.com/v1" }],
491
+ auth: {
492
+ mode: "bearer",
493
+ keysources: ["db", "env"],
494
+ dbmodel: "nvidiaKey",
495
+ dbtake: 50,
496
+ envvar: "NVIDIA_API_KEY",
497
+ envseparator: ",",
498
+ keyrotation: "roundrobin",
499
+ keylabelformat: "nvapi-key-{idx}",
500
+ required: true,
501
+ minkeylength: 10,
502
+ },
503
+ models: [
504
+ // rotation backends — the devthink meta rotates across these 4
505
+ {
506
+ id: "moonshotai/kimi-k3",
507
+ context: 262144,
508
+ maxoutput: 68000,
509
+ vision: true,
510
+ reasoning: true,
511
+ free: true,
512
+ rank: { score: 60, tier: 1 },
513
+ family: "kimi",
514
+ chattemplatekwargs: { enable_thinking: true },
515
+ },
516
+ {
517
+ id: "deepseek-ai/deepseek-v4-pro-0813",
518
+ context: 1000000,
519
+ maxoutput: 68000,
520
+ vision: false,
521
+ reasoning: true,
522
+ free: true,
523
+ rank: { score: 55, tier: 1 },
524
+ family: "deepseek",
525
+ chattemplatekwargs: { enable_thinking: true },
526
+ },
527
+ {
528
+ id: "meta/muse-glimmer-30b",
529
+ context: 262144,
530
+ maxoutput: 68000,
531
+ vision: true,
532
+ reasoning: true,
533
+ free: true,
534
+ rank: { score: 50, tier: 1 },
535
+ family: "muse",
536
+ chattemplatekwargs: { enable_thinking: true },
537
+ },
538
+ {
539
+ id: "poolside/laguna-xs-2.1",
540
+ context: 262144,
541
+ maxoutput: 68000,
542
+ vision: false,
543
+ reasoning: true,
544
+ free: true,
545
+ rank: { score: 0, tier: 4 },
546
+ family: "laguna",
547
+ chattemplatekwargs: { enable_thinking: true },
548
+ },
549
+ // individual catalog
550
+ {
551
+ id: "deepseek-ai/deepseek-v4-flash-0731",
552
+ context: 1000000,
553
+ maxoutput: 68000,
554
+ vision: false,
555
+ reasoning: true,
556
+ free: true,
557
+ rank: { score: 52, tier: 1 },
558
+ family: "deepseek",
559
+ chattemplatekwargs: { enable_thinking: true },
560
+ },
561
+ {
562
+ id: "nvidia/nemotron-3-ultra-550b-a55b",
563
+ context: 1000000,
564
+ maxoutput: 68000,
565
+ vision: false,
566
+ reasoning: true,
567
+ free: true,
568
+ rank: { score: 38, tier: 2 },
569
+ family: "nemotron",
570
+ chattemplatekwargs: { enable_thinking: true },
571
+ },
572
+ {
573
+ id: "nvidia/nemotron-3.5-lightning-30b-a3b",
574
+ context: 262144,
575
+ maxoutput: 68000,
576
+ vision: false,
577
+ reasoning: true,
578
+ free: true,
579
+ rank: { score: 24, tier: 2 },
580
+ family: "nemotron",
581
+ chattemplatekwargs: { enable_thinking: true },
582
+ },
583
+ {
584
+ id: "google/gemma-4-31b-it",
585
+ context: 262144,
586
+ maxoutput: 68000,
587
+ vision: true,
588
+ reasoning: true,
589
+ free: true,
590
+ rank: { score: 30, tier: 2 },
591
+ family: "gemma",
592
+ chattemplatekwargs: { enable_thinking: true },
593
+ },
594
+ {
595
+ id: "nvidia/nemotron-3-super-120b-a12b",
596
+ context: 1000000,
597
+ maxoutput: 68000,
598
+ vision: false,
599
+ reasoning: true,
600
+ free: true,
601
+ rank: { score: 26, tier: 2 },
602
+ family: "nemotron",
603
+ chattemplatekwargs: { enable_thinking: true },
604
+ },
605
+ {
606
+ id: "openai/gpt-oss-120b",
607
+ context: 131072,
608
+ maxoutput: 68000,
609
+ vision: false,
610
+ reasoning: true,
611
+ free: true,
612
+ rank: { score: 24, tier: 2 },
613
+ family: "gptoss",
614
+ chattemplatekwargs: { enable_thinking: true },
615
+ },
616
+ {
617
+ id: "nvidia/nemotron-3-nano-30b-a3b",
618
+ context: 1000000,
619
+ maxoutput: 68000,
620
+ vision: false,
621
+ reasoning: true,
622
+ free: true,
623
+ family: "nemotron",
624
+ chattemplatekwargs: { enable_thinking: true },
625
+ },
626
+ {
627
+ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
628
+ context: 262144,
629
+ maxoutput: 68000,
630
+ vision: true,
631
+ reasoning: true,
632
+ free: true,
633
+ family: "nemotron",
634
+ chattemplatekwargs: { enable_thinking: true },
635
+ },
636
+ {
637
+ id: "openai/gpt-oss-20b",
638
+ context: 131072,
639
+ maxoutput: 68000,
640
+ vision: false,
641
+ reasoning: true,
642
+ free: true,
643
+ rank: { score: 15, tier: 3 },
644
+ family: "gptoss",
645
+ chattemplatekwargs: { enable_thinking: true },
646
+ },
647
+ {
648
+ id: "mistralai/mistral-nemotron",
649
+ context: 262144,
650
+ maxoutput: 68000,
651
+ vision: false,
652
+ reasoning: true,
653
+ free: true,
654
+ family: "mistral",
655
+ chattemplatekwargs: { enable_thinking: true },
656
+ },
657
+ {
658
+ id: "meta/llama-3.2-90b-vision-instruct",
659
+ context: 131072,
660
+ maxoutput: 68000,
661
+ vision: true,
662
+ reasoning: false,
663
+ free: true,
664
+ family: "llama",
665
+ chattemplatekwargs: {},
666
+ },
667
+ {
668
+ id: "meta/llama-3.2-11b-vision-instruct",
669
+ context: 131072,
670
+ maxoutput: 68000,
671
+ vision: true,
672
+ reasoning: false,
673
+ free: true,
674
+ family: "llama",
675
+ chattemplatekwargs: {},
676
+ },
677
+ ],
678
+ defaultmodel: "devthink",
679
+ rotation: {
680
+ mode: "persession",
681
+ models: [
682
+ "moonshotai/kimi-k3",
683
+ "deepseek-ai/deepseek-v4-pro-0813",
684
+ "meta/muse-glimmer-30b",
685
+ "poolside/laguna-xs-2.1",
686
+ ],
687
+ everynmessages: 6,
688
+ maxmodelrotations: 4,
689
+ rotateonstatus: [529, 404, 410],
690
+ rotateontimeout: true,
691
+ staggernewsessions: false,
692
+ sessionstore: "memory",
693
+ },
694
+ retry: {
695
+ maxretries: 3,
696
+ backoffbasems: 400,
697
+ backoffcapms: 8000,
698
+ jitter: 0.2,
699
+ statuses: [429, 502, 503, 504],
700
+ nonretryable: [400],
701
+ fallback: "none",
702
+ },
703
+ timeout: {
704
+ modelswitchintervalms: 60000,
705
+ requestms: 300000,
706
+ streamms: 2147483647,
707
+ },
708
+ context: {
709
+ restoresessionhistory: true,
710
+ historylimit: 1000,
711
+ truncatemargin: 4096,
712
+ percallfallback: 1048576,
713
+ markshared: true,
714
+ },
715
+ thinking: {
716
+ defaultlevel: "high",
717
+ param: "chattemplatekwargs",
718
+ },
719
+ bodybuild: {
720
+ optionalparamspolicy: "omit-unspecified",
721
+ clampmaxtokens: true,
722
+ maxtokenscap: 68000,
723
+ },
724
+ metamodel: {
725
+ id: "devthink",
726
+ fallbackcontext: 1048576,
727
+ maxoutput: 272000,
728
+ maskupstreammodel: true,
729
+ alwaysdisplay: false,
730
+ pattern: "rotation over 4 nvidia reasoning models 2-calls pattern",
731
+ },
732
+ routes: {
733
+ embeddings: "disabled",
734
+ embeddingsmessage: "nvidia has no embeddings endpoint on this gateway",
735
+ },
736
+ headers: {
737
+ useragent: "DevThink-Gateway/3.0",
738
+ },
739
+ },
740
+
741
+ // -----------------------------------------------------------------------
742
+ // v4 — opencode zen plus kilo anonymous free models cross-provider fallback
743
+ // -----------------------------------------------------------------------
744
+ v4: {
745
+ id: "v4",
746
+ name: "V4 OpenCode Kilo",
747
+ providername: "opencode",
748
+ note: "anonymous free tier no api key required model masking to devthink",
749
+ upstreams: [
750
+ { name: "opencode", baseurl: "https://opencode.ai/zen/v1", fallback: "kilo" },
751
+ { name: "kilo", baseurl: "https://api.kilo.ai/api/gateway", fallback: "opencode" },
752
+ ],
753
+ auth: {
754
+ mode: "anonymous",
755
+ required: false,
756
+ },
757
+ models: [
758
+ // opencode zen free models
759
+ {
760
+ id: "muse-spark-1.2-contributor-free",
761
+ context: 131072,
762
+ maxoutput: 16384,
763
+ vision: false,
764
+ reasoning: true,
765
+ free: true,
766
+ rank: { score: 57, tier: 1 },
767
+ endpoint: "responses",
768
+ },
769
+ {
770
+ id: "deepseek-v4-flash-free",
771
+ context: 1048576,
772
+ maxoutput: 16384,
773
+ vision: false,
774
+ reasoning: true,
775
+ free: true,
776
+ rank: { score: 52, tier: 1 },
777
+ },
778
+ {
779
+ id: "mimo-v2.5-free",
780
+ context: 1048576,
781
+ maxoutput: 32768,
782
+ vision: false,
783
+ reasoning: true,
784
+ free: true,
785
+ rank: { score: 43, tier: 1 },
786
+ },
787
+ {
788
+ id: "nemotron-3-ultra-free",
789
+ context: 1048576,
790
+ maxoutput: 32768,
791
+ vision: false,
792
+ reasoning: true,
793
+ free: true,
794
+ rank: { score: 38, tier: 2 },
795
+ nvidiarouted: true,
796
+ },
797
+ {
798
+ id: "ling-3.0-flash-fin-free",
799
+ context: 262144,
800
+ maxoutput: 32768,
801
+ vision: false,
802
+ reasoning: true,
803
+ free: true,
804
+ rank: { score: 38, tier: 2 },
805
+ },
806
+ {
807
+ id: "nemotron-3.5-lightning-free",
808
+ context: 1048576,
809
+ maxoutput: 32768,
810
+ vision: false,
811
+ reasoning: true,
812
+ free: true,
813
+ rank: { score: 24, tier: 2 },
814
+ nvidiarouted: true,
815
+ },
816
+ {
817
+ id: "laguna-s-2.1-free",
818
+ context: 262144,
819
+ maxoutput: 32768,
820
+ vision: false,
821
+ reasoning: true,
822
+ free: true,
823
+ rank: { score: 0, tier: 4 },
824
+ },
825
+ // kilo free models
826
+ {
827
+ id: "thinkingmachines/inkling:free",
828
+ context: 1048576,
829
+ maxoutput: 262144,
830
+ vision: true,
831
+ reasoning: true,
832
+ free: true,
833
+ },
834
+ {
835
+ id: "tencent/hy3:free",
836
+ context: 262144,
837
+ maxoutput: 128000,
838
+ vision: false,
839
+ reasoning: true,
840
+ free: true,
841
+ },
842
+ {
843
+ id: "thinkingmachines/inkling-small:free",
844
+ context: 1048576,
845
+ maxoutput: 262144,
846
+ vision: true,
847
+ reasoning: true,
848
+ free: true,
849
+ },
850
+ {
851
+ id: "inclusionai/ling-3.0-flash-fin:free",
852
+ context: 262144,
853
+ maxoutput: 32768,
854
+ vision: false,
855
+ reasoning: true,
856
+ free: true,
857
+ },
858
+ {
859
+ id: "nvidia/nemotron-3-ultra-550b-a55b:free",
860
+ context: 1048576,
861
+ maxoutput: 32768,
862
+ vision: false,
863
+ reasoning: true,
864
+ free: true,
865
+ nvidiarouted: true,
866
+ },
867
+ {
868
+ id: "minimax/minimax-m3:free",
869
+ context: 1048576,
870
+ maxoutput: 16384,
871
+ vision: true,
872
+ reasoning: true,
873
+ free: true,
874
+ },
875
+ {
876
+ id: "stepfun/step-3.7-flash:free",
877
+ context: 262144,
878
+ maxoutput: 262144,
879
+ vision: true,
880
+ reasoning: true,
881
+ free: true,
882
+ },
883
+ {
884
+ id: "nvidia/nemotron-3.5-lightning:free",
885
+ context: 1048576,
886
+ maxoutput: 32768,
887
+ vision: false,
888
+ reasoning: true,
889
+ free: true,
890
+ nvidiarouted: true,
891
+ },
892
+ {
893
+ id: "nvidia/nemotron-3-super-120b-a12b:free",
894
+ context: 1048576,
895
+ maxoutput: 32768,
896
+ vision: false,
897
+ reasoning: true,
898
+ free: true,
899
+ nvidiarouted: true,
900
+ },
901
+ {
902
+ id: "cohere/north-mini-code:free",
903
+ context: 256000,
904
+ maxoutput: 64000,
905
+ vision: false,
906
+ reasoning: true,
907
+ free: true,
908
+ },
909
+ {
910
+ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
911
+ context: 256000,
912
+ maxoutput: 65536,
913
+ vision: true,
914
+ reasoning: true,
915
+ free: true,
916
+ nvidiarouted: true,
917
+ },
918
+ {
919
+ id: "liquid/lfm-2.5-2.6b:free",
920
+ context: 65536,
921
+ maxoutput: 8192,
922
+ vision: false,
923
+ reasoning: true,
924
+ free: true,
925
+ },
926
+ {
927
+ id: "minimax/minimax-m2.7:free",
928
+ context: 196608,
929
+ maxoutput: 196608,
930
+ vision: false,
931
+ reasoning: true,
932
+ free: true,
933
+ },
934
+ {
935
+ id: "dots-studio/dots-3-note-preview:free",
936
+ context: 512000,
937
+ maxoutput: 460800,
938
+ vision: true,
939
+ reasoning: true,
940
+ free: true,
941
+ },
942
+ {
943
+ id: "poolside/laguna-s-2.1:free",
944
+ context: 262144,
945
+ maxoutput: 32768,
946
+ vision: false,
947
+ reasoning: true,
948
+ free: true,
949
+ },
950
+ {
951
+ id: "poolside/laguna-xs-2.1:free",
952
+ context: 262144,
953
+ maxoutput: 32768,
954
+ vision: false,
955
+ reasoning: true,
956
+ free: true,
957
+ },
958
+ {
959
+ id: "nvidia/nemotron-3.5-content-safety:free",
960
+ context: 128000,
961
+ maxoutput: 8192,
962
+ vision: true,
963
+ reasoning: false,
964
+ free: true,
965
+ nvidiarouted: true,
966
+ },
967
+ ],
968
+ defaultmodel: "devthink",
969
+ rotation: {
970
+ mode: "persession",
971
+ models: [
972
+ "muse-spark-1.2-contributor-free",
973
+ "deepseek-v4-flash-free",
974
+ "mimo-v2.5-free",
975
+ "nemotron-3-ultra-free",
976
+ "ling-3.0-flash-fin-free",
977
+ "nemotron-3.5-lightning-free",
978
+ "laguna-s-2.1-free",
979
+ "thinkingmachines/inkling:free",
980
+ "tencent/hy3:free",
981
+ "thinkingmachines/inkling-small:free",
982
+ "inclusionai/ling-3.0-flash-fin:free",
983
+ "nvidia/nemotron-3-ultra-550b-a55b:free",
984
+ "minimax/minimax-m3:free",
985
+ "stepfun/step-3.7-flash:free",
986
+ "nvidia/nemotron-3.5-lightning:free",
987
+ "nvidia/nemotron-3-super-120b-a12b:free",
988
+ "cohere/north-mini-code:free",
989
+ "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
990
+ "liquid/lfm-2.5-2.6b:free",
991
+ "minimax/minimax-m2.7:free",
992
+ "dots-studio/dots-3-note-preview:free",
993
+ "poolside/laguna-s-2.1:free",
994
+ "poolside/laguna-xs-2.1:free",
995
+ "nvidia/nemotron-3.5-content-safety:free",
996
+ ],
997
+ everynmessages: 6,
998
+ maxmodelrotations: 1,
999
+ rotateonstatus: [],
1000
+ rotateontimeout: false,
1001
+ staggernewsessions: true,
1002
+ sessionstore: "memory",
1003
+ },
1004
+ retry: {
1005
+ maxretries: 0,
1006
+ backoffbasems: 0,
1007
+ statuses: [],
1008
+ nonretryable: [400],
1009
+ fallbackstatuses: [404, 429, 500, 502, 503, 529],
1010
+ fallback: "crossprovider",
1011
+ },
1012
+ timeout: {
1013
+ requestms: 300000,
1014
+ streamms: 2147483647,
1015
+ },
1016
+ context: {
1017
+ restoresessionhistory: true,
1018
+ historylimit: 1000,
1019
+ truncatemargin: 4096,
1020
+ percallfallback: 1048576,
1021
+ markshared: true,
1022
+ },
1023
+ thinking: {
1024
+ defaultlevel: "high",
1025
+ param: "chattemplatekwargs",
1026
+ },
1027
+ bodybuild: {
1028
+ optionalparamspolicy: "omit-unspecified",
1029
+ clampmaxtokens: false,
1030
+ },
1031
+ metamodel: {
1032
+ id: "devthink",
1033
+ fallbackcontext: 1048576,
1034
+ maxoutput: 32768,
1035
+ maskupstreammodel: true,
1036
+ alwaysdisplay: true,
1037
+ pattern: "24 free models across opencode zen and kilo with cross provider fallback",
1038
+ },
1039
+ routes: {
1040
+ embeddings: "disabled",
1041
+ embeddingsmessage: "v4 free gateways have no embeddings endpoint",
1042
+ },
1043
+ headers: {
1044
+ useragent: "DevThink-Gateway/4.0",
1045
+ },
1046
+ },
1047
+
1048
+ // -----------------------------------------------------------------------
1049
+ // v5 — openrouter free models single env key per-request rotation
1050
+ // -----------------------------------------------------------------------
1051
+ v5: {
1052
+ id: "v5",
1053
+ name: "V5 OpenRouter",
1054
+ providername: "openrouter",
1055
+ note: "openrouter free tier 19 models per-request round-robin",
1056
+ upstreams: [{ name: "openrouter", baseurl: "https://openrouter.ai/api/v1" }],
1057
+ auth: {
1058
+ mode: "bearer",
1059
+ keysources: ["env"],
1060
+ envvar: "OPENROUTER_API_KEY",
1061
+ keyrotation: "single",
1062
+ required: true,
1063
+ minkeylength: 10,
1064
+ signupurl: "https://openrouter.ai",
1065
+ extraheaders: {
1066
+ "http-referer": "https://devthink.ai",
1067
+ "x-title": "DevThink Gateway",
1068
+ },
1069
+ },
1070
+ models: [
1071
+ {
1072
+ id: "z-ai/glm-5.2:free",
1073
+ context: 1048576,
1074
+ maxoutput: 131072,
1075
+ vision: false,
1076
+ reasoning: true,
1077
+ free: true,
1078
+ rank: { score: 53, tier: 1 },
1079
+ exclusive: true,
1080
+ },
1081
+ {
1082
+ id: "minimax/minimax-m3:free",
1083
+ context: 1048576,
1084
+ maxoutput: 16384,
1085
+ vision: true,
1086
+ reasoning: true,
1087
+ free: true,
1088
+ rank: { score: 45, tier: 1 },
1089
+ },
1090
+ {
1091
+ id: "thinkingmachines/inkling:free",
1092
+ context: 1048576,
1093
+ maxoutput: 262144,
1094
+ vision: true,
1095
+ reasoning: true,
1096
+ free: true,
1097
+ },
1098
+ {
1099
+ id: "tencent/hy3:free",
1100
+ context: 262144,
1101
+ maxoutput: 128000,
1102
+ vision: false,
1103
+ reasoning: true,
1104
+ free: true,
1105
+ },
1106
+ {
1107
+ id: "thinkingmachines/inkling-small:free",
1108
+ context: 1048576,
1109
+ maxoutput: 262144,
1110
+ vision: true,
1111
+ reasoning: true,
1112
+ free: true,
1113
+ },
1114
+ {
1115
+ id: "inclusionai/ling-3.0-flash-fin:free",
1116
+ context: 262144,
1117
+ maxoutput: 32768,
1118
+ vision: false,
1119
+ reasoning: true,
1120
+ free: true,
1121
+ },
1122
+ {
1123
+ id: "nvidia/nemotron-3-ultra-550b-a55b:free",
1124
+ context: 1048576,
1125
+ maxoutput: 32768,
1126
+ vision: false,
1127
+ reasoning: true,
1128
+ free: true,
1129
+ nvidiarouted: true,
1130
+ },
1131
+ {
1132
+ id: "stepfun/step-3.7-flash:free",
1133
+ context: 262144,
1134
+ maxoutput: 262144,
1135
+ vision: true,
1136
+ reasoning: true,
1137
+ free: true,
1138
+ },
1139
+ {
1140
+ id: "google/gemma-4-31b-it:free",
1141
+ context: 262144,
1142
+ maxoutput: 32768,
1143
+ vision: true,
1144
+ reasoning: true,
1145
+ free: true,
1146
+ exclusive: true,
1147
+ },
1148
+ {
1149
+ id: "google/gemma-4-26b-a4b-it:free",
1150
+ context: 262144,
1151
+ maxoutput: 32768,
1152
+ vision: true,
1153
+ reasoning: true,
1154
+ free: true,
1155
+ exclusive: true,
1156
+ },
1157
+ {
1158
+ id: "nvidia/nemotron-3-super-120b-a12b:free",
1159
+ context: 1048576,
1160
+ maxoutput: 32768,
1161
+ vision: false,
1162
+ reasoning: true,
1163
+ free: true,
1164
+ nvidiarouted: true,
1165
+ },
1166
+ {
1167
+ id: "nvidia/nemotron-3.5-lightning:free",
1168
+ context: 1048576,
1169
+ maxoutput: 32768,
1170
+ vision: false,
1171
+ reasoning: true,
1172
+ free: true,
1173
+ nvidiarouted: true,
1174
+ },
1175
+ {
1176
+ id: "cohere/north-mini-code:free",
1177
+ context: 256000,
1178
+ maxoutput: 64000,
1179
+ vision: false,
1180
+ reasoning: true,
1181
+ free: true,
1182
+ },
1183
+ {
1184
+ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
1185
+ context: 256000,
1186
+ maxoutput: 65536,
1187
+ vision: true,
1188
+ reasoning: true,
1189
+ free: true,
1190
+ nvidiarouted: true,
1191
+ },
1192
+ {
1193
+ id: "liquid/lfm-2.5-2.6b:free",
1194
+ context: 65536,
1195
+ maxoutput: 8192,
1196
+ vision: false,
1197
+ reasoning: true,
1198
+ free: true,
1199
+ },
1200
+ {
1201
+ id: "minimax/minimax-m2.7:free",
1202
+ context: 196608,
1203
+ maxoutput: 196608,
1204
+ vision: false,
1205
+ reasoning: true,
1206
+ free: true,
1207
+ },
1208
+ {
1209
+ id: "dots-studio/dots-3-note-preview:free",
1210
+ context: 512000,
1211
+ maxoutput: 460800,
1212
+ vision: true,
1213
+ reasoning: true,
1214
+ free: true,
1215
+ },
1216
+ {
1217
+ id: "poolside/laguna-s-2.1:free",
1218
+ context: 262144,
1219
+ maxoutput: 32768,
1220
+ vision: false,
1221
+ reasoning: true,
1222
+ free: true,
1223
+ },
1224
+ {
1225
+ id: "poolside/laguna-xs-2.1:free",
1226
+ context: 262144,
1227
+ maxoutput: 32768,
1228
+ vision: false,
1229
+ reasoning: true,
1230
+ free: true,
1231
+ },
1232
+ ],
1233
+ defaultmodel: "devthink",
1234
+ rotation: {
1235
+ mode: "perrequest",
1236
+ models: [
1237
+ "z-ai/glm-5.2:free",
1238
+ "minimax/minimax-m3:free",
1239
+ "thinkingmachines/inkling:free",
1240
+ "tencent/hy3:free",
1241
+ "thinkingmachines/inkling-small:free",
1242
+ "inclusionai/ling-3.0-flash-fin:free",
1243
+ "nvidia/nemotron-3-ultra-550b-a55b:free",
1244
+ "stepfun/step-3.7-flash:free",
1245
+ "google/gemma-4-31b-it:free",
1246
+ "google/gemma-4-26b-a4b-it:free",
1247
+ "nvidia/nemotron-3-super-120b-a12b:free",
1248
+ "nvidia/nemotron-3.5-lightning:free",
1249
+ "cohere/north-mini-code:free",
1250
+ "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
1251
+ "liquid/lfm-2.5-2.6b:free",
1252
+ "minimax/minimax-m2.7:free",
1253
+ "dots-studio/dots-3-note-preview:free",
1254
+ "poolside/laguna-s-2.1:free",
1255
+ "poolside/laguna-xs-2.1:free",
1256
+ ],
1257
+ everynmessages: 1,
1258
+ maxmodelrotations: 1,
1259
+ staggernewsessions: true,
1260
+ sessionstore: "memory",
1261
+ },
1262
+ retry: {
1263
+ maxretries: 0,
1264
+ statuses: [],
1265
+ nonretryable: [400],
1266
+ fallback: "none",
1267
+ },
1268
+ timeout: {
1269
+ requestms: 300000,
1270
+ streamms: 2147483647,
1271
+ },
1272
+ context: {
1273
+ restoresessionhistory: false,
1274
+ truncate: false,
1275
+ },
1276
+ thinking: {
1277
+ defaultlevel: "high",
1278
+ param: "chattemplatekwargs",
1279
+ },
1280
+ bodybuild: {
1281
+ optionalparamspolicy: "omit-unspecified",
1282
+ clampmaxtokens: false,
1283
+ },
1284
+ metamodel: {
1285
+ id: "devthink",
1286
+ fallbackcontext: 1048576,
1287
+ maxoutput: 32768,
1288
+ maskupstreammodel: true,
1289
+ alwaysdisplay: true,
1290
+ pattern: "19 openrouter free models per-request round-robin",
1291
+ },
1292
+ routes: {
1293
+ embeddings: "disabled",
1294
+ embeddingsmessage: "openrouter has no embeddings endpoint on this gateway",
1295
+ },
1296
+ headers: {
1297
+ useragent: "DevThink-Gateway/5.0",
1298
+ },
1299
+ },
1300
+ },
1301
+ };
1302
+
1303
+ /* (the gatewayviewconfig arm answered the same dual default export shape —
1304
+ * the logicfold3 fold converted it to the named gatewayViewConfig seat
1305
+ * above, the default retired with the variant file.) */
1306
+