@wenathlan/getry 2.0.165 → 2.0.167

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.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/accounts.ts +2087 -0
  3. package/antigravity.ts +2171 -0
  4. package/auth.ts +265 -0
  5. package/cli.ts +3 -3
  6. package/constants.ts +950 -0
  7. package/db.ts +810 -0
  8. package/docs/distributionlanes.md +1 -1
  9. package/docs/features.md +1 -2
  10. package/docs/gateway.md +2 -3
  11. package/docs/getry.md +33 -0
  12. package/engine.ts +1535 -0
  13. package/fingerprint.ts +1461 -0
  14. package/gateway.ts +1306 -0
  15. package/gatewaycheck.ts +142 -0
  16. package/intelligence.ts +169 -0
  17. package/json.ts +932 -0
  18. package/labels.ts +262 -0
  19. package/llm.ts +2709 -0
  20. package/models.ts +4017 -0
  21. package/nodeshim.ts +265 -0
  22. package/oauth.ts +2201 -0
  23. package/package.json +580 -225
  24. package/project.ts +1293 -0
  25. package/providers.ts +3238 -0
  26. package/quota.ts +1891 -0
  27. package/recovery.ts +2434 -0
  28. package/request.ts +4496 -0
  29. package/search.ts +1761 -0
  30. package/server.ts +766 -0
  31. package/streaming.ts +4398 -0
  32. package/{tests → test}/cli.test.ts +1 -1
  33. package/{tests → test}/gateway.test.ts +2 -2
  34. package/{tests → test}/gatewayversions.test.ts +1 -1
  35. package/{tests → test}/intelligence.test.ts +1 -1
  36. package/{tests → test}/keyrotation.test.ts +1 -1
  37. package/{tests → test}/onboardingstate.test.ts +1 -1
  38. package/{tests → test}/providerfixtures.ts +12 -12
  39. package/{tests → test}/researchfixtures.ts +1 -1
  40. package/{tests → test}/sandboxmodality.test.ts +1 -1
  41. package/thinking.ts +416 -0
  42. package/types.ts +809 -0
  43. package/utils.ts +263 -0
  44. package/validate.ts +61 -0
  45. package/versionregistry.ts +1325 -0
  46. /package/{tests → test}/debonairlane.test.ts +0 -0
  47. /package/{tests → test}/design.test.ts +0 -0
  48. /package/{tests → test}/family.test.ts +0 -0
  49. /package/{tests → test}/gatewayserver.ts +0 -0
  50. /package/{tests → test}/jsonpolicy.test.ts +0 -0
  51. /package/{tests → test}/llm.test.ts +0 -0
  52. /package/{tests → test}/modelroute.test.ts +0 -0
  53. /package/{tests → test}/promptlibrary.test.ts +0 -0
  54. /package/{tests → test}/providercli.test.ts +0 -0
  55. /package/{tests → test}/providerconstants.test.ts +0 -0
  56. /package/{tests → test}/providerfingerprint.test.ts +0 -0
  57. /package/{tests → test}/providermodels.test.ts +0 -0
  58. /package/{tests → test}/provideroauth.test.ts +0 -0
  59. /package/{tests → test}/routerotation.test.ts +0 -0
  60. /package/{tests → test}/serverauth.test.ts +0 -0
  61. /package/{tests → test}/serverengine.test.ts +0 -0
  62. /package/{tests → test}/serverproperty.test.ts +0 -0
  63. /package/{tests → test}/serverutils.test.ts +0 -0
  64. /package/{tests → test}/streamfallback.test.ts +0 -0
  65. /package/{tests → test}/thinkingladder.test.ts +0 -0
  66. /package/{tests → test}/torturellm.test.ts +0 -0
