claude-memory-layer 1.0.44 → 1.0.46
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/README.md +1 -0
- package/dist/cli/index.js +801 -1421
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +1319 -1501
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/post-tool-use.js +465 -756
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/semantic-daemon.js +454 -734
- package/dist/hooks/semantic-daemon.js.map +2 -2
- package/dist/hooks/session-end.js +450 -726
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +451 -728
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +458 -742
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +494 -814
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/index.js +1397 -1615
- package/dist/index.js.map +4 -4
- package/dist/mcp/index.js +1587 -1655
- package/dist/mcp/index.js.map +4 -4
- package/dist/server/api/index.js +484 -792
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +492 -808
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +450 -726
- package/dist/services/memory-service.js.map +2 -2
- package/package.json +15 -3
package/dist/server/index.js
CHANGED
|
@@ -68,6 +68,7 @@ var DefaultEmbeddingMaintenanceService = class {
|
|
|
68
68
|
this.options = options;
|
|
69
69
|
this.fileSystem = options.fileSystem ?? defaultFileSystem;
|
|
70
70
|
}
|
|
71
|
+
options;
|
|
71
72
|
fileSystem;
|
|
72
73
|
getEmbeddingModelName() {
|
|
73
74
|
return this.options.getEmbeddingModelName();
|
|
@@ -102,8 +103,7 @@ var DefaultEmbeddingMaintenanceService = class {
|
|
|
102
103
|
}
|
|
103
104
|
const worker = this.options.getVectorWorker();
|
|
104
105
|
const wasRunning = worker?.isRunning() || false;
|
|
105
|
-
if (wasRunning)
|
|
106
|
-
worker?.stop();
|
|
106
|
+
if (wasRunning) worker?.stop();
|
|
107
107
|
await this.options.vectorStore.clearAll();
|
|
108
108
|
await this.options.eventStore.clearEmbeddingOutbox();
|
|
109
109
|
const enqueued = await this.reenqueueAllEvents();
|
|
@@ -120,8 +120,7 @@ var DefaultEmbeddingMaintenanceService = class {
|
|
|
120
120
|
2
|
|
121
121
|
)
|
|
122
122
|
);
|
|
123
|
-
if (wasRunning)
|
|
124
|
-
worker?.start();
|
|
123
|
+
if (wasRunning) worker?.start();
|
|
125
124
|
return {
|
|
126
125
|
changed: true,
|
|
127
126
|
previousModel,
|
|
@@ -146,15 +145,13 @@ var DefaultEmbeddingMaintenanceService = class {
|
|
|
146
145
|
let enqueued = 0;
|
|
147
146
|
while (true) {
|
|
148
147
|
const page = await this.options.eventStore.getEventsPage(DEFAULT_PAGE_SIZE, offset);
|
|
149
|
-
if (page.length === 0)
|
|
150
|
-
break;
|
|
148
|
+
if (page.length === 0) break;
|
|
151
149
|
for (const event of page) {
|
|
152
150
|
await this.options.eventStore.enqueueForEmbedding(event.id, event.content);
|
|
153
151
|
enqueued += 1;
|
|
154
152
|
}
|
|
155
153
|
offset += page.length;
|
|
156
|
-
if (page.length < DEFAULT_PAGE_SIZE)
|
|
157
|
-
break;
|
|
154
|
+
if (page.length < DEFAULT_PAGE_SIZE) break;
|
|
158
155
|
}
|
|
159
156
|
return enqueued;
|
|
160
157
|
}
|
|
@@ -172,12 +169,9 @@ import { randomUUID } from "crypto";
|
|
|
172
169
|
// src/core/db-wrapper.ts
|
|
173
170
|
import BetterSqlite3 from "better-sqlite3";
|
|
174
171
|
function toDate(value) {
|
|
175
|
-
if (value instanceof Date)
|
|
176
|
-
|
|
177
|
-
if (typeof value === "
|
|
178
|
-
return new Date(value);
|
|
179
|
-
if (typeof value === "number")
|
|
180
|
-
return new Date(value);
|
|
172
|
+
if (value instanceof Date) return value;
|
|
173
|
+
if (typeof value === "string") return new Date(value);
|
|
174
|
+
if (typeof value === "number") return new Date(value);
|
|
181
175
|
return new Date(String(value));
|
|
182
176
|
}
|
|
183
177
|
function createDatabase(dbPath, options) {
|
|
@@ -201,6 +195,8 @@ var WorkingSetStore = class {
|
|
|
201
195
|
this.eventStore = eventStore;
|
|
202
196
|
this.config = config;
|
|
203
197
|
}
|
|
198
|
+
eventStore;
|
|
199
|
+
config;
|
|
204
200
|
get db() {
|
|
205
201
|
return this.eventStore.getDatabase();
|
|
206
202
|
}
|
|
@@ -286,8 +282,7 @@ var WorkingSetStore = class {
|
|
|
286
282
|
* Prune specific events from working set (after consolidation)
|
|
287
283
|
*/
|
|
288
284
|
async prune(eventIds) {
|
|
289
|
-
if (eventIds.length === 0)
|
|
290
|
-
return;
|
|
285
|
+
if (eventIds.length === 0) return;
|
|
291
286
|
const placeholders = eventIds.map(() => "?").join(",");
|
|
292
287
|
await dbRun(
|
|
293
288
|
this.db,
|
|
@@ -357,8 +352,7 @@ var WorkingSetStore = class {
|
|
|
357
352
|
LIMIT ?`,
|
|
358
353
|
[maxEvents]
|
|
359
354
|
);
|
|
360
|
-
if (keepIds.length === 0)
|
|
361
|
-
return;
|
|
355
|
+
if (keepIds.length === 0) return;
|
|
362
356
|
const keepIdList = keepIds.map((r) => r.id);
|
|
363
357
|
const placeholders = keepIdList.map(() => "?").join(",");
|
|
364
358
|
await dbRun(
|
|
@@ -405,6 +399,7 @@ var ConsolidatedStore = class {
|
|
|
405
399
|
constructor(eventStore) {
|
|
406
400
|
this.eventStore = eventStore;
|
|
407
401
|
}
|
|
402
|
+
eventStore;
|
|
408
403
|
get db() {
|
|
409
404
|
return this.eventStore.getDatabase();
|
|
410
405
|
}
|
|
@@ -437,8 +432,7 @@ var ConsolidatedStore = class {
|
|
|
437
432
|
`SELECT * FROM consolidated_memories WHERE memory_id = ?`,
|
|
438
433
|
[memoryId]
|
|
439
434
|
);
|
|
440
|
-
if (rows.length === 0)
|
|
441
|
-
return null;
|
|
435
|
+
if (rows.length === 0) return null;
|
|
442
436
|
return this.rowToMemory(rows[0]);
|
|
443
437
|
}
|
|
444
438
|
/**
|
|
@@ -656,8 +650,7 @@ var ConsolidatedStore = class {
|
|
|
656
650
|
WHERE source_events LIKE ?`,
|
|
657
651
|
[`%"${eventId}"%`]
|
|
658
652
|
);
|
|
659
|
-
if ((result[0]?.count || 0) > 0)
|
|
660
|
-
return true;
|
|
653
|
+
if ((result[0]?.count || 0) > 0) return true;
|
|
661
654
|
}
|
|
662
655
|
return false;
|
|
663
656
|
}
|
|
@@ -671,8 +664,7 @@ var ConsolidatedStore = class {
|
|
|
671
664
|
ORDER BY created_at DESC
|
|
672
665
|
LIMIT 1`
|
|
673
666
|
);
|
|
674
|
-
if (result.length === 0)
|
|
675
|
-
return null;
|
|
667
|
+
if (result.length === 0) return null;
|
|
676
668
|
return new Date(result[0].created_at);
|
|
677
669
|
}
|
|
678
670
|
/**
|
|
@@ -702,6 +694,9 @@ var ConsolidationWorker = class {
|
|
|
702
694
|
this.consolidatedStore = consolidatedStore;
|
|
703
695
|
this.config = config;
|
|
704
696
|
}
|
|
697
|
+
workingSetStore;
|
|
698
|
+
consolidatedStore;
|
|
699
|
+
config;
|
|
705
700
|
running = false;
|
|
706
701
|
timeout = null;
|
|
707
702
|
lastActivity = /* @__PURE__ */ new Date();
|
|
@@ -709,8 +704,7 @@ var ConsolidationWorker = class {
|
|
|
709
704
|
* Start the consolidation worker
|
|
710
705
|
*/
|
|
711
706
|
start() {
|
|
712
|
-
if (this.running)
|
|
713
|
-
return;
|
|
707
|
+
if (this.running) return;
|
|
714
708
|
this.running = true;
|
|
715
709
|
this.scheduleNext();
|
|
716
710
|
}
|
|
@@ -753,8 +747,7 @@ var ConsolidationWorker = class {
|
|
|
753
747
|
* Schedule the next consolidation check
|
|
754
748
|
*/
|
|
755
749
|
scheduleNext() {
|
|
756
|
-
if (!this.running)
|
|
757
|
-
return;
|
|
750
|
+
if (!this.running) return;
|
|
758
751
|
this.timeout = setTimeout(
|
|
759
752
|
() => this.run(),
|
|
760
753
|
this.config.consolidation.triggerIntervalMs
|
|
@@ -764,8 +757,7 @@ var ConsolidationWorker = class {
|
|
|
764
757
|
* Run consolidation check
|
|
765
758
|
*/
|
|
766
759
|
async run() {
|
|
767
|
-
if (!this.running)
|
|
768
|
-
return;
|
|
760
|
+
if (!this.running) return;
|
|
769
761
|
try {
|
|
770
762
|
await this.checkAndConsolidate();
|
|
771
763
|
} catch (error) {
|
|
@@ -803,12 +795,10 @@ var ConsolidationWorker = class {
|
|
|
803
795
|
let consolidatedCount = 0;
|
|
804
796
|
const createdMemoryIds = [];
|
|
805
797
|
for (const group of groups) {
|
|
806
|
-
if (group.events.length < 3)
|
|
807
|
-
continue;
|
|
798
|
+
if (group.events.length < 3) continue;
|
|
808
799
|
const eventIds = group.events.map((e) => e.id);
|
|
809
800
|
const alreadyConsolidated = await this.consolidatedStore.isAlreadyConsolidated(eventIds);
|
|
810
|
-
if (alreadyConsolidated)
|
|
811
|
-
continue;
|
|
801
|
+
if (alreadyConsolidated) continue;
|
|
812
802
|
const summary = await this.summarize(group);
|
|
813
803
|
const memoryId = await this.consolidatedStore.create({
|
|
814
804
|
summary,
|
|
@@ -824,8 +814,7 @@ var ConsolidationWorker = class {
|
|
|
824
814
|
const consolidatedEventIds = groups.filter((g) => g.events.length >= 3).flatMap((g) => g.events.map((e) => e.id));
|
|
825
815
|
const oldEventIds = consolidatedEventIds.filter((id) => {
|
|
826
816
|
const event = workingSet.recentEvents.find((e) => e.id === id);
|
|
827
|
-
if (!event)
|
|
828
|
-
return false;
|
|
817
|
+
if (!event) return false;
|
|
829
818
|
const ageHours = (Date.now() - event.timestamp.getTime()) / (1e3 * 60 * 60);
|
|
830
819
|
return ageHours > this.config.workingSet.timeWindowHours / 2;
|
|
831
820
|
});
|
|
@@ -840,18 +829,13 @@ var ConsolidationWorker = class {
|
|
|
840
829
|
let promoted = 0;
|
|
841
830
|
for (const memoryId of memoryIds) {
|
|
842
831
|
const memory = await this.consolidatedStore.get(memoryId);
|
|
843
|
-
if (!memory)
|
|
844
|
-
|
|
845
|
-
if (memory.
|
|
846
|
-
continue;
|
|
847
|
-
if (memory.sourceEvents.length < 4)
|
|
848
|
-
continue;
|
|
832
|
+
if (!memory) continue;
|
|
833
|
+
if (memory.confidence < 0.55) continue;
|
|
834
|
+
if (memory.sourceEvents.length < 4) continue;
|
|
849
835
|
const exists = await this.consolidatedStore.hasRuleForSourceMemory(memoryId);
|
|
850
|
-
if (exists)
|
|
851
|
-
continue;
|
|
836
|
+
if (exists) continue;
|
|
852
837
|
const rule = this.buildRuleFromSummary(memory.summary, memory.topics);
|
|
853
|
-
if (!rule)
|
|
854
|
-
continue;
|
|
838
|
+
if (!rule) continue;
|
|
855
839
|
await this.consolidatedStore.createRule({
|
|
856
840
|
rule,
|
|
857
841
|
topics: memory.topics,
|
|
@@ -867,8 +851,7 @@ var ConsolidationWorker = class {
|
|
|
867
851
|
const lines = summary.split(/\r?\n/).map((l) => l.trim()).filter(Boolean).filter((l) => !l.toLowerCase().startsWith("topics:"));
|
|
868
852
|
const bullet = lines.find((l) => l.startsWith("- "))?.replace(/^-\s*/, "");
|
|
869
853
|
const seed = bullet || lines[0];
|
|
870
|
-
if (!seed || seed.length < 8)
|
|
871
|
-
return null;
|
|
854
|
+
if (!seed || seed.length < 8) return null;
|
|
872
855
|
const topicPrefix = topics.length > 0 ? `[${topics.slice(0, 2).join(", ")}] ` : "";
|
|
873
856
|
return `${topicPrefix}${seed}`;
|
|
874
857
|
}
|
|
@@ -1029,8 +1012,7 @@ var ConsolidationWorker = class {
|
|
|
1029
1012
|
*/
|
|
1030
1013
|
extractKeyPoint(content) {
|
|
1031
1014
|
const sentences = content.split(/[.!?\n]+/).filter((s) => s.trim().length > 10);
|
|
1032
|
-
if (sentences.length === 0)
|
|
1033
|
-
return null;
|
|
1015
|
+
if (sentences.length === 0) return null;
|
|
1034
1016
|
const firstSentence = sentences[0].trim();
|
|
1035
1017
|
if (firstSentence.length > 100) {
|
|
1036
1018
|
return firstSentence.slice(0, 100) + "...";
|
|
@@ -1050,8 +1032,7 @@ var ConsolidationWorker = class {
|
|
|
1050
1032
|
* Calculate time proximity score
|
|
1051
1033
|
*/
|
|
1052
1034
|
calculateTimeProximity(events) {
|
|
1053
|
-
if (events.length < 2)
|
|
1054
|
-
return 1;
|
|
1035
|
+
if (events.length < 2) return 1;
|
|
1055
1036
|
const timestamps = events.map((e) => e.timestamp.getTime()).sort((a, b) => a - b);
|
|
1056
1037
|
const timeSpan = timestamps[timestamps.length - 1] - timestamps[0];
|
|
1057
1038
|
const avgGap = timeSpan / (events.length - 1);
|
|
@@ -1070,6 +1051,8 @@ var ContinuityManager = class {
|
|
|
1070
1051
|
this.eventStore = eventStore;
|
|
1071
1052
|
this.config = config;
|
|
1072
1053
|
}
|
|
1054
|
+
eventStore;
|
|
1055
|
+
config;
|
|
1073
1056
|
lastContext = null;
|
|
1074
1057
|
get db() {
|
|
1075
1058
|
return this.eventStore.getDatabase();
|
|
@@ -1189,8 +1172,7 @@ var ContinuityManager = class {
|
|
|
1189
1172
|
* Calculate overlap between two arrays
|
|
1190
1173
|
*/
|
|
1191
1174
|
calculateOverlap(a, b) {
|
|
1192
|
-
if (a.length === 0 || b.length === 0)
|
|
1193
|
-
return 0;
|
|
1175
|
+
if (a.length === 0 || b.length === 0) return 0;
|
|
1194
1176
|
const setA = new Set(a.map((s) => s.toLowerCase()));
|
|
1195
1177
|
const setB = new Set(b.map((s) => s.toLowerCase()));
|
|
1196
1178
|
const intersection = [...setA].filter((x) => setB.has(x));
|
|
@@ -1363,6 +1345,7 @@ var DefaultEndlessMemoryServices = class {
|
|
|
1363
1345
|
this.options = options;
|
|
1364
1346
|
this.factories = options.factories ? { ...options.factories, randomUUID: options.factories.randomUUID ?? randomUUID4 } : defaultFactories;
|
|
1365
1347
|
}
|
|
1348
|
+
options;
|
|
1366
1349
|
factories;
|
|
1367
1350
|
workingSetStore = null;
|
|
1368
1351
|
consolidatedStore = null;
|
|
@@ -1377,8 +1360,7 @@ var DefaultEndlessMemoryServices = class {
|
|
|
1377
1360
|
}
|
|
1378
1361
|
}
|
|
1379
1362
|
async initializeEndlessMode() {
|
|
1380
|
-
if (this.consolidationWorker)
|
|
1381
|
-
return;
|
|
1363
|
+
if (this.consolidationWorker) return;
|
|
1382
1364
|
const config = await this.getEndlessConfig();
|
|
1383
1365
|
const workingSetStore = this.factories.createWorkingSetStore(this.options.eventStore, config);
|
|
1384
1366
|
const consolidatedStore = this.factories.createConsolidatedStore(this.options.eventStore);
|
|
@@ -1410,8 +1392,7 @@ var DefaultEndlessMemoryServices = class {
|
|
|
1410
1392
|
}
|
|
1411
1393
|
async setMode(mode) {
|
|
1412
1394
|
await this.options.initialize();
|
|
1413
|
-
if (mode === this.mode)
|
|
1414
|
-
return;
|
|
1395
|
+
if (mode === this.mode) return;
|
|
1415
1396
|
this.mode = mode;
|
|
1416
1397
|
await this.options.configStore.setEndlessConfig("mode", mode);
|
|
1417
1398
|
if (mode === "endless") {
|
|
@@ -1427,33 +1408,27 @@ var DefaultEndlessMemoryServices = class {
|
|
|
1427
1408
|
return this.mode === "endless";
|
|
1428
1409
|
}
|
|
1429
1410
|
async addToWorkingSet(eventId, relevanceScore) {
|
|
1430
|
-
if (!this.workingSetStore)
|
|
1431
|
-
return;
|
|
1411
|
+
if (!this.workingSetStore) return;
|
|
1432
1412
|
await this.workingSetStore.add(eventId, relevanceScore);
|
|
1433
1413
|
}
|
|
1434
1414
|
async getWorkingSet() {
|
|
1435
|
-
if (!this.workingSetStore)
|
|
1436
|
-
return null;
|
|
1415
|
+
if (!this.workingSetStore) return null;
|
|
1437
1416
|
return this.workingSetStore.get();
|
|
1438
1417
|
}
|
|
1439
1418
|
async searchConsolidated(query, options) {
|
|
1440
|
-
if (!this.consolidatedStore)
|
|
1441
|
-
return [];
|
|
1419
|
+
if (!this.consolidatedStore) return [];
|
|
1442
1420
|
return this.consolidatedStore.search(query, options);
|
|
1443
1421
|
}
|
|
1444
1422
|
async getConsolidatedMemories(limit) {
|
|
1445
|
-
if (!this.consolidatedStore)
|
|
1446
|
-
return [];
|
|
1423
|
+
if (!this.consolidatedStore) return [];
|
|
1447
1424
|
return this.consolidatedStore.getAll({ limit });
|
|
1448
1425
|
}
|
|
1449
1426
|
async markMemoryAccessed(memoryId) {
|
|
1450
|
-
if (!this.consolidatedStore)
|
|
1451
|
-
return;
|
|
1427
|
+
if (!this.consolidatedStore) return;
|
|
1452
1428
|
await this.consolidatedStore.markAccessed(memoryId);
|
|
1453
1429
|
}
|
|
1454
1430
|
async calculateContinuity(content, metadata) {
|
|
1455
|
-
if (!this.continuityManager)
|
|
1456
|
-
return null;
|
|
1431
|
+
if (!this.continuityManager) return null;
|
|
1457
1432
|
const snapshot = this.continuityManager.createSnapshot(
|
|
1458
1433
|
this.factories.randomUUID(),
|
|
1459
1434
|
content,
|
|
@@ -1465,8 +1440,7 @@ var DefaultEndlessMemoryServices = class {
|
|
|
1465
1440
|
this.consolidationWorker?.recordActivity();
|
|
1466
1441
|
}
|
|
1467
1442
|
async forceConsolidation() {
|
|
1468
|
-
if (!this.consolidationWorker)
|
|
1469
|
-
return 0;
|
|
1443
|
+
if (!this.consolidationWorker) return 0;
|
|
1470
1444
|
return this.consolidationWorker.forceRun();
|
|
1471
1445
|
}
|
|
1472
1446
|
async getEndlessModeStatus() {
|
|
@@ -1558,8 +1532,7 @@ var Embedder = class _Embedder {
|
|
|
1558
1532
|
* Initialize the embedding pipeline
|
|
1559
1533
|
*/
|
|
1560
1534
|
async initialize() {
|
|
1561
|
-
if (this.initialized)
|
|
1562
|
-
return;
|
|
1535
|
+
if (this.initialized) return;
|
|
1563
1536
|
const pipeline = await withSuppressedKnownTransformersWarnings(async () => {
|
|
1564
1537
|
try {
|
|
1565
1538
|
return await loadTransformersPipeline();
|
|
@@ -1676,8 +1649,7 @@ async function withSuppressedKnownTransformersWarnings(fn) {
|
|
|
1676
1649
|
originalConsoleWarn = console.warn;
|
|
1677
1650
|
console.warn = (...args) => {
|
|
1678
1651
|
const message = args.map(String).join(" ");
|
|
1679
|
-
if (isKnownBenignTransformersWarning(message))
|
|
1680
|
-
return;
|
|
1652
|
+
if (isKnownBenignTransformersWarning(message)) return;
|
|
1681
1653
|
(originalConsoleWarn ?? console.warn)(...args);
|
|
1682
1654
|
};
|
|
1683
1655
|
}
|
|
@@ -1959,8 +1931,7 @@ var GraduationPipeline = class {
|
|
|
1959
1931
|
const preferenceKeywords = ["prefer", "like", "want", "always", "never", "favorite"];
|
|
1960
1932
|
const preferences = [];
|
|
1961
1933
|
for (const event of events) {
|
|
1962
|
-
if (event.eventType !== "user_prompt")
|
|
1963
|
-
continue;
|
|
1934
|
+
if (event.eventType !== "user_prompt") continue;
|
|
1964
1935
|
const lowerContent = event.content.toLowerCase();
|
|
1965
1936
|
for (const keyword of preferenceKeywords) {
|
|
1966
1937
|
if (lowerContent.includes(keyword)) {
|
|
@@ -2126,11 +2097,9 @@ function sanitizeSegment(input, fallback) {
|
|
|
2126
2097
|
return v || fallback;
|
|
2127
2098
|
}
|
|
2128
2099
|
function getAtPath(obj, dotted) {
|
|
2129
|
-
if (!obj)
|
|
2130
|
-
return void 0;
|
|
2100
|
+
if (!obj) return void 0;
|
|
2131
2101
|
return dotted.split(".").reduce((acc, key) => {
|
|
2132
|
-
if (!acc || typeof acc !== "object")
|
|
2133
|
-
return void 0;
|
|
2102
|
+
if (!acc || typeof acc !== "object") return void 0;
|
|
2134
2103
|
return acc[key];
|
|
2135
2104
|
}, obj);
|
|
2136
2105
|
}
|
|
@@ -2150,6 +2119,7 @@ var MarkdownMirror = class {
|
|
|
2150
2119
|
constructor(rootDir) {
|
|
2151
2120
|
this.rootDir = rootDir;
|
|
2152
2121
|
}
|
|
2122
|
+
rootDir;
|
|
2153
2123
|
async append(event, eventId) {
|
|
2154
2124
|
const out = buildMirrorPath(this.rootDir, event);
|
|
2155
2125
|
fs2.mkdirSync(path2.dirname(out), { recursive: true });
|
|
@@ -2285,10 +2255,8 @@ function sqliteClose(db) {
|
|
|
2285
2255
|
db.close();
|
|
2286
2256
|
}
|
|
2287
2257
|
function toDateFromSQLite(value) {
|
|
2288
|
-
if (value instanceof Date)
|
|
2289
|
-
|
|
2290
|
-
if (typeof value === "number")
|
|
2291
|
-
return new Date(value);
|
|
2258
|
+
if (value instanceof Date) return value;
|
|
2259
|
+
if (typeof value === "number") return new Date(value);
|
|
2292
2260
|
if (typeof value === "string") {
|
|
2293
2261
|
const trimmed = value.trim();
|
|
2294
2262
|
if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(trimmed)) {
|
|
@@ -2310,8 +2278,7 @@ var DEFAULT_CATEGORY = "uncategorized";
|
|
|
2310
2278
|
function sanitizeSegment2(input, fallback) {
|
|
2311
2279
|
const raw = String(input ?? "").trim().toLowerCase();
|
|
2312
2280
|
const safe = raw.normalize("NFKD").replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2313
|
-
if (!safe || safe === "." || safe === "..")
|
|
2314
|
-
return fallback;
|
|
2281
|
+
if (!safe || safe === "." || safe === "..") return fallback;
|
|
2315
2282
|
return safe;
|
|
2316
2283
|
}
|
|
2317
2284
|
function getCategorySegments(metadata, eventType) {
|
|
@@ -2352,6 +2319,7 @@ var MarkdownMirror2 = class {
|
|
|
2352
2319
|
constructor(rootDir) {
|
|
2353
2320
|
this.rootDir = rootDir;
|
|
2354
2321
|
}
|
|
2322
|
+
rootDir;
|
|
2355
2323
|
async append(event) {
|
|
2356
2324
|
const outPath = buildMirrorPath2(this.rootDir, event);
|
|
2357
2325
|
await fs5.mkdir(path4.dirname(outPath), { recursive: true });
|
|
@@ -2374,6 +2342,7 @@ var VectorOutbox = class {
|
|
|
2374
2342
|
this.db = db;
|
|
2375
2343
|
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
2376
2344
|
}
|
|
2345
|
+
db;
|
|
2377
2346
|
config;
|
|
2378
2347
|
/**
|
|
2379
2348
|
* Enqueue item for vectorization (idempotent).
|
|
@@ -2470,8 +2439,7 @@ var VectorOutbox = class {
|
|
|
2470
2439
|
`SELECT retry_count FROM vector_outbox WHERE job_id = ?`,
|
|
2471
2440
|
[jobId]
|
|
2472
2441
|
);
|
|
2473
|
-
if (rows.length === 0)
|
|
2474
|
-
return;
|
|
2442
|
+
if (rows.length === 0) return;
|
|
2475
2443
|
const retryCount = rows[0].retry_count;
|
|
2476
2444
|
const newStatus = retryCount >= this.config.maxRetries - 1 ? "failed" : "pending";
|
|
2477
2445
|
await dbRun(
|
|
@@ -2491,8 +2459,7 @@ var VectorOutbox = class {
|
|
|
2491
2459
|
`SELECT * FROM vector_outbox WHERE job_id = ?`,
|
|
2492
2460
|
[jobId]
|
|
2493
2461
|
);
|
|
2494
|
-
if (rows.length === 0)
|
|
2495
|
-
return null;
|
|
2462
|
+
if (rows.length === 0) return null;
|
|
2496
2463
|
return this.rowToJob(rows[0]);
|
|
2497
2464
|
}
|
|
2498
2465
|
/**
|
|
@@ -2626,30 +2593,24 @@ function isRetrievalDebugLaneName(value) {
|
|
|
2626
2593
|
return typeof value === "string" && RETRIEVAL_DEBUG_LANE_NAME_SET.has(value);
|
|
2627
2594
|
}
|
|
2628
2595
|
function normalizeRetrievalDebugLanes(value, maxItems = 6) {
|
|
2629
|
-
if (!Array.isArray(value) || maxItems <= 0)
|
|
2630
|
-
return [];
|
|
2596
|
+
if (!Array.isArray(value) || maxItems <= 0) return [];
|
|
2631
2597
|
const normalized = [];
|
|
2632
2598
|
const seen = /* @__PURE__ */ new Set();
|
|
2633
2599
|
for (const item of value) {
|
|
2634
2600
|
const lane = normalizeRetrievalDebugLane(item);
|
|
2635
|
-
if (!lane)
|
|
2636
|
-
continue;
|
|
2601
|
+
if (!lane) continue;
|
|
2637
2602
|
const key = [lane.lane, lane.reason, lane.score ?? ""].join("\0");
|
|
2638
|
-
if (seen.has(key))
|
|
2639
|
-
continue;
|
|
2603
|
+
if (seen.has(key)) continue;
|
|
2640
2604
|
seen.add(key);
|
|
2641
2605
|
normalized.push(lane);
|
|
2642
|
-
if (normalized.length >= maxItems)
|
|
2643
|
-
break;
|
|
2606
|
+
if (normalized.length >= maxItems) break;
|
|
2644
2607
|
}
|
|
2645
2608
|
return normalized;
|
|
2646
2609
|
}
|
|
2647
2610
|
function normalizeRetrievalDebugLane(value) {
|
|
2648
|
-
if (!value || typeof value !== "object")
|
|
2649
|
-
return null;
|
|
2611
|
+
if (!value || typeof value !== "object") return null;
|
|
2650
2612
|
const raw = value;
|
|
2651
|
-
if (!isRetrievalDebugLaneName(raw.lane))
|
|
2652
|
-
return null;
|
|
2613
|
+
if (!isRetrievalDebugLaneName(raw.lane)) return null;
|
|
2653
2614
|
const reason = sanitizeRetrievalLaneReason(typeof raw.reason === "string" ? raw.reason : "") || "unspecified";
|
|
2654
2615
|
const score = typeof raw.score === "number" && Number.isFinite(raw.score) ? Math.max(0, Math.min(1, raw.score)) : void 0;
|
|
2655
2616
|
return score === void 0 ? { lane: raw.lane, reason } : { lane: raw.lane, reason, score };
|
|
@@ -2672,27 +2633,21 @@ function normalizeRetrievalTraceDetails(details) {
|
|
|
2672
2633
|
eventId: detail.eventId,
|
|
2673
2634
|
score: detail.score
|
|
2674
2635
|
};
|
|
2675
|
-
if (detail.semanticScore !== void 0)
|
|
2676
|
-
|
|
2677
|
-
if (detail.
|
|
2678
|
-
|
|
2679
|
-
if (detail.recencyScore !== void 0)
|
|
2680
|
-
normalized.recencyScore = detail.recencyScore;
|
|
2681
|
-
if (lanes.length > 0)
|
|
2682
|
-
normalized.lanes = lanes;
|
|
2636
|
+
if (detail.semanticScore !== void 0) normalized.semanticScore = detail.semanticScore;
|
|
2637
|
+
if (detail.lexicalScore !== void 0) normalized.lexicalScore = detail.lexicalScore;
|
|
2638
|
+
if (detail.recencyScore !== void 0) normalized.recencyScore = detail.recencyScore;
|
|
2639
|
+
if (lanes.length > 0) normalized.lanes = lanes;
|
|
2683
2640
|
return normalized;
|
|
2684
2641
|
});
|
|
2685
2642
|
}
|
|
2686
2643
|
function parseRetrievalTraceDetails(value) {
|
|
2687
|
-
if (typeof value !== "string" || value.length === 0)
|
|
2688
|
-
return [];
|
|
2644
|
+
if (typeof value !== "string" || value.length === 0) return [];
|
|
2689
2645
|
const parsed = JSON.parse(value);
|
|
2690
2646
|
return Array.isArray(parsed) ? normalizeRetrievalTraceDetails(parsed) : [];
|
|
2691
2647
|
}
|
|
2692
2648
|
function normalizeQueryRewriteKind(value) {
|
|
2693
2649
|
const normalized = (value || "").trim().toLowerCase();
|
|
2694
|
-
if (normalized === "follow-up-context" || normalized === "intent-rewrite")
|
|
2695
|
-
return normalized;
|
|
2650
|
+
if (normalized === "follow-up-context" || normalized === "intent-rewrite") return normalized;
|
|
2696
2651
|
return "none";
|
|
2697
2652
|
}
|
|
2698
2653
|
var REWRITTEN_QUERY_REWRITE_KIND_SQL = `LOWER(TRIM(COALESCE(query_rewrite_kind, 'none'))) IN ('follow-up-context', 'intent-rewrite')`;
|
|
@@ -2710,8 +2665,7 @@ function isRecord(value) {
|
|
|
2710
2665
|
function getNestedRecord(root, path14) {
|
|
2711
2666
|
let cursor = root;
|
|
2712
2667
|
for (const key of path14) {
|
|
2713
|
-
if (!isRecord(cursor))
|
|
2714
|
-
return void 0;
|
|
2668
|
+
if (!isRecord(cursor)) return void 0;
|
|
2715
2669
|
cursor = cursor[key];
|
|
2716
2670
|
}
|
|
2717
2671
|
return isRecord(cursor) ? cursor : void 0;
|
|
@@ -2719,8 +2673,7 @@ function getNestedRecord(root, path14) {
|
|
|
2719
2673
|
function getNestedString(root, path14) {
|
|
2720
2674
|
let cursor = root;
|
|
2721
2675
|
for (const key of path14) {
|
|
2722
|
-
if (!isRecord(cursor))
|
|
2723
|
-
return void 0;
|
|
2676
|
+
if (!isRecord(cursor)) return void 0;
|
|
2724
2677
|
cursor = cursor[key];
|
|
2725
2678
|
}
|
|
2726
2679
|
return typeof cursor === "string" && cursor.length > 0 ? cursor : void 0;
|
|
@@ -2736,8 +2689,7 @@ function metadataProjectPaths(metadata) {
|
|
|
2736
2689
|
];
|
|
2737
2690
|
const paths = [];
|
|
2738
2691
|
for (const value of candidates) {
|
|
2739
|
-
if (value && !paths.includes(value))
|
|
2740
|
-
paths.push(value);
|
|
2692
|
+
if (value && !paths.includes(value)) paths.push(value);
|
|
2741
2693
|
}
|
|
2742
2694
|
return paths;
|
|
2743
2695
|
}
|
|
@@ -2758,12 +2710,9 @@ function maybeQuarantinePredicate(options, column = "metadata") {
|
|
|
2758
2710
|
return options?.includeQuarantined ? "1=1" : notActiveQuarantinedSql(column);
|
|
2759
2711
|
}
|
|
2760
2712
|
function safeParseMetadataValue(value) {
|
|
2761
|
-
if (!value)
|
|
2762
|
-
|
|
2763
|
-
if (typeof value
|
|
2764
|
-
return isRecord(value) ? value : void 0;
|
|
2765
|
-
if (typeof value !== "string")
|
|
2766
|
-
return void 0;
|
|
2713
|
+
if (!value) return void 0;
|
|
2714
|
+
if (typeof value === "object") return isRecord(value) ? value : void 0;
|
|
2715
|
+
if (typeof value !== "string") return void 0;
|
|
2767
2716
|
try {
|
|
2768
2717
|
const parsed = JSON.parse(value);
|
|
2769
2718
|
return isRecord(parsed) ? parsed : void 0;
|
|
@@ -2772,16 +2721,14 @@ function safeParseMetadataValue(value) {
|
|
|
2772
2721
|
}
|
|
2773
2722
|
}
|
|
2774
2723
|
function isImportedOrLegacyScopedMetadata(metadata) {
|
|
2775
|
-
if (!metadata)
|
|
2776
|
-
return false;
|
|
2724
|
+
if (!metadata) return false;
|
|
2777
2725
|
return Boolean(
|
|
2778
2726
|
metadata.importedFrom || metadata.sourceSessionId || metadata.sourceSessionHash || metadata.hermesSource || metadata.projectPath || metadata.sourceProjectPath || metadata.source === "hermes" || metadata.source === "claude" || metadata.source === "codex"
|
|
2779
2727
|
);
|
|
2780
2728
|
}
|
|
2781
2729
|
function addMetadataTag(metadata, tag) {
|
|
2782
2730
|
const current = Array.isArray(metadata.tags) ? metadata.tags.filter((value) => typeof value === "string") : [];
|
|
2783
|
-
if (!current.includes(tag))
|
|
2784
|
-
metadata.tags = [...current, tag];
|
|
2731
|
+
if (!current.includes(tag)) metadata.tags = [...current, tag];
|
|
2785
2732
|
}
|
|
2786
2733
|
function buildRepairResult(projectHash, dryRun) {
|
|
2787
2734
|
return {
|
|
@@ -2799,8 +2746,7 @@ function normalizeRepoName(value) {
|
|
|
2799
2746
|
return value.replace(/\.git$/i, "").trim().toLowerCase();
|
|
2800
2747
|
}
|
|
2801
2748
|
function projectBasename(projectPath) {
|
|
2802
|
-
if (!projectPath)
|
|
2803
|
-
return void 0;
|
|
2749
|
+
if (!projectPath) return void 0;
|
|
2804
2750
|
const trimmed = projectPath.replace(/[\\/]+$/, "");
|
|
2805
2751
|
const basename3 = nodePath2.basename(trimmed);
|
|
2806
2752
|
return basename3 ? normalizeRepoName(basename3) : void 0;
|
|
@@ -2813,23 +2759,19 @@ function isProjectScopeRepairExplanation(content) {
|
|
|
2813
2759
|
}
|
|
2814
2760
|
function hasConflictingContentProjectHint(content, projectPath) {
|
|
2815
2761
|
const currentName = projectBasename(projectPath);
|
|
2816
|
-
if (!currentName)
|
|
2817
|
-
|
|
2818
|
-
if (isProjectScopeRepairExplanation(content))
|
|
2819
|
-
return false;
|
|
2762
|
+
if (!currentName) return false;
|
|
2763
|
+
if (isProjectScopeRepairExplanation(content)) return false;
|
|
2820
2764
|
const githubRepoPattern = /github\.com[:/]([^/\s`'"#)]+)\/([^/\s`'"#)]+)(?:\.git)?/gi;
|
|
2821
2765
|
let githubMatch;
|
|
2822
2766
|
while ((githubMatch = githubRepoPattern.exec(content)) !== null) {
|
|
2823
2767
|
const repo = normalizeRepoName(githubMatch[2] || "");
|
|
2824
|
-
if (repo && repo !== currentName)
|
|
2825
|
-
return true;
|
|
2768
|
+
if (repo && repo !== currentName) return true;
|
|
2826
2769
|
}
|
|
2827
2770
|
const workspacePathPattern = /\/workspace\/([^/\s`'"#)]+)/gi;
|
|
2828
2771
|
let workspaceMatch;
|
|
2829
2772
|
while ((workspaceMatch = workspacePathPattern.exec(content)) !== null) {
|
|
2830
2773
|
const repo = normalizeRepoName(workspaceMatch[1] || "");
|
|
2831
|
-
if (repo && repo !== currentName)
|
|
2832
|
-
return true;
|
|
2774
|
+
if (repo && repo !== currentName) return true;
|
|
2833
2775
|
}
|
|
2834
2776
|
return false;
|
|
2835
2777
|
}
|
|
@@ -2849,15 +2791,12 @@ var SQLiteEventStore = class {
|
|
|
2849
2791
|
this.vectorOutbox = this.createVectorOutbox(options?.vectorOutbox);
|
|
2850
2792
|
}
|
|
2851
2793
|
createVectorOutbox(option) {
|
|
2852
|
-
if (this.readOnly || option === false)
|
|
2853
|
-
|
|
2854
|
-
if (option instanceof VectorOutbox)
|
|
2855
|
-
return option;
|
|
2794
|
+
if (this.readOnly || option === false) return null;
|
|
2795
|
+
if (option instanceof VectorOutbox) return option;
|
|
2856
2796
|
return new VectorOutbox(this.db, option ?? {});
|
|
2857
2797
|
}
|
|
2858
2798
|
enqueueVectorOutboxEventSync(eventId) {
|
|
2859
|
-
if (!this.vectorOutbox)
|
|
2860
|
-
return;
|
|
2799
|
+
if (!this.vectorOutbox) return;
|
|
2861
2800
|
this.vectorOutbox.enqueueSync("event", eventId);
|
|
2862
2801
|
}
|
|
2863
2802
|
async enqueueVectorOutboxEvent(eventId) {
|
|
@@ -2867,8 +2806,7 @@ var SQLiteEventStore = class {
|
|
|
2867
2806
|
* Initialize database schema
|
|
2868
2807
|
*/
|
|
2869
2808
|
async initialize() {
|
|
2870
|
-
if (this.initialized)
|
|
2871
|
-
return;
|
|
2809
|
+
if (this.initialized) return;
|
|
2872
2810
|
if (this.readOnly) {
|
|
2873
2811
|
this.initialized = true;
|
|
2874
2812
|
return;
|
|
@@ -3426,10 +3364,8 @@ var SQLiteEventStore = class {
|
|
|
3426
3364
|
try {
|
|
3427
3365
|
const edgeIndexes = sqliteAll(this.db, `PRAGMA index_list(memory_action_edges)`, []);
|
|
3428
3366
|
const hasSourceAwareUnique = edgeIndexes.some((index) => {
|
|
3429
|
-
if (Number(index.unique) !== 1)
|
|
3430
|
-
|
|
3431
|
-
if (!/^[A-Za-z0-9_]+$/.test(index.name))
|
|
3432
|
-
return false;
|
|
3367
|
+
if (Number(index.unique) !== 1) return false;
|
|
3368
|
+
if (!/^[A-Za-z0-9_]+$/.test(index.name)) return false;
|
|
3433
3369
|
const escapedName = index.name.replace(/"/g, '""');
|
|
3434
3370
|
const columns = sqliteAll(this.db, 'PRAGMA index_info("' + escapedName + '")', []).map((column) => column.name);
|
|
3435
3371
|
return columns.length === 5 && columns[0] === "src_action_id" && columns[1] === "rel_type" && columns[2] === "dst_type" && columns[3] === "dst_id" && columns[4] === "source";
|
|
@@ -3669,8 +3605,7 @@ var SQLiteEventStore = class {
|
|
|
3669
3605
|
`SELECT * FROM events WHERE id = ? AND ${maybeQuarantinePredicate(options)}`,
|
|
3670
3606
|
[id]
|
|
3671
3607
|
);
|
|
3672
|
-
if (!row)
|
|
3673
|
-
return null;
|
|
3608
|
+
if (!row) return null;
|
|
3674
3609
|
return this.rowToEvent(row);
|
|
3675
3610
|
}
|
|
3676
3611
|
/**
|
|
@@ -3708,10 +3643,8 @@ var SQLiteEventStore = class {
|
|
|
3708
3643
|
* NOTE: This bypasses the append() id generation to preserve stable IDs.
|
|
3709
3644
|
*/
|
|
3710
3645
|
async importEvents(events) {
|
|
3711
|
-
if (events.length === 0)
|
|
3712
|
-
|
|
3713
|
-
if (this.readOnly)
|
|
3714
|
-
return { inserted: 0, skipped: events.length };
|
|
3646
|
+
if (events.length === 0) return { inserted: 0, skipped: 0 };
|
|
3647
|
+
if (this.readOnly) return { inserted: 0, skipped: events.length };
|
|
3715
3648
|
await this.initialize();
|
|
3716
3649
|
const getById = this.db.prepare(`SELECT id FROM events WHERE id = ?`);
|
|
3717
3650
|
const getByDedupe = this.db.prepare(`SELECT event_id FROM event_dedup WHERE dedupe_key = ?`);
|
|
@@ -3829,8 +3762,7 @@ var SQLiteEventStore = class {
|
|
|
3829
3762
|
`SELECT * FROM sessions WHERE id = ?`,
|
|
3830
3763
|
[id]
|
|
3831
3764
|
);
|
|
3832
|
-
if (!row)
|
|
3833
|
-
return null;
|
|
3765
|
+
if (!row) return null;
|
|
3834
3766
|
return {
|
|
3835
3767
|
id: row.id,
|
|
3836
3768
|
startedAt: toDateFromSQLite(row.started_at),
|
|
@@ -3885,8 +3817,7 @@ var SQLiteEventStore = class {
|
|
|
3885
3817
|
LIMIT ?`,
|
|
3886
3818
|
[limit]
|
|
3887
3819
|
);
|
|
3888
|
-
if (pending.length === 0)
|
|
3889
|
-
return [];
|
|
3820
|
+
if (pending.length === 0) return [];
|
|
3890
3821
|
const ids = pending.map((r) => r.id);
|
|
3891
3822
|
const placeholders = ids.map(() => "?").join(",");
|
|
3892
3823
|
sqliteRun(
|
|
@@ -3910,8 +3841,7 @@ var SQLiteEventStore = class {
|
|
|
3910
3841
|
* Mark outbox items as done
|
|
3911
3842
|
*/
|
|
3912
3843
|
async completeOutboxItems(ids) {
|
|
3913
|
-
if (ids.length === 0)
|
|
3914
|
-
return;
|
|
3844
|
+
if (ids.length === 0) return;
|
|
3915
3845
|
const placeholders = ids.map(() => "?").join(",");
|
|
3916
3846
|
sqliteRun(
|
|
3917
3847
|
this.db,
|
|
@@ -3950,8 +3880,7 @@ var SQLiteEventStore = class {
|
|
|
3950
3880
|
* Mark outbox items as failed
|
|
3951
3881
|
*/
|
|
3952
3882
|
async failOutboxItems(ids, error) {
|
|
3953
|
-
if (ids.length === 0)
|
|
3954
|
-
return;
|
|
3883
|
+
if (ids.length === 0) return;
|
|
3955
3884
|
const placeholders = ids.map(() => "?").join(",");
|
|
3956
3885
|
sqliteRun(
|
|
3957
3886
|
this.db,
|
|
@@ -4078,8 +4007,7 @@ var SQLiteEventStore = class {
|
|
|
4078
4007
|
[]
|
|
4079
4008
|
);
|
|
4080
4009
|
const sample = (entry) => {
|
|
4081
|
-
if (result.samples.length < 20)
|
|
4082
|
-
result.samples.push(entry);
|
|
4010
|
+
if (result.samples.length < 20) result.samples.push(entry);
|
|
4083
4011
|
};
|
|
4084
4012
|
for (const row of rows) {
|
|
4085
4013
|
result.scanned++;
|
|
@@ -4206,12 +4134,10 @@ var SQLiteEventStore = class {
|
|
|
4206
4134
|
`SELECT status, COUNT(*) as count FROM vector_outbox GROUP BY status`
|
|
4207
4135
|
);
|
|
4208
4136
|
const processingAgeMs = (value) => {
|
|
4209
|
-
if (value === null || value === void 0)
|
|
4210
|
-
return null;
|
|
4137
|
+
if (value === null || value === void 0) return null;
|
|
4211
4138
|
const date = toDateFromSQLite(value);
|
|
4212
4139
|
const time = date.getTime();
|
|
4213
|
-
if (!Number.isFinite(time))
|
|
4214
|
-
return null;
|
|
4140
|
+
if (!Number.isFinite(time)) return null;
|
|
4215
4141
|
return Math.max(0, now.getTime() - time);
|
|
4216
4142
|
};
|
|
4217
4143
|
const fromRows = (rows, stuckProcessing, oldestProcessingAgeMs) => {
|
|
@@ -4360,8 +4286,7 @@ var SQLiteEventStore = class {
|
|
|
4360
4286
|
`SELECT value FROM endless_config WHERE key = ?`,
|
|
4361
4287
|
[key]
|
|
4362
4288
|
);
|
|
4363
|
-
if (!row)
|
|
4364
|
-
return null;
|
|
4289
|
+
if (!row) return null;
|
|
4365
4290
|
return JSON.parse(row.value);
|
|
4366
4291
|
}
|
|
4367
4292
|
/**
|
|
@@ -4380,8 +4305,7 @@ var SQLiteEventStore = class {
|
|
|
4380
4305
|
* Increment access count for events
|
|
4381
4306
|
*/
|
|
4382
4307
|
async incrementAccessCount(eventIds) {
|
|
4383
|
-
if (eventIds.length === 0 || this.readOnly)
|
|
4384
|
-
return;
|
|
4308
|
+
if (eventIds.length === 0 || this.readOnly) return;
|
|
4385
4309
|
await this.initialize();
|
|
4386
4310
|
const placeholders = eventIds.map(() => "?").join(",");
|
|
4387
4311
|
const currentTime = toSQLiteTimestamp(/* @__PURE__ */ new Date());
|
|
@@ -4424,8 +4348,7 @@ var SQLiteEventStore = class {
|
|
|
4424
4348
|
* Record a memory retrieval for helpfulness tracking
|
|
4425
4349
|
*/
|
|
4426
4350
|
async recordRetrieval(eventId, sessionId, score, query) {
|
|
4427
|
-
if (this.readOnly)
|
|
4428
|
-
return;
|
|
4351
|
+
if (this.readOnly) return;
|
|
4429
4352
|
await this.initialize();
|
|
4430
4353
|
const id = randomUUID6();
|
|
4431
4354
|
sqliteRun(
|
|
@@ -4455,16 +4378,14 @@ var SQLiteEventStore = class {
|
|
|
4455
4378
|
* Called at session end - uses behavioral signals to compute score
|
|
4456
4379
|
*/
|
|
4457
4380
|
async evaluateSessionHelpfulness(sessionId) {
|
|
4458
|
-
if (this.readOnly)
|
|
4459
|
-
return;
|
|
4381
|
+
if (this.readOnly) return;
|
|
4460
4382
|
await this.initialize();
|
|
4461
4383
|
const retrievals = sqliteAll(
|
|
4462
4384
|
this.db,
|
|
4463
4385
|
`SELECT * FROM memory_helpfulness WHERE session_id = ? AND measured_at IS NULL`,
|
|
4464
4386
|
[sessionId]
|
|
4465
4387
|
);
|
|
4466
|
-
if (retrievals.length === 0)
|
|
4467
|
-
return;
|
|
4388
|
+
if (retrievals.length === 0) return;
|
|
4468
4389
|
const sessionEvents = sqliteAll(
|
|
4469
4390
|
this.db,
|
|
4470
4391
|
`SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC`,
|
|
@@ -4477,8 +4398,7 @@ var SQLiteEventStore = class {
|
|
|
4477
4398
|
for (const t of toolEvents) {
|
|
4478
4399
|
try {
|
|
4479
4400
|
const content = JSON.parse(t.content);
|
|
4480
|
-
if (content.success !== false)
|
|
4481
|
-
toolSuccessCount++;
|
|
4401
|
+
if (content.success !== false) toolSuccessCount++;
|
|
4482
4402
|
} catch {
|
|
4483
4403
|
toolSuccessCount++;
|
|
4484
4404
|
}
|
|
@@ -4496,8 +4416,7 @@ var SQLiteEventStore = class {
|
|
|
4496
4416
|
const pWords = new Set(p.content.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
|
|
4497
4417
|
let overlap = 0;
|
|
4498
4418
|
for (const w of queryWords) {
|
|
4499
|
-
if (pWords.has(w))
|
|
4500
|
-
overlap++;
|
|
4419
|
+
if (pWords.has(w)) overlap++;
|
|
4501
4420
|
}
|
|
4502
4421
|
if (queryWords.size > 0 && overlap / queryWords.size > 0.5) {
|
|
4503
4422
|
wasReasked = 1;
|
|
@@ -4679,8 +4598,7 @@ var SQLiteEventStore = class {
|
|
|
4679
4598
|
return this.db;
|
|
4680
4599
|
}
|
|
4681
4600
|
hasTableColumn(tableName, columnName2) {
|
|
4682
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(tableName))
|
|
4683
|
-
return false;
|
|
4601
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(tableName)) return false;
|
|
4684
4602
|
try {
|
|
4685
4603
|
const rows = sqliteAll(this.db, `PRAGMA table_info("${tableName}")`, []);
|
|
4686
4604
|
return rows.some((row) => row.name === columnName2);
|
|
@@ -4747,8 +4665,7 @@ var SQLiteEventStore = class {
|
|
|
4747
4665
|
createdAt: toDateFromSQLite(row.created_at)
|
|
4748
4666
|
}));
|
|
4749
4667
|
} catch (err) {
|
|
4750
|
-
if (err?.message?.includes("no such table"))
|
|
4751
|
-
return [];
|
|
4668
|
+
if (err?.message?.includes("no such table")) return [];
|
|
4752
4669
|
throw err;
|
|
4753
4670
|
}
|
|
4754
4671
|
}
|
|
@@ -4921,8 +4838,7 @@ var SQLiteEventStore = class {
|
|
|
4921
4838
|
`SELECT id FROM events WHERE session_id = ?`,
|
|
4922
4839
|
[sessionId]
|
|
4923
4840
|
);
|
|
4924
|
-
if (events.length === 0)
|
|
4925
|
-
return 0;
|
|
4841
|
+
if (events.length === 0) return 0;
|
|
4926
4842
|
const eventIds = events.map((e) => e.id);
|
|
4927
4843
|
const placeholders = eventIds.map(() => "?").join(",");
|
|
4928
4844
|
const ftsTriggersDropped = [];
|
|
@@ -5134,8 +5050,7 @@ function sanitizeGovernanceAuditValue(value, key) {
|
|
|
5134
5050
|
return value;
|
|
5135
5051
|
}
|
|
5136
5052
|
function sanitizeAuditJson(value) {
|
|
5137
|
-
if (value === void 0)
|
|
5138
|
-
return void 0;
|
|
5053
|
+
if (value === void 0) return void 0;
|
|
5139
5054
|
return sanitizeGovernanceAuditValue(value);
|
|
5140
5055
|
}
|
|
5141
5056
|
function normalizeSourceEventIds(sourceEventIds) {
|
|
@@ -5184,12 +5099,10 @@ async function writeGovernanceAuditEntry(db, input) {
|
|
|
5184
5099
|
|
|
5185
5100
|
// src/core/operations/facet-repository.ts
|
|
5186
5101
|
function parseStringArray(value) {
|
|
5187
|
-
if (typeof value !== "string")
|
|
5188
|
-
return [];
|
|
5102
|
+
if (typeof value !== "string") return [];
|
|
5189
5103
|
try {
|
|
5190
5104
|
const parsed = JSON.parse(value);
|
|
5191
|
-
if (!Array.isArray(parsed))
|
|
5192
|
-
return [];
|
|
5105
|
+
if (!Array.isArray(parsed)) return [];
|
|
5193
5106
|
return parsed.filter((item) => typeof item === "string" && item.length > 0);
|
|
5194
5107
|
} catch {
|
|
5195
5108
|
return [];
|
|
@@ -5233,6 +5146,7 @@ var FacetRepository = class {
|
|
|
5233
5146
|
constructor(db) {
|
|
5234
5147
|
this.db = db;
|
|
5235
5148
|
}
|
|
5149
|
+
db;
|
|
5236
5150
|
async assign(input) {
|
|
5237
5151
|
const assignment = parseFacetAssignmentInput(input);
|
|
5238
5152
|
const existing = this.findByUniqueKey(assignment);
|
|
@@ -5537,19 +5451,14 @@ var RetentionFacetSchema = z5.object({
|
|
|
5537
5451
|
confidence: z5.number().min(0).max(1).default(1)
|
|
5538
5452
|
});
|
|
5539
5453
|
var DateLikeSchema = z5.preprocess((value) => {
|
|
5540
|
-
if (value instanceof Date)
|
|
5541
|
-
|
|
5542
|
-
if (typeof value === "string" || typeof value === "number")
|
|
5543
|
-
return new Date(value);
|
|
5454
|
+
if (value instanceof Date) return value;
|
|
5455
|
+
if (typeof value === "string" || typeof value === "number") return new Date(value);
|
|
5544
5456
|
return value;
|
|
5545
5457
|
}, z5.date());
|
|
5546
5458
|
var NullableDateLikeSchema = z5.preprocess((value) => {
|
|
5547
|
-
if (value === null || value === void 0 || value === "")
|
|
5548
|
-
|
|
5549
|
-
if (value
|
|
5550
|
-
return value;
|
|
5551
|
-
if (typeof value === "string" || typeof value === "number")
|
|
5552
|
-
return new Date(value);
|
|
5459
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
5460
|
+
if (value instanceof Date) return value;
|
|
5461
|
+
if (typeof value === "string" || typeof value === "number") return new Date(value);
|
|
5553
5462
|
return value;
|
|
5554
5463
|
}, z5.date().nullable());
|
|
5555
5464
|
var OptionalTrimmedStringSchema2 = z5.preprocess(
|
|
@@ -5578,10 +5487,8 @@ import { z as z6 } from "zod";
|
|
|
5578
5487
|
var RequiredTrimmedStringSchema = z6.string().trim().min(1);
|
|
5579
5488
|
var OptionalTrimmedStringSchema3 = z6.string().trim().min(1).optional();
|
|
5580
5489
|
var DateLikeSchema2 = z6.preprocess((value) => {
|
|
5581
|
-
if (value instanceof Date)
|
|
5582
|
-
|
|
5583
|
-
if (typeof value === "string" || typeof value === "number")
|
|
5584
|
-
return new Date(value);
|
|
5490
|
+
if (value instanceof Date) return value;
|
|
5491
|
+
if (typeof value === "string" || typeof value === "number") return new Date(value);
|
|
5585
5492
|
return value;
|
|
5586
5493
|
}, z6.date());
|
|
5587
5494
|
var RetentionReasonSchema = z6.object({
|
|
@@ -5770,8 +5677,7 @@ var MemoryOperationsConfigSchema = z7.object({
|
|
|
5770
5677
|
}).default({});
|
|
5771
5678
|
var MemoryLessonNonEmptyStringSchema = z7.string().transform((value) => value.trim()).pipe(z7.string().min(1));
|
|
5772
5679
|
var MemoryLessonStringArraySchema = z7.preprocess((value) => {
|
|
5773
|
-
if (!Array.isArray(value))
|
|
5774
|
-
return value;
|
|
5680
|
+
if (!Array.isArray(value)) return value;
|
|
5775
5681
|
return value.map((item) => typeof item === "string" ? item.trim() : item).filter((item) => typeof item !== "string" || item.length > 0);
|
|
5776
5682
|
}, z7.array(MemoryLessonNonEmptyStringSchema)).default([]);
|
|
5777
5683
|
var MemoryLessonSchema = z7.object({
|
|
@@ -5816,14 +5722,12 @@ var ListMemoryLessonsInputSchema = z7.object({
|
|
|
5816
5722
|
});
|
|
5817
5723
|
var PerspectiveMemoryNonEmptyStringSchema = z7.string().transform((value) => value.trim()).pipe(z7.string().min(1));
|
|
5818
5724
|
var PerspectiveMemoryOptionalStringSchema = z7.preprocess((value) => {
|
|
5819
|
-
if (typeof value !== "string")
|
|
5820
|
-
return value;
|
|
5725
|
+
if (typeof value !== "string") return value;
|
|
5821
5726
|
const normalized = value.trim();
|
|
5822
5727
|
return normalized.length > 0 ? normalized : void 0;
|
|
5823
5728
|
}, PerspectiveMemoryNonEmptyStringSchema.optional());
|
|
5824
5729
|
var PerspectiveMemoryStringArraySchema = z7.preprocess((value) => {
|
|
5825
|
-
if (!Array.isArray(value))
|
|
5826
|
-
return value;
|
|
5730
|
+
if (!Array.isArray(value)) return value;
|
|
5827
5731
|
return value.map((item) => typeof item === "string" ? item.trim() : item).filter((item) => typeof item !== "string" || item.length > 0);
|
|
5828
5732
|
}, z7.array(PerspectiveMemoryNonEmptyStringSchema)).default([]);
|
|
5829
5733
|
var ActorCardSensitivePattern = /(?:\b(?:api[_-]?key|secret|password|passwd|token|access[_-]?token|client[_-]?secret|bearer)\b\s*[:=])|(?:\b(?:api[_-]?key|secret|password|passwd|token|access[_-]?token|client[_-]?secret|bearer)=)|(?:^|\s)(?:\/[A-Za-z0-9._-][^\s`'\"]*)/i;
|
|
@@ -6481,6 +6385,7 @@ var GraphPathService = class {
|
|
|
6481
6385
|
constructor(db) {
|
|
6482
6386
|
this.db = db;
|
|
6483
6387
|
}
|
|
6388
|
+
db;
|
|
6484
6389
|
expand(input) {
|
|
6485
6390
|
const graph = this.loadGraph(input.direction ?? "both");
|
|
6486
6391
|
const effectiveMaxHops = normalizeMaxHops(input.maxHops);
|
|
@@ -6498,11 +6403,9 @@ var GraphPathService = class {
|
|
|
6498
6403
|
while (queue.length > 0) {
|
|
6499
6404
|
queue.sort((a, b) => a.totalCost - b.totalCost || a.hops - b.hops || a.key.localeCompare(b.key));
|
|
6500
6405
|
const current = queue.shift();
|
|
6501
|
-
if (current.hops >= effectiveMaxHops)
|
|
6502
|
-
continue;
|
|
6406
|
+
if (current.hops >= effectiveMaxHops) continue;
|
|
6503
6407
|
for (const edge of graph.adjacency.get(current.key) ?? []) {
|
|
6504
|
-
if (current.visited.has(edge.toKey))
|
|
6505
|
-
continue;
|
|
6408
|
+
if (current.visited.has(edge.toKey)) continue;
|
|
6506
6409
|
const nextHops = current.hops + 1;
|
|
6507
6410
|
const nextTotalCost = current.totalCost + edge.step.cost;
|
|
6508
6411
|
const nextSteps = [...current.steps, edge.step];
|
|
@@ -6582,17 +6485,13 @@ function addTraversal(adjacency, fromKey, edge) {
|
|
|
6582
6485
|
adjacency.set(fromKey, edges);
|
|
6583
6486
|
}
|
|
6584
6487
|
function normalizeMaxHops(maxHops) {
|
|
6585
|
-
if (maxHops === void 0)
|
|
6586
|
-
|
|
6587
|
-
if (!Number.isFinite(maxHops))
|
|
6588
|
-
return MAX_HOPS;
|
|
6488
|
+
if (maxHops === void 0) return 1;
|
|
6489
|
+
if (!Number.isFinite(maxHops)) return MAX_HOPS;
|
|
6589
6490
|
return Math.min(Math.max(0, Math.trunc(maxHops)), MAX_HOPS);
|
|
6590
6491
|
}
|
|
6591
6492
|
function normalizeMaxResults(maxResults) {
|
|
6592
|
-
if (maxResults === void 0)
|
|
6593
|
-
|
|
6594
|
-
if (!Number.isFinite(maxResults))
|
|
6595
|
-
return DEFAULT_MAX_RESULTS;
|
|
6493
|
+
if (maxResults === void 0) return DEFAULT_MAX_RESULTS;
|
|
6494
|
+
if (!Number.isFinite(maxResults)) return DEFAULT_MAX_RESULTS;
|
|
6596
6495
|
return Math.min(Math.max(0, Math.trunc(maxResults)), MAX_RESULTS);
|
|
6597
6496
|
}
|
|
6598
6497
|
function isBetterPath(totalCost, hops, signature, existing) {
|
|
@@ -6604,18 +6503,15 @@ function pathSignature(steps) {
|
|
|
6604
6503
|
function edgeWeight(metaJson) {
|
|
6605
6504
|
const meta = parseMeta(metaJson);
|
|
6606
6505
|
const raw = meta.weight;
|
|
6607
|
-
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0)
|
|
6608
|
-
return raw;
|
|
6506
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) return raw;
|
|
6609
6507
|
if (typeof raw === "string") {
|
|
6610
6508
|
const parsed = Number(raw);
|
|
6611
|
-
if (Number.isFinite(parsed) && parsed > 0)
|
|
6612
|
-
return parsed;
|
|
6509
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
6613
6510
|
}
|
|
6614
6511
|
return DEFAULT_WEIGHT;
|
|
6615
6512
|
}
|
|
6616
6513
|
function parseMeta(metaJson) {
|
|
6617
|
-
if (!metaJson)
|
|
6618
|
-
return {};
|
|
6514
|
+
if (!metaJson) return {};
|
|
6619
6515
|
try {
|
|
6620
6516
|
const parsed = JSON.parse(metaJson);
|
|
6621
6517
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
@@ -6628,8 +6524,7 @@ function nodeKey(node) {
|
|
|
6628
6524
|
}
|
|
6629
6525
|
function nodeFromKey(key) {
|
|
6630
6526
|
const index = key.indexOf(":");
|
|
6631
|
-
if (index === -1)
|
|
6632
|
-
return { type: "entity", id: key };
|
|
6527
|
+
if (index === -1) return { type: "entity", id: key };
|
|
6633
6528
|
return { type: key.slice(0, index), id: key.slice(index + 1) };
|
|
6634
6529
|
}
|
|
6635
6530
|
|
|
@@ -6685,6 +6580,7 @@ var QueryEntityExtractor = class {
|
|
|
6685
6580
|
constructor(db) {
|
|
6686
6581
|
this.db = db;
|
|
6687
6582
|
}
|
|
6583
|
+
db;
|
|
6688
6584
|
extract(query, options = {}) {
|
|
6689
6585
|
const maxCandidates = normalizeMaxCandidates(options.maxCandidates);
|
|
6690
6586
|
const candidates = [];
|
|
@@ -6706,8 +6602,7 @@ var QueryEntityExtractor = class {
|
|
|
6706
6602
|
let match;
|
|
6707
6603
|
while ((match = regex.exec(query)) !== null) {
|
|
6708
6604
|
const text = cleanCandidateText(match[2] ?? "");
|
|
6709
|
-
if (!isUsefulCandidate(text))
|
|
6710
|
-
continue;
|
|
6605
|
+
if (!isUsefulCandidate(text)) continue;
|
|
6711
6606
|
const start = match.index + 1;
|
|
6712
6607
|
const end = start + text.length;
|
|
6713
6608
|
ranges.push([match.index, match.index + match[0].length]);
|
|
@@ -6721,8 +6616,7 @@ var QueryEntityExtractor = class {
|
|
|
6721
6616
|
return ranges;
|
|
6722
6617
|
}
|
|
6723
6618
|
extractKnownAliases(query, candidates) {
|
|
6724
|
-
if (!this.db)
|
|
6725
|
-
return;
|
|
6619
|
+
if (!this.db) return;
|
|
6726
6620
|
const rows = sqliteAll(
|
|
6727
6621
|
this.db,
|
|
6728
6622
|
`SELECT
|
|
@@ -6746,11 +6640,9 @@ var QueryEntityExtractor = class {
|
|
|
6746
6640
|
]).filter(isUsefulCandidate);
|
|
6747
6641
|
for (const alias of aliasLabels) {
|
|
6748
6642
|
const normalizedAlias = normalizeForContainment(alias);
|
|
6749
|
-
if (!normalizedAlias || !containsPhrase(normalizedQuery, normalizedAlias))
|
|
6750
|
-
continue;
|
|
6643
|
+
if (!normalizedAlias || !containsPhrase(normalizedQuery, normalizedAlias)) continue;
|
|
6751
6644
|
const aliasKey = `${row.entity_id}:${normalizedAlias}`;
|
|
6752
|
-
if (seenAliases.has(aliasKey))
|
|
6753
|
-
continue;
|
|
6645
|
+
if (seenAliases.has(aliasKey)) continue;
|
|
6754
6646
|
seenAliases.add(aliasKey);
|
|
6755
6647
|
const range = findRange(query, alias);
|
|
6756
6648
|
pushCandidate(candidates, {
|
|
@@ -6771,8 +6663,7 @@ var QueryEntityExtractor = class {
|
|
|
6771
6663
|
let match;
|
|
6772
6664
|
while ((match = regex.exec(query)) !== null) {
|
|
6773
6665
|
const text = cleanCandidateText(match[2] ?? "");
|
|
6774
|
-
if (!isUsefulCandidate(text))
|
|
6775
|
-
continue;
|
|
6666
|
+
if (!isUsefulCandidate(text)) continue;
|
|
6776
6667
|
const start = match.index + (match[1]?.length ?? 0);
|
|
6777
6668
|
pushCandidate(candidates, {
|
|
6778
6669
|
text,
|
|
@@ -6787,8 +6678,7 @@ var QueryEntityExtractor = class {
|
|
|
6787
6678
|
let match;
|
|
6788
6679
|
while ((match = regex.exec(query)) !== null) {
|
|
6789
6680
|
const text = cleanCandidateText(match[2] ?? "");
|
|
6790
|
-
if (!isUsefulCandidate(text) || text.includes("/.") || text.includes("./"))
|
|
6791
|
-
continue;
|
|
6681
|
+
if (!isUsefulCandidate(text) || text.includes("/.") || text.includes("./")) continue;
|
|
6792
6682
|
const start = match.index + (match[1]?.length ?? 0);
|
|
6793
6683
|
pushCandidate(candidates, {
|
|
6794
6684
|
text,
|
|
@@ -6807,21 +6697,17 @@ var QueryEntityExtractor = class {
|
|
|
6807
6697
|
if (previous && query.slice(previous.end, token.start).match(/^\s+$/)) {
|
|
6808
6698
|
current.push(token);
|
|
6809
6699
|
} else {
|
|
6810
|
-
if (current.length > 0)
|
|
6811
|
-
groups.push(current);
|
|
6700
|
+
if (current.length > 0) groups.push(current);
|
|
6812
6701
|
current = [token];
|
|
6813
6702
|
}
|
|
6814
6703
|
}
|
|
6815
|
-
if (current.length > 0)
|
|
6816
|
-
groups.push(current);
|
|
6704
|
+
if (current.length > 0) groups.push(current);
|
|
6817
6705
|
for (const group of groups) {
|
|
6818
|
-
if (group.length === 1 && !isStrongSingleCapitalized(group[0].text))
|
|
6819
|
-
continue;
|
|
6706
|
+
if (group.length === 1 && !isStrongSingleCapitalized(group[0].text)) continue;
|
|
6820
6707
|
const start = group[0].start;
|
|
6821
6708
|
const end = group[group.length - 1].end;
|
|
6822
6709
|
const text = query.slice(start, end);
|
|
6823
|
-
if (!isUsefulCandidate(text))
|
|
6824
|
-
continue;
|
|
6710
|
+
if (!isUsefulCandidate(text)) continue;
|
|
6825
6711
|
pushCandidate(candidates, {
|
|
6826
6712
|
text,
|
|
6827
6713
|
source: "capitalized_term",
|
|
@@ -6842,8 +6728,7 @@ function collectCapitalizedTokens(query) {
|
|
|
6842
6728
|
}
|
|
6843
6729
|
function pushCandidate(candidates, input) {
|
|
6844
6730
|
const text = cleanCandidateText(input.text);
|
|
6845
|
-
if (!isUsefulCandidate(text))
|
|
6846
|
-
return;
|
|
6731
|
+
if (!isUsefulCandidate(text)) return;
|
|
6847
6732
|
const source = input.source;
|
|
6848
6733
|
candidates.push({
|
|
6849
6734
|
...input,
|
|
@@ -6861,15 +6746,13 @@ function dedupeAndSort(candidates) {
|
|
|
6861
6746
|
for (const candidate of sorted) {
|
|
6862
6747
|
if (candidate.source === "entity_alias") {
|
|
6863
6748
|
const aliasKey = `alias:${candidate.entityId ?? ""}:${normalizeCandidate(candidate.matchedAlias ?? candidate.text)}`;
|
|
6864
|
-
if (seenAliasKeys.has(aliasKey))
|
|
6865
|
-
continue;
|
|
6749
|
+
if (seenAliasKeys.has(aliasKey)) continue;
|
|
6866
6750
|
seenAliasKeys.add(aliasKey);
|
|
6867
6751
|
seenNormalized.add(candidate.normalized);
|
|
6868
6752
|
result.push(candidate);
|
|
6869
6753
|
continue;
|
|
6870
6754
|
}
|
|
6871
|
-
if (seenNormalized.has(candidate.normalized))
|
|
6872
|
-
continue;
|
|
6755
|
+
if (seenNormalized.has(candidate.normalized)) continue;
|
|
6873
6756
|
seenNormalized.add(candidate.normalized);
|
|
6874
6757
|
result.push(candidate);
|
|
6875
6758
|
}
|
|
@@ -6879,8 +6762,7 @@ function compareCandidates(a, b) {
|
|
|
6879
6762
|
return a.priority - b.priority || a.start - b.start || a.end - b.end || compareStrings(a.text, b.text) || compareStrings(a.entityId ?? "", b.entityId ?? "") || compareStrings(a.matchedAlias ?? "", b.matchedAlias ?? "");
|
|
6880
6763
|
}
|
|
6881
6764
|
function compareStrings(a, b) {
|
|
6882
|
-
if (a === b)
|
|
6883
|
-
return 0;
|
|
6765
|
+
if (a === b) return 0;
|
|
6884
6766
|
return a < b ? -1 : 1;
|
|
6885
6767
|
}
|
|
6886
6768
|
function stripPriority(candidate) {
|
|
@@ -6888,10 +6770,8 @@ function stripPriority(candidate) {
|
|
|
6888
6770
|
return publicCandidate;
|
|
6889
6771
|
}
|
|
6890
6772
|
function normalizeMaxCandidates(maxCandidates) {
|
|
6891
|
-
if (maxCandidates === void 0)
|
|
6892
|
-
|
|
6893
|
-
if (!Number.isFinite(maxCandidates))
|
|
6894
|
-
return DEFAULT_MAX_CANDIDATES;
|
|
6773
|
+
if (maxCandidates === void 0) return DEFAULT_MAX_CANDIDATES;
|
|
6774
|
+
if (!Number.isFinite(maxCandidates)) return DEFAULT_MAX_CANDIDATES;
|
|
6895
6775
|
return Math.min(Math.max(0, Math.trunc(maxCandidates)), MAX_CANDIDATES);
|
|
6896
6776
|
}
|
|
6897
6777
|
function cleanCandidateText(text) {
|
|
@@ -6913,21 +6793,17 @@ function aliasLabelFromCanonicalKey(canonicalKey) {
|
|
|
6913
6793
|
function findRange(query, alias) {
|
|
6914
6794
|
const normalizedAlias = normalizeForContainment(alias);
|
|
6915
6795
|
const directIndex = query.toLowerCase().indexOf(alias.toLowerCase());
|
|
6916
|
-
if (directIndex >= 0)
|
|
6917
|
-
return { start: directIndex, end: directIndex + alias.length };
|
|
6796
|
+
if (directIndex >= 0) return { start: directIndex, end: directIndex + alias.length };
|
|
6918
6797
|
const normalizedQuery = normalizeForContainment(query);
|
|
6919
6798
|
const normalizedIndex = normalizedQuery.indexOf(normalizedAlias);
|
|
6920
|
-
if (normalizedIndex < 0)
|
|
6921
|
-
return { start: 0, end: 0 };
|
|
6799
|
+
if (normalizedIndex < 0) return { start: 0, end: 0 };
|
|
6922
6800
|
const queryLower = query.toLowerCase();
|
|
6923
6801
|
const words = normalizedAlias.split(" ").filter(Boolean);
|
|
6924
|
-
if (words.length === 0)
|
|
6925
|
-
return { start: 0, end: 0 };
|
|
6802
|
+
if (words.length === 0) return { start: 0, end: 0 };
|
|
6926
6803
|
const first = queryLower.indexOf(words[0]);
|
|
6927
6804
|
const lastWord = words[words.length - 1];
|
|
6928
6805
|
const last = queryLower.indexOf(lastWord, first >= 0 ? first : 0);
|
|
6929
|
-
if (first >= 0 && last >= 0)
|
|
6930
|
-
return { start: first, end: last + lastWord.length };
|
|
6806
|
+
if (first >= 0 && last >= 0) return { start: first, end: last + lastWord.length };
|
|
6931
6807
|
return { start: normalizedIndex, end: normalizedIndex + normalizedAlias.length };
|
|
6932
6808
|
}
|
|
6933
6809
|
function isUsefulCandidate(text) {
|
|
@@ -6938,10 +6814,8 @@ function isInsideAnyRange(index, ranges) {
|
|
|
6938
6814
|
return ranges.some(([start, end]) => index >= start && index < end);
|
|
6939
6815
|
}
|
|
6940
6816
|
function isStrongSingleCapitalized(text) {
|
|
6941
|
-
if (/^[A-Z]{2,}[A-Z0-9]*$/.test(text))
|
|
6942
|
-
|
|
6943
|
-
if (/^[A-Z][a-z]+[A-Z][A-Za-z0-9]*$/.test(text))
|
|
6944
|
-
return true;
|
|
6817
|
+
if (/^[A-Z]{2,}[A-Z0-9]*$/.test(text)) return true;
|
|
6818
|
+
if (/^[A-Z][a-z]+[A-Z][A-Za-z0-9]*$/.test(text)) return true;
|
|
6945
6819
|
return text.length >= 4 && !SENTENCE_START_STOPWORDS.has(text);
|
|
6946
6820
|
}
|
|
6947
6821
|
function uniqueStrings(values) {
|
|
@@ -6949,8 +6823,7 @@ function uniqueStrings(values) {
|
|
|
6949
6823
|
const result = [];
|
|
6950
6824
|
for (const value of values) {
|
|
6951
6825
|
const key = normalizeForContainment(value);
|
|
6952
|
-
if (!key || seen.has(key))
|
|
6953
|
-
continue;
|
|
6826
|
+
if (!key || seen.has(key)) continue;
|
|
6954
6827
|
seen.add(key);
|
|
6955
6828
|
result.push(value);
|
|
6956
6829
|
}
|
|
@@ -6972,8 +6845,7 @@ var LessonCandidateInputSchema = z9.object({
|
|
|
6972
6845
|
import { z as z10 } from "zod";
|
|
6973
6846
|
var NonEmptyStringSchema5 = z10.string().transform((value) => value.trim()).pipe(z10.string().min(1));
|
|
6974
6847
|
var PromotionStringArraySchema = z10.preprocess((value) => {
|
|
6975
|
-
if (!Array.isArray(value))
|
|
6976
|
-
return value;
|
|
6848
|
+
if (!Array.isArray(value)) return value;
|
|
6977
6849
|
return value.map((item) => typeof item === "string" ? item.trim() : item).filter((item) => typeof item !== "string" || item.length > 0);
|
|
6978
6850
|
}, z10.array(NonEmptyStringSchema5).max(100));
|
|
6979
6851
|
var ReviewedLessonCandidateSchema = z10.object({
|
|
@@ -7021,8 +6893,7 @@ function projectHashFromStorage(projectHash) {
|
|
|
7021
6893
|
return projectHash.length > 0 ? projectHash : void 0;
|
|
7022
6894
|
}
|
|
7023
6895
|
function parseJsonRecord(value) {
|
|
7024
|
-
if (!value)
|
|
7025
|
-
return void 0;
|
|
6896
|
+
if (!value) return void 0;
|
|
7026
6897
|
try {
|
|
7027
6898
|
const parsed = JSON.parse(value);
|
|
7028
6899
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
@@ -7034,8 +6905,7 @@ function sanitizeString(value) {
|
|
|
7034
6905
|
return String(sanitizeGovernanceAuditValue(value)).trim();
|
|
7035
6906
|
}
|
|
7036
6907
|
function sanitizeMetadata(metadata) {
|
|
7037
|
-
if (!metadata)
|
|
7038
|
-
return void 0;
|
|
6908
|
+
if (!metadata) return void 0;
|
|
7039
6909
|
return sanitizeGovernanceAuditValue(metadata);
|
|
7040
6910
|
}
|
|
7041
6911
|
function slugActorPart(value) {
|
|
@@ -7043,8 +6913,7 @@ function slugActorPart(value) {
|
|
|
7043
6913
|
return slug.length > 0 ? slug : "unknown";
|
|
7044
6914
|
}
|
|
7045
6915
|
function stableActorId(input) {
|
|
7046
|
-
if (input.actorId)
|
|
7047
|
-
return sanitizeString(input.actorId);
|
|
6916
|
+
if (input.actorId) return sanitizeString(input.actorId);
|
|
7048
6917
|
const projectPart = input.projectHash ? `project:${slugActorPart(input.projectHash)}` : "global";
|
|
7049
6918
|
return [
|
|
7050
6919
|
"actor",
|
|
@@ -7067,12 +6936,10 @@ function rowToActor(row) {
|
|
|
7067
6936
|
});
|
|
7068
6937
|
}
|
|
7069
6938
|
function metadataString(metadata, keys) {
|
|
7070
|
-
if (!metadata)
|
|
7071
|
-
return void 0;
|
|
6939
|
+
if (!metadata) return void 0;
|
|
7072
6940
|
for (const key of keys) {
|
|
7073
6941
|
const value = metadata[key];
|
|
7074
|
-
if (typeof value === "string" && value.trim().length > 0)
|
|
7075
|
-
return value.trim();
|
|
6942
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
7076
6943
|
}
|
|
7077
6944
|
return void 0;
|
|
7078
6945
|
}
|
|
@@ -7122,6 +6989,7 @@ var ActorRepository = class {
|
|
|
7122
6989
|
constructor(db) {
|
|
7123
6990
|
this.db = db;
|
|
7124
6991
|
}
|
|
6992
|
+
db;
|
|
7125
6993
|
async upsert(input) {
|
|
7126
6994
|
const parsed = UpsertMemoryActorInputSchema.parse(input);
|
|
7127
6995
|
const actorId = stableActorId(parsed);
|
|
@@ -7175,8 +7043,7 @@ var ActorRepository = class {
|
|
|
7175
7043
|
}
|
|
7176
7044
|
require(actorId) {
|
|
7177
7045
|
const actor = this.get(actorId);
|
|
7178
|
-
if (!actor)
|
|
7179
|
-
throw new Error(`Memory actor not found: ${actorId}`);
|
|
7046
|
+
if (!actor) throw new Error(`Memory actor not found: ${actorId}`);
|
|
7180
7047
|
return actor;
|
|
7181
7048
|
}
|
|
7182
7049
|
async list(input = {}) {
|
|
@@ -7212,8 +7079,7 @@ function projectHashFromStorage2(projectHash) {
|
|
|
7212
7079
|
return projectHash.length > 0 ? projectHash : void 0;
|
|
7213
7080
|
}
|
|
7214
7081
|
function parseJsonRecord2(value) {
|
|
7215
|
-
if (!value)
|
|
7216
|
-
return void 0;
|
|
7082
|
+
if (!value) return void 0;
|
|
7217
7083
|
try {
|
|
7218
7084
|
const parsed = JSON.parse(value);
|
|
7219
7085
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
@@ -7222,8 +7088,7 @@ function parseJsonRecord2(value) {
|
|
|
7222
7088
|
}
|
|
7223
7089
|
}
|
|
7224
7090
|
function sanitizeMetadata2(metadata) {
|
|
7225
|
-
if (!metadata)
|
|
7226
|
-
return void 0;
|
|
7091
|
+
if (!metadata) return void 0;
|
|
7227
7092
|
return sanitizeGovernanceAuditValue(metadata);
|
|
7228
7093
|
}
|
|
7229
7094
|
function rowToSessionActor(row) {
|
|
@@ -7243,6 +7108,7 @@ var SessionActorRepository = class {
|
|
|
7243
7108
|
constructor(db) {
|
|
7244
7109
|
this.db = db;
|
|
7245
7110
|
}
|
|
7111
|
+
db;
|
|
7246
7112
|
async upsertMembership(input) {
|
|
7247
7113
|
const parsed = UpsertSessionActorInputSchema.parse(input);
|
|
7248
7114
|
const projectHash = projectHashToStorage3(parsed.projectHash);
|
|
@@ -7289,8 +7155,7 @@ var SessionActorRepository = class {
|
|
|
7289
7155
|
);
|
|
7290
7156
|
}
|
|
7291
7157
|
const saved = this.get(projectHash, parsed.sessionId, parsed.actorId);
|
|
7292
|
-
if (!saved)
|
|
7293
|
-
throw new Error("session actor membership was not saved");
|
|
7158
|
+
if (!saved) throw new Error("session actor membership was not saved");
|
|
7294
7159
|
return saved;
|
|
7295
7160
|
}
|
|
7296
7161
|
async listBySession(input) {
|
|
@@ -7326,8 +7191,7 @@ var SessionActorRepository = class {
|
|
|
7326
7191
|
]
|
|
7327
7192
|
);
|
|
7328
7193
|
const saved = this.get(projectHash, parsed.sessionId, parsed.actorId);
|
|
7329
|
-
if (!saved)
|
|
7330
|
-
throw new Error("session actor membership not found after update");
|
|
7194
|
+
if (!saved) throw new Error("session actor membership not found after update");
|
|
7331
7195
|
return saved;
|
|
7332
7196
|
}
|
|
7333
7197
|
get(projectHash, sessionId, actorId) {
|
|
@@ -7349,8 +7213,7 @@ function projectHashFromStorage3(projectHash) {
|
|
|
7349
7213
|
return projectHash.length > 0 ? projectHash : void 0;
|
|
7350
7214
|
}
|
|
7351
7215
|
function parseStringArray2(value) {
|
|
7352
|
-
if (!value)
|
|
7353
|
-
return [];
|
|
7216
|
+
if (!value) return [];
|
|
7354
7217
|
try {
|
|
7355
7218
|
const parsed = JSON.parse(value);
|
|
7356
7219
|
return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string") : [];
|
|
@@ -7359,8 +7222,7 @@ function parseStringArray2(value) {
|
|
|
7359
7222
|
}
|
|
7360
7223
|
}
|
|
7361
7224
|
function parseJsonRecord3(value) {
|
|
7362
|
-
if (!value)
|
|
7363
|
-
return void 0;
|
|
7225
|
+
if (!value) return void 0;
|
|
7364
7226
|
try {
|
|
7365
7227
|
const parsed = JSON.parse(value);
|
|
7366
7228
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
@@ -7376,8 +7238,7 @@ function sanitizeStoredStringArray(values) {
|
|
|
7376
7238
|
return values.map(sanitizeStoredString).filter((value) => value.length > 0);
|
|
7377
7239
|
}
|
|
7378
7240
|
function sanitizeStoredRecord(value) {
|
|
7379
|
-
if (!value)
|
|
7380
|
-
return void 0;
|
|
7241
|
+
if (!value) return void 0;
|
|
7381
7242
|
return sanitizeGovernanceAuditValue(value);
|
|
7382
7243
|
}
|
|
7383
7244
|
function stableHash(value) {
|
|
@@ -7428,8 +7289,7 @@ function sanitizedObservationSnapshot(observation) {
|
|
|
7428
7289
|
});
|
|
7429
7290
|
}
|
|
7430
7291
|
function queryScore(observation, terms) {
|
|
7431
|
-
if (terms.length === 0)
|
|
7432
|
-
return 0;
|
|
7292
|
+
if (terms.length === 0) return 0;
|
|
7433
7293
|
const haystack = [observation.content, observation.level, observation.sessionId ?? ""].join(" ").toLowerCase();
|
|
7434
7294
|
return terms.reduce((score, term) => score + (haystack.includes(term) ? 1 : 0), 0);
|
|
7435
7295
|
}
|
|
@@ -7475,12 +7335,12 @@ var PerspectiveObservationRepository = class {
|
|
|
7475
7335
|
this.vectorOutbox = options.vectorOutbox;
|
|
7476
7336
|
}
|
|
7477
7337
|
}
|
|
7338
|
+
db;
|
|
7478
7339
|
vectorOutbox = null;
|
|
7479
7340
|
vectorOutboxOption;
|
|
7480
7341
|
getVectorOutbox() {
|
|
7481
7342
|
const option = this.vectorOutboxOption;
|
|
7482
|
-
if (option === false)
|
|
7483
|
-
return null;
|
|
7343
|
+
if (option === false) return null;
|
|
7484
7344
|
if (option instanceof VectorOutbox) {
|
|
7485
7345
|
this.vectorOutbox = option;
|
|
7486
7346
|
return option;
|
|
@@ -7492,8 +7352,7 @@ var PerspectiveObservationRepository = class {
|
|
|
7492
7352
|
}
|
|
7493
7353
|
enqueueObservationSync(observationId) {
|
|
7494
7354
|
const outbox = this.getVectorOutbox();
|
|
7495
|
-
if (!outbox)
|
|
7496
|
-
return;
|
|
7355
|
+
if (!outbox) return;
|
|
7497
7356
|
outbox.enqueueSync("perspective_observation", observationId);
|
|
7498
7357
|
}
|
|
7499
7358
|
async create(input) {
|
|
@@ -7555,14 +7414,12 @@ var PerspectiveObservationRepository = class {
|
|
|
7555
7414
|
contentHash,
|
|
7556
7415
|
sourceHash
|
|
7557
7416
|
);
|
|
7558
|
-
if (!saved)
|
|
7559
|
-
throw new Error("perspective observation was not saved");
|
|
7417
|
+
if (!saved) throw new Error("perspective observation was not saved");
|
|
7560
7418
|
this.enqueueObservationSync(saved.observationId);
|
|
7561
7419
|
});
|
|
7562
7420
|
transaction();
|
|
7563
7421
|
const savedObservation = saved;
|
|
7564
|
-
if (!savedObservation)
|
|
7565
|
-
throw new Error("perspective observation was not saved");
|
|
7422
|
+
if (!savedObservation) throw new Error("perspective observation was not saved");
|
|
7566
7423
|
await this.writeCreateAudit({ ...parsed, observerActorId, observedActorId, sessionId, content, sourceEventIds, sourceObservationIds, createdBy, actor, metadata }, savedObservation);
|
|
7567
7424
|
return savedObservation;
|
|
7568
7425
|
}
|
|
@@ -7572,8 +7429,7 @@ var PerspectiveObservationRepository = class {
|
|
|
7572
7429
|
const ftsQuery = buildObservationFtsQuery(parsed.query);
|
|
7573
7430
|
if (ftsQuery) {
|
|
7574
7431
|
const ftsResult = this.queryWithFts(parsed, ftsQuery);
|
|
7575
|
-
if (ftsResult)
|
|
7576
|
-
return ftsResult;
|
|
7432
|
+
if (ftsResult) return ftsResult;
|
|
7577
7433
|
}
|
|
7578
7434
|
}
|
|
7579
7435
|
return this.queryWithPrefetch(parsed);
|
|
@@ -7594,8 +7450,7 @@ var PerspectiveObservationRepository = class {
|
|
|
7594
7450
|
);
|
|
7595
7451
|
return rows.map(rowToObservation);
|
|
7596
7452
|
} catch (error) {
|
|
7597
|
-
if (isFtsUnavailableError(error))
|
|
7598
|
-
return null;
|
|
7453
|
+
if (isFtsUnavailableError(error)) return null;
|
|
7599
7454
|
throw error;
|
|
7600
7455
|
}
|
|
7601
7456
|
}
|
|
@@ -7636,8 +7491,7 @@ var PerspectiveObservationRepository = class {
|
|
|
7636
7491
|
const parsed = DeletePerspectiveObservationInputSchema.parse(input);
|
|
7637
7492
|
const projectHash = projectHashToStorage4(parsed.projectHash);
|
|
7638
7493
|
const before = this.get(projectHash, parsed.observationId);
|
|
7639
|
-
if (!before)
|
|
7640
|
-
throw new Error("perspective observation not found");
|
|
7494
|
+
if (!before) throw new Error("perspective observation not found");
|
|
7641
7495
|
const deletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7642
7496
|
sqliteRun(
|
|
7643
7497
|
this.db,
|
|
@@ -7647,8 +7501,7 @@ var PerspectiveObservationRepository = class {
|
|
|
7647
7501
|
[deletedAt, deletedAt, projectHash, parsed.observationId]
|
|
7648
7502
|
);
|
|
7649
7503
|
const after = this.get(projectHash, parsed.observationId);
|
|
7650
|
-
if (!after)
|
|
7651
|
-
throw new Error("perspective observation not found after delete");
|
|
7504
|
+
if (!after) throw new Error("perspective observation not found after delete");
|
|
7652
7505
|
await writeGovernanceAuditEntry(this.db, {
|
|
7653
7506
|
operation: "perspective_observation_delete",
|
|
7654
7507
|
actor: parsed.actor,
|
|
@@ -7704,11 +7557,9 @@ var DEFAULT_CONFIG3 = {
|
|
|
7704
7557
|
var MAX_OBSERVATION_CONTENT_CHARS = 600;
|
|
7705
7558
|
var RuleBasedPerspectiveObservationExtractor = class {
|
|
7706
7559
|
async extract(event) {
|
|
7707
|
-
if (!isSupportedSourceEvent(event))
|
|
7708
|
-
return [];
|
|
7560
|
+
if (!isSupportedSourceEvent(event)) return [];
|
|
7709
7561
|
const content = normalizeObservationContent(event.content);
|
|
7710
|
-
if (!content)
|
|
7711
|
-
return [];
|
|
7562
|
+
if (!content) return [];
|
|
7712
7563
|
return [{
|
|
7713
7564
|
content,
|
|
7714
7565
|
confidence: 0.6,
|
|
@@ -7779,8 +7630,7 @@ var PerspectiveDeriver = class {
|
|
|
7779
7630
|
for (const candidate of candidates) {
|
|
7780
7631
|
const observedActorId = candidate.observedActorId ?? sourceActor.actorId;
|
|
7781
7632
|
const observers = selectObservers(members, observedActorId, this.config.deriver.maxObserversPerSession);
|
|
7782
|
-
if (observers.length === 0)
|
|
7783
|
-
continue;
|
|
7633
|
+
if (observers.length === 0) continue;
|
|
7784
7634
|
for (const observerActorId of observers) {
|
|
7785
7635
|
await this.observations.create({
|
|
7786
7636
|
projectHash,
|
|
@@ -7833,28 +7683,22 @@ function normalizeConfig(config) {
|
|
|
7833
7683
|
};
|
|
7834
7684
|
}
|
|
7835
7685
|
function clampInteger(value, fallback, min, max) {
|
|
7836
|
-
if (!Number.isFinite(value))
|
|
7837
|
-
return fallback;
|
|
7686
|
+
if (!Number.isFinite(value)) return fallback;
|
|
7838
7687
|
return Math.max(min, Math.min(max, Math.trunc(Number(value))));
|
|
7839
7688
|
}
|
|
7840
7689
|
function isSupportedSourceEvent(event) {
|
|
7841
7690
|
return event.eventType === "user_prompt" || event.eventType === "agent_response";
|
|
7842
7691
|
}
|
|
7843
7692
|
function roleForEvent(event) {
|
|
7844
|
-
if (event.eventType === "user_prompt")
|
|
7845
|
-
|
|
7846
|
-
if (event.eventType === "
|
|
7847
|
-
|
|
7848
|
-
if (event.eventType === "tool_observation")
|
|
7849
|
-
return "tool";
|
|
7850
|
-
if (event.eventType === "session_summary")
|
|
7851
|
-
return "system";
|
|
7693
|
+
if (event.eventType === "user_prompt") return "speaker";
|
|
7694
|
+
if (event.eventType === "agent_response") return "assistant";
|
|
7695
|
+
if (event.eventType === "tool_observation") return "tool";
|
|
7696
|
+
if (event.eventType === "session_summary") return "system";
|
|
7852
7697
|
return "unknown";
|
|
7853
7698
|
}
|
|
7854
7699
|
function normalizeCandidate2(candidate) {
|
|
7855
7700
|
const content = normalizeObservationContent(candidate.content);
|
|
7856
|
-
if (!content)
|
|
7857
|
-
return null;
|
|
7701
|
+
if (!content) return null;
|
|
7858
7702
|
return {
|
|
7859
7703
|
content,
|
|
7860
7704
|
confidence: clampNumber(candidate.confidence, 0.6, 0, 1),
|
|
@@ -7866,8 +7710,7 @@ function normalizeCandidate2(candidate) {
|
|
|
7866
7710
|
}
|
|
7867
7711
|
function normalizeObservationContent(content) {
|
|
7868
7712
|
const normalized = content.replace(/\s+/g, " ").trim();
|
|
7869
|
-
if (!normalized)
|
|
7870
|
-
return null;
|
|
7713
|
+
if (!normalized) return null;
|
|
7871
7714
|
return normalized.slice(0, MAX_OBSERVATION_CONTENT_CHARS);
|
|
7872
7715
|
}
|
|
7873
7716
|
function normalizeOptionalString2(value) {
|
|
@@ -7875,13 +7718,11 @@ function normalizeOptionalString2(value) {
|
|
|
7875
7718
|
return normalized.length > 0 ? normalized : void 0;
|
|
7876
7719
|
}
|
|
7877
7720
|
function clampNumber(value, fallback, min, max) {
|
|
7878
|
-
if (!Number.isFinite(value))
|
|
7879
|
-
return fallback;
|
|
7721
|
+
if (!Number.isFinite(value)) return fallback;
|
|
7880
7722
|
return Math.max(min, Math.min(max, Number(value)));
|
|
7881
7723
|
}
|
|
7882
7724
|
function sanitizeCandidateMetadata(metadata) {
|
|
7883
|
-
if (!metadata)
|
|
7884
|
-
return void 0;
|
|
7725
|
+
if (!metadata) return void 0;
|
|
7885
7726
|
const result = {};
|
|
7886
7727
|
for (const [key, value] of Object.entries(metadata)) {
|
|
7887
7728
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
@@ -7894,12 +7735,9 @@ function selectObservers(members, observedActorId, maxObservers) {
|
|
|
7894
7735
|
const selected = [];
|
|
7895
7736
|
for (const member of members) {
|
|
7896
7737
|
const canObserve = member.actorId === observedActorId ? member.observeSelf : member.observeOthers;
|
|
7897
|
-
if (!canObserve)
|
|
7898
|
-
|
|
7899
|
-
if (
|
|
7900
|
-
selected.push(member.actorId);
|
|
7901
|
-
if (selected.length >= maxObservers)
|
|
7902
|
-
break;
|
|
7738
|
+
if (!canObserve) continue;
|
|
7739
|
+
if (!selected.includes(member.actorId)) selected.push(member.actorId);
|
|
7740
|
+
if (selected.length >= maxObservers) break;
|
|
7903
7741
|
}
|
|
7904
7742
|
return selected;
|
|
7905
7743
|
}
|
|
@@ -7935,6 +7773,7 @@ var VectorStore = class {
|
|
|
7935
7773
|
constructor(dbPath) {
|
|
7936
7774
|
this.dbPath = dbPath;
|
|
7937
7775
|
}
|
|
7776
|
+
dbPath;
|
|
7938
7777
|
db = null;
|
|
7939
7778
|
tableCache = /* @__PURE__ */ new Map();
|
|
7940
7779
|
defaultTableName = "conversations";
|
|
@@ -7946,8 +7785,7 @@ var VectorStore = class {
|
|
|
7946
7785
|
* conversations table.
|
|
7947
7786
|
*/
|
|
7948
7787
|
async initialize() {
|
|
7949
|
-
if (this.db)
|
|
7950
|
-
return;
|
|
7788
|
+
if (this.db) return;
|
|
7951
7789
|
this.db = await lancedb.connect(this.dbPath);
|
|
7952
7790
|
}
|
|
7953
7791
|
/**
|
|
@@ -7961,8 +7799,7 @@ var VectorStore = class {
|
|
|
7961
7799
|
* Add or update multiple vector records in batch, grouped by inferred table.
|
|
7962
7800
|
*/
|
|
7963
7801
|
async upsertBatch(records) {
|
|
7964
|
-
if (records.length === 0)
|
|
7965
|
-
return;
|
|
7802
|
+
if (records.length === 0) return;
|
|
7966
7803
|
await this.initialize();
|
|
7967
7804
|
if (!this.db) {
|
|
7968
7805
|
throw new Error("Database not initialized");
|
|
@@ -8017,8 +7854,7 @@ var VectorStore = class {
|
|
|
8017
7854
|
async delete(eventId) {
|
|
8018
7855
|
await this.initialize();
|
|
8019
7856
|
const table = await this.getExistingTable(this.defaultTableName);
|
|
8020
|
-
if (!table)
|
|
8021
|
-
return;
|
|
7857
|
+
if (!table) return;
|
|
8022
7858
|
await table.delete(`eventId = ${toLanceSqlString(eventId)}`);
|
|
8023
7859
|
}
|
|
8024
7860
|
/**
|
|
@@ -8027,8 +7863,7 @@ var VectorStore = class {
|
|
|
8027
7863
|
async count() {
|
|
8028
7864
|
await this.initialize();
|
|
8029
7865
|
const table = await this.getExistingTable(this.defaultTableName);
|
|
8030
|
-
if (!table)
|
|
8031
|
-
return 0;
|
|
7866
|
+
if (!table) return 0;
|
|
8032
7867
|
const result = await table.countRows();
|
|
8033
7868
|
return result;
|
|
8034
7869
|
}
|
|
@@ -8037,8 +7872,7 @@ var VectorStore = class {
|
|
|
8037
7872
|
*/
|
|
8038
7873
|
async clearAll() {
|
|
8039
7874
|
await this.initialize();
|
|
8040
|
-
if (!this.db)
|
|
8041
|
-
return;
|
|
7875
|
+
if (!this.db) return;
|
|
8042
7876
|
try {
|
|
8043
7877
|
if (typeof this.db.dropTable === "function") {
|
|
8044
7878
|
await this.db.dropTable(this.defaultTableName);
|
|
@@ -8055,8 +7889,7 @@ var VectorStore = class {
|
|
|
8055
7889
|
async exists(eventId) {
|
|
8056
7890
|
await this.initialize();
|
|
8057
7891
|
const table = await this.getExistingTable(this.defaultTableName);
|
|
8058
|
-
if (!table)
|
|
8059
|
-
return false;
|
|
7892
|
+
if (!table) return false;
|
|
8060
7893
|
const results = await table.search([]).where(`eventId = ${toLanceSqlString(eventId)}`).limit(1).toArray();
|
|
8061
7894
|
return results.length > 0;
|
|
8062
7895
|
}
|
|
@@ -8091,8 +7924,7 @@ var VectorStore = class {
|
|
|
8091
7924
|
throw new Error("Database not initialized");
|
|
8092
7925
|
}
|
|
8093
7926
|
const cached = this.tableCache.get(tableName);
|
|
8094
|
-
if (cached)
|
|
8095
|
-
return cached;
|
|
7927
|
+
if (cached) return cached;
|
|
8096
7928
|
const tableNames = await this.db.tableNames();
|
|
8097
7929
|
if (!tableNames.includes(tableName)) {
|
|
8098
7930
|
return null;
|
|
@@ -8171,12 +8003,9 @@ var IngestInterceptorRegistry = class {
|
|
|
8171
8003
|
}
|
|
8172
8004
|
};
|
|
8173
8005
|
function mergeHierarchicalMetadata(base, patch) {
|
|
8174
|
-
if (!base && !patch)
|
|
8175
|
-
|
|
8176
|
-
if (!base
|
|
8177
|
-
return patch;
|
|
8178
|
-
if (!patch)
|
|
8179
|
-
return base;
|
|
8006
|
+
if (!base && !patch) return void 0;
|
|
8007
|
+
if (!base) return patch;
|
|
8008
|
+
if (!patch) return base;
|
|
8180
8009
|
const result = { ...base };
|
|
8181
8010
|
for (const [key, value] of Object.entries(patch)) {
|
|
8182
8011
|
const current = result[key];
|
|
@@ -8206,33 +8035,26 @@ var VALID_TAG_NAMESPACES = new Set(Object.values(TAG_NAMESPACES));
|
|
|
8206
8035
|
function parseTag(tag) {
|
|
8207
8036
|
const value = (tag || "").trim();
|
|
8208
8037
|
const idx = value.indexOf(":");
|
|
8209
|
-
if (idx <= 0)
|
|
8210
|
-
return { value };
|
|
8038
|
+
if (idx <= 0) return { value };
|
|
8211
8039
|
const namespace = `${value.slice(0, idx)}:`;
|
|
8212
8040
|
const tagValue = value.slice(idx + 1);
|
|
8213
|
-
if (!tagValue)
|
|
8214
|
-
return { value };
|
|
8041
|
+
if (!tagValue) return { value };
|
|
8215
8042
|
return { namespace, value: tagValue };
|
|
8216
8043
|
}
|
|
8217
8044
|
function validateTag(tag) {
|
|
8218
8045
|
const normalized = (tag || "").trim();
|
|
8219
|
-
if (!normalized)
|
|
8220
|
-
return false;
|
|
8046
|
+
if (!normalized) return false;
|
|
8221
8047
|
const { namespace } = parseTag(normalized);
|
|
8222
|
-
if (!namespace)
|
|
8223
|
-
return true;
|
|
8048
|
+
if (!namespace) return true;
|
|
8224
8049
|
return VALID_TAG_NAMESPACES.has(namespace);
|
|
8225
8050
|
}
|
|
8226
8051
|
function normalizeTags(tags) {
|
|
8227
|
-
if (!Array.isArray(tags))
|
|
8228
|
-
return [];
|
|
8052
|
+
if (!Array.isArray(tags)) return [];
|
|
8229
8053
|
const dedup = /* @__PURE__ */ new Set();
|
|
8230
8054
|
for (const item of tags) {
|
|
8231
|
-
if (typeof item !== "string")
|
|
8232
|
-
continue;
|
|
8055
|
+
if (typeof item !== "string") continue;
|
|
8233
8056
|
const normalized = item.trim();
|
|
8234
|
-
if (!validateTag(normalized))
|
|
8235
|
-
continue;
|
|
8057
|
+
if (!validateTag(normalized)) continue;
|
|
8236
8058
|
dedup.add(normalized);
|
|
8237
8059
|
}
|
|
8238
8060
|
return [...dedup];
|
|
@@ -8249,10 +8071,8 @@ var SummaryDeriver = class {
|
|
|
8249
8071
|
* orchestration, while this class owns summary text and metadata decisions.
|
|
8250
8072
|
*/
|
|
8251
8073
|
deriveSessionSummary(events) {
|
|
8252
|
-
if (events.length < 3)
|
|
8253
|
-
|
|
8254
|
-
if (events.some((event) => event.eventType === "session_summary"))
|
|
8255
|
-
return null;
|
|
8074
|
+
if (events.length < 3) return null;
|
|
8075
|
+
if (events.some((event) => event.eventType === "session_summary")) return null;
|
|
8256
8076
|
const prompts = events.filter((event) => event.eventType === "user_prompt");
|
|
8257
8077
|
const toolObservations = events.filter((event) => event.eventType === "tool_observation");
|
|
8258
8078
|
const toolNames = Array.from(new Set(
|
|
@@ -8400,8 +8220,7 @@ var MemoryIngestService = class {
|
|
|
8400
8220
|
await this.initialize();
|
|
8401
8221
|
const events = await this.eventStore.getSessionEvents(sessionId);
|
|
8402
8222
|
const summary = this.summaryDeriver.deriveSessionSummary(events);
|
|
8403
|
-
if (!summary)
|
|
8404
|
-
return;
|
|
8223
|
+
if (!summary) return;
|
|
8405
8224
|
await this.storeSessionSummary(sessionId, summary.text, summary.metadata);
|
|
8406
8225
|
}
|
|
8407
8226
|
async storeToolObservation(sessionId, payload) {
|
|
@@ -8469,10 +8288,8 @@ var MemoryIngestService = class {
|
|
|
8469
8288
|
}
|
|
8470
8289
|
}
|
|
8471
8290
|
async runPerspectiveDeriver(input, eventId, operation) {
|
|
8472
|
-
if (!this.perspectiveDeriver)
|
|
8473
|
-
|
|
8474
|
-
if (operation !== "user_prompt" && operation !== "agent_response")
|
|
8475
|
-
return;
|
|
8291
|
+
if (!this.perspectiveDeriver) return;
|
|
8292
|
+
if (operation !== "user_prompt" && operation !== "agent_response") return;
|
|
8476
8293
|
const event = {
|
|
8477
8294
|
id: eventId,
|
|
8478
8295
|
eventType: input.eventType,
|
|
@@ -8542,11 +8359,13 @@ var MemoryQueryService = class {
|
|
|
8542
8359
|
this.queryStore = queryStore;
|
|
8543
8360
|
this.deps = deps;
|
|
8544
8361
|
}
|
|
8362
|
+
initialize;
|
|
8363
|
+
queryStore;
|
|
8364
|
+
deps;
|
|
8545
8365
|
async keywordSearch(query, options) {
|
|
8546
8366
|
await this.initialize();
|
|
8547
8367
|
const results = await this.queryStore.keywordSearch(query, options?.topK ?? 10);
|
|
8548
|
-
if (results.length === 0)
|
|
8549
|
-
return [];
|
|
8368
|
+
if (results.length === 0) return [];
|
|
8550
8369
|
const maxRank = Math.min(...results.map((r) => r.rank), -1e-3);
|
|
8551
8370
|
const minRank = Math.max(...results.map((r) => r.rank), -1e3);
|
|
8552
8371
|
const rankRange = maxRank - minRank || 1;
|
|
@@ -8641,6 +8460,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
|
|
|
8641
8460
|
/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
|
|
8642
8461
|
/<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
|
|
8643
8462
|
];
|
|
8463
|
+
var LOW_SIGNAL_CONTEXT_PATTERNS = [
|
|
8464
|
+
/<environment_context\b[\s\S]*<\/environment_context>/i,
|
|
8465
|
+
/<turn_aborted>/i,
|
|
8466
|
+
/^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
|
|
8467
|
+
/^\s*(?:understood[,\s.]*)?(?:stopping|stopped|pausing|paused)\s+here\b[\s\S]{0,180}\blet\s+me\s+know\s+when\s+you(?:'d|\s+would)?\s+like\s+to\s+continue\b/i,
|
|
8468
|
+
/^\s*\[?CONTEXT\s+COMPACTION\s*[—-]\s*REFERENCE\s+ONLY\]?\b[\s\S]{0,600}\b(?:earlier\s+turns\s+were\s+compacted|handoff\s+from\s+a\s+previous\s+context\s+window|active\s+task)\b/i,
|
|
8469
|
+
/^\s*Summary\s+generation\s+was\s+unavailable\.\s*\d+\s+message\(s\)\s+were\s+removed\s+to\s+free\s+context\s+space\b/i,
|
|
8470
|
+
/^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
|
|
8471
|
+
/^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
|
|
8472
|
+
/^➜\s+\S+\s+git:\([^)]*\)\s+/i,
|
|
8473
|
+
/^\$\s+\S+/i
|
|
8474
|
+
];
|
|
8644
8475
|
var CONTINUATION_QUERY_PATTERNS = [
|
|
8645
8476
|
/^\s*(?:continue|resume|next|what(?:'s| is)? next|next\s+(?:step|task|action)|recommended\s+(?:next\s+)?(?:step|task|action)|what should (?:we|i) do next)\??\s*$/i,
|
|
8646
8477
|
/^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
|
|
@@ -8652,7 +8483,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
|
|
|
8652
8483
|
var CURRENT_STATE_QUERY_PATTERNS = [
|
|
8653
8484
|
/\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
|
|
8654
8485
|
/\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
|
|
8655
|
-
/\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|
|
|
8486
|
+
/\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
|
|
8656
8487
|
/(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
|
|
8657
8488
|
];
|
|
8658
8489
|
var STALE_CONTENT_PATTERNS = [
|
|
@@ -8792,55 +8623,67 @@ var LOW_INFORMATION_QUERY_TERMS = /* @__PURE__ */ new Set([
|
|
|
8792
8623
|
]);
|
|
8793
8624
|
function isCommandArtifactQuery(query) {
|
|
8794
8625
|
const trimmed = query.trim();
|
|
8795
|
-
if (!trimmed)
|
|
8796
|
-
return false;
|
|
8626
|
+
if (!trimmed) return false;
|
|
8797
8627
|
const normalized = trimmed.toLowerCase();
|
|
8798
|
-
if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr"))
|
|
8799
|
-
|
|
8800
|
-
if (normalized.includes("command-name") || normalized.includes("command-message"))
|
|
8801
|
-
return true;
|
|
8628
|
+
if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
|
|
8629
|
+
if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
|
|
8802
8630
|
return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
8803
8631
|
}
|
|
8632
|
+
function isCommandArtifactContent(content) {
|
|
8633
|
+
const trimmed = content.trim();
|
|
8634
|
+
if (!trimmed) return false;
|
|
8635
|
+
const normalized = trimmed.toLowerCase();
|
|
8636
|
+
if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
|
|
8637
|
+
if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
|
|
8638
|
+
return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
8639
|
+
}
|
|
8640
|
+
function isLowSignalContextContent(content) {
|
|
8641
|
+
const trimmed = content.trim();
|
|
8642
|
+
if (!trimmed) return true;
|
|
8643
|
+
if (isCommandArtifactContent(trimmed)) return true;
|
|
8644
|
+
if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
|
|
8645
|
+
return false;
|
|
8646
|
+
}
|
|
8804
8647
|
function isGenericContinuationQuery(query) {
|
|
8805
8648
|
const trimmed = query.trim();
|
|
8806
|
-
if (!trimmed)
|
|
8807
|
-
|
|
8808
|
-
if (
|
|
8809
|
-
return false;
|
|
8810
|
-
if (extractTechnicalQueryTerms(trimmed).length > 0)
|
|
8811
|
-
return false;
|
|
8649
|
+
if (!trimmed) return false;
|
|
8650
|
+
if (!CONTINUATION_QUERY_PATTERNS.some((pattern) => pattern.test(trimmed))) return false;
|
|
8651
|
+
if (extractTechnicalQueryTerms(trimmed).length > 0) return false;
|
|
8812
8652
|
const tokens = trimmed.match(/[A-Za-z0-9가-힣#._/-]+/g) ?? [];
|
|
8813
|
-
if (tokens.length > 10)
|
|
8814
|
-
return false;
|
|
8653
|
+
if (tokens.length > 10) return false;
|
|
8815
8654
|
return !/[A-Za-z0-9_-]+\.[A-Za-z0-9]+/.test(trimmed) && !/(?:^|\s)(?:feat|fix|chore|refactor|docs)\/[A-Za-z0-9._-]+/.test(trimmed) && !/[A-Za-z]:?[\\/]|\/Users\/|\.\/|\.\.\//.test(trimmed);
|
|
8816
8655
|
}
|
|
8817
8656
|
function isShortRepairFollowUpQuery(query) {
|
|
8818
8657
|
const trimmed = query.trim();
|
|
8819
|
-
if (!trimmed)
|
|
8820
|
-
|
|
8821
|
-
if (extractTechnicalQueryTerms(trimmed).length > 0)
|
|
8822
|
-
return false;
|
|
8658
|
+
if (!trimmed) return false;
|
|
8659
|
+
if (extractTechnicalQueryTerms(trimmed).length > 0) return false;
|
|
8823
8660
|
const tokens = trimmed.match(/[A-Za-z0-9가-힣#._/-]+/g) ?? [];
|
|
8824
|
-
if (tokens.length > 8)
|
|
8825
|
-
return false;
|
|
8661
|
+
if (tokens.length > 8) return false;
|
|
8826
8662
|
return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
8827
8663
|
}
|
|
8664
|
+
function isLowConfidenceContextFallbackQuery(query) {
|
|
8665
|
+
const trimmed = query.trim();
|
|
8666
|
+
if (!trimmed) return false;
|
|
8667
|
+
if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
|
|
8668
|
+
const terms = new Set(tokenizeQualityText(trimmed));
|
|
8669
|
+
if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
|
|
8670
|
+
const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
|
|
8671
|
+
const hasValidationGateRecall = terms.has("validation") && (terms.has("gate") || terms.has("check")) && (terms.has("run") || terms.has("before") || terms.has("commit") || terms.has("committing") || terms.has("change"));
|
|
8672
|
+
return hasContinuationRecall || hasValidationGateRecall;
|
|
8673
|
+
}
|
|
8828
8674
|
function isCurrentStateQuery(query) {
|
|
8829
8675
|
const trimmed = query.trim();
|
|
8830
|
-
if (!trimmed)
|
|
8831
|
-
return false;
|
|
8676
|
+
if (!trimmed) return false;
|
|
8832
8677
|
return CURRENT_STATE_QUERY_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
8833
8678
|
}
|
|
8834
8679
|
function isStaleOrSupersededContent(content) {
|
|
8835
8680
|
const trimmed = content.trim();
|
|
8836
|
-
if (!trimmed)
|
|
8837
|
-
return false;
|
|
8681
|
+
if (!trimmed) return false;
|
|
8838
8682
|
return STALE_CONTENT_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
8839
8683
|
}
|
|
8840
8684
|
function buildRetrievalQualityQuery(query) {
|
|
8841
8685
|
const trimmed = query.trim();
|
|
8842
|
-
if (!trimmed)
|
|
8843
|
-
return query;
|
|
8686
|
+
if (!trimmed) return query;
|
|
8844
8687
|
if (isRetrievalPrivacyDecisionQuery(trimmed)) {
|
|
8845
8688
|
return `${trimmed} ${RETRIEVAL_PRIVACY_DECISION_EXPANSION}`;
|
|
8846
8689
|
}
|
|
@@ -8854,12 +8697,10 @@ function buildRetrievalQualityQuery(query) {
|
|
|
8854
8697
|
}
|
|
8855
8698
|
function isRetrievalPrivacyDecisionQuery(query) {
|
|
8856
8699
|
const trimmed = query.trim();
|
|
8857
|
-
if (!trimmed)
|
|
8858
|
-
return false;
|
|
8700
|
+
if (!trimmed) return false;
|
|
8859
8701
|
const terms = new Set(tokenizeQualityText(trimmed));
|
|
8860
8702
|
const hasDecisionSignal = hasAnyTerm(terms, DECISION_RECALL_TERMS) || /(?:결정|정책|원칙)/i.test(trimmed);
|
|
8861
|
-
if (!hasDecisionSignal)
|
|
8862
|
-
return false;
|
|
8703
|
+
if (!hasDecisionSignal) return false;
|
|
8863
8704
|
const hasRawQuerySignal = terms.has("raw") && terms.has("query");
|
|
8864
8705
|
const hasPrivacySignal = terms.has("privacy") || terms.has("expose") || terms.has("redacted");
|
|
8865
8706
|
const hasRetrievalSurface = hasAnyTerm(terms, RETRIEVAL_PRIVACY_SURFACE_TERMS) || terms.has("api") && terms.has("query");
|
|
@@ -8872,16 +8713,14 @@ function extractTechnicalQueryTerms(query) {
|
|
|
8872
8713
|
const matches = query.match(/[A-Za-z][A-Za-z0-9_.:-]{2,}/g) ?? [];
|
|
8873
8714
|
const terms = matches.filter((term) => {
|
|
8874
8715
|
const lower = term.toLowerCase();
|
|
8875
|
-
if (GENERIC_TECHNICAL_TERMS.has(lower))
|
|
8876
|
-
return false;
|
|
8716
|
+
if (GENERIC_TECHNICAL_TERMS.has(lower)) return false;
|
|
8877
8717
|
return /[._:-]/.test(term) || /[a-z][A-Z]/.test(term) || /[A-Z]{2,}/.test(term) || /\d/.test(term);
|
|
8878
8718
|
});
|
|
8879
8719
|
return Array.from(new Set(terms.map((term) => term.toLowerCase())));
|
|
8880
8720
|
}
|
|
8881
8721
|
function hasTechnicalTermOverlap(query, content) {
|
|
8882
8722
|
const terms = extractTechnicalQueryTerms(query);
|
|
8883
|
-
if (terms.length === 0)
|
|
8884
|
-
return true;
|
|
8723
|
+
if (terms.length === 0) return true;
|
|
8885
8724
|
const normalizedContent = content.toLowerCase();
|
|
8886
8725
|
return terms.some((term) => normalizedContent.includes(term));
|
|
8887
8726
|
}
|
|
@@ -8897,15 +8736,12 @@ function hasDiscriminativeTermOverlap(query, content) {
|
|
|
8897
8736
|
return topicTerms.some((term) => contentTerms.has(term));
|
|
8898
8737
|
}
|
|
8899
8738
|
}
|
|
8900
|
-
if (queryTerms.length < 3)
|
|
8901
|
-
return true;
|
|
8739
|
+
if (queryTerms.length < 3) return true;
|
|
8902
8740
|
const requiredHits = queryTerms.length >= 3 ? 2 : 1;
|
|
8903
8741
|
let hits = 0;
|
|
8904
8742
|
for (const term of queryTerms) {
|
|
8905
|
-
if (contentTerms.has(term))
|
|
8906
|
-
|
|
8907
|
-
if (hits >= requiredHits)
|
|
8908
|
-
return true;
|
|
8743
|
+
if (contentTerms.has(term)) hits += 1;
|
|
8744
|
+
if (hits >= requiredHits) return true;
|
|
8909
8745
|
}
|
|
8910
8746
|
return false;
|
|
8911
8747
|
}
|
|
@@ -8915,17 +8751,14 @@ function shouldApplyTechnicalGuard(query) {
|
|
|
8915
8751
|
function hasAnyTerm(terms, expectedTerms) {
|
|
8916
8752
|
let found = false;
|
|
8917
8753
|
expectedTerms.forEach((term) => {
|
|
8918
|
-
if (terms.has(term))
|
|
8919
|
-
found = true;
|
|
8754
|
+
if (terms.has(term)) found = true;
|
|
8920
8755
|
});
|
|
8921
8756
|
return found;
|
|
8922
8757
|
}
|
|
8923
8758
|
function shouldRequireDecisionTopicOverlap(query) {
|
|
8924
|
-
if (isRetrievalPrivacyDecisionQuery(query))
|
|
8925
|
-
return false;
|
|
8759
|
+
if (isRetrievalPrivacyDecisionQuery(query)) return false;
|
|
8926
8760
|
const trimmed = query.trim();
|
|
8927
|
-
if (!trimmed)
|
|
8928
|
-
return false;
|
|
8761
|
+
if (!trimmed) return false;
|
|
8929
8762
|
const terms = new Set(tokenizeQualityText(trimmed));
|
|
8930
8763
|
return hasAnyTerm(terms, DECISION_RECALL_TERMS) || /(?:결정|정책|원칙)/i.test(trimmed);
|
|
8931
8764
|
}
|
|
@@ -8933,12 +8766,9 @@ function extractDiscriminativeQueryTerms(query) {
|
|
|
8933
8766
|
const seen = /* @__PURE__ */ new Set();
|
|
8934
8767
|
const terms = [];
|
|
8935
8768
|
for (const token of tokenizeQualityText(query)) {
|
|
8936
|
-
if (LOW_INFORMATION_QUERY_TERMS.has(token))
|
|
8937
|
-
|
|
8938
|
-
if (
|
|
8939
|
-
continue;
|
|
8940
|
-
if (seen.has(token))
|
|
8941
|
-
continue;
|
|
8769
|
+
if (LOW_INFORMATION_QUERY_TERMS.has(token)) continue;
|
|
8770
|
+
if (GENERIC_TECHNICAL_TERMS.has(token)) continue;
|
|
8771
|
+
if (seen.has(token)) continue;
|
|
8942
8772
|
seen.add(token);
|
|
8943
8773
|
terms.push(token);
|
|
8944
8774
|
}
|
|
@@ -8953,14 +8783,10 @@ function tokenizeQualityText(text) {
|
|
|
8953
8783
|
return text.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().replace(/[^A-Za-z0-9가-힣\s_.:-]/g, " ").split(/\s+/).flatMap((token) => token.split(/(?=[._:-])|(?<=[._:-])/g)).map((token) => normalizeQualityToken(token.replace(/^[._:-]+|[._:-]+$/g, ""))).filter((token) => token.length >= 2);
|
|
8954
8784
|
}
|
|
8955
8785
|
function normalizeQualityToken(token) {
|
|
8956
|
-
if (token === "apis")
|
|
8957
|
-
|
|
8958
|
-
if (token
|
|
8959
|
-
|
|
8960
|
-
if (LOW_INFORMATION_QUERY_TERMS.has(token) || GENERIC_TECHNICAL_TERMS.has(token))
|
|
8961
|
-
return token;
|
|
8962
|
-
if (token.length > 4 && token.endsWith("ies"))
|
|
8963
|
-
return `${token.slice(0, -3)}y`;
|
|
8786
|
+
if (token === "apis") return "api";
|
|
8787
|
+
if (token === "ids") return "id";
|
|
8788
|
+
if (LOW_INFORMATION_QUERY_TERMS.has(token) || GENERIC_TECHNICAL_TERMS.has(token)) return token;
|
|
8789
|
+
if (token.length > 4 && token.endsWith("ies")) return `${token.slice(0, -3)}y`;
|
|
8964
8790
|
if (token.length > 3 && token.endsWith("s") && !token.endsWith("ss") && !token.endsWith("us") && !token.endsWith("is")) {
|
|
8965
8791
|
return token.slice(0, -1);
|
|
8966
8792
|
}
|
|
@@ -9112,7 +8938,14 @@ var Retriever = class {
|
|
|
9112
8938
|
};
|
|
9113
8939
|
fallbackTrace.push("fallback:summary");
|
|
9114
8940
|
}
|
|
9115
|
-
const
|
|
8941
|
+
const selectedResults = current.results.slice(0, opts.topK).filter((result) => {
|
|
8942
|
+
if (current.matchResult.confidence !== "none") return true;
|
|
8943
|
+
if (isLowConfidenceContextFallbackQuery(query)) {
|
|
8944
|
+
return (result.semanticScore ?? result.score) >= 0.5 || result.score >= 0.5;
|
|
8945
|
+
}
|
|
8946
|
+
return (result.semanticScore ?? result.score) >= 0.62 || result.score >= 0.62;
|
|
8947
|
+
});
|
|
8948
|
+
const memories = await this.enrichResults(selectedResults, opts, query);
|
|
9116
8949
|
const context = this.buildContext(memories, opts.maxTokens);
|
|
9117
8950
|
return {
|
|
9118
8951
|
memories,
|
|
@@ -9120,7 +8953,7 @@ var Retriever = class {
|
|
|
9120
8953
|
totalTokens: this.estimateTokens(context),
|
|
9121
8954
|
context,
|
|
9122
8955
|
fallbackTrace,
|
|
9123
|
-
selectedDebug:
|
|
8956
|
+
selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
|
|
9124
8957
|
candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
|
|
9125
8958
|
rawQueryText: current.queryRewriteKind ? query : void 0,
|
|
9126
8959
|
effectiveQueryText: current.effectiveQueryText,
|
|
@@ -9142,8 +8975,7 @@ var Retriever = class {
|
|
|
9142
8975
|
const sharedMemories = [];
|
|
9143
8976
|
for (const result of sharedVectorResults) {
|
|
9144
8977
|
const entry = await this.sharedStore.get(result.entryId);
|
|
9145
|
-
if (!entry)
|
|
9146
|
-
continue;
|
|
8978
|
+
if (!entry) continue;
|
|
9147
8979
|
if (!options.projectHash || entry.sourceProjectHash !== options.projectHash) {
|
|
9148
8980
|
sharedMemories.push(entry);
|
|
9149
8981
|
await this.sharedStore.recordUsage(entry.entryId);
|
|
@@ -9216,6 +9048,7 @@ var Retriever = class {
|
|
|
9216
9048
|
if (isCurrentStateQuery(options.query)) {
|
|
9217
9049
|
filtered = filtered.filter((result) => !isStaleOrSupersededContent(result.content));
|
|
9218
9050
|
}
|
|
9051
|
+
filtered = filtered.filter((result) => !isLowSignalContextContent(result.content));
|
|
9219
9052
|
filtered = filtered.filter(
|
|
9220
9053
|
(result) => this.isGraphPathResult(result) || hasDiscriminativeTermOverlap(options.query, result.content)
|
|
9221
9054
|
);
|
|
@@ -9224,18 +9057,15 @@ var Retriever = class {
|
|
|
9224
9057
|
(result) => this.isGraphPathResult(result) || hasTechnicalTermOverlap(options.query, result.content)
|
|
9225
9058
|
);
|
|
9226
9059
|
}
|
|
9227
|
-
if (filtered.length <= 2)
|
|
9228
|
-
return filtered;
|
|
9060
|
+
if (filtered.length <= 2) return filtered;
|
|
9229
9061
|
const topScore = filtered[0].score;
|
|
9230
|
-
if (topScore < 0.8)
|
|
9231
|
-
return filtered;
|
|
9062
|
+
if (topScore < 0.8) return filtered;
|
|
9232
9063
|
const cliffThreshold = Math.max(options.minScore, topScore - 0.25);
|
|
9233
9064
|
return filtered.filter((result) => result.score >= cliffThreshold);
|
|
9234
9065
|
}
|
|
9235
9066
|
mergeResults(primary, secondary, limit) {
|
|
9236
9067
|
const byId = /* @__PURE__ */ new Map();
|
|
9237
|
-
for (const row of primary)
|
|
9238
|
-
byId.set(row.eventId, row);
|
|
9068
|
+
for (const row of primary) byId.set(row.eventId, row);
|
|
9239
9069
|
for (const row of secondary) {
|
|
9240
9070
|
const prev = byId.get(row.eventId);
|
|
9241
9071
|
if (!prev || row.score > prev.score) {
|
|
@@ -9246,23 +9076,19 @@ var Retriever = class {
|
|
|
9246
9076
|
}
|
|
9247
9077
|
async expandGraphHops(seeds, opts) {
|
|
9248
9078
|
const byId = /* @__PURE__ */ new Map();
|
|
9249
|
-
for (const s of seeds)
|
|
9250
|
-
byId.set(s.eventId, s);
|
|
9079
|
+
for (const s of seeds) byId.set(s.eventId, s);
|
|
9251
9080
|
let frontier = seeds.map((s) => ({ row: s, hop: 0 }));
|
|
9252
9081
|
for (let hop = 1; hop <= opts.maxHops; hop += 1) {
|
|
9253
9082
|
const next = [];
|
|
9254
9083
|
for (const f of frontier) {
|
|
9255
9084
|
const ev = await this.eventStore.getEvent(f.row.eventId);
|
|
9256
|
-
if (!ev)
|
|
9257
|
-
continue;
|
|
9085
|
+
if (!ev) continue;
|
|
9258
9086
|
const rel = ev.metadata?.relatedEventIds ?? [];
|
|
9259
9087
|
const relatedIds = Array.isArray(rel) ? rel.filter((x) => typeof x === "string") : [];
|
|
9260
9088
|
for (const rid of relatedIds) {
|
|
9261
|
-
if (byId.has(rid))
|
|
9262
|
-
continue;
|
|
9089
|
+
if (byId.has(rid)) continue;
|
|
9263
9090
|
const target = await this.eventStore.getEvent(rid);
|
|
9264
|
-
if (!target)
|
|
9265
|
-
continue;
|
|
9091
|
+
if (!target) continue;
|
|
9266
9092
|
const score = Math.max(0, f.row.score - opts.hopPenalty * hop);
|
|
9267
9093
|
const row = {
|
|
9268
9094
|
id: `hop-${hop}-${rid}`,
|
|
@@ -9276,15 +9102,12 @@ var Retriever = class {
|
|
|
9276
9102
|
};
|
|
9277
9103
|
byId.set(row.eventId, row);
|
|
9278
9104
|
next.push({ row, hop });
|
|
9279
|
-
if (byId.size >= opts.limit)
|
|
9280
|
-
break;
|
|
9105
|
+
if (byId.size >= opts.limit) break;
|
|
9281
9106
|
}
|
|
9282
|
-
if (byId.size >= opts.limit)
|
|
9283
|
-
break;
|
|
9107
|
+
if (byId.size >= opts.limit) break;
|
|
9284
9108
|
}
|
|
9285
9109
|
frontier = next;
|
|
9286
|
-
if (frontier.length === 0 || byId.size >= opts.limit)
|
|
9287
|
-
break;
|
|
9110
|
+
if (frontier.length === 0 || byId.size >= opts.limit) break;
|
|
9288
9111
|
}
|
|
9289
9112
|
if (opts.queryGraphEnabled) {
|
|
9290
9113
|
await this.expandQueryGraphPaths(opts.query, byId, opts);
|
|
@@ -9292,8 +9115,7 @@ var Retriever = class {
|
|
|
9292
9115
|
return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
|
|
9293
9116
|
}
|
|
9294
9117
|
async expandQueryGraphPaths(query, byId, opts) {
|
|
9295
|
-
if (!query.trim() || !this.eventStore.getDatabase)
|
|
9296
|
-
return;
|
|
9118
|
+
if (!query.trim() || !this.eventStore.getDatabase) return;
|
|
9297
9119
|
try {
|
|
9298
9120
|
const db = this.eventStore.getDatabase();
|
|
9299
9121
|
const extraction = new QueryEntityExtractor(db).extract(query, {
|
|
@@ -9302,8 +9124,7 @@ var Retriever = class {
|
|
|
9302
9124
|
});
|
|
9303
9125
|
const startCandidates = extraction.candidates.filter((candidate) => candidate.entityId).slice(0, 8);
|
|
9304
9126
|
const startNodes = uniqueEntityStartNodes(startCandidates);
|
|
9305
|
-
if (startNodes.length === 0)
|
|
9306
|
-
return;
|
|
9127
|
+
if (startNodes.length === 0) return;
|
|
9307
9128
|
const expansion = new GraphPathService(db).expand({
|
|
9308
9129
|
startNodes: startNodes.map((node) => ({ type: "entity", id: node.entityId })),
|
|
9309
9130
|
maxHops: opts.maxHops,
|
|
@@ -9312,11 +9133,9 @@ var Retriever = class {
|
|
|
9312
9133
|
});
|
|
9313
9134
|
const titleByEntityId = new Map(startNodes.map((node) => [node.entityId, node.title]));
|
|
9314
9135
|
for (const path14 of expansion.paths) {
|
|
9315
|
-
if (path14.target.type !== "event")
|
|
9316
|
-
continue;
|
|
9136
|
+
if (path14.target.type !== "event") continue;
|
|
9317
9137
|
const target = await this.eventStore.getEvent(path14.target.id);
|
|
9318
|
-
if (!target)
|
|
9319
|
-
continue;
|
|
9138
|
+
if (!target) continue;
|
|
9320
9139
|
const graphPath = toRetrievalGraphPathDebug(path14, titleByEntityId);
|
|
9321
9140
|
const score = graphPathScore(path14, opts.hopPenalty);
|
|
9322
9141
|
const existing = byId.get(target.id);
|
|
@@ -9342,17 +9161,14 @@ var Retriever = class {
|
|
|
9342
9161
|
lanes: mergeRetrievalLanes(existing?.lanes ?? [], [graphLane])
|
|
9343
9162
|
};
|
|
9344
9163
|
byId.set(row.eventId, row);
|
|
9345
|
-
if (byId.size >= opts.limit)
|
|
9346
|
-
break;
|
|
9164
|
+
if (byId.size >= opts.limit) break;
|
|
9347
9165
|
}
|
|
9348
9166
|
} catch {
|
|
9349
9167
|
}
|
|
9350
9168
|
}
|
|
9351
9169
|
shouldFallback(matchResult, results) {
|
|
9352
|
-
if (results.length === 0)
|
|
9353
|
-
|
|
9354
|
-
if (matchResult.confidence === "none")
|
|
9355
|
-
return true;
|
|
9170
|
+
if (results.length === 0) return true;
|
|
9171
|
+
if (matchResult.confidence === "none") return true;
|
|
9356
9172
|
return false;
|
|
9357
9173
|
}
|
|
9358
9174
|
async buildSummaryFallback(query, topK) {
|
|
@@ -9457,29 +9273,21 @@ var Retriever = class {
|
|
|
9457
9273
|
(value) => typeof value === "string" && value.length > 0
|
|
9458
9274
|
)
|
|
9459
9275
|
);
|
|
9460
|
-
if (!scope && projectScopeMode === "global" && facetFilters === null)
|
|
9461
|
-
return results;
|
|
9276
|
+
if (!scope && projectScopeMode === "global" && facetFilters === null) return results;
|
|
9462
9277
|
const normalizedIncludes = (scope?.contentIncludes || []).map((s) => s.toLowerCase());
|
|
9463
9278
|
const filtered = [];
|
|
9464
9279
|
for (const result of results) {
|
|
9465
|
-
if (scope?.sessionId && result.sessionId !== scope.sessionId)
|
|
9466
|
-
|
|
9467
|
-
if (scope?.
|
|
9468
|
-
continue;
|
|
9469
|
-
if (scope?.eventTypes && scope.eventTypes.length > 0 && !scope.eventTypes.includes(result.eventType))
|
|
9470
|
-
continue;
|
|
9280
|
+
if (scope?.sessionId && result.sessionId !== scope.sessionId) continue;
|
|
9281
|
+
if (scope?.sessionIdPrefix && !result.sessionId.startsWith(scope.sessionIdPrefix)) continue;
|
|
9282
|
+
if (scope?.eventTypes && scope.eventTypes.length > 0 && !scope.eventTypes.includes(result.eventType)) continue;
|
|
9471
9283
|
const event = await this.eventStore.getEvent(result.eventId);
|
|
9472
|
-
if (!event)
|
|
9473
|
-
|
|
9474
|
-
if (scope?.canonicalKeyPrefix && !event.canonicalKey.startsWith(scope.canonicalKeyPrefix))
|
|
9475
|
-
continue;
|
|
9284
|
+
if (!event) continue;
|
|
9285
|
+
if (scope?.canonicalKeyPrefix && !event.canonicalKey.startsWith(scope.canonicalKeyPrefix)) continue;
|
|
9476
9286
|
if (normalizedIncludes.length > 0) {
|
|
9477
9287
|
const lc = event.content.toLowerCase();
|
|
9478
|
-
if (!normalizedIncludes.some((needle) => lc.includes(needle)))
|
|
9479
|
-
continue;
|
|
9288
|
+
if (!normalizedIncludes.some((needle) => lc.includes(needle))) continue;
|
|
9480
9289
|
}
|
|
9481
|
-
if (scope?.metadata && !this.matchesMetadataScope(event.metadata, scope.metadata))
|
|
9482
|
-
continue;
|
|
9290
|
+
if (scope?.metadata && !this.matchesMetadataScope(event.metadata, scope.metadata)) continue;
|
|
9483
9291
|
const projectHash = this.extractProjectHash(event.metadata);
|
|
9484
9292
|
filtered.push({ result, projectHash });
|
|
9485
9293
|
}
|
|
@@ -9496,27 +9304,21 @@ var Retriever = class {
|
|
|
9496
9304
|
});
|
|
9497
9305
|
}
|
|
9498
9306
|
normalizeFacetFilters(facets) {
|
|
9499
|
-
if (!facets || facets.length === 0)
|
|
9500
|
-
return null;
|
|
9307
|
+
if (!facets || facets.length === 0) return null;
|
|
9501
9308
|
const normalized = [];
|
|
9502
9309
|
for (const facet of facets) {
|
|
9503
9310
|
const parsedDimension = FacetDimensionSchema.safeParse(facet.dimension);
|
|
9504
9311
|
const value = typeof facet.value === "string" ? facet.value.trim() : "";
|
|
9505
|
-
if (!parsedDimension.success || !value)
|
|
9506
|
-
return [];
|
|
9312
|
+
if (!parsedDimension.success || !value) return [];
|
|
9507
9313
|
normalized.push({ dimension: parsedDimension.data, value });
|
|
9508
9314
|
}
|
|
9509
9315
|
return normalized;
|
|
9510
9316
|
}
|
|
9511
9317
|
async applyFacetFilters(results, options) {
|
|
9512
|
-
if (options.facets === null)
|
|
9513
|
-
|
|
9514
|
-
if (options.
|
|
9515
|
-
|
|
9516
|
-
if (!options.projectHash)
|
|
9517
|
-
return [];
|
|
9518
|
-
if (!this.eventStore.getDatabase)
|
|
9519
|
-
return [];
|
|
9318
|
+
if (options.facets === null) return results;
|
|
9319
|
+
if (options.facets.length === 0) return [];
|
|
9320
|
+
if (!options.projectHash) return [];
|
|
9321
|
+
if (!this.eventStore.getDatabase) return [];
|
|
9520
9322
|
const repo = new FacetRepository(this.eventStore.getDatabase());
|
|
9521
9323
|
const filtered = [];
|
|
9522
9324
|
for (const result of results) {
|
|
@@ -9573,14 +9375,11 @@ var Retriever = class {
|
|
|
9573
9375
|
return (result.graphPaths || []).length > 0;
|
|
9574
9376
|
}
|
|
9575
9377
|
extractProjectHash(metadata) {
|
|
9576
|
-
if (!metadata || typeof metadata !== "object")
|
|
9577
|
-
return void 0;
|
|
9378
|
+
if (!metadata || typeof metadata !== "object") return void 0;
|
|
9578
9379
|
const scope = metadata.scope;
|
|
9579
|
-
if (!scope || typeof scope !== "object")
|
|
9580
|
-
return void 0;
|
|
9380
|
+
if (!scope || typeof scope !== "object") return void 0;
|
|
9581
9381
|
const project = scope.project;
|
|
9582
|
-
if (!project || typeof project !== "object")
|
|
9583
|
-
return void 0;
|
|
9382
|
+
if (!project || typeof project !== "object") return void 0;
|
|
9584
9383
|
const hash = project.hash;
|
|
9585
9384
|
return typeof hash === "string" && hash.length > 0 ? hash : void 0;
|
|
9586
9385
|
}
|
|
@@ -9590,52 +9389,48 @@ var Retriever = class {
|
|
|
9590
9389
|
async retrieveRecent(limit = 100) {
|
|
9591
9390
|
return this.eventStore.getRecentEvents(limit);
|
|
9592
9391
|
}
|
|
9593
|
-
async enrichResults(results, options) {
|
|
9392
|
+
async enrichResults(results, options, query) {
|
|
9594
9393
|
const memories = [];
|
|
9595
9394
|
for (const result of results) {
|
|
9596
9395
|
const event = await this.eventStore.getEvent(result.eventId);
|
|
9597
|
-
if (!event)
|
|
9598
|
-
continue;
|
|
9396
|
+
if (!event) continue;
|
|
9599
9397
|
if (this.graduation) {
|
|
9600
9398
|
this.graduation.recordAccess(event.id, options.sessionId || "unknown", result.score);
|
|
9601
9399
|
}
|
|
9602
9400
|
let sessionContext;
|
|
9603
9401
|
if (options.includeSessionContext) {
|
|
9604
|
-
sessionContext = await this.getSessionContext(event.sessionId, event.id);
|
|
9402
|
+
sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
|
|
9605
9403
|
}
|
|
9606
9404
|
memories.push({ event, score: result.score, sessionContext });
|
|
9607
9405
|
}
|
|
9608
9406
|
return memories;
|
|
9609
9407
|
}
|
|
9610
|
-
async getSessionContext(sessionId, eventId) {
|
|
9408
|
+
async getSessionContext(sessionId, eventId, query) {
|
|
9611
9409
|
const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
|
|
9612
9410
|
const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
|
|
9613
|
-
if (eventIndex === -1)
|
|
9614
|
-
return void 0;
|
|
9411
|
+
if (eventIndex === -1) return void 0;
|
|
9615
9412
|
const start = Math.max(0, eventIndex - 1);
|
|
9616
9413
|
const end = Math.min(sessionEvents.length, eventIndex + 2);
|
|
9617
9414
|
const contextEvents = sessionEvents.slice(start, end);
|
|
9618
|
-
if (contextEvents.length <= 1)
|
|
9619
|
-
|
|
9620
|
-
|
|
9415
|
+
if (contextEvents.length <= 1) return void 0;
|
|
9416
|
+
const suppressStaleState = isCurrentStateQuery(query);
|
|
9417
|
+
const contextLines = contextEvents.filter((e) => e.id !== eventId).filter((e) => !isLowSignalContextContent(e.content)).filter((e) => !(suppressStaleState && isStaleOrSupersededContent(e.content))).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`);
|
|
9418
|
+
return contextLines.length > 0 ? contextLines.join("\n") : void 0;
|
|
9621
9419
|
}
|
|
9622
9420
|
buildUnifiedContext(projectResult, sharedMemories) {
|
|
9623
9421
|
let context = projectResult.context;
|
|
9624
|
-
if (sharedMemories.length === 0)
|
|
9625
|
-
return context;
|
|
9422
|
+
if (sharedMemories.length === 0) return context;
|
|
9626
9423
|
context += "\n\n## Cross-Project Knowledge\n\n";
|
|
9627
9424
|
for (const memory of sharedMemories.slice(0, 3)) {
|
|
9628
9425
|
context += `### ${memory.title}
|
|
9629
9426
|
`;
|
|
9630
|
-
if (memory.symptoms.length > 0)
|
|
9631
|
-
context += `**Symptoms:** ${memory.symptoms.join(", ")}
|
|
9427
|
+
if (memory.symptoms.length > 0) context += `**Symptoms:** ${memory.symptoms.join(", ")}
|
|
9632
9428
|
`;
|
|
9633
9429
|
context += `**Root Cause:** ${memory.rootCause}
|
|
9634
9430
|
`;
|
|
9635
9431
|
context += `**Solution:** ${memory.solution}
|
|
9636
9432
|
`;
|
|
9637
|
-
if (memory.technologies && memory.technologies.length > 0)
|
|
9638
|
-
context += `**Technologies:** ${memory.technologies.join(", ")}
|
|
9433
|
+
if (memory.technologies && memory.technologies.length > 0) context += `**Technologies:** ${memory.technologies.join(", ")}
|
|
9639
9434
|
`;
|
|
9640
9435
|
context += `_Confidence: ${(memory.confidence * 100).toFixed(0)}%_
|
|
9641
9436
|
|
|
@@ -9649,13 +9444,11 @@ var Retriever = class {
|
|
|
9649
9444
|
for (const memory of memories) {
|
|
9650
9445
|
const memoryText = this.formatMemory(memory);
|
|
9651
9446
|
const memoryTokens = this.estimateTokens(memoryText);
|
|
9652
|
-
if (currentTokens + memoryTokens > maxTokens)
|
|
9653
|
-
break;
|
|
9447
|
+
if (currentTokens + memoryTokens > maxTokens) break;
|
|
9654
9448
|
parts.push(memoryText);
|
|
9655
9449
|
currentTokens += memoryTokens;
|
|
9656
9450
|
}
|
|
9657
|
-
if (parts.length === 0)
|
|
9658
|
-
return "";
|
|
9451
|
+
if (parts.length === 0) return "";
|
|
9659
9452
|
return `## Relevant Memories
|
|
9660
9453
|
|
|
9661
9454
|
${parts.join("\n\n---\n\n")}`;
|
|
@@ -9665,19 +9458,16 @@ ${parts.join("\n\n---\n\n")}`;
|
|
|
9665
9458
|
const date = event.timestamp.toISOString().split("T")[0];
|
|
9666
9459
|
let text = `**${event.eventType}** (${date}, score: ${score.toFixed(2)})
|
|
9667
9460
|
${event.content}`;
|
|
9668
|
-
if (sessionContext)
|
|
9669
|
-
text += `
|
|
9461
|
+
if (sessionContext) text += `
|
|
9670
9462
|
|
|
9671
9463
|
_Context:_ ${sessionContext}`;
|
|
9672
9464
|
return text;
|
|
9673
9465
|
}
|
|
9674
9466
|
matchesMetadataScope(metadata, expected) {
|
|
9675
|
-
if (!metadata)
|
|
9676
|
-
return false;
|
|
9467
|
+
if (!metadata) return false;
|
|
9677
9468
|
return Object.entries(expected).every(([path14, value]) => {
|
|
9678
9469
|
const actual = path14.split(".").reduce((acc, key) => {
|
|
9679
|
-
if (typeof acc !== "object" || acc === null)
|
|
9680
|
-
return void 0;
|
|
9470
|
+
if (typeof acc !== "object" || acc === null) return void 0;
|
|
9681
9471
|
return acc[key];
|
|
9682
9472
|
}, metadata);
|
|
9683
9473
|
return actual === value;
|
|
@@ -9687,27 +9477,20 @@ _Context:_ ${sessionContext}`;
|
|
|
9687
9477
|
return text.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).map((token) => this.normalizeToken(token)).filter((t) => t.length >= 2).slice(0, 64);
|
|
9688
9478
|
}
|
|
9689
9479
|
normalizeToken(token) {
|
|
9690
|
-
if (token === "apis")
|
|
9691
|
-
|
|
9692
|
-
if (token === "
|
|
9693
|
-
|
|
9694
|
-
if (token === "does")
|
|
9695
|
-
return token;
|
|
9696
|
-
if (token.length > 4 && token.endsWith("ies"))
|
|
9697
|
-
return `${token.slice(0, -3)}y`;
|
|
9480
|
+
if (token === "apis") return "api";
|
|
9481
|
+
if (token === "ids") return "id";
|
|
9482
|
+
if (token === "does") return token;
|
|
9483
|
+
if (token.length > 4 && token.endsWith("ies")) return `${token.slice(0, -3)}y`;
|
|
9698
9484
|
if (token.length > 3 && token.endsWith("s") && !token.endsWith("ss") && !token.endsWith("us") && !token.endsWith("is") && !token.endsWith("ps")) {
|
|
9699
9485
|
return token.slice(0, -1);
|
|
9700
9486
|
}
|
|
9701
9487
|
return token;
|
|
9702
9488
|
}
|
|
9703
9489
|
keywordOverlap(a, b) {
|
|
9704
|
-
if (a.length === 0 || b.length === 0)
|
|
9705
|
-
return 0;
|
|
9490
|
+
if (a.length === 0 || b.length === 0) return 0;
|
|
9706
9491
|
const bs = new Set(b);
|
|
9707
9492
|
let hit = 0;
|
|
9708
|
-
for (const t of a)
|
|
9709
|
-
if (bs.has(t))
|
|
9710
|
-
hit += 1;
|
|
9493
|
+
for (const t of a) if (bs.has(t)) hit += 1;
|
|
9711
9494
|
return hit / a.length;
|
|
9712
9495
|
}
|
|
9713
9496
|
estimateTokens(text) {
|
|
@@ -9728,8 +9511,7 @@ function uniqueEntityStartNodes(candidates) {
|
|
|
9728
9511
|
const seen = /* @__PURE__ */ new Set();
|
|
9729
9512
|
const nodes = [];
|
|
9730
9513
|
for (const candidate of candidates) {
|
|
9731
|
-
if (!candidate.entityId || seen.has(candidate.entityId))
|
|
9732
|
-
continue;
|
|
9514
|
+
if (!candidate.entityId || seen.has(candidate.entityId)) continue;
|
|
9733
9515
|
seen.add(candidate.entityId);
|
|
9734
9516
|
nodes.push({ entityId: candidate.entityId, title: candidate.text });
|
|
9735
9517
|
}
|
|
@@ -9753,16 +9535,14 @@ function graphPathScore(path14, hopPenalty) {
|
|
|
9753
9535
|
return Math.max(0.05, base - hopPenalty * Math.max(0, path14.hops - 1));
|
|
9754
9536
|
}
|
|
9755
9537
|
function clampGraphHops(maxHops) {
|
|
9756
|
-
if (!Number.isFinite(maxHops))
|
|
9757
|
-
return 2;
|
|
9538
|
+
if (!Number.isFinite(maxHops)) return 2;
|
|
9758
9539
|
return Math.min(Math.max(0, Math.trunc(maxHops)), 2);
|
|
9759
9540
|
}
|
|
9760
9541
|
function mergeGraphPaths(existing, incoming) {
|
|
9761
9542
|
const byKey = /* @__PURE__ */ new Map();
|
|
9762
9543
|
for (const path14 of [...existing, ...incoming]) {
|
|
9763
9544
|
const key = [path14.startEntityId, path14.targetType, path14.targetId, path14.hops, ...path14.relationPath].join("\0");
|
|
9764
|
-
if (!byKey.has(key))
|
|
9765
|
-
byKey.set(key, path14);
|
|
9545
|
+
if (!byKey.has(key)) byKey.set(key, path14);
|
|
9766
9546
|
}
|
|
9767
9547
|
return [...byKey.values()].sort((a, b) => a.hops - b.hops || compareStable(graphPathSignature(a), graphPathSignature(b))).slice(0, 3);
|
|
9768
9548
|
}
|
|
@@ -9770,10 +9550,8 @@ function graphPathSignature(path14) {
|
|
|
9770
9550
|
return [path14.startEntityId, path14.targetType, path14.targetId, path14.hops, ...path14.relationPath].join("|");
|
|
9771
9551
|
}
|
|
9772
9552
|
function compareStable(a, b) {
|
|
9773
|
-
if (a < b)
|
|
9774
|
-
|
|
9775
|
-
if (a > b)
|
|
9776
|
-
return 1;
|
|
9553
|
+
if (a < b) return -1;
|
|
9554
|
+
if (a > b) return 1;
|
|
9777
9555
|
return 0;
|
|
9778
9556
|
}
|
|
9779
9557
|
function createRetriever(eventStore, vectorStore, embedder, matcher, sharedOptions) {
|
|
@@ -9785,6 +9563,7 @@ var RetrievalAnalyticsService = class {
|
|
|
9785
9563
|
constructor(deps) {
|
|
9786
9564
|
this.deps = deps;
|
|
9787
9565
|
}
|
|
9566
|
+
deps;
|
|
9788
9567
|
async getRetrievalTraceStats() {
|
|
9789
9568
|
await this.deps.initialize();
|
|
9790
9569
|
return this.deps.retrievalStore.getRetrievalTraceStats();
|
|
@@ -9862,6 +9641,7 @@ var RetrievalDisclosureService = class {
|
|
|
9862
9641
|
constructor(deps) {
|
|
9863
9642
|
this.deps = deps;
|
|
9864
9643
|
}
|
|
9644
|
+
deps;
|
|
9865
9645
|
async search(query, options) {
|
|
9866
9646
|
const result = await this.deps.retrievalOrchestrator.retrieveMemories(query, options);
|
|
9867
9647
|
const debugByEventId = this.buildDebugIndex(result);
|
|
@@ -9891,8 +9671,7 @@ var RetrievalDisclosureService = class {
|
|
|
9891
9671
|
return this.expandShared(parsedId.entryId);
|
|
9892
9672
|
}
|
|
9893
9673
|
const targetEvent = await this.deps.eventStore.getEvent(parsedId.eventId);
|
|
9894
|
-
if (!targetEvent)
|
|
9895
|
-
return null;
|
|
9674
|
+
if (!targetEvent) return null;
|
|
9896
9675
|
const windowSize = Math.max(0, options?.windowSize ?? 3);
|
|
9897
9676
|
const sessionEvents = (await this.deps.eventStore.getSessionEvents(targetEvent.sessionId)).slice().sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
9898
9677
|
const targetIndex = sessionEvents.findIndex((event) => event.id === targetEvent.id);
|
|
@@ -9916,8 +9695,7 @@ var RetrievalDisclosureService = class {
|
|
|
9916
9695
|
return this.sourceShared(parsedId.entryId);
|
|
9917
9696
|
}
|
|
9918
9697
|
const rawEvent = await this.deps.eventStore.getEvent(parsedId.eventId);
|
|
9919
|
-
if (!rawEvent)
|
|
9920
|
-
return null;
|
|
9698
|
+
if (!rawEvent) return null;
|
|
9921
9699
|
return {
|
|
9922
9700
|
...this.sourceReferenceForEvent(rawEvent),
|
|
9923
9701
|
rawEvents: [rawEvent],
|
|
@@ -9926,8 +9704,7 @@ var RetrievalDisclosureService = class {
|
|
|
9926
9704
|
}
|
|
9927
9705
|
async expandShared(entryId) {
|
|
9928
9706
|
const entry = await this.deps.sharedStore?.get(entryId);
|
|
9929
|
-
if (!entry)
|
|
9930
|
-
return null;
|
|
9707
|
+
if (!entry) return null;
|
|
9931
9708
|
return {
|
|
9932
9709
|
target: this.sharedToEnvelope(entry),
|
|
9933
9710
|
surroundingFacts: [],
|
|
@@ -9938,8 +9715,7 @@ var RetrievalDisclosureService = class {
|
|
|
9938
9715
|
}
|
|
9939
9716
|
async sourceShared(entryId) {
|
|
9940
9717
|
const entry = await this.deps.sharedStore?.get(entryId);
|
|
9941
|
-
if (!entry)
|
|
9942
|
-
return null;
|
|
9718
|
+
if (!entry) return null;
|
|
9943
9719
|
const sourceReference = this.sourceReferenceForShared(entry);
|
|
9944
9720
|
return {
|
|
9945
9721
|
...sourceReference,
|
|
@@ -10025,38 +9801,25 @@ var RetrievalDisclosureService = class {
|
|
|
10025
9801
|
const reasons = /* @__PURE__ */ new Set();
|
|
10026
9802
|
const usedVector = this.usedVector(result);
|
|
10027
9803
|
const usedKeyword = this.usedKeyword(result);
|
|
10028
|
-
if (usedVector && (debug?.semanticScore ?? 0) > 0)
|
|
10029
|
-
|
|
10030
|
-
if ((debug?.
|
|
10031
|
-
|
|
10032
|
-
if ((debug?.
|
|
10033
|
-
|
|
10034
|
-
if (
|
|
10035
|
-
|
|
10036
|
-
if (
|
|
10037
|
-
reasons.add("entity_overlap");
|
|
10038
|
-
if ((result.fallbackTrace || []).some((step) => step === "fallback:summary"))
|
|
10039
|
-
reasons.add("summary_fallback");
|
|
10040
|
-
if (memory.sessionContext)
|
|
10041
|
-
reasons.add("continuity_link");
|
|
10042
|
-
if (memory.event.eventType === "tool_observation")
|
|
10043
|
-
reasons.add("tool_followup");
|
|
10044
|
-
if (reasons.size === 0)
|
|
10045
|
-
reasons.add(usedVector ? "semantic_match" : "keyword_match");
|
|
9804
|
+
if (usedVector && (debug?.semanticScore ?? 0) > 0) reasons.add("semantic_match");
|
|
9805
|
+
if ((debug?.lexicalScore ?? 0) > 0 || usedKeyword) reasons.add("keyword_match");
|
|
9806
|
+
if ((debug?.recencyScore ?? 0) > 0) reasons.add("recent_relevance");
|
|
9807
|
+
if ((debug?.facetMatches || []).length > 0) reasons.add("facet_match");
|
|
9808
|
+
if ((debug?.graphPaths || []).length > 0) reasons.add("entity_overlap");
|
|
9809
|
+
if ((result.fallbackTrace || []).some((step) => step === "fallback:summary")) reasons.add("summary_fallback");
|
|
9810
|
+
if (memory.sessionContext) reasons.add("continuity_link");
|
|
9811
|
+
if (memory.event.eventType === "tool_observation") reasons.add("tool_followup");
|
|
9812
|
+
if (reasons.size === 0) reasons.add(usedVector ? "semantic_match" : "keyword_match");
|
|
10046
9813
|
return Array.from(reasons);
|
|
10047
9814
|
}
|
|
10048
9815
|
reasonsForContextEvent(event) {
|
|
10049
|
-
if (event.eventType === "tool_observation")
|
|
10050
|
-
|
|
10051
|
-
if (event.eventType === "session_summary")
|
|
10052
|
-
return ["summary_fallback"];
|
|
9816
|
+
if (event.eventType === "tool_observation") return ["tool_followup"];
|
|
9817
|
+
if (event.eventType === "session_summary") return ["summary_fallback"];
|
|
10053
9818
|
return ["continuity_link"];
|
|
10054
9819
|
}
|
|
10055
9820
|
resultTypeForEvent(event) {
|
|
10056
|
-
if (event.eventType === "session_summary")
|
|
10057
|
-
|
|
10058
|
-
if (event.eventType === "tool_observation")
|
|
10059
|
-
return "tool_evidence";
|
|
9821
|
+
if (event.eventType === "session_summary") return "summary";
|
|
9822
|
+
if (event.eventType === "tool_observation") return "tool_evidence";
|
|
10060
9823
|
return "source";
|
|
10061
9824
|
}
|
|
10062
9825
|
sourceReferenceForEvent(event) {
|
|
@@ -10080,21 +9843,15 @@ var RetrievalDisclosureService = class {
|
|
|
10080
9843
|
}
|
|
10081
9844
|
sourceTypeForEvent(event) {
|
|
10082
9845
|
const metadata = event.metadata || {};
|
|
10083
|
-
if (event.eventType === "tool_observation")
|
|
10084
|
-
|
|
10085
|
-
if (typeof metadata.
|
|
10086
|
-
return "transcript";
|
|
10087
|
-
if (typeof metadata.importedFrom === "string")
|
|
10088
|
-
return "imported_history";
|
|
9846
|
+
if (event.eventType === "tool_observation") return "tool_output";
|
|
9847
|
+
if (typeof metadata.transcriptPath === "string") return "transcript";
|
|
9848
|
+
if (typeof metadata.importedFrom === "string") return "imported_history";
|
|
10089
9849
|
return "raw_event";
|
|
10090
9850
|
}
|
|
10091
9851
|
titleForEvent(event) {
|
|
10092
|
-
if (event.eventType === "session_summary")
|
|
10093
|
-
|
|
10094
|
-
if (event.eventType === "
|
|
10095
|
-
return "Tool evidence";
|
|
10096
|
-
if (event.eventType === "agent_response")
|
|
10097
|
-
return "Agent response";
|
|
9852
|
+
if (event.eventType === "session_summary") return "Session summary";
|
|
9853
|
+
if (event.eventType === "tool_observation") return "Tool evidence";
|
|
9854
|
+
if (event.eventType === "agent_response") return "Agent response";
|
|
10098
9855
|
return "User prompt";
|
|
10099
9856
|
}
|
|
10100
9857
|
usedVector(result) {
|
|
@@ -10120,8 +9877,7 @@ var RetrievalDisclosureService = class {
|
|
|
10120
9877
|
}
|
|
10121
9878
|
preview(content, maxLength) {
|
|
10122
9879
|
const normalized = content.replace(/\s+/g, " ").trim();
|
|
10123
|
-
if (normalized.length <= maxLength)
|
|
10124
|
-
return normalized;
|
|
9880
|
+
if (normalized.length <= maxLength) return normalized;
|
|
10125
9881
|
return `${normalized.slice(0, Math.max(0, maxLength - 3))}...`;
|
|
10126
9882
|
}
|
|
10127
9883
|
};
|
|
@@ -10150,6 +9906,7 @@ var RetrievalOrchestrator = class {
|
|
|
10150
9906
|
this.deps = deps;
|
|
10151
9907
|
this.deps.retriever.setQueryRewriter((query) => this.rewriteQueryIntent(query));
|
|
10152
9908
|
}
|
|
9909
|
+
deps;
|
|
10153
9910
|
/**
|
|
10154
9911
|
* Retrieve relevant memories for a query.
|
|
10155
9912
|
*/
|
|
@@ -10231,8 +9988,7 @@ var RetrievalOrchestrator = class {
|
|
|
10231
9988
|
* the heavier retrieval/vector initialization path for prompt telemetry.
|
|
10232
9989
|
*/
|
|
10233
9990
|
async incrementMemoryAccess(eventIds) {
|
|
10234
|
-
if (eventIds.length === 0)
|
|
10235
|
-
return;
|
|
9991
|
+
if (eventIds.length === 0) return;
|
|
10236
9992
|
await this.deps.accessStore.incrementAccessCount(eventIds);
|
|
10237
9993
|
}
|
|
10238
9994
|
/**
|
|
@@ -10245,10 +10001,8 @@ var RetrievalOrchestrator = class {
|
|
|
10245
10001
|
resolveGraphHopOptions(callerOptions) {
|
|
10246
10002
|
const graphExpansion = this.deps.memoryOperationsConfig?.graphExpansion;
|
|
10247
10003
|
const durableOptions = graphExpansion?.enabled === true ? { enabled: true, maxHops: graphExpansion.maxHops } : void 0;
|
|
10248
|
-
if (!callerOptions)
|
|
10249
|
-
|
|
10250
|
-
if (!graphExpansion)
|
|
10251
|
-
return callerOptions;
|
|
10004
|
+
if (!callerOptions) return durableOptions;
|
|
10005
|
+
if (!graphExpansion) return callerOptions;
|
|
10252
10006
|
if (graphExpansion.enabled !== true) {
|
|
10253
10007
|
return {
|
|
10254
10008
|
...callerOptions,
|
|
@@ -10308,12 +10062,10 @@ var RetrievalOrchestrator = class {
|
|
|
10308
10062
|
const lexical = Number(process.env.MEMORY_RERANK_WEIGHT_LEXICAL ?? "");
|
|
10309
10063
|
const recency = Number(process.env.MEMORY_RERANK_WEIGHT_RECENCY ?? "");
|
|
10310
10064
|
const allFinite = [semantic, lexical, recency].every((value) => Number.isFinite(value));
|
|
10311
|
-
if (!allFinite)
|
|
10312
|
-
return void 0;
|
|
10065
|
+
if (!allFinite) return void 0;
|
|
10313
10066
|
const nonNegative = [semantic, lexical, recency].every((value) => value >= 0);
|
|
10314
10067
|
const total = semantic + lexical + recency;
|
|
10315
|
-
if (!nonNegative || total <= 0)
|
|
10316
|
-
return void 0;
|
|
10068
|
+
if (!nonNegative || total <= 0) return void 0;
|
|
10317
10069
|
return {
|
|
10318
10070
|
semantic: semantic / total,
|
|
10319
10071
|
lexical: lexical / total,
|
|
@@ -10322,17 +10074,14 @@ var RetrievalOrchestrator = class {
|
|
|
10322
10074
|
}
|
|
10323
10075
|
async getRerankWeights(adaptive) {
|
|
10324
10076
|
const configured = this.getConfiguredRerankWeights();
|
|
10325
|
-
if (configured)
|
|
10326
|
-
|
|
10327
|
-
if (adaptive)
|
|
10328
|
-
return this.getAdaptiveRerankWeights();
|
|
10077
|
+
if (configured) return configured;
|
|
10078
|
+
if (adaptive) return this.getAdaptiveRerankWeights();
|
|
10329
10079
|
return void 0;
|
|
10330
10080
|
}
|
|
10331
10081
|
async getAdaptiveRerankWeights() {
|
|
10332
10082
|
try {
|
|
10333
10083
|
const stats = await this.deps.traceStore.getHelpfulnessStats();
|
|
10334
|
-
if (stats.totalEvaluated < 20)
|
|
10335
|
-
return void 0;
|
|
10084
|
+
if (stats.totalEvaluated < 20) return void 0;
|
|
10336
10085
|
let semantic = 0.7;
|
|
10337
10086
|
let lexical = 0.2;
|
|
10338
10087
|
let recency = 0.1;
|
|
@@ -10354,11 +10103,9 @@ var RetrievalOrchestrator = class {
|
|
|
10354
10103
|
}
|
|
10355
10104
|
}
|
|
10356
10105
|
async rewriteQueryIntent(query) {
|
|
10357
|
-
if (process.env.MEMORY_INTENT_REWRITE_ENABLED !== "1")
|
|
10358
|
-
return null;
|
|
10106
|
+
if (process.env.MEMORY_INTENT_REWRITE_ENABLED !== "1") return null;
|
|
10359
10107
|
const apiUrl = process.env.COMPANY_STOCK_API_URL || process.env.COMPANY_INT_API_URL;
|
|
10360
|
-
if (!apiUrl)
|
|
10361
|
-
return null;
|
|
10108
|
+
if (!apiUrl) return null;
|
|
10362
10109
|
const controller = new AbortController();
|
|
10363
10110
|
const timeoutMs = Number(process.env.MEMORY_INTENT_REWRITE_TIMEOUT_MS || 5e3);
|
|
10364
10111
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -10384,11 +10131,9 @@ var RetrievalOrchestrator = class {
|
|
|
10384
10131
|
signal: controller.signal
|
|
10385
10132
|
});
|
|
10386
10133
|
const text = (await res.text()).trim();
|
|
10387
|
-
if (!text)
|
|
10388
|
-
return null;
|
|
10134
|
+
if (!text) return null;
|
|
10389
10135
|
const oneLine = text.replace(/^data:\s*/gm, "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).join(" ").slice(0, 240);
|
|
10390
|
-
if (!oneLine || oneLine.toLowerCase() === query.toLowerCase())
|
|
10391
|
-
return null;
|
|
10136
|
+
if (!oneLine || oneLine.toLowerCase() === query.toLowerCase()) return null;
|
|
10392
10137
|
return oneLine;
|
|
10393
10138
|
} catch {
|
|
10394
10139
|
return null;
|
|
@@ -10530,8 +10275,7 @@ function createMemoryEngineServices(options) {
|
|
|
10530
10275
|
};
|
|
10531
10276
|
}
|
|
10532
10277
|
function shouldEnablePerspectiveDeriver(options) {
|
|
10533
|
-
if (options.readOnly)
|
|
10534
|
-
return false;
|
|
10278
|
+
if (options.readOnly) return false;
|
|
10535
10279
|
const perspectiveMemory = options.memoryOperationsConfig?.perspectiveMemory;
|
|
10536
10280
|
return perspectiveMemory?.enabled === true && perspectiveMemory.deriver?.enabled === true;
|
|
10537
10281
|
}
|
|
@@ -10565,6 +10309,9 @@ var GraduationWorker = class {
|
|
|
10565
10309
|
this.graduation = graduation;
|
|
10566
10310
|
this.config = config;
|
|
10567
10311
|
}
|
|
10312
|
+
eventStore;
|
|
10313
|
+
graduation;
|
|
10314
|
+
config;
|
|
10568
10315
|
running = false;
|
|
10569
10316
|
timeout = null;
|
|
10570
10317
|
lastEvaluated = /* @__PURE__ */ new Map();
|
|
@@ -10572,8 +10319,7 @@ var GraduationWorker = class {
|
|
|
10572
10319
|
* Start the graduation worker
|
|
10573
10320
|
*/
|
|
10574
10321
|
start() {
|
|
10575
|
-
if (this.running)
|
|
10576
|
-
return;
|
|
10322
|
+
if (this.running) return;
|
|
10577
10323
|
this.running = true;
|
|
10578
10324
|
this.scheduleNext();
|
|
10579
10325
|
}
|
|
@@ -10603,8 +10349,7 @@ var GraduationWorker = class {
|
|
|
10603
10349
|
* Schedule the next graduation check
|
|
10604
10350
|
*/
|
|
10605
10351
|
scheduleNext() {
|
|
10606
|
-
if (!this.running)
|
|
10607
|
-
return;
|
|
10352
|
+
if (!this.running) return;
|
|
10608
10353
|
this.timeout = setTimeout(
|
|
10609
10354
|
() => this.run(),
|
|
10610
10355
|
this.config.evaluationIntervalMs
|
|
@@ -10614,8 +10359,7 @@ var GraduationWorker = class {
|
|
|
10614
10359
|
* Run graduation evaluation
|
|
10615
10360
|
*/
|
|
10616
10361
|
async run() {
|
|
10617
|
-
if (!this.running)
|
|
10618
|
-
return;
|
|
10362
|
+
if (!this.running) return;
|
|
10619
10363
|
try {
|
|
10620
10364
|
await this.runGraduation();
|
|
10621
10365
|
} catch (error) {
|
|
@@ -10679,10 +10423,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
10679
10423
|
maxRetries: 3
|
|
10680
10424
|
};
|
|
10681
10425
|
function parseJsonArray(value) {
|
|
10682
|
-
if (Array.isArray(value))
|
|
10683
|
-
|
|
10684
|
-
if (typeof value !== "string" || value.trim().length === 0)
|
|
10685
|
-
return [];
|
|
10426
|
+
if (Array.isArray(value)) return value;
|
|
10427
|
+
if (typeof value !== "string" || value.trim().length === 0) return [];
|
|
10686
10428
|
try {
|
|
10687
10429
|
const parsed = JSON.parse(value);
|
|
10688
10430
|
return Array.isArray(parsed) ? parsed : [];
|
|
@@ -10712,8 +10454,7 @@ var VectorWorker = class {
|
|
|
10712
10454
|
* Start the worker polling loop
|
|
10713
10455
|
*/
|
|
10714
10456
|
start() {
|
|
10715
|
-
if (this.running)
|
|
10716
|
-
return;
|
|
10457
|
+
if (this.running) return;
|
|
10717
10458
|
this.running = true;
|
|
10718
10459
|
this.stopping = false;
|
|
10719
10460
|
this.poll();
|
|
@@ -10789,8 +10530,7 @@ var VectorWorker = class {
|
|
|
10789
10530
|
* Poll for new items
|
|
10790
10531
|
*/
|
|
10791
10532
|
async poll() {
|
|
10792
|
-
if (!this.running || this.stopping)
|
|
10793
|
-
return;
|
|
10533
|
+
if (!this.running || this.stopping) return;
|
|
10794
10534
|
try {
|
|
10795
10535
|
await this.processBatch();
|
|
10796
10536
|
} catch (error) {
|
|
@@ -10835,6 +10575,7 @@ var DefaultContentProvider = class {
|
|
|
10835
10575
|
constructor(db) {
|
|
10836
10576
|
this.db = db;
|
|
10837
10577
|
}
|
|
10578
|
+
db;
|
|
10838
10579
|
async getContent(itemKind, itemId) {
|
|
10839
10580
|
switch (itemKind) {
|
|
10840
10581
|
case "entry":
|
|
@@ -10855,8 +10596,7 @@ var DefaultContentProvider = class {
|
|
|
10855
10596
|
`SELECT title, content_json, entry_type FROM entries WHERE entry_id = ?`,
|
|
10856
10597
|
[entryId]
|
|
10857
10598
|
);
|
|
10858
|
-
if (rows.length === 0)
|
|
10859
|
-
return null;
|
|
10599
|
+
if (rows.length === 0) return null;
|
|
10860
10600
|
const row = rows[0];
|
|
10861
10601
|
const contentJson = typeof row.content_json === "string" ? JSON.parse(row.content_json) : row.content_json;
|
|
10862
10602
|
return {
|
|
@@ -10875,8 +10615,7 @@ ${JSON.stringify(contentJson)}`,
|
|
|
10875
10615
|
WHERE entity_id = ? AND entity_type = 'task'`,
|
|
10876
10616
|
[taskId]
|
|
10877
10617
|
);
|
|
10878
|
-
if (rows.length === 0)
|
|
10879
|
-
return null;
|
|
10618
|
+
if (rows.length === 0) return null;
|
|
10880
10619
|
const row = rows[0];
|
|
10881
10620
|
return {
|
|
10882
10621
|
content: row.search_text || row.title,
|
|
@@ -10892,8 +10631,7 @@ ${JSON.stringify(contentJson)}`,
|
|
|
10892
10631
|
`SELECT content, event_type, session_id FROM events WHERE id = ?`,
|
|
10893
10632
|
[eventId]
|
|
10894
10633
|
);
|
|
10895
|
-
if (rows.length === 0)
|
|
10896
|
-
return null;
|
|
10634
|
+
if (rows.length === 0) return null;
|
|
10897
10635
|
const row = rows[0];
|
|
10898
10636
|
return {
|
|
10899
10637
|
content: row.content,
|
|
@@ -10921,8 +10659,7 @@ ${JSON.stringify(contentJson)}`,
|
|
|
10921
10659
|
}
|
|
10922
10660
|
throw error;
|
|
10923
10661
|
}
|
|
10924
|
-
if (rows.length === 0)
|
|
10925
|
-
return null;
|
|
10662
|
+
if (rows.length === 0) return null;
|
|
10926
10663
|
const row = rows[0];
|
|
10927
10664
|
const sourceEventIds = parseJsonArray(row.source_event_ids_json);
|
|
10928
10665
|
const sourceObservationIds = parseJsonArray(row.source_observation_ids_json);
|
|
@@ -10964,8 +10701,7 @@ var VectorWorkerV2 = class {
|
|
|
10964
10701
|
* Start the worker polling loop
|
|
10965
10702
|
*/
|
|
10966
10703
|
start() {
|
|
10967
|
-
if (this.running)
|
|
10968
|
-
return;
|
|
10704
|
+
if (this.running) return;
|
|
10969
10705
|
this.running = true;
|
|
10970
10706
|
this.stopping = false;
|
|
10971
10707
|
this.poll();
|
|
@@ -11035,8 +10771,7 @@ var VectorWorkerV2 = class {
|
|
|
11035
10771
|
* Poll for new jobs
|
|
11036
10772
|
*/
|
|
11037
10773
|
async poll() {
|
|
11038
|
-
if (!this.running || this.stopping)
|
|
11039
|
-
return;
|
|
10774
|
+
if (!this.running || this.stopping) return;
|
|
11040
10775
|
try {
|
|
11041
10776
|
await this.processBatch();
|
|
11042
10777
|
} catch (error) {
|
|
@@ -11103,8 +10838,7 @@ function createMemoryRuntimeService(deps) {
|
|
|
11103
10838
|
let graduationWorker = null;
|
|
11104
10839
|
return {
|
|
11105
10840
|
async initialize() {
|
|
11106
|
-
if (initialized)
|
|
11107
|
-
return;
|
|
10841
|
+
if (initialized) return;
|
|
11108
10842
|
await deps.sqliteStore.initialize();
|
|
11109
10843
|
if (deps.lightweightMode) {
|
|
11110
10844
|
initialized = true;
|
|
@@ -11198,8 +10932,7 @@ var SharedEventStore = class {
|
|
|
11198
10932
|
this.db = createDatabase(dbPath);
|
|
11199
10933
|
}
|
|
11200
10934
|
async initialize() {
|
|
11201
|
-
if (this.initialized)
|
|
11202
|
-
return;
|
|
10935
|
+
if (this.initialized) return;
|
|
11203
10936
|
await dbRun(this.db, `
|
|
11204
10937
|
CREATE TABLE IF NOT EXISTS shared_troubleshooting (
|
|
11205
10938
|
entry_id VARCHAR PRIMARY KEY,
|
|
@@ -11289,6 +11022,10 @@ var SharedPromoter = class {
|
|
|
11289
11022
|
this.embedder = embedder;
|
|
11290
11023
|
this.config = config;
|
|
11291
11024
|
}
|
|
11025
|
+
sharedStore;
|
|
11026
|
+
sharedVectorStore;
|
|
11027
|
+
embedder;
|
|
11028
|
+
config;
|
|
11292
11029
|
/**
|
|
11293
11030
|
* Check if an entry is eligible for promotion
|
|
11294
11031
|
*/
|
|
@@ -11470,6 +11207,7 @@ var SharedStore = class {
|
|
|
11470
11207
|
constructor(sharedEventStore) {
|
|
11471
11208
|
this.sharedEventStore = sharedEventStore;
|
|
11472
11209
|
}
|
|
11210
|
+
sharedEventStore;
|
|
11473
11211
|
get db() {
|
|
11474
11212
|
return this.sharedEventStore.getDatabase();
|
|
11475
11213
|
}
|
|
@@ -11574,8 +11312,7 @@ var SharedStore = class {
|
|
|
11574
11312
|
`SELECT * FROM shared_troubleshooting WHERE entry_id = ?`,
|
|
11575
11313
|
[entryId]
|
|
11576
11314
|
);
|
|
11577
|
-
if (rows.length === 0)
|
|
11578
|
-
return null;
|
|
11315
|
+
if (rows.length === 0) return null;
|
|
11579
11316
|
return this.rowToEntry(rows[0]);
|
|
11580
11317
|
}
|
|
11581
11318
|
/**
|
|
@@ -11588,8 +11325,7 @@ var SharedStore = class {
|
|
|
11588
11325
|
WHERE source_project_hash = ? AND source_entry_id = ?`,
|
|
11589
11326
|
[projectHash, sourceEntryId]
|
|
11590
11327
|
);
|
|
11591
|
-
if (rows.length === 0)
|
|
11592
|
-
return null;
|
|
11328
|
+
if (rows.length === 0) return null;
|
|
11593
11329
|
return this.rowToEntry(rows[0]);
|
|
11594
11330
|
}
|
|
11595
11331
|
/**
|
|
@@ -11699,6 +11435,7 @@ var SharedVectorStore = class {
|
|
|
11699
11435
|
constructor(dbPath) {
|
|
11700
11436
|
this.dbPath = dbPath;
|
|
11701
11437
|
}
|
|
11438
|
+
dbPath;
|
|
11702
11439
|
db = null;
|
|
11703
11440
|
table = null;
|
|
11704
11441
|
tableName = "shared_knowledge";
|
|
@@ -11706,8 +11443,7 @@ var SharedVectorStore = class {
|
|
|
11706
11443
|
* Initialize LanceDB connection
|
|
11707
11444
|
*/
|
|
11708
11445
|
async initialize() {
|
|
11709
|
-
if (this.db)
|
|
11710
|
-
return;
|
|
11446
|
+
if (this.db) return;
|
|
11711
11447
|
this.db = await lancedb2.connect(this.dbPath);
|
|
11712
11448
|
try {
|
|
11713
11449
|
const tables = await this.db.tableNames();
|
|
@@ -11749,8 +11485,7 @@ var SharedVectorStore = class {
|
|
|
11749
11485
|
* Add multiple records in batch
|
|
11750
11486
|
*/
|
|
11751
11487
|
async upsertBatch(records) {
|
|
11752
|
-
if (records.length === 0)
|
|
11753
|
-
return;
|
|
11488
|
+
if (records.length === 0) return;
|
|
11754
11489
|
await this.initialize();
|
|
11755
11490
|
if (!this.db) {
|
|
11756
11491
|
throw new Error("Database not initialized");
|
|
@@ -11811,24 +11546,21 @@ var SharedVectorStore = class {
|
|
|
11811
11546
|
* Delete vector by entry ID
|
|
11812
11547
|
*/
|
|
11813
11548
|
async delete(entryId) {
|
|
11814
|
-
if (!this.table)
|
|
11815
|
-
return;
|
|
11549
|
+
if (!this.table) return;
|
|
11816
11550
|
await this.table.delete(`entryId = '${entryId}'`);
|
|
11817
11551
|
}
|
|
11818
11552
|
/**
|
|
11819
11553
|
* Get total count
|
|
11820
11554
|
*/
|
|
11821
11555
|
async count() {
|
|
11822
|
-
if (!this.table)
|
|
11823
|
-
return 0;
|
|
11556
|
+
if (!this.table) return 0;
|
|
11824
11557
|
return this.table.countRows();
|
|
11825
11558
|
}
|
|
11826
11559
|
/**
|
|
11827
11560
|
* Check if vector exists for entry
|
|
11828
11561
|
*/
|
|
11829
11562
|
async exists(entryId) {
|
|
11830
|
-
if (!this.table)
|
|
11831
|
-
return false;
|
|
11563
|
+
if (!this.table) return false;
|
|
11832
11564
|
try {
|
|
11833
11565
|
const results = await this.table.search([]).where(`entryId = '${entryId}'`).limit(1).toArray();
|
|
11834
11566
|
return results.length > 0;
|
|
@@ -11846,6 +11578,7 @@ var SharedMemoryServices = class {
|
|
|
11846
11578
|
constructor(options) {
|
|
11847
11579
|
this.options = options;
|
|
11848
11580
|
}
|
|
11581
|
+
options;
|
|
11849
11582
|
sharedEventStore = null;
|
|
11850
11583
|
sharedStore = null;
|
|
11851
11584
|
sharedVectorStore = null;
|
|
@@ -11870,8 +11603,7 @@ var SharedMemoryServices = class {
|
|
|
11870
11603
|
return this.options.config?.sharedStoragePath ? this.options.expandPath(this.options.config.sharedStoragePath) : this.options.defaultSharedStoragePath;
|
|
11871
11604
|
}
|
|
11872
11605
|
async initialize() {
|
|
11873
|
-
if (this.options.config?.enabled === false || this.options.readOnly)
|
|
11874
|
-
return;
|
|
11606
|
+
if (this.options.config?.enabled === false || this.options.readOnly) return;
|
|
11875
11607
|
const sharedPath = this.getSharedStoragePath();
|
|
11876
11608
|
this.ensureDirectory(sharedPath, { allowCreate: true });
|
|
11877
11609
|
const store = await this.openStore(sharedPath);
|
|
@@ -11888,14 +11620,11 @@ var SharedMemoryServices = class {
|
|
|
11888
11620
|
this.options.retriever.setSharedStores(store, this.sharedVectorStore);
|
|
11889
11621
|
}
|
|
11890
11622
|
async ensureStoreForRead() {
|
|
11891
|
-
if (this.options.config?.enabled === false)
|
|
11892
|
-
|
|
11893
|
-
if (this.sharedStore)
|
|
11894
|
-
return this.sharedStore;
|
|
11623
|
+
if (this.options.config?.enabled === false) return null;
|
|
11624
|
+
if (this.sharedStore) return this.sharedStore;
|
|
11895
11625
|
const sharedPath = this.getSharedStoragePath();
|
|
11896
11626
|
const directoryReady = this.ensureDirectory(sharedPath, { allowCreate: !this.options.readOnly });
|
|
11897
|
-
if (!directoryReady)
|
|
11898
|
-
return null;
|
|
11627
|
+
if (!directoryReady) return null;
|
|
11899
11628
|
return this.openStore(sharedPath);
|
|
11900
11629
|
}
|
|
11901
11630
|
async getEntryForDisclosure(entryId) {
|
|
@@ -11912,13 +11641,11 @@ var SharedMemoryServices = class {
|
|
|
11912
11641
|
return this.sharedPromoter.promoteEntry(entry, projectHash);
|
|
11913
11642
|
}
|
|
11914
11643
|
async getStats() {
|
|
11915
|
-
if (!this.sharedStore)
|
|
11916
|
-
return null;
|
|
11644
|
+
if (!this.sharedStore) return null;
|
|
11917
11645
|
return this.sharedStore.getStats();
|
|
11918
11646
|
}
|
|
11919
11647
|
async search(query, options) {
|
|
11920
|
-
if (!this.sharedStore)
|
|
11921
|
-
return [];
|
|
11648
|
+
if (!this.sharedStore) return [];
|
|
11922
11649
|
return this.sharedStore.search(query, options);
|
|
11923
11650
|
}
|
|
11924
11651
|
async close() {
|
|
@@ -11935,8 +11662,7 @@ var SharedMemoryServices = class {
|
|
|
11935
11662
|
this.openStorePromise = null;
|
|
11936
11663
|
}
|
|
11937
11664
|
async openStore(sharedPath) {
|
|
11938
|
-
if (this.sharedStore)
|
|
11939
|
-
return this.sharedStore;
|
|
11665
|
+
if (this.sharedStore) return this.sharedStore;
|
|
11940
11666
|
if (!this.openStorePromise) {
|
|
11941
11667
|
this.openStorePromise = this.createOpenStorePromise(sharedPath);
|
|
11942
11668
|
}
|
|
@@ -11960,10 +11686,8 @@ var SharedMemoryServices = class {
|
|
|
11960
11686
|
return this.sharedStore;
|
|
11961
11687
|
}
|
|
11962
11688
|
ensureDirectory(sharedPath, options) {
|
|
11963
|
-
if (this.factories.existsSync(sharedPath))
|
|
11964
|
-
|
|
11965
|
-
if (!options.allowCreate)
|
|
11966
|
-
return false;
|
|
11689
|
+
if (this.factories.existsSync(sharedPath)) return true;
|
|
11690
|
+
if (!options.allowCreate) return false;
|
|
11967
11691
|
this.factories.mkdirSync(sharedPath);
|
|
11968
11692
|
return true;
|
|
11969
11693
|
}
|
|
@@ -13170,15 +12894,13 @@ function countRowValue(db, sql, params = []) {
|
|
|
13170
12894
|
return Number(row?.count ?? 0);
|
|
13171
12895
|
}
|
|
13172
12896
|
function projectFilter(projectHash, column = "project_hash") {
|
|
13173
|
-
if (!projectHash)
|
|
13174
|
-
return { clause: "", params: [] };
|
|
12897
|
+
if (!projectHash) return { clause: "", params: [] };
|
|
13175
12898
|
return { clause: `WHERE ${column} = ?`, params: [projectHash] };
|
|
13176
12899
|
}
|
|
13177
12900
|
function sanitizeAggregateLabel(value) {
|
|
13178
12901
|
const raw = typeof value === "string" ? value : String(value ?? "unknown");
|
|
13179
12902
|
const sanitized = String(sanitizeGovernanceAuditValue(raw));
|
|
13180
|
-
if (sanitized !== raw || sanitized.includes("[REDACTED]"))
|
|
13181
|
-
return "[REDACTED]";
|
|
12903
|
+
if (sanitized !== raw || sanitized.includes("[REDACTED]")) return "[REDACTED]";
|
|
13182
12904
|
const trimmed = sanitized.trim();
|
|
13183
12905
|
return trimmed.length > 0 ? trimmed.slice(0, 96) : "unknown";
|
|
13184
12906
|
}
|
|
@@ -13522,8 +13244,7 @@ function buildPerspectiveSourceEvidence(db, projectHash) {
|
|
|
13522
13244
|
function sortCountRows(rows, labelKey) {
|
|
13523
13245
|
return [...rows].sort((a, b) => {
|
|
13524
13246
|
const countDiff = Number(b.count ?? 0) - Number(a.count ?? 0);
|
|
13525
|
-
if (countDiff !== 0)
|
|
13526
|
-
return countDiff;
|
|
13247
|
+
if (countDiff !== 0) return countDiff;
|
|
13527
13248
|
return String(a[labelKey] ?? "").localeCompare(String(b[labelKey] ?? ""));
|
|
13528
13249
|
});
|
|
13529
13250
|
}
|
|
@@ -13606,8 +13327,7 @@ var DEFAULT_KPI_THRESHOLDS = {
|
|
|
13606
13327
|
function loadKpiThresholds() {
|
|
13607
13328
|
try {
|
|
13608
13329
|
const filePath = path11.resolve(process.cwd(), "config", "kpi-thresholds.json");
|
|
13609
|
-
if (!fs9.existsSync(filePath))
|
|
13610
|
-
return DEFAULT_KPI_THRESHOLDS;
|
|
13330
|
+
if (!fs9.existsSync(filePath)) return DEFAULT_KPI_THRESHOLDS;
|
|
13611
13331
|
const parsed = JSON.parse(fs9.readFileSync(filePath, "utf-8"));
|
|
13612
13332
|
return {
|
|
13613
13333
|
usefulRecallRateMin: Number(parsed.usefulRecallRateMin ?? DEFAULT_KPI_THRESHOLDS.usefulRecallRateMin),
|
|
@@ -13621,10 +13341,8 @@ function loadKpiThresholds() {
|
|
|
13621
13341
|
}
|
|
13622
13342
|
}
|
|
13623
13343
|
function windowToMs(window) {
|
|
13624
|
-
if (window === "24h")
|
|
13625
|
-
|
|
13626
|
-
if (window === "7d")
|
|
13627
|
-
return 7 * 24 * 60 * 60 * 1e3;
|
|
13344
|
+
if (window === "24h") return 24 * 60 * 60 * 1e3;
|
|
13345
|
+
if (window === "7d") return 7 * 24 * 60 * 60 * 1e3;
|
|
13628
13346
|
return 30 * 24 * 60 * 60 * 1e3;
|
|
13629
13347
|
}
|
|
13630
13348
|
function inWindow(e, now, window) {
|
|
@@ -13634,8 +13352,7 @@ function isEditToolName(name) {
|
|
|
13634
13352
|
return ["Write", "Edit", "MultiEdit", "NotebookEdit"].includes(name);
|
|
13635
13353
|
}
|
|
13636
13354
|
function parseToolPayload(e) {
|
|
13637
|
-
if (e.eventType !== "tool_observation")
|
|
13638
|
-
return null;
|
|
13355
|
+
if (e.eventType !== "tool_observation") return null;
|
|
13639
13356
|
try {
|
|
13640
13357
|
const payload = JSON.parse(e.content);
|
|
13641
13358
|
return {
|
|
@@ -13654,13 +13371,11 @@ function parseToolPayload(e) {
|
|
|
13654
13371
|
}
|
|
13655
13372
|
}
|
|
13656
13373
|
function isTestLikeCommand(command) {
|
|
13657
|
-
if (!command)
|
|
13658
|
-
return false;
|
|
13374
|
+
if (!command) return false;
|
|
13659
13375
|
return /(test|jest|vitest|pytest|go test|cargo test|lint|eslint|build|tsc)/i.test(command);
|
|
13660
13376
|
}
|
|
13661
13377
|
function safeRatio(num, den) {
|
|
13662
|
-
if (!Number.isFinite(num) || !Number.isFinite(den) || den <= 0)
|
|
13663
|
-
return 0;
|
|
13378
|
+
if (!Number.isFinite(num) || !Number.isFinite(den) || den <= 0) return 0;
|
|
13664
13379
|
return num / den;
|
|
13665
13380
|
}
|
|
13666
13381
|
function round(value, digits = 4) {
|
|
@@ -13671,28 +13386,23 @@ function computeSessionTurnCount(sessionEvents) {
|
|
|
13671
13386
|
const turnIds = /* @__PURE__ */ new Set();
|
|
13672
13387
|
for (const e of sessionEvents) {
|
|
13673
13388
|
const turnId = e.metadata?.turnId;
|
|
13674
|
-
if (typeof turnId === "string" && turnId.length > 0)
|
|
13675
|
-
turnIds.add(turnId);
|
|
13389
|
+
if (typeof turnId === "string" && turnId.length > 0) turnIds.add(turnId);
|
|
13676
13390
|
}
|
|
13677
|
-
if (turnIds.size > 0)
|
|
13678
|
-
return turnIds.size;
|
|
13391
|
+
if (turnIds.size > 0) return turnIds.size;
|
|
13679
13392
|
return sessionEvents.filter((e) => e.eventType === "user_prompt").length;
|
|
13680
13393
|
}
|
|
13681
13394
|
function normalizeQueryRewriteKind2(value) {
|
|
13682
13395
|
const normalized = (value || "").trim().toLowerCase();
|
|
13683
|
-
if (normalized === "follow-up-context" || normalized === "intent-rewrite")
|
|
13684
|
-
return normalized;
|
|
13396
|
+
if (normalized === "follow-up-context" || normalized === "intent-rewrite") return normalized;
|
|
13685
13397
|
return "none";
|
|
13686
13398
|
}
|
|
13687
13399
|
function normalizeMetric(value) {
|
|
13688
13400
|
const numberValue = Number(value || 0);
|
|
13689
|
-
if (!Number.isFinite(numberValue))
|
|
13690
|
-
return 0;
|
|
13401
|
+
if (!Number.isFinite(numberValue)) return 0;
|
|
13691
13402
|
return Math.max(0, Math.min(1, numberValue));
|
|
13692
13403
|
}
|
|
13693
13404
|
function getTimestampMs(value) {
|
|
13694
|
-
if (value instanceof Date)
|
|
13695
|
-
return value.getTime();
|
|
13405
|
+
if (value instanceof Date) return value.getTime();
|
|
13696
13406
|
if (typeof value === "string") {
|
|
13697
13407
|
const parsed = new Date(value).getTime();
|
|
13698
13408
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
@@ -13750,8 +13460,7 @@ function makeRetrievalReviewItem(trace) {
|
|
|
13750
13460
|
detail = `${selectedCount} of ${candidateCount} candidates were selected.`;
|
|
13751
13461
|
action = "Inspect score distribution and MMR/diversity settings before lowering thresholds.";
|
|
13752
13462
|
}
|
|
13753
|
-
if (!reason)
|
|
13754
|
-
return null;
|
|
13463
|
+
if (!reason) return null;
|
|
13755
13464
|
return {
|
|
13756
13465
|
traceId: trace.traceId || "unknown-trace",
|
|
13757
13466
|
reason,
|
|
@@ -13800,24 +13509,17 @@ function buildRetrievalReviewQueue(traces, limit) {
|
|
|
13800
13509
|
};
|
|
13801
13510
|
}
|
|
13802
13511
|
function parseStatsLimit(value, fallback, max) {
|
|
13803
|
-
if (!value)
|
|
13804
|
-
|
|
13805
|
-
if (!/^\d+$/.test(value))
|
|
13806
|
-
return fallback;
|
|
13512
|
+
if (!value) return fallback;
|
|
13513
|
+
if (!/^\d+$/.test(value)) return fallback;
|
|
13807
13514
|
const parsed = Number(value);
|
|
13808
|
-
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
13809
|
-
return fallback;
|
|
13515
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
13810
13516
|
return Math.min(parsed, max);
|
|
13811
13517
|
}
|
|
13812
13518
|
function usefulnessScoreLabel(score, confidence) {
|
|
13813
|
-
if (confidence <= 0)
|
|
13814
|
-
|
|
13815
|
-
if (score >=
|
|
13816
|
-
|
|
13817
|
-
if (score >= 60)
|
|
13818
|
-
return "good";
|
|
13819
|
-
if (score >= 40)
|
|
13820
|
-
return "watch";
|
|
13519
|
+
if (confidence <= 0) return "unknown";
|
|
13520
|
+
if (score >= 80) return "excellent";
|
|
13521
|
+
if (score >= 60) return "good";
|
|
13522
|
+
if (score >= 40) return "watch";
|
|
13821
13523
|
return "low";
|
|
13822
13524
|
}
|
|
13823
13525
|
function buildMemoryUsefulnessDiagnostics(input) {
|
|
@@ -14063,8 +13765,7 @@ function computeKpiMetrics(events, usefulRecallRate) {
|
|
|
14063
13765
|
let seenEdit = false;
|
|
14064
13766
|
for (const e of sorted) {
|
|
14065
13767
|
const payload = parseToolPayload(e);
|
|
14066
|
-
if (!payload?.toolName)
|
|
14067
|
-
continue;
|
|
13768
|
+
if (!payload?.toolName) continue;
|
|
14068
13769
|
if (isEditToolName(payload.toolName) && payload.success === true) {
|
|
14069
13770
|
editActions.push({ sessionId, timestamp: e.timestamp.getTime(), filePath: payload.filePath });
|
|
14070
13771
|
seenEdit = true;
|
|
@@ -14072,8 +13773,7 @@ function computeKpiMetrics(events, usefulRecallRate) {
|
|
|
14072
13773
|
}
|
|
14073
13774
|
if (seenEdit && isTestLikeCommand(payload.command)) {
|
|
14074
13775
|
testRunsAfterEdit++;
|
|
14075
|
-
if (payload.success === false)
|
|
14076
|
-
failedTestRunsAfterEdit++;
|
|
13776
|
+
if (payload.success === false) failedTestRunsAfterEdit++;
|
|
14077
13777
|
}
|
|
14078
13778
|
}
|
|
14079
13779
|
}
|
|
@@ -14082,8 +13782,7 @@ function computeKpiMetrics(events, usefulRecallRate) {
|
|
|
14082
13782
|
const bySessionFile = /* @__PURE__ */ new Map();
|
|
14083
13783
|
const sortedEdits = [...editActions].sort((a, b) => a.timestamp - b.timestamp);
|
|
14084
13784
|
for (const edit of sortedEdits) {
|
|
14085
|
-
if (!edit.filePath)
|
|
14086
|
-
continue;
|
|
13785
|
+
if (!edit.filePath) continue;
|
|
14087
13786
|
const key = `${edit.sessionId}::${edit.filePath}`;
|
|
14088
13787
|
const prev = bySessionFile.get(key);
|
|
14089
13788
|
if (typeof prev === "number" && edit.timestamp - prev <= THIRTY_MIN_MS) {
|
|
@@ -14458,12 +14157,9 @@ statsRouter.get("/timeline", async (c) => {
|
|
|
14458
14157
|
acc[day] = { date: day, total: 0, prompts: 0, responses: 0, tools: 0 };
|
|
14459
14158
|
}
|
|
14460
14159
|
acc[day].total++;
|
|
14461
|
-
if (e.eventType === "user_prompt")
|
|
14462
|
-
|
|
14463
|
-
if (e.eventType === "
|
|
14464
|
-
acc[day].responses++;
|
|
14465
|
-
if (e.eventType === "tool_observation")
|
|
14466
|
-
acc[day].tools++;
|
|
14160
|
+
if (e.eventType === "user_prompt") acc[day].prompts++;
|
|
14161
|
+
if (e.eventType === "agent_response") acc[day].responses++;
|
|
14162
|
+
if (e.eventType === "tool_observation") acc[day].tools++;
|
|
14467
14163
|
return acc;
|
|
14468
14164
|
}, {});
|
|
14469
14165
|
return c.json({
|
|
@@ -14674,8 +14370,7 @@ statsRouter.get("/kpi", async (c) => {
|
|
|
14674
14370
|
for (const edit of dayEditActions) {
|
|
14675
14371
|
const key = `${edit.sessionId}::${edit.filePath}`;
|
|
14676
14372
|
const prev = dayBySessionFile.get(key);
|
|
14677
|
-
if (typeof prev === "number" && edit.timestamp - prev <= THIRTY_MIN_MS)
|
|
14678
|
-
dayReworkCount++;
|
|
14373
|
+
if (typeof prev === "number" && edit.timestamp - prev <= THIRTY_MIN_MS) dayReworkCount++;
|
|
14679
14374
|
dayBySessionFile.set(key, edit.timestamp);
|
|
14680
14375
|
}
|
|
14681
14376
|
const dayTests = dayEvents.filter((e) => {
|
|
@@ -15015,8 +14710,7 @@ projectsRouter.get("/", async (c) => {
|
|
|
15015
14710
|
}
|
|
15016
14711
|
});
|
|
15017
14712
|
function formatBytes(bytes) {
|
|
15018
|
-
if (bytes === 0)
|
|
15019
|
-
return "0 B";
|
|
14713
|
+
if (bytes === 0) return "0 B";
|
|
15020
14714
|
const k = 1024;
|
|
15021
14715
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
15022
14716
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
@@ -15034,6 +14728,7 @@ var ProviderFailure = class extends Error {
|
|
|
15034
14728
|
this.code = code;
|
|
15035
14729
|
this.name = "ProviderFailure";
|
|
15036
14730
|
}
|
|
14731
|
+
code;
|
|
15037
14732
|
};
|
|
15038
14733
|
var CLAUDE_TIMEOUT_MS = 12e4;
|
|
15039
14734
|
chatRouter.post("/", async (c) => {
|
|
@@ -15110,8 +14805,7 @@ async function collectMemoryContext(memoryService, query) {
|
|
|
15110
14805
|
async function collectStatsContext(memoryService) {
|
|
15111
14806
|
try {
|
|
15112
14807
|
const stats = await memoryService.getStats?.();
|
|
15113
|
-
if (!stats)
|
|
15114
|
-
return "";
|
|
14808
|
+
if (!stats) return "";
|
|
15115
14809
|
const levels = stats.levelStats.map((l) => `${l.level}: ${l.count}`).join(", ");
|
|
15116
14810
|
return [
|
|
15117
14811
|
"## Memory Stats",
|
|
@@ -15124,8 +14818,7 @@ async function collectStatsContext(memoryService) {
|
|
|
15124
14818
|
}
|
|
15125
14819
|
}
|
|
15126
14820
|
function formatMemoryContext(memoryHits) {
|
|
15127
|
-
if (memoryHits.length === 0)
|
|
15128
|
-
return "";
|
|
14821
|
+
if (memoryHits.length === 0) return "";
|
|
15129
14822
|
const parts = ["## Relevant Memories\n"];
|
|
15130
14823
|
for (const m of memoryHits) {
|
|
15131
14824
|
const date = m.event.timestamp ? new Date(m.event.timestamp).toISOString().split("T")[0] : "unknown-date";
|
|
@@ -15247,8 +14940,7 @@ function streamClaudeResponse(prompt, stream) {
|
|
|
15247
14940
|
const lines = buffer.split("\n");
|
|
15248
14941
|
buffer = lines.pop() || "";
|
|
15249
14942
|
for (const line of lines) {
|
|
15250
|
-
if (!line.trim())
|
|
15251
|
-
continue;
|
|
14943
|
+
if (!line.trim()) continue;
|
|
15252
14944
|
try {
|
|
15253
14945
|
const parsed = JSON.parse(line);
|
|
15254
14946
|
if (parsed.type === "assistant" && parsed.message?.content) {
|
|
@@ -15477,21 +15169,17 @@ function timingSafeStringEqual(a, b) {
|
|
|
15477
15169
|
return left.length === right.length && timingSafeEqual(left, right);
|
|
15478
15170
|
}
|
|
15479
15171
|
function verifyDashboardSessionToken(token, password, maxAgeSeconds, now) {
|
|
15480
|
-
if (!token)
|
|
15481
|
-
return false;
|
|
15172
|
+
if (!token) return false;
|
|
15482
15173
|
const [payload, signature, extra] = token.split(".");
|
|
15483
|
-
if (!payload || !signature || extra !== void 0 || !/^\d+$/.test(payload))
|
|
15484
|
-
return false;
|
|
15174
|
+
if (!payload || !signature || extra !== void 0 || !/^\d+$/.test(payload)) return false;
|
|
15485
15175
|
const expectedSignature = signSessionPayload(payload, password);
|
|
15486
|
-
if (!timingSafeStringEqual(signature, expectedSignature))
|
|
15487
|
-
return false;
|
|
15176
|
+
if (!timingSafeStringEqual(signature, expectedSignature)) return false;
|
|
15488
15177
|
const issuedAt = Number.parseInt(payload, 10);
|
|
15489
15178
|
const age = nowSeconds(now) - issuedAt;
|
|
15490
15179
|
return Number.isSafeInteger(issuedAt) && age >= 0 && age <= maxAgeSeconds;
|
|
15491
15180
|
}
|
|
15492
15181
|
function isDashboardAuthenticated(c, options) {
|
|
15493
|
-
if (!options.password)
|
|
15494
|
-
return true;
|
|
15182
|
+
if (!options.password) return true;
|
|
15495
15183
|
return verifyDashboardSessionToken(
|
|
15496
15184
|
getCookie(c, DASHBOARD_SESSION_COOKIE),
|
|
15497
15185
|
options.password,
|
|
@@ -15578,8 +15266,7 @@ function createDashboardApp(options = {}) {
|
|
|
15578
15266
|
}
|
|
15579
15267
|
const submittedPassword = await readSubmittedPassword(c);
|
|
15580
15268
|
if (!timingSafeStringEqual(submittedPassword, authOptions.password)) {
|
|
15581
|
-
if (wantsAuthJson(c))
|
|
15582
|
-
return c.json({ error: "Invalid password" }, 401);
|
|
15269
|
+
if (wantsAuthJson(c)) return c.json({ error: "Invalid password" }, 401);
|
|
15583
15270
|
return c.html(renderLoginPage("Invalid password"), 401);
|
|
15584
15271
|
}
|
|
15585
15272
|
const token = createDashboardSessionToken(authOptions.password, authOptions.now);
|
|
@@ -15590,14 +15277,12 @@ function createDashboardApp(options = {}) {
|
|
|
15590
15277
|
path: "/",
|
|
15591
15278
|
maxAge: authOptions.cookieMaxAgeSeconds
|
|
15592
15279
|
});
|
|
15593
|
-
if (wantsAuthJson(c))
|
|
15594
|
-
return c.json({ authenticated: true });
|
|
15280
|
+
if (wantsAuthJson(c)) return c.json({ authenticated: true });
|
|
15595
15281
|
return c.redirect("/", 303);
|
|
15596
15282
|
});
|
|
15597
15283
|
app2.post("/api/auth/logout", (c) => {
|
|
15598
15284
|
deleteCookie(c, DASHBOARD_SESSION_COOKIE, { path: "/" });
|
|
15599
|
-
if (wantsAuthJson(c))
|
|
15600
|
-
return c.json({ authenticated: false });
|
|
15285
|
+
if (wantsAuthJson(c)) return c.json({ authenticated: false });
|
|
15601
15286
|
return c.redirect("/", 303);
|
|
15602
15287
|
});
|
|
15603
15288
|
if (authOptions.password) {
|
|
@@ -15606,8 +15291,7 @@ function createDashboardApp(options = {}) {
|
|
|
15606
15291
|
await next();
|
|
15607
15292
|
return;
|
|
15608
15293
|
}
|
|
15609
|
-
if (isApiRequest(c))
|
|
15610
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
15294
|
+
if (isApiRequest(c)) return c.json({ error: "Authentication required" }, 401);
|
|
15611
15295
|
return c.html(renderLoginPage(), 401);
|
|
15612
15296
|
});
|
|
15613
15297
|
}
|