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
@@ -1,482 +0,0 @@
1
- import { createServer } from 'node:http';
2
- import { timingSafeEqual } from 'node:crypto';
3
- import { dirname, join } from 'node:path';
4
- import { unlinkSync } from 'node:fs';
5
- import { Audrey } from '../src/index.js';
6
- import { buildAudreyConfig } from './config.js';
7
- import { VERSION } from './config.js';
8
-
9
- const DEFAULT_PORT = 3487;
10
- const MAX_BODY = 10 * 1024 * 1024; // 10 MB
11
-
12
- function getDashboardHTML() {
13
- return `<!DOCTYPE html>
14
- <html lang="en">
15
- <head>
16
- <meta charset="utf-8">
17
- <meta name="viewport" content="width=device-width, initial-scale=1">
18
- <title>Audrey Memory Dashboard</title>
19
- <style>
20
- :root { --bg: #0f0f0f; --card: #1a1a1a; --border: #2a2a2a; --text: #e0e0e0; --dim: #888; --accent: #6c9; --warn: #e94; --err: #e55; }
21
- * { margin: 0; padding: 0; box-sizing: border-box; }
22
- body { font-family: 'SF Mono', 'Cascadia Code', 'Consolas', monospace; background: var(--bg); color: var(--text); padding: 24px; max-width: 1200px; margin: 0 auto; }
23
- h1 { font-size: 1.4em; margin-bottom: 4px; color: var(--accent); }
24
- .subtitle { color: var(--dim); font-size: 0.85em; margin-bottom: 24px; }
25
- .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; margin-bottom: 24px; }
26
- .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }
27
- .card h3 { font-size: 0.8em; color: var(--dim); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px; }
28
- .stat { font-size: 2em; font-weight: bold; color: var(--accent); }
29
- .stat.warn { color: var(--warn); }
30
- .stat.err { color: var(--err); }
31
- .stat-label { font-size: 0.75em; color: var(--dim); }
32
- table { width: 100%; border-collapse: collapse; font-size: 0.8em; }
33
- th { text-align: left; color: var(--dim); font-weight: normal; padding: 6px 8px; border-bottom: 1px solid var(--border); }
34
- td { padding: 6px 8px; border-bottom: 1px solid var(--border); max-width: 400px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
35
- .badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.75em; }
36
- .badge-active, .badge-completed { background: #1a3a2a; color: var(--accent); }
37
- .badge-dormant { background: #3a2a1a; color: var(--warn); }
38
- .badge-open, .badge-failed { background: #3a1a1a; color: var(--err); }
39
- .refresh { position: fixed; top: 16px; right: 16px; background: var(--card); border: 1px solid var(--border); color: var(--text); padding: 8px 16px; border-radius: 6px; cursor: pointer; font-family: inherit; }
40
- .refresh:hover { border-color: var(--accent); }
41
- </style>
42
- </head>
43
- <body>
44
- <h1>Audrey</h1>
45
- <p class="subtitle">Memory Health Dashboard</p>
46
- <button class="refresh" onclick="load()">Refresh</button>
47
- <div id="content"><p style="color:#888">Loading...</p></div>
48
- <script>
49
- function esc(s) {
50
- const d = document.createElement('div');
51
- d.textContent = s;
52
- return d.innerHTML;
53
- }
54
- function truncate(s, n) { return s.length > n ? esc(s.slice(0, n)) + '...' : esc(s); }
55
-
56
- async function load() {
57
- try {
58
- const [s, a] = await Promise.all([
59
- fetch('/status').then(r => r.json()),
60
- fetch('/analytics').then(r => r.json()),
61
- ]);
62
- render(s, a);
63
- } catch (e) {
64
- document.getElementById('content').textContent = 'Failed to load: ' + e.message;
65
- }
66
- }
67
-
68
- function render(s, a) {
69
- const ct = s.contradictions;
70
- const el = document.getElementById('content');
71
- el.innerHTML = '';
72
-
73
- // Stats grid
74
- const grid = document.createElement('div');
75
- grid.className = 'grid';
76
- const cards = [
77
- ['Episodic', s.episodic, 'raw events'],
78
- ['Semantic', s.semantic, 'consolidated principles'],
79
- ['Procedural', s.procedural, 'learned workflows'],
80
- ['Causal Links', s.causalLinks, 'cause-effect pairs'],
81
- ['Dormant', s.dormant, 'below threshold', s.dormant > 0 ? 'warn' : ''],
82
- ['Contradictions', ct.open + ' open', (ct.open+ct.resolved+ct.context_dependent+ct.reopened) + ' total', ct.open > 0 ? 'err' : ''],
83
- ['Consolidations', s.totalConsolidationRuns, s.lastConsolidation ? 'Last: ' + new Date(s.lastConsolidation).toLocaleString() : 'Never'],
84
- ];
85
- for (const [title, value, label, cls] of cards) {
86
- const c = document.createElement('div');
87
- c.className = 'card';
88
- c.innerHTML = '<h3>' + esc(title) + '</h3><div class="stat ' + (cls||'') + '">' + esc(String(value)) + '</div><div class="stat-label">' + esc(label) + '</div>';
89
- grid.appendChild(c);
90
- }
91
- el.appendChild(grid);
92
-
93
- // Agent activity
94
- if (a.agents && a.agents.length > 0) {
95
- const card = document.createElement('div');
96
- card.className = 'card';
97
- card.style.marginBottom = '16px';
98
- let html = '<h3>Agent Activity</h3><table><tr><th>Agent</th><th>Memories</th></tr>';
99
- for (const ag of a.agents) html += '<tr><td>' + esc(ag.agent) + '</td><td>' + ag.count + '</td></tr>';
100
- html += '</table>';
101
- card.innerHTML = html;
102
- el.appendChild(card);
103
- }
104
-
105
- // Top semantics
106
- if (a.topSemantics && a.topSemantics.length > 0) {
107
- const card = document.createElement('div');
108
- card.className = 'card';
109
- card.style.marginBottom = '16px';
110
- let html = '<h3>Top Semantic Principles</h3><table><tr><th>Content</th><th>Retrieved</th><th>Used</th><th>State</th></tr>';
111
- for (const sem of a.topSemantics) {
112
- html += '<tr><td title="' + esc(sem.content) + '">' + truncate(sem.content, 80) + '</td><td>' + sem.retrieval_count + '</td><td>' + (sem.usage_count||0) + '</td><td><span class="badge badge-' + esc(sem.state) + '">' + esc(sem.state) + '</span></td></tr>';
113
- }
114
- html += '</table>';
115
- card.innerHTML = html;
116
- el.appendChild(card);
117
- }
118
-
119
- // Recent episodes
120
- if (a.topEpisodes && a.topEpisodes.length > 0) {
121
- const card = document.createElement('div');
122
- card.className = 'card';
123
- card.style.marginBottom = '16px';
124
- let html = '<h3>Recent Episodes</h3><table><tr><th>Content</th><th>Used</th><th>Created</th></tr>';
125
- for (const ep of a.topEpisodes.slice(0, 10)) {
126
- html += '<tr><td title="' + esc(ep.content) + '">' + truncate(ep.content, 80) + '</td><td>' + (ep.usage_count||0) + '</td><td>' + new Date(ep.created_at).toLocaleDateString() + '</td></tr>';
127
- }
128
- html += '</table>';
129
- card.innerHTML = html;
130
- el.appendChild(card);
131
- }
132
-
133
- // Consolidation history
134
- if (a.recentRuns && a.recentRuns.length > 0) {
135
- const card = document.createElement('div');
136
- card.className = 'card';
137
- card.style.marginBottom = '16px';
138
- let html = '<h3>Consolidation History</h3><table><tr><th>Started</th><th>Status</th><th>Duration</th></tr>';
139
- for (const run of a.recentRuns.slice(0, 10)) {
140
- const dur = run.completed_at && run.started_at ? ((new Date(run.completed_at) - new Date(run.started_at)) / 1000).toFixed(1) + 's' : '-';
141
- html += '<tr><td>' + new Date(run.started_at).toLocaleString() + '</td><td><span class="badge badge-' + esc(run.status) + '">' + esc(run.status) + '</span></td><td>' + dur + '</td></tr>';
142
- }
143
- html += '</table>';
144
- card.innerHTML = html;
145
- el.appendChild(card);
146
- }
147
-
148
- const footer = document.createElement('p');
149
- footer.style.cssText = 'color:#888;font-size:0.75em;margin-top:24px';
150
- footer.textContent = 'Audrey v${VERSION} — refreshed ' + new Date().toLocaleTimeString();
151
- el.appendChild(footer);
152
- }
153
-
154
- load();
155
- setInterval(load, 30000);
156
- </script>
157
- </body>
158
- </html>`;
159
- }
160
-
161
- function parseBody(req) {
162
- return new Promise((resolve, reject) => {
163
- const chunks = [];
164
- let size = 0;
165
- let settled = false;
166
- const fail = (err) => { if (!settled) { settled = true; reject(err); } };
167
- const succeed = (val) => { if (!settled) { settled = true; resolve(val); } };
168
- req.on('data', chunk => {
169
- if (settled) return;
170
- size += chunk.length;
171
- if (size > MAX_BODY) {
172
- req.destroy();
173
- fail(new Error('Request body too large'));
174
- return;
175
- }
176
- chunks.push(chunk);
177
- });
178
- req.on('end', () => {
179
- const raw = Buffer.concat(chunks).toString('utf-8');
180
- if (!raw) return succeed({});
181
- try {
182
- succeed(JSON.parse(raw));
183
- } catch {
184
- fail(new Error('Invalid JSON'));
185
- }
186
- });
187
- req.on('error', (err) => fail(err));
188
- });
189
- }
190
-
191
- function json(res, status, data) {
192
- const body = JSON.stringify(data);
193
- res.writeHead(status, {
194
- 'Content-Type': 'application/json',
195
- 'Content-Length': Buffer.byteLength(body),
196
- 'Access-Control-Allow-Origin': '*',
197
- 'X-Content-Type-Options': 'nosniff',
198
- 'Cache-Control': 'no-store',
199
- });
200
- res.end(body);
201
- }
202
-
203
- function cors(res) {
204
- res.writeHead(204, {
205
- 'Access-Control-Allow-Origin': '*',
206
- 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
207
- 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
208
- 'Access-Control-Max-Age': '86400',
209
- });
210
- res.end();
211
- }
212
-
213
- function route(method, pathname) {
214
- return `${method} ${pathname}`;
215
- }
216
-
217
- async function drainAndCloseAudrey(audrey) {
218
- if (audrey && typeof audrey.waitForIdle === 'function') {
219
- await audrey.waitForIdle();
220
- }
221
- audrey?.close();
222
- }
223
-
224
- /**
225
- * Creates an HTTP server wrapping an Audrey instance.
226
- * @param {Audrey} audrey - The Audrey instance to serve
227
- * @param {{ apiKey?: string, audreyFactory?: () => Audrey }} options
228
- */
229
- export function createAudreyServer(audrey, options = {}) {
230
- const apiKey = options.apiKey || null;
231
- const audreyFactory = options.audreyFactory || null;
232
-
233
- // Mutable holder so restore can swap the instance
234
- const ctx = { audrey };
235
-
236
- function authenticate(req, res) {
237
- if (!apiKey) return true;
238
- const auth = req.headers.authorization || '';
239
- const expected = `Bearer ${apiKey}`;
240
- if (auth.length === expected.length &&
241
- timingSafeEqual(Buffer.from(auth), Buffer.from(expected))) {
242
- return true;
243
- }
244
- json(res, 401, { error: 'Unauthorized' });
245
- return false;
246
- }
247
-
248
- const server = createServer(async (req, res) => {
249
- const url = new URL(req.url, `http://${req.headers.host}`);
250
- const key = route(req.method, url.pathname);
251
-
252
- if (req.method === 'OPTIONS') {
253
- cors(res);
254
- return;
255
- }
256
-
257
- if (!authenticate(req, res)) return;
258
-
259
- const requestAgent = req.headers['x-audrey-agent'] || null;
260
-
261
- try {
262
- switch (key) {
263
- case 'GET /health': {
264
- json(res, 200, { ok: true, version: VERSION });
265
- break;
266
- }
267
-
268
- case 'GET /status': {
269
- const stats = ctx.audrey.introspect();
270
- json(res, 200, stats);
271
- break;
272
- }
273
-
274
- case 'GET /analytics': {
275
- const db = ctx.audrey.db;
276
- const topEpisodes = db.prepare(
277
- 'SELECT id, content, usage_count, created_at FROM episodes ORDER BY usage_count DESC LIMIT 10'
278
- ).all();
279
- const topSemantics = db.prepare(
280
- "SELECT id, content, retrieval_count, usage_count, state FROM semantics WHERE state != 'rolled_back' ORDER BY retrieval_count DESC LIMIT 10"
281
- ).all();
282
- const recentRuns = db.prepare(
283
- 'SELECT * FROM consolidation_runs ORDER BY started_at DESC LIMIT 20'
284
- ).all();
285
- const metrics = db.prepare(
286
- 'SELECT * FROM consolidation_metrics ORDER BY completed_at DESC LIMIT 20'
287
- ).all();
288
- const agents = db.prepare(
289
- "SELECT agent, COUNT(*) as count FROM episodes GROUP BY agent ORDER BY count DESC"
290
- ).all();
291
- json(res, 200, { topEpisodes, topSemantics, recentRuns, metrics, agents });
292
- break;
293
- }
294
-
295
- case 'GET /dashboard': {
296
- res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-store' });
297
- res.end(getDashboardHTML());
298
- break;
299
- }
300
-
301
- case 'POST /encode': {
302
- const body = await parseBody(req);
303
- if (!body.content) {
304
- json(res, 400, { error: 'content is required' });
305
- return;
306
- }
307
- if (requestAgent) body.agent = requestAgent;
308
- const id = await ctx.audrey.encode(body);
309
- json(res, 201, { id });
310
- break;
311
- }
312
-
313
- case 'POST /recall': {
314
- const body = await parseBody(req);
315
- if (!body.query) {
316
- json(res, 400, { error: 'query is required' });
317
- return;
318
- }
319
- const { query, ...opts } = body;
320
- if (requestAgent) opts.agent = requestAgent;
321
- const results = await ctx.audrey.recall(query, opts);
322
- json(res, 200, {
323
- results,
324
- partialFailure: Boolean(results.partialFailure),
325
- errors: results.errors ?? [],
326
- });
327
- break;
328
- }
329
-
330
- case 'POST /dream': {
331
- const body = await parseBody(req);
332
- const result = await ctx.audrey.dream(body);
333
- json(res, 200, result);
334
- break;
335
- }
336
-
337
- case 'POST /consolidate': {
338
- const body = await parseBody(req);
339
- const result = await ctx.audrey.consolidate(body);
340
- json(res, 200, result);
341
- break;
342
- }
343
-
344
- case 'POST /mark-used': {
345
- const body = await parseBody(req);
346
- if (!body.id) {
347
- json(res, 400, { error: 'id is required' });
348
- return;
349
- }
350
- ctx.audrey.markUsed(body.id);
351
- json(res, 200, { ok: true });
352
- break;
353
- }
354
-
355
- case 'POST /forget': {
356
- const body = await parseBody(req);
357
- if (body.query) {
358
- const result = await ctx.audrey.forgetByQuery(body.query, body);
359
- json(res, 200, result);
360
- } else if (body.id) {
361
- const result = ctx.audrey.forget(body.id, body);
362
- json(res, 200, result);
363
- } else {
364
- json(res, 400, { error: 'id or query is required' });
365
- }
366
- break;
367
- }
368
-
369
- case 'POST /snapshot': {
370
- const data = ctx.audrey.export();
371
- json(res, 200, data);
372
- break;
373
- }
374
-
375
- case 'POST /restore': {
376
- const body = await parseBody(req);
377
- if (!body.version) {
378
- json(res, 400, { error: 'Invalid snapshot: missing version field' });
379
- return;
380
- }
381
- if (!audreyFactory) {
382
- json(res, 501, { error: 'Restore not available: no audreyFactory configured' });
383
- return;
384
- }
385
- const dbPath = ctx.audrey.db?.name;
386
- await drainAndCloseAudrey(ctx.audrey);
387
- if (dbPath) {
388
- const dir = dirname(dbPath);
389
- for (const f of ['audrey.db', 'audrey.db-wal', 'audrey.db-shm']) {
390
- try { unlinkSync(join(dir, f)); } catch {}
391
- }
392
- }
393
- ctx.audrey = audreyFactory();
394
- await ctx.audrey.import(body);
395
- const stats = ctx.audrey.introspect();
396
- json(res, 200, { ok: true, ...stats });
397
- break;
398
- }
399
-
400
- default: {
401
- json(res, 404, { error: 'Not found', endpoints: [
402
- 'GET /health',
403
- 'GET /status',
404
- 'POST /encode',
405
- 'POST /recall',
406
- 'POST /dream',
407
- 'POST /consolidate',
408
- 'POST /mark-used',
409
- 'POST /forget',
410
- 'POST /snapshot',
411
- 'POST /restore',
412
- ]});
413
- }
414
- }
415
- } catch (err) {
416
- if (err.message.includes('too large')) {
417
- json(res, 413, { error: 'Request body too large' });
418
- } else if (err.message.includes('Invalid JSON')) {
419
- json(res, 400, { error: 'Invalid JSON in request body' });
420
- } else if (err.message.includes('source type')) {
421
- json(res, 400, { error: err.message });
422
- } else {
423
- console.error('[audrey] Internal error:', err.message);
424
- json(res, 500, { error: 'Internal server error' });
425
- }
426
- }
427
- });
428
-
429
- server._ctx = ctx;
430
- return server;
431
- }
432
-
433
- export async function startServer(options = {}) {
434
- const port = options.port || parseInt(process.env.AUDREY_PORT, 10) || DEFAULT_PORT;
435
- const host = options.host || process.env.AUDREY_HOST || '127.0.0.1';
436
- const apiKey = options.apiKey || process.env.AUDREY_API_KEY || null;
437
-
438
- const config = buildAudreyConfig();
439
- const audrey = new Audrey(config);
440
- const audreyFactory = () => new Audrey(config);
441
-
442
- const server = createAudreyServer(audrey, { apiKey, audreyFactory });
443
-
444
- server.listen(port, host, () => {
445
- console.log(`[audrey] REST API server listening on http://${host}:${port}`);
446
- console.log(`[audrey] Data: ${config.dataDir}`);
447
- console.log(`[audrey] Embedding: ${config.embedding.provider}`);
448
- if (apiKey) {
449
- console.log('[audrey] Auth: Bearer token required');
450
- } else {
451
- console.warn('[audrey] WARNING: No API key configured. Set AUDREY_API_KEY for production use.');
452
- }
453
- console.log('');
454
- console.log('Endpoints:');
455
- console.log(' GET /health - Liveness probe');
456
- console.log(' GET /status - Memory stats (introspect)');
457
- console.log(' POST /encode - Store a memory');
458
- console.log(' POST /recall - Semantic search');
459
- console.log(' POST /dream - Consolidation + decay cycle');
460
- console.log(' POST /consolidate - Run consolidation only');
461
- console.log(' POST /forget - Forget by id or query');
462
- console.log(' POST /snapshot - Export all memories as JSON');
463
- console.log(' POST /restore - Import snapshot (wipes + reimports)');
464
- console.log('');
465
- console.log('Press Ctrl+C to stop.');
466
- });
467
-
468
- const shutdown = () => {
469
- console.log('\n[audrey] Shutting down...');
470
- void drainAndCloseAudrey(server._ctx.audrey)
471
- .catch(err => {
472
- console.error('[audrey] Shutdown drain failed:', err.message);
473
- })
474
- .finally(() => {
475
- server.close(() => process.exit(0));
476
- });
477
- };
478
- process.on('SIGINT', shutdown);
479
- process.on('SIGTERM', shutdown);
480
-
481
- return { server, audrey };
482
- }
package/src/adaptive.js DELETED
@@ -1,53 +0,0 @@
1
- export function suggestConsolidationParams(db) {
2
- const runs = db.prepare(`
3
- SELECT min_cluster_size, similarity_threshold, clusters_found, principles_extracted, episodes_evaluated
4
- FROM consolidation_metrics
5
- ORDER BY created_at DESC
6
- LIMIT 20
7
- `).all();
8
-
9
- if (runs.length === 0) {
10
- return {
11
- minClusterSize: 3,
12
- similarityThreshold: 0.85,
13
- confidence: 'no_data',
14
- };
15
- }
16
-
17
- const paramScores = new Map();
18
- for (const run of runs) {
19
- if (run.episodes_evaluated === 0) continue;
20
- const key = `${run.min_cluster_size}:${run.similarity_threshold}`;
21
- if (!paramScores.has(key)) {
22
- paramScores.set(key, {
23
- minClusterSize: run.min_cluster_size,
24
- similarityThreshold: run.similarity_threshold,
25
- yields: [],
26
- });
27
- }
28
- paramScores.get(key).yields.push(run.principles_extracted / run.episodes_evaluated);
29
- }
30
-
31
- let bestKey = null;
32
- let bestAvgYield = -1;
33
- for (const [key, data] of paramScores) {
34
- const avg = data.yields.reduce((a, b) => a + b, 0) / data.yields.length;
35
- if (avg > bestAvgYield) {
36
- bestAvgYield = avg;
37
- bestKey = key;
38
- }
39
- }
40
-
41
- if (!bestKey) {
42
- return { minClusterSize: 3, similarityThreshold: 0.85, confidence: 'no_data' };
43
- }
44
-
45
- const best = paramScores.get(bestKey);
46
- const confidence = runs.length >= 5 ? 'high' : runs.length >= 2 ? 'medium' : 'low';
47
-
48
- return {
49
- minClusterSize: best.minClusterSize,
50
- similarityThreshold: best.similarityThreshold,
51
- confidence,
52
- };
53
- }
package/src/affect.js DELETED
@@ -1,64 +0,0 @@
1
- export function arousalSalienceBoost(arousal) {
2
- if (arousal === undefined || arousal === null) return 0;
3
- // Inverted-U (Yerkes-Dodson): peaks at 0.7, Gaussian sigma=0.3
4
- return Math.exp(-Math.pow(arousal - 0.7, 2) / (2 * 0.3 * 0.3));
5
- }
6
-
7
- export function affectSimilarity(a, b) {
8
- if (!a || !b) return 0;
9
- if (a.valence === undefined || b.valence === undefined) return 0;
10
- const valenceDist = Math.abs(a.valence - b.valence);
11
- const valenceSim = 1.0 - (valenceDist / 2.0);
12
- if (a.arousal === undefined || b.arousal === undefined) return valenceSim;
13
- const arousalSim = 1.0 - Math.abs(a.arousal - b.arousal);
14
- // Valence is primary (70%), arousal secondary (30%) per Bower 1981
15
- return 0.7 * valenceSim + 0.3 * arousalSim;
16
- }
17
-
18
- export function moodCongruenceModifier(encodingAffect, retrievalMood, weight = 0.2) {
19
- if (!encodingAffect || !retrievalMood) return 1.0;
20
- const similarity = affectSimilarity(encodingAffect, retrievalMood);
21
- if (similarity === 0) return 1.0;
22
- return 1.0 + (weight * similarity);
23
- }
24
-
25
- export async function detectResonance(db, embeddingProvider, episodeId, { content, affect }, config = {}) {
26
- const { enabled = true, k = 5, threshold = 0.5, affectThreshold = 0.6 } = config;
27
- if (!enabled || !affect || affect.valence === undefined) return [];
28
-
29
- const vector = await embeddingProvider.embed(content);
30
- const buffer = embeddingProvider.vectorToBuffer(vector);
31
-
32
- const matches = db.prepare(`
33
- SELECT e.*, (1.0 - v.distance) AS similarity
34
- FROM vec_episodes v
35
- JOIN episodes e ON e.id = v.id
36
- WHERE v.embedding MATCH ?
37
- AND k = ?
38
- AND e.id != ?
39
- AND e.superseded_by IS NULL
40
- `).all(buffer, k, episodeId);
41
-
42
- const resonances = [];
43
- for (const match of matches) {
44
- if (match.similarity < threshold) continue;
45
- let priorAffect;
46
- try { priorAffect = JSON.parse(match.affect || '{}'); } catch { continue; }
47
- if (priorAffect.valence === undefined) continue;
48
-
49
- const emotionalSimilarity = affectSimilarity(affect, priorAffect);
50
- if (emotionalSimilarity < affectThreshold) continue;
51
-
52
- resonances.push({
53
- priorEpisodeId: match.id,
54
- priorContent: match.content,
55
- priorAffect,
56
- semanticSimilarity: match.similarity,
57
- emotionalSimilarity,
58
- timeDeltaDays: Math.floor((Date.now() - new Date(match.created_at).getTime()) / 86400000),
59
- priorCreatedAt: match.created_at,
60
- });
61
- }
62
-
63
- return resonances;
64
- }