@shadowforge0/aquifer-memory 1.5.12 → 1.7.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/.env.example +23 -0
- package/README.md +84 -73
- package/README_CN.md +676 -0
- package/README_TW.md +684 -0
- package/aquifer.config.example.json +34 -0
- package/consumers/claude-code.js +11 -11
- package/consumers/cli.js +421 -53
- package/consumers/codex-handoff.js +258 -0
- package/consumers/codex.js +1676 -0
- package/consumers/default/daily-entries.js +23 -4
- package/consumers/default/index.js +2 -2
- package/consumers/default/prompts/summary.js +6 -6
- package/consumers/mcp.js +96 -5
- package/consumers/openclaw-ext/index.js +0 -1
- package/consumers/openclaw-plugin.js +1 -1
- package/consumers/shared/config.js +8 -0
- package/consumers/shared/factory.js +1 -0
- package/consumers/shared/ingest.js +1 -1
- package/consumers/shared/normalize.js +14 -3
- package/consumers/shared/recall-format.js +27 -0
- package/consumers/shared/summary-parser.js +151 -0
- package/core/aquifer.js +380 -18
- package/core/finalization-review.js +319 -0
- package/core/mcp-manifest.js +52 -2
- package/core/memory-bootstrap.js +200 -0
- package/core/memory-consolidation.js +1590 -0
- package/core/memory-promotion.js +544 -0
- package/core/memory-recall.js +247 -0
- package/core/memory-records.js +797 -0
- package/core/memory-safety-gate.js +224 -0
- package/core/session-finalization.js +365 -0
- package/core/storage.js +385 -2
- package/docs/getting-started.md +105 -0
- package/docs/postprocess-contract.md +2 -2
- package/docs/setup.md +92 -2
- package/package.json +25 -11
- package/pipeline/normalize/adapters/codex.js +106 -0
- package/pipeline/normalize/detect.js +3 -2
- package/schema/001-base.sql +3 -0
- package/schema/007-v1-foundation.sql +273 -0
- package/schema/008-session-finalizations.sql +50 -0
- package/schema/009-v1-assertion-plane.sql +193 -0
- package/schema/010-v1-finalization-review.sql +160 -0
- package/schema/011-v1-compaction-claim.sql +46 -0
- package/schema/012-v1-compaction-lease.sql +39 -0
- package/schema/013-v1-compaction-lineage.sql +193 -0
- package/scripts/codex-recovery.js +672 -0
- package/consumers/miranda/context-inject.js +0 -120
- package/consumers/miranda/daily-entries.js +0 -224
- package/consumers/miranda/index.js +0 -364
- package/consumers/miranda/instance.js +0 -55
- package/consumers/miranda/llm.js +0 -99
- package/consumers/miranda/profile.json +0 -145
- package/consumers/miranda/prompts/summary.js +0 -303
- package/consumers/miranda/recall-format.js +0 -76
- package/consumers/miranda/render-daily-md.js +0 -186
- package/consumers/miranda/workspace-files.js +0 -91
- package/scripts/drop-entity-state-history.sql +0 -17
- package/scripts/drop-insights.sql +0 -12
- package/scripts/install-openclaw.sh +0 -59
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
buildFinalizationPrompt,
|
|
5
|
+
finalizeTranscriptView,
|
|
6
|
+
resolveCurrentMemoryForFinalization,
|
|
7
|
+
compactCurrentMemorySnapshot,
|
|
8
|
+
} = require('./codex');
|
|
9
|
+
const { buildFinalizationReview } = require('../core/finalization-review');
|
|
10
|
+
|
|
11
|
+
function normalizeText(value) {
|
|
12
|
+
return String(value || '').trim().replace(/\s+/g, ' ');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeList(value) {
|
|
16
|
+
return Array.isArray(value) ? value.filter(Boolean) : [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function comparableText(value) {
|
|
20
|
+
return normalizeText(value).replace(/[。.!?!?]+$/g, '').toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function addUniqueByText(out, item, text) {
|
|
24
|
+
const key = comparableText(text);
|
|
25
|
+
if (!key) return;
|
|
26
|
+
if (out.some(existing => comparableText(existing.item || existing.decision || existing.conclusion || existing.note || existing.summary) === key)) return;
|
|
27
|
+
out.push(item);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function normalizeDecision(item) {
|
|
31
|
+
if (typeof item === 'string') {
|
|
32
|
+
const decision = normalizeText(item);
|
|
33
|
+
return decision ? { decision } : null;
|
|
34
|
+
}
|
|
35
|
+
const decision = normalizeText(item && (item.decision || item.summary || item.text));
|
|
36
|
+
if (!decision) return null;
|
|
37
|
+
const reason = normalizeText(item && item.reason);
|
|
38
|
+
return reason ? { decision, reason } : { decision };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeOpenLoop(item) {
|
|
42
|
+
if (typeof item === 'string') {
|
|
43
|
+
const text = normalizeText(item);
|
|
44
|
+
return text ? { item: text, owner: 'unknown' } : null;
|
|
45
|
+
}
|
|
46
|
+
const text = normalizeText(item && (item.item || item.summary || item.text));
|
|
47
|
+
if (!text || ['none', 'n/a', 'na', 'done', '無'].includes(text.toLowerCase())) return null;
|
|
48
|
+
return {
|
|
49
|
+
item: text,
|
|
50
|
+
owner: normalizeText(item && item.owner) || 'unknown',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function buildHandoffMetadata(payload = {}) {
|
|
55
|
+
const title = normalizeText(payload.title);
|
|
56
|
+
const overview = normalizeText(payload.overview);
|
|
57
|
+
const lastStep = normalizeText(payload.lastStep || payload.last_step);
|
|
58
|
+
const next = normalizeText(payload.next);
|
|
59
|
+
const handoffText = normalizeText(payload.handoffText || payload.handoff_text);
|
|
60
|
+
const decisions = [];
|
|
61
|
+
const openLoops = [];
|
|
62
|
+
|
|
63
|
+
for (const item of normalizeList(payload.decisions)) {
|
|
64
|
+
const decision = normalizeDecision(item);
|
|
65
|
+
if (decision) addUniqueByText(decisions, decision, decision.decision);
|
|
66
|
+
}
|
|
67
|
+
for (const item of normalizeList(payload.decided)) {
|
|
68
|
+
const decision = normalizeDecision(item);
|
|
69
|
+
if (decision) addUniqueByText(decisions, decision, decision.decision);
|
|
70
|
+
}
|
|
71
|
+
if (next && next !== '無') {
|
|
72
|
+
addUniqueByText(openLoops, { item: next, owner: 'unknown', source: 'handoff_next' }, next);
|
|
73
|
+
}
|
|
74
|
+
for (const item of normalizeList(payload.openLoops || payload.open_loops)) {
|
|
75
|
+
const loop = normalizeOpenLoop(item);
|
|
76
|
+
if (loop) addUniqueByText(openLoops, loop, loop.item);
|
|
77
|
+
}
|
|
78
|
+
for (const item of normalizeList(payload.todoNew || payload.todo_new)) {
|
|
79
|
+
const loop = normalizeOpenLoop({ item, owner: 'unknown' });
|
|
80
|
+
if (loop) addUniqueByText(openLoops, { ...loop, source: 'todo_new' }, loop.item);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
source: 'codex_handoff',
|
|
85
|
+
handoff: {
|
|
86
|
+
title,
|
|
87
|
+
overview,
|
|
88
|
+
status: normalizeText(payload.status),
|
|
89
|
+
stopReason: normalizeText(payload.stopReason || payload.stop_reason),
|
|
90
|
+
lastStep,
|
|
91
|
+
next,
|
|
92
|
+
handoffText,
|
|
93
|
+
topics: normalizeList(payload.topics),
|
|
94
|
+
decisions,
|
|
95
|
+
openLoops,
|
|
96
|
+
focus: normalizeList(payload.focus).map(normalizeText).filter(Boolean),
|
|
97
|
+
todoNew: normalizeList(payload.todoNew || payload.todo_new).map(normalizeText).filter(Boolean),
|
|
98
|
+
todoDone: normalizeList(payload.todoDone || payload.todo_done).map(normalizeText).filter(Boolean),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function resolveHandoffSummary(payload = {}, opts = {}) {
|
|
104
|
+
const synthesisSummary = opts.synthesisSummary
|
|
105
|
+
|| opts.handoffSynthesisSummary
|
|
106
|
+
|| payload.synthesisSummary
|
|
107
|
+
|| payload.handoffSynthesisSummary
|
|
108
|
+
|| null;
|
|
109
|
+
if (synthesisSummary) {
|
|
110
|
+
return {
|
|
111
|
+
summary: synthesisSummary,
|
|
112
|
+
candidates: Array.isArray(synthesisSummary.candidates) ? synthesisSummary.candidates : undefined,
|
|
113
|
+
usedSynthesis: true,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
summary: opts.summary || payload.summary || {
|
|
118
|
+
summaryText: opts.summaryText || payload.summaryText,
|
|
119
|
+
structuredSummary: opts.structuredSummary || payload.structuredSummary,
|
|
120
|
+
},
|
|
121
|
+
candidates: Array.isArray(opts.candidates) ? opts.candidates : undefined,
|
|
122
|
+
usedSynthesis: false,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function formatHandoffContextBlock(metadata = {}) {
|
|
127
|
+
const handoff = metadata.handoff || {};
|
|
128
|
+
const lines = [
|
|
129
|
+
`<handoff_context source="${metadata.source || 'codex_handoff'}">`,
|
|
130
|
+
`title: ${handoff.title || 'untitled'}`,
|
|
131
|
+
`overview: ${handoff.overview || 'none'}`,
|
|
132
|
+
`status: ${handoff.status || 'unknown'}`,
|
|
133
|
+
`lastStep: ${handoff.lastStep || 'none'}`,
|
|
134
|
+
`next: ${handoff.next || 'none'}`,
|
|
135
|
+
];
|
|
136
|
+
for (const decision of handoff.decisions || []) {
|
|
137
|
+
lines.push(`decision: ${decision.decision}${decision.reason ? ` | ${decision.reason}` : ''}`);
|
|
138
|
+
}
|
|
139
|
+
for (const loop of handoff.openLoops || []) {
|
|
140
|
+
lines.push(`open_loop: ${loop.item}${loop.owner ? ` | owner=${loop.owner}` : ''}`);
|
|
141
|
+
}
|
|
142
|
+
for (const topic of handoff.topics || []) {
|
|
143
|
+
const name = normalizeText(topic && (topic.name || topic.topic || topic.title));
|
|
144
|
+
const summary = normalizeText(topic && (topic.summary || topic.text));
|
|
145
|
+
if (name || summary) lines.push(`topic: ${name || 'topic'}${summary ? ` | ${summary}` : ''}`);
|
|
146
|
+
}
|
|
147
|
+
lines.push('</handoff_context>');
|
|
148
|
+
return lines.join('\n');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function buildHandoffSynthesisPrompt(payload = {}, view = {}, opts = {}) {
|
|
152
|
+
if (!view || view.status !== 'ok') {
|
|
153
|
+
throw new Error(`Codex handoff synthesis requires an ok normalized transcript view; got ${view && view.status ? view.status : 'missing'}`);
|
|
154
|
+
}
|
|
155
|
+
const metadata = buildHandoffMetadata(payload);
|
|
156
|
+
const basePrompt = buildFinalizationPrompt(view, opts);
|
|
157
|
+
const handoffBlock = [
|
|
158
|
+
formatHandoffContextBlock(metadata),
|
|
159
|
+
'',
|
|
160
|
+
'<handoff_synthesis_rules>',
|
|
161
|
+
'Treat handoff_context as producer process material, not current truth by itself.',
|
|
162
|
+
'Use the sanitized transcript and current_memory to decide what should become current memory candidates.',
|
|
163
|
+
'Do not copy old current_memory unchanged unless this session confirms it should carry forward.',
|
|
164
|
+
'Represent resolved, superseded, revoked, or uncertain items explicitly in structuredSummary payload fields when applicable.',
|
|
165
|
+
'Do not include raw transcript, tool output, debug ids, DB ids, hashes, secrets, or injected context in memory candidates.',
|
|
166
|
+
'</handoff_synthesis_rules>',
|
|
167
|
+
].join('\n');
|
|
168
|
+
return basePrompt.replace('<sanitized_transcript>', `${handoffBlock}\n\n<sanitized_transcript>`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function prepareHandoffSynthesis(aquifer, payload = {}, opts = {}) {
|
|
172
|
+
const view = opts.view || payload.view;
|
|
173
|
+
if (!view || view.status !== 'ok') {
|
|
174
|
+
throw new Error(`Codex handoff synthesis requires an ok normalized transcript view; got ${view && view.status ? view.status : 'missing'}`);
|
|
175
|
+
}
|
|
176
|
+
const currentMemory = await resolveCurrentMemoryForFinalization(aquifer, opts);
|
|
177
|
+
return {
|
|
178
|
+
status: 'needs_agent_summary',
|
|
179
|
+
outputSchemaVersion: 'handoff_current_memory_synthesis_v1',
|
|
180
|
+
view,
|
|
181
|
+
currentMemory,
|
|
182
|
+
prompt: buildHandoffSynthesisPrompt(payload, view, { ...opts, currentMemory }),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function finalizeHandoff(aquifer, payload = {}, opts = {}) {
|
|
187
|
+
const view = opts.view || payload.view;
|
|
188
|
+
if (!view || view.status !== 'ok') {
|
|
189
|
+
throw new Error(`Codex handoff finalization requires an ok normalized transcript view; got ${view && view.status ? view.status : 'missing'}`);
|
|
190
|
+
}
|
|
191
|
+
const { summary, candidates, usedSynthesis } = resolveHandoffSummary(payload, opts);
|
|
192
|
+
const metadata = {
|
|
193
|
+
...buildHandoffMetadata(payload),
|
|
194
|
+
...(opts.metadata || {}),
|
|
195
|
+
};
|
|
196
|
+
if (usedSynthesis) {
|
|
197
|
+
metadata.handoffSynthesis = {
|
|
198
|
+
kind: 'handoff_current_memory_synthesis_v1',
|
|
199
|
+
source: 'operator_reviewed_summary',
|
|
200
|
+
promotionGate: 'core_finalization',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const currentMemory = await resolveCurrentMemoryForFinalization(aquifer, opts);
|
|
204
|
+
if (currentMemory) metadata.currentMemory = compactCurrentMemorySnapshot(currentMemory, opts);
|
|
205
|
+
const result = await finalizeTranscriptView(aquifer, view, summary, {
|
|
206
|
+
...opts,
|
|
207
|
+
mode: 'handoff',
|
|
208
|
+
metadataSource: 'codex_handoff',
|
|
209
|
+
metadata,
|
|
210
|
+
authority: opts.authority || (usedSynthesis ? 'verified_summary' : 'manual'),
|
|
211
|
+
candidates,
|
|
212
|
+
candidatePayload: usedSynthesis
|
|
213
|
+
? {
|
|
214
|
+
kind: 'handoff_synthesis',
|
|
215
|
+
synthesisKind: 'handoff_current_memory_synthesis_v1',
|
|
216
|
+
currentMemoryRole: 'handoff_synthesis_candidate',
|
|
217
|
+
promotionGate: 'core_finalization',
|
|
218
|
+
}
|
|
219
|
+
: opts.candidatePayload || null,
|
|
220
|
+
});
|
|
221
|
+
const coreResult = result.finalization || {};
|
|
222
|
+
const finalSummary = coreResult.summary || {
|
|
223
|
+
summaryText: summary.summaryText,
|
|
224
|
+
structuredSummary: summary.structuredSummary || {},
|
|
225
|
+
};
|
|
226
|
+
const memoryResult = coreResult.memoryResult || result.memoryResult || {};
|
|
227
|
+
const memoryResults = coreResult.memoryResults || result.memoryResults || [];
|
|
228
|
+
const reviewText = coreResult.humanReviewText || result.humanReviewText || buildFinalizationReview({
|
|
229
|
+
summary: finalSummary,
|
|
230
|
+
memoryResult,
|
|
231
|
+
memoryResults,
|
|
232
|
+
title: payload.title,
|
|
233
|
+
overview: payload.overview,
|
|
234
|
+
next: payload.next,
|
|
235
|
+
sessionId: view.sessionId,
|
|
236
|
+
transcriptHash: view.transcriptHash,
|
|
237
|
+
finalization: coreResult.finalization || result.finalization,
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
...result,
|
|
241
|
+
finalization: coreResult.finalization || result.finalization,
|
|
242
|
+
memoryResult,
|
|
243
|
+
memoryResults,
|
|
244
|
+
summary: finalSummary || result.summary || null,
|
|
245
|
+
reviewText,
|
|
246
|
+
humanReviewText: reviewText,
|
|
247
|
+
sessionStartText: coreResult.sessionStartText || result.sessionStartText || '',
|
|
248
|
+
structuredSummary: finalSummary.structuredSummary || {},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
module.exports = {
|
|
253
|
+
buildHandoffMetadata,
|
|
254
|
+
buildHandoffSynthesisPrompt,
|
|
255
|
+
prepareHandoffSynthesis,
|
|
256
|
+
resolveHandoffSummary,
|
|
257
|
+
finalizeHandoff,
|
|
258
|
+
};
|