stellar-memory 0.5.0
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/LICENSE +21 -0
- package/README.md +362 -0
- package/dist/api/routes/analytics.d.ts +15 -0
- package/dist/api/routes/analytics.js +131 -0
- package/dist/api/routes/analytics.js.map +1 -0
- package/dist/api/routes/conflicts.d.ts +12 -0
- package/dist/api/routes/conflicts.js +67 -0
- package/dist/api/routes/conflicts.js.map +1 -0
- package/dist/api/routes/consolidation.d.ts +11 -0
- package/dist/api/routes/consolidation.js +63 -0
- package/dist/api/routes/consolidation.js.map +1 -0
- package/dist/api/routes/constellation.d.ts +4 -0
- package/dist/api/routes/constellation.js +84 -0
- package/dist/api/routes/constellation.js.map +1 -0
- package/dist/api/routes/memories.d.ts +4 -0
- package/dist/api/routes/memories.js +219 -0
- package/dist/api/routes/memories.js.map +1 -0
- package/dist/api/routes/observations.d.ts +10 -0
- package/dist/api/routes/observations.js +42 -0
- package/dist/api/routes/observations.js.map +1 -0
- package/dist/api/routes/orbit.d.ts +4 -0
- package/dist/api/routes/orbit.js +71 -0
- package/dist/api/routes/orbit.js.map +1 -0
- package/dist/api/routes/projects.d.ts +15 -0
- package/dist/api/routes/projects.js +121 -0
- package/dist/api/routes/projects.js.map +1 -0
- package/dist/api/routes/scan.d.ts +4 -0
- package/dist/api/routes/scan.js +403 -0
- package/dist/api/routes/scan.js.map +1 -0
- package/dist/api/routes/sun.d.ts +4 -0
- package/dist/api/routes/sun.js +43 -0
- package/dist/api/routes/sun.js.map +1 -0
- package/dist/api/routes/system.d.ts +4 -0
- package/dist/api/routes/system.js +70 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/temporal.d.ts +13 -0
- package/dist/api/routes/temporal.js +82 -0
- package/dist/api/routes/temporal.js.map +1 -0
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.js +99 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/websocket.d.ts +53 -0
- package/dist/api/websocket.js +168 -0
- package/dist/api/websocket.js.map +1 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +10 -0
- package/dist/cli/init.js +163 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/engine/analytics.d.ts +93 -0
- package/dist/engine/analytics.js +437 -0
- package/dist/engine/analytics.js.map +1 -0
- package/dist/engine/conflict.d.ts +54 -0
- package/dist/engine/conflict.js +322 -0
- package/dist/engine/conflict.js.map +1 -0
- package/dist/engine/consolidation.d.ts +83 -0
- package/dist/engine/consolidation.js +368 -0
- package/dist/engine/consolidation.js.map +1 -0
- package/dist/engine/constellation.d.ts +66 -0
- package/dist/engine/constellation.js +382 -0
- package/dist/engine/constellation.js.map +1 -0
- package/dist/engine/corona.d.ts +53 -0
- package/dist/engine/corona.js +181 -0
- package/dist/engine/corona.js.map +1 -0
- package/dist/engine/embedding.d.ts +44 -0
- package/dist/engine/embedding.js +168 -0
- package/dist/engine/embedding.js.map +1 -0
- package/dist/engine/gravity.d.ts +63 -0
- package/dist/engine/gravity.js +121 -0
- package/dist/engine/gravity.js.map +1 -0
- package/dist/engine/multiproject.d.ts +75 -0
- package/dist/engine/multiproject.js +241 -0
- package/dist/engine/multiproject.js.map +1 -0
- package/dist/engine/observation.d.ts +82 -0
- package/dist/engine/observation.js +357 -0
- package/dist/engine/observation.js.map +1 -0
- package/dist/engine/orbit.d.ts +91 -0
- package/dist/engine/orbit.js +249 -0
- package/dist/engine/orbit.js.map +1 -0
- package/dist/engine/planet.d.ts +64 -0
- package/dist/engine/planet.js +432 -0
- package/dist/engine/planet.js.map +1 -0
- package/dist/engine/procedural.d.ts +71 -0
- package/dist/engine/procedural.js +259 -0
- package/dist/engine/procedural.js.map +1 -0
- package/dist/engine/quality.d.ts +48 -0
- package/dist/engine/quality.js +245 -0
- package/dist/engine/quality.js.map +1 -0
- package/dist/engine/repository.d.ts +79 -0
- package/dist/engine/repository.js +13 -0
- package/dist/engine/repository.js.map +1 -0
- package/dist/engine/sun.d.ts +61 -0
- package/dist/engine/sun.js +240 -0
- package/dist/engine/sun.js.map +1 -0
- package/dist/engine/temporal.d.ts +67 -0
- package/dist/engine/temporal.js +283 -0
- package/dist/engine/temporal.js.map +1 -0
- package/dist/engine/types.d.ts +179 -0
- package/dist/engine/types.js +27 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/connector-registry.d.ts +20 -0
- package/dist/mcp/connector-registry.js +35 -0
- package/dist/mcp/connector-registry.js.map +1 -0
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +242 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/daemon-tool.d.ts +16 -0
- package/dist/mcp/tools/daemon-tool.js +58 -0
- package/dist/mcp/tools/daemon-tool.js.map +1 -0
- package/dist/mcp/tools/ingestion-tools.d.ts +20 -0
- package/dist/mcp/tools/ingestion-tools.js +34 -0
- package/dist/mcp/tools/ingestion-tools.js.map +1 -0
- package/dist/mcp/tools/memory-tools.d.ts +122 -0
- package/dist/mcp/tools/memory-tools.js +1037 -0
- package/dist/mcp/tools/memory-tools.js.map +1 -0
- package/dist/scanner/cloud/github.d.ts +34 -0
- package/dist/scanner/cloud/github.js +260 -0
- package/dist/scanner/cloud/github.js.map +1 -0
- package/dist/scanner/cloud/google-drive.d.ts +30 -0
- package/dist/scanner/cloud/google-drive.js +289 -0
- package/dist/scanner/cloud/google-drive.js.map +1 -0
- package/dist/scanner/cloud/notion.d.ts +33 -0
- package/dist/scanner/cloud/notion.js +231 -0
- package/dist/scanner/cloud/notion.js.map +1 -0
- package/dist/scanner/cloud/slack.d.ts +38 -0
- package/dist/scanner/cloud/slack.js +282 -0
- package/dist/scanner/cloud/slack.js.map +1 -0
- package/dist/scanner/cloud/types.d.ts +73 -0
- package/dist/scanner/cloud/types.js +9 -0
- package/dist/scanner/cloud/types.js.map +1 -0
- package/dist/scanner/index.d.ts +35 -0
- package/dist/scanner/index.js +420 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/local/filesystem.d.ts +33 -0
- package/dist/scanner/local/filesystem.js +203 -0
- package/dist/scanner/local/filesystem.js.map +1 -0
- package/dist/scanner/local/git.d.ts +24 -0
- package/dist/scanner/local/git.js +161 -0
- package/dist/scanner/local/git.js.map +1 -0
- package/dist/scanner/local/parsers/code.d.ts +3 -0
- package/dist/scanner/local/parsers/code.js +127 -0
- package/dist/scanner/local/parsers/code.js.map +1 -0
- package/dist/scanner/local/parsers/index.d.ts +11 -0
- package/dist/scanner/local/parsers/index.js +24 -0
- package/dist/scanner/local/parsers/index.js.map +1 -0
- package/dist/scanner/local/parsers/json-parser.d.ts +3 -0
- package/dist/scanner/local/parsers/json-parser.js +117 -0
- package/dist/scanner/local/parsers/json-parser.js.map +1 -0
- package/dist/scanner/local/parsers/markdown.d.ts +3 -0
- package/dist/scanner/local/parsers/markdown.js +120 -0
- package/dist/scanner/local/parsers/markdown.js.map +1 -0
- package/dist/scanner/local/parsers/text.d.ts +3 -0
- package/dist/scanner/local/parsers/text.js +41 -0
- package/dist/scanner/local/parsers/text.js.map +1 -0
- package/dist/scanner/metadata-scanner.d.ts +67 -0
- package/dist/scanner/metadata-scanner.js +356 -0
- package/dist/scanner/metadata-scanner.js.map +1 -0
- package/dist/scanner/types.d.ts +47 -0
- package/dist/scanner/types.js +19 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/service/daemon.d.ts +23 -0
- package/dist/service/daemon.js +105 -0
- package/dist/service/daemon.js.map +1 -0
- package/dist/service/scheduler.d.ts +73 -0
- package/dist/service/scheduler.js +281 -0
- package/dist/service/scheduler.js.map +1 -0
- package/dist/storage/database.d.ts +10 -0
- package/dist/storage/database.js +265 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/storage/queries.d.ts +85 -0
- package/dist/storage/queries.js +865 -0
- package/dist/storage/queries.js.map +1 -0
- package/dist/storage/sqlite-repository.d.ts +32 -0
- package/dist/storage/sqlite-repository.js +68 -0
- package/dist/storage/sqlite-repository.js.map +1 -0
- package/dist/storage/vec.d.ts +62 -0
- package/dist/storage/vec.js +111 -0
- package/dist/storage/vec.js.map +1 -0
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +60 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.js +86 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/time.d.ts +21 -0
- package/dist/utils/time.js +42 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/tokenizer.d.ts +13 -0
- package/dist/utils/tokenizer.js +46 -0
- package/dist/utils/tokenizer.js.map +1 -0
- package/package.json +77 -0
- package/scripts/check-node.mjs +36 -0
- package/scripts/setup.mjs +157 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* observation.ts — Observational Memory ("Comet")
|
|
3
|
+
*
|
|
4
|
+
* Auto-extracts knowledge from raw conversation text and stores it as
|
|
5
|
+
* structured memories. Like comets that bring material from the outer
|
|
6
|
+
* solar system, observations bring new information from conversations
|
|
7
|
+
* into the memory system.
|
|
8
|
+
*
|
|
9
|
+
* Pipeline:
|
|
10
|
+
* observe() → extract pattern-matched memories from a chunk
|
|
11
|
+
* reflect() → categorize observations (novel / reinforcing / conflicting)
|
|
12
|
+
* processConversation → full pipeline: split → observe → reflect → store
|
|
13
|
+
*
|
|
14
|
+
* No LLM is used — all extraction is done via keyword matching and heuristics.
|
|
15
|
+
*/
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { createMemory } from './planet.js';
|
|
18
|
+
import { recallMemoriesAsync } from './planet.js';
|
|
19
|
+
import { createObservation } from '../storage/queries.js';
|
|
20
|
+
import { updateMemoryOrbit, updateMemoryAccess } from '../storage/queries.js';
|
|
21
|
+
import { applyAccessBoost } from './orbit.js';
|
|
22
|
+
import { createLogger } from '../utils/logger.js';
|
|
23
|
+
const log = createLogger('observation');
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Keyword dictionaries
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
const DECISION_KEYWORDS = [
|
|
28
|
+
'chose', 'decided', 'will use', 'switched to', 'selected', 'picked',
|
|
29
|
+
'going with', 'we will', 'opted for', 'adopted', 'migrated to',
|
|
30
|
+
'결정', '선택', '사용하기로', '변경', '채택',
|
|
31
|
+
];
|
|
32
|
+
const ERROR_KEYWORDS = [
|
|
33
|
+
'error', 'bug', 'fix', 'fixed', 'failed', 'crash', 'issue', 'broken',
|
|
34
|
+
'exception', 'traceback', 'undefined', 'null pointer', 'segfault',
|
|
35
|
+
'에러', '버그', '수정', '실패', '오류', '문제',
|
|
36
|
+
];
|
|
37
|
+
const MILESTONE_KEYWORDS = [
|
|
38
|
+
'complete', 'completed', 'done', 'finished', 'implemented', 'shipped',
|
|
39
|
+
'deployed', 'released', 'merged', 'integrated', 'working', 'passing',
|
|
40
|
+
'완료', '구현', '배포', '완성', '됐', '됩니다',
|
|
41
|
+
];
|
|
42
|
+
const TASK_KEYWORDS = [
|
|
43
|
+
'todo', 'to-do', 'need to', 'should', 'must', 'later', 'next step',
|
|
44
|
+
'will need', 'plan to', 'going to', 'upcoming', 'pending',
|
|
45
|
+
'해야', '필요', '다음에', '나중에', '예정',
|
|
46
|
+
];
|
|
47
|
+
const CONTEXT_KEYWORDS = [
|
|
48
|
+
'uses', 'requires', 'depends on', 'built with', 'runs on', 'configured',
|
|
49
|
+
'connects to', 'integrates', 'relies on', 'powered by',
|
|
50
|
+
'사용', '필요', '의존', '기반',
|
|
51
|
+
];
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Stop words — filtered out during key term extraction
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const STOP_WORDS = new Set([
|
|
56
|
+
// English
|
|
57
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
58
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
59
|
+
'should', 'may', 'might', 'shall', 'can', 'need', 'must', 'ought',
|
|
60
|
+
'to', 'of', 'in', 'on', 'at', 'by', 'for', 'with', 'about', 'as',
|
|
61
|
+
'into', 'through', 'from', 'up', 'down', 'out', 'off', 'over', 'under',
|
|
62
|
+
'and', 'or', 'but', 'if', 'then', 'that', 'this', 'it', 'its',
|
|
63
|
+
'i', 'we', 'you', 'he', 'she', 'they', 'them', 'their', 'our', 'my',
|
|
64
|
+
'so', 'than', 'when', 'where', 'who', 'which', 'what', 'how', 'why',
|
|
65
|
+
'not', 'no', 'all', 'each', 'both', 'few', 'more', 'other', 'some',
|
|
66
|
+
'such', 'only', 'own', 'same', 'also', 'just', 'now', 'very', 'too',
|
|
67
|
+
// Korean particles
|
|
68
|
+
'은', '는', '이', '가', '을', '를', '의', '에', '에서', '로', '으로',
|
|
69
|
+
'와', '과', '도', '만', '가', '께', '한테', '에게', '부터', '까지',
|
|
70
|
+
'이다', '입니다', '있다', '없다', '이라', '이면', '라면', '같은',
|
|
71
|
+
]);
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Key term extraction
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
/**
|
|
76
|
+
* Extract meaningful key terms from text.
|
|
77
|
+
*
|
|
78
|
+
* Filters out stop words and short tokens; keeps technical terms,
|
|
79
|
+
* proper nouns (by capitalization), version numbers, and path-like strings.
|
|
80
|
+
*
|
|
81
|
+
* Returns unique terms sorted by appearance order.
|
|
82
|
+
*/
|
|
83
|
+
export function extractKeyTerms(text) {
|
|
84
|
+
const words = text
|
|
85
|
+
.split(/\s+/)
|
|
86
|
+
.map(w => w.replace(/[^\w.\-/]/g, '').trim())
|
|
87
|
+
.filter(w => w.length >= 2);
|
|
88
|
+
const seen = new Set();
|
|
89
|
+
const terms = [];
|
|
90
|
+
for (const word of words) {
|
|
91
|
+
const lower = word.toLowerCase();
|
|
92
|
+
if (STOP_WORDS.has(lower))
|
|
93
|
+
continue;
|
|
94
|
+
if (seen.has(lower))
|
|
95
|
+
continue;
|
|
96
|
+
seen.add(lower);
|
|
97
|
+
terms.push(word);
|
|
98
|
+
}
|
|
99
|
+
return terms;
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Keyword detection helpers
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
function containsAny(text, keywords) {
|
|
105
|
+
const lower = text.toLowerCase();
|
|
106
|
+
return keywords.some(kw => lower.includes(kw.toLowerCase()));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Detect the memory type for a given sentence based on keyword presence.
|
|
110
|
+
* Returns null if no pattern matches.
|
|
111
|
+
*/
|
|
112
|
+
function detectType(sentence) {
|
|
113
|
+
if (containsAny(sentence, DECISION_KEYWORDS))
|
|
114
|
+
return 'decision';
|
|
115
|
+
if (containsAny(sentence, ERROR_KEYWORDS))
|
|
116
|
+
return 'error';
|
|
117
|
+
if (containsAny(sentence, MILESTONE_KEYWORDS))
|
|
118
|
+
return 'milestone';
|
|
119
|
+
if (containsAny(sentence, TASK_KEYWORDS))
|
|
120
|
+
return 'task';
|
|
121
|
+
if (containsAny(sentence, CONTEXT_KEYWORDS))
|
|
122
|
+
return 'context';
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Conversation splitting
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
/**
|
|
129
|
+
* Split a conversation into chunks suitable for observation.
|
|
130
|
+
*
|
|
131
|
+
* Splits on:
|
|
132
|
+
* - Common turn markers: "User:", "Assistant:", "Human:", "AI:", "System:"
|
|
133
|
+
* - Double newlines (paragraph breaks)
|
|
134
|
+
*
|
|
135
|
+
* Filters out empty or very short chunks.
|
|
136
|
+
* Chunks are bounded to 100-500 words each.
|
|
137
|
+
*/
|
|
138
|
+
export function splitConversation(text) {
|
|
139
|
+
const TURN_PATTERN = /^(?:User|Assistant|Human|AI|System|사용자|어시스턴트):/im;
|
|
140
|
+
// First try turn-based splitting
|
|
141
|
+
const turnChunks = text
|
|
142
|
+
.split(/\n(?=(?:User|Assistant|Human|AI|System|사용자|어시스턴트):)/i)
|
|
143
|
+
.map(c => c.trim())
|
|
144
|
+
.filter(c => c.length > 20);
|
|
145
|
+
if (turnChunks.length > 1) {
|
|
146
|
+
return turnChunks;
|
|
147
|
+
}
|
|
148
|
+
// Fallback: paragraph splitting
|
|
149
|
+
return text
|
|
150
|
+
.split(/\n{2,}/)
|
|
151
|
+
.map(c => c.trim())
|
|
152
|
+
.filter(c => {
|
|
153
|
+
const wordCount = c.split(/\s+/).length;
|
|
154
|
+
return wordCount >= 5 && wordCount <= 600;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Core observation
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
/**
|
|
161
|
+
* Observe a conversation chunk and extract structured memories from it.
|
|
162
|
+
*
|
|
163
|
+
* For each sentence that matches a known pattern (decision, error, milestone,
|
|
164
|
+
* task, context), a memory is created and stored.
|
|
165
|
+
*
|
|
166
|
+
* Returns the text observations extracted and the Memory objects created.
|
|
167
|
+
*/
|
|
168
|
+
export function observe(conversationChunk, project) {
|
|
169
|
+
// Split into sentences
|
|
170
|
+
const sentences = conversationChunk
|
|
171
|
+
.split(/(?<=[.!?])\s+|\n/)
|
|
172
|
+
.map(s => s.trim())
|
|
173
|
+
.filter(s => s.length > 15); // skip very short fragments
|
|
174
|
+
const observations = [];
|
|
175
|
+
const memories = [];
|
|
176
|
+
const seen = new Set();
|
|
177
|
+
for (const sentence of sentences) {
|
|
178
|
+
const type = detectType(sentence);
|
|
179
|
+
if (!type)
|
|
180
|
+
continue;
|
|
181
|
+
// Normalize to avoid creating duplicate memories in the same chunk
|
|
182
|
+
const normalized = sentence.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
183
|
+
if (seen.has(normalized))
|
|
184
|
+
continue;
|
|
185
|
+
seen.add(normalized);
|
|
186
|
+
// Generate summary (first 80 chars or the sentence itself if shorter)
|
|
187
|
+
const summary = sentence.length > 80
|
|
188
|
+
? sentence.slice(0, 80).trimEnd() + '...'
|
|
189
|
+
: sentence;
|
|
190
|
+
// Extract tags from key technical terms
|
|
191
|
+
const terms = extractKeyTerms(sentence);
|
|
192
|
+
const tags = terms.slice(0, 8); // cap at 8 tags
|
|
193
|
+
try {
|
|
194
|
+
const memory = createMemory({
|
|
195
|
+
project,
|
|
196
|
+
content: sentence,
|
|
197
|
+
summary,
|
|
198
|
+
type,
|
|
199
|
+
tags,
|
|
200
|
+
});
|
|
201
|
+
observations.push(sentence);
|
|
202
|
+
memories.push(memory);
|
|
203
|
+
log.debug('Observed memory', {
|
|
204
|
+
type,
|
|
205
|
+
summary: summary.slice(0, 60),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
log.warn('Failed to create observed memory', { error: String(err) });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Log the observation entry even if no memories were created
|
|
213
|
+
if (observations.length > 0) {
|
|
214
|
+
const entry = {
|
|
215
|
+
id: randomUUID(),
|
|
216
|
+
content: conversationChunk.slice(0, 500),
|
|
217
|
+
extracted_memories: memories.map(m => m.id),
|
|
218
|
+
source: 'conversation',
|
|
219
|
+
project,
|
|
220
|
+
created_at: new Date().toISOString(),
|
|
221
|
+
};
|
|
222
|
+
try {
|
|
223
|
+
createObservation(entry);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
log.warn('Failed to log observation entry', { error: String(err) });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return { observations, memories };
|
|
230
|
+
}
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// Reflection
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
/**
|
|
235
|
+
* Reflect on a list of observations against the existing memory store.
|
|
236
|
+
*
|
|
237
|
+
* Categorizes each observation string as:
|
|
238
|
+
* - novel : not found in existing memories (truly new)
|
|
239
|
+
* - reinforcing : confirms an existing memory (we boost that memory)
|
|
240
|
+
* - conflicting : appears to contradict an existing memory
|
|
241
|
+
*
|
|
242
|
+
* Heuristics:
|
|
243
|
+
* - If an existing memory contains most of the same key terms → reinforcing
|
|
244
|
+
* - If an existing memory uses contradicting signals (negation patterns) → conflicting
|
|
245
|
+
* - Otherwise → novel
|
|
246
|
+
*/
|
|
247
|
+
export async function reflect(newObservations, project) {
|
|
248
|
+
const novel = [];
|
|
249
|
+
const reinforcing = [];
|
|
250
|
+
const conflicting = [];
|
|
251
|
+
for (const obs of newObservations) {
|
|
252
|
+
// Search existing memories for similar content
|
|
253
|
+
const similar = await recallMemoriesAsync(project, obs, { limit: 3 });
|
|
254
|
+
if (similar.length === 0) {
|
|
255
|
+
novel.push(obs);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
// Check the top result for reinforcement vs conflict
|
|
259
|
+
const top = similar[0];
|
|
260
|
+
const topTerms = extractKeyTerms(top.content);
|
|
261
|
+
const obsTerms = extractKeyTerms(obs);
|
|
262
|
+
// Count shared key terms
|
|
263
|
+
const topSet = new Set(topTerms.map(t => t.toLowerCase()));
|
|
264
|
+
const sharedCount = obsTerms.filter(t => topSet.has(t.toLowerCase())).length;
|
|
265
|
+
const overlapRatio = sharedCount / Math.max(1, obsTerms.length);
|
|
266
|
+
if (overlapRatio >= 0.5) {
|
|
267
|
+
// High overlap → reinforcing — boost the existing memory slightly
|
|
268
|
+
const boostedDistance = applyAccessBoost(top.distance);
|
|
269
|
+
try {
|
|
270
|
+
updateMemoryAccess(top.id);
|
|
271
|
+
updateMemoryOrbit(top.id, boostedDistance, top.importance, boostedDistance - top.distance);
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
log.warn('Failed to boost reinforced memory', { id: top.id, error: String(err) });
|
|
275
|
+
}
|
|
276
|
+
reinforcing.push(obs);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
// Check for explicit contradiction signals
|
|
280
|
+
const obsLower = obs.toLowerCase();
|
|
281
|
+
const topLower = top.content.toLowerCase();
|
|
282
|
+
const negationPatterns = [
|
|
283
|
+
/\bnot\s+\w+/,
|
|
284
|
+
/\bno longer\b/,
|
|
285
|
+
/\binstead of\b/,
|
|
286
|
+
/\breplaced by\b/,
|
|
287
|
+
/\bswitched from\b/,
|
|
288
|
+
];
|
|
289
|
+
const hasNegation = negationPatterns.some(p => p.test(obsLower) || p.test(topLower));
|
|
290
|
+
if (hasNegation && overlapRatio >= 0.3) {
|
|
291
|
+
conflicting.push(obs);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
novel.push(obs);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { novel, reinforcing, conflicting };
|
|
299
|
+
}
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
// Full conversation pipeline
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
/**
|
|
304
|
+
* Process a full conversation through the observe → reflect pipeline.
|
|
305
|
+
*
|
|
306
|
+
* Steps:
|
|
307
|
+
* 1. Split conversation into chunks.
|
|
308
|
+
* 2. Run observe() on each chunk to extract memories.
|
|
309
|
+
* 3. Run reflect() on the extracted observations.
|
|
310
|
+
* 4. Boost reinforced memories.
|
|
311
|
+
* 5. Return aggregate statistics.
|
|
312
|
+
*/
|
|
313
|
+
export async function processConversation(conversation, project) {
|
|
314
|
+
log.info('Processing conversation', { project, length: conversation.length });
|
|
315
|
+
const chunks = splitConversation(conversation);
|
|
316
|
+
log.debug('Conversation chunks', { count: chunks.length });
|
|
317
|
+
const allObservations = [];
|
|
318
|
+
let memoriesCreated = 0;
|
|
319
|
+
for (const chunk of chunks) {
|
|
320
|
+
const { observations, memories } = observe(chunk, project);
|
|
321
|
+
allObservations.push(...observations);
|
|
322
|
+
memoriesCreated += memories.length;
|
|
323
|
+
}
|
|
324
|
+
// Reflect on all accumulated observations
|
|
325
|
+
const { novel, reinforcing, conflicting } = await reflect(allObservations, project);
|
|
326
|
+
// Log a reflection observation entry for the session
|
|
327
|
+
if (allObservations.length > 0) {
|
|
328
|
+
const reflectionEntry = {
|
|
329
|
+
id: randomUUID(),
|
|
330
|
+
content: `Reflection: ${novel.length} novel, ${reinforcing.length} reinforcing, ${conflicting.length} conflicting`,
|
|
331
|
+
extracted_memories: [],
|
|
332
|
+
source: 'reflection',
|
|
333
|
+
project,
|
|
334
|
+
created_at: new Date().toISOString(),
|
|
335
|
+
};
|
|
336
|
+
try {
|
|
337
|
+
createObservation(reflectionEntry);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// Non-critical — don't fail the whole pipeline
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
log.info('Conversation processed', {
|
|
344
|
+
project,
|
|
345
|
+
chunks: chunks.length,
|
|
346
|
+
memoriesCreated,
|
|
347
|
+
memoriesReinforced: reinforcing.length,
|
|
348
|
+
conflictsDetected: conflicting.length,
|
|
349
|
+
novel: novel.length,
|
|
350
|
+
});
|
|
351
|
+
return {
|
|
352
|
+
memoriesCreated,
|
|
353
|
+
memoriesReinforced: reinforcing.length,
|
|
354
|
+
conflictsDetected: conflicting.length,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=observation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation.js","sourceRoot":"","sources":["../../src/engine/observation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;AAExC,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,MAAM,iBAAiB,GAAG;IACxB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ;IACnE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa;IAC9D,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;CAChC,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ;IACpE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU;IACjE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CACnC,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS;IACrE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS;IACpE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK;CACnC,CAAC;AAEF,MAAM,aAAa,GAAG;IACpB,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW;IAClE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS;IACzD,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI;CAC/B,CAAC;AAEF,MAAM,gBAAgB,GAAG;IACvB,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY;IACvE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY;IACtD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CACvB,CAAC;AAEF,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAE9E,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,UAAU;IACV,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO;IACnE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IACjE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;IAChE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO;IACtE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK;IAC7D,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI;IACnE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;IACnE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAClE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;IACnE,mBAAmB;IACnB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IACvD,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACpD,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAChD,CAAC,CAAC;AAEH,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,KAAK,GAAG,IAAI;SACf,KAAK,CAAC,KAAK,CAAC;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SAC5C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAE9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QACpC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAC9B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,4BAA4B;AAC5B,8EAA8E;AAE9E,SAAS,WAAW,CAAC,IAAY,EAAE,QAAkB;IACnD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,WAAW,CAAC,QAAQ,EAAE,iBAAiB,CAAC;QAAG,OAAO,UAAU,CAAC;IACjE,IAAI,WAAW,CAAC,QAAQ,EAAE,cAAc,CAAC;QAAO,OAAO,OAAO,CAAC;IAC/D,IAAI,WAAW,CAAC,QAAQ,EAAE,kBAAkB,CAAC;QAAG,OAAO,WAAW,CAAC;IACnE,IAAI,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC;QAAQ,OAAO,MAAM,CAAC;IAC9D,IAAI,WAAW,CAAC,QAAQ,EAAE,gBAAgB,CAAC;QAAK,OAAO,SAAS,CAAC;IACjE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,YAAY,GAAG,kDAAkD,CAAC;IAExE,iCAAiC;IACjC,MAAM,UAAU,GAAG,IAAI;SACpB,KAAK,CAAC,sDAAsD,CAAC;SAC7D,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAE9B,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,gCAAgC;IAChC,OAAO,IAAI;SACR,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE;QACV,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QACxC,OAAO,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,GAAG,CAAC;IAC5C,CAAC,CAAC,CAAC;AACP,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CACrB,iBAAyB,EACzB,OAAe;IAEf,uBAAuB;IACvB,MAAM,SAAS,GAAG,iBAAiB;SAChC,KAAK,CAAC,kBAAkB,CAAC;SACzB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,4BAA4B;IAE3D,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,mEAAmE;QACnE,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAErB,sEAAsE;QACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,EAAE;YAClC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK;YACzC,CAAC,CAAC,QAAQ,CAAC;QAEb,wCAAwC;QACxC,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,IAAI,GAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB;QAEjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC;gBAC1B,OAAO;gBACP,OAAO,EAAE,QAAQ;gBACjB,OAAO;gBACP,IAAI;gBACJ,IAAI;aACL,CAAC,CAAC;YAEH,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAEtB,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE;gBAC3B,IAAI;gBACJ,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;aAC9B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAqB;YAC9B,EAAE,EAAkB,UAAU,EAAE;YAChC,OAAO,EAAa,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;YACnD,kBAAkB,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,MAAM,EAAc,cAAc;YAClC,OAAO;YACP,UAAU,EAAU,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC7C,CAAC;QAEF,IAAI,CAAC;YACH,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AACpC,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,eAAyB,EACzB,OAAe;IAMf,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,+CAA+C;QAC/C,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAEtE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QAED,qDAAqD;QACrD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAEtC,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7E,MAAM,YAAY,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEhE,IAAI,YAAY,IAAI,GAAG,EAAE,CAAC;YACxB,kEAAkE;YAClE,MAAM,eAAe,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvD,IAAI,CAAC;gBACH,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3B,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,EAAE,GAAG,CAAC,UAAU,EAAE,eAAe,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7F,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpF,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,gBAAgB,GAAG;gBACvB,aAAa;gBACb,eAAe;gBACf,gBAAgB;gBAChB,iBAAiB;gBACjB,mBAAmB;aACpB,CAAC;YAEF,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAC1C,CAAC;YAEF,IAAI,WAAW,IAAI,YAAY,IAAI,GAAG,EAAE,CAAC;gBACvC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAC7C,CAAC;AAED,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAoB,EACpB,OAAe;IAMf,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IAE9E,MAAM,MAAM,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC/C,GAAG,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAE3D,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC3D,eAAe,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;QACtC,eAAe,IAAI,QAAQ,CAAC,MAAM,CAAC;IACrC,CAAC;IAED,0CAA0C;IAC1C,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IAEpF,qDAAqD;IACrD,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,eAAe,GAAqB;YACxC,EAAE,EAAkB,UAAU,EAAE;YAChC,OAAO,EAAa,eAAe,KAAK,CAAC,MAAM,WAAW,WAAW,CAAC,MAAM,iBAAiB,WAAW,CAAC,MAAM,cAAc;YAC7H,kBAAkB,EAAE,EAAE;YACtB,MAAM,EAAc,YAAY;YAChC,OAAO;YACP,UAAU,EAAU,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC7C,CAAC;QAEF,IAAI,CAAC;YACH,iBAAiB,CAAC,eAAe,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;IACH,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE;QACjC,OAAO;QACP,MAAM,EAAc,MAAM,CAAC,MAAM;QACjC,eAAe;QACf,kBAAkB,EAAE,WAAW,CAAC,MAAM;QACtC,iBAAiB,EAAG,WAAW,CAAC,MAAM;QACtC,KAAK,EAAe,KAAK,CAAC,MAAM;KACjC,CAAC,CAAC;IAEH,OAAO;QACL,eAAe;QACf,kBAAkB,EAAE,WAAW,CAAC,MAAM;QACtC,iBAAiB,EAAG,WAAW,CAAC,MAAM;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* orbit.ts — Core importance function and orbital mechanics
|
|
3
|
+
*
|
|
4
|
+
* Implements the celestial mechanics metaphor:
|
|
5
|
+
* - High importance → small orbital distance (close to the sun)
|
|
6
|
+
* - Low importance → large orbital distance (far from the sun, fading)
|
|
7
|
+
* - Access boost → pulls a memory closer when it is recalled
|
|
8
|
+
* - Decay → memories drift outward over time via recency score
|
|
9
|
+
*/
|
|
10
|
+
import type { Memory, ImportanceComponents, OrbitChange, StellarConfig } from './types.js';
|
|
11
|
+
import type { MemoryType } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Calculate recency score using exponential decay.
|
|
14
|
+
*
|
|
15
|
+
* Formula: 0.5 ^ (hoursSince / effectiveHalfLife)
|
|
16
|
+
* - At t=0 → score = 1.0
|
|
17
|
+
* - At t=halfLife → score = 0.5
|
|
18
|
+
* - At t=2×halfLife → score = 0.25
|
|
19
|
+
*
|
|
20
|
+
* Procedural memories use a slower decay rate (halfLife / 0.3 ≈ 240h for default 72h)
|
|
21
|
+
* so hard-won knowledge persists longer.
|
|
22
|
+
*
|
|
23
|
+
* Returns a value in [0, 1].
|
|
24
|
+
*/
|
|
25
|
+
export declare function recencyScore(lastAccessedAt: string | null, createdAt: string, halfLifeHours?: number, memoryType?: MemoryType): number;
|
|
26
|
+
/**
|
|
27
|
+
* Calculate frequency score using logarithmic saturation.
|
|
28
|
+
*
|
|
29
|
+
* Formula: log(1 + count) / log(1 + saturationPoint)
|
|
30
|
+
* - Grows quickly for the first few accesses.
|
|
31
|
+
* - Plateaus as count approaches saturationPoint.
|
|
32
|
+
*
|
|
33
|
+
* Returns a value in [0, 1].
|
|
34
|
+
*/
|
|
35
|
+
export declare function frequencyScore(accessCount: number, saturationPoint?: number): number;
|
|
36
|
+
/**
|
|
37
|
+
* Calculate overall importance from all four components.
|
|
38
|
+
*
|
|
39
|
+
* Weights are configured via StellarConfig and must sum to 1.0 for a
|
|
40
|
+
* meaningful 0–1 total (they do in the defaults: 0.30+0.20+0.30+0.20=1.00).
|
|
41
|
+
*/
|
|
42
|
+
export declare function calculateImportance(memory: Memory, sunText: string, config: StellarConfig): ImportanceComponents;
|
|
43
|
+
/**
|
|
44
|
+
* Convert importance (0–1) to orbital distance (0.1–100).
|
|
45
|
+
*
|
|
46
|
+
* Uses quadratic mapping so that:
|
|
47
|
+
* - importance = 1.0 → distance ≈ 0.1 (core / working memory)
|
|
48
|
+
* - importance = 0.0 → distance = 100 (Oort cloud / nearly forgotten)
|
|
49
|
+
*
|
|
50
|
+
* The quadratic curve creates a non-linear relationship: a memory must fall
|
|
51
|
+
* significantly in importance before it drifts noticeably outward, which
|
|
52
|
+
* mirrors how cognitive salience works in practice.
|
|
53
|
+
*/
|
|
54
|
+
export declare function importanceToDistance(importance: number): number;
|
|
55
|
+
/**
|
|
56
|
+
* Inverse of importanceToDistance — derive importance from a given distance.
|
|
57
|
+
*
|
|
58
|
+
* Used when a user manually drags a memory to a new orbital position.
|
|
59
|
+
*/
|
|
60
|
+
export declare function distanceToImportance(distance: number): number;
|
|
61
|
+
/**
|
|
62
|
+
* Return the orbit zone label for a given distance.
|
|
63
|
+
*
|
|
64
|
+
* Iterates ORBIT_ZONES in definition order (core → forgotten) and returns the
|
|
65
|
+
* first zone whose [min, max) range contains the distance. Falls back to
|
|
66
|
+
* the 'forgotten' label for any distance at or beyond 70.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getOrbitZone(distance: number): string;
|
|
69
|
+
/**
|
|
70
|
+
* Apply access boost — pull a memory closer when it is recalled.
|
|
71
|
+
*
|
|
72
|
+
* The boost is proportional to the current distance so that:
|
|
73
|
+
* - Far-away memories (high distance) receive a large absolute pull.
|
|
74
|
+
* - Close memories (low distance) are nudged only slightly.
|
|
75
|
+
*
|
|
76
|
+
* MIN_BOOST ensures even core memories get a small reward.
|
|
77
|
+
* The floor of 0.1 prevents distance from going below the core minimum.
|
|
78
|
+
*/
|
|
79
|
+
export declare function applyAccessBoost(currentDistance: number): number;
|
|
80
|
+
/**
|
|
81
|
+
* Run a full orbit recalculation for all memories in a project.
|
|
82
|
+
*
|
|
83
|
+
* Called during stellar_commit and stellar_orbit. For each non-deleted memory:
|
|
84
|
+
* 1. Compute new importance using current sun context.
|
|
85
|
+
* 2. Map importance → distance.
|
|
86
|
+
* 3. If the distance shifted by more than 0.01, persist the change and log it.
|
|
87
|
+
*
|
|
88
|
+
* Returns every OrbitChange that was actually written.
|
|
89
|
+
*/
|
|
90
|
+
export declare function recalculateOrbits(project: string, config: StellarConfig): OrbitChange[];
|
|
91
|
+
//# sourceMappingURL=orbit.d.ts.map
|