agent-working-memory 0.5.4 → 0.5.6

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 (71) hide show
  1. package/README.md +87 -46
  2. package/dist/api/routes.d.ts.map +1 -1
  3. package/dist/api/routes.js +21 -5
  4. package/dist/api/routes.js.map +1 -1
  5. package/dist/cli.js +67 -67
  6. package/dist/coordination/index.d.ts +11 -0
  7. package/dist/coordination/index.d.ts.map +1 -0
  8. package/dist/coordination/index.js +39 -0
  9. package/dist/coordination/index.js.map +1 -0
  10. package/dist/coordination/mcp-tools.d.ts +8 -0
  11. package/dist/coordination/mcp-tools.d.ts.map +1 -0
  12. package/dist/coordination/mcp-tools.js +216 -0
  13. package/dist/coordination/mcp-tools.js.map +1 -0
  14. package/dist/coordination/routes.d.ts +9 -0
  15. package/dist/coordination/routes.d.ts.map +1 -0
  16. package/dist/coordination/routes.js +434 -0
  17. package/dist/coordination/routes.js.map +1 -0
  18. package/dist/coordination/schema.d.ts +12 -0
  19. package/dist/coordination/schema.d.ts.map +1 -0
  20. package/dist/coordination/schema.js +91 -0
  21. package/dist/coordination/schema.js.map +1 -0
  22. package/dist/coordination/schemas.d.ts +208 -0
  23. package/dist/coordination/schemas.d.ts.map +1 -0
  24. package/dist/coordination/schemas.js +109 -0
  25. package/dist/coordination/schemas.js.map +1 -0
  26. package/dist/coordination/stale.d.ts +25 -0
  27. package/dist/coordination/stale.d.ts.map +1 -0
  28. package/dist/coordination/stale.js +53 -0
  29. package/dist/coordination/stale.js.map +1 -0
  30. package/dist/index.js +21 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/mcp.js +90 -79
  33. package/dist/mcp.js.map +1 -1
  34. package/dist/storage/sqlite.d.ts +3 -0
  35. package/dist/storage/sqlite.d.ts.map +1 -1
  36. package/dist/storage/sqlite.js +285 -281
  37. package/dist/storage/sqlite.js.map +1 -1
  38. package/package.json +55 -55
  39. package/src/api/index.ts +3 -3
  40. package/src/api/routes.ts +551 -536
  41. package/src/cli.ts +397 -397
  42. package/src/coordination/index.ts +47 -0
  43. package/src/coordination/mcp-tools.ts +313 -0
  44. package/src/coordination/routes.ts +656 -0
  45. package/src/coordination/schema.ts +94 -0
  46. package/src/coordination/schemas.ts +136 -0
  47. package/src/coordination/stale.ts +89 -0
  48. package/src/core/decay.ts +63 -63
  49. package/src/core/embeddings.ts +88 -88
  50. package/src/core/hebbian.ts +93 -93
  51. package/src/core/index.ts +5 -5
  52. package/src/core/logger.ts +36 -36
  53. package/src/core/query-expander.ts +66 -66
  54. package/src/core/reranker.ts +101 -101
  55. package/src/engine/activation.ts +656 -656
  56. package/src/engine/connections.ts +103 -103
  57. package/src/engine/consolidation-scheduler.ts +125 -125
  58. package/src/engine/eval.ts +102 -102
  59. package/src/engine/eviction.ts +101 -101
  60. package/src/engine/index.ts +8 -8
  61. package/src/engine/retraction.ts +100 -100
  62. package/src/engine/staging.ts +74 -74
  63. package/src/index.ts +137 -121
  64. package/src/mcp.ts +1024 -1013
  65. package/src/storage/index.ts +3 -3
  66. package/src/storage/sqlite.ts +968 -963
  67. package/src/types/agent.ts +67 -67
  68. package/src/types/checkpoint.ts +46 -46
  69. package/src/types/engram.ts +217 -217
  70. package/src/types/eval.ts +100 -100
  71. package/src/types/index.ts +6 -6
