omnigateway 0.1.7 → 0.1.8
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/bin/omni.js +351 -124
- package/gateway.js +402 -182
- package/package.json +1 -1
- package/public/assets/{Chip-C69u2U_b.js → Chip-CM9ZMdr9.js} +1 -1
- package/public/assets/{CopyValue-CJy2T0H6.js → CopyValue-WrOTcHwq.js} +4 -4
- package/public/assets/{Field-Sc8mDqJv.js → Field-Br6jKPz8.js} +8 -8
- package/public/assets/{Lamp-7jD_9929.js → Lamp-DO-sRDg2.js} +7 -7
- package/public/assets/{Meter-C0nUftAa.js → Meter-BzMaum0C.js} +1 -1
- package/public/assets/{Modal-CiVHSJmm.js → Modal-lhjr949H.js} +8 -8
- package/public/assets/{Rack-CMqGBP4I.js → Rack-BFWC50ex.js} +18 -18
- package/public/assets/{Readout-Dv2dZWtI.js → Readout-DMJs4gYD.js} +5 -5
- package/public/assets/{States-D55MhqMx.js → States-BNeCLhZn.js} +10 -10
- package/public/assets/{Table-DBB3jdgi.js → Table-nOg_lgEJ.js} +1 -1
- package/public/assets/{Toggle-BoGjb5oi.js → Toggle-DYoCVD37.js} +2 -2
- package/public/assets/_app-lXr06Xli.js +1 -0
- package/public/assets/_app.accounts-BTb5vHI_.js +51 -0
- package/public/assets/{_app.console-Bka7AkiL.js → _app.console-DHUClMsI.js} +7 -7
- package/public/assets/_app.index-DZ--9mKU.js +61 -0
- package/public/assets/{_app.keys-BX8k8COP.js → _app.keys-B-cy-2DS.js} +8 -8
- package/public/assets/_app.logs-BQjAIT2P.js +33 -0
- package/public/assets/_app.models-BAmXHlf2.js +144 -0
- package/public/assets/_app.settings-CG8bv_rm.js +34 -0
- package/public/assets/{_app.usage-BRhEvwVr.js → _app.usage-BLrQ2hB8.js} +28 -28
- package/public/assets/index-UAZ0O5y0.js +170 -0
- package/public/assets/{login-DaC-wVpI.js → login-BpUl6C5b.js} +8 -8
- package/public/assets/{queries-2E6-CboE.js → queries-D_-Jj9vt.js} +1 -1
- package/public/assets/{trash-2--aH2iKg-.js → trash-2-DjWP2u19.js} +1 -1
- package/public/index.html +2 -2
- package/public/assets/_app-p5Mz7sXD.js +0 -1
- package/public/assets/_app.accounts-B5wMO9TH.js +0 -51
- package/public/assets/_app.index-MnQuadXb.js +0 -61
- package/public/assets/_app.logs-DD-sd4fn.js +0 -33
- package/public/assets/_app.models-CezFNL6y.js +0 -144
- package/public/assets/_app.settings-D1taAt8B.js +0 -16
- package/public/assets/index-vCuK1fRQ.js +0 -170
package/gateway.js
CHANGED
|
@@ -5543,6 +5543,54 @@ function parseJson(raw) {
|
|
|
5543
5543
|
return {};
|
|
5544
5544
|
}
|
|
5545
5545
|
}
|
|
5546
|
+
// packages/ir/src/tokens.ts
|
|
5547
|
+
var CHARS_PER_TOKEN = 4;
|
|
5548
|
+
var IMAGE_TOKENS = 1600;
|
|
5549
|
+
var BLOCK_OVERHEAD = 4;
|
|
5550
|
+
var MESSAGE_OVERHEAD = 4;
|
|
5551
|
+
function fromText(text) {
|
|
5552
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
5553
|
+
}
|
|
5554
|
+
function blockTokens(block) {
|
|
5555
|
+
switch (block.type) {
|
|
5556
|
+
case "text":
|
|
5557
|
+
return BLOCK_OVERHEAD + fromText(block.text);
|
|
5558
|
+
case "image":
|
|
5559
|
+
return BLOCK_OVERHEAD + IMAGE_TOKENS;
|
|
5560
|
+
case "thinking":
|
|
5561
|
+
return BLOCK_OVERHEAD + fromText(block.text);
|
|
5562
|
+
case "toolUse":
|
|
5563
|
+
return BLOCK_OVERHEAD + fromText(block.name) + fromText(safeJson(block.input));
|
|
5564
|
+
case "toolResult":
|
|
5565
|
+
return BLOCK_OVERHEAD + fromText(block.toolUseId) + fromText(block.content);
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5568
|
+
function messageTokens(message) {
|
|
5569
|
+
let total = MESSAGE_OVERHEAD;
|
|
5570
|
+
for (const block of message.content)
|
|
5571
|
+
total += blockTokens(block);
|
|
5572
|
+
return total;
|
|
5573
|
+
}
|
|
5574
|
+
function toolTokens(tool) {
|
|
5575
|
+
return BLOCK_OVERHEAD + fromText(tool.name) + fromText(tool.description ?? "") + fromText(safeJson(tool.inputSchema));
|
|
5576
|
+
}
|
|
5577
|
+
function safeJson(value) {
|
|
5578
|
+
try {
|
|
5579
|
+
return JSON.stringify(value) ?? "";
|
|
5580
|
+
} catch {
|
|
5581
|
+
return "";
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
function estimateInputTokens(request) {
|
|
5585
|
+
let total = 0;
|
|
5586
|
+
for (const block of request.system ?? [])
|
|
5587
|
+
total += blockTokens(block);
|
|
5588
|
+
for (const message of request.messages)
|
|
5589
|
+
total += messageTokens(message);
|
|
5590
|
+
for (const tool of request.tools ?? [])
|
|
5591
|
+
total += toolTokens(tool);
|
|
5592
|
+
return total;
|
|
5593
|
+
}
|
|
5546
5594
|
// packages/ir/src/validate.ts
|
|
5547
5595
|
function validateRequest(req) {
|
|
5548
5596
|
const seenToolUseIds = new Set;
|
|
@@ -5573,6 +5621,7 @@ function validateRequest(req) {
|
|
|
5573
5621
|
}
|
|
5574
5622
|
// packages/control/src/config.ts
|
|
5575
5623
|
var MIN_KEY_LENGTH = 16;
|
|
5624
|
+
var TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
5576
5625
|
var DECIMAL_INTEGER = /^\d+$/;
|
|
5577
5626
|
function optionalText(value, fallback) {
|
|
5578
5627
|
return value?.trim() || fallback;
|
|
@@ -5592,6 +5641,7 @@ function loadConfig(env) {
|
|
|
5592
5641
|
const baseUrl = optionalText(env.OMNI_BASE_URL, derivedBaseUrl).replace(/\/+$/, "") || derivedBaseUrl;
|
|
5593
5642
|
const staticDir = env.OMNI_STATIC_DIR?.trim();
|
|
5594
5643
|
const logFile = env.OMNI_LOG_FILE?.trim();
|
|
5644
|
+
const exposeClaudeCodeAliases = TRUTHY.has((env.OMNI_EXPOSE_CLAUDE_CODE_ALIASES ?? "").trim().toLowerCase());
|
|
5595
5645
|
const rawLogLevel = env.OMNI_LOG_LEVEL?.trim();
|
|
5596
5646
|
const logLevel = parseLogLevel(rawLogLevel);
|
|
5597
5647
|
return {
|
|
@@ -5603,9 +5653,14 @@ function loadConfig(env) {
|
|
|
5603
5653
|
encryptionKey,
|
|
5604
5654
|
baseUrl,
|
|
5605
5655
|
staticDir: staticDir === undefined || staticDir.length === 0 ? null : staticDir,
|
|
5656
|
+
exposeClaudeCodeAliases,
|
|
5606
5657
|
logFile: logFile === undefined || logFile.length === 0 ? null : logFile
|
|
5607
5658
|
};
|
|
5608
5659
|
}
|
|
5660
|
+
// packages/providers/src/betas.ts
|
|
5661
|
+
var CONTEXT_1M_BETA = "context-1m-2025-08-07";
|
|
5662
|
+
var CONTEXT_1M_TOKENS = 1e6;
|
|
5663
|
+
|
|
5609
5664
|
// packages/providers/src/body.ts
|
|
5610
5665
|
var BODY_ORDER = {
|
|
5611
5666
|
anthropic: [
|
|
@@ -5713,6 +5768,119 @@ function signAnthropicBody(json) {
|
|
|
5713
5768
|
return json.replace(needle, `cch=${computeCch(json)};`);
|
|
5714
5769
|
}
|
|
5715
5770
|
|
|
5771
|
+
// packages/providers/src/anthropic/models.ts
|
|
5772
|
+
var ANTHROPIC_MODELS = {
|
|
5773
|
+
defaultModel: "claude-opus-5",
|
|
5774
|
+
models: [
|
|
5775
|
+
{
|
|
5776
|
+
id: "claude-fable-5",
|
|
5777
|
+
label: "Claude Fable 5",
|
|
5778
|
+
pricing: { input: 10, output: 50, cacheRead: 1, cacheWrite5m: 12.5, cacheWrite1h: 20 },
|
|
5779
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
5780
|
+
},
|
|
5781
|
+
{
|
|
5782
|
+
id: "claude-opus-5",
|
|
5783
|
+
label: "Claude Opus 5",
|
|
5784
|
+
pricing: { input: 5, output: 25, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 10 },
|
|
5785
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
5786
|
+
},
|
|
5787
|
+
{
|
|
5788
|
+
id: "claude-sonnet-5",
|
|
5789
|
+
label: "Claude Sonnet 5",
|
|
5790
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 3.75, cacheWrite1h: 6 },
|
|
5791
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
5792
|
+
},
|
|
5793
|
+
{
|
|
5794
|
+
id: "claude-haiku-4-5",
|
|
5795
|
+
label: "Claude Haiku 4.5",
|
|
5796
|
+
pricing: { input: 1, output: 5, cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 2 },
|
|
5797
|
+
limits: { contextWindow: 200000, maxOutputTokens: 64000 }
|
|
5798
|
+
}
|
|
5799
|
+
]
|
|
5800
|
+
};
|
|
5801
|
+
|
|
5802
|
+
// packages/providers/src/kimi/models.ts
|
|
5803
|
+
var KIMI_MODELS = {
|
|
5804
|
+
defaultModel: "k3-256k",
|
|
5805
|
+
models: [
|
|
5806
|
+
{
|
|
5807
|
+
id: "k3-256k",
|
|
5808
|
+
label: "Kimi K3 \u2014 256K",
|
|
5809
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5810
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
5811
|
+
},
|
|
5812
|
+
{
|
|
5813
|
+
id: "k3",
|
|
5814
|
+
label: "Kimi K3 \u2014 up to 1M",
|
|
5815
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5816
|
+
limits: { contextWindow: 1048576, maxOutputTokens: 131072 }
|
|
5817
|
+
},
|
|
5818
|
+
{
|
|
5819
|
+
id: "kimi-for-coding",
|
|
5820
|
+
label: "Kimi K2.7 Code",
|
|
5821
|
+
pricing: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5822
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
5823
|
+
},
|
|
5824
|
+
{
|
|
5825
|
+
id: "kimi-for-coding-highspeed",
|
|
5826
|
+
label: "Kimi K2.7 Code \u2014 High Speed",
|
|
5827
|
+
pricing: { input: 0.95, output: 8, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5828
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
5829
|
+
}
|
|
5830
|
+
]
|
|
5831
|
+
};
|
|
5832
|
+
|
|
5833
|
+
// packages/providers/src/openai/models.ts
|
|
5834
|
+
var OPENAI_MODELS = {
|
|
5835
|
+
defaultModel: "gpt-5.6",
|
|
5836
|
+
models: [
|
|
5837
|
+
{
|
|
5838
|
+
id: "gpt-5.6",
|
|
5839
|
+
label: "GPT-5.6 \u2014 routes to Sol",
|
|
5840
|
+
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5841
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
5842
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
5843
|
+
},
|
|
5844
|
+
{
|
|
5845
|
+
id: "gpt-5.6-sol",
|
|
5846
|
+
label: "GPT-5.6 Sol \u2014 deepest reasoning",
|
|
5847
|
+
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5848
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
5849
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
5850
|
+
},
|
|
5851
|
+
{
|
|
5852
|
+
id: "gpt-5.6-terra",
|
|
5853
|
+
label: "GPT-5.6 Terra \u2014 balanced",
|
|
5854
|
+
pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5855
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
5856
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
5857
|
+
},
|
|
5858
|
+
{
|
|
5859
|
+
id: "gpt-5.6-luna",
|
|
5860
|
+
label: "GPT-5.6 Luna \u2014 fastest",
|
|
5861
|
+
pricing: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
5862
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
5863
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
5864
|
+
}
|
|
5865
|
+
]
|
|
5866
|
+
};
|
|
5867
|
+
|
|
5868
|
+
// packages/providers/src/catalog.ts
|
|
5869
|
+
var PROVIDER_MODEL_CATALOG = {
|
|
5870
|
+
anthropic: ANTHROPIC_MODELS,
|
|
5871
|
+
openai: OPENAI_MODELS,
|
|
5872
|
+
kimi: KIMI_MODELS
|
|
5873
|
+
};
|
|
5874
|
+
function catalogPricing(provider, model) {
|
|
5875
|
+
return PROVIDER_MODEL_CATALOG[provider]?.models.find((entry) => entry.id === model)?.pricing ?? null;
|
|
5876
|
+
}
|
|
5877
|
+
function catalogLimits(provider, model, auth = "apiKey") {
|
|
5878
|
+
const entry = PROVIDER_MODEL_CATALOG[provider]?.models.find((choice) => choice.id === model);
|
|
5879
|
+
if (entry === undefined)
|
|
5880
|
+
return null;
|
|
5881
|
+
return (auth === "oauth" ? entry.oauthLimits : undefined) ?? entry.limits;
|
|
5882
|
+
}
|
|
5883
|
+
|
|
5716
5884
|
// packages/providers/src/http.ts
|
|
5717
5885
|
function codeForStatus(status) {
|
|
5718
5886
|
if (status === 401 || status === 403)
|
|
@@ -6270,6 +6438,15 @@ var anthropicAdapter = {
|
|
|
6270
6438
|
["Accept", "text/event-stream"]
|
|
6271
6439
|
];
|
|
6272
6440
|
const betas = new Set(req.request.betas ?? []);
|
|
6441
|
+
const notes = [...degradations];
|
|
6442
|
+
if (betas.has(CONTEXT_1M_BETA)) {
|
|
6443
|
+
const limits = catalogLimits("anthropic", req.model, oauth ? "oauth" : "apiKey");
|
|
6444
|
+
const window2 = limits?.contextWindow;
|
|
6445
|
+
if (window2 !== undefined && window2 < CONTEXT_1M_TOKENS) {
|
|
6446
|
+
betas.delete(CONTEXT_1M_BETA);
|
|
6447
|
+
notes.push("anthropic:context-1m-dropped");
|
|
6448
|
+
}
|
|
6449
|
+
}
|
|
6273
6450
|
if (oauth) {
|
|
6274
6451
|
protocol.push(["Authorization", `Bearer ${req.credentials.accessToken}`]);
|
|
6275
6452
|
betas.add(OAUTH_BETA);
|
|
@@ -6297,121 +6474,9 @@ var anthropicAdapter = {
|
|
|
6297
6474
|
throw await httpError(res, "anthropic");
|
|
6298
6475
|
if (res.body === null)
|
|
6299
6476
|
throw new GatewayError("UPSTREAM", "empty response body", { provider: "anthropic" });
|
|
6300
|
-
return { events: decodeAnthropic(parseSse(res.body)), degradations };
|
|
6477
|
+
return { events: decodeAnthropic(parseSse(res.body)), degradations: notes };
|
|
6301
6478
|
}
|
|
6302
6479
|
};
|
|
6303
|
-
// packages/providers/src/anthropic/models.ts
|
|
6304
|
-
var ANTHROPIC_MODELS = {
|
|
6305
|
-
defaultModel: "claude-opus-5",
|
|
6306
|
-
models: [
|
|
6307
|
-
{
|
|
6308
|
-
id: "claude-fable-5",
|
|
6309
|
-
label: "Claude Fable 5",
|
|
6310
|
-
pricing: { input: 10, output: 50, cacheRead: 1, cacheWrite5m: 12.5, cacheWrite1h: 20 },
|
|
6311
|
-
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
6312
|
-
},
|
|
6313
|
-
{
|
|
6314
|
-
id: "claude-opus-5",
|
|
6315
|
-
label: "Claude Opus 5",
|
|
6316
|
-
pricing: { input: 5, output: 25, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 10 },
|
|
6317
|
-
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
6318
|
-
},
|
|
6319
|
-
{
|
|
6320
|
-
id: "claude-sonnet-5",
|
|
6321
|
-
label: "Claude Sonnet 5",
|
|
6322
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 3.75, cacheWrite1h: 6 },
|
|
6323
|
-
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
6324
|
-
},
|
|
6325
|
-
{
|
|
6326
|
-
id: "claude-haiku-4-5",
|
|
6327
|
-
label: "Claude Haiku 4.5",
|
|
6328
|
-
pricing: { input: 1, output: 5, cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 2 },
|
|
6329
|
-
limits: { contextWindow: 200000, maxOutputTokens: 64000 }
|
|
6330
|
-
}
|
|
6331
|
-
]
|
|
6332
|
-
};
|
|
6333
|
-
|
|
6334
|
-
// packages/providers/src/kimi/models.ts
|
|
6335
|
-
var KIMI_MODELS = {
|
|
6336
|
-
defaultModel: "k3-256k",
|
|
6337
|
-
models: [
|
|
6338
|
-
{
|
|
6339
|
-
id: "k3-256k",
|
|
6340
|
-
label: "Kimi K3 \u2014 256K",
|
|
6341
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6342
|
-
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
6343
|
-
},
|
|
6344
|
-
{
|
|
6345
|
-
id: "k3",
|
|
6346
|
-
label: "Kimi K3 \u2014 up to 1M",
|
|
6347
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6348
|
-
limits: { contextWindow: 1048576, maxOutputTokens: 131072 }
|
|
6349
|
-
},
|
|
6350
|
-
{
|
|
6351
|
-
id: "kimi-for-coding",
|
|
6352
|
-
label: "Kimi K2.7 Code",
|
|
6353
|
-
pricing: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6354
|
-
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
6355
|
-
},
|
|
6356
|
-
{
|
|
6357
|
-
id: "kimi-for-coding-highspeed",
|
|
6358
|
-
label: "Kimi K2.7 Code \u2014 High Speed",
|
|
6359
|
-
pricing: { input: 0.95, output: 8, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6360
|
-
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
6361
|
-
}
|
|
6362
|
-
]
|
|
6363
|
-
};
|
|
6364
|
-
|
|
6365
|
-
// packages/providers/src/openai/models.ts
|
|
6366
|
-
var OPENAI_MODELS = {
|
|
6367
|
-
defaultModel: "gpt-5.6",
|
|
6368
|
-
models: [
|
|
6369
|
-
{
|
|
6370
|
-
id: "gpt-5.6",
|
|
6371
|
-
label: "GPT-5.6 \u2014 routes to Sol",
|
|
6372
|
-
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6373
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
6374
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
6375
|
-
},
|
|
6376
|
-
{
|
|
6377
|
-
id: "gpt-5.6-sol",
|
|
6378
|
-
label: "GPT-5.6 Sol \u2014 deepest reasoning",
|
|
6379
|
-
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6380
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
6381
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
6382
|
-
},
|
|
6383
|
-
{
|
|
6384
|
-
id: "gpt-5.6-terra",
|
|
6385
|
-
label: "GPT-5.6 Terra \u2014 balanced",
|
|
6386
|
-
pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6387
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
6388
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
6389
|
-
},
|
|
6390
|
-
{
|
|
6391
|
-
id: "gpt-5.6-luna",
|
|
6392
|
-
label: "GPT-5.6 Luna \u2014 fastest",
|
|
6393
|
-
pricing: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
6394
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
6395
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
6396
|
-
}
|
|
6397
|
-
]
|
|
6398
|
-
};
|
|
6399
|
-
|
|
6400
|
-
// packages/providers/src/catalog.ts
|
|
6401
|
-
var PROVIDER_MODEL_CATALOG = {
|
|
6402
|
-
anthropic: ANTHROPIC_MODELS,
|
|
6403
|
-
openai: OPENAI_MODELS,
|
|
6404
|
-
kimi: KIMI_MODELS
|
|
6405
|
-
};
|
|
6406
|
-
function catalogPricing(provider, model) {
|
|
6407
|
-
return PROVIDER_MODEL_CATALOG[provider]?.models.find((entry) => entry.id === model)?.pricing ?? null;
|
|
6408
|
-
}
|
|
6409
|
-
function catalogLimits(provider, model, auth = "apiKey") {
|
|
6410
|
-
const entry = PROVIDER_MODEL_CATALOG[provider]?.models.find((choice) => choice.id === model);
|
|
6411
|
-
if (entry === undefined)
|
|
6412
|
-
return null;
|
|
6413
|
-
return (auth === "oauth" ? entry.oauthLimits : undefined) ?? entry.limits;
|
|
6414
|
-
}
|
|
6415
6480
|
// packages/providers/src/http-client.ts
|
|
6416
6481
|
import { request as httpRequest } from "http";
|
|
6417
6482
|
import { request as httpsRequest } from "https";
|
|
@@ -6637,6 +6702,8 @@ function toChatWire(req, model) {
|
|
|
6637
6702
|
if (!degradations.includes(d))
|
|
6638
6703
|
degradations.push(d);
|
|
6639
6704
|
};
|
|
6705
|
+
if (req.betas?.includes(CONTEXT_1M_BETA))
|
|
6706
|
+
note("kimi:context-1m-dropped");
|
|
6640
6707
|
const messages = [];
|
|
6641
6708
|
const system = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
|
|
6642
6709
|
|
|
@@ -6913,6 +6980,8 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
|
|
|
6913
6980
|
if (!degradations.includes(d))
|
|
6914
6981
|
degradations.push(d);
|
|
6915
6982
|
};
|
|
6983
|
+
if (req.betas?.includes(CONTEXT_1M_BETA))
|
|
6984
|
+
note("openai:context-1m-dropped");
|
|
6916
6985
|
for (const message of req.messages) {
|
|
6917
6986
|
const parts = [];
|
|
6918
6987
|
const inlined = message.role === "system";
|
|
@@ -7607,12 +7676,10 @@ async function readSource(deps, source, lines) {
|
|
|
7607
7676
|
return "";
|
|
7608
7677
|
if (source.kind === "file")
|
|
7609
7678
|
return deps.readFile(source.path, lines) ?? "";
|
|
7610
|
-
const
|
|
7679
|
+
const unit = source.scope === "system" ? ["-u", source.unit] : [`--user-unit=${source.unit}`];
|
|
7611
7680
|
const result = await deps.run([
|
|
7612
7681
|
"journalctl",
|
|
7613
|
-
...
|
|
7614
|
-
"-u",
|
|
7615
|
-
source.unit,
|
|
7682
|
+
...unit,
|
|
7616
7683
|
"-n",
|
|
7617
7684
|
String(lines),
|
|
7618
7685
|
"--no-pager",
|
|
@@ -21919,7 +21986,9 @@ var dryRunSchema = exports_external.object({
|
|
|
21919
21986
|
reasoning: exports_external.boolean().default(false)
|
|
21920
21987
|
}).strict();
|
|
21921
21988
|
var modelSchema = exports_external.object({
|
|
21922
|
-
id: exports_external.string().min(1),
|
|
21989
|
+
id: exports_external.string().min(1).refine((value) => !value.toLowerCase().startsWith("claude/"), {
|
|
21990
|
+
message: 'model id must not start with "claude/": that prefix is reserved for discovery mirrors'
|
|
21991
|
+
}),
|
|
21923
21992
|
strategy: exports_external.enum(["score", "priority", "roundRobin", "weighted"]),
|
|
21924
21993
|
isAlias: exports_external.boolean(),
|
|
21925
21994
|
targets: exports_external.array(exports_external.object({
|
|
@@ -23373,6 +23442,60 @@ async function createKey(store, input) {
|
|
|
23373
23442
|
async function revokeKey(store, id) {
|
|
23374
23443
|
await store.keys.revoke(id);
|
|
23375
23444
|
}
|
|
23445
|
+
// packages/control/src/modelLimits.ts
|
|
23446
|
+
function narrower(a, b) {
|
|
23447
|
+
const context = [a.contextWindow, b.contextWindow].filter((n) => n !== undefined);
|
|
23448
|
+
const output = [a.maxOutputTokens, b.maxOutputTokens].filter((n) => n !== undefined);
|
|
23449
|
+
return {
|
|
23450
|
+
...context.length === 0 ? {} : { contextWindow: Math.min(...context) },
|
|
23451
|
+
...output.length === 0 ? {} : { maxOutputTokens: Math.min(...output) }
|
|
23452
|
+
};
|
|
23453
|
+
}
|
|
23454
|
+
function targetLimits(target, auths) {
|
|
23455
|
+
const ways = auths.size === 0 ? ["apiKey"] : [...auths];
|
|
23456
|
+
let listed = {};
|
|
23457
|
+
for (const auth of ways) {
|
|
23458
|
+
const entry = catalogLimits(target.provider, target.model, auth);
|
|
23459
|
+
if (entry === null)
|
|
23460
|
+
continue;
|
|
23461
|
+
listed = narrower(listed, {
|
|
23462
|
+
contextWindow: entry.contextWindow,
|
|
23463
|
+
maxOutputTokens: entry.maxOutputTokens
|
|
23464
|
+
});
|
|
23465
|
+
}
|
|
23466
|
+
const contextWindow = target.contextWindow ?? listed.contextWindow;
|
|
23467
|
+
const maxOutputTokens = target.maxOutputTokens ?? listed.maxOutputTokens;
|
|
23468
|
+
return {
|
|
23469
|
+
...contextWindow === undefined ? {} : { contextWindow },
|
|
23470
|
+
...maxOutputTokens === undefined ? {} : { maxOutputTokens }
|
|
23471
|
+
};
|
|
23472
|
+
}
|
|
23473
|
+
function servingAuths(credentials) {
|
|
23474
|
+
const byProvider = new Map;
|
|
23475
|
+
for (const credential of credentials) {
|
|
23476
|
+
if (!credential.enabled)
|
|
23477
|
+
continue;
|
|
23478
|
+
const ways = byProvider.get(credential.provider) ?? new Set;
|
|
23479
|
+
ways.add(credential.authType);
|
|
23480
|
+
byProvider.set(credential.provider, ways);
|
|
23481
|
+
}
|
|
23482
|
+
return byProvider;
|
|
23483
|
+
}
|
|
23484
|
+
function resolveModelLimits(model, credentials) {
|
|
23485
|
+
const auths = servingAuths(credentials);
|
|
23486
|
+
let limits = {};
|
|
23487
|
+
for (const target of model.targets) {
|
|
23488
|
+
limits = narrower(limits, targetLimits(target, auths.get(target.provider) ?? new Set));
|
|
23489
|
+
}
|
|
23490
|
+
return limits;
|
|
23491
|
+
}
|
|
23492
|
+
function modelDisplayName(model) {
|
|
23493
|
+
const only = model.targets.length === 1 ? model.targets[0] : undefined;
|
|
23494
|
+
if (only === undefined)
|
|
23495
|
+
return model.id;
|
|
23496
|
+
const labelled = PROVIDER_MODEL_CATALOG[only.provider]?.models.find((choice) => choice.id === only.model);
|
|
23497
|
+
return labelled?.label ?? model.id;
|
|
23498
|
+
}
|
|
23376
23499
|
// packages/control/src/models.ts
|
|
23377
23500
|
async function listModels(store) {
|
|
23378
23501
|
return store.config.listModels();
|
|
@@ -23789,6 +23912,75 @@ async function putSettings(store, input) {
|
|
|
23789
23912
|
await store.config.putSettings(settings);
|
|
23790
23913
|
return settings;
|
|
23791
23914
|
}
|
|
23915
|
+
// packages/control/src/setup.ts
|
|
23916
|
+
var KEY_PLACEHOLDER = "<your OmniGateway key>";
|
|
23917
|
+
async function describeModelsForSetup(store) {
|
|
23918
|
+
const models = await listModels(store);
|
|
23919
|
+
const credentials = (await listCredentials(store)).map((credential) => ({
|
|
23920
|
+
provider: credential.provider,
|
|
23921
|
+
authType: credential.authType,
|
|
23922
|
+
enabled: credential.enabled
|
|
23923
|
+
}));
|
|
23924
|
+
return models.map((model) => ({
|
|
23925
|
+
model,
|
|
23926
|
+
limits: resolveModelLimits(model, credentials),
|
|
23927
|
+
label: modelDisplayName(model)
|
|
23928
|
+
}));
|
|
23929
|
+
}
|
|
23930
|
+
function slug(id) {
|
|
23931
|
+
return encodeURIComponent(id).replace(/\./g, "%2E");
|
|
23932
|
+
}
|
|
23933
|
+
function claudeProfiles(described, input) {
|
|
23934
|
+
const apiKey = input.apiKey ?? KEY_PLACEHOLDER;
|
|
23935
|
+
return described.map(({ model, limits }) => {
|
|
23936
|
+
const useMirror = input.discoveryMirrors === true && !/^(?:claude|anthropic)/i.test(model.id);
|
|
23937
|
+
const modelId = useMirror ? `claude/${model.id}` : model.id;
|
|
23938
|
+
const env2 = {
|
|
23939
|
+
ANTHROPIC_BASE_URL: input.baseUrl,
|
|
23940
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
23941
|
+
ANTHROPIC_MODEL: modelId,
|
|
23942
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: "1"
|
|
23943
|
+
};
|
|
23944
|
+
if (limits.contextWindow !== undefined && !/^claude-/i.test(modelId)) {
|
|
23945
|
+
env2.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(limits.contextWindow);
|
|
23946
|
+
}
|
|
23947
|
+
return {
|
|
23948
|
+
path: `${slug(model.id)}/settings.json`,
|
|
23949
|
+
contents: `${JSON.stringify({ env: env2 }, null, 2)}
|
|
23950
|
+
`
|
|
23951
|
+
};
|
|
23952
|
+
});
|
|
23953
|
+
}
|
|
23954
|
+
function opencodeConfig(described, input) {
|
|
23955
|
+
const models = {};
|
|
23956
|
+
for (const { model, limits, label: label2 } of described) {
|
|
23957
|
+
const limit = limits.contextWindow === undefined ? undefined : {
|
|
23958
|
+
context: limits.contextWindow,
|
|
23959
|
+
...limits.maxOutputTokens === undefined ? {} : { output: limits.maxOutputTokens }
|
|
23960
|
+
};
|
|
23961
|
+
models[model.id] = { name: label2, ...limit === undefined ? {} : { limit } };
|
|
23962
|
+
}
|
|
23963
|
+
const contents = `${JSON.stringify({
|
|
23964
|
+
$schema: "https://opencode.ai/config.json",
|
|
23965
|
+
provider: {
|
|
23966
|
+
omnigateway: {
|
|
23967
|
+
npm: "@ai-sdk/openai-compatible",
|
|
23968
|
+
name: "OmniGateway",
|
|
23969
|
+
options: {
|
|
23970
|
+
baseURL: `${input.baseUrl.replace(/\/+$/, "").replace(/(?:\/v1)+$/i, "")}/v1`,
|
|
23971
|
+
apiKey: input.apiKey ?? KEY_PLACEHOLDER
|
|
23972
|
+
},
|
|
23973
|
+
models
|
|
23974
|
+
}
|
|
23975
|
+
}
|
|
23976
|
+
}, null, 2)}
|
|
23977
|
+
`;
|
|
23978
|
+
return { path: "opencode.json", contents };
|
|
23979
|
+
}
|
|
23980
|
+
async function setupFiles(store, client, input) {
|
|
23981
|
+
const described = await describeModelsForSetup(store);
|
|
23982
|
+
return client === "claude" ? claudeProfiles(described, input) : [opencodeConfig(described, input)];
|
|
23983
|
+
}
|
|
23792
23984
|
// packages/control/src/tail.ts
|
|
23793
23985
|
import { closeSync, fstatSync, openSync, readSync, statSync } from "fs";
|
|
23794
23986
|
var CHUNK = 64 * 1024;
|
|
@@ -38503,6 +38695,16 @@ function adminRoutes(deps) {
|
|
|
38503
38695
|
await requireAdmin(request2, deps.admin);
|
|
38504
38696
|
await removeModel(deps.store, params.id);
|
|
38505
38697
|
return { ok: true };
|
|
38698
|
+
}).get("/api/agent-setup", async ({ request: request2, query }) => {
|
|
38699
|
+
await requireAdmin(request2, deps.admin);
|
|
38700
|
+
const client = query.client === "opencode" ? "opencode" : "claude";
|
|
38701
|
+
return {
|
|
38702
|
+
client,
|
|
38703
|
+
files: await setupFiles(deps.store, client, {
|
|
38704
|
+
baseUrl: deps.baseUrl,
|
|
38705
|
+
discoveryMirrors: deps.discoveryMirrors === true
|
|
38706
|
+
})
|
|
38707
|
+
};
|
|
38506
38708
|
}).get("/api/keys", async ({ request: request2 }) => {
|
|
38507
38709
|
await requireAdmin(request2, deps.admin);
|
|
38508
38710
|
return { keys: await listKeys(deps.store) };
|
|
@@ -39361,6 +39563,30 @@ function openaiErrorBody(code, message) {
|
|
|
39361
39563
|
return { error: { message, type: e.type, code: e.code } };
|
|
39362
39564
|
}
|
|
39363
39565
|
|
|
39566
|
+
// apps/gateway/src/ingress/model.ts
|
|
39567
|
+
var DISCOVERY_PREFIX = "claude/";
|
|
39568
|
+
var ONE_M_SUFFIX = "[1m]";
|
|
39569
|
+
function normalizeClientModel(raw, betas2 = []) {
|
|
39570
|
+
let model = raw.trim();
|
|
39571
|
+
let wantsOneM = false;
|
|
39572
|
+
if (model.toLowerCase().endsWith(ONE_M_SUFFIX)) {
|
|
39573
|
+
const stripped = model.slice(0, -ONE_M_SUFFIX.length).trim();
|
|
39574
|
+
if (stripped.length > 0) {
|
|
39575
|
+
model = stripped;
|
|
39576
|
+
wantsOneM = true;
|
|
39577
|
+
}
|
|
39578
|
+
}
|
|
39579
|
+
if (model.toLowerCase().startsWith(DISCOVERY_PREFIX)) {
|
|
39580
|
+
const stripped = model.slice(DISCOVERY_PREFIX.length);
|
|
39581
|
+
if (stripped.length > 0)
|
|
39582
|
+
model = stripped;
|
|
39583
|
+
}
|
|
39584
|
+
const merged = [...betas2];
|
|
39585
|
+
if (wantsOneM && !merged.includes(CONTEXT_1M_BETA))
|
|
39586
|
+
merged.push(CONTEXT_1M_BETA);
|
|
39587
|
+
return { model, betas: merged };
|
|
39588
|
+
}
|
|
39589
|
+
|
|
39364
39590
|
// apps/gateway/src/ingress/anthropic.ts
|
|
39365
39591
|
var textBlock = exports_external.object({
|
|
39366
39592
|
type: exports_external.literal("text"),
|
|
@@ -39542,8 +39768,9 @@ function parseAnthropicRequest(body2, headers) {
|
|
|
39542
39768
|
text: b.text,
|
|
39543
39769
|
...irCacheControl(b.cache_control)
|
|
39544
39770
|
}));
|
|
39771
|
+
const named = normalizeClientModel(parsed.model, readBetas(headers));
|
|
39545
39772
|
const request2 = {
|
|
39546
|
-
model:
|
|
39773
|
+
model: named.model,
|
|
39547
39774
|
messages,
|
|
39548
39775
|
stream: parsed.stream ?? false
|
|
39549
39776
|
};
|
|
@@ -39574,9 +39801,8 @@ function parseAnthropicRequest(body2, headers) {
|
|
|
39574
39801
|
const extras = extraFields(body2, KNOWN);
|
|
39575
39802
|
if (extras !== undefined)
|
|
39576
39803
|
request2.vendor = { anthropic: extras };
|
|
39577
|
-
|
|
39578
|
-
|
|
39579
|
-
request2.betas = betas;
|
|
39804
|
+
if (named.betas.length > 0)
|
|
39805
|
+
request2.betas = named.betas;
|
|
39580
39806
|
return validateRequest(request2);
|
|
39581
39807
|
}
|
|
39582
39808
|
|
|
@@ -39725,7 +39951,7 @@ function parseOpenAIRequest(body2) {
|
|
|
39725
39951
|
throw new GatewayError("BAD_REQUEST", "messages: at least one non-system message is required");
|
|
39726
39952
|
}
|
|
39727
39953
|
const request2 = {
|
|
39728
|
-
model: parsed.model,
|
|
39954
|
+
model: normalizeClientModel(parsed.model).model,
|
|
39729
39955
|
messages,
|
|
39730
39956
|
stream: parsed.stream ?? false
|
|
39731
39957
|
};
|
|
@@ -39759,65 +39985,13 @@ function parseOpenAIRequest(body2) {
|
|
|
39759
39985
|
|
|
39760
39986
|
// apps/gateway/src/routes/models.ts
|
|
39761
39987
|
var CREATED_AT = new Date(0).toISOString();
|
|
39762
|
-
function narrower(a, b) {
|
|
39763
|
-
const context = [a.contextWindow, b.contextWindow].filter((n) => n !== undefined);
|
|
39764
|
-
const output = [a.maxOutputTokens, b.maxOutputTokens].filter((n) => n !== undefined);
|
|
39765
|
-
return {
|
|
39766
|
-
...context.length === 0 ? {} : { contextWindow: Math.min(...context) },
|
|
39767
|
-
...output.length === 0 ? {} : { maxOutputTokens: Math.min(...output) }
|
|
39768
|
-
};
|
|
39769
|
-
}
|
|
39770
|
-
function targetLimits(target, auths) {
|
|
39771
|
-
const ways = auths.size === 0 ? ["apiKey"] : [...auths];
|
|
39772
|
-
let listed = {};
|
|
39773
|
-
for (const auth of ways) {
|
|
39774
|
-
const entry = catalogLimits(target.provider, target.model, auth);
|
|
39775
|
-
if (entry === null)
|
|
39776
|
-
continue;
|
|
39777
|
-
listed = narrower(listed, {
|
|
39778
|
-
contextWindow: entry.contextWindow,
|
|
39779
|
-
maxOutputTokens: entry.maxOutputTokens
|
|
39780
|
-
});
|
|
39781
|
-
}
|
|
39782
|
-
const contextWindow = target.contextWindow ?? listed.contextWindow;
|
|
39783
|
-
const maxOutputTokens = target.maxOutputTokens ?? listed.maxOutputTokens;
|
|
39784
|
-
return {
|
|
39785
|
-
...contextWindow === undefined ? {} : { contextWindow },
|
|
39786
|
-
...maxOutputTokens === undefined ? {} : { maxOutputTokens }
|
|
39787
|
-
};
|
|
39788
|
-
}
|
|
39789
|
-
function limitsOf(model, authsByProvider) {
|
|
39790
|
-
let limits = {};
|
|
39791
|
-
for (const target of model.targets) {
|
|
39792
|
-
limits = narrower(limits, targetLimits(target, authsByProvider.get(target.provider) ?? new Set));
|
|
39793
|
-
}
|
|
39794
|
-
return limits;
|
|
39795
|
-
}
|
|
39796
|
-
function displayName(model) {
|
|
39797
|
-
const only = model.targets.length === 1 ? model.targets[0] : undefined;
|
|
39798
|
-
if (only === undefined)
|
|
39799
|
-
return model.id;
|
|
39800
|
-
const labelled = PROVIDER_MODEL_CATALOG[only.provider]?.models.find((choice) => choice.id === only.model);
|
|
39801
|
-
return labelled?.label ?? model.id;
|
|
39802
|
-
}
|
|
39803
|
-
function servingAuths(credentials) {
|
|
39804
|
-
const byProvider = new Map;
|
|
39805
|
-
for (const credential of credentials) {
|
|
39806
|
-
if (!credential.enabled)
|
|
39807
|
-
continue;
|
|
39808
|
-
const ways = byProvider.get(credential.provider) ?? new Set;
|
|
39809
|
-
ways.add(credential.authType);
|
|
39810
|
-
byProvider.set(credential.provider, ways);
|
|
39811
|
-
}
|
|
39812
|
-
return byProvider;
|
|
39813
|
-
}
|
|
39814
39988
|
function describeModel(model, credentials) {
|
|
39815
|
-
const limits =
|
|
39989
|
+
const limits = resolveModelLimits(model, credentials);
|
|
39816
39990
|
return {
|
|
39817
39991
|
id: model.id,
|
|
39818
39992
|
object: "model",
|
|
39819
39993
|
type: "model",
|
|
39820
|
-
display_name:
|
|
39994
|
+
display_name: modelDisplayName(model),
|
|
39821
39995
|
created: 0,
|
|
39822
39996
|
created_at: CREATED_AT,
|
|
39823
39997
|
owned_by: "omnigateway",
|
|
@@ -39825,8 +39999,29 @@ function describeModel(model, credentials) {
|
|
|
39825
39999
|
...limits.maxOutputTokens === undefined ? {} : { max_tokens: limits.maxOutputTokens }
|
|
39826
40000
|
};
|
|
39827
40001
|
}
|
|
39828
|
-
|
|
39829
|
-
|
|
40002
|
+
var ALREADY_CLAUDE = /^(?:claude|anthropic)/i;
|
|
40003
|
+
var MIRROR_PREFIX = "claude/";
|
|
40004
|
+
function discoveryMirrors(data) {
|
|
40005
|
+
const taken = new Set(data.map((entry) => entry.id));
|
|
40006
|
+
const mirrors = [];
|
|
40007
|
+
for (const entry of data) {
|
|
40008
|
+
if (ALREADY_CLAUDE.test(entry.id))
|
|
40009
|
+
continue;
|
|
40010
|
+
const id = `${MIRROR_PREFIX}${entry.id}`;
|
|
40011
|
+
if (taken.has(id))
|
|
40012
|
+
continue;
|
|
40013
|
+
mirrors.push({
|
|
40014
|
+
...entry,
|
|
40015
|
+
id,
|
|
40016
|
+
root: entry.id,
|
|
40017
|
+
display_name: `${entry.display_name} (OmniGateway)`
|
|
40018
|
+
});
|
|
40019
|
+
}
|
|
40020
|
+
return mirrors;
|
|
40021
|
+
}
|
|
40022
|
+
function modelListBody(models, credentials, options = {}) {
|
|
40023
|
+
const described = models.map((model) => describeModel(model, credentials));
|
|
40024
|
+
const data = options.discoveryMirrors === true ? [...described, ...discoveryMirrors(described)] : described;
|
|
39830
40025
|
return {
|
|
39831
40026
|
object: "list",
|
|
39832
40027
|
data,
|
|
@@ -40028,7 +40223,9 @@ function proxyRoutes(deps) {
|
|
|
40028
40223
|
const snapshot = await dispatchDeps.snapshots.get(deps.now());
|
|
40029
40224
|
const models = [...snapshot.models.values()];
|
|
40030
40225
|
const visibleModels = key.modelAllowlist === null ? models : models.filter((model) => key.modelAllowlist?.includes(model.id));
|
|
40031
|
-
return Response.json(modelListBody(visibleModels, snapshot.credentials
|
|
40226
|
+
return Response.json(modelListBody(visibleModels, snapshot.credentials, {
|
|
40227
|
+
discoveryMirrors: deps.discoveryMirrors === true
|
|
40228
|
+
}));
|
|
40032
40229
|
} catch (error51) {
|
|
40033
40230
|
const gatewayError = asGatewayError(error51);
|
|
40034
40231
|
logger2.error("model listing failed", {
|
|
@@ -40038,6 +40235,25 @@ function proxyRoutes(deps) {
|
|
|
40038
40235
|
});
|
|
40039
40236
|
return errorResponse("anthropic", gatewayError.code, gatewayError.message);
|
|
40040
40237
|
}
|
|
40238
|
+
}).post("/v1/messages/count_tokens", async ({ request: request2 }) => {
|
|
40239
|
+
try {
|
|
40240
|
+
const key = await authenticateApiKey(deps.store, apiKeyHeader(request2.headers));
|
|
40241
|
+
rateLimiter.consume(key.id, key.rateLimitPerMin);
|
|
40242
|
+
const body2 = await request2.json();
|
|
40243
|
+
const chatRequest = parseAnthropicRequest(body2, request2.headers);
|
|
40244
|
+
if (key.modelAllowlist !== null && !key.modelAllowlist.includes(chatRequest.model)) {
|
|
40245
|
+
throw new GatewayError("AUTH", `model "${chatRequest.model}" is not allowed for this API key`);
|
|
40246
|
+
}
|
|
40247
|
+
return Response.json({ input_tokens: estimateInputTokens(chatRequest) });
|
|
40248
|
+
} catch (error51) {
|
|
40249
|
+
const gatewayError = asGatewayError(error51);
|
|
40250
|
+
logger2.warn("token count failed", {
|
|
40251
|
+
status: HTTP_STATUS[gatewayError.code],
|
|
40252
|
+
code: gatewayError.code,
|
|
40253
|
+
reason: gatewayError.message
|
|
40254
|
+
});
|
|
40255
|
+
return errorResponse("anthropic", gatewayError.code, gatewayError.message);
|
|
40256
|
+
}
|
|
40041
40257
|
}).onError(({ error: error51 }) => {
|
|
40042
40258
|
const gatewayError = asGatewayError(error51);
|
|
40043
40259
|
logger2.error("unhandled proxy route error", {
|
|
@@ -40085,10 +40301,13 @@ function createApp(deps) {
|
|
|
40085
40301
|
refresh,
|
|
40086
40302
|
requestId,
|
|
40087
40303
|
rateLimiter,
|
|
40088
|
-
logger: logger2
|
|
40304
|
+
logger: logger2,
|
|
40305
|
+
discoveryMirrors: deps.discoveryMirrors === true
|
|
40089
40306
|
})).use(adminRoutes({
|
|
40090
40307
|
store: deps.store,
|
|
40091
40308
|
admin,
|
|
40309
|
+
baseUrl: deps.baseUrl,
|
|
40310
|
+
discoveryMirrors: deps.discoveryMirrors === true,
|
|
40092
40311
|
now,
|
|
40093
40312
|
sessionTtlMs: ADMIN_SESSION_TTL_MS,
|
|
40094
40313
|
logger: logger2,
|
|
@@ -40331,7 +40550,8 @@ async function main() {
|
|
|
40331
40550
|
refresh,
|
|
40332
40551
|
staticDir,
|
|
40333
40552
|
logger: logger2,
|
|
40334
|
-
console: console2
|
|
40553
|
+
console: console2,
|
|
40554
|
+
discoveryMirrors: config2.exposeClaudeCodeAliases
|
|
40335
40555
|
});
|
|
40336
40556
|
const stopMaintenance = startMaintenance({ store, now, logger: logger2 });
|
|
40337
40557
|
const stopRefreshScheduler = startRefreshScheduler({ store, refresh, now, logger: logger2 });
|