dsh-strata-sync 0.10.3 → 0.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/dist/client.js +26 -31
- package/dist/index.js +5 -6
- package/dist/summary.mjs +49 -10
- package/docs/CAPABILITIES.md +1 -1
- package/docs/README.zh-CN.md +10 -7
- package/docs/README.zh-TW.md +10 -7
- package/docs/VALIDATION.md +17 -128
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ The plugin reads Strata's model information, previews the changes, and updates D
|
|
|
10
10
|
|
|
11
11
|
- **Sync model settings:** context window, response output limit, and confirmed input types and reasoning levels.
|
|
12
12
|
- **Align compaction budgets:** update the matching policies in enabled DSH Agent presets.
|
|
13
|
-
- **Control summary length:** edit the supplemental prompt and adjust
|
|
13
|
+
- **Control summary length:** edit the supplemental prompt and adjust two target-length ratios.
|
|
14
14
|
- **Sync on startup:** optionally synchronize once after DSH becomes idle.
|
|
15
15
|
- **Review and recover:** preview differences, back up settings, and view the last synchronization result.
|
|
16
16
|
|
|
@@ -69,7 +69,7 @@ For example, with automatic output calculation, a 32K context uses a 9,830-token
|
|
|
69
69
|
|
|
70
70
|
## Summary prompt and target length
|
|
71
71
|
|
|
72
|
-
**Dynamic summary target** is
|
|
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.
|
|
73
73
|
|
|
74
74
|
The editable **Supplemental summary prompt** starts with:
|
|
75
75
|
|
|
@@ -79,17 +79,20 @@ Keep the entire checkpoint, including all required headings, within a target of
|
|
|
79
79
|
|
|
80
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.
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
Two divisors control the target (both default to **2**, or **50%**):
|
|
83
83
|
|
|
84
84
|
| Divisor | Default | Limits the target to |
|
|
85
85
|
|---|---:|---|
|
|
86
|
-
|
|
|
87
|
-
| Summary output (O) | 2 | Actual summary output cap ÷ O |
|
|
86
|
+
| Output budget (O) | 2 | Estimated effective summary output budget ÷ O |
|
|
88
87
|
| Source length (S) | 2 | Estimated content being summarized ÷ S |
|
|
89
88
|
|
|
90
|
-
The target is the
|
|
89
|
+
The target is the smaller result, rounded down. All divisors accept decimals of at least 1. Existing output/source divisors and explicit enable choices are preserved. New or unspecified guidance remains **off**.
|
|
91
90
|
|
|
92
|
-
|
|
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.
|
|
92
|
+
|
|
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.
|
|
94
|
+
|
|
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.
|
|
93
96
|
|
|
94
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.
|
|
95
98
|
|
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/CAPABILITIES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Verified model capabilities
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Capability synchronization uses the preview, backup, rollback and idle-only synchronization workflow. It does not send generation requests or alter Strata Server.
|
|
4
4
|
|
|
5
5
|
## Input types
|
|
6
6
|
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- **同步模型设置:**上下文窗口、回复输出上限,以及已确认的输入类型和推理等级。
|
|
12
12
|
- **对齐压缩预算:**更新已启用的 DSH Agent 预设中,对应模型的压缩策略。
|
|
13
|
-
-
|
|
13
|
+
- **控制摘要长度:**编辑补充提示词,调整两项目标长度比例。
|
|
14
14
|
- **启动时同步:**可选择在 DSH 启动并空闲后同步一次。
|
|
15
15
|
- **预览与恢复:**检查差异、备份设置,并查看最近一次同步结果。
|
|
16
16
|
|
|
@@ -69,7 +69,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
69
69
|
|
|
70
70
|
## 摘要提示词与目标长度
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
**动态摘要目标**默认关闭。启用后会在 DSH 原生摘要指令后补充要求;关闭时使用 DSH 原生摘要与压缩行为。
|
|
73
73
|
|
|
74
74
|
可编辑的**摘要补充提示词**默认内容为:
|
|
75
75
|
|
|
@@ -79,17 +79,20 @@ Keep the entire checkpoint, including all required headings, within a target of
|
|
|
79
79
|
|
|
80
80
|
请保留 `{target}`,每次支持的摘要请求前,它会替换成计算出的 token 目标。模板最多 2,048 个字符。点击**恢复默认提示词**可重置内容,再点击**保存偏好**应用修改。
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
两个除数控制目标,默认均为 **2(各取 50%)**:
|
|
83
83
|
|
|
84
84
|
| 除数 | 默认值 | 将目标限制为 |
|
|
85
85
|
|---|---:|---|
|
|
86
|
-
|
|
|
87
|
-
| 摘要输出(O) | 2 | 本次摘要实际输出上限 ÷ O |
|
|
86
|
+
| 摘要输出(O) | 2 | 估算有效摘要输出预算 ÷ O |
|
|
88
87
|
| 原文长度(S) | 2 | 待摘要内容的估算长度 ÷ S |
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
目标取两项结果的较小值,再向下取整。除数支持大于或等于 1 的小数。已有输出/原文除数及明确的启用选择会保留,新安装或未指定时仍**默认关闭**。
|
|
91
90
|
|
|
92
|
-
|
|
91
|
+
有效输出预算是**估算值**,不是直接把请求的 `maxTokens` 当作服务器确认的上限。它取本次摘要输出上限与估算上下文剩余空间中的较小值;后者使用已确认的服务器/客户端窗口较小值,扣除完整提示内容(包含系统提示、工具定义和补充句),再预留支持的 pi-ai 适配器所用的 4,096 tokens 安全空间。文本以每 token 约 3.5 字符并加上格式成本估算。原文长度另采用 DSH 的每 token 约 4 字符估算,不含系统提示、工具和摘要指令。两者都不是精确 tokenizer 计数。
|
|
92
|
+
|
|
93
|
+
例如,有效输出预算为 4,096 tokens 且原文足够长时,32K 与 64K 上下文的目标都是 **2,048 tokens**;原文只有约 2,000 tokens 时,目标为 **1,000 tokens**。上下文剩余空间不足时,目标会进一步降低。界面仅以提议的摘要上限预览目标上界,尚未扣除个别请求的成本。
|
|
94
|
+
|
|
95
|
+
这是写作指令,**不是输出硬上限,也不能保证不截断**。思考可能共用输出预算;插件不会修改思考设置、`maxTokens`、`fit_max_tokens` 或压缩时机。服务器实际 tokenizer、后续中间层或不同适配器版本仍可能产生更低的上限。
|
|
93
96
|
|
|
94
97
|
保存摘要偏好不会改变模型预算,也不会替换原生提示词或增加额外推理、重试循环。无法验证请求、无法安全估算内容,或目标小于 256 tokens 时,会沿用原本的摘要请求。
|
|
95
98
|
|
package/docs/README.zh-TW.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- **同步模型設定:**上下文視窗、回覆輸出上限,以及已確認的輸入類型和推理等級。
|
|
12
12
|
- **對齊壓縮預算:**更新已啟用的 DSH Agent 預設中,對應模型的壓縮政策。
|
|
13
|
-
-
|
|
13
|
+
- **控制摘要長度:**編輯補充提示詞,調整兩項目標長度比例。
|
|
14
14
|
- **啟動時同步:**可選擇在 DSH 啟動並閒置後同步一次。
|
|
15
15
|
- **預覽與復原:**檢查差異、備份設定,並查看最近一次同步結果。
|
|
16
16
|
|
|
@@ -69,7 +69,7 @@ dsh plugin --profile desktop add dsh-strata-sync --registry=https://registry.npm
|
|
|
69
69
|
|
|
70
70
|
## 摘要提示詞與目標長度
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
**動態摘要目標**預設關閉。啟用後會在 DSH 原生摘要指令後補充要求;關閉時使用 DSH 原生摘要與壓縮行為。
|
|
73
73
|
|
|
74
74
|
可編輯的**摘要補充提示詞**預設內容為:
|
|
75
75
|
|
|
@@ -79,17 +79,20 @@ Keep the entire checkpoint, including all required headings, within a target of
|
|
|
79
79
|
|
|
80
80
|
請保留 `{target}`,每次支援的摘要請求前,它會替換成計算出的 token 目標。範本最多 2,048 個字元。點選**還原預設提示詞**可重設內容,再點選**儲存偏好**套用修改。
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
兩個除數控制目標,預設均為 **2(各取 50%)**:
|
|
83
83
|
|
|
84
84
|
| 除數 | 預設值 | 將目標限制為 |
|
|
85
85
|
|---|---:|---|
|
|
86
|
-
|
|
|
87
|
-
| 摘要輸出(O) | 2 | 本次摘要實際輸出上限 ÷ O |
|
|
86
|
+
| 摘要輸出(O) | 2 | 估算有效摘要輸出預算 ÷ O |
|
|
88
87
|
| 原文長度(S) | 2 | 待摘要內容的估算長度 ÷ S |
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
目標取兩項結果的較小值,再向下取整。除數支援大於或等於 1 的小數。既有輸出/原文除數及明確的啟用選擇會保留,新安裝或未指定時仍**預設關閉**。
|
|
91
90
|
|
|
92
|
-
|
|
91
|
+
有效輸出預算是**估算值**,不是直接把請求的 `maxTokens` 當作伺服器確認的上限。它取本次摘要輸出上限與估算上下文剩餘空間中的較小值;後者使用已確認的伺服器/客戶端視窗較小值,扣除完整提示內容(包含系統提示、工具定義和補充句),再預留支援的 pi-ai 轉接器所用的 4,096 tokens 安全空間。文字以每 token 約 3.5 字元並加上格式成本估算。原文長度另採 DSH 的每 token 約 4 字元估算,不含系統提示、工具和摘要指令。兩者都不是精確 tokenizer 計數。
|
|
92
|
+
|
|
93
|
+
例如,有效輸出預算為 4,096 tokens 且原文足夠長時,32K 與 64K 上下文的目標都是 **2,048 tokens**;原文只有約 2,000 tokens 時,目標為 **1,000 tokens**。上下文剩餘空間不足時,目標會進一步降低。介面僅以提議的摘要上限預覽目標上界,尚未扣除個別請求的成本。
|
|
94
|
+
|
|
95
|
+
這是寫作指令,**不是輸出硬上限,也不能保證不截斷**。思考可能共用輸出預算;外掛不會修改思考設定、`maxTokens`、`fit_max_tokens` 或壓縮時機。伺服器實際 tokenizer、後續中介層或不同轉接器版本仍可能產生更低的上限。
|
|
93
96
|
|
|
94
97
|
儲存摘要偏好不會改變模型預算,也不會替換原生提示詞或增加額外推論、重試循環。無法驗證請求、無法安全估算內容,或目標小於 256 tokens 時,會沿用原本的摘要請求。
|
|
95
98
|
|
package/docs/VALIDATION.md
CHANGED
|
@@ -2,140 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
Validation date: 2026-10-30 (Asia/Taipei).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Current summary behavior
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
7
|
+
- Summary guidance is off by default in the schema, host fallback, request middleware and English, Simplified Chinese and Traditional Chinese interfaces. Explicit enable choices, output/source divisors and editable templates are supported.
|
|
8
|
+
- The writing target is the smaller of estimated effective summary output budget / output divisor and selected-source estimate / source divisor, rounded down. Both divisors default to 2 (50%).
|
|
9
|
+
- Effective output room is estimated 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 reduce usable answer space.
|
|
10
|
+
- The native summary prompt and request options are preserved. Unknown content, unverified metadata and targets below 256 tokens keep native behavior. The hook sends no extra inference requests and adds no retry loop.
|
|
9
11
|
|
|
10
|
-
##
|
|
12
|
+
## Automated verification
|
|
11
13
|
|
|
12
|
-
|
|
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.
|
|
14
|
+
All **155 automated tests pass** for the current runtime. Coverage includes:
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
- Actual pi-ai context clamping across multiple input sizes, near-full and exhausted context, independent source length, additional prompt costs, disabled-mode zero discovery and restored native requests.
|
|
17
|
+
- Native Cordis waterfall dispatch, immutable messages, concurrent summaries, duplicate hooks, cancellation, metadata failures, early stream closure, native errors and unload.
|
|
18
|
+
- Verified model discovery, selected-provider/loaded-model matching, alias validation, input types, model-specific reasoning choices and eight mocked SDK wire cases.
|
|
19
|
+
- Preference validation, idle guards, stale-preview rejection, concurrent edits, backup and rollback, startup synchronization, hot reload and enabled Agent preset policies.
|
|
20
|
+
- Three-language settings rendering, editable prompt preservation, custom divisors, preview ceilings, default-off behavior and preference conflicts.
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
- Backend tests cover native schema defaults and validation, persisted controls across reloads, disabling without metadata requests, re-enabling with a custom divisor, unchanged native compaction, source/output bounds, and changes during discovery. The three-language UI tests cover default-on controls, saving, invalid input, external changes/conflicts, custom previews, disabled state and below-256 fallback messages.
|
|
21
|
-
- A local probe exercised the installed DSH 0.2.1-rc.3 `BasicCompactionEngine.summarize()` through its actual Cordis waterfall. At 32K with a 4,096 summary cap, the default divisor produced 2,048, divisor 32 produced 1,024, disabled guidance preserved the native prompt without discovery, and divisor 8 remained capped at 2,048. Original prompt content, input, output cap, tools and configuration were preserved; unloading restored native behavior. Responses were synthetic: no inference requests were sent.
|
|
22
|
-
- All **142 automated tests pass**, including the package verifier and 33 settings UI tests. These checks validate configuration and integration, not a measured reduction in real-model truncation or compaction frequency.
|
|
22
|
+
The package verifier checks the public file list, English root README selection, translated documentation links, entry points, source/build consistency and publishing metadata. It excludes private configuration, user conversations, credentials, backups and the native-prompt test fixture from the public package.
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Compatibility and limits
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
- The context contribution to the target changes from `/ 32` to `/ 16`. Summary-cap and selected-source bounds stay at `/ 2`; with a 4,096 summary cap, sufficiently long sources at both 32K and 64K now target 2,048 tokens. Other model and compaction settings are unchanged.
|
|
28
|
-
- Necessary verification consists of the 86 affected summary, plugin and UI tests plus the package verifier. Existing 0.8.0 native-runtime integration evidence below is historical; it was not rerun for this arithmetic/name change.
|
|
26
|
+
The integration targets **DSH Desktop 0.2.1-rc.3**, Cordis 4.0.5 and pi-ai 1.1.0. Native-host preview, synchronization, backup and interface checks used an isolated DSH profile and metadata-only fixture server. Native-summary integration probes used synthetic adapter responses.
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
These checks validate configuration, dispatch and preservation of native behavior. They do **not** establish that real models always follow the writing target, never truncate, or compact at an optimal frequency. No inference benchmark was run for this release. Server configuration and the user's running DSH profile were not changed.
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
- The official `llm/stream` waterfall is used without replacing the compaction engine. Tests exercise actual Cordis 4.0.5 services, plugin lifecycle and waterfall dispatch, with immutable native messages, concurrent summaries, duplicate hooks, cancellation, metadata failures, early stream closure, native errors and unload. All non-message request options and the complete native prompt are preserved.
|
|
34
|
-
- Plugin-level integration tests verify fresh metadata reads per summary, selected-provider/loaded-model matching, server identity, concurrent configuration edits and conservative client/server context matching. They assert zero configuration writes or backups during summary guidance. No prompt, raw tool content or credentials are recorded by the feature.
|
|
35
|
-
- A separate local integration probe called the **installed DSH 0.2.1-rc.3 native `BasicCompactionEngine.summarize()`** through its shipped Cordis runtime. Synthetic text yielded 1,024 at 32K and 2,048 at 64K; its original prompt, 4,096 output cap, signals, tools and configuration remained unchanged. Unloading the hook restored the original prompt. The adapter returned synthetic chunks: **no inference service was contacted**.
|
|
36
|
-
- English, Simplified Chinese and Traditional Chinese settings-render tests cover the read-only explanation, preview ceiling, unavailable values and live locale changes without adding preferences. All three READMEs describe the same behavior and limitations. Package verification checks the new runtime module is included and the authentic native-prompt test fixture is excluded from the public tarball.
|
|
37
|
-
- The target is a heuristic writing instruction. These checks establish integration and preservation, **not** that a real model always meets the target, never truncates, or stops compacting frequently. Natural-work model validation remains separate. No server or model settings are changed by this feature.
|
|
38
|
-
|
|
39
|
-
## npm documentation packaging 0.7.1
|
|
40
|
-
|
|
41
|
-
- The 0.7.0 tarball included all three root-level README files. Using the npm 11.19.0 publish-time manifest reader (`pacote` with `fullMetadata` and `fullReadJson`) selected `README.zh-TW.md` rather than `README.md`; the result matched the registry's README filename and length.
|
|
42
|
-
- Version 0.7.1 keeps only the English `README.md` at the package root. The translated READMEs move into `docs/`, along with capability and validation documentation included in the package. README links use absolute GitHub URLs so their destinations work from the npm package page as well as GitHub.
|
|
43
|
-
- All three READMEs now make public-registry installation the primary path and retain source/tarball installation as an alternative. Package metadata supplies explicit documentation, issue-reporting, discovery and publishing information.
|
|
44
|
-
- All **95 tests pass**, including the 94 existing tests and a new publish-artifact regression test. The verifier uses npm's package metadata reader and actual pack file list to check the chosen README, all 11 public files, documentation links, entry points, current build artifacts and publishing metadata. It runs again through `prepublishOnly` for directory publication. Dependency audit reported no known vulnerabilities.
|
|
45
|
-
- This patch changes release packaging and documentation, not the synchronization runtime. The native DSH checks described under 0.7.0 remain the prior integration baseline. Registry publication and npm website rendering must be verified separately after release.
|
|
46
|
-
- The observed 0.7.0 npm page showed no README even though registry metadata contained its text, matching a staged-publishing website/registry discrepancy reported in [npm/cli issue 9405](https://github.com/npm/cli/issues/9405). The root README selection issue is separately reproducible; fixing it does not by itself prove the website discrepancy is resolved.
|
|
47
|
-
|
|
48
|
-
## Synchronization and settings safeguards 0.7.0
|
|
49
|
-
|
|
50
|
-
- All **94 tests pass**, including 29 new regression tests. Coverage now includes changes during discovery and queued writes, revision-checked preference patches, multi-window conflicts, busy-to-idle startup deferral, startup readiness errors, alias resolution, non-text generators, unsupported catalog routes, delayed status responses and retained sync results.
|
|
51
|
-
- Explicitly verified the originally reported races: changing model settings during an apply query now rejects the stale preview without overwriting the newer value; a task beginning during startup discovery leaves synchronization pending until idle.
|
|
52
|
-
- The UI follows untouched preferences from other windows, reports conflicts for locally edited preferences, sends only changed fields with their baseline revision, and ignores older delayed status responses. Latest synchronization results from other windows replace older local results.
|
|
53
|
-
- All three locales cover automatic/manual output controls, provenance, partial capability alignment and result summaries. No independent language selector was added.
|
|
54
|
-
- Packed 0.7.0 and installed it through the official DSH plugin installer into the existing isolated DSH Desktop 0.2.1-rc.3 web profile. Startup synchronization, native preference saving/hot reload, manual 8,192-token output preview/application and result-card retention succeeded.
|
|
55
|
-
- Returned the isolated profile to automatic output mode. With a fixture server default of 4,096 and context 32,768, preview and apply used 4,096 output tokens and a 24,576-token (75%) compaction threshold. The UI distinguished the server default, effective value and source, and reported a backup.
|
|
56
|
-
- Native English and Simplified Chinese settings were checked through the browser. The installed host offers en/zh; Traditional Chinese is covered by automated locale/rendering tests. Reviewed the native result-card layout visually.
|
|
57
|
-
- Catalog-only routes and nonempty modelOverrides are rejected during preview; support for editing catalog overrides is not claimed. Existing explicit custom model lists remain supported, including adding the newly loaded canonical model.
|
|
58
|
-
- The fixture accepts metadata requests only. Production DSH, OpenCode and Strata server settings were not modified, and no inference requests were sent.
|
|
59
|
-
|
|
60
|
-
## Server output defaults 0.6.0
|
|
61
|
-
|
|
62
|
-
- All 65 tests pass. New coverage includes fixed server caps, absent/null and unlimited (-1/0) defaults, unavailable props, wrong model/Strata identity, invalid types, insufficient compaction space, manual precedence, stale-preview rejection after server-cap changes, applied model limits and translated output provenance.
|
|
63
|
-
- Uses the existing metadata-only GET /props?model=... response, specifically default_generation_settings.params.n_predict. [Strata server source](https://github.com/Niko1221/Strata/blob/main/serve/server.py) exposes the shared max_tokens default there; it is a default rather than a hard model maximum.
|
|
64
|
-
- Native isolated DSH 0.2.1-rc.3 startup sync adopted an 8,192-token fixture default at 32,768 context and saved a backup. English and Chinese previews reported the server source, a 20,480-token compaction threshold and unchanged 4,096 summary allowance.
|
|
65
|
-
- Changing only the fixture cap to -1 yielded a fresh preview of 9,830 output tokens, Automatic calculation, and an 18,842-token compaction threshold. This fallback preview was not applied. Traditional Chinese provenance is covered by UI tests.
|
|
66
|
-
- The updated English settings screenshot is retained locally only; it is not published with this release. Production DSH and the actual Strata server were not modified; no inference requests were sent.
|
|
67
|
-
|
|
68
|
-
## DSH language and startup synchronization 0.5.0
|
|
69
|
-
|
|
70
|
-
- All 58 tests pass. Regression coverage includes DSH locale subscriptions and cleanup, ignoring obsolete browser language preferences, Chinese regional variants, idle deferral, one attempt per process/profile, no repeat reads after completion/failure, HMR deduplication and manual retry availability.
|
|
71
|
-
- Installed the packed 0.5.0 bundle only in the existing isolated DSH Desktop 0.2.1-rc.3 web profile. Native English and Chinese UI switches automatically update the plugin. The language selector and product disclaimer are absent. The stock host exposes en/zh; Traditional Chinese regional mapping is covered by automated tests.
|
|
72
|
-
- Enabled startup sync in the UI. Saving the preference left the model at 32,768/9,830. Restarted only the isolated host; it synchronized the fixture model to 65,536/16,384 and displayed its successful sync timestamp and backup path. No Apply action or inference was used.
|
|
73
|
-
- The English screenshot is a fresh native-host capture. Older screenshots are not linked from the current READMEs.
|
|
74
|
-
- Production DSH and Strata configuration were not changed. Language integration uses DSH's locale service (getLocale/subscribe), described in [upstream client locale source](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/locale/src/client/index.ts).
|
|
75
|
-
|
|
76
|
-
## Difference-table layout 0.4.1
|
|
77
|
-
|
|
78
|
-
All 56 existing tests passed after the UI renderer change. In the isolated native host, a 32K-to-64K preview rendered a 528px table without horizontal overflow, with approximately 180/174/174px columns and right-aligned current/after values. English, Traditional Chinese and Simplified Chinese headers and values were checked in the live DOM. This version also renders capability arrays as chips, nested mappings as expandable details, and stacks rows when the table container is narrower than 440px. The narrow layout has not received a separate visual check. Browser screenshot capture timed out, so existing 0.4.0 screenshots are retained rather than presented as new captures. No synchronization was applied in this layout check.
|
|
79
|
-
|
|
80
|
-
## Capability synchronization 0.4.0
|
|
81
|
-
|
|
82
|
-
- All 56 automated tests pass. New checks cover verified template profiles, exact native efforts, unknown/malformed inputs, unverified reasoning preservation, conflicting provider defaults, localized warnings, stale capabilities, rollback and preservation of unrelated compatibility fields.
|
|
83
|
-
- Eight SDK wire tests use the public pi-ai 1.1.0 SDK (matching the installed DSH package version) with mocked fetch responses. Qwen off/low/medium/xhigh and DeepSeek off/low/high/max produce the expected thinking booleans and effort values. No inference endpoint is contacted.
|
|
84
|
-
- Queried the real Strata server's model and props metadata read-only: 32K Qwen with text/image input and the reviewed Qwen template. Inspected installed DeepSeek and Huihui tokenizer templates without loading them. Raw templates stay outside the repository.
|
|
85
|
-
- Installed the plugin into the isolated native DSH Desktop 0.2.1-rc.3 test profile. The fixture served the reviewed Qwen and DeepSeek templates as metadata. Preview/apply succeeded for each, retained 32K/9,830 budgets, saved profile backups, and the second preview showed no changes.
|
|
86
|
-
- Opened DSH's native Models editor and confirmed Qwen's context, output, text/image input and off/low/medium/xhigh entries. The DeepSeek test profile saved off/low/high/max.
|
|
87
|
-
- Unknown templates are covered by preservation tests; the plugin does not infer supported efforts from a model name or claim all future templates are compatible.
|
|
88
|
-
- Model inference quality, physical vision encoding and the production DSH profile were not changed or tested.
|
|
89
|
-
|
|
90
|
-
## Multilingual release 0.3.0
|
|
91
|
-
|
|
92
|
-
- All 38 automated tests pass, including Chinese preview labels and warnings, translated apply notices, local language persistence, invalid-language fallback and unchanged RPC write behavior on language switching.
|
|
93
|
-
- Packed and installed 0.3.0 in the isolated DSH Desktop 0.2.1-rc.3 web profile.
|
|
94
|
-
- Verified English, Traditional Chinese and Simplified Chinese in Settings → Strata Sync, including metadata preview and budget labels.
|
|
95
|
-
- Verified the selected language remains after leaving and reopening the Settings section.
|
|
96
|
-
- Captured the three native screenshots linked from the README editions.
|
|
97
|
-
- The npm package includes all three README editions. Unknown backend diagnostics deliberately retain their original text.
|
|
98
|
-
- No production DSH or Strata settings were changed; the native check only read metadata.
|
|
99
|
-
|
|
100
|
-
## Previous version scope
|
|
101
|
-
|
|
102
|
-
Version **0.2.0** moves the English interface to **Settings → Strata Sync**. Its Settings navigation, preferences, preview and synchronization were verified in the native host. The synchronization backend is unchanged from 0.1.0; the earlier full automatic-polling validation is retained below.
|
|
103
|
-
|
|
104
|
-
## Completed automated checks for 0.2.0
|
|
105
|
-
|
|
106
|
-
`npm test`: 35 passing tests covering discovery, native-client registration and UI behavior, budgeting, credentials, redirects, concurrent changes, lifecycle disposal, rollback, preset activation, retention inheritance and HMR timer context.
|
|
107
|
-
|
|
108
|
-
The updated UI tests require registration in `settings.section`, reject the old `plugins.item` location, and verify English UI text. Repository source and documentation were also scanned for remaining Chinese text; the screenshot was replaced with the English Settings page.
|
|
109
|
-
|
|
110
|
-
`npm run build` and `npm pack` produce the native host and browser entries. The package contains original plugin code only; no extracted DSH code, credentials, user conversations, server configuration or backups are distributed.
|
|
111
|
-
|
|
112
|
-
## Native Settings validation for 0.2.0
|
|
113
|
-
|
|
114
|
-
Using the installed DSH Desktop 0.2.1-rc.3 host with an isolated web profile and a metadata-only local fixture:
|
|
115
|
-
|
|
116
|
-
- Installed version 0.2.0 using the official plugin installer.
|
|
117
|
-
- Navigated through Account menu → Settings → Strata Sync; confirmed the page is a first-level Settings section.
|
|
118
|
-
- Switched only the isolated test profile to English to capture an entirely English screenshot.
|
|
119
|
-
- Previewed the context mismatch, used **Back up and sync**, and verified the saved context/output limits were 32,768/9,830 with a profile backup.
|
|
120
|
-
- Saved and cleared an output-budget override using **Save preferences**.
|
|
121
|
-
- Checked again and confirmed the settings were aligned.
|
|
122
|
-
|
|
123
|
-
No production DSH settings or Strata server settings were changed.
|
|
124
|
-
|
|
125
|
-
## Earlier native backend validation for 0.1.0
|
|
126
|
-
|
|
127
|
-
Tested using the installed DSH Desktop 0.2.1-rc.3 host in an isolated web profile, with a local metadata-only fixture. The real user profile and running inference server were not modified.
|
|
128
|
-
|
|
129
|
-
- Installed the packed bundle through the official DSH plugin installer.
|
|
130
|
-
- Opened the actual DSH Plugins page and Strata Sync UI used by version 0.1.0.
|
|
131
|
-
- Saved preferences, previewed a 64K-to-32K mismatch, and applied the change.
|
|
132
|
-
- Confirmed the native ConfigEditor saved the model limit and the exact provider/model policy in four enabled Agent presets: `standard`, `ptc`, `minimal`, and `cordis`.
|
|
133
|
-
- Confirmed the original profile was backed up, preset activation succeeded, and a second preview reported no differences.
|
|
134
|
-
- Toggled auto-sync off and on in the real UI, changed the fixture to 65,536 tokens, and verified the normal 60-second poll updated the DSH model from 32,768/9,830 to 65,536/16,384 without a manual apply or application restart.
|
|
135
|
-
- Verified metadata traffic uses only `GET /v1/models` and `GET /slots`; no inference endpoint is implemented by the fixture.
|
|
136
|
-
|
|
137
|
-
The native test exposed two host integration details now covered by regression tests: inactive root compaction placeholders must not be edited, and a timer created during HMR reload must exit the inherited transaction context before future ConfigEditor calls.
|
|
138
|
-
|
|
139
|
-
## Limits of validation
|
|
140
|
-
|
|
141
|
-
This validates configuration synchronization and native UI integration, not model answer quality or completion of arbitrary long summaries. No inference benchmark was run. Existing DSH conversations retain their Agent preset revision; start a new conversation after synchronization. The production DSH profile has not been modified or restarted by this validation.
|
|
30
|
+
Existing conversations retain their Agent preset revision; start a new conversation after synchronizing model settings.
|