omnigateway 0.2.1 → 0.2.2

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 (47) hide show
  1. package/README.md +94 -7
  2. package/bin/omni.js +3542 -1826
  3. package/gateway.js +2430 -824
  4. package/package.json +1 -1
  5. package/public/assets/{Chip-C4X8tf5z.js → Chip-DJwp7gBu.js} +2 -2
  6. package/public/assets/Confirm-CVLz9F7a.js +4 -0
  7. package/public/assets/{CopyValue-B-uR4Js-.js → CopyValue-CNZbWS59.js} +4 -4
  8. package/public/assets/{Field-Ct4SeDZD.js → Field-BDtp692L.js} +8 -8
  9. package/public/assets/Lamp-B65uWKbW.js +25 -0
  10. package/public/assets/{Meter-COdz0dwY.js → Meter-BREBUFGX.js} +2 -2
  11. package/public/assets/{Modal-DMFUHQ-A.js → Modal-DbydSAlp.js} +8 -8
  12. package/public/assets/Rack-Bbo4JfEX.js +151 -0
  13. package/public/assets/{Readout-Bl2kD9Tl.js → Readout-CEAoN5hu.js} +5 -5
  14. package/public/assets/{States-D5Memn8D.js → States-BEKLros0.js} +10 -10
  15. package/public/assets/{Table-DObRatbW.js → Table-BBypbVWj.js} +1 -1
  16. package/public/assets/{Toggle-Dkjlvck5.js → Toggle-BUr71O4J.js} +2 -2
  17. package/public/assets/{TokenBreakdown-oXP49ZTa.js → TokenBreakdown-C1ziK9d1.js} +4 -4
  18. package/public/assets/_app-ByQ1bPbe.js +1 -0
  19. package/public/assets/_app.accounts-BTug_Xfo.js +64 -0
  20. package/public/assets/{_app.console-BVVpryIB.js → _app.console-DKyGL9xx.js} +10 -10
  21. package/public/assets/_app.index-CSw9gmMf.js +62 -0
  22. package/public/assets/_app.keys-07Kbw4RS.js +39 -0
  23. package/public/assets/_app.logs-C9QiV39p.js +32 -0
  24. package/public/assets/_app.models-CDqVrAeF.js +148 -0
  25. package/public/assets/{_app.settings-BN436vI2.js → _app.settings-DmUEeTaP.js} +10 -10
  26. package/public/assets/_app.usage-B1WuMGRr.js +83 -0
  27. package/public/assets/catalog-BBKm8Ih8.js +1 -0
  28. package/public/assets/{dist-CnzT-Ut2.js → dist-Bka7ErcH.js} +1 -1
  29. package/public/assets/index-DJfb1i4P.js +186 -0
  30. package/public/assets/{login-2LpCZOtB.js → login-DKZYqRh0.js} +8 -8
  31. package/public/assets/queries-D8LJNQpL.js +144 -0
  32. package/public/assets/shared-CIhZ6FCO.js +84 -0
  33. package/public/assets/{trash-2-Da6cLgPn.js → trash-2-CLYNAAJA.js} +1 -1
  34. package/public/index.html +2 -2
  35. package/public/assets/Confirm-BnmH8Gn0.js +0 -4
  36. package/public/assets/Lamp-CBOwqG5K.js +0 -25
  37. package/public/assets/Rack-DAbY9x1I.js +0 -151
  38. package/public/assets/_app-Brc2wQZm.js +0 -1
  39. package/public/assets/_app.accounts-I9RXUiyi.js +0 -54
  40. package/public/assets/_app.index-83Ig4FUL.js +0 -62
  41. package/public/assets/_app.keys-KeP6L4g_.js +0 -39
  42. package/public/assets/_app.logs-B5oh01Ls.js +0 -32
  43. package/public/assets/_app.models-BuOFMZUN.js +0 -144
  44. package/public/assets/_app.usage-C528VOia.js +0 -166
  45. package/public/assets/catalog-kJ53n_fc.js +0 -1
  46. package/public/assets/index-CE-KQ-ju.js +0 -172
  47. package/public/assets/queries-1zRLkX-Q.js +0 -144
