audrey 0.16.1 → 0.20.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.
Files changed (188) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +146 -724
  3. package/dist/mcp-server/config.d.ts +20 -0
  4. package/dist/mcp-server/config.d.ts.map +1 -0
  5. package/dist/mcp-server/config.js +125 -0
  6. package/dist/mcp-server/config.js.map +1 -0
  7. package/dist/mcp-server/index.d.ts +100 -0
  8. package/dist/mcp-server/index.d.ts.map +1 -0
  9. package/dist/mcp-server/index.js +1113 -0
  10. package/dist/mcp-server/index.js.map +1 -0
  11. package/dist/src/adaptive.d.ts +7 -0
  12. package/dist/src/adaptive.d.ts.map +1 -0
  13. package/dist/src/adaptive.js +49 -0
  14. package/dist/src/adaptive.js.map +1 -0
  15. package/dist/src/affect.d.ts +19 -0
  16. package/dist/src/affect.d.ts.map +1 -0
  17. package/dist/src/affect.js +72 -0
  18. package/dist/src/affect.js.map +1 -0
  19. package/dist/src/audrey.d.ts +140 -0
  20. package/dist/src/audrey.d.ts.map +1 -0
  21. package/dist/src/audrey.js +564 -0
  22. package/dist/src/audrey.js.map +1 -0
  23. package/dist/src/capsule.d.ts +68 -0
  24. package/dist/src/capsule.d.ts.map +1 -0
  25. package/dist/src/capsule.js +311 -0
  26. package/dist/src/capsule.js.map +1 -0
  27. package/dist/src/causal.d.ts +28 -0
  28. package/dist/src/causal.d.ts.map +1 -0
  29. package/dist/src/causal.js +65 -0
  30. package/dist/src/causal.js.map +1 -0
  31. package/dist/src/confidence.d.ts +12 -0
  32. package/dist/src/confidence.d.ts.map +1 -0
  33. package/dist/src/confidence.js +63 -0
  34. package/dist/src/confidence.js.map +1 -0
  35. package/dist/src/consolidate.d.ts +8 -0
  36. package/dist/src/consolidate.d.ts.map +1 -0
  37. package/dist/src/consolidate.js +218 -0
  38. package/dist/src/consolidate.js.map +1 -0
  39. package/dist/src/context.d.ts +3 -0
  40. package/dist/src/context.d.ts.map +1 -0
  41. package/dist/src/context.js +19 -0
  42. package/dist/src/context.js.map +1 -0
  43. package/dist/src/db.d.ts +12 -0
  44. package/dist/src/db.d.ts.map +1 -0
  45. package/dist/src/db.js +380 -0
  46. package/dist/src/db.js.map +1 -0
  47. package/dist/src/decay.d.ts +7 -0
  48. package/dist/src/decay.d.ts.map +1 -0
  49. package/dist/src/decay.js +68 -0
  50. package/dist/src/decay.js.map +1 -0
  51. package/dist/src/embedding.d.ts +57 -0
  52. package/dist/src/embedding.d.ts.map +1 -0
  53. package/dist/src/embedding.js +254 -0
  54. package/dist/src/embedding.js.map +1 -0
  55. package/dist/src/encode.d.ts +15 -0
  56. package/dist/src/encode.d.ts.map +1 -0
  57. package/dist/src/encode.js +36 -0
  58. package/dist/src/encode.js.map +1 -0
  59. package/dist/src/events.d.ts +69 -0
  60. package/dist/src/events.d.ts.map +1 -0
  61. package/dist/src/events.js +149 -0
  62. package/dist/src/events.js.map +1 -0
  63. package/dist/src/export.d.ts +3 -0
  64. package/dist/src/export.d.ts.map +1 -0
  65. package/dist/src/export.js +46 -0
  66. package/dist/src/export.js.map +1 -0
  67. package/dist/src/forget.d.ts +11 -0
  68. package/dist/src/forget.d.ts.map +1 -0
  69. package/dist/src/forget.js +105 -0
  70. package/dist/src/forget.js.map +1 -0
  71. package/dist/src/fts.d.ts +34 -0
  72. package/dist/src/fts.d.ts.map +1 -0
  73. package/dist/src/fts.js +117 -0
  74. package/dist/src/fts.js.map +1 -0
  75. package/dist/src/hybrid-recall.d.ts +37 -0
  76. package/dist/src/hybrid-recall.d.ts.map +1 -0
  77. package/dist/src/hybrid-recall.js +213 -0
  78. package/dist/src/hybrid-recall.js.map +1 -0
  79. package/dist/src/import.d.ts +4 -0
  80. package/dist/src/import.d.ts.map +1 -0
  81. package/dist/src/import.js +127 -0
  82. package/dist/src/import.js.map +1 -0
  83. package/dist/src/index.d.ts +22 -0
  84. package/dist/src/index.d.ts.map +1 -0
  85. package/{src → dist/src}/index.js +5 -13
  86. package/dist/src/index.js.map +1 -0
  87. package/dist/src/interference.d.ts +13 -0
  88. package/dist/src/interference.d.ts.map +1 -0
  89. package/dist/src/interference.js +45 -0
  90. package/dist/src/interference.js.map +1 -0
  91. package/dist/src/introspect.d.ts +4 -0
  92. package/dist/src/introspect.d.ts.map +1 -0
  93. package/dist/src/introspect.js +40 -0
  94. package/dist/src/introspect.js.map +1 -0
  95. package/dist/src/llm.d.ts +38 -0
  96. package/dist/src/llm.d.ts.map +1 -0
  97. package/dist/src/llm.js +167 -0
  98. package/dist/src/llm.js.map +1 -0
  99. package/dist/src/migrate.d.ts +6 -0
  100. package/dist/src/migrate.d.ts.map +1 -0
  101. package/dist/src/migrate.js +51 -0
  102. package/dist/src/migrate.js.map +1 -0
  103. package/dist/src/promote.d.ts +40 -0
  104. package/dist/src/promote.d.ts.map +1 -0
  105. package/dist/src/promote.js +200 -0
  106. package/dist/src/promote.js.map +1 -0
  107. package/dist/src/prompts.d.ts +16 -0
  108. package/dist/src/prompts.d.ts.map +1 -0
  109. package/{src → dist/src}/prompts.js +172 -203
  110. package/dist/src/prompts.js.map +1 -0
  111. package/dist/src/recall.d.ts +9 -0
  112. package/dist/src/recall.d.ts.map +1 -0
  113. package/dist/src/recall.js +432 -0
  114. package/dist/src/recall.js.map +1 -0
  115. package/dist/src/redact.d.ts +27 -0
  116. package/dist/src/redact.d.ts.map +1 -0
  117. package/dist/src/redact.js +228 -0
  118. package/dist/src/redact.js.map +1 -0
  119. package/dist/src/rollback.d.ts +8 -0
  120. package/dist/src/rollback.d.ts.map +1 -0
  121. package/dist/src/rollback.js +33 -0
  122. package/dist/src/rollback.js.map +1 -0
  123. package/dist/src/routes.d.ts +7 -0
  124. package/dist/src/routes.d.ts.map +1 -0
  125. package/dist/src/routes.js +226 -0
  126. package/dist/src/routes.js.map +1 -0
  127. package/dist/src/rules-compiler.d.ts +20 -0
  128. package/dist/src/rules-compiler.d.ts.map +1 -0
  129. package/dist/src/rules-compiler.js +143 -0
  130. package/dist/src/rules-compiler.js.map +1 -0
  131. package/dist/src/server.d.ts +12 -0
  132. package/dist/src/server.d.ts.map +1 -0
  133. package/dist/src/server.js +22 -0
  134. package/dist/src/server.js.map +1 -0
  135. package/dist/src/tool-trace.d.ts +37 -0
  136. package/dist/src/tool-trace.d.ts.map +1 -0
  137. package/dist/src/tool-trace.js +142 -0
  138. package/dist/src/tool-trace.js.map +1 -0
  139. package/dist/src/types.d.ts +446 -0
  140. package/dist/src/types.d.ts.map +1 -0
  141. package/dist/src/types.js +6 -0
  142. package/dist/src/types.js.map +1 -0
  143. package/dist/src/ulid.d.ts +3 -0
  144. package/dist/src/ulid.d.ts.map +1 -0
  145. package/dist/src/ulid.js +11 -0
  146. package/dist/src/ulid.js.map +1 -0
  147. package/dist/src/utils.d.ts +10 -0
  148. package/dist/src/utils.d.ts.map +1 -0
  149. package/dist/src/utils.js +41 -0
  150. package/dist/src/utils.js.map +1 -0
  151. package/dist/src/validate.d.ts +22 -0
  152. package/dist/src/validate.d.ts.map +1 -0
  153. package/dist/src/validate.js +109 -0
  154. package/dist/src/validate.js.map +1 -0
  155. package/docs/assets/benchmarks/local-benchmark.svg +45 -0
  156. package/docs/assets/benchmarks/operations-benchmark.svg +45 -0
  157. package/docs/assets/benchmarks/published-memory-standards.svg +50 -0
  158. package/docs/benchmarking.md +151 -0
  159. package/docs/production-readiness.md +124 -0
  160. package/examples/fintech-ops-demo.js +67 -0
  161. package/examples/healthcare-ops-demo.js +67 -0
  162. package/examples/stripe-demo.js +105 -0
  163. package/package.json +53 -13
  164. package/mcp-server/config.js +0 -80
  165. package/mcp-server/index.js +0 -729
  166. package/src/adaptive.js +0 -53
  167. package/src/affect.js +0 -64
  168. package/src/audrey.js +0 -604
  169. package/src/causal.js +0 -95
  170. package/src/confidence.js +0 -120
  171. package/src/consolidate.js +0 -265
  172. package/src/context.js +0 -15
  173. package/src/db.js +0 -370
  174. package/src/decay.js +0 -84
  175. package/src/embedding.js +0 -256
  176. package/src/encode.js +0 -63
  177. package/src/export.js +0 -67
  178. package/src/forget.js +0 -111
  179. package/src/import.js +0 -245
  180. package/src/interference.js +0 -51
  181. package/src/introspect.js +0 -48
  182. package/src/llm.js +0 -246
  183. package/src/migrate.js +0 -58
  184. package/src/recall.js +0 -352
  185. package/src/rollback.js +0 -42
  186. package/src/ulid.js +0 -18
  187. package/src/utils.js +0 -38
  188. package/src/validate.js +0 -172
