@agentmemory/agentmemory 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/.github/workflows/ci.yml +22 -0
  3. package/.github/workflows/publish.yml +28 -0
  4. package/AGENTS.md +113 -0
  5. package/LICENSE +190 -0
  6. package/README.md +828 -0
  7. package/assets/banner.png +0 -0
  8. package/assets/demo.gif +0 -0
  9. package/assets/demo.mp4 +0 -0
  10. package/benchmark/QUALITY.md +73 -0
  11. package/benchmark/REAL-EMBEDDINGS.md +67 -0
  12. package/benchmark/SCALE.md +110 -0
  13. package/benchmark/dataset.ts +293 -0
  14. package/benchmark/quality-eval.ts +643 -0
  15. package/benchmark/real-embeddings-eval.ts +405 -0
  16. package/benchmark/scale-eval.ts +398 -0
  17. package/dist/cli.d.mts +1 -0
  18. package/dist/cli.mjs +137 -0
  19. package/dist/cli.mjs.map +1 -0
  20. package/dist/docker-compose.yml +14 -0
  21. package/dist/hooks/notification.d.mts +1 -0
  22. package/dist/hooks/notification.mjs +45 -0
  23. package/dist/hooks/notification.mjs.map +1 -0
  24. package/dist/hooks/post-tool-failure.d.mts +1 -0
  25. package/dist/hooks/post-tool-failure.mjs +45 -0
  26. package/dist/hooks/post-tool-failure.mjs.map +1 -0
  27. package/dist/hooks/post-tool-use.d.mts +1 -0
  28. package/dist/hooks/post-tool-use.mjs +53 -0
  29. package/dist/hooks/post-tool-use.mjs.map +1 -0
  30. package/dist/hooks/pre-compact.d.mts +1 -0
  31. package/dist/hooks/pre-compact.mjs +50 -0
  32. package/dist/hooks/pre-compact.mjs.map +1 -0
  33. package/dist/hooks/pre-tool-use.d.mts +1 -0
  34. package/dist/hooks/pre-tool-use.mjs +69 -0
  35. package/dist/hooks/pre-tool-use.mjs.map +1 -0
  36. package/dist/hooks/prompt-submit.d.mts +1 -0
  37. package/dist/hooks/prompt-submit.mjs +40 -0
  38. package/dist/hooks/prompt-submit.mjs.map +1 -0
  39. package/dist/hooks/session-end.d.mts +1 -0
  40. package/dist/hooks/session-end.mjs +61 -0
  41. package/dist/hooks/session-end.mjs.map +1 -0
  42. package/dist/hooks/session-start.d.mts +1 -0
  43. package/dist/hooks/session-start.mjs +42 -0
  44. package/dist/hooks/session-start.mjs.map +1 -0
  45. package/dist/hooks/stop.d.mts +1 -0
  46. package/dist/hooks/stop.mjs +33 -0
  47. package/dist/hooks/stop.mjs.map +1 -0
  48. package/dist/hooks/subagent-start.d.mts +1 -0
  49. package/dist/hooks/subagent-start.mjs +43 -0
  50. package/dist/hooks/subagent-start.mjs.map +1 -0
  51. package/dist/hooks/subagent-stop.d.mts +1 -0
  52. package/dist/hooks/subagent-stop.mjs +45 -0
  53. package/dist/hooks/subagent-stop.mjs.map +1 -0
  54. package/dist/hooks/task-completed.d.mts +1 -0
  55. package/dist/hooks/task-completed.mjs +46 -0
  56. package/dist/hooks/task-completed.mjs.map +1 -0
  57. package/dist/iii-config.yaml +51 -0
  58. package/dist/index.d.mts +2 -0
  59. package/dist/index.mjs +13776 -0
  60. package/dist/index.mjs.map +1 -0
  61. package/dist/src-QxitMPfJ.mjs +13775 -0
  62. package/dist/src-QxitMPfJ.mjs.map +1 -0
  63. package/dist/standalone.d.mts +1 -0
  64. package/dist/standalone.mjs +1155 -0
  65. package/dist/standalone.mjs.map +1 -0
  66. package/dist/transformers-BX_tgxdO.mjs +38684 -0
  67. package/dist/transformers-BX_tgxdO.mjs.map +1 -0
  68. package/dist/transformers-KMm1i9no.mjs +38683 -0
  69. package/dist/transformers-KMm1i9no.mjs.map +1 -0
  70. package/docker-compose.yml +14 -0
  71. package/iii-config.yaml +51 -0
  72. package/package.json +59 -0
  73. package/plugin/.claude-plugin/plugin.json +10 -0
  74. package/plugin/hooks/hooks.json +77 -0
  75. package/plugin/scripts/diagnostics.mjs +551 -0
  76. package/plugin/scripts/notification.mjs +45 -0
  77. package/plugin/scripts/post-tool-failure.mjs +45 -0
  78. package/plugin/scripts/post-tool-use.mjs +53 -0
  79. package/plugin/scripts/pre-compact.mjs +50 -0
  80. package/plugin/scripts/pre-tool-use.mjs +69 -0
  81. package/plugin/scripts/prompt-submit.mjs +40 -0
  82. package/plugin/scripts/session-end.mjs +61 -0
  83. package/plugin/scripts/session-start.mjs +42 -0
  84. package/plugin/scripts/stop.mjs +33 -0
  85. package/plugin/scripts/subagent-start.mjs +43 -0
  86. package/plugin/scripts/subagent-stop.mjs +45 -0
  87. package/plugin/scripts/task-completed.mjs +46 -0
  88. package/plugin/skills/forget/SKILL.md +32 -0
  89. package/plugin/skills/recall/SKILL.md +18 -0
  90. package/plugin/skills/remember/SKILL.md +25 -0
  91. package/plugin/skills/session-history/SKILL.md +17 -0
  92. package/src/auth.ts +12 -0
  93. package/src/cli.ts +159 -0
  94. package/src/config.ts +221 -0
  95. package/src/eval/metrics-store.ts +65 -0
  96. package/src/eval/quality.ts +51 -0
  97. package/src/eval/schemas.ts +124 -0
  98. package/src/eval/self-correct.ts +28 -0
  99. package/src/eval/validator.ts +31 -0
  100. package/src/functions/actions.ts +288 -0
  101. package/src/functions/audit.ts +61 -0
  102. package/src/functions/auto-forget.ts +169 -0
  103. package/src/functions/branch-aware.ts +169 -0
  104. package/src/functions/cascade.ts +80 -0
  105. package/src/functions/checkpoints.ts +209 -0
  106. package/src/functions/claude-bridge.ts +161 -0
  107. package/src/functions/compress.ts +194 -0
  108. package/src/functions/consolidate.ts +212 -0
  109. package/src/functions/consolidation-pipeline.ts +258 -0
  110. package/src/functions/context.ts +169 -0
  111. package/src/functions/crystallize.ts +293 -0
  112. package/src/functions/dedup.ts +57 -0
  113. package/src/functions/diagnostics.ts +785 -0
  114. package/src/functions/enrich.ts +132 -0
  115. package/src/functions/evict.ts +163 -0
  116. package/src/functions/export-import.ts +508 -0
  117. package/src/functions/facets.ts +248 -0
  118. package/src/functions/file-index.ts +106 -0
  119. package/src/functions/flow-compress.ts +214 -0
  120. package/src/functions/frontier.ts +196 -0
  121. package/src/functions/governance.ts +131 -0
  122. package/src/functions/graph-retrieval.ts +277 -0
  123. package/src/functions/graph.ts +275 -0
  124. package/src/functions/leases.ts +216 -0
  125. package/src/functions/lessons.ts +253 -0
  126. package/src/functions/mesh.ts +434 -0
  127. package/src/functions/migrate.ts +165 -0
  128. package/src/functions/observe.ts +144 -0
  129. package/src/functions/obsidian-export.ts +310 -0
  130. package/src/functions/patterns.ts +138 -0
  131. package/src/functions/privacy.ts +39 -0
  132. package/src/functions/profile.ts +155 -0
  133. package/src/functions/query-expansion.ts +186 -0
  134. package/src/functions/relations.ts +237 -0
  135. package/src/functions/remember.ts +162 -0
  136. package/src/functions/retention.ts +235 -0
  137. package/src/functions/routines.ts +289 -0
  138. package/src/functions/search.ts +80 -0
  139. package/src/functions/sentinels.ts +417 -0
  140. package/src/functions/signals.ts +186 -0
  141. package/src/functions/sketches.ts +274 -0
  142. package/src/functions/sliding-window.ts +257 -0
  143. package/src/functions/smart-search.ts +115 -0
  144. package/src/functions/snapshot.ts +219 -0
  145. package/src/functions/summarize.ts +155 -0
  146. package/src/functions/team.ts +147 -0
  147. package/src/functions/temporal-graph.ts +476 -0
  148. package/src/functions/timeline.ts +138 -0
  149. package/src/functions/verify.ts +117 -0
  150. package/src/health/monitor.ts +110 -0
  151. package/src/health/thresholds.ts +73 -0
  152. package/src/hooks/notification.ts +52 -0
  153. package/src/hooks/post-tool-failure.ts +58 -0
  154. package/src/hooks/post-tool-use.ts +62 -0
  155. package/src/hooks/pre-compact.ts +60 -0
  156. package/src/hooks/pre-tool-use.ts +72 -0
  157. package/src/hooks/prompt-submit.ts +46 -0
  158. package/src/hooks/session-end.ts +71 -0
  159. package/src/hooks/session-start.ts +48 -0
  160. package/src/hooks/stop.ts +39 -0
  161. package/src/hooks/subagent-start.ts +49 -0
  162. package/src/hooks/subagent-stop.ts +54 -0
  163. package/src/hooks/task-completed.ts +54 -0
  164. package/src/index.ts +342 -0
  165. package/src/mcp/in-memory-kv.ts +61 -0
  166. package/src/mcp/server.ts +1455 -0
  167. package/src/mcp/standalone.ts +177 -0
  168. package/src/mcp/tools-registry.ts +769 -0
  169. package/src/mcp/transport.ts +91 -0
  170. package/src/prompts/compression.ts +67 -0
  171. package/src/prompts/consolidation.ts +48 -0
  172. package/src/prompts/graph-extraction.ts +35 -0
  173. package/src/prompts/summary.ts +38 -0
  174. package/src/prompts/xml.ts +26 -0
  175. package/src/providers/agent-sdk.ts +34 -0
  176. package/src/providers/anthropic.ts +35 -0
  177. package/src/providers/circuit-breaker.ts +82 -0
  178. package/src/providers/embedding/cohere.ts +46 -0
  179. package/src/providers/embedding/gemini.ts +54 -0
  180. package/src/providers/embedding/index.ts +39 -0
  181. package/src/providers/embedding/local.ts +52 -0
  182. package/src/providers/embedding/openai.ts +45 -0
  183. package/src/providers/embedding/openrouter.ts +51 -0
  184. package/src/providers/embedding/voyage.ts +46 -0
  185. package/src/providers/fallback-chain.ts +31 -0
  186. package/src/providers/index.ts +84 -0
  187. package/src/providers/openrouter.ts +71 -0
  188. package/src/providers/resilient.ts +37 -0
  189. package/src/state/hybrid-search.ts +295 -0
  190. package/src/state/index-persistence.ts +63 -0
  191. package/src/state/keyed-mutex.ts +18 -0
  192. package/src/state/kv.ts +33 -0
  193. package/src/state/schema.ts +71 -0
  194. package/src/state/search-index.ts +245 -0
  195. package/src/state/stemmer.ts +104 -0
  196. package/src/state/synonyms.ts +63 -0
  197. package/src/state/vector-index.ts +130 -0
  198. package/src/telemetry/setup.ts +116 -0
  199. package/src/triggers/api.ts +1904 -0
  200. package/src/triggers/events.ts +71 -0
  201. package/src/types.ts +769 -0
  202. package/src/version.ts +1 -0
  203. package/src/viewer/index.html +2497 -0
  204. package/src/viewer/server.ts +207 -0
  205. package/src/xenova.d.ts +3 -0
  206. package/test/actions.test.ts +490 -0
  207. package/test/audit.test.ts +108 -0
  208. package/test/auto-forget.test.ts +188 -0
  209. package/test/cascade.test.ts +277 -0
  210. package/test/checkpoints.test.ts +493 -0
  211. package/test/circuit-breaker.test.ts +107 -0
  212. package/test/claude-bridge.test.ts +178 -0
  213. package/test/confidence.test.ts +247 -0
  214. package/test/consistency.test.ts +61 -0
  215. package/test/consolidation-pipeline.test.ts +251 -0
  216. package/test/crystallize.test.ts +521 -0
  217. package/test/diagnostics.test.ts +638 -0
  218. package/test/embedding-provider.test.ts +49 -0
  219. package/test/enrich.test.ts +209 -0
  220. package/test/eval.test.ts +300 -0
  221. package/test/export-import.test.ts +251 -0
  222. package/test/facets.test.ts +448 -0
  223. package/test/fallback-chain.test.ts +93 -0
  224. package/test/frontier.test.ts +485 -0
  225. package/test/governance.test.ts +147 -0
  226. package/test/graph-retrieval.test.ts +186 -0
  227. package/test/graph.test.ts +160 -0
  228. package/test/helpers/mocks.ts +40 -0
  229. package/test/hybrid-search.test.ts +145 -0
  230. package/test/index-persistence.test.ts +124 -0
  231. package/test/integration.test.ts +265 -0
  232. package/test/leases.test.ts +399 -0
  233. package/test/mcp-prompts.test.ts +218 -0
  234. package/test/mcp-resources.test.ts +286 -0
  235. package/test/mcp-standalone.test.ts +113 -0
  236. package/test/mesh.test.ts +700 -0
  237. package/test/privacy.test.ts +87 -0
  238. package/test/profile.test.ts +161 -0
  239. package/test/query-expansion.test.ts +154 -0
  240. package/test/relations.test.ts +198 -0
  241. package/test/retention.test.ts +245 -0
  242. package/test/routines.test.ts +497 -0
  243. package/test/schema-fingerprint.test.ts +81 -0
  244. package/test/schema.test.ts +42 -0
  245. package/test/search-index.test.ts +128 -0
  246. package/test/sentinels.test.ts +626 -0
  247. package/test/signals.test.ts +410 -0
  248. package/test/sketches.test.ts +549 -0
  249. package/test/sliding-window.test.ts +199 -0
  250. package/test/smart-search.test.ts +169 -0
  251. package/test/snapshot.test.ts +165 -0
  252. package/test/team.test.ts +156 -0
  253. package/test/temporal-graph.test.ts +378 -0
  254. package/test/timeline.test.ts +148 -0
  255. package/test/vector-index.test.ts +79 -0
  256. package/test/verify.test.ts +209 -0
  257. package/test/xml.test.ts +65 -0
  258. package/tsconfig.json +22 -0
  259. package/tsdown.config.ts +62 -0
