@shadowforge0/aquifer-memory 1.6.0 → 1.8.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 +8 -0
- package/README.md +72 -0
- package/README_CN.md +17 -0
- package/README_TW.md +4 -0
- package/aquifer.config.example.json +19 -0
- package/consumers/cli.js +259 -12
- package/consumers/codex-active-checkpoint.js +186 -0
- package/consumers/codex-current-memory.js +106 -0
- package/consumers/codex-handoff.js +551 -6
- package/consumers/codex.js +209 -25
- package/consumers/mcp.js +144 -6
- package/consumers/shared/config.js +60 -1
- package/consumers/shared/factory.js +10 -3
- package/core/aquifer.js +357 -838
- package/core/backends/capabilities.js +89 -0
- package/core/backends/local.js +430 -0
- package/core/legacy-bootstrap.js +140 -0
- package/core/mcp-manifest.js +66 -2
- package/core/memory-bootstrap.js +20 -8
- package/core/memory-consolidation.js +365 -11
- package/core/memory-promotion.js +157 -26
- package/core/memory-recall.js +341 -22
- package/core/memory-records.js +347 -11
- package/core/memory-serving.js +132 -0
- package/core/postgres-migrations.js +533 -0
- package/core/public-session-filter.js +40 -0
- package/core/recall-runtime.js +115 -0
- package/core/scope-attribution.js +279 -0
- package/core/session-checkpoint-producer.js +412 -0
- package/core/session-checkpoints.js +432 -0
- package/core/session-finalization.js +98 -2
- package/core/storage-checkpoints.js +546 -0
- package/core/storage.js +121 -8
- package/docs/getting-started.md +6 -0
- package/docs/setup.md +66 -3
- package/package.json +8 -4
- package/schema/014-v1-checkpoint-runs.sql +349 -0
- package/schema/015-v1-evidence-items.sql +92 -0
- package/schema/016-v1-evidence-ref-multi-item.sql +19 -0
- package/schema/017-v1-memory-record-embeddings.sql +25 -0
- package/schema/018-v1-finalization-candidate-envelope.sql +39 -0
- package/scripts/codex-checkpoint-commands.js +464 -0
- package/scripts/codex-checkpoint-runtime.js +520 -0
- package/scripts/codex-recovery.js +246 -1
package/core/memory-promotion.js
CHANGED
|
@@ -123,6 +123,61 @@ function normalizeEvidenceRefs(candidate = {}) {
|
|
|
123
123
|
return candidate.evidenceRefs || candidate.evidence_refs || [];
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
function normalizeEvidenceTexts(candidate = {}) {
|
|
127
|
+
const raw = candidate.evidenceItems || candidate.evidence_items || candidate.evidenceTexts || candidate.evidence_texts;
|
|
128
|
+
const values = Array.isArray(raw) ? raw : [];
|
|
129
|
+
const direct = [
|
|
130
|
+
candidate.evidenceText,
|
|
131
|
+
candidate.evidence_text,
|
|
132
|
+
candidate.evidenceExcerpt,
|
|
133
|
+
candidate.evidence_excerpt,
|
|
134
|
+
candidate.sourceText,
|
|
135
|
+
candidate.source_text,
|
|
136
|
+
candidate.quote,
|
|
137
|
+
];
|
|
138
|
+
for (const value of direct) {
|
|
139
|
+
if (value) values.push(value);
|
|
140
|
+
}
|
|
141
|
+
return values
|
|
142
|
+
.map(value => {
|
|
143
|
+
if (typeof value === 'string') return { excerptText: normalizeText(value), metadata: {} };
|
|
144
|
+
if (!value || typeof value !== 'object') return null;
|
|
145
|
+
const excerptText = normalizeText(value.excerptText || value.excerpt_text || value.text || value.quote || value.summary);
|
|
146
|
+
if (!excerptText) return null;
|
|
147
|
+
return {
|
|
148
|
+
...value,
|
|
149
|
+
excerptText,
|
|
150
|
+
metadata: value.metadata || {},
|
|
151
|
+
};
|
|
152
|
+
})
|
|
153
|
+
.filter(value => value && value.excerptText);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function buildMemoryEmbeddingText(candidate = {}) {
|
|
157
|
+
const fields = [
|
|
158
|
+
['title', candidate.title],
|
|
159
|
+
['summary', candidate.summary],
|
|
160
|
+
['context', candidate.contextKey || candidate.context_key],
|
|
161
|
+
['topic', candidate.topicKey || candidate.topic_key],
|
|
162
|
+
]
|
|
163
|
+
.map(([label, value]) => {
|
|
164
|
+
const text = normalizeText(value);
|
|
165
|
+
return text ? `${label}: ${text}` : '';
|
|
166
|
+
})
|
|
167
|
+
.filter(Boolean);
|
|
168
|
+
return fields.join('\n');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function assignEmbeddedVectors(items, vectors, errorPrefix) {
|
|
172
|
+
if (!Array.isArray(vectors) || vectors.length !== items.length) {
|
|
173
|
+
throw new Error(`${errorPrefix} returned ${Array.isArray(vectors) ? vectors.length : 'invalid'} vectors for ${items.length} texts`);
|
|
174
|
+
}
|
|
175
|
+
for (let i = 0; i < items.length; i++) {
|
|
176
|
+
const vector = vectors[i];
|
|
177
|
+
if (Array.isArray(vector) && vector.length > 0) items[i].embedding = vector;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
126
181
|
function buildFactAssertion(candidate = {}, opts = {}) {
|
|
127
182
|
const memoryType = normalizeType(candidate.memoryType || candidate.memory_type);
|
|
128
183
|
if (memoryType !== 'fact') return null;
|
|
@@ -217,6 +272,15 @@ function pushStructuredCandidates(candidates, items, spec) {
|
|
|
217
272
|
const text = textFromItem(item, spec.keys);
|
|
218
273
|
if (!text) continue;
|
|
219
274
|
const itemObj = item && typeof item === 'object' ? item : null;
|
|
275
|
+
const evidenceText = normalizeText(itemObj && (
|
|
276
|
+
itemObj.evidenceText
|
|
277
|
+
|| itemObj.evidence_text
|
|
278
|
+
|| itemObj.evidenceExcerpt
|
|
279
|
+
|| itemObj.evidence_excerpt
|
|
280
|
+
|| itemObj.sourceText
|
|
281
|
+
|| itemObj.source_text
|
|
282
|
+
|| itemObj.quote
|
|
283
|
+
));
|
|
220
284
|
const explicitSubject = normalizeText(itemObj && (itemObj.subject || itemObj.entity || itemObj.name));
|
|
221
285
|
const explicitAspect = normalizeText(itemObj && (itemObj.aspect || itemObj.predicate || itemObj.attribute));
|
|
222
286
|
const subject = explicitSubject || normalizeText(spec.subject);
|
|
@@ -242,6 +306,7 @@ function pushStructuredCandidates(candidates, items, spec) {
|
|
|
242
306
|
payload: typeof item === 'string' ? { [spec.payloadKey]: text } : { ...item, [spec.payloadKey]: text },
|
|
243
307
|
authority: spec.authority,
|
|
244
308
|
evidenceRefs: spec.evidenceRefs,
|
|
309
|
+
evidenceText: evidenceText || undefined,
|
|
245
310
|
visibleInBootstrap: true,
|
|
246
311
|
visibleInRecall: true,
|
|
247
312
|
});
|
|
@@ -355,7 +420,45 @@ function assessCandidate(candidate = {}, opts = {}) {
|
|
|
355
420
|
return { action: 'promote', reason: 'v1_foundation_allowed' };
|
|
356
421
|
}
|
|
357
422
|
|
|
358
|
-
function createMemoryPromotion({ records }) {
|
|
423
|
+
function createMemoryPromotion({ records, embedFn = null }) {
|
|
424
|
+
async function prepareCandidates(candidates = []) {
|
|
425
|
+
const prepared = candidates.map(candidate => ({ ...candidate }));
|
|
426
|
+
if (typeof embedFn !== 'function' || prepared.length === 0) return prepared;
|
|
427
|
+
|
|
428
|
+
const pendingMemoryRows = [];
|
|
429
|
+
const memoryTexts = [];
|
|
430
|
+
for (const candidate of prepared) {
|
|
431
|
+
if (Array.isArray(candidate.embedding) && candidate.embedding.length > 0) continue;
|
|
432
|
+
const text = buildMemoryEmbeddingText(candidate);
|
|
433
|
+
if (!text) continue;
|
|
434
|
+
pendingMemoryRows.push(candidate);
|
|
435
|
+
memoryTexts.push(text);
|
|
436
|
+
}
|
|
437
|
+
if (memoryTexts.length > 0) {
|
|
438
|
+
const vectors = await embedFn(memoryTexts);
|
|
439
|
+
assignEmbeddedVectors(pendingMemoryRows, vectors, 'memory promotion embedFn');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const pendingEvidenceItems = [];
|
|
443
|
+
const evidenceTexts = [];
|
|
444
|
+
for (const candidate of prepared) {
|
|
445
|
+
const normalizedEvidenceTexts = normalizeEvidenceTexts(candidate);
|
|
446
|
+
candidate._preparedEvidenceTexts = normalizedEvidenceTexts;
|
|
447
|
+
for (const item of normalizedEvidenceTexts) {
|
|
448
|
+
if (Array.isArray(item.embedding) && item.embedding.length > 0) continue;
|
|
449
|
+
if (!item.excerptText) continue;
|
|
450
|
+
pendingEvidenceItems.push(item);
|
|
451
|
+
evidenceTexts.push(item.excerptText);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (evidenceTexts.length > 0) {
|
|
455
|
+
const vectors = await embedFn(evidenceTexts);
|
|
456
|
+
assignEmbeddedVectors(pendingEvidenceItems, vectors, 'memory evidence embedFn');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return prepared;
|
|
460
|
+
}
|
|
461
|
+
|
|
359
462
|
async function promoteOne(candidate, opts = {}, candidateRecords = records, tx = {}) {
|
|
360
463
|
if (tx.inTransaction && candidateRecords.lockCanonicalKey && candidate.canonicalKey) {
|
|
361
464
|
await candidateRecords.lockCanonicalKey({
|
|
@@ -386,6 +489,7 @@ function createMemoryPromotion({ records }) {
|
|
|
386
489
|
|
|
387
490
|
const memoryType = normalizeType(candidate.memoryType || candidate.memory_type);
|
|
388
491
|
const acceptedAt = candidate.acceptedAt || opts.acceptedAt || new Date().toISOString();
|
|
492
|
+
const evidenceTexts = candidate._preparedEvidenceTexts || normalizeEvidenceTexts(candidate);
|
|
389
493
|
let scopeId = candidate.scopeId || candidate.scope_id || null;
|
|
390
494
|
if (!scopeId) {
|
|
391
495
|
const scope = await candidateRecords.upsertScope({
|
|
@@ -399,6 +503,52 @@ function createMemoryPromotion({ records }) {
|
|
|
399
503
|
scopeId = scope.id;
|
|
400
504
|
}
|
|
401
505
|
|
|
506
|
+
async function linkCandidateEvidence(ownerKind, ownerId, ref) {
|
|
507
|
+
const base = {
|
|
508
|
+
tenantId: opts.tenantId,
|
|
509
|
+
ownerKind,
|
|
510
|
+
ownerId,
|
|
511
|
+
sourceKind: ref.sourceKind || ref.source_kind,
|
|
512
|
+
sourceRef: ref.sourceRef || ref.source_ref,
|
|
513
|
+
relationKind: ref.relationKind || ref.relation_kind || 'supporting',
|
|
514
|
+
weight: ref.weight ?? 1.0,
|
|
515
|
+
metadata: ref.metadata || {},
|
|
516
|
+
createdByFinalizationId: opts.createdByFinalizationId || opts.created_by_finalization_id || null,
|
|
517
|
+
createdByCompactionRunId: opts.createdByCompactionRunId || opts.created_by_compaction_run_id || null,
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
if (!candidateRecords.upsertEvidenceItem || evidenceTexts.length === 0) {
|
|
521
|
+
await candidateRecords.linkEvidence(base);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
for (const item of evidenceTexts) {
|
|
526
|
+
const evidenceItem = await candidateRecords.upsertEvidenceItem({
|
|
527
|
+
tenantId: opts.tenantId,
|
|
528
|
+
sourceKind: item.sourceKind || item.source_kind || base.sourceKind,
|
|
529
|
+
sourceRef: item.sourceRef || item.source_ref || base.sourceRef,
|
|
530
|
+
sessionRowId: item.sessionRowId || item.session_row_id || null,
|
|
531
|
+
turnEmbeddingId: item.turnEmbeddingId || item.turn_embedding_id || null,
|
|
532
|
+
summaryRowId: item.summaryRowId || item.summary_row_id || null,
|
|
533
|
+
createdByFinalizationId: base.createdByFinalizationId,
|
|
534
|
+
excerptText: item.excerptText,
|
|
535
|
+
excerptHash: item.excerptHash || item.excerpt_hash || null,
|
|
536
|
+
embedding: item.embedding || null,
|
|
537
|
+
metadata: {
|
|
538
|
+
...(item.metadata || {}),
|
|
539
|
+
memoryType,
|
|
540
|
+
canonicalKey: candidate.canonicalKey,
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
await candidateRecords.linkEvidence({
|
|
544
|
+
...base,
|
|
545
|
+
sourceKind: item.sourceKind || item.source_kind || base.sourceKind,
|
|
546
|
+
sourceRef: item.sourceRef || item.source_ref || base.sourceRef,
|
|
547
|
+
evidenceItemId: evidenceItem ? evidenceItem.id : null,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
402
552
|
let backingFact = null;
|
|
403
553
|
const factAssertion = buildFactAssertion(candidate, {
|
|
404
554
|
tenantId: opts.tenantId,
|
|
@@ -444,18 +594,7 @@ function createMemoryPromotion({ records }) {
|
|
|
444
594
|
}
|
|
445
595
|
|
|
446
596
|
for (const ref of normalizeEvidenceRefs(candidate)) {
|
|
447
|
-
await
|
|
448
|
-
tenantId: opts.tenantId,
|
|
449
|
-
ownerKind: 'fact',
|
|
450
|
-
ownerId: backingFact.id,
|
|
451
|
-
sourceKind: ref.sourceKind || ref.source_kind,
|
|
452
|
-
sourceRef: ref.sourceRef || ref.source_ref,
|
|
453
|
-
relationKind: ref.relationKind || ref.relation_kind || 'supporting',
|
|
454
|
-
weight: ref.weight ?? 1.0,
|
|
455
|
-
metadata: ref.metadata || {},
|
|
456
|
-
createdByFinalizationId: opts.createdByFinalizationId || opts.created_by_finalization_id || null,
|
|
457
|
-
createdByCompactionRunId: opts.createdByCompactionRunId || opts.created_by_compaction_run_id || null,
|
|
458
|
-
});
|
|
597
|
+
await linkCandidateEvidence('fact', backingFact.id, ref);
|
|
459
598
|
}
|
|
460
599
|
}
|
|
461
600
|
|
|
@@ -482,6 +621,7 @@ function createMemoryPromotion({ records }) {
|
|
|
482
621
|
visibleInBootstrap: candidate.visibleInBootstrap !== false,
|
|
483
622
|
visibleInRecall: candidate.visibleInRecall !== false,
|
|
484
623
|
rankFeatures: candidate.rankFeatures || {},
|
|
624
|
+
embedding: candidate.embedding || null,
|
|
485
625
|
});
|
|
486
626
|
|
|
487
627
|
if (assessment.supersedeId && candidateRecords.updateMemoryStatus) {
|
|
@@ -495,26 +635,16 @@ function createMemoryPromotion({ records }) {
|
|
|
495
635
|
}
|
|
496
636
|
|
|
497
637
|
for (const ref of normalizeEvidenceRefs(candidate)) {
|
|
498
|
-
await
|
|
499
|
-
tenantId: opts.tenantId,
|
|
500
|
-
ownerKind: 'memory_record',
|
|
501
|
-
ownerId: memory.id,
|
|
502
|
-
sourceKind: ref.sourceKind || ref.source_kind,
|
|
503
|
-
sourceRef: ref.sourceRef || ref.source_ref,
|
|
504
|
-
relationKind: ref.relationKind || ref.relation_kind || 'supporting',
|
|
505
|
-
weight: ref.weight ?? 1.0,
|
|
506
|
-
metadata: ref.metadata || {},
|
|
507
|
-
createdByFinalizationId: opts.createdByFinalizationId || opts.created_by_finalization_id || null,
|
|
508
|
-
createdByCompactionRunId: opts.createdByCompactionRunId || opts.created_by_compaction_run_id || null,
|
|
509
|
-
});
|
|
638
|
+
await linkCandidateEvidence('memory_record', memory.id, ref);
|
|
510
639
|
}
|
|
511
640
|
|
|
512
641
|
return { candidate, action: 'promote', reason: assessment.reason, memory, backingFact };
|
|
513
642
|
}
|
|
514
643
|
|
|
515
644
|
async function promote(candidates = [], opts = {}) {
|
|
645
|
+
const preparedCandidates = await prepareCandidates(candidates);
|
|
516
646
|
const results = [];
|
|
517
|
-
for (const candidate of
|
|
647
|
+
for (const candidate of preparedCandidates) {
|
|
518
648
|
const result = records.withTransaction
|
|
519
649
|
? await records.withTransaction((txRecords, meta = {}) => promoteOne(candidate, opts, txRecords, {
|
|
520
650
|
inTransaction: meta.transactional !== false,
|
|
@@ -538,6 +668,7 @@ module.exports = {
|
|
|
538
668
|
AUTHORITY_RANK,
|
|
539
669
|
defaultInheritanceForType,
|
|
540
670
|
buildCanonicalKey,
|
|
671
|
+
buildMemoryEmbeddingText,
|
|
541
672
|
extractCandidatesFromStructuredSummary,
|
|
542
673
|
assessCandidate,
|
|
543
674
|
createMemoryPromotion,
|