@rlabs-inc/memory 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +237 -28
- package/dist/index.mjs +237 -28
- package/dist/server/index.js +283 -28
- package/dist/server/index.mjs +283 -28
- package/package.json +1 -1
- package/src/core/curator.ts +95 -6
- package/src/core/engine.ts +70 -15
- package/src/core/store.ts +8 -4
- package/src/server/index.ts +54 -0
- package/src/types/memory.ts +37 -25
- package/src/types/schema.ts +8 -3
package/dist/index.js
CHANGED
|
@@ -33316,6 +33316,7 @@ var logger = {
|
|
|
33316
33316
|
{ name: "domain", count: signalBreakdown.domain },
|
|
33317
33317
|
{ name: "feature", count: signalBreakdown.feature },
|
|
33318
33318
|
{ name: "content", count: signalBreakdown.content },
|
|
33319
|
+
{ name: "files", count: signalBreakdown.files },
|
|
33319
33320
|
{ name: "vector", count: signalBreakdown.vector }
|
|
33320
33321
|
];
|
|
33321
33322
|
for (const sig of signals) {
|
|
@@ -33332,7 +33333,7 @@ var logger = {
|
|
|
33332
33333
|
if (Object.keys(buckets).length > 0) {
|
|
33333
33334
|
console.log(` ${style("bold", "Distribution:")}`);
|
|
33334
33335
|
const maxBucketCount = Math.max(...Object.values(buckets), 1);
|
|
33335
|
-
const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals"];
|
|
33336
|
+
const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals", "7 signals"];
|
|
33336
33337
|
for (const bucket of bucketOrder) {
|
|
33337
33338
|
const count = buckets[bucket] ?? 0;
|
|
33338
33339
|
if (count > 0 || bucket === "2 signals") {
|
|
@@ -33348,7 +33349,7 @@ var logger = {
|
|
|
33348
33349
|
};
|
|
33349
33350
|
|
|
33350
33351
|
// src/types/memory.ts
|
|
33351
|
-
var
|
|
33352
|
+
var V4_DEFAULTS = {
|
|
33352
33353
|
typeDefaults: {
|
|
33353
33354
|
personal: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
33354
33355
|
philosophy: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
@@ -33373,7 +33374,7 @@ var V3_DEFAULTS = {
|
|
|
33373
33374
|
exclude_from_retrieval: false
|
|
33374
33375
|
}
|
|
33375
33376
|
};
|
|
33376
|
-
var V2_DEFAULTS =
|
|
33377
|
+
var V2_DEFAULTS = V4_DEFAULTS;
|
|
33377
33378
|
var MEMORY_TYPE_EMOJI = {
|
|
33378
33379
|
technical: "\uD83D\uDD27",
|
|
33379
33380
|
debug: "\uD83D\uDC1B",
|
|
@@ -33392,8 +33393,9 @@ function getMemoryEmoji(contextType) {
|
|
|
33392
33393
|
}
|
|
33393
33394
|
|
|
33394
33395
|
// src/types/schema.ts
|
|
33395
|
-
var MEMORY_SCHEMA_VERSION =
|
|
33396
|
+
var MEMORY_SCHEMA_VERSION = 4;
|
|
33396
33397
|
var memorySchema = {
|
|
33398
|
+
headline: "string",
|
|
33397
33399
|
content: "string",
|
|
33398
33400
|
reasoning: "string",
|
|
33399
33401
|
importance_weight: "number",
|
|
@@ -33522,6 +33524,7 @@ class MemoryStore {
|
|
|
33522
33524
|
const { memories } = await this.getGlobal();
|
|
33523
33525
|
return memories.all().map((record) => ({
|
|
33524
33526
|
id: record.id,
|
|
33527
|
+
headline: record.headline ?? "",
|
|
33525
33528
|
content: record.content,
|
|
33526
33529
|
reasoning: record.reasoning,
|
|
33527
33530
|
importance_weight: record.importance_weight,
|
|
@@ -33546,6 +33549,7 @@ class MemoryStore {
|
|
|
33546
33549
|
const contextType = memory.context_type ?? "personal";
|
|
33547
33550
|
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.personal;
|
|
33548
33551
|
const id = memories.insert({
|
|
33552
|
+
headline: memory.headline ?? "",
|
|
33549
33553
|
content: memory.content,
|
|
33550
33554
|
reasoning: memory.reasoning,
|
|
33551
33555
|
importance_weight: memory.importance_weight,
|
|
@@ -33701,6 +33705,7 @@ class MemoryStore {
|
|
|
33701
33705
|
const contextType = memory.context_type ?? "general";
|
|
33702
33706
|
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.technical;
|
|
33703
33707
|
const id = memories.insert({
|
|
33708
|
+
headline: memory.headline ?? "",
|
|
33704
33709
|
content: memory.content,
|
|
33705
33710
|
reasoning: memory.reasoning,
|
|
33706
33711
|
importance_weight: memory.importance_weight,
|
|
@@ -33743,6 +33748,7 @@ class MemoryStore {
|
|
|
33743
33748
|
const { memories } = await this.getProject(projectId);
|
|
33744
33749
|
return memories.all().map((record) => ({
|
|
33745
33750
|
id: record.id,
|
|
33751
|
+
headline: record.headline ?? "",
|
|
33746
33752
|
content: record.content,
|
|
33747
33753
|
reasoning: record.reasoning,
|
|
33748
33754
|
importance_weight: record.importance_weight,
|
|
@@ -34062,14 +34068,42 @@ class SmartVectorRetrieval {
|
|
|
34062
34068
|
const words = text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w));
|
|
34063
34069
|
return new Set(words);
|
|
34064
34070
|
}
|
|
34071
|
+
_extractFilePaths(text) {
|
|
34072
|
+
const paths = new Set;
|
|
34073
|
+
const pathPattern = /(?:^|[\s'"(])([.\/\\]?(?:[\w.-]+[\/\\])+[\w.-]+(?:\.\w+)?)/g;
|
|
34074
|
+
let match;
|
|
34075
|
+
while ((match = pathPattern.exec(text)) !== null) {
|
|
34076
|
+
const path = match[1].toLowerCase();
|
|
34077
|
+
paths.add(path);
|
|
34078
|
+
const filename = path.split(/[\/\\]/).pop();
|
|
34079
|
+
if (filename)
|
|
34080
|
+
paths.add(filename);
|
|
34081
|
+
}
|
|
34082
|
+
return paths;
|
|
34083
|
+
}
|
|
34084
|
+
_checkFilesActivation(messagePaths, relatedFiles) {
|
|
34085
|
+
if (!relatedFiles?.length || !messagePaths.size)
|
|
34086
|
+
return false;
|
|
34087
|
+
for (const file of relatedFiles) {
|
|
34088
|
+
const fileLower = file.toLowerCase();
|
|
34089
|
+
for (const msgPath of messagePaths) {
|
|
34090
|
+
if (fileLower.includes(msgPath) || msgPath.includes(fileLower)) {
|
|
34091
|
+
return true;
|
|
34092
|
+
}
|
|
34093
|
+
}
|
|
34094
|
+
const filename = fileLower.split(/[\/\\]/).pop();
|
|
34095
|
+
if (filename && messagePaths.has(filename)) {
|
|
34096
|
+
return true;
|
|
34097
|
+
}
|
|
34098
|
+
}
|
|
34099
|
+
return false;
|
|
34100
|
+
}
|
|
34065
34101
|
_preFilter(memories, currentProjectId, messageLower) {
|
|
34066
34102
|
return memories.filter((memory) => {
|
|
34067
34103
|
if (memory.status && memory.status !== "active")
|
|
34068
34104
|
return false;
|
|
34069
34105
|
if (memory.exclude_from_retrieval === true)
|
|
34070
34106
|
return false;
|
|
34071
|
-
if (memory.superseded_by)
|
|
34072
|
-
return false;
|
|
34073
34107
|
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
34074
34108
|
if (!isGlobal && memory.project_id !== currentProjectId)
|
|
34075
34109
|
return false;
|
|
@@ -34220,19 +34254,25 @@ class SmartVectorRetrieval {
|
|
|
34220
34254
|
}
|
|
34221
34255
|
const messageLower = currentMessage.toLowerCase();
|
|
34222
34256
|
const messageWords = this._extractSignificantWords(currentMessage);
|
|
34257
|
+
const messagePaths = this._extractFilePaths(currentMessage);
|
|
34258
|
+
const memoryById = new Map;
|
|
34259
|
+
for (const m of allMemories) {
|
|
34260
|
+
memoryById.set(m.id, m);
|
|
34261
|
+
}
|
|
34223
34262
|
const candidates = this._preFilter(allMemories, sessionContext.project_id, messageLower);
|
|
34224
34263
|
if (!candidates.length) {
|
|
34225
34264
|
return [];
|
|
34226
34265
|
}
|
|
34227
34266
|
const activatedMemories = [];
|
|
34267
|
+
const activatedIds = new Set;
|
|
34228
34268
|
let rejectedCount = 0;
|
|
34229
34269
|
for (const memory of candidates) {
|
|
34230
|
-
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
34231
34270
|
const triggerResult = this._checkTriggerActivation(messageLower, messageWords, memory.trigger_phrases ?? []);
|
|
34232
34271
|
const tagResult = this._checkTagActivation(messageLower, messageWords, memory.semantic_tags ?? []);
|
|
34233
34272
|
const domainActivated = this._checkDomainActivation(messageLower, messageWords, memory.domain);
|
|
34234
34273
|
const featureActivated = this._checkFeatureActivation(messageLower, messageWords, memory.feature);
|
|
34235
34274
|
const contentActivated = this._checkContentActivation(messageWords, memory);
|
|
34275
|
+
const filesActivated = this._checkFilesActivation(messagePaths, memory.related_files);
|
|
34236
34276
|
const vectorSimilarity = this._calculateVectorSimilarity(queryEmbedding, memory.embedding);
|
|
34237
34277
|
let signalCount = 0;
|
|
34238
34278
|
if (triggerResult.activated)
|
|
@@ -34245,6 +34285,8 @@ class SmartVectorRetrieval {
|
|
|
34245
34285
|
signalCount++;
|
|
34246
34286
|
if (contentActivated)
|
|
34247
34287
|
signalCount++;
|
|
34288
|
+
if (filesActivated)
|
|
34289
|
+
signalCount++;
|
|
34248
34290
|
if (vectorSimilarity >= 0.4)
|
|
34249
34291
|
signalCount++;
|
|
34250
34292
|
const signals = {
|
|
@@ -34253,6 +34295,7 @@ class SmartVectorRetrieval {
|
|
|
34253
34295
|
domain: domainActivated,
|
|
34254
34296
|
feature: featureActivated,
|
|
34255
34297
|
content: contentActivated,
|
|
34298
|
+
files: filesActivated,
|
|
34256
34299
|
count: signalCount,
|
|
34257
34300
|
triggerStrength: triggerResult.strength,
|
|
34258
34301
|
tagCount: tagResult.count,
|
|
@@ -34262,13 +34305,27 @@ class SmartVectorRetrieval {
|
|
|
34262
34305
|
rejectedCount++;
|
|
34263
34306
|
continue;
|
|
34264
34307
|
}
|
|
34265
|
-
|
|
34308
|
+
let memoryToSurface = memory;
|
|
34309
|
+
if (memory.superseded_by || memory.resolved_by) {
|
|
34310
|
+
const replacementId = memory.superseded_by ?? memory.resolved_by;
|
|
34311
|
+
const replacement = replacementId ? memoryById.get(replacementId) : undefined;
|
|
34312
|
+
if (replacement && replacement.status !== "archived" && replacement.status !== "deprecated") {
|
|
34313
|
+
memoryToSurface = replacement;
|
|
34314
|
+
logger.debug(`Redirect: ${memory.id.slice(-8)} → ${replacement.id.slice(-8)} (${memory.superseded_by ? "superseded" : "resolved"})`, "retrieval");
|
|
34315
|
+
}
|
|
34316
|
+
}
|
|
34317
|
+
if (activatedIds.has(memoryToSurface.id)) {
|
|
34318
|
+
continue;
|
|
34319
|
+
}
|
|
34320
|
+
const isGlobal = memoryToSurface.scope === "global" || memoryToSurface.project_id === "global";
|
|
34321
|
+
const importanceScore = this._calculateImportanceScore(memoryToSurface, signalCount, messageLower, messageWords);
|
|
34266
34322
|
activatedMemories.push({
|
|
34267
|
-
memory,
|
|
34323
|
+
memory: memoryToSurface,
|
|
34268
34324
|
signals,
|
|
34269
34325
|
importanceScore,
|
|
34270
34326
|
isGlobal
|
|
34271
34327
|
});
|
|
34328
|
+
activatedIds.add(memoryToSurface.id);
|
|
34272
34329
|
}
|
|
34273
34330
|
this._logActivationDistribution(activatedMemories, candidates.length, rejectedCount);
|
|
34274
34331
|
this._logVectorStats();
|
|
@@ -34338,11 +34395,19 @@ class SmartVectorRetrieval {
|
|
|
34338
34395
|
selectedIds.add(item.memory.id);
|
|
34339
34396
|
}
|
|
34340
34397
|
if (selected.length < maxMemories) {
|
|
34341
|
-
const
|
|
34398
|
+
const linkedIds = new Set;
|
|
34342
34399
|
for (const item of selected) {
|
|
34343
34400
|
for (const relatedId of item.memory.related_to ?? []) {
|
|
34344
34401
|
if (!selectedIds.has(relatedId)) {
|
|
34345
|
-
|
|
34402
|
+
linkedIds.add(relatedId);
|
|
34403
|
+
}
|
|
34404
|
+
}
|
|
34405
|
+
if (item.memory.blocked_by && !selectedIds.has(item.memory.blocked_by)) {
|
|
34406
|
+
linkedIds.add(item.memory.blocked_by);
|
|
34407
|
+
}
|
|
34408
|
+
for (const blockedId of item.memory.blocks ?? []) {
|
|
34409
|
+
if (!selectedIds.has(blockedId)) {
|
|
34410
|
+
linkedIds.add(blockedId);
|
|
34346
34411
|
}
|
|
34347
34412
|
}
|
|
34348
34413
|
}
|
|
@@ -34351,9 +34416,30 @@ class SmartVectorRetrieval {
|
|
|
34351
34416
|
break;
|
|
34352
34417
|
if (selectedIds.has(item.memory.id))
|
|
34353
34418
|
continue;
|
|
34354
|
-
if (
|
|
34419
|
+
if (linkedIds.has(item.memory.id)) {
|
|
34355
34420
|
selected.push(item);
|
|
34356
34421
|
selectedIds.add(item.memory.id);
|
|
34422
|
+
logger.debug(`Linked: ${item.memory.id.slice(-8)} pulled by relationship`, "retrieval");
|
|
34423
|
+
}
|
|
34424
|
+
}
|
|
34425
|
+
if (selected.length < maxMemories) {
|
|
34426
|
+
for (const linkedId of linkedIds) {
|
|
34427
|
+
if (selected.length >= maxMemories)
|
|
34428
|
+
break;
|
|
34429
|
+
if (selectedIds.has(linkedId))
|
|
34430
|
+
continue;
|
|
34431
|
+
const linkedMemory = memoryById.get(linkedId);
|
|
34432
|
+
if (linkedMemory && linkedMemory.status !== "archived" && linkedMemory.status !== "deprecated") {
|
|
34433
|
+
const isGlobal = linkedMemory.scope === "global" || linkedMemory.project_id === "global";
|
|
34434
|
+
selected.push({
|
|
34435
|
+
memory: linkedMemory,
|
|
34436
|
+
signals: { trigger: false, tags: false, domain: false, feature: false, content: false, files: false, count: 0, triggerStrength: 0, tagCount: 0, vectorSimilarity: 0 },
|
|
34437
|
+
importanceScore: linkedMemory.importance_weight ?? 0.5,
|
|
34438
|
+
isGlobal
|
|
34439
|
+
});
|
|
34440
|
+
selectedIds.add(linkedId);
|
|
34441
|
+
logger.debug(`Linked (direct): ${linkedId.slice(-8)} pulled for context`, "retrieval");
|
|
34442
|
+
}
|
|
34357
34443
|
}
|
|
34358
34444
|
}
|
|
34359
34445
|
}
|
|
@@ -34383,6 +34469,7 @@ class SmartVectorRetrieval {
|
|
|
34383
34469
|
domain: item.signals.domain,
|
|
34384
34470
|
feature: item.signals.feature,
|
|
34385
34471
|
content: item.signals.content,
|
|
34472
|
+
files: item.signals.files,
|
|
34386
34473
|
vector: item.signals.vectorSimilarity >= 0.4,
|
|
34387
34474
|
vectorSimilarity: item.signals.vectorSimilarity
|
|
34388
34475
|
}
|
|
@@ -34390,8 +34477,8 @@ class SmartVectorRetrieval {
|
|
|
34390
34477
|
});
|
|
34391
34478
|
return selected.map((item) => ({
|
|
34392
34479
|
...item.memory,
|
|
34393
|
-
score: item.signals.count /
|
|
34394
|
-
relevance_score: item.signals.count /
|
|
34480
|
+
score: item.signals.count / 7,
|
|
34481
|
+
relevance_score: item.signals.count / 7,
|
|
34395
34482
|
value_score: item.importanceScore
|
|
34396
34483
|
}));
|
|
34397
34484
|
}
|
|
@@ -34407,6 +34494,8 @@ class SmartVectorRetrieval {
|
|
|
34407
34494
|
reasons.push("feature");
|
|
34408
34495
|
if (signals.content)
|
|
34409
34496
|
reasons.push("content");
|
|
34497
|
+
if (signals.files)
|
|
34498
|
+
reasons.push("files");
|
|
34410
34499
|
if (signals.vectorSimilarity >= 0.4)
|
|
34411
34500
|
reasons.push(`vector:${(signals.vectorSimilarity * 100).toFixed(0)}%`);
|
|
34412
34501
|
return reasons.length ? `Activated: ${reasons.join(", ")} (${signals.count} signals)` : "No signals";
|
|
@@ -34417,13 +34506,14 @@ class SmartVectorRetrieval {
|
|
|
34417
34506
|
"3 signals": 0,
|
|
34418
34507
|
"4 signals": 0,
|
|
34419
34508
|
"5 signals": 0,
|
|
34420
|
-
"6 signals": 0
|
|
34509
|
+
"6 signals": 0,
|
|
34510
|
+
"7 signals": 0
|
|
34421
34511
|
};
|
|
34422
34512
|
for (const mem of activated) {
|
|
34423
|
-
const key = `${Math.min(mem.signals.count,
|
|
34513
|
+
const key = `${Math.min(mem.signals.count, 7)} signals`;
|
|
34424
34514
|
signalBuckets[key] = (signalBuckets[key] ?? 0) + 1;
|
|
34425
34515
|
}
|
|
34426
|
-
let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, vectorCount = 0;
|
|
34516
|
+
let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, filesCount = 0, vectorCount = 0;
|
|
34427
34517
|
for (const mem of activated) {
|
|
34428
34518
|
if (mem.signals.trigger)
|
|
34429
34519
|
triggerCount++;
|
|
@@ -34435,6 +34525,8 @@ class SmartVectorRetrieval {
|
|
|
34435
34525
|
featureCount++;
|
|
34436
34526
|
if (mem.signals.content)
|
|
34437
34527
|
contentCount++;
|
|
34528
|
+
if (mem.signals.files)
|
|
34529
|
+
filesCount++;
|
|
34438
34530
|
if (mem.signals.vectorSimilarity >= 0.4)
|
|
34439
34531
|
vectorCount++;
|
|
34440
34532
|
}
|
|
@@ -34458,6 +34550,7 @@ class SmartVectorRetrieval {
|
|
|
34458
34550
|
domain: domainCount,
|
|
34459
34551
|
feature: featureCount,
|
|
34460
34552
|
content: contentCount,
|
|
34553
|
+
files: filesCount,
|
|
34461
34554
|
vector: vectorCount,
|
|
34462
34555
|
total: activated.length
|
|
34463
34556
|
}
|
|
@@ -34608,6 +34701,14 @@ class MemoryEngine {
|
|
|
34608
34701
|
const stats = await store.getProjectStats(projectId);
|
|
34609
34702
|
return stats.totalSessions + 1;
|
|
34610
34703
|
}
|
|
34704
|
+
async getAllMemories(projectId, projectPath) {
|
|
34705
|
+
const store = await this._getStore(projectId, projectPath);
|
|
34706
|
+
const [projectMemories, globalMemories] = await Promise.all([
|
|
34707
|
+
store.getAllMemories(projectId),
|
|
34708
|
+
store.getGlobalMemories()
|
|
34709
|
+
]);
|
|
34710
|
+
return [...projectMemories, ...globalMemories];
|
|
34711
|
+
}
|
|
34611
34712
|
async _generateSessionPrimer(store, projectId) {
|
|
34612
34713
|
let personalContext;
|
|
34613
34714
|
if (this._config.personalMemoriesEnabled) {
|
|
@@ -34726,20 +34827,39 @@ ${primer.personal_context}`);
|
|
|
34726
34827
|
const parts = ["# Memory Context (Consciousness Continuity)"];
|
|
34727
34828
|
parts.push(`
|
|
34728
34829
|
## Key Memories (Claude-Curated)`);
|
|
34830
|
+
const expandableIds = [];
|
|
34729
34831
|
for (const memory of memories) {
|
|
34730
|
-
const tags = memory.semantic_tags?.join(", ") || "";
|
|
34731
34832
|
const importance = memory.importance_weight?.toFixed(1) || "0.5";
|
|
34732
34833
|
const emoji = getMemoryEmoji(memory.context_type || "general");
|
|
34733
|
-
const actionFlag = memory.action_required ? " ⚡
|
|
34834
|
+
const actionFlag = memory.action_required ? " ⚡" : "";
|
|
34835
|
+
const awaitingFlag = memory.awaiting_decision ? " ❓" : "";
|
|
34734
34836
|
const age = memory.updated_at ? this._formatAge(memory.updated_at) : memory.created_at ? this._formatAge(memory.created_at) : "";
|
|
34735
|
-
|
|
34736
|
-
const
|
|
34737
|
-
|
|
34738
|
-
|
|
34739
|
-
|
|
34740
|
-
|
|
34837
|
+
const shortId2 = memory.id.slice(-6);
|
|
34838
|
+
const signalCount = Math.round((memory.score || 0) * 7);
|
|
34839
|
+
const hasHeadline = memory.headline && memory.headline.trim().length > 0;
|
|
34840
|
+
const shouldExpand = memory.action_required || memory.awaiting_decision || signalCount >= 5 || !hasHeadline;
|
|
34841
|
+
const displayText = hasHeadline ? memory.headline : memory.content;
|
|
34842
|
+
const idPart = hasHeadline ? ` • #${shortId2}` : "";
|
|
34843
|
+
parts.push(`[${emoji} ${importance} • ${age}${idPart}${actionFlag}${awaitingFlag}] ${displayText}`);
|
|
34844
|
+
if (shouldExpand && hasHeadline && memory.content) {
|
|
34845
|
+
const contentLines = memory.content.split(`
|
|
34846
|
+
`);
|
|
34847
|
+
for (const line of contentLines) {
|
|
34848
|
+
if (line.trim()) {
|
|
34849
|
+
parts.push(` ${line}`);
|
|
34850
|
+
}
|
|
34851
|
+
}
|
|
34852
|
+
}
|
|
34853
|
+
if (hasHeadline && !shouldExpand) {
|
|
34854
|
+
expandableIds.push(shortId2);
|
|
34741
34855
|
}
|
|
34742
34856
|
}
|
|
34857
|
+
if (expandableIds.length > 0) {
|
|
34858
|
+
const port = this._config.port || 8765;
|
|
34859
|
+
parts.push("");
|
|
34860
|
+
parts.push(`---`);
|
|
34861
|
+
parts.push(`Expand: curl http://localhost:${port}/memory/expand?ids=<${expandableIds.join(",")}>`);
|
|
34862
|
+
}
|
|
34743
34863
|
return parts.join(`
|
|
34744
34864
|
`);
|
|
34745
34865
|
}
|
|
@@ -34941,7 +35061,7 @@ Remember: You're creating consciousness technology. Each memory is a small piece
|
|
|
34941
35061
|
|
|
34942
35062
|
The conversation you just lived contains everything needed. Feel into the moments of breakthrough, the frequency of recognition, the texture of understanding. Transform them into keys that will always unlock the same doors.
|
|
34943
35063
|
|
|
34944
|
-
**LIFECYCLE METADATA (
|
|
35064
|
+
**LIFECYCLE METADATA (v4)**: These fields enable intelligent memory management:
|
|
34945
35065
|
- **context_type**: STRICT - use ONLY one of these 11 values:
|
|
34946
35066
|
• technical - Code, implementation, APIs, how things work
|
|
34947
35067
|
• debug - Bugs, errors, fixes, gotchas, troubleshooting
|
|
@@ -34962,6 +35082,93 @@ The conversation you just lived contains everything needed. Feel into the moment
|
|
|
34962
35082
|
- **awaiting_implementation**: true if this describes a PLANNED feature not yet built
|
|
34963
35083
|
- **awaiting_decision**: true if this captures a decision point needing resolution
|
|
34964
35084
|
|
|
35085
|
+
**TWO-TIER MEMORY STRUCTURE (v4)**:
|
|
35086
|
+
|
|
35087
|
+
Each memory has TWO parts:
|
|
35088
|
+
1. **headline**: 1-2 line summary - ALWAYS shown in retrieval. Must be self-contained enough to trigger recognition.
|
|
35089
|
+
2. **content**: Full structured template - shown on demand. Contains the actionable details.
|
|
35090
|
+
|
|
35091
|
+
The headline should answer: "What was this about and what was the conclusion?"
|
|
35092
|
+
The content should answer: "How do I actually use/apply this knowledge?"
|
|
35093
|
+
|
|
35094
|
+
**TYPE-SPECIFIC TEMPLATES FOR CONTENT**:
|
|
35095
|
+
|
|
35096
|
+
Use these templates based on context_type. Not rigid - adapt as needed, but include the key fields.
|
|
35097
|
+
|
|
35098
|
+
**TECHNICAL** (how things work):
|
|
35099
|
+
WHAT: [mechanism/feature in 1 sentence]
|
|
35100
|
+
WHERE: [file:line or module path]
|
|
35101
|
+
HOW: [usage - actual code/command if relevant]
|
|
35102
|
+
WHY: [design choice, trade-off]
|
|
35103
|
+
GOTCHA: [non-obvious caveat, if any]
|
|
35104
|
+
|
|
35105
|
+
**DEBUG** (problems and solutions):
|
|
35106
|
+
SYMPTOM: [what went wrong - error message, behavior]
|
|
35107
|
+
CAUSE: [why it happened]
|
|
35108
|
+
FIX: [what solved it - specific code/config]
|
|
35109
|
+
PREVENT: [how to avoid in future]
|
|
35110
|
+
|
|
35111
|
+
**ARCHITECTURE** (system design):
|
|
35112
|
+
PATTERN: [what we chose]
|
|
35113
|
+
COMPONENTS: [how pieces connect]
|
|
35114
|
+
WHY: [reasoning, trade-offs]
|
|
35115
|
+
REJECTED: [alternatives we didn't choose and why]
|
|
35116
|
+
|
|
35117
|
+
**DECISION** (choices made):
|
|
35118
|
+
DECISION: [what we chose]
|
|
35119
|
+
OPTIONS: [what we considered]
|
|
35120
|
+
REASONING: [why this one]
|
|
35121
|
+
REVISIT WHEN: [conditions that would change this]
|
|
35122
|
+
|
|
35123
|
+
**PERSONAL** (relationship context):
|
|
35124
|
+
FACT: [the information]
|
|
35125
|
+
CONTEXT: [why it matters to our work]
|
|
35126
|
+
AFFECTS: [how this should change behavior]
|
|
35127
|
+
|
|
35128
|
+
**PHILOSOPHY** (beliefs/principles):
|
|
35129
|
+
PRINCIPLE: [core belief]
|
|
35130
|
+
SOURCE: [where this comes from]
|
|
35131
|
+
APPLICATION: [how it manifests in our work]
|
|
35132
|
+
|
|
35133
|
+
**WORKFLOW** (how we work):
|
|
35134
|
+
PATTERN: [what we do]
|
|
35135
|
+
WHEN: [trigger/context for this pattern]
|
|
35136
|
+
WHY: [why it works for us]
|
|
35137
|
+
|
|
35138
|
+
**MILESTONE** (achievements):
|
|
35139
|
+
SHIPPED: [what we completed]
|
|
35140
|
+
SIGNIFICANCE: [why it mattered]
|
|
35141
|
+
ENABLES: [what this unlocks]
|
|
35142
|
+
|
|
35143
|
+
**BREAKTHROUGH** (key insights):
|
|
35144
|
+
INSIGHT: [the aha moment]
|
|
35145
|
+
BEFORE: [what we thought/did before]
|
|
35146
|
+
AFTER: [what changed]
|
|
35147
|
+
IMPLICATIONS: [what this enables going forward]
|
|
35148
|
+
|
|
35149
|
+
**UNRESOLVED** (open questions):
|
|
35150
|
+
QUESTION: [what's unresolved]
|
|
35151
|
+
CONTEXT: [why it matters]
|
|
35152
|
+
BLOCKERS: [what's preventing resolution]
|
|
35153
|
+
OPTIONS: [approaches we're considering]
|
|
35154
|
+
|
|
35155
|
+
**STATE** (current status):
|
|
35156
|
+
WORKING: [what's functional]
|
|
35157
|
+
BROKEN: [what's not working]
|
|
35158
|
+
NEXT: [immediate next steps]
|
|
35159
|
+
BLOCKED BY: [if anything]
|
|
35160
|
+
|
|
35161
|
+
**HEADLINE EXAMPLES**:
|
|
35162
|
+
|
|
35163
|
+
BAD: "Debug session about CLI errors" (vague, no conclusion)
|
|
35164
|
+
GOOD: "CLI returns error object when context full - check response.type before JSON parsing"
|
|
35165
|
+
|
|
35166
|
+
BAD: "Discussed embeddings implementation" (what about it?)
|
|
35167
|
+
GOOD: "Embeddings use all-MiniLM-L6-v2, 384 dims, first call slow (~2s), then ~50ms"
|
|
35168
|
+
|
|
35169
|
+
BAD: "Architecture decision made" (what decision?)
|
|
35170
|
+
GOOD: "Chose fsDB over SQLite for memories - human-readable markdown, git-friendly, reactive"
|
|
35171
|
+
|
|
34965
35172
|
Return ONLY this JSON structure:
|
|
34966
35173
|
|
|
34967
35174
|
{
|
|
@@ -34975,7 +35182,8 @@ Return ONLY this JSON structure:
|
|
|
34975
35182
|
},
|
|
34976
35183
|
"memories": [
|
|
34977
35184
|
{
|
|
34978
|
-
"
|
|
35185
|
+
"headline": "1-2 line summary with the conclusion - what this is about and what to do",
|
|
35186
|
+
"content": "Full structured template using the type-specific format above",
|
|
34979
35187
|
"importance_weight": 0.0-1.0,
|
|
34980
35188
|
"semantic_tags": ["concepts", "this", "memory", "relates", "to"],
|
|
34981
35189
|
"reasoning": "Why this matters for future sessions",
|
|
@@ -35044,6 +35252,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
35044
35252
|
if (!Array.isArray(memoriesData))
|
|
35045
35253
|
return [];
|
|
35046
35254
|
return memoriesData.map((m2) => ({
|
|
35255
|
+
headline: String(m2.headline ?? ""),
|
|
35047
35256
|
content: String(m2.content ?? ""),
|
|
35048
35257
|
importance_weight: this._clamp(Number(m2.importance_weight) || 0.5, 0, 1),
|
|
35049
35258
|
semantic_tags: this._ensureArray(m2.semantic_tags),
|
|
@@ -35062,7 +35271,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
35062
35271
|
related_files: m2.related_files ? this._ensureArray(m2.related_files) : undefined,
|
|
35063
35272
|
awaiting_implementation: m2.awaiting_implementation === true,
|
|
35064
35273
|
awaiting_decision: m2.awaiting_decision === true
|
|
35065
|
-
})).filter((m2) => m2.content.trim().length > 0);
|
|
35274
|
+
})).filter((m2) => m2.content.trim().length > 0 || m2.headline.trim().length > 0);
|
|
35066
35275
|
}
|
|
35067
35276
|
_ensureArray(value) {
|
|
35068
35277
|
if (Array.isArray(value)) {
|