agent-working-memory 0.7.16 → 0.8.5

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 (200) hide show
  1. package/README.md +156 -15
  2. package/dist/adapters/claude-code.d.ts.map +1 -1
  3. package/dist/adapters/claude-code.js +2 -16
  4. package/dist/adapters/claude-code.js.map +1 -1
  5. package/dist/adapters/codex.d.ts.map +1 -1
  6. package/dist/adapters/codex.js +2 -11
  7. package/dist/adapters/codex.js.map +1 -1
  8. package/dist/adapters/common.d.ts +18 -0
  9. package/dist/adapters/common.d.ts.map +1 -1
  10. package/dist/adapters/common.js +254 -141
  11. package/dist/adapters/common.js.map +1 -1
  12. package/dist/adapters/cursor.d.ts.map +1 -1
  13. package/dist/adapters/cursor.js +2 -15
  14. package/dist/adapters/cursor.js.map +1 -1
  15. package/dist/adapters/http.d.ts.map +1 -1
  16. package/dist/adapters/http.js +28 -34
  17. package/dist/adapters/http.js.map +1 -1
  18. package/dist/api/routes.d.ts +1 -1
  19. package/dist/api/routes.d.ts.map +1 -1
  20. package/dist/api/routes.js +280 -113
  21. package/dist/api/routes.js.map +1 -1
  22. package/dist/cli/migrate.d.ts +42 -0
  23. package/dist/cli/migrate.d.ts.map +1 -0
  24. package/dist/cli/migrate.js +268 -0
  25. package/dist/cli/migrate.js.map +1 -0
  26. package/dist/cli.js +45 -1
  27. package/dist/cli.js.map +1 -1
  28. package/dist/coordination/circuit-breaker.d.ts +24 -0
  29. package/dist/coordination/circuit-breaker.d.ts.map +1 -0
  30. package/dist/coordination/circuit-breaker.js +70 -0
  31. package/dist/coordination/circuit-breaker.js.map +1 -0
  32. package/dist/coordination/failure-modes.d.ts +21 -0
  33. package/dist/coordination/failure-modes.d.ts.map +1 -0
  34. package/dist/coordination/failure-modes.js +49 -0
  35. package/dist/coordination/failure-modes.js.map +1 -0
  36. package/dist/coordination/peer-decisions.js +7 -7
  37. package/dist/coordination/routes.d.ts.map +1 -1
  38. package/dist/coordination/routes.js +44 -1
  39. package/dist/coordination/routes.js.map +1 -1
  40. package/dist/coordination/schema.d.ts.map +1 -1
  41. package/dist/coordination/schema.js +18 -0
  42. package/dist/coordination/schema.js.map +1 -1
  43. package/dist/coordination/schemas.d.ts +9 -9
  44. package/dist/coordination/stale.d.ts +9 -1
  45. package/dist/coordination/stale.d.ts.map +1 -1
  46. package/dist/coordination/stale.js +53 -9
  47. package/dist/coordination/stale.js.map +1 -1
  48. package/dist/core/embeddings.d.ts +16 -10
  49. package/dist/core/embeddings.d.ts.map +1 -1
  50. package/dist/core/embeddings.js +54 -38
  51. package/dist/core/embeddings.js.map +1 -1
  52. package/dist/core/ml-worker-entry.d.ts +17 -0
  53. package/dist/core/ml-worker-entry.d.ts.map +1 -0
  54. package/dist/core/ml-worker-entry.js +193 -0
  55. package/dist/core/ml-worker-entry.js.map +1 -0
  56. package/dist/core/ml-worker.d.ts +59 -0
  57. package/dist/core/ml-worker.d.ts.map +1 -0
  58. package/dist/core/ml-worker.js +253 -0
  59. package/dist/core/ml-worker.js.map +1 -0
  60. package/dist/core/query-expander.d.ts +13 -15
  61. package/dist/core/query-expander.d.ts.map +1 -1
  62. package/dist/core/query-expander.js +48 -54
  63. package/dist/core/query-expander.js.map +1 -1
  64. package/dist/core/reranker.d.ts +9 -19
  65. package/dist/core/reranker.d.ts.map +1 -1
  66. package/dist/core/reranker.js +33 -35
  67. package/dist/core/reranker.js.map +1 -1
  68. package/dist/core/salience.d.ts +32 -5
  69. package/dist/core/salience.d.ts.map +1 -1
  70. package/dist/core/salience.js +201 -28
  71. package/dist/core/salience.js.map +1 -1
  72. package/dist/core/write-pipeline.d.ts +128 -0
  73. package/dist/core/write-pipeline.d.ts.map +1 -0
  74. package/dist/core/write-pipeline.js +405 -0
  75. package/dist/core/write-pipeline.js.map +1 -0
  76. package/dist/engine/activation.d.ts +2 -2
  77. package/dist/engine/activation.d.ts.map +1 -1
  78. package/dist/engine/activation.js +238 -115
  79. package/dist/engine/activation.js.map +1 -1
  80. package/dist/engine/confidence.d.ts +62 -0
  81. package/dist/engine/confidence.d.ts.map +1 -0
  82. package/dist/engine/confidence.js +100 -0
  83. package/dist/engine/confidence.js.map +1 -0
  84. package/dist/engine/connections.d.ts +47 -8
  85. package/dist/engine/connections.d.ts.map +1 -1
  86. package/dist/engine/connections.js +83 -22
  87. package/dist/engine/connections.js.map +1 -1
  88. package/dist/engine/consolidation-scheduler.d.ts +46 -10
  89. package/dist/engine/consolidation-scheduler.d.ts.map +1 -1
  90. package/dist/engine/consolidation-scheduler.js +170 -50
  91. package/dist/engine/consolidation-scheduler.js.map +1 -1
  92. package/dist/engine/consolidation.d.ts +16 -2
  93. package/dist/engine/consolidation.d.ts.map +1 -1
  94. package/dist/engine/consolidation.js +143 -44
  95. package/dist/engine/consolidation.js.map +1 -1
  96. package/dist/engine/eval.d.ts +2 -2
  97. package/dist/engine/eval.d.ts.map +1 -1
  98. package/dist/engine/eval.js +9 -9
  99. package/dist/engine/eval.js.map +1 -1
  100. package/dist/engine/eviction.d.ts +4 -4
  101. package/dist/engine/eviction.d.ts.map +1 -1
  102. package/dist/engine/eviction.js +15 -15
  103. package/dist/engine/eviction.js.map +1 -1
  104. package/dist/engine/retraction.d.ts +93 -5
  105. package/dist/engine/retraction.d.ts.map +1 -1
  106. package/dist/engine/retraction.js +238 -19
  107. package/dist/engine/retraction.js.map +1 -1
  108. package/dist/engine/staging.d.ts +1 -1
  109. package/dist/engine/staging.d.ts.map +1 -1
  110. package/dist/engine/staging.js +3 -3
  111. package/dist/engine/staging.js.map +1 -1
  112. package/dist/hooks/sidecar.d.ts +1 -1
  113. package/dist/hooks/sidecar.d.ts.map +1 -1
  114. package/dist/hooks/sidecar.js +4 -4
  115. package/dist/hooks/sidecar.js.map +1 -1
  116. package/dist/index.js +48 -31
  117. package/dist/index.js.map +1 -1
  118. package/dist/mcp.js +110 -155
  119. package/dist/mcp.js.map +1 -1
  120. package/dist/storage/factory.d.ts +55 -0
  121. package/dist/storage/factory.d.ts.map +1 -0
  122. package/dist/storage/factory.js +135 -0
  123. package/dist/storage/factory.js.map +1 -0
  124. package/dist/storage/pglite-schema.d.ts +20 -0
  125. package/dist/storage/pglite-schema.d.ts.map +1 -0
  126. package/dist/storage/pglite-schema.js +165 -0
  127. package/dist/storage/pglite-schema.js.map +1 -0
  128. package/dist/storage/pglite.d.ts +187 -0
  129. package/dist/storage/pglite.d.ts.map +1 -0
  130. package/dist/storage/pglite.js +1114 -0
  131. package/dist/storage/pglite.js.map +1 -0
  132. package/dist/storage/sqlite.d.ts +117 -0
  133. package/dist/storage/sqlite.d.ts.map +1 -1
  134. package/dist/storage/sqlite.js +357 -8
  135. package/dist/storage/sqlite.js.map +1 -1
  136. package/dist/storage/store.d.ts +63 -0
  137. package/dist/storage/store.d.ts.map +1 -0
  138. package/dist/storage/store.js +27 -0
  139. package/dist/storage/store.js.map +1 -0
  140. package/dist/types/engram.d.ts +92 -2
  141. package/dist/types/engram.d.ts.map +1 -1
  142. package/dist/types/engram.js.map +1 -1
  143. package/package.json +3 -1
  144. package/src/adapters/claude-code.ts +218 -234
  145. package/src/adapters/codex.ts +252 -262
  146. package/src/adapters/common.ts +411 -284
  147. package/src/adapters/cursor.ts +135 -150
  148. package/src/adapters/http.ts +93 -100
  149. package/src/adapters/index.ts +31 -31
  150. package/src/adapters/types.ts +75 -75
  151. package/src/api/index.ts +3 -3
  152. package/src/api/routes.ts +367 -120
  153. package/src/cli/migrate.ts +307 -0
  154. package/src/cli.ts +37 -1
  155. package/src/coordination/circuit-breaker.ts +83 -0
  156. package/src/coordination/events.ts +90 -90
  157. package/src/coordination/failure-modes.ts +50 -0
  158. package/src/coordination/peer-decisions.ts +105 -105
  159. package/src/coordination/plugin-loader.ts +60 -60
  160. package/src/coordination/plugin.ts +44 -44
  161. package/src/coordination/routes.ts +56 -1
  162. package/src/coordination/schema.ts +13 -0
  163. package/src/coordination/stale.ts +80 -11
  164. package/src/coordination/types.ts +311 -311
  165. package/src/coordination/write-mutex.ts +69 -69
  166. package/src/core/auto-tagger.ts +168 -168
  167. package/src/core/decay.ts +63 -63
  168. package/src/core/embeddings.ts +110 -93
  169. package/src/core/index.ts +5 -5
  170. package/src/core/logger.ts +36 -36
  171. package/src/core/ml-worker-entry.ts +194 -0
  172. package/src/core/ml-worker.ts +281 -0
  173. package/src/core/query-expander.ts +122 -128
  174. package/src/core/reranker.ts +119 -125
  175. package/src/core/salience.ts +200 -33
  176. package/src/core/write-pipeline.ts +521 -0
  177. package/src/engine/activation.ts +235 -109
  178. package/src/engine/confidence.ts +120 -0
  179. package/src/engine/connections.ts +162 -103
  180. package/src/engine/consolidation-scheduler.ts +242 -125
  181. package/src/engine/consolidation.ts +138 -45
  182. package/src/engine/eval.ts +102 -102
  183. package/src/engine/eviction.ts +101 -101
  184. package/src/engine/index.ts +8 -8
  185. package/src/engine/retraction.ts +366 -116
  186. package/src/engine/staging.ts +74 -74
  187. package/src/hooks/sidecar.ts +5 -5
  188. package/src/index.ts +42 -28
  189. package/src/mcp.ts +105 -152
  190. package/src/storage/factory.ts +147 -0
  191. package/src/storage/index.ts +3 -3
  192. package/src/storage/pglite-schema.ts +166 -0
  193. package/src/storage/pglite.ts +1363 -0
  194. package/src/storage/sqlite.ts +402 -7
  195. package/src/storage/store.ts +80 -0
  196. package/src/types/agent.ts +67 -67
  197. package/src/types/checkpoint.ts +46 -46
  198. package/src/types/engram.ts +101 -3
  199. package/src/types/eval.ts +100 -100
  200. package/src/types/index.ts +6 -6
