dsh-plugin-effort-declare 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/CONTRIBUTING.en.md +20 -9
- package/CONTRIBUTING.md +24 -13
- package/INSTALL.en.md +9 -9
- package/INSTALL.md +16 -16
- package/README.en.md +25 -20
- package/README.md +28 -23
- package/lib/client.js +354 -82
- package/lib/client.js.map +1 -1
- package/lib/types/client/EffortDeclareSection.d.ts +14 -4
- package/lib/types/client/EffortDeclareSection.d.ts.map +1 -1
- package/lib/types/client/build-info.d.ts +2 -0
- package/lib/types/client/build-info.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/load-drafts.d.ts +36 -6
- package/lib/types/client/load-drafts.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/core/attribution.d.ts +13 -0
- package/lib/types/core/attribution.d.ts.map +1 -0
- package/lib/types/core/catalog.d.ts +8 -0
- package/lib/types/core/catalog.d.ts.map +1 -1
- package/lib/types/core/drafts.d.ts +8 -4
- package/lib/types/core/drafts.d.ts.map +1 -1
- package/lib/types/core/efforts.d.ts.map +1 -1
- package/lib/types/core/input.d.ts +15 -0
- package/lib/types/core/input.d.ts.map +1 -0
- package/lib/types/core/validate.d.ts +3 -0
- package/lib/types/core/validate.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/README.en.md +2 -2
- package/src/README.md +2 -2
- package/src/client/EffortDeclareSection.tsx +161 -47
- package/src/client/README.en.md +7 -5
- package/src/client/README.md +7 -5
- package/src/client/build-info.ts +12 -0
- package/src/client/effort-declare.module.css +8 -0
- package/src/client/globals.d.ts +5 -0
- package/src/client/index.ts +13 -11
- package/src/client/load-drafts.ts +124 -8
- package/src/client/locales.ts +13 -4
- package/src/core/README.en.md +10 -8
- package/src/core/README.md +10 -8
- package/src/core/attribution.ts +24 -0
- package/src/core/catalog.ts +11 -0
- package/src/core/drafts.ts +40 -26
- package/src/core/efforts.ts +4 -1
- package/src/core/input.ts +49 -0
- package/src/core/validate.ts +8 -0
package/lib/client.js
CHANGED
|
@@ -36,6 +36,13 @@ window.__ModuleLoader__.load({
|
|
|
36
36
|
const LLM_PI_AI_NS = "llm-pi-ai";
|
|
37
37
|
/** Any route key walks a dict schema to the same profile node. */
|
|
38
38
|
const SCHEMA_PROBE_ROUTE = "\0probe";
|
|
39
|
+
/** Request modalities llm-pi-ai accepts on `models[].input` / `defaultInput`. */
|
|
40
|
+
const INPUT_MODALITIES = ["text", "image"];
|
|
41
|
+
/**
|
|
42
|
+
* Canonical write for a hand-declared vision model.
|
|
43
|
+
* Must include `text`; image-only is not a serviceable OpenAI-completions route.
|
|
44
|
+
*/
|
|
45
|
+
const IMAGE_CAPABLE_INPUT = ["text", "image"];
|
|
39
46
|
//#endregion
|
|
40
47
|
//#region src/core/paths.ts
|
|
41
48
|
/**
|
|
@@ -231,25 +238,29 @@ window.__ModuleLoader__.load({
|
|
|
231
238
|
}
|
|
232
239
|
return map;
|
|
233
240
|
}
|
|
234
|
-
|
|
235
|
-
|
|
241
|
+
/** Model-row fields this page edits; other keys follow the Models page. */
|
|
242
|
+
const MODEL_OVERLAY_KEYS = ["reasoningEfforts", "input"];
|
|
243
|
+
function fieldPresence(row, key) {
|
|
244
|
+
if (row === void 0 || !Object.hasOwn(row, key)) return {
|
|
236
245
|
present: false,
|
|
237
246
|
value: void 0
|
|
238
247
|
};
|
|
239
248
|
return {
|
|
240
249
|
present: true,
|
|
241
|
-
value: row
|
|
250
|
+
value: row[key]
|
|
242
251
|
};
|
|
243
252
|
}
|
|
244
|
-
function
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
253
|
+
function fieldEqual(left, right, key) {
|
|
254
|
+
const a = fieldPresence(left, key);
|
|
255
|
+
const b = fieldPresence(right, key);
|
|
256
|
+
if (a.present !== b.present) return false;
|
|
257
|
+
if (!a.present) return true;
|
|
258
|
+
return sliceEqual(a.value, b.value);
|
|
248
259
|
}
|
|
249
|
-
function
|
|
260
|
+
function overlayLocalFields(incomingRow, prevRow, keys) {
|
|
250
261
|
const next = structuredClone(incomingRow);
|
|
251
|
-
if (Object.hasOwn(prevRow,
|
|
252
|
-
else delete next
|
|
262
|
+
for (const key of keys) if (Object.hasOwn(prevRow, key)) next[key] = structuredClone(prevRow[key]);
|
|
263
|
+
else delete next[key];
|
|
253
264
|
return next;
|
|
254
265
|
}
|
|
255
266
|
function objectKeyChanged(left, right, key) {
|
|
@@ -260,7 +271,8 @@ window.__ModuleLoader__.load({
|
|
|
260
271
|
}
|
|
261
272
|
/**
|
|
262
273
|
* Membership follows the latest user-layer models list (Models page add/delete).
|
|
263
|
-
* Local unsaved
|
|
274
|
+
* Local unsaved overlay keys (including a cleared key) overlay by id; other
|
|
275
|
+
* fields on the row follow incoming.
|
|
264
276
|
*/
|
|
265
277
|
function mergeModelsById(args) {
|
|
266
278
|
const prevById = indexById(args.prevModels);
|
|
@@ -273,16 +285,19 @@ window.__ModuleLoader__.load({
|
|
|
273
285
|
const prevRow = prevById.get(id);
|
|
274
286
|
if (prevRow === void 0) return structuredClone(incomingRow);
|
|
275
287
|
const prevOrig = prevOrigById.get(id);
|
|
276
|
-
|
|
288
|
+
const dirtyKeys = MODEL_OVERLAY_KEYS.filter((key) => !fieldEqual(prevRow, prevOrig, key));
|
|
289
|
+
if (dirtyKeys.length === 0) return structuredClone(incomingRow);
|
|
277
290
|
const incomingOrig = incomingOrigById.get(id);
|
|
278
|
-
if (!
|
|
279
|
-
return
|
|
291
|
+
for (const key of dirtyKeys) if (!fieldEqual(prevOrig, incomingOrig, key)) conflicted = true;
|
|
292
|
+
return overlayLocalFields(incomingRow, prevRow, dirtyKeys);
|
|
280
293
|
});
|
|
281
294
|
for (const [id, prevRow] of prevById) {
|
|
282
295
|
if (incomingIds.has(id)) continue;
|
|
283
296
|
const prevOrig = prevOrigById.get(id);
|
|
284
|
-
|
|
285
|
-
if (
|
|
297
|
+
const dirtyKeys = MODEL_OVERLAY_KEYS.filter((key) => !fieldEqual(prevRow, prevOrig, key));
|
|
298
|
+
if (dirtyKeys.length === 0) continue;
|
|
299
|
+
const incomingOrig = incomingOrigById.get(id);
|
|
300
|
+
for (const key of dirtyKeys) if (!fieldEqual(prevOrig, incomingOrig, key)) conflicted = true;
|
|
286
301
|
}
|
|
287
302
|
return {
|
|
288
303
|
models,
|
|
@@ -314,9 +329,9 @@ window.__ModuleLoader__.load({
|
|
|
314
329
|
}
|
|
315
330
|
/**
|
|
316
331
|
* Apply a freshly loaded table. Membership and metadata follow incoming;
|
|
317
|
-
* unsaved reasoningEfforts / dirty compat keys
|
|
318
|
-
* when a locally dirty field also changed in
|
|
319
|
-
* and sibling-card saves do not warn).
|
|
332
|
+
* unsaved overlay keys (`reasoningEfforts`, `input`) / dirty compat keys
|
|
333
|
+
* overlay by id. Conflict only when a locally dirty field also changed in
|
|
334
|
+
* originals (revision-only bumps and sibling-card saves do not warn).
|
|
320
335
|
*/
|
|
321
336
|
function mergeLoadedDrafts(current, incoming, options) {
|
|
322
337
|
const currentByProvider = new Map(current.map((draft) => [draft.provider, draft]));
|
|
@@ -389,7 +404,10 @@ window.__ModuleLoader__.load({
|
|
|
389
404
|
const next = { ...efforts };
|
|
390
405
|
delete next.off;
|
|
391
406
|
if (mode === "empty") next.off = null;
|
|
392
|
-
else if (mode === "value")
|
|
407
|
+
else if (mode === "value") {
|
|
408
|
+
const trimmed = value.trim();
|
|
409
|
+
next.off = trimmed.length > 0 ? trimmed : "none";
|
|
410
|
+
}
|
|
393
411
|
return next;
|
|
394
412
|
}
|
|
395
413
|
/** Whether a thinking level (other than Off) is currently declared. */
|
|
@@ -521,27 +539,157 @@ window.__ModuleLoader__.load({
|
|
|
521
539
|
return next;
|
|
522
540
|
}
|
|
523
541
|
//#endregion
|
|
542
|
+
//#region src/core/input.ts
|
|
543
|
+
/**
|
|
544
|
+
* Per-model `input` modalities as stored in llm-pi-ai settings.
|
|
545
|
+
* Absence falls through to route `defaultInput` (`[text]`). Empty list is
|
|
546
|
+
* treated as absent by the official resolver — do not write `[]`.
|
|
547
|
+
*/
|
|
548
|
+
/** Whether the stored `input` list includes image. Absence is false. */
|
|
549
|
+
function readImageCapable(row) {
|
|
550
|
+
const value = row.input;
|
|
551
|
+
return Array.isArray(value) && value.includes("image");
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Declare or drop image input on a spread row.
|
|
555
|
+
* Enabled writes `[text, image]`; disabled unsets the key (not `[]`, not `[text]`).
|
|
556
|
+
*/
|
|
557
|
+
function writeImageCapable(row, enabled) {
|
|
558
|
+
const next = { ...row };
|
|
559
|
+
if (enabled) next.input = [...IMAGE_CAPABLE_INPUT];
|
|
560
|
+
else delete next.input;
|
|
561
|
+
return next;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Validate a stored `input` field. Returns an error code; never throws.
|
|
565
|
+
* Absence is valid. Empty list is rejected so a bad stamp cannot be re-saved.
|
|
566
|
+
*/
|
|
567
|
+
function validateInput(input) {
|
|
568
|
+
if (input === void 0) return void 0;
|
|
569
|
+
if (!Array.isArray(input) || input.length === 0) return "bad-input";
|
|
570
|
+
const known = new Set(INPUT_MODALITIES);
|
|
571
|
+
const seen = /* @__PURE__ */ new Set();
|
|
572
|
+
for (const item of input) {
|
|
573
|
+
if (typeof item !== "string" || !known.has(item) || seen.has(item)) return "bad-input";
|
|
574
|
+
seen.add(item);
|
|
575
|
+
}
|
|
576
|
+
if (!seen.has("text")) return "bad-input";
|
|
577
|
+
}
|
|
578
|
+
/** Per-model client-side check used to show errors without throwing. */
|
|
579
|
+
function modelInputError(row) {
|
|
580
|
+
if (!("input" in row) || row.input === void 0) return void 0;
|
|
581
|
+
return validateInput(row.input);
|
|
582
|
+
}
|
|
583
|
+
//#endregion
|
|
524
584
|
//#region src/core/validate.ts
|
|
525
585
|
/** Per-model client-side check used to show errors without throwing. */
|
|
526
586
|
function modelEffortError(row) {
|
|
527
587
|
if (!("reasoningEfforts" in row) || row.reasoningEfforts === void 0) return void 0;
|
|
528
588
|
return validateReasoningEfforts(row.reasoningEfforts);
|
|
529
589
|
}
|
|
590
|
+
/** First blocking error on a model row (efforts, then input). */
|
|
591
|
+
function modelRowError(row) {
|
|
592
|
+
return modelEffortError(row) ?? modelInputError(row);
|
|
593
|
+
}
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region src/core/attribution.ts
|
|
596
|
+
/**
|
|
597
|
+
* Plugin footer attribution. Version and end-year are frozen into the client
|
|
598
|
+
* bundle at pack time; this module only formats the line.
|
|
599
|
+
*/
|
|
600
|
+
/** First publication year (LICENSE). Not the user's wall clock. */
|
|
601
|
+
const COPYRIGHT_FROM = 2026;
|
|
602
|
+
const COPYRIGHT_HOLDER = "Stardust";
|
|
603
|
+
/**
|
|
604
|
+
* `0.1.2 © 2026 Stardust` or `0.1.2 © 2026–2027 Stardust`.
|
|
605
|
+
* Throws if version is empty or `to < from` — a bad stamp must not render.
|
|
606
|
+
*/
|
|
607
|
+
function formatAttribution(version, from, to) {
|
|
608
|
+
if (version.trim() === "") throw new Error("plugin version must be a non-empty string");
|
|
609
|
+
if (!Number.isInteger(from) || !Number.isInteger(to) || to < from) throw new Error(`invalid copyright range: ${String(from)}\u2013${String(to)}`);
|
|
610
|
+
return `${version} \u00a9 ${to === from ? String(from) : `${String(from)}\u2013${String(to)}`} ${COPYRIGHT_HOLDER}`;
|
|
611
|
+
}
|
|
612
|
+
//#endregion
|
|
613
|
+
//#region src/client/build-info.ts
|
|
614
|
+
/**
|
|
615
|
+
* Footer line frozen into the client bundle. Do not read the clock or
|
|
616
|
+
* package.json at DSH startup — host apply is empty and the settings page
|
|
617
|
+
* runs in the browser.
|
|
618
|
+
*/
|
|
619
|
+
const PLUGIN_FOOTER_TEXT = formatAttribution("0.1.4", COPYRIGHT_FROM, 2026);
|
|
530
620
|
//#endregion
|
|
531
621
|
//#region src/client/load-drafts.ts
|
|
532
622
|
function schemaDefaultString(node) {
|
|
533
623
|
if (!isPlainObject(node) || !isPlainObject(node.meta)) return void 0;
|
|
534
624
|
return typeof node.meta.default === "string" ? node.meta.default : void 0;
|
|
535
625
|
}
|
|
626
|
+
/** Namespace revision on a describe snapshot, if that row exists. */
|
|
627
|
+
function namespaceRevision(snapshot, ns) {
|
|
628
|
+
return snapshot.view?.namespaces.find((view) => view.ns === ns)?.revision;
|
|
629
|
+
}
|
|
536
630
|
/**
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
|
|
541
|
-
|
|
631
|
+
* True when `incoming` is the Host echo of a mutate this page already folded,
|
|
632
|
+
* or an older revision the snapshot has already passed. `echoed` is undefined
|
|
633
|
+
* until the first successful write.
|
|
634
|
+
*/
|
|
635
|
+
function isOwnDocumentEcho(echoed, incoming) {
|
|
636
|
+
return echoed !== void 0 && incoming <= echoed;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* After a preserve-dirty reload: conflicted cards get a conflict notice;
|
|
640
|
+
* live cards drop leftover conflict/error; saved notices stay; gone cards drop.
|
|
542
641
|
*/
|
|
543
|
-
|
|
544
|
-
|
|
642
|
+
function foldReloadNotices(current, args) {
|
|
643
|
+
const live = new Set(args.liveProviders);
|
|
644
|
+
const conflicted = new Set(args.conflicted);
|
|
645
|
+
const next = {};
|
|
646
|
+
for (const [provider, notice] of Object.entries(current)) {
|
|
647
|
+
if (!live.has(provider)) continue;
|
|
648
|
+
if (conflicted.has(provider)) continue;
|
|
649
|
+
if (notice.kind === "conflict" || notice.kind === "error") continue;
|
|
650
|
+
next[provider] = notice;
|
|
651
|
+
}
|
|
652
|
+
for (const provider of args.conflicted) next[provider] = args.conflictNotice;
|
|
653
|
+
return next;
|
|
654
|
+
}
|
|
655
|
+
function waitUntil(describe, predicate, signal) {
|
|
656
|
+
if (signal?.aborted) return Promise.resolve(false);
|
|
657
|
+
if (predicate()) return Promise.resolve(true);
|
|
658
|
+
return new Promise((resolve) => {
|
|
659
|
+
let settled = false;
|
|
660
|
+
const finish = (ok) => {
|
|
661
|
+
if (settled) return;
|
|
662
|
+
settled = true;
|
|
663
|
+
stop();
|
|
664
|
+
signal?.removeEventListener("abort", onAbort);
|
|
665
|
+
resolve(ok);
|
|
666
|
+
};
|
|
667
|
+
const onAbort = () => {
|
|
668
|
+
finish(false);
|
|
669
|
+
};
|
|
670
|
+
const stop = describe.subscribe(() => {
|
|
671
|
+
if (predicate()) finish(true);
|
|
672
|
+
});
|
|
673
|
+
signal?.addEventListener("abort", onAbort);
|
|
674
|
+
if (predicate()) finish(true);
|
|
675
|
+
else if (signal?.aborted) finish(false);
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
/** Resolve when the mirror's namespace revision is at least `revision`, or abort. */
|
|
679
|
+
async function waitForNamespaceRevision(describe, ns, revision, signal) {
|
|
680
|
+
return await waitUntil(describe, () => {
|
|
681
|
+
const current = namespaceRevision(describe.getSnapshot(), ns);
|
|
682
|
+
return current !== void 0 && current >= revision;
|
|
683
|
+
}, signal) ? "matched" : "aborted";
|
|
684
|
+
}
|
|
685
|
+
/** Resolve when the namespace revision differs from `previous`, or abort. */
|
|
686
|
+
async function waitForNamespaceRevisionChange(describe, ns, previous, signal) {
|
|
687
|
+
return await waitUntil(describe, () => {
|
|
688
|
+
const current = namespaceRevision(describe.getSnapshot(), ns);
|
|
689
|
+
return current !== void 0 && current !== previous;
|
|
690
|
+
}, signal) ? "changed" : "aborted";
|
|
691
|
+
}
|
|
692
|
+
async function assembleDrafts(api, describe, schema) {
|
|
545
693
|
const mirrored = describe.getSnapshot();
|
|
546
694
|
if (mirrored.view === void 0) return {
|
|
547
695
|
writable: false,
|
|
@@ -592,6 +740,14 @@ window.__ModuleLoader__.load({
|
|
|
592
740
|
drafts
|
|
593
741
|
};
|
|
594
742
|
}
|
|
743
|
+
/**
|
|
744
|
+
* `ensure`: first paint / idle recovery (official ensure only reads from idle).
|
|
745
|
+
* `snapshot`: refresh after the mirror revision already moved — do not ensure.
|
|
746
|
+
*/
|
|
747
|
+
async function loadDrafts(api, describe, schema, mode = "ensure") {
|
|
748
|
+
if (mode === "ensure") await describe.ensure();
|
|
749
|
+
return assembleDrafts(api, describe, schema);
|
|
750
|
+
}
|
|
595
751
|
//#endregion
|
|
596
752
|
//#region src/client/schema-ops.ts
|
|
597
753
|
/** Wrap a live settingsSchema service as plain callbacks. */
|
|
@@ -624,7 +780,7 @@ window.__ModuleLoader__.load({
|
|
|
624
780
|
}
|
|
625
781
|
//#endregion
|
|
626
782
|
//#region \0dsh-css:C:\Users\zimo\AppData\Roaming\io.github.hairyf.deepseek-harness-desktop\data\dsh\临时目录\dsh-plugin-effort-declare\src\client\effort-declare.module.css.mjs
|
|
627
|
-
const cssText = ".hYEBUa_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.hYEBUa_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.hYEBUa_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.hYEBUa_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.hYEBUa_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.hYEBUa_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.hYEBUa_rowHead{align-items:baseline;gap:8px;display:flex}.hYEBUa_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.hYEBUa_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.hYEBUa_compatSummary{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.hYEBUa_presetRow,.hYEBUa_actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.hYEBUa_primaryButton,.hYEBUa_secondaryButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.hYEBUa_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border:none}.hYEBUa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.hYEBUa_secondaryButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.hYEBUa_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.hYEBUa_primaryButton:disabled,.hYEBUa_secondaryButton:disabled,.hYEBUa_linkButton:disabled,.hYEBUa_input:disabled{opacity:.4;cursor:default}.hYEBUa_primaryButton:focus-visible,.hYEBUa_secondaryButton:focus-visible,.hYEBUa_linkButton:focus-visible,.hYEBUa_input:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.hYEBUa_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.hYEBUa_modelEntry{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;padding:10px 0;display:flex}.hYEBUa_modelHead{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.hYEBUa_modelId{font-size:13px;font-weight:500;line-height:20px}.hYEBUa_modelName{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.hYEBUa_levels{flex-wrap:wrap;gap:10px 14px;display:flex}.hYEBUa_level{align-items:center;gap:6px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_wireRow{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_input,.hYEBUa_selectInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);height:32px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;padding:0 10px;font-size:13px}.hYEBUa_wireInput{width:7em}.hYEBUa_offGroup{flex-direction:column;gap:6px;display:flex}.hYEBUa_advanced{border-top:1px solid var(--dsw-alias-border-l2);padding-top:8px}.hYEBUa_advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.hYEBUa_advancedBody{flex-direction:column;gap:10px;padding-top:10px;display:flex}.hYEBUa_check{align-items:flex-start;gap:8px;font-size:12px;line-height:18px;display:flex}";
|
|
783
|
+
const cssText = ".hYEBUa_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.hYEBUa_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.hYEBUa_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.hYEBUa_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.hYEBUa_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.hYEBUa_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.hYEBUa_rowHead{align-items:baseline;gap:8px;display:flex}.hYEBUa_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.hYEBUa_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.hYEBUa_compatSummary{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.hYEBUa_presetRow,.hYEBUa_actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.hYEBUa_primaryButton,.hYEBUa_secondaryButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.hYEBUa_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border:none}.hYEBUa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.hYEBUa_secondaryButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.hYEBUa_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.hYEBUa_primaryButton:disabled,.hYEBUa_secondaryButton:disabled,.hYEBUa_linkButton:disabled,.hYEBUa_input:disabled{opacity:.4;cursor:default}.hYEBUa_primaryButton:focus-visible,.hYEBUa_secondaryButton:focus-visible,.hYEBUa_linkButton:focus-visible,.hYEBUa_input:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.hYEBUa_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.hYEBUa_modelEntry{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;padding:10px 0;display:flex}.hYEBUa_modelHead{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.hYEBUa_modelId{font-size:13px;font-weight:500;line-height:20px}.hYEBUa_modelName{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.hYEBUa_levels{flex-wrap:wrap;gap:10px 14px;display:flex}.hYEBUa_level{align-items:center;gap:6px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_wireRow{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_input,.hYEBUa_selectInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);height:32px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;padding:0 10px;font-size:13px}.hYEBUa_wireInput{width:7em}.hYEBUa_offGroup{flex-direction:column;gap:6px;display:flex}.hYEBUa_advanced{border-top:1px solid var(--dsw-alias-border-l2);padding-top:8px}.hYEBUa_advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.hYEBUa_advancedBody{flex-direction:column;gap:10px;padding-top:10px;display:flex}.hYEBUa_check{align-items:flex-start;gap:8px;font-size:12px;line-height:18px;display:flex}.hYEBUa_footer{color:var(--dsw-alias-label-tertiary);opacity:.7;margin:16px 0 0;font-size:11px;line-height:16px}";
|
|
628
784
|
const cssTagId = "dsh-plugin-effort-declare/effort-declare.module.css";
|
|
629
785
|
var effort_declare_module_css_default = {
|
|
630
786
|
"actions": "hYEBUa_actions",
|
|
@@ -634,6 +790,7 @@ window.__ModuleLoader__.load({
|
|
|
634
790
|
"compatSummary": "hYEBUa_compatSummary",
|
|
635
791
|
"error": "hYEBUa_error",
|
|
636
792
|
"fieldLabel": "hYEBUa_fieldLabel",
|
|
793
|
+
"footer": "hYEBUa_footer",
|
|
637
794
|
"input": "hYEBUa_input",
|
|
638
795
|
"intro": "hYEBUa_intro",
|
|
639
796
|
"level": "hYEBUa_level",
|
|
@@ -663,8 +820,8 @@ window.__ModuleLoader__.load({
|
|
|
663
820
|
//#endregion
|
|
664
821
|
//#region src/client/EffortDeclareSection.tsx
|
|
665
822
|
/**
|
|
666
|
-
* Settings section: per-model reasoningEfforts
|
|
667
|
-
* for hand-declared llm-pi-ai routes.
|
|
823
|
+
* Settings section: per-model reasoningEfforts, image input, and
|
|
824
|
+
* openai-completions compat for hand-declared llm-pi-ai routes.
|
|
668
825
|
*/
|
|
669
826
|
function compatSummary(compat) {
|
|
670
827
|
const parts = [];
|
|
@@ -677,6 +834,7 @@ window.__ModuleLoader__.load({
|
|
|
677
834
|
if (code === "empty") return t("errorEmpty");
|
|
678
835
|
if (code === "off-only") return t("errorOffOnly");
|
|
679
836
|
if (code === "bad-wire") return t("errorBadWire");
|
|
837
|
+
if (code === "bad-input") return t("errorBadInput");
|
|
680
838
|
}
|
|
681
839
|
function ModelRowEditor(props) {
|
|
682
840
|
const { row, disabled, t, onChange } = props;
|
|
@@ -712,6 +870,21 @@ window.__ModuleLoader__.load({
|
|
|
712
870
|
})
|
|
713
871
|
]
|
|
714
872
|
}),
|
|
873
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
874
|
+
className: effort_declare_module_css_default.check,
|
|
875
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
876
|
+
type: "checkbox",
|
|
877
|
+
checked: readImageCapable(row),
|
|
878
|
+
disabled,
|
|
879
|
+
onChange: (event) => {
|
|
880
|
+
onChange(writeImageCapable(row, event.target.checked));
|
|
881
|
+
}
|
|
882
|
+
}), t("imageInput")]
|
|
883
|
+
}),
|
|
884
|
+
readImageCapable(row) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
885
|
+
className: effort_declare_module_css_default.notice,
|
|
886
|
+
children: t("imageInputHint")
|
|
887
|
+
}) : null,
|
|
715
888
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
716
889
|
className: effort_declare_module_css_default.fieldLabel,
|
|
717
890
|
children: t("levels")
|
|
@@ -795,7 +968,7 @@ window.__ModuleLoader__.load({
|
|
|
795
968
|
const formats = thinkingFormatChoices(props.formats, draft.compat.thinkingFormat);
|
|
796
969
|
const summary = compatSummary(draft.compat);
|
|
797
970
|
const sameWire = draft.compat.supportsReasoningEffort === false;
|
|
798
|
-
const clientError = draft.models.map((row) => errorText(
|
|
971
|
+
const clientError = draft.models.map((row) => errorText(modelRowError(row), t)).find((text) => text !== void 0);
|
|
799
972
|
const dirty = draftDirty(draft);
|
|
800
973
|
const applyPreset = (id) => {
|
|
801
974
|
const preset = PRESETS[id];
|
|
@@ -999,40 +1172,92 @@ window.__ModuleLoader__.load({
|
|
|
999
1172
|
const [notices, setNotices] = (0, react.useState)({});
|
|
1000
1173
|
const generationRef = (0, react.useRef)(0);
|
|
1001
1174
|
const draftsRef = (0, react.useRef)(drafts);
|
|
1175
|
+
const echoedRevisionRef = (0, react.useRef)(void 0);
|
|
1176
|
+
const pendingRevisionRef = (0, react.useRef)(void 0);
|
|
1177
|
+
const busyRouteRef = (0, react.useRef)(null);
|
|
1178
|
+
const abortRef = (0, react.useRef)(null);
|
|
1002
1179
|
draftsRef.current = drafts;
|
|
1003
|
-
const
|
|
1180
|
+
const applyDrafts = (next) => {
|
|
1181
|
+
const resolved = typeof next === "function" ? next(draftsRef.current) : next;
|
|
1182
|
+
draftsRef.current = resolved;
|
|
1183
|
+
setDrafts(resolved);
|
|
1184
|
+
};
|
|
1185
|
+
const snapshotMode = () => describe === void 0 || describe.getSnapshot().status === "idle" ? "ensure" : "snapshot";
|
|
1186
|
+
const beginGeneration = () => {
|
|
1187
|
+
abortRef.current?.abort();
|
|
1188
|
+
const abort = new AbortController();
|
|
1189
|
+
abortRef.current = abort;
|
|
1190
|
+
return {
|
|
1191
|
+
generation: nextGeneration(generationRef),
|
|
1192
|
+
signal: abort.signal
|
|
1193
|
+
};
|
|
1194
|
+
};
|
|
1195
|
+
const failGeneration = (generation, failure) => {
|
|
1196
|
+
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1197
|
+
setStatus("error");
|
|
1198
|
+
setError(failure instanceof Error ? failure.message : t("loadError"));
|
|
1199
|
+
};
|
|
1200
|
+
const settleReload = (generation, preserveDirty, result) => {
|
|
1201
|
+
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1202
|
+
setWritable(result.writable);
|
|
1203
|
+
setFormats(result.formats);
|
|
1204
|
+
if (result.error !== void 0) {
|
|
1205
|
+
setStatus("error");
|
|
1206
|
+
setError(result.error);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
const merged = mergeLoadedDrafts(draftsRef.current, result.drafts, { preserveDirty });
|
|
1210
|
+
applyDrafts(merged.drafts);
|
|
1211
|
+
setNotices((current) => foldReloadNotices(current, {
|
|
1212
|
+
conflicted: merged.conflicted,
|
|
1213
|
+
conflictNotice: {
|
|
1214
|
+
kind: "conflict",
|
|
1215
|
+
text: t("dirtyConflict")
|
|
1216
|
+
},
|
|
1217
|
+
liveProviders: merged.drafts.map((draft) => draft.provider)
|
|
1218
|
+
}));
|
|
1219
|
+
setStatus("ready");
|
|
1220
|
+
};
|
|
1221
|
+
const loadSnapshotThenSettle = async (generation, preserveDirty) => {
|
|
1222
|
+
if (api === void 0 || describe === void 0 || schema === void 0) return;
|
|
1223
|
+
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1224
|
+
try {
|
|
1225
|
+
const result = await loadDrafts(api, describe, schema, "snapshot");
|
|
1226
|
+
settleReload(generation, preserveDirty, result);
|
|
1227
|
+
} catch (failure) {
|
|
1228
|
+
failGeneration(generation, failure);
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
const reload = (0, react.useCallback)((preserveDirty, mode = "ensure") => {
|
|
1004
1232
|
if (api === void 0 || describe === void 0 || schema === void 0) {
|
|
1005
1233
|
setStatus("error");
|
|
1006
1234
|
setError(t("loadError"));
|
|
1007
1235
|
return;
|
|
1008
1236
|
}
|
|
1009
|
-
const generation =
|
|
1237
|
+
const { generation } = beginGeneration();
|
|
1010
1238
|
if (draftsRef.current.length === 0) setStatus("loading");
|
|
1011
1239
|
setError("");
|
|
1012
|
-
loadDrafts(api, describe, schema).then((result) => {
|
|
1013
|
-
|
|
1014
|
-
setWritable(result.writable);
|
|
1015
|
-
setFormats(result.formats);
|
|
1016
|
-
if (result.error !== void 0) {
|
|
1017
|
-
setStatus("error");
|
|
1018
|
-
setError(result.error);
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
const merged = mergeLoadedDrafts(draftsRef.current, result.drafts, { preserveDirty });
|
|
1022
|
-
setDrafts(merged.drafts);
|
|
1023
|
-
if (merged.conflicted.length > 0) setNotices((current) => {
|
|
1024
|
-
const next = { ...current };
|
|
1025
|
-
for (const provider of merged.conflicted) next[provider] = {
|
|
1026
|
-
kind: "conflict",
|
|
1027
|
-
text: t("dirtyConflict")
|
|
1028
|
-
};
|
|
1029
|
-
return next;
|
|
1030
|
-
});
|
|
1031
|
-
setStatus("ready");
|
|
1240
|
+
loadDrafts(api, describe, schema, mode).then((result) => {
|
|
1241
|
+
settleReload(generation, preserveDirty, result);
|
|
1032
1242
|
}, (failure) => {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1243
|
+
failGeneration(generation, failure);
|
|
1244
|
+
});
|
|
1245
|
+
}, [
|
|
1246
|
+
api,
|
|
1247
|
+
describe,
|
|
1248
|
+
schema,
|
|
1249
|
+
t
|
|
1250
|
+
]);
|
|
1251
|
+
const refreshAtRevision = (0, react.useCallback)((revision, preserveDirty) => {
|
|
1252
|
+
if (api === void 0 || describe === void 0 || schema === void 0) return;
|
|
1253
|
+
const { generation, signal } = beginGeneration();
|
|
1254
|
+
if (draftsRef.current.length === 0) setStatus("loading");
|
|
1255
|
+
setError("");
|
|
1256
|
+
waitForNamespaceRevision(describe, LLM_PI_AI_NS, revision, signal).then((outcome) => {
|
|
1257
|
+
if (outcome === "aborted" || !generationIsCurrent(generationRef, generation)) return;
|
|
1258
|
+
return loadSnapshotThenSettle(generation, preserveDirty);
|
|
1259
|
+
}, (failure) => {
|
|
1260
|
+
failGeneration(generation, failure);
|
|
1036
1261
|
});
|
|
1037
1262
|
}, [
|
|
1038
1263
|
api,
|
|
@@ -1040,22 +1265,44 @@ window.__ModuleLoader__.load({
|
|
|
1040
1265
|
schema,
|
|
1041
1266
|
t
|
|
1042
1267
|
]);
|
|
1268
|
+
const flushPendingSettings = (refresh) => {
|
|
1269
|
+
const pending = pendingRevisionRef.current;
|
|
1270
|
+
pendingRevisionRef.current = void 0;
|
|
1271
|
+
if (pending === void 0) return;
|
|
1272
|
+
if (isOwnDocumentEcho(echoedRevisionRef.current, pending)) return;
|
|
1273
|
+
refresh(pending, true);
|
|
1274
|
+
};
|
|
1043
1275
|
(0, react.useEffect)(() => {
|
|
1044
|
-
reload(false);
|
|
1276
|
+
reload(false, "ensure");
|
|
1045
1277
|
}, [reload]);
|
|
1278
|
+
(0, react.useEffect)(() => () => {
|
|
1279
|
+
abortRef.current?.abort();
|
|
1280
|
+
nextGeneration(generationRef);
|
|
1281
|
+
}, []);
|
|
1046
1282
|
(0, react.useEffect)(() => {
|
|
1047
1283
|
if (props.subscribeInvalidate === void 0) return void 0;
|
|
1048
|
-
return props.subscribeInvalidate((
|
|
1049
|
-
if (source === "writable") {
|
|
1284
|
+
return props.subscribeInvalidate((event) => {
|
|
1285
|
+
if (event.source === "writable") {
|
|
1050
1286
|
const view = describe?.getSnapshot().view;
|
|
1051
1287
|
if (view !== void 0) setWritable(view.writable);
|
|
1052
1288
|
return;
|
|
1053
1289
|
}
|
|
1054
|
-
if (source === "settings"
|
|
1290
|
+
if (event.source === "settings") {
|
|
1291
|
+
if (busyRouteRef.current !== null) {
|
|
1292
|
+
pendingRevisionRef.current = event.revision;
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
if (isOwnDocumentEcho(echoedRevisionRef.current, event.revision)) return;
|
|
1296
|
+
refreshAtRevision(event.revision, true);
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
if (event.source === "directory") reload(true, snapshotMode());
|
|
1300
|
+
if (event.source === "reset") reload(true, "ensure");
|
|
1055
1301
|
});
|
|
1056
1302
|
}, [
|
|
1057
1303
|
describe,
|
|
1058
1304
|
props.subscribeInvalidate,
|
|
1305
|
+
refreshAtRevision,
|
|
1059
1306
|
reload
|
|
1060
1307
|
]);
|
|
1061
1308
|
const patchNotice = (provider, notice) => {
|
|
@@ -1068,14 +1315,14 @@ window.__ModuleLoader__.load({
|
|
|
1068
1315
|
};
|
|
1069
1316
|
const save = async (draft) => {
|
|
1070
1317
|
if (api === void 0 || describe === void 0 || schema === void 0) return;
|
|
1071
|
-
if (status === "loading" ||
|
|
1318
|
+
if (status === "loading" || busyRouteRef.current !== null) {
|
|
1072
1319
|
patchNotice(draft.provider, {
|
|
1073
1320
|
kind: "error",
|
|
1074
1321
|
text: t("saveBusy")
|
|
1075
1322
|
});
|
|
1076
1323
|
return;
|
|
1077
1324
|
}
|
|
1078
|
-
const blocking = draft.models.map((row) => errorText(
|
|
1325
|
+
const blocking = draft.models.map((row) => errorText(modelRowError(row), t)).find((text) => text !== void 0);
|
|
1079
1326
|
if (blocking !== void 0) {
|
|
1080
1327
|
patchNotice(draft.provider, {
|
|
1081
1328
|
kind: "error",
|
|
@@ -1083,6 +1330,7 @@ window.__ModuleLoader__.load({
|
|
|
1083
1330
|
});
|
|
1084
1331
|
return;
|
|
1085
1332
|
}
|
|
1333
|
+
busyRouteRef.current = draft.provider;
|
|
1086
1334
|
setBusyRoute(draft.provider);
|
|
1087
1335
|
patchNotice(draft.provider, void 0);
|
|
1088
1336
|
try {
|
|
@@ -1094,7 +1342,7 @@ window.__ModuleLoader__.load({
|
|
|
1094
1342
|
afterCompat: draft.compat
|
|
1095
1343
|
});
|
|
1096
1344
|
if (ops.length === 0) {
|
|
1097
|
-
|
|
1345
|
+
applyDrafts((current) => current.map((row) => row.provider === draft.provider ? alignDraft(row) : row));
|
|
1098
1346
|
return;
|
|
1099
1347
|
}
|
|
1100
1348
|
const willWriteCompat = ops.some((op) => op.path.length > draft.settingsPath.length && op.path[draft.settingsPath.length] === "compat");
|
|
@@ -1128,12 +1376,21 @@ window.__ModuleLoader__.load({
|
|
|
1128
1376
|
kind: conflict ? "conflict" : "error",
|
|
1129
1377
|
text: conflict ? t("conflict") : response.result.error.message
|
|
1130
1378
|
});
|
|
1131
|
-
if (conflict)
|
|
1379
|
+
if (conflict) {
|
|
1380
|
+
const { generation, signal } = beginGeneration();
|
|
1381
|
+
waitForNamespaceRevisionChange(describe, LLM_PI_AI_NS, draft.revision, signal).then((outcome) => {
|
|
1382
|
+
if (outcome === "aborted" || !generationIsCurrent(generationRef, generation)) return;
|
|
1383
|
+
return loadSnapshotThenSettle(generation, true);
|
|
1384
|
+
}, (failure) => {
|
|
1385
|
+
failGeneration(generation, failure);
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1132
1388
|
return;
|
|
1133
1389
|
}
|
|
1134
1390
|
const view = response.result.value;
|
|
1391
|
+
echoedRevisionRef.current = view.revision;
|
|
1135
1392
|
describe.acceptView(view);
|
|
1136
|
-
|
|
1393
|
+
applyDrafts(applySaveSuccess(draftsRef.current, draft.provider, {
|
|
1137
1394
|
user: view.user ?? {},
|
|
1138
1395
|
revision: view.revision
|
|
1139
1396
|
}));
|
|
@@ -1147,7 +1404,9 @@ window.__ModuleLoader__.load({
|
|
|
1147
1404
|
text: failure instanceof Error ? failure.message : t("loadError")
|
|
1148
1405
|
});
|
|
1149
1406
|
} finally {
|
|
1407
|
+
busyRouteRef.current = null;
|
|
1150
1408
|
setBusyRoute(null);
|
|
1409
|
+
flushPendingSettings(refreshAtRevision);
|
|
1151
1410
|
}
|
|
1152
1411
|
};
|
|
1153
1412
|
const showLoading = status === "loading" && drafts.length === 0;
|
|
@@ -1182,7 +1441,7 @@ window.__ModuleLoader__.load({
|
|
|
1182
1441
|
type: "button",
|
|
1183
1442
|
className: effort_declare_module_css_default.secondaryButton,
|
|
1184
1443
|
onClick: () => {
|
|
1185
|
-
reload(true);
|
|
1444
|
+
reload(true, snapshotMode());
|
|
1186
1445
|
},
|
|
1187
1446
|
children: t("reload")
|
|
1188
1447
|
}) : null,
|
|
@@ -1205,21 +1464,25 @@ window.__ModuleLoader__.load({
|
|
|
1205
1464
|
t,
|
|
1206
1465
|
onChange: (next) => {
|
|
1207
1466
|
patchNotice(next.provider, void 0);
|
|
1208
|
-
|
|
1467
|
+
applyDrafts((current) => current.map((row) => row.provider === next.provider ? next : row));
|
|
1209
1468
|
},
|
|
1210
1469
|
onSave: (next) => {
|
|
1211
1470
|
save(next);
|
|
1212
1471
|
},
|
|
1213
1472
|
onCancel: (next) => {
|
|
1214
1473
|
patchNotice(next.provider, void 0);
|
|
1215
|
-
|
|
1474
|
+
applyDrafts((current) => current.map((row) => row.provider === next.provider ? {
|
|
1216
1475
|
...row,
|
|
1217
1476
|
models: cloneModels(row.originalModels),
|
|
1218
1477
|
compat: cloneObject(row.originalCompat)
|
|
1219
1478
|
} : row));
|
|
1220
1479
|
}
|
|
1221
1480
|
}, draft.provider))
|
|
1222
|
-
}) : null
|
|
1481
|
+
}) : null,
|
|
1482
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1483
|
+
className: effort_declare_module_css_default.footer,
|
|
1484
|
+
children: PLUGIN_FOOTER_TEXT
|
|
1485
|
+
})
|
|
1223
1486
|
]
|
|
1224
1487
|
});
|
|
1225
1488
|
}
|
|
@@ -1229,7 +1492,7 @@ window.__ModuleLoader__.load({
|
|
|
1229
1492
|
const zh = {
|
|
1230
1493
|
nav: "推理档位",
|
|
1231
1494
|
title: "推理档位声明",
|
|
1232
|
-
intro: "
|
|
1495
|
+
intro: "声明手工模型可提供的推理档位,以及是否接受图片输入。未声明则不显示 Effort 行,图片附件也会被拒绝。档位仍在输入框菜单中选择;密钥、目录与当前选中项不在本页修改。",
|
|
1233
1496
|
empty: "没有可编辑的手工 openai-completions 路由。",
|
|
1234
1497
|
emptyHint: "请先到「模型」页添加提供方(llm-pi-ai 手工路由)。官方 DeepSeek 与 catalog 路由不在本页编辑。需要 DSH ≥ 0.1.0-rc.8(providers.declared)。",
|
|
1235
1498
|
loadError: "无法加载提供方或设置。",
|
|
@@ -1239,7 +1502,7 @@ window.__ModuleLoader__.load({
|
|
|
1239
1502
|
saving: "保存中…",
|
|
1240
1503
|
saveBusy: "另有路由正在保存,请稍候。",
|
|
1241
1504
|
cancel: "取消",
|
|
1242
|
-
saved: "
|
|
1505
|
+
saved: "已保存。对话会按新的能力声明更新 Effort 行和是否允许贴图。",
|
|
1243
1506
|
conflict: "设置已被其他地方改过,请重新加载后再保存。",
|
|
1244
1507
|
dirtyConflict: "此路由有未保存修改,设置已在其他地方更新。保存会写到最新文档上,或先取消再改。",
|
|
1245
1508
|
presets: "预设",
|
|
@@ -1267,12 +1530,15 @@ window.__ModuleLoader__.load({
|
|
|
1267
1530
|
errorOffOnly: "不能只开 Off,必须再开一档思考档。",
|
|
1268
1531
|
errorBadWire: "思考档必须填写线上拼写;只有 Off 可以留空。不能使用未知档位键。",
|
|
1269
1532
|
noModels: "这条路由还没有 models 列表。请先到「模型」页添加模型。",
|
|
1270
|
-
reload: "重新加载"
|
|
1533
|
+
reload: "重新加载",
|
|
1534
|
+
imageInput: "支持图片输入",
|
|
1535
|
+
imageInputHint: "只在这个模型确实能看图时勾选。勾错了图会进聊天记录,然后被接口打回来。",
|
|
1536
|
+
errorBadInput: "input 只能是 text / image,必须包含 text,不能重复或留空。不支持图片请清除该键,不要写成空列表。"
|
|
1271
1537
|
};
|
|
1272
1538
|
const en = {
|
|
1273
1539
|
nav: "Reasoning efforts",
|
|
1274
1540
|
title: "Reasoning effort declarations",
|
|
1275
|
-
intro: "
|
|
1541
|
+
intro: "Declare reasoning levels and image input for hand-added models. Undeclared models omit the Effort row and refuse image attachments. Effort is still chosen in the composer menu; keys, catalogs, and the current selection are not modified here.",
|
|
1276
1542
|
empty: "No editable hand-declared openai-completions routes.",
|
|
1277
1543
|
emptyHint: "Add a provider on the Models page first (an llm-pi-ai hand-declared route). Official DeepSeek and catalog routes are not edited here. Requires DSH ≥ 0.1.0-rc.8 (providers.declared).",
|
|
1278
1544
|
loadError: "Could not load providers or settings.",
|
|
@@ -1282,7 +1548,7 @@ window.__ModuleLoader__.load({
|
|
|
1282
1548
|
saving: "Saving…",
|
|
1283
1549
|
saveBusy: "Another route is saving. Wait, then save this card.",
|
|
1284
1550
|
cancel: "Cancel",
|
|
1285
|
-
saved: "Saved. The composer Effort row
|
|
1551
|
+
saved: "Saved. The composer Effort row and image admission follow this capability declaration.",
|
|
1286
1552
|
conflict: "Settings changed elsewhere. Reload, then save again.",
|
|
1287
1553
|
dirtyConflict: "This route has unsaved edits and settings changed elsewhere. Save writes onto the latest document, or cancel first.",
|
|
1288
1554
|
presets: "Presets",
|
|
@@ -1310,7 +1576,10 @@ window.__ModuleLoader__.load({
|
|
|
1310
1576
|
errorOffOnly: "Off alone is not enough; declare at least one thinking level.",
|
|
1311
1577
|
errorBadWire: "Thinking levels need a wire spelling; only Off may be empty. Unknown effort keys are rejected.",
|
|
1312
1578
|
noModels: "This route has no models list yet. Add models on the Models page first.",
|
|
1313
|
-
reload: "Reload"
|
|
1579
|
+
reload: "Reload",
|
|
1580
|
+
imageInput: "Accepts image input",
|
|
1581
|
+
imageInputHint: "Check only if this model actually sees images. Over-claiming admits a picture into history, then the gateway rejects the turn.",
|
|
1582
|
+
errorBadInput: "input may only list text and image, must include text, and must not be empty or duplicated. To drop vision, unset the key; do not write []."
|
|
1314
1583
|
};
|
|
1315
1584
|
//#endregion
|
|
1316
1585
|
//#region src/client/index.ts
|
|
@@ -1357,22 +1626,25 @@ window.__ModuleLoader__.load({
|
|
|
1357
1626
|
const describe = ctx.settingsScope.describe();
|
|
1358
1627
|
const invalidation = /* @__PURE__ */ new Set();
|
|
1359
1628
|
ctx.effect(() => {
|
|
1360
|
-
const emit = (
|
|
1361
|
-
for (const listener of invalidation) listener(
|
|
1629
|
+
const emit = (event) => {
|
|
1630
|
+
for (const listener of invalidation) listener(event);
|
|
1362
1631
|
};
|
|
1363
1632
|
const disposers = [
|
|
1364
1633
|
describe.subscribe(() => {
|
|
1365
|
-
emit("writable");
|
|
1634
|
+
emit({ source: "writable" });
|
|
1366
1635
|
}),
|
|
1367
|
-
ctx.remote.$on("settings/document-updated", (ns) => {
|
|
1636
|
+
ctx.remote.$on("settings/document-updated", (ns, revision) => {
|
|
1368
1637
|
if (ns !== "llm-pi-ai") return;
|
|
1369
|
-
emit(
|
|
1638
|
+
emit({
|
|
1639
|
+
source: "settings",
|
|
1640
|
+
revision
|
|
1641
|
+
});
|
|
1370
1642
|
}),
|
|
1371
1643
|
ctx.remote.$on("llm/adapters-updated", () => {
|
|
1372
|
-
emit("directory");
|
|
1644
|
+
emit({ source: "directory" });
|
|
1373
1645
|
}),
|
|
1374
1646
|
ctx.on("connection/reset", () => {
|
|
1375
|
-
emit("
|
|
1647
|
+
emit({ source: "reset" });
|
|
1376
1648
|
})
|
|
1377
1649
|
];
|
|
1378
1650
|
return () => {
|