audrey 0.17.0 → 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 (191) hide show
  1. package/README.md +129 -374
  2. package/dist/mcp-server/config.d.ts +20 -0
  3. package/dist/mcp-server/config.d.ts.map +1 -0
  4. package/dist/mcp-server/config.js +125 -0
  5. package/dist/mcp-server/config.js.map +1 -0
  6. package/dist/mcp-server/index.d.ts +100 -0
  7. package/dist/mcp-server/index.d.ts.map +1 -0
  8. package/dist/mcp-server/index.js +1113 -0
  9. package/dist/mcp-server/index.js.map +1 -0
  10. package/dist/src/adaptive.d.ts +7 -0
  11. package/dist/src/adaptive.d.ts.map +1 -0
  12. package/dist/src/adaptive.js +49 -0
  13. package/dist/src/adaptive.js.map +1 -0
  14. package/dist/src/affect.d.ts +19 -0
  15. package/dist/src/affect.d.ts.map +1 -0
  16. package/dist/src/affect.js +72 -0
  17. package/dist/src/affect.js.map +1 -0
  18. package/dist/src/audrey.d.ts +140 -0
  19. package/dist/src/audrey.d.ts.map +1 -0
  20. package/dist/src/audrey.js +564 -0
  21. package/dist/src/audrey.js.map +1 -0
  22. package/dist/src/capsule.d.ts +68 -0
  23. package/dist/src/capsule.d.ts.map +1 -0
  24. package/dist/src/capsule.js +311 -0
  25. package/dist/src/capsule.js.map +1 -0
  26. package/dist/src/causal.d.ts +28 -0
  27. package/dist/src/causal.d.ts.map +1 -0
  28. package/dist/src/causal.js +65 -0
  29. package/dist/src/causal.js.map +1 -0
  30. package/dist/src/confidence.d.ts +12 -0
  31. package/dist/src/confidence.d.ts.map +1 -0
  32. package/dist/src/confidence.js +63 -0
  33. package/dist/src/confidence.js.map +1 -0
  34. package/dist/src/consolidate.d.ts +8 -0
  35. package/dist/src/consolidate.d.ts.map +1 -0
  36. package/dist/src/consolidate.js +218 -0
  37. package/dist/src/consolidate.js.map +1 -0
  38. package/dist/src/context.d.ts +3 -0
  39. package/dist/src/context.d.ts.map +1 -0
  40. package/dist/src/context.js +19 -0
  41. package/dist/src/context.js.map +1 -0
  42. package/dist/src/db.d.ts +12 -0
  43. package/dist/src/db.d.ts.map +1 -0
  44. package/dist/src/db.js +380 -0
  45. package/dist/src/db.js.map +1 -0
  46. package/dist/src/decay.d.ts +7 -0
  47. package/dist/src/decay.d.ts.map +1 -0
  48. package/dist/src/decay.js +68 -0
  49. package/dist/src/decay.js.map +1 -0
  50. package/dist/src/embedding.d.ts +57 -0
  51. package/dist/src/embedding.d.ts.map +1 -0
  52. package/dist/src/embedding.js +254 -0
  53. package/dist/src/embedding.js.map +1 -0
  54. package/dist/src/encode.d.ts +15 -0
  55. package/dist/src/encode.d.ts.map +1 -0
  56. package/dist/src/encode.js +36 -0
  57. package/dist/src/encode.js.map +1 -0
  58. package/dist/src/events.d.ts +69 -0
  59. package/dist/src/events.d.ts.map +1 -0
  60. package/dist/src/events.js +149 -0
  61. package/dist/src/events.js.map +1 -0
  62. package/dist/src/export.d.ts +3 -0
  63. package/dist/src/export.d.ts.map +1 -0
  64. package/dist/src/export.js +46 -0
  65. package/dist/src/export.js.map +1 -0
  66. package/dist/src/forget.d.ts +11 -0
  67. package/dist/src/forget.d.ts.map +1 -0
  68. package/dist/src/forget.js +105 -0
  69. package/dist/src/forget.js.map +1 -0
  70. package/dist/src/fts.d.ts +34 -0
  71. package/dist/src/fts.d.ts.map +1 -0
  72. package/dist/src/fts.js +117 -0
  73. package/dist/src/fts.js.map +1 -0
  74. package/dist/src/hybrid-recall.d.ts +37 -0
  75. package/dist/src/hybrid-recall.d.ts.map +1 -0
  76. package/dist/src/hybrid-recall.js +213 -0
  77. package/dist/src/hybrid-recall.js.map +1 -0
  78. package/dist/src/import.d.ts +4 -0
  79. package/dist/src/import.d.ts.map +1 -0
  80. package/dist/src/import.js +127 -0
  81. package/dist/src/import.js.map +1 -0
  82. package/dist/src/index.d.ts +22 -0
  83. package/dist/src/index.d.ts.map +1 -0
  84. package/{src → dist/src}/index.js +5 -13
  85. package/dist/src/index.js.map +1 -0
  86. package/dist/src/interference.d.ts +13 -0
  87. package/dist/src/interference.d.ts.map +1 -0
  88. package/dist/src/interference.js +45 -0
  89. package/dist/src/interference.js.map +1 -0
  90. package/dist/src/introspect.d.ts +4 -0
  91. package/dist/src/introspect.d.ts.map +1 -0
  92. package/dist/src/introspect.js +40 -0
  93. package/dist/src/introspect.js.map +1 -0
  94. package/dist/src/llm.d.ts +38 -0
  95. package/dist/src/llm.d.ts.map +1 -0
  96. package/dist/src/llm.js +167 -0
  97. package/dist/src/llm.js.map +1 -0
  98. package/dist/src/migrate.d.ts +6 -0
  99. package/dist/src/migrate.d.ts.map +1 -0
  100. package/dist/src/migrate.js +51 -0
  101. package/dist/src/migrate.js.map +1 -0
  102. package/dist/src/promote.d.ts +40 -0
  103. package/dist/src/promote.d.ts.map +1 -0
  104. package/dist/src/promote.js +200 -0
  105. package/dist/src/promote.js.map +1 -0
  106. package/dist/src/prompts.d.ts +16 -0
  107. package/dist/src/prompts.d.ts.map +1 -0
  108. package/{src → dist/src}/prompts.js +172 -203
  109. package/dist/src/prompts.js.map +1 -0
  110. package/dist/src/recall.d.ts +9 -0
  111. package/dist/src/recall.d.ts.map +1 -0
  112. package/dist/src/recall.js +432 -0
  113. package/dist/src/recall.js.map +1 -0
  114. package/dist/src/redact.d.ts +27 -0
  115. package/dist/src/redact.d.ts.map +1 -0
  116. package/dist/src/redact.js +228 -0
  117. package/dist/src/redact.js.map +1 -0
  118. package/dist/src/rollback.d.ts +8 -0
  119. package/dist/src/rollback.d.ts.map +1 -0
  120. package/dist/src/rollback.js +33 -0
  121. package/dist/src/rollback.js.map +1 -0
  122. package/dist/src/routes.d.ts +7 -0
  123. package/dist/src/routes.d.ts.map +1 -0
  124. package/dist/src/routes.js +226 -0
  125. package/dist/src/routes.js.map +1 -0
  126. package/dist/src/rules-compiler.d.ts +20 -0
  127. package/dist/src/rules-compiler.d.ts.map +1 -0
  128. package/dist/src/rules-compiler.js +143 -0
  129. package/dist/src/rules-compiler.js.map +1 -0
  130. package/dist/src/server.d.ts +12 -0
  131. package/dist/src/server.d.ts.map +1 -0
  132. package/dist/src/server.js +22 -0
  133. package/dist/src/server.js.map +1 -0
  134. package/dist/src/tool-trace.d.ts +37 -0
  135. package/dist/src/tool-trace.d.ts.map +1 -0
  136. package/dist/src/tool-trace.js +142 -0
  137. package/dist/src/tool-trace.js.map +1 -0
  138. package/dist/src/types.d.ts +446 -0
  139. package/dist/src/types.d.ts.map +1 -0
  140. package/dist/src/types.js +6 -0
  141. package/dist/src/types.js.map +1 -0
  142. package/dist/src/ulid.d.ts +3 -0
  143. package/dist/src/ulid.d.ts.map +1 -0
  144. package/dist/src/ulid.js +11 -0
  145. package/dist/src/ulid.js.map +1 -0
  146. package/dist/src/utils.d.ts +10 -0
  147. package/dist/src/utils.d.ts.map +1 -0
  148. package/dist/src/utils.js +41 -0
  149. package/dist/src/utils.js.map +1 -0
  150. package/dist/src/validate.d.ts +22 -0
  151. package/dist/src/validate.d.ts.map +1 -0
  152. package/dist/src/validate.js +109 -0
  153. package/dist/src/validate.js.map +1 -0
  154. package/docs/production-readiness.md +28 -0
  155. package/examples/fintech-ops-demo.js +1 -1
  156. package/examples/healthcare-ops-demo.js +1 -1
  157. package/examples/stripe-demo.js +1 -1
  158. package/package.json +34 -13
  159. package/benchmarks/baselines.js +0 -169
  160. package/benchmarks/cases.js +0 -421
  161. package/benchmarks/reference-results.js +0 -70
  162. package/benchmarks/report.js +0 -255
  163. package/benchmarks/run.js +0 -514
  164. package/mcp-server/config.js +0 -133
  165. package/mcp-server/index.js +0 -1265
  166. package/mcp-server/serve.js +0 -482
  167. package/src/adaptive.js +0 -53
  168. package/src/affect.js +0 -64
  169. package/src/audrey.js +0 -642
  170. package/src/causal.js +0 -95
  171. package/src/confidence.js +0 -120
  172. package/src/consolidate.js +0 -281
  173. package/src/context.js +0 -15
  174. package/src/db.js +0 -391
  175. package/src/decay.js +0 -84
  176. package/src/embedding.js +0 -260
  177. package/src/encode.js +0 -69
  178. package/src/export.js +0 -67
  179. package/src/forget.js +0 -111
  180. package/src/fts.js +0 -134
  181. package/src/import.js +0 -273
  182. package/src/interference.js +0 -51
  183. package/src/introspect.js +0 -48
  184. package/src/llm.js +0 -249
  185. package/src/migrate.js +0 -58
  186. package/src/recall.js +0 -573
  187. package/src/rollback.js +0 -42
  188. package/src/ulid.js +0 -18
  189. package/src/utils.js +0 -63
  190. package/src/validate.js +0 -172
  191. package/types/index.d.ts +0 -434
