dsh-strata-sync 0.9.0 → 0.10.1
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 +39 -19
- package/dist/client.js +64 -31
- package/dist/index.js +18 -10
- package/dist/summary.mjs +23 -11
- package/docs/README.zh-CN.md +33 -19
- package/docs/README.zh-TW.md +33 -19
- package/docs/VALIDATION.md +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,36 +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.1 shortens the summary settings explanation. Keep the default prompt 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
|
-
divisor = summaryContextDivisor (default: 16)
|
|
20
|
-
target = floor(min(context / divisor,
|
|
21
|
-
actual summary maxTokens / 2,
|
|
22
|
-
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.
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
With the default divisor of 16, a 4,096-token summary output cap and enough source content, 32K context gives a target of **2,048 tokens**, and 64K gives **2,048 tokens**. Shorter content lowers the target. **Settings → dsh-strata-sync** shows the formula and the maximum target for a preview; it cannot know the exact target of a future summary.
|
|
28
|
-
|
|
29
|
-
In the **Dynamic summary target** card, toggle **Enable summary guidance** and set **Context divisor (context ÷ N)** to a positive safe integer. A smaller divisor allows a larger target; the summary-output and source-content bounds still apply. For example, with 32K context, a 4,096-token summary cap and enough content, divisors 32, 16 and 8 produce targets of 1,024, 2,048 and 2,048 tokens respectively. Click **Save preferences** to apply your choice to subsequent supported summary requests. Saving these controls does not synchronize model budgets or change Strata Server settings.
|
|
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.
|
|
30
24
|
|
|
31
25
|
| Plugin preference | Default | Meaning |
|
|
32
26
|
|---|---:|---|
|
|
33
|
-
| `summaryGuidance` | `true` | Append
|
|
34
|
-
| `summaryContextDivisor` | `16` | Divide the verified context by this
|
|
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}`. |
|
|
35
32
|
|
|
36
|
-
|
|
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.
|
|
37
34
|
|
|
38
|
-
|
|
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
|
+
```
|
|
43
|
+
|
|
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.
|
|
45
|
+
|
|
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.
|
|
47
|
+
|
|
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.
|
|
39
49
|
|
|
40
50
|
### Automatic model capabilities (0.4.0)
|
|
41
51
|
|
|
@@ -85,7 +95,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
85
95
|
|
|
86
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.
|
|
87
97
|
|
|
88
|
-
To install **0.
|
|
98
|
+
To install **0.10.1 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:
|
|
89
99
|
|
|
90
100
|
```sh
|
|
91
101
|
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
@@ -93,7 +103,7 @@ cd dsh-strata-sync
|
|
|
93
103
|
npm ci
|
|
94
104
|
npm test
|
|
95
105
|
npm pack
|
|
96
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.
|
|
106
|
+
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.1.tgz
|
|
97
107
|
```
|
|
98
108
|
|
|
99
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.
|
|
@@ -106,10 +116,20 @@ Then open **Settings → dsh-strata-sync**:
|
|
|
106
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.
|
|
107
117
|
5. Start a new conversation to use the new Agent preset revision.
|
|
108
118
|
|
|
109
|
-
The **Dynamic summary target** card is independent of model synchronization. Leave
|
|
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.
|
|
110
120
|
|
|
111
121
|
No API key needs to be copied into this plugin. Set up or repair credentials in DSH Models settings.
|
|
112
122
|
|
|
123
|
+
## Changes in 0.10.1
|
|
124
|
+
|
|
125
|
+
- Shortens the summary UI explanation to the formula and native-summary fallback. Calculation and runtime behavior are unchanged; full details remain in this README.
|
|
126
|
+
|
|
127
|
+
## Changes in 0.10.0
|
|
128
|
+
|
|
129
|
+
- Makes the actual supplemental prompt editable, with a dynamic `{target}` placeholder and Restore default prompt action.
|
|
130
|
+
- 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.
|
|
131
|
+
- Validates and saves prompt edits through existing backup and revision safeguards without changing native instructions or other budgets.
|
|
132
|
+
|
|
113
133
|
## Changes in 0.9.0
|
|
114
134
|
|
|
115
135
|
- Adds a default-on switch for the supplemental summary guidance and an adjustable context divisor, defaulting to 16.
|
package/dist/client.js
CHANGED
|
@@ -87,6 +87,26 @@ 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": "目标如何计算"
|
|
@@ -95,9 +115,13 @@ window.__ModuleLoader__.load({
|
|
|
95
115
|
"zh-Hant": "啟用後,在每次支援的 Strata 摘要請求前,計算長度目標,並在 DSH 原生摘要提示詞後補充一句。",
|
|
96
116
|
"zh-Hans": "启用后,在每次支持的 Strata 摘要请求前,计算长度目标,并在 DSH 原生摘要提示词后补充一句。"
|
|
97
117
|
},
|
|
98
|
-
"Target = floor(min(context / N, summary output limit /
|
|
99
|
-
"zh-Hant": "目標 = floor(min(上下文 / N, 摘要輸出上限 /
|
|
100
|
-
"zh-Hans": "目标 = floor(min(上下文 / N, 摘要输出上限 /
|
|
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
|
+
"When guidance cannot be applied, DSH keeps its native summary behavior.": {
|
|
123
|
+
"zh-Hant": "無法套用時,沿用 DSH 原生摘要。",
|
|
124
|
+
"zh-Hans": "无法应用时,沿用 DSH 原生摘要。"
|
|
101
125
|
},
|
|
102
126
|
"Enable summary guidance": {
|
|
103
127
|
"zh-Hant": "啟用摘要提示補充",
|
|
@@ -111,13 +135,21 @@ window.__ModuleLoader__.load({
|
|
|
111
135
|
"zh-Hant": "上下文除數(上下文 ÷ N)",
|
|
112
136
|
"zh-Hans": "上下文除数(上下文 ÷ N)"
|
|
113
137
|
},
|
|
114
|
-
"
|
|
115
|
-
"zh-Hant": "
|
|
116
|
-
"zh-Hans": "
|
|
138
|
+
"Summary output divisor (output limit ÷ O)": {
|
|
139
|
+
"zh-Hant": "摘要輸出除數(輸出上限 ÷ O)",
|
|
140
|
+
"zh-Hans": "摘要输出除数(输出上限 ÷ O)"
|
|
141
|
+
},
|
|
142
|
+
"Source length divisor (source estimate ÷ S)": {
|
|
143
|
+
"zh-Hant": "原文長度除數(原文估算 ÷ S)",
|
|
144
|
+
"zh-Hans": "原文长度除数(原文估算 ÷ S)"
|
|
145
|
+
},
|
|
146
|
+
"Defaults: N = 16, O = 2, S = 2. Smaller divisors allow longer targets; the smallest of the three bounds wins. Decimals are supported.": {
|
|
147
|
+
"zh-Hant": "預設 N = 16、O = 2、S = 2。除數越小,目標可越長;最後取三項限制的最小值。支援小數。",
|
|
148
|
+
"zh-Hans": "默认 N = 16、O = 2、S = 2。除数越小,目标可越长;最后取三项限制的最小值。支持小数。"
|
|
117
149
|
},
|
|
118
|
-
"Enter a
|
|
119
|
-
"zh-Hant": "
|
|
120
|
-
"zh-Hans": "
|
|
150
|
+
"Enter a finite divisor of at least 1; decimals are allowed.": {
|
|
151
|
+
"zh-Hant": "請輸入大於或等於 1 的有限除數,可使用小數。",
|
|
152
|
+
"zh-Hans": "请输入大于或等于 1 的有限除数,可使用小数。"
|
|
121
153
|
},
|
|
122
154
|
"This preview is below the 256-token minimum. The native summary prompt remains unchanged.": {
|
|
123
155
|
"zh-Hant": "本次預覽低於 256 tokens 的最低目標,將保留原生摘要提示詞。",
|
|
@@ -371,7 +403,7 @@ window.__ModuleLoader__.load({
|
|
|
371
403
|
model: 'Model', modelId: 'Model', defaultModel: 'Default model',
|
|
372
404
|
thresholdRatio: 'Compaction ratio ceiling', retainRatio: 'Recent conversation retention ratio',
|
|
373
405
|
};
|
|
374
|
-
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}}`;
|
|
406
|
+
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}}`;
|
|
375
407
|
const fmt = (v) => v == null ? 'Not set' : typeof v === 'number' ? v.toLocaleString('en-US') : typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
376
408
|
const warningText = {
|
|
377
409
|
INPUT_UNCONFIRMED: 'Input types are missing or unsupported in server metadata. Existing input settings are preserved.',
|
|
@@ -399,19 +431,20 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
399
431
|
};
|
|
400
432
|
const diagnostic = (message) => translations[message] ? t(message) : language === 'en' ? message : t('Server diagnostic: ') + message;
|
|
401
433
|
const [state,setState] = React.useState(null), [preview,setPreview] = React.useState(null), [result,setResult] = React.useState(null);
|
|
402
|
-
const [form,setForm] = React.useState({providerId:'',output:'',manual:false,auto:false,follow:true,summaryGuidance:true,summaryDivisor:'16'});
|
|
434
|
+
const [form,setForm] = React.useState({providerId:'',output:'',manual:false,auto:false,follow:true,summaryGuidance:true,summaryDivisor:'16',summaryOutputDivisor:'2',summarySourceDivisor:'2',summaryPrompt:''});
|
|
403
435
|
const [pending,setPending] = React.useState(false), [error,setError] = React.useState(''), [loadError,setLoadError] = React.useState('');
|
|
404
436
|
const [notice,setNotice] = React.useState(''), [conflict,setConflict] = React.useState(false);
|
|
405
437
|
const formRef=React.useRef(form), baseline=React.useRef(null), requestSeq=React.useRef(0), alive=React.useRef(true);
|
|
406
|
-
const
|
|
407
|
-
const
|
|
438
|
+
const numberValue = value => value.trim()===''?NaN:Number(value);
|
|
439
|
+
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});
|
|
440
|
+
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??''});
|
|
408
441
|
const equal = (a,b) => Object.keys(a).every(key=>Object.is(a[key],b[key]));
|
|
409
442
|
const acceptStatus = React.useCallback((s,force=false) => {
|
|
410
443
|
if (!alive.current) return;
|
|
411
444
|
const next=preferences(s), old=baseline.current;
|
|
412
445
|
const untouched=!old || equal(values(formRef.current),old.values);
|
|
413
446
|
if (force || untouched) {
|
|
414
|
-
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)};
|
|
447
|
+
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};
|
|
415
448
|
formRef.current=nextForm; setForm(nextForm); setConflict(false);
|
|
416
449
|
baseline.current={values:next,revision:s.settingsRevision};
|
|
417
450
|
} else if (old.revision!==s.settingsRevision || !equal(old.values,next)) {
|
|
@@ -443,13 +476,15 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
443
476
|
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.');
|
|
444
477
|
} finally { if(alive.current)setPending(false); }
|
|
445
478
|
}
|
|
446
|
-
const draft=values(form),
|
|
447
|
-
const
|
|
479
|
+
const draft=values(form), isDivisor=value=>Number.isFinite(value)&&value>=1&&value<=Number.MAX_SAFE_INTEGER;
|
|
480
|
+
const validDivisor=[draft.summaryContextDivisor,draft.summaryOutputDivisor,draft.summarySourceDivisor].every(isDivisor);
|
|
481
|
+
const validPrompt=typeof draft.summaryPromptTemplate==='string'&&draft.summaryPromptTemplate.length>0&&draft.summaryPromptTemplate.length<=2048&&draft.summaryPromptTemplate.includes('{target}');
|
|
482
|
+
const valid=validDivisor&&validPrompt&&(draft.outputTokens===null || Number.isSafeInteger(draft.outputTokens)&&draft.outputTokens>0);
|
|
448
483
|
const dirty=!!baseline.current&&!equal(draft,baseline.current.values);
|
|
449
484
|
const displayedResult=!result || state?.lastApplied?.at>result.at ? state?.lastApplied : result;
|
|
450
485
|
const activeBudget=preview?.budget;
|
|
451
486
|
const summaryTargetCeiling=form.summaryGuidance&&validDivisor&&Number.isSafeInteger(activeBudget?.contextWindow)&&activeBudget.contextWindow>0&&Number.isSafeInteger(activeBudget?.summaryMaxTokens)&&activeBudget.summaryMaxTokens>0
|
|
452
|
-
? Math.floor(Math.min(activeBudget.contextWindow/draft.summaryContextDivisor,activeBudget.summaryMaxTokens/
|
|
487
|
+
? Math.floor(Math.min(activeBudget.contextWindow/draft.summaryContextDivisor,activeBudget.summaryMaxTokens/draft.summaryOutputDivisor)) : null;
|
|
453
488
|
const outputSource=(budget)=>t(({server:'Strata Server default',manual:'Manual override',calculated:'Automatic calculation'})[budget?.outputSource]||'Automatic calculation');
|
|
454
489
|
const preserved=(view)=>{
|
|
455
490
|
const status=view?.capabilityStatus;
|
|
@@ -494,24 +529,22 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
494
529
|
h('div',{className:'ss-card','data-testid':'summary-target'},
|
|
495
530
|
h('strong',null,t('Dynamic summary target')),
|
|
496
531
|
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')),
|
|
497
|
-
h('
|
|
498
|
-
h('
|
|
499
|
-
|
|
500
|
-
h('p',{className:'ss-
|
|
501
|
-
h('
|
|
532
|
+
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})),
|
|
533
|
+
state&&!validDivisor&&h('p',{className:'ss-status ss-error',role:'alert'},t('Enter a finite divisor of at least 1; decimals are allowed.')),
|
|
534
|
+
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})),
|
|
535
|
+
state&&!validPrompt&&h('p',{className:'ss-status ss-error',role:'alert'},t('Use 1–2,048 characters and include {target}.')),
|
|
536
|
+
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')),
|
|
537
|
+
h('p',{className:'ss-muted'},t("Appended to DSH's native prompt; {target} becomes the calculated token target. Save preferences to apply.")),
|
|
502
538
|
!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.')),
|
|
503
|
-
h('p',null,t("When enabled, before each supported Strata summary, calculates a length target and appends one sentence to DSH's native summary prompt.")),
|
|
504
539
|
summaryTargetCeiling!==null&&(summaryTargetCeiling>=256
|
|
505
540
|
? h('p',{'data-testid':'summary-target-ceiling'},t('Maximum target for this preview: '),format(summaryTargetCeiling),' tokens')
|
|
506
541
|
: 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.'))),
|
|
507
|
-
h('details',{className:'ss-details'},h('summary',null,t('
|
|
508
|
-
h('
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
h('p',{className:'ss-muted'},t('
|
|
512
|
-
h('p',{className:'ss-muted'},t('
|
|
513
|
-
h('p',{className:'ss-muted'},t('If the route or native summary format cannot be verified, DSH uses its original prompt.')),
|
|
514
|
-
h('p',{className:'ss-muted'},t('Unpriced image/file attachments, cancellation or a disabled plugin preserve native request handling.')))),
|
|
542
|
+
h('details',{className:'ss-details','data-testid':'summary-details'},h('summary',null,t('Calculation and limits')),
|
|
543
|
+
h('div',{className:'ss-grid'},
|
|
544
|
+
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})),
|
|
545
|
+
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}))),
|
|
546
|
+
h('p',{className:'ss-muted'},t('Target = floor(min(context / N, summary output limit / O, selected content estimate / S)).')),
|
|
547
|
+
h('p',{className:'ss-muted'},t('When guidance cannot be applied, DSH keeps its native summary behavior.')))),
|
|
515
548
|
h('div',{className:'ss-actions'},
|
|
516
549
|
h('button',{disabled:pending||!state||!form.providerId||!valid||!dirty||conflict,onClick:()=>action(async()=>{
|
|
517
550
|
const changes=Object.fromEntries(Object.entries(values(formRef.current)).filter(([key,value])=>!Object.is(value,baseline.current.values[key])));
|
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 { DEFAULT_SUMMARY_DIVISOR, 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({
|
|
@@ -12,7 +12,10 @@ export const Config = z.object({
|
|
|
12
12
|
followLoadedModel: z.boolean().default(true),
|
|
13
13
|
outputTokens: z.number().step(1).min(1),
|
|
14
14
|
summaryGuidance: z.boolean().default(true),
|
|
15
|
-
summaryContextDivisor: z.number().
|
|
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),
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
const PACKAGE = 'dsh-strata-sync';
|
|
@@ -142,7 +145,9 @@ export function apply(ctx, initialConfig) {
|
|
|
142
145
|
function publicSettings(value = settings) {
|
|
143
146
|
return { providerId: value.providerId ?? '', autoSync: value.autoSync ?? false,
|
|
144
147
|
followLoadedModel: value.followLoadedModel ?? true, outputTokens: value.outputTokens ?? null,
|
|
145
|
-
summaryGuidance: value.summaryGuidance ?? true, summaryContextDivisor: value.summaryContextDivisor ?? DEFAULT_SUMMARY_DIVISOR
|
|
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 };
|
|
146
151
|
}
|
|
147
152
|
function status() {
|
|
148
153
|
refreshSettings();
|
|
@@ -155,7 +160,7 @@ export function apply(ctx, initialConfig) {
|
|
|
155
160
|
return { id, baseURL };
|
|
156
161
|
});
|
|
157
162
|
} catch { /* The page remains usable when the required provider is absent. */ }
|
|
158
|
-
return { ...publicSettings(), settingsRevision: hash(publicSettings()),
|
|
163
|
+
return { ...publicSettings(), defaultSummaryPromptTemplate: DEFAULT_SUMMARY_TEMPLATE, settingsRevision: hash(publicSettings()),
|
|
159
164
|
busy: busy() || !!writeBarrier, providers, lastPreview, lastApplied, lastError };
|
|
160
165
|
}
|
|
161
166
|
async function credential(providerId, route) {
|
|
@@ -384,7 +389,7 @@ export function apply(ctx, initialConfig) {
|
|
|
384
389
|
}
|
|
385
390
|
async function configure(request) {
|
|
386
391
|
ensureOpen();
|
|
387
|
-
payload(request, ['providerId', 'autoSync', 'followLoadedModel', 'outputTokens', 'summaryGuidance', 'summaryContextDivisor', 'expectedRevision']);
|
|
392
|
+
payload(request, ['providerId', 'autoSync', 'followLoadedModel', 'outputTokens', 'summaryGuidance', 'summaryContextDivisor', 'summaryOutputDivisor', 'summarySourceDivisor', 'summaryPromptTemplate', 'expectedRevision']);
|
|
388
393
|
refreshSettings();
|
|
389
394
|
if (typeof request.expectedRevision !== 'string' || request.expectedRevision !== hash(publicSettings())) {
|
|
390
395
|
refuse('stale-settings', 'Sync preferences changed. Reload the latest preferences before saving.');
|
|
@@ -400,11 +405,14 @@ export function apply(ctx, initialConfig) {
|
|
|
400
405
|
if (typeof request[key] !== 'boolean') refuse('invalid-request', `${key} must be a boolean.`);
|
|
401
406
|
next[key] = request[key];
|
|
402
407
|
}
|
|
403
|
-
|
|
404
|
-
if (!
|
|
405
|
-
|
|
406
|
-
|
|
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;
|
|
408
416
|
}
|
|
409
417
|
if (own(request, 'outputTokens')) {
|
|
410
418
|
if (request.outputTokens === null) delete next.outputTokens;
|
package/dist/summary.mjs
CHANGED
|
@@ -1,28 +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;
|
|
10
15
|
export const DEFAULT_SUMMARY_DIVISOR = 16;
|
|
11
16
|
|
|
12
|
-
export function planSummaryTarget(contextWindow, summaryMaxTokens, sourceTokens, divisor = DEFAULT_SUMMARY_DIVISOR) {
|
|
13
|
-
if (![contextWindow, summaryMaxTokens, sourceTokens,
|
|
14
|
-
const target = Math.floor(Math.min(contextWindow / divisor, summaryMaxTokens /
|
|
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));
|
|
15
20
|
return target >= MIN_SUMMARY_TARGET ? target : null;
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
export function summaryInstruction(target) {
|
|
23
|
+
export function summaryInstruction(target, template = DEFAULT_SUMMARY_TEMPLATE) {
|
|
19
24
|
if (!positive(target)) throw new TypeError('A positive integer summary target is required.');
|
|
20
|
-
|
|
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));
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
/** Recognize the shipped native prompt, without storing or replacing its text. */
|
|
24
30
|
export function nativeSummaryMessage(options) {
|
|
25
|
-
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;
|
|
26
32
|
const message = options.messages.at(-1);
|
|
27
33
|
if (message?.role !== 'user' || message.content?.length !== 1 || message.content[0]?.type !== 'text') return null;
|
|
28
34
|
const text = message.content[0].text;
|
|
@@ -73,7 +79,11 @@ export function installSummaryGuidance(ctx, resolveContext, getSettings = () =>
|
|
|
73
79
|
const value = getSettings();
|
|
74
80
|
const enabled = value.summaryGuidance === undefined ? true : value.summaryGuidance;
|
|
75
81
|
const divisor = value.summaryContextDivisor === undefined ? DEFAULT_SUMMARY_DIVISOR : value.summaryContextDivisor;
|
|
76
|
-
|
|
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;
|
|
77
87
|
} catch { return null; }
|
|
78
88
|
}
|
|
79
89
|
const remove = ctx.on('llm/stream', (options, next) => {
|
|
@@ -93,15 +103,17 @@ export function installSummaryGuidance(ctx, resolveContext, getSettings = () =>
|
|
|
93
103
|
let contextWindow;
|
|
94
104
|
try { contextWindow = await resolveContext(options); }
|
|
95
105
|
catch { /* Metadata/compatibility failure must not break native inference. */ }
|
|
96
|
-
const target = planSummaryTarget(contextWindow, options.maxTokens, sourceTokens, selected.divisor);
|
|
106
|
+
const target = planSummaryTarget(contextWindow, options.maxTokens, sourceTokens, selected.divisor, selected.outputDivisor, selected.sourceDivisor);
|
|
97
107
|
const current = preferences();
|
|
98
|
-
if (!closed && !options.signal?.aborted && current
|
|
99
|
-
const last = { ...native, content: [{ ...native.content[0], text: `${native.content[0].text}\n- ${summaryInstruction(target)}` }] };
|
|
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)}` }] };
|
|
100
110
|
augmented = [...original.slice(0, -1), last];
|
|
111
|
+
augmentedMessages.add(augmented);
|
|
101
112
|
options.messages = augmented;
|
|
102
113
|
}
|
|
103
114
|
yield* next();
|
|
104
115
|
} finally {
|
|
116
|
+
if (augmented) augmentedMessages.delete(augmented);
|
|
105
117
|
if (augmented && options.messages === augmented) options.messages = original;
|
|
106
118
|
}
|
|
107
119
|
})();
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -6,36 +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.1 进一步精简摘要设置说明。可保留默认提示词模板,或使用动态 `{target}` 自定义内容;DSH 原生提示词与输出硬上限保持不变。
|
|
10
10
|
|
|
11
11
|
## 功能
|
|
12
12
|
|
|
13
13
|
### 动态摘要引导
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
精简的“**动态摘要目标**”区域包含启用开关、上下文除数和可编辑的“**摘要补充提示词**”;展开“**计算方式与限制**”可调整摘要输出与原文长度的除数,并查看公式与限制。功能默认开启,关闭后仍保留 DSH 原生摘要与自动压缩。
|
|
16
|
+
|
|
17
|
+
编辑框直接显示实际附加到原生提示词的模板,默认内容如下:
|
|
16
18
|
|
|
17
19
|
```text
|
|
18
|
-
|
|
19
|
-
除数 = summaryContextDivisor(默认 16)
|
|
20
|
-
目标 = floor(min(上下文 / 除数,
|
|
21
|
-
本次摘要实际 maxTokens / 2,
|
|
22
|
-
待替换内容的估算 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.
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
采用默认除数 16、摘要硬上限为 4,096、原文足够长时,32K 上下文对应 **2,048 tokens**,64K 对应 **2,048 tokens**;内容较短时目标会降低。**设置 → dsh-strata-sync** 显示公式与本次预览的目标上限,无法提前得知未来摘要的实际目标。
|
|
28
|
-
|
|
29
|
-
在“动态摘要目标”区域,可切换“**启用摘要提示补充**”,并将“**上下文除数(上下文 ÷ N)**”设为正的安全整数。除数越小,目标可能越大,但仍受摘要输出上限和原文长度约束。例如,32K 上下文、4,096-token 摘要上限且原文足够长时,除数 32、16、8 的目标分别为 1,024、2,048、2,048 tokens。点击“**保存偏好**”后,后续支持的摘要请求会采用新选择。仅保存这两个控件不会同步模型预算或修改 Strata Server 设置。
|
|
23
|
+
模板须保留字面的 `{target}`,每次摘要时会将所有出现位置替换为本次计算的目标。长度最多 2,048 个字符;只做文本替换,不执行代码。“**恢复默认提示词**”会将编辑框恢复为原本的英文模板,修改或恢复后点击“**保存偏好**”才会应用。切换界面语言不会翻译或覆盖已保存的模板。这里只编辑补充内容,不修改 DSH 原生摘要指令。
|
|
30
24
|
|
|
31
25
|
| 插件偏好 | 默认值 | 含义 |
|
|
32
26
|
|---|---:|---|
|
|
33
|
-
| `summaryGuidance` | `true` |
|
|
34
|
-
| `summaryContextDivisor` | `16` |
|
|
27
|
+
| `summaryGuidance` | `true` | 对支持的摘要请求附加补充提示词。 |
|
|
28
|
+
| `summaryContextDivisor` | `16` | 以上下文除以此值。 |
|
|
29
|
+
| `summaryOutputDivisor` | `2` | 以本次摘要输出硬上限除以此值。 |
|
|
30
|
+
| `summarySourceDivisor` | `2` | 以原文估算长度除以此值。 |
|
|
31
|
+
| `summaryPromptTemplate` | 上方英文模板 | 替换 `{target}` 后附加的补充内容。 |
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
三项除数都接受至少为 1 的有限数值,也支持 1.5、2.5 等小数。除数越大,对应限制越小;最终取三项限制的最小值并向下取整,不会改变实际输出硬上限。
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
每次支持的摘要请求都会重新计算:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
上下文 = min(已确认的 Strata 上下文, DSH 已有模型上下文)
|
|
39
|
+
目标 = floor(min(上下文 / summaryContextDivisor,
|
|
40
|
+
本次摘要实际 maxTokens / summaryOutputDivisor,
|
|
41
|
+
待替换内容的估算 tokens / summarySourceDivisor))
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
原文估算涵盖这次要替换的对话片段及其中的旧摘要,不含系统提示词和工具定义。只读查询核对加载模型与上下文,实际输出硬上限来自当前请求。32K 上下文、4,096-token 摘要上限且原文足够长时,上下文除数 32、16、8 分别得到 1,024、2,048、2,048 tokens。UI 预览显示目标上限,不是未来请求的实际目标。
|
|
45
|
+
|
|
46
|
+
保存这些控件只修改插件偏好,不会同步模型预算或修改 Strata Server 设置。DSH 原生提示词、八个章节和请求参数保持不变。默认补充内容只有一句,自定义模板则按输入内容附加。目标是写作指令,**不是新的输出硬上限,也不能保证不截断**;不增加重试流程或额外推理请求。
|
|
47
|
+
|
|
48
|
+
无法确认路由或信息、原生提示词格式未知、附件用量无法估算、模板无效、请求取消、功能关闭或目标低于 256 tokens 时,保留原生请求。移除插件会停止附加内容,不改写已保存的对话历史。
|
|
39
49
|
|
|
40
50
|
### 模型能力自动同步(0.4.0)
|
|
41
51
|
|
|
@@ -74,7 +84,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
74
84
|
|
|
75
85
|
完成后重新打开 DSH。首次安装会自动选中 bundle;已安装但禁用的 bundle 需在插件管理器重新启用。
|
|
76
86
|
|
|
77
|
-
|
|
87
|
+
要从源码安装**包含摘要提示词编辑器的 0.10.1**,请使用 Node.js 22 或更新版本构建,并在最后的安装命令前完成任务、完全退出 DSH Desktop:
|
|
78
88
|
|
|
79
89
|
```sh
|
|
80
90
|
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
@@ -82,7 +92,7 @@ cd dsh-strata-sync
|
|
|
82
92
|
npm ci
|
|
83
93
|
npm test
|
|
84
94
|
npm pack
|
|
85
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.
|
|
95
|
+
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.1.tgz
|
|
86
96
|
```
|
|
87
97
|
|
|
88
98
|
执行最后一行前同样需要完全退出 DSH Desktop,安装完成后重新打开。在其他目录执行时,请使用安装包的绝对路径。
|
|
@@ -95,7 +105,7 @@ dsh plugin --profile desktop add ./dsh-strata-sync-0.9.0.tgz
|
|
|
95
105
|
4. 如需自动同步,勾选“启动 DSH 时自动同步”并保存,下次启动生效。原有 `autoSync: true` 会沿用为启动同步。
|
|
96
106
|
5. 开启新对话,使用更新后的 Agent 预设。
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
“动态摘要目标”控件独立于模型同步。保持“启用摘要提示补充”开启、使用默认模板及 16/2/2 的除数,即沿用先前行为,也可修改后保存偏好。关闭此开关不会禁用 DSH 自身的压缩功能。
|
|
99
109
|
|
|
100
110
|
无需把 API key 复制到此插件;认证问题请在 DSH 模型设置处理。
|
|
101
111
|
|
|
@@ -145,6 +155,10 @@ ConfigEditor 负责单项原子写入与热加载;跨多项设置采用补偿
|
|
|
145
155
|
|
|
146
156
|
## 开发与版本
|
|
147
157
|
|
|
158
|
+
0.10.1 将摘要界面说明缩短为公式与沿用原生摘要的提示,计算及运行机制不变,完整说明保留在 README。
|
|
159
|
+
|
|
160
|
+
0.10.0 加入补充提示词编辑器、动态 `{target}` 与恢复默认功能,精简三语摘要区域,新增高级输出/原文除数与三项除数的小数支持,并沿用备份与版本冲突保护。
|
|
161
|
+
|
|
148
162
|
0.9.0 加入默认开启的摘要提示补充开关及可调整的上下文除数(默认 16),沿用偏好保存与版本冲突保护,并同步三语界面和文档。保存这两个控件不改变原生摘要指令、输出硬上限、其他预算或服务器设置。
|
|
149
163
|
|
|
150
164
|
0.5.0 移除独立语言菜单与产品声明,改为跟随 DSH 语言及启动时单次同步。0.3.0 首次加入三语 UI,0.2.0 将 UI 移入原生设置。
|
package/docs/README.zh-TW.md
CHANGED
|
@@ -6,36 +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.1 進一步精簡摘要設定說明。可保留預設提示詞範本,或使用動態 `{target}` 自訂內容;DSH 原生提示詞與輸出硬上限保持不變。
|
|
10
10
|
|
|
11
11
|
## 功能
|
|
12
12
|
|
|
13
13
|
### 動態摘要引導
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
精簡的「**動態摘要目標**」區塊包含啟用開關、上下文除數和可編輯的「**摘要補充提示詞**」;展開「**計算方式與限制**」可調整摘要輸出與原文長度的除數,並查看公式與限制。功能預設開啟,關閉後仍保留 DSH 原生摘要與自動壓縮。
|
|
16
|
+
|
|
17
|
+
編輯框直接顯示實際附加至原生提示詞的範本,預設內容如下:
|
|
16
18
|
|
|
17
19
|
```text
|
|
18
|
-
|
|
19
|
-
除數 = summaryContextDivisor(預設 16)
|
|
20
|
-
目標 = floor(min(上下文 / 除數,
|
|
21
|
-
本次摘要實際 maxTokens / 2,
|
|
22
|
-
待替換內容的估算 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.
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
採用預設除數 16、摘要硬上限為 4,096、原文足夠長時,32K 上下文對應 **2,048 tokens**,64K 對應 **2,048 tokens**;內容較短時目標會降低。**設定 → dsh-strata-sync** 顯示公式與本次預覽的目標上限,無法提前得知未來摘要的實際目標。
|
|
28
|
-
|
|
29
|
-
在「動態摘要目標」區域,可切換「**啟用摘要提示補充**」,並將「**上下文除數(上下文 ÷ N)**」設為正的安全整數。除數越小,目標可能越大,但仍受摘要輸出上限和原文長度約束。例如,32K 上下文、4,096-token 摘要上限且原文足夠長時,除數 32、16、8 的目標分別為 1,024、2,048、2,048 tokens。按「**儲存偏好**」後,後續支援的摘要請求會採用新選擇。僅儲存這兩個控制項不會同步模型預算或修改 Strata Server 設定。
|
|
23
|
+
範本須保留字面的 `{target}`,每次摘要時會將所有出現位置替換為當次計算的目標。長度最多 2,048 個字元;只做文字替換,不執行程式碼。「**還原預設提示詞**」會將編輯框恢復為原本的英文範本,修改或還原後按「**儲存偏好**」才會套用。切換介面語言不會翻譯或覆寫已儲存的範本。這裡只編輯補充內容,不修改 DSH 原生摘要指令。
|
|
30
24
|
|
|
31
25
|
| 外掛偏好 | 預設值 | 含義 |
|
|
32
26
|
|---|---:|---|
|
|
33
|
-
| `summaryGuidance` | `true` |
|
|
34
|
-
| `summaryContextDivisor` | `16` |
|
|
27
|
+
| `summaryGuidance` | `true` | 對支援的摘要請求附加補充提示詞。 |
|
|
28
|
+
| `summaryContextDivisor` | `16` | 以上下文除以此值。 |
|
|
29
|
+
| `summaryOutputDivisor` | `2` | 以當次摘要輸出硬上限除以此值。 |
|
|
30
|
+
| `summarySourceDivisor` | `2` | 以原文估算長度除以此值。 |
|
|
31
|
+
| `summaryPromptTemplate` | 上方英文範本 | 替換 `{target}` 後附加的補充內容。 |
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
三項除數都接受至少為 1 的有限數值,也支援 1.5、2.5 等小數。除數越大,對應限制越小;最終取三項限制的最小值並向下取整,不會改變實際輸出硬上限。
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
每次支援的摘要請求都會重新計算:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
上下文 = min(已確認的 Strata 上下文, DSH 既有模型上下文)
|
|
39
|
+
目標 = floor(min(上下文 / summaryContextDivisor,
|
|
40
|
+
本次摘要實際 maxTokens / summaryOutputDivisor,
|
|
41
|
+
待替換內容的估算 tokens / summarySourceDivisor))
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
原文估算涵蓋這次要替換的對話片段與其中的舊摘要,不含系統提示詞和工具定義。唯讀查詢核對載入模型與上下文,實際輸出硬上限來自當次請求。32K 上下文、4,096-token 摘要上限且原文足夠長時,上下文除數 32、16、8 分別得到 1,024、2,048、2,048 tokens。UI 預覽顯示目標上限,不是未來請求的實際目標。
|
|
45
|
+
|
|
46
|
+
儲存這些控制項只更改外掛偏好,不會同步模型預算或修改 Strata Server 設定。DSH 原生提示詞、八個章節和請求參數保持不變。預設補充內容只有一句,自訂範本則按輸入內容附加。目標是寫作指令,**不是新的輸出硬上限,也不能保證不截斷**;不增加重試流程或額外推論請求。
|
|
47
|
+
|
|
48
|
+
無法確認路由或資訊、原生提示詞格式未知、附件用量無法估算、範本無效、請求取消、功能關閉或目標低於 256 tokens 時,保留原生請求。移除外掛會停止附加內容,不重寫已儲存的對話歷史。
|
|
39
49
|
|
|
40
50
|
### 模型能力自動同步(0.4.0)
|
|
41
51
|
|
|
@@ -74,7 +84,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
74
84
|
|
|
75
85
|
完成後重新開啟 DSH。首次安裝會自動選取 bundle;已安裝但停用的 bundle 需在外掛管理員重新啟用。
|
|
76
86
|
|
|
77
|
-
|
|
87
|
+
要從原始碼安裝**包含摘要提示詞編輯器的 0.10.1**,請使用 Node.js 22 或更新版本建置,並在最後的安裝命令前完成工作、完全結束 DSH Desktop:
|
|
78
88
|
|
|
79
89
|
```sh
|
|
80
90
|
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
@@ -82,7 +92,7 @@ cd dsh-strata-sync
|
|
|
82
92
|
npm ci
|
|
83
93
|
npm test
|
|
84
94
|
npm pack
|
|
85
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.
|
|
95
|
+
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.1.tgz
|
|
86
96
|
```
|
|
87
97
|
|
|
88
98
|
執行最後一行前同樣需要完全結束 DSH Desktop,安裝完成後重新開啟。在其他目錄執行時,請使用套件的絕對路徑。
|
|
@@ -95,7 +105,7 @@ dsh plugin --profile desktop add ./dsh-strata-sync-0.9.0.tgz
|
|
|
95
105
|
4. 如需自動同步,勾選「啟動 DSH 時自動同步」並儲存,下次啟動生效。原有 `autoSync: true` 會沿用為啟動同步。
|
|
96
106
|
5. 開啟新對話,使用更新後的 Agent 範本。
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
「動態摘要目標」控制項獨立於模型同步。保持「啟用摘要提示補充」開啟、使用預設範本及 16/2/2 的除數,即沿用先前行為,也可修改後儲存偏好。關閉此開關不會停用 DSH 自身的壓縮功能。
|
|
99
109
|
|
|
100
110
|
不需要把 API key 複製到此外掛;認證問題請在 DSH 模型設定處理。
|
|
101
111
|
|
|
@@ -145,6 +155,10 @@ ConfigEditor 負責個別原子寫入與熱載入;跨多項設定採補償回
|
|
|
145
155
|
|
|
146
156
|
## 開發與版本
|
|
147
157
|
|
|
158
|
+
0.10.1 將摘要介面說明縮短為公式與沿用原生摘要的提示,計算及執行機制不變,完整說明保留在 README。
|
|
159
|
+
|
|
160
|
+
0.10.0 加入補充提示詞編輯器、動態 `{target}` 與還原預設功能,精簡三語摘要區塊,新增進階輸出/原文除數與三項除數的小數支援,並沿用備份與版本衝突保護。
|
|
161
|
+
|
|
148
162
|
0.9.0 加入預設開啟的摘要提示補充開關及可調整的上下文除數(預設 16),沿用偏好儲存與版本衝突保護,並同步三語介面和文件。儲存這兩個控制項不改變原生摘要指令、輸出硬上限、其他預算或伺服器設定。
|
|
149
163
|
|
|
150
164
|
0.5.0 移除獨立語言選單與產品聲明,改為跟隨 DSH 語言及啟動時單次同步。0.3.0 首次加入三語 UI,0.2.0 將 UI 移入原生設定。
|
package/docs/VALIDATION.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
Validation date: 2026-10-30 (Asia/Taipei).
|
|
4
4
|
|
|
5
|
+
## Concise summary help 0.10.1
|
|
6
|
+
|
|
7
|
+
- Reduces the expanded summary help to the calculation formula and one native-fallback sentence in all three locales. Full explanations remain in the READMEs. No runtime behavior, settings, defaults or prompt text changes.
|
|
8
|
+
- Verification is limited to the 38 affected UI tests and package checks; inference and native integration tests are not repeated for this wording-only change.
|
|
9
|
+
|
|
10
|
+
## Editable summary prompt and fractional divisors 0.10.0
|
|
11
|
+
|
|
12
|
+
- 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.
|
|
13
|
+
- `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.
|
|
14
|
+
- 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.
|
|
15
|
+
- 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.
|
|
16
|
+
|
|
5
17
|
## Summary guidance controls 0.9.0
|
|
6
18
|
|
|
7
19
|
- 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.
|