@heixui/dsh-session-suite 0.6.1 → 0.6.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/index.js +6 -16
- package/lib/memory-host.js +12 -98
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -28,24 +28,14 @@ import { stripStepTagsFromStream } from './lib/step-tag-filter.js'
|
|
|
28
28
|
export const name = 'session-suite'
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* The HTTP carrier is the only hard requirement; everything else degrades gracefully.
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* queue empty for six rounds of fixes.
|
|
38
|
-
*
|
|
39
|
-
* dsh-fish-memory (16k downloads) solves the same problem by injecting `agents`, taking
|
|
40
|
-
* one with `ctx.agents.get(sid)`, and listening on `agent.ctx` — the agent's own context.
|
|
41
|
-
* Its source records the trap in a comment: the Cordis events that exist are
|
|
42
|
-
* `agent/inbox/inserted` and `agent/turn-stopping`, NOT `user/message` /
|
|
43
|
-
* `assistant/message` (those are SessionEvent types carried by `session/event`).
|
|
44
|
-
*
|
|
45
|
-
* Everything else stays optional: the HTTP carrier is still the only hard requirement,
|
|
46
|
-
* and a Host without `agents` degrades to no implicit extraction rather than failing.
|
|
33
|
+
* 0.6.2: `agents` and `timer` were added for an implicit-extraction polling loop. That
|
|
34
|
+
* loop crashed the Host with `cannot get property "timer" without inject` on every
|
|
35
|
+
* 500ms tick. Both are removed. Do not re-add them without also proving the tick body
|
|
36
|
+
* cannot throw and that the timer is disposed with the effect.
|
|
47
37
|
*/
|
|
48
|
-
export const inject = ['connection'
|
|
38
|
+
export const inject = ['connection']
|
|
49
39
|
|
|
50
40
|
/**
|
|
51
41
|
* @param {any} ctx plugin context
|
package/lib/memory-host.js
CHANGED
|
@@ -261,106 +261,20 @@ export function installMemory({ ctx, root, config, log }) {
|
|
|
261
261
|
),
|
|
262
262
|
)
|
|
263
263
|
|
|
264
|
-
// --- 2b. Per-agent extraction trigger
|
|
264
|
+
// --- 2b. Per-agent extraction trigger: REMOVED (0.6.2) -----------------
|
|
265
265
|
//
|
|
266
|
-
//
|
|
267
|
-
//
|
|
266
|
+
// The 500ms agent-poll was the source of a Host crash: its timer callback
|
|
267
|
+
// called `ctx.interval` / `ctx.get("timer")` on a context that had not
|
|
268
|
+
// injected timer, producing `TypeError: cannot get property "timer" without
|
|
269
|
+
// inject` on EVERY tick until the Host died. The WorkBuddy transcript showed
|
|
270
|
+
// `at mount, _onTimeout, listOnTimeout` from our bundle.
|
|
268
271
|
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
// by `session/event`, not Cordis events — a trap fish-memory documents in a
|
|
276
|
-
// comment after hitting it themselves.
|
|
277
|
-
//
|
|
278
|
-
// The agent is reached through `ctx.agents`, so this requires the `agents` service;
|
|
279
|
-
// index.js now injects it. Without it the feature degrades to off rather than throwing.
|
|
280
|
-
safe('per-agent extraction hook', () => {
|
|
281
|
-
const agents = ctx.get?.('agents')
|
|
282
|
-
if (!agents) return
|
|
283
|
-
|
|
284
|
-
/** @param {any} agent live agent @returns {void} */
|
|
285
|
-
const mountFor = agent => {
|
|
286
|
-
const agentCtx = agent?.ctx
|
|
287
|
-
if (!agentCtx || typeof agentCtx.on !== 'function') return
|
|
288
|
-
// One listener per agent; the context disposes it with the agent.
|
|
289
|
-
agentCtx.on('agent/turn-stopping', () => {
|
|
290
|
-
const sessionId = agent?.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
|
-
}
|
|
296
|
-
// The model choice lives in settings.json, not in the patch config.
|
|
297
|
-
void engine
|
|
298
|
-
.settings()
|
|
299
|
-
.then(settings => {
|
|
300
|
-
const chosen = settings?.implicitModel ?? config?.implicitModel
|
|
301
|
-
if (!chosen || chosen === 'off') {
|
|
302
|
-
extractionTrace.reason = 'no implicit model is selected in settings'
|
|
303
|
-
publishExtractionTrace(engine)
|
|
304
|
-
return undefined
|
|
305
|
-
}
|
|
306
|
-
const cwd = resolveCwd(ctx, agent)
|
|
307
|
-
return extractAfterTurn({ ctx, engine, sessionId, cwd, log, config })
|
|
308
|
-
})
|
|
309
|
-
.finally(() => publishExtractionTrace(engine))
|
|
310
|
-
.catch(error => {
|
|
311
|
-
extractionTrace.stage = 'threw'
|
|
312
|
-
extractionTrace.reason = errorMessage(error)
|
|
313
|
-
publishExtractionTrace(engine)
|
|
314
|
-
log('implicit memory extraction failed', error)
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
}
|
|
318
|
-
|
|
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)
|
|
345
|
-
try {
|
|
346
|
-
mountFor(agent)
|
|
347
|
-
} catch (error) {
|
|
348
|
-
log('could not mount the extraction hook on an agent', error)
|
|
349
|
-
}
|
|
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))
|
|
361
|
-
}
|
|
362
|
-
})
|
|
363
|
-
|
|
272
|
+
// A recurring timer that can throw on every tick is not an acceptable design
|
|
273
|
+
// for a plugin that runs inside a shared Host process. This whole trigger is
|
|
274
|
+
// removed, and `agents`/`timer` are dropped from inject. Implicit extraction
|
|
275
|
+
// stays off until a trigger can be proven safe. Do not re-add a polling loop
|
|
276
|
+
// without (1) injecting timer, (2) wrapping the tick body in try/catch, and
|
|
277
|
+
// (3) clearing the timer on dispose.
|
|
364
278
|
// --- 3. Implicit extraction after a turn --------------------------------
|
|
365
279
|
safe('implicit extraction', () => {
|
|
366
280
|
// A startup marker, recorded before the listener is even registered.
|
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.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",
|