@heixui/dsh-session-suite 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.js +24 -0
- package/cordis.patch.yml +13 -6
- package/index.js +4 -0
- package/lib/api.js +8 -2
- package/lib/memory-host.js +22 -2
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -272,6 +272,7 @@ window.__ModuleLoader__.load({
|
|
|
272
272
|
'memory.extractionNotRegistered': 'HOOK NOT REGISTERED',
|
|
273
273
|
'memory.extractionNoTrace': 'no extraction trace recorded by this Host',
|
|
274
274
|
'memory.diagTitle': 'Extraction diagnostics:',
|
|
275
|
+
'memory.diagSteps': '{ok}/{total} hooks installed',
|
|
275
276
|
'memory.accept': 'Keep',
|
|
276
277
|
'memory.reject': 'Discard',
|
|
277
278
|
'memory.accepted': 'Kept',
|
|
@@ -520,6 +521,7 @@ window.__ModuleLoader__.load({
|
|
|
520
521
|
'memory.extractionNotRegistered': '钩子未注册',
|
|
521
522
|
'memory.extractionNoTrace': '本次运行没有记录到提取痕迹',
|
|
522
523
|
'memory.diagTitle': '提取诊断:',
|
|
524
|
+
'memory.diagSteps': '{ok}/{total} 个钩子已装',
|
|
523
525
|
'memory.accept': '保留',
|
|
524
526
|
'memory.reject': '丢弃',
|
|
525
527
|
'memory.accepted': '已保留',
|
|
@@ -1047,6 +1049,7 @@ window.__ModuleLoader__.load({
|
|
|
1047
1049
|
font-weight: 600;
|
|
1048
1050
|
color: var(--dsw-alias-label-primary, #1f1f1f);
|
|
1049
1051
|
}
|
|
1052
|
+
.dss-diag-steps { color: var(--dsw-alias-label-secondary, #6b6b6b); }
|
|
1050
1053
|
/* The summary charts. Two narrow panels for composition and health, one wide panel
|
|
1051
1054
|
for tags: composition and health are short lists, tags can run long. Bars are divs,
|
|
1052
1055
|
not SVG, so they inherit the theme and stay legible in both palettes. */
|
|
@@ -3449,6 +3452,10 @@ window.__ModuleLoader__.load({
|
|
|
3449
3452
|
// unremarkable" from "every memory model failed" or "a filter ate the
|
|
3450
3453
|
// result". When there is nothing pending, say why.
|
|
3451
3454
|
const extraction = status?.extraction
|
|
3455
|
+
// Which optional hooks installed. Reported separately from the extraction trace
|
|
3456
|
+
// because a hook that never installed cannot write a trace — that is the whole
|
|
3457
|
+
// point: "no trace" has two causes and this separates them.
|
|
3458
|
+
const installStatus = Array.isArray(status?.install) ? status.install : []
|
|
3452
3459
|
const pendingBlock =
|
|
3453
3460
|
pending.length > 0
|
|
3454
3461
|
? h(
|
|
@@ -3565,6 +3572,23 @@ window.__ModuleLoader__.load({
|
|
|
3565
3572
|
: t('memory.extractionNotRegistered'),
|
|
3566
3573
|
)
|
|
3567
3574
|
: null,
|
|
3575
|
+
// The registration ledger: which optional hooks installed and which
|
|
3576
|
+
// threw. This is the only way to see a step that never ran, because the
|
|
3577
|
+
// code that would have reported it is the code that failed.
|
|
3578
|
+
installStatus.length > 0
|
|
3579
|
+
? h(
|
|
3580
|
+
'span',
|
|
3581
|
+
{ className: 'dss-diag-steps' },
|
|
3582
|
+
t('memory.diagSteps', {
|
|
3583
|
+
ok: installStatus.filter(step => step.ok).length,
|
|
3584
|
+
total: installStatus.length,
|
|
3585
|
+
}),
|
|
3586
|
+
installStatus
|
|
3587
|
+
.filter(step => !step.ok)
|
|
3588
|
+
.map(step => ` · ${step.label}: ${step.error ?? 'failed'}`)
|
|
3589
|
+
.join(''),
|
|
3590
|
+
)
|
|
3591
|
+
: null,
|
|
3568
3592
|
),
|
|
3569
3593
|
)
|
|
3570
3594
|
|
package/cordis.patch.yml
CHANGED
|
@@ -54,12 +54,19 @@
|
|
|
54
54
|
# says otherwise.
|
|
55
55
|
recallLimit: 6
|
|
56
56
|
# How much of the conversation before the current message is folded into the
|
|
57
|
-
# retrieval query.
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
|
|
57
|
+
# retrieval query. DEFAULT 0 = OFF.
|
|
58
|
+
#
|
|
59
|
+
# Why off by default: the model already receives the full conversation history,
|
|
60
|
+
# so it knows what 「它」 refers to. Folding earlier turns into the query only
|
|
61
|
+
# helps the RETRIEVAL step pick a better memory; it does not make the model
|
|
62
|
+
# understand the question better. That is a real but small gain, and it costs a
|
|
63
|
+
# little accuracy on self-contained questions that get padded unnecessarily.
|
|
64
|
+
#
|
|
65
|
+
# Turn it on when the prompt is short by design — a workflow that deliberately
|
|
66
|
+
# keeps requests small (an agent that works from a compact brief rather than a
|
|
67
|
+
# long transcript) benefits, because there the history is NOT in the prompt.
|
|
68
|
+
# 160 characters across 3 previous turns is a reasonable starting point.
|
|
69
|
+
contextQueryChars: 0
|
|
63
70
|
contextQueryTurns: 3
|
|
64
71
|
# How many of the most important memories ride along regardless of the
|
|
65
72
|
# question. Without a resident layer, an ordinary follow-up like "继续"
|
package/index.js
CHANGED
|
@@ -97,6 +97,10 @@ export function apply(ctx, config = {}) {
|
|
|
97
97
|
try {
|
|
98
98
|
const installed = installMemory({ ctx, root, config, log })
|
|
99
99
|
service.longTerm = installed.engine
|
|
100
|
+
// Kept separately: the engine is the memory store, and this is the record of
|
|
101
|
+
// which optional registrations succeeded. Exposed through the status endpoint so
|
|
102
|
+
// a missing feature can be traced to a step that never installed.
|
|
103
|
+
service.memoryInstallStatus = installed.installStatus
|
|
100
104
|
log('long-term memory engine ready')
|
|
101
105
|
} catch (error) {
|
|
102
106
|
log('long-term memory failed to install; continuing without it', error)
|
package/lib/api.js
CHANGED
|
@@ -303,8 +303,14 @@ async function respond(service, deps, action, input) {
|
|
|
303
303
|
})
|
|
304
304
|
case 'longterm.maintain':
|
|
305
305
|
return json({ ok: true, data: await service.longTerm.maintain(workspaceOf(input)) })
|
|
306
|
-
case 'longterm.status':
|
|
307
|
-
|
|
306
|
+
case 'longterm.status': {
|
|
307
|
+
// The engine's own status plus the registration ledger. Two sources on purpose:
|
|
308
|
+
// the engine cannot report a hook that never installed, because the code that
|
|
309
|
+
// would have written it is the code that failed.
|
|
310
|
+
const status = await service.longTerm.status()
|
|
311
|
+
const install = typeof service.memoryInstallStatus === 'function' ? service.memoryInstallStatus() : []
|
|
312
|
+
return json({ ok: true, data: { ...status, install } })
|
|
313
|
+
}
|
|
308
314
|
case 'longterm.workspaces':
|
|
309
315
|
return json({ ok: true, data: await service.longTerm.workspaces() })
|
|
310
316
|
case 'longterm.models':
|
package/lib/memory-host.js
CHANGED
|
@@ -91,13 +91,21 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
91
91
|
* Run one optional registration; a failure is reported and skipped so a single
|
|
92
92
|
* incompatible hook can never disable the rest of the bundle.
|
|
93
93
|
*
|
|
94
|
+
* Every step records its outcome. The silent-catch was the reason a broken step was
|
|
95
|
+
* invisible: "the queue is empty" could mean the hook was never installed, and
|
|
96
|
+
* nothing on screen said so. The steps list is published through status() so the
|
|
97
|
+
* settings page can show which registrations succeeded.
|
|
98
|
+
*
|
|
94
99
|
* @param {string} label what is being installed
|
|
95
100
|
* @param {() => void} install registration body
|
|
96
101
|
*/
|
|
102
|
+
const steps = []
|
|
97
103
|
const safe = (label, install) => {
|
|
98
104
|
try {
|
|
99
105
|
install()
|
|
106
|
+
steps.push({ label, ok: true })
|
|
100
107
|
} catch (error) {
|
|
108
|
+
steps.push({ label, ok: false, error: error instanceof Error ? error.message : String(error) })
|
|
101
109
|
log(`long-term memory: ${label} failed to install`, error)
|
|
102
110
|
}
|
|
103
111
|
}
|
|
@@ -410,6 +418,9 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
410
418
|
return {
|
|
411
419
|
engine,
|
|
412
420
|
dispose: () => {},
|
|
421
|
+
// The outcome of every optional registration, so "the queue is empty" can be
|
|
422
|
+
// traced to a specific step that never installed.
|
|
423
|
+
installStatus: () => [...steps],
|
|
413
424
|
// Exposed so the settings page and the status endpoint can report whether the
|
|
414
425
|
// last recall rebuild failed. Without this the failure is silent: the model
|
|
415
426
|
// simply acts as if the memory is not there.
|
|
@@ -535,8 +546,17 @@ function contextualQuery(messages, limits = {}) {
|
|
|
535
546
|
const current = lastUserText(messages)
|
|
536
547
|
if (!current) return ''
|
|
537
548
|
|
|
538
|
-
|
|
539
|
-
|
|
549
|
+
// 0 is the default, and it means disabled.
|
|
550
|
+
//
|
|
551
|
+
// Why: the model already receives the conversation history, so it knows what a
|
|
552
|
+
// pronoun refers to. Folding earlier turns into the retrieval query only improves
|
|
553
|
+
// which MEMORY is picked — a real but small gain — and it costs a little accuracy
|
|
554
|
+
// on self-contained questions that get padded unnecessarily. It matters for a
|
|
555
|
+
// workflow that deliberately keeps the prompt small, where the history is not there
|
|
556
|
+
// to be read; that is the case this exists for, and it is opt-in.
|
|
557
|
+
const maxChars = typeof limits.chars === 'number' ? limits.chars : 0
|
|
558
|
+
const maxTurns = typeof limits.turns === 'number' ? limits.turns : 3
|
|
559
|
+
if (maxChars <= 0) return current
|
|
540
560
|
|
|
541
561
|
// A self-contained question needs no help. The test is NOT length alone: a short
|
|
542
562
|
// question that names its own subject ("导出的图片为什么断链") is self-contained,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heixui/dsh-session-suite",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Session checkpoints for DSH: rewind a conversation with its files and memory, permanent session deletion, and shareable exports",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|