claude-brain 0.30.2 → 0.30.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +29 -29
- package/package.json +7 -3
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/scripts/postinstall.mjs +531 -531
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +210 -205
- package/src/cli/auto-setup.ts +75 -75
- package/src/cli/auto-start.ts +266 -266
- package/src/cli/bin.ts +264 -264
- package/src/cli/commands/autostart.ts +90 -90
- package/src/cli/commands/chroma.ts +578 -577
- package/src/cli/commands/export-training.ts +70 -70
- package/src/cli/commands/export.ts +130 -130
- package/src/cli/commands/git-hook.ts +183 -183
- package/src/cli/commands/hooks.ts +217 -217
- package/src/cli/commands/init.ts +123 -123
- package/src/cli/commands/install-mcp.ts +122 -111
- package/src/cli/commands/models.ts +979 -979
- package/src/cli/commands/pack.ts +200 -200
- package/src/cli/commands/refresh.ts +344 -339
- package/src/cli/commands/reindex.ts +120 -120
- package/src/cli/commands/serve.ts +466 -463
- package/src/cli/commands/start.ts +44 -44
- package/src/cli/commands/status.ts +220 -203
- package/src/cli/commands/uninstall-mcp.ts +45 -41
- package/src/cli/commands/update.ts +130 -124
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/code-intelligence/indexer.ts +352 -352
- package/src/code-intelligence/linker.ts +178 -178
- package/src/code-intelligence/parser.ts +484 -484
- package/src/code-intelligence/query.ts +291 -291
- package/src/code-intelligence/schema.ts +83 -83
- package/src/code-intelligence/types.ts +95 -95
- package/src/config/defaults.ts +52 -52
- package/src/config/home.ts +56 -56
- package/src/config/index.ts +5 -5
- package/src/config/loader.ts +192 -192
- package/src/config/schema.ts +446 -415
- package/src/config/validator.ts +182 -182
- package/src/context/assembler.ts +407 -400
- package/src/context/index.ts +79 -79
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +122 -121
- package/src/health/index.ts +233 -232
- package/src/hooks/brain-hook.ts +134 -131
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/claude-code-mastery.md +112 -112
- package/src/hooks/context-hook.ts +260 -245
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +211 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +306 -288
- package/src/hooks/interceptor-hook.ts +204 -201
- package/src/hooks/passive-classifier.ts +397 -397
- package/src/hooks/queue.ts +160 -129
- package/src/hooks/session-tracker.ts +312 -312
- package/src/hooks/types.ts +52 -52
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +7 -7
- package/src/intelligence/hf-downloader.ts +222 -222
- package/src/intelligence/hf-manifest.json +78 -78
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/inference-router.ts +762 -762
- package/src/intelligence/model-manager.ts +263 -245
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +213 -207
- package/src/intelligence/prediction/index.ts +7 -7
- package/src/intelligence/prediction/recommender.ts +276 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +243 -247
- package/src/intelligence/reasoning/index.ts +7 -7
- package/src/intelligence/temporal/evolution.ts +193 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +272 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/intelligence/tokenizer.ts +118 -118
- package/src/knowledge/entity-extractor.ts +447 -443
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +166 -166
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +211 -192
- package/src/memory/chroma/collection-manager.ts +92 -92
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +177 -175
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +319 -315
- package/src/memory/chroma/store.ts +755 -747
- package/src/memory/compression.ts +121 -121
- package/src/memory/consolidation/archiver.ts +162 -165
- package/src/memory/consolidation/merger.ts +182 -186
- package/src/memory/consolidation/scorer.ts +136 -136
- package/src/memory/database.ts +9 -0
- package/src/memory/dual-write.ts +145 -0
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +347 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/fts5-search.ts +692 -633
- package/src/memory/index.ts +943 -1060
- package/src/memory/migrations/add-fts5.ts +118 -108
- package/src/memory/patterns.ts +438 -438
- package/src/memory/pruning.ts +60 -60
- package/src/memory/schema.ts +88 -88
- package/src/memory/store.ts +911 -787
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -297
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +221 -221
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +221 -221
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +165 -165
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +203 -203
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +252 -252
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +189 -188
- package/src/retrieval/reranker/model.ts +99 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +454 -454
- package/src/routing/handlers/exploration-handler.ts +369 -0
- package/src/routing/handlers/index.ts +19 -0
- package/src/routing/handlers/memory-handler.ts +273 -0
- package/src/routing/handlers/mutation-handler.ts +241 -0
- package/src/routing/handlers/recall-handler.ts +642 -0
- package/src/routing/handlers/shared.ts +515 -0
- package/src/routing/handlers/types.ts +48 -0
- package/src/routing/intent-classifier.ts +552 -552
- package/src/routing/response-filter.ts +399 -391
- package/src/routing/router.ts +245 -2193
- package/src/routing/search-engine.ts +521 -514
- package/src/routing/types.ts +104 -94
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/auto-updater.ts +283 -276
- package/src/server/handlers/call-tool.ts +159 -159
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/auto-remember.ts +165 -165
- package/src/server/handlers/tools/brain.ts +86 -86
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/get-code-standards.ts +123 -123
- package/src/server/handlers/tools/get-corrections.ts +152 -152
- package/src/server/handlers/tools/get-patterns.ts +156 -156
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/index.ts +30 -30
- package/src/server/handlers/tools/init-project.ts +756 -756
- package/src/server/handlers/tools/list-projects.ts +126 -126
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +132 -132
- package/src/server/handlers/tools/record-correction.ts +131 -131
- package/src/server/handlers/tools/remember-decision.ts +168 -168
- package/src/server/handlers/tools/schemas.ts +179 -179
- package/src/server/handlers/tools/search-code.ts +122 -122
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/http-api.ts +215 -1229
- package/src/server/mcp-proxy.ts +85 -84
- package/src/server/mcp-server.ts +285 -284
- package/src/server/middleware/auth.ts +39 -0
- package/src/server/middleware/error-handler.ts +37 -0
- package/src/server/middleware/rate-limit.ts +53 -0
- package/src/server/middleware/validate.ts +42 -0
- package/src/server/pid-manager.ts +137 -136
- package/src/server/providers/resources.ts +581 -581
- package/src/server/routes/code.ts +228 -0
- package/src/server/routes/context.ts +26 -0
- package/src/server/routes/health.ts +19 -0
- package/src/server/routes/helpers.ts +100 -0
- package/src/server/routes/hooks.ts +197 -0
- package/src/server/routes/mcp.ts +47 -0
- package/src/server/routes/memory.ts +397 -0
- package/src/server/routes/models.ts +96 -0
- package/src/server/routes/projects.ts +89 -0
- package/src/server/routes/types.ts +21 -0
- package/src/server/schemas/api-schemas.ts +202 -0
- package/src/server/services.ts +720 -720
- package/src/server/utils/memory-indicator.ts +84 -84
- package/src/server/utils/response-formatter.ts +129 -129
- package/src/server/web-viewer.ts +1145 -1115
- package/src/setup/index.ts +38 -38
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.ts +666 -666
- package/src/tools/types.ts +412 -412
- package/src/training/data-store.ts +320 -298
- package/src/training/retrain-pipeline.ts +399 -394
- package/src/utils/error-handler.ts +136 -136
- package/src/utils/index.ts +58 -58
- package/src/utils/kill-port.ts +55 -53
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/safe-path.ts +43 -0
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/index.ts +4 -3
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +4 -1
- package/src/vault/reader.ts +44 -1
- package/src/vault/watcher.ts +24 -1
- package/src/vault/writer.ts +487 -413
- package/skills/persistent-memory/SKILL.md +0 -148
- package/skills/persistent-memory/references/tool-reference.md +0 -90
package/src/memory/store.ts
CHANGED
|
@@ -1,787 +1,911 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory Store - CRUD Operations
|
|
3
|
-
* Phase 3: Memory and Embedding System
|
|
4
|
-
*
|
|
5
|
-
* Handles storing and retrieving memories with embeddings
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { randomUUID } from 'crypto'
|
|
9
|
-
import type { Database } from 'bun:sqlite'
|
|
10
|
-
import type { Logger } from 'pino'
|
|
11
|
-
import type {
|
|
12
|
-
Memory,
|
|
13
|
-
Decision,
|
|
14
|
-
StoreMemoryInput,
|
|
15
|
-
StoreDecisionInput,
|
|
16
|
-
MemoryRow,
|
|
17
|
-
DecisionRow
|
|
18
|
-
} from './types'
|
|
19
|
-
import { EmbeddingService } from './embeddings'
|
|
20
|
-
import { embeddingToBuffer, bufferToEmbedding, cosineSimilarity } from './embedding-utils'
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.logger.info({
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
`
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
this.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
id
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
stmt.
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
SELECT
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Memory Store - CRUD Operations
|
|
3
|
+
* Phase 3: Memory and Embedding System
|
|
4
|
+
*
|
|
5
|
+
* Handles storing and retrieving memories with embeddings
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { randomUUID } from 'crypto'
|
|
9
|
+
import type { Database } from 'bun:sqlite'
|
|
10
|
+
import type { Logger } from 'pino'
|
|
11
|
+
import type {
|
|
12
|
+
Memory,
|
|
13
|
+
Decision,
|
|
14
|
+
StoreMemoryInput,
|
|
15
|
+
StoreDecisionInput,
|
|
16
|
+
MemoryRow,
|
|
17
|
+
DecisionRow
|
|
18
|
+
} from './types'
|
|
19
|
+
import { EmbeddingService } from './embeddings'
|
|
20
|
+
import { embeddingToBuffer, bufferToEmbedding, cosineSimilarity } from './embedding-utils'
|
|
21
|
+
|
|
22
|
+
/** Raw row from the patterns table */
|
|
23
|
+
interface PatternRow {
|
|
24
|
+
id: string
|
|
25
|
+
memory_id: string
|
|
26
|
+
project: string
|
|
27
|
+
pattern_type: string
|
|
28
|
+
description: string
|
|
29
|
+
example: string | null
|
|
30
|
+
confidence: number
|
|
31
|
+
context: string | null
|
|
32
|
+
created_at: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Raw row from the patterns table joined with memories (includes embedding) */
|
|
36
|
+
interface PatternWithEmbeddingRow extends PatternRow {
|
|
37
|
+
embedding: Buffer | Uint8Array
|
|
38
|
+
memory_content: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Raw row from the corrections table */
|
|
42
|
+
interface CorrectionRow {
|
|
43
|
+
id: string
|
|
44
|
+
memory_id: string
|
|
45
|
+
project: string
|
|
46
|
+
original: string
|
|
47
|
+
correction: string
|
|
48
|
+
reasoning: string
|
|
49
|
+
context: string | null
|
|
50
|
+
confidence: number
|
|
51
|
+
created_at: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Raw row from the corrections table joined with memories */
|
|
55
|
+
interface CorrectionWithEmbeddingRow extends CorrectionRow {
|
|
56
|
+
embedding: Buffer | Uint8Array
|
|
57
|
+
memory_content: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Decision joined with memory content */
|
|
61
|
+
interface DecisionWithContentRow {
|
|
62
|
+
id: string
|
|
63
|
+
context: string
|
|
64
|
+
decision: string
|
|
65
|
+
reasoning: string
|
|
66
|
+
alternatives: string | null
|
|
67
|
+
tags: string | null
|
|
68
|
+
content: string
|
|
69
|
+
project: string
|
|
70
|
+
created_at: string
|
|
71
|
+
metadata: string | null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Pattern joined with memory content */
|
|
75
|
+
interface PatternWithContentRow {
|
|
76
|
+
id: string
|
|
77
|
+
pattern_type: string
|
|
78
|
+
description: string
|
|
79
|
+
example: string | null
|
|
80
|
+
confidence: number
|
|
81
|
+
context: string | null
|
|
82
|
+
content: string
|
|
83
|
+
project: string
|
|
84
|
+
created_at: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Correction joined with memory content */
|
|
88
|
+
interface CorrectionWithContentRow {
|
|
89
|
+
id: string
|
|
90
|
+
original: string
|
|
91
|
+
correction: string
|
|
92
|
+
reasoning: string
|
|
93
|
+
correction_context: string | null
|
|
94
|
+
confidence: number
|
|
95
|
+
content: string
|
|
96
|
+
project: string
|
|
97
|
+
created_at: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Formatted pattern result returned by getPatternsByProject */
|
|
101
|
+
interface FormattedPatternResult {
|
|
102
|
+
id: string
|
|
103
|
+
description: string
|
|
104
|
+
metadata: {
|
|
105
|
+
project: string
|
|
106
|
+
pattern_type: string
|
|
107
|
+
description: string
|
|
108
|
+
example: string
|
|
109
|
+
confidence: number
|
|
110
|
+
context: string
|
|
111
|
+
created_at: string
|
|
112
|
+
first_seen: string
|
|
113
|
+
last_seen: string
|
|
114
|
+
occurrences: number
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Formatted correction result */
|
|
119
|
+
interface FormattedCorrectionResult {
|
|
120
|
+
id: string
|
|
121
|
+
correction: string
|
|
122
|
+
description: string
|
|
123
|
+
metadata: {
|
|
124
|
+
project: string
|
|
125
|
+
original: string
|
|
126
|
+
correction: string
|
|
127
|
+
description: string
|
|
128
|
+
reasoning: string
|
|
129
|
+
context: string
|
|
130
|
+
confidence: number
|
|
131
|
+
created_at: string
|
|
132
|
+
first_seen: string
|
|
133
|
+
last_seen: string
|
|
134
|
+
occurrences: number
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Search result with similarity score */
|
|
139
|
+
interface ScoredSearchResult {
|
|
140
|
+
id: string
|
|
141
|
+
content: string
|
|
142
|
+
metadata: Record<string, unknown>
|
|
143
|
+
similarity: number
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export class MemoryStore {
|
|
147
|
+
private db: Database
|
|
148
|
+
private embeddings: EmbeddingService
|
|
149
|
+
private logger: Logger
|
|
150
|
+
|
|
151
|
+
constructor(db: Database, embeddings: EmbeddingService, logger: Logger) {
|
|
152
|
+
this.db = db
|
|
153
|
+
this.embeddings = embeddings
|
|
154
|
+
this.logger = logger.child({ component: 'memory-store' })
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Store a new memory with embedding
|
|
159
|
+
*/
|
|
160
|
+
async storeMemory(input: StoreMemoryInput): Promise<string> {
|
|
161
|
+
try {
|
|
162
|
+
// Generate embedding
|
|
163
|
+
const embedding = await this.embeddings.generateEmbedding(input.content)
|
|
164
|
+
|
|
165
|
+
// Create memory record
|
|
166
|
+
const id = randomUUID()
|
|
167
|
+
const now = new Date().toISOString()
|
|
168
|
+
|
|
169
|
+
const stmt = this.db.prepare(`
|
|
170
|
+
INSERT INTO memories (id, project, content, embedding, created_at, updated_at, metadata)
|
|
171
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
172
|
+
`)
|
|
173
|
+
|
|
174
|
+
stmt.run(
|
|
175
|
+
id,
|
|
176
|
+
input.project,
|
|
177
|
+
input.content,
|
|
178
|
+
embeddingToBuffer(embedding),
|
|
179
|
+
now,
|
|
180
|
+
now,
|
|
181
|
+
input.metadata ? JSON.stringify(input.metadata) : null
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
this.logger.info({ id, project: input.project }, 'Memory stored')
|
|
185
|
+
return id
|
|
186
|
+
} catch (error) {
|
|
187
|
+
this.logger.error({ error, input }, 'Failed to store memory')
|
|
188
|
+
throw error
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Store a decision (creates memory + decision record)
|
|
194
|
+
*/
|
|
195
|
+
async storeDecision(input: StoreDecisionInput): Promise<string> {
|
|
196
|
+
try {
|
|
197
|
+
// Combine context, decision, and reasoning for embedding
|
|
198
|
+
const content = `Context: ${input.context}\nDecision: ${input.decision}\nReasoning: ${input.reasoning}`
|
|
199
|
+
|
|
200
|
+
// Store as memory
|
|
201
|
+
const memoryId = await this.storeMemory({
|
|
202
|
+
project: input.project,
|
|
203
|
+
content,
|
|
204
|
+
metadata: {
|
|
205
|
+
type: 'decision',
|
|
206
|
+
tags: input.tags || []
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
// Store decision details
|
|
211
|
+
const decisionId = randomUUID()
|
|
212
|
+
const stmt = this.db.prepare(`
|
|
213
|
+
INSERT INTO decisions (id, memory_id, context, decision, reasoning, alternatives, tags)
|
|
214
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
215
|
+
`)
|
|
216
|
+
|
|
217
|
+
stmt.run(
|
|
218
|
+
decisionId,
|
|
219
|
+
memoryId,
|
|
220
|
+
input.context,
|
|
221
|
+
input.decision,
|
|
222
|
+
input.reasoning,
|
|
223
|
+
input.alternatives || null,
|
|
224
|
+
input.tags ? JSON.stringify(input.tags) : null
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
this.logger.info({ decisionId, memoryId, project: input.project }, 'Decision stored')
|
|
228
|
+
return decisionId
|
|
229
|
+
} catch (error) {
|
|
230
|
+
this.logger.error({ error, input }, 'Failed to store decision')
|
|
231
|
+
throw error
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Retrieve memory by ID
|
|
237
|
+
*/
|
|
238
|
+
getMemory(id: string): Memory | null {
|
|
239
|
+
try {
|
|
240
|
+
const stmt = this.db.prepare(`
|
|
241
|
+
SELECT * FROM memories WHERE id = ?
|
|
242
|
+
`)
|
|
243
|
+
|
|
244
|
+
const row = stmt.get(id) as MemoryRow | null
|
|
245
|
+
|
|
246
|
+
if (!row) {
|
|
247
|
+
return null
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return this.rowToMemory(row)
|
|
251
|
+
} catch (error) {
|
|
252
|
+
this.logger.error({ error, id }, 'Failed to get memory')
|
|
253
|
+
return null
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Retrieve decision by ID
|
|
259
|
+
*/
|
|
260
|
+
getDecision(id: string): Decision | null {
|
|
261
|
+
try {
|
|
262
|
+
const stmt = this.db.prepare(`
|
|
263
|
+
SELECT * FROM decisions WHERE id = ?
|
|
264
|
+
`)
|
|
265
|
+
|
|
266
|
+
const row = stmt.get(id) as DecisionRow | null
|
|
267
|
+
|
|
268
|
+
if (!row) {
|
|
269
|
+
return null
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return this.rowToDecision(row)
|
|
273
|
+
} catch (error) {
|
|
274
|
+
this.logger.error({ error, id }, 'Failed to get decision')
|
|
275
|
+
return null
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Get decision by memory ID
|
|
281
|
+
*/
|
|
282
|
+
getDecisionByMemoryId(memoryId: string): Decision | null {
|
|
283
|
+
try {
|
|
284
|
+
const stmt = this.db.prepare(`
|
|
285
|
+
SELECT * FROM decisions WHERE memory_id = ?
|
|
286
|
+
`)
|
|
287
|
+
|
|
288
|
+
const row = stmt.get(memoryId) as DecisionRow | null
|
|
289
|
+
|
|
290
|
+
if (!row) {
|
|
291
|
+
return null
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return this.rowToDecision(row)
|
|
295
|
+
} catch (error) {
|
|
296
|
+
this.logger.error({ error, memoryId }, 'Failed to get decision by memory ID')
|
|
297
|
+
return null
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Update memory content (regenerates embedding)
|
|
303
|
+
*/
|
|
304
|
+
async updateMemory(id: string, content: string): Promise<void> {
|
|
305
|
+
try {
|
|
306
|
+
// Generate new embedding
|
|
307
|
+
const embedding = await this.embeddings.generateEmbedding(content)
|
|
308
|
+
|
|
309
|
+
const stmt = this.db.prepare(`
|
|
310
|
+
UPDATE memories
|
|
311
|
+
SET content = ?, embedding = ?, updated_at = ?
|
|
312
|
+
WHERE id = ?
|
|
313
|
+
`)
|
|
314
|
+
|
|
315
|
+
stmt.run(content, embeddingToBuffer(embedding), new Date().toISOString(), id)
|
|
316
|
+
|
|
317
|
+
this.logger.info({ id }, 'Memory updated')
|
|
318
|
+
} catch (error) {
|
|
319
|
+
this.logger.error({ error, id }, 'Failed to update memory')
|
|
320
|
+
throw error
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Update decision outcome
|
|
326
|
+
*/
|
|
327
|
+
updateDecisionOutcome(id: string, outcome: string): void {
|
|
328
|
+
try {
|
|
329
|
+
const stmt = this.db.prepare(`
|
|
330
|
+
UPDATE decisions
|
|
331
|
+
SET outcome = ?
|
|
332
|
+
WHERE id = ?
|
|
333
|
+
`)
|
|
334
|
+
|
|
335
|
+
stmt.run(outcome, id)
|
|
336
|
+
|
|
337
|
+
this.logger.info({ id }, 'Decision outcome updated')
|
|
338
|
+
} catch (error) {
|
|
339
|
+
this.logger.error({ error, id }, 'Failed to update decision outcome')
|
|
340
|
+
throw error
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Delete memory (cascades to decisions)
|
|
346
|
+
*/
|
|
347
|
+
deleteMemory(id: string): void {
|
|
348
|
+
try {
|
|
349
|
+
const stmt = this.db.prepare('DELETE FROM memories WHERE id = ?')
|
|
350
|
+
stmt.run(id)
|
|
351
|
+
this.logger.info({ id }, 'Memory deleted')
|
|
352
|
+
} catch (error) {
|
|
353
|
+
this.logger.error({ error, id }, 'Failed to delete memory')
|
|
354
|
+
throw error
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Get all memories for a project
|
|
360
|
+
*/
|
|
361
|
+
getProjectMemories(project: string): Memory[] {
|
|
362
|
+
try {
|
|
363
|
+
const stmt = this.db.prepare(`
|
|
364
|
+
SELECT * FROM memories WHERE project = ? ORDER BY created_at DESC
|
|
365
|
+
`)
|
|
366
|
+
|
|
367
|
+
const rows = stmt.all(project) as MemoryRow[]
|
|
368
|
+
|
|
369
|
+
return rows.map((row) => this.rowToMemory(row))
|
|
370
|
+
} catch (error) {
|
|
371
|
+
this.logger.error({ error, project }, 'Failed to get project memories')
|
|
372
|
+
return []
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Get all decisions for a project
|
|
378
|
+
*/
|
|
379
|
+
getProjectDecisions(project: string): Decision[] {
|
|
380
|
+
try {
|
|
381
|
+
const stmt = this.db.prepare(`
|
|
382
|
+
SELECT d.* FROM decisions d
|
|
383
|
+
JOIN memories m ON d.memory_id = m.id
|
|
384
|
+
WHERE m.project = ?
|
|
385
|
+
ORDER BY m.created_at DESC
|
|
386
|
+
`)
|
|
387
|
+
|
|
388
|
+
const rows = stmt.all(project) as DecisionRow[]
|
|
389
|
+
|
|
390
|
+
return rows.map((row) => this.rowToDecision(row))
|
|
391
|
+
} catch (error) {
|
|
392
|
+
this.logger.error({ error, project }, 'Failed to get project decisions')
|
|
393
|
+
return []
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Get memory count by project
|
|
399
|
+
*/
|
|
400
|
+
getMemoryCount(project?: string): number {
|
|
401
|
+
try {
|
|
402
|
+
let query = 'SELECT COUNT(*) as count FROM memories'
|
|
403
|
+
const params: string[] = []
|
|
404
|
+
|
|
405
|
+
if (project) {
|
|
406
|
+
query += ' WHERE project = ?'
|
|
407
|
+
params.push(project)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const stmt = this.db.prepare(query)
|
|
411
|
+
const result = stmt.get(...params) as { count: number }
|
|
412
|
+
|
|
413
|
+
return result.count
|
|
414
|
+
} catch (error) {
|
|
415
|
+
this.logger.error({ error, project }, 'Failed to get memory count')
|
|
416
|
+
return 0
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Get all unique project names
|
|
422
|
+
*/
|
|
423
|
+
getProjects(): string[] {
|
|
424
|
+
try {
|
|
425
|
+
const stmt = this.db.prepare(`
|
|
426
|
+
SELECT DISTINCT project FROM memories ORDER BY project
|
|
427
|
+
`)
|
|
428
|
+
|
|
429
|
+
const rows = stmt.all() as Array<{ project: string }>
|
|
430
|
+
|
|
431
|
+
return rows.map((row) => row.project)
|
|
432
|
+
} catch (error) {
|
|
433
|
+
this.logger.error({ error }, 'Failed to get projects')
|
|
434
|
+
return []
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Convert database row to Memory object
|
|
440
|
+
*/
|
|
441
|
+
private rowToMemory(row: MemoryRow): Memory {
|
|
442
|
+
return {
|
|
443
|
+
id: row.id,
|
|
444
|
+
project: row.project,
|
|
445
|
+
content: row.content,
|
|
446
|
+
embedding: bufferToEmbedding(row.embedding),
|
|
447
|
+
createdAt: new Date(row.created_at),
|
|
448
|
+
updatedAt: new Date(row.updated_at),
|
|
449
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Store a pattern (creates memory + pattern record)
|
|
455
|
+
*/
|
|
456
|
+
async storePattern(input: {
|
|
457
|
+
project: string
|
|
458
|
+
pattern_type: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
459
|
+
description: string
|
|
460
|
+
example?: string
|
|
461
|
+
confidence: number
|
|
462
|
+
context?: string
|
|
463
|
+
source?: string
|
|
464
|
+
}): Promise<string> {
|
|
465
|
+
try {
|
|
466
|
+
const content = `Pattern (${input.pattern_type}): ${input.description}${input.context ? `\nContext: ${input.context}` : ''}${input.example ? `\nExample: ${input.example}` : ''}`
|
|
467
|
+
|
|
468
|
+
const memoryId = await this.storeMemory({
|
|
469
|
+
project: input.project,
|
|
470
|
+
content,
|
|
471
|
+
metadata: {
|
|
472
|
+
type: 'pattern',
|
|
473
|
+
pattern_type: input.pattern_type,
|
|
474
|
+
confidence: input.confidence
|
|
475
|
+
}
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
const patternId = randomUUID()
|
|
479
|
+
const now = new Date().toISOString()
|
|
480
|
+
const stmt = this.db.prepare(`
|
|
481
|
+
INSERT INTO patterns (id, memory_id, project, pattern_type, description, example, confidence, context, created_at)
|
|
482
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
483
|
+
`)
|
|
484
|
+
|
|
485
|
+
stmt.run(
|
|
486
|
+
patternId,
|
|
487
|
+
memoryId,
|
|
488
|
+
input.project,
|
|
489
|
+
input.pattern_type,
|
|
490
|
+
input.description,
|
|
491
|
+
input.example || null,
|
|
492
|
+
input.confidence,
|
|
493
|
+
input.context || null,
|
|
494
|
+
now
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
this.logger.info({ patternId, memoryId, project: input.project }, 'Pattern stored')
|
|
498
|
+
return patternId
|
|
499
|
+
} catch (error) {
|
|
500
|
+
this.logger.error({ error, input }, 'Failed to store pattern')
|
|
501
|
+
throw error
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Store a correction (creates memory + correction record)
|
|
507
|
+
*/
|
|
508
|
+
async storeCorrection(input: {
|
|
509
|
+
project: string
|
|
510
|
+
original: string
|
|
511
|
+
correction: string
|
|
512
|
+
reasoning: string
|
|
513
|
+
context?: string
|
|
514
|
+
confidence: number
|
|
515
|
+
}): Promise<string> {
|
|
516
|
+
try {
|
|
517
|
+
const content = `Correction: ${input.correction}\nOriginal: ${input.original}\nReasoning: ${input.reasoning}${input.context ? `\nContext: ${input.context}` : ''}`
|
|
518
|
+
|
|
519
|
+
const memoryId = await this.storeMemory({
|
|
520
|
+
project: input.project,
|
|
521
|
+
content,
|
|
522
|
+
metadata: {
|
|
523
|
+
type: 'correction',
|
|
524
|
+
confidence: input.confidence
|
|
525
|
+
}
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
const correctionId = randomUUID()
|
|
529
|
+
const now = new Date().toISOString()
|
|
530
|
+
const stmt = this.db.prepare(`
|
|
531
|
+
INSERT INTO corrections (id, memory_id, project, original, correction, reasoning, context, confidence, created_at)
|
|
532
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
533
|
+
`)
|
|
534
|
+
|
|
535
|
+
stmt.run(
|
|
536
|
+
correctionId,
|
|
537
|
+
memoryId,
|
|
538
|
+
input.project,
|
|
539
|
+
input.original,
|
|
540
|
+
input.correction,
|
|
541
|
+
input.reasoning,
|
|
542
|
+
input.context || null,
|
|
543
|
+
input.confidence,
|
|
544
|
+
now
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
this.logger.info({ correctionId, memoryId, project: input.project }, 'Correction stored')
|
|
548
|
+
return correctionId
|
|
549
|
+
} catch (error) {
|
|
550
|
+
this.logger.error({ error, input }, 'Failed to store correction')
|
|
551
|
+
throw error
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Get patterns by project with optional type filter
|
|
557
|
+
*/
|
|
558
|
+
getPatternsByProject(project: string, options?: {
|
|
559
|
+
pattern_type?: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
560
|
+
limit?: number
|
|
561
|
+
}): FormattedPatternResult[] {
|
|
562
|
+
try {
|
|
563
|
+
let sql = 'SELECT * FROM patterns WHERE project = ?'
|
|
564
|
+
const params: (string | number)[] = [project]
|
|
565
|
+
|
|
566
|
+
if (options?.pattern_type) {
|
|
567
|
+
sql += ' AND pattern_type = ?'
|
|
568
|
+
params.push(options.pattern_type)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
sql += ' ORDER BY created_at DESC'
|
|
572
|
+
|
|
573
|
+
if (options?.limit) {
|
|
574
|
+
sql += ' LIMIT ?'
|
|
575
|
+
params.push(options.limit)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const stmt = this.db.prepare(sql)
|
|
579
|
+
const rows = stmt.all(...params) as PatternRow[]
|
|
580
|
+
|
|
581
|
+
return rows.map(row => ({
|
|
582
|
+
id: row.id,
|
|
583
|
+
description: row.description,
|
|
584
|
+
metadata: {
|
|
585
|
+
project: row.project,
|
|
586
|
+
pattern_type: row.pattern_type,
|
|
587
|
+
description: row.description,
|
|
588
|
+
example: row.example || '',
|
|
589
|
+
confidence: row.confidence,
|
|
590
|
+
context: row.context || '',
|
|
591
|
+
created_at: row.created_at,
|
|
592
|
+
first_seen: row.created_at,
|
|
593
|
+
last_seen: row.created_at,
|
|
594
|
+
occurrences: 1
|
|
595
|
+
}
|
|
596
|
+
}))
|
|
597
|
+
} catch (error) {
|
|
598
|
+
this.logger.error({ error, project }, 'Failed to get patterns by project')
|
|
599
|
+
return []
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Get corrections by project
|
|
605
|
+
*/
|
|
606
|
+
getCorrectionsByProject(project: string, limit: number = 10): FormattedCorrectionResult[] {
|
|
607
|
+
try {
|
|
608
|
+
const stmt = this.db.prepare(
|
|
609
|
+
'SELECT * FROM corrections WHERE project = ? ORDER BY created_at DESC LIMIT ?'
|
|
610
|
+
)
|
|
611
|
+
const rows = stmt.all(project, limit) as CorrectionRow[]
|
|
612
|
+
|
|
613
|
+
return rows.map(row => ({
|
|
614
|
+
id: row.id,
|
|
615
|
+
correction: row.correction,
|
|
616
|
+
description: row.correction,
|
|
617
|
+
metadata: {
|
|
618
|
+
project: row.project,
|
|
619
|
+
original: row.original,
|
|
620
|
+
correction: row.correction,
|
|
621
|
+
description: row.correction,
|
|
622
|
+
reasoning: row.reasoning,
|
|
623
|
+
context: row.context || '',
|
|
624
|
+
confidence: row.confidence,
|
|
625
|
+
created_at: row.created_at,
|
|
626
|
+
first_seen: row.created_at,
|
|
627
|
+
last_seen: row.created_at,
|
|
628
|
+
occurrences: 1
|
|
629
|
+
}
|
|
630
|
+
}))
|
|
631
|
+
} catch (error) {
|
|
632
|
+
this.logger.error({ error, project }, 'Failed to get corrections by project')
|
|
633
|
+
return []
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Search patterns using semantic search on underlying memories
|
|
639
|
+
*/
|
|
640
|
+
async searchPatterns(
|
|
641
|
+
query: string,
|
|
642
|
+
options?: {
|
|
643
|
+
project?: string
|
|
644
|
+
pattern_type?: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
645
|
+
limit?: number
|
|
646
|
+
minSimilarity?: number
|
|
647
|
+
}
|
|
648
|
+
): Promise<ScoredSearchResult[]> {
|
|
649
|
+
try {
|
|
650
|
+
// If no query, return all patterns for the project
|
|
651
|
+
if (!query && options?.project) {
|
|
652
|
+
return this.getPatternsByProject(options.project, {
|
|
653
|
+
pattern_type: options?.pattern_type,
|
|
654
|
+
limit: options?.limit
|
|
655
|
+
})
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Generate embedding for semantic search
|
|
659
|
+
const queryEmbedding = await this.embeddings.generateEmbedding(query || 'pattern')
|
|
660
|
+
|
|
661
|
+
let sql = `
|
|
662
|
+
SELECT p.*, m.embedding, m.content as memory_content
|
|
663
|
+
FROM patterns p
|
|
664
|
+
JOIN memories m ON p.memory_id = m.id
|
|
665
|
+
WHERE 1=1
|
|
666
|
+
`
|
|
667
|
+
const params: (string | number)[] = []
|
|
668
|
+
|
|
669
|
+
if (options?.project) {
|
|
670
|
+
sql += ' AND p.project = ?'
|
|
671
|
+
params.push(options.project)
|
|
672
|
+
}
|
|
673
|
+
if (options?.pattern_type) {
|
|
674
|
+
sql += ' AND p.pattern_type = ?'
|
|
675
|
+
params.push(options.pattern_type)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const stmt = this.db.prepare(sql)
|
|
679
|
+
const rows = stmt.all(...params) as PatternWithEmbeddingRow[]
|
|
680
|
+
|
|
681
|
+
const results = rows.map(row => {
|
|
682
|
+
const embedding = bufferToEmbedding(row.embedding)
|
|
683
|
+
const similarity = cosineSimilarity(queryEmbedding, embedding)
|
|
684
|
+
return {
|
|
685
|
+
id: row.id,
|
|
686
|
+
content: row.description,
|
|
687
|
+
metadata: {
|
|
688
|
+
project: row.project,
|
|
689
|
+
pattern_type: row.pattern_type,
|
|
690
|
+
description: row.description,
|
|
691
|
+
example: row.example || '',
|
|
692
|
+
confidence: row.confidence,
|
|
693
|
+
context: row.context || '',
|
|
694
|
+
created_at: row.created_at,
|
|
695
|
+
first_seen: row.created_at,
|
|
696
|
+
last_seen: row.created_at,
|
|
697
|
+
occurrences: 1
|
|
698
|
+
},
|
|
699
|
+
similarity
|
|
700
|
+
}
|
|
701
|
+
})
|
|
702
|
+
.filter(r => r.similarity >= (options?.minSimilarity || 0.3))
|
|
703
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
704
|
+
.slice(0, options?.limit || 10)
|
|
705
|
+
|
|
706
|
+
return results
|
|
707
|
+
} catch (error) {
|
|
708
|
+
this.logger.error({ error, query }, 'Pattern search failed')
|
|
709
|
+
return []
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Search corrections using semantic search on underlying memories
|
|
715
|
+
*/
|
|
716
|
+
async searchCorrections(
|
|
717
|
+
query: string,
|
|
718
|
+
options?: {
|
|
719
|
+
project?: string
|
|
720
|
+
limit?: number
|
|
721
|
+
minSimilarity?: number
|
|
722
|
+
}
|
|
723
|
+
): Promise<ScoredSearchResult[]> {
|
|
724
|
+
try {
|
|
725
|
+
// If no query, return all corrections for the project
|
|
726
|
+
if (!query && options?.project) {
|
|
727
|
+
return this.getCorrectionsByProject(options.project, options?.limit || 10)
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const queryEmbedding = await this.embeddings.generateEmbedding(query || 'correction')
|
|
731
|
+
|
|
732
|
+
let sql = `
|
|
733
|
+
SELECT c.*, m.embedding, m.content as memory_content
|
|
734
|
+
FROM corrections c
|
|
735
|
+
JOIN memories m ON c.memory_id = m.id
|
|
736
|
+
WHERE 1=1
|
|
737
|
+
`
|
|
738
|
+
const params: (string | number)[] = []
|
|
739
|
+
|
|
740
|
+
if (options?.project) {
|
|
741
|
+
sql += ' AND c.project = ?'
|
|
742
|
+
params.push(options.project)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const stmt = this.db.prepare(sql)
|
|
746
|
+
const rows = stmt.all(...params) as CorrectionWithEmbeddingRow[]
|
|
747
|
+
|
|
748
|
+
const results = rows.map(row => {
|
|
749
|
+
const embedding = bufferToEmbedding(row.embedding)
|
|
750
|
+
const similarity = cosineSimilarity(queryEmbedding, embedding)
|
|
751
|
+
return {
|
|
752
|
+
id: row.id,
|
|
753
|
+
content: row.correction,
|
|
754
|
+
description: row.correction,
|
|
755
|
+
metadata: {
|
|
756
|
+
project: row.project,
|
|
757
|
+
original: row.original,
|
|
758
|
+
correction: row.correction,
|
|
759
|
+
description: row.correction,
|
|
760
|
+
reasoning: row.reasoning,
|
|
761
|
+
context: row.context || '',
|
|
762
|
+
confidence: row.confidence,
|
|
763
|
+
created_at: row.created_at,
|
|
764
|
+
first_seen: row.created_at,
|
|
765
|
+
last_seen: row.created_at,
|
|
766
|
+
occurrences: 1
|
|
767
|
+
},
|
|
768
|
+
similarity
|
|
769
|
+
}
|
|
770
|
+
})
|
|
771
|
+
.filter(r => r.similarity >= (options?.minSimilarity || 0.3))
|
|
772
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
773
|
+
.slice(0, options?.limit || 10)
|
|
774
|
+
|
|
775
|
+
return results
|
|
776
|
+
} catch (error) {
|
|
777
|
+
this.logger.error({ error, query }, 'Correction search failed')
|
|
778
|
+
return []
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Get all decisions with full content (for analytical tools without ChromaDB)
|
|
784
|
+
*/
|
|
785
|
+
getAllDecisionsWithContent(project?: string): Record<string, unknown>[] {
|
|
786
|
+
try {
|
|
787
|
+
let sql = `
|
|
788
|
+
SELECT d.id, d.context, d.decision, d.reasoning, d.alternatives, d.tags,
|
|
789
|
+
m.content, m.project, m.created_at, m.metadata
|
|
790
|
+
FROM decisions d
|
|
791
|
+
JOIN memories m ON d.memory_id = m.id
|
|
792
|
+
`
|
|
793
|
+
const params: string[] = []
|
|
794
|
+
if (project) {
|
|
795
|
+
sql += ' WHERE m.project = ?'
|
|
796
|
+
params.push(project)
|
|
797
|
+
}
|
|
798
|
+
sql += ' ORDER BY m.created_at DESC'
|
|
799
|
+
|
|
800
|
+
const stmt = this.db.prepare(sql)
|
|
801
|
+
const rows = stmt.all(...params) as DecisionWithContentRow[]
|
|
802
|
+
|
|
803
|
+
return rows.map(row => ({
|
|
804
|
+
id: row.id,
|
|
805
|
+
content: row.content,
|
|
806
|
+
date: row.created_at,
|
|
807
|
+
project: row.project,
|
|
808
|
+
context: row.context,
|
|
809
|
+
decision: row.decision,
|
|
810
|
+
reasoning: row.reasoning,
|
|
811
|
+
alternatives: row.alternatives,
|
|
812
|
+
tags: row.tags ? JSON.parse(row.tags) : []
|
|
813
|
+
}))
|
|
814
|
+
} catch (error) {
|
|
815
|
+
this.logger.error({ error, project }, 'Failed to get all decisions with content')
|
|
816
|
+
return []
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Get all patterns with full content (for analytical tools without ChromaDB)
|
|
822
|
+
*/
|
|
823
|
+
getAllPatternsWithContent(project?: string): Record<string, unknown>[] {
|
|
824
|
+
try {
|
|
825
|
+
let sql = `
|
|
826
|
+
SELECT p.id, p.pattern_type, p.description, p.example, p.confidence, p.context,
|
|
827
|
+
m.content, m.project, m.created_at
|
|
828
|
+
FROM patterns p
|
|
829
|
+
JOIN memories m ON p.memory_id = m.id
|
|
830
|
+
`
|
|
831
|
+
const params: string[] = []
|
|
832
|
+
if (project) {
|
|
833
|
+
sql += ' WHERE p.project = ?'
|
|
834
|
+
params.push(project)
|
|
835
|
+
}
|
|
836
|
+
sql += ' ORDER BY m.created_at DESC'
|
|
837
|
+
|
|
838
|
+
const stmt = this.db.prepare(sql)
|
|
839
|
+
const rows = stmt.all(...params) as PatternWithContentRow[]
|
|
840
|
+
|
|
841
|
+
return rows.map(row => ({
|
|
842
|
+
id: row.id,
|
|
843
|
+
content: row.content,
|
|
844
|
+
date: row.created_at,
|
|
845
|
+
project: row.project,
|
|
846
|
+
pattern_type: row.pattern_type,
|
|
847
|
+
description: row.description,
|
|
848
|
+
example: row.example,
|
|
849
|
+
confidence: row.confidence,
|
|
850
|
+
context: row.context
|
|
851
|
+
}))
|
|
852
|
+
} catch (error) {
|
|
853
|
+
this.logger.error({ error, project }, 'Failed to get all patterns with content')
|
|
854
|
+
return []
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Get all corrections with full content (for analytical tools without ChromaDB)
|
|
860
|
+
*/
|
|
861
|
+
getAllCorrectionsWithContent(project?: string): Record<string, unknown>[] {
|
|
862
|
+
try {
|
|
863
|
+
let sql = `
|
|
864
|
+
SELECT c.id, c.original, c.correction, c.reasoning, c.context as correction_context,
|
|
865
|
+
c.confidence, m.content, m.project, m.created_at
|
|
866
|
+
FROM corrections c
|
|
867
|
+
JOIN memories m ON c.memory_id = m.id
|
|
868
|
+
`
|
|
869
|
+
const params: string[] = []
|
|
870
|
+
if (project) {
|
|
871
|
+
sql += ' WHERE c.project = ?'
|
|
872
|
+
params.push(project)
|
|
873
|
+
}
|
|
874
|
+
sql += ' ORDER BY m.created_at DESC'
|
|
875
|
+
|
|
876
|
+
const stmt = this.db.prepare(sql)
|
|
877
|
+
const rows = stmt.all(...params) as CorrectionWithContentRow[]
|
|
878
|
+
|
|
879
|
+
return rows.map(row => ({
|
|
880
|
+
id: row.id,
|
|
881
|
+
content: row.content,
|
|
882
|
+
date: row.created_at,
|
|
883
|
+
project: row.project,
|
|
884
|
+
original: row.original,
|
|
885
|
+
correction: row.correction,
|
|
886
|
+
reasoning: row.reasoning,
|
|
887
|
+
context: row.correction_context,
|
|
888
|
+
confidence: row.confidence
|
|
889
|
+
}))
|
|
890
|
+
} catch (error) {
|
|
891
|
+
this.logger.error({ error, project }, 'Failed to get all corrections with content')
|
|
892
|
+
return []
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Convert database row to Decision object
|
|
898
|
+
*/
|
|
899
|
+
private rowToDecision(row: DecisionRow): Decision {
|
|
900
|
+
return {
|
|
901
|
+
id: row.id,
|
|
902
|
+
memoryId: row.memory_id,
|
|
903
|
+
context: row.context,
|
|
904
|
+
decision: row.decision,
|
|
905
|
+
reasoning: row.reasoning,
|
|
906
|
+
alternatives: row.alternatives || undefined,
|
|
907
|
+
outcome: row.outcome || undefined,
|
|
908
|
+
tags: row.tags ? JSON.parse(row.tags) : undefined
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|