package/src/index.ts CHANGED
@@ -1,121 +1,137 @@
1
- // Copyright 2026 Robert Winter / Complete Ideas
2
- // SPDX-License-Identifier: Apache-2.0
3
- import { readFileSync, copyFileSync, existsSync, mkdirSync } from 'node:fs';
4
- import { resolve, dirname, basename } from 'node:path';
5
- import Fastify from 'fastify';
6
-
7
- // Load .env file if present (no external dependency)
8
- try {
9
- const envPath = resolve(process.cwd(), '.env');
10
- const envContent = readFileSync(envPath, 'utf-8');
11
- for (const line of envContent.split('\n')) {
12
- const trimmed = line.trim();
13
- if (!trimmed || trimmed.startsWith('#')) continue;
14
- const eqIdx = trimmed.indexOf('=');
15
- if (eqIdx === -1) continue;
16
- const key = trimmed.slice(0, eqIdx).trim();
17
- const val = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
18
- if (!process.env[key]) process.env[key] = val; // Don't override existing env
19
- }
20
- } catch { /* No .env file — that's fine */ }
21
- import { EngramStore } from './storage/sqlite.js';
22
- import { ActivationEngine } from './engine/activation.js';
23
- import { ConnectionEngine } from './engine/connections.js';
24
- import { StagingBuffer } from './engine/staging.js';
25
- import { EvictionEngine } from './engine/eviction.js';
26
- import { RetractionEngine } from './engine/retraction.js';
27
- import { EvalEngine } from './engine/eval.js';
28
- import { ConsolidationEngine } from './engine/consolidation.js';
29
- import { ConsolidationScheduler } from './engine/consolidation-scheduler.js';
30
- import { registerRoutes } from './api/routes.js';
31
- import { DEFAULT_AGENT_CONFIG } from './types/agent.js';
32
- import { getEmbedder } from './core/embeddings.js';
33
- import { getReranker } from './core/reranker.js';
34
- import { getExpander } from './core/query-expander.js';
35
- import { initLogger } from './core/logger.js';
36
-
37
- const PORT = parseInt(process.env.AWM_PORT ?? '8400', 10);
38
- const DB_PATH = process.env.AWM_DB_PATH ?? 'memory.db';
39
- const API_KEY = process.env.AWM_API_KEY ?? null;
40
-
41
- async function main() {
42
- // Auto-backup: copy DB to backups/ on startup (cheap insurance)
43
- if (existsSync(DB_PATH)) {
44
- const dbDir = dirname(resolve(DB_PATH));
45
- const backupDir = resolve(dbDir, 'backups');
46
- mkdirSync(backupDir, { recursive: true });
47
- const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
48
- const backupPath = resolve(backupDir, `${basename(DB_PATH, '.db')}-${ts}.db`);
49
- try {
50
- copyFileSync(resolve(DB_PATH), backupPath);
51
- console.log(`Backup: ${backupPath}`);
52
- } catch (err) {
53
- console.log(`Backup skipped: ${(err as Error).message}`);
54
- }
55
- }
56
-
57
- // Logger — write activity to awm.log alongside the DB
58
- initLogger(DB_PATH);
59
-
60
- // Storage
61
- const store = new EngramStore(DB_PATH);
62
-
63
- // Engines
64
- const activationEngine = new ActivationEngine(store);
65
- const connectionEngine = new ConnectionEngine(store, activationEngine);
66
- const stagingBuffer = new StagingBuffer(store, activationEngine);
67
- const evictionEngine = new EvictionEngine(store);
68
- const retractionEngine = new RetractionEngine(store);
69
- const evalEngine = new EvalEngine(store);
70
- const consolidationEngine = new ConsolidationEngine(store);
71
- const consolidationScheduler = new ConsolidationScheduler(store, consolidationEngine);
72
-
73
- // API
74
- const app = Fastify({ logger: true });
75
-
76
- // Bearer token auth — only enforced when AWM_API_KEY is explicitly set and non-empty
77
- if (API_KEY && API_KEY !== 'NONE' && API_KEY.length > 1) {
78
- app.addHook('onRequest', async (req, reply) => {
79
- if (req.url === '/health') return; // Health check is always public
80
- const bearer = req.headers.authorization;
81
- const xApiKey = req.headers['x-api-key'] as string | undefined;
82
- if (bearer === `Bearer ${API_KEY}` || xApiKey === API_KEY) return;
83
- reply.code(401).send({ error: 'Unauthorized' });
84
- });
85
- console.log('API key auth enabled (AWM_API_KEY set)');
86
- }
87
-
88
- registerRoutes(app, {
89
- store, activationEngine, connectionEngine,
90
- evictionEngine, retractionEngine, evalEngine,
91
- consolidationEngine, consolidationScheduler,
92
- });
93
-
94
- // Background tasks
95
- stagingBuffer.start(DEFAULT_AGENT_CONFIG.stagingTtlMs);
96
- consolidationScheduler.start();
97
-
98
- // Pre-load ML models (downloads on first run: embeddings ~22MB, reranker ~22MB, expander ~80MB)
99
- getEmbedder().catch(err => console.warn('Embedding model unavailable:', err.message));
100
- getReranker().catch(err => console.warn('Reranker model unavailable:', err.message));
101
- getExpander().catch(err => console.warn('Query expander model unavailable:', err.message));
102
-
103
- // Start server
104
- await app.listen({ port: PORT, host: '0.0.0.0' });
105
- console.log(`AgentWorkingMemory v0.5.4 listening on port ${PORT}`);
106
-
107
- // Graceful shutdown
108
- const shutdown = () => {
109
- consolidationScheduler.stop();
110
- stagingBuffer.stop();
111
- store.close();
112
- process.exit(0);
113
- };
114
- process.on('SIGINT', shutdown);
115
- process.on('SIGTERM', shutdown);
116
- }
117
-
118
- main().catch(err => {
119
- console.error('Failed to start:', err);
120
- process.exit(1);
121
- });
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { readFileSync, copyFileSync, existsSync, mkdirSync } from 'node:fs';
4
+ import { resolve, dirname, basename } from 'node:path';
5
+ import Fastify from 'fastify';
6
+
7
+ // Load .env file if present (no external dependency)
8
+ try {
9
+ const envPath = resolve(process.cwd(), '.env');
10
+ const envContent = readFileSync(envPath, 'utf-8');
11
+ for (const line of envContent.split('\n')) {
12
+ const trimmed = line.trim();
13
+ if (!trimmed || trimmed.startsWith('#')) continue;
14
+ const eqIdx = trimmed.indexOf('=');
15
+ if (eqIdx === -1) continue;
16
+ const key = trimmed.slice(0, eqIdx).trim();
17
+ const val = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
18
+ if (!process.env[key]) process.env[key] = val; // Don't override existing env
19
+ }
20
+ } catch { /* No .env file — that's fine */ }
21
+ import { EngramStore } from './storage/sqlite.js';
22
+ import { ActivationEngine } from './engine/activation.js';
23
+ import { ConnectionEngine } from './engine/connections.js';
24
+ import { StagingBuffer } from './engine/staging.js';
25
+ import { EvictionEngine } from './engine/eviction.js';
26
+ import { RetractionEngine } from './engine/retraction.js';
27
+ import { EvalEngine } from './engine/eval.js';
28
+ import { ConsolidationEngine } from './engine/consolidation.js';
29
+ import { ConsolidationScheduler } from './engine/consolidation-scheduler.js';
30
+ import { registerRoutes } from './api/routes.js';
31
+ import { DEFAULT_AGENT_CONFIG } from './types/agent.js';
32
+ import { getEmbedder } from './core/embeddings.js';
33
+ import { getReranker } from './core/reranker.js';
34
+ import { getExpander } from './core/query-expander.js';
35
+ import { initLogger } from './core/logger.js';
36
+
37
+ const PORT = parseInt(process.env.AWM_PORT ?? '8400', 10);
38
+ const DB_PATH = process.env.AWM_DB_PATH ?? 'memory.db';
39
+ const API_KEY = process.env.AWM_API_KEY ?? null;
40
+
41
+ async function main() {
42
+ // Auto-backup: copy DB to backups/ on startup (cheap insurance)
43
+ if (existsSync(DB_PATH)) {
44
+ const dbDir = dirname(resolve(DB_PATH));
45
+ const backupDir = resolve(dbDir, 'backups');
46
+ mkdirSync(backupDir, { recursive: true });
47
+ const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
48
+ const backupPath = resolve(backupDir, `${basename(DB_PATH, '.db')}-${ts}.db`);
49
+ try {
50
+ copyFileSync(resolve(DB_PATH), backupPath);
51
+ console.log(`Backup: ${backupPath}`);
52
+ } catch (err) {
53
+ console.log(`Backup skipped: ${(err as Error).message}`);
54
+ }
55
+ }
56
+
57
+ // Logger — write activity to awm.log alongside the DB
58
+ initLogger(DB_PATH);
59
+
60
+ // Storage
61
+ const store = new EngramStore(DB_PATH);
62
+
63
+ // Engines
64
+ const activationEngine = new ActivationEngine(store);
65
+ const connectionEngine = new ConnectionEngine(store, activationEngine);
66
+ const stagingBuffer = new StagingBuffer(store, activationEngine);
67
+ const evictionEngine = new EvictionEngine(store);
68
+ const retractionEngine = new RetractionEngine(store);
69
+ const evalEngine = new EvalEngine(store);
70
+ const consolidationEngine = new ConsolidationEngine(store);
71
+ const consolidationScheduler = new ConsolidationScheduler(store, consolidationEngine);
72
+
73
+ // API — disable Fastify's default request logging (too noisy for hive polling)
74
+ const app = Fastify({ logger: false });
75
+
76
+ // Bearer token auth — only enforced when AWM_API_KEY is explicitly set and non-empty
77
+ if (API_KEY && API_KEY !== 'NONE' && API_KEY.length > 1) {
78
+ app.addHook('onRequest', async (req, reply) => {
79
+ if (req.url === '/health') return; // Health check is always public
80
+ const bearer = req.headers.authorization;
81
+ const xApiKey = req.headers['x-api-key'] as string | undefined;
82
+ if (bearer === `Bearer ${API_KEY}` || xApiKey === API_KEY) return;
83
+ reply.code(401).send({ error: 'Unauthorized' });
84
+ });
85
+ console.log('API key auth enabled (AWM_API_KEY set)');
86
+ }
87
+
88
+ registerRoutes(app, {
89
+ store, activationEngine, connectionEngine,
90
+ evictionEngine, retractionEngine, evalEngine,
91
+ consolidationEngine, consolidationScheduler,
92
+ });
93
+
94
+ // Coordination module (opt-in via AWM_COORDINATION=true)
95
+ let heartbeatPruneTimer: ReturnType<typeof setInterval> | null = null;
96
+ const { isCoordinationEnabled, initCoordination } = await import('./coordination/index.js');
97
+ if (isCoordinationEnabled()) {
98
+ initCoordination(app, store.getDb());
99
+ // Prune stale heartbeat events every 30s (keeps assignment/command events permanently)
100
+ const { pruneOldHeartbeats } = await import('./coordination/stale.js');
101
+ heartbeatPruneTimer = setInterval(() => {
102
+ const pruned = pruneOldHeartbeats(store.getDb());
103
+ if (pruned > 0) console.log(`[coordination] pruned ${pruned} old heartbeat event(s)`);
104
+ }, 30_000);
105
+ } else {
106
+ console.log(' Coordination module disabled (set AWM_COORDINATION=true to enable)');
107
+ }
108
+
109
+ // Background tasks
110
+ stagingBuffer.start(DEFAULT_AGENT_CONFIG.stagingTtlMs);
111
+ consolidationScheduler.start();
112
+
113
+ // Pre-load ML models (downloads on first run: embeddings ~22MB, reranker ~22MB, expander ~80MB)
114
+ getEmbedder().catch(err => console.warn('Embedding model unavailable:', err.message));
115
+ getReranker().catch(err => console.warn('Reranker model unavailable:', err.message));
116
+ getExpander().catch(err => console.warn('Query expander model unavailable:', err.message));
117
+
118
+ // Start server
119
+ await app.listen({ port: PORT, host: '0.0.0.0' });
120
+ console.log(`AgentWorkingMemory v0.5.5 listening on port ${PORT}`);
121
+
122
+ // Graceful shutdown
123
+ const shutdown = () => {
124
+ if (heartbeatPruneTimer) clearInterval(heartbeatPruneTimer);
125
+ consolidationScheduler.stop();
126
+ stagingBuffer.stop();
127
+ store.close();
128
+ process.exit(0);
129
+ };
130
+ process.on('SIGINT', shutdown);
131
+ process.on('SIGTERM', shutdown);
132
+ }
133
+
134
+ main().catch(err => {
135
+ console.error('Failed to start:', err);
136
+ process.exit(1);
137
+ });