dsh-strata-sync 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -12
- package/dist/client.js +104 -26
- package/dist/index.js +28 -8
- package/dist/summary.mjs +37 -11
- package/docs/README.zh-CN.md +36 -12
- package/docs/README.zh-TW.md +36 -12
- package/docs/VALIDATION.md +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,28 +6,46 @@ A plugin that aligns **DeepSeek Harness (DSH)** with the model actually loaded b
|
|
|
6
6
|
|
|
7
7
|
Open **Settings → dsh-strata-sync** to inspect differences, synchronize an existing Strata provider, or enable automatic synchronization when DSH starts. The interface and README are available in English, Simplified Chinese and Traditional Chinese. The interface automatically follows DSH’s language, including live changes. DSH `zh` uses Simplified Chinese; `zh-Hant`, `zh-TW`, `zh-HK` and `zh-MO` use Traditional Chinese. Other languages fall back to English. There is no separate language preference. Unknown backend diagnostics retain their original text for troubleshooting.
|
|
8
8
|
|
|
9
|
-
Version 0.
|
|
9
|
+
Version 0.10.0 simplifies the summary settings and makes the supplemental prompt editable. Keep the default template or customize it with the dynamic `{target}` placeholder; DSH's native prompt and output cap remain unchanged.
|
|
10
10
|
|
|
11
11
|
## What it does
|
|
12
12
|
|
|
13
13
|
### Dynamic summary guidance
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The compact **Dynamic summary target** card contains the enable switch, context divisor and editable **Supplemental summary prompt**. Expand **Calculation and limits** for the summary-output and source-length divisors, formula and limitations. Guidance is enabled by default; turning it off preserves DSH's native summary and automatic compaction.
|
|
16
|
+
|
|
17
|
+
The editor shows the actual template appended to the native prompt. Its default is:
|
|
16
18
|
|
|
17
19
|
```text
|
|
18
|
-
|
|
19
|
-
target = floor(min(context / 16,
|
|
20
|
-
actual summary maxTokens / 2,
|
|
21
|
-
selected-content estimated tokens / 2))
|
|
20
|
+
Keep the entire checkpoint, including all required headings, within a target of {target} tokens by retaining only information essential to continue the remaining work, consolidating prior summaries, and removing redundant or obsolete details.
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
Keep the literal `{target}` placeholder in your template; each occurrence is replaced with the target calculated for that summary. Templates may contain up to 2,048 characters. Replacement is plain text, not executable code. **Restore default prompt** restores the original English template in the editor; click **Save preferences** to apply edits or the restored default. Changing the interface language does not translate or overwrite the saved template. This edits only the supplement, never DSH's original summary instructions.
|
|
24
|
+
|
|
25
|
+
| Plugin preference | Default | Meaning |
|
|
26
|
+
|---|---:|---|
|
|
27
|
+
| `summaryGuidance` | `true` | Append guidance to supported summary requests. |
|
|
28
|
+
| `summaryContextDivisor` | `16` | Divide the verified context by this value. |
|
|
29
|
+
| `summaryOutputDivisor` | `2` | Divide the actual summary output cap by this value. |
|
|
30
|
+
| `summarySourceDivisor` | `2` | Divide the estimated source length by this value. |
|
|
31
|
+
| `summaryPromptTemplate` | English template above | Supplement appended after substituting `{target}`. |
|
|
32
|
+
|
|
33
|
+
All three divisors accept finite numbers of at least 1, including decimals such as 1.5 or 2.5. A larger divisor makes its bound smaller. The final target is the smallest of the three bounds, rounded down; these controls do not change the actual output hard limit.
|
|
34
|
+
|
|
35
|
+
For each supported summary:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
context = min(verified Strata context, existing DSH model context)
|
|
39
|
+
target = floor(min(context / summaryContextDivisor,
|
|
40
|
+
actual summary maxTokens / summaryOutputDivisor,
|
|
41
|
+
selected-content estimated tokens / summarySourceDivisor))
|
|
42
|
+
```
|
|
25
43
|
|
|
26
|
-
|
|
44
|
+
The source estimate covers the conversation span being replaced, including prior checkpoints in that span, but excludes system prompts and tool schemas. Read-only metadata queries verify the loaded model and context; the current request supplies its actual output cap. With 32K context, a 4,096-token summary cap and enough content, context divisors 32, 16 and 8 produce targets of 1,024, 2,048 and 2,048 tokens. The UI preview is a ceiling, not the actual target of a future request.
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
Saving these controls changes only plugin preferences; it does not synchronize model budgets or change Strata Server settings. DSH's native prompt, eight-section format and request options remain intact. The default supplement is one sentence; a custom template is appended as entered. The target is a writing instruction, **not a new hard output limit or a guarantee against truncation**. No retry loop or extra inference request is added.
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
Unverified routes/metadata, unknown native prompts, unpriced attachments, invalid templates, cancellation, disabled guidance and targets below 256 tokens leave the native request unchanged. Removing the plugin stops the supplement without rewriting saved conversation history.
|
|
31
49
|
|
|
32
50
|
### Automatic model capabilities (0.4.0)
|
|
33
51
|
|
|
@@ -77,7 +95,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
77
95
|
|
|
78
96
|
Reopen DSH after installation. The bundle is automatically selected on its first installation; an already installed but disabled bundle must be enabled in DSH's plugin manager.
|
|
79
97
|
|
|
80
|
-
To install **0.
|
|
98
|
+
To install **0.10.0 with the editable summary prompt** from source, use Node.js 22 or newer, finish active tasks and fully quit DSH Desktop before the final installation command:
|
|
81
99
|
|
|
82
100
|
```sh
|
|
83
101
|
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
@@ -85,7 +103,7 @@ cd dsh-strata-sync
|
|
|
85
103
|
npm ci
|
|
86
104
|
npm test
|
|
87
105
|
npm pack
|
|
88
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.
|
|
106
|
+
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.0.tgz
|
|
89
107
|
```
|
|
90
108
|
|
|
91
109
|
Use an absolute tarball path if running the last command elsewhere. DSH's plugin installer selects the included bundle; it can require a desktop reload to mount the new browser entry. Finish any active task before restarting DSH.
|
|
@@ -98,8 +116,22 @@ Then open **Settings → dsh-strata-sync**:
|
|
|
98
116
|
4. Optionally enable **Automatically sync when DSH starts** and save. It defaults to off and takes effect on the next start. Existing `autoSync: true` preferences now use startup behavior.
|
|
99
117
|
5. Start a new conversation to use the new Agent preset revision.
|
|
100
118
|
|
|
119
|
+
The **Dynamic summary target** card is independent of model synchronization. Leave guidance enabled, keep the default template, and use divisors 16 / 2 / 2 to retain the previous behavior, or change these preferences and save. Turning this switch off does not disable DSH's own compaction.
|
|
120
|
+
|
|
101
121
|
No API key needs to be copied into this plugin. Set up or repair credentials in DSH Models settings.
|
|
102
122
|
|
|
123
|
+
## Changes in 0.10.0
|
|
124
|
+
|
|
125
|
+
- Makes the actual supplemental prompt editable, with a dynamic `{target}` placeholder and Restore default prompt action.
|
|
126
|
+
- Simplifies the summary card and moves detailed formula explanations into expandable help in all three languages. Adds advanced output/source divisors and decimal support for all three divisors.
|
|
127
|
+
- Validates and saves prompt edits through existing backup and revision safeguards without changing native instructions or other budgets.
|
|
128
|
+
|
|
129
|
+
## Changes in 0.9.0
|
|
130
|
+
|
|
131
|
+
- Adds a default-on switch for the supplemental summary guidance and an adjustable context divisor, defaulting to 16.
|
|
132
|
+
- Saves both controls through the existing preferences and revision checks, with matching English, Simplified Chinese and Traditional Chinese UI and documentation.
|
|
133
|
+
- Keeps native summary instructions, hard output limits, other budgets and server settings unchanged when saving these controls.
|
|
134
|
+
|
|
103
135
|
## Changes in 0.5.0
|
|
104
136
|
|
|
105
137
|
- Follows DSH’s native locale service; removes the independent language selector and product disclaimer.
|
package/dist/client.js
CHANGED
|
@@ -87,17 +87,77 @@ window.__ModuleLoader__.load({
|
|
|
87
87
|
"zh-Hant": "動態摘要目標",
|
|
88
88
|
"zh-Hans": "动态摘要目标"
|
|
89
89
|
},
|
|
90
|
+
"Supplemental summary prompt": {
|
|
91
|
+
"zh-Hant": "摘要補充提示詞",
|
|
92
|
+
"zh-Hans": "摘要补充提示词"
|
|
93
|
+
},
|
|
94
|
+
"Restore default prompt": {
|
|
95
|
+
"zh-Hant": "還原預設提示詞",
|
|
96
|
+
"zh-Hans": "恢复默认提示词"
|
|
97
|
+
},
|
|
98
|
+
"Appended to DSH's native prompt; {target} becomes the calculated token target. Save preferences to apply.": {
|
|
99
|
+
"zh-Hant": "附加於 DSH 原生提示詞;{target} 會替換為計算出的 token 目標。儲存偏好後套用。",
|
|
100
|
+
"zh-Hans": "附加于 DSH 原生提示词;{target} 会替换为计算出的 token 目标。保存偏好后应用。"
|
|
101
|
+
},
|
|
102
|
+
"Use 1–2,048 characters and include {target}.": {
|
|
103
|
+
"zh-Hant": "請輸入 1–2,048 個字元,並包含 {target}。",
|
|
104
|
+
"zh-Hans": "请输入 1–2,048 个字符,并包含 {target}。"
|
|
105
|
+
},
|
|
106
|
+
"Calculation and limits": {
|
|
107
|
+
"zh-Hant": "計算方式與限制",
|
|
108
|
+
"zh-Hans": "计算方式与限制"
|
|
109
|
+
},
|
|
90
110
|
"How the target is calculated": {
|
|
91
111
|
"zh-Hant": "目標如何計算",
|
|
92
112
|
"zh-Hans": "目标如何计算"
|
|
93
113
|
},
|
|
94
|
-
"
|
|
95
|
-
"zh-Hant": "
|
|
96
|
-
"zh-Hans": "
|
|
114
|
+
"When enabled, before each supported Strata summary, calculates a length target and appends one sentence to DSH's native summary prompt.": {
|
|
115
|
+
"zh-Hant": "啟用後,在每次支援的 Strata 摘要請求前,計算長度目標,並在 DSH 原生摘要提示詞後補充一句。",
|
|
116
|
+
"zh-Hans": "启用后,在每次支持的 Strata 摘要请求前,计算长度目标,并在 DSH 原生摘要提示词后补充一句。"
|
|
117
|
+
},
|
|
118
|
+
"Target = floor(min(context / N, summary output limit / O, selected content estimate / S)).": {
|
|
119
|
+
"zh-Hant": "目標 = floor(min(上下文 / N, 摘要輸出上限 / O, 待壓縮內容估算 / S))。",
|
|
120
|
+
"zh-Hans": "目标 = floor(min(上下文 / N, 摘要输出上限 / O, 待压缩内容估算 / S))。"
|
|
121
|
+
},
|
|
122
|
+
"Enable summary guidance": {
|
|
123
|
+
"zh-Hant": "啟用摘要提示補充",
|
|
124
|
+
"zh-Hans": "启用摘要提示补充"
|
|
125
|
+
},
|
|
126
|
+
"Enabled by default. Turning this off keeps DSH's native summary and automatic compaction behavior.": {
|
|
127
|
+
"zh-Hant": "預設開啟。關閉後保留 DSH 原生摘要與自動壓縮行為。",
|
|
128
|
+
"zh-Hans": "默认开启。关闭后保留 DSH 原生摘要与自动压缩行为。"
|
|
97
129
|
},
|
|
98
|
-
"
|
|
99
|
-
"zh-Hant": "
|
|
100
|
-
"zh-Hans": "
|
|
130
|
+
"Context divisor (context ÷ N)": {
|
|
131
|
+
"zh-Hant": "上下文除數(上下文 ÷ N)",
|
|
132
|
+
"zh-Hans": "上下文除数(上下文 ÷ N)"
|
|
133
|
+
},
|
|
134
|
+
"Summary output divisor (output limit ÷ O)": {
|
|
135
|
+
"zh-Hant": "摘要輸出除數(輸出上限 ÷ O)",
|
|
136
|
+
"zh-Hans": "摘要输出除数(输出上限 ÷ O)"
|
|
137
|
+
},
|
|
138
|
+
"Source length divisor (source estimate ÷ S)": {
|
|
139
|
+
"zh-Hant": "原文長度除數(原文估算 ÷ S)",
|
|
140
|
+
"zh-Hans": "原文长度除数(原文估算 ÷ S)"
|
|
141
|
+
},
|
|
142
|
+
"Defaults: N = 16, O = 2, S = 2. Smaller divisors allow longer targets; the smallest of the three bounds wins. Decimals are supported.": {
|
|
143
|
+
"zh-Hant": "預設 N = 16、O = 2、S = 2。除數越小,目標可越長;最後取三項限制的最小值。支援小數。",
|
|
144
|
+
"zh-Hans": "默认 N = 16、O = 2、S = 2。除数越小,目标可越长;最后取三项限制的最小值。支持小数。"
|
|
145
|
+
},
|
|
146
|
+
"Enter a finite divisor of at least 1; decimals are allowed.": {
|
|
147
|
+
"zh-Hant": "請輸入大於或等於 1 的有限除數,可使用小數。",
|
|
148
|
+
"zh-Hans": "请输入大于或等于 1 的有限除数,可使用小数。"
|
|
149
|
+
},
|
|
150
|
+
"This preview is below the 256-token minimum. The native summary prompt remains unchanged.": {
|
|
151
|
+
"zh-Hant": "本次預覽低於 256 tokens 的最低目標,將保留原生摘要提示詞。",
|
|
152
|
+
"zh-Hans": "本次预览低于 256 tokens 的最低目标,将保留原生摘要提示词。"
|
|
153
|
+
},
|
|
154
|
+
"Summary guidance is off. No extra sentence is added to the native prompt.": {
|
|
155
|
+
"zh-Hant": "摘要提示補充已關閉,不會在原生提示詞中加上額外句子。",
|
|
156
|
+
"zh-Hans": "摘要提示补充已关闭,不会在原生提示词中添加额外句子。"
|
|
157
|
+
},
|
|
158
|
+
"Save preferences to apply these controls to subsequent summary requests; other model and compaction settings stay unchanged.": {
|
|
159
|
+
"zh-Hant": "儲存偏好後,這些控制項會套用至後續摘要請求;其他模型與壓縮設定保持不變。",
|
|
160
|
+
"zh-Hans": "保存偏好后,这些控制项将应用于后续摘要请求;其他模型与压缩设置保持不变。"
|
|
101
161
|
},
|
|
102
162
|
"Context uses the smaller of the verified Strata window and the existing DSH model window. The preview ceiling assumes the proposed budgets; existing conversation settings can make the actual target lower.": {
|
|
103
163
|
"zh-Hant": "上下文採用已確認的 Strata 視窗與 DSH 既有模型視窗的較小值。預覽上限依提議預算計算,既有對話設定可能讓實際目標更低。",
|
|
@@ -339,7 +399,7 @@ window.__ModuleLoader__.load({
|
|
|
339
399
|
model: 'Model', modelId: 'Model', defaultModel: 'Default model',
|
|
340
400
|
thresholdRatio: 'Compaction ratio ceiling', retainRatio: 'Recent conversation retention ratio',
|
|
341
401
|
};
|
|
342
|
-
const css = `.strata-sync{max-width:880px;color:inherit;font:inherit;line-height:1.6}.strata-sync *{box-sizing:border-box}.strata-sync header{border-bottom:1px solid #8884;padding-bottom:16px;margin-bottom:20px}.strata-sync h2{margin:0;font-size:22px}.strata-sync .ss-muted{opacity:.72;font-size:13px}.strata-sync .ss-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}.strata-sync label{display:flex;flex-direction:column;gap:5px;font-size:14px}.strata-sync select,.strata-sync input[type=number]{padding:9px;border:1px solid #8886;border-radius:7px;background:transparent;color:inherit;width:100%}.strata-sync option{color:#17252b;background:#fff}.strata-sync button{padding:9px 15px;border:1px solid #8885;border-radius:7px;background:transparent;color:inherit;cursor:pointer}.strata-sync button.primary{background:#126c65;border-color:#126c65;color:#fff}.strata-sync button:disabled{opacity:.45;cursor:default}.strata-sync .ss-actions{display:flex;gap:9px;flex-wrap:wrap;margin:18px 0}.strata-sync .ss-check{display:flex;flex-direction:row;align-items:center;margin-top:13px}.strata-sync .ss-card{padding:16px;border:1px solid #8884;border-radius:9px;margin:16px 0}.strata-sync .ss-status{padding:10px 13px;border-left:3px solid #21867b;background:#21867b12;margin:13px 0;overflow-wrap:anywhere}.strata-sync .ss-error{border-color:#ce7140;background:#ce714012}.strata-sync table{width:100%;border-collapse:collapse;font-size:14px}.strata-sync td,.strata-sync th{padding:9px 8px;text-align:left;border-bottom:1px solid #8883;overflow-wrap:anywhere}.strata-sync code{font-size:12px;overflow-wrap:anywhere}.strata-sync .ss-scroll{overflow-x:auto;container-type:inline-size;border:1px solid #8883;border-radius:8px;margin-top:16px}.strata-sync table{table-layout:fixed}.strata-sync th,.strata-sync td{vertical-align:top;padding:12px;line-height:1.5}.strata-sync thead th{font-size:12px;font-weight:600;background:#8881}.strata-sync th:first-child{width:34%}.strata-sync thead th:not(:first-child){width:33%;text-align:right}.strata-sync tbody th{font-weight:500}.strata-sync tbody tr:last-child>*{border-bottom:0}.strata-sync .ss-before,.strata-sync .ss-after{text-align:right;font-variant-numeric:tabular-nums}.strata-sync .ss-before{color:inherit;opacity:.7}.strata-sync .ss-after{background:#21867b0b;font-weight:600}.strata-sync .ss-target{display:block;font-size:11px;font-weight:400;opacity:.65;margin-top:5px;overflow-wrap:anywhere}.strata-sync .ss-values{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}.strata-sync .ss-chip{display:inline-block;padding:2px 7px;border:1px solid #8883;border-radius:5px;font-size:12px;font-weight:400;max-width:100%;overflow-wrap:anywhere}.strata-sync .ss-details{text-align:left;font-weight:400;font-size:12px}.strata-sync .ss-details summary{cursor:pointer;overflow-wrap:anywhere}.strata-sync .ss-details pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:8px 0 0;font-size:11px;line-height:1.5}.strata-sync .ss-empty{font-weight:400;font-size:12px;opacity:.65}@container(max-width:440px){.strata-sync tbody th:first-child{width:100%}.strata-sync table,.strata-sync tbody,.strata-sync tr,.strata-sync tbody th,.strata-sync td{display:block;width:100%}.strata-sync thead{display:none}.strata-sync tbody tr{padding:10px 12px;border-bottom:1px solid #8883}.strata-sync tbody th,.strata-sync td{border:0;padding:5px 0}.strata-sync td::before{content:attr(data-label);float:left;font-size:12px;font-weight:400;opacity:.7}.strata-sync td{display:flow-root;padding:7px}.strata-sync .ss-values{max-width:72%;margin-left:auto}.strata-sync .ss-details{margin-top:24px}}`;
|
|
402
|
+
const css = `.strata-sync{max-width:880px;color:inherit;font:inherit;line-height:1.6}.strata-sync *{box-sizing:border-box}.strata-sync header{border-bottom:1px solid #8884;padding-bottom:16px;margin-bottom:20px}.strata-sync h2{margin:0;font-size:22px}.strata-sync .ss-muted{opacity:.72;font-size:13px}.strata-sync .ss-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}.strata-sync label{display:flex;flex-direction:column;gap:5px;font-size:14px}.strata-sync select,.strata-sync input[type=number],.strata-sync textarea{padding:9px;border:1px solid #8886;border-radius:7px;background:transparent;color:inherit;width:100%}.strata-sync textarea{resize:vertical;min-height:112px;font:inherit;line-height:1.5}.strata-sync .ss-prompt-label{margin:12px 0 8px}.strata-sync option{color:#17252b;background:#fff}.strata-sync button{padding:9px 15px;border:1px solid #8885;border-radius:7px;background:transparent;color:inherit;cursor:pointer}.strata-sync button.primary{background:#126c65;border-color:#126c65;color:#fff}.strata-sync button:disabled{opacity:.45;cursor:default}.strata-sync .ss-actions{display:flex;gap:9px;flex-wrap:wrap;margin:18px 0}.strata-sync .ss-check{display:flex;flex-direction:row;align-items:center;margin-top:13px}.strata-sync .ss-card{padding:16px;border:1px solid #8884;border-radius:9px;margin:16px 0}.strata-sync .ss-status{padding:10px 13px;border-left:3px solid #21867b;background:#21867b12;margin:13px 0;overflow-wrap:anywhere}.strata-sync .ss-error{border-color:#ce7140;background:#ce714012}.strata-sync table{width:100%;border-collapse:collapse;font-size:14px}.strata-sync td,.strata-sync th{padding:9px 8px;text-align:left;border-bottom:1px solid #8883;overflow-wrap:anywhere}.strata-sync code{font-size:12px;overflow-wrap:anywhere}.strata-sync .ss-scroll{overflow-x:auto;container-type:inline-size;border:1px solid #8883;border-radius:8px;margin-top:16px}.strata-sync table{table-layout:fixed}.strata-sync th,.strata-sync td{vertical-align:top;padding:12px;line-height:1.5}.strata-sync thead th{font-size:12px;font-weight:600;background:#8881}.strata-sync th:first-child{width:34%}.strata-sync thead th:not(:first-child){width:33%;text-align:right}.strata-sync tbody th{font-weight:500}.strata-sync tbody tr:last-child>*{border-bottom:0}.strata-sync .ss-before,.strata-sync .ss-after{text-align:right;font-variant-numeric:tabular-nums}.strata-sync .ss-before{color:inherit;opacity:.7}.strata-sync .ss-after{background:#21867b0b;font-weight:600}.strata-sync .ss-target{display:block;font-size:11px;font-weight:400;opacity:.65;margin-top:5px;overflow-wrap:anywhere}.strata-sync .ss-values{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}.strata-sync .ss-chip{display:inline-block;padding:2px 7px;border:1px solid #8883;border-radius:5px;font-size:12px;font-weight:400;max-width:100%;overflow-wrap:anywhere}.strata-sync .ss-details{text-align:left;font-weight:400;font-size:12px}.strata-sync .ss-details summary{cursor:pointer;overflow-wrap:anywhere}.strata-sync .ss-details pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:8px 0 0;font-size:11px;line-height:1.5}.strata-sync .ss-empty{font-weight:400;font-size:12px;opacity:.65}@container(max-width:440px){.strata-sync tbody th:first-child{width:100%}.strata-sync table,.strata-sync tbody,.strata-sync tr,.strata-sync tbody th,.strata-sync td{display:block;width:100%}.strata-sync thead{display:none}.strata-sync tbody tr{padding:10px 12px;border-bottom:1px solid #8883}.strata-sync tbody th,.strata-sync td{border:0;padding:5px 0}.strata-sync td::before{content:attr(data-label);float:left;font-size:12px;font-weight:400;opacity:.7}.strata-sync td{display:flow-root;padding:7px}.strata-sync .ss-values{max-width:72%;margin-left:auto}.strata-sync .ss-details{margin-top:24px}}`;
|
|
343
403
|
const fmt = (v) => v == null ? 'Not set' : typeof v === 'number' ? v.toLocaleString('en-US') : typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
344
404
|
const warningText = {
|
|
345
405
|
INPUT_UNCONFIRMED: 'Input types are missing or unsupported in server metadata. Existing input settings are preserved.',
|
|
@@ -367,19 +427,20 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
367
427
|
};
|
|
368
428
|
const diagnostic = (message) => translations[message] ? t(message) : language === 'en' ? message : t('Server diagnostic: ') + message;
|
|
369
429
|
const [state,setState] = React.useState(null), [preview,setPreview] = React.useState(null), [result,setResult] = React.useState(null);
|
|
370
|
-
const [form,setForm] = React.useState({providerId:'',output:'',manual:false,auto:false,follow:true});
|
|
430
|
+
const [form,setForm] = React.useState({providerId:'',output:'',manual:false,auto:false,follow:true,summaryGuidance:true,summaryDivisor:'16',summaryOutputDivisor:'2',summarySourceDivisor:'2',summaryPrompt:''});
|
|
371
431
|
const [pending,setPending] = React.useState(false), [error,setError] = React.useState(''), [loadError,setLoadError] = React.useState('');
|
|
372
432
|
const [notice,setNotice] = React.useState(''), [conflict,setConflict] = React.useState(false);
|
|
373
433
|
const formRef=React.useRef(form), baseline=React.useRef(null), requestSeq=React.useRef(0), alive=React.useRef(true);
|
|
374
|
-
const
|
|
375
|
-
const
|
|
434
|
+
const numberValue = value => value.trim()===''?NaN:Number(value);
|
|
435
|
+
const values = (f) => ({providerId:f.providerId,outputTokens:f.manual ? (f.output.trim()==='' ? NaN : Number(f.output)) : null,autoSync:f.auto,followLoadedModel:f.follow,summaryGuidance:f.summaryGuidance,summaryContextDivisor:numberValue(f.summaryDivisor),summaryOutputDivisor:numberValue(f.summaryOutputDivisor),summarySourceDivisor:numberValue(f.summarySourceDivisor),summaryPromptTemplate:f.summaryPrompt});
|
|
436
|
+
const preferences = (s) => ({providerId:s.providerId || '',outputTokens:s.outputTokens ?? null,autoSync:!!s.autoSync,followLoadedModel:s.followLoadedModel !== false,summaryGuidance:s.summaryGuidance!==false,summaryContextDivisor:s.summaryContextDivisor??16,summaryOutputDivisor:s.summaryOutputDivisor??2,summarySourceDivisor:s.summarySourceDivisor??2,summaryPromptTemplate:s.summaryPromptTemplate??s.defaultSummaryPromptTemplate??''});
|
|
376
437
|
const equal = (a,b) => Object.keys(a).every(key=>Object.is(a[key],b[key]));
|
|
377
438
|
const acceptStatus = React.useCallback((s,force=false) => {
|
|
378
439
|
if (!alive.current) return;
|
|
379
440
|
const next=preferences(s), old=baseline.current;
|
|
380
441
|
const untouched=!old || equal(values(formRef.current),old.values);
|
|
381
442
|
if (force || untouched) {
|
|
382
|
-
const nextForm={providerId:next.providerId,output:next.outputTokens==null?'':String(next.outputTokens),manual:next.outputTokens!=null,auto:next.autoSync,follow:next.followLoadedModel};
|
|
443
|
+
const nextForm={providerId:next.providerId,output:next.outputTokens==null?'':String(next.outputTokens),manual:next.outputTokens!=null,auto:next.autoSync,follow:next.followLoadedModel,summaryGuidance:next.summaryGuidance,summaryDivisor:String(next.summaryContextDivisor),summaryOutputDivisor:String(next.summaryOutputDivisor),summarySourceDivisor:String(next.summarySourceDivisor),summaryPrompt:next.summaryPromptTemplate};
|
|
383
444
|
formRef.current=nextForm; setForm(nextForm); setConflict(false);
|
|
384
445
|
baseline.current={values:next,revision:s.settingsRevision};
|
|
385
446
|
} else if (old.revision!==s.settingsRevision || !equal(old.values,next)) {
|
|
@@ -411,12 +472,15 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
411
472
|
else setError(e.code==='unsupported-route'?'This provider uses an unsupported model catalog configuration. Configure an explicit custom model list in DSH before syncing.':e.message||'The operation failed.');
|
|
412
473
|
} finally { if(alive.current)setPending(false); }
|
|
413
474
|
}
|
|
414
|
-
const draft=values(form),
|
|
475
|
+
const draft=values(form), isDivisor=value=>Number.isFinite(value)&&value>=1&&value<=Number.MAX_SAFE_INTEGER;
|
|
476
|
+
const validDivisor=[draft.summaryContextDivisor,draft.summaryOutputDivisor,draft.summarySourceDivisor].every(isDivisor);
|
|
477
|
+
const validPrompt=typeof draft.summaryPromptTemplate==='string'&&draft.summaryPromptTemplate.length>0&&draft.summaryPromptTemplate.length<=2048&&draft.summaryPromptTemplate.includes('{target}');
|
|
478
|
+
const valid=validDivisor&&validPrompt&&(draft.outputTokens===null || Number.isSafeInteger(draft.outputTokens)&&draft.outputTokens>0);
|
|
415
479
|
const dirty=!!baseline.current&&!equal(draft,baseline.current.values);
|
|
416
480
|
const displayedResult=!result || state?.lastApplied?.at>result.at ? state?.lastApplied : result;
|
|
417
481
|
const activeBudget=preview?.budget;
|
|
418
|
-
const summaryTargetCeiling=Number.isSafeInteger(activeBudget?.contextWindow)&&activeBudget.contextWindow>0&&Number.isSafeInteger(activeBudget?.summaryMaxTokens)&&activeBudget.summaryMaxTokens>0
|
|
419
|
-
? Math.floor(Math.min(activeBudget.contextWindow/
|
|
482
|
+
const summaryTargetCeiling=form.summaryGuidance&&validDivisor&&Number.isSafeInteger(activeBudget?.contextWindow)&&activeBudget.contextWindow>0&&Number.isSafeInteger(activeBudget?.summaryMaxTokens)&&activeBudget.summaryMaxTokens>0
|
|
483
|
+
? Math.floor(Math.min(activeBudget.contextWindow/draft.summaryContextDivisor,activeBudget.summaryMaxTokens/draft.summaryOutputDivisor)) : null;
|
|
420
484
|
const outputSource=(budget)=>t(({server:'Strata Server default',manual:'Manual override',calculated:'Automatic calculation'})[budget?.outputSource]||'Automatic calculation');
|
|
421
485
|
const preserved=(view)=>{
|
|
422
486
|
const status=view?.capabilityStatus;
|
|
@@ -458,6 +522,32 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
458
522
|
h('label',{className:'ss-check'},h('input',{type:'checkbox',checked:form.follow,onChange:e=>edit({follow:e.target.checked}),disabled:pending||!state}),t('Follow the loaded Strata model as the default')),
|
|
459
523
|
h('label',{className:'ss-check'},h('input',{type:'checkbox',checked:form.auto,onChange:e=>edit({auto:e.target.checked}),disabled:pending||!state}),t('Automatically sync when DSH starts')),
|
|
460
524
|
h('p',{className:'ss-muted'},t('Runs once on the next DSH start. Waits for running tasks to finish; no periodic server checks.')),
|
|
525
|
+
h('div',{className:'ss-card','data-testid':'summary-target'},
|
|
526
|
+
h('strong',null,t('Dynamic summary target')),
|
|
527
|
+
h('label',{className:'ss-check'},h('input',{type:'checkbox','data-testid':'summary-guidance-toggle','aria-label':t('Enable summary guidance'),checked:form.summaryGuidance,onChange:e=>edit({summaryGuidance:e.target.checked}),disabled:pending||!state}),t('Enable summary guidance')),
|
|
528
|
+
h('label',null,t('Context divisor (context ÷ N)'),h('input',{type:'number','data-testid':'summary-divisor','aria-label':t('Context divisor (context ÷ N)'),'aria-invalid':!isDivisor(draft.summaryContextDivisor),min:1,max:Number.MAX_SAFE_INTEGER,step:'any',value:form.summaryDivisor,onChange:e=>edit({summaryDivisor:e.target.value}),disabled:pending||!state})),
|
|
529
|
+
state&&!validDivisor&&h('p',{className:'ss-status ss-error',role:'alert'},t('Enter a finite divisor of at least 1; decimals are allowed.')),
|
|
530
|
+
h('label',{className:'ss-prompt-label'},t('Supplemental summary prompt'),h('textarea',{'data-testid':'summary-prompt','aria-label':t('Supplemental summary prompt'),'aria-invalid':!validPrompt,rows:5,value:form.summaryPrompt,onChange:e=>edit({summaryPrompt:e.target.value}),disabled:pending||!state,spellCheck:false})),
|
|
531
|
+
state&&!validPrompt&&h('p',{className:'ss-status ss-error',role:'alert'},t('Use 1–2,048 characters and include {target}.')),
|
|
532
|
+
h('button',{type:'button','data-testid':'summary-prompt-reset',disabled:pending||!state?.defaultSummaryPromptTemplate||form.summaryPrompt===state.defaultSummaryPromptTemplate,onClick:()=>edit({summaryPrompt:state.defaultSummaryPromptTemplate})},t('Restore default prompt')),
|
|
533
|
+
h('p',{className:'ss-muted'},t("Appended to DSH's native prompt; {target} becomes the calculated token target. Save preferences to apply.")),
|
|
534
|
+
!form.summaryGuidance&&h('p',{className:'ss-status','data-testid':'summary-guidance-off'},t('Summary guidance is off. No extra sentence is added to the native prompt.')),
|
|
535
|
+
summaryTargetCeiling!==null&&(summaryTargetCeiling>=256
|
|
536
|
+
? h('p',{'data-testid':'summary-target-ceiling'},t('Maximum target for this preview: '),format(summaryTargetCeiling),' tokens')
|
|
537
|
+
: h('p',{className:'ss-status','data-testid':'summary-target-native'},t('This preview is below the 256-token minimum. The native summary prompt remains unchanged.'))),
|
|
538
|
+
h('details',{className:'ss-details','data-testid':'summary-details'},h('summary',null,t('Calculation and limits')),
|
|
539
|
+
h('div',{className:'ss-grid'},
|
|
540
|
+
h('label',null,t('Summary output divisor (output limit ÷ O)'),h('input',{type:'number','data-testid':'summary-output-divisor','aria-label':t('Summary output divisor (output limit ÷ O)'),'aria-invalid':!isDivisor(draft.summaryOutputDivisor),min:1,max:Number.MAX_SAFE_INTEGER,step:'any',value:form.summaryOutputDivisor,onChange:e=>edit({summaryOutputDivisor:e.target.value}),disabled:pending||!state})),
|
|
541
|
+
h('label',null,t('Source length divisor (source estimate ÷ S)'),h('input',{type:'number','data-testid':'summary-source-divisor','aria-label':t('Source length divisor (source estimate ÷ S)'),'aria-invalid':!isDivisor(draft.summarySourceDivisor),min:1,max:Number.MAX_SAFE_INTEGER,step:'any',value:form.summarySourceDivisor,onChange:e=>edit({summarySourceDivisor:e.target.value}),disabled:pending||!state}))),
|
|
542
|
+
h('p',{className:'ss-muted'},t("Enabled by default. Turning this off keeps DSH's native summary and automatic compaction behavior.")),
|
|
543
|
+
h('p',{className:'ss-muted'},t('Defaults: N = 16, O = 2, S = 2. Smaller divisors allow longer targets; the smallest of the three bounds wins. Decimals are supported.')),
|
|
544
|
+
h('p',{className:'ss-muted'},t('Target = floor(min(context / N, summary output limit / O, selected content estimate / S)).')),
|
|
545
|
+
h('p',{className:'ss-muted'},t('Context uses the smaller of the verified Strata window and the existing DSH model window. The preview ceiling assumes the proposed budgets; existing conversation settings can make the actual target lower.')),
|
|
546
|
+
h('p',{className:'ss-muted'},t('The actual target may be lower for shorter content. System prompts and tool schemas are excluded from the content estimate.')),
|
|
547
|
+
h('p',{className:'ss-muted'},t('The original prompt, output cap and other settings stay unchanged. This is a writing target, not a guaranteed length or an optimal value.')),
|
|
548
|
+
h('p',{className:'ss-muted'},t('Targets below 256 tokens leave the original prompt unchanged; the native summary still runs.')),
|
|
549
|
+
h('p',{className:'ss-muted'},t('If the route or native summary format cannot be verified, DSH uses its original prompt.')),
|
|
550
|
+
h('p',{className:'ss-muted'},t('Unpriced image/file attachments, cancellation or a disabled plugin preserve native request handling.')))),
|
|
461
551
|
h('div',{className:'ss-actions'},
|
|
462
552
|
h('button',{disabled:pending||!state||!form.providerId||!valid||!dirty||conflict,onClick:()=>action(async()=>{
|
|
463
553
|
const changes=Object.fromEntries(Object.entries(values(formRef.current)).filter(([key,value])=>!Object.is(value,baseline.current.values[key])));
|
|
@@ -472,18 +562,6 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
472
562
|
setPreview(null);setNotice(r.applied?'Synced and backed up the original settings. Start a new conversation to use the updated compaction policy.':'Settings already match. No changes needed.');await refresh();
|
|
473
563
|
})},t('Back up and sync'))),
|
|
474
564
|
dirty&&!conflict&&h('p',{className:'ss-muted'},t('Save preferences before checking for differences.')),
|
|
475
|
-
h('div',{className:'ss-card','data-testid':'summary-target'},
|
|
476
|
-
h('strong',null,t('Dynamic summary target')),
|
|
477
|
-
h('p',null,t("Before each supported Strata summary, calculates a length target and appends one sentence to DSH's native summary prompt.")),
|
|
478
|
-
summaryTargetCeiling!==null&&h('p',{'data-testid':'summary-target-ceiling'},t('Maximum target for this preview: '),format(summaryTargetCeiling),' tokens'),
|
|
479
|
-
h('details',{className:'ss-details'},h('summary',null,t('How the target is calculated')),
|
|
480
|
-
h('p',{className:'ss-muted'},t('Target = floor(min(context / 16, summary output limit / 2, selected content estimate / 2)).')),
|
|
481
|
-
h('p',{className:'ss-muted'},t('Context uses the smaller of the verified Strata window and the existing DSH model window. The preview ceiling assumes the proposed budgets; existing conversation settings can make the actual target lower.')),
|
|
482
|
-
h('p',{className:'ss-muted'},t('The actual target may be lower for shorter content. System prompts and tool schemas are excluded from the content estimate.')),
|
|
483
|
-
h('p',{className:'ss-muted'},t('The original prompt, output cap and other settings stay unchanged. This is a writing target, not a guaranteed length or an optimal value.')),
|
|
484
|
-
h('p',{className:'ss-muted'},t('Targets below 256 tokens leave the original prompt unchanged; the native summary still runs.')),
|
|
485
|
-
h('p',{className:'ss-muted'},t('If the route or native summary format cannot be verified, DSH uses its original prompt.')),
|
|
486
|
-
h('p',{className:'ss-muted'},t('Unpriced image/file attachments, cancellation or a disabled plugin preserve native request handling.')))),
|
|
487
565
|
preview&&h('div',{className:'ss-card'},
|
|
488
566
|
h('strong',null,'Strata Server'),h('p',null,h('code',null,preview.server?.model?.id)),
|
|
489
567
|
h('div',{className:'ss-grid'},
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import z from '@deepseek-ai/schemastery';
|
|
5
5
|
import { discoverStrata, planBudget, StrataSyncError } from './core.mjs';
|
|
6
|
-
import { installSummaryGuidance } from './summary.mjs';
|
|
6
|
+
import { DEFAULT_SUMMARY_DIVISOR, DEFAULT_SUMMARY_TEMPLATE, validSummaryDivisor, validSummaryTemplate, installSummaryGuidance } from './summary.mjs';
|
|
7
7
|
|
|
8
8
|
export const inject = ['configEditor', 'connection', 'agents', 'credentials', 'agentPresets'];
|
|
9
9
|
export const Config = z.object({
|
|
@@ -11,6 +11,11 @@ export const Config = z.object({
|
|
|
11
11
|
autoSync: z.boolean().default(false),
|
|
12
12
|
followLoadedModel: z.boolean().default(true),
|
|
13
13
|
outputTokens: z.number().step(1).min(1),
|
|
14
|
+
summaryGuidance: z.boolean().default(true),
|
|
15
|
+
summaryContextDivisor: z.number().min(1).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_SUMMARY_DIVISOR),
|
|
16
|
+
summaryOutputDivisor: z.number().min(1).max(Number.MAX_SAFE_INTEGER).default(2),
|
|
17
|
+
summarySourceDivisor: z.number().min(1).max(Number.MAX_SAFE_INTEGER).default(2),
|
|
18
|
+
summaryPromptTemplate: z.string().default(DEFAULT_SUMMARY_TEMPLATE),
|
|
14
19
|
});
|
|
15
20
|
|
|
16
21
|
const PACKAGE = 'dsh-strata-sync';
|
|
@@ -139,7 +144,10 @@ export function apply(ctx, initialConfig) {
|
|
|
139
144
|
}
|
|
140
145
|
function publicSettings(value = settings) {
|
|
141
146
|
return { providerId: value.providerId ?? '', autoSync: value.autoSync ?? false,
|
|
142
|
-
followLoadedModel: value.followLoadedModel ?? true, outputTokens: value.outputTokens ?? null
|
|
147
|
+
followLoadedModel: value.followLoadedModel ?? true, outputTokens: value.outputTokens ?? null,
|
|
148
|
+
summaryGuidance: value.summaryGuidance ?? true, summaryContextDivisor: value.summaryContextDivisor ?? DEFAULT_SUMMARY_DIVISOR,
|
|
149
|
+
summaryOutputDivisor: value.summaryOutputDivisor ?? 2, summarySourceDivisor: value.summarySourceDivisor ?? 2,
|
|
150
|
+
summaryPromptTemplate: value.summaryPromptTemplate ?? DEFAULT_SUMMARY_TEMPLATE };
|
|
143
151
|
}
|
|
144
152
|
function status() {
|
|
145
153
|
refreshSettings();
|
|
@@ -152,7 +160,7 @@ export function apply(ctx, initialConfig) {
|
|
|
152
160
|
return { id, baseURL };
|
|
153
161
|
});
|
|
154
162
|
} catch { /* The page remains usable when the required provider is absent. */ }
|
|
155
|
-
return { ...publicSettings(), settingsRevision: hash(publicSettings()),
|
|
163
|
+
return { ...publicSettings(), defaultSummaryPromptTemplate: DEFAULT_SUMMARY_TEMPLATE, settingsRevision: hash(publicSettings()),
|
|
156
164
|
busy: busy() || !!writeBarrier, providers, lastPreview, lastApplied, lastError };
|
|
157
165
|
}
|
|
158
166
|
async function credential(providerId, route) {
|
|
@@ -193,7 +201,11 @@ export function apply(ctx, initialConfig) {
|
|
|
193
201
|
// A server/client mismatch must not enlarge the target past either capacity.
|
|
194
202
|
return Math.min(discovered.model.contextWindow, model.contextWindow);
|
|
195
203
|
}
|
|
196
|
-
installSummaryGuidance(ctx, summaryContext)
|
|
204
|
+
installSummaryGuidance(ctx, summaryContext, () => {
|
|
205
|
+
ensureOpen();
|
|
206
|
+
refreshSettings();
|
|
207
|
+
return settings;
|
|
208
|
+
});
|
|
197
209
|
async function preview(request = {}) {
|
|
198
210
|
ensureOpen();
|
|
199
211
|
payload(request, ['providerId', 'outputTokens']);
|
|
@@ -377,7 +389,7 @@ export function apply(ctx, initialConfig) {
|
|
|
377
389
|
}
|
|
378
390
|
async function configure(request) {
|
|
379
391
|
ensureOpen();
|
|
380
|
-
payload(request, ['providerId', 'autoSync', 'followLoadedModel', 'outputTokens', 'expectedRevision']);
|
|
392
|
+
payload(request, ['providerId', 'autoSync', 'followLoadedModel', 'outputTokens', 'summaryGuidance', 'summaryContextDivisor', 'summaryOutputDivisor', 'summarySourceDivisor', 'summaryPromptTemplate', 'expectedRevision']);
|
|
381
393
|
refreshSettings();
|
|
382
394
|
if (typeof request.expectedRevision !== 'string' || request.expectedRevision !== hash(publicSettings())) {
|
|
383
395
|
refuse('stale-settings', 'Sync preferences changed. Reload the latest preferences before saving.');
|
|
@@ -388,11 +400,20 @@ export function apply(ctx, initialConfig) {
|
|
|
388
400
|
if (typeof request.providerId !== 'string') refuse('invalid-request', 'Provider must be a string.');
|
|
389
401
|
next.providerId = request.providerId;
|
|
390
402
|
}
|
|
391
|
-
for (const key of ['autoSync', 'followLoadedModel']) {
|
|
403
|
+
for (const key of ['autoSync', 'followLoadedModel', 'summaryGuidance']) {
|
|
392
404
|
if (!own(request, key)) continue;
|
|
393
405
|
if (typeof request[key] !== 'boolean') refuse('invalid-request', `${key} must be a boolean.`);
|
|
394
406
|
next[key] = request[key];
|
|
395
407
|
}
|
|
408
|
+
for (const key of ['summaryContextDivisor', 'summaryOutputDivisor', 'summarySourceDivisor']) {
|
|
409
|
+
if (!own(request, key)) continue;
|
|
410
|
+
if (!validSummaryDivisor(request[key])) refuse('invalid-budget', 'Summary divisors must be finite numbers from 1 to Number.MAX_SAFE_INTEGER.');
|
|
411
|
+
next[key] = request[key];
|
|
412
|
+
}
|
|
413
|
+
if (own(request, 'summaryPromptTemplate')) {
|
|
414
|
+
if (!validSummaryTemplate(request.summaryPromptTemplate)) refuse('invalid-request', 'Summary prompt must include {target} and be at most 2048 characters.');
|
|
415
|
+
next.summaryPromptTemplate = request.summaryPromptTemplate;
|
|
416
|
+
}
|
|
396
417
|
if (own(request, 'outputTokens')) {
|
|
397
418
|
if (request.outputTokens === null) delete next.outputTokens;
|
|
398
419
|
else if (Number.isSafeInteger(request.outputTokens) && request.outputTokens > 0) next.outputTokens = request.outputTokens;
|
|
@@ -403,8 +424,7 @@ export function apply(ctx, initialConfig) {
|
|
|
403
424
|
// Editing our own entry can dispose this plugin before edit() resolves.
|
|
404
425
|
// Build the response while this Cordis scope is still alive; never read its
|
|
405
426
|
// injected services after Loader replaces it.
|
|
406
|
-
const response = { ...status(),
|
|
407
|
-
followLoadedModel: next.followLoadedModel, outputTokens: next.outputTokens ?? null,
|
|
427
|
+
const response = { ...status(), ...publicSettings(next),
|
|
408
428
|
settingsRevision: hash(publicSettings(next)), lastPreview: null, lastError: null };
|
|
409
429
|
await backup();
|
|
410
430
|
ensureOpen();
|
package/dist/summary.mjs
CHANGED
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** An editable, per-request supplement to DSH's native summary instruction. */
|
|
2
2
|
const NATIVE_OPENING = 'You are now acting as a compaction engine for this AI coding assistant.';
|
|
3
3
|
const NATIVE_HEADINGS = ['Primary Request and Intent', 'Key Technical Concepts', 'Files and Code',
|
|
4
4
|
'Errors and Fixes', 'Pending Jobs', 'Current Work', 'Next Step', 'Critical Context'];
|
|
5
5
|
const GUIDANCE_PREFIX = 'Keep the entire checkpoint, including all required headings, within a target of ';
|
|
6
6
|
const positive = value => Number.isSafeInteger(value) && value > 0;
|
|
7
|
+
export const validSummaryDivisor = value => typeof value === 'number' && Number.isFinite(value) && value >= 1 && value <= Number.MAX_SAFE_INTEGER;
|
|
8
|
+
export const DEFAULT_SUMMARY_TEMPLATE = `${GUIDANCE_PREFIX}{target} tokens by retaining only information essential to continue the remaining work, consolidating prior summaries, and removing redundant or obsolete details.`;
|
|
9
|
+
export const validSummaryTemplate = value => typeof value === 'string' && value.length <= 2048 && value.includes('{target}');
|
|
10
|
+
// Share identity across hot reloads/copies without adding fields to native requests.
|
|
11
|
+
const augmentedMessages = globalThis[Symbol.for('dsh-strata-sync/summary-augmented')] ??= new WeakSet();
|
|
7
12
|
// Eight mandatory headings need enough space for a meaningful checkpoint. Do
|
|
8
13
|
// not round a tiny target UP; leave native behavior intact instead.
|
|
9
14
|
export const MIN_SUMMARY_TARGET = 256;
|
|
15
|
+
export const DEFAULT_SUMMARY_DIVISOR = 16;
|
|
10
16
|
|
|
11
|
-
export function planSummaryTarget(contextWindow, summaryMaxTokens, sourceTokens) {
|
|
12
|
-
if (![contextWindow, summaryMaxTokens, sourceTokens].every(positive)) return null;
|
|
13
|
-
const target = Math.floor(Math.min(contextWindow /
|
|
17
|
+
export function planSummaryTarget(contextWindow, summaryMaxTokens, sourceTokens, divisor = DEFAULT_SUMMARY_DIVISOR, outputDivisor = 2, sourceDivisor = 2) {
|
|
18
|
+
if (![contextWindow, summaryMaxTokens, sourceTokens].every(positive) || ![divisor, outputDivisor, sourceDivisor].every(validSummaryDivisor)) return null;
|
|
19
|
+
const target = Math.floor(Math.min(contextWindow / divisor, summaryMaxTokens / outputDivisor, sourceTokens / sourceDivisor));
|
|
14
20
|
return target >= MIN_SUMMARY_TARGET ? target : null;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
export function summaryInstruction(target) {
|
|
23
|
+
export function summaryInstruction(target, template = DEFAULT_SUMMARY_TEMPLATE) {
|
|
18
24
|
if (!positive(target)) throw new TypeError('A positive integer summary target is required.');
|
|
19
|
-
|
|
25
|
+
if (!validSummaryTemplate(template)) throw new TypeError('Summary prompt must include {target} and be at most 2048 characters.');
|
|
26
|
+
return template.replaceAll('{target}', String(target));
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
/** Recognize the shipped native prompt, without storing or replacing its text. */
|
|
23
30
|
export function nativeSummaryMessage(options) {
|
|
24
|
-
if (options?.purpose !== 'compaction' || !Array.isArray(options.messages)) return null;
|
|
31
|
+
if (options?.purpose !== 'compaction' || !Array.isArray(options.messages) || augmentedMessages.has(options.messages)) return null;
|
|
25
32
|
const message = options.messages.at(-1);
|
|
26
33
|
if (message?.role !== 'user' || message.content?.length !== 1 || message.content[0]?.type !== 'text') return null;
|
|
27
34
|
const text = message.content[0].text;
|
|
@@ -65,12 +72,28 @@ export function estimateSummarySource(messages) {
|
|
|
65
72
|
* messages property for the lifetime of this stream; never mutate frozen
|
|
66
73
|
* messages or recursively dispatch a second LLM request.
|
|
67
74
|
*/
|
|
68
|
-
export function installSummaryGuidance(ctx, resolveContext) {
|
|
75
|
+
export function installSummaryGuidance(ctx, resolveContext, getSettings = () => ({})) {
|
|
69
76
|
let closed = false;
|
|
77
|
+
function preferences() {
|
|
78
|
+
try {
|
|
79
|
+
const value = getSettings();
|
|
80
|
+
const enabled = value.summaryGuidance === undefined ? true : value.summaryGuidance;
|
|
81
|
+
const divisor = value.summaryContextDivisor === undefined ? DEFAULT_SUMMARY_DIVISOR : value.summaryContextDivisor;
|
|
82
|
+
const outputDivisor = value.summaryOutputDivisor === undefined ? 2 : value.summaryOutputDivisor;
|
|
83
|
+
const sourceDivisor = value.summarySourceDivisor === undefined ? 2 : value.summarySourceDivisor;
|
|
84
|
+
const template = value.summaryPromptTemplate === undefined ? DEFAULT_SUMMARY_TEMPLATE : value.summaryPromptTemplate;
|
|
85
|
+
return enabled === true && [divisor, outputDivisor, sourceDivisor].every(validSummaryDivisor) && validSummaryTemplate(template)
|
|
86
|
+
? { divisor, outputDivisor, sourceDivisor, template } : null;
|
|
87
|
+
} catch { return null; }
|
|
88
|
+
}
|
|
70
89
|
const remove = ctx.on('llm/stream', (options, next) => {
|
|
71
90
|
const native = nativeSummaryMessage(options);
|
|
72
91
|
const descriptor = options && Object.getOwnPropertyDescriptor(options, 'messages');
|
|
73
92
|
if (closed || !native || !descriptor?.writable || options.signal?.aborted) return next();
|
|
93
|
+
// Disabled guidance must not perform even metadata discovery. Native DSH
|
|
94
|
+
// compaction and its request options still pass through unchanged.
|
|
95
|
+
const selected = preferences();
|
|
96
|
+
if (!selected) return next();
|
|
74
97
|
const sourceTokens = estimateSummarySource(options.messages);
|
|
75
98
|
if (!positive(sourceTokens) || !positive(options.maxTokens)) return next();
|
|
76
99
|
return (async function* () {
|
|
@@ -80,14 +103,17 @@ export function installSummaryGuidance(ctx, resolveContext) {
|
|
|
80
103
|
let contextWindow;
|
|
81
104
|
try { contextWindow = await resolveContext(options); }
|
|
82
105
|
catch { /* Metadata/compatibility failure must not break native inference. */ }
|
|
83
|
-
const target = planSummaryTarget(contextWindow, options.maxTokens, sourceTokens);
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
const target = planSummaryTarget(contextWindow, options.maxTokens, sourceTokens, selected.divisor, selected.outputDivisor, selected.sourceDivisor);
|
|
107
|
+
const current = preferences();
|
|
108
|
+
if (!closed && !options.signal?.aborted && current && Object.keys(selected).every(key => selected[key] === current[key]) && target !== null && options.messages === original) {
|
|
109
|
+
const last = { ...native, content: [{ ...native.content[0], text: `${native.content[0].text}\n- ${summaryInstruction(target, selected.template)}` }] };
|
|
86
110
|
augmented = [...original.slice(0, -1), last];
|
|
111
|
+
augmentedMessages.add(augmented);
|
|
87
112
|
options.messages = augmented;
|
|
88
113
|
}
|
|
89
114
|
yield* next();
|
|
90
115
|
} finally {
|
|
116
|
+
if (augmented) augmentedMessages.delete(augmented);
|
|
91
117
|
if (augmented && options.messages === augmented) options.messages = original;
|
|
92
118
|
}
|
|
93
119
|
})();
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -6,28 +6,46 @@
|
|
|
6
6
|
|
|
7
7
|
UI 支持 English、简体中文、繁體中文。自动跟随 DSH 界面语言并实时更新,不提供独立语言菜单。DSH 的 `zh` 对应简体中文,`zh-Hant`、`zh-TW`、`zh-HK`、`zh-MO` 对应繁体中文;其他语言使用英文。服务器返回的未知诊断消息保留原文,方便排查。
|
|
8
8
|
|
|
9
|
-
0.
|
|
9
|
+
0.10.0 精简摘要设置,并让补充提示词可直接编辑。可保留默认模板,或使用动态 `{target}` 自定义内容;DSH 原生提示词与输出硬上限保持不变。
|
|
10
10
|
|
|
11
11
|
## 功能
|
|
12
12
|
|
|
13
13
|
### 动态摘要引导
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
精简的“**动态摘要目标**”区域包含启用开关、上下文除数和可编辑的“**摘要补充提示词**”;展开“**计算方式与限制**”可调整摘要输出与原文长度的除数,并查看公式与限制。功能默认开启,关闭后仍保留 DSH 原生摘要与自动压缩。
|
|
16
|
+
|
|
17
|
+
编辑框直接显示实际附加到原生提示词的模板,默认内容如下:
|
|
16
18
|
|
|
17
19
|
```text
|
|
18
|
-
|
|
19
|
-
目标 = floor(min(上下文 / 16,
|
|
20
|
-
本次摘要实际 maxTokens / 2,
|
|
21
|
-
待替换内容的估算 tokens / 2))
|
|
20
|
+
Keep the entire checkpoint, including all required headings, within a target of {target} tokens by retaining only information essential to continue the remaining work, consolidating prior summaries, and removing redundant or obsolete details.
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
模板须保留字面的 `{target}`,每次摘要时会将所有出现位置替换为本次计算的目标。长度最多 2,048 个字符;只做文本替换,不执行代码。“**恢复默认提示词**”会将编辑框恢复为原本的英文模板,修改或恢复后点击“**保存偏好**”才会应用。切换界面语言不会翻译或覆盖已保存的模板。这里只编辑补充内容,不修改 DSH 原生摘要指令。
|
|
24
|
+
|
|
25
|
+
| 插件偏好 | 默认值 | 含义 |
|
|
26
|
+
|---|---:|---|
|
|
27
|
+
| `summaryGuidance` | `true` | 对支持的摘要请求附加补充提示词。 |
|
|
28
|
+
| `summaryContextDivisor` | `16` | 以上下文除以此值。 |
|
|
29
|
+
| `summaryOutputDivisor` | `2` | 以本次摘要输出硬上限除以此值。 |
|
|
30
|
+
| `summarySourceDivisor` | `2` | 以原文估算长度除以此值。 |
|
|
31
|
+
| `summaryPromptTemplate` | 上方英文模板 | 替换 `{target}` 后附加的补充内容。 |
|
|
32
|
+
|
|
33
|
+
三项除数都接受至少为 1 的有限数值,也支持 1.5、2.5 等小数。除数越大,对应限制越小;最终取三项限制的最小值并向下取整,不会改变实际输出硬上限。
|
|
34
|
+
|
|
35
|
+
每次支持的摘要请求都会重新计算:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
上下文 = min(已确认的 Strata 上下文, DSH 已有模型上下文)
|
|
39
|
+
目标 = floor(min(上下文 / summaryContextDivisor,
|
|
40
|
+
本次摘要实际 maxTokens / summaryOutputDivisor,
|
|
41
|
+
待替换内容的估算 tokens / summarySourceDivisor))
|
|
42
|
+
```
|
|
25
43
|
|
|
26
|
-
|
|
44
|
+
原文估算涵盖这次要替换的对话片段及其中的旧摘要,不含系统提示词和工具定义。只读查询核对加载模型与上下文,实际输出硬上限来自当前请求。32K 上下文、4,096-token 摘要上限且原文足够长时,上下文除数 32、16、8 分别得到 1,024、2,048、2,048 tokens。UI 预览显示目标上限,不是未来请求的实际目标。
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
保存这些控件只修改插件偏好,不会同步模型预算或修改 Strata Server 设置。DSH 原生提示词、八个章节和请求参数保持不变。默认补充内容只有一句,自定义模板则按输入内容附加。目标是写作指令,**不是新的输出硬上限,也不能保证不截断**;不增加重试流程或额外推理请求。
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
无法确认路由或信息、原生提示词格式未知、附件用量无法估算、模板无效、请求取消、功能关闭或目标低于 256 tokens 时,保留原生请求。移除插件会停止附加内容,不改写已保存的对话历史。
|
|
31
49
|
|
|
32
50
|
### 模型能力自动同步(0.4.0)
|
|
33
51
|
|
|
@@ -66,7 +84,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
66
84
|
|
|
67
85
|
完成后重新打开 DSH。首次安装会自动选中 bundle;已安装但禁用的 bundle 需在插件管理器重新启用。
|
|
68
86
|
|
|
69
|
-
|
|
87
|
+
要从源码安装**包含摘要提示词编辑器的 0.10.0**,请使用 Node.js 22 或更新版本构建,并在最后的安装命令前完成任务、完全退出 DSH Desktop:
|
|
70
88
|
|
|
71
89
|
```sh
|
|
72
90
|
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
@@ -74,7 +92,7 @@ cd dsh-strata-sync
|
|
|
74
92
|
npm ci
|
|
75
93
|
npm test
|
|
76
94
|
npm pack
|
|
77
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.
|
|
95
|
+
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.0.tgz
|
|
78
96
|
```
|
|
79
97
|
|
|
80
98
|
执行最后一行前同样需要完全退出 DSH Desktop,安装完成后重新打开。在其他目录执行时,请使用安装包的绝对路径。
|
|
@@ -87,6 +105,8 @@ dsh plugin --profile desktop add ./dsh-strata-sync-0.8.1.tgz
|
|
|
87
105
|
4. 如需自动同步,勾选“启动 DSH 时自动同步”并保存,下次启动生效。原有 `autoSync: true` 会沿用为启动同步。
|
|
88
106
|
5. 开启新对话,使用更新后的 Agent 预设。
|
|
89
107
|
|
|
108
|
+
“动态摘要目标”控件独立于模型同步。保持“启用摘要提示补充”开启、使用默认模板及 16/2/2 的除数,即沿用先前行为,也可修改后保存偏好。关闭此开关不会禁用 DSH 自身的压缩功能。
|
|
109
|
+
|
|
90
110
|
无需把 API key 复制到此插件;认证问题请在 DSH 模型设置处理。
|
|
91
111
|
|
|
92
112
|
## 兼容性
|
|
@@ -135,6 +155,10 @@ ConfigEditor 负责单项原子写入与热加载;跨多项设置采用补偿
|
|
|
135
155
|
|
|
136
156
|
## 开发与版本
|
|
137
157
|
|
|
158
|
+
0.10.0 加入补充提示词编辑器、动态 `{target}` 与恢复默认功能,精简三语摘要区域,新增高级输出/原文除数与三项除数的小数支持,并沿用备份与版本冲突保护。
|
|
159
|
+
|
|
160
|
+
0.9.0 加入默认开启的摘要提示补充开关及可调整的上下文除数(默认 16),沿用偏好保存与版本冲突保护,并同步三语界面和文档。保存这两个控件不改变原生摘要指令、输出硬上限、其他预算或服务器设置。
|
|
161
|
+
|
|
138
162
|
0.5.0 移除独立语言菜单与产品声明,改为跟随 DSH 语言及启动时单次同步。0.3.0 首次加入三语 UI,0.2.0 将 UI 移入原生设置。
|
|
139
163
|
|
|
140
164
|
`src/plugin.mjs` 为宿主插件,`src/client.js` 为原生 ModuleLoader/React UI,`src/core.mjs` 负责信息读取与纯预算计算,`src/summary.mjs` 提供原生摘要请求中间件。执行 `npm test`、`npm run build`、`npm pack --dry-run` 验证。安装包只包含原创插件代码,不包含私人应用程序源码、认证或对话。
|
package/docs/README.zh-TW.md
CHANGED
|
@@ -6,28 +6,46 @@
|
|
|
6
6
|
|
|
7
7
|
UI 支援 English、简体中文、繁體中文。自動跟隨 DSH 介面語言並即時更新,不提供獨立語言選單。DSH 的 `zh` 對應簡體中文,`zh-Hant`、`zh-TW`、`zh-HK`、`zh-MO` 對應繁體中文;其他語言使用英文。伺服器傳回的未知診斷訊息保留原文,以利排查。
|
|
8
8
|
|
|
9
|
-
0.
|
|
9
|
+
0.10.0 精簡摘要設定,並讓補充提示詞可直接編輯。可保留預設範本,或使用動態 `{target}` 自訂內容;DSH 原生提示詞與輸出硬上限保持不變。
|
|
10
10
|
|
|
11
11
|
## 功能
|
|
12
12
|
|
|
13
13
|
### 動態摘要引導
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
精簡的「**動態摘要目標**」區塊包含啟用開關、上下文除數和可編輯的「**摘要補充提示詞**」;展開「**計算方式與限制**」可調整摘要輸出與原文長度的除數,並查看公式與限制。功能預設開啟,關閉後仍保留 DSH 原生摘要與自動壓縮。
|
|
16
|
+
|
|
17
|
+
編輯框直接顯示實際附加至原生提示詞的範本,預設內容如下:
|
|
16
18
|
|
|
17
19
|
```text
|
|
18
|
-
|
|
19
|
-
目標 = floor(min(上下文 / 16,
|
|
20
|
-
本次摘要實際 maxTokens / 2,
|
|
21
|
-
待替換內容的估算 tokens / 2))
|
|
20
|
+
Keep the entire checkpoint, including all required headings, within a target of {target} tokens by retaining only information essential to continue the remaining work, consolidating prior summaries, and removing redundant or obsolete details.
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
範本須保留字面的 `{target}`,每次摘要時會將所有出現位置替換為當次計算的目標。長度最多 2,048 個字元;只做文字替換,不執行程式碼。「**還原預設提示詞**」會將編輯框恢復為原本的英文範本,修改或還原後按「**儲存偏好**」才會套用。切換介面語言不會翻譯或覆寫已儲存的範本。這裡只編輯補充內容,不修改 DSH 原生摘要指令。
|
|
24
|
+
|
|
25
|
+
| 外掛偏好 | 預設值 | 含義 |
|
|
26
|
+
|---|---:|---|
|
|
27
|
+
| `summaryGuidance` | `true` | 對支援的摘要請求附加補充提示詞。 |
|
|
28
|
+
| `summaryContextDivisor` | `16` | 以上下文除以此值。 |
|
|
29
|
+
| `summaryOutputDivisor` | `2` | 以當次摘要輸出硬上限除以此值。 |
|
|
30
|
+
| `summarySourceDivisor` | `2` | 以原文估算長度除以此值。 |
|
|
31
|
+
| `summaryPromptTemplate` | 上方英文範本 | 替換 `{target}` 後附加的補充內容。 |
|
|
32
|
+
|
|
33
|
+
三項除數都接受至少為 1 的有限數值,也支援 1.5、2.5 等小數。除數越大,對應限制越小;最終取三項限制的最小值並向下取整,不會改變實際輸出硬上限。
|
|
34
|
+
|
|
35
|
+
每次支援的摘要請求都會重新計算:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
上下文 = min(已確認的 Strata 上下文, DSH 既有模型上下文)
|
|
39
|
+
目標 = floor(min(上下文 / summaryContextDivisor,
|
|
40
|
+
本次摘要實際 maxTokens / summaryOutputDivisor,
|
|
41
|
+
待替換內容的估算 tokens / summarySourceDivisor))
|
|
42
|
+
```
|
|
25
43
|
|
|
26
|
-
|
|
44
|
+
原文估算涵蓋這次要替換的對話片段與其中的舊摘要,不含系統提示詞和工具定義。唯讀查詢核對載入模型與上下文,實際輸出硬上限來自當次請求。32K 上下文、4,096-token 摘要上限且原文足夠長時,上下文除數 32、16、8 分別得到 1,024、2,048、2,048 tokens。UI 預覽顯示目標上限,不是未來請求的實際目標。
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
儲存這些控制項只更改外掛偏好,不會同步模型預算或修改 Strata Server 設定。DSH 原生提示詞、八個章節和請求參數保持不變。預設補充內容只有一句,自訂範本則按輸入內容附加。目標是寫作指令,**不是新的輸出硬上限,也不能保證不截斷**;不增加重試流程或額外推論請求。
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
無法確認路由或資訊、原生提示詞格式未知、附件用量無法估算、範本無效、請求取消、功能關閉或目標低於 256 tokens 時,保留原生請求。移除外掛會停止附加內容,不重寫已儲存的對話歷史。
|
|
31
49
|
|
|
32
50
|
### 模型能力自動同步(0.4.0)
|
|
33
51
|
|
|
@@ -66,7 +84,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
66
84
|
|
|
67
85
|
完成後重新開啟 DSH。首次安裝會自動選取 bundle;已安裝但停用的 bundle 需在外掛管理員重新啟用。
|
|
68
86
|
|
|
69
|
-
|
|
87
|
+
要從原始碼安裝**包含摘要提示詞編輯器的 0.10.0**,請使用 Node.js 22 或更新版本建置,並在最後的安裝命令前完成工作、完全結束 DSH Desktop:
|
|
70
88
|
|
|
71
89
|
```sh
|
|
72
90
|
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
@@ -74,7 +92,7 @@ cd dsh-strata-sync
|
|
|
74
92
|
npm ci
|
|
75
93
|
npm test
|
|
76
94
|
npm pack
|
|
77
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.
|
|
95
|
+
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.0.tgz
|
|
78
96
|
```
|
|
79
97
|
|
|
80
98
|
執行最後一行前同樣需要完全結束 DSH Desktop,安裝完成後重新開啟。在其他目錄執行時,請使用套件的絕對路徑。
|
|
@@ -87,6 +105,8 @@ dsh plugin --profile desktop add ./dsh-strata-sync-0.8.1.tgz
|
|
|
87
105
|
4. 如需自動同步,勾選「啟動 DSH 時自動同步」並儲存,下次啟動生效。原有 `autoSync: true` 會沿用為啟動同步。
|
|
88
106
|
5. 開啟新對話,使用更新後的 Agent 範本。
|
|
89
107
|
|
|
108
|
+
「動態摘要目標」控制項獨立於模型同步。保持「啟用摘要提示補充」開啟、使用預設範本及 16/2/2 的除數,即沿用先前行為,也可修改後儲存偏好。關閉此開關不會停用 DSH 自身的壓縮功能。
|
|
109
|
+
|
|
90
110
|
不需要把 API key 複製到此外掛;認證問題請在 DSH 模型設定處理。
|
|
91
111
|
|
|
92
112
|
## 相容性
|
|
@@ -135,6 +155,10 @@ ConfigEditor 負責個別原子寫入與熱載入;跨多項設定採補償回
|
|
|
135
155
|
|
|
136
156
|
## 開發與版本
|
|
137
157
|
|
|
158
|
+
0.10.0 加入補充提示詞編輯器、動態 `{target}` 與還原預設功能,精簡三語摘要區塊,新增進階輸出/原文除數與三項除數的小數支援,並沿用備份與版本衝突保護。
|
|
159
|
+
|
|
160
|
+
0.9.0 加入預設開啟的摘要提示補充開關及可調整的上下文除數(預設 16),沿用偏好儲存與版本衝突保護,並同步三語介面和文件。儲存這兩個控制項不改變原生摘要指令、輸出硬上限、其他預算或伺服器設定。
|
|
161
|
+
|
|
138
162
|
0.5.0 移除獨立語言選單與產品聲明,改為跟隨 DSH 語言及啟動時單次同步。0.3.0 首次加入三語 UI,0.2.0 將 UI 移入原生設定。
|
|
139
163
|
|
|
140
164
|
`src/plugin.mjs` 為宿主外掛,`src/client.js` 為原生 ModuleLoader/React UI,`src/core.mjs` 負責資訊讀取與純預算計算,`src/summary.mjs` 提供原生摘要請求中介層。執行 `npm test`、`npm run build`、`npm pack --dry-run` 驗證。套件只包含原創外掛程式,不包含私人應用程式原始碼、認證或對話。
|
package/docs/VALIDATION.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Validation date: 2026-10-30 (Asia/Taipei).
|
|
4
4
|
|
|
5
|
+
## Editable summary prompt and fractional divisors 0.10.0
|
|
6
|
+
|
|
7
|
+
- The compact settings card displays the exact editable supplement; detailed limits and the output/source divisors are inside a collapsed disclosure. All three locales preserve the saved prompt verbatim. Restore-default changes the draft until preferences are saved.
|
|
8
|
+
- `summaryPromptTemplate` requires literal `{target}` and at most 2,048 characters. Substitution is plain text, never code evaluation; the native instruction remains intact. All three divisors accept finite numbers from 1 to `Number.MAX_SAFE_INTEGER`, including fractions. Defaults remain 16/2/2; the final target is floored.
|
|
9
|
+
- All **151 automated tests pass**, including 38 UI tests and the package verifier. Checks cover saved custom prompts, restore-default, locale stability, fractional bounds, invalid input, stale preferences during discovery and saving, and custom-text deduplication through the native waterfall. Saving only these preferences leaves model and compaction settings unchanged.
|
|
10
|
+
- A local probe exercised the installed DSH 0.2.1-rc.3 native summary engine with a custom supplement and divisors 8.5/1.5/2.5. At 32K with a 4,096 output cap and sufficient source, the appended target was 2,730 tokens. Defaults, off state, native prompt preservation and unload also passed. Synthetic adapter output was used; no inference requests or real-model truncation claims are involved.
|
|
11
|
+
|
|
12
|
+
## Summary guidance controls 0.9.0
|
|
13
|
+
|
|
14
|
+
- Adds persisted `summaryGuidance` (default `true`) and `summaryContextDivisor` (default `16`). The divisor must be a positive safe integer. Saving these controls uses the existing backup, idle and revision checks and leaves model settings and compaction budgets unchanged.
|
|
15
|
+
- Backend tests cover native schema defaults and validation, persisted controls across reloads, disabling without metadata requests, re-enabling with a custom divisor, unchanged native compaction, source/output bounds, and changes during discovery. The three-language UI tests cover default-on controls, saving, invalid input, external changes/conflicts, custom previews, disabled state and below-256 fallback messages.
|
|
16
|
+
- A local probe exercised the installed DSH 0.2.1-rc.3 `BasicCompactionEngine.summarize()` through its actual Cordis waterfall. At 32K with a 4,096 summary cap, the default divisor produced 2,048, divisor 32 produced 1,024, disabled guidance preserved the native prompt without discovery, and divisor 8 remained capped at 2,048. Original prompt content, input, output cap, tools and configuration were preserved; unloading restored native behavior. Responses were synthetic: no inference requests were sent.
|
|
17
|
+
- All **142 automated tests pass**, including the package verifier and 33 settings UI tests. These checks validate configuration and integration, not a measured reduction in real-model truncation or compaction frequency.
|
|
18
|
+
|
|
5
19
|
## Package rename and target ratio 0.8.1
|
|
6
20
|
|
|
7
21
|
- Package identity, native bundle and client module now use `dsh-strata-sync`; the GitHub repository is unchanged. Existing scoped installations must be migrated, not loaded alongside the renamed plugin.
|