@heixui/dsh-session-suite 0.3.0 → 0.3.2
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 +47 -0
- package/cordis.patch.yml +6 -1
- package/lib/memory-host.js +45 -2
- package/package.json +5 -2
package/client.js
CHANGED
|
@@ -2863,9 +2863,55 @@ window.__ModuleLoader__.load({
|
|
|
2863
2863
|
|
|
2864
2864
|
// ------------------------------------------------------------------ apply
|
|
2865
2865
|
|
|
2866
|
+
/**
|
|
2867
|
+
* Report a Client-half failure somewhere a human can find it.
|
|
2868
|
+
*
|
|
2869
|
+
* A throw inside apply() makes the whole module register nothing, and the
|
|
2870
|
+
* symptom is silence: no settings page, no session-menu rows, no buttons.
|
|
2871
|
+
* There is no error surface of its own, so record the failure on a global and
|
|
2872
|
+
* log it loudly. This exists because the failure was invisible for several
|
|
2873
|
+
* rounds of debugging, with only a metadata warning to go on.
|
|
2874
|
+
*
|
|
2875
|
+
* @param {string} stage where it broke
|
|
2876
|
+
* @param {unknown} error what was thrown
|
|
2877
|
+
*/
|
|
2878
|
+
function reportClientFailure(stage, error) {
|
|
2879
|
+
const detail = {
|
|
2880
|
+
bundle: 'dsh-session-suite',
|
|
2881
|
+
stage,
|
|
2882
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2883
|
+
stack: error instanceof Error ? String(error.stack ?? '').split('\n').slice(0, 6).join('\n') : '',
|
|
2884
|
+
at: new Date().toISOString(),
|
|
2885
|
+
}
|
|
2886
|
+
try {
|
|
2887
|
+
globalThis.__DSH_SESSION_SUITE_ERROR__ = detail
|
|
2888
|
+
} catch {
|
|
2889
|
+
/* a frozen global is not worth failing over */
|
|
2890
|
+
}
|
|
2891
|
+
try {
|
|
2892
|
+
console.error('[dsh-session-suite] client half failed', detail)
|
|
2893
|
+
} catch {
|
|
2894
|
+
/* console may be unavailable in a sandboxed runtime */
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2866
2898
|
return {
|
|
2867
2899
|
inject: ['slots', 'locale'],
|
|
2868
2900
|
apply(ctx) {
|
|
2901
|
+
try {
|
|
2902
|
+
applyInner(ctx)
|
|
2903
|
+
} catch (error) {
|
|
2904
|
+
reportClientFailure('apply', error)
|
|
2905
|
+
throw error
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
/**
|
|
2909
|
+
* The real body. Split out so one try/catch can cover every registration
|
|
2910
|
+
* without wrapping each line.
|
|
2911
|
+
*
|
|
2912
|
+
* @param {any} ctx client context
|
|
2913
|
+
*/
|
|
2914
|
+
function applyInner(ctx) {
|
|
2869
2915
|
const t = ctx.locale.bind(NS)
|
|
2870
2916
|
ctx.effect(() => ctx.locale.register(NS, DICTS))
|
|
2871
2917
|
ctx.effect(installStyles)
|
|
@@ -2968,6 +3014,7 @@ window.__ModuleLoader__.load({
|
|
|
2968
3014
|
withT(MemorySection),
|
|
2969
3015
|
),
|
|
2970
3016
|
)
|
|
3017
|
+
}
|
|
2971
3018
|
},
|
|
2972
3019
|
}
|
|
2973
3020
|
},
|
package/cordis.patch.yml
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
# half adds the sidebar rows, the message actions, and the settings pages.
|
|
6
6
|
- insert:
|
|
7
7
|
- id: session-suite
|
|
8
|
-
|
|
8
|
+
# The row id stays `session-suite` — patches and stored state key off it —
|
|
9
|
+
# while the package specifier is the published scoped name. They diverged
|
|
10
|
+
# when the npm name changed: the row still said `dsh-session-suite`, which
|
|
11
|
+
# no longer resolves, so the module never loaded and the entire Client half
|
|
12
|
+
# (settings pages, session menu rows, message buttons) was silently absent.
|
|
13
|
+
name: "@heixui/dsh-session-suite"
|
|
9
14
|
config:
|
|
10
15
|
# ---------- session snapshots ----------
|
|
11
16
|
# Automatic checkpoints kept per session (locked ones do not count).
|
package/lib/memory-host.js
CHANGED
|
@@ -110,6 +110,21 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
110
110
|
*/
|
|
111
111
|
const recallByScope = new Map()
|
|
112
112
|
let lastRecall = ''
|
|
113
|
+
// Diagnostics for the settings page: "did the last rebuild fail, and why" must
|
|
114
|
+
// be answerable, because the failure mode is invisible otherwise — the model
|
|
115
|
+
// simply behaves as if the memory is missing.
|
|
116
|
+
let lastRecallFailed = false
|
|
117
|
+
let lastRecallError = ''
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* How long a computed recall may be reused before it must be recomputed.
|
|
121
|
+
*
|
|
122
|
+
* `agent/pre-step` normally refreshes it every step, so this only matters when
|
|
123
|
+
* a step does not run the hook (a resumed session, a step served from a cached
|
|
124
|
+
* decision). Without a bound, a memory written elsewhere could stay invisible
|
|
125
|
+
* for the life of the process.
|
|
126
|
+
*/
|
|
127
|
+
const RECALL_TTL_MS = 60_000
|
|
113
128
|
|
|
114
129
|
// --- 1. Recall into the system prompt -----------------------------------
|
|
115
130
|
const systemPrompt = ctx.get('systemPrompt')
|
|
@@ -122,7 +137,11 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
122
137
|
order: 900,
|
|
123
138
|
text: context => {
|
|
124
139
|
const scoped = context?.scope ? recallByScope.get(context.scope) : undefined
|
|
125
|
-
|
|
140
|
+
// Expiry is checked here rather than only at write time: a cached
|
|
141
|
+
// value outlives its usefulness the moment the library changes
|
|
142
|
+
// underneath it, and this is the only place that can see the age.
|
|
143
|
+
if (scoped && Date.now() - scoped.at < RECALL_TTL_MS) return scoped.text
|
|
144
|
+
return lastRecall || ''
|
|
126
145
|
},
|
|
127
146
|
}),
|
|
128
147
|
'session-suite: memory context',
|
|
@@ -160,7 +179,19 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
160
179
|
const text = await buildRecallText({ engine, cwd, question, config })
|
|
161
180
|
if (agent) recallByScope.set(agent, { text, at: Date.now() })
|
|
162
181
|
lastRecall = text
|
|
182
|
+
lastRecallFailed = false
|
|
163
183
|
} catch (error) {
|
|
184
|
+
// A failed rebuild must not leave the previous answer in place.
|
|
185
|
+
//
|
|
186
|
+
// Observed in the wild: one failed rebuild, and every later turn kept
|
|
187
|
+
// injecting the memory text computed BEFORE it — a memory written after
|
|
188
|
+
// that point was invisible for the rest of the process, which reads as
|
|
189
|
+
// "the other workspace does not know". Stale recall is worse than no
|
|
190
|
+
// recall: empty at least tells the truth.
|
|
191
|
+
lastRecall = ''
|
|
192
|
+
if (agent) recallByScope.delete(agent)
|
|
193
|
+
lastRecallFailed = true
|
|
194
|
+
lastRecallError = error instanceof Error ? error.message : String(error)
|
|
164
195
|
log('memory recall failed', error)
|
|
165
196
|
}
|
|
166
197
|
return decision
|
|
@@ -329,7 +360,19 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
329
360
|
}, 'session-suite: memory tool')
|
|
330
361
|
}
|
|
331
362
|
|
|
332
|
-
return {
|
|
363
|
+
return {
|
|
364
|
+
engine,
|
|
365
|
+
dispose: () => {},
|
|
366
|
+
// Exposed so the settings page and the status endpoint can report whether the
|
|
367
|
+
// last recall rebuild failed. Without this the failure is silent: the model
|
|
368
|
+
// simply acts as if the memory is not there.
|
|
369
|
+
recallStatus: () => ({
|
|
370
|
+
failed: lastRecallFailed,
|
|
371
|
+
error: lastRecallError,
|
|
372
|
+
hasText: Boolean(lastRecall) || recallByScope.size > 0,
|
|
373
|
+
scopes: recallByScope.size,
|
|
374
|
+
}),
|
|
375
|
+
}
|
|
333
376
|
}
|
|
334
377
|
|
|
335
378
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heixui/dsh-session-suite",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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",
|
|
@@ -56,16 +56,19 @@
|
|
|
56
56
|
"THIRD-PARTY.md"
|
|
57
57
|
],
|
|
58
58
|
"dsh": {
|
|
59
|
+
"icon": "./icon.svg",
|
|
59
60
|
"bundle": {
|
|
60
61
|
"patch": "./cordis.patch.yml"
|
|
61
62
|
},
|
|
62
63
|
"client": {
|
|
63
64
|
"platform": "web",
|
|
64
|
-
"immediately": true,
|
|
65
65
|
"inject": [
|
|
66
66
|
"@deepseek-ai/dsh-client-locale",
|
|
67
|
+
"@deepseek-ai/dsh-client-connection",
|
|
67
68
|
"@deepseek-ai/dsh-client-ui-workspace",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-session",
|
|
68
70
|
"@deepseek-ai/dsh-client-ui-chat",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
69
72
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
70
73
|
]
|
|
71
74
|
}
|