@a9i5k4/dsh-auto-memory 2.2.7 → 2.3.0
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/lib/index.js +37 -4
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -4336,6 +4336,8 @@ class MemoryEngine {
|
|
|
4336
4336
|
|
|
4337
4337
|
/** 调用 DSH subagent 发散/提炼一段文本(90s 超时,结果取 text 块;parent 用最近 agent)。 */
|
|
4338
4338
|
async runSubagent(text, label, agent, timeoutMs) {
|
|
4339
|
+
// 2.2.7:插件 context 已卸载(重启/禁用中)→ 不再 spawn,避免向失效 context 注册 effect
|
|
4340
|
+
if (this._disposed) return ''
|
|
4339
4341
|
const subagents = this._subagents
|
|
4340
4342
|
if (!subagents) return ''
|
|
4341
4343
|
// 配置性错误熔断(问题③):UNKNOWN_MODEL 等错误不会自愈,熔断期内直接返回空,不再反复 spawn(卡顿根因)
|
|
@@ -4422,6 +4424,11 @@ class MemoryEngine {
|
|
|
4422
4424
|
return blocks.filter((b) => b && b.type === 'text').map((b) => b.text).join('').trim()
|
|
4423
4425
|
} catch (e) {
|
|
4424
4426
|
const em = e && e.message ? e.message : String(e)
|
|
4427
|
+
// 2.2.7:context 已卸载导致的 effect 创建失败是重启/卸载竞态,不是功能缺陷 —— 只记一次 diag,不刷屏
|
|
4428
|
+
if (/inactive context/i.test(em)) {
|
|
4429
|
+
if (!this._inactiveWarned) { this._inactiveWarned = true; diag('subagent ' + label + ' skipped: plugin context inactive (宿主已卸载,重启后自动恢复)') }
|
|
4430
|
+
return ''
|
|
4431
|
+
}
|
|
4425
4432
|
console.error('[dsh-auto-memory] ' + label + ' failed', em)
|
|
4426
4433
|
diag('subagent ' + label + ' failed: ' + em)
|
|
4427
4434
|
// 配置性错误熔断(问题③):UNKNOWN_MODEL / 无配置模型 / 供应商不含该模型——重试无意义,30 分钟内不再 spawn
|
|
@@ -4455,13 +4462,30 @@ class MemoryEngine {
|
|
|
4455
4462
|
const sid = session && (session.id || (header && header.id)) ? String(session.id || header.id) : ''
|
|
4456
4463
|
if (!sid) return { ok: false, reason: 'no-id' }
|
|
4457
4464
|
if (!header || header.origin !== 'subagent') return { ok: false, reason: 'not-subagent' }
|
|
4465
|
+
// 2.3.0:Windows 下 DSH 常持有会话文件句柄(子代理刚结束时仍在写)→ rename 抛 EPERM。
|
|
4466
|
+
// 同一 sid 失败后冷却 30 分钟不再尝试(避免刷屏),占用释放后由每日 sweep 兜底回收。
|
|
4467
|
+
const cool = this._gcCooldown || (this._gcCooldown = new Map())
|
|
4468
|
+
const coolUntil = cool.get(sid) || 0
|
|
4469
|
+
if (Date.now() < coolUntil) return { ok: false, reason: 'cooldown' }
|
|
4458
4470
|
const dir = await this.locateSessionDir(sid, header)
|
|
4459
4471
|
if (!dir) return { ok: false, reason: 'not-located' }
|
|
4460
4472
|
const wsDir = path.basename(path.dirname(dir))
|
|
4461
4473
|
const backupRoot = path.join(dshHome(), 'subagent-gc-backup')
|
|
4462
4474
|
const dest = path.join(backupRoot, wsDir, sid)
|
|
4463
4475
|
await mkdir(path.dirname(dest), { recursive: true })
|
|
4464
|
-
|
|
4476
|
+
let renamed = false
|
|
4477
|
+
let lastErr = null
|
|
4478
|
+
for (const delay of [0, 300, 1000]) {
|
|
4479
|
+
if (delay) await new Promise((r) => setTimeout(r, delay))
|
|
4480
|
+
try { await rename(dir, dest); renamed = true; break } catch (e) { lastErr = e }
|
|
4481
|
+
}
|
|
4482
|
+
if (!renamed) {
|
|
4483
|
+
cool.set(sid, Date.now() + 30 * 60 * 1000)
|
|
4484
|
+
// 首次失败记 diag,后续静默(同一 sid 冷却期内不再刷屏)
|
|
4485
|
+
const warned = this._gcWarned || (this._gcWarned = new Set())
|
|
4486
|
+
if (!warned.has(sid)) { warned.add(sid); diag('subagent gc deferred (file locked by host): ' + sid) }
|
|
4487
|
+
return { ok: false, reason: 'locked', sid }
|
|
4488
|
+
}
|
|
4465
4489
|
// 投影缓存同步移走,避免孤儿条目长期占用索引
|
|
4466
4490
|
try {
|
|
4467
4491
|
const cacheFile = path.join(dshHome(), 'storages', 'session_projcache', 'sessions', sid)
|
|
@@ -4511,9 +4535,11 @@ class MemoryEngine {
|
|
|
4511
4535
|
const keepDays = Math.max(0, Number(this.config.subagentGcKeepDays) || 0)
|
|
4512
4536
|
const scan = await scanPluginSubagentSessions({ sessionsRoot, labelPrefix: PLUGIN_LABEL_PREFIX, keepMs: 0 })
|
|
4513
4537
|
const now = Date.now()
|
|
4514
|
-
// 无论保留期多长,最近
|
|
4515
|
-
|
|
4516
|
-
const
|
|
4538
|
+
// 无论保留期多长,最近 60 分钟的一律不动(2.3.0:Windows 下宿主可能长期持有会话文件句柄,
|
|
4539
|
+
// 10 分钟窗口不足以判断"已不再写入";占用中的目录 rename 必失败)
|
|
4540
|
+
const floorMs = Math.max(keepDays * 24 * 3600 * 1000, 60 * 60 * 1000)
|
|
4541
|
+
const cool = this._gcCooldown || (this._gcCooldown = new Map())
|
|
4542
|
+
const eligible = scan.candidates.filter((c) => now - c.mtimeMs >= floorMs && now >= (cool.get(c.sid) || 0))
|
|
4517
4543
|
if (!eligible.length) return { ok: true, scanned: scan.scanned, recycled: 0 }
|
|
4518
4544
|
const res = await recycleSessions({
|
|
4519
4545
|
candidates: eligible,
|
|
@@ -4522,6 +4548,8 @@ class MemoryEngine {
|
|
|
4522
4548
|
apply: true,
|
|
4523
4549
|
})
|
|
4524
4550
|
diag('subagent gc sweep: recycled=' + res.moved.length + ' failed=' + res.failed.length + ' bytes=' + res.bytes)
|
|
4551
|
+
// 2.3.0:被占用的目录进入 30 分钟冷却,避免每日巡检重复无效重试
|
|
4552
|
+
for (const f of res.failed || []) { if (f && f.sid) cool.set(String(f.sid), Date.now() + 30 * 60 * 1000) }
|
|
4525
4553
|
return { ok: true, scanned: scan.scanned, recycled: res.moved.length, failed: res.failed.length, bytes: res.bytes }
|
|
4526
4554
|
} catch (e) {
|
|
4527
4555
|
diag('subagent gc sweep failed: ' + (e && e.message ? e.message : String(e)))
|
|
@@ -6281,6 +6309,11 @@ export function apply(ctx, config) {
|
|
|
6281
6309
|
const sessionQuery = ctx.get('sessionQuery')
|
|
6282
6310
|
engine._sessionQuery = sessionQuery
|
|
6283
6311
|
engine._subagents = ctx.get('subagents') || undefined
|
|
6312
|
+
// 2.2.7 修复:宿主 context 卸载后,残留的定时器/面板请求仍会调 runSubagent,
|
|
6313
|
+
// DSH 0.1.2 的 in-process 子代理会向已失效 context 注册 effect → "cannot create effect on inactive context" 刷屏。
|
|
6314
|
+
// 记 dispose 标记,runSubagent 入口直接短路。
|
|
6315
|
+
engine._disposed = false
|
|
6316
|
+
try { ctx.on('dispose', () => { engine._disposed = true }) } catch (eDispose) {}
|
|
6284
6317
|
// 时间检测用的服务(软获取,缺失时定时兜底自动降级)
|
|
6285
6318
|
engine._sessionsSvc = ctx.get('sessions') || undefined
|
|
6286
6319
|
engine._agentSvc = ctx.get('agent') || undefined
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a9i5k4/dsh-auto-memory",
|
|
3
3
|
"description": "Proactive associative memory for DSH: zero-prompt recall injected before the model speaks, three-layer auto-consolidation, skill crystallization, and Astra-style context management - handoff ledgers, PLAN whiteboard, water-level sensing. Local-first, model-agnostic, zero deps. 主动联想记忆+Astra 式上下文管理:自动唤回/自动沉淀/技能固化/交接账本与白板跨窗口续命/水位感知。",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|