dsh-memu-memory 1.1.3 → 1.2.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/AGENTS.md +1 -1
- package/README.md +39 -6
- package/README.zh.md +39 -7
- package/docs/active-memory-ab.md +385 -0
- package/docs/binding-lifecycle.md +99 -0
- package/docs/contributing.md +3 -3
- package/docs/emotion-model-spec.md +281 -0
- package/docs/env-and-commands.md +8 -0
- package/docs/host-api.md +2 -2
- package/docs/memory-semantics.md +12 -10
- package/docs/recall-benchmark.md +238 -0
- package/docs/troubleshooting.md +396 -395
- package/lib/active-memory.js +165 -0
- package/lib/activity-log.js +23 -6
- package/lib/binding-diagnostics.js +8 -3
- package/lib/client.js +335 -35
- package/lib/consolidation-ledger.js +347 -0
- package/lib/consolidation-receipt.js +284 -0
- package/lib/consolidation-snapshot.js +274 -0
- package/lib/consolidation-worker.js +144 -0
- package/lib/curator.js +86 -31
- package/lib/cycle.js +40 -6
- package/lib/graph.js +139 -5
- package/lib/index.js +33 -1
- package/lib/inject.js +104 -76
- package/lib/local-embedding-manager.js +24 -6
- package/lib/memory.js +534 -88
- package/lib/mood.js +268 -39
- package/lib/preset-scope.js +1 -1
- package/lib/private.js +430 -43
- package/lib/prompts/private-consolidation.coding.md +1 -0
- package/lib/prompts/private-consolidation.md +1 -0
- package/lib/prompts/private-consolidation.mixed.md +1 -0
- package/lib/prompts/private-consolidation.rp.md +1 -0
- package/lib/prompts.js +4 -4
- package/lib/remote-summary.js +51 -25
- package/lib/rpc.js +54 -5
- package/lib/state.js +29 -12
- package/lib/text-similarity.js +106 -0
- package/lib/tools.js +113 -10
- package/lib/vector-migration.js +28 -3
- package/lib/vector-profile.js +51 -0
- package/package.json +4 -2
- package/scripts/acceptance-local.mjs +2 -1
- package/scripts/active-memory-ab-live.mjs +655 -0
- package/scripts/active-memory-ab.mjs +1302 -0
- package/scripts/chain-matrix.mjs +11 -1
- package/scripts/check-all.mjs +10 -1
- package/scripts/replay.mjs +573 -0
- package/tests/activation.test.mjs +89 -0
- package/tests/active-memory-ab.test.mjs +745 -0
- package/tests/active-memory.test.mjs +129 -0
- package/tests/activity-log.test.mjs +126 -0
- package/tests/activity-wiring.test.mjs +103 -0
- package/tests/appendix-b.test.mjs +216 -0
- package/tests/appendix-b2.test.mjs +166 -0
- package/tests/audit-regression.test.mjs +272 -0
- package/tests/audit-safety.test.mjs +227 -0
- package/tests/backend-compensation.test.mjs +272 -0
- package/tests/backup.test.mjs +793 -0
- package/tests/binding-diagnostics.test.mjs +720 -0
- package/tests/browser.test.mjs +366 -0
- package/tests/client-render.test.mjs +892 -0
- package/tests/coalesce.test.mjs +113 -0
- package/tests/config.test.mjs +159 -0
- package/tests/consolidation-credential.test.mjs +331 -0
- package/tests/consolidation-feed.test.mjs +96 -0
- package/tests/consolidation-fork.test.mjs +489 -0
- package/tests/consolidation-ledger.test.mjs +298 -0
- package/tests/consolidation-snapshot.test.mjs +360 -0
- package/tests/consolidation-value.test.mjs +89 -0
- package/tests/context-scope.test.mjs +40 -0
- package/tests/cue.test.mjs +44 -0
- package/tests/curator-commit.test.mjs +277 -0
- package/tests/curator-probe.test.mjs +433 -0
- package/tests/curator.test.mjs +150 -0
- package/tests/cycle.test.mjs +411 -0
- package/tests/disclosure.test.mjs +231 -0
- package/tests/doc-drift.test.mjs +222 -0
- package/tests/embedding-catalog.test.mjs +266 -0
- package/tests/embedding-download.test.mjs +391 -0
- package/tests/embedding-runtime.test.mjs +389 -0
- package/tests/emotion-chain.test.mjs +84 -0
- package/tests/emotion-contract.test.mjs +445 -0
- package/tests/engine.test.mjs +35 -0
- package/tests/fixtures/active-memory-ab/README.md +56 -0
- package/tests/fixtures/active-memory-ab/cases/01-clean-dense-turn.json +351 -0
- package/tests/fixtures/active-memory-ab/cases/02-clean-thin-turn.json +122 -0
- package/tests/fixtures/active-memory-ab/cases/03-clean-starved-small.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/04-clean-large-thin.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/05-clean-half-step.json +166 -0
- package/tests/fixtures/active-memory-ab/cases/06-clean-duplicate-reread.json +197 -0
- package/tests/fixtures/active-memory-ab/cases/07-clean-recent-recall.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/08-global-relevant.json +111 -0
- package/tests/fixtures/active-memory-ab/cases/09-global-irrelevant-conflict.json +158 -0
- package/tests/fixtures/active-memory-ab/cases/10-no-human-turn.json +97 -0
- package/tests/fixtures/active-memory-ab/cases/11-clean-scale-100.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/12-clean-scale-1000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/13-clean-scale-5000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/14-clean-scale-20000.json +137 -0
- package/tests/fixtures/active-memory-ab/lead-ai-reviewed-reference.json +191 -0
- package/tests/fixtures/active-memory-ab/manifest.json +199 -0
- package/tests/fixtures/recall-bench/01-paraphrase.json +184 -0
- package/tests/fixtures/recall-bench/02-exact.json +153 -0
- package/tests/fixtures/recall-bench/03-negation.json +173 -0
- package/tests/fixtures/recall-bench/04-no-answer.json +162 -0
- package/tests/fixtures/recall-bench/05-conflict.json +194 -0
- package/tests/fixtures/recall-bench/06-boundary.json +273 -0
- package/tests/fixtures/recall-bench/07-secret.json +191 -0
- package/tests/fixtures/recall-bench/08-coding.json +164 -0
- package/tests/fixtures/recall-bench-gold-candidates/01-paraphrase.json +193 -0
- package/tests/fixtures/recall-bench-gold-candidates/02-exact.json +197 -0
- package/tests/fixtures/recall-bench-gold-candidates/03-negation.json +244 -0
- package/tests/fixtures/recall-bench-gold-candidates/04-no-answer.json +189 -0
- package/tests/fixtures/recall-bench-gold-candidates/05-conflict.json +245 -0
- package/tests/fixtures/recall-bench-gold-candidates/06-boundary.json +279 -0
- package/tests/fixtures/recall-bench-gold-candidates/07-secret.json +224 -0
- package/tests/fixtures/recall-bench-gold-candidates/08-coding.json +218 -0
- package/tests/fixtures/repetition-eval/01-zh-rp.json +93 -0
- package/tests/fixtures/repetition-eval/02-en.json +97 -0
- package/tests/fixtures/repetition-eval/03-code.json +91 -0
- package/tests/fixtures/repetition-eval/04-names.json +116 -0
- package/tests/fixtures/repetition-eval/05-user-quote.json +96 -0
- package/tests/fixtures/repetition-eval/06-agreement.json +86 -0
- package/tests/graph-cascade.test.mjs +190 -0
- package/tests/graph-view.test.mjs +187 -0
- package/tests/graph.test.mjs +94 -0
- package/tests/hook-order.test.mjs +72 -0
- package/tests/humanlike.test.mjs +232 -0
- package/tests/hybrid-recall.test.mjs +122 -0
- package/tests/inbound.test.mjs +393 -0
- package/tests/inject-guide.test.mjs +364 -0
- package/tests/inject.test.mjs +222 -0
- package/tests/injection-budget-settings.test.mjs +35 -0
- package/tests/injection-budget.test.mjs +64 -0
- package/tests/injection-chain.test.mjs +191 -0
- package/tests/loader-register.mjs +3 -0
- package/tests/loader.mjs +12 -0
- package/tests/local-embedding-entry.test.mjs +95 -0
- package/tests/local-embedding-manager.test.mjs +476 -0
- package/tests/local-embedding-protocol.test.mjs +95 -0
- package/tests/local-embedding-worker.test.mjs +346 -0
- package/tests/managed-memory.test.mjs +591 -0
- package/tests/managed-runtime.test.mjs +40 -0
- package/tests/media.test.mjs +132 -0
- package/tests/migration-payload.test.mjs +42 -0
- package/tests/mood.test.mjs +109 -0
- package/tests/multiprocess.test.mjs +29 -0
- package/tests/new-session-gate.test.mjs +361 -0
- package/tests/package-shipping.test.mjs +84 -0
- package/tests/preset-scope.test.mjs +212 -0
- package/tests/prompts.test.mjs +250 -0
- package/tests/react-snapshot.test.mjs +23 -0
- package/tests/recall-bench.test.mjs +306 -0
- package/tests/recall-dedup.test.mjs +417 -0
- package/tests/remote.test.mjs +140 -0
- package/tests/rename.test.mjs +30 -0
- package/tests/repetition-detector-snapshot.test.mjs +231 -0
- package/tests/repetition-eval-live.test.mjs +177 -0
- package/tests/repetition-eval.test.mjs +373 -0
- package/tests/salient-date.test.mjs +142 -0
- package/tests/settings-beat.test.mjs +221 -0
- package/tests/short-term.test.mjs +166 -0
- package/tests/sidebar-beat.test.mjs +212 -0
- package/tests/sidebar-refresh.test.mjs +123 -0
- package/tests/sidebar.test.mjs +70 -0
- package/tests/snippet.test.mjs +47 -0
- package/tests/source-kind.test.mjs +52 -0
- package/tests/state.test.mjs +150 -0
- package/tests/stats.test.mjs +112 -0
- package/tests/storage.test.mjs +125 -0
- package/tests/stubs/dsh-llm.js +5 -0
- package/tests/stubs/dsh-session.js +7 -0
- package/tests/stubs/dsh-tools.js +101 -0
- package/tests/tool-schema.test.mjs +73 -0
- package/tests/tools.test.mjs +184 -0
- package/tests/ui-defaults.test.mjs +57 -0
- package/tests/update-fields.test.mjs +138 -0
- package/tests/vector-migration.test.mjs +790 -0
- package/tests/vector-profile.test.mjs +425 -0
- package/tests/visibility-migration.test.mjs +152 -0
- package/tests/webui-auth.test.mjs +454 -0
- package/tests/webui.test.mjs +165 -0
- package/tests/windows-env.test.mjs +89 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主动记忆判定:一次闲时检查值不值得花 token。
|
|
3
|
+
*
|
|
4
|
+
* 三条输入都是"结构性"的,不做关键词判定:
|
|
5
|
+
* H 真人回合数(只算 source.kind === 'user' 的消息)
|
|
6
|
+
* C 新增证据量(真人文字 + 助手结论 + 去重后的工具结果,按字符估算)
|
|
7
|
+
* U 有效工具工作单元(去重的成功工具结果;轮询、空输出、重复错误只算一次)
|
|
8
|
+
*
|
|
9
|
+
* 触发规则(可被 settings 覆盖):
|
|
10
|
+
* - 会话空闲 < activeMemoryStarvationMinutes:分数必须 >= minScore;
|
|
11
|
+
* - 空闲 >= 饥饿阈值:小会话无条件检查(保证不会永远轮不到);
|
|
12
|
+
* - 大 transcript(>= largeTranscriptEvents)不吃饥饿豁免:真机回放里
|
|
13
|
+
* 5913 条事件的会话,一个"继续"回合只有 0.14~0.43 分,却会把整段
|
|
14
|
+
* 26MB 转录重新种进 fork;这种薄回合必须等分数达标;
|
|
15
|
+
* - 近期刚整理过 / 刚注入过记忆:直接抑制,避免"记忆后立刻再 fork 一次"。
|
|
16
|
+
*
|
|
17
|
+
* 纯函数,无 IO,便于回放标定与单测。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const ACTIVE_MEMORY_VERSION = 1
|
|
21
|
+
|
|
22
|
+
export const ACTIVE_MEMORY_POLICY = Object.freeze({
|
|
23
|
+
version: ACTIVE_MEMORY_VERSION,
|
|
24
|
+
minScore: 0.8,
|
|
25
|
+
starvationMinutes: 15,
|
|
26
|
+
consolidatedCooldownMinutes: 60,
|
|
27
|
+
recallCooldownMinutes: 15,
|
|
28
|
+
humanTurnsCap: 3,
|
|
29
|
+
evidenceCharsCap: 4000,
|
|
30
|
+
toolUnitsCap: 20,
|
|
31
|
+
partCap: 2,
|
|
32
|
+
// 超过这个规模,fork 的种子成本随整段转录增长,饥饿不再单独构成理由。
|
|
33
|
+
largeTranscriptEvents: 2000,
|
|
34
|
+
// 大 transcript 的守卫只该推迟一次检查,不该无限推迟。待整理区间一旦超过这个规模,
|
|
35
|
+
// 无论分数多低都要整理一次:游标不前移,那段内容就一直躺在 pending 里等着,
|
|
36
|
+
// 「省 token」和「永远不记」之间的差别是延迟上界,不是覆盖上界。
|
|
37
|
+
// 600 事件大约相当于一次中等长度的会话;20k 事件的首轮整理本来就贵,但那是内容
|
|
38
|
+
// 本身的价格,不是规则造成的浪费。
|
|
39
|
+
maxPendingEvents: 600,
|
|
40
|
+
weights: Object.freeze({ human: 0.35, content: 0.45, tool: 0.2 }),
|
|
41
|
+
// 单个工具结果计入证据量的上限;整段工具日志不能挤掉真人说的话。
|
|
42
|
+
toolResultCharsCap: 2000,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
function textOfContent(content) {
|
|
46
|
+
if (typeof content === 'string') return content.trim()
|
|
47
|
+
if (!Array.isArray(content)) return ''
|
|
48
|
+
return content
|
|
49
|
+
.filter(block => block && block.type === 'text' && typeof block.text === 'string')
|
|
50
|
+
.map(block => block.text)
|
|
51
|
+
.join(' ')
|
|
52
|
+
.trim()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 从一个事件窗口里收集证据。窗口应当只包含"上次检查之后"的事件;
|
|
57
|
+
* 调用方负责裁剪,这里不猜测边界。
|
|
58
|
+
*/
|
|
59
|
+
export function collectEvidence(events, policy = ACTIVE_MEMORY_POLICY) {
|
|
60
|
+
const evidence = {
|
|
61
|
+
humanTurns: 0,
|
|
62
|
+
humanChars: 0,
|
|
63
|
+
assistantChars: 0,
|
|
64
|
+
toolChars: 0,
|
|
65
|
+
toolUnits: 0,
|
|
66
|
+
toolCalls: 0,
|
|
67
|
+
lastHumanText: '',
|
|
68
|
+
}
|
|
69
|
+
const seenUnits = new Set()
|
|
70
|
+
for (const event of events || []) {
|
|
71
|
+
const type = event?.type
|
|
72
|
+
if (type === 'user/message') {
|
|
73
|
+
if (event.data?.source?.kind !== 'user') continue
|
|
74
|
+
const text = textOfContent(event.data?.content)
|
|
75
|
+
if (!text) continue
|
|
76
|
+
evidence.humanTurns += 1
|
|
77
|
+
evidence.humanChars += text.length
|
|
78
|
+
evidence.lastHumanText = text
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
if (type === 'assistant/message') {
|
|
82
|
+
const blocks = event.data?.message?.content
|
|
83
|
+
if (!Array.isArray(blocks)) continue
|
|
84
|
+
for (const block of blocks) {
|
|
85
|
+
if (block?.type === 'tool-call') evidence.toolCalls += 1
|
|
86
|
+
else if (block?.type === 'text' && typeof block.text === 'string') evidence.assistantChars += block.text.trim().length
|
|
87
|
+
}
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
if (type === 'tool/call') {
|
|
91
|
+
evidence.toolCalls += 1
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
if (type === 'tool/result') {
|
|
95
|
+
const message = event.data?.message || {}
|
|
96
|
+
if (message.isError === true) continue
|
|
97
|
+
const text = textOfContent(message.content)
|
|
98
|
+
if (!text) continue
|
|
99
|
+
// 同一份结果重复出现(轮询、重读、重试)只算一次工作单元。
|
|
100
|
+
const key = text.slice(0, 160) + '|' + text.length
|
|
101
|
+
if (seenUnits.has(key)) continue
|
|
102
|
+
seenUnits.add(key)
|
|
103
|
+
evidence.toolUnits += 1
|
|
104
|
+
evidence.toolChars += Math.min(text.length, policy.toolResultCharsCap)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return evidence
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** 可解释评分:每个分项封顶,避免"只刷工具次数"把分数拉满。 */
|
|
111
|
+
export function scoreEvidence(evidence, policy = ACTIVE_MEMORY_POLICY) {
|
|
112
|
+
const human = Number(evidence?.humanTurns) || 0
|
|
113
|
+
const contentChars = (Number(evidence?.humanChars) || 0) + (Number(evidence?.assistantChars) || 0) + (Number(evidence?.toolChars) || 0)
|
|
114
|
+
const units = Number(evidence?.toolUnits) || 0
|
|
115
|
+
const h = Math.min(human / policy.humanTurnsCap, policy.partCap)
|
|
116
|
+
const c = Math.min(contentChars / policy.evidenceCharsCap, policy.partCap)
|
|
117
|
+
const u = Math.min(units / policy.toolUnitsCap, policy.partCap)
|
|
118
|
+
const score = policy.weights.human * h + policy.weights.content * c + policy.weights.tool * u
|
|
119
|
+
return {
|
|
120
|
+
score: Math.round(score * 1000) / 1000,
|
|
121
|
+
parts: { human: h, content: c, tool: u, humanTurns: human, contentChars, toolUnits: units },
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 是否唤醒检查。真人回合是硬门槛(纯工具轮询不构成检查理由),
|
|
127
|
+
* 其余交给分数;`starved` 由调用方按空闲时长传入。
|
|
128
|
+
* `transcriptEvents` 是整段会话的事件数,用来决定饥饿豁免是否还有成本意义。
|
|
129
|
+
*/
|
|
130
|
+
export function assessWake({ evidence, starved = false, transcriptEvents = 0, pendingEvents = 0, policy = ACTIVE_MEMORY_POLICY } = {}) {
|
|
131
|
+
const scored = scoreEvidence(evidence, policy)
|
|
132
|
+
if ((Number(evidence?.humanTurns) || 0) === 0) {
|
|
133
|
+
return { wake: false, reason: 'no-human-turn', ...scored }
|
|
134
|
+
}
|
|
135
|
+
// 积压优先于守卫:守卫的理由是「为一句轻话重种整段转录不划算」,但当整段转录本身
|
|
136
|
+
// 还没整理过时,那不是重种,是欠着。没有这条,一个大 transcript 只要每轮都是轻话,
|
|
137
|
+
// 就永远等不到检查——延迟没有上界,长会话的早期决定再也进不了记忆。
|
|
138
|
+
if (Number(pendingEvents) >= Number(policy.maxPendingEvents || Infinity)) {
|
|
139
|
+
return { wake: true, reason: 'backlog', ...scored }
|
|
140
|
+
}
|
|
141
|
+
const large = (Number(transcriptEvents) || 0) >= policy.largeTranscriptEvents
|
|
142
|
+
if (starved && !large) return { wake: true, reason: 'starved', ...scored }
|
|
143
|
+
if (scored.score < policy.minScore) {
|
|
144
|
+
return { wake: false, reason: large && starved ? 'large-transcript-thin' : 'low-score', ...scored }
|
|
145
|
+
}
|
|
146
|
+
return { wake: true, reason: 'score', ...scored }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 抑制原因:近期整理过(避免记忆后马上再 fork)或近期注入过记忆。
|
|
151
|
+
* 返回 null 表示不抑制。
|
|
152
|
+
*/
|
|
153
|
+
export function suppressionReason({
|
|
154
|
+
now = Date.now(),
|
|
155
|
+
lastSleepAt = null,
|
|
156
|
+
lastInjectedAt = null,
|
|
157
|
+
consolidatedCooldownMinutes = ACTIVE_MEMORY_POLICY.consolidatedCooldownMinutes,
|
|
158
|
+
recallCooldownMinutes = ACTIVE_MEMORY_POLICY.recallCooldownMinutes,
|
|
159
|
+
} = {}) {
|
|
160
|
+
const sleep = Date.parse(lastSleepAt || '') || 0
|
|
161
|
+
if (sleep && now - sleep < consolidatedCooldownMinutes * 60_000) return 'recent-consolidation'
|
|
162
|
+
const recalled = Date.parse(lastInjectedAt || '') || 0
|
|
163
|
+
if (recalled && now - recalled < recallCooldownMinutes * 60_000) return 'recent-recall'
|
|
164
|
+
return null
|
|
165
|
+
}
|
package/lib/activity-log.js
CHANGED
|
@@ -13,7 +13,7 @@ import { logsDir, ensureDir, redactSecrets, warn } from './paths.js'
|
|
|
13
13
|
// 3. 出盘前脱敏。message 与 detail 都过 redactSecrets;detail 只留诊断需要的字段,
|
|
14
14
|
// 正文最多 200 字符(召回查询、记忆标题),足够定位问题又不把整段对话抄进日志。
|
|
15
15
|
|
|
16
|
-
export const ACTIVITY_KINDS = Object.freeze(['recall', 'write', 'consolidate', 'curate', 'vector', 'error', 'system'])
|
|
16
|
+
export const ACTIVITY_KINDS = Object.freeze(['recall', 'write', 'consolidate', 'curate', 'vector', 'error', 'system', 'check'])
|
|
17
17
|
const MAX_ENTRIES = 2000
|
|
18
18
|
const MAX_FILE_BYTES = 4 * 1024 * 1024
|
|
19
19
|
const MAX_MESSAGE_CHARS = 300
|
|
@@ -161,13 +161,30 @@ export function logStats() {
|
|
|
161
161
|
return { total: entries.length, bytes, counts, file: activityFile(), capped: MAX_ENTRIES, maxBytes: MAX_FILE_BYTES }
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
/**
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
/**
|
|
165
|
+
* 清空日志。无参 = 全部清掉(显式操作,不是自动裁剪);带过滤 = 只删匹配行
|
|
166
|
+
* (整理失败提醒的"清除失败记录"用:{ kind: 'consolidate', ok: false })。
|
|
167
|
+
* 返回删除条数。永不抛错。
|
|
168
|
+
*/
|
|
169
|
+
export function clearEvents(filter = null) {
|
|
170
|
+
const entries = load()
|
|
171
|
+
const matches = (entry) => {
|
|
172
|
+
if (!filter) return true
|
|
173
|
+
if (filter.kind && entry.kind !== filter.kind) return false
|
|
174
|
+
if (typeof filter.ok === 'boolean' && entry.ok !== filter.ok) return false
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
const kept = filter ? entries.filter(entry => !matches(entry)) : []
|
|
178
|
+
let removed = entries.length - kept.length
|
|
179
|
+
try {
|
|
180
|
+
rewrite(kept)
|
|
181
|
+
cache = kept
|
|
182
|
+
} catch (error) {
|
|
183
|
+
// 落盘失败就不动缓存:文件是权威,下次读盘仍是原样,别让内存和磁盘各说各话。
|
|
184
|
+
removed = 0
|
|
168
185
|
try { warn('activity log could not be cleared: ' + (error?.message || error)) } catch {}
|
|
169
186
|
}
|
|
170
|
-
return { ok: true }
|
|
187
|
+
return { ok: true, removed }
|
|
171
188
|
}
|
|
172
189
|
|
|
173
190
|
/** 导出为可直接贴进 issue 的 JSONL 文本。 */
|
|
@@ -54,9 +54,9 @@ export const RUNTIME_STATE = Object.freeze([
|
|
|
54
54
|
{ layer: 'temporary-map', file: 'lib/inbound.js:13', name: 'calls', keyedBy: 'sessionId', clearedBy: 'tool/result or turn/end' },
|
|
55
55
|
{ layer: 'temporary-map', file: 'lib/inbound.js:14', name: 'sessions', keyedBy: 'sessionId', clearedBy: 'session/disposed (releaseInboundSession)' },
|
|
56
56
|
{ layer: 'temporary-map', file: 'lib/media.js:19', name: 'captures', keyedBy: 'sessionId', clearedBy: 'capture settle' },
|
|
57
|
-
{ layer: 'temporary-map', file: 'lib/private.js:
|
|
57
|
+
{ layer: 'temporary-map', file: 'lib/private.js:347', name: 'inFlight', keyedBy: 'sessionId', clearedBy: 'consolidation settle' },
|
|
58
58
|
{ layer: 'temporary-map', file: 'lib/curator.js:13', name: 'jobs', keyedBy: 'job id', clearedBy: 'curation settle' },
|
|
59
|
-
{ layer: 'cache', file: 'lib/state.js:
|
|
59
|
+
{ layer: 'cache', file: 'lib/state.js:967', name: 'indexCache', keyedBy: 'libraryId', clearedBy: 'next load / external write' },
|
|
60
60
|
{ layer: 'cache', file: 'lib/paths.js:52', name: 'readFailures', keyedBy: 'absolute file', clearedBy: 'a later successful read' },
|
|
61
61
|
])
|
|
62
62
|
|
|
@@ -216,7 +216,12 @@ export function bindingFacts(sessionId, binding, { libraries = {}, policies = {}
|
|
|
216
216
|
present: Boolean(context),
|
|
217
217
|
scopeKeys: context ? SCOPE_KEYS.filter(key => typeof context[key] === 'string' && context[key]) : [],
|
|
218
218
|
},
|
|
219
|
-
guide: {
|
|
219
|
+
guide: {
|
|
220
|
+
sent: Boolean(b.guideMessageAt),
|
|
221
|
+
sentAt: isoAt(b.guideMessageAt),
|
|
222
|
+
rulesKey: typeof b.guideRulesKey === 'string' ? b.guideRulesKey : null,
|
|
223
|
+
lost: b.guideLost === true,
|
|
224
|
+
},
|
|
220
225
|
inbound: {
|
|
221
226
|
pending: pending.length,
|
|
222
227
|
pendingBytes,
|