omnigateway 0.1.4 → 0.1.6
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 +35 -1
- package/bin/omni.js +263 -105
- package/gateway.js +983 -423
- package/package.json +1 -1
- package/public/assets/{CopyValue-BhGx7Gy0.js → CopyValue-cAwgC1sU.js} +1 -1
- package/public/assets/{Modal-DOQGdhoM.js → Modal-Dqir9wBz.js} +1 -1
- package/public/assets/{Rack-DnbGnBvz.js → Rack-XtfiZ6GC.js} +1 -1
- package/public/assets/{Toggle-CP3RvAAB.js → Toggle-BhViDMm9.js} +1 -1
- package/public/assets/{_app-D83powx4.js → _app-B8lqq_ks.js} +1 -1
- package/public/assets/{_app.accounts-DR-2t9-7.js → _app.accounts-DSMHSYBF.js} +1 -1
- package/public/assets/{_app.index-DimCB0Bo.js → _app.index-DXH5sH41.js} +1 -1
- package/public/assets/{_app.keys-B7kl3CSe.js → _app.keys-DdEyVy_b.js} +1 -1
- package/public/assets/_app.logs-Camxditb.js +33 -0
- package/public/assets/_app.models-CuD-JtGS.js +144 -0
- package/public/assets/{_app.settings-DtDIhAAr.js → _app.settings-DA1aYcR4.js} +1 -1
- package/public/assets/{_app.usage-BChnSBbS.js → _app.usage-DAyYUfIi.js} +1 -1
- package/public/assets/catalog-C_OQ0icG.js +1 -0
- package/public/assets/{index-C53PiRfb.js → index-BtjyVE1i.js} +2 -2
- package/public/assets/{login-BuvJY1Qd.js → login-DXHM-Noj.js} +1 -1
- package/public/assets/{trash-2-Cq7ldH9D.js → trash-2-JF_uX2gE.js} +1 -1
- package/public/index.html +2 -2
- package/public/assets/_app.logs-BjtdzcDY.js +0 -18
- package/public/assets/_app.models-BEECjcLM.js +0 -144
- package/public/assets/catalog-DVRPlBJJ.js +0 -1
package/bin/omni.js
CHANGED
|
@@ -147,35 +147,6 @@ function createAdminAuth(store, opts) {
|
|
|
147
147
|
}
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
-
// packages/control/src/config.ts
|
|
151
|
-
var MIN_KEY_LENGTH = 16;
|
|
152
|
-
var DECIMAL_INTEGER = /^\d+$/;
|
|
153
|
-
function optionalText(value, fallback) {
|
|
154
|
-
return value?.trim() || fallback;
|
|
155
|
-
}
|
|
156
|
-
function loadConfig(env) {
|
|
157
|
-
const encryptionKey = env.OMNI_ENCRYPTION_KEY;
|
|
158
|
-
if (typeof encryptionKey !== "string" || encryptionKey.length < MIN_KEY_LENGTH) {
|
|
159
|
-
throw new Error(`OMNI_ENCRYPTION_KEY must be set to at least ${MIN_KEY_LENGTH} characters. ` + "Generate one with: openssl rand -base64 32");
|
|
160
|
-
}
|
|
161
|
-
const host = optionalText(env.OMNI_HOST, "127.0.0.1");
|
|
162
|
-
const rawPort = env.OMNI_PORT ?? "9000";
|
|
163
|
-
const port = Number(rawPort);
|
|
164
|
-
if (!DECIMAL_INTEGER.test(rawPort) || !Number.isInteger(port) || port < 1 || port > 65535) {
|
|
165
|
-
throw new Error(`OMNI_PORT must be an integer between 1 and 65535, got "${rawPort}"`);
|
|
166
|
-
}
|
|
167
|
-
const derivedBaseUrl = `http://${host}:${port}`;
|
|
168
|
-
const baseUrl = optionalText(env.OMNI_BASE_URL, derivedBaseUrl).replace(/\/+$/, "") || derivedBaseUrl;
|
|
169
|
-
const staticDir = env.OMNI_STATIC_DIR?.trim();
|
|
170
|
-
return {
|
|
171
|
-
port,
|
|
172
|
-
host,
|
|
173
|
-
databasePath: optionalText(env.OMNI_DB_PATH, "./omnigateway.db"),
|
|
174
|
-
encryptionKey,
|
|
175
|
-
baseUrl,
|
|
176
|
-
staticDir: staticDir === undefined || staticDir.length === 0 ? null : staticDir
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
150
|
// packages/ir/src/capabilities.ts
|
|
180
151
|
var PROVIDER_CAPABILITIES = {
|
|
181
152
|
anthropic: { tools: true, images: true, reasoning: true },
|
|
@@ -215,6 +186,67 @@ class GatewayError extends Error {
|
|
|
215
186
|
this.retryAfterMs = opts?.retryAfterMs;
|
|
216
187
|
}
|
|
217
188
|
}
|
|
189
|
+
// packages/ir/src/logger.ts
|
|
190
|
+
var LEVELS = { debug: 10, info: 20, warn: 30, error: 40 };
|
|
191
|
+
var noopLogger = {
|
|
192
|
+
debug: () => {},
|
|
193
|
+
info: () => {},
|
|
194
|
+
warn: () => {},
|
|
195
|
+
error: () => {},
|
|
196
|
+
enabled: () => false
|
|
197
|
+
};
|
|
198
|
+
function parseLogLevel(value) {
|
|
199
|
+
const normalized = value?.trim().toLowerCase();
|
|
200
|
+
if (normalized === undefined || normalized.length === 0)
|
|
201
|
+
return null;
|
|
202
|
+
return Object.hasOwn(LEVELS, normalized) ? normalized : null;
|
|
203
|
+
}
|
|
204
|
+
// packages/ir/src/request.ts
|
|
205
|
+
function cacheControlOf(block) {
|
|
206
|
+
return block.type === "thinking" ? undefined : block.cacheControl;
|
|
207
|
+
}
|
|
208
|
+
// packages/ir/src/stream.ts
|
|
209
|
+
function usageFromPromptTotal(promptTokens, outputTokens, cacheReadTokens, cacheWriteTokens = 0) {
|
|
210
|
+
return {
|
|
211
|
+
inputTokens: Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens),
|
|
212
|
+
outputTokens,
|
|
213
|
+
cacheReadTokens,
|
|
214
|
+
cacheWriteTokens
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// packages/control/src/config.ts
|
|
218
|
+
var MIN_KEY_LENGTH = 16;
|
|
219
|
+
var DECIMAL_INTEGER = /^\d+$/;
|
|
220
|
+
function optionalText(value, fallback) {
|
|
221
|
+
return value?.trim() || fallback;
|
|
222
|
+
}
|
|
223
|
+
function loadConfig(env) {
|
|
224
|
+
const encryptionKey = env.OMNI_ENCRYPTION_KEY;
|
|
225
|
+
if (typeof encryptionKey !== "string" || encryptionKey.length < MIN_KEY_LENGTH) {
|
|
226
|
+
throw new Error(`OMNI_ENCRYPTION_KEY must be set to at least ${MIN_KEY_LENGTH} characters. ` + "Generate one with: openssl rand -base64 32");
|
|
227
|
+
}
|
|
228
|
+
const host = optionalText(env.OMNI_HOST, "127.0.0.1");
|
|
229
|
+
const rawPort = env.OMNI_PORT ?? "9000";
|
|
230
|
+
const port = Number(rawPort);
|
|
231
|
+
if (!DECIMAL_INTEGER.test(rawPort) || !Number.isInteger(port) || port < 1 || port > 65535) {
|
|
232
|
+
throw new Error(`OMNI_PORT must be an integer between 1 and 65535, got "${rawPort}"`);
|
|
233
|
+
}
|
|
234
|
+
const derivedBaseUrl = `http://${host}:${port}`;
|
|
235
|
+
const baseUrl = optionalText(env.OMNI_BASE_URL, derivedBaseUrl).replace(/\/+$/, "") || derivedBaseUrl;
|
|
236
|
+
const staticDir = env.OMNI_STATIC_DIR?.trim();
|
|
237
|
+
const rawLogLevel = env.OMNI_LOG_LEVEL?.trim();
|
|
238
|
+
const logLevel = parseLogLevel(rawLogLevel);
|
|
239
|
+
return {
|
|
240
|
+
logLevel: logLevel ?? "info",
|
|
241
|
+
logLevelFallbackFrom: logLevel === null && rawLogLevel ? rawLogLevel : null,
|
|
242
|
+
port,
|
|
243
|
+
host,
|
|
244
|
+
databasePath: optionalText(env.OMNI_DB_PATH, "./omnigateway.db"),
|
|
245
|
+
encryptionKey,
|
|
246
|
+
baseUrl,
|
|
247
|
+
staticDir: staticDir === undefined || staticDir.length === 0 ? null : staticDir
|
|
248
|
+
};
|
|
249
|
+
}
|
|
218
250
|
// packages/providers/src/body.ts
|
|
219
251
|
var BODY_ORDER = {
|
|
220
252
|
anthropic: [
|
|
@@ -301,8 +333,13 @@ function applyAnthropicSystem(system) {
|
|
|
301
333
|
let rewritten = text;
|
|
302
334
|
for (const [from, to] of REWRITES)
|
|
303
335
|
rewritten = rewritten.replaceAll(from, to);
|
|
304
|
-
if (rewritten.trim().length > 0)
|
|
305
|
-
kept.push({
|
|
336
|
+
if (rewritten.trim().length > 0) {
|
|
337
|
+
kept.push({
|
|
338
|
+
type: "text",
|
|
339
|
+
text: rewritten,
|
|
340
|
+
...block.cache_control === undefined ? {} : { cache_control: block.cache_control }
|
|
341
|
+
});
|
|
342
|
+
}
|
|
306
343
|
}
|
|
307
344
|
return [{ type: "text", text: billingBlock() }, { type: "text", text: AGENT_PREAMBLE }, ...kept];
|
|
308
345
|
}
|
|
@@ -606,6 +643,8 @@ async function* decodeAnthropic(messages) {
|
|
|
606
643
|
let inputTokens = 0;
|
|
607
644
|
let cacheReadTokens = 0;
|
|
608
645
|
let cacheWriteTokens = 0;
|
|
646
|
+
let cacheWrite5mTokens;
|
|
647
|
+
let cacheWrite1hTokens;
|
|
609
648
|
let outputTokens = 0;
|
|
610
649
|
let stopReason = "endTurn";
|
|
611
650
|
let terminal = false;
|
|
@@ -619,6 +658,8 @@ async function* decodeAnthropic(messages) {
|
|
|
619
658
|
inputTokens = m.usage?.input_tokens ?? 0;
|
|
620
659
|
cacheReadTokens = m.usage?.cache_read_input_tokens ?? 0;
|
|
621
660
|
cacheWriteTokens = m.usage?.cache_creation_input_tokens ?? 0;
|
|
661
|
+
cacheWrite5mTokens = m.usage?.cache_creation?.ephemeral_5m_input_tokens;
|
|
662
|
+
cacheWrite1hTokens = m.usage?.cache_creation?.ephemeral_1h_input_tokens;
|
|
622
663
|
yield { type: "start", id: String(m.id ?? ""), model: String(m.model ?? "") };
|
|
623
664
|
break;
|
|
624
665
|
}
|
|
@@ -678,7 +719,14 @@ async function* decodeAnthropic(messages) {
|
|
|
678
719
|
yield {
|
|
679
720
|
type: "end",
|
|
680
721
|
stopReason,
|
|
681
|
-
usage: {
|
|
722
|
+
usage: {
|
|
723
|
+
inputTokens,
|
|
724
|
+
outputTokens,
|
|
725
|
+
cacheReadTokens,
|
|
726
|
+
cacheWriteTokens,
|
|
727
|
+
...cacheWrite5mTokens === undefined ? {} : { cacheWrite5mTokens },
|
|
728
|
+
...cacheWrite1hTokens === undefined ? {} : { cacheWrite1hTokens }
|
|
729
|
+
}
|
|
682
730
|
};
|
|
683
731
|
break;
|
|
684
732
|
case "error": {
|
|
@@ -708,25 +756,33 @@ async function* decodeAnthropic(messages) {
|
|
|
708
756
|
|
|
709
757
|
// packages/providers/src/anthropic/wire.ts
|
|
710
758
|
var OAUTH_IDENTITY = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
759
|
+
function wireCacheControl(c) {
|
|
760
|
+
if (c === undefined)
|
|
761
|
+
return {};
|
|
762
|
+
return { cache_control: { type: c.type, ...c.ttl === undefined ? {} : { ttl: c.ttl } } };
|
|
763
|
+
}
|
|
711
764
|
function encodeBlock(b) {
|
|
765
|
+
const cache = wireCacheControl(cacheControlOf(b));
|
|
712
766
|
switch (b.type) {
|
|
713
767
|
case "text":
|
|
714
|
-
return { type: "text", text: b.text };
|
|
768
|
+
return { type: "text", text: b.text, ...cache };
|
|
715
769
|
case "image":
|
|
716
770
|
return {
|
|
717
771
|
type: "image",
|
|
718
|
-
source: { type: "base64", media_type: b.mediaType, data: b.data }
|
|
772
|
+
source: { type: "base64", media_type: b.mediaType, data: b.data },
|
|
773
|
+
...cache
|
|
719
774
|
};
|
|
720
775
|
case "thinking":
|
|
721
776
|
return { type: "thinking", thinking: b.text, signature: b.signature };
|
|
722
777
|
case "toolUse":
|
|
723
|
-
return { type: "tool_use", id: b.id, name: b.name, input: b.input };
|
|
778
|
+
return { type: "tool_use", id: b.id, name: b.name, input: b.input, ...cache };
|
|
724
779
|
case "toolResult":
|
|
725
780
|
return {
|
|
726
781
|
type: "tool_result",
|
|
727
782
|
tool_use_id: b.toolUseId,
|
|
728
783
|
content: b.content,
|
|
729
|
-
is_error: b.isError
|
|
784
|
+
is_error: b.isError,
|
|
785
|
+
...cache
|
|
730
786
|
};
|
|
731
787
|
}
|
|
732
788
|
}
|
|
@@ -748,14 +804,25 @@ function encodeToolChoice(c) {
|
|
|
748
804
|
}
|
|
749
805
|
function toWire(req, model, opts) {
|
|
750
806
|
const degradations = [];
|
|
751
|
-
|
|
807
|
+
const note2 = (d) => {
|
|
808
|
+
if (!degradations.includes(d))
|
|
809
|
+
degradations.push(d);
|
|
810
|
+
};
|
|
811
|
+
let system = req.system?.flatMap((b) => b.type === "text" ? [{ type: "text", text: b.text, ...wireCacheControl(b.cacheControl) }] : []);
|
|
752
812
|
if (opts.oauth && system?.[0]?.text !== OAUTH_IDENTITY) {
|
|
753
813
|
system = [{ type: "text", text: OAUTH_IDENTITY }, ...system ?? []];
|
|
754
|
-
|
|
814
|
+
note2("anthropic:oauth-system-prefix");
|
|
755
815
|
}
|
|
756
816
|
const body = {
|
|
757
817
|
model,
|
|
758
|
-
messages: req.messages.map((m) =>
|
|
818
|
+
messages: req.messages.map((m) => {
|
|
819
|
+
if (m.role !== "system")
|
|
820
|
+
return { role: m.role, content: m.content.map(encodeBlock) };
|
|
821
|
+
if (m.content.some((b) => cacheControlOf(b) !== undefined)) {
|
|
822
|
+
note2("anthropic:system-turn-cache-control-dropped");
|
|
823
|
+
}
|
|
824
|
+
return { role: m.role, content: encodeSystemTurn(m.content) };
|
|
825
|
+
}),
|
|
759
826
|
max_tokens: req.maxTokens ?? 4096,
|
|
760
827
|
stream: req.stream
|
|
761
828
|
};
|
|
@@ -769,7 +836,8 @@ function toWire(req, model, opts) {
|
|
|
769
836
|
body.tools = req.tools.map((t) => ({
|
|
770
837
|
name: t.name,
|
|
771
838
|
...t.description === undefined ? {} : { description: t.description },
|
|
772
|
-
input_schema: t.inputSchema
|
|
839
|
+
input_schema: t.inputSchema,
|
|
840
|
+
...wireCacheControl(t.cacheControl)
|
|
773
841
|
}));
|
|
774
842
|
}
|
|
775
843
|
if (req.toolChoice !== undefined)
|
|
@@ -809,12 +877,13 @@ var anthropicAdapter = {
|
|
|
809
877
|
const { body, degradations } = toWire(req.request, req.model, { oauth });
|
|
810
878
|
const withSystem = {
|
|
811
879
|
...body,
|
|
812
|
-
system: applyAnthropicSystem(body.system ?? [])
|
|
880
|
+
system: applyAnthropicSystem(body.system ?? []),
|
|
881
|
+
stream: true
|
|
813
882
|
};
|
|
814
883
|
const protocol = [
|
|
815
884
|
["Content-Type", "application/json"],
|
|
816
885
|
["anthropic-version", API_VERSION],
|
|
817
|
-
["Accept",
|
|
886
|
+
["Accept", "text/event-stream"]
|
|
818
887
|
];
|
|
819
888
|
const betas = new Set(req.request.betas ?? []);
|
|
820
889
|
if (oauth) {
|
|
@@ -833,6 +902,7 @@ var anthropicAdapter = {
|
|
|
833
902
|
const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
|
|
834
903
|
const bodyString = signAnthropicBody(JSON.stringify(orderFields(withSystem, BODY_ORDER.anthropic)));
|
|
835
904
|
const res = await req.http({
|
|
905
|
+
provider: "anthropic",
|
|
836
906
|
url: BASE_URL,
|
|
837
907
|
method: "POST",
|
|
838
908
|
headers,
|
|
@@ -853,22 +923,26 @@ var ANTHROPIC_MODELS = {
|
|
|
853
923
|
{
|
|
854
924
|
id: "claude-fable-5",
|
|
855
925
|
label: "Claude Fable 5",
|
|
856
|
-
pricing: { input: 10, output: 50, cacheRead: 1 }
|
|
926
|
+
pricing: { input: 10, output: 50, cacheRead: 1, cacheWrite5m: 12.5, cacheWrite1h: 20 },
|
|
927
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
857
928
|
},
|
|
858
929
|
{
|
|
859
930
|
id: "claude-opus-5",
|
|
860
931
|
label: "Claude Opus 5",
|
|
861
|
-
pricing: { input: 5, output: 25, cacheRead: 0.5 }
|
|
932
|
+
pricing: { input: 5, output: 25, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 10 },
|
|
933
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
862
934
|
},
|
|
863
935
|
{
|
|
864
936
|
id: "claude-sonnet-5",
|
|
865
937
|
label: "Claude Sonnet 5",
|
|
866
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3 }
|
|
938
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 3.75, cacheWrite1h: 6 },
|
|
939
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
867
940
|
},
|
|
868
941
|
{
|
|
869
942
|
id: "claude-haiku-4-5",
|
|
870
943
|
label: "Claude Haiku 4.5",
|
|
871
|
-
pricing: { input: 1, output: 5, cacheRead: 0.1 }
|
|
944
|
+
pricing: { input: 1, output: 5, cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 2 },
|
|
945
|
+
limits: { contextWindow: 200000, maxOutputTokens: 64000 }
|
|
872
946
|
}
|
|
873
947
|
]
|
|
874
948
|
};
|
|
@@ -880,22 +954,26 @@ var KIMI_MODELS = {
|
|
|
880
954
|
{
|
|
881
955
|
id: "k3-256k",
|
|
882
956
|
label: "Kimi K3 \u2014 256K",
|
|
883
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3 }
|
|
957
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
958
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
884
959
|
},
|
|
885
960
|
{
|
|
886
961
|
id: "k3",
|
|
887
962
|
label: "Kimi K3 \u2014 up to 1M",
|
|
888
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3 }
|
|
963
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
964
|
+
limits: { contextWindow: 1048576, maxOutputTokens: 131072 }
|
|
889
965
|
},
|
|
890
966
|
{
|
|
891
967
|
id: "kimi-for-coding",
|
|
892
968
|
label: "Kimi K2.7 Code",
|
|
893
|
-
pricing: { input: 0.95, output: 4, cacheRead: 0.19 }
|
|
969
|
+
pricing: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
970
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
894
971
|
},
|
|
895
972
|
{
|
|
896
973
|
id: "kimi-for-coding-highspeed",
|
|
897
974
|
label: "Kimi K2.7 Code \u2014 High Speed",
|
|
898
|
-
pricing: { input: 0.95, output: 8, cacheRead: 0.19 }
|
|
975
|
+
pricing: { input: 0.95, output: 8, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
976
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
899
977
|
}
|
|
900
978
|
]
|
|
901
979
|
};
|
|
@@ -907,22 +985,30 @@ var OPENAI_MODELS = {
|
|
|
907
985
|
{
|
|
908
986
|
id: "gpt-5.6",
|
|
909
987
|
label: "GPT-5.6 \u2014 routes to Sol",
|
|
910
|
-
pricing: { input: 5, output: 30, cacheRead: 0.5 }
|
|
988
|
+
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
989
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
990
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
911
991
|
},
|
|
912
992
|
{
|
|
913
993
|
id: "gpt-5.6-sol",
|
|
914
994
|
label: "GPT-5.6 Sol \u2014 deepest reasoning",
|
|
915
|
-
pricing: { input: 5, output: 30, cacheRead: 0.5 }
|
|
995
|
+
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
996
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
997
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
916
998
|
},
|
|
917
999
|
{
|
|
918
1000
|
id: "gpt-5.6-terra",
|
|
919
1001
|
label: "GPT-5.6 Terra \u2014 balanced",
|
|
920
|
-
pricing: { input: 2, output: 12, cacheRead: 0.2 }
|
|
1002
|
+
pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1003
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
1004
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
921
1005
|
},
|
|
922
1006
|
{
|
|
923
1007
|
id: "gpt-5.6-luna",
|
|
924
1008
|
label: "GPT-5.6 Luna \u2014 fastest",
|
|
925
|
-
pricing: { input: 0.2, output: 1.2, cacheRead: 0.02 }
|
|
1009
|
+
pricing: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1010
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
1011
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
926
1012
|
}
|
|
927
1013
|
]
|
|
928
1014
|
};
|
|
@@ -934,15 +1020,38 @@ var PROVIDER_MODEL_CATALOG = {
|
|
|
934
1020
|
kimi: KIMI_MODELS
|
|
935
1021
|
};
|
|
936
1022
|
function catalogPricing(provider, model) {
|
|
937
|
-
return PROVIDER_MODEL_CATALOG[provider]
|
|
1023
|
+
return PROVIDER_MODEL_CATALOG[provider]?.models.find((entry) => entry.id === model)?.pricing ?? null;
|
|
1024
|
+
}
|
|
1025
|
+
function catalogLimits(provider, model, auth = "apiKey") {
|
|
1026
|
+
const entry = PROVIDER_MODEL_CATALOG[provider]?.models.find((choice) => choice.id === model);
|
|
1027
|
+
if (entry === undefined)
|
|
1028
|
+
return null;
|
|
1029
|
+
return (auth === "oauth" ? entry.oauthLimits : undefined) ?? entry.limits;
|
|
938
1030
|
}
|
|
939
1031
|
// packages/providers/src/http-client.ts
|
|
940
1032
|
import { request as httpRequest } from "http";
|
|
941
1033
|
import { request as httpsRequest } from "https";
|
|
942
1034
|
import { Readable } from "stream";
|
|
943
|
-
function nodeHttpClient() {
|
|
1035
|
+
function nodeHttpClient(options = {}) {
|
|
1036
|
+
const logger2 = options.logger ?? noopLogger;
|
|
1037
|
+
const now = options.now ?? (() => Date.now());
|
|
944
1038
|
return (req) => new Promise((resolve, reject) => {
|
|
945
1039
|
const url = new URL(req.url);
|
|
1040
|
+
const startedAt = now();
|
|
1041
|
+
let traced = false;
|
|
1042
|
+
const trace = (status, failed = false) => {
|
|
1043
|
+
if (traced || !logger2.enabled("debug"))
|
|
1044
|
+
return;
|
|
1045
|
+
traced = true;
|
|
1046
|
+
logger2.debug("upstream http", {
|
|
1047
|
+
provider: req.provider,
|
|
1048
|
+
status,
|
|
1049
|
+
host: url.host,
|
|
1050
|
+
path: url.pathname,
|
|
1051
|
+
durationMs: now() - startedAt,
|
|
1052
|
+
reason: failed ? "transport error" : undefined
|
|
1053
|
+
});
|
|
1054
|
+
};
|
|
946
1055
|
const send = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
947
1056
|
const bodyBytes = Buffer.from(req.body, "utf8");
|
|
948
1057
|
const headers = {};
|
|
@@ -970,6 +1079,7 @@ function nodeHttpClient() {
|
|
|
970
1079
|
else if (typeof v === "string")
|
|
971
1080
|
responseHeaders.set(k, v);
|
|
972
1081
|
}
|
|
1082
|
+
trace(incoming.statusCode);
|
|
973
1083
|
resolve({
|
|
974
1084
|
status: incoming.statusCode ?? 0,
|
|
975
1085
|
headers: responseHeaders,
|
|
@@ -985,17 +1095,17 @@ function nodeHttpClient() {
|
|
|
985
1095
|
});
|
|
986
1096
|
});
|
|
987
1097
|
const onAbort = () => outgoing.destroy(new Error("aborted"));
|
|
988
|
-
if (req.signal.aborted) {
|
|
989
|
-
outgoing.destroy(new Error("aborted"));
|
|
990
|
-
reject(new Error("aborted"));
|
|
991
|
-
return;
|
|
992
|
-
}
|
|
993
|
-
req.signal.addEventListener("abort", onAbort, { once: true });
|
|
994
1098
|
outgoing.on("error", (err) => {
|
|
995
1099
|
req.signal.removeEventListener("abort", onAbort);
|
|
1100
|
+
trace(undefined, true);
|
|
996
1101
|
reject(err);
|
|
997
1102
|
});
|
|
998
1103
|
outgoing.on("close", () => req.signal.removeEventListener("abort", onAbort));
|
|
1104
|
+
if (req.signal.aborted) {
|
|
1105
|
+
outgoing.destroy(new Error("aborted"));
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
req.signal.addEventListener("abort", onAbort, { once: true });
|
|
999
1109
|
if (bodyBytes.byteLength > 0)
|
|
1000
1110
|
outgoing.write(bodyBytes);
|
|
1001
1111
|
outgoing.end();
|
|
@@ -1064,12 +1174,8 @@ async function* decodeChat(messages) {
|
|
|
1064
1174
|
yield { type: "start", id: String(d.id ?? ""), model: String(d.model ?? "") };
|
|
1065
1175
|
}
|
|
1066
1176
|
if (d.usage) {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
outputTokens: d.usage.completion_tokens ?? 0,
|
|
1070
|
-
cacheReadTokens: d.usage.prompt_cache_hit_tokens ?? 0,
|
|
1071
|
-
cacheWriteTokens: 0
|
|
1072
|
-
};
|
|
1177
|
+
const details = d.usage.prompt_tokens_details;
|
|
1178
|
+
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);
|
|
1073
1179
|
}
|
|
1074
1180
|
const choice = d.choices?.[0];
|
|
1075
1181
|
if (!choice)
|
|
@@ -1195,7 +1301,12 @@ function toChatWire(req, model) {
|
|
|
1195
1301
|
`) });
|
|
1196
1302
|
}
|
|
1197
1303
|
}
|
|
1198
|
-
const body = {
|
|
1304
|
+
const body = {
|
|
1305
|
+
model,
|
|
1306
|
+
messages,
|
|
1307
|
+
stream: req.stream,
|
|
1308
|
+
stream_options: { include_usage: true }
|
|
1309
|
+
};
|
|
1199
1310
|
if (req.maxTokens !== undefined)
|
|
1200
1311
|
body.max_tokens = req.maxTokens;
|
|
1201
1312
|
if (req.temperature !== undefined)
|
|
@@ -1236,6 +1347,7 @@ var kimiAdapter = {
|
|
|
1236
1347
|
const profile = PROFILES.kimi;
|
|
1237
1348
|
const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
|
|
1238
1349
|
const res = await req.http({
|
|
1350
|
+
provider: "kimi",
|
|
1239
1351
|
url: BASE_URL2,
|
|
1240
1352
|
method: "POST",
|
|
1241
1353
|
headers,
|
|
@@ -1366,12 +1478,7 @@ async function* decodeResponses(messages) {
|
|
|
1366
1478
|
yield {
|
|
1367
1479
|
type: "end",
|
|
1368
1480
|
stopReason,
|
|
1369
|
-
usage:
|
|
1370
|
-
inputTokens: r.usage?.input_tokens ?? 0,
|
|
1371
|
-
outputTokens: r.usage?.output_tokens ?? 0,
|
|
1372
|
-
cacheReadTokens: r.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
1373
|
-
cacheWriteTokens: 0
|
|
1374
|
-
}
|
|
1481
|
+
usage: usageFromPromptTotal(r.usage?.input_tokens ?? 0, r.usage?.output_tokens ?? 0, r.usage?.input_tokens_details?.cached_tokens ?? r.usage?.prompt_tokens_details?.cached_tokens ?? 0)
|
|
1375
1482
|
};
|
|
1376
1483
|
break;
|
|
1377
1484
|
}
|
|
@@ -1544,6 +1651,7 @@ var openaiAdapter = {
|
|
|
1544
1651
|
const profile = PROFILES.openai;
|
|
1545
1652
|
const headers = orderHeaders(mergeHeaders(profile.headers, protocol), profile.order);
|
|
1546
1653
|
const res = await req.http({
|
|
1654
|
+
provider: "openai",
|
|
1547
1655
|
url: oauth ? OAUTH_URL : API_URL,
|
|
1548
1656
|
method: "POST",
|
|
1549
1657
|
headers,
|
|
@@ -1558,13 +1666,14 @@ var openaiAdapter = {
|
|
|
1558
1666
|
}
|
|
1559
1667
|
};
|
|
1560
1668
|
// packages/control/src/oauth/types.ts
|
|
1561
|
-
async function postJson(deps, url, profile2, opts) {
|
|
1669
|
+
async function postJson(deps, provider, url, profile2, opts) {
|
|
1562
1670
|
const headers = orderHeaders(mergeHeaders(profile2.headers, [
|
|
1563
1671
|
["Content-Type", opts.contentType],
|
|
1564
1672
|
["Accept", "application/json"],
|
|
1565
1673
|
...opts.extraHeaders ?? []
|
|
1566
1674
|
]), profile2.order);
|
|
1567
1675
|
const res = await deps.http({
|
|
1676
|
+
provider,
|
|
1568
1677
|
url,
|
|
1569
1678
|
method: "POST",
|
|
1570
1679
|
headers,
|
|
@@ -1578,13 +1687,14 @@ async function postJson(deps, url, profile2, opts) {
|
|
|
1578
1687
|
} catch {}
|
|
1579
1688
|
return { status: res.status, parsed };
|
|
1580
1689
|
}
|
|
1581
|
-
async function getJson(deps, url, profile2, opts) {
|
|
1690
|
+
async function getJson(deps, provider, url, profile2, opts) {
|
|
1582
1691
|
const headers = orderHeaders(mergeHeaders(profile2.headers, [
|
|
1583
1692
|
["Authorization", `Bearer ${opts.accessToken}`],
|
|
1584
1693
|
["Accept", "application/json"],
|
|
1585
1694
|
...opts.extraHeaders ?? []
|
|
1586
1695
|
]), profile2.order);
|
|
1587
1696
|
const res = await deps.http({
|
|
1697
|
+
provider,
|
|
1588
1698
|
url,
|
|
1589
1699
|
method: "GET",
|
|
1590
1700
|
headers,
|
|
@@ -1778,7 +1888,7 @@ function deviceCodeFrom(value) {
|
|
|
1778
1888
|
};
|
|
1779
1889
|
}
|
|
1780
1890
|
async function post(url, body2, device, deps) {
|
|
1781
|
-
const { status, parsed } = await postJson(deps, url, PROFILES.kimi, {
|
|
1891
|
+
const { status, parsed } = await postJson(deps, "kimi", url, PROFILES.kimi, {
|
|
1782
1892
|
contentType: "application/x-www-form-urlencoded",
|
|
1783
1893
|
body: new URLSearchParams({ ...body2, client_id: CLIENT_ID }).toString(),
|
|
1784
1894
|
extraHeaders: kimiDeviceHeaders(device)
|
|
@@ -1881,7 +1991,7 @@ var kimiOAuth = {
|
|
|
1881
1991
|
if (secrets.accessToken === null)
|
|
1882
1992
|
return null;
|
|
1883
1993
|
const device = deviceFrom(providerData);
|
|
1884
|
-
const { status, parsed } = await getJson(deps, USAGE_URL, PROFILES.kimi, {
|
|
1994
|
+
const { status, parsed } = await getJson(deps, "kimi", USAGE_URL, PROFILES.kimi, {
|
|
1885
1995
|
accessToken: secrets.accessToken,
|
|
1886
1996
|
extraHeaders: kimiDeviceHeaders(device)
|
|
1887
1997
|
});
|
|
@@ -1950,6 +2060,7 @@ function deviceIdFrom(start) {
|
|
|
1950
2060
|
return deviceId;
|
|
1951
2061
|
}
|
|
1952
2062
|
function createConnectFlows(deps) {
|
|
2063
|
+
const logger2 = deps.logger ?? noopLogger;
|
|
1953
2064
|
const flows = createPendingFlows({ now: deps.now, ttlMs: FLOW_TTL_MS });
|
|
1954
2065
|
const pollsInFlight = new Map;
|
|
1955
2066
|
const callbackUri = (provider) => provider === "openai" ? "http://localhost:1455/auth/callback" : "";
|
|
@@ -1994,6 +2105,10 @@ function createConnectFlows(deps) {
|
|
|
1994
2105
|
disabledAt: null,
|
|
1995
2106
|
...result.secrets
|
|
1996
2107
|
});
|
|
2108
|
+
logger2.info("oauth connect completed", {
|
|
2109
|
+
provider: flow.provider,
|
|
2110
|
+
credentialId: id
|
|
2111
|
+
});
|
|
1997
2112
|
return { id };
|
|
1998
2113
|
}
|
|
1999
2114
|
async function pollOutcome(flowId, poll) {
|
|
@@ -16369,28 +16484,18 @@ var modelSchema = exports_external.object({
|
|
|
16369
16484
|
costPerMTok: exports_external.object({
|
|
16370
16485
|
input: exports_external.number().min(0),
|
|
16371
16486
|
output: exports_external.number().min(0),
|
|
16372
|
-
cacheRead: exports_external.number().min(0)
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
tools: exports_external.boolean(),
|
|
16376
|
-
images: exports_external.boolean(),
|
|
16377
|
-
reasoning: exports_external.boolean()
|
|
16378
|
-
})
|
|
16379
|
-
}).or(exports_external.object({
|
|
16380
|
-
provider: providerIdSchema,
|
|
16381
|
-
model: exports_external.string().min(1),
|
|
16382
|
-
tier: exports_external.number().int().min(1),
|
|
16383
|
-
weight: exports_external.number().positive(),
|
|
16384
|
-
costPerMTok: exports_external.object({
|
|
16385
|
-
input: exports_external.number().min(0),
|
|
16386
|
-
output: exports_external.number().min(0)
|
|
16487
|
+
cacheRead: exports_external.number().min(0).optional(),
|
|
16488
|
+
cacheWrite5m: exports_external.number().min(0).optional(),
|
|
16489
|
+
cacheWrite1h: exports_external.number().min(0).optional()
|
|
16387
16490
|
}),
|
|
16491
|
+
contextWindow: exports_external.number().int().positive().optional(),
|
|
16492
|
+
maxOutputTokens: exports_external.number().int().positive().optional(),
|
|
16388
16493
|
capabilities: exports_external.object({
|
|
16389
16494
|
tools: exports_external.boolean(),
|
|
16390
16495
|
images: exports_external.boolean(),
|
|
16391
16496
|
reasoning: exports_external.boolean()
|
|
16392
16497
|
})
|
|
16393
|
-
}))
|
|
16498
|
+
})).min(1, "a virtual model needs at least one target")
|
|
16394
16499
|
});
|
|
16395
16500
|
var keyCreateSchema = exports_external.object({
|
|
16396
16501
|
label: exports_external.string().min(1).default("api key"),
|
|
@@ -16468,7 +16573,7 @@ async function getCredential(store, id) {
|
|
|
16468
16573
|
throw new GatewayError("BAD_REQUEST", "no such credential");
|
|
16469
16574
|
return summarizeCredential(credential);
|
|
16470
16575
|
}
|
|
16471
|
-
async function createApiKeyCredential(store, input) {
|
|
16576
|
+
async function createApiKeyCredential(store, input, logger2 = noopLogger) {
|
|
16472
16577
|
const provider = parseOrThrow(providerIdSchema, input.provider);
|
|
16473
16578
|
if (typeof input.apiKey !== "string" || input.apiKey.trim().length === 0) {
|
|
16474
16579
|
throw new GatewayError("BAD_REQUEST", "apiKey: must not be empty");
|
|
@@ -16495,6 +16600,7 @@ async function createApiKeyCredential(store, input) {
|
|
|
16495
16600
|
apiKey: input.apiKey,
|
|
16496
16601
|
idToken: null
|
|
16497
16602
|
});
|
|
16603
|
+
logger2.info("credential added", { credentialId: created.id, provider: created.provider });
|
|
16498
16604
|
return summarizeCredential(created);
|
|
16499
16605
|
}
|
|
16500
16606
|
async function refreshCredential(deps, id) {
|
|
@@ -16554,6 +16660,12 @@ async function patchCredential(deps, id, input) {
|
|
|
16554
16660
|
...patch.tier === undefined ? {} : { tier: patch.tier },
|
|
16555
16661
|
...patch.weight === undefined ? {} : { weight: patch.weight }
|
|
16556
16662
|
});
|
|
16663
|
+
if (patch.enabled !== undefined && patch.enabled !== existing.enabled) {
|
|
16664
|
+
(deps.logger ?? noopLogger).info(patch.enabled ? "credential enabled" : "credential disabled", {
|
|
16665
|
+
credentialId: id,
|
|
16666
|
+
provider: existing.provider
|
|
16667
|
+
});
|
|
16668
|
+
}
|
|
16557
16669
|
}
|
|
16558
16670
|
async function removeCredential(store, id) {
|
|
16559
16671
|
await store.credentials.remove(id);
|
|
@@ -17718,7 +17830,9 @@ function createUsageRepo(db) {
|
|
|
17718
17830
|
|
|
17719
17831
|
// packages/store/src/sqlite/store.ts
|
|
17720
17832
|
async function createStore(opts) {
|
|
17833
|
+
const logger2 = opts.logger ?? noopLogger;
|
|
17721
17834
|
const db = openDb(opts.path);
|
|
17835
|
+
logger2.debug("store opened", { path: opts.path });
|
|
17722
17836
|
const listeners = new Set;
|
|
17723
17837
|
const emit2 = (change) => {
|
|
17724
17838
|
for (const listener of listeners) {
|
|
@@ -17811,7 +17925,7 @@ var REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
|
17811
17925
|
var SCOPES = "org:create_api_key user:profile user:inference";
|
|
17812
17926
|
var USAGE_URL2 = "https://api.anthropic.com/api/oauth/usage";
|
|
17813
17927
|
async function postToken(body2, deps) {
|
|
17814
|
-
const { status, parsed } = await postJson(deps, TOKEN_URL2, PROFILES.anthropic, {
|
|
17928
|
+
const { status, parsed } = await postJson(deps, "anthropic", TOKEN_URL2, PROFILES.anthropic, {
|
|
17815
17929
|
contentType: "application/json",
|
|
17816
17930
|
body: JSON.stringify({ ...body2, client_id: CLIENT_ID2 })
|
|
17817
17931
|
});
|
|
@@ -17889,7 +18003,7 @@ var anthropicOAuth = {
|
|
|
17889
18003
|
async usage(secrets, deps) {
|
|
17890
18004
|
if (secrets.accessToken === null)
|
|
17891
18005
|
return null;
|
|
17892
|
-
const { status, parsed } = await getJson(deps, USAGE_URL2, PROFILES.anthropic, {
|
|
18006
|
+
const { status, parsed } = await getJson(deps, "anthropic", USAGE_URL2, PROFILES.anthropic, {
|
|
17893
18007
|
accessToken: secrets.accessToken,
|
|
17894
18008
|
extraHeaders: [
|
|
17895
18009
|
["anthropic-beta", "oauth-2025-04-20"],
|
|
@@ -17947,7 +18061,7 @@ function parseTokenResponse(value) {
|
|
|
17947
18061
|
};
|
|
17948
18062
|
}
|
|
17949
18063
|
async function postToken2(body2, deps) {
|
|
17950
|
-
const { status, parsed } = await postJson(deps, TOKEN_URL3, PROFILES.openai, {
|
|
18064
|
+
const { status, parsed } = await postJson(deps, "openai", TOKEN_URL3, PROFILES.openai, {
|
|
17951
18065
|
contentType: "application/x-www-form-urlencoded",
|
|
17952
18066
|
body: new URLSearchParams({ ...body2, client_id: CLIENT_ID3 }).toString()
|
|
17953
18067
|
});
|
|
@@ -18046,7 +18160,7 @@ var openaiOAuth = {
|
|
|
18046
18160
|
if (secrets.accessToken === null)
|
|
18047
18161
|
return null;
|
|
18048
18162
|
const accountId = accountIdFromProviderData(providerData);
|
|
18049
|
-
const { status, parsed } = await getJson(deps, USAGE_URL3, PROFILES.openai, {
|
|
18163
|
+
const { status, parsed } = await getJson(deps, "openai", USAGE_URL3, PROFILES.openai, {
|
|
18050
18164
|
accessToken: secrets.accessToken,
|
|
18051
18165
|
...accountId === null ? {} : { extraHeaders: [["chatgpt-account-id", accountId]] }
|
|
18052
18166
|
});
|
|
@@ -18064,6 +18178,7 @@ var OAUTH_PROVIDERS = {
|
|
|
18064
18178
|
};
|
|
18065
18179
|
// packages/control/src/oauth/refresh.ts
|
|
18066
18180
|
function createRefresher(deps) {
|
|
18181
|
+
const logger2 = deps.logger ?? noopLogger;
|
|
18067
18182
|
const inFlight = new Map;
|
|
18068
18183
|
async function run(credential) {
|
|
18069
18184
|
const secrets = await credential.openForRefresh();
|
|
@@ -18071,11 +18186,20 @@ function createRefresher(deps) {
|
|
|
18071
18186
|
throw new GatewayError("AUTH", `credential ${credential.id} has no refresh token`);
|
|
18072
18187
|
}
|
|
18073
18188
|
const provider = deps.providers[credential.provider];
|
|
18189
|
+
logger2.debug("refreshing credential", {
|
|
18190
|
+
provider: credential.provider,
|
|
18191
|
+
credentialId: credential.id
|
|
18192
|
+
});
|
|
18074
18193
|
let result;
|
|
18075
18194
|
try {
|
|
18076
18195
|
result = await provider.refresh(secrets.refreshToken, { http: deps.http, now: deps.now }, credential.providerData);
|
|
18077
18196
|
} catch (error51) {
|
|
18078
18197
|
if (error51 instanceof GatewayError && error51.code === "AUTH") {
|
|
18198
|
+
logger2.warn("credential disabled: refresh token rejected", {
|
|
18199
|
+
provider: credential.provider,
|
|
18200
|
+
credentialId: credential.id,
|
|
18201
|
+
code: "AUTH"
|
|
18202
|
+
});
|
|
18079
18203
|
await deps.store.credentials.update(credential.id, {
|
|
18080
18204
|
enabled: false,
|
|
18081
18205
|
disabledReason: "tokenRejected",
|
|
@@ -18089,6 +18213,10 @@ function createRefresher(deps) {
|
|
|
18089
18213
|
accountEmail: result.accountEmail ?? credential.accountEmail,
|
|
18090
18214
|
providerData: { ...credential.providerData, ...result.providerData }
|
|
18091
18215
|
});
|
|
18216
|
+
logger2.debug("credential refreshed", {
|
|
18217
|
+
provider: credential.provider,
|
|
18218
|
+
credentialId: credential.id
|
|
18219
|
+
});
|
|
18092
18220
|
return result.secrets;
|
|
18093
18221
|
}
|
|
18094
18222
|
return function refresh(credential) {
|
|
@@ -18696,6 +18824,11 @@ var modelsShow = {
|
|
|
18696
18824
|
{ header: "WEIGHT", align: "right" },
|
|
18697
18825
|
{ header: "IN $/MTOK", align: "right" },
|
|
18698
18826
|
{ header: "OUT $/MTOK", align: "right" },
|
|
18827
|
+
{ header: "CACHE R", align: "right" },
|
|
18828
|
+
{ header: "CACHE W 5M", align: "right" },
|
|
18829
|
+
{ header: "CACHE W 1H", align: "right" },
|
|
18830
|
+
{ header: "CONTEXT", align: "right" },
|
|
18831
|
+
{ header: "MAX OUT", align: "right" },
|
|
18699
18832
|
{ header: "CAPABILITIES" }
|
|
18700
18833
|
], model.targets.map((target) => [
|
|
18701
18834
|
provider(ctx, target.provider),
|
|
@@ -18704,12 +18837,23 @@ var modelsShow = {
|
|
|
18704
18837
|
String(target.weight),
|
|
18705
18838
|
target.costPerMTok.input.toFixed(2),
|
|
18706
18839
|
target.costPerMTok.output.toFixed(2),
|
|
18840
|
+
price(target.costPerMTok.cacheRead),
|
|
18841
|
+
price(target.costPerMTok.cacheWrite5m),
|
|
18842
|
+
price(target.costPerMTok.cacheWrite1h),
|
|
18843
|
+
tokens(target.contextWindow),
|
|
18844
|
+
tokens(target.maxOutputTokens),
|
|
18707
18845
|
capabilityList(target)
|
|
18708
18846
|
]))
|
|
18709
18847
|
].join(`
|
|
18710
18848
|
`));
|
|
18711
18849
|
}
|
|
18712
18850
|
};
|
|
18851
|
+
function price(value) {
|
|
18852
|
+
return value === undefined ? "\u2014" : value.toFixed(2);
|
|
18853
|
+
}
|
|
18854
|
+
function tokens(value) {
|
|
18855
|
+
return value === undefined ? "\u2014" : value.toLocaleString("en-US");
|
|
18856
|
+
}
|
|
18713
18857
|
function capabilityList(target) {
|
|
18714
18858
|
const on = Object.entries(target.capabilities).filter(([, enabled]) => enabled).map(([name]) => name);
|
|
18715
18859
|
return on.length === 0 ? "\u2014" : on.join(",");
|
|
@@ -18741,7 +18885,7 @@ function isCatalogProvider(value) {
|
|
|
18741
18885
|
return value in PROVIDER_MODEL_CATALOG;
|
|
18742
18886
|
}
|
|
18743
18887
|
function catalogRows() {
|
|
18744
|
-
return Object.entries(PROVIDER_MODEL_CATALOG).flatMap(([id, entry]) => entry.models.map((model) => ({
|
|
18888
|
+
return Object.entries(PROVIDER_MODEL_CATALOG).flatMap(([id, entry]) => entry.models.map((model) => ({ ...model, provider: id })));
|
|
18745
18889
|
}
|
|
18746
18890
|
var modelsCatalog = {
|
|
18747
18891
|
usage: "models catalog [--provider P]",
|
|
@@ -18755,15 +18899,29 @@ var modelsCatalog = {
|
|
|
18755
18899
|
{ header: "MODEL" },
|
|
18756
18900
|
{ header: "LABEL" },
|
|
18757
18901
|
{ header: "IN $/MTOK", align: "right" },
|
|
18758
|
-
{ header: "OUT $/MTOK", align: "right" }
|
|
18902
|
+
{ header: "OUT $/MTOK", align: "right" },
|
|
18903
|
+
{ header: "CACHE R", align: "right" },
|
|
18904
|
+
{ header: "CACHE W 5M", align: "right" },
|
|
18905
|
+
{ header: "CACHE W 1H", align: "right" },
|
|
18906
|
+
{ header: "CONTEXT", align: "right" },
|
|
18907
|
+
{ header: "CONTEXT OAUTH", align: "right" },
|
|
18908
|
+
{ header: "MAX OUT", align: "right" }
|
|
18759
18909
|
], entries.map((entry) => {
|
|
18760
|
-
const
|
|
18910
|
+
const listed = catalogPricing(entry.provider, entry.id);
|
|
18911
|
+
const limits = catalogLimits(entry.provider, entry.id);
|
|
18912
|
+
const oauth = catalogLimits(entry.provider, entry.id, "oauth");
|
|
18761
18913
|
return [
|
|
18762
18914
|
provider(ctx, entry.provider),
|
|
18763
18915
|
entry.id,
|
|
18764
18916
|
entry.label,
|
|
18765
|
-
price
|
|
18766
|
-
price
|
|
18917
|
+
price(listed?.input),
|
|
18918
|
+
price(listed?.output),
|
|
18919
|
+
price(listed?.cacheRead),
|
|
18920
|
+
price(listed?.cacheWrite5m),
|
|
18921
|
+
price(listed?.cacheWrite1h),
|
|
18922
|
+
tokens(limits?.contextWindow),
|
|
18923
|
+
oauth?.contextWindow === limits?.contextWindow ? "\u2014" : tokens(oauth?.contextWindow),
|
|
18924
|
+
tokens(limits?.maxOutputTokens)
|
|
18767
18925
|
];
|
|
18768
18926
|
})));
|
|
18769
18927
|
}
|