agent-working-memory 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -9
- package/dist/adapters/claude-code.d.ts +4 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +218 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +4 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +226 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/common.d.ts +34 -0
- package/dist/adapters/common.d.ts.map +1 -0
- package/dist/adapters/common.js +145 -0
- package/dist/adapters/common.js.map +1 -0
- package/dist/adapters/cursor.d.ts +4 -0
- package/dist/adapters/cursor.d.ts.map +1 -0
- package/dist/adapters/cursor.js +138 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/http.d.ts +4 -0
- package/dist/adapters/http.d.ts.map +1 -0
- package/dist/adapters/http.js +88 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +21 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/types.d.ts +65 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +4 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +1 -0
- package/dist/api/routes.js.map +1 -1
- package/dist/cli.js +104 -230
- package/dist/cli.js.map +1 -1
- package/dist/coordination/events.d.ts +59 -0
- package/dist/coordination/events.d.ts.map +1 -0
- package/dist/coordination/events.js +28 -0
- package/dist/coordination/events.js.map +1 -0
- package/dist/coordination/index.d.ts +10 -1
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +87 -3
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/peer-decisions.d.ts +40 -0
- package/dist/coordination/peer-decisions.d.ts.map +1 -0
- package/dist/coordination/peer-decisions.js +82 -0
- package/dist/coordination/peer-decisions.js.map +1 -0
- package/dist/coordination/plugin-loader.d.ts +18 -0
- package/dist/coordination/plugin-loader.d.ts.map +1 -0
- package/dist/coordination/plugin-loader.js +55 -0
- package/dist/coordination/plugin-loader.js.map +1 -0
- package/dist/coordination/plugin.d.ts +40 -0
- package/dist/coordination/plugin.d.ts.map +1 -0
- package/dist/coordination/plugin.js +22 -0
- package/dist/coordination/plugin.js.map +1 -0
- package/dist/coordination/routes.d.ts +2 -1
- package/dist/coordination/routes.d.ts.map +1 -1
- package/dist/coordination/routes.js +899 -76
- package/dist/coordination/routes.js.map +1 -1
- package/dist/coordination/schema.d.ts.map +1 -1
- package/dist/coordination/schema.js +72 -14
- package/dist/coordination/schema.js.map +1 -1
- package/dist/coordination/schemas.d.ts +84 -3
- package/dist/coordination/schemas.d.ts.map +1 -1
- package/dist/coordination/schemas.js +71 -1
- package/dist/coordination/schemas.js.map +1 -1
- package/dist/coordination/stale.d.ts.map +1 -1
- package/dist/coordination/stale.js +2 -1
- package/dist/coordination/stale.js.map +1 -1
- package/dist/coordination/types.d.ts +252 -0
- package/dist/coordination/types.d.ts.map +1 -0
- package/dist/coordination/types.js +8 -0
- package/dist/coordination/types.js.map +1 -0
- package/dist/coordination/write-mutex.d.ts +26 -0
- package/dist/coordination/write-mutex.d.ts.map +1 -0
- package/dist/coordination/write-mutex.js +63 -0
- package/dist/coordination/write-mutex.js.map +1 -0
- package/dist/core/embeddings.d.ts +2 -0
- package/dist/core/embeddings.d.ts.map +1 -1
- package/dist/core/embeddings.js +4 -0
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/hebbian.d.ts +25 -1
- package/dist/core/hebbian.d.ts.map +1 -1
- package/dist/core/hebbian.js +71 -3
- package/dist/core/hebbian.js.map +1 -1
- package/dist/engine/activation.d.ts +22 -4
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +152 -76
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/consolidation.d.ts.map +1 -1
- package/dist/engine/consolidation.js +15 -6
- package/dist/engine/consolidation.js.map +1 -1
- package/dist/engine/retraction.d.ts +3 -1
- package/dist/engine/retraction.d.ts.map +1 -1
- package/dist/engine/retraction.js +19 -6
- package/dist/engine/retraction.js.map +1 -1
- package/dist/index.js +6 -18
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +61 -4
- package/dist/mcp.js.map +1 -1
- package/dist/storage/sqlite.d.ts +23 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +112 -3
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/types/engram.d.ts +1 -0
- package/dist/types/engram.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude-code.ts +234 -0
- package/src/adapters/codex.ts +262 -0
- package/src/adapters/common.ts +172 -0
- package/src/adapters/cursor.ts +150 -0
- package/src/adapters/http.ts +100 -0
- package/src/adapters/index.ts +31 -0
- package/src/adapters/types.ts +75 -0
- package/src/api/routes.ts +2 -0
- package/src/cli.ts +107 -238
- package/src/coordination/events.ts +90 -0
- package/src/coordination/index.ts +102 -3
- package/src/coordination/peer-decisions.ts +105 -0
- package/src/coordination/plugin-loader.ts +60 -0
- package/src/coordination/plugin.ts +44 -0
- package/src/coordination/routes.ts +1176 -105
- package/src/coordination/schema.ts +67 -14
- package/src/coordination/schemas.ts +85 -1
- package/src/coordination/stale.ts +3 -2
- package/src/coordination/types.ts +311 -0
- package/src/coordination/write-mutex.ts +69 -0
- package/src/core/embeddings.ts +5 -0
- package/src/core/hebbian.ts +84 -3
- package/src/engine/activation.ts +149 -73
- package/src/engine/consolidation.ts +15 -6
- package/src/engine/retraction.ts +22 -6
- package/src/index.ts +6 -15
- package/src/mcp.ts +77 -4
- package/src/storage/sqlite.ts +116 -3
- package/src/types/engram.ts +1 -0
package/src/mcp.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
import { readFileSync } from 'node:fs';
|
|
28
28
|
import { resolve } from 'node:path';
|
|
29
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
29
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
30
30
|
|
|
31
31
|
// Load .env file if present (no external dependency)
|
|
32
32
|
try {
|
|
@@ -42,6 +42,12 @@ try {
|
|
|
42
42
|
if (!process.env[key]) process.env[key] = val;
|
|
43
43
|
}
|
|
44
44
|
} catch { /* No .env file */ }
|
|
45
|
+
|
|
46
|
+
// MCP uses stdout for JSON-RPC. Redirect console.log to stderr so engine
|
|
47
|
+
// startup messages (ConsolidationScheduler, model loading, etc.) don't
|
|
48
|
+
// corrupt the transport. This MUST happen before any engine imports.
|
|
49
|
+
console.log = console.error;
|
|
50
|
+
|
|
45
51
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
46
52
|
import { z } from 'zod';
|
|
47
53
|
|
|
@@ -62,6 +68,7 @@ import { DEFAULT_AGENT_CONFIG } from './types/agent.js';
|
|
|
62
68
|
import { embed } from './core/embeddings.js';
|
|
63
69
|
import { startSidecar } from './hooks/sidecar.js';
|
|
64
70
|
import { initLogger, log, getLogPath } from './core/logger.js';
|
|
71
|
+
import { queryPeerDecisions, formatPeerDecisions } from './coordination/peer-decisions.js';
|
|
65
72
|
|
|
66
73
|
// --- Incognito Mode ---
|
|
67
74
|
// When AWM_INCOGNITO=1, register zero tools. Claude won't see memory tools at all.
|
|
@@ -111,6 +118,58 @@ const server = new McpServer({
|
|
|
111
118
|
version: '0.6.0',
|
|
112
119
|
});
|
|
113
120
|
|
|
121
|
+
server.registerResource(
|
|
122
|
+
'awm-overview',
|
|
123
|
+
'awm://server/overview',
|
|
124
|
+
{
|
|
125
|
+
title: 'AWM Overview',
|
|
126
|
+
description: 'AgentWorkingMemory MCP server metadata and discovery notes',
|
|
127
|
+
mimeType: 'text/markdown',
|
|
128
|
+
},
|
|
129
|
+
async () => ({
|
|
130
|
+
contents: [{
|
|
131
|
+
uri: 'awm://server/overview',
|
|
132
|
+
text: [
|
|
133
|
+
'# Agent Working Memory',
|
|
134
|
+
'',
|
|
135
|
+
`Agent: ${AGENT_ID}`,
|
|
136
|
+
`DB: ${DB_PATH}`,
|
|
137
|
+
`Coordination: ${process.env.AWM_COORDINATION === 'true' || process.env.AWM_COORDINATION === '1' ? 'enabled' : 'disabled'}`,
|
|
138
|
+
'',
|
|
139
|
+
'This MCP server primarily exposes tools such as `memory_restore`, `memory_recall`, `memory_write`, and task/checkpoint operations.',
|
|
140
|
+
'The resources below exist so generic MCP clients can discover the server through `resources/list` and `resources/templates/list`.',
|
|
141
|
+
].join('\n'),
|
|
142
|
+
mimeType: 'text/markdown',
|
|
143
|
+
}],
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
server.registerResource(
|
|
148
|
+
'awm-memory-template',
|
|
149
|
+
new ResourceTemplate('awm://memory/{id}', { list: undefined }),
|
|
150
|
+
{
|
|
151
|
+
title: 'AWM Memory By ID',
|
|
152
|
+
description: 'Metadata resource template for a memory identifier',
|
|
153
|
+
mimeType: 'text/markdown',
|
|
154
|
+
},
|
|
155
|
+
async (_uri, variables) => ({
|
|
156
|
+
contents: [{
|
|
157
|
+
uri: `awm://memory/${variables.id ?? ''}`,
|
|
158
|
+
text: [
|
|
159
|
+
'# AWM Memory Reference',
|
|
160
|
+
'',
|
|
161
|
+
`Requested memory id: ${variables.id ?? ''}`,
|
|
162
|
+
'',
|
|
163
|
+
'Use the AWM memory tools for actual retrieval and mutation:',
|
|
164
|
+
'- `memory_recall` for cognitive retrieval',
|
|
165
|
+
'- `memory_restore` for session state',
|
|
166
|
+
'- `memory_feedback`, `memory_retract`, `memory_supersede` for memory maintenance',
|
|
167
|
+
].join('\n'),
|
|
168
|
+
mimeType: 'text/markdown',
|
|
169
|
+
}],
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
|
|
114
173
|
// --- Auto-classification for memory types ---
|
|
115
174
|
|
|
116
175
|
function classifyMemoryType(content: string): 'episodic' | 'semantic' | 'procedural' | 'unclassified' {
|
|
@@ -319,6 +378,7 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
|
|
|
319
378
|
use_reranker: z.boolean().optional().default(true).describe('Use cross-encoder re-ranking for better relevance (default true)'),
|
|
320
379
|
use_expansion: z.boolean().optional().default(true).describe('Expand query with synonyms for better recall (default true)'),
|
|
321
380
|
memory_type: z.enum(['episodic', 'semantic', 'procedural']).optional().describe('Filter by memory type (omit to search all types)'),
|
|
381
|
+
workspace: z.string().optional().describe('Search across all agents in this workspace (hive mode). Omit for agent-scoped recall only.'),
|
|
322
382
|
},
|
|
323
383
|
async (params) => {
|
|
324
384
|
const queryText = params.query ?? params.context;
|
|
@@ -330,6 +390,8 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
|
|
|
330
390
|
}],
|
|
331
391
|
};
|
|
332
392
|
}
|
|
393
|
+
// Use workspace from param, env var, or omit for agent-scoped
|
|
394
|
+
const workspace = params.workspace ?? process.env.AWM_WORKSPACE ?? undefined;
|
|
333
395
|
const results = await activationEngine.activate({
|
|
334
396
|
agentId: AGENT_ID,
|
|
335
397
|
context: queryText,
|
|
@@ -339,6 +401,7 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
|
|
|
339
401
|
useReranker: params.use_reranker,
|
|
340
402
|
useExpansion: params.use_expansion,
|
|
341
403
|
memoryType: params.memory_type,
|
|
404
|
+
workspace,
|
|
342
405
|
});
|
|
343
406
|
|
|
344
407
|
// Auto-checkpoint: track recall
|
|
@@ -349,11 +412,16 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
|
|
|
349
412
|
|
|
350
413
|
log(AGENT_ID, 'recall', `"${queryText.slice(0, 80)}" → ${results.length} results`);
|
|
351
414
|
|
|
415
|
+
// Peer decisions: append recent decisions by other agents relevant to this query
|
|
416
|
+
const peerSuffix = coordDb
|
|
417
|
+
? formatPeerDecisions(queryPeerDecisions(coordDb, AGENT_ID, queryText))
|
|
418
|
+
: '';
|
|
419
|
+
|
|
352
420
|
if (results.length === 0) {
|
|
353
421
|
return {
|
|
354
422
|
content: [{
|
|
355
423
|
type: 'text' as const,
|
|
356
|
-
text: 'No relevant memories found.',
|
|
424
|
+
text: 'No relevant memories found.' + peerSuffix,
|
|
357
425
|
}],
|
|
358
426
|
};
|
|
359
427
|
}
|
|
@@ -365,7 +433,7 @@ Returns the most relevant memories ranked by text relevance, temporal recency, a
|
|
|
365
433
|
return {
|
|
366
434
|
content: [{
|
|
367
435
|
type: 'text' as const,
|
|
368
|
-
text: lines.join('\n'),
|
|
436
|
+
text: lines.join('\n') + peerSuffix,
|
|
369
437
|
}],
|
|
370
438
|
};
|
|
371
439
|
}
|
|
@@ -392,10 +460,13 @@ Always call this after using a recalled memory so the system learns what's valua
|
|
|
392
460
|
store.updateConfidence(engram.id, engram.confidence + delta);
|
|
393
461
|
}
|
|
394
462
|
|
|
463
|
+
// Validation-gated Hebbian: resolve pending co-activation pairs for this engram
|
|
464
|
+
const hebbianUpdated = activationEngine.resolveHebbianFeedback(params.engram_id, params.useful);
|
|
465
|
+
|
|
395
466
|
return {
|
|
396
467
|
content: [{
|
|
397
468
|
type: 'text' as const,
|
|
398
|
-
text: `Feedback: ${params.useful ? '+useful' : '-not useful'}`,
|
|
469
|
+
text: `Feedback: ${params.useful ? '+useful' : '-not useful'}${hebbianUpdated > 0 ? ` (${hebbianUpdated} association${hebbianUpdated > 1 ? 's' : ''} ${params.useful ? 'strengthened' : 'weakened'})` : ''}`,
|
|
399
470
|
}],
|
|
400
471
|
};
|
|
401
472
|
}
|
|
@@ -609,6 +680,7 @@ Use this at the start of every session or after compaction to pick up where you
|
|
|
609
680
|
minScore: 0.05,
|
|
610
681
|
useReranker: true,
|
|
611
682
|
useExpansion: true,
|
|
683
|
+
workspace: process.env.AWM_WORKSPACE ?? undefined,
|
|
612
684
|
});
|
|
613
685
|
recalledMemories = results.map(r => ({
|
|
614
686
|
id: r.engram.id,
|
|
@@ -919,6 +991,7 @@ This ensures your state is saved before you start, and primes recall with releva
|
|
|
919
991
|
minScore: 0.05,
|
|
920
992
|
useReranker: true,
|
|
921
993
|
useExpansion: true,
|
|
994
|
+
workspace: process.env.AWM_WORKSPACE ?? undefined,
|
|
922
995
|
});
|
|
923
996
|
|
|
924
997
|
if (results.length > 0) {
|
package/src/storage/sqlite.ts
CHANGED
|
@@ -30,6 +30,7 @@ const DEFAULT_SALIENCE_FEATURES: SalienceFeatures = {
|
|
|
30
30
|
|
|
31
31
|
export class EngramStore {
|
|
32
32
|
private db: Database.Database;
|
|
33
|
+
private walTimer: ReturnType<typeof setInterval> | null = null;
|
|
33
34
|
|
|
34
35
|
constructor(dbPath: string = 'memory.db') {
|
|
35
36
|
this.db = new Database(dbPath);
|
|
@@ -37,7 +38,9 @@ export class EngramStore {
|
|
|
37
38
|
this.db.pragma('foreign_keys = ON');
|
|
38
39
|
this.db.pragma('busy_timeout = 5000');
|
|
39
40
|
this.db.pragma('synchronous = NORMAL');
|
|
41
|
+
this.db.pragma('wal_autocheckpoint = 1000');
|
|
40
42
|
this.init();
|
|
43
|
+
this.startWalCheckpointTimer();
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
/** Expose the raw database handle for the coordination module. */
|
|
@@ -63,7 +66,27 @@ export class EngramStore {
|
|
|
63
66
|
|
|
64
67
|
/** Flush WAL to main database file. */
|
|
65
68
|
walCheckpoint(): void {
|
|
66
|
-
|
|
69
|
+
try {
|
|
70
|
+
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
71
|
+
} catch {
|
|
72
|
+
// Checkpoint can fail if another connection holds the DB; non-fatal
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Start periodic WAL checkpoint every 5 minutes to prevent unbounded WAL growth. */
|
|
77
|
+
private startWalCheckpointTimer(): void {
|
|
78
|
+
this.walTimer = setInterval(() => {
|
|
79
|
+
this.walCheckpoint();
|
|
80
|
+
}, 5 * 60 * 1000);
|
|
81
|
+
this.walTimer.unref();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Stop the WAL checkpoint timer (call before close). */
|
|
85
|
+
stopWalCheckpointTimer(): void {
|
|
86
|
+
if (this.walTimer) {
|
|
87
|
+
clearInterval(this.walTimer);
|
|
88
|
+
this.walTimer = null;
|
|
89
|
+
}
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
private init(): void {
|
|
@@ -212,6 +235,13 @@ export class EngramStore {
|
|
|
212
235
|
`);
|
|
213
236
|
}
|
|
214
237
|
|
|
238
|
+
// Migration: add embedding_model for version tracking (prevents drift on model change)
|
|
239
|
+
try {
|
|
240
|
+
this.db.prepare('SELECT embedding_model FROM engrams LIMIT 0').get();
|
|
241
|
+
} catch {
|
|
242
|
+
this.db.exec(`ALTER TABLE engrams ADD COLUMN embedding_model TEXT`);
|
|
243
|
+
}
|
|
244
|
+
|
|
215
245
|
// Migration: add conscious_state table for checkpointing
|
|
216
246
|
this.db.exec(`
|
|
217
247
|
CREATE TABLE IF NOT EXISTS conscious_state (
|
|
@@ -299,6 +329,83 @@ export class EngramStore {
|
|
|
299
329
|
return (this.db.prepare(query).all(...params) as any[]).map(r => this.rowToEngram(r));
|
|
300
330
|
}
|
|
301
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Get engrams across multiple agents (workspace-scoped recall).
|
|
334
|
+
* Used when workspace mode is enabled for hive memory sharing.
|
|
335
|
+
*/
|
|
336
|
+
getEngramsByAgents(agentIds: string[], stage?: EngramStage, includeRetracted: boolean = false): Engram[] {
|
|
337
|
+
if (agentIds.length === 0) return [];
|
|
338
|
+
if (agentIds.length === 1) return this.getEngramsByAgent(agentIds[0], stage, includeRetracted);
|
|
339
|
+
|
|
340
|
+
const placeholders = agentIds.map(() => '?').join(',');
|
|
341
|
+
let query = `SELECT * FROM engrams WHERE agent_id IN (${placeholders})`;
|
|
342
|
+
const params: any[] = [...agentIds];
|
|
343
|
+
|
|
344
|
+
if (stage) {
|
|
345
|
+
query += ' AND stage = ?';
|
|
346
|
+
params.push(stage);
|
|
347
|
+
}
|
|
348
|
+
if (!includeRetracted) {
|
|
349
|
+
query += ' AND retracted = 0';
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return (this.db.prepare(query).all(...params) as any[]).map(r => this.rowToEngram(r));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* BM25 search across multiple agents (workspace-scoped).
|
|
357
|
+
*/
|
|
358
|
+
searchBM25WithRankMultiAgent(agentIds: string[], query: string, limit: number = 10): { engram: Engram; bm25Score: number }[] {
|
|
359
|
+
if (agentIds.length === 0) return [];
|
|
360
|
+
if (agentIds.length === 1) return this.searchBM25WithRank(agentIds[0], query, limit);
|
|
361
|
+
|
|
362
|
+
const sanitized = query
|
|
363
|
+
.replace(/[^\w\s]/g, '')
|
|
364
|
+
.split(/\s+/)
|
|
365
|
+
.filter(w => w.length > 1)
|
|
366
|
+
.map(w => `"${w}"`)
|
|
367
|
+
.join(' OR ');
|
|
368
|
+
|
|
369
|
+
if (!sanitized) return [];
|
|
370
|
+
|
|
371
|
+
try {
|
|
372
|
+
const placeholders = agentIds.map(() => '?').join(',');
|
|
373
|
+
const rows = this.db.prepare(`
|
|
374
|
+
SELECT e.*, rank FROM engrams e
|
|
375
|
+
JOIN engrams_fts ON e.rowid = engrams_fts.rowid
|
|
376
|
+
WHERE engrams_fts MATCH ? AND e.agent_id IN (${placeholders}) AND e.retracted = 0
|
|
377
|
+
ORDER BY rank
|
|
378
|
+
LIMIT ?
|
|
379
|
+
`).all(sanitized, ...agentIds, limit) as any[];
|
|
380
|
+
|
|
381
|
+
return rows.map(r => ({
|
|
382
|
+
engram: this.rowToEngram(r),
|
|
383
|
+
bm25Score: Math.abs(r.rank ?? 0) / (1 + Math.abs(r.rank ?? 0)),
|
|
384
|
+
}));
|
|
385
|
+
} catch {
|
|
386
|
+
return [];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get all distinct agent IDs that share a workspace (requires coord_agents table).
|
|
392
|
+
* Returns just the queried agentId if coordination tables don't exist.
|
|
393
|
+
*/
|
|
394
|
+
getWorkspaceAgentIds(agentId: string, workspace: string): string[] {
|
|
395
|
+
try {
|
|
396
|
+
const rows = this.db.prepare(
|
|
397
|
+
`SELECT DISTINCT id FROM coord_agents WHERE workspace = ? AND status != 'dead'`
|
|
398
|
+
).all(workspace) as Array<{ id: string }>;
|
|
399
|
+
const ids = rows.map(r => r.id);
|
|
400
|
+
// Ensure the querying agent is always included
|
|
401
|
+
if (!ids.includes(agentId)) ids.push(agentId);
|
|
402
|
+
return ids;
|
|
403
|
+
} catch {
|
|
404
|
+
// No coordination tables — fall back to single agent
|
|
405
|
+
return [agentId];
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
302
409
|
/**
|
|
303
410
|
* Touch an engram: increment access count, update last_accessed, and
|
|
304
411
|
* nudge confidence upward. Each retrieval is weak evidence the memory
|
|
@@ -327,9 +434,13 @@ export class EngramStore {
|
|
|
327
434
|
);
|
|
328
435
|
}
|
|
329
436
|
|
|
330
|
-
updateEmbedding(id: string, embedding: number[]): void {
|
|
437
|
+
updateEmbedding(id: string, embedding: number[], modelId?: string): void {
|
|
331
438
|
const blob = Buffer.from(new Float32Array(embedding).buffer);
|
|
332
|
-
|
|
439
|
+
if (modelId) {
|
|
440
|
+
this.db.prepare('UPDATE engrams SET embedding = ?, embedding_model = ? WHERE id = ?').run(blob, modelId, id);
|
|
441
|
+
} else {
|
|
442
|
+
this.db.prepare('UPDATE engrams SET embedding = ? WHERE id = ?').run(blob, id);
|
|
443
|
+
}
|
|
333
444
|
}
|
|
334
445
|
|
|
335
446
|
retractEngram(id: string, retractedBy: string | null): void {
|
|
@@ -1012,6 +1123,8 @@ export class EngramStore {
|
|
|
1012
1123
|
}
|
|
1013
1124
|
|
|
1014
1125
|
close(): void {
|
|
1126
|
+
this.stopWalCheckpointTimer();
|
|
1127
|
+
this.walCheckpoint();
|
|
1015
1128
|
this.db.close();
|
|
1016
1129
|
}
|
|
1017
1130
|
}
|
package/src/types/engram.ts
CHANGED
|
@@ -186,6 +186,7 @@ export interface ActivationQuery {
|
|
|
186
186
|
internal?: boolean; // Skip access count increment, Hebbian update, and event logging (for system calls)
|
|
187
187
|
memoryType?: MemoryType; // Filter by memory type (episodic, semantic, procedural)
|
|
188
188
|
mode?: QueryMode; // Pipeline mode — 'auto' by default
|
|
189
|
+
workspace?: string; // Search across all agents in this workspace (hive mode). If unset, agent-scoped only.
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
/**
|