package/src/embedding.js DELETED
@@ -1,260 +0,0 @@
1
- import { createHash } from 'node:crypto';
2
- import { describeHttpError, requireApiKey } from './utils.js';
3
-
4
- /**
5
- * @typedef {Object} EmbeddingProvider
6
- * @property {number} dimensions
7
- * @property {string} modelName
8
- * @property {string} modelVersion
9
- * @property {(text: string) => Promise<number[]>} embed
10
- * @property {(texts: string[]) => Promise<number[][]>} embedBatch
11
- * @property {(vector: number[]) => Buffer} vectorToBuffer
12
- * @property {(buffer: Buffer) => number[]} bufferToVector
13
- */
14
-
15
- /** @implements {EmbeddingProvider} */
16
- export class MockEmbeddingProvider {
17
- constructor({ dimensions = 64 } = {}) {
18
- this.dimensions = dimensions;
19
- this.modelName = 'mock-embedding';
20
- this.modelVersion = '1.0.0';
21
- }
22
-
23
- async embed(text) {
24
- const hash = createHash('sha256').update(text).digest();
25
- const vector = new Array(this.dimensions);
26
- for (let i = 0; i < this.dimensions; i++) {
27
- vector[i] = (hash[i % hash.length] / 255) * 2 - 1;
28
- }
29
- const magnitude = Math.sqrt(vector.reduce((sum, v) => sum + v * v, 0));
30
- return vector.map(v => v / magnitude);
31
- }
32
-
33
- async embedBatch(texts) {
34
- return Promise.all(texts.map(t => this.embed(t)));
35
- }
36
-
37
- vectorToBuffer(vector) {
38
- return Buffer.from(new Float32Array(vector).buffer);
39
- }
40
-
41
- bufferToVector(buffer) {
42
- return Array.from(new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 4));
43
- }
44
- }
45
-
46
- /** @implements {EmbeddingProvider} */
47
- export class OpenAIEmbeddingProvider {
48
- constructor({ apiKey, model = 'text-embedding-3-small', dimensions = 1536, timeout = 30000 } = {}) {
49
- this.apiKey = apiKey || process.env.OPENAI_API_KEY;
50
- this.model = model;
51
- this.dimensions = dimensions;
52
- this.timeout = timeout;
53
- this.modelName = model;
54
- this.modelVersion = 'latest';
55
- }
56
-
57
- async embed(text) {
58
- requireApiKey(this.apiKey, 'OpenAI embedding', 'OPENAI_API_KEY');
59
- const controller = new AbortController();
60
- const timer = setTimeout(() => controller.abort(), this.timeout);
61
- try {
62
- const response = await fetch('https://api.openai.com/v1/embeddings', {
63
- method: 'POST',
64
- headers: {
65
- 'Authorization': `Bearer ${this.apiKey}`,
66
- 'Content-Type': 'application/json',
67
- },
68
- body: JSON.stringify({ input: text, model: this.model, dimensions: this.dimensions }),
69
- signal: controller.signal,
70
- });
71
- if (!response.ok) throw new Error(`OpenAI embedding failed: ${await describeHttpError(response)}`);
72
- const data = await response.json();
73
- return data.data[0].embedding;
74
- } finally {
75
- clearTimeout(timer);
76
- }
77
- }
78
-
79
- async embedBatch(texts) {
80
- requireApiKey(this.apiKey, 'OpenAI embedding', 'OPENAI_API_KEY');
81
- const controller = new AbortController();
82
- const timer = setTimeout(() => controller.abort(), this.timeout);
83
- try {
84
- const response = await fetch('https://api.openai.com/v1/embeddings', {
85
- method: 'POST',
86
- headers: {
87
- 'Authorization': `Bearer ${this.apiKey}`,
88
- 'Content-Type': 'application/json',
89
- },
90
- body: JSON.stringify({ input: texts, model: this.model, dimensions: this.dimensions }),
91
- signal: controller.signal,
92
- });
93
- if (!response.ok) throw new Error(`OpenAI embedding failed: ${await describeHttpError(response)}`);
94
- const data = await response.json();
95
- return data.data.map(d => d.embedding);
96
- } finally {
97
- clearTimeout(timer);
98
- }
99
- }
100
-
101
- vectorToBuffer(vector) {
102
- return Buffer.from(new Float32Array(vector).buffer);
103
- }
104
-
105
- bufferToVector(buffer) {
106
- return Array.from(new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 4));
107
- }
108
- }
109
-
110
- /** @implements {EmbeddingProvider} */
111
- export class LocalEmbeddingProvider {
112
- constructor({ model = 'Xenova/all-MiniLM-L6-v2', device = 'gpu', batchSize = 64, pipelineFactory = null } = {}) {
113
- this.model = model;
114
- this.dimensions = 384;
115
- this.modelName = model;
116
- this.modelVersion = '1.0.0';
117
- this.device = device;
118
- this.batchSize = batchSize;
119
- this.pipelineFactory = pipelineFactory;
120
- this._pipeline = null;
121
- this._readyPromise = null;
122
- this._actualDevice = null;
123
- }
124
-
125
- ready() {
126
- if (!this._readyPromise) {
127
- this._readyPromise = (async () => {
128
- const pipeline = this.pipelineFactory || (await import('@huggingface/transformers')).pipeline;
129
- try {
130
- this._pipeline = await pipeline('feature-extraction', this.model, {
131
- dtype: 'fp32', device: this.device,
132
- });
133
- this._actualDevice = this.device;
134
- } catch {
135
- this._pipeline = await pipeline('feature-extraction', this.model, {
136
- dtype: 'fp32', device: 'cpu',
137
- });
138
- this._actualDevice = 'cpu';
139
- }
140
- })();
141
- }
142
- return this._readyPromise;
143
- }
144
-
145
- async embed(text) {
146
- await this.ready();
147
- const output = await this._pipeline(text, { pooling: 'mean', normalize: true });
148
- return Array.from(output.data);
149
- }
150
-
151
- async embedBatch(texts) {
152
- if (texts.length === 0) return [];
153
- await this.ready();
154
- const results = [];
155
- for (let i = 0; i < texts.length; i += this.batchSize) {
156
- const chunk = texts.slice(i, i + this.batchSize);
157
- const output = await this._pipeline(chunk, { pooling: 'mean', normalize: true });
158
- results.push(...output.tolist());
159
- }
160
- return results;
161
- }
162
-
163
- vectorToBuffer(vector) {
164
- return Buffer.from(new Float32Array(vector).buffer);
165
- }
166
-
167
- bufferToVector(buffer) {
168
- return Array.from(new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 4));
169
- }
170
- }
171
-
172
- /** @implements {EmbeddingProvider} */
173
- export class GeminiEmbeddingProvider {
174
- constructor({ apiKey, model = 'gemini-embedding-001', timeout = 30000 } = {}) {
175
- this.apiKey = apiKey || process.env.GOOGLE_API_KEY;
176
- this.model = model;
177
- this.dimensions = 3072;
178
- this.timeout = timeout;
179
- this.modelName = model;
180
- this.modelVersion = 'latest';
181
- }
182
-
183
- async embed(text) {
184
- requireApiKey(this.apiKey, 'Gemini embedding', 'GOOGLE_API_KEY');
185
- const controller = new AbortController();
186
- const timer = setTimeout(() => controller.abort(), this.timeout);
187
- try {
188
- const response = await fetch(
189
- `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:embedContent`,
190
- {
191
- method: 'POST',
192
- headers: { 'Content-Type': 'application/json', 'x-goog-api-key': this.apiKey },
193
- body: JSON.stringify({ model: `models/${this.model}`, content: { parts: [{ text }] } }),
194
- signal: controller.signal,
195
- }
196
- );
197
- if (!response.ok) throw new Error(`Gemini embedding failed: ${await describeHttpError(response)}`);
198
- const data = await response.json();
199
- return data.embedding.values;
200
- } finally {
201
- clearTimeout(timer);
202
- }
203
- }
204
-
205
- async embedBatch(texts) {
206
- if (texts.length === 0) return [];
207
- requireApiKey(this.apiKey, 'Gemini embedding', 'GOOGLE_API_KEY');
208
- const results = [];
209
- for (let i = 0; i < texts.length; i += 100) {
210
- const chunk = texts.slice(i, i + 100);
211
- const controller = new AbortController();
212
- const timer = setTimeout(() => controller.abort(), this.timeout);
213
- try {
214
- const response = await fetch(
215
- `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:batchEmbedContents`,
216
- {
217
- method: 'POST',
218
- headers: { 'Content-Type': 'application/json', 'x-goog-api-key': this.apiKey },
219
- body: JSON.stringify({
220
- requests: chunk.map(text => ({
221
- model: `models/${this.model}`,
222
- content: { parts: [{ text }] },
223
- })),
224
- }),
225
- signal: controller.signal,
226
- }
227
- );
228
- if (!response.ok) throw new Error(`Gemini batch embedding failed: ${await describeHttpError(response)}`);
229
- const data = await response.json();
230
- results.push(...data.embeddings.map(e => e.values));
231
- } finally {
232
- clearTimeout(timer);
233
- }
234
- }
235
- return results;
236
- }
237
-
238
- vectorToBuffer(vector) {
239
- return Buffer.from(new Float32Array(vector).buffer);
240
- }
241
-
242
- bufferToVector(buffer) {
243
- return Array.from(new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 4));
244
- }
245
- }
246
-
247
- export function createEmbeddingProvider(config) {
248
- switch (config.provider) {
249
- case 'mock':
250
- return new MockEmbeddingProvider(config);
251
- case 'openai':
252
- return new OpenAIEmbeddingProvider(config);
253
- case 'local':
254
- return new LocalEmbeddingProvider(config);
255
- case 'gemini':
256
- return new GeminiEmbeddingProvider(config);
257
- default:
258
- throw new Error(`Unknown embedding provider: ${config.provider}. Valid: mock, openai, local, gemini`);
259
- }
260
- }
package/src/encode.js DELETED
@@ -1,69 +0,0 @@
1
- import { generateId } from './ulid.js';
2
- import { sourceReliability } from './confidence.js';
3
- import { arousalSalienceBoost } from './affect.js';
4
- import { hasFTSTables, insertFTSEpisode } from './fts.js';
5
-
6
- /**
7
- * @param {import('better-sqlite3').Database} db
8
- * @param {import('./embedding.js').EmbeddingProvider} embeddingProvider
9
- * @param {{ content: string, source: string, salience?: number, causal?: { trigger?: string, consequence?: string }, tags?: string[], supersedes?: string, context?: object, affect?: object, arousalWeight?: number, private?: boolean }} params
10
- * @returns {Promise<string>}
11
- */
12
- export async function encodeEpisode(db, embeddingProvider, {
13
- content,
14
- source,
15
- salience = 0.5,
16
- causal,
17
- tags,
18
- supersedes,
19
- context = {},
20
- affect = {},
21
- arousalWeight = 0.3,
22
- private: isPrivate = false,
23
- agent = 'default',
24
- }) {
25
- if (!content || typeof content !== 'string') throw new Error('content must be a non-empty string');
26
- if (salience < 0 || salience > 1) throw new Error('salience must be between 0 and 1');
27
- if (tags && !Array.isArray(tags)) throw new Error('tags must be an array');
28
-
29
- const reliability = sourceReliability(source);
30
- const vector = await embeddingProvider.embed(content);
31
- const embeddingBuffer = embeddingProvider.vectorToBuffer(vector);
32
- const id = generateId();
33
- const now = new Date().toISOString();
34
-
35
- const boost = arousalSalienceBoost(affect.arousal);
36
- const effectiveSalience = Math.min(1.0, salience + (boost * arousalWeight));
37
-
38
- const insertAndLink = db.transaction(() => {
39
- db.prepare(`
40
- INSERT INTO episodes (
41
- id, content, embedding, source, source_reliability, salience, context, affect,
42
- tags, causal_trigger, causal_consequence, created_at,
43
- embedding_model, embedding_version, supersedes, "private", agent
44
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
45
- `).run(
46
- id, content, embeddingBuffer, source, reliability, effectiveSalience,
47
- JSON.stringify(context),
48
- JSON.stringify(affect),
49
- tags ? JSON.stringify(tags) : null,
50
- causal?.trigger || null, causal?.consequence || null,
51
- now, embeddingProvider.modelName, embeddingProvider.modelVersion,
52
- supersedes || null,
53
- isPrivate ? 1 : 0,
54
- agent,
55
- );
56
- db.prepare(
57
- 'INSERT INTO vec_episodes(id, embedding, source, consolidated) VALUES (?, ?, ?, ?)'
58
- ).run(id, embeddingBuffer, source, BigInt(0));
59
- if (supersedes) {
60
- db.prepare('UPDATE episodes SET superseded_by = ? WHERE id = ?').run(id, supersedes);
61
- }
62
- if (hasFTSTables(db)) {
63
- insertFTSEpisode(db, id, content, tags);
64
- }
65
- });
66
-
67
- insertAndLink();
68
- return id;
69
- }
package/src/export.js DELETED
@@ -1,67 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { fileURLToPath } from 'node:url';
3
- import { join, dirname } from 'node:path';
4
- import { safeJsonParse } from './utils.js';
5
-
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
- const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
8
-
9
- export function exportMemories(db) {
10
- const episodes = db.prepare(
11
- 'SELECT id, content, source, source_reliability, salience, context, affect, tags, causal_trigger, causal_consequence, created_at, embedding_model, embedding_version, supersedes, superseded_by, consolidated, "private" FROM episodes'
12
- ).all().map(ep => ({
13
- ...ep,
14
- tags: safeJsonParse(ep.tags, null),
15
- context: safeJsonParse(ep.context, null),
16
- affect: safeJsonParse(ep.affect, null),
17
- }));
18
-
19
- const semantics = db.prepare(
20
- 'SELECT id, content, state, conditions, evidence_episode_ids, evidence_count, supporting_count, contradicting_count, source_type_diversity, consolidation_checkpoint, embedding_model, embedding_version, consolidation_model, consolidation_prompt_hash, created_at, last_reinforced_at, retrieval_count, challenge_count, interference_count, salience FROM semantics'
21
- ).all().map(sem => ({
22
- ...sem,
23
- evidence_episode_ids: safeJsonParse(sem.evidence_episode_ids, []),
24
- }));
25
-
26
- const procedures = db.prepare(
27
- 'SELECT id, content, state, trigger_conditions, evidence_episode_ids, success_count, failure_count, embedding_model, embedding_version, created_at, last_reinforced_at, retrieval_count, interference_count, salience FROM procedures'
28
- ).all().map(proc => ({
29
- ...proc,
30
- evidence_episode_ids: safeJsonParse(proc.evidence_episode_ids, []),
31
- }));
32
-
33
- const causalLinks = db.prepare('SELECT * FROM causal_links').all();
34
-
35
- const contradictions = db.prepare(
36
- 'SELECT id, claim_a_id, claim_a_type, claim_b_id, claim_b_type, state, resolution, resolved_at, reopened_at, reopen_evidence_id, created_at FROM contradictions'
37
- ).all();
38
-
39
- const consolidationRuns = db.prepare(
40
- 'SELECT id, checkpoint_cursor, input_episode_ids, output_memory_ids, confidence_deltas, consolidation_model, consolidation_prompt_hash, started_at, completed_at, status FROM consolidation_runs'
41
- ).all().map(run => ({
42
- ...run,
43
- confidence_deltas: safeJsonParse(run.confidence_deltas, null),
44
- input_episode_ids: safeJsonParse(run.input_episode_ids, []),
45
- output_memory_ids: safeJsonParse(run.output_memory_ids, []),
46
- }));
47
-
48
- const consolidationMetrics = db.prepare(
49
- 'SELECT id, run_id, min_cluster_size, similarity_threshold, episodes_evaluated, clusters_found, principles_extracted, created_at FROM consolidation_metrics'
50
- ).all();
51
-
52
- const configRows = db.prepare('SELECT key, value FROM audrey_config').all();
53
- const config = Object.fromEntries(configRows.map(r => [r.key, r.value]));
54
-
55
- return {
56
- version: pkg.version,
57
- exportedAt: new Date().toISOString(),
58
- episodes,
59
- semantics,
60
- procedures,
61
- causalLinks,
62
- contradictions,
63
- consolidationRuns,
64
- consolidationMetrics,
65
- config,
66
- };
67
- }
package/src/forget.js DELETED
@@ -1,111 +0,0 @@
1
- export function forgetMemory(db, id, { purge = false } = {}) {
2
- const episode = db.prepare('SELECT id FROM episodes WHERE id = ?').get(id);
3
- if (episode) {
4
- if (purge) {
5
- db.prepare('DELETE FROM vec_episodes WHERE id = ?').run(id);
6
- db.prepare('DELETE FROM episodes WHERE id = ?').run(id);
7
- } else {
8
- db.prepare("UPDATE episodes SET superseded_by = 'forgotten' WHERE id = ?").run(id);
9
- db.prepare('DELETE FROM vec_episodes WHERE id = ?').run(id);
10
- }
11
- return { id, type: 'episodic', purged: purge };
12
- }
13
-
14
- const semantic = db.prepare('SELECT id FROM semantics WHERE id = ?').get(id);
15
- if (semantic) {
16
- if (purge) {
17
- db.prepare('DELETE FROM vec_semantics WHERE id = ?').run(id);
18
- db.prepare('DELETE FROM semantics WHERE id = ?').run(id);
19
- } else {
20
- db.prepare("UPDATE semantics SET state = 'superseded' WHERE id = ?").run(id);
21
- db.prepare('DELETE FROM vec_semantics WHERE id = ?').run(id);
22
- }
23
- return { id, type: 'semantic', purged: purge };
24
- }
25
-
26
- const procedure = db.prepare('SELECT id FROM procedures WHERE id = ?').get(id);
27
- if (procedure) {
28
- if (purge) {
29
- db.prepare('DELETE FROM vec_procedures WHERE id = ?').run(id);
30
- db.prepare('DELETE FROM procedures WHERE id = ?').run(id);
31
- } else {
32
- db.prepare("UPDATE procedures SET state = 'superseded' WHERE id = ?").run(id);
33
- db.prepare('DELETE FROM vec_procedures WHERE id = ?').run(id);
34
- }
35
- return { id, type: 'procedural', purged: purge };
36
- }
37
-
38
- throw new Error(`Memory not found: ${id}`);
39
- }
40
-
41
- export function purgeMemories(db) {
42
- const deadEpisodes = db.prepare(
43
- 'SELECT id FROM episodes WHERE superseded_by IS NOT NULL'
44
- ).all();
45
- const deadSemantics = db.prepare(
46
- "SELECT id FROM semantics WHERE state IN ('superseded', 'dormant', 'rolled_back')"
47
- ).all();
48
- const deadProcedures = db.prepare(
49
- "SELECT id FROM procedures WHERE state IN ('superseded', 'dormant', 'rolled_back')"
50
- ).all();
51
-
52
- const purgeAll = db.transaction(() => {
53
- for (const row of deadEpisodes) {
54
- db.prepare('DELETE FROM vec_episodes WHERE id = ?').run(row.id);
55
- db.prepare('DELETE FROM episodes WHERE id = ?').run(row.id);
56
- }
57
- for (const row of deadSemantics) {
58
- db.prepare('DELETE FROM vec_semantics WHERE id = ?').run(row.id);
59
- db.prepare('DELETE FROM semantics WHERE id = ?').run(row.id);
60
- }
61
- for (const row of deadProcedures) {
62
- db.prepare('DELETE FROM vec_procedures WHERE id = ?').run(row.id);
63
- db.prepare('DELETE FROM procedures WHERE id = ?').run(row.id);
64
- }
65
- });
66
-
67
- purgeAll();
68
-
69
- return {
70
- episodes: deadEpisodes.length,
71
- semantics: deadSemantics.length,
72
- procedures: deadProcedures.length,
73
- };
74
- }
75
-
76
- export async function forgetByQuery(db, embeddingProvider, query, { minSimilarity = 0.9, purge = false } = {}) {
77
- const queryVector = await embeddingProvider.embed(query);
78
- const queryBuffer = embeddingProvider.vectorToBuffer(queryVector);
79
-
80
- const candidates = [];
81
-
82
- const epMatch = db.prepare(`
83
- SELECT e.id, (1.0 - v.distance) AS similarity, 'episodic' AS type
84
- FROM vec_episodes v JOIN episodes e ON e.id = v.id
85
- WHERE v.embedding MATCH ? AND k = 1 AND e.superseded_by IS NULL
86
- `).get(queryBuffer);
87
- if (epMatch) candidates.push(epMatch);
88
-
89
- const semMatch = db.prepare(`
90
- SELECT s.id, (1.0 - v.distance) AS similarity, 'semantic' AS type
91
- FROM vec_semantics v JOIN semantics s ON s.id = v.id
92
- WHERE v.embedding MATCH ? AND k = 1 AND (v.state = 'active' OR v.state = 'context_dependent')
93
- `).get(queryBuffer);
94
- if (semMatch) candidates.push(semMatch);
95
-
96
- const procMatch = db.prepare(`
97
- SELECT p.id, (1.0 - v.distance) AS similarity, 'procedural' AS type
98
- FROM vec_procedures v JOIN procedures p ON p.id = v.id
99
- WHERE v.embedding MATCH ? AND k = 1 AND (v.state = 'active' OR v.state = 'context_dependent')
100
- `).get(queryBuffer);
101
- if (procMatch) candidates.push(procMatch);
102
-
103
- if (candidates.length === 0) return null;
104
-
105
- candidates.sort((a, b) => b.similarity - a.similarity);
106
- const best = candidates[0];
107
-
108
- if (best.similarity < minSimilarity) return null;
109
-
110
- return forgetMemory(db, best.id, { purge });
111
- }
package/src/fts.js DELETED
@@ -1,134 +0,0 @@
1
- /**
2
- * FTS5 full-text search for Audrey memories.
3
- * Creates virtual tables alongside vec0 tables for hybrid retrieval.
4
- */
5
-
6
- export function createFTSTables(db) {
7
- db.exec(`
8
- CREATE VIRTUAL TABLE IF NOT EXISTS fts_episodes
9
- USING fts5(id UNINDEXED, content, tags, tokenize='porter unicode61');
10
- CREATE VIRTUAL TABLE IF NOT EXISTS fts_semantics
11
- USING fts5(id UNINDEXED, content, tokenize='porter unicode61');
12
- CREATE VIRTUAL TABLE IF NOT EXISTS fts_procedures
13
- USING fts5(id UNINDEXED, content, tokenize='porter unicode61');
14
- `);
15
- }
16
-
17
- export function hasFTSTables(db) {
18
- const row = db.prepare(
19
- "SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='fts_episodes'"
20
- ).get();
21
- return row.c > 0;
22
- }
23
-
24
- export function insertFTSEpisode(db, id, content, tags) {
25
- db.prepare('INSERT OR REPLACE INTO fts_episodes(id, content, tags) VALUES (?, ?, ?)').run(
26
- id, content, tags ? (Array.isArray(tags) ? tags.join(' ') : tags) : ''
27
- );
28
- }
29
-
30
- export function insertFTSSemantic(db, id, content) {
31
- db.prepare('INSERT OR REPLACE INTO fts_semantics(id, content) VALUES (?, ?)').run(id, content);
32
- }
33
-
34
- export function insertFTSProcedure(db, id, content) {
35
- db.prepare('INSERT OR REPLACE INTO fts_procedures(id, content) VALUES (?, ?)').run(id, content);
36
- }
37
-
38
- export function deleteFTSEpisode(db, id) {
39
- db.prepare('DELETE FROM fts_episodes WHERE id = ?').run(id);
40
- }
41
-
42
- export function deleteFTSSemantic(db, id) {
43
- db.prepare('DELETE FROM fts_semantics WHERE id = ?').run(id);
44
- }
45
-
46
- export function deleteFTSProcedure(db, id) {
47
- db.prepare('DELETE FROM fts_procedures WHERE id = ?').run(id);
48
- }
49
-
50
- /**
51
- * Search episodes via FTS5 BM25.
52
- * Returns [{ id, content, rank }] sorted by relevance.
53
- */
54
- export function searchFTSEpisodes(db, query, limit = 30, agentFilter = null) {
55
- const agentClause = agentFilter ? 'AND e.agent = ?' : '';
56
- const params = agentFilter ? [query, agentFilter, limit] : [query, limit];
57
- return db.prepare(`
58
- SELECT f.id, f.content, e.agent, bm25(fts_episodes) AS rank
59
- FROM fts_episodes f
60
- JOIN episodes e ON e.id = f.id
61
- WHERE fts_episodes MATCH ?
62
- AND e.superseded_by IS NULL
63
- ${agentClause}
64
- ORDER BY rank
65
- LIMIT ?
66
- `).all(...params);
67
- }
68
-
69
- export function searchFTSSemantics(db, query, limit = 30, agentFilter = null) {
70
- const agentClause = agentFilter ? 'AND s.agent = ?' : '';
71
- const params = agentFilter ? [query, agentFilter, limit] : [query, limit];
72
- return db.prepare(`
73
- SELECT f.id, f.content, s.agent, bm25(fts_semantics) AS rank
74
- FROM fts_semantics f
75
- JOIN semantics s ON s.id = f.id
76
- WHERE fts_semantics MATCH ?
77
- AND s.state = 'active'
78
- ${agentClause}
79
- ORDER BY rank
80
- LIMIT ?
81
- `).all(...params);
82
- }
83
-
84
- export function searchFTSProcedures(db, query, limit = 30, agentFilter = null) {
85
- const agentClause = agentFilter ? 'AND p.agent = ?' : '';
86
- const params = agentFilter ? [query, agentFilter, limit] : [query, limit];
87
- return db.prepare(`
88
- SELECT f.id, f.content, p.agent, bm25(fts_procedures) AS rank
89
- FROM fts_procedures f
90
- JOIN procedures p ON p.id = f.id
91
- WHERE fts_procedures MATCH ?
92
- AND p.state = 'active'
93
- ${agentClause}
94
- ORDER BY rank
95
- LIMIT ?
96
- `).all(...params);
97
- }
98
-
99
- /**
100
- * Backfill FTS tables from existing data.
101
- */
102
- export function backfillFTS(db) {
103
- const episodes = db.prepare('SELECT id, content, tags FROM episodes').all();
104
- const insert = db.prepare('INSERT OR IGNORE INTO fts_episodes(id, content, tags) VALUES (?, ?, ?)');
105
- for (const ep of episodes) {
106
- const tags = ep.tags ? (typeof ep.tags === 'string' ? JSON.parse(ep.tags) : ep.tags) : [];
107
- insert.run(ep.id, ep.content, Array.isArray(tags) ? tags.join(' ') : '');
108
- }
109
-
110
- const semantics = db.prepare('SELECT id, content FROM semantics').all();
111
- const insertSem = db.prepare('INSERT OR IGNORE INTO fts_semantics(id, content) VALUES (?, ?)');
112
- for (const sem of semantics) {
113
- insertSem.run(sem.id, sem.content);
114
- }
115
-
116
- const procedures = db.prepare('SELECT id, content FROM procedures').all();
117
- const insertProc = db.prepare('INSERT OR IGNORE INTO fts_procedures(id, content) VALUES (?, ?)');
118
- for (const proc of procedures) {
119
- insertProc.run(proc.id, proc.content);
120
- }
121
- }
122
-
123
- /**
124
- * Sanitize FTS5 query — escape special characters.
125
- */
126
- export function sanitizeFTSQuery(query) {
127
- return query
128
- .replace(/[*"(){}[\]^~\\:]/g, ' ')
129
- .replace(/\bAND\b|\bOR\b|\bNOT\b|\bNEAR\b/gi, ' ')
130
- .trim()
131
- .split(/\s+/)
132
- .filter(Boolean)
133
- .join(' ');
134
- }