package/gateway.js CHANGED
@@ -4683,8 +4683,8 @@ class FileTypeParser {
4683
4683
  if (jsonSize > 12 && this.buffer.length >= jsonSize + 16) {
4684
4684
  try {
4685
4685
  const header = new TextDecoder().decode(this.buffer.subarray(16, jsonSize + 16));
4686
- const json5 = JSON.parse(header);
4687
- if (json5.files) {
4686
+ const json7 = JSON.parse(header);
4687
+ if (json7.files) {
4688
4688
  return {
4689
4689
  ext: "asar",
4690
4690
  mime: "application/x-asar"
@@ -5295,17 +5295,24 @@ function createAdminAuth(store, opts) {
5295
5295
  }
5296
5296
  };
5297
5297
  }
5298
+ // packages/ir/src/betas.ts
5299
+ var CONTEXT_1M_BETA = "context-1m-2025-08-07";
5300
+ var CONTEXT_1M_TOKENS = 1e6;
5298
5301
  // packages/ir/src/capabilities.ts
5299
5302
  var ANTHROPIC_NATIVE_TOOLS = {
5300
5303
  anthropic: true,
5301
5304
  openai: false,
5302
5305
  kimi: false,
5306
+ kilo: false,
5307
+ grok: false,
5303
5308
  custom: false
5304
5309
  };
5305
5310
  var PROVIDER_CAPABILITIES = {
5306
5311
  anthropic: { tools: true, images: true, reasoning: true },
5307
5312
  openai: { tools: true, images: true, reasoning: true },
5308
5313
  kimi: { tools: true, images: false, reasoning: false },
5314
+ kilo: { tools: true, images: true, reasoning: true },
5315
+ grok: { tools: true, images: true, reasoning: true },
5309
5316
  custom: { tools: true, images: true, reasoning: true }
5310
5317
  };
5311
5318
  // packages/ir/src/errors.ts
@@ -5387,6 +5394,7 @@ var FIELD_ORDER = [
5387
5394
  "count",
5388
5395
  "rawCount",
5389
5396
  "dailyCount",
5397
+ "quotaSampleCount",
5390
5398
  "host",
5391
5399
  "port",
5392
5400
  "path",
@@ -5720,9 +5728,50 @@ function loadConfig(env) {
5720
5728
  logFile: logFile === undefined || logFile.length === 0 ? null : logFile
5721
5729
  };
5722
5730
  }
5723
- // packages/providers/src/betas.ts
5724
- var CONTEXT_1M_BETA = "context-1m-2025-08-07";
5725
- var CONTEXT_1M_TOKENS = 1e6;
5731
+ // packages/control/src/oauth/pending.ts
5732
+ function createPendingFlows(opts) {
5733
+ const flows = new Map;
5734
+ const expired = (entry) => entry.expiresAt <= opts.now();
5735
+ return {
5736
+ put(flow) {
5737
+ const id = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString("base64url");
5738
+ flows.set(id, { flow, expiresAt: opts.now() + opts.ttlMs });
5739
+ return id;
5740
+ },
5741
+ take(id) {
5742
+ const entry = flows.get(id);
5743
+ if (entry === undefined)
5744
+ return null;
5745
+ flows.delete(id);
5746
+ return expired(entry) ? null : entry.flow;
5747
+ },
5748
+ peek(id) {
5749
+ const entry = flows.get(id);
5750
+ if (entry === undefined || expired(entry))
5751
+ return null;
5752
+ return entry.flow;
5753
+ },
5754
+ byState(state) {
5755
+ if (state.trim().length === 0)
5756
+ return null;
5757
+ for (const [id, entry] of flows) {
5758
+ if (entry.flow.pending.state === state) {
5759
+ return expired(entry) ? null : { ...entry.flow, id };
5760
+ }
5761
+ }
5762
+ return null;
5763
+ },
5764
+ sweep() {
5765
+ for (const [id, entry] of flows) {
5766
+ if (expired(entry))
5767
+ flows.delete(id);
5768
+ }
5769
+ },
5770
+ size() {
5771
+ return flows.size;
5772
+ }
5773
+ };
5774
+ }
5726
5775
 
5727
5776
  // packages/providers/src/body.ts
5728
5777
  var BODY_ORDER = {
@@ -5757,6 +5806,32 @@ var BODY_ORDER = {
5757
5806
  "metadata"
5758
5807
  ],
5759
5808
  kimi: ["model", "messages", "tools", "tool_choice", "max_tokens", "temperature", "stream"],
5809
+ kilo: [
5810
+ "model",
5811
+ "messages",
5812
+ "tools",
5813
+ "tool_choice",
5814
+ "max_tokens",
5815
+ "temperature",
5816
+ "reasoning",
5817
+ "stream"
5818
+ ],
5819
+ grok: [
5820
+ "model",
5821
+ "stream",
5822
+ "input",
5823
+ "instructions",
5824
+ "store",
5825
+ "reasoning",
5826
+ "prompt_cache_key",
5827
+ "tools",
5828
+ "tool_choice",
5829
+ "include",
5830
+ "service_tier",
5831
+ "client_metadata",
5832
+ "parallel_tool_calls",
5833
+ "metadata"
5834
+ ],
5760
5835
  custom: []
5761
5836
  };
5762
5837
  function orderFields(obj, order) {
@@ -5835,6 +5910,7 @@ function signAnthropicBody(json) {
5835
5910
  // packages/providers/src/anthropic/models.ts
5836
5911
  var ANTHROPIC_MODELS = {
5837
5912
  defaultModel: "claude-opus-5",
5913
+ authTypes: ["oauth", "apiKey"],
5838
5914
  models: [
5839
5915
  {
5840
5916
  id: "claude-fable-5",
@@ -5873,9 +5949,247 @@ function anthropicReasoningForm(model) {
5873
5949
  return ANTHROPIC_MODELS.models.find((m) => m.id === id)?.reasoningForm ?? "adaptive";
5874
5950
  }
5875
5951
 
5952
+ // packages/providers/src/grok/models.ts
5953
+ var GROK_MODELS = {
5954
+ defaultModel: "grok-4.6",
5955
+ authTypes: ["oauth", "apiKey"],
5956
+ models: [
5957
+ {
5958
+ id: "grok-4.6",
5959
+ label: "Grok 4.6",
5960
+ pricing: { input: 2, output: 6, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
5961
+ limits: { contextWindow: 500000, maxOutputTokens: 128000 }
5962
+ },
5963
+ {
5964
+ id: "grok-4.5",
5965
+ label: "Grok 4.5",
5966
+ pricing: { input: 2, output: 6, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
5967
+ limits: { contextWindow: 500000, maxOutputTokens: 128000 }
5968
+ },
5969
+ {
5970
+ id: "grok-4.3",
5971
+ label: "Grok 4.3",
5972
+ pricing: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
5973
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
5974
+ },
5975
+ {
5976
+ id: "grok-4.20-0309-reasoning",
5977
+ label: "Grok 4.20 \u2014 reasoning",
5978
+ pricing: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
5979
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
5980
+ },
5981
+ {
5982
+ id: "grok-4.20-0309-non-reasoning",
5983
+ label: "Grok 4.20 \u2014 non-reasoning",
5984
+ pricing: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
5985
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
5986
+ },
5987
+ {
5988
+ id: "grok-4.20-multi-agent-0309",
5989
+ label: "Grok 4.20 \u2014 multi-agent",
5990
+ pricing: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
5991
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
5992
+ }
5993
+ ]
5994
+ };
5995
+
5996
+ // packages/providers/src/kilo/models.ts
5997
+ var KILO_MODELS = {
5998
+ defaultModel: "anthropic/claude-sonnet-5",
5999
+ authTypes: ["oauth", "apiKey"],
6000
+ models: [
6001
+ {
6002
+ id: "anthropic/claude-fable-5",
6003
+ label: "Claude Fable 5",
6004
+ pricing: { input: 10, output: 50, cacheRead: 1, cacheWrite5m: 12.5, cacheWrite1h: 12.5 },
6005
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
6006
+ },
6007
+ {
6008
+ id: "anthropic/claude-opus-5",
6009
+ label: "Claude Opus 5",
6010
+ pricing: { input: 5, output: 25, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 6.25 },
6011
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
6012
+ },
6013
+ {
6014
+ id: "anthropic/claude-sonnet-5",
6015
+ label: "Claude Sonnet 5",
6016
+ pricing: { input: 2, output: 10, cacheRead: 0.2, cacheWrite5m: 2.5, cacheWrite1h: 2.5 },
6017
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
6018
+ },
6019
+ {
6020
+ id: "anthropic/claude-haiku-4.5",
6021
+ label: "Claude Haiku 4.5",
6022
+ pricing: { input: 1, output: 5, cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 1.25 },
6023
+ limits: { contextWindow: 200000, maxOutputTokens: 64000 }
6024
+ },
6025
+ {
6026
+ id: "openai/gpt-5.6-sol",
6027
+ label: "GPT-5.6 Sol",
6028
+ pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 6.25 },
6029
+ limits: { contextWindow: 1050000, maxOutputTokens: 128000 }
6030
+ },
6031
+ {
6032
+ id: "openai/gpt-5.6-terra",
6033
+ label: "GPT-5.6 Terra",
6034
+ pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 2.5, cacheWrite1h: 2.5 },
6035
+ limits: { contextWindow: 1050000, maxOutputTokens: 128000 }
6036
+ },
6037
+ {
6038
+ id: "openai/gpt-5.6-luna",
6039
+ label: "GPT-5.6 Luna",
6040
+ pricing: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite5m: 0.25, cacheWrite1h: 0.25 },
6041
+ limits: { contextWindow: 1050000, maxOutputTokens: 128000 }
6042
+ },
6043
+ {
6044
+ id: "google/gemini-3.1-pro-preview",
6045
+ label: "Gemini 3.1 Pro Preview",
6046
+ pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 0.375, cacheWrite1h: 0.375 },
6047
+ limits: { contextWindow: 1048576, maxOutputTokens: 65536 }
6048
+ },
6049
+ {
6050
+ id: "google/gemini-3.7-flash",
6051
+ label: "Gemini 3.7 Flash",
6052
+ pricing: {
6053
+ input: 0.75,
6054
+ output: 3.75,
6055
+ cacheRead: 0.075,
6056
+ cacheWrite5m: 0.041667,
6057
+ cacheWrite1h: 0.041667
6058
+ },
6059
+ limits: { contextWindow: 1048576, maxOutputTokens: 65536 }
6060
+ },
6061
+ {
6062
+ id: "moonshotai/kimi-k3",
6063
+ label: "Kimi K3",
6064
+ pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
6065
+ limits: { contextWindow: 1048576, maxOutputTokens: 131072 }
6066
+ },
6067
+ {
6068
+ id: "nvidia/nemotron-3-ultra-550b-a55b:free",
6069
+ label: "Nemotron 3 Ultra 550B \u2014 free",
6070
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6071
+ limits: { contextWindow: 1e6, maxOutputTokens: 65536 },
6072
+ auth: ["apiKey"]
6073
+ },
6074
+ {
6075
+ id: "nvidia/nemotron-3.5-lightning:free",
6076
+ label: "Nemotron 3.5 Lightning \u2014 free",
6077
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6078
+ limits: { contextWindow: 1e6, maxOutputTokens: 65536 },
6079
+ auth: ["apiKey"]
6080
+ },
6081
+ {
6082
+ id: "dots-studio/dots-3-note-preview:free",
6083
+ label: "Dots 3 Note Preview \u2014 free",
6084
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6085
+ limits: { contextWindow: 512000, maxOutputTokens: 512000 },
6086
+ auth: ["apiKey"]
6087
+ },
6088
+ {
6089
+ id: "cohere/north-mini-code:free",
6090
+ label: "North Mini Code \u2014 free",
6091
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6092
+ limits: { contextWindow: 256000, maxOutputTokens: 64000 },
6093
+ auth: ["apiKey"]
6094
+ },
6095
+ {
6096
+ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
6097
+ label: "Nemotron 3 Nano Omni 30B Reasoning \u2014 free",
6098
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6099
+ limits: { contextWindow: 256000, maxOutputTokens: 65536 },
6100
+ auth: ["apiKey"]
6101
+ },
6102
+ {
6103
+ id: "stepfun/step-3.7-flash:free",
6104
+ label: "Step 3.7 Flash \u2014 free",
6105
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6106
+ limits: { contextWindow: 262144, maxOutputTokens: 262144 },
6107
+ auth: ["apiKey"]
6108
+ },
6109
+ {
6110
+ id: "nvidia/nemotron-3-super-120b-a12b:free",
6111
+ label: "Nemotron 3 Super 120B \u2014 free",
6112
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6113
+ limits: { contextWindow: 262144, maxOutputTokens: 262144 },
6114
+ auth: ["apiKey"]
6115
+ },
6116
+ {
6117
+ id: "tencent/hy3:free",
6118
+ label: "Tencent HY3 \u2014 free",
6119
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6120
+ limits: { contextWindow: 262144, maxOutputTokens: 128000 },
6121
+ auth: ["apiKey"]
6122
+ },
6123
+ {
6124
+ id: "poolside/laguna-s-2.1:free",
6125
+ label: "Laguna S 2.1 \u2014 free",
6126
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6127
+ limits: { contextWindow: 262144, maxOutputTokens: 32768 },
6128
+ auth: ["apiKey"]
6129
+ },
6130
+ {
6131
+ id: "poolside/laguna-xs-2.1:free",
6132
+ label: "Laguna XS 2.1 \u2014 free",
6133
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6134
+ limits: { contextWindow: 262144, maxOutputTokens: 32768 },
6135
+ auth: ["apiKey"]
6136
+ },
6137
+ {
6138
+ id: "liquid/lfm-2.5-2.6b:free",
6139
+ label: "LFM 2.5 2.6B \u2014 free",
6140
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6141
+ limits: { contextWindow: 128000, maxOutputTokens: 8192 },
6142
+ auth: ["apiKey"]
6143
+ },
6144
+ {
6145
+ id: "nvidia/nemotron-3.5-content-safety:free",
6146
+ label: "Nemotron 3.5 Content Safety \u2014 free",
6147
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6148
+ limits: { contextWindow: 128000, maxOutputTokens: 8192 },
6149
+ auth: ["apiKey"]
6150
+ },
6151
+ {
6152
+ id: "kilo-auto/frontier",
6153
+ label: "Kilo Auto \u2014 Frontier",
6154
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6155
+ limits: { contextWindow: 1e6, maxOutputTokens: 128000 },
6156
+ auth: ["apiKey"]
6157
+ },
6158
+ {
6159
+ id: "kilo-auto/balanced",
6160
+ label: "Kilo Auto \u2014 Balanced",
6161
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6162
+ limits: { contextWindow: 1e6, maxOutputTokens: 65536 },
6163
+ auth: ["apiKey"]
6164
+ },
6165
+ {
6166
+ id: "kilo-auto/efficient",
6167
+ label: "Kilo Auto \u2014 Efficient",
6168
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6169
+ limits: { contextWindow: 1e6, maxOutputTokens: 65536 },
6170
+ auth: ["apiKey"]
6171
+ },
6172
+ {
6173
+ id: "kilo-auto/small",
6174
+ label: "Kilo Auto \u2014 Small",
6175
+ pricing: { input: 0.05, output: 0.4, cacheRead: 0.005, cacheWrite5m: 0, cacheWrite1h: 0 },
6176
+ limits: { contextWindow: 262144, maxOutputTokens: 32768 },
6177
+ auth: ["apiKey"]
6178
+ },
6179
+ {
6180
+ id: "kilo-auto/free",
6181
+ label: "Kilo Auto \u2014 Free",
6182
+ pricing: { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 },
6183
+ limits: { contextWindow: 256000, maxOutputTokens: 1e4 },
6184
+ auth: ["apiKey"]
6185
+ }
6186
+ ]
6187
+ };
6188
+
5876
6189
  // packages/providers/src/kimi/models.ts
5877
6190
  var KIMI_MODELS = {
5878
6191
  defaultModel: "k3-256k",
6192
+ authTypes: ["oauth", "apiKey"],
5879
6193
  models: [
5880
6194
  {
5881
6195
  id: "k3-256k",
@@ -5907,6 +6221,7 @@ var KIMI_MODELS = {
5907
6221
  // packages/providers/src/openai/models.ts
5908
6222
  var OPENAI_MODELS = {
5909
6223
  defaultModel: "gpt-5.6",
6224
+ authTypes: ["oauth", "apiKey"],
5910
6225
  models: [
5911
6226
  {
5912
6227
  id: "gpt-5.6",
@@ -5944,11 +6259,17 @@ var PROVIDER_MODEL_CATALOG = {
5944
6259
  anthropic: ANTHROPIC_MODELS,
5945
6260
  openai: OPENAI_MODELS,
5946
6261
  kimi: KIMI_MODELS,
5947
- custom: { defaultModel: "", models: [] }
6262
+ kilo: KILO_MODELS,
6263
+ grok: GROK_MODELS,
6264
+ custom: { defaultModel: "", authTypes: ["apiKey"], models: [] }
5948
6265
  };
5949
6266
  function catalogPricing(provider, model) {
5950
6267
  return PROVIDER_MODEL_CATALOG[provider]?.models.find((entry) => entry.id === model)?.pricing ?? null;
5951
6268
  }
6269
+ function catalogModelAuths(provider, model) {
6270
+ const entry = PROVIDER_MODEL_CATALOG[provider];
6271
+ return entry.models.find((choice) => choice.id === model)?.auth ?? entry.authTypes;
6272
+ }
5952
6273
  function catalogLimits(provider, model, auth = "apiKey") {
5953
6274
  const entry = PROVIDER_MODEL_CATALOG[provider]?.models.find((choice) => choice.id === model);
5954
6275
  if (entry === undefined)
@@ -6036,6 +6357,9 @@ function stainlessHost(platform, arch) {
6036
6357
  const os = platform === "darwin" ? "MacOS" : platform === "linux" ? "Linux" : platform === "win32" ? "Windows" : "Unknown";
6037
6358
  return { os, arch };
6038
6359
  }
6360
+ function grokHost(platform, arch) {
6361
+ return { os: platform.toLowerCase(), arch: arch === "arm64" ? "aarch64" : arch };
6362
+ }
6039
6363
  function orderHeaders(pairs, order) {
6040
6364
  const remaining = [...pairs];
6041
6365
  const out = [];
@@ -6154,10 +6478,64 @@ var kimi = {
6154
6478
  "Content-Length"
6155
6479
  ]
6156
6480
  };
6481
+ var KILO_CLI_VERSION = env("OMNI_KILO_CLI_VERSION", "4.140.0");
6482
+ var kilo = {
6483
+ headers: [
6484
+ ["User-Agent", env("OMNI_UA_KILO", `Kilo-Code/${KILO_CLI_VERSION}`)],
6485
+ ["X-KILOCODE-EDITORNAME", env("OMNI_KILO_EDITOR_NAME", "vscode")],
6486
+ ["Accept", "text/event-stream"]
6487
+ ],
6488
+ order: [
6489
+ "Host",
6490
+ "Content-Type",
6491
+ "Authorization",
6492
+ "X-Kilocode-OrganizationID",
6493
+ "X-KILOCODE-EDITORNAME",
6494
+ "User-Agent",
6495
+ "Accept",
6496
+ "Accept-Encoding",
6497
+ "Content-Length"
6498
+ ]
6499
+ };
6500
+ var GROK_CLI_VERSION = env("OMNI_GROK_CLI_VERSION", "0.2.120");
6501
+ var grokUa = grokHost(process.platform, process.arch);
6502
+ var grok = {
6503
+ headers: [
6504
+ [
6505
+ "User-Agent",
6506
+ env("OMNI_UA_GROK", `grok-shell/${GROK_CLI_VERSION} (${grokUa.os}; ${grokUa.arch})`)
6507
+ ],
6508
+ ["x-grok-client-identifier", "grok-shell"],
6509
+ ["x-grok-client-version", GROK_CLI_VERSION],
6510
+ ["x-grok-client-mode", "headless"],
6511
+ ["Accept", "text/event-stream"]
6512
+ ],
6513
+ order: [
6514
+ "Host",
6515
+ "Content-Type",
6516
+ "Authorization",
6517
+ "X-XAI-Token-Auth",
6518
+ "x-authenticateresponse",
6519
+ "x-grok-client-identifier",
6520
+ "x-grok-client-version",
6521
+ "x-grok-client-mode",
6522
+ "x-grok-agent-id",
6523
+ "x-grok-req-id",
6524
+ "x-grok-conv-id",
6525
+ "x-grok-session-id",
6526
+ "x-grok-model-override",
6527
+ "User-Agent",
6528
+ "Accept",
6529
+ "Accept-Encoding",
6530
+ "Content-Length"
6531
+ ]
6532
+ };
6157
6533
  var PROFILES = {
6158
6534
  anthropic: { ...anthropic, order: envOrder("OMNI_ORDER_ANTHROPIC", anthropic.order) },
6159
6535
  openai: { ...openai, order: envOrder("OMNI_ORDER_OPENAI", openai.order) },
6160
6536
  kimi: { ...kimi, order: envOrder("OMNI_ORDER_KIMI", kimi.order) },
6537
+ kilo: { ...kilo, order: envOrder("OMNI_ORDER_KILO", kilo.order) },
6538
+ grok: { ...grok, order: envOrder("OMNI_ORDER_GROK", grok.order) },
6161
6539
  custom: { headers: [], order: [] }
6162
6540
  };
6163
6541
 
@@ -6874,19 +7252,19 @@ var anthropicAdapter = {
6874
7252
  ["anthropic-version", API_VERSION],
6875
7253
  ["Accept", "text/event-stream"]
6876
7254
  ];
6877
- const betas = new Set(req.request.betas ?? []);
7255
+ const betas2 = new Set(req.request.betas ?? []);
6878
7256
  const notes = [...degradations];
6879
- if (betas.has(CONTEXT_1M_BETA)) {
7257
+ if (betas2.has(CONTEXT_1M_BETA)) {
6880
7258
  const limits = catalogLimits("anthropic", req.model, oauth ? "oauth" : "apiKey");
6881
7259
  const window2 = limits?.contextWindow;
6882
7260
  if (window2 !== undefined && window2 < CONTEXT_1M_TOKENS) {
6883
- betas.delete(CONTEXT_1M_BETA);
7261
+ betas2.delete(CONTEXT_1M_BETA);
6884
7262
  notes.push("anthropic:context-1m-dropped");
6885
7263
  }
6886
7264
  }
6887
7265
  if (oauth) {
6888
7266
  protocol.push(["Authorization", `Bearer ${req.credentials.accessToken}`]);
6889
- betas.add(OAUTH_BETA);
7267
+ betas2.add(OAUTH_BETA);
6890
7268
  } else if (req.credentials.apiKey !== null) {
6891
7269
  protocol.push(["x-api-key", req.credentials.apiKey]);
6892
7270
  } else {
@@ -6894,8 +7272,8 @@ var anthropicAdapter = {
6894
7272
  provider: "anthropic"
6895
7273
  });
6896
7274
  }
6897
- if (betas.size > 0)
6898
- protocol.push(["anthropic-beta", [...betas].join(",")]);
7275
+ if (betas2.size > 0)
7276
+ protocol.push(["anthropic-beta", [...betas2].join(",")]);
6899
7277
  const profile = PROFILES.anthropic;
6900
7278
  const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
6901
7279
  const bodyString = signAnthropicBody(JSON.stringify(orderFields(withSystem, BODY_ORDER.anthropic)));
@@ -6931,13 +7309,13 @@ function json2(data) {
6931
7309
  }
6932
7310
  async function* decodeChat(messages) {
6933
7311
  let started = false;
6934
- let textOpen = false;
6935
- let textIndex;
6936
7312
  let done = false;
6937
7313
  let stopReason = "endTurn";
6938
7314
  let usage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
6939
7315
  const toolIndex = new Map;
6940
7316
  let nextIndex = 0;
7317
+ let openKind;
7318
+ let openIndex = 0;
6941
7319
  for await (const msg of messages) {
6942
7320
  if (msg.data === "[DONE]") {
6943
7321
  done = true;
@@ -6959,14 +7337,16 @@ async function* decodeChat(messages) {
6959
7337
  continue;
6960
7338
  const delta = choice.delta ?? {};
6961
7339
  if (typeof delta.content === "string" && delta.content.length > 0) {
6962
- if (!textOpen) {
6963
- textOpen = true;
6964
- textIndex = nextIndex++;
6965
- yield { type: "blockStart", index: textIndex, block: { type: "text" } };
7340
+ if (openKind !== "text") {
7341
+ if (openKind !== undefined)
7342
+ yield { type: "blockEnd", index: openIndex };
7343
+ openKind = "text";
7344
+ openIndex = nextIndex++;
7345
+ yield { type: "blockStart", index: openIndex, block: { type: "text" } };
6966
7346
  }
6967
7347
  yield {
6968
7348
  type: "blockDelta",
6969
- index: textIndex ?? 0,
7349
+ index: openIndex,
6970
7350
  delta: { type: "text", text: delta.content }
6971
7351
  };
6972
7352
  }
@@ -6974,8 +7354,12 @@ async function* decodeChat(messages) {
6974
7354
  const wireIndex = call.index ?? 0;
6975
7355
  let index = toolIndex.get(wireIndex);
6976
7356
  if (index === undefined) {
7357
+ if (openKind !== undefined)
7358
+ yield { type: "blockEnd", index: openIndex };
6977
7359
  index = nextIndex++;
6978
7360
  toolIndex.set(wireIndex, index);
7361
+ openKind = "tool";
7362
+ openIndex = index;
6979
7363
  yield {
6980
7364
  type: "blockStart",
6981
7365
  index,
@@ -6996,10 +7380,8 @@ async function* decodeChat(messages) {
6996
7380
  }
6997
7381
  }
6998
7382
  if (done) {
6999
- if (textOpen)
7000
- yield { type: "blockEnd", index: textIndex ?? 0 };
7001
- for (const index of toolIndex.values())
7002
- yield { type: "blockEnd", index };
7383
+ if (openKind !== undefined)
7384
+ yield { type: "blockEnd", index: openIndex };
7003
7385
  yield { type: "end", stopReason, usage };
7004
7386
  } else {
7005
7387
  yield {
@@ -7428,6 +7810,393 @@ var customAdapter = {
7428
7810
  };
7429
7811
  }
7430
7812
  };
7813
+ // packages/providers/src/grok/device.ts
7814
+ import { randomUUID } from "crypto";
7815
+ function mintGrokDevice() {
7816
+ return { agentId: randomUUID() };
7817
+ }
7818
+ function grokDeviceHeaders(providerData) {
7819
+ const agentId = providerData.agentId;
7820
+ if (typeof agentId !== "string" || agentId.length === 0)
7821
+ return [];
7822
+ return [["x-grok-agent-id", agentId]];
7823
+ }
7824
+ // packages/providers/src/grok/index.ts
7825
+ import { createHash as createHash2 } from "crypto";
7826
+
7827
+ // packages/providers/src/grok/decode.ts
7828
+ var ERROR_CODE2 = {
7829
+ rate_limit_exceeded: "RATE_LIMIT",
7830
+ insufficient_quota: "QUOTA_EXHAUSTED",
7831
+ invalid_api_key: "AUTH",
7832
+ server_error: "UPSTREAM",
7833
+ context_length_exceeded: "BAD_REQUEST",
7834
+ content_policy_violation: "CONTENT_FILTER"
7835
+ };
7836
+ var KNOWN_EVENTS2 = new Set([
7837
+ "response.created",
7838
+ "response.queued",
7839
+ "response.in_progress",
7840
+ "response.output_item.added",
7841
+ "response.output_item.done",
7842
+ "response.content_part.added",
7843
+ "response.content_part.done",
7844
+ "response.output_text.delta",
7845
+ "response.output_text.done",
7846
+ "response.output_text.annotation.added",
7847
+ "response.refusal.delta",
7848
+ "response.refusal.done",
7849
+ "response.reasoning_summary_part.added",
7850
+ "response.reasoning_summary_part.done",
7851
+ "response.reasoning_summary_text.delta",
7852
+ "response.reasoning_summary_text.done",
7853
+ "response.reasoning_text.delta",
7854
+ "response.reasoning_text.done",
7855
+ "response.function_call_arguments.delta",
7856
+ "response.function_call_arguments.done",
7857
+ "response.completed",
7858
+ "response.incomplete",
7859
+ "response.failed",
7860
+ "error"
7861
+ ]);
7862
+ function json4(data) {
7863
+ try {
7864
+ const v = JSON.parse(data);
7865
+ return typeof v === "object" && v !== null ? v : null;
7866
+ } catch {
7867
+ return null;
7868
+ }
7869
+ }
7870
+ async function* decodeGrokResponses(messages) {
7871
+ const indices = new Map;
7872
+ let next = 0;
7873
+ const irIndex = (outputIndex, contentIndex = 0) => {
7874
+ const key = `${outputIndex}:${contentIndex}`;
7875
+ const existing = indices.get(key);
7876
+ if (existing !== undefined)
7877
+ return existing;
7878
+ const assigned = next++;
7879
+ indices.set(key, assigned);
7880
+ return assigned;
7881
+ };
7882
+ let sawToolCall = false;
7883
+ let terminal = false;
7884
+ const ownsBlock = new Set;
7885
+ for await (const msg of messages) {
7886
+ if (msg.data === "[DONE]")
7887
+ continue;
7888
+ if (!KNOWN_EVENTS2.has(msg.event)) {
7889
+ yield {
7890
+ type: "error",
7891
+ code: "UPSTREAM",
7892
+ message: `unrecognized xAI stream event "${msg.event}"`,
7893
+ retryable: false
7894
+ };
7895
+ return;
7896
+ }
7897
+ const d = json4(msg.data);
7898
+ if (d === null)
7899
+ continue;
7900
+ switch (msg.event) {
7901
+ case "response.created":
7902
+ yield {
7903
+ type: "start",
7904
+ id: String(d.response?.id ?? ""),
7905
+ model: String(d.response?.model ?? "")
7906
+ };
7907
+ break;
7908
+ case "response.output_item.added": {
7909
+ const item = d.item ?? {};
7910
+ if (item.type === "reasoning") {
7911
+ ownsBlock.add(d.output_index ?? 0);
7912
+ yield {
7913
+ type: "blockStart",
7914
+ index: irIndex(d.output_index ?? 0),
7915
+ block: { type: "thinking" }
7916
+ };
7917
+ } else if (item.type === "function_call") {
7918
+ sawToolCall = true;
7919
+ ownsBlock.add(d.output_index ?? 0);
7920
+ yield {
7921
+ type: "blockStart",
7922
+ index: irIndex(d.output_index ?? 0),
7923
+ block: { type: "toolUse", id: String(item.call_id), name: String(item.name) }
7924
+ };
7925
+ }
7926
+ break;
7927
+ }
7928
+ case "response.content_part.added":
7929
+ if (d.part?.type === "output_text") {
7930
+ yield {
7931
+ type: "blockStart",
7932
+ index: irIndex(d.output_index ?? 0, d.content_index ?? 0),
7933
+ block: { type: "text" }
7934
+ };
7935
+ }
7936
+ break;
7937
+ case "response.output_text.delta":
7938
+ yield {
7939
+ type: "blockDelta",
7940
+ index: irIndex(d.output_index ?? 0, d.content_index ?? 0),
7941
+ delta: { type: "text", text: String(d.delta ?? "") }
7942
+ };
7943
+ break;
7944
+ case "response.reasoning_summary_text.delta":
7945
+ case "response.reasoning_text.delta":
7946
+ yield {
7947
+ type: "blockDelta",
7948
+ index: irIndex(d.output_index ?? 0),
7949
+ delta: { type: "thinking", text: String(d.delta ?? "") }
7950
+ };
7951
+ break;
7952
+ case "response.function_call_arguments.delta":
7953
+ yield {
7954
+ type: "blockDelta",
7955
+ index: irIndex(d.output_index ?? 0),
7956
+ delta: { type: "toolJson", partial: String(d.delta ?? "") }
7957
+ };
7958
+ break;
7959
+ case "response.content_part.done":
7960
+ yield { type: "blockEnd", index: irIndex(d.output_index ?? 0, d.content_index ?? 0) };
7961
+ break;
7962
+ case "response.output_item.done": {
7963
+ const outputIndex = d.output_index ?? 0;
7964
+ if (ownsBlock.delete(outputIndex)) {
7965
+ yield { type: "blockEnd", index: irIndex(outputIndex) };
7966
+ }
7967
+ break;
7968
+ }
7969
+ case "response.completed":
7970
+ case "response.incomplete": {
7971
+ terminal = true;
7972
+ const r = d.response ?? {};
7973
+ const reason = r.incomplete_details?.reason;
7974
+ let stopReason = sawToolCall ? "toolUse" : "endTurn";
7975
+ if (reason === "max_output_tokens")
7976
+ stopReason = "maxTokens";
7977
+ else if (reason === "content_filter")
7978
+ stopReason = "contentFilter";
7979
+ yield {
7980
+ type: "end",
7981
+ stopReason,
7982
+ usage: usageFromPromptTotal(r.usage?.input_tokens ?? 0, r.usage?.output_tokens ?? 0, r.usage?.input_tokens_details?.cached_tokens ?? 0)
7983
+ };
7984
+ break;
7985
+ }
7986
+ case "response.failed":
7987
+ case "error": {
7988
+ terminal = true;
7989
+ const err = d.response?.error ?? d.error ?? {};
7990
+ const code = ERROR_CODE2[String(err.code ?? err.type)] ?? "UPSTREAM";
7991
+ yield {
7992
+ type: "error",
7993
+ code,
7994
+ message: String(err.message ?? "upstream error"),
7995
+ retryable: RETRYABLE[code]
7996
+ };
7997
+ break;
7998
+ }
7999
+ default:
8000
+ break;
8001
+ }
8002
+ }
8003
+ if (!terminal) {
8004
+ yield {
8005
+ type: "error",
8006
+ code: "UPSTREAM",
8007
+ message: "upstream stream ended before response completion",
8008
+ retryable: RETRYABLE.UPSTREAM
8009
+ };
8010
+ }
8011
+ }
8012
+
8013
+ // packages/providers/src/grok/wire.ts
8014
+ import { createHash } from "crypto";
8015
+ var MAX_TOOLS = 200;
8016
+ function encodeToolChoice4(c) {
8017
+ switch (c.type) {
8018
+ case "auto":
8019
+ return "auto";
8020
+ case "any":
8021
+ return "required";
8022
+ case "none":
8023
+ return "none";
8024
+ case "tool":
8025
+ return { type: "function", name: c.name };
8026
+ }
8027
+ }
8028
+ function promptCacheKey(instructions, firstInput) {
8029
+ const stable = JSON.stringify({ instructions, firstInput });
8030
+ return createHash("sha256").update(stable).digest("hex").slice(0, 32);
8031
+ }
8032
+ function toGrokWire(req, model) {
8033
+ const degradations = [];
8034
+ const input = [];
8035
+ const note = (d) => {
8036
+ if (!degradations.includes(d))
8037
+ degradations.push(d);
8038
+ };
8039
+ if (req.betas?.includes(CONTEXT_1M_BETA))
8040
+ note("grok:context-1m-dropped");
8041
+ for (const message of req.messages) {
8042
+ const parts = [];
8043
+ const inlined = message.role === "system";
8044
+ if (inlined)
8045
+ note("grok:system-turn-inlined");
8046
+ const role = inlined ? "user" : message.role;
8047
+ const flush = () => {
8048
+ if (parts.length === 0)
8049
+ return;
8050
+ input.push({ type: "message", role, content: [...parts] });
8051
+ parts.length = 0;
8052
+ };
8053
+ for (const block of message.content) {
8054
+ switch (block.type) {
8055
+ case "text":
8056
+ parts.push({
8057
+ type: role === "assistant" ? "output_text" : "input_text",
8058
+ text: inlined ? `<system-reminder>
8059
+ ${block.text}
8060
+ </system-reminder>` : block.text
8061
+ });
8062
+ break;
8063
+ case "image":
8064
+ parts.push({
8065
+ type: "input_image",
8066
+ image_url: `data:${block.mediaType};base64,${block.data}`
8067
+ });
8068
+ break;
8069
+ case "thinking":
8070
+ note("grok:thinking-dropped");
8071
+ break;
8072
+ case "toolUse":
8073
+ flush();
8074
+ input.push({
8075
+ type: "function_call",
8076
+ call_id: block.id,
8077
+ name: block.name,
8078
+ arguments: JSON.stringify(block.input)
8079
+ });
8080
+ break;
8081
+ case "toolResult":
8082
+ flush();
8083
+ input.push({
8084
+ type: "function_call_output",
8085
+ call_id: block.toolUseId,
8086
+ output: block.content
8087
+ });
8088
+ break;
8089
+ case "anthropicNative":
8090
+ note("grok:anthropic-native-block-dropped");
8091
+ break;
8092
+ }
8093
+ }
8094
+ flush();
8095
+ }
8096
+ const instructions = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
8097
+
8098
+ `);
8099
+ const body = {
8100
+ model,
8101
+ input,
8102
+ stream: req.stream,
8103
+ store: false,
8104
+ include: ["reasoning.encrypted_content"],
8105
+ prompt_cache_key: promptCacheKey(instructions ?? "", input[0])
8106
+ };
8107
+ if (instructions !== undefined && instructions.length > 0)
8108
+ body.instructions = instructions;
8109
+ if (req.maxTokens !== undefined)
8110
+ body.max_output_tokens = req.maxTokens;
8111
+ if (req.temperature !== undefined)
8112
+ body.temperature = req.temperature;
8113
+ if (req.tools !== undefined) {
8114
+ const custom = req.tools.filter((t) => t.provider === "custom");
8115
+ if (custom.length !== req.tools.length)
8116
+ note("grok:anthropic-tool-dropped");
8117
+ if (custom.length > MAX_TOOLS)
8118
+ note("grok:tools-truncated");
8119
+ body.tools = custom.slice(0, MAX_TOOLS).map((t) => ({
8120
+ type: "function",
8121
+ name: t.name,
8122
+ description: t.description,
8123
+ parameters: t.inputSchema
8124
+ }));
8125
+ }
8126
+ if (req.toolChoice !== undefined)
8127
+ body.tool_choice = encodeToolChoice4(req.toolChoice);
8128
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
8129
+ const effort = req.reasoning.mode === "adaptive" ? req.reasoning.effort ?? "medium" : "medium";
8130
+ body.reasoning = { effort, summary: "concise" };
8131
+ if (req.reasoning.mode === "budget")
8132
+ note("grok:reasoning-budget-dropped");
8133
+ }
8134
+ Object.assign(body, req.vendor?.grok ?? {});
8135
+ return { body, degradations };
8136
+ }
8137
+
8138
+ // packages/providers/src/grok/index.ts
8139
+ var PROXY_URL = "https://cli-chat-proxy.grok.com/v1/responses";
8140
+ var API_URL = "https://api.x.ai/v1/responses";
8141
+ var CONV_NAMESPACE = "omni-grok-conv";
8142
+ function derivedUuid(value) {
8143
+ const h = createHash2("sha256").update(`${CONV_NAMESPACE}:${value}`).digest("hex");
8144
+ const variant = (Number.parseInt(h[16], 16) & 3 | 8).toString(16);
8145
+ return [
8146
+ h.slice(0, 8),
8147
+ h.slice(8, 12),
8148
+ `5${h.slice(13, 16)}`,
8149
+ `${variant}${h.slice(17, 20)}`,
8150
+ h.slice(20, 32)
8151
+ ].join("-");
8152
+ }
8153
+ function requestIdentityHeaders(model, requestId) {
8154
+ const headers = [["x-grok-model-override", model]];
8155
+ if (requestId === undefined || requestId.length === 0)
8156
+ return headers;
8157
+ const conversation = derivedUuid(requestId);
8158
+ return [
8159
+ ...headers,
8160
+ ["x-grok-req-id", requestId],
8161
+ ["x-grok-conv-id", conversation],
8162
+ ["x-grok-session-id", conversation]
8163
+ ];
8164
+ }
8165
+ var grokAdapter = {
8166
+ id: "grok",
8167
+ capabilities: PROVIDER_CAPABILITIES.grok,
8168
+ async send(req) {
8169
+ const oauth = req.credentials.accessToken !== null;
8170
+ const { body, degradations } = toGrokWire(req.request, req.model);
8171
+ const protocol = [["Content-Type", "application/json"]];
8172
+ if (oauth) {
8173
+ protocol.push(["Authorization", `Bearer ${req.credentials.accessToken}`]);
8174
+ protocol.push(["X-XAI-Token-Auth", "xai-grok-cli"]);
8175
+ protocol.push(["x-authenticateresponse", "authenticate-response"]);
8176
+ } else if (req.credentials.apiKey !== null) {
8177
+ protocol.push(["Authorization", `Bearer ${req.credentials.apiKey}`]);
8178
+ } else {
8179
+ throw new GatewayError("AUTH", "grok credential has no token", { provider: "grok" });
8180
+ }
8181
+ protocol.push(...requestIdentityHeaders(req.model, req.requestId));
8182
+ protocol.push(...grokDeviceHeaders(req.credentials.providerData));
8183
+ const profile = PROFILES.grok;
8184
+ const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
8185
+ const res = await req.http({
8186
+ provider: "grok",
8187
+ url: oauth ? PROXY_URL : API_URL,
8188
+ method: "POST",
8189
+ headers,
8190
+ body: JSON.stringify(orderFields({ ...body, stream: true }, BODY_ORDER.grok)),
8191
+ signal: req.signal
8192
+ });
8193
+ if (res.status < 200 || res.status >= 300)
8194
+ throw await httpError(res, "grok");
8195
+ if (res.body === null)
8196
+ throw new GatewayError("UPSTREAM", "empty response body", { provider: "grok" });
8197
+ return { events: decodeGrokResponses(parseSse(res.body)), degradations };
8198
+ }
8199
+ };
7431
8200
  // packages/providers/src/http-client.ts
7432
8201
  import { request as httpRequest } from "http";
7433
8202
  import { request as httpsRequest } from "https";
@@ -7514,11 +8283,316 @@ function nodeHttpClient(options = {}) {
7514
8283
  function hasHeader(req, lowerName) {
7515
8284
  return req.headers.some(([name]) => name.toLowerCase() === lowerName);
7516
8285
  }
7517
- // packages/providers/src/kimi-device.ts
7518
- import { randomUUID } from "crypto";
8286
+ // packages/providers/src/kilo/decode.ts
8287
+ var FINISH2 = {
8288
+ stop: "endTurn",
8289
+ length: "maxTokens",
8290
+ tool_calls: "toolUse",
8291
+ content_filter: "contentFilter"
8292
+ };
8293
+ function reasoningText(delta) {
8294
+ if (typeof delta.reasoning === "string" && delta.reasoning.length > 0)
8295
+ return delta.reasoning;
8296
+ if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
8297
+ return delta.reasoning_content;
8298
+ }
8299
+ if (!Array.isArray(delta.reasoning_details))
8300
+ return "";
8301
+ return delta.reasoning_details.flatMap((entry) => {
8302
+ if (entry === null || typeof entry !== "object")
8303
+ return [];
8304
+ if (typeof entry.text === "string" && entry.text.length > 0)
8305
+ return [entry.text];
8306
+ if (typeof entry.summary === "string" && entry.summary.length > 0)
8307
+ return [entry.summary];
8308
+ return [];
8309
+ }).join("");
8310
+ }
8311
+ function json5(data) {
8312
+ try {
8313
+ const v = JSON.parse(data);
8314
+ return typeof v === "object" && v !== null ? v : null;
8315
+ } catch {
8316
+ return null;
8317
+ }
8318
+ }
8319
+ async function* decodeKiloChat(messages) {
8320
+ let started = false;
8321
+ let done = false;
8322
+ let stopReason = "endTurn";
8323
+ let usage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
8324
+ const toolIndex = new Map;
8325
+ let nextIndex = 0;
8326
+ let openKind;
8327
+ let openIndex = 0;
8328
+ for await (const msg of messages) {
8329
+ if (msg.data === "[DONE]") {
8330
+ done = true;
8331
+ break;
8332
+ }
8333
+ const d = json5(msg.data);
8334
+ if (d === null)
8335
+ continue;
8336
+ if (!started && (d.id !== undefined || d.model !== undefined)) {
8337
+ started = true;
8338
+ yield { type: "start", id: String(d.id ?? ""), model: String(d.model ?? "") };
8339
+ }
8340
+ if (d.usage) {
8341
+ const details = d.usage.prompt_tokens_details;
8342
+ usage = usageFromPromptTotal(d.usage.prompt_tokens ?? 0, d.usage.completion_tokens ?? 0, details?.cached_tokens ?? d.usage.prompt_cache_hit_tokens ?? 0, details?.cache_creation_tokens ?? details?.cache_write_tokens ?? 0);
8343
+ }
8344
+ const choice = d.choices?.[0];
8345
+ if (!choice)
8346
+ continue;
8347
+ const delta = choice.delta ?? {};
8348
+ const reasoning = reasoningText(delta);
8349
+ if (reasoning.length > 0) {
8350
+ if (openKind !== "thinking") {
8351
+ if (openKind !== undefined)
8352
+ yield { type: "blockEnd", index: openIndex };
8353
+ openKind = "thinking";
8354
+ openIndex = nextIndex++;
8355
+ yield { type: "blockStart", index: openIndex, block: { type: "thinking" } };
8356
+ }
8357
+ yield {
8358
+ type: "blockDelta",
8359
+ index: openIndex,
8360
+ delta: { type: "thinking", text: reasoning }
8361
+ };
8362
+ }
8363
+ const calls = delta.tool_calls ?? [];
8364
+ if (typeof delta.content === "string" && delta.content.length > 0) {
8365
+ if (openKind !== "text") {
8366
+ if (openKind !== undefined)
8367
+ yield { type: "blockEnd", index: openIndex };
8368
+ openKind = "text";
8369
+ openIndex = nextIndex++;
8370
+ yield { type: "blockStart", index: openIndex, block: { type: "text" } };
8371
+ }
8372
+ yield {
8373
+ type: "blockDelta",
8374
+ index: openIndex,
8375
+ delta: { type: "text", text: delta.content }
8376
+ };
8377
+ }
8378
+ for (const call of calls) {
8379
+ const wireIndex = call.index ?? 0;
8380
+ let index = toolIndex.get(wireIndex);
8381
+ if (index === undefined) {
8382
+ if (openKind !== undefined)
8383
+ yield { type: "blockEnd", index: openIndex };
8384
+ index = nextIndex++;
8385
+ toolIndex.set(wireIndex, index);
8386
+ openKind = "tool";
8387
+ openIndex = index;
8388
+ yield {
8389
+ type: "blockStart",
8390
+ index,
8391
+ block: {
8392
+ type: "toolUse",
8393
+ id: String(call.id ?? `call_${wireIndex}`),
8394
+ name: String(call.function?.name ?? "")
8395
+ }
8396
+ };
8397
+ }
8398
+ const args = call.function?.arguments;
8399
+ if (typeof args === "string" && args.length > 0) {
8400
+ yield { type: "blockDelta", index, delta: { type: "toolJson", partial: args } };
8401
+ }
8402
+ }
8403
+ if (typeof choice.finish_reason === "string") {
8404
+ stopReason = FINISH2[choice.finish_reason] ?? "endTurn";
8405
+ }
8406
+ }
8407
+ if (done) {
8408
+ if (openKind !== undefined)
8409
+ yield { type: "blockEnd", index: openIndex };
8410
+ yield { type: "end", stopReason, usage };
8411
+ } else {
8412
+ yield {
8413
+ type: "error",
8414
+ code: "UPSTREAM",
8415
+ message: "upstream stream ended before [DONE]",
8416
+ retryable: RETRYABLE.UPSTREAM
8417
+ };
8418
+ }
8419
+ }
8420
+
8421
+ // packages/providers/src/kilo/wire.ts
8422
+ function encodeToolChoice5(c) {
8423
+ switch (c.type) {
8424
+ case "auto":
8425
+ return "auto";
8426
+ case "any":
8427
+ return "required";
8428
+ case "none":
8429
+ return "none";
8430
+ case "tool":
8431
+ return { type: "function", function: { name: c.name } };
8432
+ }
8433
+ }
8434
+ function hasCacheBreakpoint(req) {
8435
+ const marked = (block) => ("cacheControl" in block) && block.cacheControl !== undefined;
8436
+ if (req.system?.some(marked) === true)
8437
+ return true;
8438
+ return req.messages.some((message) => message.content.some(marked));
8439
+ }
8440
+ function collapse(parts) {
8441
+ if (parts.length === 0)
8442
+ return null;
8443
+ if (parts.every((part) => part.type === "text")) {
8444
+ return parts.map((part) => part.type === "text" ? part.text : "").join(`
8445
+ `);
8446
+ }
8447
+ return [...parts];
8448
+ }
8449
+ function toKiloWire(req, model) {
8450
+ const degradations = [];
8451
+ const note = (d) => {
8452
+ if (!degradations.includes(d))
8453
+ degradations.push(d);
8454
+ };
8455
+ if (req.betas?.includes(CONTEXT_1M_BETA))
8456
+ note("kilo:context-1m-dropped");
8457
+ if (hasCacheBreakpoint(req))
8458
+ note("kilo:cache-control-dropped");
8459
+ const messages = [];
8460
+ const system = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
8461
+
8462
+ `);
8463
+ if (system !== undefined && system.length > 0)
8464
+ messages.push({ role: "system", content: system });
8465
+ for (const message of req.messages) {
8466
+ let parts = [];
8467
+ const toolCalls = [];
8468
+ const flush = () => {
8469
+ if (toolCalls.length > 0) {
8470
+ messages.push({ role: message.role, content: collapse(parts), tool_calls: [...toolCalls] });
8471
+ } else if (parts.length > 0) {
8472
+ messages.push({ role: message.role, content: collapse(parts) });
8473
+ }
8474
+ parts = [];
8475
+ toolCalls.length = 0;
8476
+ };
8477
+ for (const block of message.content) {
8478
+ switch (block.type) {
8479
+ case "text":
8480
+ parts.push({ type: "text", text: block.text });
8481
+ break;
8482
+ case "image":
8483
+ parts.push({
8484
+ type: "image_url",
8485
+ image_url: { url: `data:${block.mediaType};base64,${block.data}` }
8486
+ });
8487
+ break;
8488
+ case "thinking":
8489
+ note("kilo:thinking-dropped");
8490
+ break;
8491
+ case "toolUse":
8492
+ toolCalls.push({
8493
+ id: block.id,
8494
+ type: "function",
8495
+ function: { name: block.name, arguments: JSON.stringify(block.input) }
8496
+ });
8497
+ break;
8498
+ case "toolResult":
8499
+ flush();
8500
+ messages.push({
8501
+ role: "tool",
8502
+ tool_call_id: block.toolUseId,
8503
+ content: block.content
8504
+ });
8505
+ break;
8506
+ case "anthropicNative":
8507
+ note("kilo:anthropic-native-block-dropped");
8508
+ break;
8509
+ }
8510
+ }
8511
+ flush();
8512
+ }
8513
+ const body = {
8514
+ model,
8515
+ messages,
8516
+ stream: req.stream,
8517
+ stream_options: { include_usage: true }
8518
+ };
8519
+ if (req.maxTokens !== undefined)
8520
+ body.max_tokens = req.maxTokens;
8521
+ if (req.temperature !== undefined)
8522
+ body.temperature = req.temperature;
8523
+ if (req.stopSequences !== undefined)
8524
+ body.stop = req.stopSequences;
8525
+ if (req.tools !== undefined) {
8526
+ const custom = req.tools.filter((t) => t.provider === "custom");
8527
+ if (custom.length !== req.tools.length)
8528
+ note("kilo:anthropic-tool-dropped");
8529
+ body.tools = custom.map((t) => ({
8530
+ type: "function",
8531
+ function: { name: t.name, description: t.description, parameters: t.inputSchema }
8532
+ }));
8533
+ }
8534
+ if (req.toolChoice !== undefined)
8535
+ body.tool_choice = encodeToolChoice5(req.toolChoice);
8536
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
8537
+ if (req.reasoning.mode === "budget") {
8538
+ body.reasoning = { max_tokens: req.reasoning.budgetTokens };
8539
+ } else {
8540
+ const effort = req.reasoning.effort ?? "medium";
8541
+ if (effort === "xhigh" || effort === "max")
8542
+ note("kilo:reasoning-effort-clamped");
8543
+ body.reasoning = { effort: effort === "xhigh" || effort === "max" ? "high" : effort };
8544
+ }
8545
+ }
8546
+ Object.assign(body, req.vendor?.kilo ?? {});
8547
+ return { body, degradations };
8548
+ }
8549
+
8550
+ // packages/providers/src/kilo/index.ts
8551
+ var OAUTH_URL = "https://api.kilo.ai/api/openrouter/chat/completions";
8552
+ var API_URL2 = "https://api.kilo.ai/api/gateway/chat/completions";
8553
+ function organizationHeaders(providerData) {
8554
+ const orgId = providerData.orgId;
8555
+ if (typeof orgId !== "string" || orgId.length === 0)
8556
+ return [];
8557
+ return [["X-Kilocode-OrganizationID", orgId]];
8558
+ }
8559
+ var kiloAdapter = {
8560
+ id: "kilo",
8561
+ capabilities: PROVIDER_CAPABILITIES.kilo,
8562
+ async send(req) {
8563
+ const oauth = req.credentials.accessToken !== null;
8564
+ const token = req.credentials.accessToken ?? req.credentials.apiKey;
8565
+ if (token === null) {
8566
+ throw new GatewayError("AUTH", "kilo credential has no token", { provider: "kilo" });
8567
+ }
8568
+ const { body, degradations } = toKiloWire(req.request, req.model);
8569
+ const protocol = [
8570
+ ["Content-Type", "application/json"],
8571
+ ["Authorization", `Bearer ${token}`],
8572
+ ...organizationHeaders(req.credentials.providerData)
8573
+ ];
8574
+ const profile = PROFILES.kilo;
8575
+ const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
8576
+ const res = await req.http({
8577
+ provider: "kilo",
8578
+ url: oauth ? OAUTH_URL : API_URL2,
8579
+ method: "POST",
8580
+ headers,
8581
+ body: JSON.stringify(orderFields({ ...body, stream: true }, BODY_ORDER.kilo)),
8582
+ signal: req.signal
8583
+ });
8584
+ if (res.status < 200 || res.status >= 300)
8585
+ throw await httpError(res, "kilo");
8586
+ if (res.body === null)
8587
+ throw new GatewayError("UPSTREAM", "empty response body", { provider: "kilo" });
8588
+ return { events: decodeKiloChat(parseSse(res.body)), degradations };
8589
+ }
8590
+ };
8591
+ // packages/providers/src/kimi/device.ts
8592
+ import { randomUUID as randomUUID2 } from "crypto";
7519
8593
  function mintKimiDevice() {
7520
8594
  return {
7521
- deviceId: randomUUID(),
8595
+ deviceId: randomUUID2(),
7522
8596
  deviceName: "MacBook-Pro",
7523
8597
  deviceModel: "MacBookPro18,3",
7524
8598
  osVersion: "15.3.1"
@@ -7536,7 +8610,6 @@ function kimiDeviceHeaders(providerData) {
7536
8610
  ["X-Msh-Os-Version", str(providerData.osVersion)]
7537
8611
  ];
7538
8612
  }
7539
-
7540
8613
  // packages/providers/src/kimi/index.ts
7541
8614
  var BASE_URL2 = "https://api.kimi.com/coding/v1/chat/completions";
7542
8615
  var kimiAdapter = {
@@ -7572,8 +8645,8 @@ var kimiAdapter = {
7572
8645
  }
7573
8646
  };
7574
8647
  // packages/providers/src/openai/index.ts
7575
- var OAUTH_URL = "https://chatgpt.com/backend-api/codex/responses";
7576
- var API_URL = "https://api.openai.com/v1/responses";
8648
+ var OAUTH_URL2 = "https://chatgpt.com/backend-api/codex/responses";
8649
+ var API_URL3 = "https://api.openai.com/v1/responses";
7577
8650
  var openaiAdapter = {
7578
8651
  id: "openai",
7579
8652
  capabilities: PROVIDER_CAPABILITIES.openai,
@@ -7595,7 +8668,7 @@ var openaiAdapter = {
7595
8668
  const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
7596
8669
  const res = await req.http({
7597
8670
  provider: "openai",
7598
- url: oauth ? OAUTH_URL : API_URL,
8671
+ url: oauth ? OAUTH_URL2 : API_URL3,
7599
8672
  method: "POST",
7600
8673
  headers,
7601
8674
  body: JSON.stringify(orderFields({ ...body, stream: true }, BODY_ORDER.openai)),
@@ -7613,9 +8686,20 @@ var ADAPTERS = {
7613
8686
  anthropic: anthropicAdapter,
7614
8687
  openai: openaiAdapter,
7615
8688
  kimi: kimiAdapter,
8689
+ kilo: kiloAdapter,
8690
+ grok: grokAdapter,
7616
8691
  custom: customAdapter
7617
8692
  };
7618
8693
  // packages/control/src/oauth/types.ts
8694
+ var PENDING_MARKER = "__omni_authorization_pending";
8695
+ function isAuthorizationPending(error) {
8696
+ return error instanceof GatewayError && error[PENDING_MARKER] === true;
8697
+ }
8698
+ function pendingError(reason) {
8699
+ const error = new GatewayError("AUTH", `authorization not yet complete: ${reason}`);
8700
+ error[PENDING_MARKER] = true;
8701
+ return error;
8702
+ }
7619
8703
  async function postJson(deps, provider, url, profile2, opts) {
7620
8704
  const headers = orderHeaders(mergeHeaders(profile2.headers, [
7621
8705
  ["Content-Type", opts.contentType],
@@ -7637,11 +8721,11 @@ async function postJson(deps, provider, url, profile2, opts) {
7637
8721
  } catch {}
7638
8722
  return { status: res.status, parsed };
7639
8723
  }
7640
- async function getJson(deps, provider, url, profile2, opts) {
8724
+ async function sendGet(deps, provider, url, profile2, authHeaders, extraHeaders) {
7641
8725
  const headers = orderHeaders(mergeHeaders(profile2.headers, [
7642
- ["Authorization", `Bearer ${opts.accessToken}`],
8726
+ ...authHeaders,
7643
8727
  ["Accept", "application/json"],
7644
- ...opts.extraHeaders ?? []
8728
+ ...extraHeaders
7645
8729
  ]), profile2.order);
7646
8730
  const res = await deps.http({
7647
8731
  provider,
@@ -7658,6 +8742,12 @@ async function getJson(deps, provider, url, profile2, opts) {
7658
8742
  } catch {}
7659
8743
  return { status: res.status, parsed };
7660
8744
  }
8745
+ function getJson(deps, provider, url, profile2, opts) {
8746
+ return sendGet(deps, provider, url, profile2, [["Authorization", `Bearer ${opts.accessToken}`]], opts.extraHeaders ?? []);
8747
+ }
8748
+ function getJsonUnauthenticated(deps, provider, url, profile2, opts) {
8749
+ return sendGet(deps, provider, url, profile2, [], opts?.extraHeaders ?? []);
8750
+ }
7661
8751
  function tokenErrorCode(status) {
7662
8752
  if (status === 429)
7663
8753
  return "RATE_LIMIT";
@@ -7670,366 +8760,55 @@ function tokenErrorMessage(status, body2) {
7670
8760
  return `token endpoint rejected the request: ${code}`;
7671
8761
  }
7672
8762
 
7673
- // packages/control/src/oauth/usage.ts
7674
- function usageReadable(status, provider) {
7675
- if (status === 429) {
7676
- throw new GatewayError("RATE_LIMIT", `${provider} usage endpoint is rate limited`);
7677
- }
7678
- return status >= 200 && status < 300;
7679
- }
7680
- function recordOf(value) {
7681
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
7682
- }
7683
- function numberOf(record, keys) {
7684
- for (const key of keys) {
7685
- const value = record[key];
7686
- if (typeof value === "number" && Number.isFinite(value))
7687
- return value;
7688
- if (typeof value === "string" && value.trim().length > 0) {
7689
- const parsed = Number(value);
7690
- if (Number.isFinite(parsed))
7691
- return parsed;
7692
- }
7693
- }
7694
- return null;
7695
- }
7696
- function nestedOf(record, keys) {
7697
- for (const key of keys) {
7698
- const nested = recordOf(record[key]);
7699
- if (nested !== null)
7700
- return nested;
7701
- }
7702
- return null;
7703
- }
7704
- function resetAtOf(record, keys, now) {
7705
- for (const key of keys.absolute) {
7706
- const value = record[key];
7707
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
7708
- return value < 1000000000000 ? Math.round(value * 1000) : Math.round(value);
7709
- }
7710
- if (typeof value === "string") {
7711
- const parsed = Date.parse(value);
7712
- if (!Number.isNaN(parsed))
7713
- return parsed;
7714
- }
7715
- }
7716
- for (const key of keys.relativeSeconds ?? []) {
7717
- const value = record[key];
7718
- if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
7719
- return now + Math.round(value * 1000);
7720
- }
7721
- }
7722
- return null;
7723
- }
7724
- var USED_KEYS = ["used", "used_units", "usage", "consumed"];
7725
- var LIMIT_KEYS = ["limit", "limit_units", "total", "quota", "allowed"];
7726
- var PERCENT_KEYS = [
7727
- "utilization",
7728
- "used_percent",
7729
- "usedPercent",
7730
- "percent_used",
7731
- "percentUsed",
7732
- "percent"
7733
- ];
7734
- var RESET_ABSOLUTE_KEYS = [
7735
- "resets_at",
7736
- "resetsAt",
7737
- "reset_at",
7738
- "resetAt",
7739
- "resetTime",
7740
- "reset_time",
7741
- "resets_at_epoch",
7742
- "reset"
7743
- ];
7744
- var RESET_RELATIVE_KEYS = [
7745
- "resets_in_seconds",
7746
- "resetsInSeconds",
7747
- "reset_after_seconds",
7748
- "resetAfterSeconds",
7749
- "seconds_until_reset",
7750
- "resets_in"
7751
- ];
7752
- function windowFrom(value, windowType, now) {
7753
- const record = recordOf(value);
7754
- if (record === null)
7755
- return null;
7756
- const resetsAt = resetAtOf(record, { absolute: RESET_ABSOLUTE_KEYS, relativeSeconds: RESET_RELATIVE_KEYS }, now);
7757
- const used = numberOf(record, USED_KEYS);
7758
- const limit = numberOf(record, LIMIT_KEYS);
7759
- if (used !== null) {
7760
- return { windowType, used: Math.max(0, used), limit, resetsAt };
7761
- }
7762
- const remaining = numberOf(record, ["remaining", "remaining_units", "left"]);
7763
- if (remaining !== null && limit !== null) {
7764
- return { windowType, used: Math.max(0, limit - remaining), limit, resetsAt };
7765
- }
7766
- const percent = numberOf(record, PERCENT_KEYS);
7767
- if (percent !== null) {
7768
- return { windowType, used: Math.max(0, Math.min(100, percent)), limit: 100, resetsAt };
7769
- }
7770
- return null;
7771
- }
7772
- function reportFrom(windows) {
7773
- const kept = windows.filter((w) => w !== null);
7774
- return kept.length === 0 ? null : { windows: kept };
7775
- }
7776
-
7777
- // packages/control/src/oauth/kimi.ts
7778
- var CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
7779
- var DEVICE_CODE_URL = "https://auth.kimi.com/api/oauth/device_authorization";
7780
- var TOKEN_URL = "https://auth.kimi.com/api/oauth/token";
7781
- var USAGE_URL = "https://api.kimi.com/coding/v1/usages";
7782
- var DEFAULT_INTERVAL_SECONDS = 5;
7783
- var PENDING_ERRORS = new Set(["authorization_pending", "slow_down"]);
7784
- var PENDING_MARKER = "__omni_authorization_pending";
7785
- function isAuthorizationPending(error) {
7786
- return error instanceof GatewayError && error[PENDING_MARKER] === true;
7787
- }
7788
- function pendingError(code) {
7789
- const error = new GatewayError("AUTH", `authorization not yet complete: ${code}`);
7790
- error[PENDING_MARKER] = true;
7791
- return error;
7792
- }
7793
- function isRecord2(value) {
7794
- return typeof value === "object" && value !== null;
7795
- }
7796
- function recordFrom(value) {
7797
- return isRecord2(value) ? value : null;
7798
- }
7799
- function stringFrom(value, field) {
7800
- const candidate = value[field];
7801
- return typeof candidate === "string" && candidate.trim().length > 0 ? candidate : null;
7802
- }
7803
- function positiveNumberFrom(value, field) {
7804
- const candidate = value[field];
7805
- return typeof candidate === "number" && Number.isFinite(candidate) && candidate > 0 ? candidate : null;
7806
- }
7807
- function tokenFrom(value) {
7808
- const record = recordFrom(value);
7809
- if (record === null) {
7810
- throw new GatewayError("AUTH", "token endpoint returned no access_token");
7811
- }
7812
- const accessToken = stringFrom(record, "access_token");
7813
- if (accessToken === null) {
7814
- throw new GatewayError("AUTH", "token endpoint returned no access_token");
7815
- }
7816
- return {
7817
- accessToken,
7818
- refreshToken: stringFrom(record, "refresh_token"),
7819
- expiresIn: positiveNumberFrom(record, "expires_in"),
7820
- email: stringFrom(record, "email")
7821
- };
7822
- }
7823
- function deviceCodeFrom(value) {
7824
- const record = recordFrom(value);
7825
- if (record === null) {
7826
- throw new GatewayError("AUTH", "device code endpoint returned an unusable response");
7827
- }
7828
- const deviceCode = stringFrom(record, "device_code");
7829
- const userCode = stringFrom(record, "user_code");
7830
- if (deviceCode === null || userCode === null) {
7831
- throw new GatewayError("AUTH", "device code endpoint returned an unusable response");
7832
- }
7833
- return {
7834
- deviceCode,
7835
- userCode,
7836
- verificationUri: stringFrom(record, "verification_uri_complete") ?? stringFrom(record, "verification_uri") ?? "https://www.kimi.com/device",
7837
- interval: positiveNumberFrom(record, "interval") ?? DEFAULT_INTERVAL_SECONDS
7838
- };
7839
- }
7840
- async function post(url, body2, device, deps) {
7841
- const { status, parsed } = await postJson(deps, "kimi", url, PROFILES.kimi, {
7842
- contentType: "application/x-www-form-urlencoded",
7843
- body: new URLSearchParams({ ...body2, client_id: CLIENT_ID }).toString(),
7844
- extraHeaders: kimiDeviceHeaders(device)
7845
- });
7846
- if (status >= 200 && status < 300)
7847
- return parsed;
7848
- const record = recordFrom(parsed);
7849
- const code = record === null ? `http_${status}` : stringFrom(record, "error") ?? `http_${status}`;
7850
- if (PENDING_ERRORS.has(code))
7851
- throw pendingError(code);
7852
- throw new GatewayError(tokenErrorCode(status), tokenErrorMessage(status, parsed));
7853
- }
7854
- function deviceFrom(source) {
7855
- if (typeof source?.deviceId === "string" && source.deviceId.length > 0) {
7856
- const fresh = mintKimiDevice();
7857
- const field = (key, fallback) => {
7858
- const value = source[key];
7859
- return typeof value === "string" && value.length > 0 ? value : fallback;
7860
- };
7861
- return {
7862
- deviceId: source.deviceId,
7863
- deviceName: field("deviceName", fresh.deviceName),
7864
- deviceModel: field("deviceModel", fresh.deviceModel),
7865
- osVersion: field("osVersion", fresh.osVersion)
7866
- };
7867
- }
7868
- return mintKimiDevice();
7869
- }
7870
- function deviceForBegin(deviceId) {
7871
- return { ...mintKimiDevice(), deviceId };
7872
- }
7873
- function toResult(token, device, fallbackRefresh, deps) {
7874
- return {
7875
- secrets: {
7876
- accessToken: token.accessToken,
7877
- refreshToken: token.refreshToken ?? fallbackRefresh,
7878
- apiKey: null,
7879
- idToken: null
7880
- },
7881
- expiresAt: token.expiresIn === null ? null : deps.now() + token.expiresIn * 1000,
7882
- accountEmail: token.email,
7883
- providerData: { ...device }
7884
- };
7885
- }
7886
- function parseKimiUsage(value, now) {
7887
- const root = recordOf(value);
7888
- if (root === null)
7889
- return null;
7890
- return reportFrom([windowFrom(root.usage ?? root.Usage, "weekly", now)]);
7891
- }
7892
- var kimiOAuth = {
7893
- id: "kimi",
7894
- kind: "device",
7895
- supportsManualPaste: false,
7896
- start() {
7897
- const device = mintKimiDevice();
7898
- return {
7899
- authorizeUrl: "https://www.kimi.com/device",
7900
- pending: { verifier: "", challenge: "", state: "", redirectUri: "", extra: { ...device } }
7901
- };
7902
- },
7903
- async begin({ deviceId }, deps) {
7904
- if (deviceId.trim().length === 0) {
7905
- throw new Error("kimi begin requires a non-blank deviceId");
7906
- }
7907
- const device = deviceForBegin(deviceId);
7908
- const response = deviceCodeFrom(await post(DEVICE_CODE_URL, {}, device, deps));
7909
- return {
7910
- authorizeUrl: response.verificationUri,
7911
- userCode: response.userCode,
7912
- pending: {
7913
- verifier: "",
7914
- challenge: "",
7915
- state: "",
7916
- redirectUri: "",
7917
- deviceCode: response.deviceCode,
7918
- interval: response.interval,
7919
- extra: { ...device }
7920
- }
7921
- };
7922
- },
7923
- async exchange({ pending }, deps) {
7924
- if (pending.deviceCode === undefined) {
7925
- throw new Error("kimi exchange requires a pending flow produced by begin()");
7926
- }
7927
- const device = deviceFrom(pending.extra);
7928
- const token = tokenFrom(await post(TOKEN_URL, {
7929
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
7930
- device_code: pending.deviceCode,
7931
- device_id: device.deviceId
7932
- }, device, deps));
7933
- return toResult(token, device, null, deps);
7934
- },
7935
- async refresh(refreshToken, deps, providerData) {
7936
- const device = deviceFrom(providerData);
7937
- const token = tokenFrom(await post(TOKEN_URL, { grant_type: "refresh_token", refresh_token: refreshToken, device_id: device.deviceId }, device, deps));
7938
- return toResult(token, device, refreshToken, deps);
7939
- },
7940
- async usage(secrets, deps, providerData) {
7941
- if (secrets.accessToken === null)
7942
- return null;
7943
- const device = deviceFrom(providerData);
7944
- const { status, parsed } = await getJson(deps, "kimi", USAGE_URL, PROFILES.kimi, {
7945
- accessToken: secrets.accessToken,
7946
- extraHeaders: kimiDeviceHeaders(device)
7947
- });
7948
- if (!usageReadable(status, "kimi"))
7949
- return null;
7950
- return parseKimiUsage(parsed, deps.now());
7951
- }
7952
- };
7953
-
7954
- // packages/control/src/oauth/pending.ts
7955
- function createPendingFlows(opts) {
7956
- const flows = new Map;
7957
- const expired = (entry) => entry.expiresAt <= opts.now();
7958
- return {
7959
- put(flow) {
7960
- const id = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString("base64url");
7961
- flows.set(id, { flow, expiresAt: opts.now() + opts.ttlMs });
7962
- return id;
7963
- },
7964
- take(id) {
7965
- const entry = flows.get(id);
7966
- if (entry === undefined)
7967
- return null;
7968
- flows.delete(id);
7969
- return expired(entry) ? null : entry.flow;
7970
- },
7971
- peek(id) {
7972
- const entry = flows.get(id);
7973
- if (entry === undefined || expired(entry))
7974
- return null;
7975
- return entry.flow;
7976
- },
7977
- byState(state) {
7978
- if (state.trim().length === 0)
7979
- return null;
7980
- for (const [id, entry] of flows) {
7981
- if (entry.flow.pending.state === state) {
7982
- return expired(entry) ? null : { ...entry.flow, id };
7983
- }
7984
- }
7985
- return null;
7986
- },
7987
- sweep() {
7988
- for (const [id, entry] of flows) {
7989
- if (expired(entry))
7990
- flows.delete(id);
7991
- }
7992
- },
7993
- size() {
7994
- return flows.size;
7995
- }
7996
- };
7997
- }
7998
-
7999
8763
  // packages/control/src/connect.ts
8000
- var PROVIDER_IDS = ["anthropic", "openai", "kimi", "custom"];
8764
+ var PROVIDER_IDS = [
8765
+ "anthropic",
8766
+ "openai",
8767
+ "kimi",
8768
+ "kilo",
8769
+ "grok",
8770
+ "custom"
8771
+ ];
8001
8772
  var FLOW_TTL_MS = 600000;
8773
+ var CALLBACKS = {
8774
+ openai: { uri: "http://localhost:1455/auth/callback", label: "OpenAI" },
8775
+ grok: { uri: "http://127.0.0.1:56121/callback", label: "Grok" }
8776
+ };
8002
8777
  function isProviderId(value) {
8003
8778
  return typeof value === "string" && PROVIDER_IDS.includes(value);
8004
8779
  }
8005
- function deviceIdFrom(start) {
8780
+ function deviceIdFrom(provider, start) {
8006
8781
  const deviceId = start.pending.extra?.deviceId;
8007
- if (typeof deviceId !== "string" || deviceId.trim().length === 0) {
8782
+ if (typeof deviceId === "string" && deviceId.trim().length > 0)
8783
+ return deviceId;
8784
+ if (provider.needsDeviceId) {
8008
8785
  throw new GatewayError("INTERNAL", "device authorization did not provide a device id");
8009
8786
  }
8010
- return deviceId;
8787
+ return "";
8011
8788
  }
8012
8789
  function createConnectFlows(deps) {
8013
8790
  const logger2 = deps.logger ?? noopLogger;
8014
8791
  const flows = createPendingFlows({ now: deps.now, ttlMs: FLOW_TTL_MS });
8015
8792
  const pollsInFlight = new Map;
8016
- const callbackUri = (provider) => provider === "openai" ? "http://localhost:1455/auth/callback" : "";
8793
+ const callbackUri = (provider) => CALLBACKS[provider]?.uri ?? "";
8017
8794
  function normalizeAuthorizationCode(flow, input) {
8018
- if (flow.provider !== "openai")
8795
+ const callback = CALLBACKS[flow.provider];
8796
+ if (callback === undefined)
8019
8797
  return input;
8798
+ const expected = new URL(callback.uri);
8020
8799
  let url;
8021
8800
  try {
8022
8801
  url = new URL(input);
8023
8802
  } catch {
8024
8803
  return input;
8025
8804
  }
8026
- if (url.origin !== "http://localhost:1455" || url.pathname !== "/auth/callback") {
8027
- throw new GatewayError("BAD_REQUEST", "invalid OpenAI callback URL");
8805
+ if (url.origin !== expected.origin || url.pathname !== expected.pathname) {
8806
+ throw new GatewayError("BAD_REQUEST", `invalid ${callback.label} callback URL`);
8028
8807
  }
8029
8808
  const code = url.searchParams.get("code")?.trim() ?? "";
8030
8809
  const state = url.searchParams.get("state")?.trim() ?? "";
8031
8810
  if (code.length === 0 || state.length === 0) {
8032
- throw new GatewayError("BAD_REQUEST", "OpenAI callback URL must contain code and state");
8811
+ throw new GatewayError("BAD_REQUEST", `${callback.label} callback URL must contain code and state`);
8033
8812
  }
8034
8813
  if (state !== flow.pending.state) {
8035
8814
  throw new GatewayError("AUTH", "authorization state mismatch");
@@ -8079,7 +8858,7 @@ function createConnectFlows(deps) {
8079
8858
  async start(providerInput, labelInput) {
8080
8859
  flows.sweep();
8081
8860
  if (!isProviderId(providerInput)) {
8082
- throw new GatewayError("BAD_REQUEST", "provider must be one of anthropic, openai, kimi");
8861
+ throw new GatewayError("BAD_REQUEST", "provider must be one of anthropic, openai, kimi, kilo, grok");
8083
8862
  }
8084
8863
  const label = typeof labelInput === "string" && labelInput.trim().length > 0 ? labelInput.trim() : providerInput;
8085
8864
  const provider = deps.providers[providerInput];
@@ -8087,13 +8866,9 @@ function createConnectFlows(deps) {
8087
8866
  throw new GatewayError("BAD_REQUEST", "provider does not support OAuth");
8088
8867
  }
8089
8868
  const redirectUri = callbackUri(providerInput);
8090
- const start = provider.begin === undefined ? provider.start({ redirectUri }) : await (async () => {
8091
- const initial = provider.start({ redirectUri });
8092
- return provider.begin?.({ deviceId: deviceIdFrom(initial) }, { http: deps.http, now: deps.now });
8093
- })();
8094
- if (start === undefined) {
8095
- throw new GatewayError("INTERNAL", "device authorization could not start");
8096
- }
8869
+ const oauthDeps = { http: deps.http, now: deps.now };
8870
+ const initial = await provider.start({ redirectUri }, oauthDeps);
8871
+ const start = provider.kind === "device" ? await provider.begin({ deviceId: deviceIdFrom(provider, initial) }, oauthDeps) : initial;
8097
8872
  const flowId = flows.put({
8098
8873
  provider: providerInput,
8099
8874
  label,
@@ -8136,60 +8911,6 @@ function createConnectFlows(deps) {
8136
8911
  }
8137
8912
  };
8138
8913
  }
8139
- // packages/control/src/console.ts
8140
- var UNIT_NAME = "omnigateway.service";
8141
- var MAX_CONSOLE_LINES = 500;
8142
- var DEFAULT_CONSOLE_LINES = 200;
8143
- function resolveConsoleSource(input) {
8144
- const path = input.logFile?.trim();
8145
- if (path !== undefined && path.length > 0)
8146
- return { kind: "file", path };
8147
- if (input.unitInstalled)
8148
- return { kind: "journal", unit: UNIT_NAME, scope: input.scope };
8149
- return { kind: "none" };
8150
- }
8151
- function consoleLimit(requested) {
8152
- const value = requested === undefined ? DEFAULT_CONSOLE_LINES : Number(requested);
8153
- if (!Number.isFinite(value))
8154
- return DEFAULT_CONSOLE_LINES;
8155
- return Math.floor(Math.min(Math.max(1, value), MAX_CONSOLE_LINES));
8156
- }
8157
- function keep(line, query) {
8158
- if (query.since !== undefined && (line.at === null || line.at <= query.since))
8159
- return false;
8160
- if (query.level === undefined || line.level === null)
8161
- return true;
8162
- return LEVELS[line.level] >= LEVELS[query.level];
8163
- }
8164
- var SCAN_FACTOR = 20;
8165
- var SCAN_LIMIT = 5000;
8166
- function scanWidth(query) {
8167
- const filtered = query.level !== undefined || query.since !== undefined;
8168
- return filtered ? Math.min(query.lines * SCAN_FACTOR, SCAN_LIMIT) : query.lines;
8169
- }
8170
- async function readSource(deps, source, lines) {
8171
- if (source.kind === "none")
8172
- return "";
8173
- if (source.kind === "file")
8174
- return deps.readFile(source.path, lines) ?? "";
8175
- const unit = source.scope === "system" ? ["-u", source.unit] : [`--user-unit=${source.unit}`];
8176
- const result = await deps.run([
8177
- "journalctl",
8178
- ...unit,
8179
- "-n",
8180
- String(lines),
8181
- "--no-pager",
8182
- "--output=cat"
8183
- ]);
8184
- return result.code === 0 ? result.stdout : "";
8185
- }
8186
- async function readConsole(deps, source, query) {
8187
- const limited = { ...query, lines: consoleLimit(query.lines) };
8188
- const text = await readSource(deps, source, scanWidth(limited));
8189
- const lines = text.split(`
8190
- `).filter((raw) => raw.trim().length > 0).map(parseLine).filter((line) => keep(line, limited)).slice(-limited.lines);
8191
- return source.kind === "file" ? { source: "file", path: source.path, lines } : { source: source.kind, lines };
8192
- }
8193
8914
  // node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
8194
8915
  var exports_external = {};
8195
8916
  __export(exports_external, {
@@ -8335,7 +9056,7 @@ __export(exports_external, {
8335
9056
  ipv4: () => ipv42,
8336
9057
  ipv6: () => ipv62,
8337
9058
  iso: () => exports_iso,
8338
- json: () => json4,
9059
+ json: () => json6,
8339
9060
  jwt: () => jwt,
8340
9061
  keyof: () => keyof,
8341
9062
  ksuid: () => ksuid2,
@@ -19776,29 +20497,29 @@ var formatMap = {
19776
20497
  regex: ""
19777
20498
  };
19778
20499
  var stringProcessor = (schema, ctx, _json, _params) => {
19779
- const json4 = _json;
19780
- json4.type = "string";
20500
+ const json6 = _json;
20501
+ json6.type = "string";
19781
20502
  const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag;
19782
20503
  if (typeof minimum === "number")
19783
- json4.minLength = minimum;
20504
+ json6.minLength = minimum;
19784
20505
  if (typeof maximum === "number")
19785
- json4.maxLength = maximum;
20506
+ json6.maxLength = maximum;
19786
20507
  if (format) {
19787
- json4.format = formatMap[format] ?? format;
19788
- if (json4.format === "")
19789
- delete json4.format;
20508
+ json6.format = formatMap[format] ?? format;
20509
+ if (json6.format === "")
20510
+ delete json6.format;
19790
20511
  if (format === "time") {
19791
- delete json4.format;
20512
+ delete json6.format;
19792
20513
  }
19793
20514
  }
19794
20515
  if (contentEncoding)
19795
- json4.contentEncoding = contentEncoding;
20516
+ json6.contentEncoding = contentEncoding;
19796
20517
  if (patterns && patterns.size > 0) {
19797
20518
  const regexes = [...patterns];
19798
20519
  if (regexes.length === 1)
19799
- json4.pattern = regexes[0].source;
20520
+ json6.pattern = regexes[0].source;
19800
20521
  else if (regexes.length > 1) {
19801
- json4.allOf = [
20522
+ json6.allOf = [
19802
20523
  ...regexes.map((regex) => ({
19803
20524
  ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {},
19804
20525
  pattern: regex.source
@@ -19808,40 +20529,40 @@ var stringProcessor = (schema, ctx, _json, _params) => {
19808
20529
  }
19809
20530
  };
19810
20531
  var numberProcessor = (schema, ctx, _json, _params) => {
19811
- const json4 = _json;
20532
+ const json6 = _json;
19812
20533
  const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag;
19813
20534
  if (typeof format === "string" && format.includes("int"))
19814
- json4.type = "integer";
20535
+ json6.type = "integer";
19815
20536
  else
19816
- json4.type = "number";
20537
+ json6.type = "number";
19817
20538
  const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
19818
20539
  const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
19819
20540
  const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
19820
20541
  if (exMin) {
19821
20542
  if (legacy) {
19822
- json4.minimum = exclusiveMinimum;
19823
- json4.exclusiveMinimum = true;
20543
+ json6.minimum = exclusiveMinimum;
20544
+ json6.exclusiveMinimum = true;
19824
20545
  } else {
19825
- json4.exclusiveMinimum = exclusiveMinimum;
20546
+ json6.exclusiveMinimum = exclusiveMinimum;
19826
20547
  }
19827
20548
  } else if (typeof minimum === "number") {
19828
- json4.minimum = minimum;
20549
+ json6.minimum = minimum;
19829
20550
  }
19830
20551
  if (exMax) {
19831
20552
  if (legacy) {
19832
- json4.maximum = exclusiveMaximum;
19833
- json4.exclusiveMaximum = true;
20553
+ json6.maximum = exclusiveMaximum;
20554
+ json6.exclusiveMaximum = true;
19834
20555
  } else {
19835
- json4.exclusiveMaximum = exclusiveMaximum;
20556
+ json6.exclusiveMaximum = exclusiveMaximum;
19836
20557
  }
19837
20558
  } else if (typeof maximum === "number") {
19838
- json4.maximum = maximum;
20559
+ json6.maximum = maximum;
19839
20560
  }
19840
20561
  if (typeof multipleOf === "number")
19841
- json4.multipleOf = multipleOf;
20562
+ json6.multipleOf = multipleOf;
19842
20563
  };
19843
- var booleanProcessor = (_schema, _ctx, json4, _params) => {
19844
- json4.type = "boolean";
20564
+ var booleanProcessor = (_schema, _ctx, json6, _params) => {
20565
+ json6.type = "boolean";
19845
20566
  };
19846
20567
  var bigintProcessor = (_schema, ctx, _json, _params) => {
19847
20568
  if (ctx.unrepresentable === "throw") {
@@ -19853,13 +20574,13 @@ var symbolProcessor = (_schema, ctx, _json, _params) => {
19853
20574
  throw new Error("Symbols cannot be represented in JSON Schema");
19854
20575
  }
19855
20576
  };
19856
- var nullProcessor = (_schema, ctx, json4, _params) => {
20577
+ var nullProcessor = (_schema, ctx, json6, _params) => {
19857
20578
  if (ctx.target === "openapi-3.0") {
19858
- json4.type = "string";
19859
- json4.nullable = true;
19860
- json4.enum = [null];
20579
+ json6.type = "string";
20580
+ json6.nullable = true;
20581
+ json6.enum = [null];
19861
20582
  } else {
19862
- json4.type = "null";
20583
+ json6.type = "null";
19863
20584
  }
19864
20585
  };
19865
20586
  var undefinedProcessor = (_schema, ctx, _json, _params) => {
@@ -19872,8 +20593,8 @@ var voidProcessor = (_schema, ctx, _json, _params) => {
19872
20593
  throw new Error("Void cannot be represented in JSON Schema");
19873
20594
  }
19874
20595
  };
19875
- var neverProcessor = (_schema, _ctx, json4, _params) => {
19876
- json4.not = {};
20596
+ var neverProcessor = (_schema, _ctx, json6, _params) => {
20597
+ json6.not = {};
19877
20598
  };
19878
20599
  var anyProcessor = (_schema, _ctx, _json, _params) => {};
19879
20600
  var unknownProcessor = (_schema, _ctx, _json, _params) => {};
@@ -19882,16 +20603,16 @@ var dateProcessor = (_schema, ctx, _json, _params) => {
19882
20603
  throw new Error("Date cannot be represented in JSON Schema");
19883
20604
  }
19884
20605
  };
19885
- var enumProcessor = (schema, _ctx, json4, _params) => {
20606
+ var enumProcessor = (schema, _ctx, json6, _params) => {
19886
20607
  const def = schema._zod.def;
19887
20608
  const values = getEnumValues(def.entries);
19888
20609
  if (values.every((v) => typeof v === "number"))
19889
- json4.type = "number";
20610
+ json6.type = "number";
19890
20611
  if (values.every((v) => typeof v === "string"))
19891
- json4.type = "string";
19892
- json4.enum = values;
20612
+ json6.type = "string";
20613
+ json6.enum = values;
19893
20614
  };
19894
- var literalProcessor = (schema, ctx, json4, _params) => {
20615
+ var literalProcessor = (schema, ctx, json6, _params) => {
19895
20616
  const def = schema._zod.def;
19896
20617
  const vals = [];
19897
20618
  for (const val of def.values) {
@@ -19911,22 +20632,22 @@ var literalProcessor = (schema, ctx, json4, _params) => {
19911
20632
  }
19912
20633
  if (vals.length === 0) {} else if (vals.length === 1) {
19913
20634
  const val = vals[0];
19914
- json4.type = val === null ? "null" : typeof val;
20635
+ json6.type = val === null ? "null" : typeof val;
19915
20636
  if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
19916
- json4.enum = [val];
20637
+ json6.enum = [val];
19917
20638
  } else {
19918
- json4.const = val;
20639
+ json6.const = val;
19919
20640
  }
19920
20641
  } else {
19921
20642
  if (vals.every((v) => typeof v === "number"))
19922
- json4.type = "number";
20643
+ json6.type = "number";
19923
20644
  if (vals.every((v) => typeof v === "string"))
19924
- json4.type = "string";
20645
+ json6.type = "string";
19925
20646
  if (vals.every((v) => typeof v === "boolean"))
19926
- json4.type = "boolean";
20647
+ json6.type = "boolean";
19927
20648
  if (vals.every((v) => v === null))
19928
- json4.type = "null";
19929
- json4.enum = vals;
20649
+ json6.type = "null";
20650
+ json6.enum = vals;
19930
20651
  }
19931
20652
  };
19932
20653
  var nanProcessor = (_schema, ctx, _json, _params) => {
@@ -19934,16 +20655,16 @@ var nanProcessor = (_schema, ctx, _json, _params) => {
19934
20655
  throw new Error("NaN cannot be represented in JSON Schema");
19935
20656
  }
19936
20657
  };
19937
- var templateLiteralProcessor = (schema, _ctx, json4, _params) => {
19938
- const _json = json4;
20658
+ var templateLiteralProcessor = (schema, _ctx, json6, _params) => {
20659
+ const _json = json6;
19939
20660
  const pattern = schema._zod.pattern;
19940
20661
  if (!pattern)
19941
20662
  throw new Error("Pattern not found in template literal");
19942
20663
  _json.type = "string";
19943
20664
  _json.pattern = pattern.source;
19944
20665
  };
19945
- var fileProcessor = (schema, _ctx, json4, _params) => {
19946
- const _json = json4;
20666
+ var fileProcessor = (schema, _ctx, json6, _params) => {
20667
+ const _json = json6;
19947
20668
  const file = {
19948
20669
  type: "string",
19949
20670
  format: "binary",
@@ -19966,8 +20687,8 @@ var fileProcessor = (schema, _ctx, json4, _params) => {
19966
20687
  Object.assign(_json, file);
19967
20688
  }
19968
20689
  };
19969
- var successProcessor = (_schema, _ctx, json4, _params) => {
19970
- json4.type = "boolean";
20690
+ var successProcessor = (_schema, _ctx, json6, _params) => {
20691
+ json6.type = "boolean";
19971
20692
  };
19972
20693
  var customProcessor = (_schema, ctx, _json, _params) => {
19973
20694
  if (ctx.unrepresentable === "throw") {
@@ -19995,27 +20716,27 @@ var setProcessor = (_schema, ctx, _json, _params) => {
19995
20716
  }
19996
20717
  };
19997
20718
  var arrayProcessor = (schema, ctx, _json, params) => {
19998
- const json4 = _json;
20719
+ const json6 = _json;
19999
20720
  const def = schema._zod.def;
20000
20721
  const { minimum, maximum } = schema._zod.bag;
20001
20722
  if (typeof minimum === "number")
20002
- json4.minItems = minimum;
20723
+ json6.minItems = minimum;
20003
20724
  if (typeof maximum === "number")
20004
- json4.maxItems = maximum;
20005
- json4.type = "array";
20006
- json4.items = process2(def.element, ctx, {
20725
+ json6.maxItems = maximum;
20726
+ json6.type = "array";
20727
+ json6.items = process2(def.element, ctx, {
20007
20728
  ...params,
20008
20729
  path: [...params.path, "items"]
20009
20730
  });
20010
20731
  };
20011
20732
  var objectProcessor = (schema, ctx, _json, params) => {
20012
- const json4 = _json;
20733
+ const json6 = _json;
20013
20734
  const def = schema._zod.def;
20014
- json4.type = "object";
20015
- json4.properties = {};
20735
+ json6.type = "object";
20736
+ json6.properties = {};
20016
20737
  const shape = def.shape;
20017
20738
  for (const key in shape) {
20018
- json4.properties[key] = process2(shape[key], ctx, {
20739
+ json6.properties[key] = process2(shape[key], ctx, {
20019
20740
  ...params,
20020
20741
  path: [...params.path, "properties", key]
20021
20742
  });
@@ -20030,21 +20751,21 @@ var objectProcessor = (schema, ctx, _json, params) => {
20030
20751
  }
20031
20752
  }));
20032
20753
  if (requiredKeys.size > 0) {
20033
- json4.required = Array.from(requiredKeys);
20754
+ json6.required = Array.from(requiredKeys);
20034
20755
  }
20035
20756
  if (def.catchall?._zod.def.type === "never") {
20036
- json4.additionalProperties = false;
20757
+ json6.additionalProperties = false;
20037
20758
  } else if (!def.catchall) {
20038
20759
  if (ctx.io === "output")
20039
- json4.additionalProperties = false;
20760
+ json6.additionalProperties = false;
20040
20761
  } else if (def.catchall) {
20041
- json4.additionalProperties = process2(def.catchall, ctx, {
20762
+ json6.additionalProperties = process2(def.catchall, ctx, {
20042
20763
  ...params,
20043
20764
  path: [...params.path, "additionalProperties"]
20044
20765
  });
20045
20766
  }
20046
20767
  };
20047
- var unionProcessor = (schema, ctx, json4, params) => {
20768
+ var unionProcessor = (schema, ctx, json6, params) => {
20048
20769
  const def = schema._zod.def;
20049
20770
  const isExclusive = def.inclusive === false;
20050
20771
  const options = def.options.map((x, i) => process2(x, ctx, {
@@ -20052,12 +20773,12 @@ var unionProcessor = (schema, ctx, json4, params) => {
20052
20773
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
20053
20774
  }));
20054
20775
  if (isExclusive) {
20055
- json4.oneOf = options;
20776
+ json6.oneOf = options;
20056
20777
  } else {
20057
- json4.anyOf = options;
20778
+ json6.anyOf = options;
20058
20779
  }
20059
20780
  };
20060
- var intersectionProcessor = (schema, ctx, json4, params) => {
20781
+ var intersectionProcessor = (schema, ctx, json6, params) => {
20061
20782
  const def = schema._zod.def;
20062
20783
  const a = process2(def.left, ctx, {
20063
20784
  ...params,
@@ -20072,12 +20793,12 @@ var intersectionProcessor = (schema, ctx, json4, params) => {
20072
20793
  ...isSimpleIntersection(a) ? a.allOf : [a],
20073
20794
  ...isSimpleIntersection(b) ? b.allOf : [b]
20074
20795
  ];
20075
- json4.allOf = allOf;
20796
+ json6.allOf = allOf;
20076
20797
  };
20077
20798
  var tupleProcessor = (schema, ctx, _json, params) => {
20078
- const json4 = _json;
20799
+ const json6 = _json;
20079
20800
  const def = schema._zod.def;
20080
- json4.type = "array";
20801
+ json6.type = "array";
20081
20802
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
20082
20803
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
20083
20804
  const prefixItems = def.items.map((x, i) => process2(x, ctx, {
@@ -20089,37 +20810,37 @@ var tupleProcessor = (schema, ctx, _json, params) => {
20089
20810
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
20090
20811
  }) : null;
20091
20812
  if (ctx.target === "draft-2020-12") {
20092
- json4.prefixItems = prefixItems;
20813
+ json6.prefixItems = prefixItems;
20093
20814
  if (rest) {
20094
- json4.items = rest;
20815
+ json6.items = rest;
20095
20816
  }
20096
20817
  } else if (ctx.target === "openapi-3.0") {
20097
- json4.items = {
20818
+ json6.items = {
20098
20819
  anyOf: prefixItems
20099
20820
  };
20100
20821
  if (rest) {
20101
- json4.items.anyOf.push(rest);
20822
+ json6.items.anyOf.push(rest);
20102
20823
  }
20103
- json4.minItems = prefixItems.length;
20824
+ json6.minItems = prefixItems.length;
20104
20825
  if (!rest) {
20105
- json4.maxItems = prefixItems.length;
20826
+ json6.maxItems = prefixItems.length;
20106
20827
  }
20107
20828
  } else {
20108
- json4.items = prefixItems;
20829
+ json6.items = prefixItems;
20109
20830
  if (rest) {
20110
- json4.additionalItems = rest;
20831
+ json6.additionalItems = rest;
20111
20832
  }
20112
20833
  }
20113
20834
  const { minimum, maximum } = schema._zod.bag;
20114
20835
  if (typeof minimum === "number")
20115
- json4.minItems = minimum;
20836
+ json6.minItems = minimum;
20116
20837
  if (typeof maximum === "number")
20117
- json4.maxItems = maximum;
20838
+ json6.maxItems = maximum;
20118
20839
  };
20119
20840
  var recordProcessor = (schema, ctx, _json, params) => {
20120
- const json4 = _json;
20841
+ const json6 = _json;
20121
20842
  const def = schema._zod.def;
20122
- json4.type = "object";
20843
+ json6.type = "object";
20123
20844
  const keyType = def.keyType;
20124
20845
  const keyBag = keyType._zod.bag;
20125
20846
  const patterns = keyBag?.patterns;
@@ -20128,18 +20849,18 @@ var recordProcessor = (schema, ctx, _json, params) => {
20128
20849
  ...params,
20129
20850
  path: [...params.path, "patternProperties", "*"]
20130
20851
  });
20131
- json4.patternProperties = {};
20852
+ json6.patternProperties = {};
20132
20853
  for (const pattern of patterns) {
20133
- json4.patternProperties[pattern.source] = valueSchema;
20854
+ json6.patternProperties[pattern.source] = valueSchema;
20134
20855
  }
20135
20856
  } else {
20136
20857
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
20137
- json4.propertyNames = process2(def.keyType, ctx, {
20858
+ json6.propertyNames = process2(def.keyType, ctx, {
20138
20859
  ...params,
20139
20860
  path: [...params.path, "propertyNames"]
20140
20861
  });
20141
20862
  }
20142
- json4.additionalProperties = process2(def.valueType, ctx, {
20863
+ json6.additionalProperties = process2(def.valueType, ctx, {
20143
20864
  ...params,
20144
20865
  path: [...params.path, "additionalProperties"]
20145
20866
  });
@@ -20148,19 +20869,19 @@ var recordProcessor = (schema, ctx, _json, params) => {
20148
20869
  if (keyValues) {
20149
20870
  const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
20150
20871
  if (validKeyValues.length > 0) {
20151
- json4.required = validKeyValues;
20872
+ json6.required = validKeyValues;
20152
20873
  }
20153
20874
  }
20154
20875
  };
20155
- var nullableProcessor = (schema, ctx, json4, params) => {
20876
+ var nullableProcessor = (schema, ctx, json6, params) => {
20156
20877
  const def = schema._zod.def;
20157
20878
  const inner = process2(def.innerType, ctx, params);
20158
20879
  const seen = ctx.seen.get(schema);
20159
20880
  if (ctx.target === "openapi-3.0") {
20160
20881
  seen.ref = def.innerType;
20161
- json4.nullable = true;
20882
+ json6.nullable = true;
20162
20883
  } else {
20163
- json4.anyOf = [inner, { type: "null" }];
20884
+ json6.anyOf = [inner, { type: "null" }];
20164
20885
  }
20165
20886
  };
20166
20887
  var nonoptionalProcessor = (schema, ctx, _json, params) => {
@@ -20169,22 +20890,22 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
20169
20890
  const seen = ctx.seen.get(schema);
20170
20891
  seen.ref = def.innerType;
20171
20892
  };
20172
- var defaultProcessor = (schema, ctx, json4, params) => {
20893
+ var defaultProcessor = (schema, ctx, json6, params) => {
20173
20894
  const def = schema._zod.def;
20174
20895
  process2(def.innerType, ctx, params);
20175
20896
  const seen = ctx.seen.get(schema);
20176
20897
  seen.ref = def.innerType;
20177
- json4.default = JSON.parse(JSON.stringify(def.defaultValue));
20898
+ json6.default = JSON.parse(JSON.stringify(def.defaultValue));
20178
20899
  };
20179
- var prefaultProcessor = (schema, ctx, json4, params) => {
20900
+ var prefaultProcessor = (schema, ctx, json6, params) => {
20180
20901
  const def = schema._zod.def;
20181
20902
  process2(def.innerType, ctx, params);
20182
20903
  const seen = ctx.seen.get(schema);
20183
20904
  seen.ref = def.innerType;
20184
20905
  if (ctx.io === "input")
20185
- json4._prefault = JSON.parse(JSON.stringify(def.defaultValue));
20906
+ json6._prefault = JSON.parse(JSON.stringify(def.defaultValue));
20186
20907
  };
20187
- var catchProcessor = (schema, ctx, json4, params) => {
20908
+ var catchProcessor = (schema, ctx, json6, params) => {
20188
20909
  const def = schema._zod.def;
20189
20910
  process2(def.innerType, ctx, params);
20190
20911
  const seen = ctx.seen.get(schema);
@@ -20195,7 +20916,7 @@ var catchProcessor = (schema, ctx, json4, params) => {
20195
20916
  } catch {
20196
20917
  throw new Error("Dynamic catch values are not supported in JSON Schema");
20197
20918
  }
20198
- json4.default = catchValue;
20919
+ json6.default = catchValue;
20199
20920
  };
20200
20921
  var pipeProcessor = (schema, ctx, _json, params) => {
20201
20922
  const def = schema._zod.def;
@@ -20205,12 +20926,12 @@ var pipeProcessor = (schema, ctx, _json, params) => {
20205
20926
  const seen = ctx.seen.get(schema);
20206
20927
  seen.ref = innerType;
20207
20928
  };
20208
- var readonlyProcessor = (schema, ctx, json4, params) => {
20929
+ var readonlyProcessor = (schema, ctx, json6, params) => {
20209
20930
  const def = schema._zod.def;
20210
20931
  process2(def.innerType, ctx, params);
20211
20932
  const seen = ctx.seen.get(schema);
20212
20933
  seen.ref = def.innerType;
20213
- json4.readOnly = true;
20934
+ json6.readOnly = true;
20214
20935
  };
20215
20936
  var promiseProcessor = (schema, ctx, _json, params) => {
20216
20937
  const def = schema._zod.def;
@@ -20480,7 +21201,7 @@ __export(exports_schemas2, {
20480
21201
  invertCodec: () => invertCodec,
20481
21202
  ipv4: () => ipv42,
20482
21203
  ipv6: () => ipv62,
20483
- json: () => json4,
21204
+ json: () => json6,
20484
21205
  jwt: () => jwt,
20485
21206
  keyof: () => keyof,
20486
21207
  ksuid: () => ksuid2,
@@ -20831,7 +21552,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
20831
21552
  var _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => {
20832
21553
  $ZodString.init(inst, def);
20833
21554
  ZodType.init(inst, def);
20834
- inst._zod.processJSONSchema = (ctx, json4, params) => stringProcessor(inst, ctx, json4, params);
21555
+ inst._zod.processJSONSchema = (ctx, json6, params) => stringProcessor(inst, ctx, json6, params);
20835
21556
  const bag = inst._zod.bag;
20836
21557
  inst.format = bag.format ?? null;
20837
21558
  inst.minLength = bag.minimum ?? null;
@@ -21102,7 +21823,7 @@ function hash2(alg, params) {
21102
21823
  var ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
21103
21824
  $ZodNumber.init(inst, def);
21104
21825
  ZodType.init(inst, def);
21105
- inst._zod.processJSONSchema = (ctx, json4, params) => numberProcessor(inst, ctx, json4, params);
21826
+ inst._zod.processJSONSchema = (ctx, json6, params) => numberProcessor(inst, ctx, json6, params);
21106
21827
  _installLazyMethods(inst, "ZodNumber", {
21107
21828
  gt(value, params) {
21108
21829
  return this.check(_gt(value, params));
@@ -21182,7 +21903,7 @@ function uint32(params) {
21182
21903
  var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
21183
21904
  $ZodBoolean.init(inst, def);
21184
21905
  ZodType.init(inst, def);
21185
- inst._zod.processJSONSchema = (ctx, json4, params) => booleanProcessor(inst, ctx, json4, params);
21906
+ inst._zod.processJSONSchema = (ctx, json6, params) => booleanProcessor(inst, ctx, json6, params);
21186
21907
  });
21187
21908
  function boolean2(params) {
21188
21909
  return _boolean(ZodBoolean, params);
@@ -21190,7 +21911,7 @@ function boolean2(params) {
21190
21911
  var ZodBigInt = /* @__PURE__ */ $constructor("ZodBigInt", (inst, def) => {
21191
21912
  $ZodBigInt.init(inst, def);
21192
21913
  ZodType.init(inst, def);
21193
- inst._zod.processJSONSchema = (ctx, json4, params) => bigintProcessor(inst, ctx, json4, params);
21914
+ inst._zod.processJSONSchema = (ctx, json6, params) => bigintProcessor(inst, ctx, json6, params);
21194
21915
  inst.gte = (value, params) => inst.check(_gte(value, params));
21195
21916
  inst.min = (value, params) => inst.check(_gte(value, params));
21196
21917
  inst.gt = (value, params) => inst.check(_gt(value, params));
@@ -21225,7 +21946,7 @@ function uint64(params) {
21225
21946
  var ZodSymbol = /* @__PURE__ */ $constructor("ZodSymbol", (inst, def) => {
21226
21947
  $ZodSymbol.init(inst, def);
21227
21948
  ZodType.init(inst, def);
21228
- inst._zod.processJSONSchema = (ctx, json4, params) => symbolProcessor(inst, ctx, json4, params);
21949
+ inst._zod.processJSONSchema = (ctx, json6, params) => symbolProcessor(inst, ctx, json6, params);
21229
21950
  });
21230
21951
  function symbol(params) {
21231
21952
  return _symbol(ZodSymbol, params);
@@ -21233,7 +21954,7 @@ function symbol(params) {
21233
21954
  var ZodUndefined = /* @__PURE__ */ $constructor("ZodUndefined", (inst, def) => {
21234
21955
  $ZodUndefined.init(inst, def);
21235
21956
  ZodType.init(inst, def);
21236
- inst._zod.processJSONSchema = (ctx, json4, params) => undefinedProcessor(inst, ctx, json4, params);
21957
+ inst._zod.processJSONSchema = (ctx, json6, params) => undefinedProcessor(inst, ctx, json6, params);
21237
21958
  });
21238
21959
  function _undefined3(params) {
21239
21960
  return _undefined2(ZodUndefined, params);
@@ -21241,7 +21962,7 @@ function _undefined3(params) {
21241
21962
  var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
21242
21963
  $ZodNull.init(inst, def);
21243
21964
  ZodType.init(inst, def);
21244
- inst._zod.processJSONSchema = (ctx, json4, params) => nullProcessor(inst, ctx, json4, params);
21965
+ inst._zod.processJSONSchema = (ctx, json6, params) => nullProcessor(inst, ctx, json6, params);
21245
21966
  });
21246
21967
  function _null3(params) {
21247
21968
  return _null2(ZodNull, params);
@@ -21249,7 +21970,7 @@ function _null3(params) {
21249
21970
  var ZodAny = /* @__PURE__ */ $constructor("ZodAny", (inst, def) => {
21250
21971
  $ZodAny.init(inst, def);
21251
21972
  ZodType.init(inst, def);
21252
- inst._zod.processJSONSchema = (ctx, json4, params) => anyProcessor(inst, ctx, json4, params);
21973
+ inst._zod.processJSONSchema = (ctx, json6, params) => anyProcessor(inst, ctx, json6, params);
21253
21974
  });
21254
21975
  function any() {
21255
21976
  return _any(ZodAny);
@@ -21257,7 +21978,7 @@ function any() {
21257
21978
  var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
21258
21979
  $ZodUnknown.init(inst, def);
21259
21980
  ZodType.init(inst, def);
21260
- inst._zod.processJSONSchema = (ctx, json4, params) => unknownProcessor(inst, ctx, json4, params);
21981
+ inst._zod.processJSONSchema = (ctx, json6, params) => unknownProcessor(inst, ctx, json6, params);
21261
21982
  });
21262
21983
  function unknown() {
21263
21984
  return _unknown(ZodUnknown);
@@ -21265,7 +21986,7 @@ function unknown() {
21265
21986
  var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => {
21266
21987
  $ZodNever.init(inst, def);
21267
21988
  ZodType.init(inst, def);
21268
- inst._zod.processJSONSchema = (ctx, json4, params) => neverProcessor(inst, ctx, json4, params);
21989
+ inst._zod.processJSONSchema = (ctx, json6, params) => neverProcessor(inst, ctx, json6, params);
21269
21990
  });
21270
21991
  function never(params) {
21271
21992
  return _never(ZodNever, params);
@@ -21273,7 +21994,7 @@ function never(params) {
21273
21994
  var ZodVoid = /* @__PURE__ */ $constructor("ZodVoid", (inst, def) => {
21274
21995
  $ZodVoid.init(inst, def);
21275
21996
  ZodType.init(inst, def);
21276
- inst._zod.processJSONSchema = (ctx, json4, params) => voidProcessor(inst, ctx, json4, params);
21997
+ inst._zod.processJSONSchema = (ctx, json6, params) => voidProcessor(inst, ctx, json6, params);
21277
21998
  });
21278
21999
  function _void2(params) {
21279
22000
  return _void(ZodVoid, params);
@@ -21281,7 +22002,7 @@ function _void2(params) {
21281
22002
  var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
21282
22003
  $ZodDate.init(inst, def);
21283
22004
  ZodType.init(inst, def);
21284
- inst._zod.processJSONSchema = (ctx, json4, params) => dateProcessor(inst, ctx, json4, params);
22005
+ inst._zod.processJSONSchema = (ctx, json6, params) => dateProcessor(inst, ctx, json6, params);
21285
22006
  inst.min = (value, params) => inst.check(_gte(value, params));
21286
22007
  inst.max = (value, params) => inst.check(_lte(value, params));
21287
22008
  const c = inst._zod.bag;
@@ -21294,7 +22015,7 @@ function date3(params) {
21294
22015
  var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
21295
22016
  $ZodArray.init(inst, def);
21296
22017
  ZodType.init(inst, def);
21297
- inst._zod.processJSONSchema = (ctx, json4, params) => arrayProcessor(inst, ctx, json4, params);
22018
+ inst._zod.processJSONSchema = (ctx, json6, params) => arrayProcessor(inst, ctx, json6, params);
21298
22019
  inst.element = def.element;
21299
22020
  _installLazyMethods(inst, "ZodArray", {
21300
22021
  min(n, params) {
@@ -21324,7 +22045,7 @@ function keyof(schema) {
21324
22045
  var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
21325
22046
  $ZodObjectJIT.init(inst, def);
21326
22047
  ZodType.init(inst, def);
21327
- inst._zod.processJSONSchema = (ctx, json4, params) => objectProcessor(inst, ctx, json4, params);
22048
+ inst._zod.processJSONSchema = (ctx, json6, params) => objectProcessor(inst, ctx, json6, params);
21328
22049
  exports_util.defineLazy(inst, "shape", () => {
21329
22050
  return def.shape;
21330
22051
  });
@@ -21397,7 +22118,7 @@ function looseObject(shape, params) {
21397
22118
  var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => {
21398
22119
  $ZodUnion.init(inst, def);
21399
22120
  ZodType.init(inst, def);
21400
- inst._zod.processJSONSchema = (ctx, json4, params) => unionProcessor(inst, ctx, json4, params);
22121
+ inst._zod.processJSONSchema = (ctx, json6, params) => unionProcessor(inst, ctx, json6, params);
21401
22122
  inst.options = def.options;
21402
22123
  });
21403
22124
  function union(options, params) {
@@ -21410,7 +22131,7 @@ function union(options, params) {
21410
22131
  var ZodXor = /* @__PURE__ */ $constructor("ZodXor", (inst, def) => {
21411
22132
  ZodUnion.init(inst, def);
21412
22133
  $ZodXor.init(inst, def);
21413
- inst._zod.processJSONSchema = (ctx, json4, params) => unionProcessor(inst, ctx, json4, params);
22134
+ inst._zod.processJSONSchema = (ctx, json6, params) => unionProcessor(inst, ctx, json6, params);
21414
22135
  inst.options = def.options;
21415
22136
  });
21416
22137
  function xor(options, params) {
@@ -21436,7 +22157,7 @@ function discriminatedUnion(discriminator, options, params) {
21436
22157
  var ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => {
21437
22158
  $ZodIntersection.init(inst, def);
21438
22159
  ZodType.init(inst, def);
21439
- inst._zod.processJSONSchema = (ctx, json4, params) => intersectionProcessor(inst, ctx, json4, params);
22160
+ inst._zod.processJSONSchema = (ctx, json6, params) => intersectionProcessor(inst, ctx, json6, params);
21440
22161
  });
21441
22162
  function intersection(left, right) {
21442
22163
  return new ZodIntersection({
@@ -21448,7 +22169,7 @@ function intersection(left, right) {
21448
22169
  var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
21449
22170
  $ZodTuple.init(inst, def);
21450
22171
  ZodType.init(inst, def);
21451
- inst._zod.processJSONSchema = (ctx, json4, params) => tupleProcessor(inst, ctx, json4, params);
22172
+ inst._zod.processJSONSchema = (ctx, json6, params) => tupleProcessor(inst, ctx, json6, params);
21452
22173
  inst.rest = (rest) => inst.clone({
21453
22174
  ...inst._zod.def,
21454
22175
  rest
@@ -21468,7 +22189,7 @@ function tuple(items, _paramsOrRest, _params) {
21468
22189
  var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
21469
22190
  $ZodRecord.init(inst, def);
21470
22191
  ZodType.init(inst, def);
21471
- inst._zod.processJSONSchema = (ctx, json4, params) => recordProcessor(inst, ctx, json4, params);
22192
+ inst._zod.processJSONSchema = (ctx, json6, params) => recordProcessor(inst, ctx, json6, params);
21472
22193
  inst.keyType = def.keyType;
21473
22194
  inst.valueType = def.valueType;
21474
22195
  });
@@ -21510,7 +22231,7 @@ function looseRecord(keyType, valueType, params) {
21510
22231
  var ZodMap = /* @__PURE__ */ $constructor("ZodMap", (inst, def) => {
21511
22232
  $ZodMap.init(inst, def);
21512
22233
  ZodType.init(inst, def);
21513
- inst._zod.processJSONSchema = (ctx, json4, params) => mapProcessor(inst, ctx, json4, params);
22234
+ inst._zod.processJSONSchema = (ctx, json6, params) => mapProcessor(inst, ctx, json6, params);
21514
22235
  inst.keyType = def.keyType;
21515
22236
  inst.valueType = def.valueType;
21516
22237
  inst.min = (...args) => inst.check(_minSize(...args));
@@ -21529,7 +22250,7 @@ function map(keyType, valueType, params) {
21529
22250
  var ZodSet = /* @__PURE__ */ $constructor("ZodSet", (inst, def) => {
21530
22251
  $ZodSet.init(inst, def);
21531
22252
  ZodType.init(inst, def);
21532
- inst._zod.processJSONSchema = (ctx, json4, params) => setProcessor(inst, ctx, json4, params);
22253
+ inst._zod.processJSONSchema = (ctx, json6, params) => setProcessor(inst, ctx, json6, params);
21533
22254
  inst.min = (...args) => inst.check(_minSize(...args));
21534
22255
  inst.nonempty = (params) => inst.check(_minSize(1, params));
21535
22256
  inst.max = (...args) => inst.check(_maxSize(...args));
@@ -21545,7 +22266,7 @@ function set(valueType, params) {
21545
22266
  var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
21546
22267
  $ZodEnum.init(inst, def);
21547
22268
  ZodType.init(inst, def);
21548
- inst._zod.processJSONSchema = (ctx, json4, params) => enumProcessor(inst, ctx, json4, params);
22269
+ inst._zod.processJSONSchema = (ctx, json6, params) => enumProcessor(inst, ctx, json6, params);
21549
22270
  inst.enum = def.entries;
21550
22271
  inst.options = Object.values(def.entries);
21551
22272
  const keys = new Set(Object.keys(def.entries));
@@ -21598,7 +22319,7 @@ function nativeEnum(entries, params) {
21598
22319
  var ZodLiteral = /* @__PURE__ */ $constructor("ZodLiteral", (inst, def) => {
21599
22320
  $ZodLiteral.init(inst, def);
21600
22321
  ZodType.init(inst, def);
21601
- inst._zod.processJSONSchema = (ctx, json4, params) => literalProcessor(inst, ctx, json4, params);
22322
+ inst._zod.processJSONSchema = (ctx, json6, params) => literalProcessor(inst, ctx, json6, params);
21602
22323
  inst.values = new Set(def.values);
21603
22324
  Object.defineProperty(inst, "value", {
21604
22325
  get() {
@@ -21619,7 +22340,7 @@ function literal(value, params) {
21619
22340
  var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
21620
22341
  $ZodFile.init(inst, def);
21621
22342
  ZodType.init(inst, def);
21622
- inst._zod.processJSONSchema = (ctx, json4, params) => fileProcessor(inst, ctx, json4, params);
22343
+ inst._zod.processJSONSchema = (ctx, json6, params) => fileProcessor(inst, ctx, json6, params);
21623
22344
  inst.min = (size, params) => inst.check(_minSize(size, params));
21624
22345
  inst.max = (size, params) => inst.check(_maxSize(size, params));
21625
22346
  inst.mime = (types2, params) => inst.check(_mime(Array.isArray(types2) ? types2 : [types2], params));
@@ -21630,7 +22351,7 @@ function file(params) {
21630
22351
  var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
21631
22352
  $ZodTransform.init(inst, def);
21632
22353
  ZodType.init(inst, def);
21633
- inst._zod.processJSONSchema = (ctx, json4, params) => transformProcessor(inst, ctx, json4, params);
22354
+ inst._zod.processJSONSchema = (ctx, json6, params) => transformProcessor(inst, ctx, json6, params);
21634
22355
  inst._zod.parse = (payload, _ctx) => {
21635
22356
  if (_ctx.direction === "backward") {
21636
22357
  throw new $ZodEncodeError(inst.constructor.name);
@@ -21670,7 +22391,7 @@ function transform(fn) {
21670
22391
  var ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => {
21671
22392
  $ZodOptional.init(inst, def);
21672
22393
  ZodType.init(inst, def);
21673
- inst._zod.processJSONSchema = (ctx, json4, params) => optionalProcessor(inst, ctx, json4, params);
22394
+ inst._zod.processJSONSchema = (ctx, json6, params) => optionalProcessor(inst, ctx, json6, params);
21674
22395
  inst.unwrap = () => inst._zod.def.innerType;
21675
22396
  });
21676
22397
  function optional(innerType) {
@@ -21682,7 +22403,7 @@ function optional(innerType) {
21682
22403
  var ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => {
21683
22404
  $ZodExactOptional.init(inst, def);
21684
22405
  ZodType.init(inst, def);
21685
- inst._zod.processJSONSchema = (ctx, json4, params) => optionalProcessor(inst, ctx, json4, params);
22406
+ inst._zod.processJSONSchema = (ctx, json6, params) => optionalProcessor(inst, ctx, json6, params);
21686
22407
  inst.unwrap = () => inst._zod.def.innerType;
21687
22408
  });
21688
22409
  function exactOptional(innerType) {
@@ -21694,7 +22415,7 @@ function exactOptional(innerType) {
21694
22415
  var ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => {
21695
22416
  $ZodNullable.init(inst, def);
21696
22417
  ZodType.init(inst, def);
21697
- inst._zod.processJSONSchema = (ctx, json4, params) => nullableProcessor(inst, ctx, json4, params);
22418
+ inst._zod.processJSONSchema = (ctx, json6, params) => nullableProcessor(inst, ctx, json6, params);
21698
22419
  inst.unwrap = () => inst._zod.def.innerType;
21699
22420
  });
21700
22421
  function nullable(innerType) {
@@ -21709,7 +22430,7 @@ function nullish2(innerType) {
21709
22430
  var ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => {
21710
22431
  $ZodDefault.init(inst, def);
21711
22432
  ZodType.init(inst, def);
21712
- inst._zod.processJSONSchema = (ctx, json4, params) => defaultProcessor(inst, ctx, json4, params);
22433
+ inst._zod.processJSONSchema = (ctx, json6, params) => defaultProcessor(inst, ctx, json6, params);
21713
22434
  inst.unwrap = () => inst._zod.def.innerType;
21714
22435
  inst.removeDefault = inst.unwrap;
21715
22436
  });
@@ -21725,7 +22446,7 @@ function _default2(innerType, defaultValue) {
21725
22446
  var ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => {
21726
22447
  $ZodPrefault.init(inst, def);
21727
22448
  ZodType.init(inst, def);
21728
- inst._zod.processJSONSchema = (ctx, json4, params) => prefaultProcessor(inst, ctx, json4, params);
22449
+ inst._zod.processJSONSchema = (ctx, json6, params) => prefaultProcessor(inst, ctx, json6, params);
21729
22450
  inst.unwrap = () => inst._zod.def.innerType;
21730
22451
  });
21731
22452
  function prefault(innerType, defaultValue) {
@@ -21740,7 +22461,7 @@ function prefault(innerType, defaultValue) {
21740
22461
  var ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => {
21741
22462
  $ZodNonOptional.init(inst, def);
21742
22463
  ZodType.init(inst, def);
21743
- inst._zod.processJSONSchema = (ctx, json4, params) => nonoptionalProcessor(inst, ctx, json4, params);
22464
+ inst._zod.processJSONSchema = (ctx, json6, params) => nonoptionalProcessor(inst, ctx, json6, params);
21744
22465
  inst.unwrap = () => inst._zod.def.innerType;
21745
22466
  });
21746
22467
  function nonoptional(innerType, params) {
@@ -21753,7 +22474,7 @@ function nonoptional(innerType, params) {
21753
22474
  var ZodSuccess = /* @__PURE__ */ $constructor("ZodSuccess", (inst, def) => {
21754
22475
  $ZodSuccess.init(inst, def);
21755
22476
  ZodType.init(inst, def);
21756
- inst._zod.processJSONSchema = (ctx, json4, params) => successProcessor(inst, ctx, json4, params);
22477
+ inst._zod.processJSONSchema = (ctx, json6, params) => successProcessor(inst, ctx, json6, params);
21757
22478
  inst.unwrap = () => inst._zod.def.innerType;
21758
22479
  });
21759
22480
  function success(innerType) {
@@ -21765,7 +22486,7 @@ function success(innerType) {
21765
22486
  var ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => {
21766
22487
  $ZodCatch.init(inst, def);
21767
22488
  ZodType.init(inst, def);
21768
- inst._zod.processJSONSchema = (ctx, json4, params) => catchProcessor(inst, ctx, json4, params);
22489
+ inst._zod.processJSONSchema = (ctx, json6, params) => catchProcessor(inst, ctx, json6, params);
21769
22490
  inst.unwrap = () => inst._zod.def.innerType;
21770
22491
  inst.removeCatch = inst.unwrap;
21771
22492
  });
@@ -21779,7 +22500,7 @@ function _catch2(innerType, catchValue) {
21779
22500
  var ZodNaN = /* @__PURE__ */ $constructor("ZodNaN", (inst, def) => {
21780
22501
  $ZodNaN.init(inst, def);
21781
22502
  ZodType.init(inst, def);
21782
- inst._zod.processJSONSchema = (ctx, json4, params) => nanProcessor(inst, ctx, json4, params);
22503
+ inst._zod.processJSONSchema = (ctx, json6, params) => nanProcessor(inst, ctx, json6, params);
21783
22504
  });
21784
22505
  function nan(params) {
21785
22506
  return _nan(ZodNaN, params);
@@ -21787,7 +22508,7 @@ function nan(params) {
21787
22508
  var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => {
21788
22509
  $ZodPipe.init(inst, def);
21789
22510
  ZodType.init(inst, def);
21790
- inst._zod.processJSONSchema = (ctx, json4, params) => pipeProcessor(inst, ctx, json4, params);
22511
+ inst._zod.processJSONSchema = (ctx, json6, params) => pipeProcessor(inst, ctx, json6, params);
21791
22512
  inst.in = def.in;
21792
22513
  inst.out = def.out;
21793
22514
  });
@@ -21828,7 +22549,7 @@ var ZodPreprocess = /* @__PURE__ */ $constructor("ZodPreprocess", (inst, def) =>
21828
22549
  var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => {
21829
22550
  $ZodReadonly.init(inst, def);
21830
22551
  ZodType.init(inst, def);
21831
- inst._zod.processJSONSchema = (ctx, json4, params) => readonlyProcessor(inst, ctx, json4, params);
22552
+ inst._zod.processJSONSchema = (ctx, json6, params) => readonlyProcessor(inst, ctx, json6, params);
21832
22553
  inst.unwrap = () => inst._zod.def.innerType;
21833
22554
  });
21834
22555
  function readonly(innerType) {
@@ -21840,7 +22561,7 @@ function readonly(innerType) {
21840
22561
  var ZodTemplateLiteral = /* @__PURE__ */ $constructor("ZodTemplateLiteral", (inst, def) => {
21841
22562
  $ZodTemplateLiteral.init(inst, def);
21842
22563
  ZodType.init(inst, def);
21843
- inst._zod.processJSONSchema = (ctx, json4, params) => templateLiteralProcessor(inst, ctx, json4, params);
22564
+ inst._zod.processJSONSchema = (ctx, json6, params) => templateLiteralProcessor(inst, ctx, json6, params);
21844
22565
  });
21845
22566
  function templateLiteral(parts, params) {
21846
22567
  return new ZodTemplateLiteral({
@@ -21852,7 +22573,7 @@ function templateLiteral(parts, params) {
21852
22573
  var ZodLazy = /* @__PURE__ */ $constructor("ZodLazy", (inst, def) => {
21853
22574
  $ZodLazy.init(inst, def);
21854
22575
  ZodType.init(inst, def);
21855
- inst._zod.processJSONSchema = (ctx, json4, params) => lazyProcessor(inst, ctx, json4, params);
22576
+ inst._zod.processJSONSchema = (ctx, json6, params) => lazyProcessor(inst, ctx, json6, params);
21856
22577
  inst.unwrap = () => inst._zod.def.getter();
21857
22578
  });
21858
22579
  function lazy(getter) {
@@ -21864,7 +22585,7 @@ function lazy(getter) {
21864
22585
  var ZodPromise = /* @__PURE__ */ $constructor("ZodPromise", (inst, def) => {
21865
22586
  $ZodPromise.init(inst, def);
21866
22587
  ZodType.init(inst, def);
21867
- inst._zod.processJSONSchema = (ctx, json4, params) => promiseProcessor(inst, ctx, json4, params);
22588
+ inst._zod.processJSONSchema = (ctx, json6, params) => promiseProcessor(inst, ctx, json6, params);
21868
22589
  inst.unwrap = () => inst._zod.def.innerType;
21869
22590
  });
21870
22591
  function promise(innerType) {
@@ -21876,7 +22597,7 @@ function promise(innerType) {
21876
22597
  var ZodFunction = /* @__PURE__ */ $constructor("ZodFunction", (inst, def) => {
21877
22598
  $ZodFunction.init(inst, def);
21878
22599
  ZodType.init(inst, def);
21879
- inst._zod.processJSONSchema = (ctx, json4, params) => functionProcessor(inst, ctx, json4, params);
22600
+ inst._zod.processJSONSchema = (ctx, json6, params) => functionProcessor(inst, ctx, json6, params);
21880
22601
  });
21881
22602
  function _function(params) {
21882
22603
  return new ZodFunction({
@@ -21888,7 +22609,7 @@ function _function(params) {
21888
22609
  var ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => {
21889
22610
  $ZodCustom.init(inst, def);
21890
22611
  ZodType.init(inst, def);
21891
- inst._zod.processJSONSchema = (ctx, json4, params) => customProcessor(inst, ctx, json4, params);
22612
+ inst._zod.processJSONSchema = (ctx, json6, params) => customProcessor(inst, ctx, json6, params);
21892
22613
  });
21893
22614
  function check(fn) {
21894
22615
  const ch = new $ZodCheck({
@@ -21935,7 +22656,7 @@ var stringbool = (...args) => _stringbool({
21935
22656
  Boolean: ZodBoolean,
21936
22657
  String: ZodString
21937
22658
  }, ...args);
21938
- function json4(params) {
22659
+ function json6(params) {
21939
22660
  const jsonSchema = lazy(() => {
21940
22661
  return union([string2(params), number2(), boolean2(), _null3(), array(jsonSchema), record(string2(), jsonSchema)]);
21941
22662
  });
@@ -22475,7 +23196,15 @@ function parseOrThrow(schema, body2) {
22475
23196
  const path = issue2?.path.join(".") ?? "(root)";
22476
23197
  throw new GatewayError("BAD_REQUEST", `${path}: ${issue2?.message ?? "invalid request"}`);
22477
23198
  }
22478
- var providerIdSchema = exports_external.enum(["anthropic", "openai", "kimi", "custom"]);
23199
+ function optionalNumber(value, fallback) {
23200
+ if (value === undefined)
23201
+ return fallback;
23202
+ if (typeof value === "string" && value.trim().length === 0)
23203
+ return fallback;
23204
+ const parsed = Number(value);
23205
+ return Number.isFinite(parsed) ? parsed : fallback;
23206
+ }
23207
+ var providerIdSchema = exports_external.enum(["anthropic", "openai", "kimi", "kilo", "grok", "custom"]);
22479
23208
  var dryRunSchema = exports_external.object({
22480
23209
  tools: exports_external.boolean().default(false),
22481
23210
  images: exports_external.boolean().default(false),
@@ -22483,7 +23212,7 @@ var dryRunSchema = exports_external.object({
22483
23212
  }).strict();
22484
23213
  var targetSchema = exports_external.discriminatedUnion("provider", [
22485
23214
  exports_external.object({
22486
- provider: exports_external.enum(["anthropic", "openai", "kimi"]),
23215
+ provider: exports_external.enum(["anthropic", "openai", "kimi", "kilo", "grok"]),
22487
23216
  model: exports_external.string().min(1),
22488
23217
  tier: exports_external.number().int().min(1),
22489
23218
  weight: exports_external.number().positive(),
@@ -22580,124 +23309,57 @@ function requireDimension(grain, dimension) {
22580
23309
  throw new GatewayError("BAD_REQUEST", `usage grain "${grain}" cannot group by "${dimension}"`);
22581
23310
  }
22582
23311
 
22583
- // packages/control/src/credentials.ts
22584
- function summarizeCredential(credential) {
22585
- return {
22586
- id: credential.id,
22587
- provider: credential.provider,
22588
- label: credential.label,
22589
- authType: credential.authType,
22590
- enabled: credential.enabled,
22591
- tier: credential.tier,
22592
- weight: credential.weight,
22593
- expiresAt: credential.expiresAt,
22594
- accountEmail: credential.accountEmail,
22595
- providerData: credential.providerData,
22596
- disabledReason: credential.disabledReason,
22597
- disabledAt: credential.disabledAt,
22598
- hasRefreshToken: credential.hasRefreshToken,
22599
- createdAt: credential.createdAt,
22600
- updatedAt: credential.updatedAt
22601
- };
22602
- }
22603
- async function listCredentials(store) {
22604
- return (await store.credentials.list()).map(summarizeCredential);
22605
- }
22606
- function requiredString(value, field) {
22607
- if (typeof value !== "string" || value.trim().length === 0) {
22608
- throw new GatewayError("BAD_REQUEST", `${field}: must not be empty`);
22609
- }
22610
- return value.trim();
23312
+ // packages/control/src/console.ts
23313
+ var UNIT_NAME = "omnigateway.service";
23314
+ var MAX_CONSOLE_LINES = 500;
23315
+ var DEFAULT_CONSOLE_LINES = 200;
23316
+ function resolveConsoleSource(input) {
23317
+ const path = input.logFile?.trim();
23318
+ if (path !== undefined && path.length > 0)
23319
+ return { kind: "file", path };
23320
+ if (input.unitInstalled)
23321
+ return { kind: "journal", unit: UNIT_NAME, scope: input.scope };
23322
+ return { kind: "none" };
22611
23323
  }
22612
- function customProviderData(input) {
22613
- const endpointId = requiredString(input.endpointId, "endpointId");
22614
- const endpointLabel = requiredString(input.endpointLabel, "endpointLabel");
22615
- const originInput = requiredString(input.origin, "origin");
22616
- if (input.protocol !== "chat_completions" && input.protocol !== "responses") {
22617
- throw new GatewayError("BAD_REQUEST", "protocol: unsupported protocol");
22618
- }
22619
- let url2;
22620
- try {
22621
- url2 = new URL(originInput);
22622
- } catch {
22623
- throw new GatewayError("BAD_REQUEST", "origin: must be a valid URL");
22624
- }
22625
- if (url2.protocol !== "http:" && url2.protocol !== "https:" || url2.hostname.length === 0 || url2.username.length > 0 || url2.password.length > 0 || url2.pathname !== "" && url2.pathname !== "/" || url2.search.length > 0 || url2.hash.length > 0) {
22626
- throw new GatewayError("BAD_REQUEST", "origin: must be an HTTP(S) server origin");
22627
- }
22628
- return { endpointId, endpointLabel, origin: url2.origin, protocol: input.protocol };
23324
+ function consoleLimit(requested) {
23325
+ const value = optionalNumber(requested, DEFAULT_CONSOLE_LINES);
23326
+ return Math.floor(Math.min(Math.max(1, value), MAX_CONSOLE_LINES));
22629
23327
  }
22630
- function sameCustomEndpoint(a, b) {
22631
- return a.endpointId === b.endpointId && a.endpointLabel === b.endpointLabel && a.origin === b.origin && a.protocol === b.protocol;
23328
+ function keep(line, query) {
23329
+ if (query.since !== undefined && (line.at === null || line.at <= query.since))
23330
+ return false;
23331
+ if (query.level === undefined || line.level === null)
23332
+ return true;
23333
+ return LEVELS[line.level] >= LEVELS[query.level];
22632
23334
  }
22633
- async function createApiKeyCredential(store, input, logger2 = noopLogger) {
22634
- const provider = parseOrThrow(providerIdSchema, input.provider);
22635
- const apiKey = requiredString(input.apiKey, "apiKey");
22636
- if (input.label !== undefined && typeof input.label !== "string") {
22637
- throw new GatewayError("BAD_REQUEST", "label: must be a string");
22638
- }
22639
- let providerData = {};
22640
- if (provider === "custom") {
22641
- const custom2 = customProviderData(input);
22642
- const existing = (await store.credentials.list()).filter((credential) => credential.provider === "custom" && credential.providerData.endpointId === custom2.endpointId);
22643
- if (existing.some((credential) => !sameCustomEndpoint(credential.providerData, custom2))) {
22644
- throw new GatewayError("CONFLICT", `endpointId: metadata conflicts with existing endpoint`);
22645
- }
22646
- providerData = custom2;
22647
- }
22648
- const label = input.label?.trim() || `${provider} api key`;
22649
- const created = await store.credentials.create({
22650
- id: crypto.randomUUID(),
22651
- provider,
22652
- label,
22653
- authType: "apiKey",
22654
- enabled: true,
22655
- tier: 1,
22656
- weight: 1,
22657
- expiresAt: null,
22658
- accountEmail: null,
22659
- providerData,
22660
- disabledReason: null,
22661
- disabledAt: null,
22662
- accessToken: null,
22663
- refreshToken: null,
22664
- apiKey,
22665
- idToken: null
22666
- });
22667
- logger2.info("credential added", { credentialId: created.id, provider: created.provider });
22668
- return summarizeCredential(created);
23335
+ var SCAN_FACTOR = 20;
23336
+ var SCAN_LIMIT = 5000;
23337
+ function scanWidth(query) {
23338
+ const filtered = query.level !== undefined || query.since !== undefined;
23339
+ return filtered ? Math.min(query.lines * SCAN_FACTOR, SCAN_LIMIT) : query.lines;
22669
23340
  }
22670
- async function credentialHealth(store) {
22671
- const [health, quota] = await Promise.all([
22672
- store.credentials.listHealth(),
22673
- store.credentials.listQuota()
23341
+ async function readSource(deps, source, lines) {
23342
+ if (source.kind === "none")
23343
+ return "";
23344
+ if (source.kind === "file")
23345
+ return deps.readFile(source.path, lines) ?? "";
23346
+ const unit = source.scope === "system" ? ["-u", source.unit] : [`--user-unit=${source.unit}`];
23347
+ const result = await deps.run([
23348
+ "journalctl",
23349
+ ...unit,
23350
+ "-n",
23351
+ String(lines),
23352
+ "--no-pager",
23353
+ "--output=cat"
22674
23354
  ]);
22675
- return { health, quota };
22676
- }
22677
- async function patchCredential(deps, id, input) {
22678
- const patch = parseOrThrow(credentialPatchSchema, input);
22679
- const existing = await deps.store.credentials.get(id);
22680
- if (existing === null)
22681
- throw new GatewayError("BAD_REQUEST", "no such credential");
22682
- await deps.store.credentials.update(id, {
22683
- ...patch.label === undefined ? {} : { label: patch.label },
22684
- ...patch.enabled === undefined ? {} : {
22685
- enabled: patch.enabled,
22686
- disabledReason: patch.enabled ? null : "manual",
22687
- disabledAt: patch.enabled ? null : deps.now()
22688
- },
22689
- ...patch.tier === undefined ? {} : { tier: patch.tier },
22690
- ...patch.weight === undefined ? {} : { weight: patch.weight }
22691
- });
22692
- if (patch.enabled !== undefined && patch.enabled !== existing.enabled) {
22693
- (deps.logger ?? noopLogger).info(patch.enabled ? "credential enabled" : "credential disabled", {
22694
- credentialId: id,
22695
- provider: existing.provider
22696
- });
22697
- }
23355
+ return result.code === 0 ? result.stdout : "";
22698
23356
  }
22699
- async function removeCredential(store, id) {
22700
- await store.credentials.remove(id);
23357
+ async function readConsole(deps, source, query) {
23358
+ const limited = { ...query, lines: consoleLimit(query.lines) };
23359
+ const text = await readSource(deps, source, scanWidth(limited));
23360
+ const lines = text.split(`
23361
+ `).filter((raw) => raw.trim().length > 0).map(parseLine).filter((line) => keep(line, limited)).slice(-limited.lines);
23362
+ return source.kind === "file" ? { source: "file", path: source.path, lines } : { source: source.kind, lines };
22701
23363
  }
22702
23364
  // packages/router/src/snapshot.ts
22703
23365
  var HEALTH_KEY_SEP = "::";
@@ -22804,12 +23466,37 @@ function eligible(input) {
22804
23466
  return { pairs, excluded };
22805
23467
  }
22806
23468
 
22807
- // packages/router/src/quota.ts
23469
+ // packages/store/src/types.ts
22808
23470
  var WINDOW_DURATION_MS = {
22809
23471
  fiveHour: 5 * 60 * 60 * 1000,
22810
23472
  daily: 24 * 60 * 60 * 1000,
22811
23473
  weekly: 7 * 24 * 60 * 60 * 1000
22812
23474
  };
23475
+ function durationFor(windowType, windowMs) {
23476
+ return windowMs !== null && windowMs > 0 ? windowMs : WINDOW_DURATION_MS[windowType];
23477
+ }
23478
+ var SAME_WINDOW_TOLERANCE_MS = 60000;
23479
+ function sameWindow(a, b) {
23480
+ if (a === null || b === null)
23481
+ return a === b;
23482
+ return Math.abs(a - b) <= SAME_WINDOW_TOLERANCE_MS;
23483
+ }
23484
+ var READ_OVER_INPUT = 0.1;
23485
+ function cacheReadRate(prices) {
23486
+ return prices.cacheRead ?? prices.input * READ_OVER_INPUT;
23487
+ }
23488
+ var DEFAULT_SETTINGS = {
23489
+ weights: { tier: 10, health: 3, quota: 2, load: 2, cost: 1, latency: 1 },
23490
+ maxAttempts: 3,
23491
+ requestDeadlineMs: 120000,
23492
+ breakerThreshold: 3,
23493
+ breakerCooldownMs: 30000,
23494
+ logRetentionDays: 30,
23495
+ quotaPollIntervalMs: 300000,
23496
+ rtkEnabled: false
23497
+ };
23498
+
23499
+ // packages/router/src/quota.ts
22813
23500
  var UNKNOWN_QUOTA = 0.5;
22814
23501
  var QUOTA_FLOOR = 0.1;
22815
23502
  function quotaStaleAfterMs(pollIntervalMs) {
@@ -22822,7 +23509,7 @@ function paceAdjusted(window2, now) {
22822
23509
  const headroom = Math.max(0, Math.min(1, 1 - window2.used / limit));
22823
23510
  if (window2.resetsAt === null)
22824
23511
  return headroom;
22825
- const duration3 = WINDOW_DURATION_MS[window2.windowType];
23512
+ const duration3 = durationFor(window2.windowType, window2.windowMs);
22826
23513
  const remaining = Math.max(0.05, Math.min(1, (window2.resetsAt - now) / duration3));
22827
23514
  return Math.max(0, Math.min(1, headroom / remaining));
22828
23515
  }
@@ -22835,22 +23522,6 @@ function quotaHeadroom(credential, windows, now, pollIntervalMs) {
22835
23522
  return Math.min(...usable.map((w) => paceAdjusted(w, now)));
22836
23523
  }
22837
23524
 
22838
- // packages/store/src/types.ts
22839
- var READ_OVER_INPUT = 0.1;
22840
- function cacheReadRate(prices) {
22841
- return prices.cacheRead ?? prices.input * READ_OVER_INPUT;
22842
- }
22843
- var DEFAULT_SETTINGS = {
22844
- weights: { tier: 10, health: 3, quota: 2, load: 2, cost: 1, latency: 1 },
22845
- maxAttempts: 3,
22846
- requestDeadlineMs: 120000,
22847
- breakerThreshold: 3,
22848
- breakerCooldownMs: 30000,
22849
- logRetentionDays: 30,
22850
- quotaPollIntervalMs: 300000,
22851
- rtkEnabled: false
22852
- };
22853
-
22854
23525
  // packages/router/src/score.ts
22855
23526
  var UNKNOWN = 0.5;
22856
23527
  function lowerIsBetter(value, min, max) {
@@ -22984,7 +23655,8 @@ var PREFIX_PROVIDER = [
22984
23655
  ["o3", "openai"],
22985
23656
  ["o4", "openai"],
22986
23657
  ["kimi-", "kimi"],
22987
- ["moonshot", "kimi"]
23658
+ ["moonshot", "kimi"],
23659
+ ["grok-", "grok"]
22988
23660
  ];
22989
23661
  function synthesize(provider, model) {
22990
23662
  const listed = catalogPricing(provider, model);
@@ -23075,49 +23747,6 @@ function rank(input) {
23075
23747
  return { candidates: scored, excluded };
23076
23748
  }
23077
23749
 
23078
- // packages/control/src/dryRun.ts
23079
- async function dryRun(deps, modelId, input) {
23080
- const need = parseOrThrow(dryRunSchema, input);
23081
- const now = deps.now();
23082
- const snapshot = await buildSnapshot(deps.store, now);
23083
- const model = snapshot.models.get(modelId);
23084
- if (model === undefined) {
23085
- throw new GatewayError("MODEL_UNAVAILABLE", `no virtual model "${modelId}"`);
23086
- }
23087
- const probe = {
23088
- model: modelId,
23089
- messages: [
23090
- {
23091
- role: "user",
23092
- content: need.images ? [{ type: "image", mediaType: "image/png", data: "" }] : [{ type: "text", text: "" }]
23093
- }
23094
- ],
23095
- stream: false,
23096
- ...need.tools ? {
23097
- tools: [
23098
- { provider: "custom", name: "probe", description: "", inputSchema: { type: "object" } }
23099
- ]
23100
- } : {},
23101
- ...need.reasoning ? { reasoning: { mode: "adaptive" } } : {}
23102
- };
23103
- const result = rank({ request: probe, model, snapshot, now, rand: 0, load: new Map });
23104
- return {
23105
- modelId: model.id,
23106
- strategy: model.strategy,
23107
- deterministic: model.strategy !== "weighted",
23108
- rankedAt: now,
23109
- candidates: result.candidates.map((candidate) => ({
23110
- credentialId: candidate.credential.id,
23111
- credentialLabel: candidate.credential.label,
23112
- provider: candidate.credential.provider,
23113
- model: candidate.target.model,
23114
- tier: candidate.target.tier,
23115
- score: candidate.score,
23116
- reasons: candidate.reasons
23117
- })),
23118
- excluded: result.excluded
23119
- };
23120
- }
23121
23750
  // packages/store/src/encryption.ts
23122
23751
  var PREFIX = "enc:v1";
23123
23752
  var IV_BYTES = 12;
@@ -23454,20 +24083,36 @@ function createCredentialRepo(db, key, emit = () => {}) {
23454
24083
  used: r.used,
23455
24084
  limit: r.limit_value,
23456
24085
  resetsAt: r.resets_at,
23457
- observedAt: r.observed_at
24086
+ observedAt: r.observed_at,
24087
+ windowMs: r.window_ms
23458
24088
  }));
23459
24089
  },
23460
24090
  async saveQuota(rows) {
23461
24091
  const stmt = db.prepare(`INSERT INTO quota_windows
23462
- (credential_id, window_type, starts_at, used, limit_value, resets_at, observed_at)
23463
- VALUES (?,?,?,?,?,?,?)
24092
+ (credential_id, window_type, starts_at, used, limit_value, resets_at, observed_at,
24093
+ window_ms)
24094
+ VALUES (?,?,?,?,?,?,?,?)
23464
24095
  ON CONFLICT (credential_id, window_type) DO UPDATE SET
23465
24096
  starts_at = excluded.starts_at,
23466
24097
  used = excluded.used,
23467
24098
  limit_value = excluded.limit_value,
23468
24099
  resets_at = excluded.resets_at,
23469
- observed_at = excluded.observed_at`);
24100
+ observed_at = excluded.observed_at,
24101
+ window_ms = excluded.window_ms`);
23470
24102
  const prune = db.prepare("DELETE FROM quota_windows WHERE credential_id = ? AND window_type NOT IN (SELECT value FROM json_each(?))");
24103
+ const newestSample = db.prepare(`SELECT used, limit_value, resets_at, window_ms
24104
+ FROM quota_samples
24105
+ WHERE credential_id = ? AND window_type = ?
24106
+ ORDER BY observed_at DESC
24107
+ LIMIT 1`);
24108
+ const appendSample = db.prepare(`INSERT INTO quota_samples
24109
+ (credential_id, window_type, observed_at, used, limit_value, resets_at, window_ms)
24110
+ VALUES (?,?,?,?,?,?,?)
24111
+ ON CONFLICT (credential_id, window_type, observed_at) DO UPDATE SET
24112
+ used = excluded.used,
24113
+ limit_value = excluded.limit_value,
24114
+ resets_at = excluded.resets_at,
24115
+ window_ms = excluded.window_ms`);
23471
24116
  const kept = new Map;
23472
24117
  for (const r of rows) {
23473
24118
  const types2 = kept.get(r.credentialId);
@@ -23478,13 +24123,37 @@ function createCredentialRepo(db, key, emit = () => {}) {
23478
24123
  }
23479
24124
  db.transaction(() => {
23480
24125
  for (const r of rows) {
23481
- stmt.run(r.credentialId, r.windowType, r.startsAt, r.used, r.limit, r.resetsAt, r.observedAt);
24126
+ stmt.run(r.credentialId, r.windowType, r.startsAt, r.used, r.limit, r.resetsAt, r.observedAt, r.windowMs);
24127
+ const previous = newestSample.get(r.credentialId, r.windowType);
24128
+ const unchanged = previous !== null && previous.used === r.used && previous.limit_value === r.limit && sameWindow(previous.resets_at, r.resetsAt) && previous.window_ms === r.windowMs;
24129
+ if (unchanged)
24130
+ continue;
24131
+ appendSample.run(r.credentialId, r.windowType, r.observedAt, r.used, r.limit, r.resetsAt, r.windowMs);
23482
24132
  }
23483
24133
  for (const [credentialId, types2] of kept) {
23484
24134
  prune.run(credentialId, JSON.stringify(types2));
23485
24135
  }
23486
24136
  })();
23487
24137
  emit({ type: "quotaSaved", rows });
24138
+ },
24139
+ async listQuotaSamples(q) {
24140
+ const sql = (extra) => `SELECT * FROM quota_samples
24141
+ WHERE observed_at >= ? AND observed_at <= ?${extra}
24142
+ ORDER BY credential_id, window_type, observed_at`;
24143
+ const rows = q.credentialId === undefined ? db.query(sql("")).all(q.since, q.until) : db.query(sql(" AND credential_id = ?")).all(q.since, q.until, q.credentialId);
24144
+ return rows.map((r) => ({
24145
+ credentialId: r.credential_id,
24146
+ windowType: r.window_type,
24147
+ observedAt: r.observed_at,
24148
+ used: r.used,
24149
+ limit: r.limit_value,
24150
+ resetsAt: r.resets_at,
24151
+ windowMs: r.window_ms
24152
+ }));
24153
+ },
24154
+ async pruneQuotaSamples(olderThan) {
24155
+ db.run("DELETE FROM quota_samples WHERE observed_at < ?", [olderThan]);
24156
+ return db.query("SELECT changes() AS n").get()?.n ?? 0;
23488
24157
  }
23489
24158
  };
23490
24159
  }
@@ -23672,6 +24341,51 @@ var _006_rtk_usage_default = `ALTER TABLE usage_daily ADD COLUMN rtk_saved_token
23672
24341
  ALTER TABLE usage_daily ADD COLUMN rtk_applied_requests INTEGER NOT NULL DEFAULT 0;
23673
24342
  `;
23674
24343
 
24344
+ // packages/store/src/sqlite/migrations/007_quota_samples.sql
24345
+ var _007_quota_samples_default = `-- Retained provider quota readings, and the duration a window really runs for.
24346
+ --
24347
+ -- \`quota_windows\` is keyed (credential_id, window_type) and overwritten in
24348
+ -- place, so every reading is lost the moment the next probe lands. That is
24349
+ -- enough to draw a bar and to price a route against, and not enough to answer
24350
+ -- "is this draining faster than usual". This table keeps the readings.
24351
+ --
24352
+ -- \`observed_at\` is part of the key rather than a plain column: a reading is
24353
+ -- identified by which window it describes and when it was taken, and two
24354
+ -- readings of the same window at the same instant are the same reading.
24355
+ -- WITHOUT ROWID for the same reason as \`usage_daily\` \u2014 the key is the whole
24356
+ -- row's identity, so a separate rowid buys nothing and costs a second b-tree.
24357
+ --
24358
+ -- There is no window-set replacement here as there is for \`quota_windows\`. A
24359
+ -- window the provider stopped reporting still happened, and its history stays
24360
+ -- readable until it ages out. Rows die two ways: the credential is deleted, or
24361
+ -- retention prunes them.
24362
+ --
24363
+ -- No backfill: there is no history to recover.
24364
+ CREATE TABLE quota_samples (
24365
+ credential_id TEXT NOT NULL REFERENCES credentials (id) ON DELETE CASCADE,
24366
+ window_type TEXT NOT NULL,
24367
+ observed_at INTEGER NOT NULL,
24368
+ used INTEGER NOT NULL,
24369
+ limit_value INTEGER,
24370
+ resets_at INTEGER,
24371
+ window_ms INTEGER,
24372
+ PRIMARY KEY (credential_id, window_type, observed_at)
24373
+ ) WITHOUT ROWID;
24374
+
24375
+ -- On \`observed_at\` alone, because pruning sweeps every credential at once and
24376
+ -- the primary key already serves a lookup that names one.
24377
+ CREATE INDEX quota_samples_observed ON quota_samples (observed_at);
24378
+
24379
+ -- How long the window runs for, when the provider states it.
24380
+ --
24381
+ -- The three window names are buckets: Codex declares \`limit_window_seconds\` and
24382
+ -- the nearest of the three names is what gets stored, so a three-hour window is
24383
+ -- filed under \`fiveHour\`. Inferring its start from the nominal five hours would
24384
+ -- place it about two hours too early. Null means the provider said nothing,
24385
+ -- which is the normal state for Anthropic and Kimi.
24386
+ ALTER TABLE quota_windows ADD COLUMN window_ms INTEGER;
24387
+ `;
24388
+
23675
24389
  // packages/store/src/sqlite/rollup.ts
23676
24390
  function startOfLocalDay(at) {
23677
24391
  const day = new Date(at);
@@ -23816,7 +24530,8 @@ var MIGRATIONS = [
23816
24530
  { id: 3, sql: _003_quota_snapshot_default },
23817
24531
  { id: 4, sql: _004_request_state_default },
23818
24532
  { id: 5, sql: _005_rtk_metrics_default },
23819
- { id: 6, sql: _006_rtk_usage_default, after: backfillRtkUsage }
24533
+ { id: 6, sql: _006_rtk_usage_default, after: backfillRtkUsage },
24534
+ { id: 7, sql: _007_quota_samples_default }
23820
24535
  ];
23821
24536
  function openDb(path) {
23822
24537
  const db = new Database(path, { create: true });
@@ -24151,6 +24866,214 @@ async function createStore(opts) {
24151
24866
  close: () => db.close()
24152
24867
  };
24153
24868
  }
24869
+ // packages/control/src/quota/burn.ts
24870
+ var HOUR_MS = 3600000;
24871
+ function windowStartOf(window2) {
24872
+ if (window2.resetsAt === null)
24873
+ return null;
24874
+ return window2.resetsAt - durationFor(window2.windowType, window2.windowMs);
24875
+ }
24876
+ var suppressed = (window2) => ({
24877
+ credentialId: window2.credentialId,
24878
+ windowType: window2.windowType,
24879
+ windowStartsAt: null,
24880
+ ratePerHour: null,
24881
+ exhaustsAt: null,
24882
+ survives: null,
24883
+ stale: true
24884
+ });
24885
+ function burnFor(window2, input) {
24886
+ if (window2.observedAt <= 0)
24887
+ return suppressed(window2);
24888
+ if (input.now - window2.observedAt > quotaStaleAfterMs(input.pollIntervalMs)) {
24889
+ return suppressed(window2);
24890
+ }
24891
+ const windowStartsAt = windowStartOf(window2);
24892
+ const elapsedMs = windowStartsAt === null ? null : window2.observedAt - windowStartsAt;
24893
+ const elapsedHours = elapsedMs === null ? null : elapsedMs / HOUR_MS;
24894
+ const ratePerHour = elapsedHours === null ? null : elapsedHours <= 0 || window2.used === 0 ? 0 : window2.used / elapsedHours;
24895
+ const exhaustsAt = window2.limit === null || ratePerHour === null || ratePerHour <= 0 ? null : window2.observedAt + Math.max(0, window2.limit - window2.used) / ratePerHour * HOUR_MS;
24896
+ return {
24897
+ credentialId: window2.credentialId,
24898
+ windowType: window2.windowType,
24899
+ windowStartsAt,
24900
+ ratePerHour,
24901
+ exhaustsAt,
24902
+ survives: exhaustsAt === null || window2.resetsAt === null || exhaustsAt >= window2.resetsAt,
24903
+ stale: false
24904
+ };
24905
+ }
24906
+ function burnEstimates(windows, input) {
24907
+ return windows.map((window2) => burnFor(window2, input));
24908
+ }
24909
+
24910
+ // packages/control/src/credentials.ts
24911
+ function summarizeCredential(credential) {
24912
+ return {
24913
+ id: credential.id,
24914
+ provider: credential.provider,
24915
+ label: credential.label,
24916
+ authType: credential.authType,
24917
+ enabled: credential.enabled,
24918
+ tier: credential.tier,
24919
+ weight: credential.weight,
24920
+ expiresAt: credential.expiresAt,
24921
+ accountEmail: credential.accountEmail,
24922
+ providerData: credential.providerData,
24923
+ disabledReason: credential.disabledReason,
24924
+ disabledAt: credential.disabledAt,
24925
+ hasRefreshToken: credential.hasRefreshToken,
24926
+ createdAt: credential.createdAt,
24927
+ updatedAt: credential.updatedAt
24928
+ };
24929
+ }
24930
+ async function listCredentials(store) {
24931
+ return (await store.credentials.list()).map(summarizeCredential);
24932
+ }
24933
+ function requiredString(value, field) {
24934
+ if (typeof value !== "string" || value.trim().length === 0) {
24935
+ throw new GatewayError("BAD_REQUEST", `${field}: must not be empty`);
24936
+ }
24937
+ return value.trim();
24938
+ }
24939
+ function customProviderData(input) {
24940
+ const endpointId = requiredString(input.endpointId, "endpointId");
24941
+ const endpointLabel = requiredString(input.endpointLabel, "endpointLabel");
24942
+ const originInput = requiredString(input.origin, "origin");
24943
+ if (input.protocol !== "chat_completions" && input.protocol !== "responses") {
24944
+ throw new GatewayError("BAD_REQUEST", "protocol: unsupported protocol");
24945
+ }
24946
+ let url2;
24947
+ try {
24948
+ url2 = new URL(originInput);
24949
+ } catch {
24950
+ throw new GatewayError("BAD_REQUEST", "origin: must be a valid URL");
24951
+ }
24952
+ if (url2.protocol !== "http:" && url2.protocol !== "https:" || url2.hostname.length === 0 || url2.username.length > 0 || url2.password.length > 0 || url2.pathname !== "" && url2.pathname !== "/" || url2.search.length > 0 || url2.hash.length > 0) {
24953
+ throw new GatewayError("BAD_REQUEST", "origin: must be an HTTP(S) server origin");
24954
+ }
24955
+ return { endpointId, endpointLabel, origin: url2.origin, protocol: input.protocol };
24956
+ }
24957
+ function sameCustomEndpoint(a, b) {
24958
+ return a.endpointId === b.endpointId && a.endpointLabel === b.endpointLabel && a.origin === b.origin && a.protocol === b.protocol;
24959
+ }
24960
+ async function createApiKeyCredential(store, input, logger2 = noopLogger) {
24961
+ const provider = parseOrThrow(providerIdSchema, input.provider);
24962
+ const apiKey = requiredString(input.apiKey, "apiKey");
24963
+ if (input.label !== undefined && typeof input.label !== "string") {
24964
+ throw new GatewayError("BAD_REQUEST", "label: must be a string");
24965
+ }
24966
+ let providerData = {};
24967
+ if (provider === "custom") {
24968
+ const custom2 = customProviderData(input);
24969
+ const existing = (await store.credentials.list()).filter((credential) => credential.provider === "custom" && credential.providerData.endpointId === custom2.endpointId);
24970
+ if (existing.some((credential) => !sameCustomEndpoint(credential.providerData, custom2))) {
24971
+ throw new GatewayError("CONFLICT", `endpointId: metadata conflicts with existing endpoint`);
24972
+ }
24973
+ providerData = custom2;
24974
+ }
24975
+ const label2 = input.label?.trim() || `${provider} api key`;
24976
+ const created = await store.credentials.create({
24977
+ id: crypto.randomUUID(),
24978
+ provider,
24979
+ label: label2,
24980
+ authType: "apiKey",
24981
+ enabled: true,
24982
+ tier: 1,
24983
+ weight: 1,
24984
+ expiresAt: null,
24985
+ accountEmail: null,
24986
+ providerData,
24987
+ disabledReason: null,
24988
+ disabledAt: null,
24989
+ accessToken: null,
24990
+ refreshToken: null,
24991
+ apiKey,
24992
+ idToken: null
24993
+ });
24994
+ logger2.info("credential added", { credentialId: created.id, provider: created.provider });
24995
+ return summarizeCredential(created);
24996
+ }
24997
+ async function credentialHealth(deps) {
24998
+ const [health, quota, settings] = await Promise.all([
24999
+ deps.store.credentials.listHealth(),
25000
+ deps.store.credentials.listQuota(),
25001
+ deps.store.config.getSettings()
25002
+ ]);
25003
+ const burn = burnEstimates(quota, {
25004
+ now: deps.now(),
25005
+ pollIntervalMs: settings.quotaPollIntervalMs
25006
+ });
25007
+ return { health, quota, burn };
25008
+ }
25009
+ async function patchCredential(deps, id, input) {
25010
+ const patch = parseOrThrow(credentialPatchSchema, input);
25011
+ const existing = await deps.store.credentials.get(id);
25012
+ if (existing === null)
25013
+ throw new GatewayError("BAD_REQUEST", "no such credential");
25014
+ await deps.store.credentials.update(id, {
25015
+ ...patch.label === undefined ? {} : { label: patch.label },
25016
+ ...patch.enabled === undefined ? {} : {
25017
+ enabled: patch.enabled,
25018
+ disabledReason: patch.enabled ? null : "manual",
25019
+ disabledAt: patch.enabled ? null : deps.now()
25020
+ },
25021
+ ...patch.tier === undefined ? {} : { tier: patch.tier },
25022
+ ...patch.weight === undefined ? {} : { weight: patch.weight }
25023
+ });
25024
+ if (patch.enabled !== undefined && patch.enabled !== existing.enabled) {
25025
+ (deps.logger ?? noopLogger).info(patch.enabled ? "credential enabled" : "credential disabled", {
25026
+ credentialId: id,
25027
+ provider: existing.provider
25028
+ });
25029
+ }
25030
+ }
25031
+ async function removeCredential(store, id) {
25032
+ await store.credentials.remove(id);
25033
+ }
25034
+ // packages/control/src/dryRun.ts
25035
+ async function dryRun(deps, modelId, input) {
25036
+ const need = parseOrThrow(dryRunSchema, input);
25037
+ const now = deps.now();
25038
+ const snapshot = await buildSnapshot(deps.store, now);
25039
+ const model = snapshot.models.get(modelId);
25040
+ if (model === undefined) {
25041
+ throw new GatewayError("MODEL_UNAVAILABLE", `no virtual model "${modelId}"`);
25042
+ }
25043
+ const probe = {
25044
+ model: modelId,
25045
+ messages: [
25046
+ {
25047
+ role: "user",
25048
+ content: need.images ? [{ type: "image", mediaType: "image/png", data: "" }] : [{ type: "text", text: "" }]
25049
+ }
25050
+ ],
25051
+ stream: false,
25052
+ ...need.tools ? {
25053
+ tools: [
25054
+ { provider: "custom", name: "probe", description: "", inputSchema: { type: "object" } }
25055
+ ]
25056
+ } : {},
25057
+ ...need.reasoning ? { reasoning: { mode: "adaptive" } } : {}
25058
+ };
25059
+ const result = rank({ request: probe, model, snapshot, now, rand: 0, load: new Map });
25060
+ return {
25061
+ modelId: model.id,
25062
+ strategy: model.strategy,
25063
+ deterministic: model.strategy !== "weighted",
25064
+ rankedAt: now,
25065
+ candidates: result.candidates.map((candidate) => ({
25066
+ credentialId: candidate.credential.id,
25067
+ credentialLabel: candidate.credential.label,
25068
+ provider: candidate.credential.provider,
25069
+ model: candidate.target.model,
25070
+ tier: candidate.target.tier,
25071
+ score: candidate.score,
25072
+ reasons: candidate.reasons
25073
+ })),
25074
+ excluded: result.excluded
25075
+ };
25076
+ }
24154
25077
  // packages/control/src/keys.ts
24155
25078
  async function listKeys(store) {
24156
25079
  const keys = await store.keys.list();
@@ -24238,16 +25161,55 @@ function modelDisplayName(model) {
24238
25161
  async function listModels(store) {
24239
25162
  return store.config.listModels();
24240
25163
  }
25164
+ var AUTH_LABEL = {
25165
+ oauth: "OAuth",
25166
+ apiKey: "API key"
25167
+ };
25168
+ function phrase(auths) {
25169
+ return auths.map((auth) => AUTH_LABEL[auth]).join(" or ");
25170
+ }
25171
+ function heldAuths(credentials) {
25172
+ const byProvider = new Map;
25173
+ for (const credential of credentials) {
25174
+ const ways = byProvider.get(credential.provider) ?? new Set;
25175
+ ways.add(credential.authType);
25176
+ byProvider.set(credential.provider, ways);
25177
+ }
25178
+ return byProvider;
25179
+ }
25180
+ function pairOf(target) {
25181
+ return `${target.provider}\x00${target.model}`;
25182
+ }
25183
+ function unreachable(model, credentials, stored) {
25184
+ const held = heldAuths(credentials);
25185
+ const grandfathered = new Set((stored?.targets ?? []).map(pairOf));
25186
+ for (const target of model.targets) {
25187
+ if (grandfathered.has(pairOf(target)))
25188
+ continue;
25189
+ const have = held.get(target.provider);
25190
+ if (have === undefined)
25191
+ continue;
25192
+ const reach = catalogModelAuths(target.provider, target.model);
25193
+ if (reach.some((auth) => have.has(auth)))
25194
+ continue;
25195
+ return new GatewayError("BAD_REQUEST", `${target.provider} serves "${target.model}" to ${phrase(reach)} credentials only, ` + `and every ${target.provider} credential here is ${phrase([...have])} \u2014 ` + `connect the other kind, or pick a model this one can reach`);
25196
+ }
25197
+ return null;
25198
+ }
24241
25199
  async function putModel(store, id, input) {
24242
25200
  const model = parseOrThrow(modelSchema, input);
24243
25201
  if (model.id !== id) {
24244
25202
  throw new GatewayError("BAD_REQUEST", "model id in the path and body must match");
24245
25203
  }
24246
- const customEndpointIds = new Set((await store.credentials.list()).filter((credential) => credential.provider === "custom").map((credential) => credential.providerData.endpointId).filter((endpointId) => typeof endpointId === "string"));
25204
+ const credentials = await store.credentials.list();
25205
+ const customEndpointIds = new Set(credentials.filter((credential) => credential.provider === "custom").map((credential) => credential.providerData.endpointId).filter((endpointId) => typeof endpointId === "string"));
24247
25206
  const missing = model.targets.find((target) => target.provider === "custom" && (target.endpointId === undefined || !customEndpointIds.has(target.endpointId)));
24248
25207
  if (missing !== undefined) {
24249
25208
  throw new GatewayError("BAD_REQUEST", `custom endpoint "${missing.endpointId}" has no credential`);
24250
25209
  }
25210
+ const stranded = unreachable(model, credentials, (await store.config.listModels()).find((existing) => existing.id === id));
25211
+ if (stranded !== null)
25212
+ throw stranded;
24251
25213
  await store.config.putModel(model);
24252
25214
  }
24253
25215
  async function removeModel(store, id) {
@@ -24265,17 +25227,127 @@ function randomState() {
24265
25227
  return randomToken();
24266
25228
  }
24267
25229
 
25230
+ // packages/control/src/oauth/usage.ts
25231
+ function usageReadable(status, provider) {
25232
+ if (status === 429) {
25233
+ throw new GatewayError("RATE_LIMIT", `${provider} usage endpoint is rate limited`);
25234
+ }
25235
+ return status >= 200 && status < 300;
25236
+ }
25237
+ function recordOf(value) {
25238
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
25239
+ }
25240
+ function numberOf(record2, keys) {
25241
+ for (const key of keys) {
25242
+ const value = record2[key];
25243
+ if (typeof value === "number" && Number.isFinite(value))
25244
+ return value;
25245
+ if (typeof value === "string" && value.trim().length > 0) {
25246
+ const parsed = Number(value);
25247
+ if (Number.isFinite(parsed))
25248
+ return parsed;
25249
+ }
25250
+ }
25251
+ return null;
25252
+ }
25253
+ function nestedOf(record2, keys) {
25254
+ for (const key of keys) {
25255
+ const nested = recordOf(record2[key]);
25256
+ if (nested !== null)
25257
+ return nested;
25258
+ }
25259
+ return null;
25260
+ }
25261
+ function resetAtOf(record2, keys, now) {
25262
+ for (const key of keys.absolute) {
25263
+ const value = record2[key];
25264
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
25265
+ return value < 1000000000000 ? Math.round(value * 1000) : Math.round(value);
25266
+ }
25267
+ if (typeof value === "string") {
25268
+ const parsed = Date.parse(value);
25269
+ if (!Number.isNaN(parsed))
25270
+ return parsed;
25271
+ }
25272
+ }
25273
+ for (const key of keys.relativeSeconds ?? []) {
25274
+ const value = record2[key];
25275
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
25276
+ return now + Math.round(value * 1000);
25277
+ }
25278
+ }
25279
+ return null;
25280
+ }
25281
+ var USED_KEYS = ["used", "used_units", "usage", "consumed"];
25282
+ var LIMIT_KEYS = ["limit", "limit_units", "total", "quota", "allowed"];
25283
+ var PERCENT_KEYS = [
25284
+ "utilization",
25285
+ "used_percent",
25286
+ "usedPercent",
25287
+ "percent_used",
25288
+ "percentUsed",
25289
+ "percent"
25290
+ ];
25291
+ var RESET_ABSOLUTE_KEYS = [
25292
+ "resets_at",
25293
+ "resetsAt",
25294
+ "reset_at",
25295
+ "resetAt",
25296
+ "resetTime",
25297
+ "reset_time",
25298
+ "resets_at_epoch",
25299
+ "reset"
25300
+ ];
25301
+ var RESET_RELATIVE_KEYS = [
25302
+ "resets_in_seconds",
25303
+ "resetsInSeconds",
25304
+ "reset_after_seconds",
25305
+ "resetAfterSeconds",
25306
+ "seconds_until_reset",
25307
+ "resets_in"
25308
+ ];
25309
+ function windowFrom(value, windowType, now, windowMs = null) {
25310
+ const record2 = recordOf(value);
25311
+ if (record2 === null)
25312
+ return null;
25313
+ const resetsAt = resetAtOf(record2, { absolute: RESET_ABSOLUTE_KEYS, relativeSeconds: RESET_RELATIVE_KEYS }, now);
25314
+ const used = numberOf(record2, USED_KEYS);
25315
+ const limit = numberOf(record2, LIMIT_KEYS);
25316
+ if (used !== null) {
25317
+ return { windowType, used: Math.max(0, used), limit, resetsAt, windowMs };
25318
+ }
25319
+ const remaining = numberOf(record2, ["remaining", "remaining_units", "left"]);
25320
+ if (remaining !== null && limit !== null) {
25321
+ return { windowType, used: Math.max(0, limit - remaining), limit, resetsAt, windowMs };
25322
+ }
25323
+ const percent = numberOf(record2, PERCENT_KEYS);
25324
+ if (percent !== null) {
25325
+ return {
25326
+ windowType,
25327
+ used: Math.max(0, Math.min(100, percent)),
25328
+ limit: 100,
25329
+ resetsAt,
25330
+ windowMs
25331
+ };
25332
+ }
25333
+ return null;
25334
+ }
25335
+ function reportFrom(windows) {
25336
+ const kept = windows.filter((w) => w !== null);
25337
+ return kept.length === 0 ? null : { windows: kept };
25338
+ }
25339
+
24268
25340
  // packages/control/src/oauth/anthropic.ts
24269
- var CLIENT_ID2 = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
25341
+ var CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
24270
25342
  var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
24271
- var TOKEN_URL2 = "https://api.anthropic.com/v1/oauth/token";
25343
+ var TOKEN_URL = "https://api.anthropic.com/v1/oauth/token";
24272
25344
  var REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
24273
25345
  var SCOPES = "org:create_api_key user:profile user:inference";
24274
- var USAGE_URL2 = "https://api.anthropic.com/api/oauth/usage";
25346
+ var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
24275
25347
  async function postToken(body2, deps) {
24276
- const { status, parsed } = await postJson(deps, "anthropic", TOKEN_URL2, PROFILES.anthropic, {
25348
+ const { status, parsed } = await postJson(deps, "anthropic", TOKEN_URL, PROFILES.anthropic, {
24277
25349
  contentType: "application/json",
24278
- body: JSON.stringify({ ...body2, client_id: CLIENT_ID2 })
25350
+ body: JSON.stringify({ ...body2, client_id: CLIENT_ID })
24279
25351
  });
24280
25352
  if (status < 200 || status >= 300) {
24281
25353
  throw new GatewayError(tokenErrorCode(status), tokenErrorMessage(status, parsed));
@@ -24288,7 +25360,7 @@ async function postToken(body2, deps) {
24288
25360
  function isTokenResponse(value) {
24289
25361
  return typeof value === "object" && value !== null;
24290
25362
  }
24291
- function toResult2(token, fallbackRefresh, deps) {
25363
+ function toResult(token, fallbackRefresh, deps) {
24292
25364
  return {
24293
25365
  secrets: {
24294
25366
  accessToken: token.access_token ?? null,
@@ -24321,7 +25393,7 @@ var anthropicOAuth = {
24321
25393
  const redirectUri = REDIRECT_URI;
24322
25394
  const url2 = new URL(AUTHORIZE_URL);
24323
25395
  url2.searchParams.set("code", "true");
24324
- url2.searchParams.set("client_id", CLIENT_ID2);
25396
+ url2.searchParams.set("client_id", CLIENT_ID);
24325
25397
  url2.searchParams.set("response_type", "code");
24326
25398
  url2.searchParams.set("redirect_uri", redirectUri);
24327
25399
  url2.searchParams.set("scope", SCOPES);
@@ -24342,16 +25414,16 @@ var anthropicOAuth = {
24342
25414
  code_verifier: pending.verifier,
24343
25415
  state: pending.state
24344
25416
  }, deps);
24345
- return toResult2(token, null, deps);
25417
+ return toResult(token, null, deps);
24346
25418
  },
24347
25419
  async refresh(refreshToken, deps) {
24348
25420
  const token = await postToken({ grant_type: "refresh_token", refresh_token: refreshToken }, deps);
24349
- return toResult2(token, refreshToken, deps);
25421
+ return toResult(token, refreshToken, deps);
24350
25422
  },
24351
25423
  async usage(secrets, deps) {
24352
25424
  if (secrets.accessToken === null)
24353
25425
  return null;
24354
- const { status, parsed } = await getJson(deps, "anthropic", USAGE_URL2, PROFILES.anthropic, {
25426
+ const { status, parsed } = await getJson(deps, "anthropic", USAGE_URL, PROFILES.anthropic, {
24355
25427
  accessToken: secrets.accessToken,
24356
25428
  extraHeaders: [
24357
25429
  ["anthropic-beta", "oauth-2025-04-20"],
@@ -24364,13 +25436,474 @@ var anthropicOAuth = {
24364
25436
  }
24365
25437
  };
24366
25438
 
25439
+ // packages/control/src/oauth/grok.ts
25440
+ var CLIENT_ID2 = "b1a00492-073a-47ea-816f-4c329264a828";
25441
+ var ISSUER = "https://auth.x.ai";
25442
+ var DISCOVERY_URL = `${ISSUER}/.well-known/openid-configuration`;
25443
+ var SCOPES2 = [
25444
+ "openid",
25445
+ "profile",
25446
+ "email",
25447
+ "offline_access",
25448
+ "grok-cli:access",
25449
+ "api:access",
25450
+ "conversations:read",
25451
+ "conversations:write",
25452
+ "workspaces:read",
25453
+ "workspaces:write"
25454
+ ].join(" ");
25455
+ var TRUSTED_HOST = "x.ai";
25456
+ function isRecord2(value) {
25457
+ return typeof value === "object" && value !== null;
25458
+ }
25459
+ function trustedEndpoint(value, field) {
25460
+ if (typeof value !== "string" || value.trim().length === 0) {
25461
+ throw new GatewayError("UPSTREAM", `discovery document has no ${field}`);
25462
+ }
25463
+ let url2;
25464
+ try {
25465
+ url2 = new URL(value);
25466
+ } catch {
25467
+ throw new GatewayError("UPSTREAM", `discovery document has an unusable ${field}`);
25468
+ }
25469
+ const host2 = url2.hostname;
25470
+ if (url2.protocol !== "https:" || host2 !== TRUSTED_HOST && !host2.endsWith(`.${TRUSTED_HOST}`)) {
25471
+ throw new GatewayError("UPSTREAM", `discovery document ${field} is not an ${TRUSTED_HOST} https url`);
25472
+ }
25473
+ return url2.toString();
25474
+ }
25475
+ async function discover(deps) {
25476
+ const res = await deps.http({
25477
+ provider: "grok",
25478
+ url: DISCOVERY_URL,
25479
+ method: "GET",
25480
+ headers: orderHeaders(mergeHeaders(PROFILES.grok.headers, [["Accept", "application/json"]]), PROFILES.grok.order),
25481
+ body: "",
25482
+ signal: AbortSignal.timeout(15000)
25483
+ });
25484
+ const text = await res.text();
25485
+ if (res.status < 200 || res.status >= 300) {
25486
+ throw new GatewayError("UPSTREAM", `discovery endpoint returned http_${res.status}`);
25487
+ }
25488
+ let parsed = null;
25489
+ try {
25490
+ parsed = JSON.parse(text);
25491
+ } catch {}
25492
+ if (!isRecord2(parsed)) {
25493
+ throw new GatewayError("UPSTREAM", "discovery endpoint returned an unusable response");
25494
+ }
25495
+ return {
25496
+ authorizeUrl: trustedEndpoint(parsed.authorization_endpoint, "authorization_endpoint"),
25497
+ tokenUrl: trustedEndpoint(parsed.token_endpoint, "token_endpoint")
25498
+ };
25499
+ }
25500
+ function parseTokenResponse(value) {
25501
+ if (!isRecord2(value) || typeof value.access_token !== "string")
25502
+ return null;
25503
+ return {
25504
+ accessToken: value.access_token,
25505
+ refreshToken: typeof value.refresh_token === "string" ? value.refresh_token : null,
25506
+ expiresIn: typeof value.expires_in === "number" ? value.expires_in : null,
25507
+ idToken: typeof value.id_token === "string" ? value.id_token : null
25508
+ };
25509
+ }
25510
+ function emailFromIdToken(idToken) {
25511
+ const parts = typeof idToken === "string" ? idToken.split(".") : [];
25512
+ const payload = parts[1];
25513
+ if (parts.length !== 3 || payload === undefined || payload.length === 0)
25514
+ return null;
25515
+ try {
25516
+ const json7 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
25517
+ if (!isRecord2(json7))
25518
+ return null;
25519
+ return typeof json7.email === "string" && json7.email.trim().length > 0 ? json7.email : null;
25520
+ } catch {
25521
+ return null;
25522
+ }
25523
+ }
25524
+ async function postToken2(tokenUrl, body2, deps) {
25525
+ const { status, parsed } = await postJson(deps, "grok", tokenUrl, PROFILES.grok, {
25526
+ contentType: "application/x-www-form-urlencoded",
25527
+ body: new URLSearchParams(body2).toString()
25528
+ });
25529
+ if (status < 200 || status >= 300) {
25530
+ throw new GatewayError(tokenErrorCode(status), tokenErrorMessage(status, parsed));
25531
+ }
25532
+ const token = parseTokenResponse(parsed);
25533
+ if (token === null) {
25534
+ throw new GatewayError("AUTH", "token endpoint returned no access_token");
25535
+ }
25536
+ return token;
25537
+ }
25538
+ function agentIdFrom(providerData) {
25539
+ const stored = providerData.agentId;
25540
+ return typeof stored === "string" && stored.trim().length > 0 ? stored : mintGrokDevice().agentId;
25541
+ }
25542
+ function toResult2(token, fallbackRefresh, agentId, deps) {
25543
+ return {
25544
+ secrets: {
25545
+ accessToken: token.accessToken,
25546
+ refreshToken: token.refreshToken ?? fallbackRefresh,
25547
+ apiKey: null,
25548
+ idToken: token.idToken
25549
+ },
25550
+ expiresAt: token.expiresIn === null ? null : deps.now() + token.expiresIn * 1000,
25551
+ accountEmail: emailFromIdToken(token.idToken),
25552
+ providerData: { agentId }
25553
+ };
25554
+ }
25555
+ var grokOAuth = {
25556
+ id: "grok",
25557
+ kind: "pkce",
25558
+ supportsManualPaste: true,
25559
+ async start({ redirectUri }, deps) {
25560
+ const { authorizeUrl } = await discover(deps);
25561
+ const { verifier, challenge } = createPkce();
25562
+ const state = randomState();
25563
+ const url2 = new URL(authorizeUrl);
25564
+ url2.searchParams.set("response_type", "code");
25565
+ url2.searchParams.set("client_id", CLIENT_ID2);
25566
+ url2.searchParams.set("redirect_uri", redirectUri);
25567
+ url2.searchParams.set("scope", SCOPES2);
25568
+ url2.searchParams.set("code_challenge", challenge);
25569
+ url2.searchParams.set("code_challenge_method", "S256");
25570
+ url2.searchParams.set("state", state);
25571
+ url2.searchParams.set("nonce", randomState());
25572
+ url2.searchParams.set("referrer", "grok-build");
25573
+ return { authorizeUrl: url2.toString(), pending: { verifier, challenge, state, redirectUri } };
25574
+ },
25575
+ async exchange({ code, pending }, deps) {
25576
+ const [rawCode, pastedState] = code.split("#");
25577
+ if (pastedState !== undefined && pastedState !== pending.state) {
25578
+ throw new GatewayError("AUTH", "authorization state mismatch");
25579
+ }
25580
+ const { tokenUrl } = await discover(deps);
25581
+ const token = await postToken2(tokenUrl, {
25582
+ grant_type: "authorization_code",
25583
+ code: (rawCode ?? "").trim(),
25584
+ redirect_uri: pending.redirectUri,
25585
+ client_id: CLIENT_ID2,
25586
+ code_verifier: pending.verifier
25587
+ }, deps);
25588
+ return toResult2(token, null, mintGrokDevice().agentId, deps);
25589
+ },
25590
+ async refresh(refreshToken, deps, providerData) {
25591
+ const { tokenUrl } = await discover(deps);
25592
+ const token = await postToken2(tokenUrl, { grant_type: "refresh_token", client_id: CLIENT_ID2, refresh_token: refreshToken }, deps);
25593
+ return toResult2(token, refreshToken, agentIdFrom(providerData), deps);
25594
+ }
25595
+ };
25596
+
25597
+ // packages/control/src/oauth/kilo.ts
25598
+ var CODES_URL = "https://api.kilo.ai/api/device-auth/codes";
25599
+ var PROFILE_URL = "https://api.kilo.ai/api/profile";
25600
+ var FALLBACK_VERIFICATION_URL = "https://kilo.ai";
25601
+ var DEFAULT_EXPIRES_SECONDS = 300;
25602
+ var POLL_INTERVAL_SECONDS = 3;
25603
+ function isRecord3(value) {
25604
+ return typeof value === "object" && value !== null;
25605
+ }
25606
+ function recordFrom(value) {
25607
+ return isRecord3(value) ? value : null;
25608
+ }
25609
+ function stringFrom(value, field) {
25610
+ const candidate = value[field];
25611
+ return typeof candidate === "string" && candidate.trim().length > 0 ? candidate : null;
25612
+ }
25613
+ function positiveNumberFrom(value, field) {
25614
+ const candidate = value[field];
25615
+ return typeof candidate === "number" && Number.isFinite(candidate) && candidate > 0 ? candidate : null;
25616
+ }
25617
+ function deviceCodeFrom(value) {
25618
+ const record2 = recordFrom(value);
25619
+ const code = record2 === null ? null : stringFrom(record2, "code");
25620
+ if (record2 === null || code === null) {
25621
+ throw new GatewayError("AUTH", "device code endpoint returned an unusable response");
25622
+ }
25623
+ return {
25624
+ code,
25625
+ verificationUrl: stringFrom(record2, "verificationUrl") ?? FALLBACK_VERIFICATION_URL,
25626
+ expiresIn: positiveNumberFrom(record2, "expiresIn") ?? DEFAULT_EXPIRES_SECONDS
25627
+ };
25628
+ }
25629
+ async function orgIdFor(accessToken, deps) {
25630
+ try {
25631
+ const { status, parsed } = await getJson(deps, "kilo", PROFILE_URL, PROFILES.kilo, {
25632
+ accessToken
25633
+ });
25634
+ if (status < 200 || status >= 300)
25635
+ return null;
25636
+ const record2 = recordFrom(parsed);
25637
+ const organizations = record2?.organizations;
25638
+ if (!Array.isArray(organizations))
25639
+ return null;
25640
+ const first = recordFrom(organizations[0]);
25641
+ return first === null ? null : stringFrom(first, "id");
25642
+ } catch {
25643
+ return null;
25644
+ }
25645
+ }
25646
+ var kiloOAuth = {
25647
+ id: "kilo",
25648
+ kind: "device",
25649
+ needsDeviceId: false,
25650
+ supportsManualPaste: false,
25651
+ start() {
25652
+ return {
25653
+ authorizeUrl: FALLBACK_VERIFICATION_URL,
25654
+ pending: { verifier: "", challenge: "", state: "", redirectUri: "" }
25655
+ };
25656
+ },
25657
+ async begin(_opts, deps) {
25658
+ const { status, parsed } = await postJson(deps, "kilo", CODES_URL, PROFILES.kilo, {
25659
+ contentType: "application/json",
25660
+ body: ""
25661
+ });
25662
+ if (status === 429) {
25663
+ throw new GatewayError("RATE_LIMIT", "kilo has too many pending device authorizations; wait for one to expire and retry");
25664
+ }
25665
+ if (status < 200 || status >= 300) {
25666
+ throw new GatewayError(tokenErrorCode(status), `kilo refused a device code: http_${status}`);
25667
+ }
25668
+ const response = deviceCodeFrom(parsed);
25669
+ return {
25670
+ authorizeUrl: response.verificationUrl,
25671
+ userCode: response.code,
25672
+ pending: {
25673
+ verifier: "",
25674
+ challenge: "",
25675
+ state: "",
25676
+ redirectUri: "",
25677
+ deviceCode: response.code,
25678
+ interval: POLL_INTERVAL_SECONDS,
25679
+ extra: { expiresAt: deps.now() + response.expiresIn * 1000 }
25680
+ }
25681
+ };
25682
+ },
25683
+ async exchange({ pending }, deps) {
25684
+ const code = pending.deviceCode;
25685
+ if (code === undefined) {
25686
+ throw new Error("kilo exchange requires a pending flow produced by begin()");
25687
+ }
25688
+ const expiresAt = pending.extra === undefined ? null : positiveNumberFrom(pending.extra, "expiresAt");
25689
+ if (expiresAt !== null && deps.now() >= expiresAt) {
25690
+ throw new GatewayError("AUTH", "kilo device code expired; start the authorization again");
25691
+ }
25692
+ const { status, parsed } = await getJsonUnauthenticated(deps, "kilo", `${CODES_URL}/${encodeURIComponent(code)}`, PROFILES.kilo);
25693
+ if (status === 202)
25694
+ throw pendingError("http_202");
25695
+ if (status === 403) {
25696
+ throw new GatewayError("AUTH", "kilo authorization was denied");
25697
+ }
25698
+ if (status === 410) {
25699
+ throw new GatewayError("AUTH", "kilo device code expired; start the authorization again");
25700
+ }
25701
+ if (status < 200 || status >= 300) {
25702
+ throw new GatewayError(tokenErrorCode(status), `kilo refused the device code poll: http_${status}`);
25703
+ }
25704
+ const record2 = recordFrom(parsed);
25705
+ if (record2 === null)
25706
+ throw pendingError("http_200");
25707
+ if (stringFrom(record2, "status") !== "approved")
25708
+ throw pendingError("http_200");
25709
+ const token = stringFrom(record2, "token");
25710
+ if (token === null) {
25711
+ throw new GatewayError("AUTH", "kilo approved the authorization without a token");
25712
+ }
25713
+ const orgId = await orgIdFor(token, deps);
25714
+ return {
25715
+ secrets: {
25716
+ accessToken: token,
25717
+ refreshToken: null,
25718
+ apiKey: null,
25719
+ idToken: null
25720
+ },
25721
+ expiresAt: null,
25722
+ accountEmail: stringFrom(record2, "userEmail"),
25723
+ providerData: orgId === null ? {} : { orgId }
25724
+ };
25725
+ },
25726
+ async refresh() {
25727
+ throw new GatewayError("AUTH", "kilo tokens cannot be refreshed; reconnect the kilo account to get a new one");
25728
+ }
25729
+ };
25730
+
25731
+ // packages/control/src/oauth/kimi.ts
25732
+ var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
25733
+ var DEVICE_CODE_URL = "https://auth.kimi.com/api/oauth/device_authorization";
25734
+ var TOKEN_URL2 = "https://auth.kimi.com/api/oauth/token";
25735
+ var USAGE_URL2 = "https://api.kimi.com/coding/v1/usages";
25736
+ var DEFAULT_INTERVAL_SECONDS = 5;
25737
+ var PENDING_ERRORS = new Set(["authorization_pending", "slow_down"]);
25738
+ function isRecord4(value) {
25739
+ return typeof value === "object" && value !== null;
25740
+ }
25741
+ function recordFrom2(value) {
25742
+ return isRecord4(value) ? value : null;
25743
+ }
25744
+ function stringFrom2(value, field) {
25745
+ const candidate = value[field];
25746
+ return typeof candidate === "string" && candidate.trim().length > 0 ? candidate : null;
25747
+ }
25748
+ function positiveNumberFrom2(value, field) {
25749
+ const candidate = value[field];
25750
+ return typeof candidate === "number" && Number.isFinite(candidate) && candidate > 0 ? candidate : null;
25751
+ }
25752
+ function tokenFrom(value) {
25753
+ const record2 = recordFrom2(value);
25754
+ if (record2 === null) {
25755
+ throw new GatewayError("AUTH", "token endpoint returned no access_token");
25756
+ }
25757
+ const accessToken = stringFrom2(record2, "access_token");
25758
+ if (accessToken === null) {
25759
+ throw new GatewayError("AUTH", "token endpoint returned no access_token");
25760
+ }
25761
+ return {
25762
+ accessToken,
25763
+ refreshToken: stringFrom2(record2, "refresh_token"),
25764
+ expiresIn: positiveNumberFrom2(record2, "expires_in"),
25765
+ email: stringFrom2(record2, "email")
25766
+ };
25767
+ }
25768
+ function deviceCodeFrom2(value) {
25769
+ const record2 = recordFrom2(value);
25770
+ if (record2 === null) {
25771
+ throw new GatewayError("AUTH", "device code endpoint returned an unusable response");
25772
+ }
25773
+ const deviceCode = stringFrom2(record2, "device_code");
25774
+ const userCode = stringFrom2(record2, "user_code");
25775
+ if (deviceCode === null || userCode === null) {
25776
+ throw new GatewayError("AUTH", "device code endpoint returned an unusable response");
25777
+ }
25778
+ return {
25779
+ deviceCode,
25780
+ userCode,
25781
+ verificationUri: stringFrom2(record2, "verification_uri_complete") ?? stringFrom2(record2, "verification_uri") ?? "https://www.kimi.com/device",
25782
+ interval: positiveNumberFrom2(record2, "interval") ?? DEFAULT_INTERVAL_SECONDS
25783
+ };
25784
+ }
25785
+ async function post(url2, body2, device3, deps) {
25786
+ const { status, parsed } = await postJson(deps, "kimi", url2, PROFILES.kimi, {
25787
+ contentType: "application/x-www-form-urlencoded",
25788
+ body: new URLSearchParams({ ...body2, client_id: CLIENT_ID3 }).toString(),
25789
+ extraHeaders: kimiDeviceHeaders(device3)
25790
+ });
25791
+ if (status >= 200 && status < 300)
25792
+ return parsed;
25793
+ const record2 = recordFrom2(parsed);
25794
+ const code = record2 === null ? `http_${status}` : stringFrom2(record2, "error") ?? `http_${status}`;
25795
+ if (PENDING_ERRORS.has(code))
25796
+ throw pendingError(code);
25797
+ throw new GatewayError(tokenErrorCode(status), tokenErrorMessage(status, parsed));
25798
+ }
25799
+ function deviceFrom(source) {
25800
+ if (typeof source?.deviceId === "string" && source.deviceId.length > 0) {
25801
+ const fresh = mintKimiDevice();
25802
+ const field = (key, fallback) => {
25803
+ const value = source[key];
25804
+ return typeof value === "string" && value.length > 0 ? value : fallback;
25805
+ };
25806
+ return {
25807
+ deviceId: source.deviceId,
25808
+ deviceName: field("deviceName", fresh.deviceName),
25809
+ deviceModel: field("deviceModel", fresh.deviceModel),
25810
+ osVersion: field("osVersion", fresh.osVersion)
25811
+ };
25812
+ }
25813
+ return mintKimiDevice();
25814
+ }
25815
+ function deviceForBegin(deviceId) {
25816
+ return { ...mintKimiDevice(), deviceId };
25817
+ }
25818
+ function toResult3(token, device3, fallbackRefresh, deps) {
25819
+ return {
25820
+ secrets: {
25821
+ accessToken: token.accessToken,
25822
+ refreshToken: token.refreshToken ?? fallbackRefresh,
25823
+ apiKey: null,
25824
+ idToken: null
25825
+ },
25826
+ expiresAt: token.expiresIn === null ? null : deps.now() + token.expiresIn * 1000,
25827
+ accountEmail: token.email,
25828
+ providerData: { ...device3 }
25829
+ };
25830
+ }
25831
+ function parseKimiUsage(value, now) {
25832
+ const root = recordOf(value);
25833
+ if (root === null)
25834
+ return null;
25835
+ return reportFrom([windowFrom(root.usage ?? root.Usage, "weekly", now)]);
25836
+ }
25837
+ var kimiOAuth = {
25838
+ id: "kimi",
25839
+ kind: "device",
25840
+ needsDeviceId: true,
25841
+ supportsManualPaste: false,
25842
+ start() {
25843
+ const device3 = mintKimiDevice();
25844
+ return {
25845
+ authorizeUrl: "https://www.kimi.com/device",
25846
+ pending: { verifier: "", challenge: "", state: "", redirectUri: "", extra: { ...device3 } }
25847
+ };
25848
+ },
25849
+ async begin({ deviceId }, deps) {
25850
+ if (deviceId.trim().length === 0) {
25851
+ throw new GatewayError("INTERNAL", "kimi begin requires a non-blank deviceId");
25852
+ }
25853
+ const device3 = deviceForBegin(deviceId);
25854
+ const response = deviceCodeFrom2(await post(DEVICE_CODE_URL, {}, device3, deps));
25855
+ return {
25856
+ authorizeUrl: response.verificationUri,
25857
+ userCode: response.userCode,
25858
+ pending: {
25859
+ verifier: "",
25860
+ challenge: "",
25861
+ state: "",
25862
+ redirectUri: "",
25863
+ deviceCode: response.deviceCode,
25864
+ interval: response.interval,
25865
+ extra: { ...device3 }
25866
+ }
25867
+ };
25868
+ },
25869
+ async exchange({ pending }, deps) {
25870
+ if (pending.deviceCode === undefined) {
25871
+ throw new Error("kimi exchange requires a pending flow produced by begin()");
25872
+ }
25873
+ const device3 = deviceFrom(pending.extra);
25874
+ const token = tokenFrom(await post(TOKEN_URL2, {
25875
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
25876
+ device_code: pending.deviceCode,
25877
+ device_id: device3.deviceId
25878
+ }, device3, deps));
25879
+ return toResult3(token, device3, null, deps);
25880
+ },
25881
+ async refresh(refreshToken, deps, providerData) {
25882
+ const device3 = deviceFrom(providerData);
25883
+ const token = tokenFrom(await post(TOKEN_URL2, { grant_type: "refresh_token", refresh_token: refreshToken, device_id: device3.deviceId }, device3, deps));
25884
+ return toResult3(token, device3, refreshToken, deps);
25885
+ },
25886
+ async usage(secrets, deps, providerData) {
25887
+ if (secrets.accessToken === null)
25888
+ return null;
25889
+ const device3 = deviceFrom(providerData);
25890
+ const { status, parsed } = await getJson(deps, "kimi", USAGE_URL2, PROFILES.kimi, {
25891
+ accessToken: secrets.accessToken,
25892
+ extraHeaders: kimiDeviceHeaders(device3)
25893
+ });
25894
+ if (!usageReadable(status, "kimi"))
25895
+ return null;
25896
+ return parseKimiUsage(parsed, deps.now());
25897
+ }
25898
+ };
25899
+
24367
25900
  // packages/control/src/oauth/openai.ts
24368
- var CLIENT_ID3 = "app_EMoamEEZ73f0CkXaXp7hrann";
25901
+ var CLIENT_ID4 = "app_EMoamEEZ73f0CkXaXp7hrann";
24369
25902
  var AUTHORIZE_URL2 = "https://auth.openai.com/oauth/authorize";
24370
25903
  var TOKEN_URL3 = "https://auth.openai.com/oauth/token";
24371
- var SCOPES2 = "openid profile email offline_access";
25904
+ var SCOPES3 = "openid profile email offline_access";
24372
25905
  var USAGE_URL3 = "https://chatgpt.com/backend-api/wham/usage";
24373
- function isRecord3(value) {
25906
+ function isRecord5(value) {
24374
25907
  return typeof value === "object" && value !== null;
24375
25908
  }
24376
25909
  function nonBlankStringOrNull(value) {
@@ -24386,20 +25919,20 @@ function decodeClaims(idToken) {
24386
25919
  return { email: null, accountId: null };
24387
25920
  }
24388
25921
  try {
24389
- const json5 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
24390
- if (!isRecord3(json5))
25922
+ const json7 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
25923
+ if (!isRecord5(json7))
24391
25924
  return { email: null, accountId: null };
24392
- const auth = json5["https://api.openai.com/auth"];
25925
+ const auth = json7["https://api.openai.com/auth"];
24393
25926
  return {
24394
- email: typeof json5.email === "string" ? json5.email : null,
24395
- accountId: isRecord3(auth) ? nonBlankStringOrNull(auth.chatgpt_account_id) : null
25927
+ email: typeof json7.email === "string" ? json7.email : null,
25928
+ accountId: isRecord5(auth) ? nonBlankStringOrNull(auth.chatgpt_account_id) : null
24396
25929
  };
24397
25930
  } catch {
24398
25931
  return { email: null, accountId: null };
24399
25932
  }
24400
25933
  }
24401
- function parseTokenResponse(value) {
24402
- if (!isRecord3(value) || typeof value.access_token !== "string")
25934
+ function parseTokenResponse2(value) {
25935
+ if (!isRecord5(value) || typeof value.access_token !== "string")
24403
25936
  return null;
24404
25937
  return {
24405
25938
  accessToken: value.access_token,
@@ -24408,21 +25941,21 @@ function parseTokenResponse(value) {
24408
25941
  idToken: typeof value.id_token === "string" ? value.id_token : null
24409
25942
  };
24410
25943
  }
24411
- async function postToken2(body2, deps) {
25944
+ async function postToken3(body2, deps) {
24412
25945
  const { status, parsed } = await postJson(deps, "openai", TOKEN_URL3, PROFILES.openai, {
24413
25946
  contentType: "application/x-www-form-urlencoded",
24414
- body: new URLSearchParams({ ...body2, client_id: CLIENT_ID3 }).toString()
25947
+ body: new URLSearchParams({ ...body2, client_id: CLIENT_ID4 }).toString()
24415
25948
  });
24416
25949
  if (status < 200 || status >= 300) {
24417
25950
  throw new GatewayError(tokenErrorCode(status), tokenErrorMessage(status, parsed));
24418
25951
  }
24419
- const token = parseTokenResponse(parsed);
25952
+ const token = parseTokenResponse2(parsed);
24420
25953
  if (token === null) {
24421
25954
  throw new GatewayError("AUTH", "token endpoint returned no access_token");
24422
25955
  }
24423
25956
  return token;
24424
25957
  }
24425
- function toResult3(token, fallbackRefresh, deps, fallbackAccountId = null) {
25958
+ function toResult4(token, fallbackRefresh, deps, fallbackAccountId = null) {
24426
25959
  const claims = decodeClaims(token.idToken);
24427
25960
  return {
24428
25961
  secrets: {
@@ -24436,17 +25969,21 @@ function toResult3(token, fallbackRefresh, deps, fallbackAccountId = null) {
24436
25969
  providerData: { accountId: claims.accountId ?? fallbackAccountId }
24437
25970
  };
24438
25971
  }
24439
- function windowTypeOf(value, fallback) {
25972
+ function windowSecondsOf(value) {
24440
25973
  const record2 = recordOf(value);
24441
25974
  if (record2 === null)
24442
- return fallback;
25975
+ return null;
24443
25976
  const seconds = numberOf(record2, [
24444
25977
  "limit_window_seconds",
24445
25978
  "limitWindowSeconds",
24446
25979
  "window_seconds",
24447
25980
  "windowSeconds"
24448
25981
  ]);
24449
- if (seconds === null || seconds <= 0)
25982
+ return seconds === null || seconds <= 0 ? null : seconds;
25983
+ }
25984
+ function windowTypeOf(value, fallback) {
25985
+ const seconds = windowSecondsOf(value);
25986
+ if (seconds === null)
24450
25987
  return fallback;
24451
25988
  if (seconds <= 6 * 60 * 60)
24452
25989
  return "fiveHour";
@@ -24454,6 +25991,10 @@ function windowTypeOf(value, fallback) {
24454
25991
  return "daily";
24455
25992
  return "weekly";
24456
25993
  }
25994
+ function windowMsOf(value) {
25995
+ const seconds = windowSecondsOf(value);
25996
+ return seconds === null ? null : seconds * 1000;
25997
+ }
24457
25998
  function parseOpenAIUsage(value, now) {
24458
25999
  const root = recordOf(value);
24459
26000
  if (root === null)
@@ -24462,8 +26003,8 @@ function parseOpenAIUsage(value, now) {
24462
26003
  const primary = rateLimit.primary_window ?? rateLimit.primaryWindow;
24463
26004
  const secondary = rateLimit.secondary_window ?? rateLimit.secondaryWindow;
24464
26005
  return reportFrom([
24465
- windowFrom(primary, windowTypeOf(primary, "fiveHour"), now),
24466
- windowFrom(secondary, windowTypeOf(secondary, "weekly"), now)
26006
+ windowFrom(primary, windowTypeOf(primary, "fiveHour"), now, windowMsOf(primary)),
26007
+ windowFrom(secondary, windowTypeOf(secondary, "weekly"), now, windowMsOf(secondary))
24467
26008
  ]);
24468
26009
  }
24469
26010
  var openaiOAuth = {
@@ -24474,10 +26015,10 @@ var openaiOAuth = {
24474
26015
  const { verifier, challenge } = createPkce();
24475
26016
  const state = randomState();
24476
26017
  const url2 = new URL(AUTHORIZE_URL2);
24477
- url2.searchParams.set("client_id", CLIENT_ID3);
26018
+ url2.searchParams.set("client_id", CLIENT_ID4);
24478
26019
  url2.searchParams.set("response_type", "code");
24479
26020
  url2.searchParams.set("redirect_uri", redirectUri);
24480
- url2.searchParams.set("scope", SCOPES2);
26021
+ url2.searchParams.set("scope", SCOPES3);
24481
26022
  url2.searchParams.set("code_challenge", challenge);
24482
26023
  url2.searchParams.set("code_challenge_method", "S256");
24483
26024
  url2.searchParams.set("id_token_add_organizations", "true");
@@ -24492,17 +26033,17 @@ var openaiOAuth = {
24492
26033
  if (pastedState !== undefined && pastedState !== pending.state) {
24493
26034
  throw new GatewayError("AUTH", "authorization state mismatch");
24494
26035
  }
24495
- const token = await postToken2({
26036
+ const token = await postToken3({
24496
26037
  grant_type: "authorization_code",
24497
26038
  code: (rawCode ?? "").trim(),
24498
26039
  redirect_uri: pending.redirectUri,
24499
26040
  code_verifier: pending.verifier
24500
26041
  }, deps);
24501
- return toResult3(token, null, deps);
26042
+ return toResult4(token, null, deps);
24502
26043
  },
24503
26044
  async refresh(refreshToken, deps, providerData) {
24504
- const token = await postToken2({ grant_type: "refresh_token", refresh_token: refreshToken, scope: SCOPES2 }, deps);
24505
- return toResult3(token, refreshToken, deps, accountIdFromProviderData(providerData));
26045
+ const token = await postToken3({ grant_type: "refresh_token", refresh_token: refreshToken, scope: SCOPES3 }, deps);
26046
+ return toResult4(token, refreshToken, deps, accountIdFromProviderData(providerData));
24506
26047
  },
24507
26048
  async usage(secrets, deps, providerData) {
24508
26049
  if (secrets.accessToken === null)
@@ -24522,7 +26063,9 @@ var openaiOAuth = {
24522
26063
  var OAUTH_PROVIDERS = {
24523
26064
  anthropic: anthropicOAuth,
24524
26065
  openai: openaiOAuth,
24525
- kimi: kimiOAuth
26066
+ kimi: kimiOAuth,
26067
+ kilo: kiloOAuth,
26068
+ grok: grokOAuth
24526
26069
  };
24527
26070
  // packages/control/src/oauth/lead.ts
24528
26071
  var DISPATCH_REFRESH_LEAD_MS = 120000;
@@ -24584,7 +26127,57 @@ function createRefresher(deps) {
24584
26127
  return promise2;
24585
26128
  };
24586
26129
  }
24587
- // packages/control/src/quota.ts
26130
+ // packages/control/src/quota/history.ts
26131
+ var DAY_MS = 24 * 60 * 60 * 1000;
26132
+ var HOUR_MS2 = 3600000;
26133
+ async function gatewayRatesFor(store, windows) {
26134
+ const rates = [];
26135
+ for (const window2 of windows) {
26136
+ const since = windowStartOf(window2);
26137
+ if (since === null || window2.observedAt <= since) {
26138
+ rates.push({
26139
+ credentialId: window2.credentialId,
26140
+ windowType: window2.windowType,
26141
+ gatewayRatePerHour: null
26142
+ });
26143
+ continue;
26144
+ }
26145
+ const rows = await store.usage.aggregate({
26146
+ grain: "raw",
26147
+ groupBy: "credential",
26148
+ since,
26149
+ until: window2.observedAt
26150
+ });
26151
+ const row = rows.find((r) => r.key === window2.credentialId);
26152
+ const tokens2 = row === undefined ? 0 : row.inputTokens + row.outputTokens + row.cacheReadTokens + row.cacheWriteTokens;
26153
+ rates.push({
26154
+ credentialId: window2.credentialId,
26155
+ windowType: window2.windowType,
26156
+ gatewayRatePerHour: tokens2 / ((window2.observedAt - since) / HOUR_MS2)
26157
+ });
26158
+ }
26159
+ return rates;
26160
+ }
26161
+ async function quotaHistory(deps, input) {
26162
+ const now = deps.now();
26163
+ const settings = await deps.store.config.getSettings();
26164
+ const oldest = now - settings.logRetentionDays * DAY_MS;
26165
+ const since = Math.max(optionalNumber(input.since, oldest), oldest);
26166
+ const until = Math.min(optionalNumber(input.until, now), now);
26167
+ const raw = input.credentialId?.trim();
26168
+ const credentialId = raw === undefined || raw.length === 0 ? undefined : raw;
26169
+ const [samples, quota] = await Promise.all([
26170
+ deps.store.credentials.listQuotaSamples({
26171
+ since,
26172
+ until,
26173
+ ...credentialId === undefined ? {} : { credentialId }
26174
+ }),
26175
+ deps.store.credentials.listQuota()
26176
+ ]);
26177
+ const scoped = credentialId === undefined ? quota : quota.filter((w) => w.credentialId === credentialId);
26178
+ return { samples, gatewayRates: await gatewayRatesFor(deps.store, scoped) };
26179
+ }
26180
+ // packages/control/src/quota/poll.ts
24588
26181
  var CONCURRENCY = 4;
24589
26182
  var RATE_LIMIT_COOLDOWN_MS = 180000;
24590
26183
  var cooldowns = new Map;
@@ -24607,7 +26200,8 @@ async function probe(deps, credential) {
24607
26200
  used: w.used,
24608
26201
  limit: w.limit,
24609
26202
  resetsAt: w.resetsAt,
24610
- observedAt
26203
+ observedAt,
26204
+ windowMs: w.windowMs
24611
26205
  }));
24612
26206
  await deps.store.credentials.saveQuota(rows);
24613
26207
  (deps.logger ?? noopLogger).debug("quota snapshot written", {
@@ -24818,20 +26412,16 @@ async function queryUsage(deps, input) {
24818
26412
  const grain = parseOrThrow(grainSchema, input.grain ?? "raw");
24819
26413
  const groupBy = requireDimension(grain, parseOrThrow(dimensionSchema, input.groupBy ?? "model"));
24820
26414
  const splitBy = input.splitBy === undefined ? undefined : requireDimension(grain, parseOrThrow(dimensionSchema, input.splitBy));
24821
- const since = input.since === undefined ? 0 : Number(input.since);
24822
- const until = input.until === undefined ? deps.now() : Number(input.until);
24823
26415
  return deps.store.usage.aggregate({
24824
26416
  grain,
24825
26417
  groupBy,
24826
26418
  ...splitBy === undefined ? {} : { splitBy },
24827
- since: Number.isFinite(since) ? since : 0,
24828
- until: Number.isFinite(until) ? until : deps.now()
26419
+ since: optionalNumber(input.since, 0),
26420
+ until: optionalNumber(input.until, deps.now())
24829
26421
  });
24830
26422
  }
24831
26423
  function logLimit(requested) {
24832
- const value = requested === undefined ? DEFAULT_LOG_LIMIT : Number(requested);
24833
- if (!Number.isFinite(value))
24834
- return DEFAULT_LOG_LIMIT;
26424
+ const value = optionalNumber(requested, DEFAULT_LOG_LIMIT);
24835
26425
  return Math.floor(Math.min(Math.max(1, value), MAX_LOG_LIMIT));
24836
26426
  }
24837
26427
  async function recentLogs(store, requested) {
@@ -32237,7 +33827,7 @@ var emptySchema = {
32237
33827
 
32238
33828
  // node_modules/.bun/elysia@1.4.29+5b33ebcc42722450/node_modules/elysia/dist/error.mjs
32239
33829
  var env2 = typeof Bun < "u" ? Bun.env : typeof process < "u" ? process?.env : undefined;
32240
- var ERROR_CODE2 = Symbol("ElysiaErrorCode");
33830
+ var ERROR_CODE3 = Symbol("ElysiaErrorCode");
32241
33831
  var isProduction = (env2?.NODE_ENV ?? env2?.ENV) === "production";
32242
33832
  var emptyHttpStatus = {
32243
33833
  101: undefined,
@@ -36793,7 +38383,7 @@ c.defs=definitions
36793
38383
  schema: app.router.history,
36794
38384
  definitions: app.definitions.type,
36795
38385
  tee,
36796
- ERROR_CODE: ERROR_CODE2,
38386
+ ERROR_CODE: ERROR_CODE3,
36797
38387
  parseCookie: hasCookie ? parseCookie : undefined,
36798
38388
  signCookie: hasCookie ? signCookie : undefined,
36799
38389
  Cookie: hasCookie ? Cookie : undefined,
@@ -37066,7 +38656,7 @@ return mapResponse(${saveResponse}error,set${adapter.mapResponseContext})}`;
37066
38656
  return Function("inject", `"use strict";
37067
38657
  ` + fnLiteral)({
37068
38658
  mapResponse: app["~adapter"].handler.mapResponse,
37069
- ERROR_CODE: ERROR_CODE2,
38659
+ ERROR_CODE: ERROR_CODE3,
37070
38660
  ElysiaCustomStatusResponse,
37071
38661
  ValidationError,
37072
38662
  TransformDecodeError,
@@ -38521,12 +40111,12 @@ var _Elysia = class _Elysia2 {
38521
40111
  error(name, error51) {
38522
40112
  switch (typeof name) {
38523
40113
  case "string":
38524
- return error51.prototype[ERROR_CODE2] = name, this.definitions.error[name] = error51, this;
40114
+ return error51.prototype[ERROR_CODE3] = name, this.definitions.error[name] = error51, this;
38525
40115
  case "function":
38526
40116
  return this.definitions.error = name(this.definitions.error), this;
38527
40117
  }
38528
40118
  for (const [code, error210] of Object.entries(name))
38529
- error210.prototype[ERROR_CODE2] = code, this.definitions.error[code] = error210;
40119
+ error210.prototype[ERROR_CODE3] = code, this.definitions.error[code] = error210;
38530
40120
  return this;
38531
40121
  }
38532
40122
  onError(options, handler) {
@@ -39340,7 +40930,7 @@ function parseOrThrow2(schema, body2) {
39340
40930
  const path = issue2?.path.join(".") ?? "(root)";
39341
40931
  throw new GatewayError("BAD_REQUEST", `${path}: ${issue2?.message ?? "invalid request"}`);
39342
40932
  }
39343
- function isRecord4(value) {
40933
+ function isRecord6(value) {
39344
40934
  return typeof value === "object" && value !== null;
39345
40935
  }
39346
40936
  function extraFields(body2, known) {
@@ -39399,7 +40989,7 @@ async function readJson(request2) {
39399
40989
  }
39400
40990
  async function readJsonRecord(request2) {
39401
40991
  const body2 = await readJson(request2);
39402
- return isRecord4(body2) ? body2 : null;
40992
+ return isRecord6(body2) ? body2 : null;
39403
40993
  }
39404
40994
  function apiErrorResponse(error51) {
39405
40995
  const gatewayError = error51 instanceof GatewayError ? error51 : new GatewayError("INTERNAL", "internal error");
@@ -39476,7 +41066,14 @@ function adminRoutes(deps) {
39476
41066
  };
39477
41067
  }).get("/api/credentials/health", async ({ request: request2 }) => {
39478
41068
  await requireAdmin(request2, deps.admin);
39479
- return credentialHealth(deps.store);
41069
+ return credentialHealth(deps);
41070
+ }).get("/api/credentials/quota/history", async ({ request: request2, query }) => {
41071
+ await requireAdmin(request2, deps.admin);
41072
+ return quotaHistory(deps, {
41073
+ since: query.since,
41074
+ until: query.until,
41075
+ credentialId: query.credentialId
41076
+ });
39480
41077
  }).patch("/api/credentials/:id", async ({ request: request2, params }) => {
39481
41078
  await requireAdmin(request2, deps.admin);
39482
41079
  await patchCredential(deps, params.id, await readJson(request2));
@@ -41517,7 +43114,8 @@ async function attempt(opts) {
41517
43114
  providerData: credential.providerData
41518
43115
  },
41519
43116
  http,
41520
- signal
43117
+ signal,
43118
+ ...opts.requestId === undefined ? {} : { requestId: opts.requestId }
41521
43119
  });
41522
43120
  }
41523
43121
 
@@ -41551,6 +43149,8 @@ var WRITE_OVER_INPUT = {
41551
43149
  anthropic: { fiveMinute: 1.25, oneHour: 2 },
41552
43150
  openai: { fiveMinute: 0, oneHour: 0 },
41553
43151
  kimi: { fiveMinute: 0, oneHour: 0 },
43152
+ kilo: { fiveMinute: 0, oneHour: 0 },
43153
+ grok: { fiveMinute: 0, oneHour: 0 },
41554
43154
  custom: { fiveMinute: 0, oneHour: 0 }
41555
43155
  };
41556
43156
  function splitWrites(usage) {
@@ -42009,7 +43609,7 @@ var frame = (event, data) => ({
42009
43609
  });
42010
43610
  async function* anthropicStream(events, requestId) {
42011
43611
  let model = "";
42012
- const suppressed = new Set;
43612
+ const suppressed2 = new Set;
42013
43613
  const outIndex = new Map;
42014
43614
  let nextOutIndex = 0;
42015
43615
  for await (const event of events) {
@@ -42038,7 +43638,7 @@ async function* anthropicStream(events, requestId) {
42038
43638
  case "blockStart": {
42039
43639
  const b = event.block;
42040
43640
  if (b.type === "thinking" && b.signed !== true) {
42041
- suppressed.add(event.index);
43641
+ suppressed2.add(event.index);
42042
43642
  break;
42043
43643
  }
42044
43644
  const content_block = b.type === "text" ? { type: "text", text: "" } : b.type === "thinking" ? { type: "thinking", thinking: "" } : b.type === "anthropicNative" ? { ...b.data, type: b.blockType } : { type: "tool_use", id: b.id, name: b.name, input: {} };
@@ -42052,7 +43652,7 @@ async function* anthropicStream(events, requestId) {
42052
43652
  break;
42053
43653
  }
42054
43654
  case "blockDelta": {
42055
- if (suppressed.has(event.index))
43655
+ if (suppressed2.has(event.index))
42056
43656
  break;
42057
43657
  const d = event.delta;
42058
43658
  const delta2 = d.type === "text" ? { type: "text_delta", text: d.text } : d.type === "thinking" ? { type: "thinking_delta", thinking: d.text } : d.type === "thinkingSignature" ? { type: "signature_delta", signature: d.signature } : d.type === "anthropicNative" ? { type: d.deltaType, ...d.data } : { type: "input_json_delta", partial_json: d.partial };
@@ -42064,7 +43664,7 @@ async function* anthropicStream(events, requestId) {
42064
43664
  break;
42065
43665
  }
42066
43666
  case "blockEnd":
42067
- if (suppressed.has(event.index))
43667
+ if (suppressed2.has(event.index))
42068
43668
  break;
42069
43669
  yield frame("content_block_stop", {
42070
43670
  type: "content_block_stop",
@@ -42141,7 +43741,7 @@ function usageBody(usage) {
42141
43741
  prompt_tokens_details: { cached_tokens: usage.cacheReadTokens }
42142
43742
  };
42143
43743
  }
42144
- var FINISH2 = {
43744
+ var FINISH3 = {
42145
43745
  endTurn: "stop",
42146
43746
  maxTokens: "length",
42147
43747
  stopSequence: "stop",
@@ -42240,7 +43840,7 @@ async function* openaiStream(events, requestId, created) {
42240
43840
  break;
42241
43841
  case "end":
42242
43842
  completed = true;
42243
- yield emit(chunk(requestId, created, model, { index: 0, delta: {}, finish_reason: FINISH2[event.stopReason] }, usageBody(event.usage)));
43843
+ yield emit(chunk(requestId, created, model, { index: 0, delta: {}, finish_reason: FINISH3[event.stopReason] }, usageBody(event.usage)));
42244
43844
  break;
42245
43845
  case "error": {
42246
43846
  const e = ERROR_TYPE3[event.code];
@@ -42274,7 +43874,7 @@ function openaiResponse(collected, requestId, created) {
42274
43874
  content: toolCalls.length > 0 && text.length === 0 ? null : text,
42275
43875
  ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
42276
43876
  },
42277
- finish_reason: FINISH2[collected.stopReason]
43877
+ finish_reason: FINISH3[collected.stopReason]
42278
43878
  }
42279
43879
  ],
42280
43880
  usage: usageBody(collected.usage)
@@ -42802,10 +44402,10 @@ function toIrToolChoice(c) {
42802
44402
  }
42803
44403
  var EFFORTS = ["low", "medium", "high", "xhigh", "max"];
42804
44404
  function readEffort(body2) {
42805
- if (!isRecord4(body2))
44405
+ if (!isRecord6(body2))
42806
44406
  return;
42807
44407
  const outputConfig = body2.output_config;
42808
- if (!isRecord4(outputConfig))
44408
+ if (!isRecord6(outputConfig))
42809
44409
  return;
42810
44410
  const effort = outputConfig.effort;
42811
44411
  return EFFORTS.find((level) => level === effort);
@@ -43461,18 +45061,24 @@ function createApp(deps) {
43461
45061
 
43462
45062
  // apps/gateway/src/maintenance.ts
43463
45063
  var SWEEP_INTERVAL_MS = 60 * 60 * 1000;
43464
- var DAY_MS = 24 * 60 * 60 * 1000;
45064
+ var DAY_MS2 = 24 * 60 * 60 * 1000;
43465
45065
  var ROLLUP_RETENTION_DAYS = 400;
43466
45066
  async function pruneLogs(store, now) {
43467
45067
  const settings = await store.config.getSettings();
43468
- const raw = await store.usage.prune(now - settings.logRetentionDays * DAY_MS);
43469
- const daily = await store.usage.pruneDaily(now - ROLLUP_RETENTION_DAYS * DAY_MS);
43470
- return { raw, daily };
45068
+ const rawHorizon = now - settings.logRetentionDays * DAY_MS2;
45069
+ const raw = await store.usage.prune(rawHorizon);
45070
+ const daily = await store.usage.pruneDaily(now - ROLLUP_RETENTION_DAYS * DAY_MS2);
45071
+ const quotaSamples = await store.credentials.pruneQuotaSamples(rawHorizon);
45072
+ return { raw, daily, quotaSamples };
43471
45073
  }
43472
45074
  function startMaintenance(deps) {
43473
45075
  const logger2 = deps.logger ?? noopLogger;
43474
45076
  const timer = setInterval(() => {
43475
- pruneLogs(deps.store, deps.now()).then(({ raw, daily }) => logger2.debug("request logs pruned", { rawCount: raw, dailyCount: daily })).catch((error51) => {
45077
+ pruneLogs(deps.store, deps.now()).then(({ raw, daily, quotaSamples }) => logger2.debug("request logs pruned", {
45078
+ rawCount: raw,
45079
+ dailyCount: daily,
45080
+ quotaSampleCount: quotaSamples
45081
+ })).catch((error51) => {
43476
45082
  logger2.error("log pruning failed", {
43477
45083
  reason: error51 instanceof Error ? error51.message : "unknown"
43478
45084
  });