omnigateway 0.1.7 → 0.2.0
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 +27 -33
- package/bin/omni.js +917 -161
- package/gateway.js +3247 -300
- package/package.json +1 -1
- package/public/assets/{Chip-C69u2U_b.js → Chip-BB_5C1Zp.js} +1 -1
- package/public/assets/Confirm-B6aAiVbT.js +4 -0
- package/public/assets/{CopyValue-CJy2T0H6.js → CopyValue-CRQDLo7k.js} +4 -4
- package/public/assets/{Field-Sc8mDqJv.js → Field-uHZxl4fI.js} +8 -8
- package/public/assets/Lamp-B-5SjXbG.js +25 -0
- package/public/assets/{Meter-C0nUftAa.js → Meter-DI_BRUKt.js} +1 -1
- package/public/assets/Modal-CI6jk2D4.js +82 -0
- package/public/assets/{Rack-CMqGBP4I.js → Rack-D1WJswv3.js} +23 -19
- package/public/assets/{Readout-Dv2dZWtI.js → Readout-BocZ2HXP.js} +5 -5
- package/public/assets/{States-D55MhqMx.js → States-Bbiu5cHE.js} +10 -10
- package/public/assets/{Table-DBB3jdgi.js → Table-CdPWxYaz.js} +1 -1
- package/public/assets/Toggle-CiLC67Dw.js +39 -0
- package/public/assets/TokenBreakdown-B96iPBm9.js +28 -0
- package/public/assets/_app-BBOF6A0T.js +1 -0
- package/public/assets/_app.accounts-BNkhpvaB.js +54 -0
- package/public/assets/_app.console-Daz4aKhf.js +44 -0
- package/public/assets/_app.index-LO6d38oe.js +62 -0
- package/public/assets/{_app.keys-BX8k8COP.js → _app.keys-kBqLqoFf.js} +8 -8
- package/public/assets/_app.logs-_wYNS47N.js +32 -0
- package/public/assets/_app.models-Cjng8ohC.js +144 -0
- package/public/assets/_app.settings-a0FKyQAi.js +38 -0
- package/public/assets/{_app.usage-BRhEvwVr.js → _app.usage-D3KtgLrC.js} +32 -29
- package/public/assets/dist-C-IbPRiV.js +1 -0
- package/public/assets/index-PW6EvVh5.js +170 -0
- package/public/assets/{login-DaC-wVpI.js → login-CTvH_KAd.js} +8 -8
- package/public/assets/queries-D2o-X8Pj.js +144 -0
- package/public/assets/{trash-2--aH2iKg-.js → trash-2-BcZb-sCT.js} +1 -1
- package/public/index.html +2 -2
- package/public/assets/Lamp-7jD_9929.js +0 -25
- package/public/assets/Modal-CiVHSJmm.js +0 -82
- package/public/assets/Toggle-BoGjb5oi.js +0 -42
- package/public/assets/_app-p5Mz7sXD.js +0 -1
- package/public/assets/_app.accounts-B5wMO9TH.js +0 -51
- package/public/assets/_app.console-Bka7AkiL.js +0 -25
- 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/public/assets/queries-2E6-CboE.js +0 -144
package/bin/omni.js
CHANGED
|
@@ -90,6 +90,10 @@ function formatUsd(value) {
|
|
|
90
90
|
return `$${value.toFixed(value < 1 ? 4 : 2)}`;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
// apps/cli/src/run.ts
|
|
94
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
95
|
+
import { homedir as homedir3 } from "os";
|
|
96
|
+
|
|
93
97
|
// packages/control/src/adminAuth.ts
|
|
94
98
|
import { hash, verify } from "@node-rs/argon2";
|
|
95
99
|
var MIN_PASSWORD_LENGTH = 12;
|
|
@@ -148,6 +152,11 @@ function createAdminAuth(store, opts) {
|
|
|
148
152
|
};
|
|
149
153
|
}
|
|
150
154
|
// packages/ir/src/capabilities.ts
|
|
155
|
+
var ANTHROPIC_NATIVE_TOOLS = {
|
|
156
|
+
anthropic: true,
|
|
157
|
+
openai: false,
|
|
158
|
+
kimi: false
|
|
159
|
+
};
|
|
151
160
|
var PROVIDER_CAPABILITIES = {
|
|
152
161
|
anthropic: { tools: true, images: true, reasoning: true },
|
|
153
162
|
openai: { tools: true, images: true, reasoning: true },
|
|
@@ -233,6 +242,7 @@ function usageFromPromptTotal(promptTokens, outputTokens, cacheReadTokens, cache
|
|
|
233
242
|
}
|
|
234
243
|
// packages/control/src/config.ts
|
|
235
244
|
var MIN_KEY_LENGTH = 16;
|
|
245
|
+
var TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
236
246
|
var DECIMAL_INTEGER = /^\d+$/;
|
|
237
247
|
function optionalText(value, fallback) {
|
|
238
248
|
return value?.trim() || fallback;
|
|
@@ -252,6 +262,7 @@ function loadConfig(env) {
|
|
|
252
262
|
const baseUrl = optionalText(env.OMNI_BASE_URL, derivedBaseUrl).replace(/\/+$/, "") || derivedBaseUrl;
|
|
253
263
|
const staticDir = env.OMNI_STATIC_DIR?.trim();
|
|
254
264
|
const logFile = env.OMNI_LOG_FILE?.trim();
|
|
265
|
+
const exposeClaudeCodeAliases = TRUTHY.has((env.OMNI_EXPOSE_CLAUDE_CODE_ALIASES ?? "").trim().toLowerCase());
|
|
255
266
|
const rawLogLevel = env.OMNI_LOG_LEVEL?.trim();
|
|
256
267
|
const logLevel = parseLogLevel(rawLogLevel);
|
|
257
268
|
return {
|
|
@@ -263,9 +274,14 @@ function loadConfig(env) {
|
|
|
263
274
|
encryptionKey,
|
|
264
275
|
baseUrl,
|
|
265
276
|
staticDir: staticDir === undefined || staticDir.length === 0 ? null : staticDir,
|
|
277
|
+
exposeClaudeCodeAliases,
|
|
266
278
|
logFile: logFile === undefined || logFile.length === 0 ? null : logFile
|
|
267
279
|
};
|
|
268
280
|
}
|
|
281
|
+
// packages/providers/src/betas.ts
|
|
282
|
+
var CONTEXT_1M_BETA = "context-1m-2025-08-07";
|
|
283
|
+
var CONTEXT_1M_TOKENS = 1e6;
|
|
284
|
+
|
|
269
285
|
// packages/providers/src/body.ts
|
|
270
286
|
var BODY_ORDER = {
|
|
271
287
|
anthropic: [
|
|
@@ -373,6 +389,119 @@ function signAnthropicBody(json) {
|
|
|
373
389
|
return json.replace(needle, `cch=${computeCch(json)};`);
|
|
374
390
|
}
|
|
375
391
|
|
|
392
|
+
// packages/providers/src/anthropic/models.ts
|
|
393
|
+
var ANTHROPIC_MODELS = {
|
|
394
|
+
defaultModel: "claude-opus-5",
|
|
395
|
+
models: [
|
|
396
|
+
{
|
|
397
|
+
id: "claude-fable-5",
|
|
398
|
+
label: "Claude Fable 5",
|
|
399
|
+
pricing: { input: 10, output: 50, cacheRead: 1, cacheWrite5m: 12.5, cacheWrite1h: 20 },
|
|
400
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
id: "claude-opus-5",
|
|
404
|
+
label: "Claude Opus 5",
|
|
405
|
+
pricing: { input: 5, output: 25, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 10 },
|
|
406
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: "claude-sonnet-5",
|
|
410
|
+
label: "Claude Sonnet 5",
|
|
411
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 3.75, cacheWrite1h: 6 },
|
|
412
|
+
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
id: "claude-haiku-4-5",
|
|
416
|
+
label: "Claude Haiku 4.5",
|
|
417
|
+
pricing: { input: 1, output: 5, cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 2 },
|
|
418
|
+
limits: { contextWindow: 200000, maxOutputTokens: 64000 }
|
|
419
|
+
}
|
|
420
|
+
]
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// packages/providers/src/kimi/models.ts
|
|
424
|
+
var KIMI_MODELS = {
|
|
425
|
+
defaultModel: "k3-256k",
|
|
426
|
+
models: [
|
|
427
|
+
{
|
|
428
|
+
id: "k3-256k",
|
|
429
|
+
label: "Kimi K3 \u2014 256K",
|
|
430
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
431
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
id: "k3",
|
|
435
|
+
label: "Kimi K3 \u2014 up to 1M",
|
|
436
|
+
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
437
|
+
limits: { contextWindow: 1048576, maxOutputTokens: 131072 }
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
id: "kimi-for-coding",
|
|
441
|
+
label: "Kimi K2.7 Code",
|
|
442
|
+
pricing: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
443
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
id: "kimi-for-coding-highspeed",
|
|
447
|
+
label: "Kimi K2.7 Code \u2014 High Speed",
|
|
448
|
+
pricing: { input: 0.95, output: 8, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
449
|
+
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
450
|
+
}
|
|
451
|
+
]
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// packages/providers/src/openai/models.ts
|
|
455
|
+
var OPENAI_MODELS = {
|
|
456
|
+
defaultModel: "gpt-5.6",
|
|
457
|
+
models: [
|
|
458
|
+
{
|
|
459
|
+
id: "gpt-5.6",
|
|
460
|
+
label: "GPT-5.6 \u2014 routes to Sol",
|
|
461
|
+
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
462
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
463
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
id: "gpt-5.6-sol",
|
|
467
|
+
label: "GPT-5.6 Sol \u2014 deepest reasoning",
|
|
468
|
+
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
469
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
470
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
id: "gpt-5.6-terra",
|
|
474
|
+
label: "GPT-5.6 Terra \u2014 balanced",
|
|
475
|
+
pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
476
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
477
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
id: "gpt-5.6-luna",
|
|
481
|
+
label: "GPT-5.6 Luna \u2014 fastest",
|
|
482
|
+
pricing: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
483
|
+
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
484
|
+
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
485
|
+
}
|
|
486
|
+
]
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// packages/providers/src/catalog.ts
|
|
490
|
+
var PROVIDER_MODEL_CATALOG = {
|
|
491
|
+
anthropic: ANTHROPIC_MODELS,
|
|
492
|
+
openai: OPENAI_MODELS,
|
|
493
|
+
kimi: KIMI_MODELS
|
|
494
|
+
};
|
|
495
|
+
function catalogPricing(provider, model) {
|
|
496
|
+
return PROVIDER_MODEL_CATALOG[provider]?.models.find((entry) => entry.id === model)?.pricing ?? null;
|
|
497
|
+
}
|
|
498
|
+
function catalogLimits(provider, model, auth = "apiKey") {
|
|
499
|
+
const entry = PROVIDER_MODEL_CATALOG[provider]?.models.find((choice) => choice.id === model);
|
|
500
|
+
if (entry === undefined)
|
|
501
|
+
return null;
|
|
502
|
+
return (auth === "oauth" ? entry.oauthLimits : undefined) ?? entry.limits;
|
|
503
|
+
}
|
|
504
|
+
|
|
376
505
|
// packages/providers/src/http.ts
|
|
377
506
|
function codeForStatus(status) {
|
|
378
507
|
if (status === 401 || status === 403)
|
|
@@ -634,14 +763,232 @@ function parseRecord(record) {
|
|
|
634
763
|
`) };
|
|
635
764
|
}
|
|
636
765
|
|
|
766
|
+
// packages/providers/src/anthropic/tools.ts
|
|
767
|
+
var COMMON = ["cache_control", "strict", "defer_loading", "allowed_callers"];
|
|
768
|
+
var COMMON_WITH_EXAMPLES = [...COMMON, "input_examples"];
|
|
769
|
+
var searchDomains = ["max_uses", "allowed_domains", "blocked_domains"];
|
|
770
|
+
var ANTHROPIC_TOOL_SPECS = {
|
|
771
|
+
web_search_20250305: {
|
|
772
|
+
family: "webSearch",
|
|
773
|
+
name: "web_search",
|
|
774
|
+
required: [],
|
|
775
|
+
optional: [...COMMON, ...searchDomains, "user_location"]
|
|
776
|
+
},
|
|
777
|
+
web_search_20260209: {
|
|
778
|
+
family: "webSearch",
|
|
779
|
+
name: "web_search",
|
|
780
|
+
required: [],
|
|
781
|
+
optional: [...COMMON, ...searchDomains, "user_location"]
|
|
782
|
+
},
|
|
783
|
+
web_search_20260318: {
|
|
784
|
+
family: "webSearch",
|
|
785
|
+
name: "web_search",
|
|
786
|
+
required: [],
|
|
787
|
+
optional: [...COMMON, ...searchDomains, "user_location", "response_inclusion"]
|
|
788
|
+
},
|
|
789
|
+
web_fetch_20250910: {
|
|
790
|
+
family: "webFetch",
|
|
791
|
+
name: "web_fetch",
|
|
792
|
+
required: [],
|
|
793
|
+
optional: [...COMMON, ...searchDomains, "citations", "max_content_tokens"]
|
|
794
|
+
},
|
|
795
|
+
web_fetch_20260209: {
|
|
796
|
+
family: "webFetch",
|
|
797
|
+
name: "web_fetch",
|
|
798
|
+
required: [],
|
|
799
|
+
optional: [...COMMON, ...searchDomains, "citations", "max_content_tokens"]
|
|
800
|
+
},
|
|
801
|
+
web_fetch_20260309: {
|
|
802
|
+
family: "webFetch",
|
|
803
|
+
name: "web_fetch",
|
|
804
|
+
required: [],
|
|
805
|
+
optional: [...COMMON, ...searchDomains, "citations", "max_content_tokens", "use_cache"]
|
|
806
|
+
},
|
|
807
|
+
web_fetch_20260318: {
|
|
808
|
+
family: "webFetch",
|
|
809
|
+
name: "web_fetch",
|
|
810
|
+
required: [],
|
|
811
|
+
optional: [
|
|
812
|
+
...COMMON,
|
|
813
|
+
...searchDomains,
|
|
814
|
+
"citations",
|
|
815
|
+
"max_content_tokens",
|
|
816
|
+
"use_cache",
|
|
817
|
+
"response_inclusion"
|
|
818
|
+
]
|
|
819
|
+
},
|
|
820
|
+
code_execution_20250522: {
|
|
821
|
+
family: "codeExecution",
|
|
822
|
+
name: "code_execution",
|
|
823
|
+
required: [],
|
|
824
|
+
optional: [...COMMON]
|
|
825
|
+
},
|
|
826
|
+
code_execution_20250825: {
|
|
827
|
+
family: "codeExecution",
|
|
828
|
+
name: "code_execution",
|
|
829
|
+
required: [],
|
|
830
|
+
optional: [...COMMON]
|
|
831
|
+
},
|
|
832
|
+
code_execution_20260120: {
|
|
833
|
+
family: "codeExecution",
|
|
834
|
+
name: "code_execution",
|
|
835
|
+
required: [],
|
|
836
|
+
optional: [...COMMON]
|
|
837
|
+
},
|
|
838
|
+
code_execution_20260521: {
|
|
839
|
+
family: "codeExecution",
|
|
840
|
+
name: "code_execution",
|
|
841
|
+
required: [],
|
|
842
|
+
optional: [...COMMON]
|
|
843
|
+
},
|
|
844
|
+
bash_20241022: {
|
|
845
|
+
family: "bash",
|
|
846
|
+
name: "bash",
|
|
847
|
+
required: [],
|
|
848
|
+
optional: [...COMMON_WITH_EXAMPLES]
|
|
849
|
+
},
|
|
850
|
+
bash_20250124: {
|
|
851
|
+
family: "bash",
|
|
852
|
+
name: "bash",
|
|
853
|
+
required: [],
|
|
854
|
+
optional: [...COMMON_WITH_EXAMPLES]
|
|
855
|
+
},
|
|
856
|
+
text_editor_20241022: {
|
|
857
|
+
family: "textEditor",
|
|
858
|
+
name: "str_replace_editor",
|
|
859
|
+
required: [],
|
|
860
|
+
optional: [...COMMON_WITH_EXAMPLES]
|
|
861
|
+
},
|
|
862
|
+
text_editor_20250124: {
|
|
863
|
+
family: "textEditor",
|
|
864
|
+
name: "str_replace_editor",
|
|
865
|
+
required: [],
|
|
866
|
+
optional: [...COMMON_WITH_EXAMPLES]
|
|
867
|
+
},
|
|
868
|
+
text_editor_20250429: {
|
|
869
|
+
family: "textEditor",
|
|
870
|
+
name: "str_replace_based_edit_tool",
|
|
871
|
+
required: [],
|
|
872
|
+
optional: [...COMMON_WITH_EXAMPLES]
|
|
873
|
+
},
|
|
874
|
+
text_editor_20250728: {
|
|
875
|
+
family: "textEditor",
|
|
876
|
+
name: "str_replace_based_edit_tool",
|
|
877
|
+
required: [],
|
|
878
|
+
optional: [...COMMON_WITH_EXAMPLES, "max_characters"]
|
|
879
|
+
},
|
|
880
|
+
computer_20241022: {
|
|
881
|
+
family: "computer",
|
|
882
|
+
name: "computer",
|
|
883
|
+
required: ["display_width_px", "display_height_px"],
|
|
884
|
+
optional: [...COMMON_WITH_EXAMPLES, "display_number"]
|
|
885
|
+
},
|
|
886
|
+
computer_20250124: {
|
|
887
|
+
family: "computer",
|
|
888
|
+
name: "computer",
|
|
889
|
+
required: ["display_width_px", "display_height_px"],
|
|
890
|
+
optional: [...COMMON_WITH_EXAMPLES, "display_number"]
|
|
891
|
+
},
|
|
892
|
+
computer_20251124: {
|
|
893
|
+
family: "computer",
|
|
894
|
+
name: "computer",
|
|
895
|
+
required: ["display_width_px", "display_height_px"],
|
|
896
|
+
optional: [...COMMON_WITH_EXAMPLES, "display_number", "enable_zoom"]
|
|
897
|
+
},
|
|
898
|
+
memory_20250818: {
|
|
899
|
+
family: "memory",
|
|
900
|
+
name: "memory",
|
|
901
|
+
required: [],
|
|
902
|
+
optional: [...COMMON_WITH_EXAMPLES]
|
|
903
|
+
},
|
|
904
|
+
tool_search_tool_regex_20251119: {
|
|
905
|
+
family: "toolSearchRegex",
|
|
906
|
+
name: "tool_search_tool_regex",
|
|
907
|
+
required: [],
|
|
908
|
+
optional: [...COMMON]
|
|
909
|
+
},
|
|
910
|
+
tool_search_tool_regex: {
|
|
911
|
+
family: "toolSearchRegex",
|
|
912
|
+
name: "tool_search_tool_regex",
|
|
913
|
+
required: [],
|
|
914
|
+
optional: [...COMMON]
|
|
915
|
+
},
|
|
916
|
+
tool_search_tool_bm25_20251119: {
|
|
917
|
+
family: "toolSearchBm25",
|
|
918
|
+
name: "tool_search_tool_bm25",
|
|
919
|
+
required: [],
|
|
920
|
+
optional: [...COMMON]
|
|
921
|
+
},
|
|
922
|
+
tool_search_tool_bm25: {
|
|
923
|
+
family: "toolSearchBm25",
|
|
924
|
+
name: "tool_search_tool_bm25",
|
|
925
|
+
required: [],
|
|
926
|
+
optional: [...COMMON]
|
|
927
|
+
},
|
|
928
|
+
advisor_20260301: {
|
|
929
|
+
family: "advisor",
|
|
930
|
+
name: "advisor",
|
|
931
|
+
required: ["model"],
|
|
932
|
+
optional: [...COMMON, "caching", "max_uses", "max_tokens"]
|
|
933
|
+
},
|
|
934
|
+
mcp_toolset: {
|
|
935
|
+
family: "mcpToolset",
|
|
936
|
+
required: ["mcp_server_name"],
|
|
937
|
+
optional: ["cache_control", "configs", "default_config"]
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
var ANTHROPIC_NATIVE_BLOCK_TYPES = new Set([
|
|
941
|
+
"server_tool_use",
|
|
942
|
+
"web_search_tool_result",
|
|
943
|
+
"web_fetch_tool_result",
|
|
944
|
+
"code_execution_tool_result",
|
|
945
|
+
"bash_code_execution_tool_result",
|
|
946
|
+
"text_editor_code_execution_tool_result",
|
|
947
|
+
"mcp_tool_use",
|
|
948
|
+
"mcp_tool_result",
|
|
949
|
+
"tool_search_tool_result",
|
|
950
|
+
"tool_reference",
|
|
951
|
+
"advisor_tool_result",
|
|
952
|
+
"advisor_result",
|
|
953
|
+
"advisor_redacted_result",
|
|
954
|
+
"container_upload",
|
|
955
|
+
"compaction",
|
|
956
|
+
"search_result",
|
|
957
|
+
"document",
|
|
958
|
+
"mid_conv_system",
|
|
959
|
+
"tool_addition",
|
|
960
|
+
"tool_removal",
|
|
961
|
+
"fallback",
|
|
962
|
+
"redacted_thinking"
|
|
963
|
+
]);
|
|
964
|
+
|
|
637
965
|
// packages/providers/src/anthropic/decode.ts
|
|
638
966
|
var STOP_REASON = {
|
|
639
967
|
end_turn: "endTurn",
|
|
640
968
|
max_tokens: "maxTokens",
|
|
641
969
|
stop_sequence: "stopSequence",
|
|
642
970
|
tool_use: "toolUse",
|
|
643
|
-
refusal: "contentFilter"
|
|
971
|
+
refusal: "contentFilter",
|
|
972
|
+
pause_turn: "pauseTurn"
|
|
644
973
|
};
|
|
974
|
+
var KNOWN_EVENTS = new Set([
|
|
975
|
+
"message_start",
|
|
976
|
+
"content_block_start",
|
|
977
|
+
"content_block_delta",
|
|
978
|
+
"content_block_stop",
|
|
979
|
+
"message_delta",
|
|
980
|
+
"message_stop",
|
|
981
|
+
"error",
|
|
982
|
+
"ping"
|
|
983
|
+
]);
|
|
984
|
+
var KNOWN_DELTAS = new Set([
|
|
985
|
+
"text_delta",
|
|
986
|
+
"thinking_delta",
|
|
987
|
+
"signature_delta",
|
|
988
|
+
"input_json_delta",
|
|
989
|
+
"citations_delta",
|
|
990
|
+
"compaction_delta"
|
|
991
|
+
]);
|
|
645
992
|
var ERROR_TYPE = {
|
|
646
993
|
overloaded_error: "OVERLOADED",
|
|
647
994
|
rate_limit_error: "RATE_LIMIT",
|
|
@@ -667,10 +1014,21 @@ async function* decodeAnthropic(messages) {
|
|
|
667
1014
|
let outputTokens = 0;
|
|
668
1015
|
let stopReason = "endTurn";
|
|
669
1016
|
let terminal = false;
|
|
1017
|
+
const nativeBlocks = new Set;
|
|
1018
|
+
const protocolError = (message) => ({
|
|
1019
|
+
type: "error",
|
|
1020
|
+
code: "UPSTREAM",
|
|
1021
|
+
message,
|
|
1022
|
+
retryable: false
|
|
1023
|
+
});
|
|
670
1024
|
for await (const msg of messages) {
|
|
671
1025
|
const d = json(msg.data);
|
|
672
1026
|
if (d === null)
|
|
673
1027
|
continue;
|
|
1028
|
+
if (!KNOWN_EVENTS.has(msg.event)) {
|
|
1029
|
+
yield protocolError(`unrecognized Anthropic stream event "${msg.event}"`);
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
674
1032
|
switch (msg.event) {
|
|
675
1033
|
case "message_start": {
|
|
676
1034
|
const m = d.message ?? {};
|
|
@@ -695,6 +1053,18 @@ async function* decodeAnthropic(messages) {
|
|
|
695
1053
|
index,
|
|
696
1054
|
block: { type: "toolUse", id: String(cb.id), name: String(cb.name) }
|
|
697
1055
|
};
|
|
1056
|
+
else if (cb.type !== undefined && ANTHROPIC_NATIVE_BLOCK_TYPES.has(cb.type)) {
|
|
1057
|
+
nativeBlocks.add(index);
|
|
1058
|
+
const { type: _blockType, ...data } = cb;
|
|
1059
|
+
yield {
|
|
1060
|
+
type: "blockStart",
|
|
1061
|
+
index,
|
|
1062
|
+
block: { type: "anthropicNative", blockType: cb.type, data }
|
|
1063
|
+
};
|
|
1064
|
+
} else {
|
|
1065
|
+
yield protocolError(`unrecognized Anthropic content block type "${String(cb.type)}"`);
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
698
1068
|
break;
|
|
699
1069
|
}
|
|
700
1070
|
case "content_block_delta": {
|
|
@@ -718,17 +1088,51 @@ async function* decodeAnthropic(messages) {
|
|
|
718
1088
|
yield {
|
|
719
1089
|
type: "blockDelta",
|
|
720
1090
|
index,
|
|
721
|
-
delta: { type: "toolJson", partial: delta.partial_json ?? "" }
|
|
1091
|
+
delta: nativeBlocks.has(index) ? { type: "anthropicNativeJson", partial: delta.partial_json ?? "" } : { type: "toolJson", partial: delta.partial_json ?? "" }
|
|
1092
|
+
};
|
|
1093
|
+
else if (delta.type === "citations_delta")
|
|
1094
|
+
yield {
|
|
1095
|
+
type: "blockDelta",
|
|
1096
|
+
index,
|
|
1097
|
+
delta: {
|
|
1098
|
+
type: "anthropicNative",
|
|
1099
|
+
deltaType: delta.type,
|
|
1100
|
+
data: { citation: delta.citation }
|
|
1101
|
+
}
|
|
722
1102
|
};
|
|
1103
|
+
else if (delta.type === "compaction_delta")
|
|
1104
|
+
yield {
|
|
1105
|
+
type: "blockDelta",
|
|
1106
|
+
index,
|
|
1107
|
+
delta: {
|
|
1108
|
+
type: "anthropicNative",
|
|
1109
|
+
deltaType: delta.type,
|
|
1110
|
+
data: {
|
|
1111
|
+
...delta.content === undefined ? {} : { content: delta.content },
|
|
1112
|
+
...delta.encrypted_content === undefined ? {} : { encrypted_content: delta.encrypted_content }
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
else if (delta.type === undefined || !KNOWN_DELTAS.has(delta.type)) {
|
|
1117
|
+
yield protocolError(`unrecognized Anthropic content block delta "${String(delta.type)}"`);
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
723
1120
|
break;
|
|
724
1121
|
}
|
|
725
1122
|
case "content_block_stop":
|
|
1123
|
+
nativeBlocks.delete(d.index ?? 0);
|
|
726
1124
|
yield { type: "blockEnd", index: d.index ?? 0 };
|
|
727
1125
|
break;
|
|
728
1126
|
case "message_delta": {
|
|
729
1127
|
const reason = d.delta?.stop_reason;
|
|
730
|
-
if (typeof reason === "string")
|
|
731
|
-
|
|
1128
|
+
if (typeof reason === "string") {
|
|
1129
|
+
const mapped = STOP_REASON[reason];
|
|
1130
|
+
if (mapped === undefined) {
|
|
1131
|
+
yield protocolError(`unrecognized Anthropic stop reason "${reason}"`);
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
stopReason = mapped;
|
|
1135
|
+
}
|
|
732
1136
|
inputTokens = d.usage?.input_tokens ?? inputTokens;
|
|
733
1137
|
outputTokens = d.usage?.output_tokens ?? outputTokens;
|
|
734
1138
|
break;
|
|
@@ -787,7 +1191,12 @@ function encodeBlock(b) {
|
|
|
787
1191
|
const cache = wireCacheControl(cacheControlOf(b));
|
|
788
1192
|
switch (b.type) {
|
|
789
1193
|
case "text":
|
|
790
|
-
return {
|
|
1194
|
+
return {
|
|
1195
|
+
type: "text",
|
|
1196
|
+
text: b.text,
|
|
1197
|
+
...b.citations === undefined ? {} : { citations: b.citations },
|
|
1198
|
+
...cache
|
|
1199
|
+
};
|
|
791
1200
|
case "image":
|
|
792
1201
|
return {
|
|
793
1202
|
type: "image",
|
|
@@ -806,11 +1215,16 @@ function encodeBlock(b) {
|
|
|
806
1215
|
is_error: b.isError,
|
|
807
1216
|
...cache
|
|
808
1217
|
};
|
|
1218
|
+
case "anthropicNative":
|
|
1219
|
+
return { ...b.data, type: b.blockType, ...cache };
|
|
809
1220
|
}
|
|
810
1221
|
}
|
|
811
1222
|
function encodeSystemTurn(content) {
|
|
812
|
-
|
|
1223
|
+
if (content.every((block) => block.type === "text")) {
|
|
1224
|
+
return content.map((block) => block.text).join(`
|
|
813
1225
|
`);
|
|
1226
|
+
}
|
|
1227
|
+
return content.map(encodeBlock);
|
|
814
1228
|
}
|
|
815
1229
|
function systemCacheControl(req) {
|
|
816
1230
|
const cacheable = req.messages.flatMap((message) => message.content.flatMap((block) => block.type === "thinking" ? [] : [{ role: message.role, block }]));
|
|
@@ -822,6 +1236,23 @@ function systemCacheControl(req) {
|
|
|
822
1236
|
lost: markedSystemBlocks.length > (promoted === undefined ? 0 : 1)
|
|
823
1237
|
};
|
|
824
1238
|
}
|
|
1239
|
+
function encodeTool(t) {
|
|
1240
|
+
if (t.provider === "anthropic") {
|
|
1241
|
+
return {
|
|
1242
|
+
type: t.type,
|
|
1243
|
+
...t.name === "" ? {} : { name: t.name },
|
|
1244
|
+
...t.wire,
|
|
1245
|
+
...wireCacheControl(t.cacheControl)
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
return {
|
|
1249
|
+
name: t.name,
|
|
1250
|
+
...t.description === undefined ? {} : { description: t.description },
|
|
1251
|
+
input_schema: t.inputSchema,
|
|
1252
|
+
...t.options ?? {},
|
|
1253
|
+
...wireCacheControl(t.cacheControl)
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
825
1256
|
function encodeToolChoice(c) {
|
|
826
1257
|
switch (c.type) {
|
|
827
1258
|
case "auto":
|
|
@@ -876,14 +1307,8 @@ function toWire(req, model, opts) {
|
|
|
876
1307
|
body.temperature = req.temperature;
|
|
877
1308
|
if (req.stopSequences !== undefined)
|
|
878
1309
|
body.stop_sequences = req.stopSequences;
|
|
879
|
-
if (req.tools !== undefined)
|
|
880
|
-
body.tools = req.tools.map(
|
|
881
|
-
name: t.name,
|
|
882
|
-
...t.description === undefined ? {} : { description: t.description },
|
|
883
|
-
input_schema: t.inputSchema,
|
|
884
|
-
...wireCacheControl(t.cacheControl)
|
|
885
|
-
}));
|
|
886
|
-
}
|
|
1310
|
+
if (req.tools !== undefined)
|
|
1311
|
+
body.tools = req.tools.map(encodeTool);
|
|
887
1312
|
if (req.toolChoice !== undefined)
|
|
888
1313
|
body.tool_choice = encodeToolChoice(req.toolChoice);
|
|
889
1314
|
if (req.reasoning !== undefined) {
|
|
@@ -930,6 +1355,15 @@ var anthropicAdapter = {
|
|
|
930
1355
|
["Accept", "text/event-stream"]
|
|
931
1356
|
];
|
|
932
1357
|
const betas = new Set(req.request.betas ?? []);
|
|
1358
|
+
const notes = [...degradations];
|
|
1359
|
+
if (betas.has(CONTEXT_1M_BETA)) {
|
|
1360
|
+
const limits = catalogLimits("anthropic", req.model, oauth ? "oauth" : "apiKey");
|
|
1361
|
+
const window = limits?.contextWindow;
|
|
1362
|
+
if (window !== undefined && window < CONTEXT_1M_TOKENS) {
|
|
1363
|
+
betas.delete(CONTEXT_1M_BETA);
|
|
1364
|
+
notes.push("anthropic:context-1m-dropped");
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
933
1367
|
if (oauth) {
|
|
934
1368
|
protocol.push(["Authorization", `Bearer ${req.credentials.accessToken}`]);
|
|
935
1369
|
betas.add(OAUTH_BETA);
|
|
@@ -957,121 +1391,9 @@ var anthropicAdapter = {
|
|
|
957
1391
|
throw await httpError(res, "anthropic");
|
|
958
1392
|
if (res.body === null)
|
|
959
1393
|
throw new GatewayError("UPSTREAM", "empty response body", { provider: "anthropic" });
|
|
960
|
-
return { events: decodeAnthropic(parseSse(res.body)), degradations };
|
|
1394
|
+
return { events: decodeAnthropic(parseSse(res.body)), degradations: notes };
|
|
961
1395
|
}
|
|
962
1396
|
};
|
|
963
|
-
// packages/providers/src/anthropic/models.ts
|
|
964
|
-
var ANTHROPIC_MODELS = {
|
|
965
|
-
defaultModel: "claude-opus-5",
|
|
966
|
-
models: [
|
|
967
|
-
{
|
|
968
|
-
id: "claude-fable-5",
|
|
969
|
-
label: "Claude Fable 5",
|
|
970
|
-
pricing: { input: 10, output: 50, cacheRead: 1, cacheWrite5m: 12.5, cacheWrite1h: 20 },
|
|
971
|
-
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
972
|
-
},
|
|
973
|
-
{
|
|
974
|
-
id: "claude-opus-5",
|
|
975
|
-
label: "Claude Opus 5",
|
|
976
|
-
pricing: { input: 5, output: 25, cacheRead: 0.5, cacheWrite5m: 6.25, cacheWrite1h: 10 },
|
|
977
|
-
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
978
|
-
},
|
|
979
|
-
{
|
|
980
|
-
id: "claude-sonnet-5",
|
|
981
|
-
label: "Claude Sonnet 5",
|
|
982
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 3.75, cacheWrite1h: 6 },
|
|
983
|
-
limits: { contextWindow: 1e6, maxOutputTokens: 128000 }
|
|
984
|
-
},
|
|
985
|
-
{
|
|
986
|
-
id: "claude-haiku-4-5",
|
|
987
|
-
label: "Claude Haiku 4.5",
|
|
988
|
-
pricing: { input: 1, output: 5, cacheRead: 0.1, cacheWrite5m: 1.25, cacheWrite1h: 2 },
|
|
989
|
-
limits: { contextWindow: 200000, maxOutputTokens: 64000 }
|
|
990
|
-
}
|
|
991
|
-
]
|
|
992
|
-
};
|
|
993
|
-
|
|
994
|
-
// packages/providers/src/kimi/models.ts
|
|
995
|
-
var KIMI_MODELS = {
|
|
996
|
-
defaultModel: "k3-256k",
|
|
997
|
-
models: [
|
|
998
|
-
{
|
|
999
|
-
id: "k3-256k",
|
|
1000
|
-
label: "Kimi K3 \u2014 256K",
|
|
1001
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1002
|
-
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
1003
|
-
},
|
|
1004
|
-
{
|
|
1005
|
-
id: "k3",
|
|
1006
|
-
label: "Kimi K3 \u2014 up to 1M",
|
|
1007
|
-
pricing: { input: 3, output: 15, cacheRead: 0.3, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1008
|
-
limits: { contextWindow: 1048576, maxOutputTokens: 131072 }
|
|
1009
|
-
},
|
|
1010
|
-
{
|
|
1011
|
-
id: "kimi-for-coding",
|
|
1012
|
-
label: "Kimi K2.7 Code",
|
|
1013
|
-
pricing: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1014
|
-
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
1015
|
-
},
|
|
1016
|
-
{
|
|
1017
|
-
id: "kimi-for-coding-highspeed",
|
|
1018
|
-
label: "Kimi K2.7 Code \u2014 High Speed",
|
|
1019
|
-
pricing: { input: 0.95, output: 8, cacheRead: 0.19, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1020
|
-
limits: { contextWindow: 262144, maxOutputTokens: 131072 }
|
|
1021
|
-
}
|
|
1022
|
-
]
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
// packages/providers/src/openai/models.ts
|
|
1026
|
-
var OPENAI_MODELS = {
|
|
1027
|
-
defaultModel: "gpt-5.6",
|
|
1028
|
-
models: [
|
|
1029
|
-
{
|
|
1030
|
-
id: "gpt-5.6",
|
|
1031
|
-
label: "GPT-5.6 \u2014 routes to Sol",
|
|
1032
|
-
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1033
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
1034
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
1035
|
-
},
|
|
1036
|
-
{
|
|
1037
|
-
id: "gpt-5.6-sol",
|
|
1038
|
-
label: "GPT-5.6 Sol \u2014 deepest reasoning",
|
|
1039
|
-
pricing: { input: 5, output: 30, cacheRead: 0.5, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1040
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
1041
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
1042
|
-
},
|
|
1043
|
-
{
|
|
1044
|
-
id: "gpt-5.6-terra",
|
|
1045
|
-
label: "GPT-5.6 Terra \u2014 balanced",
|
|
1046
|
-
pricing: { input: 2, output: 12, cacheRead: 0.2, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1047
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
1048
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
1049
|
-
},
|
|
1050
|
-
{
|
|
1051
|
-
id: "gpt-5.6-luna",
|
|
1052
|
-
label: "GPT-5.6 Luna \u2014 fastest",
|
|
1053
|
-
pricing: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite5m: 0, cacheWrite1h: 0 },
|
|
1054
|
-
limits: { contextWindow: 922000, maxOutputTokens: 128000 },
|
|
1055
|
-
oauthLimits: { contextWindow: 272000, maxOutputTokens: 128000 }
|
|
1056
|
-
}
|
|
1057
|
-
]
|
|
1058
|
-
};
|
|
1059
|
-
|
|
1060
|
-
// packages/providers/src/catalog.ts
|
|
1061
|
-
var PROVIDER_MODEL_CATALOG = {
|
|
1062
|
-
anthropic: ANTHROPIC_MODELS,
|
|
1063
|
-
openai: OPENAI_MODELS,
|
|
1064
|
-
kimi: KIMI_MODELS
|
|
1065
|
-
};
|
|
1066
|
-
function catalogPricing(provider, model) {
|
|
1067
|
-
return PROVIDER_MODEL_CATALOG[provider]?.models.find((entry) => entry.id === model)?.pricing ?? null;
|
|
1068
|
-
}
|
|
1069
|
-
function catalogLimits(provider, model, auth = "apiKey") {
|
|
1070
|
-
const entry = PROVIDER_MODEL_CATALOG[provider]?.models.find((choice) => choice.id === model);
|
|
1071
|
-
if (entry === undefined)
|
|
1072
|
-
return null;
|
|
1073
|
-
return (auth === "oauth" ? entry.oauthLimits : undefined) ?? entry.limits;
|
|
1074
|
-
}
|
|
1075
1397
|
// packages/providers/src/http-client.ts
|
|
1076
1398
|
import { request as httpRequest } from "http";
|
|
1077
1399
|
import { request as httpsRequest } from "https";
|
|
@@ -1297,6 +1619,8 @@ function toChatWire(req, model) {
|
|
|
1297
1619
|
if (!degradations.includes(d))
|
|
1298
1620
|
degradations.push(d);
|
|
1299
1621
|
};
|
|
1622
|
+
if (req.betas?.includes(CONTEXT_1M_BETA))
|
|
1623
|
+
note2("kimi:context-1m-dropped");
|
|
1300
1624
|
const messages = [];
|
|
1301
1625
|
const system = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
|
|
1302
1626
|
|
|
@@ -1331,6 +1655,9 @@ function toChatWire(req, model) {
|
|
|
1331
1655
|
content: block.content
|
|
1332
1656
|
});
|
|
1333
1657
|
break;
|
|
1658
|
+
case "anthropicNative":
|
|
1659
|
+
note2("kimi:anthropic-native-block-dropped");
|
|
1660
|
+
break;
|
|
1334
1661
|
}
|
|
1335
1662
|
}
|
|
1336
1663
|
if (toolCalls.length > 0) {
|
|
@@ -1358,7 +1685,10 @@ function toChatWire(req, model) {
|
|
|
1358
1685
|
if (req.stopSequences !== undefined)
|
|
1359
1686
|
body.stop = req.stopSequences;
|
|
1360
1687
|
if (req.tools !== undefined) {
|
|
1361
|
-
|
|
1688
|
+
const custom = req.tools.filter((t) => t.provider === "custom");
|
|
1689
|
+
if (custom.length !== req.tools.length)
|
|
1690
|
+
note2("kimi:anthropic-tool-dropped");
|
|
1691
|
+
body.tools = custom.map((t) => ({
|
|
1362
1692
|
type: "function",
|
|
1363
1693
|
function: { name: t.name, description: t.description, parameters: t.inputSchema }
|
|
1364
1694
|
}));
|
|
@@ -1573,6 +1903,8 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
|
|
|
1573
1903
|
if (!degradations.includes(d))
|
|
1574
1904
|
degradations.push(d);
|
|
1575
1905
|
};
|
|
1906
|
+
if (req.betas?.includes(CONTEXT_1M_BETA))
|
|
1907
|
+
note2("openai:context-1m-dropped");
|
|
1576
1908
|
for (const message of req.messages) {
|
|
1577
1909
|
const parts = [];
|
|
1578
1910
|
const inlined = message.role === "system";
|
|
@@ -1623,6 +1955,9 @@ ${block.text}
|
|
|
1623
1955
|
output: block.content
|
|
1624
1956
|
});
|
|
1625
1957
|
break;
|
|
1958
|
+
case "anthropicNative":
|
|
1959
|
+
note2("openai:anthropic-native-block-dropped");
|
|
1960
|
+
break;
|
|
1626
1961
|
}
|
|
1627
1962
|
}
|
|
1628
1963
|
flush();
|
|
@@ -1646,7 +1981,10 @@ ${block.text}
|
|
|
1646
1981
|
body.temperature = req.temperature;
|
|
1647
1982
|
}
|
|
1648
1983
|
if (req.tools !== undefined) {
|
|
1649
|
-
|
|
1984
|
+
const custom = req.tools.filter((t) => t.provider === "custom");
|
|
1985
|
+
if (custom.length !== req.tools.length)
|
|
1986
|
+
note2("openai:anthropic-tool-dropped");
|
|
1987
|
+
body.tools = custom.map((t) => ({
|
|
1650
1988
|
type: "function",
|
|
1651
1989
|
name: t.name,
|
|
1652
1990
|
description: t.description,
|
|
@@ -2261,12 +2599,10 @@ async function readSource(deps, source, lines) {
|
|
|
2261
2599
|
return "";
|
|
2262
2600
|
if (source.kind === "file")
|
|
2263
2601
|
return deps.readFile(source.path, lines) ?? "";
|
|
2264
|
-
const
|
|
2602
|
+
const unit = source.scope === "system" ? ["-u", source.unit] : [`--user-unit=${source.unit}`];
|
|
2265
2603
|
const result = await deps.run([
|
|
2266
2604
|
"journalctl",
|
|
2267
|
-
...
|
|
2268
|
-
"-u",
|
|
2269
|
-
source.unit,
|
|
2605
|
+
...unit,
|
|
2270
2606
|
"-n",
|
|
2271
2607
|
String(lines),
|
|
2272
2608
|
"--no-pager",
|
|
@@ -16573,7 +16909,9 @@ var dryRunSchema = exports_external.object({
|
|
|
16573
16909
|
reasoning: exports_external.boolean().default(false)
|
|
16574
16910
|
}).strict();
|
|
16575
16911
|
var modelSchema = exports_external.object({
|
|
16576
|
-
id: exports_external.string().min(1),
|
|
16912
|
+
id: exports_external.string().min(1).refine((value) => !value.toLowerCase().startsWith("claude/"), {
|
|
16913
|
+
message: 'model id must not start with "claude/": that prefix is reserved for discovery mirrors'
|
|
16914
|
+
}),
|
|
16577
16915
|
strategy: exports_external.enum(["score", "priority", "roundRobin", "weighted"]),
|
|
16578
16916
|
isAlias: exports_external.boolean(),
|
|
16579
16917
|
targets: exports_external.array(exports_external.object({
|
|
@@ -16612,11 +16950,12 @@ var settingsSchema = exports_external.object({
|
|
|
16612
16950
|
recency: exports_external.number()
|
|
16613
16951
|
}).strict(),
|
|
16614
16952
|
maxAttempts: exports_external.number().int().min(1).max(10),
|
|
16615
|
-
requestDeadlineMs: exports_external.number().int().
|
|
16953
|
+
requestDeadlineMs: exports_external.number().int().min(0),
|
|
16616
16954
|
breakerThreshold: exports_external.number().int().min(1),
|
|
16617
16955
|
breakerCooldownMs: exports_external.number().int().positive(),
|
|
16618
16956
|
logRetentionDays: exports_external.number().int().min(1),
|
|
16619
|
-
quotaPollIntervalMs: exports_external.number().int().min(0)
|
|
16957
|
+
quotaPollIntervalMs: exports_external.number().int().min(0),
|
|
16958
|
+
rtkEnabled: exports_external.boolean()
|
|
16620
16959
|
});
|
|
16621
16960
|
var credentialPatchSchema = exports_external.object({
|
|
16622
16961
|
label: exports_external.string().min(1).optional(),
|
|
@@ -16803,6 +17142,11 @@ async function buildSnapshot(store, now) {
|
|
|
16803
17142
|
}
|
|
16804
17143
|
|
|
16805
17144
|
// packages/router/src/filters.ts
|
|
17145
|
+
function needsAnthropicNative(request2) {
|
|
17146
|
+
if (request2.tools?.some((t) => t.provider === "anthropic") === true)
|
|
17147
|
+
return true;
|
|
17148
|
+
return request2.messages.some((m) => m.content.some((b) => b.type === "anthropicNative"));
|
|
17149
|
+
}
|
|
16806
17150
|
function requiredCapabilities(request2) {
|
|
16807
17151
|
const images = request2.messages.some((m) => m.content.some((b) => b.type === "image"));
|
|
16808
17152
|
return {
|
|
@@ -16819,10 +17163,11 @@ function eligible(input) {
|
|
|
16819
17163
|
const { request: request2, model, snapshot, now } = input;
|
|
16820
17164
|
const { breakerThreshold, breakerCooldownMs } = snapshot.settings;
|
|
16821
17165
|
const need = requiredCapabilities(request2);
|
|
17166
|
+
const needNative = needsAnthropicNative(request2);
|
|
16822
17167
|
const pairs = [];
|
|
16823
17168
|
const excluded = [];
|
|
16824
17169
|
for (const target of model.targets) {
|
|
16825
|
-
const missing = ["tools", "images", "reasoning"].find((cap) => need[cap] && !target.capabilities[cap]);
|
|
17170
|
+
const missing = needNative && !ANTHROPIC_NATIVE_TOOLS[target.provider] ? "anthropicTools" : ["tools", "images", "reasoning"].find((cap) => need[cap] && !target.capabilities[cap]);
|
|
16826
17171
|
for (const credential of snapshot.credentials) {
|
|
16827
17172
|
if (credential.provider !== target.provider)
|
|
16828
17173
|
continue;
|
|
@@ -17017,7 +17362,11 @@ async function dryRun(deps, modelId, input) {
|
|
|
17017
17362
|
}
|
|
17018
17363
|
],
|
|
17019
17364
|
stream: false,
|
|
17020
|
-
...need.tools ? {
|
|
17365
|
+
...need.tools ? {
|
|
17366
|
+
tools: [
|
|
17367
|
+
{ provider: "custom", name: "probe", description: "", inputSchema: { type: "object" } }
|
|
17368
|
+
]
|
|
17369
|
+
} : {},
|
|
17021
17370
|
...need.reasoning ? { reasoning: { mode: "adaptive" } } : {}
|
|
17022
17371
|
};
|
|
17023
17372
|
const result = rank({ request: probe, model, snapshot, now, rand: 0 });
|
|
@@ -17085,7 +17434,8 @@ var DEFAULT_SETTINGS = {
|
|
|
17085
17434
|
breakerThreshold: 3,
|
|
17086
17435
|
breakerCooldownMs: 30000,
|
|
17087
17436
|
logRetentionDays: 30,
|
|
17088
|
-
quotaPollIntervalMs: 300000
|
|
17437
|
+
quotaPollIntervalMs: 300000,
|
|
17438
|
+
rtkEnabled: false
|
|
17089
17439
|
};
|
|
17090
17440
|
|
|
17091
17441
|
// packages/store/src/sqlite/config.ts
|
|
@@ -17121,12 +17471,18 @@ function createConfigRepo(db, emit2 = () => {}) {
|
|
|
17121
17471
|
const raw = readRaw(SETTINGS_KEY);
|
|
17122
17472
|
if (raw === null)
|
|
17123
17473
|
return DEFAULT_SETTINGS;
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17474
|
+
try {
|
|
17475
|
+
const parsed = JSON.parse(raw);
|
|
17476
|
+
const stored = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
17477
|
+
return {
|
|
17478
|
+
...DEFAULT_SETTINGS,
|
|
17479
|
+
...stored,
|
|
17480
|
+
rtkEnabled: stored.rtkEnabled === true,
|
|
17481
|
+
weights: { ...DEFAULT_SETTINGS.weights, ...stored.weights }
|
|
17482
|
+
};
|
|
17483
|
+
} catch {
|
|
17484
|
+
return DEFAULT_SETTINGS;
|
|
17485
|
+
}
|
|
17130
17486
|
},
|
|
17131
17487
|
async putSettings(patch) {
|
|
17132
17488
|
const current = await this.getSettings();
|
|
@@ -17568,6 +17924,20 @@ ALTER TABLE request_logs ADD COLUMN state TEXT NOT NULL DEFAULT 'done';
|
|
|
17568
17924
|
CREATE INDEX idx_request_logs_pending ON request_logs(state) WHERE state = 'pending';
|
|
17569
17925
|
`;
|
|
17570
17926
|
|
|
17927
|
+
// packages/store/src/sqlite/migrations/005_rtk_metrics.sql
|
|
17928
|
+
var _005_rtk_metrics_default = `ALTER TABLE request_logs ADD COLUMN rtk_applied INTEGER NOT NULL DEFAULT 0;
|
|
17929
|
+
ALTER TABLE request_logs ADD COLUMN rtk_filter_hits INTEGER NOT NULL DEFAULT 0;
|
|
17930
|
+
ALTER TABLE request_logs ADD COLUMN rtk_original_code_units INTEGER NOT NULL DEFAULT 0;
|
|
17931
|
+
ALTER TABLE request_logs ADD COLUMN rtk_compressed_code_units INTEGER NOT NULL DEFAULT 0;
|
|
17932
|
+
ALTER TABLE request_logs ADD COLUMN rtk_estimated_tokens_saved INTEGER NOT NULL DEFAULT 0;
|
|
17933
|
+
ALTER TABLE request_logs ADD COLUMN rtk_filters TEXT NOT NULL DEFAULT '[]';
|
|
17934
|
+
`;
|
|
17935
|
+
|
|
17936
|
+
// packages/store/src/sqlite/migrations/006_rtk_usage.sql
|
|
17937
|
+
var _006_rtk_usage_default = `ALTER TABLE usage_daily ADD COLUMN rtk_saved_tokens INTEGER NOT NULL DEFAULT 0;
|
|
17938
|
+
ALTER TABLE usage_daily ADD COLUMN rtk_applied_requests INTEGER NOT NULL DEFAULT 0;
|
|
17939
|
+
`;
|
|
17940
|
+
|
|
17571
17941
|
// packages/store/src/sqlite/rollup.ts
|
|
17572
17942
|
function startOfLocalDay(at) {
|
|
17573
17943
|
const day = new Date(at);
|
|
@@ -17578,8 +17948,8 @@ var UPSERT = `
|
|
|
17578
17948
|
INSERT INTO usage_daily
|
|
17579
17949
|
(day, provider, credential_id, requested_model, resolved_model, api_key_id,
|
|
17580
17950
|
requests, errors, input_tokens, output_tokens, cache_read_tokens,
|
|
17581
|
-
cache_write_tokens, cost_usd, duration_ms_sum)
|
|
17582
|
-
VALUES (
|
|
17951
|
+
cache_write_tokens, rtk_saved_tokens, rtk_applied_requests, cost_usd, duration_ms_sum)
|
|
17952
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
17583
17953
|
ON CONFLICT (day, provider, credential_id, requested_model, resolved_model, api_key_id)
|
|
17584
17954
|
DO UPDATE SET
|
|
17585
17955
|
requests = requests + excluded.requests,
|
|
@@ -17587,8 +17957,10 @@ var UPSERT = `
|
|
|
17587
17957
|
input_tokens = input_tokens + excluded.input_tokens,
|
|
17588
17958
|
output_tokens = output_tokens + excluded.output_tokens,
|
|
17589
17959
|
cache_read_tokens = cache_read_tokens + excluded.cache_read_tokens,
|
|
17590
|
-
cache_write_tokens
|
|
17591
|
-
|
|
17960
|
+
cache_write_tokens = cache_write_tokens + excluded.cache_write_tokens,
|
|
17961
|
+
rtk_saved_tokens = rtk_saved_tokens + excluded.rtk_saved_tokens,
|
|
17962
|
+
rtk_applied_requests = rtk_applied_requests + excluded.rtk_applied_requests,
|
|
17963
|
+
cost_usd = cost_usd + excluded.cost_usd,
|
|
17592
17964
|
duration_ms_sum = duration_ms_sum + excluded.duration_ms_sum`;
|
|
17593
17965
|
function keyOf(log) {
|
|
17594
17966
|
return [
|
|
@@ -17608,6 +17980,8 @@ function countersOf(log) {
|
|
|
17608
17980
|
outputTokens: log.outputTokens,
|
|
17609
17981
|
cacheReadTokens: log.cacheReadTokens,
|
|
17610
17982
|
cacheWriteTokens: log.cacheWriteTokens,
|
|
17983
|
+
rtkSavedTokens: log.rtkEstimatedTokensSaved,
|
|
17984
|
+
rtkAppliedRequests: log.rtkApplied ? 1 : 0,
|
|
17611
17985
|
costUsd: log.costUsd,
|
|
17612
17986
|
durationMsSum: log.durationMs
|
|
17613
17987
|
};
|
|
@@ -17621,6 +17995,8 @@ function upsert(db, key, c) {
|
|
|
17621
17995
|
c.outputTokens,
|
|
17622
17996
|
c.cacheReadTokens,
|
|
17623
17997
|
c.cacheWriteTokens,
|
|
17998
|
+
c.rtkSavedTokens,
|
|
17999
|
+
c.rtkAppliedRequests,
|
|
17624
18000
|
c.costUsd,
|
|
17625
18001
|
c.durationMsSum
|
|
17626
18002
|
]);
|
|
@@ -17651,6 +18027,8 @@ function backfillDaily(db) {
|
|
|
17651
18027
|
outputTokens: 0,
|
|
17652
18028
|
cacheReadTokens: 0,
|
|
17653
18029
|
cacheWriteTokens: 0,
|
|
18030
|
+
rtkSavedTokens: 0,
|
|
18031
|
+
rtkAppliedRequests: 0,
|
|
17654
18032
|
costUsd: 0,
|
|
17655
18033
|
durationMsSum: 0
|
|
17656
18034
|
};
|
|
@@ -17669,13 +18047,42 @@ function backfillDaily(db) {
|
|
|
17669
18047
|
upsert(db, group.key, group.counters);
|
|
17670
18048
|
return groups.size;
|
|
17671
18049
|
}
|
|
18050
|
+
function backfillRtkUsage(db) {
|
|
18051
|
+
const groups = new Map;
|
|
18052
|
+
for (const row of db.query(`SELECT at, api_key_id, requested_model, resolved_provider, resolved_model, credential_id,
|
|
18053
|
+
rtk_applied, rtk_estimated_tokens_saved
|
|
18054
|
+
FROM request_logs
|
|
18055
|
+
WHERE state = 'done'`).all()) {
|
|
18056
|
+
const key = [
|
|
18057
|
+
startOfLocalDay(row.at),
|
|
18058
|
+
row.resolved_provider ?? "",
|
|
18059
|
+
row.credential_id ?? "",
|
|
18060
|
+
row.requested_model,
|
|
18061
|
+
row.resolved_model ?? "",
|
|
18062
|
+
row.api_key_id ?? ""
|
|
18063
|
+
];
|
|
18064
|
+
const id = key.join("\x00");
|
|
18065
|
+
const group = groups.get(id) ?? { key, saved: 0, applied: 0 };
|
|
18066
|
+
group.saved += row.rtk_estimated_tokens_saved;
|
|
18067
|
+
group.applied += row.rtk_applied === 1 ? 1 : 0;
|
|
18068
|
+
groups.set(id, group);
|
|
18069
|
+
}
|
|
18070
|
+
for (const { key, saved, applied } of groups.values()) {
|
|
18071
|
+
db.run(`UPDATE usage_daily
|
|
18072
|
+
SET rtk_saved_tokens = ?, rtk_applied_requests = ?
|
|
18073
|
+
WHERE day = ? AND provider = ? AND credential_id = ? AND requested_model = ?
|
|
18074
|
+
AND resolved_model = ? AND api_key_id = ?`, [saved, applied, ...key]);
|
|
18075
|
+
}
|
|
18076
|
+
}
|
|
17672
18077
|
|
|
17673
18078
|
// packages/store/src/sqlite/db.ts
|
|
17674
18079
|
var MIGRATIONS = [
|
|
17675
18080
|
{ id: 1, sql: _001_init_default },
|
|
17676
18081
|
{ id: 2, sql: _002_usage_daily_default, after: backfillDaily },
|
|
17677
18082
|
{ id: 3, sql: _003_quota_snapshot_default },
|
|
17678
|
-
{ id: 4, sql: _004_request_state_default }
|
|
18083
|
+
{ id: 4, sql: _004_request_state_default },
|
|
18084
|
+
{ id: 5, sql: _005_rtk_metrics_default },
|
|
18085
|
+
{ id: 6, sql: _006_rtk_usage_default, after: backfillRtkUsage }
|
|
17679
18086
|
];
|
|
17680
18087
|
function openDb(path) {
|
|
17681
18088
|
const db = new Database(path, { create: true });
|
|
@@ -17744,7 +18151,38 @@ function createKeyRepo(db) {
|
|
|
17744
18151
|
}
|
|
17745
18152
|
};
|
|
17746
18153
|
}
|
|
18154
|
+
// packages/rtk/src/catalog.ts
|
|
18155
|
+
var RTK_FILTER_IDS = [
|
|
18156
|
+
"git-diff",
|
|
18157
|
+
"git-status",
|
|
18158
|
+
"git-log",
|
|
18159
|
+
"grep",
|
|
18160
|
+
"path-list",
|
|
18161
|
+
"numbered-read",
|
|
18162
|
+
"build-output",
|
|
18163
|
+
"test-output",
|
|
18164
|
+
"deduplicate-log",
|
|
18165
|
+
"smart-truncate",
|
|
18166
|
+
"lint-output",
|
|
18167
|
+
"package-output",
|
|
18168
|
+
"tree-output",
|
|
18169
|
+
"git-operation",
|
|
18170
|
+
"docker-build"
|
|
18171
|
+
];
|
|
18172
|
+
var FILTER_IDS = new Set(RTK_FILTER_IDS);
|
|
18173
|
+
function isRtkFilterId(value) {
|
|
18174
|
+
return FILTER_IDS.has(value);
|
|
18175
|
+
}
|
|
18176
|
+
|
|
17747
18177
|
// packages/store/src/sqlite/usage.ts
|
|
18178
|
+
function parseRtkFilters(raw) {
|
|
18179
|
+
try {
|
|
18180
|
+
const parsed = JSON.parse(raw);
|
|
18181
|
+
return Array.isArray(parsed) ? parsed.filter(isRtkFilterId) : [];
|
|
18182
|
+
} catch {
|
|
18183
|
+
return [];
|
|
18184
|
+
}
|
|
18185
|
+
}
|
|
17748
18186
|
var toLog = (r) => ({
|
|
17749
18187
|
id: r.id,
|
|
17750
18188
|
state: r.state === "pending" ? "pending" : "done",
|
|
@@ -17764,7 +18202,13 @@ var toLog = (r) => ({
|
|
|
17764
18202
|
ttftMs: r.ttft_ms,
|
|
17765
18203
|
durationMs: r.duration_ms,
|
|
17766
18204
|
costUsd: r.cost_usd,
|
|
17767
|
-
degradations: JSON.parse(r.degradations)
|
|
18205
|
+
degradations: JSON.parse(r.degradations),
|
|
18206
|
+
rtkApplied: r.rtk_applied === 1,
|
|
18207
|
+
rtkFilterHits: r.rtk_filter_hits,
|
|
18208
|
+
rtkOriginalCodeUnits: r.rtk_original_code_units,
|
|
18209
|
+
rtkCompressedCodeUnits: r.rtk_compressed_code_units,
|
|
18210
|
+
rtkEstimatedTokensSaved: r.rtk_estimated_tokens_saved,
|
|
18211
|
+
rtkFilters: parseRtkFilters(r.rtk_filters)
|
|
17768
18212
|
});
|
|
17769
18213
|
var GROUP_COLUMN = {
|
|
17770
18214
|
raw: {
|
|
@@ -17809,8 +18253,9 @@ function label(value) {
|
|
|
17809
18253
|
var COLUMNS = `(id, state, at, api_key_id, requested_model, resolved_provider, resolved_model,
|
|
17810
18254
|
credential_id, attempts, status, error_code, input_tokens, output_tokens,
|
|
17811
18255
|
cache_read_tokens, cache_write_tokens, ttft_ms, duration_ms, cost_usd,
|
|
17812
|
-
degradations
|
|
17813
|
-
|
|
18256
|
+
degradations, rtk_applied, rtk_filter_hits, rtk_original_code_units,
|
|
18257
|
+
rtk_compressed_code_units, rtk_estimated_tokens_saved, rtk_filters)`;
|
|
18258
|
+
var PLACEHOLDERS = "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
|
17814
18259
|
function values(log, state) {
|
|
17815
18260
|
return [
|
|
17816
18261
|
log.id,
|
|
@@ -17831,7 +18276,13 @@ function values(log, state) {
|
|
|
17831
18276
|
log.ttftMs,
|
|
17832
18277
|
log.durationMs,
|
|
17833
18278
|
log.costUsd,
|
|
17834
|
-
JSON.stringify(log.degradations)
|
|
18279
|
+
JSON.stringify(log.degradations),
|
|
18280
|
+
log.rtkApplied === true ? 1 : 0,
|
|
18281
|
+
log.rtkFilterHits ?? 0,
|
|
18282
|
+
log.rtkOriginalCodeUnits ?? 0,
|
|
18283
|
+
log.rtkCompressedCodeUnits ?? 0,
|
|
18284
|
+
log.rtkEstimatedTokensSaved ?? 0,
|
|
18285
|
+
JSON.stringify(log.rtkFilters ?? [])
|
|
17835
18286
|
];
|
|
17836
18287
|
}
|
|
17837
18288
|
var COMPLETE = `INSERT INTO request_logs ${COLUMNS} VALUES ${PLACEHOLDERS}
|
|
@@ -17852,7 +18303,13 @@ var COMPLETE = `INSERT INTO request_logs ${COLUMNS} VALUES ${PLACEHOLDERS}
|
|
|
17852
18303
|
ttft_ms = excluded.ttft_ms,
|
|
17853
18304
|
duration_ms = excluded.duration_ms,
|
|
17854
18305
|
cost_usd = excluded.cost_usd,
|
|
17855
|
-
degradations = excluded.degradations
|
|
18306
|
+
degradations = excluded.degradations,
|
|
18307
|
+
rtk_applied = excluded.rtk_applied,
|
|
18308
|
+
rtk_filter_hits = excluded.rtk_filter_hits,
|
|
18309
|
+
rtk_original_code_units = excluded.rtk_original_code_units,
|
|
18310
|
+
rtk_compressed_code_units = excluded.rtk_compressed_code_units,
|
|
18311
|
+
rtk_estimated_tokens_saved = excluded.rtk_estimated_tokens_saved,
|
|
18312
|
+
rtk_filters = excluded.rtk_filters`;
|
|
17856
18313
|
function createUsageRepo(db) {
|
|
17857
18314
|
const complete = db.transaction((log) => {
|
|
17858
18315
|
db.run(COMPLETE, values(log, "done"));
|
|
@@ -17897,6 +18354,8 @@ function createUsageRepo(db) {
|
|
|
17897
18354
|
COALESCE(SUM(output_tokens), 0) AS output_tokens,
|
|
17898
18355
|
COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,
|
|
17899
18356
|
COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens,
|
|
18357
|
+
COALESCE(SUM(${daily ? "rtk_saved_tokens" : "rtk_estimated_tokens_saved"}), 0) AS rtk_saved_tokens,
|
|
18358
|
+
COALESCE(SUM(${daily ? "rtk_applied_requests" : "CASE WHEN rtk_applied = 1 THEN 1 ELSE 0 END"}), 0) AS rtk_applied_requests,
|
|
17900
18359
|
COALESCE(SUM(cost_usd), 0) AS cost_usd
|
|
17901
18360
|
FROM ${daily ? "usage_daily" : "request_logs"}
|
|
17902
18361
|
WHERE ${daily ? "" : "state = 'done' AND "}${timeColumn} >= ? AND ${timeColumn} <= ?
|
|
@@ -17910,6 +18369,8 @@ function createUsageRepo(db) {
|
|
|
17910
18369
|
outputTokens: r.output_tokens,
|
|
17911
18370
|
cacheReadTokens: r.cache_read_tokens,
|
|
17912
18371
|
cacheWriteTokens: r.cache_write_tokens,
|
|
18372
|
+
rtkSavedTokens: r.rtk_saved_tokens,
|
|
18373
|
+
rtkAppliedRequests: r.rtk_applied_requests,
|
|
17913
18374
|
costUsd: r.cost_usd,
|
|
17914
18375
|
errors: r.errors,
|
|
17915
18376
|
durationMsSum: r.duration_ms_sum
|
|
@@ -17985,6 +18446,60 @@ async function createKey(store, input) {
|
|
|
17985
18446
|
async function revokeKey(store, id) {
|
|
17986
18447
|
await store.keys.revoke(id);
|
|
17987
18448
|
}
|
|
18449
|
+
// packages/control/src/modelLimits.ts
|
|
18450
|
+
function narrower(a, b) {
|
|
18451
|
+
const context = [a.contextWindow, b.contextWindow].filter((n) => n !== undefined);
|
|
18452
|
+
const output = [a.maxOutputTokens, b.maxOutputTokens].filter((n) => n !== undefined);
|
|
18453
|
+
return {
|
|
18454
|
+
...context.length === 0 ? {} : { contextWindow: Math.min(...context) },
|
|
18455
|
+
...output.length === 0 ? {} : { maxOutputTokens: Math.min(...output) }
|
|
18456
|
+
};
|
|
18457
|
+
}
|
|
18458
|
+
function targetLimits(target, auths) {
|
|
18459
|
+
const ways = auths.size === 0 ? ["apiKey"] : [...auths];
|
|
18460
|
+
let listed = {};
|
|
18461
|
+
for (const auth of ways) {
|
|
18462
|
+
const entry = catalogLimits(target.provider, target.model, auth);
|
|
18463
|
+
if (entry === null)
|
|
18464
|
+
continue;
|
|
18465
|
+
listed = narrower(listed, {
|
|
18466
|
+
contextWindow: entry.contextWindow,
|
|
18467
|
+
maxOutputTokens: entry.maxOutputTokens
|
|
18468
|
+
});
|
|
18469
|
+
}
|
|
18470
|
+
const contextWindow = target.contextWindow ?? listed.contextWindow;
|
|
18471
|
+
const maxOutputTokens = target.maxOutputTokens ?? listed.maxOutputTokens;
|
|
18472
|
+
return {
|
|
18473
|
+
...contextWindow === undefined ? {} : { contextWindow },
|
|
18474
|
+
...maxOutputTokens === undefined ? {} : { maxOutputTokens }
|
|
18475
|
+
};
|
|
18476
|
+
}
|
|
18477
|
+
function servingAuths(credentials) {
|
|
18478
|
+
const byProvider = new Map;
|
|
18479
|
+
for (const credential of credentials) {
|
|
18480
|
+
if (!credential.enabled)
|
|
18481
|
+
continue;
|
|
18482
|
+
const ways = byProvider.get(credential.provider) ?? new Set;
|
|
18483
|
+
ways.add(credential.authType);
|
|
18484
|
+
byProvider.set(credential.provider, ways);
|
|
18485
|
+
}
|
|
18486
|
+
return byProvider;
|
|
18487
|
+
}
|
|
18488
|
+
function resolveModelLimits(model, credentials) {
|
|
18489
|
+
const auths = servingAuths(credentials);
|
|
18490
|
+
let limits = {};
|
|
18491
|
+
for (const target of model.targets) {
|
|
18492
|
+
limits = narrower(limits, targetLimits(target, auths.get(target.provider) ?? new Set));
|
|
18493
|
+
}
|
|
18494
|
+
return limits;
|
|
18495
|
+
}
|
|
18496
|
+
function modelDisplayName(model) {
|
|
18497
|
+
const only = model.targets.length === 1 ? model.targets[0] : undefined;
|
|
18498
|
+
if (only === undefined)
|
|
18499
|
+
return model.id;
|
|
18500
|
+
const labelled = PROVIDER_MODEL_CATALOG[only.provider]?.models.find((choice) => choice.id === only.model);
|
|
18501
|
+
return labelled?.label ?? model.id;
|
|
18502
|
+
}
|
|
17988
18503
|
// packages/control/src/models.ts
|
|
17989
18504
|
async function listModels(store) {
|
|
17990
18505
|
return store.config.listModels();
|
|
@@ -18341,6 +18856,116 @@ async function putSettings(store, input) {
|
|
|
18341
18856
|
await store.config.putSettings(settings);
|
|
18342
18857
|
return settings;
|
|
18343
18858
|
}
|
|
18859
|
+
// packages/control/src/setup.ts
|
|
18860
|
+
var KEY_PLACEHOLDER = "<your OmniGateway key>";
|
|
18861
|
+
async function describeModelsForSetup(store) {
|
|
18862
|
+
const models = await listModels(store);
|
|
18863
|
+
const credentials = (await listCredentials(store)).map((credential) => ({
|
|
18864
|
+
provider: credential.provider,
|
|
18865
|
+
authType: credential.authType,
|
|
18866
|
+
enabled: credential.enabled
|
|
18867
|
+
}));
|
|
18868
|
+
return models.map((model) => ({
|
|
18869
|
+
model,
|
|
18870
|
+
limits: resolveModelLimits(model, credentials),
|
|
18871
|
+
label: modelDisplayName(model)
|
|
18872
|
+
}));
|
|
18873
|
+
}
|
|
18874
|
+
var CLAUDE_MAPPING_KEYS = {
|
|
18875
|
+
defaultModel: "ANTHROPIC_MODEL",
|
|
18876
|
+
fableModel: "ANTHROPIC_DEFAULT_FABLE_MODEL",
|
|
18877
|
+
opusModel: "ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
18878
|
+
sonnetModel: "ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
18879
|
+
haikuModel: "ANTHROPIC_DEFAULT_HAIKU_MODEL"
|
|
18880
|
+
};
|
|
18881
|
+
function settingsObject(existing) {
|
|
18882
|
+
if (existing === undefined)
|
|
18883
|
+
return {};
|
|
18884
|
+
try {
|
|
18885
|
+
const parsed = JSON.parse(existing);
|
|
18886
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
18887
|
+
throw new Error("settings root is not an object");
|
|
18888
|
+
}
|
|
18889
|
+
return parsed;
|
|
18890
|
+
} catch (error51) {
|
|
18891
|
+
const reason = error51 instanceof Error ? error51.message : "invalid JSON";
|
|
18892
|
+
throw new Error(`cannot parse existing settings.json: ${reason}`);
|
|
18893
|
+
}
|
|
18894
|
+
}
|
|
18895
|
+
function claudeSettings(described, input, mapping, existing) {
|
|
18896
|
+
if (mapping.defaultModel === "")
|
|
18897
|
+
throw new Error("default model is required");
|
|
18898
|
+
const ids = new Set(described.map(({ model }) => model.id));
|
|
18899
|
+
const visibleId = (slot, id) => {
|
|
18900
|
+
if (!ids.has(id))
|
|
18901
|
+
throw new Error(`${slot} names unknown virtual model "${id}"`);
|
|
18902
|
+
const useMirror = input.discoveryMirrors === true && !/^(?:claude|anthropic)/i.test(id);
|
|
18903
|
+
return useMirror ? `claude/${id}` : id;
|
|
18904
|
+
};
|
|
18905
|
+
const settings = settingsObject(existing);
|
|
18906
|
+
const currentEnv = settings.env;
|
|
18907
|
+
const env2 = typeof currentEnv === "object" && currentEnv !== null && !Array.isArray(currentEnv) ? { ...currentEnv } : {};
|
|
18908
|
+
for (const key of Object.values(CLAUDE_MAPPING_KEYS))
|
|
18909
|
+
delete env2[key];
|
|
18910
|
+
delete env2.CLAUDE_CODE_MAX_CONTEXT_TOKENS;
|
|
18911
|
+
env2.ANTHROPIC_BASE_URL = input.baseUrl;
|
|
18912
|
+
env2.ANTHROPIC_AUTH_TOKEN = input.apiKey ?? KEY_PLACEHOLDER;
|
|
18913
|
+
env2.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY = "1";
|
|
18914
|
+
for (const [slot, key] of Object.entries(CLAUDE_MAPPING_KEYS)) {
|
|
18915
|
+
const id = mapping[slot];
|
|
18916
|
+
if (id !== undefined && id !== "")
|
|
18917
|
+
env2[key] = visibleId(slot, id);
|
|
18918
|
+
}
|
|
18919
|
+
return {
|
|
18920
|
+
path: "settings.json",
|
|
18921
|
+
contents: `${JSON.stringify({ ...settings, env: env2 }, null, 2)}
|
|
18922
|
+
`
|
|
18923
|
+
};
|
|
18924
|
+
}
|
|
18925
|
+
function opencodeConfig(described, input, mapping) {
|
|
18926
|
+
if (mapping.defaultModel === "")
|
|
18927
|
+
throw new Error("default model is required");
|
|
18928
|
+
const byId = new Map(described.map((entry) => [entry.model.id, entry]));
|
|
18929
|
+
const selected = [];
|
|
18930
|
+
const seen = new Set;
|
|
18931
|
+
for (const slot of Object.keys(CLAUDE_MAPPING_KEYS)) {
|
|
18932
|
+
const id = mapping[slot];
|
|
18933
|
+
if (id === undefined || id === "")
|
|
18934
|
+
continue;
|
|
18935
|
+
const entry = byId.get(id);
|
|
18936
|
+
if (entry === undefined)
|
|
18937
|
+
throw new Error(`${slot} names unknown virtual model "${id}"`);
|
|
18938
|
+
if (!seen.has(id)) {
|
|
18939
|
+
seen.add(id);
|
|
18940
|
+
selected.push(entry);
|
|
18941
|
+
}
|
|
18942
|
+
}
|
|
18943
|
+
const models = {};
|
|
18944
|
+
for (const { model, limits, label: label2 } of selected) {
|
|
18945
|
+
const limit = limits.contextWindow === undefined ? undefined : {
|
|
18946
|
+
context: limits.contextWindow,
|
|
18947
|
+
...limits.maxOutputTokens === undefined ? {} : { output: limits.maxOutputTokens }
|
|
18948
|
+
};
|
|
18949
|
+
models[model.id] = { name: label2, ...limit === undefined ? {} : { limit } };
|
|
18950
|
+
}
|
|
18951
|
+
const contents = `${JSON.stringify({
|
|
18952
|
+
$schema: "https://opencode.ai/config.json",
|
|
18953
|
+
model: `omnigateway/${mapping.defaultModel}`,
|
|
18954
|
+
provider: {
|
|
18955
|
+
omnigateway: {
|
|
18956
|
+
npm: "@ai-sdk/openai-compatible",
|
|
18957
|
+
name: "OmniGateway",
|
|
18958
|
+
options: {
|
|
18959
|
+
baseURL: `${input.baseUrl.replace(/\/+$/, "").replace(/(?:\/v1)+$/i, "")}/v1`,
|
|
18960
|
+
apiKey: input.apiKey ?? KEY_PLACEHOLDER
|
|
18961
|
+
},
|
|
18962
|
+
models
|
|
18963
|
+
}
|
|
18964
|
+
}
|
|
18965
|
+
}, null, 2)}
|
|
18966
|
+
`;
|
|
18967
|
+
return { path: "opencode.json", contents };
|
|
18968
|
+
}
|
|
18344
18969
|
// packages/control/src/tail.ts
|
|
18345
18970
|
import { closeSync, fstatSync, openSync, readSync, statSync } from "fs";
|
|
18346
18971
|
var CHUNK = 64 * 1024;
|
|
@@ -19256,8 +19881,8 @@ var modelsShow = {
|
|
|
19256
19881
|
price(target.costPerMTok.cacheRead),
|
|
19257
19882
|
price(target.costPerMTok.cacheWrite5m),
|
|
19258
19883
|
price(target.costPerMTok.cacheWrite1h),
|
|
19259
|
-
|
|
19260
|
-
|
|
19884
|
+
tokens2(target.contextWindow),
|
|
19885
|
+
tokens2(target.maxOutputTokens),
|
|
19261
19886
|
capabilityList(target)
|
|
19262
19887
|
]))
|
|
19263
19888
|
].join(`
|
|
@@ -19267,7 +19892,7 @@ var modelsShow = {
|
|
|
19267
19892
|
function price(value) {
|
|
19268
19893
|
return value === undefined ? "\u2014" : value.toFixed(2);
|
|
19269
19894
|
}
|
|
19270
|
-
function
|
|
19895
|
+
function tokens2(value) {
|
|
19271
19896
|
return value === undefined ? "\u2014" : value.toLocaleString("en-US");
|
|
19272
19897
|
}
|
|
19273
19898
|
function capabilityList(target) {
|
|
@@ -19335,9 +19960,9 @@ var modelsCatalog = {
|
|
|
19335
19960
|
price(listed?.cacheRead),
|
|
19336
19961
|
price(listed?.cacheWrite5m),
|
|
19337
19962
|
price(listed?.cacheWrite1h),
|
|
19338
|
-
|
|
19339
|
-
oauth?.contextWindow === limits?.contextWindow ? "\u2014" :
|
|
19340
|
-
|
|
19963
|
+
tokens2(limits?.contextWindow),
|
|
19964
|
+
oauth?.contextWindow === limits?.contextWindow ? "\u2014" : tokens2(oauth?.contextWindow),
|
|
19965
|
+
tokens2(limits?.maxOutputTokens)
|
|
19341
19966
|
];
|
|
19342
19967
|
})));
|
|
19343
19968
|
}
|
|
@@ -19721,6 +20346,104 @@ var settingsSet = {
|
|
|
19721
20346
|
}
|
|
19722
20347
|
};
|
|
19723
20348
|
|
|
20349
|
+
// apps/cli/src/commands/setup.ts
|
|
20350
|
+
import { join as join4 } from "path";
|
|
20351
|
+
var OPTIONS = {
|
|
20352
|
+
dir: { type: "string" },
|
|
20353
|
+
key: { type: "string" },
|
|
20354
|
+
"dry-run": { type: "boolean" }
|
|
20355
|
+
};
|
|
20356
|
+
async function described(ctx) {
|
|
20357
|
+
const models = await describeModelsForSetup(await ctx.store());
|
|
20358
|
+
if (models.length === 0) {
|
|
20359
|
+
throw new CliError("no virtual models configured; add one with `omni models put`");
|
|
20360
|
+
}
|
|
20361
|
+
return models;
|
|
20362
|
+
}
|
|
20363
|
+
function baseUrl(ctx) {
|
|
20364
|
+
if (ctx.configError !== null)
|
|
20365
|
+
throw new CliError(ctx.configError);
|
|
20366
|
+
return ctx.config().baseUrl;
|
|
20367
|
+
}
|
|
20368
|
+
function finish(ctx, writer, files, dryRun2, key, write) {
|
|
20369
|
+
if (!dryRun2) {
|
|
20370
|
+
for (const file2 of files)
|
|
20371
|
+
write(file2.path, file2.contents);
|
|
20372
|
+
}
|
|
20373
|
+
emit(ctx, writer, { files }, () => dryRun2 ? files.map((f) => `--- ${f.path}
|
|
20374
|
+
${f.contents}`).join(`
|
|
20375
|
+
`) : files.map((f) => f.path).join(`
|
|
20376
|
+
`));
|
|
20377
|
+
if (key === undefined) {
|
|
20378
|
+
note(ctx, writer, "no --key given: the files carry a placeholder, so paste your key over it");
|
|
20379
|
+
}
|
|
20380
|
+
}
|
|
20381
|
+
function at(dir, file2) {
|
|
20382
|
+
return { path: join4(dir, file2.path), contents: file2.contents };
|
|
20383
|
+
}
|
|
20384
|
+
async function promptMapping(models, prompt) {
|
|
20385
|
+
const choices = models.map(({ model }) => model.id).join(", ");
|
|
20386
|
+
if (prompt.input === undefined) {
|
|
20387
|
+
throw new CliError("model mapping requires an interactive terminal");
|
|
20388
|
+
}
|
|
20389
|
+
const ask = async (label2, required2) => {
|
|
20390
|
+
const answer = await prompt.input?.(`${label2} model${required2 ? "" : " (blank to omit)"} [${choices}]: `);
|
|
20391
|
+
if (required2 && answer === "")
|
|
20392
|
+
throw new CliError("default model is required");
|
|
20393
|
+
return answer === "" ? undefined : answer;
|
|
20394
|
+
};
|
|
20395
|
+
const defaultModel = await ask("Default", true);
|
|
20396
|
+
if (defaultModel === undefined)
|
|
20397
|
+
throw new CliError("default model is required");
|
|
20398
|
+
const fableModel = await ask("Fable", false);
|
|
20399
|
+
const opusModel = await ask("Opus", false);
|
|
20400
|
+
const sonnetModel = await ask("Sonnet", false);
|
|
20401
|
+
const haikuModel = await ask("Haiku", false);
|
|
20402
|
+
return {
|
|
20403
|
+
defaultModel,
|
|
20404
|
+
...fableModel === undefined ? {} : { fableModel },
|
|
20405
|
+
...opusModel === undefined ? {} : { opusModel },
|
|
20406
|
+
...sonnetModel === undefined ? {} : { sonnetModel },
|
|
20407
|
+
...haikuModel === undefined ? {} : { haikuModel }
|
|
20408
|
+
};
|
|
20409
|
+
}
|
|
20410
|
+
var setupClaude = {
|
|
20411
|
+
usage: "setup claude [--dir <path>] [--key <key>] [--dry-run]",
|
|
20412
|
+
summary: "Write Claude Code settings for this gateway",
|
|
20413
|
+
options: OPTIONS,
|
|
20414
|
+
async run(args, { ctx, writer, prompt, setupFs }) {
|
|
20415
|
+
const models = await described(ctx);
|
|
20416
|
+
const dir = stringFlag(args.values, "dir") ?? join4(setupFs.homeDir, ".claude");
|
|
20417
|
+
const key = stringFlag(args.values, "key");
|
|
20418
|
+
const dryRun2 = boolFlag(args.values, "dry-run");
|
|
20419
|
+
const mapping = await promptMapping(models, prompt);
|
|
20420
|
+
const path = join4(dir, "settings.json");
|
|
20421
|
+
const file2 = claudeSettings(models, {
|
|
20422
|
+
baseUrl: baseUrl(ctx),
|
|
20423
|
+
discoveryMirrors: ctx.config().exposeClaudeCodeAliases,
|
|
20424
|
+
...key === undefined ? {} : { apiKey: key }
|
|
20425
|
+
}, mapping, setupFs.read(path) ?? undefined);
|
|
20426
|
+
finish(ctx, writer, [at(dir, file2)], dryRun2, key, setupFs.write);
|
|
20427
|
+
}
|
|
20428
|
+
};
|
|
20429
|
+
var setupOpencode = {
|
|
20430
|
+
usage: "setup opencode [--dir <path>] [--key <key>] [--dry-run]",
|
|
20431
|
+
summary: "Write an opencode.json provider entry for this gateway",
|
|
20432
|
+
options: OPTIONS,
|
|
20433
|
+
async run(args, { ctx, writer, prompt, setupFs }) {
|
|
20434
|
+
const models = await described(ctx);
|
|
20435
|
+
const dir = stringFlag(args.values, "dir") ?? setupFs.cwd;
|
|
20436
|
+
const key = stringFlag(args.values, "key");
|
|
20437
|
+
const dryRun2 = boolFlag(args.values, "dry-run");
|
|
20438
|
+
const mapping = await promptMapping(models, prompt);
|
|
20439
|
+
const file2 = opencodeConfig(models, {
|
|
20440
|
+
baseUrl: baseUrl(ctx),
|
|
20441
|
+
...key === undefined ? {} : { apiKey: key }
|
|
20442
|
+
}, mapping);
|
|
20443
|
+
finish(ctx, writer, [at(dir, file2)], dryRun2, key, setupFs.write);
|
|
20444
|
+
}
|
|
20445
|
+
};
|
|
20446
|
+
|
|
19724
20447
|
// apps/cli/src/commands/status.ts
|
|
19725
20448
|
var WINDOW_ORDER = {
|
|
19726
20449
|
fiveHour: 0,
|
|
@@ -19955,6 +20678,8 @@ var COMMANDS = {
|
|
|
19955
20678
|
"keys revoke": keysRevoke,
|
|
19956
20679
|
"settings get": settingsGet,
|
|
19957
20680
|
"settings set": settingsSet,
|
|
20681
|
+
"setup claude": setupClaude,
|
|
20682
|
+
"setup opencode": setupOpencode,
|
|
19958
20683
|
"admin set-password": adminSetPassword,
|
|
19959
20684
|
"db migrate": dbMigrate
|
|
19960
20685
|
};
|
|
@@ -20097,6 +20822,12 @@ function createPrompt(ctx, writer) {
|
|
|
20097
20822
|
const isTty = process.stdin.isTTY === true;
|
|
20098
20823
|
return {
|
|
20099
20824
|
isTty,
|
|
20825
|
+
async input(question) {
|
|
20826
|
+
if (!isTty)
|
|
20827
|
+
throw new CliError(`${question} \u2014 refusing without a terminal`);
|
|
20828
|
+
writer.err(question);
|
|
20829
|
+
return (await readLine()).trim();
|
|
20830
|
+
},
|
|
20100
20831
|
async secret(question) {
|
|
20101
20832
|
if (!isTty)
|
|
20102
20833
|
return (await readAllStdin()).trim();
|
|
@@ -20117,6 +20848,20 @@ function createPrompt(ctx, writer) {
|
|
|
20117
20848
|
};
|
|
20118
20849
|
}
|
|
20119
20850
|
|
|
20851
|
+
// apps/cli/src/setupFs.ts
|
|
20852
|
+
import { dirname as dirname2 } from "path";
|
|
20853
|
+
function atomicWriteFile(path, contents, ops) {
|
|
20854
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
20855
|
+
ops.mkdir(dirname2(path));
|
|
20856
|
+
try {
|
|
20857
|
+
ops.write(temporary, contents);
|
|
20858
|
+
ops.rename(temporary, path);
|
|
20859
|
+
} catch (error51) {
|
|
20860
|
+
ops.remove(temporary);
|
|
20861
|
+
throw error51;
|
|
20862
|
+
}
|
|
20863
|
+
}
|
|
20864
|
+
|
|
20120
20865
|
// apps/cli/src/run.ts
|
|
20121
20866
|
var VERSION = "0.0.0";
|
|
20122
20867
|
async function run(argv, writer, options = {}) {
|
|
@@ -20155,6 +20900,17 @@ async function run(argv, writer, options = {}) {
|
|
|
20155
20900
|
ctx,
|
|
20156
20901
|
writer,
|
|
20157
20902
|
prompt,
|
|
20903
|
+
setupFs: options.setupFs ?? {
|
|
20904
|
+
homeDir: homedir3(),
|
|
20905
|
+
cwd: process.cwd(),
|
|
20906
|
+
read: (path) => existsSync6(path) ? readFileSync3(path, "utf8") : null,
|
|
20907
|
+
write: (path, contents) => atomicWriteFile(path, contents, {
|
|
20908
|
+
mkdir: (directory) => mkdirSync2(directory, { recursive: true }),
|
|
20909
|
+
write: (temporary, data) => writeFileSync2(temporary, data),
|
|
20910
|
+
rename: renameSync,
|
|
20911
|
+
remove: (temporary) => rmSync2(temporary, { force: true })
|
|
20912
|
+
})
|
|
20913
|
+
},
|
|
20158
20914
|
service: () => options.service?.({ root: ctx.root.root, env: ctx.env }) ?? createServiceDeps({ root: ctx.root.root, env: ctx.env, scope, now: ctx.now }),
|
|
20159
20915
|
foreground: options.foreground ?? runForeground,
|
|
20160
20916
|
connect: (store) => options.connect?.(store) ?? createConnectFlows({
|