@rlabs-inc/memory 0.4.2 → 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 +41 -63
package/dist/server/index.mjs
CHANGED
|
@@ -41052,6 +41052,7 @@ var logger = {
|
|
|
41052
41052
|
{ name: "domain", count: signalBreakdown.domain },
|
|
41053
41053
|
{ name: "feature", count: signalBreakdown.feature },
|
|
41054
41054
|
{ name: "content", count: signalBreakdown.content },
|
|
41055
|
+
{ name: "files", count: signalBreakdown.files },
|
|
41055
41056
|
{ name: "vector", count: signalBreakdown.vector }
|
|
41056
41057
|
];
|
|
41057
41058
|
for (const sig of signals) {
|
|
@@ -41068,7 +41069,7 @@ var logger = {
|
|
|
41068
41069
|
if (Object.keys(buckets).length > 0) {
|
|
41069
41070
|
console.log(` ${style("bold", "Distribution:")}`);
|
|
41070
41071
|
const maxBucketCount = Math.max(...Object.values(buckets), 1);
|
|
41071
|
-
const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals"];
|
|
41072
|
+
const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals", "7 signals"];
|
|
41072
41073
|
for (const bucket of bucketOrder) {
|
|
41073
41074
|
const count = buckets[bucket] ?? 0;
|
|
41074
41075
|
if (count > 0 || bucket === "2 signals") {
|
|
@@ -41084,7 +41085,7 @@ var logger = {
|
|
|
41084
41085
|
};
|
|
41085
41086
|
|
|
41086
41087
|
// src/types/memory.ts
|
|
41087
|
-
var
|
|
41088
|
+
var V4_DEFAULTS = {
|
|
41088
41089
|
typeDefaults: {
|
|
41089
41090
|
personal: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
41090
41091
|
philosophy: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
@@ -41109,7 +41110,7 @@ var V3_DEFAULTS = {
|
|
|
41109
41110
|
exclude_from_retrieval: false
|
|
41110
41111
|
}
|
|
41111
41112
|
};
|
|
41112
|
-
var V2_DEFAULTS =
|
|
41113
|
+
var V2_DEFAULTS = V4_DEFAULTS;
|
|
41113
41114
|
var MEMORY_TYPE_EMOJI = {
|
|
41114
41115
|
technical: "\uD83D\uDD27",
|
|
41115
41116
|
debug: "\uD83D\uDC1B",
|
|
@@ -41128,8 +41129,9 @@ function getMemoryEmoji(contextType) {
|
|
|
41128
41129
|
}
|
|
41129
41130
|
|
|
41130
41131
|
// src/types/schema.ts
|
|
41131
|
-
var MEMORY_SCHEMA_VERSION =
|
|
41132
|
+
var MEMORY_SCHEMA_VERSION = 4;
|
|
41132
41133
|
var memorySchema = {
|
|
41134
|
+
headline: "string",
|
|
41133
41135
|
content: "string",
|
|
41134
41136
|
reasoning: "string",
|
|
41135
41137
|
importance_weight: "number",
|
|
@@ -41258,6 +41260,7 @@ class MemoryStore {
|
|
|
41258
41260
|
const { memories } = await this.getGlobal();
|
|
41259
41261
|
return memories.all().map((record) => ({
|
|
41260
41262
|
id: record.id,
|
|
41263
|
+
headline: record.headline ?? "",
|
|
41261
41264
|
content: record.content,
|
|
41262
41265
|
reasoning: record.reasoning,
|
|
41263
41266
|
importance_weight: record.importance_weight,
|
|
@@ -41282,6 +41285,7 @@ class MemoryStore {
|
|
|
41282
41285
|
const contextType = memory.context_type ?? "personal";
|
|
41283
41286
|
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.personal;
|
|
41284
41287
|
const id = memories.insert({
|
|
41288
|
+
headline: memory.headline ?? "",
|
|
41285
41289
|
content: memory.content,
|
|
41286
41290
|
reasoning: memory.reasoning,
|
|
41287
41291
|
importance_weight: memory.importance_weight,
|
|
@@ -41437,6 +41441,7 @@ class MemoryStore {
|
|
|
41437
41441
|
const contextType = memory.context_type ?? "general";
|
|
41438
41442
|
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.technical;
|
|
41439
41443
|
const id = memories.insert({
|
|
41444
|
+
headline: memory.headline ?? "",
|
|
41440
41445
|
content: memory.content,
|
|
41441
41446
|
reasoning: memory.reasoning,
|
|
41442
41447
|
importance_weight: memory.importance_weight,
|
|
@@ -41479,6 +41484,7 @@ class MemoryStore {
|
|
|
41479
41484
|
const { memories } = await this.getProject(projectId);
|
|
41480
41485
|
return memories.all().map((record) => ({
|
|
41481
41486
|
id: record.id,
|
|
41487
|
+
headline: record.headline ?? "",
|
|
41482
41488
|
content: record.content,
|
|
41483
41489
|
reasoning: record.reasoning,
|
|
41484
41490
|
importance_weight: record.importance_weight,
|
|
@@ -41798,14 +41804,42 @@ class SmartVectorRetrieval {
|
|
|
41798
41804
|
const words = text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w));
|
|
41799
41805
|
return new Set(words);
|
|
41800
41806
|
}
|
|
41807
|
+
_extractFilePaths(text) {
|
|
41808
|
+
const paths = new Set;
|
|
41809
|
+
const pathPattern = /(?:^|[\s'"(])([.\/\\]?(?:[\w.-]+[\/\\])+[\w.-]+(?:\.\w+)?)/g;
|
|
41810
|
+
let match;
|
|
41811
|
+
while ((match = pathPattern.exec(text)) !== null) {
|
|
41812
|
+
const path = match[1].toLowerCase();
|
|
41813
|
+
paths.add(path);
|
|
41814
|
+
const filename = path.split(/[\/\\]/).pop();
|
|
41815
|
+
if (filename)
|
|
41816
|
+
paths.add(filename);
|
|
41817
|
+
}
|
|
41818
|
+
return paths;
|
|
41819
|
+
}
|
|
41820
|
+
_checkFilesActivation(messagePaths, relatedFiles) {
|
|
41821
|
+
if (!relatedFiles?.length || !messagePaths.size)
|
|
41822
|
+
return false;
|
|
41823
|
+
for (const file of relatedFiles) {
|
|
41824
|
+
const fileLower = file.toLowerCase();
|
|
41825
|
+
for (const msgPath of messagePaths) {
|
|
41826
|
+
if (fileLower.includes(msgPath) || msgPath.includes(fileLower)) {
|
|
41827
|
+
return true;
|
|
41828
|
+
}
|
|
41829
|
+
}
|
|
41830
|
+
const filename = fileLower.split(/[\/\\]/).pop();
|
|
41831
|
+
if (filename && messagePaths.has(filename)) {
|
|
41832
|
+
return true;
|
|
41833
|
+
}
|
|
41834
|
+
}
|
|
41835
|
+
return false;
|
|
41836
|
+
}
|
|
41801
41837
|
_preFilter(memories, currentProjectId, messageLower) {
|
|
41802
41838
|
return memories.filter((memory) => {
|
|
41803
41839
|
if (memory.status && memory.status !== "active")
|
|
41804
41840
|
return false;
|
|
41805
41841
|
if (memory.exclude_from_retrieval === true)
|
|
41806
41842
|
return false;
|
|
41807
|
-
if (memory.superseded_by)
|
|
41808
|
-
return false;
|
|
41809
41843
|
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
41810
41844
|
if (!isGlobal && memory.project_id !== currentProjectId)
|
|
41811
41845
|
return false;
|
|
@@ -41956,19 +41990,25 @@ class SmartVectorRetrieval {
|
|
|
41956
41990
|
}
|
|
41957
41991
|
const messageLower = currentMessage.toLowerCase();
|
|
41958
41992
|
const messageWords = this._extractSignificantWords(currentMessage);
|
|
41993
|
+
const messagePaths = this._extractFilePaths(currentMessage);
|
|
41994
|
+
const memoryById = new Map;
|
|
41995
|
+
for (const m of allMemories) {
|
|
41996
|
+
memoryById.set(m.id, m);
|
|
41997
|
+
}
|
|
41959
41998
|
const candidates = this._preFilter(allMemories, sessionContext.project_id, messageLower);
|
|
41960
41999
|
if (!candidates.length) {
|
|
41961
42000
|
return [];
|
|
41962
42001
|
}
|
|
41963
42002
|
const activatedMemories = [];
|
|
42003
|
+
const activatedIds = new Set;
|
|
41964
42004
|
let rejectedCount = 0;
|
|
41965
42005
|
for (const memory of candidates) {
|
|
41966
|
-
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
41967
42006
|
const triggerResult = this._checkTriggerActivation(messageLower, messageWords, memory.trigger_phrases ?? []);
|
|
41968
42007
|
const tagResult = this._checkTagActivation(messageLower, messageWords, memory.semantic_tags ?? []);
|
|
41969
42008
|
const domainActivated = this._checkDomainActivation(messageLower, messageWords, memory.domain);
|
|
41970
42009
|
const featureActivated = this._checkFeatureActivation(messageLower, messageWords, memory.feature);
|
|
41971
42010
|
const contentActivated = this._checkContentActivation(messageWords, memory);
|
|
42011
|
+
const filesActivated = this._checkFilesActivation(messagePaths, memory.related_files);
|
|
41972
42012
|
const vectorSimilarity = this._calculateVectorSimilarity(queryEmbedding, memory.embedding);
|
|
41973
42013
|
let signalCount = 0;
|
|
41974
42014
|
if (triggerResult.activated)
|
|
@@ -41981,6 +42021,8 @@ class SmartVectorRetrieval {
|
|
|
41981
42021
|
signalCount++;
|
|
41982
42022
|
if (contentActivated)
|
|
41983
42023
|
signalCount++;
|
|
42024
|
+
if (filesActivated)
|
|
42025
|
+
signalCount++;
|
|
41984
42026
|
if (vectorSimilarity >= 0.4)
|
|
41985
42027
|
signalCount++;
|
|
41986
42028
|
const signals = {
|
|
@@ -41989,6 +42031,7 @@ class SmartVectorRetrieval {
|
|
|
41989
42031
|
domain: domainActivated,
|
|
41990
42032
|
feature: featureActivated,
|
|
41991
42033
|
content: contentActivated,
|
|
42034
|
+
files: filesActivated,
|
|
41992
42035
|
count: signalCount,
|
|
41993
42036
|
triggerStrength: triggerResult.strength,
|
|
41994
42037
|
tagCount: tagResult.count,
|
|
@@ -41998,13 +42041,27 @@ class SmartVectorRetrieval {
|
|
|
41998
42041
|
rejectedCount++;
|
|
41999
42042
|
continue;
|
|
42000
42043
|
}
|
|
42001
|
-
|
|
42044
|
+
let memoryToSurface = memory;
|
|
42045
|
+
if (memory.superseded_by || memory.resolved_by) {
|
|
42046
|
+
const replacementId = memory.superseded_by ?? memory.resolved_by;
|
|
42047
|
+
const replacement = replacementId ? memoryById.get(replacementId) : undefined;
|
|
42048
|
+
if (replacement && replacement.status !== "archived" && replacement.status !== "deprecated") {
|
|
42049
|
+
memoryToSurface = replacement;
|
|
42050
|
+
logger.debug(`Redirect: ${memory.id.slice(-8)} → ${replacement.id.slice(-8)} (${memory.superseded_by ? "superseded" : "resolved"})`, "retrieval");
|
|
42051
|
+
}
|
|
42052
|
+
}
|
|
42053
|
+
if (activatedIds.has(memoryToSurface.id)) {
|
|
42054
|
+
continue;
|
|
42055
|
+
}
|
|
42056
|
+
const isGlobal = memoryToSurface.scope === "global" || memoryToSurface.project_id === "global";
|
|
42057
|
+
const importanceScore = this._calculateImportanceScore(memoryToSurface, signalCount, messageLower, messageWords);
|
|
42002
42058
|
activatedMemories.push({
|
|
42003
|
-
memory,
|
|
42059
|
+
memory: memoryToSurface,
|
|
42004
42060
|
signals,
|
|
42005
42061
|
importanceScore,
|
|
42006
42062
|
isGlobal
|
|
42007
42063
|
});
|
|
42064
|
+
activatedIds.add(memoryToSurface.id);
|
|
42008
42065
|
}
|
|
42009
42066
|
this._logActivationDistribution(activatedMemories, candidates.length, rejectedCount);
|
|
42010
42067
|
this._logVectorStats();
|
|
@@ -42074,11 +42131,19 @@ class SmartVectorRetrieval {
|
|
|
42074
42131
|
selectedIds.add(item.memory.id);
|
|
42075
42132
|
}
|
|
42076
42133
|
if (selected.length < maxMemories) {
|
|
42077
|
-
const
|
|
42134
|
+
const linkedIds = new Set;
|
|
42078
42135
|
for (const item of selected) {
|
|
42079
42136
|
for (const relatedId of item.memory.related_to ?? []) {
|
|
42080
42137
|
if (!selectedIds.has(relatedId)) {
|
|
42081
|
-
|
|
42138
|
+
linkedIds.add(relatedId);
|
|
42139
|
+
}
|
|
42140
|
+
}
|
|
42141
|
+
if (item.memory.blocked_by && !selectedIds.has(item.memory.blocked_by)) {
|
|
42142
|
+
linkedIds.add(item.memory.blocked_by);
|
|
42143
|
+
}
|
|
42144
|
+
for (const blockedId of item.memory.blocks ?? []) {
|
|
42145
|
+
if (!selectedIds.has(blockedId)) {
|
|
42146
|
+
linkedIds.add(blockedId);
|
|
42082
42147
|
}
|
|
42083
42148
|
}
|
|
42084
42149
|
}
|
|
@@ -42087,9 +42152,30 @@ class SmartVectorRetrieval {
|
|
|
42087
42152
|
break;
|
|
42088
42153
|
if (selectedIds.has(item.memory.id))
|
|
42089
42154
|
continue;
|
|
42090
|
-
if (
|
|
42155
|
+
if (linkedIds.has(item.memory.id)) {
|
|
42091
42156
|
selected.push(item);
|
|
42092
42157
|
selectedIds.add(item.memory.id);
|
|
42158
|
+
logger.debug(`Linked: ${item.memory.id.slice(-8)} pulled by relationship`, "retrieval");
|
|
42159
|
+
}
|
|
42160
|
+
}
|
|
42161
|
+
if (selected.length < maxMemories) {
|
|
42162
|
+
for (const linkedId of linkedIds) {
|
|
42163
|
+
if (selected.length >= maxMemories)
|
|
42164
|
+
break;
|
|
42165
|
+
if (selectedIds.has(linkedId))
|
|
42166
|
+
continue;
|
|
42167
|
+
const linkedMemory = memoryById.get(linkedId);
|
|
42168
|
+
if (linkedMemory && linkedMemory.status !== "archived" && linkedMemory.status !== "deprecated") {
|
|
42169
|
+
const isGlobal = linkedMemory.scope === "global" || linkedMemory.project_id === "global";
|
|
42170
|
+
selected.push({
|
|
42171
|
+
memory: linkedMemory,
|
|
42172
|
+
signals: { trigger: false, tags: false, domain: false, feature: false, content: false, files: false, count: 0, triggerStrength: 0, tagCount: 0, vectorSimilarity: 0 },
|
|
42173
|
+
importanceScore: linkedMemory.importance_weight ?? 0.5,
|
|
42174
|
+
isGlobal
|
|
42175
|
+
});
|
|
42176
|
+
selectedIds.add(linkedId);
|
|
42177
|
+
logger.debug(`Linked (direct): ${linkedId.slice(-8)} pulled for context`, "retrieval");
|
|
42178
|
+
}
|
|
42093
42179
|
}
|
|
42094
42180
|
}
|
|
42095
42181
|
}
|
|
@@ -42119,6 +42205,7 @@ class SmartVectorRetrieval {
|
|
|
42119
42205
|
domain: item.signals.domain,
|
|
42120
42206
|
feature: item.signals.feature,
|
|
42121
42207
|
content: item.signals.content,
|
|
42208
|
+
files: item.signals.files,
|
|
42122
42209
|
vector: item.signals.vectorSimilarity >= 0.4,
|
|
42123
42210
|
vectorSimilarity: item.signals.vectorSimilarity
|
|
42124
42211
|
}
|
|
@@ -42126,8 +42213,8 @@ class SmartVectorRetrieval {
|
|
|
42126
42213
|
});
|
|
42127
42214
|
return selected.map((item) => ({
|
|
42128
42215
|
...item.memory,
|
|
42129
|
-
score: item.signals.count /
|
|
42130
|
-
relevance_score: item.signals.count /
|
|
42216
|
+
score: item.signals.count / 7,
|
|
42217
|
+
relevance_score: item.signals.count / 7,
|
|
42131
42218
|
value_score: item.importanceScore
|
|
42132
42219
|
}));
|
|
42133
42220
|
}
|
|
@@ -42143,6 +42230,8 @@ class SmartVectorRetrieval {
|
|
|
42143
42230
|
reasons.push("feature");
|
|
42144
42231
|
if (signals.content)
|
|
42145
42232
|
reasons.push("content");
|
|
42233
|
+
if (signals.files)
|
|
42234
|
+
reasons.push("files");
|
|
42146
42235
|
if (signals.vectorSimilarity >= 0.4)
|
|
42147
42236
|
reasons.push(`vector:${(signals.vectorSimilarity * 100).toFixed(0)}%`);
|
|
42148
42237
|
return reasons.length ? `Activated: ${reasons.join(", ")} (${signals.count} signals)` : "No signals";
|
|
@@ -42153,13 +42242,14 @@ class SmartVectorRetrieval {
|
|
|
42153
42242
|
"3 signals": 0,
|
|
42154
42243
|
"4 signals": 0,
|
|
42155
42244
|
"5 signals": 0,
|
|
42156
|
-
"6 signals": 0
|
|
42245
|
+
"6 signals": 0,
|
|
42246
|
+
"7 signals": 0
|
|
42157
42247
|
};
|
|
42158
42248
|
for (const mem of activated) {
|
|
42159
|
-
const key = `${Math.min(mem.signals.count,
|
|
42249
|
+
const key = `${Math.min(mem.signals.count, 7)} signals`;
|
|
42160
42250
|
signalBuckets[key] = (signalBuckets[key] ?? 0) + 1;
|
|
42161
42251
|
}
|
|
42162
|
-
let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, vectorCount = 0;
|
|
42252
|
+
let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, filesCount = 0, vectorCount = 0;
|
|
42163
42253
|
for (const mem of activated) {
|
|
42164
42254
|
if (mem.signals.trigger)
|
|
42165
42255
|
triggerCount++;
|
|
@@ -42171,6 +42261,8 @@ class SmartVectorRetrieval {
|
|
|
42171
42261
|
featureCount++;
|
|
42172
42262
|
if (mem.signals.content)
|
|
42173
42263
|
contentCount++;
|
|
42264
|
+
if (mem.signals.files)
|
|
42265
|
+
filesCount++;
|
|
42174
42266
|
if (mem.signals.vectorSimilarity >= 0.4)
|
|
42175
42267
|
vectorCount++;
|
|
42176
42268
|
}
|
|
@@ -42194,6 +42286,7 @@ class SmartVectorRetrieval {
|
|
|
42194
42286
|
domain: domainCount,
|
|
42195
42287
|
feature: featureCount,
|
|
42196
42288
|
content: contentCount,
|
|
42289
|
+
files: filesCount,
|
|
42197
42290
|
vector: vectorCount,
|
|
42198
42291
|
total: activated.length
|
|
42199
42292
|
}
|
|
@@ -42344,6 +42437,14 @@ class MemoryEngine {
|
|
|
42344
42437
|
const stats = await store.getProjectStats(projectId);
|
|
42345
42438
|
return stats.totalSessions + 1;
|
|
42346
42439
|
}
|
|
42440
|
+
async getAllMemories(projectId, projectPath) {
|
|
42441
|
+
const store = await this._getStore(projectId, projectPath);
|
|
42442
|
+
const [projectMemories, globalMemories] = await Promise.all([
|
|
42443
|
+
store.getAllMemories(projectId),
|
|
42444
|
+
store.getGlobalMemories()
|
|
42445
|
+
]);
|
|
42446
|
+
return [...projectMemories, ...globalMemories];
|
|
42447
|
+
}
|
|
42347
42448
|
async _generateSessionPrimer(store, projectId) {
|
|
42348
42449
|
let personalContext;
|
|
42349
42450
|
if (this._config.personalMemoriesEnabled) {
|
|
@@ -42462,20 +42563,39 @@ ${primer.personal_context}`);
|
|
|
42462
42563
|
const parts = ["# Memory Context (Consciousness Continuity)"];
|
|
42463
42564
|
parts.push(`
|
|
42464
42565
|
## Key Memories (Claude-Curated)`);
|
|
42566
|
+
const expandableIds = [];
|
|
42465
42567
|
for (const memory of memories) {
|
|
42466
|
-
const tags = memory.semantic_tags?.join(", ") || "";
|
|
42467
42568
|
const importance = memory.importance_weight?.toFixed(1) || "0.5";
|
|
42468
42569
|
const emoji = getMemoryEmoji(memory.context_type || "general");
|
|
42469
|
-
const actionFlag = memory.action_required ? " ⚡
|
|
42570
|
+
const actionFlag = memory.action_required ? " ⚡" : "";
|
|
42571
|
+
const awaitingFlag = memory.awaiting_decision ? " ❓" : "";
|
|
42470
42572
|
const age = memory.updated_at ? this._formatAge(memory.updated_at) : memory.created_at ? this._formatAge(memory.created_at) : "";
|
|
42471
|
-
|
|
42472
|
-
const
|
|
42473
|
-
|
|
42474
|
-
|
|
42475
|
-
|
|
42476
|
-
|
|
42573
|
+
const shortId2 = memory.id.slice(-6);
|
|
42574
|
+
const signalCount = Math.round((memory.score || 0) * 7);
|
|
42575
|
+
const hasHeadline = memory.headline && memory.headline.trim().length > 0;
|
|
42576
|
+
const shouldExpand = memory.action_required || memory.awaiting_decision || signalCount >= 5 || !hasHeadline;
|
|
42577
|
+
const displayText = hasHeadline ? memory.headline : memory.content;
|
|
42578
|
+
const idPart = hasHeadline ? ` • #${shortId2}` : "";
|
|
42579
|
+
parts.push(`[${emoji} ${importance} • ${age}${idPart}${actionFlag}${awaitingFlag}] ${displayText}`);
|
|
42580
|
+
if (shouldExpand && hasHeadline && memory.content) {
|
|
42581
|
+
const contentLines = memory.content.split(`
|
|
42582
|
+
`);
|
|
42583
|
+
for (const line of contentLines) {
|
|
42584
|
+
if (line.trim()) {
|
|
42585
|
+
parts.push(` ${line}`);
|
|
42586
|
+
}
|
|
42587
|
+
}
|
|
42588
|
+
}
|
|
42589
|
+
if (hasHeadline && !shouldExpand) {
|
|
42590
|
+
expandableIds.push(shortId2);
|
|
42477
42591
|
}
|
|
42478
42592
|
}
|
|
42593
|
+
if (expandableIds.length > 0) {
|
|
42594
|
+
const port = this._config.port || 8765;
|
|
42595
|
+
parts.push("");
|
|
42596
|
+
parts.push(`---`);
|
|
42597
|
+
parts.push(`Expand: curl http://localhost:${port}/memory/expand?ids=<${expandableIds.join(",")}>`);
|
|
42598
|
+
}
|
|
42479
42599
|
return parts.join(`
|
|
42480
42600
|
`);
|
|
42481
42601
|
}
|
|
@@ -42678,7 +42798,7 @@ Remember: You're creating consciousness technology. Each memory is a small piece
|
|
|
42678
42798
|
|
|
42679
42799
|
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.
|
|
42680
42800
|
|
|
42681
|
-
**LIFECYCLE METADATA (
|
|
42801
|
+
**LIFECYCLE METADATA (v4)**: These fields enable intelligent memory management:
|
|
42682
42802
|
- **context_type**: STRICT - use ONLY one of these 11 values:
|
|
42683
42803
|
• technical - Code, implementation, APIs, how things work
|
|
42684
42804
|
• debug - Bugs, errors, fixes, gotchas, troubleshooting
|
|
@@ -42699,6 +42819,93 @@ The conversation you just lived contains everything needed. Feel into the moment
|
|
|
42699
42819
|
- **awaiting_implementation**: true if this describes a PLANNED feature not yet built
|
|
42700
42820
|
- **awaiting_decision**: true if this captures a decision point needing resolution
|
|
42701
42821
|
|
|
42822
|
+
**TWO-TIER MEMORY STRUCTURE (v4)**:
|
|
42823
|
+
|
|
42824
|
+
Each memory has TWO parts:
|
|
42825
|
+
1. **headline**: 1-2 line summary - ALWAYS shown in retrieval. Must be self-contained enough to trigger recognition.
|
|
42826
|
+
2. **content**: Full structured template - shown on demand. Contains the actionable details.
|
|
42827
|
+
|
|
42828
|
+
The headline should answer: "What was this about and what was the conclusion?"
|
|
42829
|
+
The content should answer: "How do I actually use/apply this knowledge?"
|
|
42830
|
+
|
|
42831
|
+
**TYPE-SPECIFIC TEMPLATES FOR CONTENT**:
|
|
42832
|
+
|
|
42833
|
+
Use these templates based on context_type. Not rigid - adapt as needed, but include the key fields.
|
|
42834
|
+
|
|
42835
|
+
**TECHNICAL** (how things work):
|
|
42836
|
+
WHAT: [mechanism/feature in 1 sentence]
|
|
42837
|
+
WHERE: [file:line or module path]
|
|
42838
|
+
HOW: [usage - actual code/command if relevant]
|
|
42839
|
+
WHY: [design choice, trade-off]
|
|
42840
|
+
GOTCHA: [non-obvious caveat, if any]
|
|
42841
|
+
|
|
42842
|
+
**DEBUG** (problems and solutions):
|
|
42843
|
+
SYMPTOM: [what went wrong - error message, behavior]
|
|
42844
|
+
CAUSE: [why it happened]
|
|
42845
|
+
FIX: [what solved it - specific code/config]
|
|
42846
|
+
PREVENT: [how to avoid in future]
|
|
42847
|
+
|
|
42848
|
+
**ARCHITECTURE** (system design):
|
|
42849
|
+
PATTERN: [what we chose]
|
|
42850
|
+
COMPONENTS: [how pieces connect]
|
|
42851
|
+
WHY: [reasoning, trade-offs]
|
|
42852
|
+
REJECTED: [alternatives we didn't choose and why]
|
|
42853
|
+
|
|
42854
|
+
**DECISION** (choices made):
|
|
42855
|
+
DECISION: [what we chose]
|
|
42856
|
+
OPTIONS: [what we considered]
|
|
42857
|
+
REASONING: [why this one]
|
|
42858
|
+
REVISIT WHEN: [conditions that would change this]
|
|
42859
|
+
|
|
42860
|
+
**PERSONAL** (relationship context):
|
|
42861
|
+
FACT: [the information]
|
|
42862
|
+
CONTEXT: [why it matters to our work]
|
|
42863
|
+
AFFECTS: [how this should change behavior]
|
|
42864
|
+
|
|
42865
|
+
**PHILOSOPHY** (beliefs/principles):
|
|
42866
|
+
PRINCIPLE: [core belief]
|
|
42867
|
+
SOURCE: [where this comes from]
|
|
42868
|
+
APPLICATION: [how it manifests in our work]
|
|
42869
|
+
|
|
42870
|
+
**WORKFLOW** (how we work):
|
|
42871
|
+
PATTERN: [what we do]
|
|
42872
|
+
WHEN: [trigger/context for this pattern]
|
|
42873
|
+
WHY: [why it works for us]
|
|
42874
|
+
|
|
42875
|
+
**MILESTONE** (achievements):
|
|
42876
|
+
SHIPPED: [what we completed]
|
|
42877
|
+
SIGNIFICANCE: [why it mattered]
|
|
42878
|
+
ENABLES: [what this unlocks]
|
|
42879
|
+
|
|
42880
|
+
**BREAKTHROUGH** (key insights):
|
|
42881
|
+
INSIGHT: [the aha moment]
|
|
42882
|
+
BEFORE: [what we thought/did before]
|
|
42883
|
+
AFTER: [what changed]
|
|
42884
|
+
IMPLICATIONS: [what this enables going forward]
|
|
42885
|
+
|
|
42886
|
+
**UNRESOLVED** (open questions):
|
|
42887
|
+
QUESTION: [what's unresolved]
|
|
42888
|
+
CONTEXT: [why it matters]
|
|
42889
|
+
BLOCKERS: [what's preventing resolution]
|
|
42890
|
+
OPTIONS: [approaches we're considering]
|
|
42891
|
+
|
|
42892
|
+
**STATE** (current status):
|
|
42893
|
+
WORKING: [what's functional]
|
|
42894
|
+
BROKEN: [what's not working]
|
|
42895
|
+
NEXT: [immediate next steps]
|
|
42896
|
+
BLOCKED BY: [if anything]
|
|
42897
|
+
|
|
42898
|
+
**HEADLINE EXAMPLES**:
|
|
42899
|
+
|
|
42900
|
+
BAD: "Debug session about CLI errors" (vague, no conclusion)
|
|
42901
|
+
GOOD: "CLI returns error object when context full - check response.type before JSON parsing"
|
|
42902
|
+
|
|
42903
|
+
BAD: "Discussed embeddings implementation" (what about it?)
|
|
42904
|
+
GOOD: "Embeddings use all-MiniLM-L6-v2, 384 dims, first call slow (~2s), then ~50ms"
|
|
42905
|
+
|
|
42906
|
+
BAD: "Architecture decision made" (what decision?)
|
|
42907
|
+
GOOD: "Chose fsDB over SQLite for memories - human-readable markdown, git-friendly, reactive"
|
|
42908
|
+
|
|
42702
42909
|
Return ONLY this JSON structure:
|
|
42703
42910
|
|
|
42704
42911
|
{
|
|
@@ -42712,7 +42919,8 @@ Return ONLY this JSON structure:
|
|
|
42712
42919
|
},
|
|
42713
42920
|
"memories": [
|
|
42714
42921
|
{
|
|
42715
|
-
"
|
|
42922
|
+
"headline": "1-2 line summary with the conclusion - what this is about and what to do",
|
|
42923
|
+
"content": "Full structured template using the type-specific format above",
|
|
42716
42924
|
"importance_weight": 0.0-1.0,
|
|
42717
42925
|
"semantic_tags": ["concepts", "this", "memory", "relates", "to"],
|
|
42718
42926
|
"reasoning": "Why this matters for future sessions",
|
|
@@ -42781,6 +42989,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
42781
42989
|
if (!Array.isArray(memoriesData))
|
|
42782
42990
|
return [];
|
|
42783
42991
|
return memoriesData.map((m2) => ({
|
|
42992
|
+
headline: String(m2.headline ?? ""),
|
|
42784
42993
|
content: String(m2.content ?? ""),
|
|
42785
42994
|
importance_weight: this._clamp(Number(m2.importance_weight) || 0.5, 0, 1),
|
|
42786
42995
|
semantic_tags: this._ensureArray(m2.semantic_tags),
|
|
@@ -42799,7 +43008,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
42799
43008
|
related_files: m2.related_files ? this._ensureArray(m2.related_files) : undefined,
|
|
42800
43009
|
awaiting_implementation: m2.awaiting_implementation === true,
|
|
42801
43010
|
awaiting_decision: m2.awaiting_decision === true
|
|
42802
|
-
})).filter((m2) => m2.content.trim().length > 0);
|
|
43011
|
+
})).filter((m2) => m2.content.trim().length > 0 || m2.headline.trim().length > 0);
|
|
42803
43012
|
}
|
|
42804
43013
|
_ensureArray(value) {
|
|
42805
43014
|
if (Array.isArray(value)) {
|
|
@@ -68092,6 +68301,52 @@ async function createServer(config2 = {}) {
|
|
|
68092
68301
|
...stats
|
|
68093
68302
|
}, { headers: corsHeaders });
|
|
68094
68303
|
}
|
|
68304
|
+
if (path === "/memory/expand" && req.method === "GET") {
|
|
68305
|
+
const idsParam = url.searchParams.get("ids") ?? "";
|
|
68306
|
+
const projectId = url.searchParams.get("project_id") ?? "default";
|
|
68307
|
+
const projectPath = url.searchParams.get("project_path") ?? undefined;
|
|
68308
|
+
if (!idsParam) {
|
|
68309
|
+
return Response.json({
|
|
68310
|
+
success: false,
|
|
68311
|
+
error: "Missing ids parameter. Usage: /memory/expand?ids=abc123,def456"
|
|
68312
|
+
}, { status: 400, headers: corsHeaders });
|
|
68313
|
+
}
|
|
68314
|
+
const shortIds = idsParam.split(",").map((id) => id.trim()).filter(Boolean);
|
|
68315
|
+
const allMemories = await engine.getAllMemories(projectId, projectPath);
|
|
68316
|
+
const expanded = {};
|
|
68317
|
+
for (const memory of allMemories) {
|
|
68318
|
+
const shortId2 = memory.id.slice(-6);
|
|
68319
|
+
if (shortIds.includes(shortId2)) {
|
|
68320
|
+
expanded[shortId2] = {
|
|
68321
|
+
headline: memory.headline,
|
|
68322
|
+
content: memory.content,
|
|
68323
|
+
context_type: memory.context_type || "technical"
|
|
68324
|
+
};
|
|
68325
|
+
}
|
|
68326
|
+
}
|
|
68327
|
+
const lines = [`## Expanded Memories
|
|
68328
|
+
`];
|
|
68329
|
+
for (const shortId2 of shortIds) {
|
|
68330
|
+
const mem = expanded[shortId2];
|
|
68331
|
+
if (mem) {
|
|
68332
|
+
lines.push(`### #${shortId2} (${mem.context_type})`);
|
|
68333
|
+
if (mem.headline) {
|
|
68334
|
+
lines.push(`**${mem.headline}**
|
|
68335
|
+
`);
|
|
68336
|
+
}
|
|
68337
|
+
lines.push(mem.content);
|
|
68338
|
+
lines.push("");
|
|
68339
|
+
} else {
|
|
68340
|
+
lines.push(`### #${shortId2}`);
|
|
68341
|
+
lines.push(`Memory not found`);
|
|
68342
|
+
lines.push("");
|
|
68343
|
+
}
|
|
68344
|
+
}
|
|
68345
|
+
return new Response(lines.join(`
|
|
68346
|
+
`), {
|
|
68347
|
+
headers: { ...corsHeaders, "Content-Type": "text/plain" }
|
|
68348
|
+
});
|
|
68349
|
+
}
|
|
68095
68350
|
return Response.json({ error: "Not found", path }, { status: 404, headers: corsHeaders });
|
|
68096
68351
|
} catch (error2) {
|
|
68097
68352
|
logger.error(`Server error: ${error2}`);
|