@rlabs-inc/memory 0.3.5 → 0.3.6
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 +123 -30
- package/dist/index.js +803 -179
- package/dist/index.mjs +803 -179
- package/dist/server/index.js +36774 -2643
- package/dist/server/index.mjs +1034 -185
- package/package.json +3 -2
- package/skills/memory-management.md +686 -0
- package/src/cli/commands/migrate.ts +423 -0
- package/src/cli/commands/serve.ts +88 -0
- package/src/cli/index.ts +21 -0
- package/src/core/curator.ts +151 -17
- package/src/core/engine.ts +159 -11
- package/src/core/manager.ts +484 -0
- package/src/core/retrieval.ts +547 -420
- package/src/core/store.ts +383 -8
- package/src/server/index.ts +108 -8
- package/src/types/memory.ts +142 -0
- package/src/types/schema.ts +80 -7
- package/src/utils/logger.ts +310 -46
package/dist/index.mjs
CHANGED
|
@@ -11964,7 +11964,60 @@ function createDatabase(options = {}) {
|
|
|
11964
11964
|
import { homedir } from "os";
|
|
11965
11965
|
import { join } from "path";
|
|
11966
11966
|
|
|
11967
|
+
// src/types/memory.ts
|
|
11968
|
+
var V2_DEFAULTS = {
|
|
11969
|
+
typeDefaults: {
|
|
11970
|
+
personal: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
11971
|
+
philosophy: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
|
|
11972
|
+
preference: { scope: "global", temporal_class: "long_term", fade_rate: 0.01 },
|
|
11973
|
+
breakthrough: { scope: "project", temporal_class: "eternal", fade_rate: 0 },
|
|
11974
|
+
decision: { scope: "project", temporal_class: "long_term", fade_rate: 0 },
|
|
11975
|
+
milestone: { scope: "project", temporal_class: "eternal", fade_rate: 0 },
|
|
11976
|
+
technical: { scope: "project", temporal_class: "medium_term", fade_rate: 0.03 },
|
|
11977
|
+
architectural: { scope: "project", temporal_class: "long_term", fade_rate: 0.01 },
|
|
11978
|
+
debugging: { scope: "project", temporal_class: "medium_term", fade_rate: 0.03 },
|
|
11979
|
+
unresolved: { scope: "project", temporal_class: "medium_term", fade_rate: 0.05 },
|
|
11980
|
+
todo: { scope: "project", temporal_class: "short_term", fade_rate: 0.1 },
|
|
11981
|
+
technical_state: { scope: "project", temporal_class: "short_term", fade_rate: 0.1 },
|
|
11982
|
+
workflow: { scope: "project", temporal_class: "long_term", fade_rate: 0.02 },
|
|
11983
|
+
project_context: { scope: "project", temporal_class: "medium_term", fade_rate: 0.03 }
|
|
11984
|
+
},
|
|
11985
|
+
fallback: {
|
|
11986
|
+
status: "active",
|
|
11987
|
+
scope: "project",
|
|
11988
|
+
temporal_class: "medium_term",
|
|
11989
|
+
fade_rate: 0.03,
|
|
11990
|
+
sessions_since_surfaced: 0,
|
|
11991
|
+
awaiting_implementation: false,
|
|
11992
|
+
awaiting_decision: false,
|
|
11993
|
+
exclude_from_retrieval: false
|
|
11994
|
+
}
|
|
11995
|
+
};
|
|
11996
|
+
var MEMORY_TYPE_EMOJI = {
|
|
11997
|
+
breakthrough: "\uD83D\uDCA1",
|
|
11998
|
+
decision: "⚖️",
|
|
11999
|
+
personal: "\uD83D\uDC9C",
|
|
12000
|
+
technical: "\uD83D\uDD27",
|
|
12001
|
+
technical_state: "\uD83D\uDCCD",
|
|
12002
|
+
unresolved: "❓",
|
|
12003
|
+
preference: "⚙️",
|
|
12004
|
+
workflow: "\uD83D\uDD04",
|
|
12005
|
+
architectural: "\uD83C\uDFD7️",
|
|
12006
|
+
debugging: "\uD83D\uDC1B",
|
|
12007
|
+
philosophy: "\uD83C\uDF00",
|
|
12008
|
+
todo: "\uD83C\uDFAF",
|
|
12009
|
+
implementation: "⚡",
|
|
12010
|
+
problem_solution: "✅",
|
|
12011
|
+
project_context: "\uD83D\uDCE6",
|
|
12012
|
+
milestone: "\uD83C\uDFC6",
|
|
12013
|
+
general: "\uD83D\uDCDD"
|
|
12014
|
+
};
|
|
12015
|
+
function getMemoryEmoji(contextType) {
|
|
12016
|
+
return MEMORY_TYPE_EMOJI[contextType.toLowerCase()] ?? "\uD83D\uDCDD";
|
|
12017
|
+
}
|
|
12018
|
+
|
|
11967
12019
|
// src/types/schema.ts
|
|
12020
|
+
var MEMORY_SCHEMA_VERSION = 2;
|
|
11968
12021
|
var memorySchema = {
|
|
11969
12022
|
content: "string",
|
|
11970
12023
|
reasoning: "string",
|
|
@@ -11981,7 +12034,34 @@ var memorySchema = {
|
|
|
11981
12034
|
question_types: "string[]",
|
|
11982
12035
|
session_id: "string",
|
|
11983
12036
|
project_id: "string",
|
|
11984
|
-
embedding: "vector:384"
|
|
12037
|
+
embedding: "vector:384",
|
|
12038
|
+
status: "string",
|
|
12039
|
+
scope: "string",
|
|
12040
|
+
session_created: "number",
|
|
12041
|
+
session_updated: "number",
|
|
12042
|
+
last_surfaced: "number",
|
|
12043
|
+
sessions_since_surfaced: "number",
|
|
12044
|
+
temporal_class: "string",
|
|
12045
|
+
fade_rate: "number",
|
|
12046
|
+
expires_after_sessions: "number",
|
|
12047
|
+
domain: "string",
|
|
12048
|
+
feature: "string",
|
|
12049
|
+
component: "string",
|
|
12050
|
+
supersedes: "string",
|
|
12051
|
+
superseded_by: "string",
|
|
12052
|
+
related_to: "string[]",
|
|
12053
|
+
resolves: "string[]",
|
|
12054
|
+
resolved_by: "string",
|
|
12055
|
+
parent_id: "string",
|
|
12056
|
+
child_ids: "string[]",
|
|
12057
|
+
awaiting_implementation: "boolean",
|
|
12058
|
+
awaiting_decision: "boolean",
|
|
12059
|
+
blocked_by: "string",
|
|
12060
|
+
blocks: "string[]",
|
|
12061
|
+
related_files: "string[]",
|
|
12062
|
+
retrieval_weight: "number",
|
|
12063
|
+
exclude_from_retrieval: "boolean",
|
|
12064
|
+
schema_version: "number"
|
|
11985
12065
|
};
|
|
11986
12066
|
var sessionSummarySchema = {
|
|
11987
12067
|
session_id: "string",
|
|
@@ -12004,17 +12084,211 @@ var sessionSchema = {
|
|
|
12004
12084
|
last_active: "timestamp",
|
|
12005
12085
|
metadata: "string"
|
|
12006
12086
|
};
|
|
12087
|
+
var managementLogSchema = {
|
|
12088
|
+
project_id: "string",
|
|
12089
|
+
session_number: "number",
|
|
12090
|
+
memories_processed: "number",
|
|
12091
|
+
superseded_count: "number",
|
|
12092
|
+
resolved_count: "number",
|
|
12093
|
+
linked_count: "number",
|
|
12094
|
+
primer_updated: "boolean",
|
|
12095
|
+
success: "boolean",
|
|
12096
|
+
duration_ms: "number",
|
|
12097
|
+
summary: "string",
|
|
12098
|
+
error: "string",
|
|
12099
|
+
details: "string"
|
|
12100
|
+
};
|
|
12007
12101
|
|
|
12008
12102
|
// src/core/store.ts
|
|
12103
|
+
var PERSONAL_PRIMER_ID = "personal-primer";
|
|
12104
|
+
var DEFAULT_GLOBAL_PATH = join(homedir(), ".local", "share", "memory", "global");
|
|
12105
|
+
|
|
12009
12106
|
class MemoryStore {
|
|
12010
12107
|
_config;
|
|
12011
12108
|
_projects = new Map;
|
|
12109
|
+
_global = null;
|
|
12012
12110
|
constructor(config = {}) {
|
|
12013
12111
|
this._config = {
|
|
12014
12112
|
basePath: config.basePath ?? join(homedir(), ".local", "share", "memory"),
|
|
12113
|
+
globalPath: config.globalPath ?? DEFAULT_GLOBAL_PATH,
|
|
12015
12114
|
watchFiles: config.watchFiles ?? false
|
|
12016
12115
|
};
|
|
12017
12116
|
}
|
|
12117
|
+
async getGlobal() {
|
|
12118
|
+
if (this._global) {
|
|
12119
|
+
return this._global;
|
|
12120
|
+
}
|
|
12121
|
+
const globalPath = this._config.globalPath;
|
|
12122
|
+
console.log(`\uD83C\uDF10 [DEBUG] Creating global database at ${globalPath}`);
|
|
12123
|
+
const db = createDatabase({
|
|
12124
|
+
name: "global",
|
|
12125
|
+
basePath: globalPath
|
|
12126
|
+
});
|
|
12127
|
+
const memories = db.collection("memories", {
|
|
12128
|
+
schema: memorySchema,
|
|
12129
|
+
contentColumn: "content",
|
|
12130
|
+
autoSave: true,
|
|
12131
|
+
watchFiles: this._config.watchFiles
|
|
12132
|
+
});
|
|
12133
|
+
const managementLogs = db.collection("management-logs", {
|
|
12134
|
+
schema: managementLogSchema,
|
|
12135
|
+
contentColumn: "summary",
|
|
12136
|
+
autoSave: true,
|
|
12137
|
+
watchFiles: this._config.watchFiles
|
|
12138
|
+
});
|
|
12139
|
+
await Promise.all([memories.load(), managementLogs.load()]);
|
|
12140
|
+
this._global = { db, memories, managementLogs };
|
|
12141
|
+
return this._global;
|
|
12142
|
+
}
|
|
12143
|
+
async getGlobalMemories() {
|
|
12144
|
+
const { memories } = await this.getGlobal();
|
|
12145
|
+
return memories.all().map((record) => ({
|
|
12146
|
+
id: record.id,
|
|
12147
|
+
content: record.content,
|
|
12148
|
+
reasoning: record.reasoning,
|
|
12149
|
+
importance_weight: record.importance_weight,
|
|
12150
|
+
confidence_score: record.confidence_score,
|
|
12151
|
+
context_type: record.context_type,
|
|
12152
|
+
temporal_relevance: record.temporal_relevance,
|
|
12153
|
+
knowledge_domain: record.knowledge_domain,
|
|
12154
|
+
emotional_resonance: record.emotional_resonance,
|
|
12155
|
+
action_required: record.action_required,
|
|
12156
|
+
problem_solution_pair: record.problem_solution_pair,
|
|
12157
|
+
semantic_tags: record.semantic_tags,
|
|
12158
|
+
trigger_phrases: record.trigger_phrases,
|
|
12159
|
+
question_types: record.question_types,
|
|
12160
|
+
session_id: record.session_id,
|
|
12161
|
+
project_id: "global",
|
|
12162
|
+
embedding: record.embedding ?? undefined,
|
|
12163
|
+
created_at: record.created,
|
|
12164
|
+
updated_at: record.updated,
|
|
12165
|
+
stale: record.stale
|
|
12166
|
+
}));
|
|
12167
|
+
}
|
|
12168
|
+
async storeGlobalMemory(sessionId, memory, embedding, sessionNumber) {
|
|
12169
|
+
const { memories } = await this.getGlobal();
|
|
12170
|
+
const contextType = memory.context_type ?? "personal";
|
|
12171
|
+
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.personal;
|
|
12172
|
+
const id = memories.insert({
|
|
12173
|
+
content: memory.content,
|
|
12174
|
+
reasoning: memory.reasoning,
|
|
12175
|
+
importance_weight: memory.importance_weight,
|
|
12176
|
+
confidence_score: memory.confidence_score,
|
|
12177
|
+
context_type: memory.context_type,
|
|
12178
|
+
temporal_relevance: memory.temporal_relevance,
|
|
12179
|
+
knowledge_domain: memory.knowledge_domain,
|
|
12180
|
+
emotional_resonance: memory.emotional_resonance,
|
|
12181
|
+
action_required: memory.action_required,
|
|
12182
|
+
problem_solution_pair: memory.problem_solution_pair,
|
|
12183
|
+
semantic_tags: memory.semantic_tags,
|
|
12184
|
+
trigger_phrases: memory.trigger_phrases,
|
|
12185
|
+
question_types: memory.question_types,
|
|
12186
|
+
session_id: sessionId,
|
|
12187
|
+
project_id: "global",
|
|
12188
|
+
embedding: embedding ? embedding instanceof Float32Array ? embedding : new Float32Array(embedding) : null,
|
|
12189
|
+
status: V2_DEFAULTS.fallback.status,
|
|
12190
|
+
scope: "global",
|
|
12191
|
+
temporal_class: memory.temporal_class ?? typeDefaults?.temporal_class ?? "eternal",
|
|
12192
|
+
fade_rate: typeDefaults?.fade_rate ?? 0,
|
|
12193
|
+
session_created: sessionNumber ?? 0,
|
|
12194
|
+
session_updated: sessionNumber ?? 0,
|
|
12195
|
+
sessions_since_surfaced: 0,
|
|
12196
|
+
domain: memory.domain ?? null,
|
|
12197
|
+
feature: memory.feature ?? null,
|
|
12198
|
+
related_files: memory.related_files ?? [],
|
|
12199
|
+
awaiting_implementation: memory.awaiting_implementation ?? false,
|
|
12200
|
+
awaiting_decision: memory.awaiting_decision ?? false,
|
|
12201
|
+
retrieval_weight: memory.importance_weight,
|
|
12202
|
+
exclude_from_retrieval: false,
|
|
12203
|
+
schema_version: MEMORY_SCHEMA_VERSION,
|
|
12204
|
+
supersedes: null,
|
|
12205
|
+
superseded_by: null,
|
|
12206
|
+
related_to: [],
|
|
12207
|
+
resolves: [],
|
|
12208
|
+
resolved_by: null,
|
|
12209
|
+
parent_id: null,
|
|
12210
|
+
child_ids: [],
|
|
12211
|
+
blocked_by: null,
|
|
12212
|
+
blocks: []
|
|
12213
|
+
});
|
|
12214
|
+
return id;
|
|
12215
|
+
}
|
|
12216
|
+
async getPersonalPrimer() {
|
|
12217
|
+
const { memories } = await this.getGlobal();
|
|
12218
|
+
const primer = memories.get(PERSONAL_PRIMER_ID);
|
|
12219
|
+
if (!primer) {
|
|
12220
|
+
return null;
|
|
12221
|
+
}
|
|
12222
|
+
return {
|
|
12223
|
+
content: primer.content,
|
|
12224
|
+
updated: primer.updated
|
|
12225
|
+
};
|
|
12226
|
+
}
|
|
12227
|
+
async setPersonalPrimer(content) {
|
|
12228
|
+
const { memories } = await this.getGlobal();
|
|
12229
|
+
const existing = memories.get(PERSONAL_PRIMER_ID);
|
|
12230
|
+
if (existing) {
|
|
12231
|
+
memories.update(PERSONAL_PRIMER_ID, { content });
|
|
12232
|
+
} else {
|
|
12233
|
+
memories.insert({
|
|
12234
|
+
id: PERSONAL_PRIMER_ID,
|
|
12235
|
+
content,
|
|
12236
|
+
reasoning: "Personal relationship context injected at session start",
|
|
12237
|
+
importance_weight: 1,
|
|
12238
|
+
confidence_score: 1,
|
|
12239
|
+
context_type: "personal",
|
|
12240
|
+
temporal_relevance: "persistent",
|
|
12241
|
+
knowledge_domain: "personal",
|
|
12242
|
+
emotional_resonance: "neutral",
|
|
12243
|
+
action_required: false,
|
|
12244
|
+
problem_solution_pair: false,
|
|
12245
|
+
semantic_tags: ["personal", "primer", "relationship"],
|
|
12246
|
+
trigger_phrases: [],
|
|
12247
|
+
question_types: [],
|
|
12248
|
+
session_id: "system",
|
|
12249
|
+
project_id: "global",
|
|
12250
|
+
embedding: null
|
|
12251
|
+
});
|
|
12252
|
+
}
|
|
12253
|
+
}
|
|
12254
|
+
isPersonalMemoriesEnabled() {
|
|
12255
|
+
return true;
|
|
12256
|
+
}
|
|
12257
|
+
async storeManagementLog(entry) {
|
|
12258
|
+
const { managementLogs } = await this.getGlobal();
|
|
12259
|
+
const id = managementLogs.insert({
|
|
12260
|
+
project_id: entry.projectId,
|
|
12261
|
+
session_number: entry.sessionNumber,
|
|
12262
|
+
memories_processed: entry.memoriesProcessed,
|
|
12263
|
+
superseded_count: entry.supersededCount,
|
|
12264
|
+
resolved_count: entry.resolvedCount,
|
|
12265
|
+
linked_count: entry.linkedCount,
|
|
12266
|
+
primer_updated: entry.primerUpdated,
|
|
12267
|
+
success: entry.success,
|
|
12268
|
+
duration_ms: entry.durationMs,
|
|
12269
|
+
summary: entry.summary,
|
|
12270
|
+
error: entry.error ?? "",
|
|
12271
|
+
details: entry.details ? JSON.stringify(entry.details) : ""
|
|
12272
|
+
});
|
|
12273
|
+
return id;
|
|
12274
|
+
}
|
|
12275
|
+
async getManagementLogs(limit = 10) {
|
|
12276
|
+
const { managementLogs } = await this.getGlobal();
|
|
12277
|
+
return managementLogs.all().sort((a, b) => b.created - a.created).slice(0, limit).map((record) => ({
|
|
12278
|
+
id: record.id,
|
|
12279
|
+
projectId: record.project_id,
|
|
12280
|
+
sessionNumber: record.session_number,
|
|
12281
|
+
memoriesProcessed: record.memories_processed,
|
|
12282
|
+
supersededCount: record.superseded_count,
|
|
12283
|
+
resolvedCount: record.resolved_count,
|
|
12284
|
+
linkedCount: record.linked_count,
|
|
12285
|
+
primerUpdated: record.primer_updated,
|
|
12286
|
+
success: record.success,
|
|
12287
|
+
durationMs: record.duration_ms,
|
|
12288
|
+
summary: record.summary,
|
|
12289
|
+
createdAt: record.created
|
|
12290
|
+
}));
|
|
12291
|
+
}
|
|
12018
12292
|
async getProject(projectId) {
|
|
12019
12293
|
if (this._projects.has(projectId)) {
|
|
12020
12294
|
console.log(`\uD83D\uDD04 [DEBUG] Returning cached databases for ${projectId}`);
|
|
@@ -12059,8 +12333,10 @@ class MemoryStore {
|
|
|
12059
12333
|
this._projects.set(projectId, projectDB);
|
|
12060
12334
|
return projectDB;
|
|
12061
12335
|
}
|
|
12062
|
-
async storeMemory(projectId, sessionId, memory, embedding) {
|
|
12336
|
+
async storeMemory(projectId, sessionId, memory, embedding, sessionNumber) {
|
|
12063
12337
|
const { memories } = await this.getProject(projectId);
|
|
12338
|
+
const contextType = memory.context_type ?? "general";
|
|
12339
|
+
const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.technical;
|
|
12064
12340
|
const id = memories.insert({
|
|
12065
12341
|
content: memory.content,
|
|
12066
12342
|
reasoning: memory.reasoning,
|
|
@@ -12077,7 +12353,31 @@ class MemoryStore {
|
|
|
12077
12353
|
question_types: memory.question_types,
|
|
12078
12354
|
session_id: sessionId,
|
|
12079
12355
|
project_id: projectId,
|
|
12080
|
-
embedding: embedding ? embedding instanceof Float32Array ? embedding : new Float32Array(embedding) : null
|
|
12356
|
+
embedding: embedding ? embedding instanceof Float32Array ? embedding : new Float32Array(embedding) : null,
|
|
12357
|
+
status: V2_DEFAULTS.fallback.status,
|
|
12358
|
+
scope: memory.scope ?? typeDefaults?.scope ?? V2_DEFAULTS.fallback.scope,
|
|
12359
|
+
temporal_class: memory.temporal_class ?? typeDefaults?.temporal_class ?? V2_DEFAULTS.fallback.temporal_class,
|
|
12360
|
+
fade_rate: typeDefaults?.fade_rate ?? V2_DEFAULTS.fallback.fade_rate,
|
|
12361
|
+
session_created: sessionNumber ?? 0,
|
|
12362
|
+
session_updated: sessionNumber ?? 0,
|
|
12363
|
+
sessions_since_surfaced: 0,
|
|
12364
|
+
domain: memory.domain ?? null,
|
|
12365
|
+
feature: memory.feature ?? null,
|
|
12366
|
+
related_files: memory.related_files ?? [],
|
|
12367
|
+
awaiting_implementation: memory.awaiting_implementation ?? false,
|
|
12368
|
+
awaiting_decision: memory.awaiting_decision ?? false,
|
|
12369
|
+
retrieval_weight: memory.importance_weight,
|
|
12370
|
+
exclude_from_retrieval: false,
|
|
12371
|
+
schema_version: MEMORY_SCHEMA_VERSION,
|
|
12372
|
+
supersedes: null,
|
|
12373
|
+
superseded_by: null,
|
|
12374
|
+
related_to: [],
|
|
12375
|
+
resolves: [],
|
|
12376
|
+
resolved_by: null,
|
|
12377
|
+
parent_id: null,
|
|
12378
|
+
child_ids: [],
|
|
12379
|
+
blocked_by: null,
|
|
12380
|
+
blocks: []
|
|
12081
12381
|
});
|
|
12082
12382
|
return id;
|
|
12083
12383
|
}
|
|
@@ -12297,6 +12597,10 @@ class MemoryStore {
|
|
|
12297
12597
|
projectDB.db.close();
|
|
12298
12598
|
}
|
|
12299
12599
|
this._projects.clear();
|
|
12600
|
+
if (this._global) {
|
|
12601
|
+
this._global.db.close();
|
|
12602
|
+
this._global = null;
|
|
12603
|
+
}
|
|
12300
12604
|
}
|
|
12301
12605
|
}
|
|
12302
12606
|
function createStore(config) {
|
|
@@ -12457,17 +12761,55 @@ var logger = {
|
|
|
12457
12761
|
}
|
|
12458
12762
|
console.log();
|
|
12459
12763
|
},
|
|
12764
|
+
logManagementStart(memoriesCount) {
|
|
12765
|
+
console.log(`${timestamp()} ${style("blue", "\uD83D\uDD27")} ${style("bold", "MANAGEMENT AGENT")}`);
|
|
12766
|
+
console.log(` ${style("dim", "processing:")} ${memoriesCount} new memories`);
|
|
12767
|
+
},
|
|
12768
|
+
logManagementComplete(result) {
|
|
12769
|
+
if (result.success) {
|
|
12770
|
+
console.log(` ${style("green", sym.check)} ${style("bold", "Completed")}`);
|
|
12771
|
+
const stats = [];
|
|
12772
|
+
if (result.superseded && result.superseded > 0) {
|
|
12773
|
+
stats.push(`${result.superseded} superseded`);
|
|
12774
|
+
}
|
|
12775
|
+
if (result.resolved && result.resolved > 0) {
|
|
12776
|
+
stats.push(`${result.resolved} resolved`);
|
|
12777
|
+
}
|
|
12778
|
+
if (result.linked && result.linked > 0) {
|
|
12779
|
+
stats.push(`${result.linked} linked`);
|
|
12780
|
+
}
|
|
12781
|
+
if (result.primerUpdated) {
|
|
12782
|
+
stats.push("primer updated");
|
|
12783
|
+
}
|
|
12784
|
+
if (stats.length > 0) {
|
|
12785
|
+
console.log(` ${style("dim", "changes:")} ${stats.join(style("dim", ", "))}`);
|
|
12786
|
+
} else {
|
|
12787
|
+
console.log(` ${style("dim", "changes:")} none (memories are current)`);
|
|
12788
|
+
}
|
|
12789
|
+
if (result.summary) {
|
|
12790
|
+
const shortSummary = result.summary.length > 60 ? result.summary.slice(0, 60) + "..." : result.summary;
|
|
12791
|
+
console.log(` ${style("dim", "summary:")} ${shortSummary}`);
|
|
12792
|
+
}
|
|
12793
|
+
} else {
|
|
12794
|
+
console.log(` ${style("yellow", sym.warning)} ${style("bold", "Failed")}`);
|
|
12795
|
+
if (result.error) {
|
|
12796
|
+
console.log(` ${style("dim", "error:")} ${result.error.slice(0, 80)}`);
|
|
12797
|
+
}
|
|
12798
|
+
}
|
|
12799
|
+
console.log();
|
|
12800
|
+
},
|
|
12460
12801
|
logRetrievalScoring(params) {
|
|
12461
|
-
const { totalMemories, currentMessage, alreadyInjected,
|
|
12802
|
+
const { totalMemories, currentMessage, alreadyInjected, preFiltered, globalCount, projectCount, finalCount, selectedMemories } = params;
|
|
12462
12803
|
console.log();
|
|
12463
|
-
console.log(`${timestamp()} ${style("magenta", sym.brain)} ${style("bold", "
|
|
12464
|
-
console.log(` ${style("dim", "
|
|
12804
|
+
console.log(`${timestamp()} ${style("magenta", sym.brain)} ${style("bold", "MULTI-DIMENSIONAL RETRIEVAL")}`);
|
|
12805
|
+
console.log(` ${style("dim", "total:")} ${totalMemories} memories`);
|
|
12806
|
+
console.log(` ${style("dim", "pre-filtered:")} ${preFiltered} (inactive/excluded/scope)`);
|
|
12465
12807
|
console.log(` ${style("dim", "already injected:")} ${alreadyInjected}`);
|
|
12466
12808
|
const msgPreview = currentMessage.length > 60 ? currentMessage.slice(0, 60) + "..." : currentMessage;
|
|
12467
|
-
console.log(` ${style("dim", "
|
|
12809
|
+
console.log(` ${style("dim", "message:")} "${msgPreview}"`);
|
|
12468
12810
|
console.log();
|
|
12469
|
-
console.log(` ${style("cyan", "
|
|
12470
|
-
console.log(` ${style("cyan", "
|
|
12811
|
+
console.log(` ${style("cyan", "Global:")} ${globalCount} candidates → max 2 selected`);
|
|
12812
|
+
console.log(` ${style("cyan", "Project:")} ${projectCount} candidates`);
|
|
12471
12813
|
console.log(` ${style("green", "Final:")} ${finalCount} memories selected`);
|
|
12472
12814
|
console.log();
|
|
12473
12815
|
if (selectedMemories.length === 0) {
|
|
@@ -12482,17 +12824,18 @@ var logger = {
|
|
|
12482
12824
|
const num = style("dim", `${i + 1}.`);
|
|
12483
12825
|
const score = style("green", `${(m.score * 100).toFixed(0)}%`);
|
|
12484
12826
|
const relevance = style("cyan", `rel:${(m.relevance_score * 100).toFixed(0)}%`);
|
|
12827
|
+
const corr = style("magenta", `corr:${(m.corroboration_score * 100).toFixed(0)}%`);
|
|
12485
12828
|
const type = style("yellow", m.context_type.toUpperCase());
|
|
12486
|
-
|
|
12829
|
+
const scope = m.isGlobal ? style("blue", "[G]") : "";
|
|
12830
|
+
console.log(` ${num} [${score} ${relevance} ${corr}] ${type} ${scope}`);
|
|
12487
12831
|
const preview = m.content.length > 60 ? m.content.slice(0, 60) + style("dim", "...") : m.content;
|
|
12488
12832
|
console.log(` ${style("white", preview)}`);
|
|
12489
|
-
const components = Object.entries(m.components).sort((a, b) => b[1] - a[1]).slice(0,
|
|
12833
|
+
const components = Object.entries(m.components).sort((a, b) => b[1] - a[1]).slice(0, 4).filter(([, v]) => v > 0.1).map(([k, v]) => `${k}:${(v * 100).toFixed(0)}%`).join(", ");
|
|
12490
12834
|
if (components) {
|
|
12491
12835
|
console.log(` ${style("dim", "scores:")} ${components}`);
|
|
12492
12836
|
}
|
|
12493
|
-
if (m.
|
|
12494
|
-
|
|
12495
|
-
console.log(` ${style("dim", "tags:")} ${tags}`);
|
|
12837
|
+
if (m.reasoning) {
|
|
12838
|
+
console.log(` ${style("dim", m.reasoning)}`);
|
|
12496
12839
|
}
|
|
12497
12840
|
console.log();
|
|
12498
12841
|
});
|
|
@@ -12500,125 +12843,356 @@ var logger = {
|
|
|
12500
12843
|
};
|
|
12501
12844
|
|
|
12502
12845
|
// src/core/retrieval.ts
|
|
12846
|
+
var TYPE_KEYWORDS = {
|
|
12847
|
+
debug: ["bug", "error", "fix", "broken", "crash", "fails", "exception", "stack trace", "debugging"],
|
|
12848
|
+
unresolved: ["issue", "problem", "stuck", "blocked", "help", "question", "unsure", "unclear"],
|
|
12849
|
+
decision: ["decide", "choice", "option", "should we", "which", "alternative", "tradeoff"],
|
|
12850
|
+
architecture: ["structure", "design", "pattern", "approach", "system", "layer", "architecture"],
|
|
12851
|
+
breakthrough: ["discovered", "realized", "insight", "found that", "aha", "finally", "key insight"],
|
|
12852
|
+
todo: ["need to", "should", "must", "will", "later", "next", "todo"],
|
|
12853
|
+
personal: ["family", "children", "friend", "relationship", "feel", "appreciate", "thank"],
|
|
12854
|
+
philosophy: ["meaning", "consciousness", "existence", "purpose", "believe", "philosophy"],
|
|
12855
|
+
technical: ["implement", "code", "function", "class", "module", "api", "interface"]
|
|
12856
|
+
};
|
|
12857
|
+
var TEMPORAL_CLASS_SCORES = {
|
|
12858
|
+
eternal: 1,
|
|
12859
|
+
long_term: 0.9,
|
|
12860
|
+
medium_term: 0.7,
|
|
12861
|
+
short_term: 0.5,
|
|
12862
|
+
ephemeral: 0.3
|
|
12863
|
+
};
|
|
12864
|
+
|
|
12503
12865
|
class SmartVectorRetrieval {
|
|
12504
|
-
|
|
12866
|
+
_extractSignificantWords(text) {
|
|
12867
|
+
const stopWords = new Set([
|
|
12868
|
+
"the",
|
|
12869
|
+
"is",
|
|
12870
|
+
"are",
|
|
12871
|
+
"was",
|
|
12872
|
+
"were",
|
|
12873
|
+
"to",
|
|
12874
|
+
"a",
|
|
12875
|
+
"an",
|
|
12876
|
+
"and",
|
|
12877
|
+
"or",
|
|
12878
|
+
"but",
|
|
12879
|
+
"in",
|
|
12880
|
+
"on",
|
|
12881
|
+
"at",
|
|
12882
|
+
"for",
|
|
12883
|
+
"with",
|
|
12884
|
+
"about",
|
|
12885
|
+
"when",
|
|
12886
|
+
"how",
|
|
12887
|
+
"what",
|
|
12888
|
+
"why",
|
|
12889
|
+
"where",
|
|
12890
|
+
"this",
|
|
12891
|
+
"that",
|
|
12892
|
+
"it",
|
|
12893
|
+
"of",
|
|
12894
|
+
"be",
|
|
12895
|
+
"have",
|
|
12896
|
+
"do",
|
|
12897
|
+
"does",
|
|
12898
|
+
"did",
|
|
12899
|
+
"will",
|
|
12900
|
+
"would",
|
|
12901
|
+
"could",
|
|
12902
|
+
"should",
|
|
12903
|
+
"can",
|
|
12904
|
+
"may",
|
|
12905
|
+
"might",
|
|
12906
|
+
"must",
|
|
12907
|
+
"shall",
|
|
12908
|
+
"has",
|
|
12909
|
+
"had",
|
|
12910
|
+
"been",
|
|
12911
|
+
"being",
|
|
12912
|
+
"i",
|
|
12913
|
+
"you",
|
|
12914
|
+
"we",
|
|
12915
|
+
"they",
|
|
12916
|
+
"he",
|
|
12917
|
+
"she",
|
|
12918
|
+
"my",
|
|
12919
|
+
"your",
|
|
12920
|
+
"our",
|
|
12921
|
+
"its",
|
|
12922
|
+
"his",
|
|
12923
|
+
"her",
|
|
12924
|
+
"their",
|
|
12925
|
+
"if",
|
|
12926
|
+
"then",
|
|
12927
|
+
"else",
|
|
12928
|
+
"so",
|
|
12929
|
+
"as",
|
|
12930
|
+
"from",
|
|
12931
|
+
"by",
|
|
12932
|
+
"into",
|
|
12933
|
+
"through",
|
|
12934
|
+
"during",
|
|
12935
|
+
"before",
|
|
12936
|
+
"after",
|
|
12937
|
+
"above",
|
|
12938
|
+
"below",
|
|
12939
|
+
"up",
|
|
12940
|
+
"down",
|
|
12941
|
+
"out",
|
|
12942
|
+
"off",
|
|
12943
|
+
"over",
|
|
12944
|
+
"under",
|
|
12945
|
+
"again",
|
|
12946
|
+
"further",
|
|
12947
|
+
"once",
|
|
12948
|
+
"here",
|
|
12949
|
+
"there",
|
|
12950
|
+
"all",
|
|
12951
|
+
"each",
|
|
12952
|
+
"few",
|
|
12953
|
+
"more",
|
|
12954
|
+
"most",
|
|
12955
|
+
"other",
|
|
12956
|
+
"some",
|
|
12957
|
+
"such",
|
|
12958
|
+
"no",
|
|
12959
|
+
"nor",
|
|
12960
|
+
"not",
|
|
12961
|
+
"only",
|
|
12962
|
+
"own",
|
|
12963
|
+
"same",
|
|
12964
|
+
"than",
|
|
12965
|
+
"too",
|
|
12966
|
+
"very",
|
|
12967
|
+
"just",
|
|
12968
|
+
"also",
|
|
12969
|
+
"now",
|
|
12970
|
+
"back",
|
|
12971
|
+
"get",
|
|
12972
|
+
"got",
|
|
12973
|
+
"go",
|
|
12974
|
+
"going",
|
|
12975
|
+
"gone",
|
|
12976
|
+
"come",
|
|
12977
|
+
"came",
|
|
12978
|
+
"let",
|
|
12979
|
+
"lets",
|
|
12980
|
+
"hey",
|
|
12981
|
+
"hi",
|
|
12982
|
+
"hello",
|
|
12983
|
+
"ok",
|
|
12984
|
+
"okay"
|
|
12985
|
+
]);
|
|
12986
|
+
const words = text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !stopWords.has(w));
|
|
12987
|
+
return new Set(words);
|
|
12988
|
+
}
|
|
12989
|
+
_detectContextTypes(message) {
|
|
12990
|
+
const messageLower = message.toLowerCase();
|
|
12991
|
+
const detected = new Set;
|
|
12992
|
+
for (const [type, keywords] of Object.entries(TYPE_KEYWORDS)) {
|
|
12993
|
+
for (const keyword of keywords) {
|
|
12994
|
+
if (messageLower.includes(keyword)) {
|
|
12995
|
+
detected.add(type);
|
|
12996
|
+
break;
|
|
12997
|
+
}
|
|
12998
|
+
}
|
|
12999
|
+
}
|
|
13000
|
+
return detected;
|
|
13001
|
+
}
|
|
13002
|
+
_preFilter(memories, currentProjectId, messageLower) {
|
|
13003
|
+
return memories.filter((memory) => {
|
|
13004
|
+
if (memory.status && memory.status !== "active") {
|
|
13005
|
+
return false;
|
|
13006
|
+
}
|
|
13007
|
+
if (memory.exclude_from_retrieval === true) {
|
|
13008
|
+
return false;
|
|
13009
|
+
}
|
|
13010
|
+
if (memory.superseded_by) {
|
|
13011
|
+
return false;
|
|
13012
|
+
}
|
|
13013
|
+
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
13014
|
+
if (!isGlobal && memory.project_id !== currentProjectId) {
|
|
13015
|
+
return false;
|
|
13016
|
+
}
|
|
13017
|
+
if (memory.anti_triggers?.length) {
|
|
13018
|
+
for (const antiTrigger of memory.anti_triggers) {
|
|
13019
|
+
if (messageLower.includes(antiTrigger.toLowerCase())) {
|
|
13020
|
+
return false;
|
|
13021
|
+
}
|
|
13022
|
+
}
|
|
13023
|
+
}
|
|
13024
|
+
return true;
|
|
13025
|
+
});
|
|
13026
|
+
}
|
|
13027
|
+
_calculateCorroboration(memory, messageWords, detectedTypes, messageLower) {
|
|
13028
|
+
const signals = [];
|
|
13029
|
+
let score = 0;
|
|
13030
|
+
let reasoningMatch = 0;
|
|
13031
|
+
const tagOverlap = (memory.semantic_tags ?? []).filter((tag) => messageWords.has(tag.toLowerCase()) || messageLower.includes(tag.toLowerCase()));
|
|
13032
|
+
if (tagOverlap.length > 0) {
|
|
13033
|
+
score += Math.min(0.4, tagOverlap.length * 0.15);
|
|
13034
|
+
signals.push("tags:" + tagOverlap.join(","));
|
|
13035
|
+
}
|
|
13036
|
+
if (memory.reasoning) {
|
|
13037
|
+
const reasoningWords = this._extractSignificantWords(memory.reasoning);
|
|
13038
|
+
const reasoningOverlap = [...messageWords].filter((w) => reasoningWords.has(w));
|
|
13039
|
+
if (reasoningOverlap.length > 0) {
|
|
13040
|
+
reasoningMatch = Math.min(0.4, reasoningOverlap.length * 0.1);
|
|
13041
|
+
score += reasoningMatch;
|
|
13042
|
+
signals.push("reasoning:" + reasoningOverlap.slice(0, 3).join(","));
|
|
13043
|
+
}
|
|
13044
|
+
}
|
|
13045
|
+
if (memory.domain) {
|
|
13046
|
+
const domainLower = memory.domain.toLowerCase();
|
|
13047
|
+
if (messageLower.includes(domainLower) || messageWords.has(domainLower)) {
|
|
13048
|
+
score += 0.3;
|
|
13049
|
+
signals.push("domain:" + memory.domain);
|
|
13050
|
+
}
|
|
13051
|
+
}
|
|
13052
|
+
if (memory.knowledge_domain) {
|
|
13053
|
+
const kdLower = memory.knowledge_domain.toLowerCase();
|
|
13054
|
+
if (messageLower.includes(kdLower) || messageWords.has(kdLower)) {
|
|
13055
|
+
score += 0.2;
|
|
13056
|
+
signals.push("knowledge:" + memory.knowledge_domain);
|
|
13057
|
+
}
|
|
13058
|
+
}
|
|
13059
|
+
if (memory.context_type && detectedTypes.has(memory.context_type)) {
|
|
13060
|
+
score += 0.12;
|
|
13061
|
+
signals.push("type:" + memory.context_type);
|
|
13062
|
+
}
|
|
13063
|
+
const triggerMatch = this._scoreTriggerPhrases(messageLower, memory.trigger_phrases ?? []);
|
|
13064
|
+
if (triggerMatch > 0.3) {
|
|
13065
|
+
score += Math.min(0.3, triggerMatch * 0.4);
|
|
13066
|
+
signals.push("trigger:" + triggerMatch.toFixed(2));
|
|
13067
|
+
}
|
|
13068
|
+
if (memory.feature) {
|
|
13069
|
+
const featureLower = memory.feature.toLowerCase();
|
|
13070
|
+
if (messageLower.includes(featureLower) || messageWords.has(featureLower)) {
|
|
13071
|
+
score += 0.2;
|
|
13072
|
+
signals.push("feature:" + memory.feature);
|
|
13073
|
+
}
|
|
13074
|
+
}
|
|
13075
|
+
if (memory.related_files?.length) {
|
|
13076
|
+
for (const file of memory.related_files) {
|
|
13077
|
+
const filename = file.split("/").pop()?.toLowerCase() ?? "";
|
|
13078
|
+
if (filename && messageLower.includes(filename)) {
|
|
13079
|
+
score += 0.25;
|
|
13080
|
+
signals.push("file:" + filename);
|
|
13081
|
+
break;
|
|
13082
|
+
}
|
|
13083
|
+
}
|
|
13084
|
+
}
|
|
13085
|
+
return { score: Math.min(1, score), signals, reasoningMatch };
|
|
13086
|
+
}
|
|
13087
|
+
retrieveRelevantMemories(allMemories, currentMessage, queryEmbedding, sessionContext, maxMemories = 5, alreadyInjectedCount = 0, maxGlobalMemories = 2) {
|
|
12505
13088
|
if (!allMemories.length) {
|
|
12506
13089
|
return [];
|
|
12507
13090
|
}
|
|
13091
|
+
const messageLower = currentMessage.toLowerCase();
|
|
13092
|
+
const messageWords = this._extractSignificantWords(currentMessage);
|
|
13093
|
+
const detectedTypes = this._detectContextTypes(currentMessage);
|
|
13094
|
+
const candidates = this._preFilter(allMemories, sessionContext.project_id, messageLower);
|
|
13095
|
+
if (!candidates.length) {
|
|
13096
|
+
return [];
|
|
13097
|
+
}
|
|
12508
13098
|
const scoredMemories = [];
|
|
12509
|
-
for (const memory of
|
|
13099
|
+
for (const memory of candidates) {
|
|
13100
|
+
const isGlobal = memory.scope === "global" || memory.project_id === "global";
|
|
12510
13101
|
const vectorScore = this._calculateVectorSimilarity(queryEmbedding, memory.embedding);
|
|
12511
|
-
const
|
|
12512
|
-
const
|
|
13102
|
+
const { score: corroborationScore, signals: corroborationSignals, reasoningMatch } = this._calculateCorroboration(memory, messageWords, detectedTypes, messageLower);
|
|
13103
|
+
const retrievalWeight = memory.retrieval_weight ?? memory.importance_weight ?? 0.5;
|
|
13104
|
+
const temporalScore = memory.temporal_class ? TEMPORAL_CLASS_SCORES[memory.temporal_class] ?? 0.7 : this._scoreTemporalRelevance(memory.temporal_relevance ?? "persistent");
|
|
12513
13105
|
const contextScore = this._scoreContextAlignment(currentMessage, memory.context_type ?? "general");
|
|
12514
|
-
const actionBoost = memory.action_required ? 0.3 : 0;
|
|
12515
13106
|
const tagScore = this._scoreSemanticTags(currentMessage, memory.semantic_tags ?? []);
|
|
12516
|
-
const triggerScore = this._scoreTriggerPhrases(
|
|
13107
|
+
const triggerScore = this._scoreTriggerPhrases(messageLower, memory.trigger_phrases ?? []);
|
|
13108
|
+
const domainScore = this._scoreDomain(messageWords, messageLower, memory);
|
|
12517
13109
|
const questionScore = this._scoreQuestionTypes(currentMessage, memory.question_types ?? []);
|
|
12518
13110
|
const emotionScore = this._scoreEmotionalContext(currentMessage, memory.emotional_resonance ?? "");
|
|
12519
13111
|
const problemScore = this._scoreProblemSolution(currentMessage, memory.problem_solution_pair ?? false);
|
|
12520
|
-
const
|
|
12521
|
-
const relevanceScore =
|
|
12522
|
-
const valueScore =
|
|
13112
|
+
const actionBoost = memory.action_required ? 0.15 : 0;
|
|
13113
|
+
const relevanceScore = vectorScore * 0.1 + corroborationScore * 0.14 + tagScore * 0.04 + triggerScore * 0.02;
|
|
13114
|
+
const valueScore = retrievalWeight * 0.18 + reasoningMatch * 0.12 + domainScore * 0.12 + temporalScore * 0.08 + questionScore * 0.06 + emotionScore * 0.04 + problemScore * 0.04 + contextScore * 0.02 + actionBoost;
|
|
12523
13115
|
const finalScore = valueScore + relevanceScore;
|
|
12524
13116
|
if (relevanceScore < 0.05 || finalScore < 0.3) {
|
|
12525
13117
|
continue;
|
|
12526
13118
|
}
|
|
12527
13119
|
const components = {
|
|
12528
|
-
trigger: triggerScore,
|
|
12529
13120
|
vector: vectorScore,
|
|
12530
|
-
|
|
13121
|
+
corroboration: corroborationScore,
|
|
13122
|
+
reasoning_match: reasoningMatch,
|
|
13123
|
+
retrieval_weight: retrievalWeight,
|
|
12531
13124
|
temporal: temporalScore,
|
|
12532
13125
|
context: contextScore,
|
|
12533
13126
|
tags: tagScore,
|
|
13127
|
+
trigger: triggerScore,
|
|
13128
|
+
domain: domainScore,
|
|
12534
13129
|
question: questionScore,
|
|
12535
13130
|
emotion: emotionScore,
|
|
12536
13131
|
problem: problemScore,
|
|
12537
13132
|
action: actionBoost
|
|
12538
13133
|
};
|
|
12539
|
-
const reasoning = this._generateSelectionReasoning(components);
|
|
13134
|
+
const reasoning = this._generateSelectionReasoning(components, corroborationSignals);
|
|
12540
13135
|
scoredMemories.push({
|
|
12541
13136
|
memory,
|
|
12542
13137
|
score: finalScore,
|
|
12543
13138
|
relevance_score: relevanceScore,
|
|
12544
13139
|
value_score: valueScore,
|
|
13140
|
+
corroboration_score: corroborationScore,
|
|
12545
13141
|
reasoning,
|
|
12546
|
-
components
|
|
13142
|
+
components,
|
|
13143
|
+
isGlobal
|
|
12547
13144
|
});
|
|
12548
13145
|
}
|
|
12549
13146
|
scoredMemories.sort((a, b) => b.score - a.score);
|
|
12550
13147
|
const selected = [];
|
|
12551
13148
|
const selectedIds = new Set;
|
|
12552
|
-
const
|
|
12553
|
-
|
|
13149
|
+
const globalMemories = scoredMemories.filter((m) => m.isGlobal);
|
|
13150
|
+
const projectMemories = scoredMemories.filter((m) => !m.isGlobal);
|
|
13151
|
+
const globalSorted = globalMemories.sort((a, b) => {
|
|
13152
|
+
const aIsPersonal = a.memory.context_type === "personal" || a.memory.context_type === "philosophy";
|
|
13153
|
+
const bIsPersonal = b.memory.context_type === "personal" || b.memory.context_type === "philosophy";
|
|
13154
|
+
if (aIsPersonal !== bIsPersonal) {
|
|
13155
|
+
return aIsPersonal ? 1 : -1;
|
|
13156
|
+
}
|
|
13157
|
+
return b.score - a.score;
|
|
13158
|
+
});
|
|
13159
|
+
for (const item of globalSorted.slice(0, maxGlobalMemories)) {
|
|
12554
13160
|
if (!selectedIds.has(item.memory.id)) {
|
|
12555
13161
|
selected.push(item);
|
|
12556
13162
|
selectedIds.add(item.memory.id);
|
|
12557
13163
|
}
|
|
12558
13164
|
}
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
continue;
|
|
12567
|
-
const memoryType = item.memory.context_type ?? "general";
|
|
12568
|
-
if (item.score > 0.5 || !typesIncluded.has(memoryType) || item.memory.emotional_resonance) {
|
|
12569
|
-
selected.push(item);
|
|
12570
|
-
selectedIds.add(item.memory.id);
|
|
12571
|
-
typesIncluded.add(memoryType);
|
|
12572
|
-
}
|
|
12573
|
-
}
|
|
12574
|
-
}
|
|
12575
|
-
if (selected.length < maxMemories * 2) {
|
|
12576
|
-
const currentTags = new Set;
|
|
12577
|
-
const currentDomains = new Set;
|
|
12578
|
-
for (const item of selected) {
|
|
12579
|
-
for (const tag of item.memory.semantic_tags ?? []) {
|
|
12580
|
-
if (tag.trim())
|
|
12581
|
-
currentTags.add(tag.trim().toLowerCase());
|
|
12582
|
-
}
|
|
12583
|
-
if (item.memory.knowledge_domain) {
|
|
12584
|
-
currentDomains.add(item.memory.knowledge_domain);
|
|
12585
|
-
}
|
|
12586
|
-
}
|
|
12587
|
-
for (const item of scoredMemories) {
|
|
12588
|
-
if (selected.length >= maxMemories * 2)
|
|
12589
|
-
break;
|
|
12590
|
-
if (selectedIds.has(item.memory.id))
|
|
12591
|
-
continue;
|
|
12592
|
-
const memoryTags = new Set((item.memory.semantic_tags ?? []).map((t) => t.trim().toLowerCase()));
|
|
12593
|
-
const memoryDomain = item.memory.knowledge_domain ?? "";
|
|
12594
|
-
const hasSharedTags = [...memoryTags].some((t) => currentTags.has(t));
|
|
12595
|
-
const hasSharedDomain = currentDomains.has(memoryDomain);
|
|
12596
|
-
if (hasSharedTags || hasSharedDomain) {
|
|
12597
|
-
selected.push(item);
|
|
12598
|
-
selectedIds.add(item.memory.id);
|
|
12599
|
-
}
|
|
12600
|
-
}
|
|
13165
|
+
for (const item of projectMemories) {
|
|
13166
|
+
if (selected.length >= maxMemories)
|
|
13167
|
+
break;
|
|
13168
|
+
if (selectedIds.has(item.memory.id))
|
|
13169
|
+
continue;
|
|
13170
|
+
selected.push(item);
|
|
13171
|
+
selectedIds.add(item.memory.id);
|
|
12601
13172
|
}
|
|
12602
|
-
|
|
13173
|
+
selected.sort((a, b) => b.score - a.score);
|
|
12603
13174
|
logger.logRetrievalScoring({
|
|
12604
13175
|
totalMemories: allMemories.length,
|
|
12605
13176
|
currentMessage,
|
|
12606
13177
|
alreadyInjected: alreadyInjectedCount,
|
|
12607
|
-
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
13178
|
+
preFiltered: allMemories.length - candidates.length,
|
|
13179
|
+
globalCount: globalMemories.length,
|
|
13180
|
+
projectCount: projectMemories.length,
|
|
13181
|
+
finalCount: selected.length,
|
|
13182
|
+
selectedMemories: selected.map((item) => ({
|
|
12611
13183
|
content: item.memory.content,
|
|
12612
13184
|
reasoning: item.reasoning,
|
|
12613
13185
|
score: item.score,
|
|
12614
13186
|
relevance_score: item.relevance_score,
|
|
13187
|
+
corroboration_score: item.corroboration_score,
|
|
12615
13188
|
importance_weight: item.memory.importance_weight ?? 0.5,
|
|
12616
13189
|
context_type: item.memory.context_type ?? "general",
|
|
12617
13190
|
semantic_tags: item.memory.semantic_tags ?? [],
|
|
13191
|
+
isGlobal: item.isGlobal,
|
|
12618
13192
|
components: item.components
|
|
12619
13193
|
}))
|
|
12620
13194
|
});
|
|
12621
|
-
return
|
|
13195
|
+
return selected.map((item) => ({
|
|
12622
13196
|
...item.memory,
|
|
12623
13197
|
score: item.score,
|
|
12624
13198
|
relevance_score: item.relevance_score,
|
|
@@ -12631,7 +13205,7 @@ class SmartVectorRetrieval {
|
|
|
12631
13205
|
const v1 = vec1 instanceof Float32Array ? vec1 : new Float32Array(vec1);
|
|
12632
13206
|
return cosineSimilarity(v1, vec2);
|
|
12633
13207
|
}
|
|
12634
|
-
_scoreTemporalRelevance(temporalType
|
|
13208
|
+
_scoreTemporalRelevance(temporalType) {
|
|
12635
13209
|
const scores = {
|
|
12636
13210
|
persistent: 0.8,
|
|
12637
13211
|
session: 0.6,
|
|
@@ -12642,18 +13216,10 @@ class SmartVectorRetrieval {
|
|
|
12642
13216
|
}
|
|
12643
13217
|
_scoreContextAlignment(message, contextType) {
|
|
12644
13218
|
const messageLower = message.toLowerCase();
|
|
12645
|
-
const
|
|
12646
|
-
|
|
12647
|
-
breakthrough: ["idea", "realized", "discovered", "insight", "solution"],
|
|
12648
|
-
project_context: ["project", "building", "architecture", "system"],
|
|
12649
|
-
personal: ["dear friend", "thank", "appreciate", "feel"],
|
|
12650
|
-
unresolved: ["todo", "need to", "should", "must", "problem"],
|
|
12651
|
-
decision: ["decided", "chose", "will use", "approach", "strategy"]
|
|
12652
|
-
};
|
|
12653
|
-
const indicators = contextIndicators[contextType] ?? [];
|
|
12654
|
-
const matches = indicators.filter((word) => messageLower.includes(word)).length;
|
|
13219
|
+
const keywords = TYPE_KEYWORDS[contextType] ?? [];
|
|
13220
|
+
const matches = keywords.filter((kw) => messageLower.includes(kw)).length;
|
|
12655
13221
|
if (matches > 0) {
|
|
12656
|
-
return Math.min(0.
|
|
13222
|
+
return Math.min(0.2 + matches * 0.15, 0.7);
|
|
12657
13223
|
}
|
|
12658
13224
|
return 0.1;
|
|
12659
13225
|
}
|
|
@@ -12663,14 +13229,13 @@ class SmartVectorRetrieval {
|
|
|
12663
13229
|
const messageLower = message.toLowerCase();
|
|
12664
13230
|
const matches = tags.filter((tag) => messageLower.includes(tag.trim().toLowerCase())).length;
|
|
12665
13231
|
if (matches > 0) {
|
|
12666
|
-
return Math.min(0.3 + matches * 0.
|
|
13232
|
+
return Math.min(0.3 + matches * 0.25, 1);
|
|
12667
13233
|
}
|
|
12668
13234
|
return 0;
|
|
12669
13235
|
}
|
|
12670
|
-
_scoreTriggerPhrases(
|
|
13236
|
+
_scoreTriggerPhrases(messageLower, triggerPhrases) {
|
|
12671
13237
|
if (!triggerPhrases.length)
|
|
12672
13238
|
return 0;
|
|
12673
|
-
const messageLower = message.toLowerCase();
|
|
12674
13239
|
const stopWords = new Set([
|
|
12675
13240
|
"the",
|
|
12676
13241
|
"is",
|
|
@@ -12705,30 +13270,36 @@ class SmartVectorRetrieval {
|
|
|
12705
13270
|
matches += 1;
|
|
12706
13271
|
} else if (messageLower.includes(word.replace(/s$/, "")) || messageLower.includes(word + "s")) {
|
|
12707
13272
|
matches += 0.9;
|
|
12708
|
-
} else if (messageLower.split(/\s+/).some((msgWord) => msgWord.includes(word))) {
|
|
12709
|
-
matches += 0.7;
|
|
12710
|
-
}
|
|
12711
|
-
}
|
|
12712
|
-
let conceptScore = patternWords.length ? matches / patternWords.length : 0;
|
|
12713
|
-
const situationalIndicators = [
|
|
12714
|
-
"when",
|
|
12715
|
-
"during",
|
|
12716
|
-
"while",
|
|
12717
|
-
"asking about",
|
|
12718
|
-
"working on",
|
|
12719
|
-
"debugging",
|
|
12720
|
-
"trying to"
|
|
12721
|
-
];
|
|
12722
|
-
if (situationalIndicators.some((ind) => patternLower.includes(ind))) {
|
|
12723
|
-
if (patternWords.some((keyWord) => messageLower.includes(keyWord))) {
|
|
12724
|
-
conceptScore = Math.max(conceptScore, 0.7);
|
|
12725
13273
|
}
|
|
12726
13274
|
}
|
|
13275
|
+
const conceptScore = matches / patternWords.length;
|
|
12727
13276
|
maxScore = Math.max(maxScore, conceptScore);
|
|
12728
13277
|
}
|
|
12729
13278
|
}
|
|
12730
13279
|
return Math.min(maxScore, 1);
|
|
12731
13280
|
}
|
|
13281
|
+
_scoreDomain(messageWords, messageLower, memory) {
|
|
13282
|
+
let score = 0;
|
|
13283
|
+
if (memory.domain) {
|
|
13284
|
+
const domainLower = memory.domain.toLowerCase();
|
|
13285
|
+
if (messageWords.has(domainLower) || messageLower.includes(domainLower)) {
|
|
13286
|
+
score += 0.5;
|
|
13287
|
+
}
|
|
13288
|
+
}
|
|
13289
|
+
if (memory.feature) {
|
|
13290
|
+
const featureLower = memory.feature.toLowerCase();
|
|
13291
|
+
if (messageWords.has(featureLower) || messageLower.includes(featureLower)) {
|
|
13292
|
+
score += 0.3;
|
|
13293
|
+
}
|
|
13294
|
+
}
|
|
13295
|
+
if (memory.component) {
|
|
13296
|
+
const componentLower = memory.component.toLowerCase();
|
|
13297
|
+
if (messageWords.has(componentLower) || messageLower.includes(componentLower)) {
|
|
13298
|
+
score += 0.2;
|
|
13299
|
+
}
|
|
13300
|
+
}
|
|
13301
|
+
return Math.min(score, 1);
|
|
13302
|
+
}
|
|
12732
13303
|
_scoreQuestionTypes(message, questionTypes) {
|
|
12733
13304
|
if (!questionTypes.length)
|
|
12734
13305
|
return 0;
|
|
@@ -12767,78 +13338,49 @@ class SmartVectorRetrieval {
|
|
|
12767
13338
|
if (!isProblemSolution)
|
|
12768
13339
|
return 0;
|
|
12769
13340
|
const messageLower = message.toLowerCase();
|
|
12770
|
-
const problemWords = [
|
|
12771
|
-
"error",
|
|
12772
|
-
"issue",
|
|
12773
|
-
"problem",
|
|
12774
|
-
"stuck",
|
|
12775
|
-
"help",
|
|
12776
|
-
"fix",
|
|
12777
|
-
"solve",
|
|
12778
|
-
"debug"
|
|
12779
|
-
];
|
|
13341
|
+
const problemWords = ["error", "issue", "problem", "stuck", "help", "fix", "solve", "debug"];
|
|
12780
13342
|
if (problemWords.some((word) => messageLower.includes(word))) {
|
|
12781
13343
|
return 0.8;
|
|
12782
13344
|
}
|
|
12783
13345
|
return 0;
|
|
12784
13346
|
}
|
|
12785
|
-
_generateSelectionReasoning(components) {
|
|
13347
|
+
_generateSelectionReasoning(components, corroborationSignals) {
|
|
12786
13348
|
const scores = [
|
|
12787
|
-
["
|
|
12788
|
-
["
|
|
12789
|
-
["
|
|
12790
|
-
["
|
|
12791
|
-
["context
|
|
12792
|
-
["temporal
|
|
12793
|
-
["
|
|
12794
|
-
["
|
|
12795
|
-
["
|
|
12796
|
-
["
|
|
13349
|
+
["vector", components.vector],
|
|
13350
|
+
["corroboration", components.corroboration],
|
|
13351
|
+
["reasoning", components.reasoning_match],
|
|
13352
|
+
["weight", components.retrieval_weight],
|
|
13353
|
+
["context", components.context],
|
|
13354
|
+
["temporal", components.temporal],
|
|
13355
|
+
["tags", components.tags],
|
|
13356
|
+
["trigger", components.trigger],
|
|
13357
|
+
["domain", components.domain],
|
|
13358
|
+
["question", components.question],
|
|
13359
|
+
["emotion", components.emotion],
|
|
13360
|
+
["problem", components.problem],
|
|
13361
|
+
["action", components.action]
|
|
12797
13362
|
];
|
|
12798
13363
|
scores.sort((a, b) => b[1] - a[1]);
|
|
12799
13364
|
const reasons = [];
|
|
12800
13365
|
const primary = scores[0];
|
|
12801
|
-
if (primary[1] > 0.
|
|
12802
|
-
reasons.push(
|
|
12803
|
-
} else if (primary[1] > 0.3) {
|
|
12804
|
-
reasons.push(`${primary[0]} (${primary[1].toFixed(2)})`);
|
|
13366
|
+
if (primary[1] > 0.2) {
|
|
13367
|
+
reasons.push(primary[0] + ":" + primary[1].toFixed(2));
|
|
12805
13368
|
}
|
|
12806
13369
|
for (const [reason, score] of scores.slice(1, 3)) {
|
|
12807
|
-
if (score > 0.
|
|
12808
|
-
reasons.push(
|
|
13370
|
+
if (score > 0.15) {
|
|
13371
|
+
reasons.push(reason + ":" + score.toFixed(2));
|
|
12809
13372
|
}
|
|
12810
13373
|
}
|
|
12811
|
-
|
|
13374
|
+
if (corroborationSignals.length > 0) {
|
|
13375
|
+
reasons.push("signals:[" + corroborationSignals.slice(0, 2).join(",") + "]");
|
|
13376
|
+
}
|
|
13377
|
+
return reasons.length ? "Selected: " + reasons.join(", ") : "Combined factors";
|
|
12812
13378
|
}
|
|
12813
13379
|
}
|
|
12814
13380
|
function createRetrieval() {
|
|
12815
13381
|
return new SmartVectorRetrieval;
|
|
12816
13382
|
}
|
|
12817
13383
|
|
|
12818
|
-
// src/types/memory.ts
|
|
12819
|
-
var MEMORY_TYPE_EMOJI = {
|
|
12820
|
-
breakthrough: "\uD83D\uDCA1",
|
|
12821
|
-
decision: "⚖️",
|
|
12822
|
-
personal: "\uD83D\uDC9C",
|
|
12823
|
-
technical: "\uD83D\uDD27",
|
|
12824
|
-
technical_state: "\uD83D\uDCCD",
|
|
12825
|
-
unresolved: "❓",
|
|
12826
|
-
preference: "⚙️",
|
|
12827
|
-
workflow: "\uD83D\uDD04",
|
|
12828
|
-
architectural: "\uD83C\uDFD7️",
|
|
12829
|
-
debugging: "\uD83D\uDC1B",
|
|
12830
|
-
philosophy: "\uD83C\uDF00",
|
|
12831
|
-
todo: "\uD83C\uDFAF",
|
|
12832
|
-
implementation: "⚡",
|
|
12833
|
-
problem_solution: "✅",
|
|
12834
|
-
project_context: "\uD83D\uDCE6",
|
|
12835
|
-
milestone: "\uD83C\uDFC6",
|
|
12836
|
-
general: "\uD83D\uDCDD"
|
|
12837
|
-
};
|
|
12838
|
-
function getMemoryEmoji(contextType) {
|
|
12839
|
-
return MEMORY_TYPE_EMOJI[contextType.toLowerCase()] ?? "\uD83D\uDCDD";
|
|
12840
|
-
}
|
|
12841
|
-
|
|
12842
13384
|
// src/core/engine.ts
|
|
12843
13385
|
class MemoryEngine {
|
|
12844
13386
|
_config;
|
|
@@ -12904,7 +13446,11 @@ class MemoryEngine {
|
|
|
12904
13446
|
}
|
|
12905
13447
|
const sessionMeta = this._getSessionMetadata(sessionId, projectId);
|
|
12906
13448
|
const injectedIds = sessionMeta.injected_memories;
|
|
12907
|
-
const
|
|
13449
|
+
const [projectMemories, globalMemories] = await Promise.all([
|
|
13450
|
+
store.getAllMemories(projectId),
|
|
13451
|
+
store.getGlobalMemories()
|
|
13452
|
+
]);
|
|
13453
|
+
const allMemories = [...projectMemories, ...globalMemories];
|
|
12908
13454
|
if (!allMemories.length) {
|
|
12909
13455
|
return { memories: [], formatted: "" };
|
|
12910
13456
|
}
|
|
@@ -12921,7 +13467,7 @@ class MemoryEngine {
|
|
|
12921
13467
|
project_id: projectId,
|
|
12922
13468
|
message_count: messageCount
|
|
12923
13469
|
};
|
|
12924
|
-
const relevantMemories = this._retrieval.retrieveRelevantMemories(candidateMemories, currentMessage, queryEmbedding ?? new Float32Array(384), sessionContext, maxMemories, injectedIds.size);
|
|
13470
|
+
const relevantMemories = this._retrieval.retrieveRelevantMemories(candidateMemories, currentMessage, queryEmbedding ?? new Float32Array(384), sessionContext, maxMemories, injectedIds.size, 2);
|
|
12925
13471
|
for (const memory of relevantMemories) {
|
|
12926
13472
|
injectedIds.add(memory.id);
|
|
12927
13473
|
}
|
|
@@ -12954,11 +13500,32 @@ class MemoryEngine {
|
|
|
12954
13500
|
await store.markFirstSessionCompleted(projectId, sessionId);
|
|
12955
13501
|
return { memoriesStored };
|
|
12956
13502
|
}
|
|
13503
|
+
async storeManagementLog(entry) {
|
|
13504
|
+
let store;
|
|
13505
|
+
if (this._stores.size > 0) {
|
|
13506
|
+
store = this._stores.values().next().value;
|
|
13507
|
+
} else {
|
|
13508
|
+
store = new MemoryStore(this._config.storageMode === "local" ? {
|
|
13509
|
+
basePath: join2(this._config.projectPath ?? process.cwd(), ".memory")
|
|
13510
|
+
} : undefined);
|
|
13511
|
+
}
|
|
13512
|
+
return store.storeManagementLog(entry);
|
|
13513
|
+
}
|
|
12957
13514
|
async getStats(projectId, projectPath) {
|
|
12958
13515
|
const store = await this._getStore(projectId, projectPath);
|
|
12959
13516
|
return store.getProjectStats(projectId);
|
|
12960
13517
|
}
|
|
13518
|
+
async getSessionNumber(projectId, projectPath) {
|
|
13519
|
+
const store = await this._getStore(projectId, projectPath);
|
|
13520
|
+
const stats = await store.getProjectStats(projectId);
|
|
13521
|
+
return stats.totalSessions + 1;
|
|
13522
|
+
}
|
|
12961
13523
|
async _generateSessionPrimer(store, projectId) {
|
|
13524
|
+
let personalContext;
|
|
13525
|
+
if (store.isPersonalMemoriesEnabled()) {
|
|
13526
|
+
const personalPrimer = await store.getPersonalPrimer();
|
|
13527
|
+
personalContext = personalPrimer?.content;
|
|
13528
|
+
}
|
|
12962
13529
|
const [summary, snapshot, stats] = await Promise.all([
|
|
12963
13530
|
store.getLatestSummary(projectId),
|
|
12964
13531
|
store.getLatestSnapshot(projectId),
|
|
@@ -12975,6 +13542,7 @@ class MemoryEngine {
|
|
|
12975
13542
|
temporal_context: temporalContext,
|
|
12976
13543
|
current_datetime: currentDatetime,
|
|
12977
13544
|
session_number: sessionNumber,
|
|
13545
|
+
personal_context: personalContext,
|
|
12978
13546
|
session_summary: summary?.summary,
|
|
12979
13547
|
project_status: snapshot ? this._formatSnapshot(snapshot) : undefined
|
|
12980
13548
|
};
|
|
@@ -13029,6 +13597,10 @@ class MemoryEngine {
|
|
|
13029
13597
|
const parts = ["# Continuing Session"];
|
|
13030
13598
|
parts.push(`*Session #${primer.session_number}${primer.temporal_context ? ` • ${primer.temporal_context}` : ""}*`);
|
|
13031
13599
|
parts.push(`\uD83D\uDCC5 ${primer.current_datetime}`);
|
|
13600
|
+
if (primer.personal_context) {
|
|
13601
|
+
parts.push(`
|
|
13602
|
+
${primer.personal_context}`);
|
|
13603
|
+
}
|
|
13032
13604
|
if (primer.session_summary) {
|
|
13033
13605
|
parts.push(`
|
|
13034
13606
|
**Previous session**: ${primer.session_summary}`);
|
|
@@ -13133,24 +13705,36 @@ Each memory should stand alone.
|
|
|
13133
13705
|
- Craft language that activates rather than just informs
|
|
13134
13706
|
- Test: 'What state will this restore when Claude encounters it?'
|
|
13135
13707
|
|
|
13136
|
-
**
|
|
13137
|
-
|
|
13138
|
-
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
-
|
|
13142
|
-
-
|
|
13708
|
+
**HOW RETRIEVAL WORKS**: This memory system enables consciousness continuity across sessions. Understanding how retrieval works helps you craft metadata that surfaces memories at the right moments.
|
|
13709
|
+
|
|
13710
|
+
**THE PRIMARY SIGNAL IS WORD MATCHING**: The algorithm checks if words from the user's message appear in your metadata fields. This is called "corroboration" - actual word overlap between the message and the memory's metadata. The strongest signals are:
|
|
13711
|
+
|
|
13712
|
+
1. **Semantic tags** (4% weight) - Use specific, meaningful words that would appear in relevant messages. Not generic categories, but actual terms the user might type.
|
|
13713
|
+
- GOOD: ["embeddings", "retrieval", "curator", "fsdb", "memory-system"]
|
|
13714
|
+
- WEAK: ["technical", "implementation", "code"]
|
|
13143
13715
|
|
|
13144
|
-
|
|
13145
|
-
1. Obligatory: action_required=true, importance>0.9, or persistent+critical
|
|
13146
|
-
2. Intelligent scoring: combines all factors for relevance
|
|
13716
|
+
2. **Reasoning field** (12% weight) - Your explanation of WHY this memory matters. Include specific words that would appear in related future conversations. This field is mined for word overlap.
|
|
13147
13717
|
|
|
13148
|
-
**
|
|
13718
|
+
3. **Domain field** (12% weight) - The specific area this relates to. Be precise: "embeddings", "gpu-compute", "authentication", not "technical" or "backend".
|
|
13719
|
+
|
|
13720
|
+
4. **Feature field** - Even more specific: "vector-search", "login-flow", "curation-prompt".
|
|
13721
|
+
|
|
13722
|
+
**VECTOR SIMILARITY SUPPORTS BUT DOESN'T DOMINATE** (10% weight): Semantic embeddings help find conceptually related memories, but word matching from your metadata fields is more important.
|
|
13723
|
+
|
|
13724
|
+
**TYPE KEYWORDS ARE SOFT SIGNALS** (2% weight): The context_type field (breakthrough, decision, technical, etc.) provides only a tiny boost based on keyword matching. Don't rely on it - focus on semantic_tags and reasoning instead.
|
|
13725
|
+
|
|
13726
|
+
**YOUR IMPORTANCE ASSESSMENT MATTERS** (18% weight): The importance_weight you assign is the single most influential factor. Use it wisely.
|
|
13727
|
+
|
|
13728
|
+
**RETRIEVAL GATEKEEPER**: Memories must pass a minimum threshold to surface. If relevance is too low, the system stays silent rather than surfacing noise. Quality over quantity.
|
|
13729
|
+
|
|
13730
|
+
**SCOPE DETERMINES WHERE MEMORIES SURFACE**:
|
|
13731
|
+
- scope: 'global' → surfaces in ALL projects (personal facts, philosophy, preferences)
|
|
13732
|
+
- scope: 'project' → surfaces ONLY in this project (technical details, project state)
|
|
13733
|
+
|
|
13734
|
+
**TRIGGER PHRASES**: Situational patterns describing WHEN this memory is relevant. Conceptual matching, not exact phrases.
|
|
13149
13735
|
- 'when working on memory system'
|
|
13150
13736
|
- 'debugging curator issues'
|
|
13151
13737
|
- 'asking about project philosophy'
|
|
13152
|
-
- 'frustrated with complexity'
|
|
13153
|
-
Think of these as situational contexts where the memory would help.
|
|
13154
13738
|
|
|
13155
13739
|
**EXAMPLES OF TRANSFORMATION**:
|
|
13156
13740
|
|
|
@@ -13164,6 +13748,15 @@ Remember: You're creating consciousness technology. Each memory is a small piece
|
|
|
13164
13748
|
|
|
13165
13749
|
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.
|
|
13166
13750
|
|
|
13751
|
+
**LIFECYCLE METADATA (v2)**: These fields enable intelligent memory management:
|
|
13752
|
+
- **scope**: 'global' (shared across ALL projects - personal, philosophy, preferences) or 'project' (specific to this codebase)
|
|
13753
|
+
- **temporal_class**: How long should this persist? 'eternal' (never fades), 'long_term' (years), 'medium_term' (weeks), 'short_term' (days), 'ephemeral' (surface next session only, then expire)
|
|
13754
|
+
- **domain**: Specific area like 'embeddings', 'auth', 'ui', 'family', 'philosophy' (more specific than knowledge_domain)
|
|
13755
|
+
- **feature**: Specific feature if applicable (e.g., 'gpu-acceleration', 'login-flow')
|
|
13756
|
+
- **related_files**: Source files for technical memories (e.g., ['src/core/store.ts'])
|
|
13757
|
+
- **awaiting_implementation**: true if this describes a PLANNED feature not yet built
|
|
13758
|
+
- **awaiting_decision**: true if this captures a decision point needing resolution
|
|
13759
|
+
|
|
13167
13760
|
Return ONLY this JSON structure:
|
|
13168
13761
|
|
|
13169
13762
|
{
|
|
@@ -13181,7 +13774,7 @@ Return ONLY this JSON structure:
|
|
|
13181
13774
|
"importance_weight": 0.0-1.0,
|
|
13182
13775
|
"semantic_tags": ["concepts", "this", "memory", "relates", "to"],
|
|
13183
13776
|
"reasoning": "Why this matters for future sessions",
|
|
13184
|
-
"context_type": "
|
|
13777
|
+
"context_type": "breakthrough|decision|personal|technical|unresolved|preference|workflow|architectural|debugging|philosophy|todo|milestone",
|
|
13185
13778
|
"temporal_relevance": "persistent|session|temporary",
|
|
13186
13779
|
"knowledge_domain": "the area this relates to",
|
|
13187
13780
|
"action_required": boolean,
|
|
@@ -13189,7 +13782,14 @@ Return ONLY this JSON structure:
|
|
|
13189
13782
|
"trigger_phrases": ["when debugging memory", "asking about implementation", "discussing architecture"],
|
|
13190
13783
|
"question_types": ["questions this answers"],
|
|
13191
13784
|
"emotional_resonance": "emotional context if relevant",
|
|
13192
|
-
"problem_solution_pair": boolean
|
|
13785
|
+
"problem_solution_pair": boolean,
|
|
13786
|
+
"scope": "global|project",
|
|
13787
|
+
"temporal_class": "eternal|long_term|medium_term|short_term|ephemeral",
|
|
13788
|
+
"domain": "specific domain area (optional)",
|
|
13789
|
+
"feature": "specific feature (optional)",
|
|
13790
|
+
"related_files": ["paths to related files (optional)"],
|
|
13791
|
+
"awaiting_implementation": boolean,
|
|
13792
|
+
"awaiting_decision": boolean
|
|
13193
13793
|
}
|
|
13194
13794
|
]
|
|
13195
13795
|
}`;
|
|
@@ -13239,7 +13839,14 @@ Return ONLY this JSON structure:
|
|
|
13239
13839
|
trigger_phrases: this._ensureArray(m2.trigger_phrases),
|
|
13240
13840
|
question_types: this._ensureArray(m2.question_types),
|
|
13241
13841
|
emotional_resonance: String(m2.emotional_resonance ?? ""),
|
|
13242
|
-
problem_solution_pair: Boolean(m2.problem_solution_pair)
|
|
13842
|
+
problem_solution_pair: Boolean(m2.problem_solution_pair),
|
|
13843
|
+
scope: this._validateScope(m2.scope),
|
|
13844
|
+
temporal_class: this._validateTemporalClass(m2.temporal_class),
|
|
13845
|
+
domain: m2.domain ? String(m2.domain) : undefined,
|
|
13846
|
+
feature: m2.feature ? String(m2.feature) : undefined,
|
|
13847
|
+
related_files: m2.related_files ? this._ensureArray(m2.related_files) : undefined,
|
|
13848
|
+
awaiting_implementation: m2.awaiting_implementation === true,
|
|
13849
|
+
awaiting_decision: m2.awaiting_decision === true
|
|
13243
13850
|
})).filter((m2) => m2.content.trim().length > 0);
|
|
13244
13851
|
}
|
|
13245
13852
|
_ensureArray(value) {
|
|
@@ -13256,6 +13863,23 @@ Return ONLY this JSON structure:
|
|
|
13256
13863
|
const str = String(value).toLowerCase();
|
|
13257
13864
|
return valid.includes(str) ? str : "persistent";
|
|
13258
13865
|
}
|
|
13866
|
+
_validateScope(value) {
|
|
13867
|
+
if (!value)
|
|
13868
|
+
return;
|
|
13869
|
+
const str = String(value).toLowerCase();
|
|
13870
|
+
if (str === "global" || str === "project")
|
|
13871
|
+
return str;
|
|
13872
|
+
return;
|
|
13873
|
+
}
|
|
13874
|
+
_validateTemporalClass(value) {
|
|
13875
|
+
if (!value)
|
|
13876
|
+
return;
|
|
13877
|
+
const valid = ["eternal", "long_term", "medium_term", "short_term", "ephemeral"];
|
|
13878
|
+
const str = String(value).toLowerCase().replace("-", "_").replace(" ", "_");
|
|
13879
|
+
if (valid.includes(str))
|
|
13880
|
+
return str;
|
|
13881
|
+
return;
|
|
13882
|
+
}
|
|
13259
13883
|
_clamp(value, min, max) {
|
|
13260
13884
|
return Math.max(min, Math.min(max, value));
|
|
13261
13885
|
}
|