@heixui/dsh-session-suite 0.6.0 → 0.6.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/index.js +1 -1
- package/lib/memory-host.js +50 -10
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -45,7 +45,7 @@ export const name = 'session-suite'
|
|
|
45
45
|
* Everything else stays optional: the HTTP carrier is still the only hard requirement,
|
|
46
46
|
* and a Host without `agents` degrades to no implicit extraction rather than failing.
|
|
47
47
|
*/
|
|
48
|
-
export const inject = ['connection', 'agents']
|
|
48
|
+
export const inject = ['connection', 'agents', 'timer']
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* @param {any} ctx plugin context
|
package/lib/memory-host.js
CHANGED
|
@@ -288,13 +288,21 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
288
288
|
// One listener per agent; the context disposes it with the agent.
|
|
289
289
|
agentCtx.on('agent/turn-stopping', () => {
|
|
290
290
|
const sessionId = agent?.sessionId
|
|
291
|
-
if (typeof sessionId !== 'string' || !sessionId)
|
|
291
|
+
if (typeof sessionId !== 'string' || !sessionId) {
|
|
292
|
+
extractionTrace.reason = `turn-stopping fired but agent.sessionId was ${typeof sessionId}`
|
|
293
|
+
publishExtractionTrace(engine)
|
|
294
|
+
return
|
|
295
|
+
}
|
|
292
296
|
// The model choice lives in settings.json, not in the patch config.
|
|
293
297
|
void engine
|
|
294
298
|
.settings()
|
|
295
299
|
.then(settings => {
|
|
296
300
|
const chosen = settings?.implicitModel ?? config?.implicitModel
|
|
297
|
-
if (!chosen || chosen === 'off')
|
|
301
|
+
if (!chosen || chosen === 'off') {
|
|
302
|
+
extractionTrace.reason = 'no implicit model is selected in settings'
|
|
303
|
+
publishExtractionTrace(engine)
|
|
304
|
+
return undefined
|
|
305
|
+
}
|
|
298
306
|
const cwd = resolveCwd(ctx, agent)
|
|
299
307
|
return extractAfterTurn({ ctx, engine, sessionId, cwd, log, config })
|
|
300
308
|
})
|
|
@@ -308,16 +316,48 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
308
316
|
})
|
|
309
317
|
}
|
|
310
318
|
|
|
311
|
-
// Mount
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
319
|
+
// Mount by POLLING, not by an event.
|
|
320
|
+
//
|
|
321
|
+
// The first version listened for `agent/created`, which never delivered a usable
|
|
322
|
+
// agent — the hook stayed unmounted and the trace stayed null, the same symptom as
|
|
323
|
+
// every earlier attempt. dsh-fish-memory does not use an event either: it runs
|
|
324
|
+
// `ctx.effect(() => ctx.interval(tick, 500))` and calls `agents.list()` every half
|
|
325
|
+
// second, mounting on any agent it has not seen yet. That is what makes its version
|
|
326
|
+
// work, and its source notes the tradeoff — the tick is cheap because `agents.list()`
|
|
327
|
+
// reads memory.
|
|
328
|
+
//
|
|
329
|
+
// Polling also handles the case an event cannot: the agent instance is REPLACED when
|
|
330
|
+
// a session is resumed, a plugin reloads, or the Host rebuilds it. A one-shot
|
|
331
|
+
// listener dies with the old instance; a poll re-mounts on the new one.
|
|
332
|
+
const mounted = new WeakSet()
|
|
333
|
+
const tick = () => {
|
|
334
|
+
let live = []
|
|
335
|
+
try {
|
|
336
|
+
live = agents.list?.() ?? []
|
|
337
|
+
} catch {
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
for (const agent of live) {
|
|
341
|
+
if (!agent || mounted.has(agent)) continue
|
|
342
|
+
// Subagents only do one job; a memory store for them is wasted work.
|
|
343
|
+
if (agent.origin === 'subagent' || agent.delegationDepth > 0) continue
|
|
344
|
+
mounted.add(agent)
|
|
315
345
|
try {
|
|
316
|
-
mountFor(
|
|
317
|
-
} catch {
|
|
318
|
-
|
|
346
|
+
mountFor(agent)
|
|
347
|
+
} catch (error) {
|
|
348
|
+
log('could not mount the extraction hook on an agent', error)
|
|
319
349
|
}
|
|
320
|
-
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// First pass immediately, so an already-running session is covered without waiting.
|
|
353
|
+
tick()
|
|
354
|
+
// Then every half second. `ctx.interval` is the Cordis timer facility; fall back to
|
|
355
|
+
// setInterval when it is absent so the feature still works on a leaner Host.
|
|
356
|
+
if (typeof ctx.interval === 'function') ctx.effect(() => ctx.interval(tick, 500))
|
|
357
|
+
else if (typeof setInterval === 'function') {
|
|
358
|
+
const handle = setInterval(tick, 500)
|
|
359
|
+
handle.unref?.()
|
|
360
|
+
ctx.effect(() => () => clearInterval(handle))
|
|
321
361
|
}
|
|
322
362
|
})
|
|
323
363
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heixui/dsh-session-suite",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.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",
|