agent-working-memory 0.13.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +200 -238
  2. package/dist/adapters/common.d.ts +6 -0
  3. package/dist/adapters/common.d.ts.map +1 -1
  4. package/dist/adapters/common.js +457 -362
  5. package/dist/adapters/common.js.map +1 -1
  6. package/dist/api/routes.d.ts.map +1 -1
  7. package/dist/api/routes.js +24 -8
  8. package/dist/api/routes.js.map +1 -1
  9. package/dist/core/alias-map.d.ts +16 -0
  10. package/dist/core/alias-map.d.ts.map +1 -0
  11. package/dist/core/alias-map.js +102 -0
  12. package/dist/core/alias-map.js.map +1 -0
  13. package/dist/core/embeddings.d.ts +17 -0
  14. package/dist/core/embeddings.d.ts.map +1 -1
  15. package/dist/core/embeddings.js +50 -1
  16. package/dist/core/embeddings.js.map +1 -1
  17. package/dist/core/recall-config.d.ts +52 -0
  18. package/dist/core/recall-config.d.ts.map +1 -0
  19. package/dist/core/recall-config.js +110 -0
  20. package/dist/core/recall-config.js.map +1 -0
  21. package/dist/core/rerank-window.d.ts +61 -0
  22. package/dist/core/rerank-window.d.ts.map +1 -0
  23. package/dist/core/rerank-window.js +153 -0
  24. package/dist/core/rerank-window.js.map +1 -0
  25. package/dist/core/rerank2.d.ts +62 -0
  26. package/dist/core/rerank2.d.ts.map +1 -0
  27. package/dist/core/rerank2.js +75 -0
  28. package/dist/core/rerank2.js.map +1 -0
  29. package/dist/core/retrieval-text.d.ts +55 -0
  30. package/dist/core/retrieval-text.d.ts.map +1 -0
  31. package/dist/core/retrieval-text.js +87 -0
  32. package/dist/core/retrieval-text.js.map +1 -0
  33. package/dist/core/temporal-query.d.ts +61 -0
  34. package/dist/core/temporal-query.d.ts.map +1 -0
  35. package/dist/core/temporal-query.js +168 -0
  36. package/dist/core/temporal-query.js.map +1 -0
  37. package/dist/core/token-budget.d.ts +75 -0
  38. package/dist/core/token-budget.d.ts.map +1 -0
  39. package/dist/core/token-budget.js +136 -0
  40. package/dist/core/token-budget.js.map +1 -0
  41. package/dist/core/whoami.d.ts +11 -0
  42. package/dist/core/whoami.d.ts.map +1 -1
  43. package/dist/core/whoami.js +10 -0
  44. package/dist/core/whoami.js.map +1 -1
  45. package/dist/core/write-pipeline.d.ts.map +1 -1
  46. package/dist/core/write-pipeline.js +6 -3
  47. package/dist/core/write-pipeline.js.map +1 -1
  48. package/dist/engine/activation.d.ts.map +1 -1
  49. package/dist/engine/activation.js +146 -32
  50. package/dist/engine/activation.js.map +1 -1
  51. package/dist/hooks/prime.d.ts +77 -0
  52. package/dist/hooks/prime.d.ts.map +1 -0
  53. package/dist/hooks/prime.js +92 -0
  54. package/dist/hooks/prime.js.map +1 -0
  55. package/dist/hooks/sidecar.d.ts.map +1 -1
  56. package/dist/hooks/sidecar.js +39 -0
  57. package/dist/hooks/sidecar.js.map +1 -1
  58. package/dist/mcp.js +160 -107
  59. package/dist/mcp.js.map +1 -1
  60. package/dist/storage/pglite.d.ts.map +1 -1
  61. package/dist/storage/pglite.js +10 -2
  62. package/dist/storage/pglite.js.map +1 -1
  63. package/dist/storage/postgres.d.ts.map +1 -1
  64. package/dist/storage/postgres.js +10 -2
  65. package/dist/storage/postgres.js.map +1 -1
  66. package/dist/storage/sqlite.d.ts.map +1 -1
  67. package/dist/storage/sqlite.js +12 -2
  68. package/dist/storage/sqlite.js.map +1 -1
  69. package/dist/types/engram.d.ts +31 -0
  70. package/dist/types/engram.d.ts.map +1 -1
  71. package/package.json +3 -2
  72. package/src/adapters/common.ts +666 -567
  73. package/src/api/routes.ts +1015 -999
  74. package/src/core/alias-map.ts +97 -0
  75. package/src/core/embeddings.ts +172 -115
  76. package/src/core/recall-config.ts +115 -0
  77. package/src/core/rerank-window.ts +158 -0
  78. package/src/core/rerank2.ts +82 -0
  79. package/src/core/retrieval-text.ts +82 -0
  80. package/src/core/temporal-query.ts +193 -0
  81. package/src/core/token-budget.ts +160 -0
  82. package/src/core/whoami.ts +110 -92
  83. package/src/core/write-pipeline.ts +6 -3
  84. package/src/engine/activation.ts +1579 -1468
  85. package/src/hooks/prime.ts +136 -0
  86. package/src/hooks/sidecar.ts +43 -0
  87. package/src/mcp.ts +1443 -1387
  88. package/src/storage/pglite.ts +10 -2
  89. package/src/storage/postgres.ts +10 -2
  90. package/src/storage/sqlite.ts +12 -2
  91. package/src/types/engram.ts +32 -0