package/src/mcp.ts CHANGED
@@ -52,6 +52,8 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
52
52
  import { z } from 'zod';
53
53
 
54
54
  import { EngramStore } from './storage/sqlite.js';
55
+ import { openStore, getConfiguredBackend, type StoreBackend } from './storage/factory.js';
56
+ import type { IEngramStore } from './storage/store.js';
55
57
  import { ActivationEngine } from './engine/activation.js';
56
58
  import { ConnectionEngine } from './engine/connections.js';
57
59
  import { StagingBuffer } from './engine/staging.js';
@@ -61,6 +63,7 @@ import { EvalEngine } from './engine/eval.js';
61
63
  import { ConsolidationEngine } from './engine/consolidation.js';
62
64
  import { ConsolidationScheduler } from './engine/consolidation-scheduler.js';
63
65
  import { evaluateSalience, computeNovelty, computeNoveltyWithMatch } from './core/salience.js';
66
+ import { performWrite } from './core/write-pipeline.js';
64
67
  import type { ConsciousState } from './types/checkpoint.js';
65
68
  import type { SalienceEventType } from './core/salience.js';
66
69
  import type { TaskStatus, TaskPriority } from './types/engram.js';
@@ -78,7 +81,7 @@ const INCOGNITO = process.env.AWM_INCOGNITO === '1' || process.env.AWM_INCOGNITO
78
81
 