package/types.ts ADDED
@@ -0,0 +1,809 @@
1
+ /**
2
+ * types — the gateway engine type families of the getry ownership split
3
+ * (wave/ownership.getry). the llm integration contracts (protocol styles,
4
+ * provider configs, model routes, prompt library, usage accounting) and the
5
+ * gateway engine configuration vocabulary (auth methods, model defs,
6
+ * upstreams, rotation, retry, timeouts, thinking, body building, routes,
7
+ * meta model, transport, db, headers and the top-level gatewayconfig
8
+ * family) moved here from devthink/types.ts — the os module keeps the
9
+ * action/protocol/policy families. the apikeyref of the fetch family moved
10
+ * here with the split (every consumer of the kind is a gateway module since
11
+ * the wave; the os surface no longer references it), while the os-owned
12
+ * contracts the gateway still consumes (policyevaluation of the plan family,
13
+ * secretvaultentry of the security family and tooldef of the mcp tools
14
+ * family) are imported through the devthink library specifier — never
15
+ * copied — so the two modules can never drift apart.
16
+ */
17
+
18
+ import type { ThinkingLevelName } from "@wenathlan/getry/thinking";
19
+
20
+ /** One stored api key reference: name, origin scope, header name and the storage id of the secret; the key material itself never enters any audit trail. Moved from devthink/types.ts with the wave/ownership.getry split — every consumer of the kind is a gateway module. */
21
+ export interface apikeyref {
22
+ name: string;
23
+ origins: string[];
24
+ header: string;
25
+ storageid: string;
26
+ configuredat: number;
27
+ }
28
+
29
+ /**
30
+ * Llm integration contracts of the 1.1.57 family: provider configs with endpoint url, auth reference and model list, model routes that map task kinds to provider models, local model endpoints, openapi style tool briefs, natural language command parsing with intents, model drafted plans with replans and reflection, cost budgets with usage records, the prompt template library and the parse guardrails that keep model output honest.
31
+ * Nothing here hardcodes a provider, an endpoint, a model or a key: every gateway url, base url, model name and parameter is a user configured value, the protocol styles are wire shapes the user picks for interoperability, api keys live behind storage id references and every model drafted plan still passes the same human review the local plans pass.
32
+ */
33
+
34
+ /** The protocol request shapes a user may pick for a provider endpoint: the openai compatible chat completions shape, the openai responses shape, the anthropic messages shape and the google gemini shape. These are wire shapes for interoperability, never provider names, and any gateway speaking one of them works. */
35
+ export type protocolstyle = "chatcompletions" | "responses" | "messages" | "gemini";
36
+
37
+ /** One message of a model conversation: the system, user or assistant role with its content. */
38
+ export interface modelmessage {
39
+ role: "system" | "user" | "assistant";
40
+ content: string;
41
+ }
42
+
43
+ /** One user configured provider of model completions: the endpoint url the user typed, the protocol shape it speaks, the model list the user maintains, the api key reference (never the key material), the extra headers the user reviewed and the availability status of the last test call. */
44
+ export interface providerconfig {
45
+ id: string;
46
+ name: string;
47
+ /** The user configured endpoint url; no default and no built-in provider endpoint ever applies. */
48
+ endpoint: string;
49
+ style: protocolstyle;
50
+ /** The user configured model list; every entry is a free text model name. */
51
+ models: string[];
52
+ /** Reference to the stored api key record; the key material lives in the browser credential store behind its storage id, never in memory files or audit trails. */
53
+ authref?: apikeyref;
54
+ /** Extra headers the user reviewed for gateways that need them; merged over the protocol shape headers. */
55
+ headers?: Record<string, string>;
56
+ status: "available" | "unavailable";
57
+ lastcheckedat?: number;
58
+ /** Optional user configured price per million tokens and its currency unit for the cost accounting of the usage records; absent pricing keeps the recorded cost at zero. */
59
+ costpermilliontokens?: number;
60
+ currency?: string;
61
+ createdat: number;
62
+ }
63
+
64
+ /** One model route entry: the task kind it routes, the provider and model it prefers and the user configured fallback pair for refusals and outages; the revision history tracks every change. */
65
+ export interface modelroute {
66
+ id: string;
67
+ /** The task kind of the route: the internal kinds parsecommand, classifyintent, draftplan, replan, reflect and summarize plus any user defined task kind. */
68
+ kind: string;
69
+ providerid: string;
70
+ model: string;
71
+ fallbackproviderid?: string;
72
+ fallbackmodel?: string;
73
+ revision: number;
74
+ updatedat: number;
75
+ }
76
+
77
+ /** One browser reachable local model endpoint: the endpoint url, the model name, the protocol shape and the optional key reference of gateways that ask one; the health block carries the last check. */
78
+ export interface localmodelconfig {
79
+ endpoint: string;
80
+ model: string;
81
+ style: protocolstyle;
82
+ authref?: apikeyref;
83
+ health?: { checkedat: number; ok: boolean; detail?: string };
84
+ }
85
+
86
+ /** One openapi style tool brief for model consumption: the tool name, the summary, the description, the risk class and the typed parameter list. */
87
+ export interface toolbrief {
88
+ tool: string;
89
+ summary: string;
90
+ description: string;
91
+ risk: string;
92
+ parameters: Array<{ name: string; type: string; description: string; required: boolean }>;
93
+ }
94
+
95
+ /** The intent kinds a natural language command may carry: navigate, extract, fill, monitor, automate and ask. */
96
+ export type intentkind = "navigate" | "extract" | "fill" | "monitor" | "automate" | "ask";
97
+
98
+ /** One entity of a parsed command: the entity name and its value. */
99
+ export interface commandentity {
100
+ name: string;
101
+ value: string;
102
+ }
103
+
104
+ /** One parsed natural language command: the source text, the classified intent, the extracted entities, the confidence between zero and one, the model that parsed it and the parse time. */
105
+ export interface commandparse {
106
+ text: string;
107
+ intent: intentkind;
108
+ entities: commandentity[];
109
+ confidence: number;
110
+ model?: string;
111
+ providerid?: string;
112
+ parsedat: number;
113
+ }
114
+
115
+ /** One model drafted step: the action kind, the optional target and value, the summary and the fresh review marker a replan sets on revised steps. */
116
+ export interface draftstep {
117
+ id: string;
118
+ kind: string;
119
+ target?: string;
120
+ value?: string;
121
+ summary: string;
122
+ /** True on the revised steps of a replan; every marked step needs the fresh human review before it executes. */
123
+ freshreview?: boolean;
124
+ }
125
+
126
+ /** One model drafted plan: the goal, the drafted steps, the open questions the model could not resolve, the lint findings of the grammar check, the model provenance and the review state. A draft never executes until the human review approves it and the plan review approves the plan it produces. */
127
+ export interface plandraft {
128
+ id: string;
129
+ goal: string;
130
+ steps: draftstep[];
131
+ openquestions: string[];
132
+ providerid: string;
133
+ model: string;
134
+ state: "draft" | "approved" | "rejected";
135
+ lintfindings: string[];
136
+ createdat: number;
137
+ }
138
+
139
+ /** One replan record of a failed run: the draft it revises, the completed steps it keeps, the failed steps it replaces, the revised tail that needs fresh review, the failure reason and the model provenance. */
140
+ export interface replanrecord {
141
+ id: string;
142
+ draftid: string;
143
+ completedstepids: string[];
144
+ failedstepids: string[];
145
+ tail: draftstep[];
146
+ reason: string;
147
+ providerid: string;
148
+ model: string;
149
+ state: "pending" | "approved" | "rejected";
150
+ createdat: number;
151
+ }
152
+
153
+ /** One reflection note of an executed step: the step outcome, the lesson learned, the advice for the next step and the model provenance; the running lessons feed the next prompt. */
154
+ export interface reflectnote {
155
+ id: string;
156
+ runid: string;
157
+ stepid: string;
158
+ outcome: string;
159
+ lesson: string;
160
+ advice: string;
161
+ providerid: string;
162
+ model: string;
163
+ createdat: number;
164
+ }
165
+
166
+ /** One cost budget of a run: the optional token ceiling, the optional currency ceiling with its currency, the warning threshold ratio of the 1.1.83 gateway family and the configuration time; every ceiling and threshold is a user choice and an absent ceiling stays unbounded. */
167
+ export interface costbudget {
168
+ runid?: string;
169
+ maxtokens?: number;
170
+ maxcost?: number;
171
+ currency?: string;
172
+ /** Warning threshold ratio between zero and one of the gateway family: the budget tracking warns once the recorded usage crosses the share of its ceiling; an absent threshold never warns. */
173
+ warnratio?: number;
174
+ configuredat: number;
175
+ }
176
+
177
+ /** One usage record of a model call: the run and step it belongs to, the provider, the endpoint and the model called, the prompt, completion and total token counts, the cost in the user configured currency and the local marker. */
178
+ export interface usagerecord {
179
+ id: string;
180
+ runid?: string;
181
+ stepid?: string;
182
+ providerid: string;
183
+ endpoint: string;
184
+ model: string;
185
+ prompttokens: number;
186
+ completiontokens: number;
187
+ totaltokens: number;
188
+ cost: number;
189
+ /** True when the call went to the local model endpoint. */
190
+ local?: boolean;
191
+ /** Session of the call of the 1.1.83 gateway family so the token budget reports its totals per session beside the per run totals. */
192
+ sessionid?: string;
193
+ /** Correlation request id of the 1.1.83 gateway family; every provider call carries one and the audit trail records it. */
194
+ requestid?: string;
195
+ at: number;
196
+ }
197
+
198
+ /** One prompt template of the library: the name, the body with double braced variables, the declared variable list, the version and the change notes of the version. */
199
+ export interface prompttemplate {
200
+ id: string;
201
+ name: string;
202
+ body: string;
203
+ variables: string[];
204
+ version: number;
205
+ notes?: string;
206
+ createdat: number;
207
+ }
208
+
209
+ /** One parse guard of model output: the expected schema of the parsed payload, the retry count before refusal and the refusal markers the user reviews. */
210
+ export interface parseguard {
211
+ schema: Record<string, { type: "string" | "number" | "boolean" | "object" | "array"; required?: boolean }>;
212
+ retries: number;
213
+ refusalmarkers?: string[];
214
+ }
215
+
216
+ /** One model output after the guardrails: the raw text, the parsed payload when it validated, the guard verdict of valid, invalid or refused, the verdict reason and the attempt count. */
217
+ export interface modeloutput {
218
+ raw: string;
219
+ parsed?: Record<string, unknown>;
220
+ verdict: "valid" | "invalid" | "refused";
221
+ reason?: string;
222
+ attempts: number;
223
+ }
224
+
225
+ /** One token of a streamed model answer: the sequence number, the token text and the done marker. */
226
+ export interface tokenstream {
227
+ seq: number;
228
+ text: string;
229
+ done: boolean;
230
+ }
231
+
232
+ /**
233
+ * Model provider gateway contracts of the 1.1.83 family: the four provider adapters (the openai compatible chat completions shape, the anthropic messages shape, the gemini generate content shape and the local ollama runtime), the baseurlconfig one endpoint url per provider the user configures, the per provider key vault behind the secretvault seam, the modellist discovery with its cache window, the capabilityad tool catalog advertisement, the routing of task kinds onto providers with the local fallback, the token budget accounting with its warning threshold and the guardrails over every parsed model answer.
234
+ * Nothing here hardcodes a provider endpoint: the base url of every remote provider is a user configured value with no default, the ollamalocal adapter alone defaults to the localhost machine and never to a cloud url, api keys live behind the vault seam and never inside a payload, a log or an export, and every model drafted plan still passes the same human review.
235
+ */
236
+
237
+ /** The provider adapters of the gateway family: the openai compatible chat completions shape, the anthropic messages shape, the google gemini generate content shape and the local ollama runtime. These are wire shapes for interoperability, never vendor endorsements; any gateway speaking one of them works. */
238
+ export type gatewaykind = "openaicompat" | "anthropicgateway" | "geminigateway" | "ollamalocal";
239
+
240
+ /** One user configured provider gateway: the base url the user typed (no default cloud endpoint ever ships), the optional path prefix gateway deployments prepend, the enable toggle that defaults to disabled, the consent stamp of the first remote call and the key reference behind the vault seam. */
241
+ export interface baseurlconfig {
242
+ providerid: string;
243
+ kind: gatewaykind;
244
+ /** The user configured base url; the ollamalocal adapter alone defaults to the localhost machine address and every remote kind refuses an empty base url. */
245
+ baseurl: string;
246
+ /** Per provider path prefix for gateway deployments that serve one adapter under a namespace; the prefix sits between the base url and the wire path of the adapter. */
247
+ pathprefix?: string;
248
+ /** Per provider enable toggle; every provider ships disabled until the user turns it on. */
249
+ enabled: boolean;
250
+ /** True once the user consented to the first remote call of this provider; a provider without the stamp never leaves the machine. */
251
+ consented?: boolean;
252
+ consentedat?: number;
253
+ /** Reference to the stored api key of this provider; the key material lives behind the vault seam, never inside this record. */
254
+ keyref?: apikeyref;
255
+ /** Optional user configured price per million tokens for the cost accounting of the gateway calls. */
256
+ costpermilliontokens?: number;
257
+ currency?: string;
258
+ updatedat: number;
259
+ }
260
+
261
+ /** One discovered model of a provider: the model id, the display label, the context window hint and the modality hints when the provider offers them. */
262
+ export interface gatewaymodelinfo {
263
+ id: string;
264
+ label?: string;
265
+ /** Context window hint in tokens when the provider offers it. */
266
+ contextwindow?: number;
267
+ /** Modality hints when the provider offers them: text, image, audio, video or embedding entries. */
268
+ modalities?: string[];
269
+ }
270
+
271
+ /** One cached model list of a provider: the models discovered at the fetch time; the configurable refresh window decides whether the cache still serves. */
272
+ export interface modelcacherecord {
273
+ providerid: string;
274
+ models: gatewaymodelinfo[];
275
+ fetchedat: number;
276
+ }
277
+
278
+ /** The structured error surface of the gateway family: every gateway failure carries its code, its plain language message, the retry hint and the request id so the surfaces and the audit trail correlate the failure with its call. */
279
+ export interface gatewayerror {
280
+ code:
281
+ | "noconsent"
282
+ | "notconfigured"
283
+ | "notlocal"
284
+ | "cancelled"
285
+ | "timeout"
286
+ | "ratelimited"
287
+ | "unauthorized"
288
+ | "transport"
289
+ | "parse"
290
+ | "guardrefused";
291
+ message: string;
292
+ /** Plain language hint whether and how a retry may succeed. */
293
+ retryhint?: string;
294
+ /** Milliseconds a rate limited call waited before its next attempt, when the provider answered one. */
295
+ retryafter?: number;
296
+ requestid: string;
297
+ }
298
+
299
+ /** One streamed token of a gateway chat: the sequence number, the token text and the arrival time; the sidepanel chat appends every token as it arrives. */
300
+ export interface gatewaychattoken {
301
+ seq: number;
302
+ text: string;
303
+ at: number;
304
+ }
305
+
306
+ /** One gateway chat exchange: the request id, the provider and model that answered, the prompt text, the streamed tokens, the done marker and the structured error when the call failed; the state never carries key material. */
307
+ export interface gatewaychatstate {
308
+ requestid: string;
309
+ providerid: string;
310
+ kind: gatewaykind;
311
+ model: string;
312
+ prompt: string;
313
+ tokens: gatewaychattoken[];
314
+ done: boolean;
315
+ error?: gatewayerror;
316
+ at: number;
317
+ }
318
+
319
+ /** One cost estimate of a provider and model pair: the projected cost per million tokens with its currency and the recorded totals the projection answers. */
320
+ export interface costestimate {
321
+ providerid: string;
322
+ model: string;
323
+ /** Projected cost of one million tokens at the user configured price; absent pricing keeps the estimate at zero. */
324
+ permillion: number;
325
+ currency?: string;
326
+ recordedtokens: number;
327
+ recordedcost: number;
328
+ }
329
+
330
+ /* === section: the gateway engine configuration vocabulary (the embedded gateway of the grand merge) === */
331
+ // ---------------------------------------------------------------------------
332
+ // thinking levels
333
+ // ---------------------------------------------------------------------------
334
+
335
+ /** thinking levels ordered by budget ascending — the union is consumed from
336
+ * the getry engine (the one owner of the registerable reasoning ladder,
337
+ * pr16 and the pr5 engine freedom fold): the os speaks the owner's
338
+ * ThinkingLevelName and never redeclares the rung names — the rungs are
339
+ * what the person registers (any count), so the ladder can only ever drift
340
+ * in one place. */
341
+ export type thinkinglevel = ThinkingLevelName;
342
+
343
+ // ---------------------------------------------------------------------------
344
+ // auth — 12 methods covering the whole llm api market
345
+ // ---------------------------------------------------------------------------
346
+
347
+ /**
348
+ * gwauthmethod — every authentication pattern found in production llm apis
349
+ * bearer covers ~90 percent of providers (openai nvidia groq mistral deepseek kimi xai etc)
350
+ * apikeyheader covers anthropic (x-api-key) google gemini (x-goog-api-key) azure (api-key)
351
+ * queryparam covers legacy google and saas apis that pass the key in the url
352
+ * basic covers generic rest apis with user colon password base64
353
+ * oauth2clientcredentials covers ibm watsonx azure entra auth0 m2m — token endpoint then bearer
354
+ * jwtsign covers zhipu bigmodel legacy — hs256 signed tokens from keyid dot secret
355
+ * sigv4 covers aws bedrock — aws4-hmac-sha256 request signing
356
+ * hmacsign covers stripe github slack webhook style signatures
357
+ * cookie covers session-cookie authenticated apis
358
+ * mtls covers client certificate mutual tls
359
+ * keylesssdk covers sdk-resolved auth like z-ai-web-dev-sdk (server side config file)
360
+ * anonymous covers keyless free endpoints like opencode zen kilo
361
+ * none covers local servers like ollama
362
+ */
363
+ export type gwauthmethod =
364
+ | "bearer"
365
+ | "apikeyheader"
366
+ | "queryparam"
367
+ | "basic"
368
+ | "oauth2clientcredentials"
369
+ | "jwtsign"
370
+ | "sigv4"
371
+ | "hmacsign"
372
+ | "cookie"
373
+ | "mtls"
374
+ | "keylesssdk"
375
+ | "anonymous"
376
+ | "none";
377
+
378
+ /** where keys are resolved from — order matters first hit wins */
379
+ export type keysource = "db" | "env" | "inline" | "ephemeralurl";
380
+
381
+ /** how multiple keys rotate across requests */
382
+ export type keyrotationmode = "single" | "roundrobin" | "lru";
383
+
384
+ /**
385
+ * authconfig — full authentication configuration for one gateway version
386
+ * supports every auth method via mode plus per-method extras
387
+ */
388
+ export interface authconfig {
389
+ /** authentication method — see gwauthmethod union for the full list */
390
+ mode: gwauthmethod;
391
+ /** header name for apikeyheader mode — e.g. x-api-key x-goog-api-key api-key */
392
+ headername?: string;
393
+ /** query param name for queryparam mode — e.g. key api_key */
394
+ queryparamname?: string;
395
+ /** environment variable holding the key or comma-separated keys — e.g. NVIDIA_API_KEY */
396
+ envvar?: string;
397
+ /** separator used when envvar holds multiple keys — default comma */
398
+ envseparator?: string;
399
+ /** ordered key sources — first source with keys wins per request */
400
+ keysources?: keysource[];
401
+ /** prisma model name for db-sourced keys — e.g. apiKey nvidiaKey */
402
+ dbmodel?: string;
403
+ /** max keys fetched from db per refresh — default 50 */
404
+ dbtake?: number;
405
+ /** key rotation strategy when multiple keys exist */
406
+ keyrotation?: keyrotationmode;
407
+ /** label format for rotated keys — e.g. nvapi-key-{idx} */
408
+ keylabelformat?: string;
409
+ /** reject requests when no key is resolvable — 401 key_required */
410
+ required?: boolean;
411
+ /** minimum key length to be considered valid — default 10 */
412
+ minkeylength?: number;
413
+ /** signup url shown in 401 responses — e.g. https://openrouter.ai */
414
+ signupurl?: string;
415
+ /** ephemeral key endpoint for ephemeralurl source — e.g. babel get_api_key */
416
+ keyurl?: string;
417
+ /** ephemeral key expiry minutes — default 60 */
418
+ keyexpiryminutes?: number;
419
+ /** whether ephemeral keys are ip bound */
420
+ ipbound?: boolean;
421
+ /** ride-along headers sent with every upstream request — e.g. http-referer x-title anthropic-version */
422
+ extraheaders?: Record<string, string>;
423
+ /** ride-along query params sent with every upstream request — e.g. azure api-version */
424
+ extraparams?: Record<string, string>;
425
+ /** oauth2 token endpoint for oauth2clientcredentials mode */
426
+ tokenurl?: string;
427
+ /** oauth2 client id for oauth2clientcredentials mode */
428
+ clientid?: string;
429
+ /** oauth2 client secret env var for oauth2clientcredentials mode */
430
+ clientsecretenv?: string;
431
+ /** jwt key id for jwtsign mode (zhipu keyid.secret format) */
432
+ jwtkeyid?: string;
433
+ /** aws region for sigv4 mode */
434
+ awsignregion?: string;
435
+ /** aws service name for sigv4 mode — e.g. bedrock */
436
+ awsservice?: string;
437
+ /** inline keys for testing or small deployments */
438
+ inlinekeys?: string[];
439
+ }
440
+
441
+ // ---------------------------------------------------------------------------
442
+ // models
443
+ // ---------------------------------------------------------------------------
444
+
445
+ /** intelligence rank from artificial analysis style leaderboards */
446
+ export interface intelligencerank {
447
+ score: number;
448
+ tier: 1 | 2 | 3 | 4;
449
+ }
450
+
451
+ /** a single model entry in a version catalog */
452
+ export interface modeldef {
453
+ /** model id as exposed on the gateway route — e.g. glm-5.3 moonshotai/kimi-k3 */
454
+ id: string;
455
+ /** upstream model id when different from the exposed id — e.g. babel mapping */
456
+ upstream?: string;
457
+ /** context window in tokens */
458
+ context: number;
459
+ /** max output tokens */
460
+ maxoutput: number;
461
+ /** supports vision input */
462
+ vision?: boolean;
463
+ /** supports reasoning output */
464
+ reasoning?: boolean;
465
+ /** free tier model */
466
+ free?: boolean;
467
+ /** leaderboard rank metadata */
468
+ rank?: intelligencerank;
469
+ /** model family — kimi deepseek nemotron etc */
470
+ family?: string;
471
+ /** modality list string — e.g. text image audio */
472
+ modalities?: string;
473
+ /** nvidia-style chat template kwargs — e.g. { enable_thinking: true } */
474
+ chattemplatekwargs?: Record<string, unknown>;
475
+ /** model is routed through nvidia infrastructure — drives pii warning */
476
+ nvidiarouted?: boolean;
477
+ /** exclusive to this provider — openrouter exclusives */
478
+ exclusive?: boolean;
479
+ /** which endpoint this model lives on — chat or responses */
480
+ endpoint?: "chat" | "responses";
481
+ }
482
+
483
+ // ---------------------------------------------------------------------------
484
+ // upstreams
485
+ // ---------------------------------------------------------------------------
486
+
487
+ /** one upstream provider endpoint */
488
+ export interface upstreamdef {
489
+ /** upstream name — opencode kilo nvidia zai openrouter etc */
490
+ name: string;
491
+ /** base url — e.g. https://integrate.api.nvidia.com/v1 */
492
+ baseurl: string;
493
+ /** endpoint path overrides — default /chat/completions */
494
+ endpoints?: {
495
+ chat?: string;
496
+ completions?: string;
497
+ embeddings?: string;
498
+ };
499
+ /** cross-provider fallback target name — v4 pattern opencode to kilo */
500
+ fallback?: string;
501
+ /** auth override per upstream — defaults to the version level auth */
502
+ auth?: authconfig;
503
+ }
504
+
505
+ // ---------------------------------------------------------------------------
506
+ // rotation
507
+ // ---------------------------------------------------------------------------
508
+
509
+ /** rotation mode */
510
+ export type rotationmode = "none" | "persession" | "perrequest";
511
+
512
+ /** model rotation configuration */
513
+ export interface rotationconfig {
514
+ /** rotation mode — none persession perrequest */
515
+ mode: rotationmode;
516
+ /** rotation pool — model ids that the meta model rotates across */
517
+ models: string[];
518
+ /** rotate every n messages within a session — v3 v4 use 6 */
519
+ everynmessages?: number;
520
+ /** max model rotations per request before giving up — v3 uses 4 */
521
+ maxmodelrotations?: number;
522
+ /** http statuses that trigger an immediate model rotation — v3 [529,404,410] */
523
+ rotateonstatus?: number[];
524
+ /** rotate model when the per-attempt timeout fires — v3 true */
525
+ rotateontimeout?: boolean;
526
+ /** stagger new sessions across the rotation pool — v4 devthinkcounter */
527
+ staggernewsessions?: boolean;
528
+ /** where session rotation state lives — memory or durable db */
529
+ sessionstore?: "memory" | "db";
530
+ }
531
+
532
+ // ---------------------------------------------------------------------------
533
+ // retry and backoff
534
+ // ---------------------------------------------------------------------------
535
+
536
+ /** retry and backoff configuration */
537
+ export interface retryconfig {
538
+ /** max retries per model before rotating or failing — v3 uses 3 */
539
+ maxretries?: number;
540
+ /** base backoff in ms — v3 uses 400 */
541
+ backoffbasems?: number;
542
+ /** backoff cap in ms — v3 uses 8000 */
543
+ backoffcapms?: number;
544
+ /** jitter fraction 0 to 1 — v3 uses 0.2 for plus minus 20 percent */
545
+ jitter?: number;
546
+ /** statuses that retry the same model with the next key — v3 [429,502,503,504] */
547
+ statuses?: number[];
548
+ /** statuses that never retry — v3 [400] */
549
+ nonretryable?: number[];
550
+ /** statuses that trigger the fallback strategy — v4 [404,429,500,502,503,529] */
551
+ fallbackstatuses?: number[];
552
+ /** fallback strategy — none or cross-provider swap */
553
+ fallback?: "none" | "crossprovider";
554
+ /** optional circuit breaker — opens after n consecutive failures for cooldown ms */
555
+ circuitbreaker?: {
556
+ failures: number;
557
+ cooldownms: number;
558
+ };
559
+ }
560
+
561
+ // ---------------------------------------------------------------------------
562
+ // timeouts
563
+ // ---------------------------------------------------------------------------
564
+
565
+ /** timeout configuration */
566
+ export interface timeoutconfig {
567
+ /** per model attempt timeout in ms — v3 uses 60000 abort rotates model */
568
+ modelswitchintervalms?: number;
569
+ /** non-stream request timeout in ms — v4 v5 use 300000 */
570
+ requestms?: number;
571
+ /** stream timeout in ms — v4 v5 use 2147483647 infinite */
572
+ streamms?: number;
573
+ /** keepalive interval in ms — default 200 */
574
+ keepaliveintervalms?: number;
575
+ /** suppress keepalive when a write happened within this ms — default 1000 */
576
+ keepalivesuppressms?: number;
577
+ /** maximum duration constant — default 2147483647 */
578
+ maxduration?: number;
579
+ }
580
+
581
+ // ---------------------------------------------------------------------------
582
+ // context and session
583
+ // ---------------------------------------------------------------------------
584
+
585
+ /** context window and session configuration */
586
+ export interface contextconfig {
587
+ /** restore session history from db before each request — v3 v4 true */
588
+ restoresessionhistory?: boolean;
589
+ /** truncate messages to fit per-call context — defaults to true when restoresessionhistory is true */
590
+ truncate?: boolean;
591
+ /** max messages fetched from db history — v3 v4 use 1000 */
592
+ historylimit?: number;
593
+ /** truncate messages to fit per-call context minus this margin — 4096 */
594
+ truncatemargin?: number;
595
+ /** fallback per-call context when model is unknown — 1048576 */
596
+ percallfallback?: number;
597
+ /** mark contextshared flag in db for meta model requests */
598
+ markshared?: boolean;
599
+ }
600
+
601
+ // ---------------------------------------------------------------------------
602
+ // thinking
603
+ // ---------------------------------------------------------------------------
604
+
605
+ /** thinking configuration */
606
+ export interface thinkingconfig {
607
+ /** default thinking level when absent — high */
608
+ defaultlevel?: thinkinglevel;
609
+ /** budget in tokens per level — v1 canonical 7-level map */
610
+ budgets?: Record<thinkinglevel, number>;
611
+ /** two-calls pattern — call 1 thinking then call 2 fresh response */
612
+ twocalls?: {
613
+ /** trigger threshold in tokens — v1 uses 98304 glm max */
614
+ threshold: number;
615
+ /** guarantee thinking differs from response — force call 2 with original messages */
616
+ freshresponseguarantee?: boolean;
617
+ };
618
+ /** how the thinking param is sent — thinking object or chat_template_kwargs */
619
+ param?: "thinking" | "chattemplatekwargs";
620
+ }
621
+
622
+ // ---------------------------------------------------------------------------
623
+ // body building
624
+ // ---------------------------------------------------------------------------
625
+
626
+ /** request body building configuration */
627
+ export interface bodybuildconfig {
628
+ /** only include sampling params when the user specified them — nvidia rejects immutable defaults */
629
+ optionalparamspolicy?: "omit-unspecified" | "always";
630
+ /** clamp max_tokens to model maxoutput — v1 true v4 v5 false */
631
+ clampmaxtokens?: boolean;
632
+ /** advisory max tokens cap reported in metadata — v3 68000 */
633
+ maxtokenscap?: number;
634
+ }
635
+
636
+ // ---------------------------------------------------------------------------
637
+ // routes
638
+ // ---------------------------------------------------------------------------
639
+
640
+ /** per-route enable/disable configuration */
641
+ export interface routesconfig {
642
+ /** embeddings route — disabled when upstream has no embeddings endpoint */
643
+ embeddings?: "enabled" | "disabled";
644
+ /** message shown when embeddings is disabled */
645
+ embeddingsmessage?: string;
646
+ /** paused status code — v2 uses 503 */
647
+ pausedstatus?: number;
648
+ /** paused message body */
649
+ pausedmessage?: string;
650
+ /** fallback route suggested when paused — v2 /v1/chat/completions */
651
+ fallbackroute?: string;
652
+ }
653
+
654
+ // ---------------------------------------------------------------------------
655
+ // meta model
656
+ // ---------------------------------------------------------------------------
657
+
658
+ /** meta model (devthink pattern) configuration */
659
+ export interface metamodelconfig {
660
+ /** meta model id exposed on the route — devthink */
661
+ id: string;
662
+ /** override the computed fusion context — v1 uses 2300000 not the sum */
663
+ contextoverride?: number;
664
+ /** fallback context when models list is empty — 1048576 */
665
+ fallbackcontext?: number;
666
+ /** meta model max output tokens — 32768 */
667
+ maxoutput?: number;
668
+ /** mask upstream model ids to the meta id in all responses */
669
+ maskupstreammodel?: boolean;
670
+ /** always display the meta id even for individually selected models — v4 v5 true v3 false */
671
+ alwaysdisplay?: boolean;
672
+ /** listed created timestamp — 1700000000 */
673
+ listedcreated?: number;
674
+ /** meta pattern description shown in info payloads */
675
+ pattern?: string;
676
+ }
677
+
678
+ // ---------------------------------------------------------------------------
679
+ // transport
680
+ // ---------------------------------------------------------------------------
681
+
682
+ /** transport type — how the gateway reaches the upstream */
683
+ export type transporttype = "fetch" | "zai-sdk" | "custom";
684
+
685
+ /** transport configuration */
686
+ export interface transportconfig {
687
+ /** transport type — fetch for standard rest apis zai-sdk for the zai sdk */
688
+ type: transporttype;
689
+ /** sdk config path for keylesssdk transports — default /etc/.z-ai-config */
690
+ sdkconfigpath?: string;
691
+ /** custom transport module name — must export a create function */
692
+ custommodule?: string;
693
+ }
694
+
695
+ // ---------------------------------------------------------------------------
696
+ // logging
697
+ // ---------------------------------------------------------------------------
698
+
699
+ /** db persistence configuration */
700
+ export interface dbconfig {
701
+ /** database url — libsql http https postgres or file prefix */
702
+ url?: string;
703
+ /** local sqlite path fallback — file:./devthink.db */
704
+ localpath?: string;
705
+ /** prisma model for chat message persistence — chatMessage */
706
+ logmodel?: string;
707
+ /** extra fields to persist per version — v3 rotation fields */
708
+ extrafields?: string[];
709
+ }
710
+
711
+ /** user-agent and header configuration */
712
+ export interface headersconfig {
713
+ /** user-agent sent upstream — e.g. DevThink-Gateway/3.0 */
714
+ useragent?: string;
715
+ /** accept header strategy — sse for stream deleted for non-stream */
716
+ acceptstrategy?: "standard" | "eventstream";
717
+ }
718
+
719
+ // ---------------------------------------------------------------------------
720
+ // top-level gateway config
721
+ // ---------------------------------------------------------------------------
722
+
723
+ /** one gateway version — one route prefix with its own upstream and models */
724
+ export interface gatewayconfig {
725
+ /** version id — path prefix segment — v1 v2 v3 up to v9 and beyond */
726
+ id: string;
727
+ /** display name shown in info payloads */
728
+ name?: string;
729
+ /** provider name persisted to db — zai nvidia opencode kilo openrouter */
730
+ providername: string;
731
+ /** transport configuration */
732
+ transport?: transportconfig;
733
+ /** upstream endpoints — multiple enables cross-provider fallback */
734
+ upstreams: upstreamdef[];
735
+ /** authentication configuration */
736
+ auth: authconfig;
737
+ /** full model catalog exposed on this version */
738
+ models: modeldef[];
739
+ /** default model when request omits one */
740
+ defaultmodel?: string;
741
+ /** default sampling values */
742
+ defaults?: {
743
+ primary?: string;
744
+ fallback?: string;
745
+ maxtokens?: number;
746
+ maxtokensclamp?: number;
747
+ temperature?: [number, number, number];
748
+ topp?: [number, number, number];
749
+ };
750
+ /** paused kill-switch — all post routes return pausedstatus */
751
+ paused?: boolean;
752
+ /** model rotation configuration */
753
+ rotation?: rotationconfig;
754
+ /** retry and backoff configuration */
755
+ retry?: retryconfig;
756
+ /** timeout configuration */
757
+ timeout?: timeoutconfig;
758
+ /** context and session configuration */
759
+ context?: contextconfig;
760
+ /** thinking configuration */
761
+ thinking?: thinkingconfig;
762
+ /** body building configuration */
763
+ bodybuild?: bodybuildconfig;
764
+ /** meta model configuration */
765
+ metamodel: metamodelconfig;
766
+ /** per-route configuration */
767
+ routes?: routesconfig;
768
+ /** header configuration */
769
+ headers?: headersconfig;
770
+ /** db persistence configuration */
771
+ db?: dbconfig;
772
+ /** notes shown in info payloads */
773
+ note?: string;
774
+ }
775
+
776
+ /** the full gateway definition — a map of version id to version config */
777
+ export interface gatewaydefinition {
778
+ versions: Record<string, gatewayconfig>;
779
+ /** gateway display name */
780
+ name?: string;
781
+ /** gateway description */
782
+ description?: string;
783
+ }
784
+
785
+ /** resolved key material after auth resolution */
786
+ export interface resolvedkey {
787
+ key: string;
788
+ label: string;
789
+ source: keysource;
790
+ }
791
+
792
+ /** session rotation state tracked by the engine */
793
+ export interface sessionstate {
794
+ messagecount: number;
795
+ rotationindex: number;
796
+ model: string;
797
+ }
798
+
799
+ /** the 7 route handlers produced by the engine for one version */
800
+ export interface versionhandlers {
801
+ handleinfo: (req: Request) => Promise<Response>;
802
+ handlekeys: (req: Request) => Promise<Response>;
803
+ handlemodels: (req: Request) => Promise<Response>;
804
+ handlechatcompletions: (req: Request) => Promise<Response>;
805
+ handlecompletions: (req: Request) => Promise<Response>;
806
+ handlemessages: (req: Request) => Promise<Response>;
807
+ handleresponses: (req: Request) => Promise<Response>;
808
+ handleembeddings: (req: Request) => Promise<Response>;
809
+ }