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.
- package/README.md +156 -15
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +2 -16
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/codex.js +2 -11
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/common.d.ts +18 -0
- package/dist/adapters/common.d.ts.map +1 -1
- package/dist/adapters/common.js +254 -141
- package/dist/adapters/common.js.map +1 -1
- package/dist/adapters/cursor.d.ts.map +1 -1
- package/dist/adapters/cursor.js +2 -15
- package/dist/adapters/cursor.js.map +1 -1
- package/dist/adapters/http.d.ts.map +1 -1
- package/dist/adapters/http.js +28 -34
- package/dist/adapters/http.js.map +1 -1
- package/dist/api/routes.d.ts +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +280 -113
- package/dist/api/routes.js.map +1 -1
- package/dist/cli/migrate.d.ts +42 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli/migrate.js +268 -0
- package/dist/cli/migrate.js.map +1 -0
- package/dist/cli.js +45 -1
- package/dist/cli.js.map +1 -1
- package/dist/coordination/circuit-breaker.d.ts +24 -0
- package/dist/coordination/circuit-breaker.d.ts.map +1 -0
- package/dist/coordination/circuit-breaker.js +70 -0
- package/dist/coordination/circuit-breaker.js.map +1 -0
- package/dist/coordination/failure-modes.d.ts +21 -0
- package/dist/coordination/failure-modes.d.ts.map +1 -0
- package/dist/coordination/failure-modes.js +49 -0
- package/dist/coordination/failure-modes.js.map +1 -0
- package/dist/coordination/peer-decisions.js +7 -7
- package/dist/coordination/routes.d.ts.map +1 -1
- package/dist/coordination/routes.js +44 -1
- package/dist/coordination/routes.js.map +1 -1
- package/dist/coordination/schema.d.ts.map +1 -1
- package/dist/coordination/schema.js +18 -0
- package/dist/coordination/schema.js.map +1 -1
- package/dist/coordination/schemas.d.ts +9 -9
- package/dist/coordination/stale.d.ts +9 -1
- package/dist/coordination/stale.d.ts.map +1 -1
- package/dist/coordination/stale.js +53 -9
- package/dist/coordination/stale.js.map +1 -1
- package/dist/core/embeddings.d.ts +16 -10
- package/dist/core/embeddings.d.ts.map +1 -1
- package/dist/core/embeddings.js +54 -38
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/ml-worker-entry.d.ts +17 -0
- package/dist/core/ml-worker-entry.d.ts.map +1 -0
- package/dist/core/ml-worker-entry.js +193 -0
- package/dist/core/ml-worker-entry.js.map +1 -0
- package/dist/core/ml-worker.d.ts +59 -0
- package/dist/core/ml-worker.d.ts.map +1 -0
- package/dist/core/ml-worker.js +253 -0
- package/dist/core/ml-worker.js.map +1 -0
- package/dist/core/query-expander.d.ts +13 -15
- package/dist/core/query-expander.d.ts.map +1 -1
- package/dist/core/query-expander.js +48 -54
- package/dist/core/query-expander.js.map +1 -1
- package/dist/core/reranker.d.ts +9 -19
- package/dist/core/reranker.d.ts.map +1 -1
- package/dist/core/reranker.js +33 -35
- package/dist/core/reranker.js.map +1 -1
- package/dist/core/salience.d.ts +32 -5
- package/dist/core/salience.d.ts.map +1 -1
- package/dist/core/salience.js +201 -28
- package/dist/core/salience.js.map +1 -1
- package/dist/core/write-pipeline.d.ts +128 -0
- package/dist/core/write-pipeline.d.ts.map +1 -0
- package/dist/core/write-pipeline.js +405 -0
- package/dist/core/write-pipeline.js.map +1 -0
- package/dist/engine/activation.d.ts +2 -2
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +238 -115
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/confidence.d.ts +62 -0
- package/dist/engine/confidence.d.ts.map +1 -0
- package/dist/engine/confidence.js +100 -0
- package/dist/engine/confidence.js.map +1 -0
- package/dist/engine/connections.d.ts +47 -8
- package/dist/engine/connections.d.ts.map +1 -1
- package/dist/engine/connections.js +83 -22
- package/dist/engine/connections.js.map +1 -1
- package/dist/engine/consolidation-scheduler.d.ts +46 -10
- package/dist/engine/consolidation-scheduler.d.ts.map +1 -1
- package/dist/engine/consolidation-scheduler.js +170 -50
- package/dist/engine/consolidation-scheduler.js.map +1 -1
- package/dist/engine/consolidation.d.ts +16 -2
- package/dist/engine/consolidation.d.ts.map +1 -1
- package/dist/engine/consolidation.js +143 -44
- package/dist/engine/consolidation.js.map +1 -1
- package/dist/engine/eval.d.ts +2 -2
- package/dist/engine/eval.d.ts.map +1 -1
- package/dist/engine/eval.js +9 -9
- package/dist/engine/eval.js.map +1 -1
- package/dist/engine/eviction.d.ts +4 -4
- package/dist/engine/eviction.d.ts.map +1 -1
- package/dist/engine/eviction.js +15 -15
- package/dist/engine/eviction.js.map +1 -1
- package/dist/engine/retraction.d.ts +93 -5
- package/dist/engine/retraction.d.ts.map +1 -1
- package/dist/engine/retraction.js +238 -19
- package/dist/engine/retraction.js.map +1 -1
- package/dist/engine/staging.d.ts +1 -1
- package/dist/engine/staging.d.ts.map +1 -1
- package/dist/engine/staging.js +3 -3
- package/dist/engine/staging.js.map +1 -1
- package/dist/hooks/sidecar.d.ts +1 -1
- package/dist/hooks/sidecar.d.ts.map +1 -1
- package/dist/hooks/sidecar.js +4 -4
- package/dist/hooks/sidecar.js.map +1 -1
- package/dist/index.js +48 -31
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +110 -155
- package/dist/mcp.js.map +1 -1
- package/dist/storage/factory.d.ts +55 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/factory.js +135 -0
- package/dist/storage/factory.js.map +1 -0
- package/dist/storage/pglite-schema.d.ts +20 -0
- package/dist/storage/pglite-schema.d.ts.map +1 -0
- package/dist/storage/pglite-schema.js +165 -0
- package/dist/storage/pglite-schema.js.map +1 -0
- package/dist/storage/pglite.d.ts +187 -0
- package/dist/storage/pglite.d.ts.map +1 -0
- package/dist/storage/pglite.js +1114 -0
- package/dist/storage/pglite.js.map +1 -0
- package/dist/storage/sqlite.d.ts +117 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +357 -8
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/storage/store.d.ts +63 -0
- package/dist/storage/store.d.ts.map +1 -0
- package/dist/storage/store.js +27 -0
- package/dist/storage/store.js.map +1 -0
- package/dist/types/engram.d.ts +92 -2
- package/dist/types/engram.d.ts.map +1 -1
- package/dist/types/engram.js.map +1 -1
- package/package.json +3 -1
- package/src/adapters/claude-code.ts +218 -234
- package/src/adapters/codex.ts +252 -262
- package/src/adapters/common.ts +411 -284
- package/src/adapters/cursor.ts +135 -150
- package/src/adapters/http.ts +93 -100
- package/src/adapters/index.ts +31 -31
- package/src/adapters/types.ts +75 -75
- package/src/api/index.ts +3 -3
- package/src/api/routes.ts +367 -120
- package/src/cli/migrate.ts +307 -0
- package/src/cli.ts +37 -1
- package/src/coordination/circuit-breaker.ts +83 -0
- package/src/coordination/events.ts +90 -90
- package/src/coordination/failure-modes.ts +50 -0
- package/src/coordination/peer-decisions.ts +105 -105
- package/src/coordination/plugin-loader.ts +60 -60
- package/src/coordination/plugin.ts +44 -44
- package/src/coordination/routes.ts +56 -1
- package/src/coordination/schema.ts +13 -0
- package/src/coordination/stale.ts +80 -11
- package/src/coordination/types.ts +311 -311
- package/src/coordination/write-mutex.ts +69 -69
- package/src/core/auto-tagger.ts +168 -168
- package/src/core/decay.ts +63 -63
- package/src/core/embeddings.ts +110 -93
- package/src/core/index.ts +5 -5
- package/src/core/logger.ts +36 -36
- package/src/core/ml-worker-entry.ts +194 -0
- package/src/core/ml-worker.ts +281 -0
- package/src/core/query-expander.ts +122 -128
- package/src/core/reranker.ts +119 -125
- package/src/core/salience.ts +200 -33
- package/src/core/write-pipeline.ts +521 -0
- package/src/engine/activation.ts +235 -109
- package/src/engine/confidence.ts +120 -0
- package/src/engine/connections.ts +162 -103
- package/src/engine/consolidation-scheduler.ts +242 -125
- package/src/engine/consolidation.ts +138 -45
- package/src/engine/eval.ts +102 -102
- package/src/engine/eviction.ts +101 -101
- package/src/engine/index.ts +8 -8
- package/src/engine/retraction.ts +366 -116
- package/src/engine/staging.ts +74 -74
- package/src/hooks/sidecar.ts +5 -5
- package/src/index.ts +42 -28
- package/src/mcp.ts +105 -152
- package/src/storage/factory.ts +147 -0
- package/src/storage/index.ts +3 -3
- package/src/storage/pglite-schema.ts +166 -0
- package/src/storage/pglite.ts +1363 -0
- package/src/storage/sqlite.ts +402 -7
- package/src/storage/store.ts +80 -0
- package/src/types/agent.ts +67 -67
- package/src/types/checkpoint.ts +46 -46
- package/src/types/engram.ts +101 -3
- package/src/types/eval.ts +100 -100
- 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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
-
|
|
336
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
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
|
-
|
|
1181
|
-
|
|
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()
|
|
1184
|
-
process.on('SIGTERM', () => { cleanup()
|
|
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 => {
|