package/src/audrey.js DELETED
@@ -1,604 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import { createDatabase, closeDatabase } from './db.js';
3
- import { createEmbeddingProvider } from './embedding.js';
4
- import { createLLMProvider } from './llm.js';
5
- import { encodeEpisode } from './encode.js';
6
- import { recall as recallFn, recallStream as recallStreamFn } from './recall.js';
7
- import { validateMemory } from './validate.js';
8
- import { runConsolidation } from './consolidate.js';
9
- import { applyDecay } from './decay.js';
10
- import { rollbackConsolidation, getConsolidationHistory } from './rollback.js';
11
- import { forgetMemory, forgetByQuery as forgetByQueryFn, purgeMemories } from './forget.js';
12
- import { introspect as introspectFn } from './introspect.js';
13
- import { buildContextResolutionPrompt, buildReflectionPrompt } from './prompts.js';
14
- import { exportMemories } from './export.js';
15
- import { importMemories } from './import.js';
16
- import { suggestConsolidationParams as suggestParamsFn } from './adaptive.js';
17
- import { reembedAll } from './migrate.js';
18
- import { applyInterference } from './interference.js';
19
- import { detectResonance } from './affect.js';
20
-
21
- /**
22
- * @typedef {'direct-observation' | 'told-by-user' | 'tool-result' | 'inference' | 'model-generated'} SourceType
23
- * @typedef {'episodic' | 'semantic' | 'procedural'} MemoryType
24
- *
25
- * @typedef {Object} EncodeParams
26
- * @property {string} content
27
- * @property {SourceType} source
28
- * @property {number} [salience]
29
- * @property {{ trigger?: string, consequence?: string }} [causal]
30
- * @property {string[]} [tags]
31
- * @property {string} [supersedes]
32
- * @property {Record<string, string>} [context]
33
- * @property {{ valence?: number, arousal?: number, label?: string }} [affect]
34
- *
35
- * @typedef {Object} RecallOptions
36
- * @property {number} [minConfidence]
37
- * @property {MemoryType[]} [types]
38
- * @property {number} [limit]
39
- * @property {boolean} [includeProvenance]
40
- * @property {boolean} [includeDormant]
41
- * @property {string[]} [tags]
42
- * @property {string[]} [sources]
43
- * @property {string} [after]
44
- * @property {string} [before]
45
- * @property {Record<string, string>} [context]
46
- * @property {{ valence?: number, arousal?: number }} [mood]
47
- *
48
- * @typedef {Object} RecallResult
49
- * @property {string} id
50
- * @property {string} content
51
- * @property {MemoryType} type
52
- * @property {number} confidence
53
- * @property {number} score
54
- * @property {string} source
55
- * @property {string} createdAt
56
- *
57
- * @typedef {Object} ConsolidationResult
58
- * @property {string} runId
59
- * @property {number} episodesEvaluated
60
- * @property {number} clustersFound
61
- * @property {number} principlesExtracted
62
- * @property {string} status
63
- *
64
- * @typedef {Object} IntrospectResult
65
- * @property {number} episodic
66
- * @property {number} semantic
67
- * @property {number} procedural
68
- * @property {number} causalLinks
69
- * @property {number} dormant
70
- * @property {{ open: number, resolved: number, context_dependent: number, reopened: number }} contradictions
71
- * @property {string | null} lastConsolidation
72
- * @property {number} totalConsolidationRuns
73
- *
74
- * @typedef {Object} TruthResolution
75
- * @property {'a_wins' | 'b_wins' | 'context_dependent'} resolution
76
- * @property {Object} [conditions]
77
- * @property {string} explanation
78
- *
79
- * @typedef {Object} AudreyConfig
80
- * @property {string} [dataDir]
81
- * @property {string} [agent]
82
- * @property {{ provider: 'mock' | 'openai', dimensions?: number, apiKey?: string }} [embedding]
83
- * @property {{ provider: 'mock' | 'anthropic' | 'openai', apiKey?: string, model?: string }} [llm]
84
- * @property {{ minEpisodes?: number }} [consolidation]
85
- * @property {{ dormantThreshold?: number }} [decay]
86
- */
87
-
88
- export class Audrey extends EventEmitter {
89
- /** @param {AudreyConfig} [config] */
90
- constructor({
91
- dataDir = './audrey-data',
92
- agent = 'default',
93
- embedding = { provider: 'mock', dimensions: 64 },
94
- llm,
95
- confidence = {},
96
- consolidation = {},
97
- decay = {},
98
- interference = {},
99
- context = {},
100
- affect = {},
101
- autoReflect = false,
102
- } = {}) {
103
- super();
104
-
105
- const dormantThreshold = decay.dormantThreshold ?? 0.1;
106
- if (dormantThreshold < 0 || dormantThreshold > 1) {
107
- throw new Error(`dormantThreshold must be between 0 and 1, got: ${dormantThreshold}`);
108
- }
109
-
110
- const minEpisodes = consolidation.minEpisodes ?? 3;
111
- if (!Number.isInteger(minEpisodes) || minEpisodes < 1) {
112
- throw new Error(`minEpisodes must be a positive integer, got: ${minEpisodes}`);
113
- }
114
-
115
- this.agent = agent;
116
- this.dataDir = dataDir;
117
- this.embeddingProvider = createEmbeddingProvider(embedding);
118
- const { db, migrated } = createDatabase(dataDir, { dimensions: this.embeddingProvider.dimensions });
119
- this.db = db;
120
- this._migrationPending = migrated;
121
- this.llmProvider = llm ? createLLMProvider(llm) : null;
122
- this.confidenceConfig = {
123
- weights: confidence.weights,
124
- halfLives: confidence.halfLives,
125
- sourceReliability: confidence.sourceReliability,
126
- interferenceWeight: interference.weight ?? 0.1,
127
- contextWeight: context.weight ?? 0.3,
128
- affectWeight: affect.weight ?? 0.2,
129
- };
130
- this.consolidationConfig = {
131
- minEpisodes: consolidation.minEpisodes || 3,
132
- };
133
- this.decayConfig = { dormantThreshold: decay.dormantThreshold || 0.1 };
134
- this._autoConsolidateTimer = null;
135
- this.interferenceConfig = {
136
- enabled: interference.enabled ?? true,
137
- k: interference.k ?? 5,
138
- threshold: interference.threshold ?? 0.6,
139
- weight: interference.weight ?? 0.1,
140
- };
141
- this.contextConfig = {
142
- enabled: context.enabled ?? true,
143
- weight: context.weight ?? 0.3,
144
- };
145
- this.affectConfig = {
146
- enabled: affect.enabled ?? true,
147
- weight: affect.weight ?? 0.2,
148
- arousalWeight: affect.arousalWeight ?? 0.3,
149
- resonance: {
150
- enabled: affect.resonance?.enabled ?? true,
151
- k: affect.resonance?.k ?? 5,
152
- threshold: affect.resonance?.threshold ?? 0.5,
153
- affectThreshold: affect.resonance?.affectThreshold ?? 0.6,
154
- },
155
- };
156
- this.autoReflect = autoReflect;
157
- }
158
-
159
- async _ensureMigrated() {
160
- if (!this._migrationPending) return;
161
- const counts = await reembedAll(this.db, this.embeddingProvider);
162
- this._migrationPending = false;
163
- this.emit('migration', counts);
164
- }
165
-
166
- _emitValidation(id, params) {
167
- validateMemory(this.db, this.embeddingProvider, { id, ...params }, {
168
- llmProvider: this.llmProvider,
169
- })
170
- .then(validation => {
171
- if (validation.action === 'reinforced') {
172
- this.emit('reinforcement', {
173
- episodeId: id,
174
- targetId: validation.semanticId,
175
- similarity: validation.similarity,
176
- });
177
- } else if (validation.action === 'contradiction') {
178
- this.emit('contradiction', {
179
- episodeId: id,
180
- contradictionId: validation.contradictionId,
181
- semanticId: validation.semanticId,
182
- similarity: validation.similarity,
183
- resolution: validation.resolution,
184
- });
185
- }
186
- })
187
- .catch(err => this.emit('error', err));
188
- }
189
-
190
- /**
191
- * @param {EncodeParams} params
192
- * @returns {Promise<string>}
193
- */
194
- async encode(params) {
195
- await this._ensureMigrated();
196
- const encodeParams = { ...params, arousalWeight: this.affectConfig.arousalWeight };
197
- const id = await encodeEpisode(this.db, this.embeddingProvider, encodeParams);
198
- this.emit('encode', { id, ...params });
199
- if (this.interferenceConfig.enabled) {
200
- applyInterference(this.db, this.embeddingProvider, id, params, this.interferenceConfig)
201
- .then(affected => {
202
- if (affected.length > 0) {
203
- this.emit('interference', { episodeId: id, affected });
204
- }
205
- })
206
- .catch(err => this.emit('error', err));
207
- }
208
- if (this.affectConfig.enabled && this.affectConfig.resonance.enabled && params.affect?.valence !== undefined) {
209
- detectResonance(this.db, this.embeddingProvider, id, params, this.affectConfig.resonance)
210
- .then(echoes => {
211
- if (echoes.length > 0) {
212
- this.emit('resonance', { episodeId: id, affect: params.affect, echoes });
213
- }
214
- })
215
- .catch(err => this.emit('error', err));
216
- }
217
- this._emitValidation(id, params);
218
- return id;
219
- }
220
-
221
-
222
- async reflect(turns) {
223
- if (!this.llmProvider) return { encoded: 0, memories: [], skipped: 'no llm provider' };
224
-
225
- const prompt = buildReflectionPrompt(turns);
226
- let raw;
227
- try {
228
- raw = await this.llmProvider.chat(prompt);
229
- } catch (err) {
230
- this.emit('error', err);
231
- return { encoded: 0, memories: [], skipped: 'llm error' };
232
- }
233
-
234
- let parsed;
235
- try {
236
- parsed = JSON.parse(raw);
237
- } catch {
238
- return { encoded: 0, memories: [], skipped: 'invalid llm response' };
239
- }
240
-
241
- const memories = parsed.memories ?? [];
242
- let encoded = 0;
243
- for (const mem of memories) {
244
- if (!mem.content || !mem.source) continue;
245
- try {
246
- await this.encode({
247
- content: mem.content,
248
- source: mem.source,
249
- salience: mem.salience,
250
- tags: mem.tags,
251
- private: mem.private ?? false,
252
- affect: mem.affect ?? undefined,
253
- });
254
- encoded++;
255
- } catch (err) {
256
- this.emit('error', err);
257
- }
258
- }
259
-
260
- return { encoded, memories };
261
- }
262
-
263
- /**
264
- * @param {EncodeParams[]} paramsList
265
- * @returns {Promise<string[]>}
266
- */
267
- async encodeBatch(paramsList) {
268
- await this._ensureMigrated();
269
- const ids = [];
270
- for (const params of paramsList) {
271
- const id = await encodeEpisode(this.db, this.embeddingProvider, params);
272
- ids.push(id);
273
- this.emit('encode', { id, ...params });
274
- }
275
-
276
- for (let i = 0; i < ids.length; i++) {
277
- this._emitValidation(ids[i], paramsList[i]);
278
- }
279
-
280
- return ids;
281
- }
282
-
283
- /**
284
- * @param {string} query
285
- * @param {RecallOptions} [options]
286
- * @returns {Promise<RecallResult[]>}
287
- */
288
- async recall(query, options = {}) {
289
- await this._ensureMigrated();
290
- return recallFn(this.db, this.embeddingProvider, query, {
291
- ...options,
292
- confidenceConfig: this._recallConfig(options),
293
- });
294
- }
295
-
296
- /**
297
- * @param {string} query
298
- * @param {RecallOptions} [options]
299
- * @returns {AsyncGenerator<RecallResult>}
300
- */
301
- async *recallStream(query, options = {}) {
302
- await this._ensureMigrated();
303
- yield* recallStreamFn(this.db, this.embeddingProvider, query, {
304
- ...options,
305
- confidenceConfig: this._recallConfig(options),
306
- });
307
- }
308
-
309
- _recallConfig(options) {
310
- let config = options.confidenceConfig ?? this.confidenceConfig;
311
- if (this.contextConfig.enabled && options.context) {
312
- config = { ...config, retrievalContext: options.context };
313
- }
314
- if (this.affectConfig.enabled && options.mood) {
315
- config = { ...config, retrievalMood: options.mood };
316
- }
317
- return config;
318
- }
319
-
320
- /**
321
- * @param {{ minClusterSize?: number, similarityThreshold?: number, extractPrinciple?: Function, llmProvider?: import('./llm.js').LLMProvider }} [options]
322
- * @returns {Promise<ConsolidationResult>}
323
- */
324
- async consolidate(options = {}) {
325
- await this._ensureMigrated();
326
- const result = await runConsolidation(this.db, this.embeddingProvider, {
327
- minClusterSize: options.minClusterSize || this.consolidationConfig.minEpisodes,
328
- similarityThreshold: options.similarityThreshold || 0.80,
329
- extractPrinciple: options.extractPrinciple,
330
- llmProvider: options.llmProvider || this.llmProvider,
331
- });
332
- const run = this.db.prepare('SELECT status FROM consolidation_runs WHERE id = ?').get(result.runId);
333
- const output = { ...result, status: run?.status || 'completed' };
334
- this.emit('consolidation', output);
335
- return output;
336
- }
337
-
338
- /**
339
- * @param {{ dormantThreshold?: number }} [options]
340
- * @returns {{ totalEvaluated: number, transitionedToDormant: number, timestamp: string }}
341
- */
342
- decay(options = {}) {
343
- const result = applyDecay(this.db, {
344
- dormantThreshold: options.dormantThreshold || this.decayConfig.dormantThreshold,
345
- halfLives: options.halfLives ?? this.confidenceConfig.halfLives,
346
- });
347
- this.emit('decay', result);
348
- return result;
349
- }
350
-
351
- /**
352
- * @param {string} runId
353
- * @returns {{ rolledBackMemories: number, restoredEpisodes: number }}
354
- */
355
- rollback(runId) {
356
- const result = rollbackConsolidation(this.db, runId);
357
- this.emit('rollback', { runId, ...result });
358
- return result;
359
- }
360
-
361
- /**
362
- * @param {string} contradictionId
363
- * @returns {Promise<TruthResolution>}
364
- */
365
- async resolveTruth(contradictionId) {
366
- if (!this.llmProvider) {
367
- throw new Error('resolveTruth requires an LLM provider');
368
- }
369
-
370
- const contradiction = this.db.prepare(
371
- 'SELECT * FROM contradictions WHERE id = ?'
372
- ).get(contradictionId);
373
- if (!contradiction) throw new Error(`Contradiction not found: ${contradictionId}`);
374
-
375
- const claimA = this._loadClaimContent(contradiction.claim_a_id, contradiction.claim_a_type);
376
- const claimB = this._loadClaimContent(contradiction.claim_b_id, contradiction.claim_b_type);
377
-
378
- const messages = buildContextResolutionPrompt(claimA, claimB);
379
- const result = await this.llmProvider.json(messages);
380
-
381
- const now = new Date().toISOString();
382
- const newState = result.resolution === 'context_dependent' ? 'context_dependent' : 'resolved';
383
- this.db.prepare(`
384
- UPDATE contradictions SET state = ?, resolution = ?, resolved_at = ?
385
- WHERE id = ?
386
- `).run(newState, JSON.stringify(result), now, contradictionId);
387
-
388
- if (result.resolution === 'a_wins' && contradiction.claim_a_type === 'semantic') {
389
- this.db.prepare("UPDATE semantics SET state = 'active' WHERE id = ?").run(contradiction.claim_a_id);
390
- }
391
- if (result.resolution === 'b_wins' && contradiction.claim_b_type === 'semantic') {
392
- this.db.prepare("UPDATE semantics SET state = 'active' WHERE id = ?").run(contradiction.claim_b_id);
393
- }
394
- if (result.resolution === 'context_dependent') {
395
- if (contradiction.claim_a_type === 'semantic' && result.conditions) {
396
- this.db.prepare("UPDATE semantics SET state = 'context_dependent', conditions = ? WHERE id = ?")
397
- .run(JSON.stringify(result.conditions), contradiction.claim_a_id);
398
- }
399
- }
400
-
401
- return result;
402
- }
403
-
404
- _loadClaimContent(claimId, claimType) {
405
- if (claimType === 'semantic') {
406
- const row = this.db.prepare('SELECT content FROM semantics WHERE id = ?').get(claimId);
407
- if (!row) throw new Error(`Semantic memory not found: ${claimId}`);
408
- return row.content;
409
- } else if (claimType === 'episodic') {
410
- const row = this.db.prepare('SELECT content FROM episodes WHERE id = ?').get(claimId);
411
- if (!row) throw new Error(`Episode not found: ${claimId}`);
412
- return row.content;
413
- }
414
- throw new Error(`Unknown claim type: ${claimType}`);
415
- }
416
-
417
- /** @returns {Array<{ id: string, input_episode_ids: string, output_memory_ids: string, started_at: string, completed_at: string, status: string }>} */
418
- consolidationHistory() {
419
- return getConsolidationHistory(this.db);
420
- }
421
-
422
- /** @returns {IntrospectResult} */
423
- introspect() {
424
- return introspectFn(this.db);
425
- }
426
-
427
- memoryStatus() {
428
- const episodes = this.db.prepare('SELECT COUNT(*) as c FROM episodes').get().c;
429
- const semantics = this.db.prepare('SELECT COUNT(*) as c FROM semantics').get().c;
430
- const procedures = this.db.prepare('SELECT COUNT(*) as c FROM procedures').get().c;
431
- const searchableEpisodes = this.db.prepare('SELECT COUNT(*) as c FROM episodes WHERE embedding IS NOT NULL').get().c;
432
- const searchableSemantics = this.db.prepare('SELECT COUNT(*) as c FROM semantics WHERE embedding IS NOT NULL').get().c;
433
- const searchableProcedures = this.db.prepare('SELECT COUNT(*) as c FROM procedures WHERE embedding IS NOT NULL').get().c;
434
-
435
- let vecEpisodes = 0, vecSemantics = 0, vecProcedures = 0;
436
- try {
437
- vecEpisodes = this.db.prepare('SELECT COUNT(*) as c FROM vec_episodes').get().c;
438
- vecSemantics = this.db.prepare('SELECT COUNT(*) as c FROM vec_semantics').get().c;
439
- vecProcedures = this.db.prepare('SELECT COUNT(*) as c FROM vec_procedures').get().c;
440
- } catch {
441
- // vec tables may not exist if no dimensions configured
442
- }
443
-
444
- const dimsRow = this.db.prepare("SELECT value FROM audrey_config WHERE key = 'dimensions'").get();
445
- const dimensions = dimsRow ? parseInt(dimsRow.value, 10) : null;
446
- const versionRow = this.db.prepare("SELECT value FROM audrey_config WHERE key = 'schema_version'").get();
447
- const schemaVersion = versionRow ? parseInt(versionRow.value, 10) : 0;
448
-
449
- const device = this.embeddingProvider._actualDevice
450
- ?? this.embeddingProvider.device
451
- ?? null;
452
-
453
- const healthy = episodes === vecEpisodes
454
- && semantics === vecSemantics
455
- && procedures === vecProcedures;
456
- const reembedRecommended = searchableEpisodes !== vecEpisodes
457
- || searchableSemantics !== vecSemantics
458
- || searchableProcedures !== vecProcedures;
459
-
460
- return {
461
- episodes,
462
- vec_episodes: vecEpisodes,
463
- semantics,
464
- vec_semantics: vecSemantics,
465
- procedures,
466
- vec_procedures: vecProcedures,
467
- searchable_episodes: searchableEpisodes,
468
- searchable_semantics: searchableSemantics,
469
- searchable_procedures: searchableProcedures,
470
- dimensions,
471
- schema_version: schemaVersion,
472
- device,
473
- healthy,
474
- reembed_recommended: reembedRecommended,
475
- };
476
- }
477
-
478
- async greeting({ context, recentLimit = 10, principleLimit = 5, identityLimit = 5 } = {}) {
479
- const recent = this.db.prepare(
480
- 'SELECT id, content, source, tags, salience, created_at FROM episodes WHERE "private" = 0 ORDER BY created_at DESC LIMIT ?'
481
- ).all(recentLimit);
482
-
483
- const principles = this.db.prepare(
484
- 'SELECT id, content, salience, created_at FROM semantics WHERE state = ? ORDER BY salience DESC LIMIT ?'
485
- ).all('active', principleLimit);
486
-
487
- const identity = this.db.prepare(
488
- 'SELECT id, content, tags, salience, created_at FROM episodes WHERE "private" = 1 ORDER BY created_at DESC LIMIT ?'
489
- ).all(identityLimit);
490
-
491
- const unresolved = this.db.prepare(
492
- "SELECT id, content, tags, salience, created_at FROM episodes WHERE tags LIKE '%unresolved%' AND salience > 0.3 ORDER BY created_at DESC LIMIT 10"
493
- ).all();
494
-
495
- const rawAffectRows = this.db.prepare(
496
- "SELECT affect FROM episodes WHERE affect IS NOT NULL AND affect != '{}' ORDER BY created_at DESC LIMIT 20"
497
- ).all();
498
-
499
- const affectParsed = rawAffectRows
500
- .map(r => { try { return JSON.parse(r.affect); } catch { return null; } })
501
- .filter(a => a && a.valence !== undefined);
502
-
503
- let mood;
504
- if (affectParsed.length === 0) {
505
- mood = { valence: 0, arousal: 0, samples: 0 };
506
- } else {
507
- const sumV = affectParsed.reduce((s, a) => s + a.valence, 0);
508
- const sumA = affectParsed.reduce((s, a) => s + (a.arousal ?? 0), 0);
509
- mood = {
510
- valence: sumV / affectParsed.length,
511
- arousal: sumA / affectParsed.length,
512
- samples: affectParsed.length,
513
- };
514
- }
515
-
516
- const result = { recent, principles, mood, unresolved, identity };
517
-
518
- if (context) {
519
- result.contextual = await this.recall(context, { limit: 5, includePrivate: true });
520
- }
521
-
522
- return result;
523
- }
524
-
525
- async dream(options = {}) {
526
- await this._ensureMigrated();
527
-
528
- const consolidation = await this.consolidate({
529
- minClusterSize: options.minClusterSize,
530
- similarityThreshold: options.similarityThreshold,
531
- });
532
-
533
- const decay = this.decay({
534
- dormantThreshold: options.dormantThreshold,
535
- });
536
-
537
- const stats = this.introspect();
538
-
539
- const result = {
540
- consolidation,
541
- decay,
542
- stats,
543
- };
544
-
545
- this.emit('dream', result);
546
- return result;
547
- }
548
-
549
- export() {
550
- return exportMemories(this.db);
551
- }
552
-
553
- async import(snapshot) {
554
- return importMemories(this.db, this.embeddingProvider, snapshot);
555
- }
556
-
557
- startAutoConsolidate(intervalMs, options = {}) {
558
- if (intervalMs < 1000) {
559
- throw new Error('Auto-consolidation interval must be at least 1000ms');
560
- }
561
- if (this._autoConsolidateTimer) {
562
- throw new Error('Auto-consolidation is already running');
563
- }
564
- this._autoConsolidateTimer = setInterval(() => {
565
- this.consolidate(options).catch(err => this.emit('error', err));
566
- }, intervalMs);
567
- }
568
-
569
- stopAutoConsolidate() {
570
- if (this._autoConsolidateTimer) {
571
- clearInterval(this._autoConsolidateTimer);
572
- this._autoConsolidateTimer = null;
573
- }
574
- }
575
-
576
- suggestConsolidationParams() {
577
- return suggestParamsFn(this.db);
578
- }
579
-
580
- forget(id, options = {}) {
581
- const result = forgetMemory(this.db, id, options);
582
- this.emit('forget', result);
583
- return result;
584
- }
585
-
586
- async forgetByQuery(query, options = {}) {
587
- await this._ensureMigrated();
588
- const result = await forgetByQueryFn(this.db, this.embeddingProvider, query, options);
589
- if (result) this.emit('forget', result);
590
- return result;
591
- }
592
-
593
- purge() {
594
- const result = purgeMemories(this.db);
595
- this.emit('purge', result);
596
- return result;
597
- }
598
-
599
- /** @returns {void} */
600
- close() {
601
- this.stopAutoConsolidate();
602
- closeDatabase(this.db);
603
- }
604
- }
package/src/causal.js DELETED
@@ -1,95 +0,0 @@
1
- import { generateId } from './ulid.js';
2
- import { buildCausalArticulationPrompt } from './prompts.js';
3
-
4
- /**
5
- * @param {import('better-sqlite3').Database} db
6
- * @param {{ causeId: string, effectId: string, linkType?: string, mechanism?: string, confidence?: number }} params
7
- * @returns {string}
8
- */
9
- export function addCausalLink(db, { causeId, effectId, linkType = 'causal', mechanism, confidence }) {
10
- const id = generateId();
11
- const now = new Date().toISOString();
12
-
13
- db.prepare(`
14
- INSERT INTO causal_links (id, cause_id, effect_id, link_type, mechanism, confidence, created_at)
15
- VALUES (?, ?, ?, ?, ?, ?, ?)
16
- `).run(id, causeId, effectId, linkType, mechanism, confidence, now);
17
-
18
- return id;
19
- }
20
-
21
- /**
22
- * @param {import('better-sqlite3').Database} db
23
- * @param {string} memoryId
24
- * @param {{ depth?: number }} [options]
25
- * @returns {Object[]}
26
- */
27
- export function getCausalChain(db, memoryId, options = {}) {
28
- const { depth = 10 } = options;
29
- const results = [];
30
- const visited = new Set();
31
- const queue = [memoryId];
32
- let currentDepth = 0;
33
-
34
- while (queue.length > 0 && currentDepth < depth) {
35
- const nextQueue = [];
36
- for (const nodeId of queue) {
37
- if (visited.has(nodeId)) continue;
38
- visited.add(nodeId);
39
-
40
- const links = db.prepare(
41
- 'SELECT * FROM causal_links WHERE cause_id = ?'
42
- ).all(nodeId);
43
-
44
- for (const link of links) {
45
- if (!visited.has(link.effect_id)) {
46
- results.push(link);
47
- nextQueue.push(link.effect_id);
48
- }
49
- }
50
- }
51
- queue.length = 0;
52
- queue.push(...nextQueue);
53
- currentDepth++;
54
- }
55
-
56
- return results;
57
- }
58
-
59
- /**
60
- * @param {import('better-sqlite3').Database} db
61
- * @param {import('./llm.js').LLMProvider} llmProvider
62
- * @param {{ id: string, content: string, source: string }} cause
63
- * @param {{ id: string, content: string, source: string }} effect
64
- * @returns {Promise<{ linkId: string|null, mechanism: string, linkType: string, confidence: number, spurious: boolean }>}
65
- */
66
- export async function articulateCausalLink(db, llmProvider, cause, effect) {
67
- const messages = buildCausalArticulationPrompt(cause, effect);
68
- const result = await llmProvider.json(messages);
69
-
70
- if (result.spurious) {
71
- return {
72
- linkId: null,
73
- mechanism: result.mechanism,
74
- linkType: result.linkType,
75
- confidence: result.confidence,
76
- spurious: true,
77
- };
78
- }
79
-
80
- const linkId = addCausalLink(db, {
81
- causeId: cause.id,
82
- effectId: effect.id,
83
- linkType: result.linkType || 'correlational',
84
- mechanism: result.mechanism,
85
- confidence: result.confidence,
86
- });
87
-
88
- return {
89
- linkId,
90
- mechanism: result.mechanism,
91
- linkType: result.linkType,
92
- confidence: result.confidence,
93
- spurious: false,
94
- };
95
- }