@@ -1,92 +1,110 @@
1
- // Copyright 2026 Robert Winter / Complete Ideas
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- /**
5
- * Instance identity (D3, 2026-07-30).
6
- *
7
- * Answers "which AWM am I talking to?" — the recurring confusion class where
8
- * sessions mix up the hosted multi-agent connector with the local instance,
9
- * or run blind to sibling agent spaces in the same store (an evaluation once
10
- * analyzed this project without seeing the `personal` space that held its
11
- * design decisions).
12
- *
13
- * Exposed as the `memory_whoami` MCP tool and the `GET /whoami` HTTP route.
14
- * Read-only; additive module.
15
- */
16
-
17
- import { dirname, join, resolve } from 'node:path';
18
- import { fileURLToPath } from 'node:url';
19
- import { VERSION } from '../version.js';
20
- import { getConfiguredBackend, getConfiguredPath } from '../storage/factory.js';
21
-
22
- export interface WhoamiInfo {
23
- agentId: string;
24
- workspace: string | null;
25
- surface: 'mcp' | 'http';
26
- mode: 'standalone' | 'hive';
27
- backend: string;
28
- storePath: string;
29
- version: string;
30
- codePath: string;
31
- pid: number;
32
- ports: { http: number | null; hookSidecar: number | null };
33
- siblingAgents: string[];
34
- }
35
-
36
- /** Store subset whoami needs every backend implements listAgentIds. */
37
- export interface WhoamiStore {
38
- listAgentIds(): string[] | Promise<string[]>;
39
- }
40
-
41
- function packageRoot(): string {
42
- // src/core/whoami.ts (dev) and dist/core/whoami.js (build) both sit two
43
- // levels below the package root.
44
- const here = dirname(fileURLToPath(import.meta.url));
45
- return resolve(join(here, '..', '..'));
46
- }
47
-
48
- export async function buildWhoami(
49
- store: WhoamiStore,
50
- agentId: string,
51
- surface: 'mcp' | 'http',
52
- ): Promise<WhoamiInfo> {
53
- const coordination = process.env.AWM_COORDINATION === 'true' || process.env.AWM_COORDINATION === '1';
54
- let siblings: string[] = [];
55
- try {
56
- const all = await store.listAgentIds();
57
- siblings = all.filter(a => a !== agentId).sort();
58
- } catch { /* identity must never fail on a listing error */ }
59
- const httpPort = Number(process.env.AWM_PORT ?? '');
60
- const hookPort = Number(process.env.AWM_HOOK_PORT ?? '');
61
- return {
62
- agentId,
63
- workspace: process.env.AWM_WORKSPACE ?? null,
64
- surface,
65
- mode: coordination ? 'hive' : 'standalone',
66
- backend: getConfiguredBackend(),
67
- storePath: getConfiguredPath(),
68
- version: VERSION,
69
- codePath: packageRoot(),
70
- pid: process.pid,
71
- ports: {
72
- http: Number.isFinite(httpPort) && httpPort > 0 ? httpPort : null,
73
- hookSidecar: Number.isFinite(hookPort) && hookPort > 0 ? hookPort : null,
74
- },
75
- siblingAgents: siblings,
76
- };
77
- }
78
-
79
- /** Human-readable rendering for the MCP tool response. */
80
- export function formatWhoami(w: WhoamiInfo): string {
81
- return [
82
- `Agent: ${w.agentId}${w.workspace ? ` (workspace: ${w.workspace})` : ''}`,
83
- `Mode: ${w.mode} · Surface: ${w.surface} · Version: ${w.version}`,
84
- `Backend: ${w.backend}`,
85
- `Store: ${w.storePath}`,
86
- `Code: ${w.codePath} (pid ${w.pid})`,
87
- `Ports: http=${w.ports.http ?? 'off'} hookSidecar=${w.ports.hookSidecar ?? 'off'}`,
88
- w.siblingAgents.length
89
- ? `Sibling agent spaces in this store: ${w.siblingAgents.join(', ')} — recall is scoped to '${w.agentId}'; other spaces need workspace recall, \`awm export --agent <id>\`, or a session configured for that agent.`
90
- : 'Sibling agent spaces in this store: none',
91
- ].join('\n');
92
- }
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /**
5
+ * Instance identity (D3, 2026-07-30).
6
+ *
7
+ * Answers "which AWM am I talking to?" — the recurring confusion class where
8
+ * sessions mix up the hosted multi-agent connector with the local instance,
9
+ * or run blind to sibling agent spaces in the same store (an evaluation once
10
+ * analyzed this project without seeing the `personal` space that held its
11
+ * design decisions).
12
+ *
13
+ * Exposed as the `memory_whoami` MCP tool and the `GET /whoami` HTTP route.
14
+ * Read-only; additive module.
15
+ */
16
+
17
+ import { dirname, join, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { VERSION } from '../version.js';
20
+ import { getConfiguredBackend, getConfiguredPath } from '../storage/factory.js';
21
+ import { activeRecallConfig, recallConfigFingerprint } from './recall-config.js';
22
+ import { embeddingHealth } from './embeddings.js';
23
+
24
+ export interface WhoamiInfo {
25
+ agentId: string;
26
+ workspace: string | null;
27
+ surface: 'mcp' | 'http';
28
+ mode: 'standalone' | 'hive';
29
+ backend: string;
30
+ storePath: string;
31
+ version: string;
32
+ codePath: string;
33
+ pid: number;
34
+ ports: { http: number | null; hookSidecar: number | null };
35
+ /**
36
+ * Effective recall configuration. `whoami` is the "what am I actually
37
+ * running" tool, and the version alone does not answer that: a build can be
38
+ * current while the recall flags that change its behaviour are unset, or set
39
+ * to something unintended. GET /health already reports this, but HTTP is off
40
+ * by default, so an MCP-only session had no way to see it.
41
+ */
42
+ recall: { fingerprint: string; flags: Record<string, string> };
43
+ siblingAgents: string[];
44
+ }
45
+
46
+ /** Store subset whoami needs — every backend implements listAgentIds. */
47
+ export interface WhoamiStore {
48
+ listAgentIds(): string[] | Promise<string[]>;
49
+ }
50
+
51
+ function packageRoot(): string {
52
+ // src/core/whoami.ts (dev) and dist/core/whoami.js (build) both sit two
53
+ // levels below the package root.
54
+ const here = dirname(fileURLToPath(import.meta.url));
55
+ return resolve(join(here, '..', '..'));
56
+ }
57
+
58
+ export async function buildWhoami(
59
+ store: WhoamiStore,
60
+ agentId: string,
61
+ surface: 'mcp' | 'http',
62
+ ): Promise<WhoamiInfo> {
63
+ const coordination = process.env.AWM_COORDINATION === 'true' || process.env.AWM_COORDINATION === '1';
64
+ let siblings: string[] = [];
65
+ try {
66
+ const all = await store.listAgentIds();
67
+ siblings = all.filter(a => a !== agentId).sort();
68
+ } catch { /* identity must never fail on a listing error */ }
69
+ const httpPort = Number(process.env.AWM_PORT ?? '');
70
+ const hookPort = Number(process.env.AWM_HOOK_PORT ?? '');
71
+ return {
72
+ agentId,
73
+ workspace: process.env.AWM_WORKSPACE ?? null,
74
+ surface,
75
+ mode: coordination ? 'hive' : 'standalone',
76
+ backend: getConfiguredBackend(),
77
+ storePath: getConfiguredPath(),
78
+ version: VERSION,
79
+ codePath: packageRoot(),
80
+ pid: process.pid,
81
+ ports: {
82
+ http: Number.isFinite(httpPort) && httpPort > 0 ? httpPort : null,
83
+ hookSidecar: Number.isFinite(hookPort) && hookPort > 0 ? hookPort : null,
84
+ },
85
+ recall: { fingerprint: recallConfigFingerprint(), flags: activeRecallConfig() },
86
+ siblingAgents: siblings,
87
+ };
88
+ }
89
+
90
+ /** Human-readable rendering for the MCP tool response. */
91
+ export function formatWhoami(w: WhoamiInfo): string {
92
+ return [
93
+ `Agent: ${w.agentId}${w.workspace ? ` (workspace: ${w.workspace})` : ''}`,
94
+ `Mode: ${w.mode} · Surface: ${w.surface} · Version: ${w.version}`,
95
+ `Backend: ${w.backend}`,
96
+ `Store: ${w.storePath}`,
97
+ `Code: ${w.codePath} (pid ${w.pid})`,
98
+ `Ports: http=${w.ports.http ?? 'off'} hookSidecar=${w.ports.hookSidecar ?? 'off'}`,
99
+ `Recall config: ${w.recall.fingerprint}`,
100
+ ...(embeddingHealth().dimensionMismatches > 0
101
+ ? [`\u26a0 EMBEDDING INTEGRITY: ${embeddingHealth().dimensionMismatches} dimension mismatches ` +
102
+ `(expected ${embeddingHealth().expectedDimensions}d). Affected memories score 0 on the ` +
103
+ `vector channel — the corpus is probably half-migrated. Re-embed the whole store or ` +
104
+ `revert AWM_EMBED_MODEL/AWM_EMBED_DIMS.`]
105
+ : []),
106
+ w.siblingAgents.length
107
+ ? `Sibling agent spaces in this store: ${w.siblingAgents.join(', ')} — recall is scoped to '${w.agentId}'; other spaces need workspace recall, \`awm export --agent <id>\`, or a session configured for that agent.`
108
+ : 'Sibling agent spaces in this store: none',
109
+ ].join('\n');
110
+ }
@@ -51,6 +51,7 @@ import { extractMetaTags } from './auto-tagger.js';
51
51
  import { extractEntitiesFromTags } from './entity-extract.js';
52
52
  import { reportWrite } from './write-telemetry.js';
53
53
  import { DEFAULT_AGENT_CONFIG } from '../types/agent.js';
54
+ import { buildRetrievalText } from './retrieval-text.js';
54
55
 
55
56
  /** Confidence floor below which a matched engram is treated as "decaying out". */
56
57
  export const HEALTHY_CONFIDENCE_FLOOR = 0.3;
@@ -195,7 +196,7 @@ export async function performWrite(
195
196
  let prewriteEmbedding: number[] | null = null;
196
197
  if (process.env.AWM_NOVELTY_EMBED !== '0') {
197
198
  try {
198
- prewriteEmbedding = await embed(`${input.concept} ${input.content}`);
199
+ prewriteEmbedding = await embed(buildRetrievalText(input.concept, input.content, input.tags));
199
200
  } catch { /* fall through — async embed will retry later */ }
200
201
  }
201
202
  tEmbed = performance.now() - tStartEmbed;
@@ -434,7 +435,9 @@ async function reinforceMatched(
434
435
  // beyond 512 tokens but the topic anchor (early content) drives
435
436
  // the vector for retrieval purposes.
436
437
  const conceptForEmbed = newConceptHint || matched.concept;
437
- const newVec = await embed(`${conceptForEmbed} ${mergedContent}`);
438
+ // The reinforced engram's OWN tags — `input` is not in scope here, and
439
+ // the stored tags are the right vocabulary for the stored memory anyway.
440
+ const newVec = await embed(buildRetrievalText(conceptForEmbed, mergedContent, matched.tags));
438
441
  await store.updateEmbedding(matched.id, newVec);
439
442
  } catch { /* merge is best-effort — confidence bump already landed */ }
440
443
  }
@@ -574,7 +577,7 @@ async function createNewEngram(
574
577
  const alreadyEmbedded = prewriteEmbedding != null && prewriteEmbedding.length > 0;
575
578
  const shouldEmbed = (!isStructural || input.embed === true) && !alreadyEmbedded;
576
579
  if (shouldEmbed) {
577
- embed(`${input.concept} ${input.content}`)
580
+ embed(buildRetrievalText(input.concept, input.content, input.tags))
578
581
  .then(async vec => {
579
582
  try { await store.updateEmbedding(engram.id, vec); } catch { /* engram may be evicted */ }
580
583
  })