79
82
  if (INCOGNITO) {
80
83
  console.error('AWM: incognito mode — all memory tools disabled, nothing will be recorded');
81
- const server = new McpServer({ name: 'agent-working-memory', version: '0.7.16' });
84
+ const server = new McpServer({ name: 'agent-working-memory', version: '0.8.5' });
82
85
  const transport = new StdioServerTransport();
83
86
  server.connect(transport).catch(err => {
84
87
  console.error('MCP server failed:', err);
@@ -89,22 +92,27 @@ if (INCOGNITO) {
89
92
 
90
93
  // --- Setup ---
91
94
 
92
- const DB_PATH = process.env.AWM_DB_PATH ?? 'memory.db';
95
+ const BACKEND: StoreBackend = getConfiguredBackend();
96
+ const DB_PATH = process.env.AWM_DB_PATH ?? (BACKEND === 'pglite' ? 'memory-pglite' : 'memory.db');
93
97
  const AGENT_ID = process.env.AWM_AGENT_ID ?? process.env.WORKER_NAME ?? 'claude-code';
94
98
  const HOOK_PORT = parseInt(process.env.AWM_HOOK_PORT ?? '8401', 10);
95
99
  const HOOK_SECRET = process.env.AWM_HOOK_SECRET ?? null;
96
100
 
97
101
  initLogger(DB_PATH);
98
- log(AGENT_ID, 'startup', `MCP server starting (db: ${DB_PATH}, hooks: ${HOOK_PORT})`);
102
+ log(AGENT_ID, 'startup', `MCP server starting (backend: ${BACKEND}, db: ${DB_PATH}, hooks: ${HOOK_PORT})`);
99
103
 
100
- const store = new EngramStore(DB_PATH);
104
+ // AWM 0.8.x: openStore() returns either SQLite (sync) or PGlite (async) store.
105
+ // Engines accept either via IEngramStore (MaybePromise<T> contract).
106
+ const { store: storeAny } = await openStore();
107
+ // Engines accept the async contract; SQLite-only call sites must guard on BACKEND.
108
+ const store = storeAny as unknown as IEngramStore & Partial<EngramStore>;
101
109
  const activationEngine = new ActivationEngine(store);
102
110
  const connectionEngine = new ConnectionEngine(store, activationEngine);
103
111
  const stagingBuffer = new StagingBuffer(store, activationEngine);
104
112
  const evictionEngine = new EvictionEngine(store);
105
113
  const retractionEngine = new RetractionEngine(store);
106
114
  const evalEngine = new EvalEngine(store);
107
- const consolidationEngine = new ConsolidationEngine(store);
115
+ const consolidationEngine = new ConsolidationEngine(store, connectionEngine);
108
116
  const consolidationScheduler = new ConsolidationScheduler(store, consolidationEngine);
109
117
 
110
118
  stagingBuffer.start(DEFAULT_AGENT_CONFIG.stagingTtlMs);
@@ -115,7 +123,7 @@ let coordDb: import('better-sqlite3').Database | null = null;
115
123
 
116
124
  const server = new McpServer({
117
125
  name: 'agent-working-memory',
118
- version: '0.7.16',
126
+ version: '0.8.5',
119
127
  });
120
128
 
121
129
  server.registerResource(
@@ -239,71 +247,6 @@ The concept should be a short label (3-8 words). The content should be the full
239
247
  .describe('What kind of memory this is.'),
240
248
  },
241
249
  async (params) => {
242
- // Check novelty with match info for reinforcement
243
- const noveltyResult = computeNoveltyWithMatch(store, AGENT_ID, params.concept, params.content);
244
- const novelty = noveltyResult.novelty;
245
-
246
- // --- Reinforce-on-Duplicate check ---
247
- // Tightened thresholds: require near-exact match (novelty < 0.3, BM25 > 0.85, 60% content overlap)
248
- if (novelty < 0.3
249
- && noveltyResult.matchScore > 0.85
250
- && noveltyResult.matchedEngramId) {
251
- const matchedEngram = store.getEngram(noveltyResult.matchedEngramId);
252
- if (matchedEngram) {
253
- const existingTokens = new Set(matchedEngram.content.toLowerCase().split(/\s+/).filter(w => w.length > 3));
254
- const newTokens = new Set(params.content.toLowerCase().split(/\s+/).filter(w => w.length > 3));
255
- let overlap = 0;
256
- for (const t of newTokens) { if (existingTokens.has(t)) overlap++; }
257
- const contentOverlap = newTokens.size > 0 ? overlap / newTokens.size : 0;
258
-
259
- if (contentOverlap > 0.6) {
260
- // True duplicate — reinforce existing and skip creation
261
- store.touchEngram(noveltyResult.matchedEngramId);
262
- try { store.updateAutoCheckpointWrite(AGENT_ID, noveltyResult.matchedEngramId); } catch { /* non-fatal */ }
263
- log(AGENT_ID, 'write:reinforce', `"${params.concept}" → reinforced "${matchedEngram.concept}" (overlap=${contentOverlap.toFixed(2)})`);
264
- return {
265
- content: [{
266
- type: 'text' as const,
267
- text: `Reinforced existing memory "${matchedEngram.concept}" (overlap ${(contentOverlap * 100).toFixed(0)}%)`,
268
- }],
269
- };
270
- }
271
- // Partial match — continue to create new memory
272
- log(AGENT_ID, 'write:partial-match', `"${params.concept}" partially matched "${matchedEngram.concept}" (overlap=${contentOverlap.toFixed(2)}), creating new memory`);
273
- }
274
- }
275
-
276
- const salience = evaluateSalience({
277
- content: params.content,
278
- eventType: params.event_type as SalienceEventType,
279
- surprise: params.surprise,
280
- decisionMade: params.decision_made,
281
- causalDepth: params.causal_depth,
282
- resolutionEffort: params.resolution_effort,
283
- novelty,
284
- memoryClass: params.memory_class,
285
- });
286
-
287
- // v0.5.4: No longer discard — store everything, use salience for ranking.
288
- // Low-salience memories get low confidence so they rank below high-salience
289
- // in retrieval, but remain available for recall when needed.
290
- const isLowSalience = salience.disposition === 'discard';
291
-
292
- const CONFIDENCE_PRIORS: Record<string, number> = {
293
- decision: 0.65,
294
- friction: 0.60,
295
- causal: 0.60,
296
- surprise: 0.55,
297
- observation: 0.45,
298
- };
299
- const confidencePrior = isLowSalience
300
- ? 0.25
301
- : salience.disposition === 'staging'
302
- ? 0.40
303
- : CONFIDENCE_PRIORS[params.event_type ?? 'observation'] ?? 0.45;
304
-
305
- const memoryType = params.memory_type ?? classifyMemoryType(params.content);
306
-
307
250
  // Assemble tags: user-provided + agent metadata (stored as searchable prefixed tags)
308
251
  const userTags = params.tags ?? [];
309
252
  const metaTags: string[] = [];
@@ -313,48 +256,41 @@ The concept should be a short label (3-8 words). The content should be the full
313
256
  if (params.confidence_level) metaTags.push(`conf=${params.confidence_level}`);
314
257
  if (params.session_id) metaTags.push(`sid=${params.session_id}`);
315
258
  if (params.intent) metaTags.push(`intent=${params.intent}`);
316
- const allTags = isLowSalience
317
- ? [...userTags, ...metaTags, 'low-salience']
318
- : [...userTags, ...metaTags];
319
259
 
320
- const engram = store.createEngram({
260
+ const memoryType = params.memory_type ?? classifyMemoryType(params.content);
261
+
262
+ const result = await performWrite({ store, connectionEngine }, {
321
263
  agentId: AGENT_ID,
322
264
  concept: params.concept,
323
265
  content: params.content,
324
- tags: allTags,
325
- salience: salience.score,
326
- confidence: confidencePrior,
327
- salienceFeatures: salience.features,
328
- reasonCodes: salience.reasonCodes,
329
- ttl: salience.disposition === 'staging' ? DEFAULT_AGENT_CONFIG.stagingTtlMs : undefined,
266
+ tags: [...userTags, ...metaTags],
267
+ eventType: params.event_type as SalienceEventType,
268
+ surprise: params.surprise,
269
+ decisionMade: params.decision_made,
270
+ causalDepth: params.causal_depth,
271
+ resolutionEffort: params.resolution_effort,
330
272
  memoryClass: params.memory_class,
331
273
  memoryType,
332
274
  supersedes: params.supersedes,
333
275
  });
334
276
 
335
- if (salience.disposition === 'staging') {
336
- store.updateStage(engram.id, 'staging');
337
- } else {
338
- connectionEngine.enqueue(engram.id);
339
- }
277
+ // Auto-checkpoint covers create/reinforce/supersede uniformly
278
+ try { await store.updateAutoCheckpointWrite(AGENT_ID, result.engram.id); } catch { /* non-fatal */ }
340
279
 
341
- // Handle supersession: mark old memory as superseded
342
- if (params.supersedes) {
343
- const oldEngram = store.getEngram(params.supersedes);
344
- if (oldEngram) {
345
- store.supersedeEngram(params.supersedes, engram.id);
346
- // Create supersession association
347
- store.upsertAssociation(engram.id, oldEngram.id, 0.8, 'causal', 0.9);
348
- }
280
+ if (result.action === 'reinforce') {
281
+ log(AGENT_ID, 'write:reinforce', `"${params.concept}" → reinforced "${result.engram.concept}" (conf ${result.reinforce!.previousConfidence.toFixed(2)} → ${result.reinforce!.newConfidence.toFixed(2)}, novelty=${result.noveltyResult.novelty.toFixed(2)})`);
282
+ return {
283
+ content: [{
284
+ type: 'text' as const,
285
+ text: `Reinforced existing memory "${result.engram.concept}" (confidence ${result.reinforce!.previousConfidence.toFixed(2)} → ${result.reinforce!.newConfidence.toFixed(2)})`,
286
+ }],
287
+ };
349
288
  }
350
289
 
351
- // Generate embedding asynchronously (don't block response)
352
- embed(`${params.concept} ${params.content}`).then(vec => {
353
- store.updateEmbedding(engram.id, vec);
354
- }).catch(() => {}); // Embedding failure is non-fatal
355
-
356
- // Auto-checkpoint: track write
357
- try { store.updateAutoCheckpointWrite(AGENT_ID, engram.id); } catch { /* non-fatal */ }
290
+ const engram = result.engram;
291
+ const salience = result.salience!; // create/supersede always have salience
292
+ const novelty = result.noveltyResult.novelty;
293
+ const isLowSalience = salience.disposition === 'discard';
358
294
 
359
295
  // Decision propagation: when decision_made=true and coordination is enabled,
360
296
  // broadcast to coord_decisions so other agents can discover it
@@ -405,6 +341,8 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
405
341
  use_expansion: z.boolean().optional().default(true).describe('Expand query with synonyms for better recall (default true)'),
406
342
  memory_type: z.enum(['episodic', 'semantic', 'procedural']).optional().describe('Filter by memory type (omit to search all types)'),
407
343
  workspace: z.string().optional().describe('Search across all agents in this workspace (hive mode). Omit for agent-scoped recall only.'),
344
+ require_confidence: z.number().optional().describe('Opt-in: abstain (return []) when recall confidence is below this threshold. Typical values: 0.10 (strict), 0.25 (balanced), 0.40 (aggressive). Confidence is the shape of the result-score distribution; low confidence indicates a noisy or best-of-bad-bunch recall.'),
345
+ granularity: z.enum(['full', 'compact', 'auto']).optional().describe('Output granularity (Paper 3: cognitive teaming). "full" (default): no change. "compact": every result carries a short summary field. "auto": confidence-adaptive — top result gets a longer summary when there is a clear winner, otherwise everything is compact for scanning.'),
408
346
  },
409
347
  async (params) => {
410
348
  const queryText = params.query ?? params.context;
@@ -428,12 +366,14 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
428
366
  useExpansion: params.use_expansion,
429
367
  memoryType: params.memory_type,
430
368
  workspace,
369
+ requireConfidence: params.require_confidence,
370
+ granularity: params.granularity,
431
371
  });
432
372
 
433
373
  // Auto-checkpoint: track recall
434
374
  try {
435
375
  const ids = results.map(r => r.engram.id);
436
- store.updateAutoCheckpointRecall(AGENT_ID, queryText, ids);
376
+ await store.updateAutoCheckpointRecall(AGENT_ID, queryText, ids);
437
377
  } catch { /* non-fatal */ }
438
378
 
439
379
  log(AGENT_ID, 'recall', `"${queryText.slice(0, 80)}" → ${results.length} results`);
@@ -453,7 +393,11 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
453
393
  }
454
394
 
455
395
  const lines = results.map((r, i) => {
456
- return `${i + 1}. **${r.engram.concept}** (${r.score.toFixed(3)}): ${r.engram.content}`;
396
+ // Confidence-adaptive output (Paper 3: cognitive teaming). When the caller
397
+ // requested 'compact' or 'auto' granularity, surface the engine-computed
398
+ // summary instead of the full content — same engram, less to read.
399
+ const body = r.summary ?? r.engram.content;
400
+ return `${i + 1}. **${r.engram.concept}** (${r.score.toFixed(3)}): ${body}`;
457
401
  });
458
402
 
459
403
  return {
@@ -476,18 +420,18 @@ Always call this after using a recalled memory so the system learns what's valua
476
420
  context: z.string().optional().describe('Brief note on why it was/wasn\'t useful'),
477
421
  },
478
422
  async (params) => {
479
- store.logRetrievalFeedback(null, params.engram_id, params.useful, params.context ?? '');
423
+ await store.logRetrievalFeedback(null, params.engram_id, params.useful, params.context ?? '');
480
424
 
481
- const engram = store.getEngram(params.engram_id);
425
+ const engram = await store.getEngram(params.engram_id);
482
426
  if (engram) {
483
427
  const delta = params.useful
484
428
  ? DEFAULT_AGENT_CONFIG.feedbackPositiveBoost
485
429
  : -DEFAULT_AGENT_CONFIG.feedbackNegativePenalty;
486
- store.updateConfidence(engram.id, engram.confidence + delta);
430
+ await store.updateConfidence(engram.id, engram.confidence + delta);
487
431
  }
488
432
 
489
433
  // Validation-gated Hebbian: resolve pending co-activation pairs for this engram
490
- const hebbianUpdated = activationEngine.resolveHebbianFeedback(params.engram_id, params.useful);
434
+ const hebbianUpdated = await activationEngine.resolveHebbianFeedback(params.engram_id, params.useful);
491
435
 
492
436
  return {
493
437
  content: [{
@@ -509,7 +453,7 @@ Use this when you discover a memory contains incorrect information.`,
509
453
  correction: z.string().optional().describe('What is the correct information? (creates a new memory)'),
510
454
  },
511
455
  async (params) => {
512
- const result = retractionEngine.retract({
456
+ const result = await retractionEngine.retract({
513
457
  agentId: AGENT_ID,
514
458
  targetEngramId: params.engram_id,
515
459
  reason: params.reason,
@@ -547,22 +491,22 @@ The old memory stays in the database (searchable for history) but is heavily dow
547
491
  reason: z.string().optional().describe('Why the old memory is outdated'),
548
492
  },
549
493
  async (params) => {
550
- const oldEngram = store.getEngram(params.old_engram_id);
494
+ const oldEngram = await store.getEngram(params.old_engram_id);
551
495
  if (!oldEngram) {
552
496
  return { content: [{ type: 'text' as const, text: `Old memory not found: ${params.old_engram_id}` }] };
553
497
  }
554
- const newEngram = store.getEngram(params.new_engram_id);
498
+ const newEngram = await store.getEngram(params.new_engram_id);
555
499
  if (!newEngram) {
556
500
  return { content: [{ type: 'text' as const, text: `New memory not found: ${params.new_engram_id}` }] };
557
501
  }
558
502
 
559
- store.supersedeEngram(params.old_engram_id, params.new_engram_id);
503
+ await store.supersedeEngram(params.old_engram_id, params.new_engram_id);
560
504
 
561
505
  // Create supersession association (new → old)
562
- store.upsertAssociation(params.new_engram_id, params.old_engram_id, 0.8, 'causal', 0.9);
506
+ await store.upsertAssociation(params.new_engram_id, params.old_engram_id, 0.8, 'causal', 0.9);
563
507
 
564
508
  // Reduce old memory's confidence (not to zero — it's historical, not wrong)
565
- store.updateConfidence(params.old_engram_id, Math.max(0.2, oldEngram.confidence * 0.4));
509
+ await store.updateConfidence(params.old_engram_id, Math.max(0.2, oldEngram.confidence * 0.4));
566
510
 
567
511
  log(AGENT_ID, 'supersede', `"${oldEngram.concept}" → "${newEngram.concept}"${params.reason ? ` (${params.reason})` : ''}`);
568
512
 
@@ -581,8 +525,8 @@ server.tool(
581
525
  Also shows the activity log path so the user can tail it to see what's happening.`,
582
526
  {},
583
527
  async () => {
584
- const metrics = evalEngine.computeMetrics(AGENT_ID);
585
- const checkpoint = store.getCheckpoint(AGENT_ID);
528
+ const metrics = await evalEngine.computeMetrics(AGENT_ID);
529
+ const checkpoint = await store.getCheckpoint(AGENT_ID);
586
530
  const lines = [
587
531
  `Agent: ${AGENT_ID}`,
588
532
  `Active memories: ${metrics.activeEngramCount}`,
@@ -650,7 +594,7 @@ Also call periodically during long sessions to avoid losing state. The state is
650
594
  episodeId: params.episode_id ?? null,
651
595
  };
652
596
 
653
- store.saveCheckpoint(AGENT_ID, state);
597
+ await store.saveCheckpoint(AGENT_ID, state);
654
598
  log(AGENT_ID, 'checkpoint', `"${params.current_task}" decisions=${params.decisions.length} files=${params.active_files.length}`);
655
599
 
656
600
  return {
@@ -675,7 +619,7 @@ Returns:
675
619
  Use this at the start of every session or after compaction to pick up where you left off.`,
676
620
  {},
677
621
  async () => {
678
- const checkpoint = store.getCheckpoint(AGENT_ID);
622
+ const checkpoint = await store.getCheckpoint(AGENT_ID);
679
623
 
680
624
  const now = Date.now();
681
625
  const idleMs = checkpoint
@@ -685,7 +629,7 @@ Use this at the start of every session or after compaction to pick up where you
685
629
  // Get last written engram
686
630
  let lastWrite: { id: string; concept: string; content: string } | null = null;
687
631
  if (checkpoint?.auto.lastWriteId) {
688
- const engram = store.getEngram(checkpoint.auto.lastWriteId);
632
+ const engram = await store.getEngram(checkpoint.auto.lastWriteId);
689
633
  if (engram) {
690
634
  lastWrite = { id: engram.id, concept: engram.concept, content: engram.content };
691
635
  }
@@ -735,7 +679,7 @@ Use this at the start of every session or after compaction to pick up where you
735
679
  fullConsolidationTriggered = true;
736
680
  try {
737
681
  const result = await consolidationEngine.consolidate(AGENT_ID);
738
- store.markConsolidation(AGENT_ID, false);
682
+ await store.markConsolidation(AGENT_ID, false);
739
683
  log(AGENT_ID, 'consolidation', `full sleep cycle on restore (no graceful exit, idle ${Math.round(idleMs / 60_000)}min, last consolidation ${Math.round(sinceLastConsolidation / 60_000)}min ago) — ${result.edgesStrengthened} strengthened, ${result.memoriesForgotten} forgotten`);
740
684
  } catch { /* consolidation failure is non-fatal */ }
741
685
  } else {
@@ -833,7 +777,7 @@ Tasks automatically get high salience so they won't be discarded.`,
833
777
  blocked_by: z.string().optional().describe('ID of a task that must finish first'),
834
778
  },
835
779
  async (params) => {
836
- const engram = store.createEngram({
780
+ const engram = await store.createEngram({
837
781
  agentId: AGENT_ID,
838
782
  concept: params.concept,
839
783
  content: params.content,
@@ -856,8 +800,8 @@ Tasks automatically get high salience so they won't be discarded.`,
856
800
  connectionEngine.enqueue(engram.id);
857
801
 
858
802
  // Generate embedding asynchronously
859
- embed(`${params.concept} ${params.content}`).then(vec => {
860
- store.updateEmbedding(engram.id, vec);
803
+ embed(`${params.concept} ${params.content}`).then(async vec => {
804
+ await store.updateEmbedding(engram.id, vec);
861
805
  }).catch(() => {});
862
806
 
863
807
  return {
@@ -886,22 +830,22 @@ server.tool(
886
830
  blocked_by: z.string().optional().describe('ID of blocking task (set to empty string to unblock)'),
887
831
  },
888
832
  async (params) => {
889
- const engram = store.getEngram(params.task_id);
833
+ const engram = await store.getEngram(params.task_id);
890
834
  if (!engram || !engram.taskStatus) {
891
835
  return { content: [{ type: 'text' as const, text: `Task not found: ${params.task_id}` }] };
892
836
  }
893
837
 
894
838
  if (params.blocked_by !== undefined) {
895
- store.updateBlockedBy(params.task_id, params.blocked_by || null);
839
+ await store.updateBlockedBy(params.task_id, params.blocked_by || null);
896
840
  }
897
841
  if (params.status) {
898
- store.updateTaskStatus(params.task_id, params.status as TaskStatus);
842
+ await store.updateTaskStatus(params.task_id, params.status as TaskStatus);
899
843
  }
900
844
  if (params.priority) {
901
- store.updateTaskPriority(params.task_id, params.priority as TaskPriority);
845
+ await store.updateTaskPriority(params.task_id, params.priority as TaskPriority);
902
846
  }
903
847
 
904
- const updated = store.getEngram(params.task_id)!;
848
+ const updated = (await store.getEngram(params.task_id))!;
905
849
  return {
906
850
  content: [{
907
851
  type: 'text' as const,
@@ -923,7 +867,7 @@ Use at the start of a session to see what's pending, or to check blocked/done ta
923
867
  .describe('Include completed tasks?'),
924
868
  },
925
869
  async (params) => {
926
- let tasks = store.getTasks(AGENT_ID, params.status as TaskStatus | undefined);
870
+ let tasks = await store.getTasks(AGENT_ID, params.status as TaskStatus | undefined);
927
871
  if (!params.include_done && !params.status) {
928
872
  tasks = tasks.filter(t => t.taskStatus !== 'done');
929
873
  }
@@ -956,7 +900,7 @@ Prioritizes: in_progress tasks first (finish what you started), then by priority
956
900
  Use this when you finish a task or need to decide what to do next.`,
957
901
  {},
958
902
  async () => {
959
- const next = store.getNextTask(AGENT_ID);
903
+ const next = await store.getNextTask(AGENT_ID);
960
904
  if (!next) {
961
905
  return { content: [{ type: 'text' as const, text: 'No actionable tasks. All clear!' }] };
962
906
  }
@@ -994,10 +938,10 @@ This ensures your state is saved before you start, and primes recall with releva
994
938
  },
995
939
  async (params) => {
996
940
  // 1. Checkpoint current state
997
- const checkpoint = store.getCheckpoint(AGENT_ID);
941
+ const checkpoint = await store.getCheckpoint(AGENT_ID);
998
942
  const prevTask = checkpoint?.executionState?.currentTask ?? 'None';
999
943
 
1000
- store.saveCheckpoint(AGENT_ID, {
944
+ await store.saveCheckpoint(AGENT_ID, {
1001
945
  currentTask: params.topic,
1002
946
  decisions: [],
1003
947
  activeFiles: params.files,
@@ -1028,7 +972,7 @@ This ensures your state is saved before you start, and primes recall with releva
1028
972
  recalledSummary = `\n\n**Recalled memories (${results.length}):**\n${lines.join('\n')}`;
1029
973
 
1030
974
  // Track recall
1031
- store.updateAutoCheckpointRecall(AGENT_ID, params.topic, results.map(r => r.engram.id));
975
+ await store.updateAutoCheckpointRecall(AGENT_ID, params.topic, results.map(r => r.engram.id));
1032
976
  }
1033
977
  } catch { /* recall failure is non-fatal */ }
1034
978
 
@@ -1072,7 +1016,7 @@ This captures what was accomplished so future sessions can recall it.`,
1072
1016
  });
1073
1017
 
1074
1018
  // Determine the real task name for the summary engram
1075
- const checkpoint = store.getCheckpoint(AGENT_ID);
1019
+ const checkpoint = await store.getCheckpoint(AGENT_ID);
1076
1020
  const rawTask = checkpoint?.executionState?.currentTask ?? 'Unknown task';
1077
1021
  // Strip any "Completed: " prefixes to avoid cascading
1078
1022
  const cleanedTask = rawTask.replace(/^(Completed: )+/, '');
@@ -1082,7 +1026,7 @@ This captures what was accomplished so future sessions can recall it.`,
1082
1026
  ? cleanedTask
1083
1027
  : params.summary.slice(0, 60).replace(/\n/g, ' ');
1084
1028
 
1085
- const engram = store.createEngram({
1029
+ const engram = await store.createEngram({
1086
1030
  agentId: AGENT_ID,
1087
1031
  concept: completedTask.slice(0, 80),
1088
1032
  content: params.summary,
@@ -1098,22 +1042,22 @@ This captures what was accomplished so future sessions can recall it.`,
1098
1042
  // 2. Handle supersessions — mark old memories as outdated
1099
1043
  let supersededCount = 0;
1100
1044
  for (const oldId of params.supersedes) {
1101
- const oldEngram = store.getEngram(oldId);
1045
+ const oldEngram = await store.getEngram(oldId);
1102
1046
  if (oldEngram) {
1103
- store.supersedeEngram(oldId, engram.id);
1104
- store.upsertAssociation(engram.id, oldId, 0.8, 'causal', 0.9);
1105
- store.updateConfidence(oldId, Math.max(0.2, oldEngram.confidence * 0.4));
1047
+ await store.supersedeEngram(oldId, engram.id);
1048
+ await store.upsertAssociation(engram.id, oldId, 0.8, 'causal', 0.9);
1049
+ await store.updateConfidence(oldId, Math.max(0.2, oldEngram.confidence * 0.4));
1106
1050
  supersededCount++;
1107
1051
  }
1108
1052
  }
1109
1053
 
1110
1054
  // Generate embedding asynchronously
1111
- embed(`Task completed: ${params.summary}`).then(vec => {
1112
- store.updateEmbedding(engram.id, vec);
1055
+ embed(`Task completed: ${params.summary}`).then(async vec => {
1056
+ await store.updateEmbedding(engram.id, vec);
1113
1057
  }).catch(() => {});
1114
1058
 
1115
1059
  // 2. Update checkpoint to reflect completion
1116
- store.saveCheckpoint(AGENT_ID, {
1060
+ await store.saveCheckpoint(AGENT_ID, {
1117
1061
  currentTask: `Completed: ${completedTask}`,
1118
1062
  decisions: checkpoint?.executionState?.decisions ?? [],
1119
1063
  activeFiles: [],
@@ -1123,7 +1067,7 @@ This captures what was accomplished so future sessions can recall it.`,
1123
1067
  episodeId: null,
1124
1068
  });
1125
1069
 
1126
- store.updateAutoCheckpointWrite(AGENT_ID, engram.id);
1070
+ await store.updateAutoCheckpointWrite(AGENT_ID, engram.id);
1127
1071
  log(AGENT_ID, 'task:end', `"${completedTask}" summary=${engram.id} salience=${salience.score.toFixed(2)} superseded=${supersededCount}`);
1128
1072
 
1129
1073
  const supersededNote = supersededCount > 0 ? ` (${supersededCount} old memories superseded)` : '';
@@ -1151,19 +1095,26 @@ async function main() {
1151
1095
  onConsolidate: async (agentId, reason) => {
1152
1096
  console.error(`[mcp] consolidation triggered: ${reason}`);
1153
1097
  const result = await consolidationEngine.consolidate(agentId);
1154
- store.markConsolidation(agentId, false);
1098
+ await store.markConsolidation(agentId, false);
1155
1099
  console.error(`[mcp] consolidation done: ${result.edgesStrengthened} strengthened, ${result.memoriesForgotten} forgotten`);
1156
1100
  },
1157
1101
  });
1158
1102
 
1159
1103
  // Coordination MCP tools (opt-in via AWM_COORDINATION=true)
1160
- const coordEnabled = process.env.AWM_COORDINATION === 'true' || process.env.AWM_COORDINATION === '1';
1104
+ // AWM 0.8.x: coordination requires SQLite (uses store.getDb()). On PGlite,
1105
+ // coordination is auto-disabled with a warning; re-enable when coordination
1106
+ // is ported to async/PGlite.
1107
+ const coordRequested = process.env.AWM_COORDINATION === 'true' || process.env.AWM_COORDINATION === '1';
1108
+ const coordEnabled = coordRequested && BACKEND === 'sqlite';
1161
1109
  if (coordEnabled) {
1162
1110
  const { initCoordinationTables } = await import('./coordination/schema.js');
1163
1111
  const { registerCoordinationTools } = await import('./coordination/mcp-tools.js');
1164
- initCoordinationTables(store.getDb());
1165
- registerCoordinationTools(server, store.getDb());
1166
- coordDb = store.getDb();
1112
+ const sqliteStore = store as unknown as EngramStore;
1113
+ initCoordinationTables(sqliteStore.getDb());
1114
+ registerCoordinationTools(server, sqliteStore.getDb());
1115
+ coordDb = sqliteStore.getDb();
1116
+ } else if (coordRequested && BACKEND === 'pglite') {
1117
+ console.error('AWM: coordination requested but disabled — coordination plugin requires SQLite backend');
1167
1118
  } else {
1168
1119
  console.error('AWM: coordination tools disabled (set AWM_COORDINATION=true to enable)');
1169
1120
  }
@@ -1173,15 +1124,17 @@ async function main() {
1173
1124
  console.error(`Hook sidecar on 127.0.0.1:${HOOK_PORT}${HOOK_SECRET ? ' (auth enabled)' : ' (no auth — set AWM_HOOK_SECRET)'}`);
1174
1125
 
1175
1126
  // Clean shutdown
1176
- const cleanup = () => {
1127
+ const cleanup = async () => {
1177
1128
  sidecar.close();
1178
1129
  consolidationScheduler.stop();
1179
1130
  stagingBuffer.stop();
1180
- try { store.walCheckpoint(); } catch { /* non-fatal */ }
1181
- store.close();
1131
+ if (BACKEND === 'sqlite') {
1132
+ try { (store as Partial<EngramStore>).walCheckpoint?.(); } catch { /* non-fatal */ }
1133
+ }
1134
+ try { await (store as any).close?.(); } catch { /* best-effort */ }
1182
1135
  };
1183
- process.on('SIGINT', () => { cleanup(); process.exit(0); });
1184
- process.on('SIGTERM', () => { cleanup(); process.exit(0); });
1136
+ process.on('SIGINT', () => { void cleanup().finally(() => process.exit(0)); });
1137
+ process.on('SIGTERM', () => { void cleanup().finally(() => process.exit(0)); });
1185
1138
  }
1186
1139
 
1187
1140
  main().catch(err => {