ai-memory-layer 2.0.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.
Files changed (245) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +765 -0
  4. package/bin/memory-server.mjs +157 -0
  5. package/dist/adapters/memory/embeddings.d.ts +4 -0
  6. package/dist/adapters/memory/embeddings.d.ts.map +1 -0
  7. package/dist/adapters/memory/embeddings.js +53 -0
  8. package/dist/adapters/memory/embeddings.js.map +1 -0
  9. package/dist/adapters/memory/index.d.ts +7 -0
  10. package/dist/adapters/memory/index.d.ts.map +1 -0
  11. package/dist/adapters/memory/index.js +650 -0
  12. package/dist/adapters/memory/index.js.map +1 -0
  13. package/dist/adapters/postgres/index.d.ts +38 -0
  14. package/dist/adapters/postgres/index.d.ts.map +1 -0
  15. package/dist/adapters/postgres/index.js +982 -0
  16. package/dist/adapters/postgres/index.js.map +1 -0
  17. package/dist/adapters/sqlite/embeddings.d.ts +5 -0
  18. package/dist/adapters/sqlite/embeddings.d.ts.map +1 -0
  19. package/dist/adapters/sqlite/embeddings.js +122 -0
  20. package/dist/adapters/sqlite/embeddings.js.map +1 -0
  21. package/dist/adapters/sqlite/index.d.ts +8 -0
  22. package/dist/adapters/sqlite/index.d.ts.map +1 -0
  23. package/dist/adapters/sqlite/index.js +839 -0
  24. package/dist/adapters/sqlite/index.js.map +1 -0
  25. package/dist/adapters/sqlite/mappers.d.ts +40 -0
  26. package/dist/adapters/sqlite/mappers.d.ts.map +1 -0
  27. package/dist/adapters/sqlite/mappers.js +95 -0
  28. package/dist/adapters/sqlite/mappers.js.map +1 -0
  29. package/dist/adapters/sqlite/schema.d.ts +4 -0
  30. package/dist/adapters/sqlite/schema.d.ts.map +1 -0
  31. package/dist/adapters/sqlite/schema.js +394 -0
  32. package/dist/adapters/sqlite/schema.js.map +1 -0
  33. package/dist/adapters/sync-to-async.d.ts +15 -0
  34. package/dist/adapters/sync-to-async.d.ts.map +1 -0
  35. package/dist/adapters/sync-to-async.js +95 -0
  36. package/dist/adapters/sync-to-async.js.map +1 -0
  37. package/dist/cli/inspect.d.ts +34 -0
  38. package/dist/cli/inspect.d.ts.map +1 -0
  39. package/dist/cli/inspect.js +190 -0
  40. package/dist/cli/inspect.js.map +1 -0
  41. package/dist/contracts/async-storage.d.ts +86 -0
  42. package/dist/contracts/async-storage.d.ts.map +1 -0
  43. package/dist/contracts/async-storage.js +2 -0
  44. package/dist/contracts/async-storage.js.map +1 -0
  45. package/dist/contracts/embedding.d.ts +22 -0
  46. package/dist/contracts/embedding.d.ts.map +1 -0
  47. package/dist/contracts/embedding.js +2 -0
  48. package/dist/contracts/embedding.js.map +1 -0
  49. package/dist/contracts/identity.d.ts +29 -0
  50. package/dist/contracts/identity.d.ts.map +1 -0
  51. package/dist/contracts/identity.js +34 -0
  52. package/dist/contracts/identity.js.map +1 -0
  53. package/dist/contracts/observability.d.ts +18 -0
  54. package/dist/contracts/observability.d.ts.map +1 -0
  55. package/dist/contracts/observability.js +7 -0
  56. package/dist/contracts/observability.js.map +1 -0
  57. package/dist/contracts/policy.d.ts +108 -0
  58. package/dist/contracts/policy.d.ts.map +1 -0
  59. package/dist/contracts/policy.js +107 -0
  60. package/dist/contracts/policy.js.map +1 -0
  61. package/dist/contracts/storage.d.ts +78 -0
  62. package/dist/contracts/storage.d.ts.map +1 -0
  63. package/dist/contracts/storage.js +2 -0
  64. package/dist/contracts/storage.js.map +1 -0
  65. package/dist/contracts/types.d.ts +381 -0
  66. package/dist/contracts/types.d.ts.map +1 -0
  67. package/dist/contracts/types.js +94 -0
  68. package/dist/contracts/types.js.map +1 -0
  69. package/dist/core/circuit-breaker.d.ts +11 -0
  70. package/dist/core/circuit-breaker.d.ts.map +1 -0
  71. package/dist/core/circuit-breaker.js +38 -0
  72. package/dist/core/circuit-breaker.js.map +1 -0
  73. package/dist/core/context.d.ts +56 -0
  74. package/dist/core/context.d.ts.map +1 -0
  75. package/dist/core/context.js +345 -0
  76. package/dist/core/context.js.map +1 -0
  77. package/dist/core/events.d.ts +8 -0
  78. package/dist/core/events.d.ts.map +1 -0
  79. package/dist/core/events.js +25 -0
  80. package/dist/core/events.js.map +1 -0
  81. package/dist/core/extractor.d.ts +37 -0
  82. package/dist/core/extractor.d.ts.map +1 -0
  83. package/dist/core/extractor.js +448 -0
  84. package/dist/core/extractor.js.map +1 -0
  85. package/dist/core/formatter.d.ts +25 -0
  86. package/dist/core/formatter.d.ts.map +1 -0
  87. package/dist/core/formatter.js +97 -0
  88. package/dist/core/formatter.js.map +1 -0
  89. package/dist/core/knowledge-lifecycle.d.ts +15 -0
  90. package/dist/core/knowledge-lifecycle.d.ts.map +1 -0
  91. package/dist/core/knowledge-lifecycle.js +103 -0
  92. package/dist/core/knowledge-lifecycle.js.map +1 -0
  93. package/dist/core/maintenance.d.ts +13 -0
  94. package/dist/core/maintenance.d.ts.map +1 -0
  95. package/dist/core/maintenance.js +102 -0
  96. package/dist/core/maintenance.js.map +1 -0
  97. package/dist/core/manager.d.ts +110 -0
  98. package/dist/core/manager.d.ts.map +1 -0
  99. package/dist/core/manager.js +640 -0
  100. package/dist/core/manager.js.map +1 -0
  101. package/dist/core/monitor.d.ts +73 -0
  102. package/dist/core/monitor.d.ts.map +1 -0
  103. package/dist/core/monitor.js +395 -0
  104. package/dist/core/monitor.js.map +1 -0
  105. package/dist/core/orchestrator.d.ts +64 -0
  106. package/dist/core/orchestrator.d.ts.map +1 -0
  107. package/dist/core/orchestrator.js +916 -0
  108. package/dist/core/orchestrator.js.map +1 -0
  109. package/dist/core/presets.d.ts +15 -0
  110. package/dist/core/presets.d.ts.map +1 -0
  111. package/dist/core/presets.js +99 -0
  112. package/dist/core/presets.js.map +1 -0
  113. package/dist/core/provider-managers.d.ts +47 -0
  114. package/dist/core/provider-managers.d.ts.map +1 -0
  115. package/dist/core/provider-managers.js +112 -0
  116. package/dist/core/provider-managers.js.map +1 -0
  117. package/dist/core/quick.d.ts +62 -0
  118. package/dist/core/quick.d.ts.map +1 -0
  119. package/dist/core/quick.js +300 -0
  120. package/dist/core/quick.js.map +1 -0
  121. package/dist/core/retrieval.d.ts +29 -0
  122. package/dist/core/retrieval.d.ts.map +1 -0
  123. package/dist/core/retrieval.js +150 -0
  124. package/dist/core/retrieval.js.map +1 -0
  125. package/dist/core/runtime.d.ts +67 -0
  126. package/dist/core/runtime.d.ts.map +1 -0
  127. package/dist/core/runtime.js +84 -0
  128. package/dist/core/runtime.js.map +1 -0
  129. package/dist/core/streaming.d.ts +37 -0
  130. package/dist/core/streaming.d.ts.map +1 -0
  131. package/dist/core/streaming.js +51 -0
  132. package/dist/core/streaming.js.map +1 -0
  133. package/dist/core/sync.d.ts +13 -0
  134. package/dist/core/sync.d.ts.map +1 -0
  135. package/dist/core/sync.js +46 -0
  136. package/dist/core/sync.js.map +1 -0
  137. package/dist/core/telemetry.d.ts +8 -0
  138. package/dist/core/telemetry.d.ts.map +1 -0
  139. package/dist/core/telemetry.js +14 -0
  140. package/dist/core/telemetry.js.map +1 -0
  141. package/dist/core/tokens.d.ts +8 -0
  142. package/dist/core/tokens.d.ts.map +1 -0
  143. package/dist/core/tokens.js +59 -0
  144. package/dist/core/tokens.js.map +1 -0
  145. package/dist/core/trust.d.ts +23 -0
  146. package/dist/core/trust.d.ts.map +1 -0
  147. package/dist/core/trust.js +164 -0
  148. package/dist/core/trust.js.map +1 -0
  149. package/dist/core/validation.d.ts +36 -0
  150. package/dist/core/validation.d.ts.map +1 -0
  151. package/dist/core/validation.js +185 -0
  152. package/dist/core/validation.js.map +1 -0
  153. package/dist/embeddings/local.d.ts +5 -0
  154. package/dist/embeddings/local.d.ts.map +1 -0
  155. package/dist/embeddings/local.js +128 -0
  156. package/dist/embeddings/local.js.map +1 -0
  157. package/dist/embeddings/openai.d.ts +26 -0
  158. package/dist/embeddings/openai.d.ts.map +1 -0
  159. package/dist/embeddings/openai.js +48 -0
  160. package/dist/embeddings/openai.js.map +1 -0
  161. package/dist/embeddings/resilience.d.ts +5 -0
  162. package/dist/embeddings/resilience.d.ts.map +1 -0
  163. package/dist/embeddings/resilience.js +53 -0
  164. package/dist/embeddings/resilience.js.map +1 -0
  165. package/dist/embeddings/voyage.d.ts +30 -0
  166. package/dist/embeddings/voyage.d.ts.map +1 -0
  167. package/dist/embeddings/voyage.js +53 -0
  168. package/dist/embeddings/voyage.js.map +1 -0
  169. package/dist/index.d.ts +72 -0
  170. package/dist/index.d.ts.map +1 -0
  171. package/dist/index.js +40 -0
  172. package/dist/index.js.map +1 -0
  173. package/dist/integrations/claude-agent.d.ts +21 -0
  174. package/dist/integrations/claude-agent.d.ts.map +1 -0
  175. package/dist/integrations/claude-agent.js +44 -0
  176. package/dist/integrations/claude-agent.js.map +1 -0
  177. package/dist/integrations/claude-tools.d.ts +18 -0
  178. package/dist/integrations/claude-tools.d.ts.map +1 -0
  179. package/dist/integrations/claude-tools.js +60 -0
  180. package/dist/integrations/claude-tools.js.map +1 -0
  181. package/dist/integrations/langchain.d.ts +24 -0
  182. package/dist/integrations/langchain.d.ts.map +1 -0
  183. package/dist/integrations/langchain.js +48 -0
  184. package/dist/integrations/langchain.js.map +1 -0
  185. package/dist/integrations/mcp.d.ts +23 -0
  186. package/dist/integrations/mcp.d.ts.map +1 -0
  187. package/dist/integrations/mcp.js +60 -0
  188. package/dist/integrations/mcp.js.map +1 -0
  189. package/dist/integrations/middleware.d.ts +15 -0
  190. package/dist/integrations/middleware.d.ts.map +1 -0
  191. package/dist/integrations/middleware.js +27 -0
  192. package/dist/integrations/middleware.js.map +1 -0
  193. package/dist/integrations/openai-tools.d.ts +21 -0
  194. package/dist/integrations/openai-tools.d.ts.map +1 -0
  195. package/dist/integrations/openai-tools.js +69 -0
  196. package/dist/integrations/openai-tools.js.map +1 -0
  197. package/dist/integrations/vercel-ai.d.ts +19 -0
  198. package/dist/integrations/vercel-ai.d.ts.map +1 -0
  199. package/dist/integrations/vercel-ai.js +41 -0
  200. package/dist/integrations/vercel-ai.js.map +1 -0
  201. package/dist/server/http-server.d.ts +61 -0
  202. package/dist/server/http-server.d.ts.map +1 -0
  203. package/dist/server/http-server.js +684 -0
  204. package/dist/server/http-server.js.map +1 -0
  205. package/dist/server/index.d.ts +5 -0
  206. package/dist/server/index.d.ts.map +1 -0
  207. package/dist/server/index.js +3 -0
  208. package/dist/server/index.js.map +1 -0
  209. package/dist/server/mcp-server.d.ts +61 -0
  210. package/dist/server/mcp-server.d.ts.map +1 -0
  211. package/dist/server/mcp-server.js +465 -0
  212. package/dist/server/mcp-server.js.map +1 -0
  213. package/dist/summarizers/claude.d.ts +11 -0
  214. package/dist/summarizers/claude.d.ts.map +1 -0
  215. package/dist/summarizers/claude.js +39 -0
  216. package/dist/summarizers/claude.js.map +1 -0
  217. package/dist/summarizers/client.d.ts +23 -0
  218. package/dist/summarizers/client.d.ts.map +1 -0
  219. package/dist/summarizers/client.js +24 -0
  220. package/dist/summarizers/client.js.map +1 -0
  221. package/dist/summarizers/extractive.d.ts +6 -0
  222. package/dist/summarizers/extractive.d.ts.map +1 -0
  223. package/dist/summarizers/extractive.js +204 -0
  224. package/dist/summarizers/extractive.js.map +1 -0
  225. package/dist/summarizers/extractor.d.ts +12 -0
  226. package/dist/summarizers/extractor.d.ts.map +1 -0
  227. package/dist/summarizers/extractor.js +75 -0
  228. package/dist/summarizers/extractor.js.map +1 -0
  229. package/dist/summarizers/openai.d.ts +11 -0
  230. package/dist/summarizers/openai.d.ts.map +1 -0
  231. package/dist/summarizers/openai.js +41 -0
  232. package/dist/summarizers/openai.js.map +1 -0
  233. package/dist/summarizers/prompts.d.ts +11 -0
  234. package/dist/summarizers/prompts.d.ts.map +1 -0
  235. package/dist/summarizers/prompts.js +104 -0
  236. package/dist/summarizers/prompts.js.map +1 -0
  237. package/docs/DEPLOYMENT.md +84 -0
  238. package/docs/INTEGRATIONS.md +64 -0
  239. package/docs/MEMORY_QUALITY_BASELINE.md +55 -0
  240. package/docs/MEMORY_QUALITY_RELEASE_GATE.md +63 -0
  241. package/docs/MEMORY_QUALITY_RUBRIC.md +249 -0
  242. package/docs/OPERATIONS.md +49 -0
  243. package/docs/SECURITY.md +25 -0
  244. package/openapi.yaml +843 -0
  245. package/package.json +157 -0