@@ -0,0 +1,508 @@
1
+ import type { ISdk } from "iii-sdk";
2
+ import { getContext } from "iii-sdk";
3
+ import type {
4
+ Session,
5
+ CompressedObservation,
6
+ Memory,
7
+ SessionSummary,
8
+ ProjectProfile,
9
+ ExportData,
10
+ GraphNode,
11
+ GraphEdge,
12
+ SemanticMemory,
13
+ ProceduralMemory,
14
+ Action,
15
+ ActionEdge,
16
+ Routine,
17
+ Signal,
18
+ Checkpoint,
19
+ Sentinel,
20
+ Sketch,
21
+ Crystal,
22
+ Facet,
23
+ Lesson,
24
+ ExportPagination,
25
+ } from "../types.js";
26
+ import { KV } from "../state/schema.js";
27
+ import { StateKV } from "../state/kv.js";
28
+ import { VERSION } from "../version.js";
29
+
30
+ export function registerExportImportFunction(sdk: ISdk, kv: StateKV): void {
31
+ sdk.registerFunction(
32
+ { id: "mem::export", description: "Export all memory data as JSON" },
33
+ async (data?: { maxSessions?: number; offset?: number }) => {
34
+ const ctx = getContext();
35
+ const rawMax = Number(data?.maxSessions);
36
+ const maxSessions = Number.isFinite(rawMax) && rawMax > 0 ? Math.min(Math.floor(rawMax), 1000) : undefined;
37
+ const rawOffset = Number(data?.offset);
38
+ const offset = Number.isFinite(rawOffset) && rawOffset >= 0 ? Math.floor(rawOffset) : 0;
39
+
40
+ const allSessions = await kv.list<Session>(KV.sessions);
41
+ const paginatedSessions = maxSessions !== undefined
42
+ ? allSessions.slice(offset, offset + maxSessions)
43
+ : allSessions;
44
+ const memories = await kv.list<Memory>(KV.memories);
45
+ const summaries = await kv.list<SessionSummary>(KV.summaries);
46
+
47
+ const observations: Record<string, CompressedObservation[]> = {};
48
+ const obsResults = await Promise.all(
49
+ paginatedSessions.map((session) =>
50
+ kv
51
+ .list<CompressedObservation>(KV.observations(session.id))
52
+ .catch(() => [] as CompressedObservation[])
53
+ .then((obs) => ({ sessionId: session.id, obs })),
54
+ ),
55
+ );
56
+ for (const { sessionId, obs } of obsResults) {
57
+ if (obs.length > 0) {
58
+ observations[sessionId] = obs;
59
+ }
60
+ }
61
+
62
+ const profiles: ProjectProfile[] = [];
63
+ const uniqueProjects = [...new Set(paginatedSessions.map((s) => s.project))];
64
+ const profileResults = await Promise.all(
65
+ uniqueProjects.map((project) =>
66
+ kv.get<ProjectProfile>(KV.profiles, project).catch(() => null),
67
+ ),
68
+ );
69
+ for (const profile of profileResults) {
70
+ if (profile) profiles.push(profile);
71
+ }
72
+
73
+ const [
74
+ graphNodes,
75
+ graphEdges,
76
+ semanticMemories,
77
+ proceduralMemories,
78
+ actions,
79
+ actionEdges,
80
+ sentinels,
81
+ sketches,
82
+ crystals,
83
+ facets,
84
+ lessons,
85
+ routines,
86
+ signals,
87
+ checkpoints,
88
+ ] = await Promise.all([
89
+ kv.list<GraphNode>(KV.graphNodes).catch(() => []),
90
+ kv.list<GraphEdge>(KV.graphEdges).catch(() => []),
91
+ kv.list<SemanticMemory>(KV.semantic).catch(() => []),
92
+ kv.list<ProceduralMemory>(KV.procedural).catch(() => []),
93
+ kv.list<Action>(KV.actions).catch(() => []),
94
+ kv.list<ActionEdge>(KV.actionEdges).catch(() => []),
95
+ kv.list<Sentinel>(KV.sentinels).catch(() => []),
96
+ kv.list<Sketch>(KV.sketches).catch(() => []),
97
+ kv.list<Crystal>(KV.crystals).catch(() => []),
98
+ kv.list<Facet>(KV.facets).catch(() => []),
99
+ kv.list<Lesson>(KV.lessons).catch(() => []),
100
+ kv.list<Routine>(KV.routines).catch(() => []),
101
+ kv.list<Signal>(KV.signals).catch(() => []),
102
+ kv.list<Checkpoint>(KV.checkpoints).catch(() => []),
103
+ ]);
104
+
105
+ const exportData: ExportData = {
106
+ version: VERSION,
107
+ exportedAt: new Date().toISOString(),
108
+ sessions: paginatedSessions,
109
+ observations,
110
+ memories,
111
+ summaries,
112
+ profiles: profiles.length > 0 ? profiles : undefined,
113
+ graphNodes: graphNodes.length > 0 ? graphNodes : undefined,
114
+ graphEdges: graphEdges.length > 0 ? graphEdges : undefined,
115
+ semanticMemories:
116
+ semanticMemories.length > 0 ? semanticMemories : undefined,
117
+ proceduralMemories:
118
+ proceduralMemories.length > 0 ? proceduralMemories : undefined,
119
+ actions: actions.length > 0 ? actions : undefined,
120
+ actionEdges: actionEdges.length > 0 ? actionEdges : undefined,
121
+ sentinels: sentinels.length > 0 ? sentinels : undefined,
122
+ sketches: sketches.length > 0 ? sketches : undefined,
123
+ crystals: crystals.length > 0 ? crystals : undefined,
124
+ facets: facets.length > 0 ? facets : undefined,
125
+ lessons: lessons.length > 0 ? lessons : undefined,
126
+ routines: routines.length > 0 ? routines : undefined,
127
+ signals: signals.length > 0 ? signals : undefined,
128
+ checkpoints: checkpoints.length > 0 ? checkpoints : undefined,
129
+ };
130
+
131
+ if (maxSessions !== undefined) {
132
+ exportData.pagination = {
133
+ offset,
134
+ limit: maxSessions,
135
+ total: allSessions.length,
136
+ hasMore: offset + maxSessions < allSessions.length,
137
+ };
138
+ }
139
+
140
+ const totalObs = Object.values(observations).reduce(
141
+ (sum, arr) => sum + arr.length,
142
+ 0,
143
+ );
144
+ ctx.logger.info("Export complete", {
145
+ sessions: paginatedSessions.length,
146
+ totalSessions: allSessions.length,
147
+ observations: totalObs,
148
+ memories: memories.length,
149
+ summaries: summaries.length,
150
+ });
151
+
152
+ return exportData;
153
+ },
154
+ );
155
+
156
+ sdk.registerFunction(
157
+ {
158
+ id: "mem::import",
159
+ description: "Import memory data from JSON export",
160
+ },
161
+ async (data: {
162
+ exportData: ExportData;
163
+ strategy?: "merge" | "replace" | "skip";
164
+ }) => {
165
+ const ctx = getContext();
166
+ const strategy = data.strategy || "merge";
167
+ const importData = data.exportData;
168
+
169
+ const supportedVersions = new Set(["0.3.0", "0.4.0", "0.5.0", "0.6.0", "0.6.1", "0.7.0"]);
170
+ if (!supportedVersions.has(importData.version)) {
171
+ return {
172
+ success: false,
173
+ error: `Unsupported export version: ${importData.version}`,
174
+ };
175
+ }
176
+
177
+ const MAX_SESSIONS = 10_000;
178
+ const MAX_MEMORIES = 50_000;
179
+ const MAX_SUMMARIES = 10_000;
180
+ const MAX_OBS_PER_SESSION = 5_000;
181
+ const MAX_TOTAL_OBSERVATIONS = 500_000;
182
+
183
+ if (!Array.isArray(importData.sessions)) {
184
+ return { success: false, error: "sessions must be an array" };
185
+ }
186
+ if (!Array.isArray(importData.memories)) {
187
+ return { success: false, error: "memories must be an array" };
188
+ }
189
+ if (!Array.isArray(importData.summaries)) {
190
+ return { success: false, error: "summaries must be an array" };
191
+ }
192
+ if (
193
+ typeof importData.observations !== "object" ||
194
+ importData.observations === null ||
195
+ Array.isArray(importData.observations)
196
+ ) {
197
+ return { success: false, error: "observations must be an object" };
198
+ }
199
+
200
+ if (importData.sessions.length > MAX_SESSIONS) {
201
+ return {
202
+ success: false,
203
+ error: `Too many sessions (max ${MAX_SESSIONS})`,
204
+ };
205
+ }
206
+ if (importData.memories.length > MAX_MEMORIES) {
207
+ return {
208
+ success: false,
209
+ error: `Too many memories (max ${MAX_MEMORIES})`,
210
+ };
211
+ }
212
+ if (importData.summaries.length > MAX_SUMMARIES) {
213
+ return {
214
+ success: false,
215
+ error: `Too many summaries (max ${MAX_SUMMARIES})`,
216
+ };
217
+ }
218
+ const MAX_OBS_BUCKETS = 10_000;
219
+ const obsBuckets = Object.keys(importData.observations);
220
+ if (obsBuckets.length > MAX_OBS_BUCKETS) {
221
+ return {
222
+ success: false,
223
+ error: `Too many observation buckets (max ${MAX_OBS_BUCKETS})`,
224
+ };
225
+ }
226
+
227
+ let totalObservations = 0;
228
+ for (const [, obs] of Object.entries(importData.observations)) {
229
+ if (!Array.isArray(obs)) {
230
+ return { success: false, error: "observation values must be arrays" };
231
+ }
232
+ if (obs.length > MAX_OBS_PER_SESSION) {
233
+ return {
234
+ success: false,
235
+ error: `Too many observations per session (max ${MAX_OBS_PER_SESSION})`,
236
+ };
237
+ }
238
+ totalObservations += obs.length;
239
+ }
240
+ if (totalObservations > MAX_TOTAL_OBSERVATIONS) {
241
+ return {
242
+ success: false,
243
+ error: `Too many total observations (max ${MAX_TOTAL_OBSERVATIONS})`,
244
+ };
245
+ }
246
+
247
+ const stats = {
248
+ sessions: 0,
249
+ observations: 0,
250
+ memories: 0,
251
+ summaries: 0,
252
+ skipped: 0,
253
+ };
254
+
255
+ if (strategy === "replace") {
256
+ const existing = await kv.list<Session>(KV.sessions);
257
+ for (const session of existing) {
258
+ await kv.delete(KV.sessions, session.id);
259
+ const obs = await kv
260
+ .list<CompressedObservation>(KV.observations(session.id))
261
+ .catch(() => []);
262
+ for (const o of obs) {
263
+ await kv.delete(KV.observations(session.id), o.id);
264
+ }
265
+ }
266
+ const existingMem = await kv.list<Memory>(KV.memories);
267
+ for (const m of existingMem) {
268
+ await kv.delete(KV.memories, m.id);
269
+ }
270
+ const existingSummaries = await kv.list<SessionSummary>(KV.summaries);
271
+ for (const s of existingSummaries) {
272
+ await kv.delete(KV.summaries, s.sessionId);
273
+ }
274
+ for (const a of await kv.list<Action>(KV.actions).catch(() => [])) {
275
+ await kv.delete(KV.actions, a.id);
276
+ }
277
+ for (const e of await kv.list<ActionEdge>(KV.actionEdges).catch(() => [])) {
278
+ await kv.delete(KV.actionEdges, e.id);
279
+ }
280
+ for (const r of await kv.list<Routine>(KV.routines).catch(() => [])) {
281
+ await kv.delete(KV.routines, r.id);
282
+ }
283
+ for (const s of await kv.list<Signal>(KV.signals).catch(() => [])) {
284
+ await kv.delete(KV.signals, s.id);
285
+ }
286
+ for (const c of await kv.list<Checkpoint>(KV.checkpoints).catch(() => [])) {
287
+ await kv.delete(KV.checkpoints, c.id);
288
+ }
289
+ for (const s of await kv.list<Sentinel>(KV.sentinels).catch(() => [])) {
290
+ await kv.delete(KV.sentinels, s.id);
291
+ }
292
+ for (const s of await kv.list<Sketch>(KV.sketches).catch(() => [])) {
293
+ await kv.delete(KV.sketches, s.id);
294
+ }
295
+ for (const c of await kv.list<Crystal>(KV.crystals).catch(() => [])) {
296
+ await kv.delete(KV.crystals, c.id);
297
+ }
298
+ for (const f of await kv.list<Facet>(KV.facets).catch(() => [])) {
299
+ await kv.delete(KV.facets, f.id);
300
+ }
301
+ for (const l of await kv.list<Lesson>(KV.lessons).catch(() => [])) {
302
+ await kv.delete(KV.lessons, l.id);
303
+ }
304
+ for (const n of await kv.list<{ id: string }>(KV.graphNodes).catch(() => [])) {
305
+ await kv.delete(KV.graphNodes, n.id);
306
+ }
307
+ for (const e of await kv.list<{ id: string }>(KV.graphEdges).catch(() => [])) {
308
+ await kv.delete(KV.graphEdges, e.id);
309
+ }
310
+ for (const s of await kv.list<{ id: string }>(KV.semantic).catch(() => [])) {
311
+ await kv.delete(KV.semantic, s.id);
312
+ }
313
+ for (const p of await kv.list<{ id: string }>(KV.procedural).catch(() => [])) {
314
+ await kv.delete(KV.procedural, p.id);
315
+ }
316
+ }
317
+
318
+ for (const session of importData.sessions) {
319
+ if (strategy === "skip") {
320
+ const existing = await kv
321
+ .get<Session>(KV.sessions, session.id)
322
+ .catch(() => null);
323
+ if (existing) {
324
+ stats.skipped++;
325
+ continue;
326
+ }
327
+ }
328
+ await kv.set(KV.sessions, session.id, session);
329
+ stats.sessions++;
330
+ }
331
+
332
+ for (const [sessionId, obs] of Object.entries(importData.observations)) {
333
+ for (const o of obs) {
334
+ if (strategy === "skip") {
335
+ const existing = await kv
336
+ .get<CompressedObservation>(KV.observations(sessionId), o.id)
337
+ .catch(() => null);
338
+ if (existing) {
339
+ stats.skipped++;
340
+ continue;
341
+ }
342
+ }
343
+ await kv.set(KV.observations(sessionId), o.id, o);
344
+ stats.observations++;
345
+ }
346
+ }
347
+
348
+ for (const memory of importData.memories) {
349
+ if (strategy === "skip") {
350
+ const existing = await kv
351
+ .get<Memory>(KV.memories, memory.id)
352
+ .catch(() => null);
353
+ if (existing) {
354
+ stats.skipped++;
355
+ continue;
356
+ }
357
+ }
358
+ await kv.set(KV.memories, memory.id, memory);
359
+ stats.memories++;
360
+ }
361
+
362
+ for (const summary of importData.summaries) {
363
+ if (strategy === "skip") {
364
+ const existing = await kv
365
+ .get<SessionSummary>(KV.summaries, summary.sessionId)
366
+ .catch(() => null);
367
+ if (existing) {
368
+ stats.skipped++;
369
+ continue;
370
+ }
371
+ }
372
+ await kv.set(KV.summaries, summary.sessionId, summary);
373
+ stats.summaries++;
374
+ }
375
+
376
+ if (importData.graphNodes) {
377
+ for (const node of importData.graphNodes) {
378
+ if (strategy === "skip") {
379
+ const existing = await kv.get(KV.graphNodes, node.id).catch(() => null);
380
+ if (existing) { stats.skipped++; continue; }
381
+ }
382
+ await kv.set(KV.graphNodes, node.id, node);
383
+ }
384
+ }
385
+ if (importData.graphEdges) {
386
+ for (const edge of importData.graphEdges) {
387
+ if (strategy === "skip") {
388
+ const existing = await kv.get(KV.graphEdges, edge.id).catch(() => null);
389
+ if (existing) { stats.skipped++; continue; }
390
+ }
391
+ await kv.set(KV.graphEdges, edge.id, edge);
392
+ }
393
+ }
394
+ if (importData.semanticMemories) {
395
+ for (const sem of importData.semanticMemories) {
396
+ if (strategy === "skip") {
397
+ const existing = await kv.get(KV.semantic, sem.id).catch(() => null);
398
+ if (existing) { stats.skipped++; continue; }
399
+ }
400
+ await kv.set(KV.semantic, sem.id, sem);
401
+ }
402
+ }
403
+ if (importData.proceduralMemories) {
404
+ for (const proc of importData.proceduralMemories) {
405
+ if (strategy === "skip") {
406
+ const existing = await kv.get(KV.procedural, proc.id).catch(() => null);
407
+ if (existing) { stats.skipped++; continue; }
408
+ }
409
+ await kv.set(KV.procedural, proc.id, proc);
410
+ }
411
+ }
412
+
413
+ if (importData.actions) {
414
+ for (const action of importData.actions) {
415
+ if (strategy === "skip") {
416
+ const existing = await kv.get(KV.actions, action.id).catch(() => null);
417
+ if (existing) { stats.skipped++; continue; }
418
+ }
419
+ await kv.set(KV.actions, action.id, action);
420
+ }
421
+ }
422
+ if (importData.actionEdges) {
423
+ for (const edge of importData.actionEdges) {
424
+ if (strategy === "skip") {
425
+ const existing = await kv.get(KV.actionEdges, edge.id).catch(() => null);
426
+ if (existing) { stats.skipped++; continue; }
427
+ }
428
+ await kv.set(KV.actionEdges, edge.id, edge);
429
+ }
430
+ }
431
+ if (importData.routines) {
432
+ for (const routine of importData.routines) {
433
+ if (strategy === "skip") {
434
+ const existing = await kv.get(KV.routines, routine.id).catch(() => null);
435
+ if (existing) { stats.skipped++; continue; }
436
+ }
437
+ await kv.set(KV.routines, routine.id, routine);
438
+ }
439
+ }
440
+ if (importData.signals) {
441
+ for (const signal of importData.signals) {
442
+ if (strategy === "skip") {
443
+ const existing = await kv.get(KV.signals, signal.id).catch(() => null);
444
+ if (existing) { stats.skipped++; continue; }
445
+ }
446
+ await kv.set(KV.signals, signal.id, signal);
447
+ }
448
+ }
449
+ if (importData.checkpoints) {
450
+ for (const checkpoint of importData.checkpoints) {
451
+ if (strategy === "skip") {
452
+ const existing = await kv.get(KV.checkpoints, checkpoint.id).catch(() => null);
453
+ if (existing) { stats.skipped++; continue; }
454
+ }
455
+ await kv.set(KV.checkpoints, checkpoint.id, checkpoint);
456
+ }
457
+ }
458
+ if (importData.sentinels) {
459
+ for (const sentinel of importData.sentinels) {
460
+ if (strategy === "skip") {
461
+ const existing = await kv.get(KV.sentinels, sentinel.id).catch(() => null);
462
+ if (existing) { stats.skipped++; continue; }
463
+ }
464
+ await kv.set(KV.sentinels, sentinel.id, sentinel);
465
+ }
466
+ }
467
+ if (importData.sketches) {
468
+ for (const sketch of importData.sketches) {
469
+ if (strategy === "skip") {
470
+ const existing = await kv.get(KV.sketches, sketch.id).catch(() => null);
471
+ if (existing) { stats.skipped++; continue; }
472
+ }
473
+ await kv.set(KV.sketches, sketch.id, sketch);
474
+ }
475
+ }
476
+ if (importData.crystals) {
477
+ for (const crystal of importData.crystals) {
478
+ if (strategy === "skip") {
479
+ const existing = await kv.get(KV.crystals, crystal.id).catch(() => null);
480
+ if (existing) { stats.skipped++; continue; }
481
+ }
482
+ await kv.set(KV.crystals, crystal.id, crystal);
483
+ }
484
+ }
485
+ if (importData.facets) {
486
+ for (const facet of importData.facets) {
487
+ if (strategy === "skip") {
488
+ const existing = await kv.get(KV.facets, facet.id).catch(() => null);
489
+ if (existing) { stats.skipped++; continue; }
490
+ }
491
+ await kv.set(KV.facets, facet.id, facet);
492
+ }
493
+ }
494
+ if (importData.lessons) {
495
+ for (const lesson of importData.lessons) {
496
+ if (strategy === "skip") {
497
+ const existing = await kv.get(KV.lessons, lesson.id).catch(() => null);
498
+ if (existing) { stats.skipped++; continue; }
499
+ }
500
+ await kv.set(KV.lessons, lesson.id, lesson);
501
+ }
502
+ }
503
+
504
+ ctx.logger.info("Import complete", { strategy, ...stats });
505
+ return { success: true, strategy, ...stats };
506
+ },
507
+ );
508
+ }