@liyang8246/dsh-accounts 0.1.12 → 0.1.14
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/lib/client.js +10 -4
- package/lib/index.js +26 -62
- package/package.json +1 -2
package/lib/client.js
CHANGED
|
@@ -182,7 +182,8 @@
|
|
|
182
182
|
}
|
|
183
183
|
function activeQuota(snapshot, channel) {
|
|
184
184
|
const quota = snapshot?.accounts.find((account) => account.channel === channel && account.active)?.quota;
|
|
185
|
-
|
|
185
|
+
if (!quota) return [];
|
|
186
|
+
return measuredWindows(quota.windows);
|
|
186
187
|
}
|
|
187
188
|
function leftOf(window) {
|
|
188
189
|
return window.exhausted ? 0 : Math.min(100, Math.max(0, 100 - window.usedPercent));
|
|
@@ -542,6 +543,7 @@
|
|
|
542
543
|
}
|
|
543
544
|
// src/client/composer-quota.tsx
|
|
544
545
|
function createComposerQuota(React, ctx, store, QuotaBars) {
|
|
546
|
+
let lastChannel;
|
|
545
547
|
return function ComposerQuota({ sessionId }) {
|
|
546
548
|
React.useSyncExternalStore((fn) => ctx.locale.subscribe(fn), () => ctx.locale.getSnapshot());
|
|
547
549
|
const models = ctx.get("modelDirectories");
|
|
@@ -554,7 +556,11 @@
|
|
|
554
556
|
}, [models, sessionId]);
|
|
555
557
|
const state = React.useSyncExternalStore(React.useCallback((listener) => modelStore ? modelStore.subscribe(listener) : () => {}, [modelStore]), React.useCallback(() => modelStore?.getSnapshot(), [modelStore]));
|
|
556
558
|
const data = React.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
557
|
-
const
|
|
559
|
+
const current = state?.current;
|
|
560
|
+
let channel;
|
|
561
|
+
if (current === null) channel = lastChannel;
|
|
562
|
+
else if (current !== void 0) channel = channelOf(current.provider);
|
|
563
|
+
if (channel !== void 0) lastChannel = channel;
|
|
558
564
|
React.useEffect(() => {
|
|
559
565
|
if (channel) store.reload().catch(() => {});
|
|
560
566
|
}, [channel]);
|
|
@@ -698,7 +704,7 @@
|
|
|
698
704
|
// src/client/quota.tsx
|
|
699
705
|
function createQuotaComponents(React, t) {
|
|
700
706
|
function Quota({ quota }) {
|
|
701
|
-
const windows =
|
|
707
|
+
const windows = measuredWindows(quota?.windows ?? []);
|
|
702
708
|
return /* @__PURE__ */ React.createElement("div", { className: windows.length ? void 0 : "zph-quota-unavailable" }, windows.length ? /* @__PURE__ */ React.createElement("div", { className: "zph-quota" }, windows.map((window) => /* @__PURE__ */ React.createElement("div", {
|
|
703
709
|
key: window.period,
|
|
704
710
|
className: "zph-window"
|
|
@@ -707,7 +713,7 @@
|
|
|
707
713
|
"data-level": levelOf(window),
|
|
708
714
|
role: "img",
|
|
709
715
|
"aria-label": `${window.period} ${t("left")} ${Math.round(leftOf(window))}%`
|
|
710
|
-
}, /* @__PURE__ */ React.createElement("b", { style: { width: `${leftOf(window)}%` } })), window.used !== void 0 && window.limit !== void 0 && /* @__PURE__ */ React.createElement("div", { className: "zph-muted" }, `${window.used} / ${window.limit} ${window.unit || ""}`)))) : /* @__PURE__ */ React.createElement("p", { className: "zph-muted" }, t(quota ? "unavailable" : "notFetched")), quota?.
|
|
716
|
+
}, /* @__PURE__ */ React.createElement("b", { style: { width: `${leftOf(window)}%` } })), window.used !== void 0 && window.limit !== void 0 && /* @__PURE__ */ React.createElement("div", { className: "zph-muted" }, `${window.used} / ${window.limit} ${window.unit || ""}`)))) : /* @__PURE__ */ React.createElement("p", { className: "zph-muted" }, t(quota ? "unavailable" : "notFetched")), quota?.windows.filter((window) => window.period === "other").map((window, index) => /* @__PURE__ */ React.createElement("div", {
|
|
711
717
|
className: "zph-muted",
|
|
712
718
|
key: index
|
|
713
719
|
}, `${window.label || t("other")}: ${window.usedPercent?.toFixed(1) ?? "—"}% ${t("used")}`)), quota?.reason && /* @__PURE__ */ React.createElement("p", { className: quota.status === "error" ? "zph-error" : "zph-muted" }, quota.reason));
|
package/lib/index.js
CHANGED
|
@@ -7317,12 +7317,15 @@ var ModelAccountsService = class {
|
|
|
7317
7317
|
this.accounts.saveQuota(id, quota).catch(() => {});
|
|
7318
7318
|
}
|
|
7319
7319
|
} catch (error) {
|
|
7320
|
-
if (!this.controller.signal.aborted && (await this.accounts.list()).some((account) => account.id === id))
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7320
|
+
if (!this.controller.signal.aborted && (await this.accounts.list()).some((account) => account.id === id)) {
|
|
7321
|
+
const previous = await this.lastGoodQuota(id);
|
|
7322
|
+
this.quotas.set(id, {
|
|
7323
|
+
status: "error",
|
|
7324
|
+
fetchedAt: previous?.fetchedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
7325
|
+
windows: previous?.windows ?? [],
|
|
7326
|
+
reason: safeError(error)
|
|
7327
|
+
});
|
|
7328
|
+
}
|
|
7326
7329
|
}
|
|
7327
7330
|
})();
|
|
7328
7331
|
this.fetching.set(id, operation);
|
|
@@ -7332,6 +7335,20 @@ var ModelAccountsService = class {
|
|
|
7332
7335
|
this.fetching.delete(id);
|
|
7333
7336
|
}
|
|
7334
7337
|
}
|
|
7338
|
+
/**
|
|
7339
|
+
* Read the last measurement a failed refresh should keep showing.
|
|
7340
|
+
* @param id - account whose quota is being reported.
|
|
7341
|
+
* @returns the cached view, else the persisted one, else the bare cached one.
|
|
7342
|
+
*/
|
|
7343
|
+
async lastGoodQuota(id) {
|
|
7344
|
+
const cached = this.quotas.get(id);
|
|
7345
|
+
if (cached?.windows.length) return cached;
|
|
7346
|
+
try {
|
|
7347
|
+
return (await this.accounts.quotas())[id] ?? cached;
|
|
7348
|
+
} catch {
|
|
7349
|
+
return cached;
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7335
7352
|
async resetCredit(id, signal) {
|
|
7336
7353
|
const view = (await this.accounts.list()).find((account) => account.id === id);
|
|
7337
7354
|
if (!view) throw new Error("Account not found");
|
|
@@ -7339,7 +7356,7 @@ var ModelAccountsService = class {
|
|
|
7339
7356
|
await consumeCodexResetCredit(await this.accounts.resolve(view.channel, signal, id), signal);
|
|
7340
7357
|
await this.refreshQuota(id, signal);
|
|
7341
7358
|
}
|
|
7342
|
-
async dispatch(raw,
|
|
7359
|
+
async dispatch(raw, signal) {
|
|
7343
7360
|
if (this.controller.signal.aborted) throw new Error("Plugin is unloading");
|
|
7344
7361
|
const args = record(raw);
|
|
7345
7362
|
const action = text(args.action, "action");
|
|
@@ -7347,7 +7364,7 @@ var ModelAccountsService = class {
|
|
|
7347
7364
|
case "list": {
|
|
7348
7365
|
const snapshot = await this.snapshot();
|
|
7349
7366
|
const login = this.logins.pending;
|
|
7350
|
-
return
|
|
7367
|
+
return login ? {
|
|
7351
7368
|
...snapshot,
|
|
7352
7369
|
login
|
|
7353
7370
|
} : snapshot;
|
|
@@ -7371,11 +7388,9 @@ var ModelAccountsService = class {
|
|
|
7371
7388
|
break;
|
|
7372
7389
|
}
|
|
7373
7390
|
case "reset_credit":
|
|
7374
|
-
if (origin !== "ui") throw new Error("Resetting quota is user-only; open Settings → Model Accounts");
|
|
7375
7391
|
await this.resetCredit(text(args.id, "account id"), signal);
|
|
7376
7392
|
break;
|
|
7377
7393
|
case "set_filter":
|
|
7378
|
-
if (origin !== "ui") throw new Error("The model filter is user-only; open Settings → Model Accounts");
|
|
7379
7394
|
await this.accounts.saveFilter(filterText(args.filter));
|
|
7380
7395
|
break;
|
|
7381
7396
|
case "refresh_quota": {
|
|
@@ -7386,7 +7401,6 @@ var ModelAccountsService = class {
|
|
|
7386
7401
|
break;
|
|
7387
7402
|
}
|
|
7388
7403
|
default:
|
|
7389
|
-
if (origin !== "ui") throw new Error("Authentication is user-only; open Settings → Model Accounts");
|
|
7390
7404
|
if (action !== "add_key") return this.logins.dispatch(action, args);
|
|
7391
7405
|
await this.accounts.add(channelFor(args.channel).id, text(args.label, "account label"), {
|
|
7392
7406
|
kind: "api-key",
|
|
@@ -29354,57 +29368,8 @@ const inject = [
|
|
|
29354
29368
|
"llm",
|
|
29355
29369
|
"credentials",
|
|
29356
29370
|
"connection",
|
|
29357
|
-
"tools",
|
|
29358
29371
|
"attachments"
|
|
29359
29372
|
];
|
|
29360
|
-
function accountTool(service) {
|
|
29361
|
-
return {
|
|
29362
|
-
name: "zephyr_accounts",
|
|
29363
|
-
description: "List model-channel accounts, select one active account per channel, rename/remove a saved login, or refresh quota. Removal does not revoke upstream access. Login and API-key entry are user-only in Settings → Model Accounts. Never returns tokens.",
|
|
29364
|
-
parameters: {
|
|
29365
|
-
type: "object",
|
|
29366
|
-
properties: {
|
|
29367
|
-
action: {
|
|
29368
|
-
type: "string",
|
|
29369
|
-
enum: [
|
|
29370
|
-
"list",
|
|
29371
|
-
"activate",
|
|
29372
|
-
"deactivate",
|
|
29373
|
-
"rename",
|
|
29374
|
-
"remove",
|
|
29375
|
-
"refresh_quota"
|
|
29376
|
-
]
|
|
29377
|
-
},
|
|
29378
|
-
channel: {
|
|
29379
|
-
type: "string",
|
|
29380
|
-
enum: channels.map((channel) => channel.id),
|
|
29381
|
-
description: "Required for activate/deactivate."
|
|
29382
|
-
},
|
|
29383
|
-
id: {
|
|
29384
|
-
type: "string",
|
|
29385
|
-
description: "Account id returned by list. Required for activate/rename/remove; omit to refresh all quotas."
|
|
29386
|
-
},
|
|
29387
|
-
label: {
|
|
29388
|
-
type: "string",
|
|
29389
|
-
description: "New display label, required for rename."
|
|
29390
|
-
}
|
|
29391
|
-
},
|
|
29392
|
-
required: ["action"],
|
|
29393
|
-
additionalProperties: false
|
|
29394
|
-
},
|
|
29395
|
-
output: {
|
|
29396
|
-
schema: {
|
|
29397
|
-
type: "object",
|
|
29398
|
-
additionalProperties: true
|
|
29399
|
-
},
|
|
29400
|
-
render: (_args, value) => [{
|
|
29401
|
-
type: "text",
|
|
29402
|
-
text: JSON.stringify(value)
|
|
29403
|
-
}]
|
|
29404
|
-
},
|
|
29405
|
-
execute: (args, exec) => service.dispatch(args, "agent", exec.signal)
|
|
29406
|
-
};
|
|
29407
|
-
}
|
|
29408
29373
|
function apply(ctx) {
|
|
29409
29374
|
const service = new ModelAccountsService(ctx);
|
|
29410
29375
|
const transport = createTransport(ctx, (channel, signal) => service.accounts.resolve(channel, signal), service.catalog, (channel, signal) => service.refreshCatalog(channel, signal));
|
|
@@ -29432,7 +29397,6 @@ function apply(ctx) {
|
|
|
29432
29397
|
registration?.();
|
|
29433
29398
|
};
|
|
29434
29399
|
});
|
|
29435
|
-
ctx.effect(() => ctx.tools.register(accountTool(service)));
|
|
29436
29400
|
ctx.effect(() => ctx.connection.fetch.register({
|
|
29437
29401
|
path: "/api/zephyr-models",
|
|
29438
29402
|
methods: ["POST"],
|
|
@@ -29440,7 +29404,7 @@ function apply(ctx) {
|
|
|
29440
29404
|
async fetch(request) {
|
|
29441
29405
|
try {
|
|
29442
29406
|
const args = await jsonResponse(new Response(request.body), 65536);
|
|
29443
|
-
const value = await service.dispatch(args,
|
|
29407
|
+
const value = await service.dispatch(args, request.signal);
|
|
29444
29408
|
return Response.json(value, { headers: { "Cache-Control": "no-store" } });
|
|
29445
29409
|
} catch (error) {
|
|
29446
29410
|
return Response.json({ error: safeError(error) }, {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liyang8246/dsh-accounts",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.14",
|
|
5
5
|
"description": "Independent multi-account Codex, OpenCode Go and CommandCode Go plugin for DeepSeek Harness.",
|
|
6
6
|
"repository": { "type": "git", "url": "https://github.com/liyang8246/dsh-zolin.git", "directory": "packages/dsh-accounts" },
|
|
7
7
|
"exports": {
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.5",
|
|
34
34
|
"@deepseek-ai/dsh-credentials": "0.2.1-rc.5",
|
|
35
35
|
"@deepseek-ai/dsh-llm": "0.2.1-rc.5",
|
|
36
|
-
"@deepseek-ai/dsh-tools": "0.2.1-rc.5",
|
|
37
36
|
"@earendil-works/pi-ai": "1.1.0"
|
|
38
37
|
},
|
|
39
38
|
"dsh": {
|