@@ -0,0 +1,640 @@
1
+ import { DEFAULT_CONTEXT_POLICY, DEFAULT_MONITOR_POLICY, } from '../contracts/policy.js';
2
+ import { buildMemoryContext } from './context.js';
3
+ import { compactTurns, extractKnowledge, } from './orchestrator.js';
4
+ import { assessContext } from './monitor.js';
5
+ import { runMaintenance } from './maintenance.js';
6
+ import { emitMemoryEvent } from './telemetry.js';
7
+ import { wrapSyncAdapter } from '../adapters/sync-to-async.js';
8
+ import { estimateTokens } from './tokens.js';
9
+ import { createCircuitBreaker } from './circuit-breaker.js';
10
+ import { DEFAULT_EXTRACTION_POLICY } from '../contracts/policy.js';
11
+ import { assessKnowledgeReverification } from './trust.js';
12
+ import { matchesKnowledgeSearchOptions, rankKnowledge } from './retrieval.js';
13
+ import { computeNextReverificationAt, getDueReverificationKnowledge, resolveMaintenancePolicy, } from './knowledge-lifecycle.js';
14
+ import { normalizeScope } from '../contracts/identity.js';
15
+ function resolveAdapter(config) {
16
+ if (config.asyncAdapter) {
17
+ return config.asyncAdapter;
18
+ }
19
+ if (config.adapter) {
20
+ return wrapSyncAdapter(config.adapter);
21
+ }
22
+ throw new Error("MemoryManagerConfig requires either 'adapter' or 'asyncAdapter'");
23
+ }
24
+ function manualKnowledgeClassForFactType(factType) {
25
+ switch (factType) {
26
+ case 'preference':
27
+ return 'preference';
28
+ case 'constraint':
29
+ return 'constraint';
30
+ case 'decision':
31
+ return 'procedure';
32
+ case 'entity':
33
+ return 'identity';
34
+ default:
35
+ return 'project_fact';
36
+ }
37
+ }
38
+ function knowledgeMatchesScope(knowledge, scope) {
39
+ const normalized = normalizeScope(scope);
40
+ return (knowledge.tenant_id === normalized.tenant_id &&
41
+ knowledge.system_id === normalized.system_id &&
42
+ knowledge.workspace_id === normalized.workspace_id &&
43
+ knowledge.collaboration_id === normalized.collaboration_id &&
44
+ knowledge.scope_id === normalized.scope_id);
45
+ }
46
+ export function createMemoryManager(config) {
47
+ const asyncAdapter = resolveAdapter(config);
48
+ const autoCompact = config.autoCompact ?? true;
49
+ let autoExtractEnabled = config.autoExtract ?? Boolean(config.extractor);
50
+ let deferredSoftCompaction = false;
51
+ const tokenEstimator = config.tokenEstimator ?? estimateTokens;
52
+ const circuitBreakers = {
53
+ summarizer: createCircuitBreaker(config.circuitBreaker?.summarizer),
54
+ extractor: createCircuitBreaker(config.circuitBreaker?.extractor),
55
+ embeddings: createCircuitBreaker(config.circuitBreaker?.embeddings),
56
+ };
57
+ const onEvent = (event) => {
58
+ config.onEvent?.(event);
59
+ config.eventEmitter?.emit({
60
+ ...event,
61
+ meta: {
62
+ schemaVersion: 1,
63
+ ...event.meta,
64
+ },
65
+ });
66
+ };
67
+ function emitKnowledgeChange(action, knowledge) {
68
+ emitMemoryEvent('knowledge_change', knowledge, { logger: config.logger, onEvent }, 0, {
69
+ action,
70
+ knowledgeId: knowledge.id,
71
+ fact: knowledge.fact,
72
+ factType: knowledge.fact_type,
73
+ knowledgeState: knowledge.knowledge_state,
74
+ scope: {
75
+ tenant_id: knowledge.tenant_id,
76
+ system_id: knowledge.system_id,
77
+ workspace_id: knowledge.workspace_id,
78
+ collaboration_id: knowledge.collaboration_id,
79
+ scope_id: knowledge.scope_id,
80
+ },
81
+ });
82
+ }
83
+ function emitDegradation(kind, detail) {
84
+ emitMemoryEvent('manager', config.scope, { logger: config.logger, onEvent }, 0, {
85
+ action: 'degraded_mode',
86
+ subsystem: kind,
87
+ ...detail,
88
+ });
89
+ }
90
+ async function withFailurePolicy(kind, run, fallback) {
91
+ const strategy = config.failurePolicy?.[kind] ??
92
+ (kind === 'extractor' ? 'disable_auto_extract' : 'throw');
93
+ try {
94
+ return await circuitBreakers[kind].execute(run);
95
+ }
96
+ catch (error) {
97
+ if (strategy === 'retry_once') {
98
+ try {
99
+ return await run();
100
+ }
101
+ catch (retryError) {
102
+ config.logger?.error(`memory.${kind}.retry_failed`, {
103
+ error: String(retryError),
104
+ });
105
+ throw retryError;
106
+ }
107
+ }
108
+ config.logger?.error(`memory.${kind}.failed`, {
109
+ error: String(error),
110
+ });
111
+ if (strategy === 'disable_auto_extract' && kind === 'extractor') {
112
+ autoExtractEnabled = false;
113
+ emitDegradation(kind, {
114
+ strategy,
115
+ error: String(error),
116
+ autoExtractEnabled,
117
+ });
118
+ return fallback();
119
+ }
120
+ if (strategy === 'log_and_continue') {
121
+ emitDegradation(kind, {
122
+ strategy,
123
+ error: String(error),
124
+ });
125
+ return fallback();
126
+ }
127
+ throw error;
128
+ }
129
+ }
130
+ async function persistMonitorState(state, score, turns, lastCompactionAt) {
131
+ await asyncAdapter.upsertContextMonitor({
132
+ ...config.scope,
133
+ compaction_state: state,
134
+ active_turn_count: turns.length,
135
+ active_token_estimate: turns.reduce((acc, turn) => acc + turn.token_estimate, 0),
136
+ compaction_score: score,
137
+ last_compaction_at: lastCompactionAt,
138
+ });
139
+ }
140
+ async function buildQueryVector(input) {
141
+ if (!config.embeddingGenerator || input.trim().length === 0) {
142
+ return undefined;
143
+ }
144
+ try {
145
+ const vectors = await circuitBreakers.embeddings.execute(() => config.embeddingGenerator([input]));
146
+ return vectors[0];
147
+ }
148
+ catch (error) {
149
+ config.logger?.warn('memory.embeddings.query_vector_failed', {
150
+ error: String(error),
151
+ });
152
+ emitDegradation('embeddings', {
153
+ stage: 'query_vector',
154
+ error: String(error),
155
+ });
156
+ return undefined;
157
+ }
158
+ }
159
+ async function maybeEmbedKnowledge(knowledge) {
160
+ if (!config.embeddingAdapter || !config.embeddingGenerator || knowledge.length === 0) {
161
+ return;
162
+ }
163
+ try {
164
+ const vectors = await circuitBreakers.embeddings.execute(() => config.embeddingGenerator(knowledge.map((item) => item.fact)));
165
+ for (const [index, item] of knowledge.entries()) {
166
+ const vector = vectors[index];
167
+ if (vector) {
168
+ await config.embeddingAdapter.storeEmbedding(item.id, vector);
169
+ }
170
+ }
171
+ }
172
+ catch (error) {
173
+ config.logger?.warn('memory.embeddings.index_failed', {
174
+ error: String(error),
175
+ knowledgeCount: knowledge.length,
176
+ });
177
+ emitDegradation('embeddings', {
178
+ stage: 'index',
179
+ error: String(error),
180
+ knowledgeCount: knowledge.length,
181
+ });
182
+ }
183
+ }
184
+ function normalizeSemanticMatches(matches) {
185
+ if (matches.length === 0) {
186
+ return new Map();
187
+ }
188
+ const maxSimilarity = Math.max(...matches.map((match) => match.similarity), 1);
189
+ return new Map(matches.map((match) => [match.knowledgeMemoryId, match.similarity / maxSimilarity]));
190
+ }
191
+ async function getHybridKnowledgeResults(query, options, level = config.crossScopeLevel ?? 'scope') {
192
+ const resolvedContextPolicy = {
193
+ ...DEFAULT_CONTEXT_POLICY,
194
+ ...config.contextPolicy,
195
+ };
196
+ const lexical = level === 'scope'
197
+ ? await asyncAdapter.searchKnowledge(config.scope, query, options)
198
+ : await asyncAdapter.searchKnowledgeCrossScope(config.scope, level, query, options);
199
+ const filteredLexical = lexical.filter((result) => matchesKnowledgeSearchOptions(result.item, options));
200
+ if (!config.embeddingAdapter) {
201
+ return filteredLexical;
202
+ }
203
+ const queryVector = await buildQueryVector(query);
204
+ if (!queryVector) {
205
+ return filteredLexical;
206
+ }
207
+ let semantic;
208
+ try {
209
+ semantic =
210
+ level === 'scope'
211
+ ? await config.embeddingAdapter.findSimilar(config.scope, queryVector, {
212
+ limit: options?.limit ?? 10,
213
+ minSimilarity: resolvedContextPolicy.semanticMinSimilarity,
214
+ })
215
+ : await config.embeddingAdapter.findSimilarCrossScope(config.scope, level, queryVector, {
216
+ limit: options?.limit ?? 10,
217
+ minSimilarity: resolvedContextPolicy.semanticMinSimilarity,
218
+ });
219
+ }
220
+ catch (error) {
221
+ config.logger?.warn('memory.embeddings.semantic_search_failed', {
222
+ error: String(error),
223
+ scopeLevel: level,
224
+ });
225
+ emitDegradation('embeddings', {
226
+ stage: 'semantic_search',
227
+ error: String(error),
228
+ scopeLevel: level,
229
+ });
230
+ return filteredLexical;
231
+ }
232
+ const lexicalRanks = new Map();
233
+ const semanticRanks = normalizeSemanticMatches(semantic);
234
+ filteredLexical.forEach((result) => lexicalRanks.set(result.item.id, result.rank));
235
+ const merged = new Map();
236
+ for (const result of filteredLexical) {
237
+ merged.set(result.item.id, result);
238
+ }
239
+ for (const result of semantic) {
240
+ const knowledge = await asyncAdapter.getKnowledgeMemoryById(result.knowledgeMemoryId);
241
+ if (!knowledge)
242
+ continue;
243
+ if (!matchesKnowledgeSearchOptions(knowledge, options))
244
+ continue;
245
+ const existing = merged.get(knowledge.id);
246
+ const recencyScore = knowledge.last_accessed_at > 0
247
+ ? 1 / (1 + Math.max(0, Math.floor(Date.now() / 1000) - knowledge.last_accessed_at) / 86400)
248
+ : 0;
249
+ const ranking = rankKnowledge({
250
+ knowledge,
251
+ lexicalScore: lexicalRanks.get(knowledge.id) ?? 0,
252
+ semanticScore: semanticRanks.get(knowledge.id) ?? 0,
253
+ recencyScore,
254
+ importanceScore: Math.min(1, knowledge.access_count / 10),
255
+ policy: resolvedContextPolicy,
256
+ scope: config.scope,
257
+ relevanceTexts: [query],
258
+ preferLocalTrusted: options?.preferLocalTrusted ?? true,
259
+ preferLineageMemory: options?.preferLineageMemory ?? level !== 'scope',
260
+ });
261
+ merged.set(knowledge.id, {
262
+ item: knowledge,
263
+ rank: existing ? Math.max(existing.rank, ranking.finalScore) : ranking.finalScore,
264
+ });
265
+ }
266
+ const results = [...merged.values()]
267
+ .sort((a, b) => b.rank - a.rank || b.item.last_accessed_at - a.item.last_accessed_at)
268
+ .slice(0, options?.limit ?? 10);
269
+ if (config.contextPolicy?.touchSelectedKnowledge ?? true) {
270
+ for (const result of results) {
271
+ await asyncAdapter.touchKnowledgeMemory(result.item.id);
272
+ }
273
+ }
274
+ return results;
275
+ }
276
+ async function getContextInternal(relevanceQuery, asOf) {
277
+ const activeTurns = await asyncAdapter.getActiveTurns(config.scope, config.sessionId);
278
+ const queryVector = await buildQueryVector(relevanceQuery ??
279
+ activeTurns
280
+ .slice(-4)
281
+ .map((turn) => turn.content)
282
+ .join('\n'));
283
+ return buildMemoryContext(asyncAdapter, config.scope, {
284
+ sessionId: config.sessionId,
285
+ relevanceQuery,
286
+ queryVector,
287
+ embeddingAdapter: config.embeddingAdapter,
288
+ crossScopeLevel: config.crossScopeLevel,
289
+ policy: config.contextPolicy,
290
+ tokenEstimator,
291
+ asOf,
292
+ logger: config.logger,
293
+ onEvent,
294
+ });
295
+ }
296
+ async function executeCompaction(turns, trigger, retainedTurnCount, score) {
297
+ await persistMonitorState('compacting', score, turns);
298
+ const result = await withFailurePolicy('summarizer', () => compactTurns(asyncAdapter, config.scope, config.sessionId, turns, config.summarizer, trigger, retainedTurnCount, { logger: config.logger, onEvent }), () => null);
299
+ if (!result) {
300
+ await persistMonitorState('idle', score, turns);
301
+ emitDegradation('summarizer', {
302
+ stage: 'compaction',
303
+ strategy: config.failurePolicy?.summarizer ?? 'throw',
304
+ });
305
+ return null;
306
+ }
307
+ const remainingTurns = await asyncAdapter.getActiveTurns(config.scope, config.sessionId);
308
+ await persistMonitorState('idle', score, remainingTurns, Math.floor(Date.now() / 1000));
309
+ deferredSoftCompaction = false;
310
+ if (config.extractor && autoExtractEnabled) {
311
+ const extracted = await withFailurePolicy('extractor', () => extractKnowledge(asyncAdapter, result.workingMemory.id, config.scope, config.extractor, {
312
+ logger: config.logger,
313
+ onEvent,
314
+ policy: config.extractionPolicy,
315
+ }), () => []);
316
+ await maybeEmbedKnowledge(extracted);
317
+ extracted.forEach((knowledge) => emitKnowledgeChange('promoted', knowledge));
318
+ }
319
+ return result;
320
+ }
321
+ async function runCompaction(turns) {
322
+ const latestWorkingMemory = await asyncAdapter.getLatestWorkingMemory(config.scope, config.sessionId);
323
+ const report = assessContext({
324
+ scope: config.scope,
325
+ session_id: config.sessionId,
326
+ active_turns: turns,
327
+ latest_working_memory: latestWorkingMemory,
328
+ }, config.monitorPolicy);
329
+ const longGapDetected = report.topic_drift_signals.some((signal) => signal.type === 'long_intra_session_gap' && signal.detected);
330
+ if (longGapDetected && turns.length > 1) {
331
+ return executeCompaction(turns, 'session_gap', Math.max(1, Math.min(config.monitorPolicy?.softRetainTurns ?? DEFAULT_MONITOR_POLICY.softRetainTurns, turns.length - 1)), report.score_breakdown.total);
332
+ }
333
+ if (report.recommendation.action === 'none') {
334
+ await persistMonitorState('idle', report.score_breakdown.total, turns);
335
+ deferredSoftCompaction = false;
336
+ return null;
337
+ }
338
+ if (report.recommendation.action === 'soft' && report.recommendation.defer_to_idle) {
339
+ await persistMonitorState('soft_triggered', report.score_breakdown.total, turns);
340
+ deferredSoftCompaction = true;
341
+ return null;
342
+ }
343
+ return executeCompaction(turns, report.recommendation.action, Math.max(0, Math.min(report.recommendation.post_compaction_target_turns, turns.length - 1)), report.score_breakdown.total);
344
+ }
345
+ async function insertManagedTurn(role, content, actor) {
346
+ const redactedContent = config.redactText ? config.redactText({ kind: 'turn', text: content }) : content;
347
+ const turn = await asyncAdapter.insertTurn({
348
+ ...config.scope,
349
+ session_id: config.sessionId,
350
+ actor,
351
+ role,
352
+ content: redactedContent,
353
+ token_estimate: tokenEstimator(redactedContent),
354
+ });
355
+ emitMemoryEvent('manager', config.scope, { logger: config.logger, onEvent }, 0, {
356
+ action: 'process_turn',
357
+ role,
358
+ turnId: turn.id,
359
+ });
360
+ return turn;
361
+ }
362
+ return {
363
+ async processTurn(role, content, actor = role === 'assistant' ? 'assistant' : 'user') {
364
+ const turn = await insertManagedTurn(role, content, actor);
365
+ if (autoCompact) {
366
+ const activeTurns = await asyncAdapter.getActiveTurns(config.scope, config.sessionId);
367
+ await runCompaction(activeTurns);
368
+ }
369
+ return turn;
370
+ },
371
+ async processExchange(userContent, assistantContent, actors) {
372
+ const userTurn = await insertManagedTurn('user', userContent, actors?.user ?? 'user');
373
+ const assistantTurn = await insertManagedTurn('assistant', assistantContent, actors?.assistant ?? 'assistant');
374
+ const compactionResult = autoCompact
375
+ ? await runCompaction(await asyncAdapter.getActiveTurns(config.scope, config.sessionId))
376
+ : null;
377
+ return {
378
+ userTurn,
379
+ assistantTurn,
380
+ compactionResult,
381
+ };
382
+ },
383
+ async getContext(relevanceQuery) {
384
+ return getContextInternal(relevanceQuery);
385
+ },
386
+ async getContextAt(asOf, relevanceQuery) {
387
+ return getContextInternal(relevanceQuery, asOf);
388
+ },
389
+ async getSessionBootstrap(relevanceQuery) {
390
+ const context = await getContextInternal(relevanceQuery);
391
+ return {
392
+ currentObjective: context.currentObjective,
393
+ workingMemory: context.workingMemory,
394
+ relevantKnowledge: context.relevantKnowledge,
395
+ recentSummaries: context.recentSummaries,
396
+ activeObjectives: context.activeObjectives,
397
+ unresolvedWork: context.unresolvedWork,
398
+ };
399
+ },
400
+ async recall(timeRange) {
401
+ return {
402
+ turns: await asyncAdapter.getTurnsByTimeRange(config.scope, timeRange),
403
+ workingMemory: await asyncAdapter.getWorkingMemoryByTimeRange(config.scope, timeRange),
404
+ knowledge: await asyncAdapter.getKnowledgeByTimeRange(config.scope, timeRange),
405
+ workItems: await asyncAdapter.getWorkItemsByTimeRange(config.scope, timeRange),
406
+ };
407
+ },
408
+ async search(query, options) {
409
+ const results = {
410
+ turns: await asyncAdapter.searchTurns(config.scope, query, options),
411
+ knowledge: await getHybridKnowledgeResults(query, options, config.crossScopeLevel ?? 'scope'),
412
+ };
413
+ emitMemoryEvent('manager', config.scope, { logger: config.logger, onEvent }, 0, {
414
+ action: 'search',
415
+ query,
416
+ turnResultCount: results.turns.length,
417
+ knowledgeResultCount: results.knowledge.length,
418
+ });
419
+ return results;
420
+ },
421
+ async searchCrossScope(query, level, options) {
422
+ return {
423
+ knowledge: await getHybridKnowledgeResults(query, options, level),
424
+ };
425
+ },
426
+ async pollForChanges(since, options) {
427
+ return asyncAdapter.getKnowledgeSince(config.scope, options?.scopeLevel ?? config.crossScopeLevel ?? 'scope', Math.floor(since.valueOf() / 1000));
428
+ },
429
+ async forceCompact() {
430
+ if (deferredSoftCompaction) {
431
+ config.logger?.info('memory.compaction.flushing_deferred');
432
+ }
433
+ const turns = await asyncAdapter.getActiveTurns(config.scope, config.sessionId);
434
+ const latestWorkingMemory = await asyncAdapter.getLatestWorkingMemory(config.scope, config.sessionId);
435
+ const report = assessContext({
436
+ scope: config.scope,
437
+ session_id: config.sessionId,
438
+ active_turns: turns,
439
+ latest_working_memory: latestWorkingMemory,
440
+ }, config.monitorPolicy);
441
+ if (report.recommendation.action === 'none') {
442
+ return null;
443
+ }
444
+ return executeCompaction(turns, 'manual', Math.max(0, Math.min(report.recommendation.post_compaction_target_turns, turns.length - 1)), report.score_breakdown.total);
445
+ },
446
+ async learnFact(fact, factType, confidence = 'high') {
447
+ const knowledge = await asyncAdapter.insertKnowledgeMemory({
448
+ ...config.scope,
449
+ fact: config.redactText ? config.redactText({ kind: 'fact', text: fact }) : fact,
450
+ fact_type: factType,
451
+ knowledge_class: manualKnowledgeClassForFactType(factType),
452
+ source: 'manual',
453
+ confidence,
454
+ });
455
+ await maybeEmbedKnowledge([knowledge]);
456
+ emitMemoryEvent('manager', config.scope, { logger: config.logger, onEvent }, 0, {
457
+ action: 'learn_fact',
458
+ knowledgeMemoryId: knowledge.id,
459
+ factType,
460
+ });
461
+ emitKnowledgeChange('learned', knowledge);
462
+ return knowledge;
463
+ },
464
+ async trackWorkItem(title, kind = 'objective', status = 'open', detail) {
465
+ return asyncAdapter.insertWorkItem({
466
+ ...config.scope,
467
+ session_id: config.sessionId,
468
+ title: config.redactText ? config.redactText({ kind: 'work_item', text: title }) : title,
469
+ kind,
470
+ status,
471
+ detail: detail && config.redactText
472
+ ? config.redactText({ kind: 'work_item', text: detail })
473
+ : detail,
474
+ });
475
+ },
476
+ async inspectKnowledge(id) {
477
+ const knowledge = await asyncAdapter.getKnowledgeMemoryById(id);
478
+ if (!knowledge || !knowledgeMatchesScope(knowledge, config.scope)) {
479
+ return { knowledge: null, evidence: [], audits: [] };
480
+ }
481
+ const evidence = await asyncAdapter.listKnowledgeEvidenceForKnowledge(id);
482
+ const audits = await asyncAdapter.getKnowledgeMemoryAuditsForKnowledge(config.scope, id, 50);
483
+ return { knowledge, evidence, audits };
484
+ },
485
+ async listKnowledge(options) {
486
+ return asyncAdapter.getActiveKnowledgeMemoryPaginated(config.scope, options);
487
+ },
488
+ async getKnowledgeAudits(options) {
489
+ if (options?.knowledgeId != null) {
490
+ return asyncAdapter.getKnowledgeMemoryAuditsForKnowledge(config.scope, options.knowledgeId, options.limit ?? 20);
491
+ }
492
+ return asyncAdapter.getRecentKnowledgeMemoryAudits(config.scope, options?.limit ?? 20);
493
+ },
494
+ async getContextMonitor() {
495
+ return asyncAdapter.getContextMonitor(config.scope);
496
+ },
497
+ async getRecentCompactionLogs(limit) {
498
+ return asyncAdapter.getRecentCompactionLogs(config.scope, limit ?? 10);
499
+ },
500
+ async getDueReverification(options) {
501
+ const now = Math.floor(Date.now() / 1000);
502
+ const maintenancePolicy = resolveMaintenancePolicy(config.maintenancePolicy);
503
+ const activeKnowledge = await asyncAdapter.getActiveKnowledgeMemory(config.scope);
504
+ return getDueReverificationKnowledge(activeKnowledge, maintenancePolicy, now).slice(0, options?.limit ?? activeKnowledge.length);
505
+ },
506
+ async reverifyKnowledge(id) {
507
+ const knowledge = await asyncAdapter.getKnowledgeMemoryById(id);
508
+ if (!knowledge) {
509
+ throw new Error(`Memory validation: knowledge memory ${id} was not found`);
510
+ }
511
+ if (!knowledgeMatchesScope(knowledge, config.scope)) {
512
+ throw new Error(`Memory validation: knowledge memory ${id} does not belong to the requested scope`);
513
+ }
514
+ const evidence = await asyncAdapter.listKnowledgeEvidenceForKnowledge(id);
515
+ const policy = {
516
+ ...DEFAULT_EXTRACTION_POLICY,
517
+ ...config.extractionPolicy,
518
+ };
519
+ const assessment = assessKnowledgeReverification({
520
+ knowledge,
521
+ evidence,
522
+ policy,
523
+ });
524
+ const supportEvidence = evidence.filter((item) => item.support_polarity === 'supports');
525
+ const successCount = supportEvidence.filter((item) => item.outcome === 'success').length;
526
+ const failureCount = supportEvidence.filter((item) => item.outcome === 'failure').length;
527
+ const now = Math.floor(Date.now() / 1000);
528
+ const maintenancePolicy = resolveMaintenancePolicy(config.maintenancePolicy);
529
+ const nextReverificationAt = computeNextReverificationAt({
530
+ ...knowledge,
531
+ knowledge_state: assessment.state,
532
+ last_verified_at: now,
533
+ last_confirmed_at: assessment.state === 'trusted' ? now : knowledge.last_confirmed_at,
534
+ confirmation_count: assessment.state === 'trusted'
535
+ ? knowledge.confirmation_count + 1
536
+ : knowledge.confirmation_count,
537
+ }, maintenancePolicy);
538
+ const updated = await asyncAdapter.updateKnowledgeMemory(id, {
539
+ knowledge_state: assessment.state,
540
+ knowledge_class: failureCount > successCount &&
541
+ ['strategy', 'procedure'].includes(knowledge.knowledge_class)
542
+ ? 'anti_pattern'
543
+ : successCount > 0 &&
544
+ assessment.state === 'trusted' &&
545
+ knowledge.knowledge_class === 'procedure'
546
+ ? 'strategy'
547
+ : knowledge.knowledge_class,
548
+ trust_score: assessment.trust_score,
549
+ verification_status: assessment.state === 'trusted'
550
+ ? 'verified'
551
+ : assessment.state === 'provisional'
552
+ ? 'corroborated'
553
+ : 'unverified',
554
+ verification_notes: assessment.reasons.join(', ') || null,
555
+ last_verified_at: now,
556
+ next_reverification_at: nextReverificationAt,
557
+ last_confirmed_at: assessment.state === 'trusted' ? now : knowledge.last_confirmed_at,
558
+ confirmation_count: assessment.state === 'trusted'
559
+ ? knowledge.confirmation_count + 1
560
+ : knowledge.confirmation_count,
561
+ disputed_at: assessment.state === 'disputed' ? now : knowledge.disputed_at,
562
+ dispute_reason: assessment.state === 'disputed' ? assessment.reasons.join(', ') : knowledge.dispute_reason,
563
+ contradiction_score: assessment.state === 'disputed'
564
+ ? Math.max(knowledge.contradiction_score, 1)
565
+ : knowledge.contradiction_score,
566
+ successful_use_count: knowledge.successful_use_count + successCount,
567
+ failed_use_count: knowledge.failed_use_count + failureCount,
568
+ });
569
+ if (updated) {
570
+ emitKnowledgeChange(assessment.state === 'trusted' ? 'reverified' : 'demoted', updated);
571
+ }
572
+ return assessment;
573
+ },
574
+ async runReverification(options) {
575
+ const now = Math.floor(Date.now() / 1000);
576
+ const maintenancePolicy = resolveMaintenancePolicy(config.maintenancePolicy);
577
+ const activeKnowledge = await asyncAdapter.getActiveKnowledgeMemory(config.scope);
578
+ const due = getDueReverificationKnowledge(activeKnowledge, maintenancePolicy, now).slice(0, options?.limit ?? activeKnowledge.length);
579
+ const reverifiedKnowledgeIds = [];
580
+ const demotedKnowledgeIds = [];
581
+ for (const item of due) {
582
+ const assessment = await this.reverifyKnowledge(item.id);
583
+ reverifiedKnowledgeIds.push(item.id);
584
+ if (assessment.state !== 'trusted') {
585
+ demotedKnowledgeIds.push(item.id);
586
+ }
587
+ }
588
+ return { reverifiedKnowledgeIds, demotedKnowledgeIds };
589
+ },
590
+ async runMaintenance(policy) {
591
+ const effectivePolicyInput = {
592
+ ...(config.maintenancePolicy ?? {}),
593
+ ...(policy ?? {}),
594
+ classRetentionOverrides: {
595
+ ...(config.maintenancePolicy?.classRetentionOverrides ?? {}),
596
+ ...(policy?.classRetentionOverrides ?? {}),
597
+ },
598
+ };
599
+ const effectivePolicy = resolveMaintenancePolicy(effectivePolicyInput);
600
+ const report = await runMaintenance(asyncAdapter, config.scope, effectivePolicy);
601
+ const activeKnowledge = await asyncAdapter.getActiveKnowledgeMemory(config.scope);
602
+ const due = getDueReverificationKnowledge(activeKnowledge, effectivePolicy, Math.floor(Date.now() / 1000));
603
+ const reverification = { reverifiedKnowledgeIds: [], demotedKnowledgeIds: [] };
604
+ for (const item of due) {
605
+ const assessment = await this.reverifyKnowledge(item.id);
606
+ reverification.reverifiedKnowledgeIds.push(item.id);
607
+ if (assessment.state !== 'trusted') {
608
+ reverification.demotedKnowledgeIds.push(item.id);
609
+ }
610
+ }
611
+ report.reverifiedKnowledgeIds.push(...reverification.reverifiedKnowledgeIds);
612
+ report.demotedKnowledgeIds.push(...reverification.demotedKnowledgeIds);
613
+ report.reverifiedKnowledgeIds = [...new Set(report.reverifiedKnowledgeIds)];
614
+ report.demotedKnowledgeIds = [...new Set(report.demotedKnowledgeIds)];
615
+ for (const retiredId of report.retiredKnowledgeIds) {
616
+ const retired = await asyncAdapter.getKnowledgeMemoryById(retiredId);
617
+ if (retired)
618
+ emitKnowledgeChange('retired', retired);
619
+ }
620
+ for (const demotedId of report.demotedKnowledgeIds) {
621
+ const demoted = await asyncAdapter.getKnowledgeMemoryById(demotedId);
622
+ if (demoted)
623
+ emitKnowledgeChange('demoted', demoted);
624
+ }
625
+ emitMemoryEvent('manager', config.scope, { logger: config.logger, onEvent }, 0, {
626
+ action: 'run_maintenance',
627
+ expiredWorkingMemoryCount: report.expiredWorkingMemoryIds.length,
628
+ retiredKnowledgeCount: report.retiredKnowledgeIds.length,
629
+ deletedWorkItemCount: report.deletedWorkItemIds.length,
630
+ reverifiedKnowledgeCount: report.reverifiedKnowledgeIds.length,
631
+ demotedKnowledgeCount: report.demotedKnowledgeIds.length,
632
+ });
633
+ return report;
634
+ },
635
+ async close() {
636
+ await asyncAdapter.close();
637
+ },
638
+ };
639
+ }
640
+ //# sourceMappingURL=manager.js.map