@jacobbd/relay-ai 0.6.3 → 0.7.1
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 +26 -0
- package/dist/{chunk-WHEMJ7C3.js → chunk-6CBNKM55.js} +877 -21
- package/dist/chunk-6CBNKM55.js.map +1 -0
- package/dist/{chunk-EJONCU3B.js → chunk-HXGZ4CTV.js} +13 -1
- package/dist/chunk-HXGZ4CTV.js.map +1 -0
- package/dist/cli.js +172 -671
- package/dist/cli.js.map +1 -1
- package/dist/core/index.d.ts +91 -0
- package/dist/core/index.js +1854 -0
- package/dist/core/index.js.map +1 -0
- package/dist/{provider-templates-BPGB5V2L.js → provider-templates-4H3C4DRL.js} +2 -2
- package/dist/ui/public/app.js +71 -15
- package/dist/ui/public/provider-model-browser.js +4 -1
- package/dist/ui/public/style.css +7 -0
- package/dist/{ui-command-AMF7XGFD.js → ui-command-S3TQKB3D.js} +32 -11
- package/dist/ui-command-S3TQKB3D.js.map +1 -0
- package/package.json +10 -2
- package/dist/chunk-EJONCU3B.js.map +0 -1
- package/dist/chunk-WHEMJ7C3.js.map +0 -1
- package/dist/ui-command-AMF7XGFD.js.map +0 -1
- /package/dist/{provider-templates-BPGB5V2L.js.map → provider-templates-4H3C4DRL.js.map} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getTemplateById,
|
|
4
4
|
init_provider_templates
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HXGZ4CTV.js";
|
|
6
6
|
|
|
7
7
|
// src/constants.ts
|
|
8
8
|
import { homedir } from "os";
|
|
@@ -11,7 +11,7 @@ import { join } from "path";
|
|
|
11
11
|
// package.json
|
|
12
12
|
var package_default = {
|
|
13
13
|
name: "@jacobbd/relay-ai",
|
|
14
|
-
version: "0.
|
|
14
|
+
version: "0.7.1",
|
|
15
15
|
publishConfig: {
|
|
16
16
|
access: "public"
|
|
17
17
|
},
|
|
@@ -46,7 +46,7 @@ var package_default = {
|
|
|
46
46
|
node: ">=18"
|
|
47
47
|
},
|
|
48
48
|
scripts: {
|
|
49
|
-
build: "tsup && node scripts/copy-ui-assets.mjs",
|
|
49
|
+
build: "tsup && tsup --config tsup.core.config.ts && node scripts/copy-ui-assets.mjs",
|
|
50
50
|
dev: "tsup --watch",
|
|
51
51
|
test: "vitest run",
|
|
52
52
|
"test:watch": "vitest",
|
|
@@ -100,6 +100,14 @@ var package_default = {
|
|
|
100
100
|
},
|
|
101
101
|
overrides: {
|
|
102
102
|
ws: "^8.21.0"
|
|
103
|
+
},
|
|
104
|
+
exports: {
|
|
105
|
+
"./core": {
|
|
106
|
+
types: "./dist/core/index.d.ts",
|
|
107
|
+
import: "./dist/core/index.js",
|
|
108
|
+
default: "./dist/core/index.js"
|
|
109
|
+
},
|
|
110
|
+
"./package.json": "./package.json"
|
|
103
111
|
}
|
|
104
112
|
};
|
|
105
113
|
|
|
@@ -149,6 +157,7 @@ var PARENT_SESSION_ENV_VARS = [
|
|
|
149
157
|
];
|
|
150
158
|
var OPENCODE_CACHE_PATH = join(homedir(), ".cache", "opencode", "models.json");
|
|
151
159
|
var MAX_MODEL_CATALOG = 20;
|
|
160
|
+
var MIN_CONTEXT_WINDOW = 128e3;
|
|
152
161
|
var VERTEX_ANTHROPIC_NPM = "@ai-sdk/google-vertex/anthropic";
|
|
153
162
|
function classifyModelFormat(modelId, providerNpm) {
|
|
154
163
|
if (providerNpm === "@ai-sdk/anthropic") return "anthropic";
|
|
@@ -1464,13 +1473,36 @@ function providerSelectOption(provider) {
|
|
|
1464
1473
|
}
|
|
1465
1474
|
function modelSelectOption(model, hint) {
|
|
1466
1475
|
const label = formatCodexModelLabel(model);
|
|
1467
|
-
|
|
1476
|
+
let defaultHint = hint;
|
|
1477
|
+
if (!defaultHint) {
|
|
1478
|
+
const isCloudflare = model.id.startsWith("@cf/") || model.id.startsWith("@hf/");
|
|
1479
|
+
if (model.isFree) {
|
|
1480
|
+
defaultHint = pc.green(isCloudflare ? "Free (10k/day)" : "Free");
|
|
1481
|
+
} else if (model.cost && (model.cost.input > 0 || model.cost.output > 0)) {
|
|
1482
|
+
const inputStr = `$${model.cost.input}`;
|
|
1483
|
+
const outputStr = `$${model.cost.output}`;
|
|
1484
|
+
defaultHint = pc.dim(isCloudflare ? `Paid plan req (${inputStr}/${outputStr} 1M)` : `${inputStr}/${outputStr} 1M`);
|
|
1485
|
+
} else {
|
|
1486
|
+
defaultHint = model.name !== model.id ? model.id : model.brand || model.family || "";
|
|
1487
|
+
}
|
|
1488
|
+
} else if (hint === "recent") {
|
|
1489
|
+
const isCloudflare = model.id.startsWith("@cf/") || model.id.startsWith("@hf/");
|
|
1490
|
+
const freeLabel = isCloudflare ? "Free (10k/day)" : "Free";
|
|
1491
|
+
const freeSuffix = model.isFree ? " \xB7 " + pc.green(freeLabel) : "";
|
|
1492
|
+
defaultHint = fmtRecentHint() + freeSuffix;
|
|
1493
|
+
}
|
|
1494
|
+
const ctxSuffix = fmtContextWindow(model.contextWindow);
|
|
1468
1495
|
return {
|
|
1469
1496
|
value: model.id,
|
|
1470
1497
|
label: fmtModel(label),
|
|
1471
|
-
hint:
|
|
1498
|
+
hint: defaultHint && ctxSuffix ? `${defaultHint} \xB7 ${ctxSuffix}` : defaultHint || ctxSuffix
|
|
1472
1499
|
};
|
|
1473
1500
|
}
|
|
1501
|
+
function fmtContextWindow(contextWindow) {
|
|
1502
|
+
if (!contextWindow) return "";
|
|
1503
|
+
const k = contextWindow >= 1e3 ? `${Math.round(contextWindow / 1e3)}k` : String(contextWindow);
|
|
1504
|
+
return pc.dim(`${k} ctx`);
|
|
1505
|
+
}
|
|
1474
1506
|
function navOption(value, label, hint = "") {
|
|
1475
1507
|
return { value, label: pc.cyan(label), hint };
|
|
1476
1508
|
}
|
|
@@ -3627,7 +3659,7 @@ function parseRegistry(raw) {
|
|
|
3627
3659
|
if (typeof data.pricingCacheAt === "string") registry.pricingCacheAt = data.pricingCacheAt;
|
|
3628
3660
|
return registry;
|
|
3629
3661
|
}
|
|
3630
|
-
function loadRegistry(path = getProvidersPath()) {
|
|
3662
|
+
function loadRegistry(path = getProvidersPath(), { persist = true } = {}) {
|
|
3631
3663
|
if (!existsSync6(path)) {
|
|
3632
3664
|
return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };
|
|
3633
3665
|
}
|
|
@@ -3638,7 +3670,7 @@ function loadRegistry(path = getProvidersPath()) {
|
|
|
3638
3670
|
if (migrateOAuthOpenAiProvider(registry)) migrated = true;
|
|
3639
3671
|
if (migrateOAuthXaiProvider(registry)) migrated = true;
|
|
3640
3672
|
if (migrateAlibabaDashScopeChinaLabel(registry)) migrated = true;
|
|
3641
|
-
if (migrated) {
|
|
3673
|
+
if (migrated && persist) {
|
|
3642
3674
|
try {
|
|
3643
3675
|
saveRegistry(registry, path);
|
|
3644
3676
|
} catch {
|
|
@@ -3681,6 +3713,7 @@ function isFreeProviderAccess(providerId, templateId) {
|
|
|
3681
3713
|
return FREE_PROVIDER_IDS.has((providerId ?? "").toLowerCase()) || FREE_PROVIDER_IDS.has((templateId ?? "").toLowerCase());
|
|
3682
3714
|
}
|
|
3683
3715
|
function classifyFreeStatus(opts) {
|
|
3716
|
+
if (opts.freeAccess === true) return "free_provider";
|
|
3684
3717
|
if (isFreeProviderAccess(opts.providerId, opts.templateId)) return "free_provider";
|
|
3685
3718
|
if (isZeroCost(opts.model.cost)) return "verified_free";
|
|
3686
3719
|
if (isPaidCost(opts.model.cost)) return "paid";
|
|
@@ -3842,7 +3875,12 @@ function enrichModelsWithPricing(models, index, platform) {
|
|
|
3842
3875
|
return models.map((model) => {
|
|
3843
3876
|
const cost = lookupModelCost(index, model.id, platform) ?? lookupModelCost(index, model.upstreamModelId, platform);
|
|
3844
3877
|
if (!cost) return model;
|
|
3845
|
-
const freeStatus = classifyFreeStatus({
|
|
3878
|
+
const freeStatus = classifyFreeStatus({
|
|
3879
|
+
model: { ...model, cost },
|
|
3880
|
+
// Keep provider-granted free access (e.g. Cloudflare's daily allowance) when
|
|
3881
|
+
// real pricing resolves later.
|
|
3882
|
+
freeAccess: model.freeStatus === "free_provider"
|
|
3883
|
+
});
|
|
3846
3884
|
return { ...model, cost, isFree: isFreeStatus(freeStatus), freeStatus };
|
|
3847
3885
|
});
|
|
3848
3886
|
}
|
|
@@ -7280,16 +7318,707 @@ function localProvidersToServerModels(localProviders) {
|
|
|
7280
7318
|
);
|
|
7281
7319
|
}
|
|
7282
7320
|
|
|
7321
|
+
// src/antigravity/slot-registry.ts
|
|
7322
|
+
var AGY_SLOT_VALIDATION_SOURCE = "AGY CLI 1.0.10 / Antigravity IDE 2.1.1 fixture capture 2026-06-23";
|
|
7323
|
+
var AGY_NATIVE_SLOT_REGISTRY = [
|
|
7324
|
+
{
|
|
7325
|
+
slotId: "gemini-3.5-flash-low",
|
|
7326
|
+
model: "MODEL_PLACEHOLDER_M20",
|
|
7327
|
+
role: "agent-switch",
|
|
7328
|
+
status: "validated",
|
|
7329
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7330
|
+
},
|
|
7331
|
+
{
|
|
7332
|
+
slotId: "gemini-3.5-flash-extra-low",
|
|
7333
|
+
model: "MODEL_PLACEHOLDER_M187",
|
|
7334
|
+
role: "agent-switch",
|
|
7335
|
+
status: "validated",
|
|
7336
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7337
|
+
},
|
|
7338
|
+
{
|
|
7339
|
+
slotId: "gemini-3.1-pro-low",
|
|
7340
|
+
model: "MODEL_PLACEHOLDER_M36",
|
|
7341
|
+
role: "agent-switch",
|
|
7342
|
+
status: "validated",
|
|
7343
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7344
|
+
},
|
|
7345
|
+
{
|
|
7346
|
+
slotId: "gemini-pro-agent",
|
|
7347
|
+
model: "MODEL_PLACEHOLDER_M16",
|
|
7348
|
+
role: "agent-switch",
|
|
7349
|
+
status: "validated",
|
|
7350
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7351
|
+
},
|
|
7352
|
+
{
|
|
7353
|
+
slotId: "claude-sonnet-4-6",
|
|
7354
|
+
model: "MODEL_PLACEHOLDER_M35",
|
|
7355
|
+
role: "agent-switch",
|
|
7356
|
+
status: "validated",
|
|
7357
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7358
|
+
},
|
|
7359
|
+
{
|
|
7360
|
+
slotId: "claude-opus-4-6-thinking",
|
|
7361
|
+
model: "MODEL_PLACEHOLDER_M26",
|
|
7362
|
+
role: "agent-switch",
|
|
7363
|
+
status: "validated",
|
|
7364
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7365
|
+
},
|
|
7366
|
+
{
|
|
7367
|
+
slotId: "gpt-oss-120b-medium",
|
|
7368
|
+
model: "MODEL_OPENAI_GPT_OSS_120B_MEDIUM",
|
|
7369
|
+
role: "agent-switch",
|
|
7370
|
+
status: "validated",
|
|
7371
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7372
|
+
},
|
|
7373
|
+
{
|
|
7374
|
+
slotId: "gemini-3-flash-agent",
|
|
7375
|
+
model: "MODEL_PLACEHOLDER_M132",
|
|
7376
|
+
role: "cascade-plan",
|
|
7377
|
+
status: "reserved",
|
|
7378
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7379
|
+
notes: "Visible in agentModelSorts, but reserved for cascade plan construction."
|
|
7380
|
+
},
|
|
7381
|
+
{
|
|
7382
|
+
slotId: "gemini-2.5-flash",
|
|
7383
|
+
model: "MODEL_GOOGLE_GEMINI_2_5_FLASH",
|
|
7384
|
+
role: "cascade-intent",
|
|
7385
|
+
status: "reserved",
|
|
7386
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7387
|
+
},
|
|
7388
|
+
{
|
|
7389
|
+
slotId: "gemini-2.5-flash-lite",
|
|
7390
|
+
model: "MODEL_GOOGLE_GEMINI_2_5_FLASH_LITE",
|
|
7391
|
+
role: "cascade-fallback",
|
|
7392
|
+
status: "reserved",
|
|
7393
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7394
|
+
},
|
|
7395
|
+
{
|
|
7396
|
+
slotId: "gemini-3.1-pro-high",
|
|
7397
|
+
model: "MODEL_PLACEHOLDER_M37",
|
|
7398
|
+
role: "agent-switch",
|
|
7399
|
+
status: "candidate",
|
|
7400
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7401
|
+
notes: "Model-shaped fixture entry; requires live switching proof before promotion."
|
|
7402
|
+
},
|
|
7403
|
+
{
|
|
7404
|
+
slotId: "gemini-2.5-pro",
|
|
7405
|
+
model: "MODEL_GOOGLE_GEMINI_2_5_PRO",
|
|
7406
|
+
role: "agent-switch",
|
|
7407
|
+
status: "candidate",
|
|
7408
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7409
|
+
notes: "Model-shaped fixture entry; requires live switching proof before promotion."
|
|
7410
|
+
},
|
|
7411
|
+
{
|
|
7412
|
+
slotId: "gemini-2.5-flash-thinking",
|
|
7413
|
+
model: "MODEL_GOOGLE_GEMINI_2_5_FLASH_THINKING",
|
|
7414
|
+
role: "agent-switch",
|
|
7415
|
+
status: "candidate",
|
|
7416
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7417
|
+
notes: "Model-shaped fixture entry; requires live switching proof before promotion."
|
|
7418
|
+
},
|
|
7419
|
+
{
|
|
7420
|
+
slotId: "gemini-3-flash",
|
|
7421
|
+
model: "MODEL_PLACEHOLDER_M18",
|
|
7422
|
+
role: "command",
|
|
7423
|
+
status: "candidate",
|
|
7424
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7425
|
+
notes: "Command model in the fixture; not switch-safe without live proof."
|
|
7426
|
+
},
|
|
7427
|
+
{
|
|
7428
|
+
slotId: "gemini-3.1-flash-lite",
|
|
7429
|
+
model: "MODEL_PLACEHOLDER_M50",
|
|
7430
|
+
role: "cascade-checkpoint",
|
|
7431
|
+
status: "candidate",
|
|
7432
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7433
|
+
notes: "Checkpoint/search/commit slot; route as helper until live proof exists."
|
|
7434
|
+
},
|
|
7435
|
+
{
|
|
7436
|
+
slotId: "gemini-3.1-flash-image",
|
|
7437
|
+
model: "MODEL_PLACEHOLDER_M21",
|
|
7438
|
+
role: "image",
|
|
7439
|
+
status: "candidate",
|
|
7440
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE,
|
|
7441
|
+
notes: "Image generation slot; not switch-safe without live proof."
|
|
7442
|
+
},
|
|
7443
|
+
{
|
|
7444
|
+
slotId: "tab_jump_flash_lite_preview",
|
|
7445
|
+
model: "MODEL_PLACEHOLDER_M28",
|
|
7446
|
+
role: "tab",
|
|
7447
|
+
status: "unsafe",
|
|
7448
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7449
|
+
},
|
|
7450
|
+
{
|
|
7451
|
+
slotId: "tab_flash_lite_preview",
|
|
7452
|
+
model: "MODEL_PLACEHOLDER_M19",
|
|
7453
|
+
role: "tab",
|
|
7454
|
+
status: "unsafe",
|
|
7455
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7456
|
+
},
|
|
7457
|
+
{
|
|
7458
|
+
slotId: "chat_20706",
|
|
7459
|
+
model: "MODEL_CHAT_20706",
|
|
7460
|
+
role: "chat",
|
|
7461
|
+
status: "unsafe",
|
|
7462
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7463
|
+
},
|
|
7464
|
+
{
|
|
7465
|
+
slotId: "chat_23310",
|
|
7466
|
+
model: "MODEL_CHAT_23310",
|
|
7467
|
+
role: "chat",
|
|
7468
|
+
status: "unsafe",
|
|
7469
|
+
validatedWith: AGY_SLOT_VALIDATION_SOURCE
|
|
7470
|
+
}
|
|
7471
|
+
];
|
|
7472
|
+
var KNOWN_COMPATIBLE_AGY_VERSIONS = /* @__PURE__ */ new Set([
|
|
7473
|
+
"1.0.10",
|
|
7474
|
+
"1.1.0",
|
|
7475
|
+
"1.1.1",
|
|
7476
|
+
"1.1.2",
|
|
7477
|
+
"1.1.3",
|
|
7478
|
+
"1.1.4",
|
|
7479
|
+
"1.1.5",
|
|
7480
|
+
"1.1.6",
|
|
7481
|
+
"1.1.7"
|
|
7482
|
+
]);
|
|
7483
|
+
var KNOWN_INCOMPATIBLE_AGY_VERSIONS = /* @__PURE__ */ new Set(["1.0.9"]);
|
|
7484
|
+
function withFixtureModel(definition, model) {
|
|
7485
|
+
return model === definition.model ? definition : { ...definition, model };
|
|
7486
|
+
}
|
|
7487
|
+
function assertNoDuplicateSwitchEnums(fixture, definitions) {
|
|
7488
|
+
const seen = /* @__PURE__ */ new Map();
|
|
7489
|
+
for (const definition of definitions) {
|
|
7490
|
+
if (definition.status !== "validated") continue;
|
|
7491
|
+
const actualModel = fixture.models[definition.slotId]?.model;
|
|
7492
|
+
if (!actualModel) continue;
|
|
7493
|
+
const previousSlotId = seen.get(actualModel);
|
|
7494
|
+
if (previousSlotId) {
|
|
7495
|
+
throw new Error(
|
|
7496
|
+
`Duplicate AGY switch slot enum ${actualModel}: ${previousSlotId} and ${definition.slotId}`
|
|
7497
|
+
);
|
|
7498
|
+
}
|
|
7499
|
+
seen.set(actualModel, definition.slotId);
|
|
7500
|
+
}
|
|
7501
|
+
}
|
|
7502
|
+
function validateAgySlotRegistry(fixture) {
|
|
7503
|
+
assertNoDuplicateSwitchEnums(fixture, AGY_NATIVE_SLOT_REGISTRY);
|
|
7504
|
+
const switchSlots = [];
|
|
7505
|
+
const reservedSlots = [];
|
|
7506
|
+
const candidateSlots = [];
|
|
7507
|
+
const warnings = [];
|
|
7508
|
+
for (const definition of AGY_NATIVE_SLOT_REGISTRY) {
|
|
7509
|
+
const entry = fixture.models[definition.slotId];
|
|
7510
|
+
if (!entry) {
|
|
7511
|
+
if (definition.status === "validated" || definition.status === "reserved") {
|
|
7512
|
+
warnings.push(`AGY slot ${definition.slotId} missing from fixture`);
|
|
7513
|
+
}
|
|
7514
|
+
continue;
|
|
7515
|
+
}
|
|
7516
|
+
if (entry.model !== definition.model) {
|
|
7517
|
+
warnings.push(
|
|
7518
|
+
`AGY slot ${definition.slotId} expected ${definition.model} but fixture has ${entry.model}`
|
|
7519
|
+
);
|
|
7520
|
+
continue;
|
|
7521
|
+
}
|
|
7522
|
+
if (definition.status === "validated") {
|
|
7523
|
+
switchSlots.push(withFixtureModel(definition, entry.model));
|
|
7524
|
+
} else if (definition.status === "reserved") {
|
|
7525
|
+
reservedSlots.push(withFixtureModel(definition, entry.model));
|
|
7526
|
+
} else if (definition.status === "candidate") {
|
|
7527
|
+
candidateSlots.push(withFixtureModel(definition, entry.model));
|
|
7528
|
+
}
|
|
7529
|
+
}
|
|
7530
|
+
return { switchSlots, reservedSlots, candidateSlots, warnings };
|
|
7531
|
+
}
|
|
7532
|
+
function getValidatedAgySwitchSlots(fixture) {
|
|
7533
|
+
return validateAgySlotRegistry(fixture).switchSlots;
|
|
7534
|
+
}
|
|
7535
|
+
function evaluateAgySwitchCompatibility(opts) {
|
|
7536
|
+
const validation = validateAgySlotRegistry(opts.fixture);
|
|
7537
|
+
const shapeMatches = validation.warnings.length === 0 && validation.switchSlots.length > 0;
|
|
7538
|
+
const warnings = [];
|
|
7539
|
+
if (opts.versionReadError) {
|
|
7540
|
+
warnings.push(`Could not read agy --version (${opts.versionReadError}); validating AGY fixture shape instead.`);
|
|
7541
|
+
}
|
|
7542
|
+
if (opts.version && KNOWN_INCOMPATIBLE_AGY_VERSIONS.has(opts.version)) {
|
|
7543
|
+
return {
|
|
7544
|
+
mode: "single-model",
|
|
7545
|
+
validatedSwitchSlotCount: validation.switchSlots.length,
|
|
7546
|
+
warnings: [
|
|
7547
|
+
...warnings,
|
|
7548
|
+
`Known-incompatible AGY version ${opts.version}; falling back to single-model mode.`
|
|
7549
|
+
]
|
|
7550
|
+
};
|
|
7551
|
+
}
|
|
7552
|
+
if (!shapeMatches) {
|
|
7553
|
+
return {
|
|
7554
|
+
mode: "single-model",
|
|
7555
|
+
validatedSwitchSlotCount: validation.switchSlots.length,
|
|
7556
|
+
warnings: [
|
|
7557
|
+
...warnings,
|
|
7558
|
+
...validation.warnings,
|
|
7559
|
+
"AGY fixture shape does not match the validated slot registry; falling back to single-model mode."
|
|
7560
|
+
]
|
|
7561
|
+
};
|
|
7562
|
+
}
|
|
7563
|
+
if (opts.version && !KNOWN_COMPATIBLE_AGY_VERSIONS.has(opts.version)) {
|
|
7564
|
+
return {
|
|
7565
|
+
mode: "single-model",
|
|
7566
|
+
validatedSwitchSlotCount: validation.switchSlots.length,
|
|
7567
|
+
warnings: [
|
|
7568
|
+
...warnings,
|
|
7569
|
+
`Unvalidated AGY version ${opts.version}; falling back to single-model mode for maximum stability.`
|
|
7570
|
+
]
|
|
7571
|
+
};
|
|
7572
|
+
} else if (!opts.version && !opts.versionReadError) {
|
|
7573
|
+
warnings.push("AGY version is unknown; fixture shape matches, so multi-model switching remains enabled.");
|
|
7574
|
+
}
|
|
7575
|
+
return {
|
|
7576
|
+
mode: "multi-model",
|
|
7577
|
+
validatedSwitchSlotCount: validation.switchSlots.length,
|
|
7578
|
+
warnings
|
|
7579
|
+
};
|
|
7580
|
+
}
|
|
7581
|
+
|
|
7582
|
+
// src/antigravity/catalog.ts
|
|
7583
|
+
var RELAY_CASCADE_PLAN_MODEL = "MODEL_PLACEHOLDER_M132";
|
|
7584
|
+
var RELAY_AGENT_PLACEHOLDER = "MODEL_PLACEHOLDER_M20";
|
|
7585
|
+
var RELAY_CASCADE_CHECKPOINT_MODEL = "MODEL_PLACEHOLDER_M50";
|
|
7586
|
+
var RELAY_CASCADE_INTENT_MODEL = "MODEL_GOOGLE_GEMINI_2_5_FLASH";
|
|
7587
|
+
var RELAY_CASCADE_ANCHOR_ID = "gemini-3.5-flash-low";
|
|
7588
|
+
var RELAY_CASCADE_PLAN_ANCHOR_ID = "gemini-3-flash-agent";
|
|
7589
|
+
var RELAY_CASCADE_FALLBACK_ID = "gemini-2.5-flash-lite";
|
|
7590
|
+
var RELAY_CASCADE_INTENT_MODEL_ID = "gemini-2.5-flash";
|
|
7591
|
+
function withCascadeCheckpointer(entry, maxTokenLimit = 128e3) {
|
|
7592
|
+
const tokenThreshold = Math.min(5e4, Math.floor(maxTokenLimit * 0.75));
|
|
7593
|
+
const existingModelExperiments = entry.modelExperiments;
|
|
7594
|
+
entry.modelExperiments = {
|
|
7595
|
+
...existingModelExperiments,
|
|
7596
|
+
experiments: {
|
|
7597
|
+
...existingModelExperiments?.experiments ?? {},
|
|
7598
|
+
CASCADE_USE_EXPERIMENT_CHECKPOINTER: {
|
|
7599
|
+
stringValue: JSON.stringify({
|
|
7600
|
+
strategy: "CHECKPOINT_STRATEGY_SAME_MODEL",
|
|
7601
|
+
max_token_limit: String(maxTokenLimit),
|
|
7602
|
+
token_threshold: String(tokenThreshold),
|
|
7603
|
+
max_overhead_ratio: "0.15",
|
|
7604
|
+
moving_window_size: "1",
|
|
7605
|
+
enabled: true,
|
|
7606
|
+
max_output_tokens: "16384",
|
|
7607
|
+
checkpoint_model: RELAY_CASCADE_CHECKPOINT_MODEL,
|
|
7608
|
+
use_last_planner_model: true,
|
|
7609
|
+
is_sync: true,
|
|
7610
|
+
max_user_requests: 10,
|
|
7611
|
+
include_last_user_message: true,
|
|
7612
|
+
include_conversation_log: false,
|
|
7613
|
+
include_running_task_snapshots: true,
|
|
7614
|
+
include_subagent_snapshots: true,
|
|
7615
|
+
include_artifact_snapshots: true,
|
|
7616
|
+
retry_config: {
|
|
7617
|
+
max_retries: 0,
|
|
7618
|
+
initial_sleep_duration_ms: 1e3,
|
|
7619
|
+
exponential_multiplier: 2,
|
|
7620
|
+
include_error_feedback: false
|
|
7621
|
+
}
|
|
7622
|
+
})
|
|
7623
|
+
}
|
|
7624
|
+
}
|
|
7625
|
+
};
|
|
7626
|
+
return entry;
|
|
7627
|
+
}
|
|
7628
|
+
var ANTIGRAVITY_REQUIRED_INPUT_TOKENS = 128e3;
|
|
7629
|
+
var ANTIGRAVITY_MIN_OUTPUT_TOKENS = 8192;
|
|
7630
|
+
var ANTIGRAVITY_MIN_CONTEXT_WINDOW = ANTIGRAVITY_REQUIRED_INPUT_TOKENS + ANTIGRAVITY_MIN_OUTPUT_TOKENS;
|
|
7631
|
+
function applyRouteContextBounds(entry, route) {
|
|
7632
|
+
const maxTokenLimit = route.contextWindow ?? 128e3;
|
|
7633
|
+
const maxOutputTokens = Math.min(
|
|
7634
|
+
entry.maxOutputTokens ?? 65536,
|
|
7635
|
+
Math.max(
|
|
7636
|
+
ANTIGRAVITY_MIN_OUTPUT_TOKENS,
|
|
7637
|
+
maxTokenLimit - ANTIGRAVITY_REQUIRED_INPUT_TOKENS
|
|
7638
|
+
)
|
|
7639
|
+
);
|
|
7640
|
+
const checkpointTokenLimit = Math.min(
|
|
7641
|
+
128e3,
|
|
7642
|
+
Math.max(1, maxTokenLimit - maxOutputTokens)
|
|
7643
|
+
);
|
|
7644
|
+
entry.maxTokens = maxTokenLimit;
|
|
7645
|
+
entry.maxOutputTokens = maxOutputTokens;
|
|
7646
|
+
return withCascadeCheckpointer(entry, checkpointTokenLimit);
|
|
7647
|
+
}
|
|
7648
|
+
var RELAY_CASCADE_FALLBACK_ENTRY = withCascadeCheckpointer({
|
|
7649
|
+
displayName: "Gemini 3.1 Flash Lite",
|
|
7650
|
+
model: "MODEL_GOOGLE_GEMINI_2_5_FLASH_LITE",
|
|
7651
|
+
apiProvider: "API_PROVIDER_GOOGLE_GEMINI",
|
|
7652
|
+
modelProvider: "MODEL_PROVIDER_GOOGLE",
|
|
7653
|
+
tokenizerType: "LLAMA_WITH_SPECIAL",
|
|
7654
|
+
maxTokens: 1048576,
|
|
7655
|
+
maxOutputTokens: 65535,
|
|
7656
|
+
quotaInfo: { remainingFraction: 1 }
|
|
7657
|
+
});
|
|
7658
|
+
var RELAY_CASCADE_INTENT_MODEL_ENTRY = withCascadeCheckpointer({
|
|
7659
|
+
...RELAY_CASCADE_FALLBACK_ENTRY,
|
|
7660
|
+
model: RELAY_CASCADE_INTENT_MODEL
|
|
7661
|
+
});
|
|
7662
|
+
function planRelayCatalogSlots(catalog, routes, templateKey) {
|
|
7663
|
+
const validation = validateAgySlotRegistry(catalog);
|
|
7664
|
+
const switchSlots = getValidatedAgySwitchSlots(catalog);
|
|
7665
|
+
const templateSlot = switchSlots.find((slot) => slot.slotId === templateKey);
|
|
7666
|
+
const orderedSlots = templateSlot ? [templateSlot, ...switchSlots.filter((slot) => slot.slotId !== templateKey)] : switchSlots;
|
|
7667
|
+
if (routes.length > 0 && orderedSlots.length === 0) {
|
|
7668
|
+
throw new Error("No validated AGY switch slots are available for the selected launch route");
|
|
7669
|
+
}
|
|
7670
|
+
const switchableRoutes = routes.slice(0, orderedSlots.length);
|
|
7671
|
+
const skippedRoutes = routes.slice(orderedSlots.length);
|
|
7672
|
+
const slots = switchableRoutes.map((route, index) => ({
|
|
7673
|
+
slotId: orderedSlots[index].slotId,
|
|
7674
|
+
route
|
|
7675
|
+
}));
|
|
7676
|
+
return {
|
|
7677
|
+
slots,
|
|
7678
|
+
switchableRoutes,
|
|
7679
|
+
skippedRoutes,
|
|
7680
|
+
validation
|
|
7681
|
+
};
|
|
7682
|
+
}
|
|
7683
|
+
function resolveRelayCatalogSlots(catalog, routes, templateKey) {
|
|
7684
|
+
return planRelayCatalogSlots(catalog, routes, templateKey).slots;
|
|
7685
|
+
}
|
|
7686
|
+
function buildRelayCatalogEntry(route, template) {
|
|
7687
|
+
const entry = structuredClone(template);
|
|
7688
|
+
entry.displayName = route.displayName;
|
|
7689
|
+
entry.model = template.model ?? RELAY_AGENT_PLACEHOLDER;
|
|
7690
|
+
entry.requestedModelId = route.catalogId;
|
|
7691
|
+
entry.modelVersion = route.catalogId;
|
|
7692
|
+
entry.modelVersionId = route.catalogId;
|
|
7693
|
+
entry.quotaInfo = { remainingFraction: 1, resetTime: "2026-06-23T02:00:57Z" };
|
|
7694
|
+
return applyRouteContextBounds(entry, route);
|
|
7695
|
+
}
|
|
7696
|
+
function buildRelayCatalogSlotEntry(route, template) {
|
|
7697
|
+
const entry = structuredClone(template);
|
|
7698
|
+
entry.displayName = route.displayName;
|
|
7699
|
+
entry.quotaInfo = { remainingFraction: 1, resetTime: "2026-06-23T02:00:57Z" };
|
|
7700
|
+
delete entry.requestedModelId;
|
|
7701
|
+
delete entry.modelVersion;
|
|
7702
|
+
delete entry.modelVersionId;
|
|
7703
|
+
delete entry.isInternal;
|
|
7704
|
+
return applyRouteContextBounds(entry, route);
|
|
7705
|
+
}
|
|
7706
|
+
function injectRelayModels(fixture, routes, templateKey) {
|
|
7707
|
+
const result = structuredClone(fixture);
|
|
7708
|
+
const template = fixture.models[templateKey];
|
|
7709
|
+
if (!template) {
|
|
7710
|
+
throw new Error(`Template model "${templateKey}" not found in catalog fixture`);
|
|
7711
|
+
}
|
|
7712
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7713
|
+
for (const route of routes) {
|
|
7714
|
+
if (seen.has(route.catalogId)) {
|
|
7715
|
+
throw new Error(`Catalog ID collision: ${route.catalogId}`);
|
|
7716
|
+
}
|
|
7717
|
+
if (fixture.models[route.catalogId]) {
|
|
7718
|
+
throw new Error(`Catalog ID collision with native model: ${route.catalogId}`);
|
|
7719
|
+
}
|
|
7720
|
+
seen.add(route.catalogId);
|
|
7721
|
+
}
|
|
7722
|
+
if (routes.length > 0) {
|
|
7723
|
+
result.models[RELAY_CASCADE_ANCHOR_ID] ??= structuredClone(template);
|
|
7724
|
+
result.models[RELAY_CASCADE_FALLBACK_ID] ??= structuredClone(RELAY_CASCADE_FALLBACK_ENTRY);
|
|
7725
|
+
result.models[RELAY_CASCADE_INTENT_MODEL_ID] ??= structuredClone(RELAY_CASCADE_INTENT_MODEL_ENTRY);
|
|
7726
|
+
if (!result.models[RELAY_CASCADE_PLAN_ANCHOR_ID]) {
|
|
7727
|
+
const planAnchor = withCascadeCheckpointer(structuredClone(template));
|
|
7728
|
+
planAnchor.model = RELAY_CASCADE_PLAN_MODEL;
|
|
7729
|
+
result.models[RELAY_CASCADE_PLAN_ANCHOR_ID] = planAnchor;
|
|
7730
|
+
}
|
|
7731
|
+
const slotPlan = planRelayCatalogSlots(result, routes, templateKey);
|
|
7732
|
+
const slots = slotPlan.slots;
|
|
7733
|
+
for (const { slotId, route } of slots) {
|
|
7734
|
+
const slotTemplate = result.models[slotId] ?? template;
|
|
7735
|
+
if (result.models[slotId]) {
|
|
7736
|
+
result.models[slotId] = buildRelayCatalogSlotEntry(route, slotTemplate);
|
|
7737
|
+
}
|
|
7738
|
+
result.models[route.catalogId] = buildRelayCatalogEntry(route, slotTemplate);
|
|
7739
|
+
}
|
|
7740
|
+
result.defaultAgentModelId = slots[0]?.slotId ?? RELAY_CASCADE_ANCHOR_ID;
|
|
7741
|
+
result.agentModelSorts = [
|
|
7742
|
+
{
|
|
7743
|
+
displayName: "Recommended",
|
|
7744
|
+
groups: [{
|
|
7745
|
+
modelIds: slots.map((slot) => slot.slotId)
|
|
7746
|
+
}]
|
|
7747
|
+
}
|
|
7748
|
+
];
|
|
7749
|
+
return result;
|
|
7750
|
+
}
|
|
7751
|
+
if (!result.agentModelSorts?.[0]?.groups?.[0]) {
|
|
7752
|
+
result.agentModelSorts = [
|
|
7753
|
+
{
|
|
7754
|
+
displayName: "Recommended",
|
|
7755
|
+
groups: [{ modelIds: [] }]
|
|
7756
|
+
}
|
|
7757
|
+
];
|
|
7758
|
+
}
|
|
7759
|
+
return result;
|
|
7760
|
+
}
|
|
7761
|
+
function buildAntigravityRoutes(resolvedFavorites, maxRoutes = MAX_MODEL_CATALOG) {
|
|
7762
|
+
const routes = [];
|
|
7763
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7764
|
+
for (const fav of resolvedFavorites) {
|
|
7765
|
+
if (routes.length >= maxRoutes) break;
|
|
7766
|
+
const favModel = fav.model;
|
|
7767
|
+
const modelId = favModel.id;
|
|
7768
|
+
const safeModelSlug = modelId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7769
|
+
const catalogId = `relay-ai__${fav.providerId}__${safeModelSlug}`;
|
|
7770
|
+
if (seen.has(catalogId)) continue;
|
|
7771
|
+
seen.add(catalogId);
|
|
7772
|
+
const npm = favModel.npm || "@ai-sdk/openai-compatible";
|
|
7773
|
+
const upstreamModelId2 = favModel.upstreamModelId || modelId;
|
|
7774
|
+
const baseURL = favModel.apiBaseUrl || favModel.completionsUrl || void 0;
|
|
7775
|
+
const contextWindow = favModel.contextWindow;
|
|
7776
|
+
const modelFormat = favModel.modelFormat;
|
|
7777
|
+
routes.push({
|
|
7778
|
+
catalogId,
|
|
7779
|
+
providerId: fav.providerId,
|
|
7780
|
+
providerName: fav.providerName,
|
|
7781
|
+
modelId,
|
|
7782
|
+
upstreamModelId: upstreamModelId2,
|
|
7783
|
+
displayName: `${favModel.name} (Relay)`,
|
|
7784
|
+
...modelFormat ? { modelFormat } : {},
|
|
7785
|
+
npm,
|
|
7786
|
+
apiKey: fav.apiKey,
|
|
7787
|
+
...fav.authType ? { authType: fav.authType } : {},
|
|
7788
|
+
...fav.oauthAccountId ? { oauthAccountId: fav.oauthAccountId } : {},
|
|
7789
|
+
...fav.providerData ? { providerData: fav.providerData } : {},
|
|
7790
|
+
baseURL,
|
|
7791
|
+
contextWindow
|
|
7792
|
+
});
|
|
7793
|
+
}
|
|
7794
|
+
return applyUniqueAntigravityRouteLabels(routes);
|
|
7795
|
+
}
|
|
7796
|
+
function routeBaseModelName(route) {
|
|
7797
|
+
const relayMatch = route.displayName.match(/^(.*) \(Relay(?: - .*)?\)$/);
|
|
7798
|
+
return relayMatch?.[1] ?? route.displayName;
|
|
7799
|
+
}
|
|
7800
|
+
function authKindLabel(route) {
|
|
7801
|
+
if (route.authType === "oauth") return "OAuth";
|
|
7802
|
+
if (route.authType === "api") return "API key";
|
|
7803
|
+
if (route.authType === "none") return "local";
|
|
7804
|
+
return "provider";
|
|
7805
|
+
}
|
|
7806
|
+
function duplicateCounts(values) {
|
|
7807
|
+
const counts = /* @__PURE__ */ new Map();
|
|
7808
|
+
for (const value of values) {
|
|
7809
|
+
counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
7810
|
+
}
|
|
7811
|
+
return counts;
|
|
7812
|
+
}
|
|
7813
|
+
function assertUniqueRouteDisplayNames(routes) {
|
|
7814
|
+
const counts = duplicateCounts(routes.map((route) => route.displayName));
|
|
7815
|
+
const duplicate = [...counts.entries()].find(([, count]) => count > 1);
|
|
7816
|
+
if (duplicate) {
|
|
7817
|
+
throw new Error(`Duplicate AGY model label after disambiguation: ${duplicate[0]}`);
|
|
7818
|
+
}
|
|
7819
|
+
}
|
|
7820
|
+
function applyUniqueAntigravityRouteLabels(routes) {
|
|
7821
|
+
const baseNames = routes.map(routeBaseModelName);
|
|
7822
|
+
const baseNameCounts = duplicateCounts(baseNames);
|
|
7823
|
+
const upstreamCounts = duplicateCounts(routes.map((route) => route.upstreamModelId));
|
|
7824
|
+
const providerNameCounts = duplicateCounts(routes.map((route) => route.providerName));
|
|
7825
|
+
const labeled = routes.map((route, index) => {
|
|
7826
|
+
const baseName = baseNames[index];
|
|
7827
|
+
const needsSuffix = (baseNameCounts.get(baseName) ?? 0) > 1 || (upstreamCounts.get(route.upstreamModelId) ?? 0) > 1;
|
|
7828
|
+
if (!needsSuffix) {
|
|
7829
|
+
return { ...route, displayName: `${baseName} (Relay)` };
|
|
7830
|
+
}
|
|
7831
|
+
const providerName = route.providerName || route.providerId;
|
|
7832
|
+
const providerSuffix = (providerNameCounts.get(providerName) ?? 0) > 1 ? `${providerName} ${authKindLabel(route)}` : providerName;
|
|
7833
|
+
return {
|
|
7834
|
+
...route,
|
|
7835
|
+
displayName: `${baseName} (Relay - ${providerSuffix})`
|
|
7836
|
+
};
|
|
7837
|
+
});
|
|
7838
|
+
const firstPassCounts = duplicateCounts(labeled.map((route) => route.displayName));
|
|
7839
|
+
const withProviderIds = labeled.map((route) => {
|
|
7840
|
+
if ((firstPassCounts.get(route.displayName) ?? 0) <= 1) return route;
|
|
7841
|
+
return {
|
|
7842
|
+
...route,
|
|
7843
|
+
displayName: route.displayName.replace(/\)$/, ` - ${route.providerId})`)
|
|
7844
|
+
};
|
|
7845
|
+
});
|
|
7846
|
+
assertUniqueRouteDisplayNames(withProviderIds);
|
|
7847
|
+
return withProviderIds;
|
|
7848
|
+
}
|
|
7849
|
+
function routeLabels(routes) {
|
|
7850
|
+
assertUniqueRouteDisplayNames(routes);
|
|
7851
|
+
const labels = /* @__PURE__ */ new Map();
|
|
7852
|
+
for (const route of routes) {
|
|
7853
|
+
labels.set(route.catalogId, route.displayName);
|
|
7854
|
+
}
|
|
7855
|
+
return labels;
|
|
7856
|
+
}
|
|
7857
|
+
function buildClientModelConfigData(routes, catalog, templateKey = RELAY_CASCADE_ANCHOR_ID, precomputedSlots) {
|
|
7858
|
+
const catalogRoutes = routes.slice(0, MAX_MODEL_CATALOG);
|
|
7859
|
+
const slots = precomputedSlots ?? (catalog ? resolveRelayCatalogSlots(catalog, catalogRoutes, templateKey) : catalogRoutes.map((route) => ({ slotId: route.catalogId, route })));
|
|
7860
|
+
const labels = routeLabels(catalogRoutes);
|
|
7861
|
+
const clientModelConfigs = slots.map(({ slotId, route }) => {
|
|
7862
|
+
const entry = catalog?.models[slotId] ?? catalog?.models[route.catalogId] ?? catalog?.models[RELAY_CASCADE_ANCHOR_ID];
|
|
7863
|
+
const label = labels.get(route.catalogId) ?? route.displayName;
|
|
7864
|
+
return {
|
|
7865
|
+
label,
|
|
7866
|
+
modelOrAlias: {
|
|
7867
|
+
alias: slotId,
|
|
7868
|
+
choice: { case: "alias", value: slotId }
|
|
7869
|
+
},
|
|
7870
|
+
disabled: false,
|
|
7871
|
+
supportedMimeTypes: entry?.supportedMimeTypes ?? {},
|
|
7872
|
+
quotaInfo: entry?.quotaInfo ?? { remainingFraction: 1 },
|
|
7873
|
+
tagTitle: entry?.tagTitle,
|
|
7874
|
+
tagDescription: entry?.tagDescription,
|
|
7875
|
+
supportsThoughtCirculation: entry?.supportsThoughtCirculation ?? false
|
|
7876
|
+
};
|
|
7877
|
+
});
|
|
7878
|
+
return {
|
|
7879
|
+
clientModelConfigs,
|
|
7880
|
+
clientModelSorts: [
|
|
7881
|
+
{
|
|
7882
|
+
name: "Recommended",
|
|
7883
|
+
groups: [
|
|
7884
|
+
{
|
|
7885
|
+
groupName: "",
|
|
7886
|
+
modelLabels: clientModelConfigs.map((config) => config.label)
|
|
7887
|
+
}
|
|
7888
|
+
]
|
|
7889
|
+
}
|
|
7890
|
+
],
|
|
7891
|
+
defaultOverrideModelConfig: clientModelConfigs[0] ?? {}
|
|
7892
|
+
};
|
|
7893
|
+
}
|
|
7894
|
+
function buildListModelConfigsResponse(routes, catalog, templateKey = RELAY_CASCADE_ANCHOR_ID) {
|
|
7895
|
+
const catalogRoutes = routes.slice(0, MAX_MODEL_CATALOG);
|
|
7896
|
+
const slots = catalog ? resolveRelayCatalogSlots(catalog, catalogRoutes, templateKey) : catalogRoutes.map((route) => ({ slotId: route.catalogId, route }));
|
|
7897
|
+
const config = slots.map(({ slotId }) => ({
|
|
7898
|
+
requestedModelId: slotId,
|
|
7899
|
+
planModel: RELAY_CASCADE_PLAN_MODEL,
|
|
7900
|
+
requestedModel: catalog?.models[slotId]?.model ?? RELAY_AGENT_PLACEHOLDER
|
|
7901
|
+
}));
|
|
7902
|
+
return {
|
|
7903
|
+
...buildClientModelConfigData(routes, catalog, templateKey, slots),
|
|
7904
|
+
allowedModelConfigs: config,
|
|
7905
|
+
defaultAgentModelConfig: config[0] ?? {}
|
|
7906
|
+
};
|
|
7907
|
+
}
|
|
7908
|
+
var CURRENT_EXPERIMENT_IDS = [
|
|
7909
|
+
105979552,
|
|
7910
|
+
105979574,
|
|
7911
|
+
106015351,
|
|
7912
|
+
105979579,
|
|
7913
|
+
105867471,
|
|
7914
|
+
105979530,
|
|
7915
|
+
105995634,
|
|
7916
|
+
106121401,
|
|
7917
|
+
106100625,
|
|
7918
|
+
104638466,
|
|
7919
|
+
101868197,
|
|
7920
|
+
104817729,
|
|
7921
|
+
105695344,
|
|
7922
|
+
106064591,
|
|
7923
|
+
104913215,
|
|
7924
|
+
106324349,
|
|
7925
|
+
106309078,
|
|
7926
|
+
105821930,
|
|
7927
|
+
104922093,
|
|
7928
|
+
103012598,
|
|
7929
|
+
106143956,
|
|
7930
|
+
105856899,
|
|
7931
|
+
106312323,
|
|
7932
|
+
106064030,
|
|
7933
|
+
105746183,
|
|
7934
|
+
105757908,
|
|
7935
|
+
104892493,
|
|
7936
|
+
105822886,
|
|
7937
|
+
105785683,
|
|
7938
|
+
105721273,
|
|
7939
|
+
105897325,
|
|
7940
|
+
105658071,
|
|
7941
|
+
106240758,
|
|
7942
|
+
105943702,
|
|
7943
|
+
106106760,
|
|
7944
|
+
106283618,
|
|
7945
|
+
105620019,
|
|
7946
|
+
106038160,
|
|
7947
|
+
106309520,
|
|
7948
|
+
106281951,
|
|
7949
|
+
106264532,
|
|
7950
|
+
106222835,
|
|
7951
|
+
106094629,
|
|
7952
|
+
105887313,
|
|
7953
|
+
105849474,
|
|
7954
|
+
106032303,
|
|
7955
|
+
106228452,
|
|
7956
|
+
106113900,
|
|
7957
|
+
106121607,
|
|
7958
|
+
105979531,
|
|
7959
|
+
105979553,
|
|
7960
|
+
106015328,
|
|
7961
|
+
105867469,
|
|
7962
|
+
105979517,
|
|
7963
|
+
106121399,
|
|
7964
|
+
106100654,
|
|
7965
|
+
104638459,
|
|
7966
|
+
101551624,
|
|
7967
|
+
104673683,
|
|
7968
|
+
105695346,
|
|
7969
|
+
106064590,
|
|
7970
|
+
104913210,
|
|
7971
|
+
105821928,
|
|
7972
|
+
104922082,
|
|
7973
|
+
103012592,
|
|
7974
|
+
106064028,
|
|
7975
|
+
105746181,
|
|
7976
|
+
104892490,
|
|
7977
|
+
105822881,
|
|
7978
|
+
105721268,
|
|
7979
|
+
105895316,
|
|
7980
|
+
105658068,
|
|
7981
|
+
106240748,
|
|
7982
|
+
105943694,
|
|
7983
|
+
106283614,
|
|
7984
|
+
105620012,
|
|
7985
|
+
106038153,
|
|
7986
|
+
105887311,
|
|
7987
|
+
106032301,
|
|
7988
|
+
106113877,
|
|
7989
|
+
106121604
|
|
7990
|
+
];
|
|
7991
|
+
function buildListExperimentsResponse() {
|
|
7992
|
+
return {
|
|
7993
|
+
experimentIds: [...CURRENT_EXPERIMENT_IDS]
|
|
7994
|
+
};
|
|
7995
|
+
}
|
|
7996
|
+
|
|
7283
7997
|
// src/target-compatibility.ts
|
|
7284
7998
|
function blacklistAgentForTarget(target) {
|
|
7285
7999
|
if (target === "claude-app") return "codex-app";
|
|
7286
8000
|
return target;
|
|
7287
8001
|
}
|
|
8002
|
+
function contextFloorForTarget(target) {
|
|
8003
|
+
if (target === "antigravity") return ANTIGRAVITY_MIN_CONTEXT_WINDOW;
|
|
8004
|
+
if (target === "server") return 0;
|
|
8005
|
+
return MIN_CONTEXT_WINDOW;
|
|
8006
|
+
}
|
|
8007
|
+
function meetsContextFloor(target, contextWindow) {
|
|
8008
|
+
return contextWindow === void 0 || contextWindow >= contextFloorForTarget(target);
|
|
8009
|
+
}
|
|
7288
8010
|
function isTargetCompatibleModel(ctx) {
|
|
7289
8011
|
const blacklistAgent = blacklistAgentForTarget(ctx.target);
|
|
7290
8012
|
if (shouldHideModel({ providerId: ctx.providerId, modelId: ctx.model.id, agent: blacklistAgent })) {
|
|
7291
8013
|
return { compatible: false, reason: "model is hidden by compatibility filters" };
|
|
7292
8014
|
}
|
|
8015
|
+
if (!meetsContextFloor(ctx.target, ctx.model.contextWindow)) {
|
|
8016
|
+
const floor = contextFloorForTarget(ctx.target);
|
|
8017
|
+
return {
|
|
8018
|
+
compatible: false,
|
|
8019
|
+
reason: `${ctx.target} needs a ${Math.round(floor / 1e3)}K+ context window; this model has ${Math.round(ctx.model.contextWindow / 1e3)}K`
|
|
8020
|
+
};
|
|
8021
|
+
}
|
|
7293
8022
|
if (ctx.model.modelFormat === "cloud-code") {
|
|
7294
8023
|
if (ctx.target === "server") {
|
|
7295
8024
|
return { compatible: false, reason: "Cloud Code models are not supported for the server target yet" };
|
|
@@ -7354,8 +8083,11 @@ function modelFormatForNpm(npm) {
|
|
|
7354
8083
|
return npm === "@ai-sdk/anthropic" ? "anthropic" : "openai";
|
|
7355
8084
|
}
|
|
7356
8085
|
function modelsUrl(baseUrl, template) {
|
|
7357
|
-
|
|
8086
|
+
let trimmed = baseUrl.replace(/\/$/, "");
|
|
7358
8087
|
if (template.modelsPath) {
|
|
8088
|
+
if (trimmed.endsWith("/v1") && (template.modelsPath.startsWith("/models") || template.modelsPath.startsWith("/ai/models"))) {
|
|
8089
|
+
trimmed = trimmed.slice(0, -3);
|
|
8090
|
+
}
|
|
7359
8091
|
const path = template.modelsPath.startsWith("/") ? template.modelsPath : `/${template.modelsPath}`;
|
|
7360
8092
|
return `${trimmed}${path}`;
|
|
7361
8093
|
}
|
|
@@ -7392,20 +8124,64 @@ function parseNativePricing(pricing) {
|
|
|
7392
8124
|
if (cacheWrite !== void 0) cost.cache_write = cacheWrite;
|
|
7393
8125
|
return cost;
|
|
7394
8126
|
}
|
|
8127
|
+
function parseCloudflarePricing(priceValue) {
|
|
8128
|
+
if (!Array.isArray(priceValue)) return void 0;
|
|
8129
|
+
let input;
|
|
8130
|
+
let output;
|
|
8131
|
+
for (const item of priceValue) {
|
|
8132
|
+
if (typeof item !== "object" || !item) continue;
|
|
8133
|
+
const row = item;
|
|
8134
|
+
const unit = String(row.unit || "").toLowerCase();
|
|
8135
|
+
const price = Number(row.price);
|
|
8136
|
+
if (!Number.isFinite(price)) continue;
|
|
8137
|
+
if (unit.includes("input")) input = price;
|
|
8138
|
+
else if (unit.includes("output")) output = price;
|
|
8139
|
+
}
|
|
8140
|
+
if (input === void 0 && output === void 0) return void 0;
|
|
8141
|
+
return { input: input ?? 0, output: output ?? 0 };
|
|
8142
|
+
}
|
|
8143
|
+
var LEGACY_NON_TOOL_MODELS = /* @__PURE__ */ new Set([
|
|
8144
|
+
"@cf/google/gemma-2b-it-lora",
|
|
8145
|
+
"@cf/google/gemma-7b-it-lora",
|
|
8146
|
+
"@cf/meta-llama/llama-2-7b-chat-hf-lora",
|
|
8147
|
+
"@cf/mistral/mistral-7b-instruct-v0.2-lora"
|
|
8148
|
+
]);
|
|
7395
8149
|
function parseModelList(body, npm) {
|
|
7396
|
-
const rows = body.data ?? body.models ?? [];
|
|
8150
|
+
const rows = body.data ?? body.models ?? body.result ?? [];
|
|
7397
8151
|
const format = modelFormatForNpm(npm);
|
|
7398
8152
|
const models = [];
|
|
7399
8153
|
for (const row of rows) {
|
|
7400
|
-
const rawId = row.id?.trim();
|
|
8154
|
+
const rawId = (row.name?.startsWith("@cf/") || row.name?.startsWith("@hf/") ? row.name : row.id)?.trim();
|
|
7401
8155
|
if (!rawId) continue;
|
|
8156
|
+
let contextWindowFromProps;
|
|
8157
|
+
let isFreeFromProps;
|
|
8158
|
+
let costFromProps;
|
|
8159
|
+
if (Array.isArray(row.properties)) {
|
|
8160
|
+
if (LEGACY_NON_TOOL_MODELS.has(rawId)) continue;
|
|
8161
|
+
const cwProp = row.properties.find((p8) => p8.property_id === "context_window");
|
|
8162
|
+
if (cwProp?.value) contextWindowFromProps = toNumber(cwProp.value);
|
|
8163
|
+
const priceProp = row.properties.find((p8) => p8.property_id === "price");
|
|
8164
|
+
const isRestrictedPaidPlan = rawId.includes("/glm-") || rawId.includes("/kimi-");
|
|
8165
|
+
if (isRestrictedPaidPlan) {
|
|
8166
|
+
costFromProps = parseCloudflarePricing(priceProp?.value);
|
|
8167
|
+
isFreeFromProps = false;
|
|
8168
|
+
} else {
|
|
8169
|
+
isFreeFromProps = true;
|
|
8170
|
+
if (priceProp?.value) {
|
|
8171
|
+
costFromProps = parseCloudflarePricing(priceProp.value);
|
|
8172
|
+
}
|
|
8173
|
+
}
|
|
8174
|
+
}
|
|
7402
8175
|
const { id, upstreamModelId: upstreamModelId2 } = normalizeGoogleModelId(rawId, npm);
|
|
7403
|
-
const family = id.split(/[-/:]/)[0] ?? id;
|
|
7404
|
-
const cost = parseNativePricing(row.pricing);
|
|
8176
|
+
const family = id.replace(/^@[a-z0-9_-]+\//i, "").split(/[-/:]/)[0] ?? id;
|
|
8177
|
+
const cost = costFromProps ?? parseNativePricing(row.pricing);
|
|
7405
8178
|
const freeStatus = classifyFreeStatus({
|
|
7406
|
-
model: { cost, isFree: row.isFree }
|
|
8179
|
+
model: { cost, isFree: row.isFree },
|
|
8180
|
+
// Cloudflare standard models carry a list price but are covered by the free
|
|
8181
|
+
// daily Neuron allowance, so free access is a provider rule, not a price.
|
|
8182
|
+
freeAccess: isFreeFromProps === true
|
|
7407
8183
|
});
|
|
7408
|
-
const contextWindow = row.context_length ?? row.contextWindow ?? row.context_window ?? resolveContextWindow(id);
|
|
8184
|
+
const contextWindow = contextWindowFromProps ?? row.context_length ?? row.contextWindow ?? row.context_window ?? resolveContextWindow(id);
|
|
7409
8185
|
models.push({
|
|
7410
8186
|
id,
|
|
7411
8187
|
name: normalizeGoogleDisplayName(row.name, id),
|
|
@@ -10689,14 +11465,14 @@ function codexAppInstallHint() {
|
|
|
10689
11465
|
|
|
10690
11466
|
// src/claude-desktop/app-launch.ts
|
|
10691
11467
|
import { execSync as execSync3, spawn as spawn3 } from "child_process";
|
|
10692
|
-
import { existsSync as existsSync12, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
11468
|
+
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync12, statSync as statSync4 } from "fs";
|
|
10693
11469
|
import { homedir as homedir8 } from "os";
|
|
10694
11470
|
import { join as join12 } from "path";
|
|
10695
11471
|
import * as p7 from "@clack/prompts";
|
|
10696
11472
|
var CLAUDE_BUNDLE_ID = "com.anthropic.claudefordesktop";
|
|
10697
11473
|
function claudeAppSupported() {
|
|
10698
|
-
if (process.platform !== "darwin" && process.platform !== "win32") {
|
|
10699
|
-
throw new Error("Claude Desktop launch is supported on macOS and
|
|
11474
|
+
if (process.platform !== "darwin" && process.platform !== "win32" && process.platform !== "linux") {
|
|
11475
|
+
throw new Error("Claude Desktop launch is supported on macOS, Windows, and Linux only.");
|
|
10700
11476
|
}
|
|
10701
11477
|
}
|
|
10702
11478
|
function run2(cmd, encoding = "utf8") {
|
|
@@ -10738,6 +11514,58 @@ function winClaudeExeCandidates() {
|
|
|
10738
11514
|
}
|
|
10739
11515
|
return out;
|
|
10740
11516
|
}
|
|
11517
|
+
function linuxClaudeCandidates() {
|
|
11518
|
+
return [
|
|
11519
|
+
// Wrapper launcher installed by the .deb/.rpm — sets up the Electron sandbox.
|
|
11520
|
+
"/usr/bin/claude-desktop",
|
|
11521
|
+
"/usr/lib/claude-desktop/claude-desktop",
|
|
11522
|
+
"/opt/Claude/claude-desktop",
|
|
11523
|
+
join12(homedir8(), ".local", "bin", "claude-desktop")
|
|
11524
|
+
];
|
|
11525
|
+
}
|
|
11526
|
+
function linuxWhichClaude() {
|
|
11527
|
+
try {
|
|
11528
|
+
const out = run2("command -v claude-desktop");
|
|
11529
|
+
return out && existsSync12(out) ? out : null;
|
|
11530
|
+
} catch {
|
|
11531
|
+
return null;
|
|
11532
|
+
}
|
|
11533
|
+
}
|
|
11534
|
+
function linuxMatchingPids() {
|
|
11535
|
+
try {
|
|
11536
|
+
const out = run2("pgrep -x claude-desktop");
|
|
11537
|
+
return out.split(/\s+/).map((s) => Number.parseInt(s, 10)).filter((n) => Number.isFinite(n) && n > 0);
|
|
11538
|
+
} catch {
|
|
11539
|
+
return [];
|
|
11540
|
+
}
|
|
11541
|
+
}
|
|
11542
|
+
function linuxMainPid() {
|
|
11543
|
+
const pids = linuxMatchingPids();
|
|
11544
|
+
for (const pid of pids) {
|
|
11545
|
+
try {
|
|
11546
|
+
const cmdline = readFileSync12(`/proc/${pid}/cmdline`, "utf8");
|
|
11547
|
+
if (!cmdline.includes("--type=")) return pid;
|
|
11548
|
+
} catch {
|
|
11549
|
+
}
|
|
11550
|
+
}
|
|
11551
|
+
return pids[0] ?? null;
|
|
11552
|
+
}
|
|
11553
|
+
function linuxQuit() {
|
|
11554
|
+
const pid = linuxMainPid();
|
|
11555
|
+
if (pid === null) return;
|
|
11556
|
+
try {
|
|
11557
|
+
process.kill(pid, "SIGTERM");
|
|
11558
|
+
} catch {
|
|
11559
|
+
}
|
|
11560
|
+
}
|
|
11561
|
+
function linuxForceQuit() {
|
|
11562
|
+
for (const pid of linuxMatchingPids()) {
|
|
11563
|
+
try {
|
|
11564
|
+
process.kill(pid, "SIGKILL");
|
|
11565
|
+
} catch {
|
|
11566
|
+
}
|
|
11567
|
+
}
|
|
11568
|
+
}
|
|
10741
11569
|
function mdfindClaudeApp() {
|
|
10742
11570
|
try {
|
|
10743
11571
|
const out = run2(`mdfind "kMDItemCFBundleIdentifier == '${CLAUDE_BUNDLE_ID}'"`);
|
|
@@ -10769,6 +11597,15 @@ function findClaudeApp() {
|
|
|
10769
11597
|
} catch {
|
|
10770
11598
|
}
|
|
10771
11599
|
}
|
|
11600
|
+
if (process.platform === "linux") {
|
|
11601
|
+
for (const path of linuxClaudeCandidates()) {
|
|
11602
|
+
try {
|
|
11603
|
+
if (existsSync12(path)) return path;
|
|
11604
|
+
} catch {
|
|
11605
|
+
}
|
|
11606
|
+
}
|
|
11607
|
+
return linuxWhichClaude();
|
|
11608
|
+
}
|
|
10772
11609
|
return null;
|
|
10773
11610
|
}
|
|
10774
11611
|
function darwinIsRunning2() {
|
|
@@ -10801,6 +11638,7 @@ function winHasWindow2() {
|
|
|
10801
11638
|
function isClaudeAppRunning() {
|
|
10802
11639
|
if (process.platform === "darwin") return darwinIsRunning2();
|
|
10803
11640
|
if (process.platform === "win32") return winMatchingPids2().length > 0 || winHasWindow2();
|
|
11641
|
+
if (process.platform === "linux") return linuxMatchingPids().length > 0;
|
|
10804
11642
|
return false;
|
|
10805
11643
|
}
|
|
10806
11644
|
function sleep2(ms) {
|
|
@@ -10811,12 +11649,16 @@ async function waitForQuit2(timeoutMs) {
|
|
|
10811
11649
|
while (Date.now() < deadline) {
|
|
10812
11650
|
if (process.platform === "win32") {
|
|
10813
11651
|
if (winMatchingPids2().length === 0) return true;
|
|
11652
|
+
} else if (process.platform === "linux") {
|
|
11653
|
+
if (linuxMatchingPids().length === 0) return true;
|
|
10814
11654
|
} else if (!darwinIsRunning2()) {
|
|
10815
11655
|
return true;
|
|
10816
11656
|
}
|
|
10817
11657
|
await sleep2(200);
|
|
10818
11658
|
}
|
|
10819
|
-
|
|
11659
|
+
if (process.platform === "win32") return winMatchingPids2().length === 0;
|
|
11660
|
+
if (process.platform === "linux") return linuxMatchingPids().length === 0;
|
|
11661
|
+
return !darwinIsRunning2();
|
|
10820
11662
|
}
|
|
10821
11663
|
function openClaudeAppAt(path) {
|
|
10822
11664
|
if (process.platform === "darwin") {
|
|
@@ -10833,6 +11675,10 @@ function openClaudeAppAt(path) {
|
|
|
10833
11675
|
} else {
|
|
10834
11676
|
runPowerShell2(`Start-Process -FilePath '${path.replace(/'/g, "''")}'`);
|
|
10835
11677
|
}
|
|
11678
|
+
return;
|
|
11679
|
+
}
|
|
11680
|
+
if (process.platform === "linux") {
|
|
11681
|
+
spawn3(path, [], { stdio: "ignore", detached: true }).unref();
|
|
10836
11682
|
}
|
|
10837
11683
|
}
|
|
10838
11684
|
function openClaudeApp() {
|
|
@@ -10859,6 +11705,7 @@ function winQuitGraceful2() {
|
|
|
10859
11705
|
function quitClaudeAppGracefully() {
|
|
10860
11706
|
if (process.platform === "darwin") darwinQuit2();
|
|
10861
11707
|
else if (process.platform === "win32") winQuitGraceful2();
|
|
11708
|
+
else if (process.platform === "linux") linuxQuit();
|
|
10862
11709
|
}
|
|
10863
11710
|
function winForceQuit2() {
|
|
10864
11711
|
const pids = winMatchingPids2();
|
|
@@ -10880,9 +11727,11 @@ async function launchOrRestartClaudeApp(prompt = "Restart Claude Desktop to appl
|
|
|
10880
11727
|
return;
|
|
10881
11728
|
}
|
|
10882
11729
|
if (process.platform === "darwin") darwinQuit2();
|
|
10883
|
-
else winQuitGraceful2();
|
|
11730
|
+
else if (process.platform === "win32") winQuitGraceful2();
|
|
11731
|
+
else if (process.platform === "linux") linuxQuit();
|
|
10884
11732
|
if (!await waitForQuit2(5e3)) {
|
|
10885
11733
|
if (process.platform === "win32") winForceQuit2();
|
|
11734
|
+
else if (process.platform === "linux") linuxForceQuit();
|
|
10886
11735
|
await waitForQuit2(5e3);
|
|
10887
11736
|
}
|
|
10888
11737
|
if (appPath) openClaudeAppAt(appPath);
|
|
@@ -11062,6 +11911,13 @@ export {
|
|
|
11062
11911
|
resolveLocalProviderApiKey,
|
|
11063
11912
|
formatRegistryAuthLabel,
|
|
11064
11913
|
resolveProvidersForDisplay,
|
|
11914
|
+
evaluateAgySwitchCompatibility,
|
|
11915
|
+
resolveRelayCatalogSlots,
|
|
11916
|
+
injectRelayModels,
|
|
11917
|
+
buildAntigravityRoutes,
|
|
11918
|
+
buildListModelConfigsResponse,
|
|
11919
|
+
buildListExperimentsResponse,
|
|
11920
|
+
meetsContextFloor,
|
|
11065
11921
|
routableModelsForTarget,
|
|
11066
11922
|
providersForTarget,
|
|
11067
11923
|
refreshProviderModels,
|
|
@@ -11103,4 +11959,4 @@ export {
|
|
|
11103
11959
|
supportsClaudeTransparentMode,
|
|
11104
11960
|
buildHttpProxyRoutes
|
|
11105
11961
|
};
|
|
11106
|
-
//# sourceMappingURL=chunk-
|
|
11962
|
+
//# sourceMappingURL=chunk-6CBNKM55.js.map
|