dsh-model-capability-sync 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +114 -3
- package/cordis.patch.yml +8 -0
- package/lib/client.js +746 -0
- package/lib/client.js.map +7 -0
- package/lib/index.js +332 -0
- package/lib/index.js.map +7 -0
- package/package.json +88 -4
- package/scripts/build-client.mjs +42 -0
- package/scripts/build-host.mjs +22 -0
- package/scripts/smoke.mjs +56 -0
- package/scripts/verify-package.mjs +64 -0
- package/scripts/warm-cache.mjs +15 -0
- package/src/catalog.ts +204 -0
- package/src/client/SyncSection.tsx +650 -0
- package/src/client/apply.ts +223 -0
- package/src/client/index.ts +6 -0
- package/src/client/locale.ts +124 -0
- package/src/index.ts +148 -0
- package/src/mapping.ts +71 -0
- package/src/match.ts +130 -0
- package/src/sort.ts +62 -0
- package/src/types.ts +120 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: "dsh-model-capability-sync", factory: (require) => {
|
|
2
|
+
var module = { exports: {} }; var exports = module.exports;
|
|
3
|
+
"use strict";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/client/index.ts
|
|
23
|
+
var index_exports = {};
|
|
24
|
+
__export(index_exports, {
|
|
25
|
+
apply: () => apply,
|
|
26
|
+
inject: () => inject
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/client/SyncSection.tsx
|
|
31
|
+
var import_react = require("react");
|
|
32
|
+
|
|
33
|
+
// src/sort.ts
|
|
34
|
+
function modelSortKey(id) {
|
|
35
|
+
const slash = id.lastIndexOf("/");
|
|
36
|
+
if (slash === -1) {
|
|
37
|
+
const folded = id.toLowerCase();
|
|
38
|
+
return { group: folded, name: folded };
|
|
39
|
+
}
|
|
40
|
+
return { group: id.slice(0, slash).toLowerCase(), name: id.slice(slash + 1).toLowerCase() };
|
|
41
|
+
}
|
|
42
|
+
function compareModelIds(left, right) {
|
|
43
|
+
const a = modelSortKey(left);
|
|
44
|
+
const b = modelSortKey(right);
|
|
45
|
+
if (a.group !== b.group) return a.group < b.group ? -1 : 1;
|
|
46
|
+
if (a.name !== b.name) return a.name < b.name ? -1 : 1;
|
|
47
|
+
if (left === right) return 0;
|
|
48
|
+
return left < right ? -1 : 1;
|
|
49
|
+
}
|
|
50
|
+
function sortByModelId(items, idOf) {
|
|
51
|
+
return [...items].sort((left, right) => compareModelIds(idOf(left), idOf(right)));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/client/SyncSection.tsx
|
|
55
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
56
|
+
var TARGET_DEFAULT = "llm-pi-ai";
|
|
57
|
+
var TARGET_DIRECTORY = {
|
|
58
|
+
"llm-pi-ai": { native: true, nameKey: "nameLlmPiAi" },
|
|
59
|
+
"llm-deepseek": { native: true, nameKey: "nameLlmDeepseek" },
|
|
60
|
+
"llm-deepseek-account": { native: true, nameKey: "nameLlmDeepseekAccount" },
|
|
61
|
+
"llm-newapi": { native: false, nameKey: "nameLlmNewapi" }
|
|
62
|
+
};
|
|
63
|
+
function targetLabelOf(ns, t) {
|
|
64
|
+
const known = TARGET_DIRECTORY[ns];
|
|
65
|
+
if (known === void 0) return `${t("sourcePlugin")} \xB7 ${ns}`;
|
|
66
|
+
return `${known.native ? t("sourceNative") : t("sourcePlugin")} \xB7 ${t(known.nameKey)}`;
|
|
67
|
+
}
|
|
68
|
+
function textOf(model, key) {
|
|
69
|
+
const value = model[key];
|
|
70
|
+
return typeof value === "string" ? value : "";
|
|
71
|
+
}
|
|
72
|
+
function providersOf(descriptor) {
|
|
73
|
+
const providers = descriptor?.value?.providers;
|
|
74
|
+
return typeof providers === "object" && providers !== null ? providers : {};
|
|
75
|
+
}
|
|
76
|
+
function modelsOf(provider) {
|
|
77
|
+
const models = provider?.models;
|
|
78
|
+
return Array.isArray(models) ? models.filter((entry) => typeof entry === "object" && entry !== null) : [];
|
|
79
|
+
}
|
|
80
|
+
function sortedModelsOf(provider) {
|
|
81
|
+
return sortByModelId(modelsOf(provider), (model) => textOf(model, "id"));
|
|
82
|
+
}
|
|
83
|
+
function tokens(value) {
|
|
84
|
+
if (typeof value !== "number") return "\u2014";
|
|
85
|
+
if (value >= 1e6) return `${String(Number((value / 1e6).toFixed(1)))}M`;
|
|
86
|
+
if (value >= 1e3) return `${String(Number((value / 1e3).toFixed(0)))}K`;
|
|
87
|
+
return String(value);
|
|
88
|
+
}
|
|
89
|
+
function viaLabel(row, t) {
|
|
90
|
+
switch (row.match?.via) {
|
|
91
|
+
case "alias":
|
|
92
|
+
return t("viaAlias");
|
|
93
|
+
case "exact":
|
|
94
|
+
return t("viaExact");
|
|
95
|
+
case "folded":
|
|
96
|
+
return t("viaFolded");
|
|
97
|
+
case "basename":
|
|
98
|
+
return t("viaBasename");
|
|
99
|
+
case "suffix":
|
|
100
|
+
return t("viaSuffix");
|
|
101
|
+
default:
|
|
102
|
+
return "";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function isBlank(value) {
|
|
106
|
+
if (value === void 0 || value === null || value === "") return true;
|
|
107
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
108
|
+
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function mergeModel(model, fields, overwrite) {
|
|
112
|
+
const next = { ...model };
|
|
113
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
114
|
+
if (key === "name" || value === void 0) continue;
|
|
115
|
+
if (!overwrite && !isBlank(next[key])) continue;
|
|
116
|
+
next[key] = value;
|
|
117
|
+
}
|
|
118
|
+
return next;
|
|
119
|
+
}
|
|
120
|
+
function changesBetween(model, fields, overwrite) {
|
|
121
|
+
const next = mergeModel(model, fields, overwrite);
|
|
122
|
+
const changes = [];
|
|
123
|
+
for (const key of Object.keys(fields)) {
|
|
124
|
+
const before = model[key];
|
|
125
|
+
const after = next[key];
|
|
126
|
+
if (JSON.stringify(before) === JSON.stringify(after)) continue;
|
|
127
|
+
changes.push({ key, before, after });
|
|
128
|
+
}
|
|
129
|
+
return changes;
|
|
130
|
+
}
|
|
131
|
+
function imageText(value, t) {
|
|
132
|
+
if (Array.isArray(value) && value.includes("image")) return t("imageYes");
|
|
133
|
+
if (isBlank(value)) return t("fieldEmpty");
|
|
134
|
+
return t("imageNo");
|
|
135
|
+
}
|
|
136
|
+
function reasoningText(value) {
|
|
137
|
+
if (value === false) return "off";
|
|
138
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
139
|
+
const keys = Object.keys(value);
|
|
140
|
+
return keys.length === 0 ? "\u2014" : keys.join(" / ");
|
|
141
|
+
}
|
|
142
|
+
return "\u2014";
|
|
143
|
+
}
|
|
144
|
+
function liveLabel(row, t) {
|
|
145
|
+
if (row === void 0) return "\u2014";
|
|
146
|
+
if (row.error !== void 0) return t("liveError");
|
|
147
|
+
if (row.input === void 0) return "\u2014";
|
|
148
|
+
return row.input.includes("image") ? t("imageYes") : t("imageNo");
|
|
149
|
+
}
|
|
150
|
+
function valueCell(change, current, format) {
|
|
151
|
+
if (change === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-dim", children: format(current) });
|
|
152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "cs-change", children: [
|
|
153
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-from", children: format(change.before) }),
|
|
154
|
+
" \u2192 ",
|
|
155
|
+
format(change.after)
|
|
156
|
+
] });
|
|
157
|
+
}
|
|
158
|
+
function SyncSection(props) {
|
|
159
|
+
const { t, preview, live, describeSettings, mutateSettings } = props;
|
|
160
|
+
const [status, setStatus] = (0, import_react.useState)("loading");
|
|
161
|
+
const [errorText, setErrorText] = (0, import_react.useState)(void 0);
|
|
162
|
+
const [descriptors, setDescriptors] = (0, import_react.useState)([]);
|
|
163
|
+
const [targetNs, setTargetNs] = (0, import_react.useState)(TARGET_DEFAULT);
|
|
164
|
+
const [providerKey, setProviderKey] = (0, import_react.useState)("");
|
|
165
|
+
const [models, setModels] = (0, import_react.useState)([]);
|
|
166
|
+
const [rows, setRows] = (0, import_react.useState)(void 0);
|
|
167
|
+
const [liveRows, setLiveRows] = (0, import_react.useState)(/* @__PURE__ */ new Map());
|
|
168
|
+
const [selected, setSelected] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
169
|
+
const [overwrite, setOverwrite] = (0, import_react.useState)(false);
|
|
170
|
+
const [query, setQuery] = (0, import_react.useState)("");
|
|
171
|
+
const [onlyChanged, setOnlyChanged] = (0, import_react.useState)(false);
|
|
172
|
+
const [busy, setBusy] = (0, import_react.useState)("idle");
|
|
173
|
+
const [notice, setNotice] = (0, import_react.useState)(void 0);
|
|
174
|
+
const [catalogInfo, setCatalogInfo] = (0, import_react.useState)(void 0);
|
|
175
|
+
const [staleInfo, setStaleInfo] = (0, import_react.useState)(void 0);
|
|
176
|
+
const plan = (() => {
|
|
177
|
+
if (rows === void 0) return [];
|
|
178
|
+
const stored = new Map(models.map((model) => [textOf(model, "id"), model]));
|
|
179
|
+
return rows.map((row) => {
|
|
180
|
+
const model = stored.get(row.id) ?? {};
|
|
181
|
+
const fields = row.fields;
|
|
182
|
+
return {
|
|
183
|
+
row,
|
|
184
|
+
model,
|
|
185
|
+
changes: fields === void 0 ? [] : changesBetween(model, fields, overwrite)
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
})();
|
|
189
|
+
const matched = plan.filter((entry) => entry.row.fields !== void 0);
|
|
190
|
+
const unmatched = plan.filter((entry) => entry.row.fields === void 0);
|
|
191
|
+
const changing = matched.filter((entry) => entry.changes.length > 0);
|
|
192
|
+
const changeFields = changing.reduce((total, entry) => total + entry.changes.length, 0);
|
|
193
|
+
const liveImage = matched.filter((entry) => liveRows.get(entry.row.id)?.input?.includes("image") === true).length;
|
|
194
|
+
const liveText = matched.filter((entry) => {
|
|
195
|
+
const answer = liveRows.get(entry.row.id);
|
|
196
|
+
return answer?.input !== void 0 && !answer.input.includes("image");
|
|
197
|
+
}).length;
|
|
198
|
+
const load = async () => {
|
|
199
|
+
setStatus("loading");
|
|
200
|
+
setErrorText(void 0);
|
|
201
|
+
try {
|
|
202
|
+
const list = await describeSettings();
|
|
203
|
+
setDescriptors(list);
|
|
204
|
+
const candidates2 = list.filter((entry) => Object.keys(providersOf(entry)).length > 0);
|
|
205
|
+
const target = candidates2.find((entry) => entry.ns === TARGET_DEFAULT) ?? candidates2[0];
|
|
206
|
+
if (target === void 0) {
|
|
207
|
+
setStatus("error");
|
|
208
|
+
setErrorText(t("noTarget"));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const providers = providersOf(target);
|
|
212
|
+
const firstKey = Object.keys(providers)[0] ?? "";
|
|
213
|
+
setTargetNs(target.ns);
|
|
214
|
+
setProviderKey(firstKey);
|
|
215
|
+
setModels(sortedModelsOf(providers[firstKey]));
|
|
216
|
+
setRows(void 0);
|
|
217
|
+
setLiveRows(/* @__PURE__ */ new Map());
|
|
218
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
219
|
+
setQuery("");
|
|
220
|
+
setStatus("ready");
|
|
221
|
+
} catch (error) {
|
|
222
|
+
setStatus("error");
|
|
223
|
+
setErrorText(error instanceof Error ? error.message : String(error));
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
(0, import_react.useEffect)(() => {
|
|
227
|
+
void load();
|
|
228
|
+
}, []);
|
|
229
|
+
const showProvider = (ns, key) => {
|
|
230
|
+
const providers = providersOf(descriptors.find((entry) => entry.ns === ns));
|
|
231
|
+
const resolved = key !== "" && providers[key] !== void 0 ? key : Object.keys(providers)[0] ?? "";
|
|
232
|
+
setTargetNs(ns);
|
|
233
|
+
setProviderKey(resolved);
|
|
234
|
+
setModels(sortedModelsOf(providers[resolved]));
|
|
235
|
+
setRows(void 0);
|
|
236
|
+
setLiveRows(/* @__PURE__ */ new Map());
|
|
237
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
238
|
+
setNotice(void 0);
|
|
239
|
+
setQuery("");
|
|
240
|
+
};
|
|
241
|
+
const refreshLive = async (provider, ids) => {
|
|
242
|
+
try {
|
|
243
|
+
const answer = await live({ provider, ids });
|
|
244
|
+
setLiveRows(answer.ok ? new Map(answer.value.rows.map((row) => [row.id, row])) : /* @__PURE__ */ new Map());
|
|
245
|
+
} catch {
|
|
246
|
+
setLiveRows(/* @__PURE__ */ new Map());
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
const reloadConfig = async () => {
|
|
250
|
+
const list = await describeSettings();
|
|
251
|
+
setDescriptors(list);
|
|
252
|
+
const descriptor2 = list.find((entry) => entry.ns === targetNs);
|
|
253
|
+
if (descriptor2 !== void 0) setModels(sortedModelsOf(providersOf(descriptor2)[providerKey]));
|
|
254
|
+
};
|
|
255
|
+
const selectChanging = (source, stored, mode) => {
|
|
256
|
+
const byId = new Map(stored.map((model) => [textOf(model, "id"), model]));
|
|
257
|
+
setSelected(new Set(source.filter((row) => row.fields !== void 0 && changesBetween(byId.get(row.id) ?? {}, row.fields, mode).length > 0).map((row) => row.id)));
|
|
258
|
+
};
|
|
259
|
+
const analyze = async (refresh) => {
|
|
260
|
+
setBusy("analyzing");
|
|
261
|
+
setErrorText(void 0);
|
|
262
|
+
setNotice(void 0);
|
|
263
|
+
setStaleInfo(void 0);
|
|
264
|
+
try {
|
|
265
|
+
const ids = models.map((model) => textOf(model, "id")).filter((id) => id.length > 0);
|
|
266
|
+
const result = await preview({ ids, ...refresh ? { refresh: true } : {} });
|
|
267
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
268
|
+
setRows(result.value.rows);
|
|
269
|
+
selectChanging(result.value.rows, models, overwrite);
|
|
270
|
+
setCatalogInfo(t("catalogInfo", {
|
|
271
|
+
models: result.value.catalogModels,
|
|
272
|
+
time: new Date(result.value.fetchedAt).toLocaleString()
|
|
273
|
+
}));
|
|
274
|
+
setStaleInfo(result.value.stale === true ? t("catalogStale", { time: new Date(result.value.fetchedAt).toLocaleString() }) : void 0);
|
|
275
|
+
await refreshLive(providerKey, ids);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
setErrorText(error instanceof Error ? error.message : String(error));
|
|
278
|
+
} finally {
|
|
279
|
+
setBusy("idle");
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const setOverwriteMode = (mode) => {
|
|
283
|
+
setOverwrite(mode);
|
|
284
|
+
if (rows === void 0) return;
|
|
285
|
+
selectChanging(rows, models, mode);
|
|
286
|
+
};
|
|
287
|
+
const applyRows = async () => {
|
|
288
|
+
const descriptor2 = descriptors.find((entry) => entry.ns === targetNs);
|
|
289
|
+
if (descriptor2 === void 0) return;
|
|
290
|
+
const targets = new Map(changing.filter((entry) => selected.has(entry.row.id)).map((entry) => [entry.row.id, entry]));
|
|
291
|
+
if (targets.size === 0) {
|
|
292
|
+
setNotice(t("nothingSelected"));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
let written = 0;
|
|
296
|
+
const next = models.map((model) => {
|
|
297
|
+
const entry = targets.get(textOf(model, "id"));
|
|
298
|
+
if (entry?.row.fields === void 0) return model;
|
|
299
|
+
written += 1;
|
|
300
|
+
return mergeModel(model, entry.row.fields, overwrite);
|
|
301
|
+
});
|
|
302
|
+
setBusy("applying");
|
|
303
|
+
setErrorText(void 0);
|
|
304
|
+
setNotice(void 0);
|
|
305
|
+
try {
|
|
306
|
+
const view = await mutateSettings(targetNs, [{
|
|
307
|
+
op: "set",
|
|
308
|
+
path: ["providers", providerKey, "models"],
|
|
309
|
+
value: next
|
|
310
|
+
}], descriptor2.revision);
|
|
311
|
+
setModels(next);
|
|
312
|
+
setDescriptors((previous) => previous.map((entry) => entry.ns === targetNs && typeof view.revision === "number" ? { ...entry, revision: view.revision } : entry));
|
|
313
|
+
setNotice(t("applied", { count: written }));
|
|
314
|
+
await refreshLive(providerKey, next.map((model) => textOf(model, "id")).filter((id) => id.length > 0));
|
|
315
|
+
} catch (error) {
|
|
316
|
+
const code = error?.code;
|
|
317
|
+
if (code === "settings/conflict") {
|
|
318
|
+
try {
|
|
319
|
+
await reloadConfig();
|
|
320
|
+
} catch {
|
|
321
|
+
}
|
|
322
|
+
setNotice(t("conflictReload"));
|
|
323
|
+
} else {
|
|
324
|
+
setErrorText(error instanceof Error ? error.message : String(error));
|
|
325
|
+
}
|
|
326
|
+
} finally {
|
|
327
|
+
setBusy("idle");
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
if (status === "loading") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "cs-hint", children: t("loading") });
|
|
331
|
+
if (status === "error") {
|
|
332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "cs-field", children: [
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "cs-error", children: [
|
|
334
|
+
t("loadFailed"),
|
|
335
|
+
": ",
|
|
336
|
+
errorText
|
|
337
|
+
] }),
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "cs-button", onClick: () => {
|
|
339
|
+
void load();
|
|
340
|
+
}, children: t("retry") })
|
|
341
|
+
] });
|
|
342
|
+
}
|
|
343
|
+
const descriptor = descriptors.find((entry) => entry.ns === targetNs);
|
|
344
|
+
const candidates = descriptors.filter((entry) => Object.keys(providersOf(entry)).length > 0);
|
|
345
|
+
const providerKeys = Object.keys(providersOf(descriptor));
|
|
346
|
+
const needle = query.trim().toLowerCase();
|
|
347
|
+
const visible = matched.filter((entry) => {
|
|
348
|
+
if (onlyChanged && entry.changes.length === 0) return false;
|
|
349
|
+
if (needle === "") return true;
|
|
350
|
+
return entry.row.id.toLowerCase().includes(needle) || entry.row.match?.modelId.toLowerCase().includes(needle) === true;
|
|
351
|
+
});
|
|
352
|
+
const selectable = visible.filter((entry) => entry.changes.length > 0);
|
|
353
|
+
const toggle = (id) => {
|
|
354
|
+
const next = new Set(selected);
|
|
355
|
+
if (next.has(id)) next.delete(id);
|
|
356
|
+
else next.add(id);
|
|
357
|
+
setSelected(next);
|
|
358
|
+
};
|
|
359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
360
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: t("intro") }),
|
|
361
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "cs-row", children: [
|
|
362
|
+
candidates.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "cs-field", children: [
|
|
363
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-hint", children: t("writeTarget") }),
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "cs-select", value: targetNs, onChange: (event) => {
|
|
365
|
+
showProvider(event.target.value, "");
|
|
366
|
+
}, children: candidates.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: entry.ns, children: targetLabelOf(entry.ns, t) }, entry.ns)) })
|
|
367
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "cs-field", title: targetNs, children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-hint", children: t("writeTarget") }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-target", children: targetLabelOf(targetNs, t) })
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "cs-field", children: [
|
|
372
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-hint", children: t("provider") }),
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "cs-select", value: providerKey, onChange: (event) => {
|
|
374
|
+
showProvider(targetNs, event.target.value);
|
|
375
|
+
}, children: providerKeys.map((key) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: key, children: key }, key)) })
|
|
376
|
+
] }),
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-hint", children: t("modelCount", { count: models.length }) }),
|
|
378
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-hint", children: t("willSort") })
|
|
379
|
+
] }),
|
|
380
|
+
models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: t("noModels") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "cs-row", children: [
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "cs-button cs-button--primary", disabled: busy !== "idle", onClick: () => {
|
|
382
|
+
void analyze(false);
|
|
383
|
+
}, children: busy === "analyzing" ? t("analyzing") : t("analyze") }),
|
|
384
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "cs-button", disabled: busy !== "idle", onClick: () => {
|
|
385
|
+
void analyze(true);
|
|
386
|
+
}, children: t("refreshCatalog") }),
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "cs-hint", title: t("overwriteHint"), children: [
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: overwrite, onChange: (event) => {
|
|
389
|
+
setOverwriteMode(event.target.checked);
|
|
390
|
+
} }),
|
|
391
|
+
" ",
|
|
392
|
+
t("overwrite")
|
|
393
|
+
] })
|
|
394
|
+
] }),
|
|
395
|
+
errorText !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-error", children: errorText }) : null,
|
|
396
|
+
notice !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: notice }) : null,
|
|
397
|
+
catalogInfo !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: catalogInfo }) : null,
|
|
398
|
+
staleInfo !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-warn", children: staleInfo }) : null,
|
|
399
|
+
rows !== void 0 && matched.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
400
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "cs-row", children: [
|
|
401
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
402
|
+
"input",
|
|
403
|
+
{
|
|
404
|
+
className: "cs-input",
|
|
405
|
+
type: "search",
|
|
406
|
+
value: query,
|
|
407
|
+
placeholder: t("search"),
|
|
408
|
+
onChange: (event) => {
|
|
409
|
+
setQuery(event.target.value);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
),
|
|
413
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "cs-hint", children: [
|
|
414
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: onlyChanged, onChange: (event) => {
|
|
415
|
+
setOnlyChanged(event.target.checked);
|
|
416
|
+
} }),
|
|
417
|
+
" ",
|
|
418
|
+
t("onlyChanged")
|
|
419
|
+
] }),
|
|
420
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-hint", children: changing.length === 0 ? t("noChanges") : t("changeSummary", { rows: changing.length, fields: changeFields }) })
|
|
421
|
+
] }),
|
|
422
|
+
visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: t("filteredEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "cs-table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "cs-table", children: [
|
|
423
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
425
|
+
"input",
|
|
426
|
+
{
|
|
427
|
+
type: "checkbox",
|
|
428
|
+
"aria-label": t("selectAll"),
|
|
429
|
+
checked: selectable.length > 0 && selectable.every((entry) => selected.has(entry.row.id)),
|
|
430
|
+
onChange: (event) => {
|
|
431
|
+
const keep = event.target.checked ? new Set(selectable.map((entry) => entry.row.id)) : /* @__PURE__ */ new Set();
|
|
432
|
+
setSelected(keep);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
) }),
|
|
436
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("colModel") }),
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("colMatch") }),
|
|
438
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("colContext") }),
|
|
439
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("colOutput") }),
|
|
440
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("colImage") }),
|
|
441
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { title: t("colLiveHint"), children: t("colLive") }),
|
|
442
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("colReasoning") })
|
|
443
|
+
] }) }),
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: visible.map(({ row, model, changes }) => {
|
|
445
|
+
const changeOf = (key) => changes.find((change) => change.key === key);
|
|
446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: changes.length > 0 ? "cs-row--changed" : void 0, children: [
|
|
447
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
448
|
+
"input",
|
|
449
|
+
{
|
|
450
|
+
type: "checkbox",
|
|
451
|
+
"aria-label": row.id,
|
|
452
|
+
checked: selected.has(row.id),
|
|
453
|
+
disabled: changes.length === 0,
|
|
454
|
+
onChange: () => {
|
|
455
|
+
toggle(row.id);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
) }),
|
|
459
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "cs-id", children: row.id }),
|
|
460
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { className: "cs-dim", children: [
|
|
461
|
+
row.match === void 0 ? "\u2014" : `${row.match.provider}/${row.match.modelId}`,
|
|
462
|
+
" ",
|
|
463
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cs-badge", children: viaLabel(row, t) })
|
|
464
|
+
] }),
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: valueCell(changeOf("contextWindow"), model.contextWindow, tokens) }),
|
|
466
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: valueCell(changeOf("maxTokens"), model.maxTokens, tokens) }),
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: valueCell(changeOf("input"), model.input, (value) => imageText(value, t)) }),
|
|
468
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: liveRows.get(row.id)?.input?.includes("image") === true ? "cs-badge cs-badge--image" : "cs-dim", children: liveLabel(liveRows.get(row.id), t) }) }),
|
|
469
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "cs-dim", children: valueCell(changeOf("reasoningEfforts"), model.reasoningEfforts, reasoningText) })
|
|
470
|
+
] }, row.id);
|
|
471
|
+
}) })
|
|
472
|
+
] }) }),
|
|
473
|
+
liveRows.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: t("liveSummary", { image: liveImage, text: liveText }) }) : null,
|
|
474
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "cs-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
475
|
+
"button",
|
|
476
|
+
{
|
|
477
|
+
type: "button",
|
|
478
|
+
className: "cs-button cs-button--primary",
|
|
479
|
+
disabled: busy !== "idle" || !changing.some((entry) => selected.has(entry.row.id)),
|
|
480
|
+
onClick: () => {
|
|
481
|
+
void applyRows();
|
|
482
|
+
},
|
|
483
|
+
children: busy === "applying" ? t("applying") : t("apply")
|
|
484
|
+
}
|
|
485
|
+
) })
|
|
486
|
+
] }) : null,
|
|
487
|
+
unmatched.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "cs-hint", children: t("unmatchedHint") }),
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "cs-unmatched", children: unmatched.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
|
|
490
|
+
entry.row.id,
|
|
491
|
+
entry.row.reason === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "cs-dim", children: [
|
|
492
|
+
" \u2014 ",
|
|
493
|
+
entry.row.reason
|
|
494
|
+
] })
|
|
495
|
+
] }, entry.row.id)) })
|
|
496
|
+
] }) : null
|
|
497
|
+
] });
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// src/client/locale.ts
|
|
501
|
+
var zh = {
|
|
502
|
+
nav: "\u6A21\u578B\u80FD\u529B\u540C\u6B65",
|
|
503
|
+
loading: "\u6B63\u5728\u8BFB\u53D6\u914D\u7F6E\u2026",
|
|
504
|
+
intro: "\u4ECE models.dev \u67E5\u8BE2\u5DF2\u914D\u7F6E\u6A21\u578B\u7684\u80FD\u529B\uFF08\u4E0A\u4E0B\u6587\u7A97\u53E3\u3001\u8F93\u51FA\u4E0A\u9650\u3001\u662F\u5426\u652F\u6301\u56FE\u7247\u3001\u63A8\u7406\u6863\u4F4D\uFF09\uFF0C\u5E76\u5199\u5165\u6240\u9009\u4F9B\u5E94\u5546\u7684\u914D\u7F6E\u3002\u672C\u9875\u53EA\u5199\u914D\u7F6E\uFF0C\u4E0D\u53D1\u9001\u4EFB\u4F55\u63A8\u7406\u8BF7\u6C42\u3002",
|
|
505
|
+
writeTarget: "\u5199\u5165\u4F4D\u7F6E",
|
|
506
|
+
sourceNative: "\u539F\u751F\u914D\u7F6E",
|
|
507
|
+
sourcePlugin: "\u63D2\u4EF6\u914D\u7F6E",
|
|
508
|
+
nameLlmPiAi: "pi-ai \u9002\u914D\u5668",
|
|
509
|
+
nameLlmDeepseek: "DeepSeek \u5B98\u65B9",
|
|
510
|
+
nameLlmDeepseekAccount: "DeepSeek \u8D26\u53F7",
|
|
511
|
+
nameLlmNewapi: "NewAPI",
|
|
512
|
+
provider: "\u4F9B\u5E94\u5546",
|
|
513
|
+
modelCount: "\u5171 {count} \u4E2A\u6A21\u578B",
|
|
514
|
+
willSort: "\u5199\u5165\u65F6\u6309\u300C\u524D\u7F00\u5206\u7EC4 + \u540D\u79F0\u300D\u6392\u5E8F",
|
|
515
|
+
search: "\u641C\u7D22\u6A21\u578B ID \u6216\u76EE\u5F55 ID",
|
|
516
|
+
onlyChanged: "\u53EA\u770B\u6709\u53D8\u5316\u7684",
|
|
517
|
+
changeSummary: "\u5C06\u4FEE\u6539 {rows} \u884C \xB7 {fields} \u4E2A\u5B57\u6BB5",
|
|
518
|
+
noChanges: "\u6CA1\u6709\u9700\u8981\u5199\u5165\u7684\u53D8\u5316\uFF08\u76EE\u5F55\u503C\u4E0E\u4F60\u73B0\u6709\u914D\u7F6E\u4E00\u81F4\uFF09\u3002",
|
|
519
|
+
filteredEmpty: "\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u6A21\u578B\u3002",
|
|
520
|
+
fieldEmpty: "\u672A\u8BBE\u7F6E",
|
|
521
|
+
conflictReload: "\u914D\u7F6E\u5DF2\u88AB\u5176\u4ED6\u6539\u52A8\u66F4\u65B0\uFF0C\u5DF2\u91CD\u65B0\u8BFB\u53D6\u6700\u65B0\u503C\uFF1B\u8BF7\u786E\u8BA4\u540E\u518D\u70B9\u4E00\u6B21\u300C\u5E94\u7528\u300D\u3002",
|
|
522
|
+
analyze: "\u5206\u6790\u80FD\u529B",
|
|
523
|
+
analyzing: "\u6B63\u5728\u5339\u914D\u2026",
|
|
524
|
+
refreshCatalog: "\u91CD\u65B0\u4E0B\u8F7D\u76EE\u5F55",
|
|
525
|
+
apply: "\u5E94\u7528",
|
|
526
|
+
applying: "\u6B63\u5728\u5199\u5165\u2026",
|
|
527
|
+
applied: "\u5DF2\u5199\u5165 {count} \u4E2A\u6A21\u578B",
|
|
528
|
+
overwrite: "\u8986\u76D6\u5DF2\u6709\u503C",
|
|
529
|
+
overwriteHint: "\u4E0D\u52FE\u9009\u65F6\u53EA\u586B\u7A7A\u767D\u5B57\u6BB5\uFF0C\u4F60\u624B\u586B\u8FC7\u7684\u503C\u4E0D\u4F1A\u88AB\u6539\u5199\u3002",
|
|
530
|
+
selectAll: "\u5168\u9009",
|
|
531
|
+
colModel: "\u6A21\u578B ID",
|
|
532
|
+
colMatch: "\u5339\u914D",
|
|
533
|
+
colContext: "\u4E0A\u4E0B\u6587",
|
|
534
|
+
colOutput: "\u8F93\u51FA",
|
|
535
|
+
colImage: "\u56FE\u7247",
|
|
536
|
+
colLive: "\u5F53\u524D\u751F\u6548",
|
|
537
|
+
colLiveHint: "\u7531\u771F\u6B63\u63A5\u7BA1\u8FD9\u6761\u8DEF\u7531\u7684\u9002\u914D\u5668\u4E0A\u62A5\uFF0C\u4E5F\u5C31\u662F\u804A\u5929\u8BF7\u6C42\u5B9E\u9645\u770B\u5230\u7684\u503C\u3002\u82E5\u5B83\u4E0E\u300C\u56FE\u7247\u300D\u5217\u4E0D\u4E00\u81F4\uFF0C\u8BF4\u660E\u914D\u7F6E\u88AB\u53E6\u4E00\u4E2A\u63D2\u4EF6\u62A2\u5360\u4E86\u8DEF\u7531\u3002",
|
|
538
|
+
liveError: "\u65E0\u6CD5\u8BFB\u53D6",
|
|
539
|
+
liveSummary: "\u5F53\u524D\u751F\u6548\uFF1A{image} \u4E2A\u652F\u6301\u56FE\u7247\uFF0C{text} \u4E2A\u7EAF\u6587\u672C\u3002\u82E5\u4E0E\u300C\u56FE\u7247\u300D\u5217\u4E0D\u4E00\u81F4\uFF0C\u8BF4\u660E\u8FD9\u6761\u8DEF\u7531\u7531\u522B\u7684\u63D2\u4EF6\u63A5\u7BA1\uFF0C\u5199\u5165\u672C\u914D\u7F6E\u4E0D\u4F1A\u751F\u6548\u3002",
|
|
540
|
+
colReasoning: "\u63A8\u7406\u6863\u4F4D",
|
|
541
|
+
imageYes: "\u652F\u6301",
|
|
542
|
+
imageNo: "\u7EAF\u6587\u672C",
|
|
543
|
+
unmatched: "\u672A\u5339\u914D",
|
|
544
|
+
unmatchedHint: "\u8FD9\u4E9B\u6A21\u578B\u5728 models.dev \u91CC\u627E\u4E0D\u5230\uFF0C\u4FDD\u6301\u539F\u6837\u3002\u53EF\u5728\u522B\u540D\u8868\u91CC\u624B\u52A8\u6307\u5B9A\u3002",
|
|
545
|
+
noModels: "\u8BE5\u4F9B\u5E94\u5546\u4E0B\u8FD8\u6CA1\u6709\u6A21\u578B\u3002",
|
|
546
|
+
noTarget: "\u6CA1\u6709\u627E\u5230\u53EF\u5199\u7684\u914D\u7F6E\u6761\u76EE\uFF08\u9700\u8981\u5DF2\u542F\u7528\u7684 llm-pi-ai \u4F9B\u5E94\u5546\u914D\u7F6E\uFF09\u3002",
|
|
547
|
+
loadFailed: "\u52A0\u8F7D\u5931\u8D25",
|
|
548
|
+
retry: "\u91CD\u8BD5",
|
|
549
|
+
viaAlias: "\u522B\u540D",
|
|
550
|
+
viaExact: "\u7CBE\u786E",
|
|
551
|
+
viaFolded: "\u5FFD\u7565\u5927\u5C0F\u5199",
|
|
552
|
+
viaBasename: "\u53BB\u524D\u7F00",
|
|
553
|
+
viaSuffix: "\u53BB\u53D8\u4F53\u540E\u7F00",
|
|
554
|
+
catalogInfo: "\u76EE\u5F55\uFF1A{models} \u4E2A\u6A21\u578B \xB7 {time}",
|
|
555
|
+
catalogStale: "\u5728\u7EBF\u76EE\u5F55\u4E0B\u8F7D\u5931\u8D25\uFF0C\u6B63\u5728\u4F7F\u7528\u672C\u673A\u7F13\u5B58\uFF08{time}\uFF09\u3002\u6570\u636E\u53EF\u80FD\u4E0D\u662F\u6700\u65B0\uFF0C\u5B57\u6BB5\u542B\u4E49\u4E0D\u53D8\u3002",
|
|
556
|
+
nothingSelected: "\u6CA1\u6709\u9009\u4E2D\u4EFB\u4F55\u6A21\u578B\u3002",
|
|
557
|
+
done: "\u5B8C\u6210\u3002"
|
|
558
|
+
};
|
|
559
|
+
var en = {
|
|
560
|
+
nav: "Model capabilities",
|
|
561
|
+
loading: "Reading configuration\u2026",
|
|
562
|
+
intro: "Look up capabilities (context window, output cap, image input, reasoning efforts) for the models already configured here, then write them into the selected provider. This page only writes configuration; it never sends a model request.",
|
|
563
|
+
writeTarget: "Write to",
|
|
564
|
+
sourceNative: "Built in",
|
|
565
|
+
sourcePlugin: "Plugin",
|
|
566
|
+
nameLlmPiAi: "pi-ai adapter",
|
|
567
|
+
nameLlmDeepseek: "DeepSeek official",
|
|
568
|
+
nameLlmDeepseekAccount: "DeepSeek account",
|
|
569
|
+
nameLlmNewapi: "NewAPI",
|
|
570
|
+
provider: "Provider",
|
|
571
|
+
modelCount: "{count} models",
|
|
572
|
+
willSort: "Written sorted by vendor prefix, then name",
|
|
573
|
+
search: "Search model id or catalog id",
|
|
574
|
+
onlyChanged: "Only rows that change",
|
|
575
|
+
changeSummary: "Will change {rows} rows \xB7 {fields} fields",
|
|
576
|
+
noChanges: "Nothing to write: the catalog agrees with your configuration.",
|
|
577
|
+
filteredEmpty: "No model matches the filter.",
|
|
578
|
+
fieldEmpty: "unset",
|
|
579
|
+
conflictReload: "The configuration changed elsewhere; the latest values were reloaded. Check them, then press Apply again.",
|
|
580
|
+
analyze: "Analyze",
|
|
581
|
+
analyzing: "Matching\u2026",
|
|
582
|
+
refreshCatalog: "Re-download catalog",
|
|
583
|
+
apply: "Apply",
|
|
584
|
+
applying: "Writing\u2026",
|
|
585
|
+
applied: "Wrote {count} models",
|
|
586
|
+
overwrite: "Overwrite existing values",
|
|
587
|
+
overwriteHint: "Unchecked: only blank fields are filled, so values you typed are preserved.",
|
|
588
|
+
selectAll: "Select all",
|
|
589
|
+
colModel: "Model id",
|
|
590
|
+
colMatch: "Match",
|
|
591
|
+
colContext: "Context",
|
|
592
|
+
colOutput: "Output",
|
|
593
|
+
colImage: "Image",
|
|
594
|
+
colLive: "In effect",
|
|
595
|
+
colLiveHint: "Reported by the adapter that actually serves this route \u2014 what a chat request sees. A value that disagrees with the Image column means another plugin owns the route.",
|
|
596
|
+
liveError: "unreadable",
|
|
597
|
+
liveSummary: "In effect: {image} image-capable, {text} text-only. If this disagrees with the Image column, another plugin serves the route and writing this entry changes nothing.",
|
|
598
|
+
colReasoning: "Reasoning",
|
|
599
|
+
imageYes: "yes",
|
|
600
|
+
imageNo: "text only",
|
|
601
|
+
unmatched: "unmatched",
|
|
602
|
+
unmatchedHint: "These ids are absent from models.dev and stay untouched. Add an alias to map them by hand.",
|
|
603
|
+
noModels: "This provider has no models yet.",
|
|
604
|
+
noTarget: "No writable configuration entry found (an enabled llm-pi-ai provider is required).",
|
|
605
|
+
loadFailed: "Load failed",
|
|
606
|
+
retry: "Retry",
|
|
607
|
+
viaAlias: "alias",
|
|
608
|
+
viaExact: "exact",
|
|
609
|
+
viaFolded: "case-folded",
|
|
610
|
+
viaBasename: "basename",
|
|
611
|
+
viaSuffix: "suffix",
|
|
612
|
+
catalogInfo: "Catalog: {models} models \xB7 {time}",
|
|
613
|
+
catalogStale: "The online catalog download failed; using the local copy from {time}. The facts still mean the same thing, they may just be older.",
|
|
614
|
+
nothingSelected: "Nothing selected.",
|
|
615
|
+
done: "Done."
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// src/client/apply.ts
|
|
619
|
+
var NS = "settings.capability-sync";
|
|
620
|
+
var CHANNEL = "/model-capability-sync";
|
|
621
|
+
function refusalOf(answer) {
|
|
622
|
+
if (typeof answer !== "object" || answer === null) return void 0;
|
|
623
|
+
const envelope = answer;
|
|
624
|
+
if (envelope.ok !== false) return void 0;
|
|
625
|
+
return {
|
|
626
|
+
...typeof envelope.error?.code === "string" ? { code: envelope.error.code } : {},
|
|
627
|
+
message: typeof envelope.error?.message === "string" ? envelope.error.message : "settings request refused"
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function unwrap(answer) {
|
|
631
|
+
const refusal = refusalOf(answer);
|
|
632
|
+
if (refusal !== void 0) {
|
|
633
|
+
throw Object.assign(new Error(refusal.message), refusal.code === void 0 ? {} : { code: refusal.code });
|
|
634
|
+
}
|
|
635
|
+
if (typeof answer === "object" && answer !== null && "ok" in answer && "value" in answer) {
|
|
636
|
+
return answer.value;
|
|
637
|
+
}
|
|
638
|
+
return answer;
|
|
639
|
+
}
|
|
640
|
+
function namespacesOf(answer) {
|
|
641
|
+
const document2 = unwrap(answer);
|
|
642
|
+
if (Array.isArray(document2)) return document2;
|
|
643
|
+
const namespaces = document2?.namespaces;
|
|
644
|
+
if (!Array.isArray(namespaces)) throw new Error("settings.describe returned no namespace list");
|
|
645
|
+
return namespaces;
|
|
646
|
+
}
|
|
647
|
+
var inject = ["slots", "locale", "connection", "remote", "remote.settings"];
|
|
648
|
+
var SECTION_CSS = `
|
|
649
|
+
.cs-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
|
|
650
|
+
.cs-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
|
|
651
|
+
.cs-select {
|
|
652
|
+
box-sizing: border-box; padding: 6px 10px; border-radius: 8px;
|
|
653
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
654
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
655
|
+
color: var(--dsw-alias-label-primary);
|
|
656
|
+
font: inherit; font-size: 13px;
|
|
657
|
+
}
|
|
658
|
+
.cs-button {
|
|
659
|
+
padding: 6px 12px; border-radius: 6px; font: inherit; font-size: 13px;
|
|
660
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
661
|
+
background: transparent; color: var(--dsw-alias-label-primary);
|
|
662
|
+
cursor: pointer;
|
|
663
|
+
}
|
|
664
|
+
.cs-button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
665
|
+
.cs-button:disabled { opacity: 0.4; cursor: default; }
|
|
666
|
+
.cs-button--primary {
|
|
667
|
+
border-color: transparent;
|
|
668
|
+
background: var(--dsw-alias-button-primary-fill);
|
|
669
|
+
color: var(--dsw-alias-label-primary-foreground);
|
|
670
|
+
}
|
|
671
|
+
.cs-button--primary:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); }
|
|
672
|
+
.cs-hint { font-size: 12px; color: var(--dsw-alias-label-tertiary); line-height: 18px; }
|
|
673
|
+
.cs-error { color: var(--dsw-alias-state-error-primary); font-size: 12px; }
|
|
674
|
+
.cs-warn { color: var(--dsw-alias-state-warning-primary, var(--dsw-alias-label-secondary)); font-size: 12px; line-height: 18px; }
|
|
675
|
+
.cs-input {
|
|
676
|
+
box-sizing: border-box; padding: 6px 10px; border-radius: 8px; min-width: 200px;
|
|
677
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
678
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
679
|
+
color: var(--dsw-alias-label-primary);
|
|
680
|
+
font: inherit; font-size: 13px;
|
|
681
|
+
}
|
|
682
|
+
.cs-target { font-size: 13px; color: var(--dsw-alias-label-primary); line-height: 30px; }
|
|
683
|
+
.cs-table-wrap {
|
|
684
|
+
max-height: 460px; overflow: auto; margin-bottom: 12px;
|
|
685
|
+
border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px;
|
|
686
|
+
}
|
|
687
|
+
.cs-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12px; }
|
|
688
|
+
.cs-table th {
|
|
689
|
+
position: sticky; top: 0; z-index: 1;
|
|
690
|
+
text-align: left; font-weight: 500; color: var(--dsw-alias-label-secondary);
|
|
691
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
692
|
+
padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l2); white-space: nowrap;
|
|
693
|
+
}
|
|
694
|
+
.cs-table td {
|
|
695
|
+
padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l2);
|
|
696
|
+
color: var(--dsw-alias-label-primary); vertical-align: top;
|
|
697
|
+
}
|
|
698
|
+
.cs-table tr:last-child td { border-bottom: none; }
|
|
699
|
+
.cs-row--changed td { background: var(--dsw-alias-bg-layer-2, transparent); }
|
|
700
|
+
.cs-id { font-variant-numeric: tabular-nums; word-break: break-all; }
|
|
701
|
+
.cs-dim { color: var(--dsw-alias-label-tertiary); }
|
|
702
|
+
.cs-change { white-space: nowrap; }
|
|
703
|
+
.cs-from { color: var(--dsw-alias-label-tertiary); text-decoration: line-through; }
|
|
704
|
+
.cs-badge {
|
|
705
|
+
display: inline-block; padding: 0 6px; border-radius: 9px; font-size: 11px; line-height: 18px;
|
|
706
|
+
border: 1px solid var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary);
|
|
707
|
+
}
|
|
708
|
+
.cs-badge--image { border-color: var(--dsw-alias-brand-primary); color: var(--dsw-alias-brand-primary); }
|
|
709
|
+
.cs-unmatched { margin: 8px 0 0; padding-left: 18px; color: var(--dsw-alias-label-tertiary); font-size: 12px; }
|
|
710
|
+
`;
|
|
711
|
+
function apply(ctx) {
|
|
712
|
+
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "model-capability-sync: copy dictionaries");
|
|
713
|
+
if (typeof document !== "undefined") {
|
|
714
|
+
ctx.effect(() => {
|
|
715
|
+
const element = document.createElement("style");
|
|
716
|
+
element.textContent = SECTION_CSS;
|
|
717
|
+
document.head.append(element);
|
|
718
|
+
return () => {
|
|
719
|
+
element.remove();
|
|
720
|
+
};
|
|
721
|
+
}, "model-capability-sync: section styles");
|
|
722
|
+
}
|
|
723
|
+
const connection = ctx.get("connection");
|
|
724
|
+
const remote = ctx.get("remote");
|
|
725
|
+
const t = ctx.locale.bind(NS);
|
|
726
|
+
const injected = () => ({
|
|
727
|
+
preview: (request) => connection.rpc.call(CHANNEL, "preview", request),
|
|
728
|
+
live: (request) => connection.rpc.call(CHANNEL, "live", request),
|
|
729
|
+
describeSettings: async () => namespacesOf(await remote.settings.describe()),
|
|
730
|
+
mutateSettings: async (ns, ops, expectedRevision) => {
|
|
731
|
+
const view = unwrap(await remote.settings.mutate(ns, ops, expectedRevision));
|
|
732
|
+
if (view === void 0) throw new Error("settings.mutate returned no namespace view");
|
|
733
|
+
return view;
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
737
|
+
name: "settings.section",
|
|
738
|
+
id: "model-capability-sync",
|
|
739
|
+
order: 16,
|
|
740
|
+
label: () => t("nav"),
|
|
741
|
+
locale: NS,
|
|
742
|
+
inject: injected
|
|
743
|
+
}, SyncSection));
|
|
744
|
+
}
|
|
745
|
+
return module.exports; } });
|
|
746
|
+
//# sourceMappingURL=client.js.map
|