@devflow-tools/memory-engine 0.17.0 → 0.17.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/dist/consolidator.d.ts.map +1 -1
- package/dist/consolidator.js +11 -12
- package/dist/consolidator.js.map +1 -1
- package/dist/event-grouper.d.ts +1 -0
- package/dist/event-grouper.d.ts.map +1 -1
- package/dist/event-grouper.js +18 -13
- package/dist/event-grouper.js.map +1 -1
- package/dist/hybrid-search.d.ts +1 -0
- package/dist/hybrid-search.d.ts.map +1 -1
- package/dist/hybrid-search.js +73 -6
- package/dist/hybrid-search.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/memory-capsule.d.ts +3 -0
- package/dist/memory-capsule.d.ts.map +1 -1
- package/dist/memory-capsule.js +27 -0
- package/dist/memory-capsule.js.map +1 -1
- package/dist/memory-engine.d.ts.map +1 -1
- package/dist/memory-engine.js +75 -34
- package/dist/memory-engine.js.map +1 -1
- package/dist/memory-gate.d.ts +5 -0
- package/dist/memory-gate.d.ts.map +1 -1
- package/dist/memory-gate.js +276 -30
- package/dist/memory-gate.js.map +1 -1
- package/dist/memory-relevance.d.ts +3 -0
- package/dist/memory-relevance.d.ts.map +1 -1
- package/dist/memory-relevance.js +8 -2
- package/dist/memory-relevance.js.map +1 -1
- package/dist/memory-store.d.ts +1 -0
- package/dist/memory-store.d.ts.map +1 -1
- package/dist/memory-store.js +57 -18
- package/dist/memory-store.js.map +1 -1
- package/dist/semantic-memory-compiler.d.ts +29 -0
- package/dist/semantic-memory-compiler.d.ts.map +1 -0
- package/dist/semantic-memory-compiler.js +148 -0
- package/dist/semantic-memory-compiler.js.map +1 -0
- package/dist/session-summarizer.d.ts +2 -0
- package/dist/session-summarizer.d.ts.map +1 -1
- package/dist/session-summarizer.js.map +1 -1
- package/package.json +4 -3
package/dist/memory-gate.js
CHANGED
|
@@ -12,7 +12,8 @@ import { join } from 'node:path';
|
|
|
12
12
|
import { isObservationType, observationDedupKey, } from './observation-types.js';
|
|
13
13
|
import { evaluateObservationQuality } from './observation-quality.js';
|
|
14
14
|
import { mergeSemanticEntities, normalizeEntityKey, normalizeSemanticMemory, } from './semantic-memory.js';
|
|
15
|
-
import { validateMemoryCapsules } from './memory-capsule.js';
|
|
15
|
+
import { validateEvidenceSpans, validateMemoryCapsules } from './memory-capsule.js';
|
|
16
|
+
import { emitSemanticControlLog } from '@devflow-tools/telemetry';
|
|
16
17
|
const BATCH_CONCEPT_STOP_WORDS = new Set([
|
|
17
18
|
'a', 'an', 'the', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
18
19
|
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'should',
|
|
@@ -180,10 +181,12 @@ export class MemoryGate {
|
|
|
180
181
|
if (this.engine && signals.length > 0) {
|
|
181
182
|
try {
|
|
182
183
|
this.engine.recordSignals(signals);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
emitSemanticControlLog({
|
|
185
|
+
event: 'memory.write.completed',
|
|
186
|
+
identity: { projectRoot: this.projectRoot, sessionId: event.sessionId },
|
|
187
|
+
level: 'debug',
|
|
188
|
+
timestamp: Date.now(),
|
|
189
|
+
data: { stage: 'signals', count: signals.length, types: signals.map(signal => signal.type) },
|
|
187
190
|
});
|
|
188
191
|
}
|
|
189
192
|
catch { /* non-critical */ }
|
|
@@ -263,9 +266,9 @@ export class MemoryGate {
|
|
|
263
266
|
.filter(event => sessionId === undefined || event.session_id === sessionId);
|
|
264
267
|
if (events.length === 0)
|
|
265
268
|
return null;
|
|
266
|
-
const groups = groupEventsBySession(events);
|
|
269
|
+
const groups = groupEventsBySession(events, { projectRoot: this.projectRoot });
|
|
267
270
|
const preserveSessionIds = this.getActiveSessionIds(groups);
|
|
268
|
-
const { selected, discarded } = triageGroupsWithDisposition(groups, 8, { preserveSessionIds });
|
|
271
|
+
const { selected, discarded } = triageGroupsWithDisposition(groups, 8, { preserveSessionIds, projectRoot: this.projectRoot });
|
|
269
272
|
const discardedEventIds = discarded.flatMap(group => group.events).map(event => event.id);
|
|
270
273
|
if (discardedEventIds.length > 0) {
|
|
271
274
|
const discardedSessionIds = [...new Set(discarded.flatMap(group => group.events).map(event => event.session_id).filter(Boolean))];
|
|
@@ -452,10 +455,12 @@ export class MemoryGate {
|
|
|
452
455
|
leases.commitLease(batchId);
|
|
453
456
|
});
|
|
454
457
|
transaction();
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
458
|
+
emitSemanticControlLog({
|
|
459
|
+
event: 'memory.write.completed',
|
|
460
|
+
identity: { projectRoot: this.projectRoot, sessionId: lease.sessionIds[0] },
|
|
461
|
+
level: 'info',
|
|
462
|
+
timestamp: Date.now(),
|
|
463
|
+
data: { stage: 'distill_batch', batchId, observationCount: validObs.length, eventsMarked: lease.eventIds.length },
|
|
459
464
|
});
|
|
460
465
|
return validObs.length;
|
|
461
466
|
}
|
|
@@ -503,6 +508,7 @@ export class MemoryGate {
|
|
|
503
508
|
observations: validObs,
|
|
504
509
|
sourceEvents: [event],
|
|
505
510
|
defaultSourceEventIds: [turnEventId],
|
|
511
|
+
evidenceText: readCanonicalPrompt(event.payload, event.user_message) || undefined,
|
|
506
512
|
});
|
|
507
513
|
if (capsules.rejected.length > 0 || capsules.accepted.length !== validObs.length) {
|
|
508
514
|
throw new Error(`memory_commit_turn failed semantic capsule validation: ${JSON.stringify(capsules.rejected)}`);
|
|
@@ -579,6 +585,139 @@ export class MemoryGate {
|
|
|
579
585
|
})();
|
|
580
586
|
return saved;
|
|
581
587
|
}
|
|
588
|
+
async refineExplicitTurnObservations(turnEventId, sessionId, observations) {
|
|
589
|
+
if (!this.engine)
|
|
590
|
+
await this.forceWarmUp();
|
|
591
|
+
const engine = this.requireEngine();
|
|
592
|
+
const event = engine.store.getEvent(turnEventId);
|
|
593
|
+
if (!event || event.session_id !== sessionId) {
|
|
594
|
+
throw new Error(`Memory turn event ${turnEventId} was not found for session ${sessionId}`);
|
|
595
|
+
}
|
|
596
|
+
const sourceText = readCanonicalPrompt(event.payload, event.user_message);
|
|
597
|
+
if (!sourceText)
|
|
598
|
+
throw new Error(`Memory turn event ${turnEventId} has no canonical user prompt`);
|
|
599
|
+
for (const observation of observations) {
|
|
600
|
+
validateEvidenceSpans(sourceText, observation.evidenceSpans ?? []);
|
|
601
|
+
}
|
|
602
|
+
const durableCandidates = observations.filter(observation => observation.disposition !== 'turn_constraint');
|
|
603
|
+
const turnConstraints = observations.filter(observation => observation.disposition === 'turn_constraint');
|
|
604
|
+
const validObs = durableCandidates.length > 0 ? validateObservationBatch(durableCandidates) : [];
|
|
605
|
+
if (!validObs)
|
|
606
|
+
throw new Error('Explicit memory refinement contains invalid durable candidates');
|
|
607
|
+
const capsules = validateMemoryCapsules({
|
|
608
|
+
projectRoot: this.projectRoot,
|
|
609
|
+
observations: validObs,
|
|
610
|
+
sourceEvents: [event],
|
|
611
|
+
defaultSourceEventIds: [turnEventId],
|
|
612
|
+
evidenceText: sourceText,
|
|
613
|
+
requireEvidenceSpans: true,
|
|
614
|
+
});
|
|
615
|
+
if (capsules.rejected.length > 0 || capsules.accepted.length !== validObs.length) {
|
|
616
|
+
throw new Error(`Explicit memory refinement failed evidence validation: ${JSON.stringify(capsules.rejected)}`);
|
|
617
|
+
}
|
|
618
|
+
const existingIds = new Set(engine.store.listObservations().map(observation => observation.id));
|
|
619
|
+
const turnId = eventTurnId(event, turnEventId);
|
|
620
|
+
const memories = [];
|
|
621
|
+
const retiredMemoryIds = [];
|
|
622
|
+
const operations = [];
|
|
623
|
+
this.getStoreDb().transaction(() => {
|
|
624
|
+
for (const acceptedCapsule of capsules.accepted) {
|
|
625
|
+
const observation = acceptedCapsule.observation;
|
|
626
|
+
const semantic = normalizeSemanticMemory({
|
|
627
|
+
project: this.projectRoot,
|
|
628
|
+
type: observation.type,
|
|
629
|
+
title: observation.title,
|
|
630
|
+
narrative: observation.narrative ?? '',
|
|
631
|
+
concepts: observation.concepts,
|
|
632
|
+
subject: observation.subject,
|
|
633
|
+
predicate: observation.predicate,
|
|
634
|
+
value: observation.value,
|
|
635
|
+
polarity: observation.polarity,
|
|
636
|
+
entities: observation.entities,
|
|
637
|
+
temporal: observation.temporal,
|
|
638
|
+
});
|
|
639
|
+
const write = engine.store.acceptSemanticObservation({
|
|
640
|
+
sessionId,
|
|
641
|
+
project: this.projectRoot,
|
|
642
|
+
type: observation.type,
|
|
643
|
+
title: observation.title,
|
|
644
|
+
narrative: observation.narrative,
|
|
645
|
+
facts: [...new Set([...(observation.facts ?? []), ...(observation.evidenceSpans ?? [])])],
|
|
646
|
+
concepts: mergeSemanticEntities(normalizeBatchConcepts(observation), [semantic.subject, semantic.predicate, semantic.value], semantic.entities.map(normalizeEntityKey)),
|
|
647
|
+
importance: Math.max(8, observation.importance),
|
|
648
|
+
confidence: Math.max(0.9, observation.confidence),
|
|
649
|
+
source: 'explicit_intent',
|
|
650
|
+
sourceEventIds: [turnEventId],
|
|
651
|
+
qualityStatus: 'accepted',
|
|
652
|
+
evidenceStatus: 'verified',
|
|
653
|
+
evidenceDetails: (observation.evidenceSpans ?? []).map(span => ({
|
|
654
|
+
kind: 'host_evidence_span',
|
|
655
|
+
source: turnEventId,
|
|
656
|
+
summary: span,
|
|
657
|
+
})),
|
|
658
|
+
semantic,
|
|
659
|
+
capsule: acceptedCapsule.capsule,
|
|
660
|
+
projection: acceptedCapsule.projection,
|
|
661
|
+
preferIncomingNarrative: true,
|
|
662
|
+
});
|
|
663
|
+
const row = write.row;
|
|
664
|
+
operations.push(write.action.toLocaleLowerCase('en-US'));
|
|
665
|
+
memories.push({
|
|
666
|
+
id: row.id,
|
|
667
|
+
type: row.type,
|
|
668
|
+
title: row.title,
|
|
669
|
+
content: row.narrative,
|
|
670
|
+
source: row.source,
|
|
671
|
+
scope: row.project,
|
|
672
|
+
confidence: row.confidence,
|
|
673
|
+
importance: row.importance,
|
|
674
|
+
score: 1,
|
|
675
|
+
createdAt: row.timestamp,
|
|
676
|
+
indexStatus: row.embedding ? 'indexed' : 'pending',
|
|
677
|
+
});
|
|
678
|
+
engine.store.recordPendingTurnObservation({
|
|
679
|
+
turnEventId,
|
|
680
|
+
turnId,
|
|
681
|
+
sessionId,
|
|
682
|
+
project: this.projectRoot,
|
|
683
|
+
observationId: row.id,
|
|
684
|
+
createdByTurn: !existingIds.has(row.id),
|
|
685
|
+
createdAt: event.created_at,
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
const constraintSpans = turnConstraints.flatMap(candidate => candidate.evidenceSpans ?? []);
|
|
689
|
+
const baseline = engine.store.listObservations({ project: this.projectRoot })
|
|
690
|
+
.filter(observation => observation.source === 'explicit_intent')
|
|
691
|
+
.filter(observation => parseLearningStringArray(observation.source_event_ids).includes(turnEventId));
|
|
692
|
+
for (const observation of baseline) {
|
|
693
|
+
if (!constraintSpans.some(span => sameGroundedClause(observation.narrative, span)))
|
|
694
|
+
continue;
|
|
695
|
+
if (engine.store.quarantineObservation(observation.id, 'host_classified_turn_constraint', {
|
|
696
|
+
turnId,
|
|
697
|
+
eventId: turnEventId,
|
|
698
|
+
evidenceSpans: constraintSpans,
|
|
699
|
+
})) {
|
|
700
|
+
retiredMemoryIds.push(observation.id);
|
|
701
|
+
operations.push('retire');
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
})();
|
|
705
|
+
emitSemanticControlLog({
|
|
706
|
+
event: 'memory.semantic.refined',
|
|
707
|
+
identity: { projectRoot: this.projectRoot, sessionId, turnId },
|
|
708
|
+
level: 'info',
|
|
709
|
+
timestamp: Date.now(),
|
|
710
|
+
data: {
|
|
711
|
+
candidateCount: observations.length,
|
|
712
|
+
durableCount: durableCandidates.length,
|
|
713
|
+
turnConstraintCount: turnConstraints.length,
|
|
714
|
+
memoryIds: memories.map(memory => memory.id),
|
|
715
|
+
retiredMemoryIds,
|
|
716
|
+
operations,
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
return { memories, retiredMemoryIds, operations };
|
|
720
|
+
}
|
|
582
721
|
async skipTurnEvent(turnEventId, sessionId, reason) {
|
|
583
722
|
if (!this.engine)
|
|
584
723
|
await this.forceWarmUp();
|
|
@@ -639,7 +778,13 @@ export class MemoryGate {
|
|
|
639
778
|
* @deprecated Use saveDistilledObservationsByBatch(batchId, observations) instead.
|
|
640
779
|
*/
|
|
641
780
|
async saveDistilledObservations(observations, sessionId) {
|
|
642
|
-
|
|
781
|
+
emitSemanticControlLog({
|
|
782
|
+
event: 'memory.write.degraded',
|
|
783
|
+
identity: { projectRoot: this.projectRoot, sessionId },
|
|
784
|
+
level: 'warn',
|
|
785
|
+
timestamp: Date.now(),
|
|
786
|
+
data: { stage: 'legacy_distill', reason: 'deprecated_session_write', fallback: 'legacy_compatibility_path' },
|
|
787
|
+
});
|
|
643
788
|
if (!this.engine)
|
|
644
789
|
return 0;
|
|
645
790
|
const validObs = validateObservationBatch(observations);
|
|
@@ -684,10 +829,12 @@ export class MemoryGate {
|
|
|
684
829
|
engine.store.markEventsProcessed(unprocessedIds);
|
|
685
830
|
});
|
|
686
831
|
transaction();
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
832
|
+
emitSemanticControlLog({
|
|
833
|
+
event: 'memory.write.completed',
|
|
834
|
+
identity: { projectRoot: this.projectRoot, sessionId },
|
|
835
|
+
level: 'info',
|
|
836
|
+
timestamp: Date.now(),
|
|
837
|
+
data: { stage: 'legacy_distill', observationCount: validObs.length, eventsMarked: unprocessedIds.length },
|
|
691
838
|
});
|
|
692
839
|
return validObs.length;
|
|
693
840
|
}
|
|
@@ -716,11 +863,12 @@ export class MemoryGate {
|
|
|
716
863
|
const events = this.engine.store.getUnprocessedEvents();
|
|
717
864
|
if (events.length === 0)
|
|
718
865
|
return 0;
|
|
719
|
-
const groups = groupEventsBySession(events, { log: false });
|
|
866
|
+
const groups = groupEventsBySession(events, { log: false, projectRoot: this.projectRoot });
|
|
720
867
|
const preserveSessionIds = this.getActiveSessionIds(groups);
|
|
721
868
|
const { discarded } = triageGroupsWithDisposition(groups, Number.MAX_SAFE_INTEGER, {
|
|
722
869
|
log: false,
|
|
723
870
|
preserveSessionIds,
|
|
871
|
+
projectRoot: this.projectRoot,
|
|
724
872
|
});
|
|
725
873
|
const ids = discarded.flatMap(group => group.events).map(event => event.id);
|
|
726
874
|
return this.engine.store.discardEvents(ids, 'low_value_auto_triage', `auto-triage:${Date.now()}`);
|
|
@@ -753,7 +901,10 @@ export class MemoryGate {
|
|
|
753
901
|
this.projectValid = true;
|
|
754
902
|
}
|
|
755
903
|
this.state = 'warming';
|
|
756
|
-
|
|
904
|
+
emitSemanticControlLog({
|
|
905
|
+
event: 'memory.engine.transitioned', identity: { projectRoot: this.projectRoot }, level: 'info', timestamp: Date.now(),
|
|
906
|
+
data: { from: 'cold', to: 'warming' },
|
|
907
|
+
});
|
|
757
908
|
this.engine = new MemoryEngine(this.projectRoot, this.embedder);
|
|
758
909
|
this.setLeaseStore(new LeaseStore(this.getStoreDb()));
|
|
759
910
|
// Clean up zombie sessions (>24h active)
|
|
@@ -761,7 +912,13 @@ export class MemoryGate {
|
|
|
761
912
|
const zombies = this.engine.store.getZombieSessions(24);
|
|
762
913
|
for (const z of zombies) {
|
|
763
914
|
this.engine.store.closeSession(z.id);
|
|
764
|
-
|
|
915
|
+
emitSemanticControlLog({
|
|
916
|
+
event: 'memory.engine.transitioned',
|
|
917
|
+
identity: { projectRoot: this.projectRoot, sessionId: z.id },
|
|
918
|
+
level: 'warn',
|
|
919
|
+
timestamp: Date.now(),
|
|
920
|
+
data: { from: 'active', to: 'closed', reason: 'zombie_session', ageHours: Math.round((Date.now() - z.created_at) / 3600000) },
|
|
921
|
+
});
|
|
765
922
|
}
|
|
766
923
|
}
|
|
767
924
|
catch { /* non-critical */ }
|
|
@@ -771,7 +928,10 @@ export class MemoryGate {
|
|
|
771
928
|
}
|
|
772
929
|
catch { /* non-critical */ }
|
|
773
930
|
this.state = 'hot';
|
|
774
|
-
|
|
931
|
+
emitSemanticControlLog({
|
|
932
|
+
event: 'memory.engine.transitioned', identity: { projectRoot: this.projectRoot }, level: 'info', timestamp: Date.now(),
|
|
933
|
+
data: { from: 'warming', to: 'hot' },
|
|
934
|
+
});
|
|
775
935
|
}
|
|
776
936
|
// --- IMemoryEngine implementation (delegates to engine when hot) ---
|
|
777
937
|
requireEngine() {
|
|
@@ -854,7 +1014,28 @@ export class MemoryGate {
|
|
|
854
1014
|
async saveExplicitMemoryIntent(content, sessionId, sourceEventId) {
|
|
855
1015
|
if (!this.engine)
|
|
856
1016
|
await this.forceWarmUp();
|
|
857
|
-
|
|
1017
|
+
try {
|
|
1018
|
+
const result = await this.requireEngine().saveExplicitMemoryIntent(content, sessionId, sourceEventId);
|
|
1019
|
+
emitSemanticControlLog({
|
|
1020
|
+
event: 'memory.write.completed',
|
|
1021
|
+
identity: { projectRoot: this.projectRoot, sessionId },
|
|
1022
|
+
level: 'info',
|
|
1023
|
+
timestamp: Date.now(),
|
|
1024
|
+
data: {
|
|
1025
|
+
stage: 'explicit_memory', memoryId: result.id, relatedMemoryIds: result.relatedMemoryIds ?? [],
|
|
1026
|
+
semanticStatus: result.semanticDecision?.status,
|
|
1027
|
+
operations: result.semanticDecision?.operations ?? [],
|
|
1028
|
+
},
|
|
1029
|
+
});
|
|
1030
|
+
return result;
|
|
1031
|
+
}
|
|
1032
|
+
catch (error) {
|
|
1033
|
+
emitSemanticControlLog({
|
|
1034
|
+
event: 'memory.write.degraded', identity: { projectRoot: this.projectRoot, sessionId }, level: 'error', timestamp: Date.now(),
|
|
1035
|
+
data: { stage: 'explicit_memory', reason: memoryErrorReason(error) },
|
|
1036
|
+
});
|
|
1037
|
+
throw error;
|
|
1038
|
+
}
|
|
858
1039
|
}
|
|
859
1040
|
async enrichExplicitMemoryObservation(observationId) {
|
|
860
1041
|
if (!this.engine)
|
|
@@ -924,15 +1105,28 @@ export class MemoryGate {
|
|
|
924
1105
|
const rows = engine.store.listObservationsMissingEmbedding(batchSize, lastId);
|
|
925
1106
|
if (rows.length === 0)
|
|
926
1107
|
break;
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
|
|
1108
|
+
const texts = rows.map(row => `${row.title}\n${row.narrative}`);
|
|
1109
|
+
let indexed = [];
|
|
1110
|
+
try {
|
|
1111
|
+
const embeddings = await this.embedder.embedBatch(texts);
|
|
1112
|
+
if (embeddings.length !== rows.length) {
|
|
1113
|
+
throw new Error(`Observation vector count mismatch: ${rows.length} observations, ${embeddings.length} vectors`);
|
|
1114
|
+
}
|
|
1115
|
+
indexed = rows.map((row, index) => ({ id: row.id, embedding: embeddings[index] }));
|
|
930
1116
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1117
|
+
catch {
|
|
1118
|
+
for (let index = 0; index < rows.length; index++) {
|
|
1119
|
+
try {
|
|
1120
|
+
indexed.push({ id: rows[index].id, embedding: await this.embedder.embed(texts[index]) });
|
|
1121
|
+
}
|
|
1122
|
+
catch {
|
|
1123
|
+
// Keep this observation pending; deterministic retrieval remains available.
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
if (indexed.length > 0)
|
|
1128
|
+
engine.store.insertObservationEmbeddings(indexed);
|
|
1129
|
+
processed += indexed.length;
|
|
936
1130
|
lastId = rows.at(-1).id;
|
|
937
1131
|
const coverage = engine.store.countObservationVectors();
|
|
938
1132
|
options.onProgress?.({ processed, remaining: coverage.missing, lastId });
|
|
@@ -964,7 +1158,38 @@ export class MemoryGate {
|
|
|
964
1158
|
async search(query, options) {
|
|
965
1159
|
if (!this.engine)
|
|
966
1160
|
await this.forceWarmUp();
|
|
967
|
-
|
|
1161
|
+
const startedAt = Date.now();
|
|
1162
|
+
try {
|
|
1163
|
+
const results = await this.requireEngine().search(query, options);
|
|
1164
|
+
emitSemanticControlLog({
|
|
1165
|
+
event: 'memory.search.completed',
|
|
1166
|
+
identity: {
|
|
1167
|
+
projectRoot: this.projectRoot,
|
|
1168
|
+
sessionId: options?.sessionId,
|
|
1169
|
+
executionId: options?.executionId,
|
|
1170
|
+
requestId: options?.requestId,
|
|
1171
|
+
},
|
|
1172
|
+
level: 'info',
|
|
1173
|
+
timestamp: Date.now(),
|
|
1174
|
+
data: {
|
|
1175
|
+
status: results.length > 0 ? 'selected' : 'empty', selected: results.length,
|
|
1176
|
+
verified: results.filter(result => result.entry.status === 'approved').length,
|
|
1177
|
+
durationMs: Date.now() - startedAt,
|
|
1178
|
+
vectorReady: results.filter(result => (result.scoreDetails?.semanticScore ?? 0) > 0).length,
|
|
1179
|
+
},
|
|
1180
|
+
});
|
|
1181
|
+
return results;
|
|
1182
|
+
}
|
|
1183
|
+
catch (error) {
|
|
1184
|
+
emitSemanticControlLog({
|
|
1185
|
+
event: 'memory.search.completed',
|
|
1186
|
+
identity: { projectRoot: this.projectRoot, sessionId: options?.sessionId, executionId: options?.executionId, requestId: options?.requestId },
|
|
1187
|
+
level: 'error',
|
|
1188
|
+
timestamp: Date.now(),
|
|
1189
|
+
data: { status: 'failed', selected: 0, durationMs: Date.now() - startedAt, reason: memoryErrorReason(error) },
|
|
1190
|
+
});
|
|
1191
|
+
throw error;
|
|
1192
|
+
}
|
|
968
1193
|
}
|
|
969
1194
|
async listMemories(filter) {
|
|
970
1195
|
if (!this.engine)
|
|
@@ -1070,6 +1295,24 @@ function eventTurnId(event, fallbackEventId) {
|
|
|
1070
1295
|
}
|
|
1071
1296
|
return `turn:${fallbackEventId}`;
|
|
1072
1297
|
}
|
|
1298
|
+
function readCanonicalPrompt(payloadJson, userMessage) {
|
|
1299
|
+
if (payloadJson) {
|
|
1300
|
+
try {
|
|
1301
|
+
const payload = JSON.parse(payloadJson);
|
|
1302
|
+
if (typeof payload.prompt === 'string' && payload.prompt.trim())
|
|
1303
|
+
return payload.prompt.trim();
|
|
1304
|
+
}
|
|
1305
|
+
catch { }
|
|
1306
|
+
}
|
|
1307
|
+
return userMessage?.trim() ?? '';
|
|
1308
|
+
}
|
|
1309
|
+
function sameGroundedClause(narrative, evidenceSpan) {
|
|
1310
|
+
const left = narrative.normalize('NFKC').trim().toLocaleLowerCase('en-US');
|
|
1311
|
+
const right = evidenceSpan.normalize('NFKC').trim().toLocaleLowerCase('en-US');
|
|
1312
|
+
if (left.length < 4 || right.length < 4)
|
|
1313
|
+
return false;
|
|
1314
|
+
return left === right || (right.includes(left) && left.length / right.length >= 0.7);
|
|
1315
|
+
}
|
|
1073
1316
|
// --- L1 Rule Scorer (backward compat) ---
|
|
1074
1317
|
function scoreL1Rules(event) {
|
|
1075
1318
|
let score = 0;
|
|
@@ -1131,5 +1374,8 @@ function scoreDialogSignals(message) {
|
|
|
1131
1374
|
}
|
|
1132
1375
|
return maxScore;
|
|
1133
1376
|
}
|
|
1377
|
+
function memoryErrorReason(error) {
|
|
1378
|
+
return (error instanceof Error ? error.message : String(error)).trim().slice(0, 500) || 'memory_operation_failed';
|
|
1379
|
+
}
|
|
1134
1380
|
export { scoreL1Rules, scoreDialogSignals };
|
|
1135
1381
|
//# sourceMappingURL=memory-gate.js.map
|