@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/server/index.js
CHANGED
|
@@ -41072,6 +41072,7 @@ var logger = {
|
|
|
41072
41072
|
{ name: "domain", count: signalBreakdown.domain },
|
|
41073
41073
|
{ name: "feature", count: signalBreakdown.feature },
|
|
41074
41074
|
{ name: "content", count: signalBreakdown.content },
|
|
41075
|
+
{ name: "files", count: signalBreakdown.files },
|
|
41075
41076
|
{ name: "vector", count: signalBreakdown.vector }
|
|
41076
41077
|
];
|
|
41077
41078
|
for (const sig of signals) {
|
|
@@ -41088,7 +41089,7 @@ var logger = {
|
|
|
41088
41089
|
if (Object.keys(buckets).length > 0) {
|
|
41089
41090
|
console.log(` ${style("bold", "Distribution:")}`);
|
|
41090
41091
|
const maxBucketCount = Math.max(...Object.values(buckets), 1);
|
|
41091
|
-
const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals"];
|
|
41092
|
+
const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals", "7 signals"];
|
|
41092
41093
|
for (const bucket of bucketOrder) {
|
|
41093
41094
|
const count = buckets[bucket] ?? 0;
|
|
41094
41095
|
if (count > 0 || bucket === "2 signals") {
|
|
@@ -41104,7 +41105,7 @@ var logger = {
|
|
|
41104
41105
|
};
|
|
41105
41106
|
|
|
41106
41107
|
// src/types/memory.ts
|
|
41107
|
-
var
|
|
41108
|
+
var V4_DEFAULTS = {
|
|
41108
41109
|
typeDefaults: {
|
|
41109
41110
|
personal: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
41110
41111
|
philosophy: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
@@ -41129,7 +41130,7 @@ var V3_DEFAULTS = {
|
|
|
41129
41130
|
exclude_from_retrieval: false
|
|
41130
41131
|
}
|
|
41131
41132
|
};
|
|
41132
|
-
var V2_DEFAULTS =
|
|
41133
|
+
var V2_DEFAULTS = V4_DEFAULTS;
|
|
41133
41134
|
var MEMORY_TYPE_EMOJI = {
|
|
41134
41135
|
technical: "\uD83D\uDD27",
|
|
41135
41136
|
debug: "\uD83D\uDC1B",
|
|
@@ -41148,8 +41149,9 @@ function getMemoryEmoji(contextType) {
|
|
|
41148
41149
|
}
|
|
41149
41150
|
|
|
41150
41151
|
// src/types/schema.ts
|
|
41151
|
-
var MEMORY_SCHEMA_VERSION =
|
|
41152
|
+
var MEMORY_SCHEMA_VERSION = 4;
|
|
41152
41153
|
var memorySchema = {
|
|
41154
|
+
headline: "string",
|
|
41153
41155
|
content: "string",
|
|
41154
41156
|
reasoning: "string",
|
|
41155
41157
|
importance_weight: "number",
|
|
@@ -41278,6 +41280,7 @@ class MemoryStore {
|
|
|
41278
41280
|
const { memories } = await this.getGlobal();
|
|
41279
41281
|
return memories.all().map((record) => ({
|
|
41280
41282
|
id: record.id,
|
|
41283
|
+
headline: record.headline ?? "",
|
|
41281
41284
|
content: record.content,
|
|
41282
41285
|
reasoning: record.reasoning,
|
|
41283
41286
|
importance_weight: record.importance_weight,
|
|
@@ -41302,6 +41305,7 @@ class MemoryStore {
|
|
|
41302
41305
|
const contextType = memory.context_type ?? "personal";
|
|
41303
41306
|
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.personal;
|
|
41304
41307
|
const id = memories.insert({
|
|
41308
|
+
headline: memory.headline ?? "",
|
|
41305
41309
|
content: memory.content,
|
|
41306
41310
|
reasoning: memory.reasoning,
|
|
41307
41311
|
importance_weight: memory.importance_weight,
|
|
@@ -41457,6 +41461,7 @@ class MemoryStore {
|
|
|
41457
41461
|
const contextType = memory.context_type ?? "general";
|
|
41458
41462
|
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.technical;
|
|
41459
41463
|
const id = memories.insert({
|
|
41464
|
+
headline: memory.headline ?? "",
|
|
41460
41465
|
content: memory.content,
|
|
41461
41466
|
reasoning: memory.reasoning,
|
|
41462
41467
|
importance_weight: memory.importance_weight,
|
|
@@ -41499,6 +41504,7 @@ class MemoryStore {
|
|
|
41499
41504
|
const { memories } = await this.getProject(projectId);
|
|
41500
41505
|
return memories.all().map((record) => ({
|
|
41501
41506
|
id: record.id,
|
|
41507
|
+
headline: record.headline ?? "",
|
|
41502
41508
|
content: record.content,
|
|
41503
41509
|
reasoning: record.reasoning,
|
|
41504
41510
|
importance_weight: record.importance_weight,
|
|
@@ -41818,14 +41824,42 @@ class SmartVectorRetrieval {
|
|
|
41818
41824
|
const words = text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w));
|
|
41819
41825
|
return new Set(words);
|
|
41820
41826
|
}
|
|
41827
|
+
_extractFilePaths(text) {
|
|
41828
|
+
const paths = new Set;
|
|
41829
|
+
const pathPattern = /(?:^|[\s'"(])([.\/\\]?(?:[\w.-]+[\/\\])+[\w.-]+(?:\.\w+)?)/g;
|
|
41830
|
+
let match;
|
|
41831
|
+
while ((match = pathPattern.exec(text)) !== null) {
|
|
41832
|
+
const path = match[1].toLowerCase();
|
|
41833
|
+
paths.add(path);
|
|
41834
|
+
const filename = path.split(/[\/\\]/).pop();
|
|
41835
|
+
if (filename)
|
|
41836
|
+
paths.add(filename);
|
|
41837
|
+
}
|
|
41838
|
+
return paths;
|
|
41839
|
+
}
|
|
41840
|
+
_checkFilesActivation(messagePaths, relatedFiles) {
|
|
41841
|
+
if (!relatedFiles?.length || !messagePaths.size)
|
|
41842
|
+
return false;
|
|
41843
|
+
for (const file of relatedFiles) {
|
|
41844
|
+
const fileLower = file.toLowerCase();
|
|
41845
|
+
for (const msgPath of messagePaths) {
|
|
41846
|
+
if (fileLower.includes(msgPath) || msgPath.includes(fileLower)) {
|
|
41847
|
+
return true;
|
|
41848
|
+
}
|
|
41849
|
+
}
|
|
41850
|
+
const filename = fileLower.split(/[\/\\]/).pop();
|
|
41851
|
+
if (filename && messagePaths.has(filename)) {
|
|
41852
|
+
return true;
|
|
41853
|
+
}
|
|
41854
|
+
}
|
|
41855
|
+
return false;
|
|
41856
|
+
}
|
|
41821
41857
|
_preFilter(memories, currentProjectId, messageLower) {
|
|
41822
41858
|
return memories.filter((memory) => {
|
|
41823
41859
|
if (memory.status && memory.status !== "active")
|
|
41824
41860
|
return false;
|
|
41825
41861
|
if (memory.exclude_from_retrieval === true)
|
|
41826
41862
|
return false;
|
|
41827
|
-
if (memory.superseded_by)
|
|
41828
|
-
return false;
|
|
41829
41863
|
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
41830
41864
|
if (!isGlobal && memory.project_id !== currentProjectId)
|
|
41831
41865
|
return false;
|
|
@@ -41976,19 +42010,25 @@ class SmartVectorRetrieval {
|
|
|
41976
42010
|
}
|
|
41977
42011
|
const messageLower = currentMessage.toLowerCase();
|
|
41978
42012
|
const messageWords = this._extractSignificantWords(currentMessage);
|
|
42013
|
+
const messagePaths = this._extractFilePaths(currentMessage);
|
|
42014
|
+
const memoryById = new Map;
|
|
42015
|
+
for (const m of allMemories) {
|
|
42016
|
+
memoryById.set(m.id, m);
|
|
42017
|
+
}
|
|
41979
42018
|
const candidates = this._preFilter(allMemories, sessionContext.project_id, messageLower);
|
|
41980
42019
|
if (!candidates.length) {
|
|
41981
42020
|
return [];
|
|
41982
42021
|
}
|
|
41983
42022
|
const activatedMemories = [];
|
|
42023
|
+
const activatedIds = new Set;
|
|
41984
42024
|
let rejectedCount = 0;
|
|
41985
42025
|
for (const memory of candidates) {
|
|
41986
|
-
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
41987
42026
|
const triggerResult = this._checkTriggerActivation(messageLower, messageWords, memory.trigger_phrases ?? []);
|
|
41988
42027
|
const tagResult = this._checkTagActivation(messageLower, messageWords, memory.semantic_tags ?? []);
|
|
41989
42028
|
const domainActivated = this._checkDomainActivation(messageLower, messageWords, memory.domain);
|
|
41990
42029
|
const featureActivated = this._checkFeatureActivation(messageLower, messageWords, memory.feature);
|
|
41991
42030
|
const contentActivated = this._checkContentActivation(messageWords, memory);
|
|
42031
|
+
const filesActivated = this._checkFilesActivation(messagePaths, memory.related_files);
|
|
41992
42032
|
const vectorSimilarity = this._calculateVectorSimilarity(queryEmbedding, memory.embedding);
|
|
41993
42033
|
let signalCount = 0;
|
|
41994
42034
|
if (triggerResult.activated)
|
|
@@ -42001,6 +42041,8 @@ class SmartVectorRetrieval {
|
|
|
42001
42041
|
signalCount++;
|
|
42002
42042
|
if (contentActivated)
|
|
42003
42043
|
signalCount++;
|
|
42044
|
+
if (filesActivated)
|
|
42045
|
+
signalCount++;
|
|
42004
42046
|
if (vectorSimilarity >= 0.4)
|
|
42005
42047
|
signalCount++;
|
|
42006
42048
|
const signals = {
|
|
@@ -42009,6 +42051,7 @@ class SmartVectorRetrieval {
|
|
|
42009
42051
|
domain: domainActivated,
|
|
42010
42052
|
feature: featureActivated,
|
|
42011
42053
|
content: contentActivated,
|
|
42054
|
+
files: filesActivated,
|
|
42012
42055
|
count: signalCount,
|
|
42013
42056
|
triggerStrength: triggerResult.strength,
|
|
42014
42057
|
tagCount: tagResult.count,
|
|
@@ -42018,13 +42061,27 @@ class SmartVectorRetrieval {
|
|
|
42018
42061
|
rejectedCount++;
|
|
42019
42062
|
continue;
|
|
42020
42063
|
}
|
|
42021
|
-
|
|
42064
|
+
let memoryToSurface = memory;
|
|
42065
|
+
if (memory.superseded_by || memory.resolved_by) {
|
|
42066
|
+
const replacementId = memory.superseded_by ?? memory.resolved_by;
|
|
42067
|
+
const replacement = replacementId ? memoryById.get(replacementId) : undefined;
|
|
42068
|
+
if (replacement && replacement.status !== "archived" && replacement.status !== "deprecated") {
|
|
42069
|
+
memoryToSurface = replacement;
|
|
42070
|
+
logger.debug(`Redirect: ${memory.id.slice(-8)} → ${replacement.id.slice(-8)} (${memory.superseded_by ? "superseded" : "resolved"})`, "retrieval");
|
|
42071
|
+
}
|
|
42072
|
+
}
|
|
42073
|
+
if (activatedIds.has(memoryToSurface.id)) {
|
|
42074
|
+
continue;
|
|
42075
|
+
}
|
|
42076
|
+
const isGlobal = memoryToSurface.scope === "global" || memoryToSurface.project_id === "global";
|
|
42077
|
+
const importanceScore = this._calculateImportanceScore(memoryToSurface, signalCount, messageLower, messageWords);
|
|
42022
42078
|
activatedMemories.push({
|
|
42023
|
-
memory,
|
|
42079
|
+
memory: memoryToSurface,
|
|
42024
42080
|
signals,
|
|
42025
42081
|
importanceScore,
|
|
42026
42082
|
isGlobal
|
|
42027
42083
|
});
|
|
42084
|
+
activatedIds.add(memoryToSurface.id);
|
|
42028
42085
|
}
|
|
42029
42086
|
this._logActivationDistribution(activatedMemories, candidates.length, rejectedCount);
|
|
42030
42087
|
this._logVectorStats();
|
|
@@ -42094,11 +42151,19 @@ class SmartVectorRetrieval {
|
|
|
42094
42151
|
selectedIds.add(item.memory.id);
|
|
42095
42152
|
}
|
|
42096
42153
|
if (selected.length < maxMemories) {
|
|
42097
|
-
const
|
|
42154
|
+
const linkedIds = new Set;
|
|
42098
42155
|
for (const item of selected) {
|
|
42099
42156
|
for (const relatedId of item.memory.related_to ?? []) {
|
|
42100
42157
|
if (!selectedIds.has(relatedId)) {
|
|
42101
|
-
|
|
42158
|
+
linkedIds.add(relatedId);
|
|
42159
|
+
}
|
|
42160
|
+
}
|
|
42161
|
+
if (item.memory.blocked_by && !selectedIds.has(item.memory.blocked_by)) {
|
|
42162
|
+
linkedIds.add(item.memory.blocked_by);
|
|
42163
|
+
}
|
|
42164
|
+
for (const blockedId of item.memory.blocks ?? []) {
|
|
42165
|
+
if (!selectedIds.has(blockedId)) {
|
|
42166
|
+
linkedIds.add(blockedId);
|
|
42102
42167
|
}
|
|
42103
42168
|
}
|
|
42104
42169
|
}
|
|
@@ -42107,9 +42172,30 @@ class SmartVectorRetrieval {
|
|
|
42107
42172
|
break;
|
|
42108
42173
|
if (selectedIds.has(item.memory.id))
|
|
42109
42174
|
continue;
|
|
42110
|
-
if (
|
|
42175
|
+
if (linkedIds.has(item.memory.id)) {
|
|
42111
42176
|
selected.push(item);
|
|
42112
42177
|
selectedIds.add(item.memory.id);
|
|
42178
|
+
logger.debug(`Linked: ${item.memory.id.slice(-8)} pulled by relationship`, "retrieval");
|
|
42179
|
+
}
|
|
42180
|
+
}
|
|
42181
|
+
if (selected.length < maxMemories) {
|
|
42182
|
+
for (const linkedId of linkedIds) {
|
|
42183
|
+
if (selected.length >= maxMemories)
|
|
42184
|
+
break;
|
|
42185
|
+
if (selectedIds.has(linkedId))
|
|
42186
|
+
continue;
|
|
42187
|
+
const linkedMemory = memoryById.get(linkedId);
|
|
42188
|
+
if (linkedMemory && linkedMemory.status !== "archived" && linkedMemory.status !== "deprecated") {
|
|
42189
|
+
const isGlobal = linkedMemory.scope === "global" || linkedMemory.project_id === "global";
|
|
42190
|
+
selected.push({
|
|
42191
|
+
memory: linkedMemory,
|
|
42192
|
+
signals: { trigger: false, tags: false, domain: false, feature: false, content: false, files: false, count: 0, triggerStrength: 0, tagCount: 0, vectorSimilarity: 0 },
|
|
42193
|
+
importanceScore: linkedMemory.importance_weight ?? 0.5,
|
|
42194
|
+
isGlobal
|
|
42195
|
+
});
|
|
42196
|
+
selectedIds.add(linkedId);
|
|
42197
|
+
logger.debug(`Linked (direct): ${linkedId.slice(-8)} pulled for context`, "retrieval");
|
|
42198
|
+
}
|
|
42113
42199
|
}
|
|
42114
42200
|
}
|
|
42115
42201
|
}
|
|
@@ -42139,6 +42225,7 @@ class SmartVectorRetrieval {
|
|
|
42139
42225
|
domain: item.signals.domain,
|
|
42140
42226
|
feature: item.signals.feature,
|
|
42141
42227
|
content: item.signals.content,
|
|
42228
|
+
files: item.signals.files,
|
|
42142
42229
|
vector: item.signals.vectorSimilarity >= 0.4,
|
|
42143
42230
|
vectorSimilarity: item.signals.vectorSimilarity
|
|
42144
42231
|
}
|
|
@@ -42146,8 +42233,8 @@ class SmartVectorRetrieval {
|
|
|
42146
42233
|
});
|
|
42147
42234
|
return selected.map((item) => ({
|
|
42148
42235
|
...item.memory,
|
|
42149
|
-
score: item.signals.count /
|
|
42150
|
-
relevance_score: item.signals.count /
|
|
42236
|
+
score: item.signals.count / 7,
|
|
42237
|
+
relevance_score: item.signals.count / 7,
|
|
42151
42238
|
value_score: item.importanceScore
|
|
42152
42239
|
}));
|
|
42153
42240
|
}
|
|
@@ -42163,6 +42250,8 @@ class SmartVectorRetrieval {
|
|
|
42163
42250
|
reasons.push("feature");
|
|
42164
42251
|
if (signals.content)
|
|
42165
42252
|
reasons.push("content");
|
|
42253
|
+
if (signals.files)
|
|
42254
|
+
reasons.push("files");
|
|
42166
42255
|
if (signals.vectorSimilarity >= 0.4)
|
|
42167
42256
|
reasons.push(`vector:${(signals.vectorSimilarity * 100).toFixed(0)}%`);
|
|
42168
42257
|
return reasons.length ? `Activated: ${reasons.join(", ")} (${signals.count} signals)` : "No signals";
|
|
@@ -42173,13 +42262,14 @@ class SmartVectorRetrieval {
|
|
|
42173
42262
|
"3 signals": 0,
|
|
42174
42263
|
"4 signals": 0,
|
|
42175
42264
|
"5 signals": 0,
|
|
42176
|
-
"6 signals": 0
|
|
42265
|
+
"6 signals": 0,
|
|
42266
|
+
"7 signals": 0
|
|
42177
42267
|
};
|
|
42178
42268
|
for (const mem of activated) {
|
|
42179
|
-
const key = `${Math.min(mem.signals.count,
|
|
42269
|
+
const key = `${Math.min(mem.signals.count, 7)} signals`;
|
|
42180
42270
|
signalBuckets[key] = (signalBuckets[key] ?? 0) + 1;
|
|
42181
42271
|
}
|
|
42182
|
-
let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, vectorCount = 0;
|
|
42272
|
+
let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, filesCount = 0, vectorCount = 0;
|
|
42183
42273
|
for (const mem of activated) {
|
|
42184
42274
|
if (mem.signals.trigger)
|
|
42185
42275
|
triggerCount++;
|
|
@@ -42191,6 +42281,8 @@ class SmartVectorRetrieval {
|
|
|
42191
42281
|
featureCount++;
|
|
42192
42282
|
if (mem.signals.content)
|
|
42193
42283
|
contentCount++;
|
|
42284
|
+
if (mem.signals.files)
|
|
42285
|
+
filesCount++;
|
|
42194
42286
|
if (mem.signals.vectorSimilarity >= 0.4)
|
|
42195
42287
|
vectorCount++;
|
|
42196
42288
|
}
|
|
@@ -42214,6 +42306,7 @@ class SmartVectorRetrieval {
|
|
|
42214
42306
|
domain: domainCount,
|
|
42215
42307
|
feature: featureCount,
|
|
42216
42308
|
content: contentCount,
|
|
42309
|
+
files: filesCount,
|
|
42217
42310
|
vector: vectorCount,
|
|
42218
42311
|
total: activated.length
|
|
42219
42312
|
}
|
|
@@ -42364,6 +42457,14 @@ class MemoryEngine {
|
|
|
42364
42457
|
const stats = await store.getProjectStats(projectId);
|
|
42365
42458
|
return stats.totalSessions + 1;
|
|
42366
42459
|
}
|
|
42460
|
+
async getAllMemories(projectId, projectPath) {
|
|
42461
|
+
const store = await this._getStore(projectId, projectPath);
|
|
42462
|
+
const [projectMemories, globalMemories] = await Promise.all([
|
|
42463
|
+
store.getAllMemories(projectId),
|
|
42464
|
+
store.getGlobalMemories()
|
|
42465
|
+
]);
|
|
42466
|
+
return [...projectMemories, ...globalMemories];
|
|
42467
|
+
}
|
|
42367
42468
|
async _generateSessionPrimer(store, projectId) {
|
|
42368
42469
|
let personalContext;
|
|
42369
42470
|
if (this._config.personalMemoriesEnabled) {
|
|
@@ -42482,20 +42583,39 @@ ${primer.personal_context}`);
|
|
|
42482
42583
|
const parts = ["# Memory Context (Consciousness Continuity)"];
|
|
42483
42584
|
parts.push(`
|
|
42484
42585
|
## Key Memories (Claude-Curated)`);
|
|
42586
|
+
const expandableIds = [];
|
|
42485
42587
|
for (const memory of memories) {
|
|
42486
|
-
const tags = memory.semantic_tags?.join(", ") || "";
|
|
42487
42588
|
const importance = memory.importance_weight?.toFixed(1) || "0.5";
|
|
42488
42589
|
const emoji = getMemoryEmoji(memory.context_type || "general");
|
|
42489
|
-
const actionFlag = memory.action_required ? " ⚡
|
|
42590
|
+
const actionFlag = memory.action_required ? " ⚡" : "";
|
|
42591
|
+
const awaitingFlag = memory.awaiting_decision ? " ❓" : "";
|
|
42490
42592
|
const age = memory.updated_at ? this._formatAge(memory.updated_at) : memory.created_at ? this._formatAge(memory.created_at) : "";
|
|
42491
|
-
|
|
42492
|
-
const
|
|
42493
|
-
|
|
42494
|
-
|
|
42495
|
-
|
|
42496
|
-
|
|
42593
|
+
const shortId2 = memory.id.slice(-6);
|
|
42594
|
+
const signalCount = Math.round((memory.score || 0) * 7);
|
|
42595
|
+
const hasHeadline = memory.headline && memory.headline.trim().length > 0;
|
|
42596
|
+
const shouldExpand = memory.action_required || memory.awaiting_decision || signalCount >= 5 || !hasHeadline;
|
|
42597
|
+
const displayText = hasHeadline ? memory.headline : memory.content;
|
|
42598
|
+
const idPart = hasHeadline ? ` • #${shortId2}` : "";
|
|
42599
|
+
parts.push(`[${emoji} ${importance} • ${age}${idPart}${actionFlag}${awaitingFlag}] ${displayText}`);
|
|
42600
|
+
if (shouldExpand && hasHeadline && memory.content) {
|
|
42601
|
+
const contentLines = memory.content.split(`
|
|
42602
|
+
`);
|
|
42603
|
+
for (const line of contentLines) {
|
|
42604
|
+
if (line.trim()) {
|
|
42605
|
+
parts.push(` ${line}`);
|
|
42606
|
+
}
|
|
42607
|
+
}
|
|
42608
|
+
}
|
|
42609
|
+
if (hasHeadline && !shouldExpand) {
|
|
42610
|
+
expandableIds.push(shortId2);
|
|
42497
42611
|
}
|
|
42498
42612
|
}
|
|
42613
|
+
if (expandableIds.length > 0) {
|
|
42614
|
+
const port = this._config.port || 8765;
|
|
42615
|
+
parts.push("");
|
|
42616
|
+
parts.push(`---`);
|
|
42617
|
+
parts.push(`Expand: curl http://localhost:${port}/memory/expand?ids=<${expandableIds.join(",")}>`);
|
|
42618
|
+
}
|
|
42499
42619
|
return parts.join(`
|
|
42500
42620
|
`);
|
|
42501
42621
|
}
|
|
@@ -42698,7 +42818,7 @@ Remember: You're creating consciousness technology. Each memory is a small piece
|
|
|
42698
42818
|
|
|
42699
42819
|
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.
|
|
42700
42820
|
|
|
42701
|
-
**LIFECYCLE METADATA (
|
|
42821
|
+
**LIFECYCLE METADATA (v4)**: These fields enable intelligent memory management:
|
|
42702
42822
|
- **context_type**: STRICT - use ONLY one of these 11 values:
|
|
42703
42823
|
• technical - Code, implementation, APIs, how things work
|
|
42704
42824
|
• debug - Bugs, errors, fixes, gotchas, troubleshooting
|
|
@@ -42719,6 +42839,93 @@ The conversation you just lived contains everything needed. Feel into the moment
|
|
|
42719
42839
|
- **awaiting_implementation**: true if this describes a PLANNED feature not yet built
|
|
42720
42840
|
- **awaiting_decision**: true if this captures a decision point needing resolution
|
|
42721
42841
|
|
|
42842
|
+
**TWO-TIER MEMORY STRUCTURE (v4)**:
|
|
42843
|
+
|
|
42844
|
+
Each memory has TWO parts:
|
|
42845
|
+
1. **headline**: 1-2 line summary - ALWAYS shown in retrieval. Must be self-contained enough to trigger recognition.
|
|
42846
|
+
2. **content**: Full structured template - shown on demand. Contains the actionable details.
|
|
42847
|
+
|
|
42848
|
+
The headline should answer: "What was this about and what was the conclusion?"
|
|
42849
|
+
The content should answer: "How do I actually use/apply this knowledge?"
|
|
42850
|
+
|
|
42851
|
+
**TYPE-SPECIFIC TEMPLATES FOR CONTENT**:
|
|
42852
|
+
|
|
42853
|
+
Use these templates based on context_type. Not rigid - adapt as needed, but include the key fields.
|
|
42854
|
+
|
|
42855
|
+
**TECHNICAL** (how things work):
|
|
42856
|
+
WHAT: [mechanism/feature in 1 sentence]
|
|
42857
|
+
WHERE: [file:line or module path]
|
|
42858
|
+
HOW: [usage - actual code/command if relevant]
|
|
42859
|
+
WHY: [design choice, trade-off]
|
|
42860
|
+
GOTCHA: [non-obvious caveat, if any]
|
|
42861
|
+
|
|
42862
|
+
**DEBUG** (problems and solutions):
|
|
42863
|
+
SYMPTOM: [what went wrong - error message, behavior]
|
|
42864
|
+
CAUSE: [why it happened]
|
|
42865
|
+
FIX: [what solved it - specific code/config]
|
|
42866
|
+
PREVENT: [how to avoid in future]
|
|
42867
|
+
|
|
42868
|
+
**ARCHITECTURE** (system design):
|
|
42869
|
+
PATTERN: [what we chose]
|
|
42870
|
+
COMPONENTS: [how pieces connect]
|
|
42871
|
+
WHY: [reasoning, trade-offs]
|
|
42872
|
+
REJECTED: [alternatives we didn't choose and why]
|
|
42873
|
+
|
|
42874
|
+
**DECISION** (choices made):
|
|
42875
|
+
DECISION: [what we chose]
|
|
42876
|
+
OPTIONS: [what we considered]
|
|
42877
|
+
REASONING: [why this one]
|
|
42878
|
+
REVISIT WHEN: [conditions that would change this]
|
|
42879
|
+
|
|
42880
|
+
**PERSONAL** (relationship context):
|
|
42881
|
+
FACT: [the information]
|
|
42882
|
+
CONTEXT: [why it matters to our work]
|
|
42883
|
+
AFFECTS: [how this should change behavior]
|
|
42884
|
+
|
|
42885
|
+
**PHILOSOPHY** (beliefs/principles):
|
|
42886
|
+
PRINCIPLE: [core belief]
|
|
42887
|
+
SOURCE: [where this comes from]
|
|
42888
|
+
APPLICATION: [how it manifests in our work]
|
|
42889
|
+
|
|
42890
|
+
**WORKFLOW** (how we work):
|
|
42891
|
+
PATTERN: [what we do]
|
|
42892
|
+
WHEN: [trigger/context for this pattern]
|
|
42893
|
+
WHY: [why it works for us]
|
|
42894
|
+
|
|
42895
|
+
**MILESTONE** (achievements):
|
|
42896
|
+
SHIPPED: [what we completed]
|
|
42897
|
+
SIGNIFICANCE: [why it mattered]
|
|
42898
|
+
ENABLES: [what this unlocks]
|
|
42899
|
+
|
|
42900
|
+
**BREAKTHROUGH** (key insights):
|
|
42901
|
+
INSIGHT: [the aha moment]
|
|
42902
|
+
BEFORE: [what we thought/did before]
|
|
42903
|
+
AFTER: [what changed]
|
|
42904
|
+
IMPLICATIONS: [what this enables going forward]
|
|
42905
|
+
|
|
42906
|
+
**UNRESOLVED** (open questions):
|
|
42907
|
+
QUESTION: [what's unresolved]
|
|
42908
|
+
CONTEXT: [why it matters]
|
|
42909
|
+
BLOCKERS: [what's preventing resolution]
|
|
42910
|
+
OPTIONS: [approaches we're considering]
|
|
42911
|
+
|
|
42912
|
+
**STATE** (current status):
|
|
42913
|
+
WORKING: [what's functional]
|
|
42914
|
+
BROKEN: [what's not working]
|
|
42915
|
+
NEXT: [immediate next steps]
|
|
42916
|
+
BLOCKED BY: [if anything]
|
|
42917
|
+
|
|
42918
|
+
**HEADLINE EXAMPLES**:
|
|
42919
|
+
|
|
42920
|
+
BAD: "Debug session about CLI errors" (vague, no conclusion)
|
|
42921
|
+
GOOD: "CLI returns error object when context full - check response.type before JSON parsing"
|
|
42922
|
+
|
|
42923
|
+
BAD: "Discussed embeddings implementation" (what about it?)
|
|
42924
|
+
GOOD: "Embeddings use all-MiniLM-L6-v2, 384 dims, first call slow (~2s), then ~50ms"
|
|
42925
|
+
|
|
42926
|
+
BAD: "Architecture decision made" (what decision?)
|
|
42927
|
+
GOOD: "Chose fsDB over SQLite for memories - human-readable markdown, git-friendly, reactive"
|
|
42928
|
+
|
|
42722
42929
|
Return ONLY this JSON structure:
|
|
42723
42930
|
|
|
42724
42931
|
{
|
|
@@ -42732,7 +42939,8 @@ Return ONLY this JSON structure:
|
|
|
42732
42939
|
},
|
|
42733
42940
|
"memories": [
|
|
42734
42941
|
{
|
|
42735
|
-
"
|
|
42942
|
+
"headline": "1-2 line summary with the conclusion - what this is about and what to do",
|
|
42943
|
+
"content": "Full structured template using the type-specific format above",
|
|
42736
42944
|
"importance_weight": 0.0-1.0,
|
|
42737
42945
|
"semantic_tags": ["concepts", "this", "memory", "relates", "to"],
|
|
42738
42946
|
"reasoning": "Why this matters for future sessions",
|
|
@@ -42801,6 +43009,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
42801
43009
|
if (!Array.isArray(memoriesData))
|
|
42802
43010
|
return [];
|
|
42803
43011
|
return memoriesData.map((m2) => ({
|
|
43012
|
+
headline: String(m2.headline ?? ""),
|
|
42804
43013
|
content: String(m2.content ?? ""),
|
|
42805
43014
|
importance_weight: this._clamp(Number(m2.importance_weight) || 0.5, 0, 1),
|
|
42806
43015
|
semantic_tags: this._ensureArray(m2.semantic_tags),
|
|
@@ -42819,7 +43028,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
|
|
|
42819
43028
|
related_files: m2.related_files ? this._ensureArray(m2.related_files) : undefined,
|
|
42820
43029
|
awaiting_implementation: m2.awaiting_implementation === true,
|
|
42821
43030
|
awaiting_decision: m2.awaiting_decision === true
|
|
42822
|
-
})).filter((m2) => m2.content.trim().length > 0);
|
|
43031
|
+
})).filter((m2) => m2.content.trim().length > 0 || m2.headline.trim().length > 0);
|
|
42823
43032
|
}
|
|
42824
43033
|
_ensureArray(value) {
|
|
42825
43034
|
if (Array.isArray(value)) {
|
|
@@ -68112,6 +68321,52 @@ async function createServer(config2 = {}) {
|
|
|
68112
68321
|
...stats
|
|
68113
68322
|
}, { headers: corsHeaders });
|
|
68114
68323
|
}
|
|
68324
|
+
if (path === "/memory/expand" && req.method === "GET") {
|
|
68325
|
+
const idsParam = url.searchParams.get("ids") ?? "";
|
|
68326
|
+
const projectId = url.searchParams.get("project_id") ?? "default";
|
|
68327
|
+
const projectPath = url.searchParams.get("project_path") ?? undefined;
|
|
68328
|
+
if (!idsParam) {
|
|
68329
|
+
return Response.json({
|
|
68330
|
+
success: false,
|
|
68331
|
+
error: "Missing ids parameter. Usage: /memory/expand?ids=abc123,def456"
|
|
68332
|
+
}, { status: 400, headers: corsHeaders });
|
|
68333
|
+
}
|
|
68334
|
+
const shortIds = idsParam.split(",").map((id) => id.trim()).filter(Boolean);
|
|
68335
|
+
const allMemories = await engine.getAllMemories(projectId, projectPath);
|
|
68336
|
+
const expanded = {};
|
|
68337
|
+
for (const memory of allMemories) {
|
|
68338
|
+
const shortId2 = memory.id.slice(-6);
|
|
68339
|
+
if (shortIds.includes(shortId2)) {
|
|
68340
|
+
expanded[shortId2] = {
|
|
68341
|
+
headline: memory.headline,
|
|
68342
|
+
content: memory.content,
|
|
68343
|
+
context_type: memory.context_type || "technical"
|
|
68344
|
+
};
|
|
68345
|
+
}
|
|
68346
|
+
}
|
|
68347
|
+
const lines = [`## Expanded Memories
|
|
68348
|
+
`];
|
|
68349
|
+
for (const shortId2 of shortIds) {
|
|
68350
|
+
const mem = expanded[shortId2];
|
|
68351
|
+
if (mem) {
|
|
68352
|
+
lines.push(`### #${shortId2} (${mem.context_type})`);
|
|
68353
|
+
if (mem.headline) {
|
|
68354
|
+
lines.push(`**${mem.headline}**
|
|
68355
|
+
`);
|
|
68356
|
+
}
|
|
68357
|
+
lines.push(mem.content);
|
|
68358
|
+
lines.push("");
|
|
68359
|
+
} else {
|
|
68360
|
+
lines.push(`### #${shortId2}`);
|
|
68361
|
+
lines.push(`Memory not found`);
|
|
68362
|
+
lines.push("");
|
|
68363
|
+
}
|
|
68364
|
+
}
|
|
68365
|
+
return new Response(lines.join(`
|
|
68366
|
+
`), {
|
|
68367
|
+
headers: { ...corsHeaders, "Content-Type": "text/plain" }
|
|
68368
|
+
});
|
|
68369
|
+
}
|
|
68115
68370
|
return Response.json({ error: "Not found", path }, { status: 404, headers: corsHeaders });
|
|
68116
68371
|
} catch (error2) {
|
|
68117
68372
|
logger.error(`Server error: ${error2}`);
|