agent-working-memory 0.7.17 → 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/common.js +202 -202
- package/dist/adapters/http.js +22 -22
- package/dist/api/routes.d.ts +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +258 -79
- 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 +147 -103
- 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 +10 -2
- package/dist/core/write-pipeline.d.ts.map +1 -1
- package/dist/core/write-pipeline.js +218 -49
- package/dist/core/write-pipeline.js.map +1 -1
- 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 +167 -141
- 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 -218
- package/src/adapters/codex.ts +252 -252
- package/src/adapters/common.ts +411 -411
- package/src/adapters/cursor.ts +135 -135
- package/src/adapters/http.ts +93 -93
- 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 +970 -714
- package/src/cli/migrate.ts +307 -0
- package/src/cli.ts +755 -719
- 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 -343
- 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 +226 -212
- package/src/mcp.ts +1145 -1121
- 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/dist/adapters/http.js
CHANGED
|
@@ -9,28 +9,28 @@
|
|
|
9
9
|
import { existsSync } from 'node:fs';
|
|
10
10
|
import { join } from 'node:path';
|
|
11
11
|
import { AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
|
|
12
|
-
const HTTP_ADDENDUM = `
|
|
13
|
-
### HTTP API (for tools without MCP support)
|
|
14
|
-
|
|
15
|
-
If your tool doesn't support MCP, use the HTTP API directly:
|
|
16
|
-
|
|
17
|
-
**Base URL:** \`http://127.0.0.1:8400\`
|
|
18
|
-
|
|
19
|
-
| Method | Endpoint | Purpose |
|
|
20
|
-
|--------|----------|---------|
|
|
21
|
-
| GET | /memory/restore/:agentId | Restore context from prior sessions |
|
|
22
|
-
| POST | /memory/activate | Cognitive recall (use \`context\` field) |
|
|
23
|
-
| POST | /memory/write | Write a memory |
|
|
24
|
-
| POST | /memory/feedback | Report if memory was useful |
|
|
25
|
-
| POST | /memory/retract | Invalidate a wrong memory |
|
|
26
|
-
| POST | /memory/checkpoint | Save execution state |
|
|
27
|
-
| POST | /task/create | Create a task |
|
|
28
|
-
| POST | /task/update | Update task status |
|
|
29
|
-
| GET | /task/list/:agentId | List tasks |
|
|
30
|
-
| GET | /task/next/:agentId | Get next actionable task |
|
|
31
|
-
| GET | /health | Health check |
|
|
32
|
-
|
|
33
|
-
Start the server with: \`awm serve\`
|
|
12
|
+
const HTTP_ADDENDUM = `
|
|
13
|
+
### HTTP API (for tools without MCP support)
|
|
14
|
+
|
|
15
|
+
If your tool doesn't support MCP, use the HTTP API directly:
|
|
16
|
+
|
|
17
|
+
**Base URL:** \`http://127.0.0.1:8400\`
|
|
18
|
+
|
|
19
|
+
| Method | Endpoint | Purpose |
|
|
20
|
+
|--------|----------|---------|
|
|
21
|
+
| GET | /memory/restore/:agentId | Restore context from prior sessions |
|
|
22
|
+
| POST | /memory/activate | Cognitive recall (use \`context\` field) |
|
|
23
|
+
| POST | /memory/write | Write a memory |
|
|
24
|
+
| POST | /memory/feedback | Report if memory was useful |
|
|
25
|
+
| POST | /memory/retract | Invalidate a wrong memory |
|
|
26
|
+
| POST | /memory/checkpoint | Save execution state |
|
|
27
|
+
| POST | /task/create | Create a task |
|
|
28
|
+
| POST | /task/update | Update task status |
|
|
29
|
+
| GET | /task/list/:agentId | List tasks |
|
|
30
|
+
| GET | /task/next/:agentId | Get next actionable task |
|
|
31
|
+
| GET | /health | Health check |
|
|
32
|
+
|
|
33
|
+
Start the server with: \`awm serve\`
|
|
34
34
|
`;
|
|
35
35
|
const adapter = {
|
|
36
36
|
id: 'http',
|
package/dist/api/routes.d.ts
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* GET /health — health check
|
|
32
32
|
*/
|
|
33
33
|
import type { FastifyInstance } from 'fastify';
|
|
34
|
-
import type { EngramStore } from '../storage/
|
|
34
|
+
import type { IEngramStore as EngramStore } from '../storage/store.js';
|
|
35
35
|
import type { ActivationEngine } from '../engine/activation.js';
|
|
36
36
|
import type { ConnectionEngine } from '../engine/connections.js';
|
|
37
37
|
import type { EvictionEngine } from '../engine/eviction.js';
|
package/dist/api/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AASnF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,sBAAsB,EAAE,sBAAsB,CAAC;CAChD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CA04B3E"}
|
package/dist/api/routes.js
CHANGED
|
@@ -62,7 +62,21 @@ export function registerRoutes(app, deps) {
|
|
|
62
62
|
metaTags.push(`sid=${body.sessionId}`);
|
|
63
63
|
if (body.intent)
|
|
64
64
|
metaTags.push(`intent=${body.intent}`);
|
|
65
|
-
|
|
65
|
+
// Resolve references (0.8 Cluster D): if matchConcept is given without
|
|
66
|
+
// matchEngramId, look up the most recent active engram with that concept
|
|
67
|
+
// (+ optional matchTags) and store both. Stable link survives concept
|
|
68
|
+
// edits. No match found → store just matchConcept so the intent
|
|
69
|
+
// (link-to-future or link-to-deleted) is preserved.
|
|
70
|
+
const resolvedRefs = await Promise.all((body.references ?? []).map(async (ref) => {
|
|
71
|
+
if (!ref.matchEngramId && ref.matchConcept) {
|
|
72
|
+
const matched = await store.findActiveMatchByConcept(body.agentId, ref.matchConcept, ref.matchTags);
|
|
73
|
+
if (matched) {
|
|
74
|
+
return { type: ref.type, matchEngramId: matched.id, matchConcept: ref.matchConcept };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { type: ref.type, matchEngramId: ref.matchEngramId, matchConcept: ref.matchConcept };
|
|
78
|
+
}));
|
|
79
|
+
const result = await performWrite({ store, connectionEngine }, {
|
|
66
80
|
agentId: body.agentId,
|
|
67
81
|
concept: body.concept,
|
|
68
82
|
content: body.content,
|
|
@@ -74,10 +88,13 @@ export function registerRoutes(app, deps) {
|
|
|
74
88
|
causalDepth: body.causalDepth,
|
|
75
89
|
resolutionEffort: body.resolutionEffort,
|
|
76
90
|
confidence: body.confidence,
|
|
91
|
+
sequence: body.sequence,
|
|
92
|
+
embed: body.embed,
|
|
93
|
+
references: resolvedRefs.length > 0 ? resolvedRefs : undefined,
|
|
77
94
|
});
|
|
78
95
|
// Auto-checkpoint always (covers create, reinforce, and supersede).
|
|
79
96
|
try {
|
|
80
|
-
store.updateAutoCheckpointWrite(body.agentId, result.engram.id);
|
|
97
|
+
await store.updateAutoCheckpointWrite(body.agentId, result.engram.id);
|
|
81
98
|
}
|
|
82
99
|
catch { /* non-fatal */ }
|
|
83
100
|
if (result.action === 'reinforce') {
|
|
@@ -91,29 +108,40 @@ export function registerRoutes(app, deps) {
|
|
|
91
108
|
});
|
|
92
109
|
}
|
|
93
110
|
// create / supersede paths follow legacy temporal-edge + episode logic.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
catch { /* Temporal edge creation is non-fatal */ }
|
|
101
|
-
if (result.salience
|
|
102
|
-
&& (result.salience.disposition === 'active' || result.salience.disposition === 'discard')) {
|
|
111
|
+
// Structural-class writes (0.8 Cluster A) skip these: they're system-written
|
|
112
|
+
// event-log records, not conversational beats, so keeping them out of the
|
|
113
|
+
// temporal graph + episode index keeps cognitive retrieval clean.
|
|
114
|
+
const isStructural = body.memory_class === 'structural';
|
|
115
|
+
if (!isStructural) {
|
|
103
116
|
try {
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
117
|
+
const prev = await store.getLatestEngram(body.agentId, result.engram.id);
|
|
118
|
+
if (prev) {
|
|
119
|
+
await store.upsertAssociation(prev.id, result.engram.id, 0.3, 'temporal', 0.8);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch { /* Temporal edge creation is non-fatal */ }
|
|
123
|
+
if (result.salience
|
|
124
|
+
&& (result.salience.disposition === 'active' || result.salience.disposition === 'discard')) {
|
|
125
|
+
try {
|
|
126
|
+
let episode = await store.getActiveEpisode(body.agentId, 3600_000);
|
|
127
|
+
if (!episode) {
|
|
128
|
+
episode = await store.createEpisode({ agentId: body.agentId, label: body.concept });
|
|
129
|
+
}
|
|
130
|
+
await store.addEngramToEpisode(result.engram.id, episode.id);
|
|
107
131
|
}
|
|
108
|
-
|
|
132
|
+
catch { /* Episode assignment is non-fatal */ }
|
|
109
133
|
}
|
|
110
|
-
catch { /* Episode assignment is non-fatal */ }
|
|
111
134
|
}
|
|
112
135
|
const isLowSalience = result.salience?.disposition === 'discard';
|
|
113
136
|
return reply.code(201).send({
|
|
114
137
|
stored: true,
|
|
115
138
|
action: result.action,
|
|
139
|
+
// disposition: legacy field — 'low-salience' is returned for discard so
|
|
140
|
+
// callers know the engram was kept but marked low-value. The raw inner
|
|
141
|
+
// salience decision is exposed as `salienceDisposition` for callers
|
|
142
|
+
// (and tests) that want the unmapped value.
|
|
116
143
|
disposition: isLowSalience ? 'low-salience' : (result.salience?.disposition ?? 'active'),
|
|
144
|
+
salienceDisposition: result.salience?.disposition ?? null,
|
|
117
145
|
salience: result.salience?.score ?? 0,
|
|
118
146
|
reasonCodes: result.salience?.reasonCodes ?? [],
|
|
119
147
|
engram: result.engram,
|
|
@@ -137,7 +165,7 @@ export function registerRoutes(app, deps) {
|
|
|
137
165
|
const memTags = [...(mem.tags ?? [])];
|
|
138
166
|
if (sid)
|
|
139
167
|
memTags.push(`sid=${sid}`);
|
|
140
|
-
const engram = store.createEngram({
|
|
168
|
+
const engram = await store.createEngram({
|
|
141
169
|
agentId: body.agentId,
|
|
142
170
|
concept: mem.concept,
|
|
143
171
|
content: mem.content,
|
|
@@ -148,9 +176,9 @@ export function registerRoutes(app, deps) {
|
|
|
148
176
|
});
|
|
149
177
|
// Handle supersession inline — archive superseded memory to remove from active pool
|
|
150
178
|
if (mem.supersedes) {
|
|
151
|
-
store.supersedeEngram(mem.supersedes, engram.id);
|
|
152
|
-
store.updateConfidence(mem.supersedes, 0.1);
|
|
153
|
-
store.updateStage(mem.supersedes, 'archived'); // Remove from active search pool
|
|
179
|
+
await store.supersedeEngram(mem.supersedes, engram.id);
|
|
180
|
+
await store.updateConfidence(mem.supersedes, 0.1);
|
|
181
|
+
await store.updateStage(mem.supersedes, 'archived'); // Remove from active search pool
|
|
154
182
|
}
|
|
155
183
|
results.push({ id: engram.id, concept: mem.concept, disposition: 'active' });
|
|
156
184
|
}
|
|
@@ -160,13 +188,13 @@ export function registerRoutes(app, deps) {
|
|
|
160
188
|
const vecs = await embedBatch(texts);
|
|
161
189
|
for (let i = 0; i < vecs.length; i++) {
|
|
162
190
|
if (results[i]) {
|
|
163
|
-
store.updateEmbedding(results[i].id, vecs[i]);
|
|
191
|
+
await store.updateEmbedding(results[i].id, vecs[i]);
|
|
164
192
|
}
|
|
165
193
|
}
|
|
166
194
|
}
|
|
167
195
|
catch { /* Embedding failure is non-fatal */ }
|
|
168
196
|
try {
|
|
169
|
-
store.updateAutoCheckpointWrite(body.agentId, results[results.length - 1]?.id ?? '');
|
|
197
|
+
await store.updateAutoCheckpointWrite(body.agentId, results[results.length - 1]?.id ?? '');
|
|
170
198
|
}
|
|
171
199
|
catch { }
|
|
172
200
|
return reply.code(201).send({
|
|
@@ -185,33 +213,39 @@ export function registerRoutes(app, deps) {
|
|
|
185
213
|
useReranker: body.useReranker,
|
|
186
214
|
useExpansion: body.useExpansion,
|
|
187
215
|
abstentionThreshold: body.abstentionThreshold,
|
|
216
|
+
requireConfidence: body.requireConfidence,
|
|
188
217
|
workspace: body.workspace,
|
|
189
218
|
bm25Only: body.bm25Only,
|
|
219
|
+
granularity: body.granularity,
|
|
190
220
|
});
|
|
191
221
|
// Auto-checkpoint: track recall for consolidation scheduling
|
|
192
222
|
try {
|
|
193
223
|
const ids = results.map(r => r.engram.id);
|
|
194
|
-
store.updateAutoCheckpointRecall(body.agentId, body.context, ids);
|
|
224
|
+
await store.updateAutoCheckpointRecall(body.agentId, body.context, ids);
|
|
195
225
|
}
|
|
196
226
|
catch { /* non-fatal */ }
|
|
197
|
-
|
|
227
|
+
// Surface recall confidence as a top-level field too — same value is on
|
|
228
|
+
// every result, but it describes the recall as a whole, so exposing it
|
|
229
|
+
// once is easier for consumers (and lets them inspect 0-result recalls).
|
|
230
|
+
const confidence = results[0]?.confidence ?? 0;
|
|
231
|
+
return reply.send({ results, confidence });
|
|
198
232
|
});
|
|
199
233
|
app.post('/memory/feedback', async (req, reply) => {
|
|
200
234
|
const body = req.body;
|
|
201
|
-
store.logRetrievalFeedback(body.activationEventId ?? null, body.engramId, body.useful, body.context ?? '');
|
|
235
|
+
await store.logRetrievalFeedback(body.activationEventId ?? null, body.engramId, body.useful, body.context ?? '');
|
|
202
236
|
// Update engram confidence based on feedback
|
|
203
|
-
const engram = store.getEngram(body.engramId);
|
|
237
|
+
const engram = await store.getEngram(body.engramId);
|
|
204
238
|
if (engram) {
|
|
205
239
|
const config = DEFAULT_AGENT_CONFIG;
|
|
206
240
|
const delta = body.useful
|
|
207
241
|
? config.feedbackPositiveBoost
|
|
208
242
|
: -config.feedbackNegativePenalty;
|
|
209
|
-
store.updateConfidence(engram.id, engram.confidence + delta);
|
|
243
|
+
await store.updateConfidence(engram.id, engram.confidence + delta);
|
|
210
244
|
}
|
|
211
245
|
// Touch activity for consolidation scheduling
|
|
212
246
|
if (engram) {
|
|
213
247
|
try {
|
|
214
|
-
store.touchActivity(engram.agentId);
|
|
248
|
+
await store.touchActivity(engram.agentId);
|
|
215
249
|
}
|
|
216
250
|
catch { /* non-fatal */ }
|
|
217
251
|
}
|
|
@@ -219,7 +253,7 @@ export function registerRoutes(app, deps) {
|
|
|
219
253
|
});
|
|
220
254
|
app.post('/memory/retract', async (req, reply) => {
|
|
221
255
|
const body = req.body;
|
|
222
|
-
const result = retractionEngine.retract({
|
|
256
|
+
const result = await retractionEngine.retract({
|
|
223
257
|
agentId: body.agentId,
|
|
224
258
|
targetEngramId: body.targetEngramId,
|
|
225
259
|
reason: body.reason,
|
|
@@ -227,33 +261,83 @@ export function registerRoutes(app, deps) {
|
|
|
227
261
|
});
|
|
228
262
|
// Touch activity for consolidation scheduling
|
|
229
263
|
try {
|
|
230
|
-
store.touchActivity(body.agentId);
|
|
264
|
+
await store.touchActivity(body.agentId);
|
|
231
265
|
}
|
|
232
266
|
catch { /* non-fatal */ }
|
|
233
267
|
return reply.send(result);
|
|
234
268
|
});
|
|
235
269
|
app.post('/memory/supersede', async (req, reply) => {
|
|
236
270
|
const body = req.body;
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
if (
|
|
240
|
-
return reply.code(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
271
|
+
const isFormA = !!(body.oldEngramId && body.newEngramId);
|
|
272
|
+
const isFormB = !!(body.matchConcept && body.newEngram && body.agentId);
|
|
273
|
+
if (isFormA && isFormB) {
|
|
274
|
+
return reply.code(400).send({
|
|
275
|
+
error: 'Pass either {oldEngramId, newEngramId} (Form A) OR ' +
|
|
276
|
+
'{agentId, matchConcept, newEngram} (Form B), not both.',
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
if (!isFormA && !isFormB) {
|
|
280
|
+
return reply.code(400).send({
|
|
281
|
+
error: 'Missing required fields. Form A: {oldEngramId, newEngramId}. ' +
|
|
282
|
+
'Form B: {agentId, matchConcept, newEngram}.',
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// ── Form A — by IDs ──
|
|
286
|
+
if (isFormA) {
|
|
287
|
+
const oldEngram = await store.getEngram(body.oldEngramId);
|
|
288
|
+
const newEngram = await store.getEngram(body.newEngramId);
|
|
289
|
+
if (!oldEngram)
|
|
290
|
+
return reply.code(404).send({ error: `Old engram ${body.oldEngramId} not found` });
|
|
291
|
+
if (!newEngram)
|
|
292
|
+
return reply.code(404).send({ error: `New engram ${body.newEngramId} not found` });
|
|
293
|
+
await store.upsertAssociation(body.newEngramId, body.oldEngramId, 0.8, 'causal', 1.0);
|
|
294
|
+
await store.updateConfidence(body.oldEngramId, oldEngram.confidence * 0.2);
|
|
295
|
+
await store.supersedeEngram(body.oldEngramId, body.newEngramId);
|
|
296
|
+
try {
|
|
297
|
+
await store.touchActivity(oldEngram.agentId);
|
|
298
|
+
}
|
|
299
|
+
catch { /* non-fatal */ }
|
|
300
|
+
return reply.send({
|
|
301
|
+
superseded: body.oldEngramId,
|
|
302
|
+
supersededBy: body.newEngramId,
|
|
303
|
+
reason: body.reason ?? 'outdated',
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
// ── Form B — atomic write-and-supersede by concept match ──
|
|
307
|
+
// Find old (most recent active match by concept + optional tags), write
|
|
308
|
+
// new engram via performWrite, link them — all in one SQL transaction.
|
|
309
|
+
// If no match: write new anyway, return { superseded: null }.
|
|
310
|
+
// AWM 0.8.x P4b follow-up: Form B atomicity via withTransaction.
|
|
311
|
+
// Holds the SQLite/PGlite lock across the async write + supersede pair
|
|
312
|
+
// so callers never observe a half-completed state.
|
|
313
|
+
const result = await store.withTransaction(async () => {
|
|
314
|
+
const matched = await store.findActiveMatchByConcept(body.agentId, body.matchConcept, body.matchTags);
|
|
315
|
+
const writeRes = await performWrite({ store, connectionEngine }, {
|
|
316
|
+
agentId: body.agentId,
|
|
317
|
+
concept: body.newEngram.concept,
|
|
318
|
+
content: body.newEngram.content,
|
|
319
|
+
tags: body.newEngram.tags ?? [],
|
|
320
|
+
memoryClass: body.newEngram.memory_class,
|
|
321
|
+
sequence: body.newEngram.sequence,
|
|
322
|
+
eventType: body.newEngram.eventType,
|
|
323
|
+
enableReinforcement: false,
|
|
324
|
+
});
|
|
325
|
+
if (matched) {
|
|
326
|
+
await store.upsertAssociation(writeRes.engram.id, matched.id, 0.8, 'causal', 1.0);
|
|
327
|
+
await store.updateConfidence(matched.id, matched.confidence * 0.2);
|
|
328
|
+
await store.supersedeEngram(matched.id, writeRes.engram.id);
|
|
329
|
+
}
|
|
330
|
+
return { writeRes, matched };
|
|
331
|
+
});
|
|
249
332
|
try {
|
|
250
|
-
store.touchActivity(
|
|
333
|
+
await store.touchActivity(body.agentId);
|
|
251
334
|
}
|
|
252
335
|
catch { /* non-fatal */ }
|
|
253
|
-
return reply.send({
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
336
|
+
return reply.code(201).send({
|
|
337
|
+
newEngram: result.writeRes.engram,
|
|
338
|
+
superseded: result.matched ? result.matched.id : null,
|
|
339
|
+
supersededBy: result.writeRes.engram.id,
|
|
340
|
+
reason: body.reason ?? 'resolved by concept match',
|
|
257
341
|
});
|
|
258
342
|
});
|
|
259
343
|
// ============================================================
|
|
@@ -261,32 +345,122 @@ export function registerRoutes(app, deps) {
|
|
|
261
345
|
// ============================================================
|
|
262
346
|
app.post('/memory/search', async (req, reply) => {
|
|
263
347
|
const body = req.body;
|
|
264
|
-
const results = store.search({
|
|
348
|
+
const results = await store.search({
|
|
265
349
|
agentId: body.agentId,
|
|
266
350
|
text: body.text,
|
|
267
351
|
concept: body.concept,
|
|
268
352
|
tags: body.tags,
|
|
353
|
+
tagsAll: body.tagsAll,
|
|
354
|
+
tagsAny: body.tagsAny,
|
|
355
|
+
tagsNone: body.tagsNone,
|
|
269
356
|
stage: body.stage,
|
|
270
357
|
retracted: body.retracted,
|
|
271
358
|
limit: body.limit,
|
|
272
359
|
offset: body.offset,
|
|
360
|
+
sortBy: body.sortBy,
|
|
361
|
+
sortOrder: body.sortOrder,
|
|
362
|
+
});
|
|
363
|
+
return reply.send({ results, count: results.length });
|
|
364
|
+
});
|
|
365
|
+
// ============================================================
|
|
366
|
+
// 0.8 Cluster C — materialized-view + atomic-counter endpoints
|
|
367
|
+
// ============================================================
|
|
368
|
+
/**
|
|
369
|
+
* For each distinct value of `tagKey`, return the most recent active
|
|
370
|
+
* engram. Used by NovelForge for "latest emotional state per character",
|
|
371
|
+
* "latest motif phase per motif", etc.
|
|
372
|
+
*/
|
|
373
|
+
app.post('/memory/latest-by-tag', async (req, reply) => {
|
|
374
|
+
const body = req.body;
|
|
375
|
+
if (!body.agentId || !body.tagKey) {
|
|
376
|
+
return reply.code(400).send({ error: 'agentId and tagKey are required' });
|
|
377
|
+
}
|
|
378
|
+
const results = await store.getLatestByTag({
|
|
379
|
+
agentId: body.agentId,
|
|
380
|
+
tagKeyPrefix: body.tagKey,
|
|
381
|
+
scopeTagsAll: body.scopeTagsAll,
|
|
382
|
+
retracted: body.retracted ?? false,
|
|
383
|
+
sortBy: body.sortBy,
|
|
384
|
+
limit: body.limit,
|
|
273
385
|
});
|
|
274
386
|
return reply.send({ results, count: results.length });
|
|
275
387
|
});
|
|
388
|
+
/**
|
|
389
|
+
* Filter by tag-set operators, sort by numeric value extracted from a
|
|
390
|
+
* tag prefix, return top N. Used by NovelForge for "top N active
|
|
391
|
+
* promises by weight".
|
|
392
|
+
*/
|
|
393
|
+
app.post('/memory/top-by', async (req, reply) => {
|
|
394
|
+
const body = req.body;
|
|
395
|
+
if (!body.agentId || !body.sortField) {
|
|
396
|
+
return reply.code(400).send({ error: 'agentId and sortField are required' });
|
|
397
|
+
}
|
|
398
|
+
const results = await store.getTopBy({
|
|
399
|
+
agentId: body.agentId,
|
|
400
|
+
sortField: body.sortField,
|
|
401
|
+
order: body.order ?? 'desc',
|
|
402
|
+
filterTagsAll: body.filterTagsAll,
|
|
403
|
+
filterTagsAny: body.filterTagsAny,
|
|
404
|
+
filterTagsNone: body.filterTagsNone,
|
|
405
|
+
retracted: body.retracted ?? false,
|
|
406
|
+
limit: body.limit,
|
|
407
|
+
});
|
|
408
|
+
return reply.send({ results, count: results.length });
|
|
409
|
+
});
|
|
410
|
+
/**
|
|
411
|
+
* Compute effective state of an engram from referenced events. Two
|
|
412
|
+
* targeting modes: by ID, or by concept match (same semantics as Form B's
|
|
413
|
+
* findActiveMatchByConcept).
|
|
414
|
+
*/
|
|
415
|
+
app.post('/memory/resolve', async (req, reply) => {
|
|
416
|
+
const body = req.body;
|
|
417
|
+
if (!body.agentId) {
|
|
418
|
+
return reply.code(400).send({ error: 'agentId is required' });
|
|
419
|
+
}
|
|
420
|
+
let targetId = body.targetEngramId;
|
|
421
|
+
if (!targetId && body.matchConcept) {
|
|
422
|
+
const matched = await store.findActiveMatchByConcept(body.agentId, body.matchConcept, body.matchTags);
|
|
423
|
+
if (!matched) {
|
|
424
|
+
return reply.code(404).send({
|
|
425
|
+
error: `No active engram matches concept "${body.matchConcept}"`,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
targetId = matched.id;
|
|
429
|
+
}
|
|
430
|
+
if (!targetId) {
|
|
431
|
+
return reply.code(400).send({
|
|
432
|
+
error: 'Provide either targetEngramId or matchConcept',
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
const result = await store.resolveEffectiveState(targetId);
|
|
436
|
+
if (!result)
|
|
437
|
+
return reply.code(404).send({ error: `Engram ${targetId} not found` });
|
|
438
|
+
return reply.send(result);
|
|
439
|
+
});
|
|
440
|
+
/**
|
|
441
|
+
* Race-free next-sequence allocator. Caller writes the engram with the
|
|
442
|
+
* returned value in `sequence`. Doesn't reserve — concurrent allocations
|
|
443
|
+
* always serialize via BEGIN IMMEDIATE.
|
|
444
|
+
*/
|
|
445
|
+
app.get('/memory/sequence/:agentId/next', async (req, reply) => {
|
|
446
|
+
const { agentId } = req.params;
|
|
447
|
+
const next = await store.allocateNextSequence(agentId);
|
|
448
|
+
return reply.send({ agentId, next });
|
|
449
|
+
});
|
|
276
450
|
app.get('/memory/:id', async (req, reply) => {
|
|
277
451
|
const { id } = req.params;
|
|
278
|
-
const engram = store.getEngram(id);
|
|
452
|
+
const engram = await store.getEngram(id);
|
|
279
453
|
if (!engram)
|
|
280
454
|
return reply.code(404).send({ error: 'Not found' });
|
|
281
|
-
const associations = store.getAssociationsFor(id);
|
|
455
|
+
const associations = await store.getAssociationsFor(id);
|
|
282
456
|
return reply.send({ engram, associations });
|
|
283
457
|
});
|
|
284
458
|
app.get('/agent/:id/stats', async (req, reply) => {
|
|
285
459
|
const { id } = req.params;
|
|
286
|
-
const active = store.getEngramsByAgent(id, 'active');
|
|
287
|
-
const staging = store.getEngramsByAgent(id, 'staging');
|
|
288
|
-
const retracted = store.getEngramsByAgent(id, undefined, true).filter(e => e.retracted);
|
|
289
|
-
const associations = store.getAllAssociations(id);
|
|
460
|
+
const active = await store.getEngramsByAgent(id, 'active');
|
|
461
|
+
const staging = await store.getEngramsByAgent(id, 'staging');
|
|
462
|
+
const retracted = (await store.getEngramsByAgent(id, undefined, true)).filter(e => e.retracted);
|
|
463
|
+
const associations = await store.getAllAssociations(id);
|
|
290
464
|
return reply.send({
|
|
291
465
|
agentId: id,
|
|
292
466
|
engrams: {
|
|
@@ -304,7 +478,7 @@ export function registerRoutes(app, deps) {
|
|
|
304
478
|
app.get('/agent/:id/metrics', async (req, reply) => {
|
|
305
479
|
const { id } = req.params;
|
|
306
480
|
const windowHours = parseInt(req.query.window ?? '24', 10);
|
|
307
|
-
const metrics = evalEngine.computeMetrics(id, windowHours);
|
|
481
|
+
const metrics = await evalEngine.computeMetrics(id, windowHours);
|
|
308
482
|
return reply.send({ metrics });
|
|
309
483
|
});
|
|
310
484
|
app.post('/agent/register', async (req, reply) => {
|
|
@@ -321,12 +495,12 @@ export function registerRoutes(app, deps) {
|
|
|
321
495
|
// ============================================================
|
|
322
496
|
app.post('/system/evict', async (req, reply) => {
|
|
323
497
|
const body = req.body;
|
|
324
|
-
const result = evictionEngine.enforceCapacity(body.agentId, DEFAULT_AGENT_CONFIG);
|
|
498
|
+
const result = await evictionEngine.enforceCapacity(body.agentId, DEFAULT_AGENT_CONFIG);
|
|
325
499
|
return reply.send(result);
|
|
326
500
|
});
|
|
327
501
|
app.post('/system/decay', async (req, reply) => {
|
|
328
502
|
const body = req.body;
|
|
329
|
-
const decayed = evictionEngine.decayEdges(body.agentId, body.halfLifeDays);
|
|
503
|
+
const decayed = await evictionEngine.decayEdges(body.agentId, body.halfLifeDays);
|
|
330
504
|
return reply.send({ edgesDecayed: decayed });
|
|
331
505
|
});
|
|
332
506
|
app.post('/system/consolidate', async (req, reply) => {
|
|
@@ -353,7 +527,7 @@ export function registerRoutes(app, deps) {
|
|
|
353
527
|
});
|
|
354
528
|
app.get('/memory/restore/:agentId', async (req, reply) => {
|
|
355
529
|
const { agentId } = req.params;
|
|
356
|
-
const checkpoint = store.getCheckpoint(agentId);
|
|
530
|
+
const checkpoint = await store.getCheckpoint(agentId);
|
|
357
531
|
const now = Date.now();
|
|
358
532
|
const idleMs = checkpoint
|
|
359
533
|
? now - checkpoint.auto.lastActivityAt.getTime()
|
|
@@ -361,7 +535,7 @@ export function registerRoutes(app, deps) {
|
|
|
361
535
|
// Get last written engram for context
|
|
362
536
|
let lastWrite = null;
|
|
363
537
|
if (checkpoint?.auto.lastWriteId) {
|
|
364
|
-
const engram = store.getEngram(checkpoint.auto.lastWriteId);
|
|
538
|
+
const engram = await store.getEngram(checkpoint.auto.lastWriteId);
|
|
365
539
|
if (engram) {
|
|
366
540
|
lastWrite = { id: engram.id, concept: engram.concept, content: engram.content };
|
|
367
541
|
}
|
|
@@ -411,7 +585,7 @@ export function registerRoutes(app, deps) {
|
|
|
411
585
|
// ============================================================
|
|
412
586
|
app.post('/task/create', async (req, reply) => {
|
|
413
587
|
const body = req.body;
|
|
414
|
-
const engram = store.createEngram({
|
|
588
|
+
const engram = await store.createEngram({
|
|
415
589
|
agentId: body.agentId,
|
|
416
590
|
concept: body.concept,
|
|
417
591
|
content: body.content,
|
|
@@ -428,32 +602,32 @@ export function registerRoutes(app, deps) {
|
|
|
428
602
|
blockedBy: body.blockedBy,
|
|
429
603
|
});
|
|
430
604
|
connectionEngine.enqueue(engram.id);
|
|
431
|
-
embed(`${body.concept} ${body.content}`).then(vec => {
|
|
432
|
-
store.updateEmbedding(engram.id, vec);
|
|
605
|
+
embed(`${body.concept} ${body.content}`).then(async (vec) => {
|
|
606
|
+
await store.updateEmbedding(engram.id, vec);
|
|
433
607
|
}).catch(() => { });
|
|
434
608
|
return reply.send(engram);
|
|
435
609
|
});
|
|
436
610
|
app.post('/task/update', async (req, reply) => {
|
|
437
611
|
const body = req.body;
|
|
438
|
-
const engram = store.getEngram(body.taskId);
|
|
612
|
+
const engram = await store.getEngram(body.taskId);
|
|
439
613
|
if (!engram || !engram.taskStatus) {
|
|
440
614
|
return reply.code(404).send({ error: 'Task not found' });
|
|
441
615
|
}
|
|
442
616
|
if (body.blockedBy !== undefined) {
|
|
443
|
-
store.updateBlockedBy(body.taskId, body.blockedBy);
|
|
617
|
+
await store.updateBlockedBy(body.taskId, body.blockedBy);
|
|
444
618
|
}
|
|
445
619
|
if (body.status) {
|
|
446
|
-
store.updateTaskStatus(body.taskId, body.status);
|
|
620
|
+
await store.updateTaskStatus(body.taskId, body.status);
|
|
447
621
|
}
|
|
448
622
|
if (body.priority) {
|
|
449
|
-
store.updateTaskPriority(body.taskId, body.priority);
|
|
623
|
+
await store.updateTaskPriority(body.taskId, body.priority);
|
|
450
624
|
}
|
|
451
|
-
return reply.send(store.getEngram(body.taskId));
|
|
625
|
+
return reply.send(await store.getEngram(body.taskId));
|
|
452
626
|
});
|
|
453
627
|
app.get('/task/list/:agentId', async (req, reply) => {
|
|
454
628
|
const { agentId } = req.params;
|
|
455
629
|
const { status, includeDone } = req.query;
|
|
456
|
-
let tasks = store.getTasks(agentId, status);
|
|
630
|
+
let tasks = await store.getTasks(agentId, status);
|
|
457
631
|
if (includeDone !== 'true' && !status) {
|
|
458
632
|
tasks = tasks.filter(t => t.taskStatus !== 'done');
|
|
459
633
|
}
|
|
@@ -461,24 +635,29 @@ export function registerRoutes(app, deps) {
|
|
|
461
635
|
});
|
|
462
636
|
app.get('/task/next/:agentId', async (req, reply) => {
|
|
463
637
|
const { agentId } = req.params;
|
|
464
|
-
const next = store.getNextTask(agentId);
|
|
638
|
+
const next = await store.getNextTask(agentId);
|
|
465
639
|
return reply.send(next ? { task: next } : { task: null, message: 'No actionable tasks' });
|
|
466
640
|
});
|
|
467
641
|
// Time warp — shift all timestamps backward by N days (for testing)
|
|
468
642
|
app.post('/system/time-warp', async (req, reply) => {
|
|
469
643
|
const body = req.body;
|
|
470
644
|
const ms = body.days * 24 * 60 * 60 * 1000;
|
|
471
|
-
const shifted = store.timeWarp(body.agentId, ms);
|
|
645
|
+
const shifted = await store.timeWarp(body.agentId, ms);
|
|
472
646
|
return reply.send({ shifted, days: body.days });
|
|
473
647
|
});
|
|
474
648
|
// ─── Export ─────────────────────────────────────────────────────────────
|
|
475
649
|
app.get('/memory/export', async (req, reply) => {
|
|
476
650
|
const { agentId, all } = req.query;
|
|
477
651
|
const includeAll = all === 'true';
|
|
652
|
+
// /memory/export uses raw SQL — SQLite-only. On PGlite, callers should use
|
|
653
|
+
// the awm CLI export/merge tools instead.
|
|
654
|
+
if (typeof store.getDb !== 'function') {
|
|
655
|
+
return reply.code(501).send({ error: 'export endpoint requires the SQLite backend' });
|
|
656
|
+
}
|
|
478
657
|
const db = store.getDb();
|
|
479
|
-
let engramSql = `SELECT id, agent_id, concept, content, confidence, salience, access_count,
|
|
480
|
-
last_accessed, created_at, salience_features, reason_codes, stage, ttl,
|
|
481
|
-
retracted, retracted_by, retracted_at, tags
|
|
658
|
+
let engramSql = `SELECT id, agent_id, concept, content, confidence, salience, access_count,
|
|
659
|
+
last_accessed, created_at, salience_features, reason_codes, stage, ttl,
|
|
660
|
+
retracted, retracted_by, retracted_at, tags
|
|
482
661
|
FROM engrams`;
|
|
483
662
|
const conditions = [];
|
|
484
663
|
const params = [];
|
|
@@ -496,7 +675,7 @@ export function registerRoutes(app, deps) {
|
|
|
496
675
|
engramSql += ' ORDER BY created_at ASC';
|
|
497
676
|
const engrams = db.prepare(engramSql).all(...params);
|
|
498
677
|
const engramIds = new Set(engrams.map(e => e.id));
|
|
499
|
-
const allAssocs = db.prepare(`SELECT id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated
|
|
678
|
+
const allAssocs = db.prepare(`SELECT id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated
|
|
500
679
|
FROM associations`).all();
|
|
501
680
|
const associations = allAssocs.filter(a => engramIds.has(a.from_engram_id) && engramIds.has(a.to_engram_id));
|
|
502
681
|
return reply.send({
|
|
@@ -515,15 +694,15 @@ export function registerRoutes(app, deps) {
|
|
|
515
694
|
const base = {
|
|
516
695
|
status: 'ok',
|
|
517
696
|
timestamp: new Date().toISOString(),
|
|
518
|
-
version: '0.
|
|
697
|
+
version: '0.8.5',
|
|
519
698
|
coordination: coordEnabled,
|
|
520
699
|
};
|
|
521
|
-
if (coordEnabled) {
|
|
700
|
+
if (coordEnabled && typeof deps.store.getDb === 'function') {
|
|
522
701
|
try {
|
|
523
702
|
const db = deps.store.getDb();
|
|
524
|
-
const stats = db.prepare(`SELECT
|
|
525
|
-
(SELECT COUNT(*) FROM coord_agents WHERE status != 'dead') AS agents_alive,
|
|
526
|
-
(SELECT COUNT(*) FROM coord_assignments WHERE status = 'pending') AS pending_tasks,
|
|
703
|
+
const stats = db.prepare(`SELECT
|
|
704
|
+
(SELECT COUNT(*) FROM coord_agents WHERE status != 'dead') AS agents_alive,
|
|
705
|
+
(SELECT COUNT(*) FROM coord_assignments WHERE status = 'pending') AS pending_tasks,
|
|
527
706
|
(SELECT COUNT(*) FROM coord_locks) AS active_locks`).get();
|
|
528
707
|
Object.assign(base, stats);
|
|
529
708
|
}
|