@hanzo/browser-extension 1.9.31 → 1.9.34
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/dist/browser-extension/background-firefox.js +1427 -0
- package/dist/browser-extension/background.js +1443 -18
- package/dist/browser-extension/chrome/background.js +1443 -18
- package/dist/browser-extension/chrome/manifest.json +17 -2
- package/dist/browser-extension/chrome/newtab.css +277 -0
- package/dist/browser-extension/chrome/newtab.html +13 -0
- package/dist/browser-extension/chrome/newtab.js +64 -0
- package/dist/browser-extension/chrome/popup.html +28 -0
- package/dist/browser-extension/chrome/popup.js +67 -1
- package/dist/browser-extension/firefox/background.js +1427 -0
- package/dist/browser-extension/firefox/manifest.json +10 -2
- package/dist/browser-extension/firefox/newtab.css +277 -0
- package/dist/browser-extension/firefox/newtab.html +13 -0
- package/dist/browser-extension/firefox/newtab.js +64 -0
- package/dist/browser-extension/firefox/popup.html +28 -0
- package/dist/browser-extension/firefox/popup.js +67 -1
- package/dist/browser-extension/manifest.json +17 -2
- package/dist/browser-extension/newtab.js +64 -0
- package/dist/browser-extension/popup.js +67 -1
- package/dist/browser-extension/safari/Info.plist +2 -2
- package/dist/browser-extension/safari/background.js +1443 -18
- package/dist/browser-extension/safari/newtab.css +277 -0
- package/dist/browser-extension/safari/newtab.html +13 -0
- package/dist/browser-extension/safari/newtab.js +64 -0
- package/dist/browser-extension/safari/popup.html +28 -0
- package/dist/browser-extension/safari/popup.js +67 -1
- package/package.json +3 -1
- package/src/answer/AnswerEngine.tsx +553 -0
- package/src/manifest-firefox.json +10 -2
- package/src/manifest.json +17 -2
- package/src/newtab.css +277 -0
- package/src/newtab.html +13 -0
- package/src/popup.html +28 -0
|
@@ -3306,8 +3306,8 @@ var WebGPUAI = class {
|
|
|
3306
3306
|
chunks.push(value);
|
|
3307
3307
|
received += value.byteLength;
|
|
3308
3308
|
if (total > 0 && received >= nextLog) {
|
|
3309
|
-
const
|
|
3310
|
-
console.log(`[Hanzo AI] ${label}: ${
|
|
3309
|
+
const pct2 = Math.floor(received / total * 100);
|
|
3310
|
+
console.log(`[Hanzo AI] ${label}: ${pct2}% (${received}/${total} bytes)`);
|
|
3311
3311
|
nextLog = received + Math.floor(total * 0.05);
|
|
3312
3312
|
}
|
|
3313
3313
|
}
|
|
@@ -3585,14 +3585,14 @@ function parseTabId(raw) {
|
|
|
3585
3585
|
function unwrapEvaluateResult(raw) {
|
|
3586
3586
|
if (raw === null || raw === void 0) return raw;
|
|
3587
3587
|
if (typeof raw !== "object") return raw;
|
|
3588
|
-
const
|
|
3589
|
-
const inner =
|
|
3588
|
+
const obj3 = raw;
|
|
3589
|
+
const inner = obj3.result;
|
|
3590
3590
|
if (inner && typeof inner === "object" && "value" in inner) {
|
|
3591
3591
|
return inner.value;
|
|
3592
3592
|
}
|
|
3593
|
-
if ("result" in
|
|
3594
|
-
if ("value" in
|
|
3595
|
-
if (Object.keys(
|
|
3593
|
+
if ("result" in obj3) return obj3.result;
|
|
3594
|
+
if ("value" in obj3) return obj3.value;
|
|
3595
|
+
if (Object.keys(obj3).length === 0 && !Array.isArray(obj3)) return void 0;
|
|
3596
3596
|
return raw;
|
|
3597
3597
|
}
|
|
3598
3598
|
|
|
@@ -4377,6 +4377,1419 @@ async function getAuthStatus2() {
|
|
|
4377
4377
|
return getAuthStatus(adapter.storage);
|
|
4378
4378
|
}
|
|
4379
4379
|
|
|
4380
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/host.js
|
|
4381
|
+
var expandHome = (host, path) => path.startsWith("~/") ? `${host.homeDir()}/${path.slice(2)}` : path;
|
|
4382
|
+
var readJsonFile = async (host, path) => {
|
|
4383
|
+
const text = await host.readTextFile(expandHome(host, path));
|
|
4384
|
+
if (text === void 0)
|
|
4385
|
+
return void 0;
|
|
4386
|
+
try {
|
|
4387
|
+
return JSON.parse(text);
|
|
4388
|
+
} catch {
|
|
4389
|
+
return void 0;
|
|
4390
|
+
}
|
|
4391
|
+
};
|
|
4392
|
+
|
|
4393
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/provider.js
|
|
4394
|
+
var matchesMode = (kind, mode) => {
|
|
4395
|
+
if (mode === "auto")
|
|
4396
|
+
return true;
|
|
4397
|
+
if (mode === "web")
|
|
4398
|
+
return kind === "web";
|
|
4399
|
+
if (mode === "cli")
|
|
4400
|
+
return kind === "cli" || kind === "localProbe";
|
|
4401
|
+
if (mode === "oauth")
|
|
4402
|
+
return kind === "oauth";
|
|
4403
|
+
return kind === "apiToken";
|
|
4404
|
+
};
|
|
4405
|
+
var forMode = (all, mode) => all.filter((s) => matchesMode(s.kind, mode));
|
|
4406
|
+
var runPipeline = async (descriptor, ctx) => {
|
|
4407
|
+
var _a;
|
|
4408
|
+
const attempts = [];
|
|
4409
|
+
let lastError;
|
|
4410
|
+
for (const strategy of descriptor.strategies(ctx.sourceMode)) {
|
|
4411
|
+
if (!await strategy.isAvailable(ctx)) {
|
|
4412
|
+
attempts.push({ strategyId: strategy.id, ok: false, skipped: true });
|
|
4413
|
+
continue;
|
|
4414
|
+
}
|
|
4415
|
+
try {
|
|
4416
|
+
const result = await strategy.fetch(ctx);
|
|
4417
|
+
attempts.push({ strategyId: strategy.id, ok: true });
|
|
4418
|
+
return { result, attempts };
|
|
4419
|
+
} catch (error) {
|
|
4420
|
+
attempts.push({
|
|
4421
|
+
strategyId: strategy.id,
|
|
4422
|
+
ok: false,
|
|
4423
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4424
|
+
});
|
|
4425
|
+
lastError = error;
|
|
4426
|
+
const fallback = ((_a = strategy.shouldFallback) == null ? void 0 : _a.call(strategy, error, ctx)) ?? true;
|
|
4427
|
+
if (!fallback)
|
|
4428
|
+
break;
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
return { error: lastError ?? new Error(`${descriptor.id}: no strategy available`), attempts };
|
|
4432
|
+
};
|
|
4433
|
+
|
|
4434
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/codex.js
|
|
4435
|
+
var codexHome = (ctx) => ctx.host.env("CODEX_HOME") ?? expandHome(ctx.host, "~/.codex");
|
|
4436
|
+
var toWindow = (w) => {
|
|
4437
|
+
if (!w || typeof w.used_percent !== "number")
|
|
4438
|
+
return void 0;
|
|
4439
|
+
return {
|
|
4440
|
+
usedPercent: w.used_percent,
|
|
4441
|
+
windowMinutes: w.limit_window_seconds ? Math.round(w.limit_window_seconds / 60) : void 0,
|
|
4442
|
+
resetsAt: w.reset_at ? new Date(w.reset_at * 1e3).toISOString() : void 0
|
|
4443
|
+
};
|
|
4444
|
+
};
|
|
4445
|
+
var oauthStrategy = {
|
|
4446
|
+
id: "codex.oauth",
|
|
4447
|
+
kind: "oauth",
|
|
4448
|
+
async isAvailable(ctx) {
|
|
4449
|
+
var _a;
|
|
4450
|
+
const auth = await readJsonFile(ctx.host, `${codexHome(ctx)}/auth.json`);
|
|
4451
|
+
return Boolean((_a = auth == null ? void 0 : auth.tokens) == null ? void 0 : _a.access_token);
|
|
4452
|
+
},
|
|
4453
|
+
async fetch(ctx) {
|
|
4454
|
+
var _a, _b, _c, _d, _e;
|
|
4455
|
+
const auth = await readJsonFile(ctx.host, `${codexHome(ctx)}/auth.json`);
|
|
4456
|
+
const token = (_a = auth == null ? void 0 : auth.tokens) == null ? void 0 : _a.access_token;
|
|
4457
|
+
if (!token)
|
|
4458
|
+
throw new Error("codex: no access token in auth.json");
|
|
4459
|
+
const headers = {
|
|
4460
|
+
Authorization: `Bearer ${token}`,
|
|
4461
|
+
Accept: "application/json",
|
|
4462
|
+
"User-Agent": "HanzoUsage"
|
|
4463
|
+
};
|
|
4464
|
+
if ((_b = auth == null ? void 0 : auth.tokens) == null ? void 0 : _b.account_id)
|
|
4465
|
+
headers["ChatGPT-Account-Id"] = auth.tokens.account_id;
|
|
4466
|
+
const res = await ctx.host.http({
|
|
4467
|
+
url: "https://chatgpt.com/backend-api/wham/usage",
|
|
4468
|
+
headers,
|
|
4469
|
+
timeoutMs: 3e4
|
|
4470
|
+
});
|
|
4471
|
+
if (res.status !== 200)
|
|
4472
|
+
throw new Error(`codex usage HTTP ${res.status}`);
|
|
4473
|
+
const body = JSON.parse(res.text);
|
|
4474
|
+
const now = ctx.host.now().toISOString();
|
|
4475
|
+
const usage = {
|
|
4476
|
+
providerId: "codex",
|
|
4477
|
+
primary: toWindow((_c = body.rate_limit) == null ? void 0 : _c.primary_window),
|
|
4478
|
+
secondary: toWindow((_d = body.rate_limit) == null ? void 0 : _d.secondary_window),
|
|
4479
|
+
extraRateWindows: (body.additional_rate_limits ?? []).map((extra) => {
|
|
4480
|
+
var _a2;
|
|
4481
|
+
const window = toWindow((_a2 = extra.rate_limit) == null ? void 0 : _a2.primary_window);
|
|
4482
|
+
if (!window || !extra.limit_name)
|
|
4483
|
+
return void 0;
|
|
4484
|
+
return { id: extra.limit_name, title: extra.limit_name, window, usageKnown: true };
|
|
4485
|
+
}).filter((w) => Boolean(w)),
|
|
4486
|
+
identity: { providerId: "codex", plan: body.plan_type, loginMethod: "oauth" },
|
|
4487
|
+
dataConfidence: "percentOnly",
|
|
4488
|
+
updatedAt: now
|
|
4489
|
+
};
|
|
4490
|
+
let credits;
|
|
4491
|
+
if ((_e = body.credits) == null ? void 0 : _e.has_credits) {
|
|
4492
|
+
credits = {
|
|
4493
|
+
remaining: body.credits.balance ?? 0,
|
|
4494
|
+
unlimited: body.credits.unlimited,
|
|
4495
|
+
updatedAt: now
|
|
4496
|
+
};
|
|
4497
|
+
}
|
|
4498
|
+
return {
|
|
4499
|
+
usage,
|
|
4500
|
+
credits,
|
|
4501
|
+
sourceLabel: "OpenAI OAuth",
|
|
4502
|
+
strategyId: this.id,
|
|
4503
|
+
strategyKind: this.kind
|
|
4504
|
+
};
|
|
4505
|
+
}
|
|
4506
|
+
};
|
|
4507
|
+
var codexProvider = {
|
|
4508
|
+
id: "codex",
|
|
4509
|
+
metadata: {
|
|
4510
|
+
displayName: "Codex",
|
|
4511
|
+
sessionLabel: "5h limit",
|
|
4512
|
+
weeklyLabel: "Weekly limit",
|
|
4513
|
+
supportsCredits: true,
|
|
4514
|
+
defaultEnabled: true,
|
|
4515
|
+
dashboardUrl: "https://chatgpt.com/codex/settings/usage",
|
|
4516
|
+
statusPageUrl: "https://status.openai.com",
|
|
4517
|
+
color: "#10a37f"
|
|
4518
|
+
},
|
|
4519
|
+
strategies: (mode) => forMode([oauthStrategy], mode)
|
|
4520
|
+
};
|
|
4521
|
+
|
|
4522
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/claude.js
|
|
4523
|
+
var WINDOW_MINUTES = {
|
|
4524
|
+
five_hour: 300,
|
|
4525
|
+
seven_day: 10080,
|
|
4526
|
+
seven_day_sonnet: 10080,
|
|
4527
|
+
seven_day_opus: 10080
|
|
4528
|
+
};
|
|
4529
|
+
var toWindow2 = (key, w) => {
|
|
4530
|
+
const used = (w == null ? void 0 : w.utilization) ?? (w == null ? void 0 : w.used_percent);
|
|
4531
|
+
if (typeof used !== "number")
|
|
4532
|
+
return void 0;
|
|
4533
|
+
return { usedPercent: used, windowMinutes: WINDOW_MINUTES[key], resetsAt: w == null ? void 0 : w.resets_at };
|
|
4534
|
+
};
|
|
4535
|
+
var mapUsage = (body, now, loginMethod, plan) => {
|
|
4536
|
+
const extras = [];
|
|
4537
|
+
for (const [key, title] of [
|
|
4538
|
+
["seven_day_sonnet", "Sonnet weekly"],
|
|
4539
|
+
["seven_day_opus", "Opus weekly"]
|
|
4540
|
+
]) {
|
|
4541
|
+
const window = toWindow2(key, body[key]);
|
|
4542
|
+
if (window)
|
|
4543
|
+
extras.push({ id: key, title, window, usageKnown: true });
|
|
4544
|
+
}
|
|
4545
|
+
return {
|
|
4546
|
+
providerId: "claude",
|
|
4547
|
+
primary: toWindow2("five_hour", body.five_hour),
|
|
4548
|
+
secondary: toWindow2("seven_day", body.seven_day),
|
|
4549
|
+
extraRateWindows: extras.length ? extras : void 0,
|
|
4550
|
+
identity: {
|
|
4551
|
+
providerId: "claude",
|
|
4552
|
+
plan: plan ?? body.subscriptionType ?? body.rate_limit_tier,
|
|
4553
|
+
loginMethod
|
|
4554
|
+
},
|
|
4555
|
+
providerCost: body.extra_usage && typeof body.extra_usage.used_cents === "number" ? {
|
|
4556
|
+
used: body.extra_usage.used_cents / 100,
|
|
4557
|
+
limit: typeof body.extra_usage.limit_cents === "number" ? body.extra_usage.limit_cents / 100 : void 0,
|
|
4558
|
+
currencyCode: "USD",
|
|
4559
|
+
period: "monthly",
|
|
4560
|
+
updatedAt: now
|
|
4561
|
+
} : void 0,
|
|
4562
|
+
dataConfidence: "percentOnly",
|
|
4563
|
+
updatedAt: now
|
|
4564
|
+
};
|
|
4565
|
+
};
|
|
4566
|
+
var credentialPaths = ["~/.claude/.credentials.json", "~/.config/claude/.credentials.json"];
|
|
4567
|
+
var readCredentials = async (ctx) => {
|
|
4568
|
+
var _a;
|
|
4569
|
+
for (const path of credentialPaths) {
|
|
4570
|
+
const file = await readJsonFile(ctx.host, path);
|
|
4571
|
+
if ((_a = file == null ? void 0 : file.claudeAiOauth) == null ? void 0 : _a.accessToken)
|
|
4572
|
+
return file.claudeAiOauth;
|
|
4573
|
+
}
|
|
4574
|
+
return void 0;
|
|
4575
|
+
};
|
|
4576
|
+
var oauthStrategy2 = {
|
|
4577
|
+
id: "claude.oauth",
|
|
4578
|
+
kind: "oauth",
|
|
4579
|
+
async isAvailable(ctx) {
|
|
4580
|
+
return Boolean(await readCredentials(ctx));
|
|
4581
|
+
},
|
|
4582
|
+
async fetch(ctx) {
|
|
4583
|
+
const creds = await readCredentials(ctx);
|
|
4584
|
+
if (!(creds == null ? void 0 : creds.accessToken))
|
|
4585
|
+
throw new Error("claude: no OAuth credentials");
|
|
4586
|
+
const res = await ctx.host.http({
|
|
4587
|
+
url: "https://api.anthropic.com/api/oauth/usage",
|
|
4588
|
+
headers: {
|
|
4589
|
+
Authorization: `Bearer ${creds.accessToken}`,
|
|
4590
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
4591
|
+
Accept: "application/json"
|
|
4592
|
+
},
|
|
4593
|
+
timeoutMs: 3e4
|
|
4594
|
+
});
|
|
4595
|
+
if (res.status !== 200)
|
|
4596
|
+
throw new Error(`claude usage HTTP ${res.status}`);
|
|
4597
|
+
const body = JSON.parse(res.text);
|
|
4598
|
+
return {
|
|
4599
|
+
usage: mapUsage(body, ctx.host.now().toISOString(), "oauth", creds.subscriptionType),
|
|
4600
|
+
sourceLabel: "Claude OAuth",
|
|
4601
|
+
strategyId: this.id,
|
|
4602
|
+
strategyKind: this.kind
|
|
4603
|
+
};
|
|
4604
|
+
}
|
|
4605
|
+
};
|
|
4606
|
+
var webStrategy = {
|
|
4607
|
+
id: "claude.web",
|
|
4608
|
+
kind: "web",
|
|
4609
|
+
async isAvailable(ctx) {
|
|
4610
|
+
var _a;
|
|
4611
|
+
return typeof ((_a = ctx.settings) == null ? void 0 : _a.cookieHeader) === "string";
|
|
4612
|
+
},
|
|
4613
|
+
async fetch(ctx) {
|
|
4614
|
+
var _a, _b;
|
|
4615
|
+
const cookie = String((_a = ctx.settings) == null ? void 0 : _a.cookieHeader);
|
|
4616
|
+
const get = async (path) => {
|
|
4617
|
+
const res = await ctx.host.http({
|
|
4618
|
+
url: `https://claude.ai/api${path}`,
|
|
4619
|
+
headers: { Cookie: cookie, Accept: "application/json" },
|
|
4620
|
+
timeoutMs: 3e4
|
|
4621
|
+
});
|
|
4622
|
+
if (res.status !== 200)
|
|
4623
|
+
throw new Error(`claude.ai${path} HTTP ${res.status}`);
|
|
4624
|
+
return JSON.parse(res.text);
|
|
4625
|
+
};
|
|
4626
|
+
const orgs = await get("/organizations");
|
|
4627
|
+
const orgId = (_b = orgs[0]) == null ? void 0 : _b.uuid;
|
|
4628
|
+
if (!orgId)
|
|
4629
|
+
throw new Error("claude: no organization for session");
|
|
4630
|
+
const body = await get(`/organizations/${orgId}/usage`);
|
|
4631
|
+
return {
|
|
4632
|
+
usage: mapUsage(body, ctx.host.now().toISOString(), "web"),
|
|
4633
|
+
sourceLabel: "claude.ai session",
|
|
4634
|
+
strategyId: this.id,
|
|
4635
|
+
strategyKind: this.kind
|
|
4636
|
+
};
|
|
4637
|
+
}
|
|
4638
|
+
};
|
|
4639
|
+
var claudeProvider = {
|
|
4640
|
+
id: "claude",
|
|
4641
|
+
metadata: {
|
|
4642
|
+
displayName: "Claude",
|
|
4643
|
+
sessionLabel: "Session (5h)",
|
|
4644
|
+
weeklyLabel: "Weekly limit",
|
|
4645
|
+
defaultEnabled: true,
|
|
4646
|
+
dashboardUrl: "https://claude.ai/settings/usage",
|
|
4647
|
+
statusPageUrl: "https://status.anthropic.com",
|
|
4648
|
+
color: "#d97757"
|
|
4649
|
+
},
|
|
4650
|
+
strategies: (mode) => forMode([oauthStrategy2, webStrategy], mode)
|
|
4651
|
+
};
|
|
4652
|
+
|
|
4653
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/hanzo.js
|
|
4654
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
4655
|
+
var cloudStrategy = {
|
|
4656
|
+
id: "hanzo.cloud",
|
|
4657
|
+
kind: "apiToken",
|
|
4658
|
+
async isAvailable(ctx) {
|
|
4659
|
+
var _a, _b;
|
|
4660
|
+
return Boolean(((_a = ctx.settings) == null ? void 0 : _a.getToken) || ((_b = ctx.settings) == null ? void 0 : _b.apiKey));
|
|
4661
|
+
},
|
|
4662
|
+
async fetch(ctx) {
|
|
4663
|
+
var _a, _b, _c, _d;
|
|
4664
|
+
const base = ((_a = ctx.settings) == null ? void 0 : _a.baseUrl) ?? "https://api.hanzo.ai";
|
|
4665
|
+
const token = await ((_c = (_b = ctx.settings) == null ? void 0 : _b.getToken) == null ? void 0 : _c.call(_b)) ?? ((_d = ctx.settings) == null ? void 0 : _d.apiKey);
|
|
4666
|
+
if (!token)
|
|
4667
|
+
throw new Error("hanzo: no token for cloud usage");
|
|
4668
|
+
const res = await ctx.host.http({
|
|
4669
|
+
url: `${base}/v1/billing/usage`,
|
|
4670
|
+
headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
|
|
4671
|
+
timeoutMs: 3e4
|
|
4672
|
+
});
|
|
4673
|
+
if (res.status !== 200)
|
|
4674
|
+
throw new Error(`hanzo billing usage HTTP ${res.status}`);
|
|
4675
|
+
const body = JSON.parse(res.text);
|
|
4676
|
+
const entries = Array.isArray(body.usage) ? body.usage : Array.isArray(body.data) ? body.data : [];
|
|
4677
|
+
let tokens = num(body.total_tokens ?? body.totalTokens);
|
|
4678
|
+
let spendCents = num(body.spend_cents ?? body.spendCents);
|
|
4679
|
+
let requests = num(body.total_requests ?? body.requests);
|
|
4680
|
+
for (const e of entries) {
|
|
4681
|
+
tokens += num(e.total_tokens ?? e.totalTokens ?? e.tokens);
|
|
4682
|
+
spendCents += num(e.spend_cents ?? e.spendCents ?? e.cost_cents);
|
|
4683
|
+
requests += num(e.requests ?? e.request_count ?? 1) - (e.requests === void 0 && e.request_count === void 0 ? 1 : 0);
|
|
4684
|
+
}
|
|
4685
|
+
const now = ctx.host.now().toISOString();
|
|
4686
|
+
const usage = {
|
|
4687
|
+
providerId: "hanzo",
|
|
4688
|
+
identity: { providerId: "hanzo", loginMethod: "iam" },
|
|
4689
|
+
providerCost: {
|
|
4690
|
+
used: spendCents / 100,
|
|
4691
|
+
currencyCode: "USD",
|
|
4692
|
+
period: "monthly",
|
|
4693
|
+
updatedAt: now
|
|
4694
|
+
},
|
|
4695
|
+
totals: { tokens, requests },
|
|
4696
|
+
dataConfidence: "exact",
|
|
4697
|
+
updatedAt: now
|
|
4698
|
+
};
|
|
4699
|
+
return {
|
|
4700
|
+
usage,
|
|
4701
|
+
sourceLabel: "Hanzo Cloud",
|
|
4702
|
+
strategyId: this.id,
|
|
4703
|
+
strategyKind: this.kind
|
|
4704
|
+
};
|
|
4705
|
+
}
|
|
4706
|
+
};
|
|
4707
|
+
var devHome = async (ctx) => {
|
|
4708
|
+
const candidates = [
|
|
4709
|
+
ctx.host.env("HANZO_HOME"),
|
|
4710
|
+
ctx.host.env("CODEX_HOME"),
|
|
4711
|
+
expandHome(ctx.host, "~/.hanzo"),
|
|
4712
|
+
expandHome(ctx.host, "~/.codex")
|
|
4713
|
+
].filter((c) => Boolean(c));
|
|
4714
|
+
for (const dir of candidates) {
|
|
4715
|
+
if ((await ctx.host.listDir(`${dir}/sessions`)).length > 0)
|
|
4716
|
+
return dir;
|
|
4717
|
+
}
|
|
4718
|
+
return void 0;
|
|
4719
|
+
};
|
|
4720
|
+
var newest = (names) => names.filter((n) => /^\d+$/.test(n)).sort().at(-1);
|
|
4721
|
+
var toRateWindow = (w, now) => {
|
|
4722
|
+
if (!w || typeof w.used_percent !== "number")
|
|
4723
|
+
return void 0;
|
|
4724
|
+
return {
|
|
4725
|
+
usedPercent: w.used_percent,
|
|
4726
|
+
windowMinutes: w.window_minutes,
|
|
4727
|
+
resetsAt: typeof w.resets_in_seconds === "number" ? new Date(now.getTime() + w.resets_in_seconds * 1e3).toISOString() : void 0
|
|
4728
|
+
};
|
|
4729
|
+
};
|
|
4730
|
+
var devStrategy = {
|
|
4731
|
+
id: "hanzo.dev",
|
|
4732
|
+
kind: "localProbe",
|
|
4733
|
+
async isAvailable(ctx) {
|
|
4734
|
+
return Boolean(await devHome(ctx));
|
|
4735
|
+
},
|
|
4736
|
+
async fetch(ctx) {
|
|
4737
|
+
var _a, _b, _c, _d;
|
|
4738
|
+
const home = await devHome(ctx);
|
|
4739
|
+
if (!home)
|
|
4740
|
+
throw new Error("hanzo: no dev CLI home with sessions");
|
|
4741
|
+
const sessions = `${home}/sessions`;
|
|
4742
|
+
const year = newest(await ctx.host.listDir(sessions));
|
|
4743
|
+
const month = year && newest(await ctx.host.listDir(`${sessions}/${year}`));
|
|
4744
|
+
const day = month && newest(await ctx.host.listDir(`${sessions}/${year}/${month}`));
|
|
4745
|
+
if (!day)
|
|
4746
|
+
throw new Error("hanzo: no dev sessions found");
|
|
4747
|
+
const dayDir = `${sessions}/${year}/${month}/${day}`;
|
|
4748
|
+
const rollouts = (await ctx.host.listDir(dayDir)).filter((f) => f.endsWith(".jsonl")).sort();
|
|
4749
|
+
const latest = rollouts.at(-1);
|
|
4750
|
+
if (!latest)
|
|
4751
|
+
throw new Error("hanzo: no rollout files today");
|
|
4752
|
+
const text = await ctx.host.readTextFile(`${dayDir}/${latest}`) ?? "";
|
|
4753
|
+
let payload;
|
|
4754
|
+
for (const line of text.split("\n")) {
|
|
4755
|
+
if (!line.includes('"token_count"'))
|
|
4756
|
+
continue;
|
|
4757
|
+
try {
|
|
4758
|
+
const item = JSON.parse(line);
|
|
4759
|
+
if (((_a = item.payload) == null ? void 0 : _a.type) === "token_count")
|
|
4760
|
+
payload = item.payload;
|
|
4761
|
+
} catch {
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
const now = ctx.host.now();
|
|
4765
|
+
const totals = (_b = payload == null ? void 0 : payload.info) == null ? void 0 : _b.total_token_usage;
|
|
4766
|
+
const usage = {
|
|
4767
|
+
providerId: "hanzo",
|
|
4768
|
+
primary: toRateWindow((_c = payload == null ? void 0 : payload.rate_limits) == null ? void 0 : _c.primary, now),
|
|
4769
|
+
secondary: toRateWindow((_d = payload == null ? void 0 : payload.rate_limits) == null ? void 0 : _d.secondary, now),
|
|
4770
|
+
identity: { providerId: "hanzo", loginMethod: "dev-cli" },
|
|
4771
|
+
totals: totals ? {
|
|
4772
|
+
tokens: totals.total_tokens ?? 0,
|
|
4773
|
+
inputTokens: totals.input_tokens ?? 0,
|
|
4774
|
+
outputTokens: totals.output_tokens ?? 0,
|
|
4775
|
+
cachedInputTokens: totals.cached_input_tokens ?? 0
|
|
4776
|
+
} : void 0,
|
|
4777
|
+
dataConfidence: totals ? "exact" : "unknown",
|
|
4778
|
+
updatedAt: now.toISOString()
|
|
4779
|
+
};
|
|
4780
|
+
return {
|
|
4781
|
+
usage,
|
|
4782
|
+
sourceLabel: "Hanzo Dev CLI",
|
|
4783
|
+
strategyId: this.id,
|
|
4784
|
+
strategyKind: this.kind
|
|
4785
|
+
};
|
|
4786
|
+
}
|
|
4787
|
+
};
|
|
4788
|
+
var hanzoProvider = {
|
|
4789
|
+
id: "hanzo",
|
|
4790
|
+
metadata: {
|
|
4791
|
+
displayName: "Hanzo",
|
|
4792
|
+
sessionLabel: "5h limit",
|
|
4793
|
+
weeklyLabel: "Weekly limit",
|
|
4794
|
+
defaultEnabled: true,
|
|
4795
|
+
dashboardUrl: "https://console.hanzo.ai/billing/usage",
|
|
4796
|
+
color: "#ff2d55"
|
|
4797
|
+
},
|
|
4798
|
+
strategies: (mode) => forMode([cloudStrategy, devStrategy], mode)
|
|
4799
|
+
};
|
|
4800
|
+
|
|
4801
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/api-token.js
|
|
4802
|
+
var resolveBaseUrl = (ctx, envKeys = []) => {
|
|
4803
|
+
var _a;
|
|
4804
|
+
const fromSettings = (_a = ctx.settings) == null ? void 0 : _a.baseUrl;
|
|
4805
|
+
if (typeof fromSettings === "string" && fromSettings.length > 0)
|
|
4806
|
+
return fromSettings;
|
|
4807
|
+
for (const name of envKeys) {
|
|
4808
|
+
const value = ctx.host.env(name);
|
|
4809
|
+
if (value)
|
|
4810
|
+
return value;
|
|
4811
|
+
}
|
|
4812
|
+
return void 0;
|
|
4813
|
+
};
|
|
4814
|
+
var resolveApiKey = (ctx, envKeys = []) => {
|
|
4815
|
+
var _a;
|
|
4816
|
+
const fromSettings = (_a = ctx.settings) == null ? void 0 : _a.apiKey;
|
|
4817
|
+
if (typeof fromSettings === "string" && fromSettings.length > 0)
|
|
4818
|
+
return fromSettings;
|
|
4819
|
+
for (const name of envKeys) {
|
|
4820
|
+
const value = ctx.host.env(name);
|
|
4821
|
+
if (value)
|
|
4822
|
+
return value;
|
|
4823
|
+
}
|
|
4824
|
+
return void 0;
|
|
4825
|
+
};
|
|
4826
|
+
var makeApiTokenStrategy = (config) => {
|
|
4827
|
+
const label = config.sourceLabel ?? config.metadata.displayName;
|
|
4828
|
+
return {
|
|
4829
|
+
id: `${config.id}.apiToken`,
|
|
4830
|
+
kind: "apiToken",
|
|
4831
|
+
async isAvailable(ctx) {
|
|
4832
|
+
if (!resolveApiKey(ctx, config.envKeys))
|
|
4833
|
+
return false;
|
|
4834
|
+
if (config.requireBaseUrl && !resolveBaseUrl(ctx, config.baseUrlEnv))
|
|
4835
|
+
return false;
|
|
4836
|
+
return true;
|
|
4837
|
+
},
|
|
4838
|
+
async fetch(ctx) {
|
|
4839
|
+
const apiKey = resolveApiKey(ctx, config.envKeys);
|
|
4840
|
+
if (!apiKey)
|
|
4841
|
+
throw new Error(`${config.id}: no API key`);
|
|
4842
|
+
const baseUrl = resolveBaseUrl(ctx, config.baseUrlEnv);
|
|
4843
|
+
if (config.requireBaseUrl && !baseUrl)
|
|
4844
|
+
throw new Error(`${config.id}: no base URL`);
|
|
4845
|
+
const settings = { ...ctx.settings, apiKey, ...baseUrl ? { baseUrl } : {} };
|
|
4846
|
+
const req = config.request(settings, ctx);
|
|
4847
|
+
const res = await ctx.host.http({ method: "GET", timeoutMs: 3e4, ...req });
|
|
4848
|
+
if (res.status !== 200)
|
|
4849
|
+
throw new Error(`${config.id} HTTP ${res.status}`);
|
|
4850
|
+
let body;
|
|
4851
|
+
try {
|
|
4852
|
+
body = JSON.parse(res.text);
|
|
4853
|
+
} catch {
|
|
4854
|
+
throw new Error(`${config.id}: invalid JSON body`);
|
|
4855
|
+
}
|
|
4856
|
+
const now = ctx.host.now();
|
|
4857
|
+
const iso = now.toISOString();
|
|
4858
|
+
const { usage, credits } = config.map(body, now, settings);
|
|
4859
|
+
return {
|
|
4860
|
+
usage: { ...usage, providerId: config.id, updatedAt: iso },
|
|
4861
|
+
credits: credits ? { ...credits, updatedAt: iso } : void 0,
|
|
4862
|
+
sourceLabel: label,
|
|
4863
|
+
strategyId: `${config.id}.apiToken`,
|
|
4864
|
+
strategyKind: "apiToken"
|
|
4865
|
+
};
|
|
4866
|
+
},
|
|
4867
|
+
// API-key providers have exactly one source; nothing to fall back to.
|
|
4868
|
+
shouldFallback() {
|
|
4869
|
+
return false;
|
|
4870
|
+
}
|
|
4871
|
+
};
|
|
4872
|
+
};
|
|
4873
|
+
var makeApiTokenProvider = (config) => {
|
|
4874
|
+
const strategy = makeApiTokenStrategy(config);
|
|
4875
|
+
return {
|
|
4876
|
+
id: config.id,
|
|
4877
|
+
metadata: config.metadata,
|
|
4878
|
+
strategies: (mode) => forMode([strategy], mode)
|
|
4879
|
+
};
|
|
4880
|
+
};
|
|
4881
|
+
var numberOrUndefined = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
4882
|
+
var bearer = (key) => ({
|
|
4883
|
+
Authorization: `Bearer ${key}`,
|
|
4884
|
+
Accept: "application/json"
|
|
4885
|
+
});
|
|
4886
|
+
|
|
4887
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/groq.js
|
|
4888
|
+
var ENV_KEYS = ["GROQ_API_KEY"];
|
|
4889
|
+
var ENV_URL = "GROQ_API_URL";
|
|
4890
|
+
var DEFAULT_BASE = "https://api.groq.com/v1";
|
|
4891
|
+
var QUERIES = {
|
|
4892
|
+
requests: "sum(model_project_id_status_code:requests:rate5m)",
|
|
4893
|
+
tokensIn: "sum(model_project_id:tokens_in:rate5m)",
|
|
4894
|
+
tokensOut: "sum(model_project_id:tokens_out:rate5m)"
|
|
4895
|
+
};
|
|
4896
|
+
var sumRate = (body) => {
|
|
4897
|
+
var _a, _b;
|
|
4898
|
+
if (body.status !== "success")
|
|
4899
|
+
return 0;
|
|
4900
|
+
let total = 0;
|
|
4901
|
+
for (const series of ((_a = body.data) == null ? void 0 : _a.result) ?? []) {
|
|
4902
|
+
const raw = (_b = series.value) == null ? void 0 : _b[1];
|
|
4903
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
4904
|
+
if (Number.isFinite(n))
|
|
4905
|
+
total += n;
|
|
4906
|
+
}
|
|
4907
|
+
return total;
|
|
4908
|
+
};
|
|
4909
|
+
var groqStrategy = {
|
|
4910
|
+
id: "groq.apiToken",
|
|
4911
|
+
kind: "apiToken",
|
|
4912
|
+
async isAvailable(ctx) {
|
|
4913
|
+
return Boolean(resolveApiKey(ctx, ENV_KEYS));
|
|
4914
|
+
},
|
|
4915
|
+
async fetch(ctx) {
|
|
4916
|
+
var _a;
|
|
4917
|
+
const key = resolveApiKey(ctx, ENV_KEYS);
|
|
4918
|
+
if (!key)
|
|
4919
|
+
throw new Error("groq: no API key");
|
|
4920
|
+
const base = ((_a = ctx.settings) == null ? void 0 : _a.baseUrl) ?? ctx.host.env(ENV_URL) ?? DEFAULT_BASE;
|
|
4921
|
+
const query = async (promql) => {
|
|
4922
|
+
const res = await ctx.host.http({
|
|
4923
|
+
url: `${base}/metrics/prometheus/api/v1/query?query=${encodeURIComponent(promql)}`,
|
|
4924
|
+
headers: bearer(key),
|
|
4925
|
+
timeoutMs: 3e4
|
|
4926
|
+
});
|
|
4927
|
+
if (res.status !== 200)
|
|
4928
|
+
throw new Error(`groq metrics HTTP ${res.status}`);
|
|
4929
|
+
return JSON.parse(res.text);
|
|
4930
|
+
};
|
|
4931
|
+
const [requests, tokensIn, tokensOut] = await Promise.all([
|
|
4932
|
+
query(QUERIES.requests),
|
|
4933
|
+
query(QUERIES.tokensIn),
|
|
4934
|
+
query(QUERIES.tokensOut)
|
|
4935
|
+
]);
|
|
4936
|
+
const requestsPerMin = Math.round(sumRate(requests) * 60);
|
|
4937
|
+
const tokensPerMin = Math.round((sumRate(tokensIn) + sumRate(tokensOut)) * 60);
|
|
4938
|
+
const now = ctx.host.now().toISOString();
|
|
4939
|
+
const usage = {
|
|
4940
|
+
providerId: "groq",
|
|
4941
|
+
identity: { providerId: "groq", loginMethod: "api" },
|
|
4942
|
+
totals: { tokens: tokensPerMin, requests: requestsPerMin },
|
|
4943
|
+
dataConfidence: "estimated",
|
|
4944
|
+
updatedAt: now
|
|
4945
|
+
};
|
|
4946
|
+
return { usage, sourceLabel: "Groq metrics", strategyId: this.id, strategyKind: this.kind };
|
|
4947
|
+
},
|
|
4948
|
+
shouldFallback() {
|
|
4949
|
+
return false;
|
|
4950
|
+
}
|
|
4951
|
+
};
|
|
4952
|
+
var groqProvider = {
|
|
4953
|
+
id: "groq",
|
|
4954
|
+
metadata: {
|
|
4955
|
+
displayName: "Groq",
|
|
4956
|
+
sessionLabel: "Throughput (req/min)",
|
|
4957
|
+
weeklyLabel: "Tokens/min",
|
|
4958
|
+
dashboardUrl: "https://console.groq.com/metrics",
|
|
4959
|
+
color: "#f55036"
|
|
4960
|
+
},
|
|
4961
|
+
strategies: (mode) => forMode([groqStrategy], mode)
|
|
4962
|
+
};
|
|
4963
|
+
|
|
4964
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/deepgram.js
|
|
4965
|
+
var ENV_KEYS2 = ["DEEPGRAM_API_KEY"];
|
|
4966
|
+
var ENV_URL2 = "DEEPGRAM_API_URL";
|
|
4967
|
+
var ENV_PROJECT = "DEEPGRAM_PROJECT_ID";
|
|
4968
|
+
var DEFAULT_BASE2 = "https://api.deepgram.com/v1";
|
|
4969
|
+
var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
4970
|
+
var deepgramStrategy = {
|
|
4971
|
+
id: "deepgram.apiToken",
|
|
4972
|
+
kind: "apiToken",
|
|
4973
|
+
async isAvailable(ctx) {
|
|
4974
|
+
return Boolean(resolveApiKey(ctx, ENV_KEYS2));
|
|
4975
|
+
},
|
|
4976
|
+
async fetch(ctx) {
|
|
4977
|
+
var _a, _b;
|
|
4978
|
+
const key = resolveApiKey(ctx, ENV_KEYS2);
|
|
4979
|
+
if (!key)
|
|
4980
|
+
throw new Error("deepgram: no API key");
|
|
4981
|
+
const base = ((_a = ctx.settings) == null ? void 0 : _a.baseUrl) ?? ctx.host.env(ENV_URL2) ?? DEFAULT_BASE2;
|
|
4982
|
+
const headers = { Authorization: `Token ${key}`, Accept: "application/json" };
|
|
4983
|
+
const get = async (path) => {
|
|
4984
|
+
const res = await ctx.host.http({ url: `${base}${path}`, headers, timeoutMs: 3e4 });
|
|
4985
|
+
if (res.status !== 200)
|
|
4986
|
+
throw new Error(`deepgram ${path} HTTP ${res.status}`);
|
|
4987
|
+
return JSON.parse(res.text);
|
|
4988
|
+
};
|
|
4989
|
+
const configured = (typeof ((_b = ctx.settings) == null ? void 0 : _b.projectId) === "string" ? ctx.settings.projectId : void 0) ?? ctx.host.env(ENV_PROJECT);
|
|
4990
|
+
let projectIds;
|
|
4991
|
+
if (configured) {
|
|
4992
|
+
projectIds = [configured];
|
|
4993
|
+
} else {
|
|
4994
|
+
const body = await get("/projects");
|
|
4995
|
+
const projects = Array.isArray(body.projects) ? body.projects : [];
|
|
4996
|
+
projectIds = projects.map((p) => p.project_id).filter((id) => Boolean(id));
|
|
4997
|
+
}
|
|
4998
|
+
let hours = 0;
|
|
4999
|
+
let tokens = 0;
|
|
5000
|
+
let requests = 0;
|
|
5001
|
+
for (const id of projectIds) {
|
|
5002
|
+
const body = await get(`/projects/${id}/usage/breakdown`);
|
|
5003
|
+
for (const r of Array.isArray(body.results) ? body.results : []) {
|
|
5004
|
+
hours += num2(r.total_hours);
|
|
5005
|
+
tokens += num2(r.tokens_in) + num2(r.tokens_out);
|
|
5006
|
+
requests += num2(r.requests);
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
const now = ctx.host.now().toISOString();
|
|
5010
|
+
const usage = {
|
|
5011
|
+
providerId: "deepgram",
|
|
5012
|
+
identity: {
|
|
5013
|
+
providerId: "deepgram",
|
|
5014
|
+
loginMethod: "api",
|
|
5015
|
+
accountOrganization: projectIds.length === 1 ? projectIds[0] : `${projectIds.length} projects`
|
|
5016
|
+
},
|
|
5017
|
+
totals: { tokens, requests },
|
|
5018
|
+
dataConfidence: tokens > 0 || requests > 0 || hours > 0 ? "exact" : "unknown",
|
|
5019
|
+
updatedAt: now
|
|
5020
|
+
};
|
|
5021
|
+
return { usage, sourceLabel: "Deepgram usage", strategyId: this.id, strategyKind: this.kind };
|
|
5022
|
+
},
|
|
5023
|
+
shouldFallback() {
|
|
5024
|
+
return false;
|
|
5025
|
+
}
|
|
5026
|
+
};
|
|
5027
|
+
var deepgramProvider = {
|
|
5028
|
+
id: "deepgram",
|
|
5029
|
+
metadata: {
|
|
5030
|
+
displayName: "Deepgram",
|
|
5031
|
+
sessionLabel: "Usage",
|
|
5032
|
+
weeklyLabel: "Requests",
|
|
5033
|
+
dashboardUrl: "https://console.deepgram.com/usage",
|
|
5034
|
+
color: "#13ef93"
|
|
5035
|
+
},
|
|
5036
|
+
strategies: (mode) => forMode([deepgramStrategy], mode)
|
|
5037
|
+
};
|
|
5038
|
+
|
|
5039
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/byo.js
|
|
5040
|
+
var ENV_KEYS3 = ["BYO_API_KEY"];
|
|
5041
|
+
var ENV_URL3 = ["BYO_BASE_URL"];
|
|
5042
|
+
var num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
5043
|
+
var obj = (v) => v && typeof v === "object" ? v : {};
|
|
5044
|
+
var stripV1 = (base) => base.replace(/\/v1\/?$/, "").replace(/\/$/, "");
|
|
5045
|
+
var keyInfo = async (ctx, base, key, now) => {
|
|
5046
|
+
const res = await ctx.host.http({
|
|
5047
|
+
url: `${stripV1(base)}/key/info`,
|
|
5048
|
+
headers: bearer(key),
|
|
5049
|
+
timeoutMs: 15e3
|
|
5050
|
+
});
|
|
5051
|
+
if (res.status !== 200)
|
|
5052
|
+
return void 0;
|
|
5053
|
+
let info;
|
|
5054
|
+
try {
|
|
5055
|
+
info = obj(obj(JSON.parse(res.text)).info);
|
|
5056
|
+
} catch {
|
|
5057
|
+
return void 0;
|
|
5058
|
+
}
|
|
5059
|
+
if (Object.keys(info).length === 0)
|
|
5060
|
+
return void 0;
|
|
5061
|
+
const spend = num3(info.spend);
|
|
5062
|
+
return {
|
|
5063
|
+
providerId: "byo",
|
|
5064
|
+
identity: {
|
|
5065
|
+
providerId: "byo",
|
|
5066
|
+
loginMethod: "api",
|
|
5067
|
+
accountEmail: typeof info.user_id === "string" ? info.user_id : void 0,
|
|
5068
|
+
accountOrganization: typeof info.team_id === "string" ? info.team_id : void 0,
|
|
5069
|
+
plan: typeof info.key_name === "string" ? info.key_name : void 0
|
|
5070
|
+
},
|
|
5071
|
+
providerCost: { used: spend, currencyCode: "USD", period: "key", updatedAt: now.toISOString() },
|
|
5072
|
+
subscriptionExpiresAt: typeof info.expires === "string" ? info.expires : void 0,
|
|
5073
|
+
dataConfidence: "exact",
|
|
5074
|
+
updatedAt: now.toISOString()
|
|
5075
|
+
};
|
|
5076
|
+
};
|
|
5077
|
+
var modelsLiveness = async (ctx, base, key, now) => {
|
|
5078
|
+
const root = stripV1(base);
|
|
5079
|
+
const res = await ctx.host.http({
|
|
5080
|
+
url: `${root}/v1/models`,
|
|
5081
|
+
headers: bearer(key),
|
|
5082
|
+
timeoutMs: 15e3
|
|
5083
|
+
});
|
|
5084
|
+
if (res.status !== 200)
|
|
5085
|
+
throw new Error(`byo: /v1/models HTTP ${res.status}`);
|
|
5086
|
+
let count;
|
|
5087
|
+
try {
|
|
5088
|
+
const data = obj(JSON.parse(res.text)).data;
|
|
5089
|
+
if (Array.isArray(data))
|
|
5090
|
+
count = data.length;
|
|
5091
|
+
} catch {
|
|
5092
|
+
}
|
|
5093
|
+
return {
|
|
5094
|
+
providerId: "byo",
|
|
5095
|
+
identity: {
|
|
5096
|
+
providerId: "byo",
|
|
5097
|
+
loginMethod: "api",
|
|
5098
|
+
accountOrganization: count !== void 0 ? `${count} models` : void 0
|
|
5099
|
+
},
|
|
5100
|
+
dataConfidence: "unknown",
|
|
5101
|
+
updatedAt: now.toISOString()
|
|
5102
|
+
};
|
|
5103
|
+
};
|
|
5104
|
+
var byoStrategy = {
|
|
5105
|
+
id: "byo.apiToken",
|
|
5106
|
+
kind: "apiToken",
|
|
5107
|
+
async isAvailable(ctx) {
|
|
5108
|
+
return Boolean(resolveApiKey(ctx, ENV_KEYS3) && resolveBaseUrl(ctx, ENV_URL3));
|
|
5109
|
+
},
|
|
5110
|
+
async fetch(ctx) {
|
|
5111
|
+
const key = resolveApiKey(ctx, ENV_KEYS3);
|
|
5112
|
+
const base = resolveBaseUrl(ctx, ENV_URL3);
|
|
5113
|
+
if (!key || !base)
|
|
5114
|
+
throw new Error("byo: baseUrl and apiKey are required");
|
|
5115
|
+
const now = ctx.host.now();
|
|
5116
|
+
const info = await keyInfo(ctx, base, key, now);
|
|
5117
|
+
if (info) {
|
|
5118
|
+
return { usage: info, sourceLabel: "BYO /key/info", strategyId: this.id, strategyKind: this.kind };
|
|
5119
|
+
}
|
|
5120
|
+
const usage = await modelsLiveness(ctx, base, key, now);
|
|
5121
|
+
return { usage, sourceLabel: "BYO liveness", strategyId: this.id, strategyKind: this.kind };
|
|
5122
|
+
},
|
|
5123
|
+
shouldFallback() {
|
|
5124
|
+
return false;
|
|
5125
|
+
}
|
|
5126
|
+
};
|
|
5127
|
+
var byoProvider = {
|
|
5128
|
+
id: "byo",
|
|
5129
|
+
metadata: {
|
|
5130
|
+
displayName: "BYO endpoint",
|
|
5131
|
+
sessionLabel: "Key spend",
|
|
5132
|
+
weeklyLabel: "Liveness",
|
|
5133
|
+
dashboardUrl: "https://docs.hanzo.ai/docs/gateway",
|
|
5134
|
+
color: "#64748b"
|
|
5135
|
+
},
|
|
5136
|
+
strategies: (mode) => forMode([byoStrategy], mode)
|
|
5137
|
+
};
|
|
5138
|
+
|
|
5139
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/providers/api-token-providers.js
|
|
5140
|
+
var num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
5141
|
+
var loose = (v) => {
|
|
5142
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
5143
|
+
return v;
|
|
5144
|
+
if (typeof v === "string") {
|
|
5145
|
+
const n = Number(v);
|
|
5146
|
+
return Number.isFinite(n) ? n : void 0;
|
|
5147
|
+
}
|
|
5148
|
+
return void 0;
|
|
5149
|
+
};
|
|
5150
|
+
var pct = (used, limit) => limit > 0 ? Math.min(100, Math.max(0, used / limit * 100)) : 0;
|
|
5151
|
+
var obj2 = (v) => v && typeof v === "object" ? v : {};
|
|
5152
|
+
var openrouterProvider = makeApiTokenProvider({
|
|
5153
|
+
id: "openrouter",
|
|
5154
|
+
metadata: {
|
|
5155
|
+
displayName: "OpenRouter",
|
|
5156
|
+
sessionLabel: "Credits used",
|
|
5157
|
+
weeklyLabel: "Credit limit",
|
|
5158
|
+
supportsCredits: true,
|
|
5159
|
+
dashboardUrl: "https://openrouter.ai/settings/credits",
|
|
5160
|
+
color: "#6467f2"
|
|
5161
|
+
},
|
|
5162
|
+
envKeys: ["OPENROUTER_API_KEY"],
|
|
5163
|
+
request: (s, ctx) => ({
|
|
5164
|
+
url: `${s.baseUrl ?? ctx.host.env("OPENROUTER_API_URL") ?? "https://openrouter.ai/api/v1"}/credits`,
|
|
5165
|
+
headers: bearer(s.apiKey)
|
|
5166
|
+
}),
|
|
5167
|
+
map: (json, now) => {
|
|
5168
|
+
const d = obj2(obj2(json).data);
|
|
5169
|
+
const total = num4(d.total_credits);
|
|
5170
|
+
const used = num4(d.total_usage);
|
|
5171
|
+
return {
|
|
5172
|
+
usage: {
|
|
5173
|
+
identity: { providerId: "openrouter", loginMethod: "api" },
|
|
5174
|
+
providerCost: { used, limit: total, currencyCode: "USD", period: "total", updatedAt: now.toISOString() },
|
|
5175
|
+
dataConfidence: "exact"
|
|
5176
|
+
},
|
|
5177
|
+
credits: { remaining: Math.max(0, total - used) }
|
|
5178
|
+
};
|
|
5179
|
+
}
|
|
5180
|
+
});
|
|
5181
|
+
var deepseekProvider = makeApiTokenProvider({
|
|
5182
|
+
id: "deepseek",
|
|
5183
|
+
metadata: {
|
|
5184
|
+
displayName: "DeepSeek",
|
|
5185
|
+
sessionLabel: "Balance",
|
|
5186
|
+
weeklyLabel: "Balance",
|
|
5187
|
+
supportsCredits: true,
|
|
5188
|
+
dashboardUrl: "https://platform.deepseek.com/usage",
|
|
5189
|
+
color: "#527df0"
|
|
5190
|
+
},
|
|
5191
|
+
envKeys: ["DEEPSEEK_API_KEY", "DEEPSEEK_KEY"],
|
|
5192
|
+
request: (s) => ({ url: "https://api.deepseek.com/user/balance", headers: bearer(s.apiKey) }),
|
|
5193
|
+
map: (json) => {
|
|
5194
|
+
const infos = Array.isArray(obj2(json).balance_infos) ? obj2(json).balance_infos : [];
|
|
5195
|
+
const bal = (r) => loose(r.total_balance) ?? 0;
|
|
5196
|
+
const row = infos.find((r) => r.currency === "USD" && bal(r) > 0) ?? infos.find((r) => bal(r) > 0) ?? infos.find((r) => r.currency === "USD") ?? infos[0];
|
|
5197
|
+
return {
|
|
5198
|
+
usage: {
|
|
5199
|
+
identity: { providerId: "deepseek", loginMethod: "api", plan: typeof (row == null ? void 0 : row.currency) === "string" ? row.currency : void 0 },
|
|
5200
|
+
dataConfidence: "exact"
|
|
5201
|
+
},
|
|
5202
|
+
credits: { remaining: row ? bal(row) : 0 }
|
|
5203
|
+
};
|
|
5204
|
+
}
|
|
5205
|
+
});
|
|
5206
|
+
var elevenlabsProvider = makeApiTokenProvider({
|
|
5207
|
+
id: "elevenlabs",
|
|
5208
|
+
metadata: {
|
|
5209
|
+
displayName: "ElevenLabs",
|
|
5210
|
+
sessionLabel: "Characters",
|
|
5211
|
+
weeklyLabel: "Character limit",
|
|
5212
|
+
dashboardUrl: "https://elevenlabs.io/app/subscription",
|
|
5213
|
+
color: "#ebebe6"
|
|
5214
|
+
},
|
|
5215
|
+
envKeys: ["ELEVENLABS_API_KEY", "XI_API_KEY"],
|
|
5216
|
+
request: (s, ctx) => ({
|
|
5217
|
+
url: `${s.baseUrl ?? ctx.host.env("ELEVENLABS_API_URL") ?? "https://api.elevenlabs.io"}/v1/user/subscription`,
|
|
5218
|
+
headers: { "xi-api-key": s.apiKey, Accept: "application/json" }
|
|
5219
|
+
}),
|
|
5220
|
+
map: (json, now) => {
|
|
5221
|
+
const b = obj2(json);
|
|
5222
|
+
const count = num4(b.character_count);
|
|
5223
|
+
const limit = num4(b.character_limit);
|
|
5224
|
+
const resetUnix = numberOrUndefined(b.next_character_count_reset_unix);
|
|
5225
|
+
const resetsAt = resetUnix !== void 0 ? new Date(resetUnix * 1e3).toISOString() : void 0;
|
|
5226
|
+
const overage = obj2(b.current_overage);
|
|
5227
|
+
const overageAmount = loose(overage.amount);
|
|
5228
|
+
return {
|
|
5229
|
+
usage: {
|
|
5230
|
+
primary: { usedPercent: pct(count, limit), resetsAt },
|
|
5231
|
+
identity: { providerId: "elevenlabs", loginMethod: "api", plan: typeof b.tier === "string" ? b.tier : void 0 },
|
|
5232
|
+
subscriptionRenewsAt: resetsAt,
|
|
5233
|
+
providerCost: overageAmount !== void 0 && overageAmount > 0 ? {
|
|
5234
|
+
used: overageAmount,
|
|
5235
|
+
currencyCode: typeof overage.currency === "string" ? overage.currency : "USD",
|
|
5236
|
+
period: "overage",
|
|
5237
|
+
updatedAt: now.toISOString()
|
|
5238
|
+
} : void 0,
|
|
5239
|
+
dataConfidence: "exact"
|
|
5240
|
+
}
|
|
5241
|
+
};
|
|
5242
|
+
}
|
|
5243
|
+
});
|
|
5244
|
+
var poeProvider = makeApiTokenProvider({
|
|
5245
|
+
id: "poe",
|
|
5246
|
+
metadata: {
|
|
5247
|
+
displayName: "Poe",
|
|
5248
|
+
sessionLabel: "Points",
|
|
5249
|
+
weeklyLabel: "Points",
|
|
5250
|
+
supportsCredits: true,
|
|
5251
|
+
dashboardUrl: "https://poe.com/api/keys",
|
|
5252
|
+
color: "#5d5cde"
|
|
5253
|
+
},
|
|
5254
|
+
envKeys: ["POE_API_KEY"],
|
|
5255
|
+
request: (s) => ({ url: "https://api.poe.com/usage/current_balance", headers: bearer(s.apiKey) }),
|
|
5256
|
+
map: (json) => ({
|
|
5257
|
+
usage: { identity: { providerId: "poe", loginMethod: "api" }, dataConfidence: "exact" },
|
|
5258
|
+
credits: { remaining: num4(obj2(json).current_point_balance) }
|
|
5259
|
+
})
|
|
5260
|
+
});
|
|
5261
|
+
var veniceProvider = makeApiTokenProvider({
|
|
5262
|
+
id: "venice",
|
|
5263
|
+
metadata: {
|
|
5264
|
+
displayName: "Venice",
|
|
5265
|
+
sessionLabel: "Balance",
|
|
5266
|
+
weeklyLabel: "DIEM allocation",
|
|
5267
|
+
supportsCredits: true,
|
|
5268
|
+
dashboardUrl: "https://venice.ai/settings/api",
|
|
5269
|
+
color: "#3399ff"
|
|
5270
|
+
},
|
|
5271
|
+
envKeys: ["VENICE_API_KEY", "VENICE_KEY"],
|
|
5272
|
+
request: (s) => ({ url: "https://api.venice.ai/api/v1/billing/balance", headers: bearer(s.apiKey) }),
|
|
5273
|
+
map: (json) => {
|
|
5274
|
+
const b = obj2(json);
|
|
5275
|
+
const balances = obj2(b.balances);
|
|
5276
|
+
const canConsume = b.canConsume !== false;
|
|
5277
|
+
const currency = (typeof b.consumptionCurrency === "string" ? b.consumptionCurrency : "USD").toUpperCase();
|
|
5278
|
+
const usd = loose(balances.usd);
|
|
5279
|
+
const diem = loose(balances.diem);
|
|
5280
|
+
const alloc = loose(b.diemEpochAllocation);
|
|
5281
|
+
const isDiem = currency === "DIEM";
|
|
5282
|
+
const remaining = (isDiem ? diem : usd) ?? 0;
|
|
5283
|
+
let usedPercent = 0;
|
|
5284
|
+
if (!canConsume)
|
|
5285
|
+
usedPercent = 100;
|
|
5286
|
+
else if (isDiem && alloc && alloc > 0)
|
|
5287
|
+
usedPercent = pct(Math.max(0, alloc - remaining), alloc);
|
|
5288
|
+
return {
|
|
5289
|
+
usage: {
|
|
5290
|
+
primary: { usedPercent },
|
|
5291
|
+
identity: { providerId: "venice", loginMethod: "api", plan: currency },
|
|
5292
|
+
dataConfidence: "exact"
|
|
5293
|
+
},
|
|
5294
|
+
credits: { remaining }
|
|
5295
|
+
};
|
|
5296
|
+
}
|
|
5297
|
+
});
|
|
5298
|
+
var chutesWindow = (container, windowMinutes) => {
|
|
5299
|
+
const w = obj2(container);
|
|
5300
|
+
const pick = (keys) => {
|
|
5301
|
+
for (const k of keys) {
|
|
5302
|
+
const v = loose(w[k]);
|
|
5303
|
+
if (v !== void 0)
|
|
5304
|
+
return v;
|
|
5305
|
+
}
|
|
5306
|
+
return void 0;
|
|
5307
|
+
};
|
|
5308
|
+
const explicit = pick(["percent_used", "usage_percent", "used_percent", "utilization", "utilization_percent"]);
|
|
5309
|
+
const remainingPct = pick(["percent_remaining", "remaining_percent"]);
|
|
5310
|
+
const used = pick(["used", "usage", "consumed", "current", "requests", "tokens", "monthly_usage"]);
|
|
5311
|
+
const limit = pick(["limit", "cap", "max", "maximum", "quota", "quota_limit", "monthly_limit", "total"]);
|
|
5312
|
+
const remaining = pick(["remaining", "available", "balance", "left"]);
|
|
5313
|
+
let usedPercent = explicit;
|
|
5314
|
+
if (usedPercent === void 0 && remainingPct !== void 0)
|
|
5315
|
+
usedPercent = 100 - remainingPct;
|
|
5316
|
+
if (usedPercent !== void 0 && usedPercent <= 1 && usedPercent >= 0)
|
|
5317
|
+
usedPercent *= 100;
|
|
5318
|
+
if (usedPercent === void 0 && limit !== void 0) {
|
|
5319
|
+
const u = used ?? (remaining !== void 0 ? limit - remaining : void 0);
|
|
5320
|
+
if (u !== void 0)
|
|
5321
|
+
usedPercent = pct(u, limit);
|
|
5322
|
+
}
|
|
5323
|
+
if (usedPercent === void 0)
|
|
5324
|
+
return void 0;
|
|
5325
|
+
const resetRaw = pick(["reset_at", "resets_at", "next_reset_at", "period_end", "current_period_end", "expires_at", "window_end"]);
|
|
5326
|
+
return {
|
|
5327
|
+
usedPercent: Math.min(100, Math.max(0, usedPercent)),
|
|
5328
|
+
windowMinutes,
|
|
5329
|
+
resetsAt: resetRaw !== void 0 ? new Date(resetRaw * 1e3).toISOString() : void 0
|
|
5330
|
+
};
|
|
5331
|
+
};
|
|
5332
|
+
var chutesProvider = makeApiTokenProvider({
|
|
5333
|
+
id: "chutes",
|
|
5334
|
+
metadata: {
|
|
5335
|
+
displayName: "Chutes",
|
|
5336
|
+
sessionLabel: "4h quota",
|
|
5337
|
+
weeklyLabel: "Monthly quota",
|
|
5338
|
+
dashboardUrl: "https://chutes.ai",
|
|
5339
|
+
color: "#eab308"
|
|
5340
|
+
},
|
|
5341
|
+
envKeys: ["CHUTES_API_KEY"],
|
|
5342
|
+
request: (s, ctx) => ({
|
|
5343
|
+
url: `${s.baseUrl ?? ctx.host.env("CHUTES_API_URL") ?? "https://api.chutes.ai"}/users/me/subscription_usage`,
|
|
5344
|
+
headers: bearer(s.apiKey)
|
|
5345
|
+
}),
|
|
5346
|
+
map: (json) => {
|
|
5347
|
+
const b = obj2(json);
|
|
5348
|
+
const rolling = chutesWindow(b.rolling, 240) ?? chutesWindow(b.rolling_window, 240) ?? chutesWindow(b.four_hour, 240);
|
|
5349
|
+
const monthly = chutesWindow(b.monthly, 43200) ?? chutesWindow(b.subscription, 43200) ?? chutesWindow(b.subscription_usage, 43200);
|
|
5350
|
+
const plan = b.plan_name ?? b.plan ?? b.tier;
|
|
5351
|
+
return {
|
|
5352
|
+
usage: {
|
|
5353
|
+
primary: rolling,
|
|
5354
|
+
secondary: monthly,
|
|
5355
|
+
identity: { providerId: "chutes", loginMethod: "api", plan: typeof plan === "string" ? plan : void 0 },
|
|
5356
|
+
dataConfidence: rolling || monthly ? "percentOnly" : "unknown"
|
|
5357
|
+
}
|
|
5358
|
+
};
|
|
5359
|
+
}
|
|
5360
|
+
});
|
|
5361
|
+
var moonshotBase = (region) => region === "china" ? "https://api.moonshot.cn" : "https://api.moonshot.ai";
|
|
5362
|
+
var moonshotProvider = makeApiTokenProvider({
|
|
5363
|
+
id: "moonshot",
|
|
5364
|
+
metadata: {
|
|
5365
|
+
displayName: "Moonshot",
|
|
5366
|
+
sessionLabel: "Balance",
|
|
5367
|
+
weeklyLabel: "Balance",
|
|
5368
|
+
supportsCredits: true,
|
|
5369
|
+
dashboardUrl: "https://platform.moonshot.ai/console/info",
|
|
5370
|
+
color: "#16a34a"
|
|
5371
|
+
},
|
|
5372
|
+
envKeys: ["MOONSHOT_API_KEY", "MOONSHOT_KEY"],
|
|
5373
|
+
request: (s, ctx) => ({
|
|
5374
|
+
url: `${s.baseUrl ?? moonshotBase(s.region ?? ctx.host.env("MOONSHOT_REGION"))}/v1/users/me/balance`,
|
|
5375
|
+
headers: bearer(s.apiKey)
|
|
5376
|
+
}),
|
|
5377
|
+
map: (json) => {
|
|
5378
|
+
const d = obj2(obj2(json).data);
|
|
5379
|
+
return {
|
|
5380
|
+
usage: { identity: { providerId: "moonshot", loginMethod: "api" }, dataConfidence: "exact" },
|
|
5381
|
+
credits: { remaining: num4(d.available_balance) }
|
|
5382
|
+
};
|
|
5383
|
+
}
|
|
5384
|
+
});
|
|
5385
|
+
var kimiProvider = makeApiTokenProvider({
|
|
5386
|
+
id: "kimi",
|
|
5387
|
+
metadata: {
|
|
5388
|
+
displayName: "Kimi",
|
|
5389
|
+
sessionLabel: "Weekly",
|
|
5390
|
+
weeklyLabel: "Rate (5h)",
|
|
5391
|
+
dashboardUrl: "https://www.kimi.com/code/console",
|
|
5392
|
+
color: "#111111"
|
|
5393
|
+
},
|
|
5394
|
+
envKeys: ["KIMI_CODE_API_KEY"],
|
|
5395
|
+
request: (s, ctx) => ({
|
|
5396
|
+
url: `${s.baseUrl ?? ctx.host.env("KIMI_CODE_BASE_URL") ?? "https://api.kimi.com"}/coding/v1/usages`,
|
|
5397
|
+
headers: bearer(s.apiKey)
|
|
5398
|
+
}),
|
|
5399
|
+
map: (json) => {
|
|
5400
|
+
const b = obj2(json);
|
|
5401
|
+
const detail = obj2(b.usage);
|
|
5402
|
+
const limit = loose(detail.limit) ?? 0;
|
|
5403
|
+
const used = loose(detail.used) ?? (limit && loose(detail.remaining) !== void 0 ? limit - loose(detail.remaining) : 0);
|
|
5404
|
+
const resetTime = detail.resetTime ?? detail.resetAt ?? detail.reset_time;
|
|
5405
|
+
const rate = obj2(obj2(Array.isArray(b.limits) ? b.limits[0] : void 0).detail);
|
|
5406
|
+
const rateLimit = loose(rate.limit);
|
|
5407
|
+
const rateUsed = loose(rate.used);
|
|
5408
|
+
const secondary = rateLimit !== void 0 ? { usedPercent: pct(rateUsed ?? 0, rateLimit), windowMinutes: 300 } : void 0;
|
|
5409
|
+
return {
|
|
5410
|
+
usage: {
|
|
5411
|
+
primary: { usedPercent: pct(used, limit), resetsAt: typeof resetTime === "string" ? resetTime : void 0 },
|
|
5412
|
+
secondary,
|
|
5413
|
+
identity: { providerId: "kimi", loginMethod: "api" },
|
|
5414
|
+
dataConfidence: "percentOnly"
|
|
5415
|
+
}
|
|
5416
|
+
};
|
|
5417
|
+
}
|
|
5418
|
+
});
|
|
5419
|
+
var kimik2Provider = makeApiTokenProvider({
|
|
5420
|
+
id: "kimik2",
|
|
5421
|
+
metadata: {
|
|
5422
|
+
displayName: "Kimi K2",
|
|
5423
|
+
sessionLabel: "Credits",
|
|
5424
|
+
weeklyLabel: "Credits",
|
|
5425
|
+
supportsCredits: true,
|
|
5426
|
+
dashboardUrl: "https://kimi-k2.ai",
|
|
5427
|
+
color: "#111111"
|
|
5428
|
+
},
|
|
5429
|
+
envKeys: ["KIMI_K2_API_KEY", "KIMI_API_KEY", "KIMI_KEY"],
|
|
5430
|
+
request: (s) => ({ url: "https://kimi-k2.ai/api/user/credits", headers: bearer(s.apiKey) }),
|
|
5431
|
+
map: (json) => {
|
|
5432
|
+
const b = obj2(json);
|
|
5433
|
+
const nested = { ...obj2(b.data), ...obj2(b.result), ...obj2(b.usage), ...obj2(b.credits) };
|
|
5434
|
+
const pick = (keys) => {
|
|
5435
|
+
for (const k of keys) {
|
|
5436
|
+
const v = loose(b[k]) ?? loose(nested[k]);
|
|
5437
|
+
if (v !== void 0)
|
|
5438
|
+
return v;
|
|
5439
|
+
}
|
|
5440
|
+
return void 0;
|
|
5441
|
+
};
|
|
5442
|
+
const remaining = pick([
|
|
5443
|
+
"credits_remaining",
|
|
5444
|
+
"creditsRemaining",
|
|
5445
|
+
"remaining_credits",
|
|
5446
|
+
"remainingCredits",
|
|
5447
|
+
"available_credits",
|
|
5448
|
+
"availableCredits",
|
|
5449
|
+
"credits_left",
|
|
5450
|
+
"creditsLeft",
|
|
5451
|
+
"remaining"
|
|
5452
|
+
]) ?? 0;
|
|
5453
|
+
return {
|
|
5454
|
+
usage: { identity: { providerId: "kimik2", loginMethod: "api" }, dataConfidence: "exact" },
|
|
5455
|
+
credits: { remaining }
|
|
5456
|
+
};
|
|
5457
|
+
}
|
|
5458
|
+
});
|
|
5459
|
+
var zaiBase = (region) => region === "bigmodel-cn" ? "https://open.bigmodel.cn" : "https://api.z.ai";
|
|
5460
|
+
var ZAI_UNIT_MINUTES = { 1: 1440, 3: 60, 5: 1, 6: 10080 };
|
|
5461
|
+
var zaiWindow = (raw) => {
|
|
5462
|
+
const limit = loose(raw.usage) ?? 0;
|
|
5463
|
+
const current = loose(raw.currentValue);
|
|
5464
|
+
const remaining = loose(raw.remaining);
|
|
5465
|
+
const used = current ?? (remaining !== void 0 ? Math.max(0, limit - remaining) : void 0);
|
|
5466
|
+
const explicit = loose(raw.percentage);
|
|
5467
|
+
const usedPercent = used !== void 0 && limit > 0 ? pct(used, limit) : explicit ?? 0;
|
|
5468
|
+
const unit = loose(raw.unit);
|
|
5469
|
+
const number = loose(raw.number);
|
|
5470
|
+
const resetMs = loose(raw.nextResetTime);
|
|
5471
|
+
return {
|
|
5472
|
+
usedPercent,
|
|
5473
|
+
windowMinutes: unit !== void 0 && number !== void 0 ? (ZAI_UNIT_MINUTES[unit] ?? 0) * number : void 0,
|
|
5474
|
+
resetsAt: resetMs !== void 0 ? new Date(resetMs).toISOString() : void 0
|
|
5475
|
+
};
|
|
5476
|
+
};
|
|
5477
|
+
var zaiProvider = makeApiTokenProvider({
|
|
5478
|
+
id: "zai",
|
|
5479
|
+
metadata: {
|
|
5480
|
+
displayName: "z.ai",
|
|
5481
|
+
sessionLabel: "Token quota",
|
|
5482
|
+
weeklyLabel: "Time quota",
|
|
5483
|
+
dashboardUrl: "https://z.ai/manage-apikey/coding-plan/personal/my-plan",
|
|
5484
|
+
color: "#3b82f6"
|
|
5485
|
+
},
|
|
5486
|
+
envKeys: ["Z_AI_API_KEY"],
|
|
5487
|
+
baseUrlEnv: ["Z_AI_API_HOST"],
|
|
5488
|
+
request: (s, ctx) => ({
|
|
5489
|
+
url: `${resolveZaiBase(s, ctx.host.env("Z_AI_API_HOST"))}/api/monitor/usage/quota/limit`,
|
|
5490
|
+
headers: { ...bearer(s.apiKey), accept: "application/json" }
|
|
5491
|
+
}),
|
|
5492
|
+
map: (json) => {
|
|
5493
|
+
const data = obj2(obj2(json).data);
|
|
5494
|
+
const limits = Array.isArray(data.limits) ? data.limits : [];
|
|
5495
|
+
const tokens = limits.filter((l) => l.type === "TOKENS_LIMIT").map(zaiWindow);
|
|
5496
|
+
const time = limits.find((l) => l.type === "TIME_LIMIT");
|
|
5497
|
+
const plan = data.planName ?? data.plan ?? data.planType ?? data.packageName;
|
|
5498
|
+
return {
|
|
5499
|
+
usage: {
|
|
5500
|
+
primary: tokens[0],
|
|
5501
|
+
secondary: time ? zaiWindow(time) : void 0,
|
|
5502
|
+
tertiary: tokens[1],
|
|
5503
|
+
identity: { providerId: "zai", loginMethod: "api", plan: typeof plan === "string" ? plan : void 0 },
|
|
5504
|
+
dataConfidence: tokens.length || time ? "percentOnly" : "unknown"
|
|
5505
|
+
}
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
5508
|
+
});
|
|
5509
|
+
var resolveZaiBase = (s, hostEnv) => s.baseUrl ?? hostEnv ?? zaiBase(s.region);
|
|
5510
|
+
var openaiProvider = makeApiTokenProvider({
|
|
5511
|
+
id: "openai",
|
|
5512
|
+
metadata: {
|
|
5513
|
+
displayName: "OpenAI",
|
|
5514
|
+
sessionLabel: "Credits used",
|
|
5515
|
+
weeklyLabel: "Credit grant",
|
|
5516
|
+
supportsCredits: true,
|
|
5517
|
+
dashboardUrl: "https://platform.openai.com/usage",
|
|
5518
|
+
statusPageUrl: "https://status.openai.com",
|
|
5519
|
+
color: "#0f826e"
|
|
5520
|
+
},
|
|
5521
|
+
envKeys: ["OPENAI_ADMIN_KEY", "OPENAI_API_KEY"],
|
|
5522
|
+
request: (s) => ({
|
|
5523
|
+
url: "https://api.openai.com/v1/dashboard/billing/credit_grants",
|
|
5524
|
+
headers: bearer(s.apiKey)
|
|
5525
|
+
}),
|
|
5526
|
+
map: (json, now) => {
|
|
5527
|
+
const b = obj2(json);
|
|
5528
|
+
const granted = num4(b.total_granted);
|
|
5529
|
+
const used = num4(b.total_used);
|
|
5530
|
+
const available = num4(b.total_available);
|
|
5531
|
+
return {
|
|
5532
|
+
usage: {
|
|
5533
|
+
primary: { usedPercent: pct(used, granted) },
|
|
5534
|
+
identity: { providerId: "openai", loginMethod: "api" },
|
|
5535
|
+
providerCost: { used, limit: granted, currencyCode: "USD", period: "grant", updatedAt: now.toISOString() },
|
|
5536
|
+
dataConfidence: "exact"
|
|
5537
|
+
},
|
|
5538
|
+
credits: { remaining: available }
|
|
5539
|
+
};
|
|
5540
|
+
}
|
|
5541
|
+
});
|
|
5542
|
+
var stripV12 = (base) => base.replace(/\/v1\/?$/, "");
|
|
5543
|
+
var litellmProvider = makeApiTokenProvider({
|
|
5544
|
+
id: "litellm",
|
|
5545
|
+
metadata: {
|
|
5546
|
+
displayName: "LiteLLM",
|
|
5547
|
+
sessionLabel: "Key spend",
|
|
5548
|
+
weeklyLabel: "Budget",
|
|
5549
|
+
dashboardUrl: "https://docs.litellm.ai/docs/proxy/cost_tracking",
|
|
5550
|
+
color: "#22c55e"
|
|
5551
|
+
},
|
|
5552
|
+
envKeys: ["LITELLM_API_KEY"],
|
|
5553
|
+
baseUrlEnv: ["LITELLM_BASE_URL"],
|
|
5554
|
+
requireBaseUrl: true,
|
|
5555
|
+
request: (s) => ({ url: `${stripV12(s.baseUrl)}/key/info`, headers: bearer(s.apiKey) }),
|
|
5556
|
+
map: (json, now) => {
|
|
5557
|
+
const info = obj2(obj2(json).info);
|
|
5558
|
+
const spend = num4(info.spend);
|
|
5559
|
+
return {
|
|
5560
|
+
usage: {
|
|
5561
|
+
identity: {
|
|
5562
|
+
providerId: "litellm",
|
|
5563
|
+
loginMethod: "api",
|
|
5564
|
+
accountOrganization: typeof info.team_id === "string" ? info.team_id : void 0,
|
|
5565
|
+
accountEmail: typeof info.user_id === "string" ? info.user_id : void 0,
|
|
5566
|
+
plan: typeof info.key_name === "string" ? info.key_name : void 0
|
|
5567
|
+
},
|
|
5568
|
+
providerCost: { used: spend, currencyCode: "USD", period: "key", updatedAt: now.toISOString() },
|
|
5569
|
+
subscriptionExpiresAt: typeof info.expires === "string" ? info.expires : void 0,
|
|
5570
|
+
dataConfidence: "exact"
|
|
5571
|
+
}
|
|
5572
|
+
};
|
|
5573
|
+
}
|
|
5574
|
+
});
|
|
5575
|
+
var llmProxyV1 = (base) => /\/v1\/?$/.test(base) ? base.replace(/\/$/, "") : `${base.replace(/\/$/, "")}/v1`;
|
|
5576
|
+
var llmproxyProvider = makeApiTokenProvider({
|
|
5577
|
+
id: "llmproxy",
|
|
5578
|
+
metadata: {
|
|
5579
|
+
displayName: "LLM Proxy",
|
|
5580
|
+
sessionLabel: "Quota used",
|
|
5581
|
+
weeklyLabel: "Approx. spend",
|
|
5582
|
+
dashboardUrl: "https://github.com/hzruo/LLM-API-Key-Proxy",
|
|
5583
|
+
color: "#8b5cf6"
|
|
5584
|
+
},
|
|
5585
|
+
envKeys: ["LLM_PROXY_API_KEY"],
|
|
5586
|
+
baseUrlEnv: ["LLM_PROXY_BASE_URL"],
|
|
5587
|
+
requireBaseUrl: true,
|
|
5588
|
+
request: (s) => ({ url: `${llmProxyV1(s.baseUrl)}/quota-stats`, headers: bearer(s.apiKey) }),
|
|
5589
|
+
map: (json, now) => {
|
|
5590
|
+
const b = obj2(json);
|
|
5591
|
+
const providers = obj2(b.providers);
|
|
5592
|
+
const summary = obj2(b.summary);
|
|
5593
|
+
let minRemaining = 100;
|
|
5594
|
+
let earliestReset;
|
|
5595
|
+
let sumTokens = 0;
|
|
5596
|
+
let sumRequests = 0;
|
|
5597
|
+
let sumCost = 0;
|
|
5598
|
+
for (const p of Object.values(providers)) {
|
|
5599
|
+
const stats = obj2(p);
|
|
5600
|
+
sumRequests += num4(stats.total_requests);
|
|
5601
|
+
sumCost += num4(stats.approx_cost);
|
|
5602
|
+
const t = obj2(stats.tokens);
|
|
5603
|
+
sumTokens += num4(t.input_cached) + num4(t.input_uncached) + num4(t.output);
|
|
5604
|
+
const groups = Array.isArray(stats.quota_groups) ? stats.quota_groups : Object.values(obj2(stats.quota_groups));
|
|
5605
|
+
for (const g of groups) {
|
|
5606
|
+
const grp = obj2(g);
|
|
5607
|
+
const rem = loose(grp.remaining_percent);
|
|
5608
|
+
if (rem !== void 0 && rem < minRemaining)
|
|
5609
|
+
minRemaining = rem;
|
|
5610
|
+
const reset = typeof grp.reset_time === "string" ? grp.reset_time : void 0;
|
|
5611
|
+
if (reset && (!earliestReset || reset < earliestReset))
|
|
5612
|
+
earliestReset = reset;
|
|
5613
|
+
}
|
|
5614
|
+
}
|
|
5615
|
+
const totalRequests = numberOrUndefined(summary.total_requests) ?? sumRequests;
|
|
5616
|
+
const totalTokens = numberOrUndefined(summary.total_tokens) ?? sumTokens;
|
|
5617
|
+
const approxCost = numberOrUndefined(summary.approx_cost) ?? sumCost;
|
|
5618
|
+
return {
|
|
5619
|
+
usage: {
|
|
5620
|
+
primary: { usedPercent: Math.min(100, Math.max(0, 100 - minRemaining)), resetsAt: earliestReset },
|
|
5621
|
+
identity: { providerId: "llmproxy", loginMethod: "api" },
|
|
5622
|
+
totals: { tokens: totalTokens, requests: totalRequests },
|
|
5623
|
+
providerCost: approxCost > 0 ? { used: approxCost, currencyCode: "USD", period: "approx", updatedAt: now.toISOString() } : void 0,
|
|
5624
|
+
dataConfidence: "exact"
|
|
5625
|
+
}
|
|
5626
|
+
};
|
|
5627
|
+
}
|
|
5628
|
+
});
|
|
5629
|
+
var minimaxApiBase = (region) => region === "cn" || region === "china" ? "https://api.minimaxi.com" : "https://api.minimax.io";
|
|
5630
|
+
var minimaxWindow = (m, prefix, windowMinutes) => {
|
|
5631
|
+
const remainingPct = loose(m[`${prefix}_remaining_percent`]);
|
|
5632
|
+
const total = loose(m[`${prefix}_total_count`]);
|
|
5633
|
+
const usedCount = loose(m[`${prefix}_usage_count`]);
|
|
5634
|
+
let usedPercent;
|
|
5635
|
+
if (remainingPct !== void 0)
|
|
5636
|
+
usedPercent = 100 - remainingPct;
|
|
5637
|
+
else if (total !== void 0 && usedCount !== void 0)
|
|
5638
|
+
usedPercent = pct(usedCount, total);
|
|
5639
|
+
if (usedPercent === void 0)
|
|
5640
|
+
return void 0;
|
|
5641
|
+
return { usedPercent: Math.min(100, Math.max(0, usedPercent)), windowMinutes };
|
|
5642
|
+
};
|
|
5643
|
+
var minimaxProvider = makeApiTokenProvider({
|
|
5644
|
+
id: "minimax",
|
|
5645
|
+
metadata: {
|
|
5646
|
+
displayName: "MiniMax",
|
|
5647
|
+
sessionLabel: "Interval",
|
|
5648
|
+
weeklyLabel: "Weekly",
|
|
5649
|
+
dashboardUrl: "https://platform.minimax.io/user-center/payment/coding-plan",
|
|
5650
|
+
color: "#f43f5e"
|
|
5651
|
+
},
|
|
5652
|
+
envKeys: ["MINIMAX_CODING_API_KEY", "MINIMAX_API_KEY"],
|
|
5653
|
+
request: (s, ctx) => ({
|
|
5654
|
+
url: `${s.baseUrl ?? minimaxApiBase(s.region ?? ctx.host.env("MINIMAX_REGION"))}/v1/api/openplatform/coding_plan/remains`,
|
|
5655
|
+
headers: { ...bearer(s.apiKey), accept: "application/json", "MM-API-Source": "HanzoUsage" }
|
|
5656
|
+
}),
|
|
5657
|
+
map: (json) => {
|
|
5658
|
+
const data = obj2(obj2(json).data);
|
|
5659
|
+
const models = Array.isArray(data.model_remains) ? data.model_remains : [];
|
|
5660
|
+
const m = obj2(models[0]);
|
|
5661
|
+
const plan = data.plan_name ?? data.current_plan_title ?? data.current_subscribe_title;
|
|
5662
|
+
const points = loose(data.points_balance) ?? loose(data.balance);
|
|
5663
|
+
return {
|
|
5664
|
+
usage: {
|
|
5665
|
+
primary: minimaxWindow(m, "current_interval", 0),
|
|
5666
|
+
secondary: minimaxWindow(m, "current_weekly", 10080),
|
|
5667
|
+
identity: { providerId: "minimax", loginMethod: "api", plan: typeof plan === "string" ? plan : void 0 },
|
|
5668
|
+
dataConfidence: models.length ? "percentOnly" : "unknown"
|
|
5669
|
+
},
|
|
5670
|
+
credits: points !== void 0 ? { remaining: points } : void 0
|
|
5671
|
+
};
|
|
5672
|
+
}
|
|
5673
|
+
});
|
|
5674
|
+
|
|
5675
|
+
// ../../node_modules/.pnpm/@hanzo+usage@0.1.6_react@18.3.1/node_modules/@hanzo/usage/dist/index.js
|
|
5676
|
+
var providerRegistry = {
|
|
5677
|
+
hanzo: hanzoProvider,
|
|
5678
|
+
codex: codexProvider,
|
|
5679
|
+
claude: claudeProvider,
|
|
5680
|
+
openai: openaiProvider,
|
|
5681
|
+
openrouter: openrouterProvider,
|
|
5682
|
+
deepseek: deepseekProvider,
|
|
5683
|
+
elevenlabs: elevenlabsProvider,
|
|
5684
|
+
deepgram: deepgramProvider,
|
|
5685
|
+
groq: groqProvider,
|
|
5686
|
+
poe: poeProvider,
|
|
5687
|
+
venice: veniceProvider,
|
|
5688
|
+
chutes: chutesProvider,
|
|
5689
|
+
moonshot: moonshotProvider,
|
|
5690
|
+
kimi: kimiProvider,
|
|
5691
|
+
kimik2: kimik2Provider,
|
|
5692
|
+
zai: zaiProvider,
|
|
5693
|
+
litellm: litellmProvider,
|
|
5694
|
+
llmproxy: llmproxyProvider,
|
|
5695
|
+
minimax: minimaxProvider,
|
|
5696
|
+
byo: byoProvider
|
|
5697
|
+
};
|
|
5698
|
+
var allProviders = Object.values(providerRegistry);
|
|
5699
|
+
var trackedProviderIds = Object.keys(providerRegistry);
|
|
5700
|
+
|
|
5701
|
+
// src/shared/usage.ts
|
|
5702
|
+
var http = async (req) => {
|
|
5703
|
+
const controller = new AbortController();
|
|
5704
|
+
const timeout = req.timeoutMs ? setTimeout(() => controller.abort(), req.timeoutMs) : void 0;
|
|
5705
|
+
try {
|
|
5706
|
+
const res = await fetch(req.url, {
|
|
5707
|
+
method: req.method ?? "GET",
|
|
5708
|
+
headers: req.headers,
|
|
5709
|
+
body: req.body,
|
|
5710
|
+
credentials: "include",
|
|
5711
|
+
signal: controller.signal
|
|
5712
|
+
});
|
|
5713
|
+
const headers = {};
|
|
5714
|
+
res.headers.forEach((v, k) => {
|
|
5715
|
+
headers[k] = v;
|
|
5716
|
+
});
|
|
5717
|
+
return { status: res.status, headers, text: await res.text() };
|
|
5718
|
+
} finally {
|
|
5719
|
+
if (timeout) clearTimeout(timeout);
|
|
5720
|
+
}
|
|
5721
|
+
};
|
|
5722
|
+
var browserHost = {
|
|
5723
|
+
readTextFile: async () => void 0,
|
|
5724
|
+
listDir: async () => [],
|
|
5725
|
+
writeTextFile: async () => {
|
|
5726
|
+
},
|
|
5727
|
+
http,
|
|
5728
|
+
env: () => void 0,
|
|
5729
|
+
homeDir: () => "",
|
|
5730
|
+
now: () => /* @__PURE__ */ new Date()
|
|
5731
|
+
};
|
|
5732
|
+
var isAuthError = (text) => /\b(401|403)\b/.test(text);
|
|
5733
|
+
var outcomeError = (providerHost, outcome) => {
|
|
5734
|
+
const attempt = [...outcome.attempts].reverse().find((a) => a.error);
|
|
5735
|
+
const detail = (attempt == null ? void 0 : attempt.error) ?? "no data";
|
|
5736
|
+
return isAuthError(detail) ? `Open ${providerHost} to sign in` : detail;
|
|
5737
|
+
};
|
|
5738
|
+
var fetchClaude = async () => {
|
|
5739
|
+
const { displayName, color, dashboardUrl } = claudeProvider.metadata;
|
|
5740
|
+
const base = { providerId: "claude", displayName, color, dashboardUrl };
|
|
5741
|
+
try {
|
|
5742
|
+
const outcome = await runPipeline(claudeProvider, {
|
|
5743
|
+
host: browserHost,
|
|
5744
|
+
sourceMode: "web",
|
|
5745
|
+
settings: { cookieHeader: "" }
|
|
5746
|
+
});
|
|
5747
|
+
if (outcome.result) return { ...base, snapshot: outcome.result.usage };
|
|
5748
|
+
return { ...base, error: outcomeError("claude.ai", outcome) };
|
|
5749
|
+
} catch (e) {
|
|
5750
|
+
return { ...base, error: e instanceof Error ? e.message : String(e) };
|
|
5751
|
+
}
|
|
5752
|
+
};
|
|
5753
|
+
var toWindow3 = (w) => {
|
|
5754
|
+
if (!w || typeof w.used_percent !== "number") return void 0;
|
|
5755
|
+
return {
|
|
5756
|
+
usedPercent: w.used_percent,
|
|
5757
|
+
windowMinutes: w.limit_window_seconds ? Math.round(w.limit_window_seconds / 60) : void 0,
|
|
5758
|
+
resetsAt: w.reset_at ? new Date(w.reset_at * 1e3).toISOString() : void 0
|
|
5759
|
+
};
|
|
5760
|
+
};
|
|
5761
|
+
var fetchCodex = async () => {
|
|
5762
|
+
var _a, _b;
|
|
5763
|
+
const { displayName, color, dashboardUrl } = codexProvider.metadata;
|
|
5764
|
+
const base = { providerId: "codex", displayName, color, dashboardUrl };
|
|
5765
|
+
try {
|
|
5766
|
+
const res = await http({
|
|
5767
|
+
url: "https://chatgpt.com/backend-api/wham/usage",
|
|
5768
|
+
headers: { Accept: "application/json" },
|
|
5769
|
+
timeoutMs: 3e4
|
|
5770
|
+
});
|
|
5771
|
+
if (res.status !== 200) {
|
|
5772
|
+
return {
|
|
5773
|
+
...base,
|
|
5774
|
+
error: isAuthError(String(res.status)) ? "Open chatgpt.com to sign in" : `HTTP ${res.status}`
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
const body = JSON.parse(res.text);
|
|
5778
|
+
const snapshot = {
|
|
5779
|
+
providerId: "codex",
|
|
5780
|
+
primary: toWindow3((_a = body.rate_limit) == null ? void 0 : _a.primary_window),
|
|
5781
|
+
secondary: toWindow3((_b = body.rate_limit) == null ? void 0 : _b.secondary_window),
|
|
5782
|
+
identity: { providerId: "codex", plan: body.plan_type, loginMethod: "web" },
|
|
5783
|
+
dataConfidence: "percentOnly",
|
|
5784
|
+
updatedAt: browserHost.now().toISOString()
|
|
5785
|
+
};
|
|
5786
|
+
return { ...base, snapshot };
|
|
5787
|
+
} catch (e) {
|
|
5788
|
+
return { ...base, error: e instanceof Error ? e.message : String(e) };
|
|
5789
|
+
}
|
|
5790
|
+
};
|
|
5791
|
+
var fetchAllUsage = async () => Promise.all([fetchClaude(), fetchCodex()]);
|
|
5792
|
+
|
|
4380
5793
|
// src/chat-client.ts
|
|
4381
5794
|
var API_BASE = API_BASE_URL;
|
|
4382
5795
|
async function listModels(token) {
|
|
@@ -4676,19 +6089,19 @@ var PageMonitor = class {
|
|
|
4676
6089
|
Object.assign(this.config, config);
|
|
4677
6090
|
}
|
|
4678
6091
|
// --- Helpers ---
|
|
4679
|
-
formatRemoteObject(
|
|
4680
|
-
if (!
|
|
4681
|
-
if (
|
|
4682
|
-
if (
|
|
4683
|
-
if (
|
|
4684
|
-
if (
|
|
4685
|
-
if (
|
|
4686
|
-
if (
|
|
4687
|
-
const props =
|
|
6092
|
+
formatRemoteObject(obj3) {
|
|
6093
|
+
if (!obj3) return "undefined";
|
|
6094
|
+
if (obj3.value !== void 0) return String(obj3.value);
|
|
6095
|
+
if (obj3.description) return obj3.description;
|
|
6096
|
+
if (obj3.type === "undefined") return "undefined";
|
|
6097
|
+
if (obj3.type === "object" && obj3.subtype === "null") return "null";
|
|
6098
|
+
if (obj3.unserializableValue) return obj3.unserializableValue;
|
|
6099
|
+
if (obj3.preview) {
|
|
6100
|
+
const props = obj3.preview.properties || [];
|
|
4688
6101
|
const pairs = props.map((p) => `${p.name}: ${p.value ?? p.type}`).join(", ");
|
|
4689
|
-
return
|
|
6102
|
+
return obj3.preview.type === "object" ? `{${pairs}}` : `[${pairs}]`;
|
|
4690
6103
|
}
|
|
4691
|
-
return
|
|
6104
|
+
return obj3.type || "unknown";
|
|
4692
6105
|
}
|
|
4693
6106
|
truncate(str) {
|
|
4694
6107
|
if (str.length <= this.config.stringSizeLimit) return str;
|
|
@@ -7204,6 +8617,18 @@ async function handleMessage(request, sender, sendResponse) {
|
|
|
7204
8617
|
})();
|
|
7205
8618
|
break;
|
|
7206
8619
|
}
|
|
8620
|
+
// --- AI provider usage (Claude + Codex, via @hanzo/usage) ---
|
|
8621
|
+
case "usage.fetch": {
|
|
8622
|
+
(async () => {
|
|
8623
|
+
try {
|
|
8624
|
+
const providers = await fetchAllUsage();
|
|
8625
|
+
sendResponse({ success: true, providers });
|
|
8626
|
+
} catch (e) {
|
|
8627
|
+
sendResponse({ success: false, error: e.message });
|
|
8628
|
+
}
|
|
8629
|
+
})();
|
|
8630
|
+
break;
|
|
8631
|
+
}
|
|
7207
8632
|
}
|
|
7208
8633
|
}
|
|
7209
8634
|
chrome.tabs.onRemoved.addListener((tabId) => {
|