dsh-strata-sync 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -145
- package/dist/client.js +26 -31
- package/dist/index.js +5 -6
- package/dist/summary.mjs +49 -10
- package/docs/README.zh-CN.md +72 -114
- package/docs/README.zh-TW.md +72 -114
- package/docs/VALIDATION.md +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,205 +2,125 @@
|
|
|
2
2
|
|
|
3
3
|
**English** · [简体中文](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/README.zh-CN.md) · [繁體中文](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/README.zh-TW.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Connect **DeepSeek Harness (DSH)** to the model loaded in **Strata Server**, with model settings and summary controls in one DSH settings page.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The plugin reads Strata's model information, previews the changes, and updates DSH's custom model and context-compaction budgets. It also adds an editable length instruction to supported summary requests, helping the model keep checkpoints concise.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## What you can do
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **Sync model settings:** context window, response output limit, and confirmed input types and reasoning levels.
|
|
12
|
+
- **Align compaction budgets:** update the matching policies in enabled DSH Agent presets.
|
|
13
|
+
- **Control summary length:** edit the supplemental prompt and adjust three target-length ratios.
|
|
14
|
+
- **Sync on startup:** optionally synchronize once after DSH becomes idle.
|
|
15
|
+
- **Review and recover:** preview differences, back up settings, and view the last synchronization result.
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
Strata Server is read-only to this plugin. Synchronization does not switch or load server models, change server settings, or send test inference requests. Unconfirmed model capabilities keep their existing DSH values.
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## Get started
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
### 1. Prepare the connection
|
|
18
22
|
|
|
19
|
-
|
|
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.
|
|
21
|
-
```
|
|
23
|
+
Load a model in Strata Server. In **DSH → Settings → Models**, configure its OpenAI-compatible provider, API URL and credentials, with an explicit custom model entry.
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
The plugin reuses that connection; you do not need to copy an API key into it.
|
|
24
26
|
|
|
25
|
-
|
|
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.
|
|
27
|
+
### 2. Install the plugin
|
|
34
28
|
|
|
35
|
-
|
|
29
|
+
In DSH's plugin manager, choose **Add plugin** and enter:
|
|
36
30
|
|
|
37
31
|
```text
|
|
38
|
-
|
|
39
|
-
target = floor(min(context / summaryContextDivisor,
|
|
40
|
-
actual summary maxTokens / summaryOutputDivisor,
|
|
41
|
-
selected-content estimated tokens / summarySourceDivisor))
|
|
32
|
+
dsh-strata-sync
|
|
42
33
|
```
|
|
43
34
|
|
|
44
|
-
|
|
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.
|
|
49
|
-
|
|
50
|
-
### Automatic model capabilities (0.4.0)
|
|
51
|
-
|
|
52
|
-
The preview includes **Input types**, **Reasoning levels**, and **Reasoning request mapping**, with the same backup, rollback and idle-only safeguards as token budgets.
|
|
53
|
-
|
|
54
|
-
- Input types follow the server's explicit `architecture.input_modalities`: text, or text plus image. Unknown or unsupported values preserve the existing field.
|
|
55
|
-
- Reasoning requires matching Strata identity, model identity and a reviewed chat-template fingerprint from `/props?model=...`. A model name alone is insufficient.
|
|
56
|
-
- Verified Qwen3.8-Flash-Next templates offer **off / low / medium / xhigh**. Verified DeepSeek-V4.1-Flash templates offer **off / low / high / max**, including the inspected Huihui variants. The template, not quantization, determines eligibility.
|
|
57
|
-
- Native DSH request mapping sends both thinking enablement and the selected effort. Unknown templates or unavailable props preserve existing reasoning settings and show a warning.
|
|
58
|
-
- Provider defaults and current conversation selections are not changed. An incompatible provider default skips reasoning synchronization with a warning. Start a new conversation after syncing.
|
|
59
|
-
|
|
60
|
-
See [capability evidence and exact mappings](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/CAPABILITIES.md). No additional plugin or Strata server changes are required.
|
|
61
|
-
|
|
62
|
-
### Existing synchronization features
|
|
63
|
-
|
|
64
|
-
- Reads `/v1/models` and, when available, `/slots`. Uses the loaded canonical text-model ID and actual engine context; it never guesses context from a model name. Verified aliases refer to the same model; image-generation endpoints are excluded.
|
|
65
|
-
- Updates that DSH model's context and output limit, and its native `compaction-basic` policy inside enabled Agent presets. The preview identifies the affected presets.
|
|
66
|
-
- Shows server-reported values separately from client-derived budgets.
|
|
67
|
-
- Uses **Follow Strata** for output selection by default. **Advanced settings** provides an explicit manual override. Server-reported output defaults, effective output values and their sources are shown separately. Default-model following remains optional.
|
|
68
|
-
- When enabled before startup, synchronizes once per DSH host process/profile after tasks become idle. If a task starts during discovery, the pending sync waits and resumes after it finishes. There are no recurring checks after completion; other failures are shown in the UI and require manual retry or the next start. Enabling it during a session takes effect on the next start; use **Back up and sync** for an immediate sync. No generation requests, model loading or server changes.
|
|
69
|
-
- Previews differences, rechecks the server and the same configuration revision before applying, rejects stale previews, backs up the profile and rolls back completed edits if a later edit fails. Preferences also use revision checks: untouched forms follow fresh values; locally edited forms report conflicts instead of silently overwriting another window.
|
|
70
|
-
- Keeps a read-only last-sync result with model, budgets, output source and backup information. Reports verified and preserved capabilities separately.
|
|
71
|
-
- Uses DSH's existing credential service. Keys never appear in the page or diagnostics; redirects are not followed.
|
|
72
|
-
|
|
73
|
-
**Start a new conversation after syncing model or budget settings.** Existing conversations keep their selected model route and Agent preset revision. Default-model following and updated preset policies apply to new work; this plugin does not rewrite existing conversations or restart DSH. Dynamic summary guidance operates on supported summary requests while the updated plugin is active and does not require changing those saved settings.
|
|
74
|
-
|
|
75
|
-
## Compatibility
|
|
76
|
-
|
|
77
|
-
Developed against **DSH desktop 0.2.1-rc.3** and Strata's OpenAI-compatible model/slot metadata. Requires the standard desktop services `configEditor`, `connection`, `agents`, `credentials`, `llm-pi-ai`, and enabled Agent presets containing `compaction-basic` (or an active legacy global compaction plugin). Only API-key or unauthenticated `openai-completions` providers are supported. Configure the provider in DSH Models first.
|
|
78
|
-
|
|
79
|
-
Configure an explicit, nonempty custom `models` list for the Strata provider. Catalog-only routes and nonempty `modelOverrides` routes are rejected during preview, before any backup or write; the plugin does not convert catalog providers or combine incompatible model configuration formats.
|
|
80
|
-
|
|
81
|
-
Unknown context, no loaded text model, ambiguous multiple loaded text models, or conflicting slot capacities are refused. Aliases are resolved to their loaded canonical model, and explicit non-text output endpoints are excluded. Invalid alias chains are refused. This version's UI follows one loaded text model; it does not select among multiple simultaneously loaded text models.
|
|
82
|
-
|
|
83
|
-
The startup idle-wait scheduler includes a narrow DSH 0.2.1-rc.3 compatibility adapter for HMR's `executing.exit` context, following the host's own watcher pattern. This prevents timers created during a settings reload from retaining the completed HMR transaction. All writes still go through ConfigEditor and its normal transaction queue. Revalidate this adapter after upgrading DSH.
|
|
84
|
-
|
|
85
|
-
## Install
|
|
86
|
-
|
|
87
|
-
Package name: `dsh-strata-sync` (formerly `@ethan741205/dsh-strata-sync`). Remove the old scoped plugin before installing this package to avoid loading two copies; retain its settings when migrating.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
For the existing npm release, finish active tasks and fully quit DSH Desktop, then install with the official DSH CLI:
|
|
35
|
+
Or, after finishing active tasks and fully quitting DSH Desktop, use the official CLI:
|
|
91
36
|
|
|
92
37
|
```sh
|
|
93
38
|
dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npmjs.org/
|
|
94
39
|
```
|
|
95
40
|
|
|
96
|
-
Reopen DSH
|
|
97
|
-
|
|
98
|
-
To install **0.10.2 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:
|
|
99
|
-
|
|
100
|
-
```sh
|
|
101
|
-
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
102
|
-
cd dsh-strata-sync
|
|
103
|
-
npm ci
|
|
104
|
-
npm test
|
|
105
|
-
npm pack
|
|
106
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.2.tgz
|
|
107
|
-
```
|
|
108
|
-
|
|
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.
|
|
41
|
+
Reopen DSH if needed to load the settings page. If the plugin is disabled, enable it in the plugin manager.
|
|
110
42
|
|
|
111
|
-
|
|
43
|
+
### 3. Preview and synchronize
|
|
112
44
|
|
|
113
|
-
|
|
114
|
-
2. Click **Check differences** to read the loaded model and preview the proposed settings.
|
|
115
|
-
3. Click **Back up and sync** while DSH is idle.
|
|
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.
|
|
117
|
-
5. Start a new conversation to use the new Agent preset revision.
|
|
45
|
+
Open **Settings → dsh-strata-sync**:
|
|
118
46
|
|
|
119
|
-
|
|
47
|
+
1. Select your Strata provider and click **Save preferences**.
|
|
48
|
+
2. Click **Check differences** to inspect the loaded model and proposed changes.
|
|
49
|
+
3. While DSH is idle, click **Back up and sync**.
|
|
50
|
+
4. **Start a new conversation** to use the updated model and Agent preset settings.
|
|
120
51
|
|
|
121
|
-
|
|
52
|
+
Existing conversations keep their selected model route and preset revision. To make future setup automatic, enable **Automatically sync when DSH starts** and save. This option is off by default and takes effect on the next start; it waits for idle and does not poll continuously.
|
|
122
53
|
|
|
123
|
-
##
|
|
54
|
+
## Model and output settings
|
|
124
55
|
|
|
125
|
-
|
|
56
|
+
| Setting | How it is chosen |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Model and context | Strata's loaded text model and verified context capacity. |
|
|
59
|
+
| Response output limit | Manual override, if set; otherwise the verified Strata output default. If unavailable or unlimited, use 30% of context, capped at 16,384 tokens. |
|
|
60
|
+
| Input types | Confirmed server capabilities, such as text or text plus image. |
|
|
61
|
+
| Reasoning levels | Verified model-template support; unknown templates preserve existing settings. |
|
|
62
|
+
| Default model | Follows the loaded Strata model when **Follow the loaded Strata model as the default** is enabled. |
|
|
126
63
|
|
|
127
|
-
|
|
64
|
+
Keep **Follow Strata output limit** enabled for automatic selection. Turn it off to set a manual override under **Advanced settings**. The preview shows the server default, effective value and source separately.
|
|
128
65
|
|
|
129
|
-
|
|
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.
|
|
66
|
+
When synchronizing, the plugin sets a 4,096-token summary output cap and 4,096-token compaction headroom. The effective compaction trigger is the smaller of **80% of context** and **context − response output − 4,096**. Recent-content retention is **(context − response output) × 16%**, rounded down. These are client-side budgets calculated by the plugin, not settings supplied by Strata.
|
|
132
67
|
|
|
133
|
-
|
|
68
|
+
For example, with automatic output calculation, a 32K context uses a 9,830-token response allowance and an 18,842-token compaction trigger. It does **not** necessarily compact at 80%.
|
|
134
69
|
|
|
135
|
-
|
|
136
|
-
- Saves both controls through the existing preferences and revision checks, with matching English, Simplified Chinese and Traditional Chinese UI and documentation.
|
|
137
|
-
- Keeps native summary instructions, hard output limits, other budgets and server settings unchanged when saving these controls.
|
|
70
|
+
## Summary prompt and target length
|
|
138
71
|
|
|
139
|
-
|
|
72
|
+
**Dynamic summary target** is off by default. Enable it to supplement DSH's native summary instructions. When off, DSH uses its native summary and compaction behavior.
|
|
140
73
|
|
|
141
|
-
|
|
142
|
-
- Performs one optional startup sync per host process/profile, waiting for idle. Hot reloads and reopening Settings do not repeat it.
|
|
143
|
-
- Preserves the existing opt-in `autoSync` preference; no recurring server polling.
|
|
74
|
+
The editable **Supplemental summary prompt** starts with:
|
|
144
75
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
- Includes all three README editions in the package.
|
|
149
|
-
- Keeps the synchronization backend and budgets unchanged.
|
|
76
|
+
```text
|
|
77
|
+
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.
|
|
78
|
+
```
|
|
150
79
|
|
|
151
|
-
|
|
80
|
+
Keep `{target}` in your text—it is replaced with the calculated token target before each supported summary. The template can contain up to 2,048 characters. Use **Restore default prompt** to reset it, then **Save preferences** to apply your choice.
|
|
152
81
|
|
|
153
|
-
|
|
154
|
-
- Uses English throughout the interface and repository documentation.
|
|
155
|
-
- Preserves the synchronization policy, optional idle polling, backups and existing-conversation behavior described below.
|
|
82
|
+
Two divisors control the target (both default to **2**, or **50%**):
|
|
156
83
|
|
|
157
|
-
|
|
84
|
+
| Divisor | Default | Limits the target to |
|
|
85
|
+
|---|---:|---|
|
|
86
|
+
| Output budget (O) | 2 | Estimated effective summary output budget ÷ O |
|
|
87
|
+
| Source length (S) | 2 | Estimated content being summarized ÷ S |
|
|
158
88
|
|
|
159
|
-
|
|
89
|
+
The target is the smaller result, rounded down. All divisors accept decimals of at least 1. There is no context divisor; a legacy `summaryContextDivisor` value is ignored. Existing output/source divisors and explicit enable choices are preserved. New or unspecified guidance remains **off**.
|
|
160
90
|
|
|
161
|
-
|
|
162
|
-
ordinary output = explicit manual override, else verified positive server n_predict
|
|
163
|
-
fallback output = min(16384, floor(context × 0.30))
|
|
164
|
-
compaction headroom = 4096
|
|
165
|
-
summary maxTokens = 4096
|
|
166
|
-
thresholdRatio = 0.8
|
|
167
|
-
retainRatio = 0.16
|
|
168
|
-
effective trigger = floor(min(context × 0.8, context − ordinary output − 4096))
|
|
169
|
-
recent retention = floor((context − ordinary output) × 0.16)
|
|
170
|
-
```
|
|
91
|
+
The effective output budget is an **estimate**, not the raw requested `maxTokens` or a server-confirmed cap. It is the smaller of the request's summary cap and estimated remaining context. The latter uses the smaller verified server/client window, subtracts the full prompt (including system text, tool schemas and the supplement), and allows for the supported pi-ai adapter's 4,096-token safety reserve. Text is estimated at 3.5 characters/token with extra framing. The separate source estimate uses DSH's four-character heuristic and excludes the system prompt, tools and summary instruction. Neither estimate is an exact tokenizer count.
|
|
171
92
|
|
|
172
|
-
|
|
93
|
+
For example, a 4,096-token effective output budget with enough source content gives a **2,048-token target** in either 32K or 64K context. A 2,000-token source instead gives a **1,000-token target**. Less remaining context can reduce the target further. The UI previews an upper bound from the proposed summary cap, before request-specific costs are known.
|
|
173
94
|
|
|
174
|
-
|
|
95
|
+
This is a writing instruction, **not a hard output limit or a guarantee against truncation**. Reasoning may consume the same output budget; the plugin does not change reasoning, `maxTokens`, `fit_max_tokens` or compaction timing. The server's actual tokenizer, later middleware, or a different adapter version may impose a lower limit.
|
|
175
96
|
|
|
176
|
-
|
|
177
|
-
|---|---:|---:|---:|---:|---:|
|
|
178
|
-
| 32,768 | 9,830 | 4,096 | 4,096 | 18,842 (57.50%) | 3,670 |
|
|
179
|
-
| 65,536 | 16,384 | 4,096 | 4,096 | 45,056 (68.75%) | 7,864 |
|
|
97
|
+
Saving summary preferences does not change model budgets. Native prompt content is preserved, and no extra inference or retry loop is added. If the request cannot be verified or safely estimated, or the target is below 256 tokens, the original summary request proceeds unchanged.
|
|
180
98
|
|
|
181
|
-
|
|
99
|
+
## Backups and compatibility
|
|
182
100
|
|
|
183
|
-
|
|
101
|
+
Settings writes create a backup of `cordis.patch.yml` under the profile's `backups/strata-sync/` directory. Synchronization checks for concurrent edits and attempts to roll back completed changes if a later step fails. Backups may contain private configuration; keep them local.
|
|
184
102
|
|
|
185
|
-
|
|
103
|
+
Removing the plugin does not undo previously synchronized settings. To restore a backup, fully quit DSH first.
|
|
186
104
|
|
|
187
|
-
|
|
105
|
+
Tested with **DSH Desktop 0.2.1-rc.3**. Use an API-key or unauthenticated OpenAI-compatible provider with an explicit custom model list and an enabled Agent preset containing `compaction-basic`. Contexts below 8,192 tokens, catalog-only providers, nonempty `modelOverrides`, and ambiguous loaded-model metadata are unsupported.
|
|
188
106
|
|
|
189
|
-
|
|
107
|
+
See [verified capabilities and reasoning mappings](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/CAPABILITIES.md) and [validation notes](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/VALIDATION.md) for technical details and test coverage.
|
|
190
108
|
|
|
191
109
|
## Development
|
|
192
110
|
|
|
193
|
-
|
|
111
|
+
Requires Node.js 22 or newer.
|
|
194
112
|
|
|
195
113
|
```sh
|
|
114
|
+
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
115
|
+
cd dsh-strata-sync
|
|
196
116
|
npm ci
|
|
197
117
|
npm test
|
|
198
118
|
npm run build
|
|
199
|
-
npm pack
|
|
119
|
+
npm pack
|
|
200
120
|
```
|
|
201
121
|
|
|
202
|
-
|
|
122
|
+
To install your build, fully quit DSH and run `dsh plugin --profile desktop add <path-to-generated.tgz>`.
|
|
203
123
|
|
|
204
|
-
|
|
124
|
+
Source: `src/plugin.mjs` (host integration), `src/core.mjs` (discovery and budgets), `src/summary.mjs` (summary guidance), and `src/client.js` (settings UI).
|
|
205
125
|
|
|
206
|
-
MIT
|
|
126
|
+
[npm](https://www.npmjs.com/package/dsh-strata-sync) · [Report an issue](https://github.com/ethan741205/dsh-strata-sync/issues) · [MIT license](https://github.com/ethan741205/dsh-strata-sync/blob/main/LICENSE)
|
package/dist/client.js
CHANGED
|
@@ -115,9 +115,9 @@ window.__ModuleLoader__.load({
|
|
|
115
115
|
"zh-Hant": "啟用後,在每次支援的 Strata 摘要請求前,計算長度目標,並在 DSH 原生摘要提示詞後補充一句。",
|
|
116
116
|
"zh-Hans": "启用后,在每次支持的 Strata 摘要请求前,计算长度目标,并在 DSH 原生摘要提示词后补充一句。"
|
|
117
117
|
},
|
|
118
|
-
"Target = floor(min(
|
|
119
|
-
"zh-Hant": "目標 = floor(min(
|
|
120
|
-
"zh-Hans": "目标 = floor(min(
|
|
118
|
+
"Target = floor(min(estimated effective output budget / O, selected content estimate / S)). Default divisors: 2 and 2 (50% each).": {
|
|
119
|
+
"zh-Hant": "目標 = floor(min(估算有效輸出預算 / O, 待壓縮內容估算 / S))。兩個除數預設均為 2(各取 50%)。",
|
|
120
|
+
"zh-Hans": "目标 = floor(min(估算有效输出预算 / O, 待压缩内容估算 / S))。两个除数默认均为 2(各取 50%)。"
|
|
121
121
|
},
|
|
122
122
|
"When guidance cannot be applied, DSH keeps its native summary behavior.": {
|
|
123
123
|
"zh-Hant": "無法套用時,沿用 DSH 原生摘要。",
|
|
@@ -127,25 +127,21 @@ window.__ModuleLoader__.load({
|
|
|
127
127
|
"zh-Hant": "啟用摘要提示補充",
|
|
128
128
|
"zh-Hans": "启用摘要提示补充"
|
|
129
129
|
},
|
|
130
|
-
"
|
|
131
|
-
"zh-Hant": "
|
|
132
|
-
"zh-Hans": "
|
|
130
|
+
"Off by default. Enable it to supplement DSH's native summary and automatic compaction behavior.": {
|
|
131
|
+
"zh-Hant": "預設關閉。啟用後補充 DSH 原生摘要提示詞。",
|
|
132
|
+
"zh-Hans": "默认关闭。启用后补充 DSH 原生摘要提示词。"
|
|
133
133
|
},
|
|
134
|
-
"
|
|
135
|
-
"zh-Hant": "
|
|
136
|
-
"zh-Hans": "
|
|
137
|
-
},
|
|
138
|
-
"Summary output divisor (output limit ÷ O)": {
|
|
139
|
-
"zh-Hant": "摘要輸出除數(輸出上限 ÷ O)",
|
|
140
|
-
"zh-Hans": "摘要输出除数(输出上限 ÷ O)"
|
|
134
|
+
"Output budget divisor (estimated budget ÷ O)": {
|
|
135
|
+
"zh-Hant": "摘要輸出除數(估算可用預算 ÷ O)",
|
|
136
|
+
"zh-Hans": "摘要输出除数(估算可用预算 ÷ O)"
|
|
141
137
|
},
|
|
142
138
|
"Source length divisor (source estimate ÷ S)": {
|
|
143
139
|
"zh-Hant": "原文長度除數(原文估算 ÷ S)",
|
|
144
140
|
"zh-Hans": "原文长度除数(原文估算 ÷ S)"
|
|
145
141
|
},
|
|
146
|
-
"Defaults:
|
|
147
|
-
"zh-Hant": "預設
|
|
148
|
-
"zh-Hans": "默认
|
|
142
|
+
"Defaults: O = 2, S = 2 (50% each). Smaller divisors allow longer targets; the smaller of the two bounds wins. Decimals are supported.": {
|
|
143
|
+
"zh-Hant": "預設 O = 2、S = 2(各取 50%)。除數越小,目標可越長;最後取兩項限制的較小值。支援小數。",
|
|
144
|
+
"zh-Hans": "默认 O = 2、S = 2(各取 50%)。除数越小,目标可越长;最后取两项限制的较小值。支持小数。"
|
|
149
145
|
},
|
|
150
146
|
"Enter a finite divisor of at least 1; decimals are allowed.": {
|
|
151
147
|
"zh-Hant": "請輸入大於或等於 1 的有限除數,可使用小數。",
|
|
@@ -163,9 +159,9 @@ window.__ModuleLoader__.load({
|
|
|
163
159
|
"zh-Hant": "儲存偏好後,這些控制項會套用至後續摘要請求;其他模型與壓縮設定保持不變。",
|
|
164
160
|
"zh-Hans": "保存偏好后,这些控制项将应用于后续摘要请求;其他模型与压缩设置保持不变。"
|
|
165
161
|
},
|
|
166
|
-
"
|
|
167
|
-
"zh-Hant": "
|
|
168
|
-
"zh-Hans": "
|
|
162
|
+
"The preview uses the proposed summary cap. Actual targets also account for the estimated remaining context and source length; they may be lower.": {
|
|
163
|
+
"zh-Hant": "預覽採用提議的摘要上限。實際目標還會考慮估算的上下文剩餘空間與原文長度,可能更低。",
|
|
164
|
+
"zh-Hans": "预览采用提议的摘要上限。实际目标还会考虑估算的上下文剩余空间与原文长度,可能更低。"
|
|
169
165
|
},
|
|
170
166
|
"The original prompt, output cap and other settings stay unchanged. This is a writing target, not a guaranteed length or an optimal value.": {
|
|
171
167
|
"zh-Hant": "保留原生提示詞、輸出硬上限與其他設定。這是寫作目標,不保證實際長度,也不代表最佳值。",
|
|
@@ -431,20 +427,20 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
431
427
|
};
|
|
432
428
|
const diagnostic = (message) => translations[message] ? t(message) : language === 'en' ? message : t('Server diagnostic: ') + message;
|
|
433
429
|
const [state,setState] = React.useState(null), [preview,setPreview] = React.useState(null), [result,setResult] = React.useState(null);
|
|
434
|
-
const [form,setForm] = React.useState({providerId:'',output:'',manual:false,auto:false,follow:true,summaryGuidance:
|
|
430
|
+
const [form,setForm] = React.useState({providerId:'',output:'',manual:false,auto:false,follow:true,summaryGuidance:false,summaryOutputDivisor:'2',summarySourceDivisor:'2',summaryPrompt:''});
|
|
435
431
|
const [pending,setPending] = React.useState(false), [error,setError] = React.useState(''), [loadError,setLoadError] = React.useState('');
|
|
436
432
|
const [notice,setNotice] = React.useState(''), [conflict,setConflict] = React.useState(false);
|
|
437
433
|
const formRef=React.useRef(form), baseline=React.useRef(null), requestSeq=React.useRef(0), alive=React.useRef(true);
|
|
438
434
|
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,
|
|
440
|
-
const preferences = (s) => ({providerId:s.providerId || '',outputTokens:s.outputTokens ?? null,autoSync:!!s.autoSync,followLoadedModel:s.followLoadedModel !== false,summaryGuidance:s.summaryGuidance
|
|
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,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===true,summaryOutputDivisor:s.summaryOutputDivisor??2,summarySourceDivisor:s.summarySourceDivisor??2,summaryPromptTemplate:s.summaryPromptTemplate??s.defaultSummaryPromptTemplate??''});
|
|
441
437
|
const equal = (a,b) => Object.keys(a).every(key=>Object.is(a[key],b[key]));
|
|
442
438
|
const acceptStatus = React.useCallback((s,force=false) => {
|
|
443
439
|
if (!alive.current) return;
|
|
444
440
|
const next=preferences(s), old=baseline.current;
|
|
445
441
|
const untouched=!old || equal(values(formRef.current),old.values);
|
|
446
442
|
if (force || untouched) {
|
|
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,
|
|
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,summaryOutputDivisor:String(next.summaryOutputDivisor),summarySourceDivisor:String(next.summarySourceDivisor),summaryPrompt:next.summaryPromptTemplate};
|
|
448
444
|
formRef.current=nextForm; setForm(nextForm); setConflict(false);
|
|
449
445
|
baseline.current={values:next,revision:s.settingsRevision};
|
|
450
446
|
} else if (old.revision!==s.settingsRevision || !equal(old.values,next)) {
|
|
@@ -477,14 +473,14 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
477
473
|
} finally { if(alive.current)setPending(false); }
|
|
478
474
|
}
|
|
479
475
|
const draft=values(form), isDivisor=value=>Number.isFinite(value)&&value>=1&&value<=Number.MAX_SAFE_INTEGER;
|
|
480
|
-
const validDivisor=[draft.
|
|
476
|
+
const validDivisor=[draft.summaryOutputDivisor,draft.summarySourceDivisor].every(isDivisor);
|
|
481
477
|
const validPrompt=typeof draft.summaryPromptTemplate==='string'&&draft.summaryPromptTemplate.length>0&&draft.summaryPromptTemplate.length<=2048&&draft.summaryPromptTemplate.includes('{target}');
|
|
482
478
|
const valid=validDivisor&&validPrompt&&(draft.outputTokens===null || Number.isSafeInteger(draft.outputTokens)&&draft.outputTokens>0);
|
|
483
479
|
const dirty=!!baseline.current&&!equal(draft,baseline.current.values);
|
|
484
480
|
const displayedResult=!result || state?.lastApplied?.at>result.at ? state?.lastApplied : result;
|
|
485
481
|
const activeBudget=preview?.budget;
|
|
486
482
|
const summaryTargetCeiling=form.summaryGuidance&&validDivisor&&Number.isSafeInteger(activeBudget?.contextWindow)&&activeBudget.contextWindow>0&&Number.isSafeInteger(activeBudget?.summaryMaxTokens)&&activeBudget.summaryMaxTokens>0
|
|
487
|
-
? Math.floor(
|
|
483
|
+
? Math.floor(activeBudget.summaryMaxTokens/draft.summaryOutputDivisor) : null;
|
|
488
484
|
const outputSource=(budget)=>t(({server:'Strata Server default',manual:'Manual override',calculated:'Automatic calculation'})[budget?.outputSource]||'Automatic calculation');
|
|
489
485
|
const preserved=(view)=>{
|
|
490
486
|
const status=view?.capabilityStatus;
|
|
@@ -529,7 +525,9 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
529
525
|
h('div',{className:'ss-card','data-testid':'summary-target'},
|
|
530
526
|
h('strong',null,t('Dynamic summary target')),
|
|
531
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')),
|
|
532
|
-
h('
|
|
528
|
+
h('div',{className:'ss-grid'},
|
|
529
|
+
h('label',null,t('Output budget divisor (estimated budget ÷ O)'),h('input',{type:'number','data-testid':'summary-output-divisor','aria-label':t('Output budget divisor (estimated budget ÷ 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})),
|
|
530
|
+
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}))),
|
|
533
531
|
state&&!validDivisor&&h('p',{className:'ss-status ss-error',role:'alert'},t('Enter a finite divisor of at least 1; decimals are allowed.')),
|
|
534
532
|
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
533
|
state&&!validPrompt&&h('p',{className:'ss-status ss-error',role:'alert'},t('Use 1–2,048 characters and include {target}.')),
|
|
@@ -540,11 +538,8 @@ REASONING_DEFAULT_CONFLICT: 'The provider default reasoning level is not support
|
|
|
540
538
|
? h('p',{'data-testid':'summary-target-ceiling'},t('Maximum target for this preview: '),format(summaryTargetCeiling),' tokens')
|
|
541
539
|
: 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.'))),
|
|
542
540
|
h('details',{className:'ss-details','data-testid':'summary-details'},h('summary',null,t('Calculation and limits')),
|
|
543
|
-
h('
|
|
544
|
-
|
|
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.')))),
|
|
541
|
+
h('p',{className:'ss-muted'},t('Target = floor(min(estimated effective output budget / O, selected content estimate / S)). Default divisors: 2 and 2 (50% each).')),
|
|
542
|
+
h('p',{className:'ss-muted'},t('The preview uses the proposed summary cap. Actual targets also account for the estimated remaining context and source length; they may be lower.'),' ',t('When guidance cannot be applied, DSH keeps its native summary behavior.')))),
|
|
548
543
|
h('div',{className:'ss-actions'},
|
|
549
544
|
h('button',{disabled:pending||!state||!form.providerId||!valid||!dirty||conflict,onClick:()=>action(async()=>{
|
|
550
545
|
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 {
|
|
6
|
+
import { 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,8 +11,7 @@ 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(
|
|
15
|
-
summaryContextDivisor: z.number().min(1).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_SUMMARY_DIVISOR),
|
|
14
|
+
summaryGuidance: z.boolean().default(false),
|
|
16
15
|
summaryOutputDivisor: z.number().min(1).max(Number.MAX_SAFE_INTEGER).default(2),
|
|
17
16
|
summarySourceDivisor: z.number().min(1).max(Number.MAX_SAFE_INTEGER).default(2),
|
|
18
17
|
summaryPromptTemplate: z.string().default(DEFAULT_SUMMARY_TEMPLATE),
|
|
@@ -145,7 +144,7 @@ export function apply(ctx, initialConfig) {
|
|
|
145
144
|
function publicSettings(value = settings) {
|
|
146
145
|
return { providerId: value.providerId ?? '', autoSync: value.autoSync ?? false,
|
|
147
146
|
followLoadedModel: value.followLoadedModel ?? true, outputTokens: value.outputTokens ?? null,
|
|
148
|
-
summaryGuidance: value.summaryGuidance ??
|
|
147
|
+
summaryGuidance: value.summaryGuidance ?? false,
|
|
149
148
|
summaryOutputDivisor: value.summaryOutputDivisor ?? 2, summarySourceDivisor: value.summarySourceDivisor ?? 2,
|
|
150
149
|
summaryPromptTemplate: value.summaryPromptTemplate ?? DEFAULT_SUMMARY_TEMPLATE };
|
|
151
150
|
}
|
|
@@ -389,7 +388,7 @@ export function apply(ctx, initialConfig) {
|
|
|
389
388
|
}
|
|
390
389
|
async function configure(request) {
|
|
391
390
|
ensureOpen();
|
|
392
|
-
payload(request, ['providerId', 'autoSync', 'followLoadedModel', 'outputTokens', 'summaryGuidance', '
|
|
391
|
+
payload(request, ['providerId', 'autoSync', 'followLoadedModel', 'outputTokens', 'summaryGuidance', 'summaryOutputDivisor', 'summarySourceDivisor', 'summaryPromptTemplate', 'expectedRevision']);
|
|
393
392
|
refreshSettings();
|
|
394
393
|
if (typeof request.expectedRevision !== 'string' || request.expectedRevision !== hash(publicSettings())) {
|
|
395
394
|
refuse('stale-settings', 'Sync preferences changed. Reload the latest preferences before saving.');
|
|
@@ -405,7 +404,7 @@ export function apply(ctx, initialConfig) {
|
|
|
405
404
|
if (typeof request[key] !== 'boolean') refuse('invalid-request', `${key} must be a boolean.`);
|
|
406
405
|
next[key] = request[key];
|
|
407
406
|
}
|
|
408
|
-
for (const key of ['
|
|
407
|
+
for (const key of ['summaryOutputDivisor', 'summarySourceDivisor']) {
|
|
409
408
|
if (!own(request, key)) continue;
|
|
410
409
|
if (!validSummaryDivisor(request[key])) refuse('invalid-budget', 'Summary divisors must be finite numbers from 1 to Number.MAX_SAFE_INTEGER.');
|
|
411
410
|
next[key] = request[key];
|
package/dist/summary.mjs
CHANGED
|
@@ -12,11 +12,9 @@ const augmentedMessages = globalThis[Symbol.for('dsh-strata-sync/summary-augment
|
|
|
12
12
|
// Eight mandatory headings need enough space for a meaningful checkpoint. Do
|
|
13
13
|
// not round a tiny target UP; leave native behavior intact instead.
|
|
14
14
|
export const MIN_SUMMARY_TARGET = 256;
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
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
|
+
export function planSummaryTarget(effectiveOutputTokens, sourceTokens, outputDivisor = 2, sourceDivisor = 2) {
|
|
16
|
+
if (![effectiveOutputTokens, sourceTokens].every(positive) || ![outputDivisor, sourceDivisor].every(validSummaryDivisor)) return null;
|
|
17
|
+
const target = Math.floor(Math.min(effectiveOutputTokens / outputDivisor, sourceTokens / sourceDivisor));
|
|
20
18
|
return target >= MIN_SUMMARY_TARGET ? target : null;
|
|
21
19
|
}
|
|
22
20
|
|
|
@@ -68,6 +66,47 @@ export function estimateSummarySource(messages) {
|
|
|
68
66
|
return positive(tokens) ? tokens : null;
|
|
69
67
|
}
|
|
70
68
|
|
|
69
|
+
/** Conservative text-only estimate of the output room before provider dispatch.
|
|
70
|
+
* The supported DSH adapter uses pi-ai 1.1.0: 3.5 chars/token and
|
|
71
|
+
* reserves 4096 tokens before clamping maxTokens. Replayed assistant usage is
|
|
72
|
+
* zeroed by DSH. Include system text, tool schemas and framing as well, even
|
|
73
|
+
* where that adapter's heuristic omits them. This is NOT a tokenizer count or
|
|
74
|
+
* the server's final cap; unknown content leaves the native prompt untouched.
|
|
75
|
+
*/
|
|
76
|
+
export function estimateEffectiveSummaryBudget(options, contextWindow, template = DEFAULT_SUMMARY_TEMPLATE) {
|
|
77
|
+
if (!positive(contextWindow) || !positive(options?.maxTokens) || !validSummaryTemplate(template) || !Array.isArray(options.messages)) return null;
|
|
78
|
+
const price = text => Math.ceil(text.length / 3.5) + 4;
|
|
79
|
+
let input = 0;
|
|
80
|
+
try {
|
|
81
|
+
if (options.system !== undefined) {
|
|
82
|
+
if (typeof options.system !== 'string') return null;
|
|
83
|
+
input += price(options.system);
|
|
84
|
+
}
|
|
85
|
+
if (options.tools !== undefined) {
|
|
86
|
+
if (!Array.isArray(options.tools)) return null;
|
|
87
|
+
input += price(JSON.stringify(options.tools));
|
|
88
|
+
}
|
|
89
|
+
for (const message of options.messages) {
|
|
90
|
+
if (!['system', 'user', 'assistant', 'tool'].includes(message?.role) || !Array.isArray(message.content)) return null;
|
|
91
|
+
input += 4;
|
|
92
|
+
if (message.role === 'tool' && !message.content.some(block => block.type === 'text' && block.text?.length)) input += price('(no output)');
|
|
93
|
+
for (const block of message.content) {
|
|
94
|
+
if (['text', 'reasoning'].includes(block?.type) && typeof block.text === 'string') input += price(block.text);
|
|
95
|
+
else if (block?.type === 'tool-call' && typeof block.name === 'string' && typeof block.arguments === 'string') {
|
|
96
|
+
// JSON normalization can expand compact numeric literals (e.g. 1e9).
|
|
97
|
+
const normalized = JSON.stringify(JSON.parse(block.arguments));
|
|
98
|
+
input += price(block.name) + Math.max(price(block.arguments), price(normalized));
|
|
99
|
+
} else return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Reserve the longest possible rendered supplement once, avoiding a
|
|
103
|
+
// self-referential target calculation. The target never exceeds maxTokens.
|
|
104
|
+
input += price('\n- ' + summaryInstruction(options.maxTokens, template));
|
|
105
|
+
} catch { return null; }
|
|
106
|
+
if (!Number.isSafeInteger(input)) return null;
|
|
107
|
+
return Math.max(0, Math.min(options.maxTokens, contextWindow - input - 4096));
|
|
108
|
+
}
|
|
109
|
+
|
|
71
110
|
/** The native waterfall's next() closes over options, so replace only its
|
|
72
111
|
* messages property for the lifetime of this stream; never mutate frozen
|
|
73
112
|
* messages or recursively dispatch a second LLM request.
|
|
@@ -77,13 +116,12 @@ export function installSummaryGuidance(ctx, resolveContext, getSettings = () =>
|
|
|
77
116
|
function preferences() {
|
|
78
117
|
try {
|
|
79
118
|
const value = getSettings();
|
|
80
|
-
const enabled = value.summaryGuidance === undefined ?
|
|
81
|
-
const divisor = value.summaryContextDivisor === undefined ? DEFAULT_SUMMARY_DIVISOR : value.summaryContextDivisor;
|
|
119
|
+
const enabled = value.summaryGuidance === undefined ? false : value.summaryGuidance;
|
|
82
120
|
const outputDivisor = value.summaryOutputDivisor === undefined ? 2 : value.summaryOutputDivisor;
|
|
83
121
|
const sourceDivisor = value.summarySourceDivisor === undefined ? 2 : value.summarySourceDivisor;
|
|
84
122
|
const template = value.summaryPromptTemplate === undefined ? DEFAULT_SUMMARY_TEMPLATE : value.summaryPromptTemplate;
|
|
85
|
-
return enabled === true && [
|
|
86
|
-
? {
|
|
123
|
+
return enabled === true && [outputDivisor, sourceDivisor].every(validSummaryDivisor) && validSummaryTemplate(template)
|
|
124
|
+
? { outputDivisor, sourceDivisor, template } : null;
|
|
87
125
|
} catch { return null; }
|
|
88
126
|
}
|
|
89
127
|
const remove = ctx.on('llm/stream', (options, next) => {
|
|
@@ -103,7 +141,8 @@ export function installSummaryGuidance(ctx, resolveContext, getSettings = () =>
|
|
|
103
141
|
let contextWindow;
|
|
104
142
|
try { contextWindow = await resolveContext(options); }
|
|
105
143
|
catch { /* Metadata/compatibility failure must not break native inference. */ }
|
|
106
|
-
const
|
|
144
|
+
const effectiveOutput = estimateEffectiveSummaryBudget(options, contextWindow, selected.template);
|
|
145
|
+
const target = planSummaryTarget(effectiveOutput, sourceTokens, selected.outputDivisor, selected.sourceDivisor);
|
|
107
146
|
const current = preferences();
|
|
108
147
|
if (!closed && !options.signal?.aborted && current && Object.keys(selected).every(key => selected[key] === current[key]) && target !== null && options.messages === original) {
|
|
109
148
|
const last = { ...native, content: [{ ...native.content[0], text: `${native.content[0].text}\n- ${summaryInstruction(target, selected.template)}` }] };
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -2,167 +2,125 @@
|
|
|
2
2
|
|
|
3
3
|
[English](https://github.com/ethan741205/dsh-strata-sync/blob/main/README.md) · **简体中文** · [繁體中文](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/README.zh-TW.md)
|
|
4
4
|
|
|
5
|
-
让 **DeepSeek Harness(DSH)**
|
|
5
|
+
让 **DeepSeek Harness(DSH)** 连接 **Strata Server** 当前加载的模型,在同一个 DSH 设置页管理模型配置与摘要控制。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
插件读取 Strata 的模型信息,预览差异,再更新 DSH 自定义模型与上下文压缩预算。它还会为支持的摘要请求补充可编辑的长度指令,帮助模型生成精简的摘要。
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 可以做什么
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **同步模型设置:**上下文窗口、回复输出上限,以及已确认的输入类型和推理等级。
|
|
12
|
+
- **对齐压缩预算:**更新已启用的 DSH Agent 预设中,对应模型的压缩策略。
|
|
13
|
+
- **控制摘要长度:**编辑补充提示词,调整三项目标长度比例。
|
|
14
|
+
- **启动时同步:**可选择在 DSH 启动并空闲后同步一次。
|
|
15
|
+
- **预览与恢复:**检查差异、备份设置,并查看最近一次同步结果。
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
插件只读访问 Strata Server。同步不会切换或加载服务器模型、修改服务器设置,也不会发送测试推理请求。无法确认的模型能力会保留 DSH 原有值。
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## 开始使用
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
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.
|
|
19
|
-
```
|
|
21
|
+
### 1. 准备连接
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
先在 Strata Server 加载模型,再到 **DSH → 设置 → 模型**,配置兼容 OpenAI 的提供方、API 地址与认证,并明确添加自定义模型条目。
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|---|---:|---|
|
|
25
|
-
| `summaryGuidance` | `true` | 对支持的摘要请求附加补充提示词。 |
|
|
26
|
-
| `summaryContextDivisor` | `16` | 以上下文除以此值。 |
|
|
27
|
-
| `summaryOutputDivisor` | `2` | 以本次摘要输出硬上限除以此值。 |
|
|
28
|
-
| `summarySourceDivisor` | `2` | 以原文估算长度除以此值。 |
|
|
29
|
-
| `summaryPromptTemplate` | 上方英文模板 | 替换 `{target}` 后附加的补充内容。 |
|
|
25
|
+
插件直接复用这个连接,无需另外复制 API key。
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
### 2. 安装插件
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
在 DSH 插件管理器选择**添加插件**,输入:
|
|
34
30
|
|
|
35
31
|
```text
|
|
36
|
-
|
|
37
|
-
目标 = floor(min(上下文 / summaryContextDivisor,
|
|
38
|
-
本次摘要实际 maxTokens / summaryOutputDivisor,
|
|
39
|
-
待替换内容的估算 tokens / summarySourceDivisor))
|
|
32
|
+
dsh-strata-sync
|
|
40
33
|
```
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
保存这些控件只修改插件偏好,不会同步模型预算或修改 Strata Server 设置。DSH 原生提示词、八个章节和请求参数保持不变。默认补充内容只有一句,自定义模板则按输入内容附加。目标是写作指令,**不是新的输出硬上限,也不能保证不截断**;不增加重试流程或额外推理请求。
|
|
45
|
-
|
|
46
|
-
无法确认路由或信息、原生提示词格式未知、附件用量无法估算、模板无效、请求取消、功能关闭或目标低于 256 tokens 时,保留原生请求。移除插件会停止附加内容,不改写已保存的对话历史。
|
|
47
|
-
|
|
48
|
-
### 模型能力自动同步(0.4.0)
|
|
49
|
-
|
|
50
|
-
预览新增“输入类型”“推理等级”和“推理请求映射”,与 token 预算共用备份、回滚及空闲时才应用的保护。
|
|
51
|
-
|
|
52
|
-
- 输入类型按服务器明确报告的 `architecture.input_modalities` 设置为文本或文本+图片;缺少信息或格式不支持时保留原值。
|
|
53
|
-
- 推理等级从 `/props?model=...` 核对 Strata 身份、模型身份及已审查的对话模板指纹,不只凭名称猜测。
|
|
54
|
-
- 已验证的 Qwen3.8-Flash-Next:**off/low/medium/xhigh**;DeepSeek-V4.1-Flash:**off/low/high/max**。包含已核对的 Huihui 版本,以模板而非量化名称判定。
|
|
55
|
-
- 使用 DSH 原生请求映射,同时设置是否思考及推理等级。模板未知或无法获取 props 时,保留原推理设置并显示原因。
|
|
56
|
-
- 不修改提供方默认等级或当前对话选择。提供方默认值与已验证选项冲突时,跳过推理同步并提示。同步后请开启新对话。
|
|
57
|
-
|
|
58
|
-
详见[能力验证与映射表](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/CAPABILITIES.md)。不新增其他插件、不修改 Strata 设置。
|
|
59
|
-
|
|
60
|
-
### 已有同步功能
|
|
61
|
-
|
|
62
|
-
- 读取 `/v1/models` 和可用的 `/slots`,确认文本模型的正式 ID 和引擎实际上下文,不从模型名称猜测。已确认的别名视为同一模型,图片生成端点不计入文本模型选择。
|
|
63
|
-
- 更新选定 DSH 模型的上下文、输出上限,以及已启用 Agent 预设中的原生 `compaction-basic` 策略;预览会列出受影响的预设。
|
|
64
|
-
- 默认使用“跟随 Strata”选择输出上限;手动覆盖放在“高级设置”。分别显示服务器原值、实际采用值与来源,也可选择让默认模型跟随服务器。
|
|
65
|
-
- 自动同步默认关闭;在启动前启用后,每次 DSH 宿主进程启动、所有任务空闲时同步一次。查询途中开始任务时保留待同步状态,任务完成后补做;成功后不再定期查询。其他错误需手动重试或下次启动再试。运行期间启用会在下次启动生效;立即同步请点击“备份并同步”。
|
|
66
|
-
- 应用前重新确认服务器与同一份设置版本、拒绝过期预览、备份设置;后续写入失败时回滚已完成的更改。偏好保存也会核对版本;未编辑的表单跟随最新值,已有编辑时提示冲突,避免覆盖其他窗口的更改。
|
|
67
|
-
- 同步完成后保留只读结果,包含模型、预算、输出来源及备份信息,并区分已确认与保留原值的能力。
|
|
68
|
-
- 沿用 DSH 现有认证,不在页面或诊断中显示密钥,不跟随 HTTP 重定向。
|
|
69
|
-
|
|
70
|
-
**同步模型或预算设置后请开启新对话。** 已有对话保留原模型路由与 Agent 预设版本;插件不改写已有对话、不重启 DSH,也不增加额外推理请求。新版插件启用期间,动态摘要引导会作用于支持的摘要请求,不需要修改这些已保存设置。
|
|
71
|
-
|
|
72
|
-
## 安装与使用
|
|
73
|
-
|
|
74
|
-
包名为 `dsh-strata-sync`(原名 `@ethan741205/dsh-strata-sync`);迁移时保留原设置,移除旧 scoped 插件后再安装新包,避免同时加载两份。
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
如需安装已有的 npm 版本,先完成任务并完全退出 DSH Desktop,再使用官方 DSH CLI 从 npm 官方 registry 安装:
|
|
35
|
+
也可以先完成当前任务、完全退出 DSH Desktop,再使用官方 CLI:
|
|
78
36
|
|
|
79
37
|
```sh
|
|
80
38
|
dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npmjs.org/
|
|
81
39
|
```
|
|
82
40
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
要从源码安装**包含摘要提示词编辑器的 0.10.2**,请使用 Node.js 22 或更新版本构建,并在最后的安装命令前完成任务、完全退出 DSH Desktop:
|
|
86
|
-
|
|
87
|
-
```sh
|
|
88
|
-
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
89
|
-
cd dsh-strata-sync
|
|
90
|
-
npm ci
|
|
91
|
-
npm test
|
|
92
|
-
npm pack
|
|
93
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.2.tgz
|
|
94
|
-
```
|
|
41
|
+
如设置页尚未出现,请重新打开 DSH。若插件处于禁用状态,请在插件管理器启用。
|
|
95
42
|
|
|
96
|
-
|
|
43
|
+
### 3. 预览并同步
|
|
97
44
|
|
|
98
|
-
|
|
45
|
+
打开**设置 → dsh-strata-sync**:
|
|
99
46
|
|
|
100
|
-
1.
|
|
101
|
-
2.
|
|
102
|
-
3. DSH
|
|
103
|
-
4.
|
|
104
|
-
5. 开启新对话,使用更新后的 Agent 预设。
|
|
47
|
+
1. 选择 Strata 提供方,点击**保存偏好**。
|
|
48
|
+
2. 点击**检查差异**,查看已加载模型与拟修改的设置。
|
|
49
|
+
3. 在 DSH 空闲时,点击**备份并同步**。
|
|
50
|
+
4. **开启新对话**,使用更新后的模型与 Agent 预设。
|
|
105
51
|
|
|
106
|
-
|
|
52
|
+
已有对话会保留原先选定的模型路由和预设版本。如需自动设置,可勾选**启动 DSH 时自动同步**并保存。此选项默认关闭,下次启动才生效;会等待空闲,不会持续轮询。
|
|
107
53
|
|
|
108
|
-
|
|
54
|
+
## 模型与输出设置
|
|
109
55
|
|
|
110
|
-
|
|
56
|
+
| 设置 | 如何决定 |
|
|
57
|
+
|---|---|
|
|
58
|
+
| 模型与上下文 | 采用 Strata 已加载的文本模型及已确认的上下文容量。 |
|
|
59
|
+
| 回复输出上限 | 优先使用手动覆盖值;否则采用已确认的 Strata 输出默认值。无法取得或未限制时,使用上下文的 30%,最多 16,384 tokens。 |
|
|
60
|
+
| 输入类型 | 采用服务器已确认的能力,例如文本或文本+图片。 |
|
|
61
|
+
| 推理等级 | 根据已验证的模型模板确定;未知模板保留原有设置。 |
|
|
62
|
+
| 默认模型 | 启用**默认模型跟随 Strata 已加载的模型**时,跟随服务器当前模型。 |
|
|
111
63
|
|
|
112
|
-
|
|
64
|
+
保持**输出上限跟随 Strata**开启,即可自动选择。关闭后可在**高级设置**输入手动覆盖值。预览会分别显示服务器默认值、实际应用值及其来源。
|
|
113
65
|
|
|
114
|
-
|
|
66
|
+
同步时,插件将摘要输出上限和压缩预留空间均设为 4,096 tokens。实际压缩阈值取**上下文的 80%**与**上下文 − 回复输出预算 − 4,096**中的较小值,近期内容保留量为 **(上下文 − 回复输出预算)× 16%**,向下取整。这些是插件计算的客户端预算,并非 Strata 提供的设置。
|
|
115
67
|
|
|
116
|
-
|
|
68
|
+
例如,采用自动输出计算时,32K 上下文的回复预算为 9,830 tokens,压缩阈值为 18,842 tokens,**不一定在 80% 时压缩**。
|
|
117
69
|
|
|
118
|
-
|
|
70
|
+
## 摘要提示词与目标长度
|
|
119
71
|
|
|
120
|
-
|
|
72
|
+
**动态摘要目标**默认关闭。启用后会在 DSH 原生摘要指令后补充要求;关闭时使用 DSH 原生摘要与压缩行为。
|
|
121
73
|
|
|
122
|
-
|
|
74
|
+
可编辑的**摘要补充提示词**默认内容为:
|
|
123
75
|
|
|
124
76
|
```text
|
|
125
|
-
|
|
126
|
-
备用输出 = min(16384, floor(上下文 × 0.30))
|
|
127
|
-
压缩余量 = 4096
|
|
128
|
-
摘要 maxTokens = 4096
|
|
129
|
-
thresholdRatio = 0.8
|
|
130
|
-
retainRatio = 0.16
|
|
131
|
-
实际压缩阈值 = floor(min(上下文 × 0.8, 上下文 − 普通输出 − 4096))
|
|
132
|
-
近期对话保留量 = floor((上下文 − 普通输出) × 0.16)
|
|
77
|
+
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.
|
|
133
78
|
```
|
|
134
79
|
|
|
135
|
-
|
|
80
|
+
请保留 `{target}`,每次支持的摘要请求前,它会替换成计算出的 token 目标。模板最多 2,048 个字符。点击**恢复默认提示词**可重置内容,再点击**保存偏好**应用修改。
|
|
136
81
|
|
|
137
|
-
|
|
82
|
+
两个除数控制目标,默认均为 **2(各取 50%)**:
|
|
83
|
+
|
|
84
|
+
| 除数 | 默认值 | 将目标限制为 |
|
|
85
|
+
|---|---:|---|
|
|
86
|
+
| 摘要输出(O) | 2 | 估算有效摘要输出预算 ÷ O |
|
|
87
|
+
| 原文长度(S) | 2 | 待摘要内容的估算长度 ÷ S |
|
|
138
88
|
|
|
139
|
-
|
|
140
|
-
|---|---:|---:|---:|---:|---:|
|
|
141
|
-
| 32,768 | 9,830 | 4,096 | 4,096 | 18,842(57.50%) | 3,670 |
|
|
142
|
-
| 65,536 | 16,384 | 4,096 | 4,096 | 45,056(68.75%) | 7,864 |
|
|
89
|
+
目标取两项结果的较小值,再向下取整。除数支持大于或等于 1 的小数。已移除上下文除数;旧设置中的 `summaryContextDivisor` 不再参与计算。已有输出/原文除数及明确的启用选择会保留,新安装或未指定时仍**默认关闭**。
|
|
143
90
|
|
|
144
|
-
|
|
91
|
+
有效输出预算是**估算值**,不是直接把请求的 `maxTokens` 当作服务器确认的上限。它取本次摘要输出上限与估算上下文剩余空间中的较小值;后者使用已确认的服务器/客户端窗口较小值,扣除完整提示内容(包含系统提示、工具定义和补充句),再预留支持的 pi-ai 适配器所用的 4,096 tokens 安全空间。文本以每 token 约 3.5 字符并加上格式成本估算。原文长度另采用 DSH 的每 token 约 4 字符估算,不含系统提示、工具和摘要指令。两者都不是精确 tokenizer 计数。
|
|
145
92
|
|
|
146
|
-
|
|
93
|
+
例如,有效输出预算为 4,096 tokens 且原文足够长时,32K 与 64K 上下文的目标都是 **2,048 tokens**;原文只有约 2,000 tokens 时,目标为 **1,000 tokens**。上下文剩余空间不足时,目标会进一步降低。界面仅以提议的摘要上限预览目标上界,尚未扣除个别请求的成本。
|
|
147
94
|
|
|
148
|
-
|
|
95
|
+
这是写作指令,**不是输出硬上限,也不能保证不截断**。思考可能共用输出预算;插件不会修改思考设置、`maxTokens`、`fit_max_tokens` 或压缩时机。服务器实际 tokenizer、后续中间层或不同适配器版本仍可能产生更低的上限。
|
|
149
96
|
|
|
150
|
-
|
|
97
|
+
保存摘要偏好不会改变模型预算,也不会替换原生提示词或增加额外推理、重试循环。无法验证请求、无法安全估算内容,或目标小于 256 tokens 时,会沿用原本的摘要请求。
|
|
151
98
|
|
|
152
|
-
|
|
99
|
+
## 备份与兼容性
|
|
153
100
|
|
|
154
|
-
|
|
101
|
+
写入设置前,会将 `cordis.patch.yml` 备份到配置目录下的 `backups/strata-sync/`。同步会检查是否有并发修改,并在后续步骤失败时尝试回滚已完成的更改。备份可能包含私人配置,请保存在本机。
|
|
155
102
|
|
|
156
|
-
|
|
103
|
+
移除插件不会撤销已经同步的设置。如需恢复备份,请先完全退出 DSH。
|
|
157
104
|
|
|
158
|
-
0.
|
|
105
|
+
已在 **DSH Desktop 0.2.1-rc.3** 上验证。请使用 API key 或无需认证的 OpenAI 兼容提供方,明确配置自定义模型列表,并启用包含 `compaction-basic` 的 Agent 预设。不支持小于 8,192 tokens 的上下文、仅使用模型目录的提供方、非空的 `modelOverrides`,或无法明确判断已加载模型的信息。
|
|
159
106
|
|
|
160
|
-
|
|
107
|
+
技术细节与测试范围请见[已验证能力与推理映射](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/CAPABILITIES.md)及[验证记录](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/VALIDATION.md)。
|
|
161
108
|
|
|
162
|
-
|
|
109
|
+
## 开发
|
|
110
|
+
|
|
111
|
+
需要 Node.js 22 或更新版本。
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
115
|
+
cd dsh-strata-sync
|
|
116
|
+
npm ci
|
|
117
|
+
npm test
|
|
118
|
+
npm run build
|
|
119
|
+
npm pack
|
|
120
|
+
```
|
|
163
121
|
|
|
164
|
-
|
|
122
|
+
安装自行构建的版本前,请完全退出 DSH,再执行 `dsh plugin --profile desktop add <path-to-generated.tgz>`。
|
|
165
123
|
|
|
166
|
-
|
|
124
|
+
源码:`src/plugin.mjs`(宿主整合)、`src/core.mjs`(信息读取与预算)、`src/summary.mjs`(摘要引导)、`src/client.js`(设置界面)。
|
|
167
125
|
|
|
168
|
-
MIT
|
|
126
|
+
[npm](https://www.npmjs.com/package/dsh-strata-sync) · [反馈问题](https://github.com/ethan741205/dsh-strata-sync/issues) · [MIT 许可证](https://github.com/ethan741205/dsh-strata-sync/blob/main/LICENSE)
|
package/docs/README.zh-TW.md
CHANGED
|
@@ -2,167 +2,125 @@
|
|
|
2
2
|
|
|
3
3
|
[English](https://github.com/ethan741205/dsh-strata-sync/blob/main/README.md) · [简体中文](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/README.zh-CN.md) · **繁體中文**
|
|
4
4
|
|
|
5
|
-
讓 **DeepSeek Harness(DSH)**
|
|
5
|
+
讓 **DeepSeek Harness(DSH)** 連接 **Strata Server** 目前載入的模型,在同一個 DSH 設定頁管理模型配置與摘要控制。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
外掛讀取 Strata 的模型資訊、預覽差異,再更新 DSH 自訂模型與上下文壓縮預算。它也會為支援的摘要請求補充可編輯的長度指令,幫助模型產生精簡的摘要。
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 可以做什麼
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **同步模型設定:**上下文視窗、回覆輸出上限,以及已確認的輸入類型和推理等級。
|
|
12
|
+
- **對齊壓縮預算:**更新已啟用的 DSH Agent 預設中,對應模型的壓縮政策。
|
|
13
|
+
- **控制摘要長度:**編輯補充提示詞,調整三項目標長度比例。
|
|
14
|
+
- **啟動時同步:**可選擇在 DSH 啟動並閒置後同步一次。
|
|
15
|
+
- **預覽與復原:**檢查差異、備份設定,並查看最近一次同步結果。
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
外掛僅以唯讀方式存取 Strata Server。同步不會切換或載入伺服器模型、修改伺服器設定,也不會傳送測試推論請求。無法確認的模型能力會保留 DSH 原有值。
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## 開始使用
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
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.
|
|
19
|
-
```
|
|
21
|
+
### 1. 準備連線
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
先在 Strata Server 載入模型,再到 **DSH → 設定 → 模型**,設定相容 OpenAI 的提供者、API 網址與認證,並明確新增自訂模型項目。
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|---|---:|---|
|
|
25
|
-
| `summaryGuidance` | `true` | 對支援的摘要請求附加補充提示詞。 |
|
|
26
|
-
| `summaryContextDivisor` | `16` | 以上下文除以此值。 |
|
|
27
|
-
| `summaryOutputDivisor` | `2` | 以當次摘要輸出硬上限除以此值。 |
|
|
28
|
-
| `summarySourceDivisor` | `2` | 以原文估算長度除以此值。 |
|
|
29
|
-
| `summaryPromptTemplate` | 上方英文範本 | 替換 `{target}` 後附加的補充內容。 |
|
|
25
|
+
外掛直接沿用這個連線,不必另外複製 API key。
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
### 2. 安裝外掛
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
在 DSH 外掛管理員選擇**新增外掛**,輸入:
|
|
34
30
|
|
|
35
31
|
```text
|
|
36
|
-
|
|
37
|
-
目標 = floor(min(上下文 / summaryContextDivisor,
|
|
38
|
-
本次摘要實際 maxTokens / summaryOutputDivisor,
|
|
39
|
-
待替換內容的估算 tokens / summarySourceDivisor))
|
|
32
|
+
dsh-strata-sync
|
|
40
33
|
```
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
儲存這些控制項只更改外掛偏好,不會同步模型預算或修改 Strata Server 設定。DSH 原生提示詞、八個章節和請求參數保持不變。預設補充內容只有一句,自訂範本則按輸入內容附加。目標是寫作指令,**不是新的輸出硬上限,也不能保證不截斷**;不增加重試流程或額外推論請求。
|
|
45
|
-
|
|
46
|
-
無法確認路由或資訊、原生提示詞格式未知、附件用量無法估算、範本無效、請求取消、功能關閉或目標低於 256 tokens 時,保留原生請求。移除外掛會停止附加內容,不重寫已儲存的對話歷史。
|
|
47
|
-
|
|
48
|
-
### 模型能力自動同步(0.4.0)
|
|
49
|
-
|
|
50
|
-
預覽新增「輸入類型」、「推理等級」和「推理請求對應」,與 token 預算共用備份、回復及閒置才套用的保護。
|
|
51
|
-
|
|
52
|
-
- 輸入類型依伺服器明確回報的 `architecture.input_modalities` 設定為文字或文字+圖片;缺少資訊或格式不支援時保留原值。
|
|
53
|
-
- 推理等級從 `/props?model=...` 核對 Strata 身分、模型身分及已審查的對話範本指紋,不單憑名稱猜測。
|
|
54
|
-
- 已驗證的 Qwen3.8-Flash-Next:**off/low/medium/xhigh**;DeepSeek-V4.1-Flash:**off/low/high/max**。包含已核對的 Huihui 版本,以範本而非量化名稱判定。
|
|
55
|
-
- 使用 DSH 原生請求對應,同時設定是否思考及推理等級。範本未知或無法取得 props 時,保留原推理設定並顯示原因。
|
|
56
|
-
- 不修改供應者預設等級或目前對話選擇。供應者預設值與已驗證選項衝突時,跳過推理同步並提示。同步後請開新對話。
|
|
57
|
-
|
|
58
|
-
詳見[能力驗證與對應表](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/CAPABILITIES.md)。不新增其他外掛、不修改 Strata 設定。
|
|
59
|
-
|
|
60
|
-
### 既有同步功能
|
|
61
|
-
|
|
62
|
-
- 讀取 `/v1/models` 與可用的 `/slots`,確認文字模型的正式 ID 和引擎實際上下文,不從模型名稱猜測。已確認的別名視為同一模型,圖片生成端點不列入文字模型選擇。
|
|
63
|
-
- 更新選定 DSH 模型的上下文、輸出上限,以及已啟用 Agent 範本中的原生 `compaction-basic` 策略;預覽會列出受影響的範本。
|
|
64
|
-
- 預設使用「跟隨 Strata」選擇輸出上限;手動覆寫放在「進階設定」。分開顯示伺服器原值、實際採用值與來源,也可選擇讓預設模型跟隨伺服器。
|
|
65
|
-
- 自動同步預設關閉;在啟動前啟用後,每次 DSH 宿主程序啟動、所有工作閒置時同步一次。查詢途中開始工作時保留待同步狀態,工作完成後補做;成功後不再定期查詢。其他錯誤需手動重試或下次啟動再試。執行期間啟用會在下次啟動生效;立即同步請按「備份並同步」。
|
|
66
|
-
- 套用前重新確認伺服器與同一份設定版本、拒絕過期預覽、備份設定;後續寫入失敗時回復已完成的變更。偏好儲存也會核對版本;未編輯的表單跟隨最新值,已有編輯時提示衝突,避免覆蓋其他視窗的變更。
|
|
67
|
-
- 同步完成後保留唯讀結果,包含模型、預算、輸出來源及備份資訊,並區分已確認與保留原值的能力。
|
|
68
|
-
- 沿用 DSH 現有認證,不在頁面或診斷中顯示金鑰,不跟隨 HTTP 重新導向。
|
|
69
|
-
|
|
70
|
-
**同步模型或預算設定後請開新對話。** 既有對話保留原模型路由與 Agent 範本版本;外掛不重寫既有對話、不重啟 DSH,也不增加額外推論請求。新版外掛啟用期間,動態摘要引導會作用於支援的摘要請求,不需要修改這些已儲存設定。
|
|
71
|
-
|
|
72
|
-
## 安裝與使用
|
|
73
|
-
|
|
74
|
-
套件名稱為 `dsh-strata-sync`(原名 `@ethan741205/dsh-strata-sync`);遷移時保留原設定,移除舊 scoped 插件後再安裝新套件,避免同時載入兩份。
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
若要安裝既有的 npm 版本,先完成工作並完全結束 DSH Desktop,再使用官方 DSH CLI 從 npm 官方 registry 安裝:
|
|
35
|
+
也可以先完成目前工作、完全結束 DSH Desktop,再使用官方 CLI:
|
|
78
36
|
|
|
79
37
|
```sh
|
|
80
38
|
dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npmjs.org/
|
|
81
39
|
```
|
|
82
40
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
要從原始碼安裝**包含摘要提示詞編輯器的 0.10.2**,請使用 Node.js 22 或更新版本建置,並在最後的安裝命令前完成工作、完全結束 DSH Desktop:
|
|
86
|
-
|
|
87
|
-
```sh
|
|
88
|
-
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
89
|
-
cd dsh-strata-sync
|
|
90
|
-
npm ci
|
|
91
|
-
npm test
|
|
92
|
-
npm pack
|
|
93
|
-
dsh plugin --profile desktop add ./dsh-strata-sync-0.10.2.tgz
|
|
94
|
-
```
|
|
41
|
+
若設定頁尚未出現,請重新開啟 DSH。若外掛處於停用狀態,請在外掛管理員啟用。
|
|
95
42
|
|
|
96
|
-
|
|
43
|
+
### 3. 預覽並同步
|
|
97
44
|
|
|
98
|
-
|
|
45
|
+
開啟**設定 → dsh-strata-sync**:
|
|
99
46
|
|
|
100
|
-
1.
|
|
101
|
-
2.
|
|
102
|
-
3. DSH
|
|
103
|
-
4.
|
|
104
|
-
5. 開啟新對話,使用更新後的 Agent 範本。
|
|
47
|
+
1. 選擇 Strata 提供方,點選**儲存偏好**。
|
|
48
|
+
2. 點選**檢查差異**,查看已載入模型與預計修改的設定。
|
|
49
|
+
3. 在 DSH 閒置時,點選**備份並同步**。
|
|
50
|
+
4. **開啟新對話**,使用更新後的模型與 Agent 預設。
|
|
105
51
|
|
|
106
|
-
|
|
52
|
+
既有對話會保留原先選定的模型路由和預設版本。如需自動設定,可勾選**啟動 DSH 時自動同步**並儲存。此選項預設關閉,下次啟動才生效;會等待閒置,不會持續輪詢。
|
|
107
53
|
|
|
108
|
-
|
|
54
|
+
## 模型與輸出設定
|
|
109
55
|
|
|
110
|
-
|
|
56
|
+
| 設定 | 如何決定 |
|
|
57
|
+
|---|---|
|
|
58
|
+
| 模型與上下文 | 採用 Strata 已載入的文字模型及已確認的上下文容量。 |
|
|
59
|
+
| 回覆輸出上限 | 優先使用手動覆寫值;否則採用已確認的 Strata 輸出預設值。無法取得或未限制時,使用上下文的 30%,最多 16,384 tokens。 |
|
|
60
|
+
| 輸入類型 | 採用伺服器已確認的能力,例如文字或文字+圖片。 |
|
|
61
|
+
| 推理等級 | 依已驗證的模型範本決定;未知範本保留原有設定。 |
|
|
62
|
+
| 預設模型 | 啟用**預設模型跟隨 Strata 已載入的模型**時,跟隨伺服器目前模型。 |
|
|
111
63
|
|
|
112
|
-
|
|
64
|
+
保持**輸出上限跟隨 Strata**開啟,即可自動選擇。關閉後可在**進階設定**輸入手動覆寫值。預覽會分別顯示伺服器預設值、實際套用值及其來源。
|
|
113
65
|
|
|
114
|
-
|
|
66
|
+
同步時,外掛將摘要輸出上限和壓縮預留空間均設為 4,096 tokens。實際壓縮門檻取**上下文的 80%**與**上下文 − 回覆輸出預算 − 4,096**中的較小值,近期內容保留量為 **(上下文 − 回覆輸出預算)× 16%**,向下取整。這些是外掛計算的客戶端預算,並非 Strata 提供的設定。
|
|
115
67
|
|
|
116
|
-
|
|
68
|
+
例如,採用自動輸出計算時,32K 上下文的回覆預算為 9,830 tokens,壓縮門檻為 18,842 tokens,**不一定在 80% 時壓縮**。
|
|
117
69
|
|
|
118
|
-
|
|
70
|
+
## 摘要提示詞與目標長度
|
|
119
71
|
|
|
120
|
-
|
|
72
|
+
**動態摘要目標**預設關閉。啟用後會在 DSH 原生摘要指令後補充要求;關閉時使用 DSH 原生摘要與壓縮行為。
|
|
121
73
|
|
|
122
|
-
|
|
74
|
+
可編輯的**摘要補充提示詞**預設內容為:
|
|
123
75
|
|
|
124
76
|
```text
|
|
125
|
-
|
|
126
|
-
備用輸出 = min(16384, floor(上下文 × 0.30))
|
|
127
|
-
壓縮餘裕 = 4096
|
|
128
|
-
摘要 maxTokens = 4096
|
|
129
|
-
thresholdRatio = 0.8
|
|
130
|
-
retainRatio = 0.16
|
|
131
|
-
實際壓縮門檻 = floor(min(上下文 × 0.8, 上下文 − 一般輸出 − 4096))
|
|
132
|
-
近期對話保留量 = floor((上下文 − 一般輸出) × 0.16)
|
|
77
|
+
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.
|
|
133
78
|
```
|
|
134
79
|
|
|
135
|
-
|
|
80
|
+
請保留 `{target}`,每次支援的摘要請求前,它會替換成計算出的 token 目標。範本最多 2,048 個字元。點選**還原預設提示詞**可重設內容,再點選**儲存偏好**套用修改。
|
|
136
81
|
|
|
137
|
-
|
|
82
|
+
兩個除數控制目標,預設均為 **2(各取 50%)**:
|
|
83
|
+
|
|
84
|
+
| 除數 | 預設值 | 將目標限制為 |
|
|
85
|
+
|---|---:|---|
|
|
86
|
+
| 摘要輸出(O) | 2 | 估算有效摘要輸出預算 ÷ O |
|
|
87
|
+
| 原文長度(S) | 2 | 待摘要內容的估算長度 ÷ S |
|
|
138
88
|
|
|
139
|
-
|
|
140
|
-
|---|---:|---:|---:|---:|---:|
|
|
141
|
-
| 32,768 | 9,830 | 4,096 | 4,096 | 18,842(57.50%) | 3,670 |
|
|
142
|
-
| 65,536 | 16,384 | 4,096 | 4,096 | 45,056(68.75%) | 7,864 |
|
|
89
|
+
目標取兩項結果的較小值,再向下取整。除數支援大於或等於 1 的小數。已移除上下文除數;舊設定中的 `summaryContextDivisor` 不再參與計算。既有輸出/原文除數及明確的啟用選擇會保留,新安裝或未指定時仍**預設關閉**。
|
|
143
90
|
|
|
144
|
-
|
|
91
|
+
有效輸出預算是**估算值**,不是直接把請求的 `maxTokens` 當作伺服器確認的上限。它取本次摘要輸出上限與估算上下文剩餘空間中的較小值;後者使用已確認的伺服器/客戶端視窗較小值,扣除完整提示內容(包含系統提示、工具定義和補充句),再預留支援的 pi-ai 轉接器所用的 4,096 tokens 安全空間。文字以每 token 約 3.5 字元並加上格式成本估算。原文長度另採 DSH 的每 token 約 4 字元估算,不含系統提示、工具和摘要指令。兩者都不是精確 tokenizer 計數。
|
|
145
92
|
|
|
146
|
-
|
|
93
|
+
例如,有效輸出預算為 4,096 tokens 且原文足夠長時,32K 與 64K 上下文的目標都是 **2,048 tokens**;原文只有約 2,000 tokens 時,目標為 **1,000 tokens**。上下文剩餘空間不足時,目標會進一步降低。介面僅以提議的摘要上限預覽目標上界,尚未扣除個別請求的成本。
|
|
147
94
|
|
|
148
|
-
|
|
95
|
+
這是寫作指令,**不是輸出硬上限,也不能保證不截斷**。思考可能共用輸出預算;外掛不會修改思考設定、`maxTokens`、`fit_max_tokens` 或壓縮時機。伺服器實際 tokenizer、後續中介層或不同轉接器版本仍可能產生更低的上限。
|
|
149
96
|
|
|
150
|
-
|
|
97
|
+
儲存摘要偏好不會改變模型預算,也不會替換原生提示詞或增加額外推論、重試循環。無法驗證請求、無法安全估算內容,或目標小於 256 tokens 時,會沿用原本的摘要請求。
|
|
151
98
|
|
|
152
|
-
|
|
99
|
+
## 備份與相容性
|
|
153
100
|
|
|
154
|
-
|
|
101
|
+
寫入設定前,會將 `cordis.patch.yml` 備份至設定目錄下的 `backups/strata-sync/`。同步會檢查是否有並行修改,並在後續步驟失敗時嘗試回復已完成的變更。備份可能包含私人設定,請儲存在本機。
|
|
155
102
|
|
|
156
|
-
|
|
103
|
+
移除外掛不會撤銷已經同步的設定。如需還原備份,請先完全結束 DSH。
|
|
157
104
|
|
|
158
|
-
0.
|
|
105
|
+
已在 **DSH Desktop 0.2.1-rc.3** 上驗證。請使用 API key 或不需認證的 OpenAI 相容提供者,明確設定自訂模型清單,並啟用包含 `compaction-basic` 的 Agent 預設。不支援小於 8,192 tokens 的上下文、僅使用模型目錄的提供者、非空的 `modelOverrides`,或無法明確判斷已載入模型的資訊。
|
|
159
106
|
|
|
160
|
-
|
|
107
|
+
技術細節與測試範圍請見[已驗證能力與推理對應](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/CAPABILITIES.md)及[驗證紀錄](https://github.com/ethan741205/dsh-strata-sync/blob/main/docs/VALIDATION.md)。
|
|
161
108
|
|
|
162
|
-
|
|
109
|
+
## 開發
|
|
110
|
+
|
|
111
|
+
需要 Node.js 22 或更新版本。
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
git clone https://github.com/ethan741205/dsh-strata-sync.git
|
|
115
|
+
cd dsh-strata-sync
|
|
116
|
+
npm ci
|
|
117
|
+
npm test
|
|
118
|
+
npm run build
|
|
119
|
+
npm pack
|
|
120
|
+
```
|
|
163
121
|
|
|
164
|
-
|
|
122
|
+
安裝自行建置的版本前,請完全結束 DSH,再執行 `dsh plugin --profile desktop add <path-to-generated.tgz>`。
|
|
165
123
|
|
|
166
|
-
|
|
124
|
+
原始碼:`src/plugin.mjs`(宿主整合)、`src/core.mjs`(資訊讀取與預算)、`src/summary.mjs`(摘要引導)、`src/client.js`(設定介面)。
|
|
167
125
|
|
|
168
|
-
MIT
|
|
126
|
+
[npm](https://www.npmjs.com/package/dsh-strata-sync) · [回報問題](https://github.com/ethan741205/dsh-strata-sync/issues) · [MIT 授權](https://github.com/ethan741205/dsh-strata-sync/blob/main/LICENSE)
|
package/docs/VALIDATION.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Validation date: 2026-10-30 (Asia/Taipei).
|
|
4
4
|
|
|
5
|
+
## Two-bound summary target 0.10.4
|
|
6
|
+
|
|
7
|
+
- The target uses only estimated effective output budget / output divisor and selected-source estimate / source divisor. Both divisors default to 2 (50%). The context-divisor control and formula term are removed; legacy stored context divisors are ignored without enabling guidance.
|
|
8
|
+
- Guidance remains off by default in schema, host fallback, request middleware and all three UI locales. Explicit enable choices, output/source divisors and editable templates remain supported. No production settings were edited. Installing the release is left to the user.
|
|
9
|
+
- Effective output room is estimated conservatively against the supported pi-ai 1.1.0 context clamp, including the supplement, system text and tools. It is not a server tokenizer result. Reasoning and later request transformations can still reduce usable answer space.
|
|
10
|
+
- All **155 automated tests pass**. Tests cover the actual pi-ai clamp on multiple context/input sizes, near-full and exhausted context, independent source length, additional prompt costs, ignored legacy divisors, disabled-mode zero discovery, restored native requests and localized controls. The package verifier also passes.
|
|
11
|
+
- No model inference requests were sent. Tests do not prove truncation is impossible; this supplement is a writing target and leaves native hard caps, reasoning and server configuration unchanged.
|
|
12
|
+
|
|
13
|
+
## Earlier opt-in summary validation (before the two-bound update)
|
|
14
|
+
|
|
15
|
+
- Summary guidance now defaults to `false` in the schema, host fallback, request hook and UI. An existing explicit `true` remains enabled; all other budgets and summary parameters are preserved.
|
|
16
|
+
- Added a three-language UI regression for an omitted preference. Host and middleware tests verify that omitted/disabled guidance preserves native requests and makes no metadata calls; explicit opt-in still appends the configured sentence.
|
|
17
|
+
- All 152 automated tests pass, including 39 UI tests and the package verifier. No inference requests were sent.
|
|
18
|
+
|
|
5
19
|
## Concise summary help 0.10.1
|
|
6
20
|
|
|
7
21
|
- 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.
|