dsh-plugin-effort-declare 0.1.3 → 0.1.5
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 -10
- package/CONTRIBUTING.md +23 -13
- package/INSTALL.en.md +9 -9
- package/INSTALL.md +16 -16
- package/README.en.md +27 -21
- package/README.md +30 -24
- package/lib/client.js +142 -61
- package/lib/client.js.map +1 -1
- package/lib/types/client/EffortDeclareSection.d.ts +5 -4
- package/lib/types/client/EffortDeclareSection.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +23 -2
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/load-drafts.d.ts +3 -3
- 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/client/remotes.d.ts +40 -0
- package/lib/types/client/remotes.d.ts.map +1 -0
- package/lib/types/core/catalog.d.ts +11 -3
- package/lib/types/core/catalog.d.ts.map +1 -1
- package/lib/types/core/drafts.d.ts +9 -5
- package/lib/types/core/drafts.d.ts.map +1 -1
- package/lib/types/core/filter.d.ts +1 -1
- package/lib/types/core/filter.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/path-ops.d.ts +1 -1
- package/lib/types/core/path-ops.d.ts.map +1 -1
- package/lib/types/core/validate.d.ts +3 -0
- package/lib/types/core/validate.d.ts.map +1 -1
- package/package.json +10 -13
- package/src/README.en.md +2 -2
- package/src/README.md +2 -2
- package/src/client/EffortDeclareSection.tsx +36 -26
- package/src/client/README.en.md +8 -7
- package/src/client/README.md +8 -7
- package/src/client/index.ts +35 -6
- package/src/client/load-drafts.ts +10 -10
- package/src/client/locales.ts +15 -6
- package/src/client/remotes.ts +39 -0
- package/src/core/README.en.md +8 -7
- package/src/core/README.md +8 -7
- package/src/core/catalog.ts +14 -2
- package/src/core/drafts.ts +41 -27
- package/src/core/filter.ts +1 -1
- package/src/core/input.ts +49 -0
- package/src/core/path-ops.ts +1 -1
- package/src/core/validate.ts +8 -0
package/lib/client.js
CHANGED
|
@@ -11,7 +11,7 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
* Canonical thinking levels and openai-completions thinkingFormat names.
|
|
12
12
|
*
|
|
13
13
|
* Levels match `@deepseek-ai/dsh-llm-pi-ai` catalog.ts `THINKING_LEVELS`.
|
|
14
|
-
* Formats match `SUPPORTED_THINKING_FORMATS` in the same file (
|
|
14
|
+
* Formats match `SUPPORTED_THINKING_FORMATS` in the same file (0.1.2-alpha.2).
|
|
15
15
|
* Tests pin these lists against a checked-in schema fixture
|
|
16
16
|
* (`tests/fixtures/pi-ai-thinking-format-union.ts`) and the local level
|
|
17
17
|
* whitelist. The settings page never offers the handwritten thinkingFormat
|
|
@@ -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]));
|
|
@@ -524,12 +539,58 @@ window.__ModuleLoader__.load({
|
|
|
524
539
|
return next;
|
|
525
540
|
}
|
|
526
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
|
|
527
584
|
//#region src/core/validate.ts
|
|
528
585
|
/** Per-model client-side check used to show errors without throwing. */
|
|
529
586
|
function modelEffortError(row) {
|
|
530
587
|
if (!("reasoningEfforts" in row) || row.reasoningEfforts === void 0) return void 0;
|
|
531
588
|
return validateReasoningEfforts(row.reasoningEfforts);
|
|
532
589
|
}
|
|
590
|
+
/** First blocking error on a model row (efforts, then input). */
|
|
591
|
+
function modelRowError(row) {
|
|
592
|
+
return modelEffortError(row) ?? modelInputError(row);
|
|
593
|
+
}
|
|
533
594
|
//#endregion
|
|
534
595
|
//#region src/core/attribution.ts
|
|
535
596
|
/**
|
|
@@ -555,7 +616,7 @@ window.__ModuleLoader__.load({
|
|
|
555
616
|
* package.json at DSH startup — host apply is empty and the settings page
|
|
556
617
|
* runs in the browser.
|
|
557
618
|
*/
|
|
558
|
-
const PLUGIN_FOOTER_TEXT = formatAttribution("0.1.
|
|
619
|
+
const PLUGIN_FOOTER_TEXT = formatAttribution("0.1.5", COPYRIGHT_FROM, 2026);
|
|
559
620
|
//#endregion
|
|
560
621
|
//#region src/client/load-drafts.ts
|
|
561
622
|
function schemaDefaultString(node) {
|
|
@@ -628,7 +689,7 @@ window.__ModuleLoader__.load({
|
|
|
628
689
|
return current !== void 0 && current !== previous;
|
|
629
690
|
}, signal) ? "changed" : "aborted";
|
|
630
691
|
}
|
|
631
|
-
async function assembleDrafts(
|
|
692
|
+
async function assembleDrafts(llm, describe, schema) {
|
|
632
693
|
const mirrored = describe.getSnapshot();
|
|
633
694
|
if (mirrored.view === void 0) return {
|
|
634
695
|
writable: false,
|
|
@@ -636,12 +697,12 @@ window.__ModuleLoader__.load({
|
|
|
636
697
|
drafts: [],
|
|
637
698
|
error: mirrored.error ?? void 0
|
|
638
699
|
};
|
|
639
|
-
const providersResponse = await
|
|
640
|
-
if (!providersResponse.
|
|
700
|
+
const providersResponse = await llm.listConfigurableProviders();
|
|
701
|
+
if (!providersResponse.ok) return {
|
|
641
702
|
writable: mirrored.view.writable,
|
|
642
703
|
formats: [],
|
|
643
704
|
drafts: [],
|
|
644
|
-
error: providersResponse.
|
|
705
|
+
error: providersResponse.error.message
|
|
645
706
|
};
|
|
646
707
|
const pi = new Map(mirrored.view.namespaces.map((view) => [view.ns, view])).get(LLM_PI_AI_NS);
|
|
647
708
|
let formats = [];
|
|
@@ -662,7 +723,7 @@ window.__ModuleLoader__.load({
|
|
|
662
723
|
]));
|
|
663
724
|
} catch {}
|
|
664
725
|
const drafts = [];
|
|
665
|
-
for (const entry of providersResponse.
|
|
726
|
+
for (const entry of providersResponse.value) {
|
|
666
727
|
const settingsPath = entry.settingsPath !== void 0 && entry.settingsPath.length > 0 ? [...entry.settingsPath] : ["providers", entry.provider];
|
|
667
728
|
if (!classifyRoute(entry, profileAt(pi?.value, settingsPath, entry.provider), schemaDefaultApi).editable) continue;
|
|
668
729
|
drafts.push(routeDraftFromUserProfile({
|
|
@@ -683,9 +744,9 @@ window.__ModuleLoader__.load({
|
|
|
683
744
|
* `ensure`: first paint / idle recovery (official ensure only reads from idle).
|
|
684
745
|
* `snapshot`: refresh after the mirror revision already moved — do not ensure.
|
|
685
746
|
*/
|
|
686
|
-
async function loadDrafts(
|
|
747
|
+
async function loadDrafts(llm, describe, schema, mode = "ensure") {
|
|
687
748
|
if (mode === "ensure") await describe.ensure();
|
|
688
|
-
return assembleDrafts(
|
|
749
|
+
return assembleDrafts(llm, describe, schema);
|
|
689
750
|
}
|
|
690
751
|
//#endregion
|
|
691
752
|
//#region src/client/schema-ops.ts
|
|
@@ -759,8 +820,8 @@ window.__ModuleLoader__.load({
|
|
|
759
820
|
//#endregion
|
|
760
821
|
//#region src/client/EffortDeclareSection.tsx
|
|
761
822
|
/**
|
|
762
|
-
* Settings section: per-model reasoningEfforts
|
|
763
|
-
* 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.
|
|
764
825
|
*/
|
|
765
826
|
function compatSummary(compat) {
|
|
766
827
|
const parts = [];
|
|
@@ -773,6 +834,7 @@ window.__ModuleLoader__.load({
|
|
|
773
834
|
if (code === "empty") return t("errorEmpty");
|
|
774
835
|
if (code === "off-only") return t("errorOffOnly");
|
|
775
836
|
if (code === "bad-wire") return t("errorBadWire");
|
|
837
|
+
if (code === "bad-input") return t("errorBadInput");
|
|
776
838
|
}
|
|
777
839
|
function ModelRowEditor(props) {
|
|
778
840
|
const { row, disabled, t, onChange } = props;
|
|
@@ -808,6 +870,21 @@ window.__ModuleLoader__.load({
|
|
|
808
870
|
})
|
|
809
871
|
]
|
|
810
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,
|
|
811
888
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
812
889
|
className: effort_declare_module_css_default.fieldLabel,
|
|
813
890
|
children: t("levels")
|
|
@@ -891,7 +968,7 @@ window.__ModuleLoader__.load({
|
|
|
891
968
|
const formats = thinkingFormatChoices(props.formats, draft.compat.thinkingFormat);
|
|
892
969
|
const summary = compatSummary(draft.compat);
|
|
893
970
|
const sameWire = draft.compat.supportsReasoningEffort === false;
|
|
894
|
-
const clientError = draft.models.map((row) => errorText(
|
|
971
|
+
const clientError = draft.models.map((row) => errorText(modelRowError(row), t)).find((text) => text !== void 0);
|
|
895
972
|
const dirty = draftDirty(draft);
|
|
896
973
|
const applyPreset = (id) => {
|
|
897
974
|
const preset = PRESETS[id];
|
|
@@ -1083,7 +1160,8 @@ window.__ModuleLoader__.load({
|
|
|
1083
1160
|
}
|
|
1084
1161
|
function EffortDeclareSection(props) {
|
|
1085
1162
|
const t = props.t;
|
|
1086
|
-
const
|
|
1163
|
+
const llm = props.llm;
|
|
1164
|
+
const settings = props.settings;
|
|
1087
1165
|
const describe = props.describe;
|
|
1088
1166
|
const schema = props.schema;
|
|
1089
1167
|
const [status, setStatus] = (0, react.useState)("loading");
|
|
@@ -1142,17 +1220,17 @@ window.__ModuleLoader__.load({
|
|
|
1142
1220
|
setStatus("ready");
|
|
1143
1221
|
};
|
|
1144
1222
|
const loadSnapshotThenSettle = async (generation, preserveDirty) => {
|
|
1145
|
-
if (
|
|
1223
|
+
if (llm === void 0 || typeof llm.listConfigurableProviders !== "function" || describe === void 0 || schema === void 0) return;
|
|
1146
1224
|
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1147
1225
|
try {
|
|
1148
|
-
const result = await loadDrafts(
|
|
1226
|
+
const result = await loadDrafts(llm, describe, schema, "snapshot");
|
|
1149
1227
|
settleReload(generation, preserveDirty, result);
|
|
1150
1228
|
} catch (failure) {
|
|
1151
1229
|
failGeneration(generation, failure);
|
|
1152
1230
|
}
|
|
1153
1231
|
};
|
|
1154
1232
|
const reload = (0, react.useCallback)((preserveDirty, mode = "ensure") => {
|
|
1155
|
-
if (
|
|
1233
|
+
if (llm === void 0 || typeof llm.listConfigurableProviders !== "function" || describe === void 0 || schema === void 0) {
|
|
1156
1234
|
setStatus("error");
|
|
1157
1235
|
setError(t("loadError"));
|
|
1158
1236
|
return;
|
|
@@ -1160,19 +1238,19 @@ window.__ModuleLoader__.load({
|
|
|
1160
1238
|
const { generation } = beginGeneration();
|
|
1161
1239
|
if (draftsRef.current.length === 0) setStatus("loading");
|
|
1162
1240
|
setError("");
|
|
1163
|
-
loadDrafts(
|
|
1241
|
+
loadDrafts(llm, describe, schema, mode).then((result) => {
|
|
1164
1242
|
settleReload(generation, preserveDirty, result);
|
|
1165
1243
|
}, (failure) => {
|
|
1166
1244
|
failGeneration(generation, failure);
|
|
1167
1245
|
});
|
|
1168
1246
|
}, [
|
|
1169
|
-
|
|
1247
|
+
llm,
|
|
1170
1248
|
describe,
|
|
1171
1249
|
schema,
|
|
1172
1250
|
t
|
|
1173
1251
|
]);
|
|
1174
1252
|
const refreshAtRevision = (0, react.useCallback)((revision, preserveDirty) => {
|
|
1175
|
-
if (
|
|
1253
|
+
if (llm === void 0 || typeof llm.listConfigurableProviders !== "function" || describe === void 0 || schema === void 0) return;
|
|
1176
1254
|
const { generation, signal } = beginGeneration();
|
|
1177
1255
|
if (draftsRef.current.length === 0) setStatus("loading");
|
|
1178
1256
|
setError("");
|
|
@@ -1183,7 +1261,7 @@ window.__ModuleLoader__.load({
|
|
|
1183
1261
|
failGeneration(generation, failure);
|
|
1184
1262
|
});
|
|
1185
1263
|
}, [
|
|
1186
|
-
|
|
1264
|
+
llm,
|
|
1187
1265
|
describe,
|
|
1188
1266
|
schema,
|
|
1189
1267
|
t
|
|
@@ -1237,7 +1315,7 @@ window.__ModuleLoader__.load({
|
|
|
1237
1315
|
});
|
|
1238
1316
|
};
|
|
1239
1317
|
const save = async (draft) => {
|
|
1240
|
-
if (
|
|
1318
|
+
if (settings === void 0 || typeof settings.mutate !== "function" || describe === void 0 || schema === void 0) return;
|
|
1241
1319
|
if (status === "loading" || busyRouteRef.current !== null) {
|
|
1242
1320
|
patchNotice(draft.provider, {
|
|
1243
1321
|
kind: "error",
|
|
@@ -1245,7 +1323,7 @@ window.__ModuleLoader__.load({
|
|
|
1245
1323
|
});
|
|
1246
1324
|
return;
|
|
1247
1325
|
}
|
|
1248
|
-
const blocking = draft.models.map((row) => errorText(
|
|
1326
|
+
const blocking = draft.models.map((row) => errorText(modelRowError(row), t)).find((text) => text !== void 0);
|
|
1249
1327
|
if (blocking !== void 0) {
|
|
1250
1328
|
patchNotice(draft.provider, {
|
|
1251
1329
|
kind: "error",
|
|
@@ -1288,16 +1366,12 @@ window.__ModuleLoader__.load({
|
|
|
1288
1366
|
}
|
|
1289
1367
|
}
|
|
1290
1368
|
}
|
|
1291
|
-
const response = await
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
expectedRevision: draft.revision
|
|
1295
|
-
});
|
|
1296
|
-
if (!response.result.ok) {
|
|
1297
|
-
const conflict = response.result.error.code === "settings-conflict";
|
|
1369
|
+
const response = await settings.mutate(LLM_PI_AI_NS, ops, draft.revision);
|
|
1370
|
+
if (!response.ok) {
|
|
1371
|
+
const conflict = response.error.code === "settings/conflict";
|
|
1298
1372
|
patchNotice(draft.provider, {
|
|
1299
1373
|
kind: conflict ? "conflict" : "error",
|
|
1300
|
-
text: conflict ? t("conflict") : response.
|
|
1374
|
+
text: conflict ? t("conflict") : response.error.message
|
|
1301
1375
|
});
|
|
1302
1376
|
if (conflict) {
|
|
1303
1377
|
const { generation, signal } = beginGeneration();
|
|
@@ -1310,7 +1384,7 @@ window.__ModuleLoader__.load({
|
|
|
1310
1384
|
}
|
|
1311
1385
|
return;
|
|
1312
1386
|
}
|
|
1313
|
-
const view = response.
|
|
1387
|
+
const view = response.value;
|
|
1314
1388
|
echoedRevisionRef.current = view.revision;
|
|
1315
1389
|
describe.acceptView(view);
|
|
1316
1390
|
applyDrafts(applySaveSuccess(draftsRef.current, draft.provider, {
|
|
@@ -1415,9 +1489,9 @@ window.__ModuleLoader__.load({
|
|
|
1415
1489
|
const zh = {
|
|
1416
1490
|
nav: "推理档位",
|
|
1417
1491
|
title: "推理档位声明",
|
|
1418
|
-
intro: "
|
|
1492
|
+
intro: "声明手工模型可提供的推理档位,以及是否接受图片输入。未声明则不显示 Effort 行,图片附件也会被拒绝。档位仍在输入框菜单中选择;密钥、目录与当前选中项不在本页修改。",
|
|
1419
1493
|
empty: "没有可编辑的手工 openai-completions 路由。",
|
|
1420
|
-
emptyHint: "请先到「模型」页添加提供方(llm-pi-ai 手工路由)。官方 DeepSeek 与 catalog 路由不在本页编辑。需要 DSH ≥ 0.1.
|
|
1494
|
+
emptyHint: "请先到「模型」页添加提供方(llm-pi-ai 手工路由)。官方 DeepSeek 与 catalog 路由不在本页编辑。需要 DSH ≥ 0.1.2-alpha.2。",
|
|
1421
1495
|
loadError: "无法加载提供方或设置。",
|
|
1422
1496
|
loading: "正在加载…",
|
|
1423
1497
|
readOnly: "当前设置为只读,无法保存。",
|
|
@@ -1425,7 +1499,7 @@ window.__ModuleLoader__.load({
|
|
|
1425
1499
|
saving: "保存中…",
|
|
1426
1500
|
saveBusy: "另有路由正在保存,请稍候。",
|
|
1427
1501
|
cancel: "取消",
|
|
1428
|
-
saved: "
|
|
1502
|
+
saved: "已保存。对话会按新的能力声明更新 Effort 行和是否允许贴图。",
|
|
1429
1503
|
conflict: "设置已被其他地方改过,请重新加载后再保存。",
|
|
1430
1504
|
dirtyConflict: "此路由有未保存修改,设置已在其他地方更新。保存会写到最新文档上,或先取消再改。",
|
|
1431
1505
|
presets: "预设",
|
|
@@ -1453,14 +1527,17 @@ window.__ModuleLoader__.load({
|
|
|
1453
1527
|
errorOffOnly: "不能只开 Off,必须再开一档思考档。",
|
|
1454
1528
|
errorBadWire: "思考档必须填写线上拼写;只有 Off 可以留空。不能使用未知档位键。",
|
|
1455
1529
|
noModels: "这条路由还没有 models 列表。请先到「模型」页添加模型。",
|
|
1456
|
-
reload: "重新加载"
|
|
1530
|
+
reload: "重新加载",
|
|
1531
|
+
imageInput: "支持图片输入",
|
|
1532
|
+
imageInputHint: "只在这个模型确实能看图时勾选。勾错了图会进聊天记录,然后被接口打回来。",
|
|
1533
|
+
errorBadInput: "input 只能是 text / image,必须包含 text,不能重复或留空。不支持图片请清除该键,不要写成空列表。"
|
|
1457
1534
|
};
|
|
1458
1535
|
const en = {
|
|
1459
1536
|
nav: "Reasoning efforts",
|
|
1460
1537
|
title: "Reasoning effort declarations",
|
|
1461
|
-
intro: "
|
|
1538
|
+
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.",
|
|
1462
1539
|
empty: "No editable hand-declared openai-completions routes.",
|
|
1463
|
-
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.
|
|
1540
|
+
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.2-alpha.2.",
|
|
1464
1541
|
loadError: "Could not load providers or settings.",
|
|
1465
1542
|
loading: "Loading…",
|
|
1466
1543
|
readOnly: "Settings are read-only; saving is disabled.",
|
|
@@ -1468,7 +1545,7 @@ window.__ModuleLoader__.load({
|
|
|
1468
1545
|
saving: "Saving…",
|
|
1469
1546
|
saveBusy: "Another route is saving. Wait, then save this card.",
|
|
1470
1547
|
cancel: "Cancel",
|
|
1471
|
-
saved: "Saved. The composer Effort row
|
|
1548
|
+
saved: "Saved. The composer Effort row and image admission follow this capability declaration.",
|
|
1472
1549
|
conflict: "Settings changed elsewhere. Reload, then save again.",
|
|
1473
1550
|
dirtyConflict: "This route has unsaved edits and settings changed elsewhere. Save writes onto the latest document, or cancel first.",
|
|
1474
1551
|
presets: "Presets",
|
|
@@ -1496,15 +1573,19 @@ window.__ModuleLoader__.load({
|
|
|
1496
1573
|
errorOffOnly: "Off alone is not enough; declare at least one thinking level.",
|
|
1497
1574
|
errorBadWire: "Thinking levels need a wire spelling; only Off may be empty. Unknown effort keys are rejected.",
|
|
1498
1575
|
noModels: "This route has no models list yet. Add models on the Models page first.",
|
|
1499
|
-
reload: "Reload"
|
|
1576
|
+
reload: "Reload",
|
|
1577
|
+
imageInput: "Accepts image input",
|
|
1578
|
+
imageInputHint: "Check only if this model actually sees images. Over-claiming admits a picture into history, then the gateway rejects the turn.",
|
|
1579
|
+
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 []."
|
|
1500
1580
|
};
|
|
1501
1581
|
//#endregion
|
|
1502
1582
|
//#region src/client/index.ts
|
|
1503
1583
|
const inject = [
|
|
1504
1584
|
"slots",
|
|
1505
1585
|
"locale",
|
|
1506
|
-
"connection",
|
|
1507
1586
|
"remote",
|
|
1587
|
+
"remote.llm",
|
|
1588
|
+
"remote.settings",
|
|
1508
1589
|
"settingsScope",
|
|
1509
1590
|
"settingsSchema"
|
|
1510
1591
|
];
|
|
@@ -1530,7 +1611,6 @@ window.__ModuleLoader__.load({
|
|
|
1530
1611
|
en
|
|
1531
1612
|
}), `${PLUGIN_ID}: dictionaries`);
|
|
1532
1613
|
ctx.effect(() => mountPluginCss(), `${PLUGIN_ID}: css`);
|
|
1533
|
-
const connection = ctx.get("connection");
|
|
1534
1614
|
const settingsSchema = ctx.settingsSchema;
|
|
1535
1615
|
const schema = bindSchema({
|
|
1536
1616
|
rehydrate: (serialized) => settingsSchema.rehydrate(serialized),
|
|
@@ -1581,7 +1661,8 @@ window.__ModuleLoader__.load({
|
|
|
1581
1661
|
label: () => t("nav"),
|
|
1582
1662
|
locale: NS,
|
|
1583
1663
|
inject: () => ({
|
|
1584
|
-
|
|
1664
|
+
llm: ctx.remote.llm,
|
|
1665
|
+
settings: ctx.remote.settings,
|
|
1585
1666
|
describe,
|
|
1586
1667
|
schema,
|
|
1587
1668
|
subscribeInvalidate
|