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.
- package/README.md +94 -7
- package/bin/omni.js +3542 -1826
- package/gateway.js +2430 -824
- package/package.json +1 -1
- package/public/assets/{Chip-C4X8tf5z.js → Chip-DJwp7gBu.js} +2 -2
- package/public/assets/Confirm-CVLz9F7a.js +4 -0
- package/public/assets/{CopyValue-B-uR4Js-.js → CopyValue-CNZbWS59.js} +4 -4
- package/public/assets/{Field-Ct4SeDZD.js → Field-BDtp692L.js} +8 -8
- package/public/assets/Lamp-B65uWKbW.js +25 -0
- package/public/assets/{Meter-COdz0dwY.js → Meter-BREBUFGX.js} +2 -2
- package/public/assets/{Modal-DMFUHQ-A.js → Modal-DbydSAlp.js} +8 -8
- package/public/assets/Rack-Bbo4JfEX.js +151 -0
- package/public/assets/{Readout-Bl2kD9Tl.js → Readout-CEAoN5hu.js} +5 -5
- package/public/assets/{States-D5Memn8D.js → States-BEKLros0.js} +10 -10
- package/public/assets/{Table-DObRatbW.js → Table-BBypbVWj.js} +1 -1
- package/public/assets/{Toggle-Dkjlvck5.js → Toggle-BUr71O4J.js} +2 -2
- package/public/assets/{TokenBreakdown-oXP49ZTa.js → TokenBreakdown-C1ziK9d1.js} +4 -4
- package/public/assets/_app-ByQ1bPbe.js +1 -0
- package/public/assets/_app.accounts-BTug_Xfo.js +64 -0
- package/public/assets/{_app.console-BVVpryIB.js → _app.console-DKyGL9xx.js} +10 -10
- package/public/assets/_app.index-CSw9gmMf.js +62 -0
- package/public/assets/_app.keys-07Kbw4RS.js +39 -0
- package/public/assets/_app.logs-C9QiV39p.js +32 -0
- package/public/assets/_app.models-CDqVrAeF.js +148 -0
- package/public/assets/{_app.settings-BN436vI2.js → _app.settings-DmUEeTaP.js} +10 -10
- package/public/assets/_app.usage-B1WuMGRr.js +83 -0
- package/public/assets/catalog-BBKm8Ih8.js +1 -0
- package/public/assets/{dist-CnzT-Ut2.js → dist-Bka7ErcH.js} +1 -1
- package/public/assets/index-DJfb1i4P.js +186 -0
- package/public/assets/{login-2LpCZOtB.js → login-DKZYqRh0.js} +8 -8
- package/public/assets/queries-D8LJNQpL.js +144 -0
- package/public/assets/shared-CIhZ6FCO.js +84 -0
- package/public/assets/{trash-2-Da6cLgPn.js → trash-2-CLYNAAJA.js} +1 -1
- package/public/index.html +2 -2
- package/public/assets/Confirm-BnmH8Gn0.js +0 -4
- package/public/assets/Lamp-CBOwqG5K.js +0 -25
- package/public/assets/Rack-DAbY9x1I.js +0 -151
- package/public/assets/_app-Brc2wQZm.js +0 -1
- package/public/assets/_app.accounts-I9RXUiyi.js +0 -54
- package/public/assets/_app.index-83Ig4FUL.js +0 -62
- package/public/assets/_app.keys-KeP6L4g_.js +0 -39
- package/public/assets/_app.logs-B5oh01Ls.js +0 -32
- package/public/assets/_app.models-BuOFMZUN.js +0 -144
- package/public/assets/_app.usage-C528VOia.js +0 -166
- package/public/assets/catalog-kJ53n_fc.js +0 -1
- package/public/assets/index-CE-KQ-ju.js +0 -172
- 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
|
|
4687
|
-
if (
|
|
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/
|
|
5724
|
-
|
|
5725
|
-
|
|
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
|
-
|
|
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
|
|
7255
|
+
const betas2 = new Set(req.request.betas ?? []);
|
|
6878
7256
|
const notes = [...degradations];
|
|
6879
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
6898
|
-
protocol.push(["anthropic-beta", [...
|
|
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 (
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
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:
|
|
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 (
|
|
7000
|
-
yield { type: "blockEnd", index:
|
|
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/
|
|
7518
|
-
|
|
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:
|
|
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
|
|
7576
|
-
var
|
|
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 ?
|
|
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
|
|
8724
|
+
async function sendGet(deps, provider, url, profile2, authHeaders, extraHeaders) {
|
|
7641
8725
|
const headers = orderHeaders(mergeHeaders(profile2.headers, [
|
|
7642
|
-
|
|
8726
|
+
...authHeaders,
|
|
7643
8727
|
["Accept", "application/json"],
|
|
7644
|
-
...
|
|
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 = [
|
|
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
|
|
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
|
|
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
|
|
8793
|
+
const callbackUri = (provider) => CALLBACKS[provider]?.uri ?? "";
|
|
8017
8794
|
function normalizeAuthorizationCode(flow, input) {
|
|
8018
|
-
|
|
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 !==
|
|
8027
|
-
throw new GatewayError("BAD_REQUEST",
|
|
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",
|
|
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
|
|
8091
|
-
|
|
8092
|
-
|
|
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: () =>
|
|
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
|
|
19780
|
-
|
|
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
|
-
|
|
20504
|
+
json6.minLength = minimum;
|
|
19784
20505
|
if (typeof maximum === "number")
|
|
19785
|
-
|
|
20506
|
+
json6.maxLength = maximum;
|
|
19786
20507
|
if (format) {
|
|
19787
|
-
|
|
19788
|
-
if (
|
|
19789
|
-
delete
|
|
20508
|
+
json6.format = formatMap[format] ?? format;
|
|
20509
|
+
if (json6.format === "")
|
|
20510
|
+
delete json6.format;
|
|
19790
20511
|
if (format === "time") {
|
|
19791
|
-
delete
|
|
20512
|
+
delete json6.format;
|
|
19792
20513
|
}
|
|
19793
20514
|
}
|
|
19794
20515
|
if (contentEncoding)
|
|
19795
|
-
|
|
20516
|
+
json6.contentEncoding = contentEncoding;
|
|
19796
20517
|
if (patterns && patterns.size > 0) {
|
|
19797
20518
|
const regexes = [...patterns];
|
|
19798
20519
|
if (regexes.length === 1)
|
|
19799
|
-
|
|
20520
|
+
json6.pattern = regexes[0].source;
|
|
19800
20521
|
else if (regexes.length > 1) {
|
|
19801
|
-
|
|
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
|
|
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
|
-
|
|
20535
|
+
json6.type = "integer";
|
|
19815
20536
|
else
|
|
19816
|
-
|
|
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
|
-
|
|
19823
|
-
|
|
20543
|
+
json6.minimum = exclusiveMinimum;
|
|
20544
|
+
json6.exclusiveMinimum = true;
|
|
19824
20545
|
} else {
|
|
19825
|
-
|
|
20546
|
+
json6.exclusiveMinimum = exclusiveMinimum;
|
|
19826
20547
|
}
|
|
19827
20548
|
} else if (typeof minimum === "number") {
|
|
19828
|
-
|
|
20549
|
+
json6.minimum = minimum;
|
|
19829
20550
|
}
|
|
19830
20551
|
if (exMax) {
|
|
19831
20552
|
if (legacy) {
|
|
19832
|
-
|
|
19833
|
-
|
|
20553
|
+
json6.maximum = exclusiveMaximum;
|
|
20554
|
+
json6.exclusiveMaximum = true;
|
|
19834
20555
|
} else {
|
|
19835
|
-
|
|
20556
|
+
json6.exclusiveMaximum = exclusiveMaximum;
|
|
19836
20557
|
}
|
|
19837
20558
|
} else if (typeof maximum === "number") {
|
|
19838
|
-
|
|
20559
|
+
json6.maximum = maximum;
|
|
19839
20560
|
}
|
|
19840
20561
|
if (typeof multipleOf === "number")
|
|
19841
|
-
|
|
20562
|
+
json6.multipleOf = multipleOf;
|
|
19842
20563
|
};
|
|
19843
|
-
var booleanProcessor = (_schema, _ctx,
|
|
19844
|
-
|
|
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,
|
|
20577
|
+
var nullProcessor = (_schema, ctx, json6, _params) => {
|
|
19857
20578
|
if (ctx.target === "openapi-3.0") {
|
|
19858
|
-
|
|
19859
|
-
|
|
19860
|
-
|
|
20579
|
+
json6.type = "string";
|
|
20580
|
+
json6.nullable = true;
|
|
20581
|
+
json6.enum = [null];
|
|
19861
20582
|
} else {
|
|
19862
|
-
|
|
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,
|
|
19876
|
-
|
|
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,
|
|
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
|
-
|
|
20610
|
+
json6.type = "number";
|
|
19890
20611
|
if (values.every((v) => typeof v === "string"))
|
|
19891
|
-
|
|
19892
|
-
|
|
20612
|
+
json6.type = "string";
|
|
20613
|
+
json6.enum = values;
|
|
19893
20614
|
};
|
|
19894
|
-
var literalProcessor = (schema, ctx,
|
|
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
|
-
|
|
20635
|
+
json6.type = val === null ? "null" : typeof val;
|
|
19915
20636
|
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
|
|
19916
|
-
|
|
20637
|
+
json6.enum = [val];
|
|
19917
20638
|
} else {
|
|
19918
|
-
|
|
20639
|
+
json6.const = val;
|
|
19919
20640
|
}
|
|
19920
20641
|
} else {
|
|
19921
20642
|
if (vals.every((v) => typeof v === "number"))
|
|
19922
|
-
|
|
20643
|
+
json6.type = "number";
|
|
19923
20644
|
if (vals.every((v) => typeof v === "string"))
|
|
19924
|
-
|
|
20645
|
+
json6.type = "string";
|
|
19925
20646
|
if (vals.every((v) => typeof v === "boolean"))
|
|
19926
|
-
|
|
20647
|
+
json6.type = "boolean";
|
|
19927
20648
|
if (vals.every((v) => v === null))
|
|
19928
|
-
|
|
19929
|
-
|
|
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,
|
|
19938
|
-
const _json =
|
|
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,
|
|
19946
|
-
const _json =
|
|
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,
|
|
19970
|
-
|
|
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
|
|
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
|
-
|
|
20723
|
+
json6.minItems = minimum;
|
|
20003
20724
|
if (typeof maximum === "number")
|
|
20004
|
-
|
|
20005
|
-
|
|
20006
|
-
|
|
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
|
|
20733
|
+
const json6 = _json;
|
|
20013
20734
|
const def = schema._zod.def;
|
|
20014
|
-
|
|
20015
|
-
|
|
20735
|
+
json6.type = "object";
|
|
20736
|
+
json6.properties = {};
|
|
20016
20737
|
const shape = def.shape;
|
|
20017
20738
|
for (const key in shape) {
|
|
20018
|
-
|
|
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
|
-
|
|
20754
|
+
json6.required = Array.from(requiredKeys);
|
|
20034
20755
|
}
|
|
20035
20756
|
if (def.catchall?._zod.def.type === "never") {
|
|
20036
|
-
|
|
20757
|
+
json6.additionalProperties = false;
|
|
20037
20758
|
} else if (!def.catchall) {
|
|
20038
20759
|
if (ctx.io === "output")
|
|
20039
|
-
|
|
20760
|
+
json6.additionalProperties = false;
|
|
20040
20761
|
} else if (def.catchall) {
|
|
20041
|
-
|
|
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,
|
|
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
|
-
|
|
20776
|
+
json6.oneOf = options;
|
|
20056
20777
|
} else {
|
|
20057
|
-
|
|
20778
|
+
json6.anyOf = options;
|
|
20058
20779
|
}
|
|
20059
20780
|
};
|
|
20060
|
-
var intersectionProcessor = (schema, ctx,
|
|
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
|
-
|
|
20796
|
+
json6.allOf = allOf;
|
|
20076
20797
|
};
|
|
20077
20798
|
var tupleProcessor = (schema, ctx, _json, params) => {
|
|
20078
|
-
const
|
|
20799
|
+
const json6 = _json;
|
|
20079
20800
|
const def = schema._zod.def;
|
|
20080
|
-
|
|
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
|
-
|
|
20813
|
+
json6.prefixItems = prefixItems;
|
|
20093
20814
|
if (rest) {
|
|
20094
|
-
|
|
20815
|
+
json6.items = rest;
|
|
20095
20816
|
}
|
|
20096
20817
|
} else if (ctx.target === "openapi-3.0") {
|
|
20097
|
-
|
|
20818
|
+
json6.items = {
|
|
20098
20819
|
anyOf: prefixItems
|
|
20099
20820
|
};
|
|
20100
20821
|
if (rest) {
|
|
20101
|
-
|
|
20822
|
+
json6.items.anyOf.push(rest);
|
|
20102
20823
|
}
|
|
20103
|
-
|
|
20824
|
+
json6.minItems = prefixItems.length;
|
|
20104
20825
|
if (!rest) {
|
|
20105
|
-
|
|
20826
|
+
json6.maxItems = prefixItems.length;
|
|
20106
20827
|
}
|
|
20107
20828
|
} else {
|
|
20108
|
-
|
|
20829
|
+
json6.items = prefixItems;
|
|
20109
20830
|
if (rest) {
|
|
20110
|
-
|
|
20831
|
+
json6.additionalItems = rest;
|
|
20111
20832
|
}
|
|
20112
20833
|
}
|
|
20113
20834
|
const { minimum, maximum } = schema._zod.bag;
|
|
20114
20835
|
if (typeof minimum === "number")
|
|
20115
|
-
|
|
20836
|
+
json6.minItems = minimum;
|
|
20116
20837
|
if (typeof maximum === "number")
|
|
20117
|
-
|
|
20838
|
+
json6.maxItems = maximum;
|
|
20118
20839
|
};
|
|
20119
20840
|
var recordProcessor = (schema, ctx, _json, params) => {
|
|
20120
|
-
const
|
|
20841
|
+
const json6 = _json;
|
|
20121
20842
|
const def = schema._zod.def;
|
|
20122
|
-
|
|
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
|
-
|
|
20852
|
+
json6.patternProperties = {};
|
|
20132
20853
|
for (const pattern of patterns) {
|
|
20133
|
-
|
|
20854
|
+
json6.patternProperties[pattern.source] = valueSchema;
|
|
20134
20855
|
}
|
|
20135
20856
|
} else {
|
|
20136
20857
|
if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
|
|
20137
|
-
|
|
20858
|
+
json6.propertyNames = process2(def.keyType, ctx, {
|
|
20138
20859
|
...params,
|
|
20139
20860
|
path: [...params.path, "propertyNames"]
|
|
20140
20861
|
});
|
|
20141
20862
|
}
|
|
20142
|
-
|
|
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
|
-
|
|
20872
|
+
json6.required = validKeyValues;
|
|
20152
20873
|
}
|
|
20153
20874
|
}
|
|
20154
20875
|
};
|
|
20155
|
-
var nullableProcessor = (schema, ctx,
|
|
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
|
-
|
|
20882
|
+
json6.nullable = true;
|
|
20162
20883
|
} else {
|
|
20163
|
-
|
|
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,
|
|
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
|
-
|
|
20898
|
+
json6.default = JSON.parse(JSON.stringify(def.defaultValue));
|
|
20178
20899
|
};
|
|
20179
|
-
var prefaultProcessor = (schema, ctx,
|
|
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
|
-
|
|
20906
|
+
json6._prefault = JSON.parse(JSON.stringify(def.defaultValue));
|
|
20186
20907
|
};
|
|
20187
|
-
var catchProcessor = (schema, ctx,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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: () =>
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
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/
|
|
22584
|
-
|
|
22585
|
-
|
|
22586
|
-
|
|
22587
|
-
|
|
22588
|
-
|
|
22589
|
-
|
|
22590
|
-
|
|
22591
|
-
|
|
22592
|
-
|
|
22593
|
-
|
|
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
|
|
22613
|
-
const
|
|
22614
|
-
|
|
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
|
|
22631
|
-
|
|
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
|
-
|
|
22634
|
-
|
|
22635
|
-
|
|
22636
|
-
|
|
22637
|
-
|
|
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
|
|
22671
|
-
|
|
22672
|
-
|
|
22673
|
-
|
|
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
|
|
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
|
|
22700
|
-
|
|
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/
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
25341
|
+
var CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
24270
25342
|
var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
24271
|
-
var
|
|
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
|
|
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",
|
|
25348
|
+
const { status, parsed } = await postJson(deps, "anthropic", TOKEN_URL, PROFILES.anthropic, {
|
|
24277
25349
|
contentType: "application/json",
|
|
24278
|
-
body: JSON.stringify({ ...body2, client_id:
|
|
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
|
|
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",
|
|
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
|
|
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
|
|
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",
|
|
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
|
|
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
|
|
25904
|
+
var SCOPES3 = "openid profile email offline_access";
|
|
24372
25905
|
var USAGE_URL3 = "https://chatgpt.com/backend-api/wham/usage";
|
|
24373
|
-
function
|
|
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
|
|
24390
|
-
if (!
|
|
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 =
|
|
25925
|
+
const auth = json7["https://api.openai.com/auth"];
|
|
24393
25926
|
return {
|
|
24394
|
-
email: typeof
|
|
24395
|
-
accountId:
|
|
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
|
|
24402
|
-
if (!
|
|
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
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
25972
|
+
function windowSecondsOf(value) {
|
|
24440
25973
|
const record2 = recordOf(value);
|
|
24441
25974
|
if (record2 === null)
|
|
24442
|
-
return
|
|
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
|
-
|
|
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",
|
|
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",
|
|
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
|
|
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
|
|
26042
|
+
return toResult4(token, null, deps);
|
|
24502
26043
|
},
|
|
24503
26044
|
async refresh(refreshToken, deps, providerData) {
|
|
24504
|
-
const token = await
|
|
24505
|
-
return
|
|
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:
|
|
24828
|
-
until:
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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[
|
|
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[
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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
|
|
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:
|
|
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:
|
|
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 (!
|
|
44405
|
+
if (!isRecord6(body2))
|
|
42806
44406
|
return;
|
|
42807
44407
|
const outputConfig = body2.output_config;
|
|
42808
|
-
if (!
|
|
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
|
|
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
|
|
43469
|
-
const
|
|
43470
|
-
|
|
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", {
|
|
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
|
});
|