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
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Load editable route drafts from llm.providers + the llm-pi-ai namespace.
|
|
3
3
|
* Drafts come from the user layer; route protocol classification may use effective value.
|
|
4
|
+
*
|
|
5
|
+
* First paint uses `ensure()` (idle-only). Refresh never calls `ensure()`:
|
|
6
|
+
* wait until the mirror subscribe shows a namespace revision at least as new
|
|
7
|
+
* as the Host event, then `getSnapshot()`. Own mutate echoes are identified
|
|
8
|
+
* by revision (including older delayed echoes), not ignored as a generic
|
|
9
|
+
* document-updated.
|
|
4
10
|
*/
|
|
5
11
|
import type { IApiClient } from '@deepseek-ai/dsh-api-remotes/client';
|
|
6
12
|
import type { SettingsDescribeFace } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
@@ -12,12 +18,36 @@ export interface LoadDraftsResult {
|
|
|
12
18
|
drafts: RouteDraft[];
|
|
13
19
|
error?: string;
|
|
14
20
|
}
|
|
21
|
+
export type LoadDraftsMode = 'ensure' | 'snapshot';
|
|
22
|
+
type MirrorSnapshot = ReturnType<SettingsDescribeFace['getSnapshot']>;
|
|
23
|
+
type MirrorDescribe = Pick<SettingsDescribeFace, 'getSnapshot' | 'subscribe'>;
|
|
24
|
+
/** Namespace revision on a describe snapshot, if that row exists. */
|
|
25
|
+
export declare function namespaceRevision(snapshot: MirrorSnapshot, ns: string): number | undefined;
|
|
15
26
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
* True when `incoming` is the Host echo of a mutate this page already folded,
|
|
28
|
+
* or an older revision the snapshot has already passed. `echoed` is undefined
|
|
29
|
+
* until the first successful write.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isOwnDocumentEcho(echoed: number | undefined, incoming: number): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* After a preserve-dirty reload: conflicted cards get a conflict notice;
|
|
34
|
+
* live cards drop leftover conflict/error; saved notices stay; gone cards drop.
|
|
35
|
+
*/
|
|
36
|
+
export declare function foldReloadNotices<T extends {
|
|
37
|
+
kind: string;
|
|
38
|
+
}>(current: Record<string, T>, args: {
|
|
39
|
+
conflicted: readonly string[];
|
|
40
|
+
conflictNotice: T;
|
|
41
|
+
liveProviders: readonly string[];
|
|
42
|
+
}): Record<string, T>;
|
|
43
|
+
/** Resolve when the mirror's namespace revision is at least `revision`, or abort. */
|
|
44
|
+
export declare function waitForNamespaceRevision(describe: MirrorDescribe, ns: string, revision: number, signal?: AbortSignal): Promise<'matched' | 'aborted'>;
|
|
45
|
+
/** Resolve when the namespace revision differs from `previous`, or abort. */
|
|
46
|
+
export declare function waitForNamespaceRevisionChange(describe: MirrorDescribe, ns: string, previous: number, signal?: AbortSignal): Promise<'changed' | 'aborted'>;
|
|
47
|
+
/**
|
|
48
|
+
* `ensure`: first paint / idle recovery (official ensure only reads from idle).
|
|
49
|
+
* `snapshot`: refresh after the mirror revision already moved — do not ensure.
|
|
21
50
|
*/
|
|
22
|
-
export declare function loadDrafts(api: Pick<IApiClient, 'llm'>, describe: Pick<SettingsDescribeFace, 'ensure' | 'getSnapshot'>, schema: SchemaOps): Promise<LoadDraftsResult>;
|
|
51
|
+
export declare function loadDrafts(api: Pick<IApiClient, 'llm'>, describe: Pick<SettingsDescribeFace, 'ensure' | 'getSnapshot'>, schema: SchemaOps, mode?: LoadDraftsMode): Promise<LoadDraftsResult>;
|
|
52
|
+
export {};
|
|
23
53
|
//# sourceMappingURL=load-drafts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-drafts.d.ts","sourceRoot":"","sources":["../../../src/client/load-drafts.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"load-drafts.d.ts","sourceRoot":"","sources":["../../../src/client/load-drafts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,UAAU,EAAyB,MAAM,qCAAqC,CAAA;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAA;AAKtF,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAG9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAOhD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,CAAA;AAElD,KAAK,cAAc,GAAG,UAAU,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CAAA;AACrE,KAAK,cAAc,GAAG,IAAI,CAAC,oBAAoB,EAAE,aAAa,GAAG,WAAW,CAAC,CAAA;AAE7E,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1F;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAC1D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAC1B,IAAI,EAAE;IACJ,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7B,cAAc,EAAE,CAAC,CAAA;IACjB,aAAa,EAAE,SAAS,MAAM,EAAE,CAAA;CACjC,GACA,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAcnB;AA4BD,qFAAqF;AACrF,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,cAAc,EACxB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAUhC;AAED,6EAA6E;AAC7E,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,cAAc,EACxB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAMhC;AAqDD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,EAC5B,QAAQ,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,aAAa,CAAC,EAC9D,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,cAAyB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAG3B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dictionary namespace for the effort-declare settings section.
|
|
3
3
|
*/
|
|
4
|
-
export type EffortDeclareKey = 'nav' | 'title' | 'intro' | 'empty' | 'emptyHint' | 'loadError' | 'loading' | 'readOnly' | 'save' | 'saving' | 'saveBusy' | 'cancel' | 'saved' | 'conflict' | 'dirtyConflict' | 'presets' | 'presetDeepSeek' | 'presetOpenAI' | 'presetToggle' | 'presetToggleWarn' | 'model' | 'levels' | 'wire' | 'offMode' | 'offAbsent' | 'offEmpty' | 'offValue' | 'offValuePlaceholder' | 'clear' | 'advanced' | 'thinkingFormat' | 'thinkingFormatDefault' | 'supportsDeveloperRole' | 'supportsReasoningEffort' | 'developerTrueHint' | 'compatSummary' | 'errorEmpty' | 'errorOffOnly' | 'errorBadWire' | 'noModels' | 'reload';
|
|
4
|
+
export type EffortDeclareKey = 'nav' | 'title' | 'intro' | 'empty' | 'emptyHint' | 'loadError' | 'loading' | 'readOnly' | 'save' | 'saving' | 'saveBusy' | 'cancel' | 'saved' | 'conflict' | 'dirtyConflict' | 'presets' | 'presetDeepSeek' | 'presetOpenAI' | 'presetToggle' | 'presetToggleWarn' | 'model' | 'levels' | 'wire' | 'offMode' | 'offAbsent' | 'offEmpty' | 'offValue' | 'offValuePlaceholder' | 'clear' | 'advanced' | 'thinkingFormat' | 'thinkingFormatDefault' | 'supportsDeveloperRole' | 'supportsReasoningEffort' | 'developerTrueHint' | 'compatSummary' | 'errorEmpty' | 'errorOffOnly' | 'errorBadWire' | 'noModels' | 'reload' | 'imageInput' | 'imageInputHint' | 'errorBadInput';
|
|
5
5
|
export declare const NS = "plugin-effort-declare";
|
|
6
6
|
export declare const zh: Record<EffortDeclareKey, string>;
|
|
7
7
|
export declare const en: Record<EffortDeclareKey, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,gBAAgB,GACxB,KAAK,GACL,OAAO,GACP,OAAO,GACP,OAAO,GACP,WAAW,GACX,WAAW,GACX,SAAS,GACT,UAAU,GACV,MAAM,GACN,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,OAAO,GACP,UAAU,GACV,eAAe,GACf,SAAS,GACT,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,kBAAkB,GAClB,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,GACT,WAAW,GACX,UAAU,GACV,UAAU,GACV,qBAAqB,GACrB,OAAO,GACP,UAAU,GACV,gBAAgB,GAChB,uBAAuB,GACvB,uBAAuB,GACvB,yBAAyB,GACzB,mBAAmB,GACnB,eAAe,GACf,YAAY,GACZ,cAAc,GACd,cAAc,GACd,UAAU,GACV,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,gBAAgB,GACxB,KAAK,GACL,OAAO,GACP,OAAO,GACP,OAAO,GACP,WAAW,GACX,WAAW,GACX,SAAS,GACT,UAAU,GACV,MAAM,GACN,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,OAAO,GACP,UAAU,GACV,eAAe,GACf,SAAS,GACT,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,kBAAkB,GAClB,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,GACT,WAAW,GACX,UAAU,GACV,UAAU,GACV,qBAAqB,GACrB,OAAO,GACP,UAAU,GACV,gBAAgB,GAChB,uBAAuB,GACvB,uBAAuB,GACvB,yBAAyB,GACzB,mBAAmB,GACnB,eAAe,GACf,YAAY,GACZ,cAAc,GACd,cAAc,GACd,UAAU,GACV,QAAQ,GACR,YAAY,GACZ,gBAAgB,GAChB,eAAe,CAAA;AAEnB,eAAO,MAAM,EAAE,0BAA0B,CAAA;AAEzC,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CA6C/C,CAAA;AAED,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CA6C/C,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin footer attribution. Version and end-year are frozen into the client
|
|
3
|
+
* bundle at pack time; this module only formats the line.
|
|
4
|
+
*/
|
|
5
|
+
/** First publication year (LICENSE). Not the user's wall clock. */
|
|
6
|
+
export declare const COPYRIGHT_FROM = 2026;
|
|
7
|
+
export declare const COPYRIGHT_HOLDER = "Stardust";
|
|
8
|
+
/**
|
|
9
|
+
* `0.1.2 © 2026 Stardust` or `0.1.2 © 2026–2027 Stardust`.
|
|
10
|
+
* Throws if version is empty or `to < from` — a bad stamp must not render.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatAttribution(version: string, from: number, to: number): string;
|
|
13
|
+
//# sourceMappingURL=attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../../../src/core/attribution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mEAAmE;AACnE,eAAO,MAAM,cAAc,OAAO,CAAA;AAElC,eAAO,MAAM,gBAAgB,aAAa,CAAA;AAE1C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CASnF"}
|
|
@@ -30,4 +30,12 @@ export declare const LLM_DEEPSEEK_NS = "llm-deepseek";
|
|
|
30
30
|
export declare const DEEPSEEK_OFFICIAL = "deepseek-official";
|
|
31
31
|
/** Any route key walks a dict schema to the same profile node. */
|
|
32
32
|
export declare const SCHEMA_PROBE_ROUTE = "\0probe";
|
|
33
|
+
/** Request modalities llm-pi-ai accepts on `models[].input` / `defaultInput`. */
|
|
34
|
+
export declare const INPUT_MODALITIES: readonly ["text", "image"];
|
|
35
|
+
export type InputModality = (typeof INPUT_MODALITIES)[number];
|
|
36
|
+
/**
|
|
37
|
+
* Canonical write for a hand-declared vision model.
|
|
38
|
+
* Must include `text`; image-only is not a serviceable OpenAI-completions route.
|
|
39
|
+
*/
|
|
40
|
+
export declare const IMAGE_CAPABLE_INPUT: readonly InputModality[];
|
|
33
41
|
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/core/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,eAAe,sEAQlB,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAE5D,yEAAyE;AACzE,eAAO,MAAM,2BAA2B,6DAEvC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,gJAW5B,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,sDAAsD;AACtD,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AAEtD,6CAA6C;AAC7C,eAAO,MAAM,YAAY,cAAc,CAAA;AAEvC,kDAAkD;AAClD,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAE7C,+CAA+C;AAC/C,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AAEpD,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,YAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/core/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,eAAe,sEAQlB,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAE5D,yEAAyE;AACzE,eAAO,MAAM,2BAA2B,6DAEvC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,gJAW5B,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,sDAAsD;AACtD,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AAEtD,6CAA6C;AAC7C,eAAO,MAAM,YAAY,cAAc,CAAA;AAEvC,kDAAkD;AAClD,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAE7C,+CAA+C;AAC/C,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AAEpD,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,YAAgB,CAAA;AAE/C,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,4BAA6B,CAAA;AAE1D,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,aAAa,EAAsB,CAAA"}
|
|
@@ -34,9 +34,13 @@ export declare function applySaveSuccess(drafts: readonly RouteDraft[], savedPro
|
|
|
34
34
|
user: unknown;
|
|
35
35
|
revision: number;
|
|
36
36
|
}): RouteDraft[];
|
|
37
|
+
/** Model-row fields this page edits; other keys follow the Models page. */
|
|
38
|
+
export declare const MODEL_OVERLAY_KEYS: readonly ["reasoningEfforts", "input"];
|
|
39
|
+
export type ModelOverlayKey = (typeof MODEL_OVERLAY_KEYS)[number];
|
|
37
40
|
/**
|
|
38
41
|
* Membership follows the latest user-layer models list (Models page add/delete).
|
|
39
|
-
* Local unsaved
|
|
42
|
+
* Local unsaved overlay keys (including a cleared key) overlay by id; other
|
|
43
|
+
* fields on the row follow incoming.
|
|
40
44
|
*/
|
|
41
45
|
export declare function mergeModelsById(args: {
|
|
42
46
|
prevModels: readonly Record<string, unknown>[];
|
|
@@ -62,9 +66,9 @@ export declare function mergeCompat(args: {
|
|
|
62
66
|
};
|
|
63
67
|
/**
|
|
64
68
|
* Apply a freshly loaded table. Membership and metadata follow incoming;
|
|
65
|
-
* unsaved reasoningEfforts / dirty compat keys
|
|
66
|
-
* when a locally dirty field also changed in
|
|
67
|
-
* and sibling-card saves do not warn).
|
|
69
|
+
* unsaved overlay keys (`reasoningEfforts`, `input`) / dirty compat keys
|
|
70
|
+
* overlay by id. Conflict only when a locally dirty field also changed in
|
|
71
|
+
* originals (revision-only bumps and sibling-card saves do not warn).
|
|
68
72
|
*/
|
|
69
73
|
export declare function mergeLoadedDrafts(current: readonly RouteDraft[], incoming: readonly RouteDraft[], options: {
|
|
70
74
|
preserveDirty: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drafts.d.ts","sourceRoot":"","sources":["../../../src/core/drafts.ts"],"names":[],"mappings":"AAQA,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,0EAA0E;IAC1E,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;IACjC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC,gFAAgF;IAChF,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAEjE;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAErE;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,OAAO,CAAA;CACrB,GAAG,UAAU,CAgBb;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAQrD;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAOxD;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACzC,UAAU,EAAE,CAcd;
|
|
1
|
+
{"version":3,"file":"drafts.d.ts","sourceRoot":"","sources":["../../../src/core/drafts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"efforts.d.ts","sourceRoot":"","sources":["../../../src/core/efforts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAElE,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;AAE5E,mEAAmE;AACnE,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAA;AAElD,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,GAAG,KAAK,GAAG,SAAS,CAAA;AAExE,kDAAkD;AAClD,wBAAgB,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAM/F;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CACtB,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,GACZ,gBAAgB,
|
|
1
|
+
{"version":3,"file":"efforts.d.ts","sourceRoot":"","sources":["../../../src/core/efforts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAElE,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;AAE5E,mEAAmE;AACnE,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAA;AAElD,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,GAAG,KAAK,GAAG,SAAS,CAAA;AAExE,kDAAkD;AAClD,wBAAgB,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAM/F;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CACtB,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,GACZ,gBAAgB,CASlB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,OAAO,CAE7G;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CACzB,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,EACpC,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,MAAM,GACZ,gBAAgB,CAKlB;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAC7B,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,EACpC,IAAI,EAAE,MAAM,GACX,gBAAgB,CAGlB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAwBxG;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAI3F;AAED,2FAA2F;AAC3F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,GAAG,SAAS,CAKtF;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,EAAE,gBAAgB,GAAG,SAAS,GACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Whether the stored `input` list includes image. Absence is false. */
|
|
2
|
+
export declare function readImageCapable(row: Record<string, unknown>): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Declare or drop image input on a spread row.
|
|
5
|
+
* Enabled writes `[text, image]`; disabled unsets the key (not `[]`, not `[text]`).
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeImageCapable(row: Record<string, unknown>, enabled: boolean): Record<string, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Validate a stored `input` field. Returns an error code; never throws.
|
|
10
|
+
* Absence is valid. Empty list is rejected so a bad stamp cannot be re-saved.
|
|
11
|
+
*/
|
|
12
|
+
export declare function validateInput(input: unknown): 'bad-input' | undefined;
|
|
13
|
+
/** Per-model client-side check used to show errors without throwing. */
|
|
14
|
+
export declare function modelInputError(row: Record<string, unknown>): 'bad-input' | undefined;
|
|
15
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/core/input.ts"],"names":[],"mappings":"AAOA,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAGtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,CAWrE;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,GAAG,SAAS,CAGrF"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export type ModelRowError = 'empty' | 'off-only' | 'bad-wire' | 'bad-input';
|
|
1
2
|
/** Per-model client-side check used to show errors without throwing. */
|
|
2
3
|
export declare function modelEffortError(row: Record<string, unknown>): 'empty' | 'off-only' | 'bad-wire' | undefined;
|
|
4
|
+
/** First blocking error on a model row (efforts, then input). */
|
|
5
|
+
export declare function modelRowError(row: Record<string, unknown>): ModelRowError | undefined;
|
|
3
6
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/core/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/core/validate.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAA;AAE3E,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAG5G;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,GAAG,SAAS,CAErF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-effort-declare",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "0.1.
|
|
3
|
+
"description": "Declare per-model reasoning efforts, image input, and openai-completions dialect on hand-declared llm-pi-ai routes. Writes the official namespace; does not intercept llm/stream or replace the Models page.",
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
package/src/README.en.md
CHANGED
|
@@ -16,8 +16,8 @@ Install: [INSTALL.en.md](../INSTALL.en.md). Usage: root [README.en.md](../README
|
|
|
16
16
|
| Path | Role |
|
|
17
17
|
| --- | --- |
|
|
18
18
|
| [`index.ts`](./index.ts) | Host entry. Exports `name` and `apply`. v1 registers no host services or adapters; the bundle still needs this entry so `dsh plugin add` can load the package. |
|
|
19
|
-
| [`core/`](./core/) | UI-free pure functions: efforts, presets, save ops, draft merge, route filtering. Shared by the client and tests; the v1 host entry does not import them (`tsconfig.host` still compiles `core` for types). |
|
|
20
|
-
| [`client/`](./client/) | Browser half: locale, settings page, `settings.mutate` against `llm-pi-ai`. |
|
|
19
|
+
| [`core/`](./core/) | UI-free pure functions: reasoning efforts, image input, presets, save ops, draft merge, route filtering, footer attribution. Shared by the client and tests; the v1 host entry does not import them (`tsconfig.host` still compiles `core` for types). |
|
|
20
|
+
| [`client/`](./client/) | Browser half: locale, settings page, and official `settings.mutate` against `llm-pi-ai` for `reasoningEfforts` and `input`. |
|
|
21
21
|
| [`css-modules.d.ts`](./css-modules.d.ts) | Types for `*.module.css` (class map plus `cssText` / `cssTagId`). |
|
|
22
22
|
|
|
23
23
|
`tsconfig.host.json` compiles host + `core`; `tsconfig.client.json` compiles `client` + `core`. Build output lives in [`lib/`](../lib/).
|
package/src/README.md
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
| 路径 | 说明 |
|
|
17
17
|
| --- | --- |
|
|
18
18
|
| [`index.ts`](./index.ts) | Host 入口。导出 `name` 与 `apply`。v1 不注册 host 服务、不挂适配器;组合包仍需要这一入口才能被 `dsh plugin add` 加载。 |
|
|
19
|
-
| [`core/`](./core/) | 与 UI
|
|
20
|
-
| [`client/`](./client/) | 浏览器半区:locale
|
|
19
|
+
| [`core/`](./core/) | 与 UI 无关的纯函数:推理档位、图片输入、预设、保存 ops、草稿合并、路由过滤、页脚归因格式。client 与单测共用;Host 入口 v1 不引用这些函数(`tsconfig.host` 仍编译 `core` 以产出类型)。 |
|
|
20
|
+
| [`client/`](./client/) | 浏览器半区:locale、设置页,经官方 `settings.mutate` 写入 `llm-pi-ai` 的 `reasoningEfforts` 与 `input`。 |
|
|
21
21
|
| [`css-modules.d.ts`](./css-modules.d.ts) | `*.module.css` 模块类型(class map + `cssText` / `cssTagId`)。 |
|
|
22
22
|
|
|
23
23
|
`tsconfig.host.json` 编译 host + `core`;`tsconfig.client.json` 编译 `client` + `core`。构建产物在 [`lib/`](../lib/)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings section: per-model reasoningEfforts
|
|
3
|
-
* for hand-declared llm-pi-ai routes.
|
|
2
|
+
* Settings section: per-model reasoningEfforts, image input, and
|
|
3
|
+
* openai-completions compat for hand-declared llm-pi-ai routes.
|
|
4
4
|
*/
|
|
5
5
|
import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'
|
|
6
6
|
import type { IApiClient } from '@deepseek-ai/dsh-api-remotes/client'
|
|
@@ -29,19 +29,34 @@ import {
|
|
|
29
29
|
import { applyPresetCompat, applyPresetEfforts, PRESETS, type PresetId } from '../core/presets.ts'
|
|
30
30
|
import { buildSaveOps } from '../core/path-ops.ts'
|
|
31
31
|
import { cloneModels, cloneObject } from '../core/paths.ts'
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
32
|
+
import { readImageCapable, writeImageCapable } from '../core/input.ts'
|
|
33
|
+
import { modelRowError } from '../core/validate.ts'
|
|
34
|
+
import { PLUGIN_FOOTER_TEXT } from './build-info.ts'
|
|
35
|
+
import {
|
|
36
|
+
foldReloadNotices,
|
|
37
|
+
isOwnDocumentEcho,
|
|
38
|
+
loadDrafts,
|
|
39
|
+
waitForNamespaceRevision,
|
|
40
|
+
waitForNamespaceRevisionChange,
|
|
41
|
+
type LoadDraftsMode,
|
|
42
|
+
} from './load-drafts.ts'
|
|
34
43
|
import { validateSaveDraft, type SchemaOps } from './schema-ops.ts'
|
|
35
44
|
import type { EffortDeclareKey } from './locales.ts'
|
|
36
45
|
import css from './effort-declare.module.css'
|
|
37
46
|
|
|
38
|
-
export type InvalidationSource = 'settings' | 'directory' | 'writable'
|
|
47
|
+
export type InvalidationSource = 'settings' | 'directory' | 'reset' | 'writable'
|
|
48
|
+
|
|
49
|
+
export type Invalidation =
|
|
50
|
+
| { source: 'writable' }
|
|
51
|
+
| { source: 'directory' }
|
|
52
|
+
| { source: 'reset' }
|
|
53
|
+
| { source: 'settings'; revision: number }
|
|
39
54
|
|
|
40
55
|
export interface EffortDeclareSectionInjected {
|
|
41
56
|
api: Pick<IApiClient, 'settings' | 'llm'>
|
|
42
57
|
describe: SettingsDescribeFace
|
|
43
58
|
schema: SchemaOps
|
|
44
|
-
subscribeInvalidate: (listener: (
|
|
59
|
+
subscribeInvalidate: (listener: (event: Invalidation) => void) => () => void
|
|
45
60
|
}
|
|
46
61
|
|
|
47
62
|
export interface EffortDeclareSectionProps extends Partial<EffortDeclareSectionInjected> {
|
|
@@ -61,10 +76,11 @@ function compatSummary(compat: Record<string, unknown>): string {
|
|
|
61
76
|
return parts.join(' · ')
|
|
62
77
|
}
|
|
63
78
|
|
|
64
|
-
function errorText(code: ReturnType<typeof
|
|
79
|
+
function errorText(code: ReturnType<typeof modelRowError>, t: (key: EffortDeclareKey) => string): string | undefined {
|
|
65
80
|
if (code === 'empty') return t('errorEmpty')
|
|
66
81
|
if (code === 'off-only') return t('errorOffOnly')
|
|
67
82
|
if (code === 'bad-wire') return t('errorBadWire')
|
|
83
|
+
if (code === 'bad-input') return t('errorBadInput')
|
|
68
84
|
return undefined
|
|
69
85
|
}
|
|
70
86
|
|
|
@@ -100,6 +116,16 @@ function ModelRowEditor(props: {
|
|
|
100
116
|
{t('clear')}
|
|
101
117
|
</button>
|
|
102
118
|
</div>
|
|
119
|
+
<label className={css.check}>
|
|
120
|
+
<input
|
|
121
|
+
type="checkbox"
|
|
122
|
+
checked={readImageCapable(row)}
|
|
123
|
+
disabled={disabled}
|
|
124
|
+
onChange={(event) => { onChange(writeImageCapable(row, event.target.checked)) }}
|
|
125
|
+
/>
|
|
126
|
+
{t('imageInput')}
|
|
127
|
+
</label>
|
|
128
|
+
{readImageCapable(row) ? <p className={css.notice}>{t('imageInputHint')}</p> : null}
|
|
103
129
|
<span className={css.fieldLabel}>{t('levels')}</span>
|
|
104
130
|
<div className={css.levels}>
|
|
105
131
|
{THINKING_LEVELS_WITHOUT_OFF.map((level) => (
|
|
@@ -183,7 +209,7 @@ function RouteCard(props: {
|
|
|
183
209
|
const summary = compatSummary(draft.compat)
|
|
184
210
|
const sameWire = draft.compat.supportsReasoningEffort === false
|
|
185
211
|
const clientError = draft.models
|
|
186
|
-
.map(row => errorText(
|
|
212
|
+
.map(row => errorText(modelRowError(row), t))
|
|
187
213
|
.find(text => text !== undefined)
|
|
188
214
|
const dirty = draftDirty(draft)
|
|
189
215
|
|
|
@@ -328,58 +354,133 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
328
354
|
const [notices, setNotices] = useState<Record<string, CardNotice>>({})
|
|
329
355
|
const generationRef = useRef(0)
|
|
330
356
|
const draftsRef = useRef(drafts)
|
|
357
|
+
const echoedRevisionRef = useRef<number | undefined>(undefined)
|
|
358
|
+
const pendingRevisionRef = useRef<number | undefined>(undefined)
|
|
359
|
+
const busyRouteRef = useRef<string | null>(null)
|
|
360
|
+
const abortRef = useRef<AbortController | null>(null)
|
|
331
361
|
draftsRef.current = drafts
|
|
332
362
|
|
|
333
|
-
const
|
|
363
|
+
const applyDrafts = (next: RouteDraft[] | ((current: RouteDraft[]) => RouteDraft[])): void => {
|
|
364
|
+
const resolved = typeof next === 'function' ? next(draftsRef.current) : next
|
|
365
|
+
draftsRef.current = resolved
|
|
366
|
+
setDrafts(resolved)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const snapshotMode = (): LoadDraftsMode => (
|
|
370
|
+
describe === undefined || describe.getSnapshot().status === 'idle' ? 'ensure' : 'snapshot'
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
const beginGeneration = (): { generation: number; signal: AbortSignal } => {
|
|
374
|
+
abortRef.current?.abort()
|
|
375
|
+
const abort = new AbortController()
|
|
376
|
+
abortRef.current = abort
|
|
377
|
+
return { generation: nextGeneration(generationRef), signal: abort.signal }
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const failGeneration = (generation: number, failure: unknown): void => {
|
|
381
|
+
if (!generationIsCurrent(generationRef, generation)) return
|
|
382
|
+
setStatus('error')
|
|
383
|
+
setError(failure instanceof Error ? failure.message : t('loadError'))
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const settleReload = (
|
|
387
|
+
generation: number,
|
|
388
|
+
preserveDirty: boolean,
|
|
389
|
+
result: Awaited<ReturnType<typeof loadDrafts>>,
|
|
390
|
+
): void => {
|
|
391
|
+
if (!generationIsCurrent(generationRef, generation)) return
|
|
392
|
+
setWritable(result.writable)
|
|
393
|
+
setFormats(result.formats)
|
|
394
|
+
if (result.error !== undefined) {
|
|
395
|
+
setStatus('error')
|
|
396
|
+
setError(result.error)
|
|
397
|
+
return
|
|
398
|
+
}
|
|
399
|
+
const merged = mergeLoadedDrafts(draftsRef.current, result.drafts, { preserveDirty })
|
|
400
|
+
applyDrafts(merged.drafts)
|
|
401
|
+
setNotices(current => foldReloadNotices(current, {
|
|
402
|
+
conflicted: merged.conflicted,
|
|
403
|
+
conflictNotice: { kind: 'conflict', text: t('dirtyConflict') },
|
|
404
|
+
liveProviders: merged.drafts.map(draft => draft.provider),
|
|
405
|
+
}))
|
|
406
|
+
setStatus('ready')
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const loadSnapshotThenSettle = async (generation: number, preserveDirty: boolean): Promise<void> => {
|
|
410
|
+
if (api === undefined || describe === undefined || schema === undefined) return
|
|
411
|
+
if (!generationIsCurrent(generationRef, generation)) return
|
|
412
|
+
try {
|
|
413
|
+
const result = await loadDrafts(api, describe, schema, 'snapshot')
|
|
414
|
+
settleReload(generation, preserveDirty, result)
|
|
415
|
+
} catch (failure) {
|
|
416
|
+
failGeneration(generation, failure)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const reload = useCallback((preserveDirty: boolean, mode: LoadDraftsMode = 'ensure'): void => {
|
|
334
421
|
if (api === undefined || describe === undefined || schema === undefined) {
|
|
335
422
|
setStatus('error')
|
|
336
423
|
setError(t('loadError'))
|
|
337
424
|
return
|
|
338
425
|
}
|
|
339
|
-
const generation =
|
|
426
|
+
const { generation } = beginGeneration()
|
|
340
427
|
if (draftsRef.current.length === 0) setStatus('loading')
|
|
341
428
|
setError('')
|
|
342
|
-
void loadDrafts(api, describe, schema).then((result) => {
|
|
343
|
-
|
|
344
|
-
setWritable(result.writable)
|
|
345
|
-
setFormats(result.formats)
|
|
346
|
-
if (result.error !== undefined) {
|
|
347
|
-
setStatus('error')
|
|
348
|
-
setError(result.error)
|
|
349
|
-
return
|
|
350
|
-
}
|
|
351
|
-
const merged = mergeLoadedDrafts(draftsRef.current, result.drafts, { preserveDirty })
|
|
352
|
-
setDrafts(merged.drafts)
|
|
353
|
-
if (merged.conflicted.length > 0) {
|
|
354
|
-
setNotices(current => {
|
|
355
|
-
const next = { ...current }
|
|
356
|
-
for (const provider of merged.conflicted) {
|
|
357
|
-
next[provider] = { kind: 'conflict', text: t('dirtyConflict') }
|
|
358
|
-
}
|
|
359
|
-
return next
|
|
360
|
-
})
|
|
361
|
-
}
|
|
362
|
-
setStatus('ready')
|
|
429
|
+
void loadDrafts(api, describe, schema, mode).then((result) => {
|
|
430
|
+
settleReload(generation, preserveDirty, result)
|
|
363
431
|
}, (failure: unknown) => {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
432
|
+
failGeneration(generation, failure)
|
|
433
|
+
})
|
|
434
|
+
}, [api, describe, schema, t])
|
|
435
|
+
|
|
436
|
+
const refreshAtRevision = useCallback((revision: number, preserveDirty: boolean): void => {
|
|
437
|
+
if (api === undefined || describe === undefined || schema === undefined) return
|
|
438
|
+
const { generation, signal } = beginGeneration()
|
|
439
|
+
if (draftsRef.current.length === 0) setStatus('loading')
|
|
440
|
+
setError('')
|
|
441
|
+
void waitForNamespaceRevision(describe, LLM_PI_AI_NS, revision, signal).then((outcome) => {
|
|
442
|
+
if (outcome === 'aborted' || !generationIsCurrent(generationRef, generation)) return
|
|
443
|
+
return loadSnapshotThenSettle(generation, preserveDirty)
|
|
444
|
+
}, (failure: unknown) => {
|
|
445
|
+
failGeneration(generation, failure)
|
|
367
446
|
})
|
|
368
447
|
}, [api, describe, schema, t])
|
|
369
448
|
|
|
370
|
-
|
|
449
|
+
const flushPendingSettings = (refresh: (revision: number, preserveDirty: boolean) => void): void => {
|
|
450
|
+
const pending = pendingRevisionRef.current
|
|
451
|
+
pendingRevisionRef.current = undefined
|
|
452
|
+
if (pending === undefined) return
|
|
453
|
+
if (isOwnDocumentEcho(echoedRevisionRef.current, pending)) return
|
|
454
|
+
refresh(pending, true)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
useEffect(() => { reload(false, 'ensure') }, [reload])
|
|
458
|
+
useEffect(() => () => {
|
|
459
|
+
abortRef.current?.abort()
|
|
460
|
+
nextGeneration(generationRef)
|
|
461
|
+
}, [])
|
|
371
462
|
|
|
372
463
|
useEffect(() => {
|
|
373
464
|
if (props.subscribeInvalidate === undefined) return undefined
|
|
374
|
-
return props.subscribeInvalidate((
|
|
375
|
-
if (source === 'writable') {
|
|
465
|
+
return props.subscribeInvalidate((event) => {
|
|
466
|
+
if (event.source === 'writable') {
|
|
376
467
|
const view = describe?.getSnapshot().view
|
|
377
468
|
if (view !== undefined) setWritable(view.writable)
|
|
378
469
|
return
|
|
379
470
|
}
|
|
380
|
-
if (source === 'settings'
|
|
471
|
+
if (event.source === 'settings') {
|
|
472
|
+
if (busyRouteRef.current !== null) {
|
|
473
|
+
pendingRevisionRef.current = event.revision
|
|
474
|
+
return
|
|
475
|
+
}
|
|
476
|
+
if (isOwnDocumentEcho(echoedRevisionRef.current, event.revision)) return
|
|
477
|
+
refreshAtRevision(event.revision, true)
|
|
478
|
+
return
|
|
479
|
+
}
|
|
480
|
+
if (event.source === 'directory') reload(true, snapshotMode())
|
|
481
|
+
if (event.source === 'reset') reload(true, 'ensure')
|
|
381
482
|
})
|
|
382
|
-
}, [describe, props.subscribeInvalidate, reload])
|
|
483
|
+
}, [describe, props.subscribeInvalidate, refreshAtRevision, reload])
|
|
383
484
|
|
|
384
485
|
const patchNotice = (provider: string, notice: CardNotice | undefined): void => {
|
|
385
486
|
setNotices(current => {
|
|
@@ -392,17 +493,18 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
392
493
|
|
|
393
494
|
const save = async (draft: RouteDraft): Promise<void> => {
|
|
394
495
|
if (api === undefined || describe === undefined || schema === undefined) return
|
|
395
|
-
if (status === 'loading' ||
|
|
496
|
+
if (status === 'loading' || busyRouteRef.current !== null) {
|
|
396
497
|
patchNotice(draft.provider, { kind: 'error', text: t('saveBusy') })
|
|
397
498
|
return
|
|
398
499
|
}
|
|
399
500
|
const blocking = draft.models
|
|
400
|
-
.map(row => errorText(
|
|
501
|
+
.map(row => errorText(modelRowError(row), t))
|
|
401
502
|
.find(text => text !== undefined)
|
|
402
503
|
if (blocking !== undefined) {
|
|
403
504
|
patchNotice(draft.provider, { kind: 'error', text: blocking })
|
|
404
505
|
return
|
|
405
506
|
}
|
|
507
|
+
busyRouteRef.current = draft.provider
|
|
406
508
|
setBusyRoute(draft.provider)
|
|
407
509
|
patchNotice(draft.provider, undefined)
|
|
408
510
|
try {
|
|
@@ -414,7 +516,7 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
414
516
|
afterCompat: draft.compat,
|
|
415
517
|
})
|
|
416
518
|
if (ops.length === 0) {
|
|
417
|
-
|
|
519
|
+
applyDrafts(current => current.map(row => row.provider === draft.provider ? alignDraft(row) : row))
|
|
418
520
|
return
|
|
419
521
|
}
|
|
420
522
|
const willWriteCompat = ops.some(op => (
|
|
@@ -454,12 +556,21 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
454
556
|
kind: conflict ? 'conflict' : 'error',
|
|
455
557
|
text: conflict ? t('conflict') : response.result.error.message,
|
|
456
558
|
})
|
|
457
|
-
if (conflict)
|
|
559
|
+
if (conflict) {
|
|
560
|
+
const { generation, signal } = beginGeneration()
|
|
561
|
+
void waitForNamespaceRevisionChange(describe, LLM_PI_AI_NS, draft.revision, signal).then((outcome) => {
|
|
562
|
+
if (outcome === 'aborted' || !generationIsCurrent(generationRef, generation)) return
|
|
563
|
+
return loadSnapshotThenSettle(generation, true)
|
|
564
|
+
}, (failure: unknown) => {
|
|
565
|
+
failGeneration(generation, failure)
|
|
566
|
+
})
|
|
567
|
+
}
|
|
458
568
|
return
|
|
459
569
|
}
|
|
460
570
|
const view = response.result.value
|
|
571
|
+
echoedRevisionRef.current = view.revision
|
|
461
572
|
describe.acceptView(view)
|
|
462
|
-
|
|
573
|
+
applyDrafts(applySaveSuccess(draftsRef.current, draft.provider, {
|
|
463
574
|
user: view.user ?? {},
|
|
464
575
|
revision: view.revision,
|
|
465
576
|
}))
|
|
@@ -470,7 +581,9 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
470
581
|
text: failure instanceof Error ? failure.message : t('loadError'),
|
|
471
582
|
})
|
|
472
583
|
} finally {
|
|
584
|
+
busyRouteRef.current = null
|
|
473
585
|
setBusyRoute(null)
|
|
586
|
+
flushPendingSettings(refreshAtRevision)
|
|
474
587
|
}
|
|
475
588
|
}
|
|
476
589
|
|
|
@@ -491,7 +604,7 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
491
604
|
{status === 'error' ? <p className={css.error}>{error}</p> : null}
|
|
492
605
|
{showReload
|
|
493
606
|
? (
|
|
494
|
-
<button type="button" className={css.secondaryButton} onClick={() => { reload(true) }}>{t('reload')}</button>
|
|
607
|
+
<button type="button" className={css.secondaryButton} onClick={() => { reload(true, snapshotMode()) }}>{t('reload')}</button>
|
|
495
608
|
)
|
|
496
609
|
: null}
|
|
497
610
|
{showEmpty
|
|
@@ -517,12 +630,12 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
517
630
|
t={t}
|
|
518
631
|
onChange={(next) => {
|
|
519
632
|
patchNotice(next.provider, undefined)
|
|
520
|
-
|
|
633
|
+
applyDrafts(current => current.map(row => row.provider === next.provider ? next : row))
|
|
521
634
|
}}
|
|
522
635
|
onSave={(next) => { void save(next) }}
|
|
523
636
|
onCancel={(next) => {
|
|
524
637
|
patchNotice(next.provider, undefined)
|
|
525
|
-
|
|
638
|
+
applyDrafts(current => current.map(row => row.provider === next.provider
|
|
526
639
|
? {
|
|
527
640
|
...row,
|
|
528
641
|
models: cloneModels(row.originalModels),
|
|
@@ -535,6 +648,7 @@ export function EffortDeclareSection(props: EffortDeclareSectionProps): ReactNod
|
|
|
535
648
|
</ul>
|
|
536
649
|
)
|
|
537
650
|
: null}
|
|
651
|
+
<p className={css.footer}>{PLUGIN_FOOTER_TEXT}</p>
|
|
538
652
|
</div>
|
|
539
653
|
)
|
|
540
654
|
}
|
package/src/client/README.en.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</samp>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
|
-
Browser half: registers **Reasoning efforts** in the Web UI settings panel and writes `llm-pi-ai` through the official settings RPC.
|
|
10
|
+
Browser half: registers **Reasoning efforts** in the Web UI settings panel and writes per-model `reasoningEfforts` and `input` on `llm-pi-ai` through the official settings RPC.
|
|
11
11
|
|
|
12
12
|
Wiring failures in `apply` throw, same as the official Models page. Do not swallow `apply` with a blanket `try/catch`. Locale, CSS, and event subscriptions are cleaned up through `ctx.effect` on unload.
|
|
13
13
|
|
|
@@ -17,10 +17,12 @@ Cross-plugin work uses Cordis services only (`connection`, `settingsScope`, `set
|
|
|
17
17
|
|
|
18
18
|
| File | Role |
|
|
19
19
|
| --- | --- |
|
|
20
|
-
| [`index.ts`](./index.ts) | Registers zh/en copy, CSS (`ctx.effect` insert/remove), and `settings.section` (id `effort-declare`, order 12). `describe.subscribe` only syncs `writable` (it fires for every namespace, including this page’s own `acceptView`).
|
|
21
|
-
| [`EffortDeclareSection.tsx`](./EffortDeclareSection.tsx) | Route cards, presets, Off tri-state, advanced protocol switches, save and cancel. Save is exclusive for the whole `llm-pi-ai` namespace; `busy` is “Saving…” on the in-flight card, `saveLocked` disables the others. A successful write folds `acceptView` + `applySaveSuccess`
|
|
22
|
-
| [`
|
|
23
|
-
| [`
|
|
20
|
+
| [`index.ts`](./index.ts) | Registers zh/en copy, CSS (`ctx.effect` insert/remove), and `settings.section` (id `effort-declare`, order 12). `describe.subscribe` only syncs `writable` (it fires for every namespace, including this page’s own `acceptView`). `settings/document-updated` (`llm-pi-ai` only) carries the Host revision; the section skips its own mutate echo, waits until the mirror revision has **caught up**, then `getSnapshot()` — it does not use `ensure()` as refresh. Provider directory changes come from `llm/adapters-updated`; `connection/reset` uses `ensure()` so an in-flight official `load()` is awaited. `locale: NS` lets the framework inject `t`; `inject` only returns `api` / `describe` / `schema` / `subscribeInvalidate`. |
|
|
21
|
+
| [`EffortDeclareSection.tsx`](./EffortDeclareSection.tsx) | Route cards, presets, Off tri-state, per-model **Accepts image input**, advanced protocol switches, save and cancel. Save is exclusive for the whole `llm-pi-ai` namespace (ref-guarded against double-click); `busy` is “Saving…” on the in-flight card, `saveLocked` disables the others. Save is blocked by `modelRowError` for empty efforts, Off-only, and illegal `input`. A successful write syncs `draftsRef` immediately and folds `acceptView` + `applySaveSuccess`. External `document-updated` events that arrive during save are replayed afterwards. A reload with no conflict clears that card’s conflict/error notice. Footer shows the version and copyright years frozen at pack time. |
|
|
22
|
+
| [`build-info.ts`](./build-info.ts) | Reads `package.json` version and UTC pack year injected by tsdown `define`, and formats the footer line. |
|
|
23
|
+
| [`globals.d.ts`](./globals.d.ts) | Types for `__PLUGIN_VERSION__` and `__COPYRIGHT_TO__`. |
|
|
24
|
+
| [`load-drafts.ts`](./load-drafts.ts) | Builds drafts from `llm.providers` + the settings mirror; drafts come from `user`, protocol classification may use `value`. `thinkingFormat` choices come only from the live schema union. First paint uses `ensure()`; refresh reads `getSnapshot()` only, with helpers that wait for the namespace revision. |
|
|
25
|
+
| [`locales.ts`](./locales.ts) | Copy namespace `plugin-effort-declare` (efforts, image input, and validation errors). |
|
|
24
26
|
| [`effort-declare.module.css`](./effort-declare.module.css) | `--dsw-alias-*` tokens only, so dark theme stays correct. |
|
|
25
27
|
| [`schema-ops.ts`](./schema-ops.ts) | Binds `settingsSchema` as plain callbacks (including `validate`) so the service identity is not passed into React. |
|
|
26
28
|
|