@klarkxy/dsh-model-hub 0.1.2 → 0.1.4
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 +8 -4
- package/docs/README.zh-CN.md +8 -4
- package/lib/client.inner.cjs +298 -115
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +298 -115
- package/lib/index.js +206 -182
- package/lib/index.js.map +1 -1
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +12 -12
package/lib/client.js
CHANGED
|
@@ -5,30 +5,7 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var module = { exports: {} };
|
|
6
6
|
var exports = module.exports;
|
|
7
7
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
8
|
-
//#region \0rolldown/runtime.js
|
|
9
|
-
var __create = Object.create;
|
|
10
|
-
var __defProp = Object.defineProperty;
|
|
11
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
14
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
-
var __copyProps = (to, from, except, desc) => {
|
|
16
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
-
key = keys[i];
|
|
18
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
-
get: ((k) => from[k]).bind(null, key),
|
|
20
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
return to;
|
|
24
|
-
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
26
|
-
value: mod,
|
|
27
|
-
enumerable: true
|
|
28
|
-
}) : target, mod));
|
|
29
|
-
//#endregion
|
|
30
8
|
let react = require("react");
|
|
31
|
-
react = __toESM(react, 1);
|
|
32
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
10
|
let react_dom = require("react-dom");
|
|
34
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -67,12 +44,68 @@ function normalizeModelRoute(value) {
|
|
|
67
44
|
}
|
|
68
45
|
//#endregion
|
|
69
46
|
//#region ../dsh-model-route/src/catalog.ts
|
|
47
|
+
/** Both services are required: Cordis checks the nested namespace separately. */
|
|
48
|
+
const MODEL_CATALOG_INJECT = ["remote", "remote.session"];
|
|
70
49
|
function asRecord(value) {
|
|
71
50
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
72
51
|
}
|
|
73
52
|
function asText(value) {
|
|
74
53
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
75
54
|
}
|
|
55
|
+
/** A useful diagnostic even when a transport rejects with a plain object. */
|
|
56
|
+
function modelCatalogErrorMessage(value) {
|
|
57
|
+
if (value instanceof Error && value.message) return value.message;
|
|
58
|
+
return asText(asRecord(value)?.message) ?? asText(value) ?? "Unable to load the model catalog.";
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate and unwrap a successful catalog without discarding provider failures
|
|
62
|
+
* or newer host metadata. Names and metadata remain optional for older hosts.
|
|
63
|
+
* A broken response is never presented as a successfully loaded empty menu.
|
|
64
|
+
*/
|
|
65
|
+
function checkedModelCatalog(value) {
|
|
66
|
+
const envelope = asRecord(value);
|
|
67
|
+
if (envelope?.ok === false) throw new Error(modelCatalogErrorMessage(envelope.error ?? envelope));
|
|
68
|
+
const root = envelope?.ok === true ? asRecord(envelope.value) : envelope;
|
|
69
|
+
const malformed = (field) => {
|
|
70
|
+
throw new Error(`Invalid model catalog: ${field}.`);
|
|
71
|
+
};
|
|
72
|
+
if (!root || !Array.isArray(root.groups)) return malformed("groups must be an array");
|
|
73
|
+
for (const value of root.groups) {
|
|
74
|
+
const group = asRecord(value);
|
|
75
|
+
if (!group || !asText(group.id) || !Array.isArray(group.models)) return malformed("each group needs an id and models array");
|
|
76
|
+
for (const value of group.models) {
|
|
77
|
+
const model = asRecord(value);
|
|
78
|
+
if (!model || !asText(model.id)) return malformed("each model needs an id");
|
|
79
|
+
if (model.reasoning !== void 0) {
|
|
80
|
+
const reasoning = asRecord(model.reasoning);
|
|
81
|
+
if (!reasoning || !Array.isArray(reasoning.efforts) || reasoning.efforts.some((value) => !parseEffort(value))) return malformed("reasoning efforts must be an array of identified efforts");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (root.failures !== void 0 && (!Array.isArray(root.failures) || root.failures.some((value) => {
|
|
86
|
+
const failure = asRecord(value);
|
|
87
|
+
return !failure || !asText(failure.id) || typeof failure.name !== "string" || typeof failure.message !== "string";
|
|
88
|
+
}))) return malformed("failures must be an array of provider failures");
|
|
89
|
+
return root;
|
|
90
|
+
}
|
|
91
|
+
/** Read through the injected session namespace; absence and rejection are errors. */
|
|
92
|
+
async function readModelCatalog(client) {
|
|
93
|
+
const session = client.remote?.session;
|
|
94
|
+
if (typeof session?.modelCatalog !== "function") throw new Error("Model catalog unavailable: inject both remote and remote.session.");
|
|
95
|
+
return checkedModelCatalog(await session.modelCatalog());
|
|
96
|
+
}
|
|
97
|
+
/** Provider failures are partial results, not a transport failure. */
|
|
98
|
+
function modelCatalogFailures(value) {
|
|
99
|
+
try {
|
|
100
|
+
return checkedModelCatalog(value).failures ?? [];
|
|
101
|
+
} catch {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Text adapter for existing model-hub status messages. */
|
|
106
|
+
function catalogFailures(value) {
|
|
107
|
+
return modelCatalogFailures(value).map((failure) => `${failure.name || failure.id}: ${failure.message}`);
|
|
108
|
+
}
|
|
76
109
|
function parseEffort(value) {
|
|
77
110
|
const row = asRecord(value);
|
|
78
111
|
const id = row ? asText(row.id) : void 0;
|
|
@@ -169,6 +202,59 @@ function groupModelMenuChoices(choices, query) {
|
|
|
169
202
|
return groups;
|
|
170
203
|
}
|
|
171
204
|
//#endregion
|
|
205
|
+
//#region ../dsh-model-route/src/catalog-ui.tsx
|
|
206
|
+
/** Also accepts a mapped state from a caller that owns broader async orchestration. */
|
|
207
|
+
function ModelCatalogStatus({ state, locale }) {
|
|
208
|
+
const zh = locale?.toLowerCase().startsWith("zh") === true;
|
|
209
|
+
const copy = zh ? {
|
|
210
|
+
loading: "正在加载模型…",
|
|
211
|
+
error: "模型列表加载失败",
|
|
212
|
+
partial: "部分提供商的模型未能加载",
|
|
213
|
+
retry: "重试"
|
|
214
|
+
} : {
|
|
215
|
+
loading: "Loading models…",
|
|
216
|
+
error: "Unable to load models",
|
|
217
|
+
partial: "Some providers could not load their models",
|
|
218
|
+
retry: "Retry"
|
|
219
|
+
};
|
|
220
|
+
if (!state.loading && !state.error && state.failures.length === 0) return null;
|
|
221
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
222
|
+
className: "dsh-model-catalog-status",
|
|
223
|
+
lang: zh ? "zh" : "en",
|
|
224
|
+
children: [
|
|
225
|
+
state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
226
|
+
role: "status",
|
|
227
|
+
children: copy.loading
|
|
228
|
+
}) : null,
|
|
229
|
+
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
230
|
+
role: "alert",
|
|
231
|
+
children: [
|
|
232
|
+
copy.error,
|
|
233
|
+
": ",
|
|
234
|
+
state.error
|
|
235
|
+
]
|
|
236
|
+
}) : null,
|
|
237
|
+
state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
238
|
+
role: "status",
|
|
239
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
240
|
+
failure.name || failure.id,
|
|
241
|
+
": ",
|
|
242
|
+
failure.message
|
|
243
|
+
] }, `${failure.id}:${index}`)) })]
|
|
244
|
+
}) : null,
|
|
245
|
+
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
246
|
+
type: "button",
|
|
247
|
+
size: "sm",
|
|
248
|
+
disabled: state.loading,
|
|
249
|
+
onClick: () => {
|
|
250
|
+
state.refresh();
|
|
251
|
+
},
|
|
252
|
+
children: copy.retry
|
|
253
|
+
}) : null
|
|
254
|
+
]
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
//#endregion
|
|
172
258
|
//#region ../dsh-model-route/src/ui.tsx
|
|
173
259
|
/**
|
|
174
260
|
* ModelMenu: the standard editor of one model-route field — the visible half
|
|
@@ -1178,6 +1264,29 @@ ${scope} {
|
|
|
1178
1264
|
& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }
|
|
1179
1265
|
& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }
|
|
1180
1266
|
|
|
1267
|
+
/* --- Native textarea. The primitives ship no textarea either, so a settings
|
|
1268
|
+
* prompt keeps the platform element and the same field shell as the select:
|
|
1269
|
+
* 0.5px l4, radius-md, layer-3, 13/1.5 type. It grows vertically instead of
|
|
1270
|
+
* locking to the select's 34px row. --- */
|
|
1271
|
+
& .dsh-ui-textarea {
|
|
1272
|
+
box-sizing: border-box;
|
|
1273
|
+
width: 100%;
|
|
1274
|
+
min-width: 0;
|
|
1275
|
+
resize: vertical;
|
|
1276
|
+
padding: 8px 12px;
|
|
1277
|
+
border: 0.5px solid var(--dsw-alias-border-l4);
|
|
1278
|
+
border-radius: var(--dsw-radius-md);
|
|
1279
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
1280
|
+
font: inherit;
|
|
1281
|
+
font-size: 13px;
|
|
1282
|
+
line-height: 1.5;
|
|
1283
|
+
color: var(--dsw-alias-label-primary);
|
|
1284
|
+
}
|
|
1285
|
+
& .dsh-ui-textarea:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }
|
|
1286
|
+
& .dsh-ui-textarea:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }
|
|
1287
|
+
& .dsh-ui-textarea::placeholder { color: var(--dsw-alias-label-dimmed); }
|
|
1288
|
+
& .dsh-ui-textarea[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }
|
|
1289
|
+
|
|
1181
1290
|
/* Long panels scroll inside themselves instead of growing the host page. */
|
|
1182
1291
|
& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
|
|
1183
1292
|
& .dsh-ui-panel-wide { max-width: 100%; }
|
|
@@ -1190,25 +1299,18 @@ ${scope} {
|
|
|
1190
1299
|
}
|
|
1191
1300
|
//#endregion
|
|
1192
1301
|
//#region ../dsh-plugin-kit/src/contracts.ts
|
|
1193
|
-
/**
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
method: "watch",
|
|
1206
|
-
mode: "stream",
|
|
1207
|
-
invocation: { kind: "direct" },
|
|
1208
|
-
parameters: [],
|
|
1209
|
-
cancellation: { parameter: "signal" }
|
|
1210
|
-
}]
|
|
1211
|
-
};
|
|
1302
|
+
/** `@klarkxy/dsh-git-commit` becomes `KlarkxyDshGitCommitModelSettingsChanges`. */
|
|
1303
|
+
function modelSettingsChangesIdentity(packageName) {
|
|
1304
|
+
const scoped = /^@([^/]+)\/(.+)$/.exec(packageName);
|
|
1305
|
+
const parts = (scoped ? `${scoped[1]}/${scoped[2]}` : packageName).split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
1306
|
+
if (!parts.length) throw new Error("Model settings package name has no RPC segment");
|
|
1307
|
+
const segment = `${parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}ModelSettingsChanges`;
|
|
1308
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(segment)) throw new Error(`Model settings sync name is not an RPC segment: ${segment}`);
|
|
1309
|
+
return {
|
|
1310
|
+
service: segment,
|
|
1311
|
+
namespace: segment
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1212
1314
|
//#endregion
|
|
1213
1315
|
//#region ../dsh-plugin-kit/src/model-settings-client.ts
|
|
1214
1316
|
/** This stream carries invalidations only; ready is never a settings snapshot. */
|
|
@@ -1223,21 +1325,44 @@ function parseModelSettingsChangeFrame(value) {
|
|
|
1223
1325
|
};
|
|
1224
1326
|
throw new Error("Invalid model settings change frame");
|
|
1225
1327
|
}
|
|
1226
|
-
/** One contribution
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1328
|
+
/** One owner's contribution. Each package mounts only its own endpoint. */
|
|
1329
|
+
function modelSettingsChangesRemote(packageName, identity = modelSettingsChangesIdentity(packageName)) {
|
|
1330
|
+
return {
|
|
1331
|
+
package: packageName,
|
|
1332
|
+
descriptors: [{
|
|
1333
|
+
id: `${identity.namespace}/watch`,
|
|
1334
|
+
service: identity.service,
|
|
1335
|
+
namespace: identity.namespace,
|
|
1336
|
+
method: "watch",
|
|
1337
|
+
mode: "stream",
|
|
1338
|
+
invocation: { kind: "direct" },
|
|
1339
|
+
parameters: [],
|
|
1340
|
+
cancellation: { parameter: "signal" },
|
|
1341
|
+
result: {
|
|
1342
|
+
mode: "strict",
|
|
1343
|
+
typeSymbol: "ModelSettings.ChangeFrame",
|
|
1344
|
+
create: () => ({ parse: parseModelSettingsChangeFrame })
|
|
1345
|
+
}
|
|
1346
|
+
}]
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
/** Mount from a synchronous apply. Disposal waits for an in-flight mount and
|
|
1350
|
+
* then withdraws it, so the contribution cannot outlive the plugin. */
|
|
1351
|
+
function mountModelSettingsChanges(ctx, packageName) {
|
|
1352
|
+
const contribution = modelSettingsChangesRemote(packageName);
|
|
1353
|
+
ctx.inject(["remote"], (injected) => {
|
|
1354
|
+
const scope = injected;
|
|
1355
|
+
const mounting = scope.remote.$mount(contribution);
|
|
1356
|
+
mounting.catch(() => {});
|
|
1357
|
+
scope.effect(() => async () => {
|
|
1358
|
+
await (await mounting.catch(() => void 0))?.();
|
|
1359
|
+
});
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1238
1362
|
/** Native RemoteStream owns carrier reconnects; no timers or browser transport.
|
|
1239
1363
|
* A factory shares one logical stream while at least one subscriber remains. */
|
|
1240
|
-
function createModelSettingsSubscriber(ctx,
|
|
1364
|
+
function createModelSettingsSubscriber(ctx, packageName, identity = modelSettingsChangesIdentity(packageName), accept = (ns) => ns === packageName) {
|
|
1365
|
+
const endpoint = identity;
|
|
1241
1366
|
const listeners = /* @__PURE__ */ new Set();
|
|
1242
1367
|
let injection;
|
|
1243
1368
|
let current;
|
|
@@ -1263,12 +1388,18 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
1263
1388
|
};
|
|
1264
1389
|
const start = () => {
|
|
1265
1390
|
const life = ++lifecycle;
|
|
1266
|
-
injection = ctx.inject(["remote",
|
|
1391
|
+
injection = ctx.inject(["remote", `remote.${endpoint.namespace}`], (injected) => {
|
|
1267
1392
|
if (life !== lifecycle || !listeners.size) return;
|
|
1268
1393
|
const scope = injected;
|
|
1394
|
+
const service = scope.remote[endpoint.namespace];
|
|
1395
|
+
if (!service || !("watch" in service) || !service.watch) {
|
|
1396
|
+
report("Model settings sync service unavailable");
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
const watch = service.watch;
|
|
1269
1400
|
const stream = scope.remote.$stream({
|
|
1270
1401
|
name: "Model settings sync",
|
|
1271
|
-
open: (signal) =>
|
|
1402
|
+
open: (signal) => watch(signal),
|
|
1272
1403
|
ended: (accepted) => /* @__PURE__ */ new Error(`Model settings sync stream ended ${accepted ? "after" : "before"} ready; refresh or reopen the page`)
|
|
1273
1404
|
});
|
|
1274
1405
|
const session = {
|
|
@@ -1303,7 +1434,7 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
1303
1434
|
invalidate();
|
|
1304
1435
|
} else {
|
|
1305
1436
|
if (!ready) throw new Error("Model settings sync change arrived before ready");
|
|
1306
|
-
if (
|
|
1437
|
+
if (accept(frame.ns)) invalidate();
|
|
1307
1438
|
}
|
|
1308
1439
|
}
|
|
1309
1440
|
} catch (error) {
|
|
@@ -1435,20 +1566,6 @@ function messageOf(error) {
|
|
|
1435
1566
|
if (error && typeof error === "object" && "message" in error) return String(error.message);
|
|
1436
1567
|
return String(error);
|
|
1437
1568
|
}
|
|
1438
|
-
function checkedCatalog(value) {
|
|
1439
|
-
if (value && typeof value === "object" && "ok" in value && value.ok === false) throw new Error("error" in value ? messageOf(value.error) : "Request failed");
|
|
1440
|
-
return value;
|
|
1441
|
-
}
|
|
1442
|
-
function catalogFailures(value) {
|
|
1443
|
-
if (!value || typeof value !== "object") return [];
|
|
1444
|
-
const root = "ok" in value && value.ok === true && "value" in value ? value.value : value;
|
|
1445
|
-
if (!root || typeof root !== "object" || !("failures" in root) || !Array.isArray(root.failures)) return [];
|
|
1446
|
-
return root.failures.map((failure) => {
|
|
1447
|
-
if (!failure || typeof failure !== "object") return messageOf(failure);
|
|
1448
|
-
const provider = "name" in failure ? failure.name : "id" in failure ? failure.id : "provider" in failure ? failure.provider : "";
|
|
1449
|
-
return provider ? `${provider}: ${messageOf(failure)}` : messageOf(failure);
|
|
1450
|
-
});
|
|
1451
|
-
}
|
|
1452
1569
|
//#endregion
|
|
1453
1570
|
//#region src/client-copy.ts
|
|
1454
1571
|
function hubText(value, language) {
|
|
@@ -1553,7 +1670,6 @@ const TEXT$1 = {
|
|
|
1553
1670
|
loading: "正在读取…",
|
|
1554
1671
|
failed: (message) => `读取失败:${message}`,
|
|
1555
1672
|
syncFailed: (message) => `自动同步不可用:${message}`,
|
|
1556
|
-
catalogFailed: (message) => `模型列表读取失败:${message}`,
|
|
1557
1673
|
writeFailed: (message) => `未保存:${message}。请刷新后重试。`,
|
|
1558
1674
|
saved: "已保存,正在刷新…",
|
|
1559
1675
|
savedRefreshFailed: (message) => `已保存;阵容刷新失败:${message}。请刷新以读取最新设置。`,
|
|
@@ -1576,7 +1692,13 @@ const TEXT$1 = {
|
|
|
1576
1692
|
effortDefault: "默认",
|
|
1577
1693
|
searchModels: "搜索模型…",
|
|
1578
1694
|
noModels: "没有匹配的模型",
|
|
1579
|
-
clearSearch: "清除搜索"
|
|
1695
|
+
clearSearch: "清除搜索",
|
|
1696
|
+
runningTitle: "运行中的子代理",
|
|
1697
|
+
runningEmpty: "当前没有运行中的子代理。",
|
|
1698
|
+
runningPending: "尚未发起模型请求",
|
|
1699
|
+
runningRemote: "远程子代理,无法读取路由",
|
|
1700
|
+
runningFailed: (message) => `运行状态读取失败:${message}`,
|
|
1701
|
+
effortAdapterDefault: (effort) => `${effort}(适配器默认)`
|
|
1580
1702
|
},
|
|
1581
1703
|
en: {
|
|
1582
1704
|
title: "Subagent Cast",
|
|
@@ -1585,7 +1707,6 @@ const TEXT$1 = {
|
|
|
1585
1707
|
loading: "Loading…",
|
|
1586
1708
|
failed: (message) => `Load failed: ${message}`,
|
|
1587
1709
|
syncFailed: (message) => `Live sync unavailable: ${message}`,
|
|
1588
|
-
catalogFailed: (message) => `Model list failed: ${message}`,
|
|
1589
1710
|
writeFailed: (message) => `Not saved: ${message}. Refresh, then try again.`,
|
|
1590
1711
|
saved: "Saved; refreshing…",
|
|
1591
1712
|
savedRefreshFailed: (message) => `Saved; cast refresh failed: ${message}. Refresh to read the latest settings.`,
|
|
@@ -1608,7 +1729,13 @@ const TEXT$1 = {
|
|
|
1608
1729
|
effortDefault: "Default",
|
|
1609
1730
|
searchModels: "Search models…",
|
|
1610
1731
|
noModels: "No matching models",
|
|
1611
|
-
clearSearch: "Clear search"
|
|
1732
|
+
clearSearch: "Clear search",
|
|
1733
|
+
runningTitle: "Running subagents",
|
|
1734
|
+
runningEmpty: "No subagents are running.",
|
|
1735
|
+
runningPending: "No model request yet",
|
|
1736
|
+
runningRemote: "Remote subagent; route unavailable",
|
|
1737
|
+
runningFailed: (message) => `Running state failed: ${message}`,
|
|
1738
|
+
effortAdapterDefault: (effort) => `${effort} (adapter default)`
|
|
1612
1739
|
}
|
|
1613
1740
|
};
|
|
1614
1741
|
function useText$1(locale) {
|
|
@@ -1631,6 +1758,11 @@ const castCss = `
|
|
|
1631
1758
|
.dsh-model-hub .cast-banner{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}
|
|
1632
1759
|
.dsh-model-hub .cast-add{display:flex}
|
|
1633
1760
|
.dsh-model-hub .cast-add .dsh-model-menu-root{max-width:100%}
|
|
1761
|
+
.dsh-model-hub .cast-running{margin-top:16px}
|
|
1762
|
+
.dsh-model-hub .cast-running-title{font-size:14px;line-height:22px;font-weight:600;margin:0 0 4px;color:var(--dsw-alias-label-primary)}
|
|
1763
|
+
.dsh-model-hub .cast-running-row{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap;padding:6px 0;border-bottom:.5px solid var(--dsw-alias-border-l1)}
|
|
1764
|
+
.dsh-model-hub .cast-running-label{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;min-width:0}
|
|
1765
|
+
.dsh-model-hub .cast-running-route{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;min-width:0}
|
|
1634
1766
|
@media(max-width:520px){.dsh-model-hub .cast-row{grid-template-columns:minmax(0,1fr);gap:8px}}
|
|
1635
1767
|
`;
|
|
1636
1768
|
/** CAS rejections all carry a refresh hint in either language. */
|
|
@@ -1654,6 +1786,14 @@ function routeInput(route) {
|
|
|
1654
1786
|
model: normalized.model
|
|
1655
1787
|
};
|
|
1656
1788
|
}
|
|
1789
|
+
/** One live subagent row: label (or short id) plus its effective route. */
|
|
1790
|
+
function runningRouteText(entry, t) {
|
|
1791
|
+
if (!entry.local) return t("runningRemote");
|
|
1792
|
+
const route = entry.route;
|
|
1793
|
+
if (!route) return t("runningPending");
|
|
1794
|
+
const effort = route.reasoningEffort ? entry.effortIsAdapterDefault ? t("effortAdapterDefault", route.reasoningEffort) : route.reasoningEffort : "";
|
|
1795
|
+
return `${route.provider} / ${route.model}${effort ? ` · ${effort}` : ""}`;
|
|
1796
|
+
}
|
|
1657
1797
|
/** One cast entry: model picker, tendency input saved on blur, remove button. */
|
|
1658
1798
|
function CastRow({ t, catalog, route, tendencyRevision, draftReview, disabled, tendencyDisabled, menuDisabled, onSetRoute, onSetTendency, onRemove }) {
|
|
1659
1799
|
const label = `${route.provider} / ${route.model}`;
|
|
@@ -1737,6 +1877,8 @@ function CastPage({ api, locale }) {
|
|
|
1737
1877
|
const t = useText$1(locale);
|
|
1738
1878
|
const [cast, setCast] = (0, react.useState)(null);
|
|
1739
1879
|
const [catalog, setCatalog] = (0, react.useState)(null);
|
|
1880
|
+
const [running, setRunning] = (0, react.useState)(null);
|
|
1881
|
+
const [runningError, setRunningError] = (0, react.useState)("");
|
|
1740
1882
|
const [loadError, setLoadError] = (0, react.useState)("");
|
|
1741
1883
|
const [catalogError, setCatalogError] = (0, react.useState)("");
|
|
1742
1884
|
const [syncError, setSyncError] = (0, react.useState)("");
|
|
@@ -1756,7 +1898,11 @@ function CastPage({ api, locale }) {
|
|
|
1756
1898
|
scope.queued = false;
|
|
1757
1899
|
scope.busy = true;
|
|
1758
1900
|
setRefreshing(true);
|
|
1759
|
-
const [castResult, models] = await Promise.allSettled([
|
|
1901
|
+
const [castResult, models, live] = await Promise.allSettled([
|
|
1902
|
+
Promise.resolve().then(() => scope.api.getCast()),
|
|
1903
|
+
Promise.resolve().then(() => scope.api.modelCatalog()).then(checkedModelCatalog),
|
|
1904
|
+
Promise.resolve().then(() => scope.api.listRunning())
|
|
1905
|
+
]);
|
|
1760
1906
|
if (!scope.active) return;
|
|
1761
1907
|
if (castResult.status === "fulfilled") {
|
|
1762
1908
|
setCast(castResult.value);
|
|
@@ -1770,6 +1916,10 @@ function CastPage({ api, locale }) {
|
|
|
1770
1916
|
setCatalog(models.value);
|
|
1771
1917
|
setCatalogError("");
|
|
1772
1918
|
} else setCatalogError(messageOf(models.reason));
|
|
1919
|
+
if (live.status === "fulfilled") {
|
|
1920
|
+
setRunning(live.value);
|
|
1921
|
+
setRunningError("");
|
|
1922
|
+
} else setRunningError(messageOf(live.reason));
|
|
1773
1923
|
scope.busy = false;
|
|
1774
1924
|
setRefreshing(false);
|
|
1775
1925
|
if (scope.queued) refresh(scope);
|
|
@@ -1791,6 +1941,8 @@ function CastPage({ api, locale }) {
|
|
|
1791
1941
|
setSyncError("");
|
|
1792
1942
|
setCast(null);
|
|
1793
1943
|
setCatalog(null);
|
|
1944
|
+
setRunning(null);
|
|
1945
|
+
setRunningError("");
|
|
1794
1946
|
refresh(scope);
|
|
1795
1947
|
const unsubscribe = api.subscribeChanges?.(() => {
|
|
1796
1948
|
if (!scope.active) return;
|
|
@@ -1833,12 +1985,17 @@ function CastPage({ api, locale }) {
|
|
|
1833
1985
|
}
|
|
1834
1986
|
});
|
|
1835
1987
|
};
|
|
1836
|
-
const refreshNow = () => {
|
|
1988
|
+
const refreshNow = async () => {
|
|
1837
1989
|
const scope = scopeRef.current;
|
|
1838
|
-
if (scope?.api === api) refresh(scope, true);
|
|
1990
|
+
if (scope?.api === api && !scope.busy) await refresh(scope, true);
|
|
1839
1991
|
};
|
|
1840
1992
|
const disabled = saving !== "" || refreshing || writeError !== "" || saved && loadError !== "";
|
|
1841
|
-
const
|
|
1993
|
+
const catalogStatus = {
|
|
1994
|
+
loading: refreshing,
|
|
1995
|
+
error: catalogError ? hubMessage(catalogError, t.language) : "",
|
|
1996
|
+
failures: modelCatalogFailures(catalog),
|
|
1997
|
+
refresh: refreshNow
|
|
1998
|
+
};
|
|
1842
1999
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1843
2000
|
className: "cast-root dsh-ui-stack",
|
|
1844
2001
|
"aria-label": t("title"),
|
|
@@ -1883,16 +2040,10 @@ function CastPage({ api, locale }) {
|
|
|
1883
2040
|
className: "dsh-ui-error dsh-ui-wrap",
|
|
1884
2041
|
children: t("syncFailed", hubMessage(syncError, t.language))
|
|
1885
2042
|
}) : null,
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
}) : null,
|
|
1891
|
-
failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1892
|
-
role: "alert",
|
|
1893
|
-
className: "dsh-ui-error dsh-ui-wrap",
|
|
1894
|
-
children: t("catalogFailed", hubMessage(failure, t.language))
|
|
1895
|
-
}, index)),
|
|
2043
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
|
|
2044
|
+
state: catalogStatus,
|
|
2045
|
+
locale: t.language
|
|
2046
|
+
}),
|
|
1896
2047
|
writeError ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1897
2048
|
className: "dsh-ui-banner dsh-ui-banner--danger cast-banner",
|
|
1898
2049
|
role: "alert",
|
|
@@ -1969,7 +2120,40 @@ function CastPage({ api, locale }) {
|
|
|
1969
2120
|
expectedRevision: cast.revision
|
|
1970
2121
|
}))
|
|
1971
2122
|
})
|
|
1972
|
-
}) : null
|
|
2123
|
+
}) : null,
|
|
2124
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2125
|
+
className: "cast-running",
|
|
2126
|
+
"aria-label": t("runningTitle"),
|
|
2127
|
+
children: [
|
|
2128
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
2129
|
+
className: "cast-running-title",
|
|
2130
|
+
children: t("runningTitle")
|
|
2131
|
+
}),
|
|
2132
|
+
runningError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2133
|
+
role: "alert",
|
|
2134
|
+
className: "dsh-ui-error dsh-ui-wrap",
|
|
2135
|
+
children: t("runningFailed", hubMessage(runningError, t.language))
|
|
2136
|
+
}) : null,
|
|
2137
|
+
running === null && !runningError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2138
|
+
className: "dsh-ui-loading",
|
|
2139
|
+
children: t("loading")
|
|
2140
|
+
}) : null,
|
|
2141
|
+
running !== null && running.entries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2142
|
+
className: "dsh-ui-help",
|
|
2143
|
+
children: t("runningEmpty")
|
|
2144
|
+
}) : null,
|
|
2145
|
+
running?.entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2146
|
+
className: "cast-running-row",
|
|
2147
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2148
|
+
className: "cast-running-label",
|
|
2149
|
+
children: entry.label || entry.id
|
|
2150
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2151
|
+
className: "cast-running-route",
|
|
2152
|
+
children: runningRouteText(entry, t)
|
|
2153
|
+
})]
|
|
2154
|
+
}, entry.id))
|
|
2155
|
+
]
|
|
2156
|
+
})
|
|
1973
2157
|
]
|
|
1974
2158
|
});
|
|
1975
2159
|
}
|
|
@@ -1987,8 +2171,7 @@ const name = "dsh-model-hub-client";
|
|
|
1987
2171
|
const inject = [
|
|
1988
2172
|
"slots",
|
|
1989
2173
|
"connection",
|
|
1990
|
-
|
|
1991
|
-
"remote.session",
|
|
2174
|
+
...MODEL_CATALOG_INJECT,
|
|
1992
2175
|
"locale"
|
|
1993
2176
|
];
|
|
1994
2177
|
const CHANNEL = "/dsh-model-hub";
|
|
@@ -2120,7 +2303,7 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2120
2303
|
scope.queued = false;
|
|
2121
2304
|
scope.busy = true;
|
|
2122
2305
|
setRefreshing(true);
|
|
2123
|
-
const [fields, models] = await Promise.allSettled([Promise.resolve().then(() => scope.api.list()), Promise.resolve().then(() => scope.api.modelCatalog()).then(
|
|
2306
|
+
const [fields, models] = await Promise.allSettled([Promise.resolve().then(() => scope.api.list()), Promise.resolve().then(() => scope.api.modelCatalog()).then(checkedModelCatalog)]);
|
|
2124
2307
|
if (!scope.active) return;
|
|
2125
2308
|
if (fields.status === "fulfilled") {
|
|
2126
2309
|
setEntries(fields.value);
|
|
@@ -2233,7 +2416,16 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2233
2416
|
})
|
|
2234
2417
|
})).filter((entry) => entry.fields.length > 0 || (entry.error || entry.catalogError) && (!needle || [entry.ns, pluginTitle(entry, t)].some((text) => text.toLocaleLowerCase().includes(needle))));
|
|
2235
2418
|
const disabled = writing !== "" || refreshing || writeError !== "" || saved && listError !== "";
|
|
2236
|
-
const
|
|
2419
|
+
const refreshNow = async () => {
|
|
2420
|
+
const scope = scopeRef.current;
|
|
2421
|
+
if (scope?.api === api && !scope.busy) await refresh(scope);
|
|
2422
|
+
};
|
|
2423
|
+
const catalogStatus = {
|
|
2424
|
+
loading: refreshing,
|
|
2425
|
+
error: catalogError ? hubMessage(catalogError, t.language) : "",
|
|
2426
|
+
failures: modelCatalogFailures(catalog),
|
|
2427
|
+
refresh: refreshNow
|
|
2428
|
+
};
|
|
2237
2429
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2238
2430
|
className: "dsh-model-hub dsh-ui-stack",
|
|
2239
2431
|
lang: t.language,
|
|
@@ -2277,10 +2469,7 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2277
2469
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2278
2470
|
variant: "ghost",
|
|
2279
2471
|
disabled: writing !== "" || refreshing,
|
|
2280
|
-
onClick:
|
|
2281
|
-
const scope = scopeRef.current;
|
|
2282
|
-
if (scope?.api === api) refresh(scope);
|
|
2283
|
-
},
|
|
2472
|
+
onClick: refreshNow,
|
|
2284
2473
|
children: refreshing ? t("refreshing") : t("refresh")
|
|
2285
2474
|
})]
|
|
2286
2475
|
}),
|
|
@@ -2294,16 +2483,10 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2294
2483
|
className: "dsh-ui-error dsh-ui-wrap",
|
|
2295
2484
|
children: t("syncFailed", hubMessage(syncError, t.language))
|
|
2296
2485
|
}) : null,
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
}) : null,
|
|
2302
|
-
failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2303
|
-
role: "alert",
|
|
2304
|
-
className: "dsh-ui-error dsh-ui-wrap",
|
|
2305
|
-
children: t("catalogFailed", hubMessage(failure, t.language))
|
|
2306
|
-
}, index)),
|
|
2486
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
|
|
2487
|
+
state: catalogStatus,
|
|
2488
|
+
locale: t.language
|
|
2489
|
+
}),
|
|
2307
2490
|
writeError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2308
2491
|
role: "alert",
|
|
2309
2492
|
className: "dsh-ui-error dsh-ui-wrap",
|
|
@@ -2410,11 +2593,10 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
|
|
|
2410
2593
|
]
|
|
2411
2594
|
});
|
|
2412
2595
|
}
|
|
2413
|
-
|
|
2596
|
+
function apply(ctx) {
|
|
2414
2597
|
const client = ctx;
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
const changes = createModelSettingsSubscriber(ctx, "*");
|
|
2598
|
+
mountModelSettingsChanges(ctx, BUNDLE);
|
|
2599
|
+
const changes = createModelSettingsSubscriber(ctx, BUNDLE, modelSettingsChangesIdentity(BUNDLE), () => true);
|
|
2418
2600
|
const call = async (endpoint, payload) => {
|
|
2419
2601
|
const result = await client.connection.rpc.call(CHANNEL, endpoint, payload);
|
|
2420
2602
|
if (!result?.ok) throw new Error(result?.error?.message || "Request failed");
|
|
@@ -2423,14 +2605,15 @@ async function apply(ctx) {
|
|
|
2423
2605
|
const api = Object.freeze({
|
|
2424
2606
|
list: () => call("fields.list", {}),
|
|
2425
2607
|
setField: (payload) => call("fields.set", payload),
|
|
2426
|
-
modelCatalog: () => client
|
|
2608
|
+
modelCatalog: () => readModelCatalog(client),
|
|
2427
2609
|
subscribeChanges: changes.subscribe,
|
|
2428
2610
|
getCast: () => call("cast.get", {}),
|
|
2429
2611
|
setCastEnabled: (payload) => call("cast.setEnabled", payload),
|
|
2430
2612
|
addCastRoute: (payload) => call("cast.addRoute", payload),
|
|
2431
2613
|
setCastRoute: (payload) => call("cast.setRoute", payload),
|
|
2432
2614
|
removeCastRoute: (payload) => call("cast.removeRoute", payload),
|
|
2433
|
-
setCastTendency: (payload) => call("cast.setTendency", payload)
|
|
2615
|
+
setCastTendency: (payload) => call("cast.setTendency", payload),
|
|
2616
|
+
listRunning: () => call("cast.running", {})
|
|
2434
2617
|
});
|
|
2435
2618
|
client.slots.inject("plugins.bundle.config", () => client.slots.register({
|
|
2436
2619
|
name: "plugins.bundle.config",
|