@vellumai/assistant 0.7.0 → 0.7.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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -6,15 +6,15 @@
6
6
  // Implements §5 of the design doc:
7
7
  //
8
8
  // 1. Hydrate prior activation state for the conversation.
9
- // 2. Read edges.json (the topology source of truth).
9
+ // 2. Build the in-memory edge index from concept-page frontmatter.
10
10
  // 3. Select the per-turn candidate set (prior-state survivors ∪ ANN top-K).
11
11
  // 4. Compute own activation A_o over the candidates.
12
- // 5. Apply 2-hop spreading activation with neighborhood normalization → A.
12
+ // 5. Apply 2-hop spreading activation along directed edges (incoming) → A.
13
13
  // 6. Pick top-K by activation; subtract everInjected to get the injection delta.
14
14
  // 7. If no new slugs, render nothing — caller leaves the prior cached
15
15
  // attachments on prior user messages exactly as Anthropic prompt caching
16
16
  // requires.
17
- // 8. Otherwise render a `<memory __injected>` block scoped to the *new* slugs
17
+ // 8. Otherwise render a `<memory>` block scoped to the *new* slugs
18
18
  // ordered by activation (descending) and persist the updated state +
19
19
  // everInjected list (with `currentTurn` annotated) so future turns can
20
20
  // append-inject cache-stably.
@@ -24,8 +24,14 @@
24
24
  // cached prefix bytes-identical across turns.
25
25
 
26
26
  import type { AssistantConfig } from "../../config/types.js";
27
+ import { getLogger } from "../../util/logger.js";
27
28
  import { getWorkspaceDir } from "../../util/platform.js";
28
29
  import type { DrizzleDb } from "../db-connection.js";
30
+ import {
31
+ type MemoryV2ConceptRowRecord,
32
+ type MemoryV2SkillRowRecord,
33
+ recordMemoryV2ActivationLog,
34
+ } from "../memory-v2-activation-log-store.js";
29
35
  import {
30
36
  computeOwnActivation,
31
37
  computeSkillActivation,
@@ -36,11 +42,13 @@ import {
36
42
  spreadActivation,
37
43
  } from "./activation.js";
38
44
  import { hydrate, save } from "./activation-store.js";
39
- import { readEdges } from "./edges.js";
40
- import { readPage } from "./page-store.js";
45
+ import { getEdgeIndex } from "./edge-index.js";
46
+ import { readPage, renderPageContent } from "./page-store.js";
41
47
  import { getSkillCapability } from "./skill-store.js";
42
48
  import type { ActivationState, EverInjectedEntry } from "./types.js";
43
49
 
50
+ const log = getLogger("memory-v2-injection");
51
+
44
52
  // ---------------------------------------------------------------------------
45
53
  // Public types
46
54
  // ---------------------------------------------------------------------------
@@ -49,7 +57,7 @@ import type { ActivationState, EverInjectedEntry } from "./types.js";
49
57
  * Discriminator the wiring layer (`conversation-graph-memory.ts`) sets to
50
58
  * tell the v2 injector which call site is asking. Both modes currently share
51
59
  * the same block layout (mirroring v1 which also wraps both flows in
52
- * `<memory __injected>...</memory>`); the parameter exists so future tuning
60
+ * `<memory>...</memory>`); the parameter exists so future tuning
53
61
  * can shape the conversation-start block without touching the call site.
54
62
  */
55
63
  export type InjectMemoryV2Mode = "context-load" | "per-turn";
@@ -81,7 +89,7 @@ export interface InjectMemoryV2BlockParams {
81
89
 
82
90
  export interface InjectMemoryV2BlockResult {
83
91
  /**
84
- * Rendered `<memory __injected>` block, ready to prepend to the current
92
+ * Rendered `<memory>` block, ready to prepend to the current
85
93
  * user message — or `null` when nothing new is eligible for injection.
86
94
  * `null` is the cache-stable default: the caller adds nothing to the new
87
95
  * user message and prior attachments stay byte-identical.
@@ -127,12 +135,14 @@ export async function injectMemoryV2Block(
127
135
  // with an effective empty prior state so the first turn can still inject.
128
136
  const priorState = await hydrate(database, conversationId);
129
137
 
130
- // (2) Topology. `readEdges` returns the canonical empty index when the
131
- // file is missing (fresh workspace pre-consolidation).
132
- const edgesIdx = await readEdges(workspaceDir);
138
+ // (2) Topology. `getEdgeIndex` walks concept-page frontmatter and caches
139
+ // the result module-locally; an empty workspace yields an empty index.
140
+ const edgeIndex = await getEdgeIndex(workspaceDir);
133
141
 
134
142
  // (3) Candidate set: prior-state survivors above epsilon ∪ ANN top-50.
135
- const candidates = await selectCandidates({
143
+ // `selectCandidates` also returns `fromPrior` / `fromAnn` provenance sets so
144
+ // telemetry can attribute each candidate back to its source.
145
+ const { candidates, fromPrior, fromAnn } = await selectCandidates({
136
146
  priorState,
137
147
  userText: userMessage,
138
148
  assistantText: assistantMessage,
@@ -141,27 +151,36 @@ export async function injectMemoryV2Block(
141
151
  });
142
152
 
143
153
  // (4) Own activation: A_o = d·prev + c_user·sim_u + c_a·sim_a + c_now·sim_n.
144
- const ownActivation = await computeOwnActivation({
145
- candidates,
146
- priorState,
147
- userText: userMessage,
148
- assistantText: assistantMessage,
149
- nowText,
150
- config,
151
- });
154
+ const { activation: ownActivation, breakdown: ownBreakdown } =
155
+ await computeOwnActivation({
156
+ candidates,
157
+ priorState,
158
+ userText: userMessage,
159
+ assistantText: assistantMessage,
160
+ nowText,
161
+ config,
162
+ });
152
163
 
153
164
  // (5) Spreading activation across the edge graph (k, hops from config).
154
165
  const { k, hops, top_k, epsilon } = config.memory.v2;
155
- const finalActivation = spreadActivation(ownActivation, edgesIdx, k, hops);
166
+ const { final: finalActivation, contribution: spreadContribution } =
167
+ spreadActivation(ownActivation, edgeIndex, k, hops);
156
168
 
157
- // (6) Pick top-K by activation; subtract everInjected for the injection delta.
169
+ // (6) Pick top-K by activation. Per-turn turns subtract everInjected for the
170
+ // injection delta (cache-stable append-only); context-load renders the
171
+ // entire top-K because it's a fresh load (turn 1 / post-compaction) where
172
+ // prior cached attachments don't exist or have been thrown away. The user
173
+ // message gets a complete top-K dump alongside the static
174
+ // essentials/threads/recent block, then per-turn turns just add deltas.
175
+ const mode = params.mode ?? "per-turn";
158
176
  const priorEverInjected: readonly EverInjectedEntry[] =
159
177
  priorState?.everInjected ?? [];
160
- const { toInject } = selectInjections({
178
+ const { topNow, toInject } = selectInjections({
161
179
  A: finalActivation,
162
180
  priorEverInjected,
163
181
  topK: top_k,
164
182
  });
183
+ const slugsToRender = mode === "context-load" ? topNow : toInject;
165
184
 
166
185
  // (6b) Skill pipeline — a sibling pipeline to the concept-page one above.
167
186
  // Skills are stateless: no decay carry-over, no spread, no `everInjected`
@@ -174,13 +193,14 @@ export async function injectMemoryV2Block(
174
193
  config,
175
194
  topK: config.memory.v2.top_k_skills,
176
195
  });
177
- const skillActivation = await computeSkillActivation({
178
- candidates: skillCandidates,
179
- userText: userMessage,
180
- assistantText: assistantMessage,
181
- nowText,
182
- config,
183
- });
196
+ const { activation: skillActivation, breakdown: skillBreakdown } =
197
+ await computeSkillActivation({
198
+ candidates: skillCandidates,
199
+ userText: userMessage,
200
+ assistantText: assistantMessage,
201
+ nowText,
202
+ config,
203
+ });
184
204
  const { topNow: topSkillIds } = selectSkillInjections({
185
205
  A: skillActivation,
186
206
  topK: config.memory.v2.top_k_skills,
@@ -195,14 +215,20 @@ export async function injectMemoryV2Block(
195
215
  if (value > epsilon) nextState[slug] = value;
196
216
  }
197
217
 
198
- // Append the freshly injected slugs to everInjected (with their turn) so
199
- // future turns can subtract them. We append rather than reset so that
200
- // compaction-driven eviction (`evictCompactedTurns`) is the only path that
201
- // can re-enable a previously-injected slug. Skills do NOT enter
202
- // `everInjected` they are stateless and re-presented every turn.
218
+ // Mark every rendered slug as ever-injected so future per-turn deltas don't
219
+ // re-attach the same content. On context-load this is the full top-K (we
220
+ // just rendered all of them); on per-turn it's just the newly added slugs.
221
+ // We append rather than reset so that compaction-driven eviction
222
+ // (`evictCompactedTurns`) is the only path that can re-enable a previously-
223
+ // injected slug. Skills do NOT enter `everInjected` — they are stateless
224
+ // and re-presented every turn.
225
+ const everInjectedSet = new Set(priorEverInjected.map((entry) => entry.slug));
226
+ const newlyInjected = slugsToRender.filter(
227
+ (slug) => !everInjectedSet.has(slug),
228
+ );
203
229
  const nextEverInjected: EverInjectedEntry[] = [
204
230
  ...priorEverInjected,
205
- ...toInject.map((slug) => ({ slug, turn: currentTurn })),
231
+ ...newlyInjected.map((slug) => ({ slug, turn: currentTurn })),
206
232
  ];
207
233
 
208
234
  const nextActivationState: ActivationState = {
@@ -215,19 +241,110 @@ export async function injectMemoryV2Block(
215
241
 
216
242
  await save(database, conversationId, nextActivationState);
217
243
 
218
- // (7) Cache-stable empty path: nothing new since the last turn AND no
219
- // ranked skills to surface.
220
- if (toInject.length === 0 && topSkillIds.length === 0) {
244
+ // Record per-turn activation telemetry. This runs *before* the cache-stable
245
+ // empty-block return so we capture diagnostics even on no-op turns. Failures
246
+ // are warn-logged and never block memory injection.
247
+ const toInjectSet = new Set(toInject);
248
+ const renderedSet = new Set(slugsToRender);
249
+ const topSkillIdSet = new Set(topSkillIds);
250
+ const conceptRows: MemoryV2ConceptRowRecord[] = [...candidates].map(
251
+ (slug) => {
252
+ const breakdown = ownBreakdown.get(slug);
253
+ const inPrior = fromPrior.has(slug);
254
+ const inAnn = fromAnn.has(slug);
255
+ // Status reflects what was rendered for *this* turn:
256
+ // - context-load: cache was wiped (turn 1 / post-compaction), so
257
+ // `slugsToRender = topNow` and every rendered slug is freshly
258
+ // injected on this turn. `in_context` is unreachable because there
259
+ // is no prior cached attachment for the inspector to point at.
260
+ // - per-turn: cached attachments from prior turns are still on the
261
+ // user message, so prior-everInjected slugs are `in_context` and
262
+ // the delta (`toInject`) is `injected`.
263
+ let status: MemoryV2ConceptRowRecord["status"];
264
+ if (mode === "context-load") {
265
+ status = renderedSet.has(slug) ? "injected" : "not_injected";
266
+ } else if (everInjectedSet.has(slug)) {
267
+ status = "in_context";
268
+ } else if (toInjectSet.has(slug)) {
269
+ status = "injected";
270
+ } else {
271
+ status = "not_injected";
272
+ }
273
+ return {
274
+ slug,
275
+ finalActivation: finalActivation.get(slug) ?? 0,
276
+ ownActivation: ownActivation.get(slug) ?? 0,
277
+ priorActivation: breakdown?.priorContribution ?? 0,
278
+ simUser: breakdown?.simUser ?? 0,
279
+ simAssistant: breakdown?.simAssistant ?? 0,
280
+ simNow: breakdown?.simNow ?? 0,
281
+ spreadContribution: spreadContribution.get(slug) ?? 0,
282
+ source:
283
+ inPrior && inAnn ? "both" : inPrior ? "prior_state" : "ann_top50",
284
+ status,
285
+ };
286
+ },
287
+ );
288
+ conceptRows.sort((a, b) => b.finalActivation - a.finalActivation);
289
+
290
+ const skillRows: MemoryV2SkillRowRecord[] = [...skillCandidates].map((id) => {
291
+ const breakdown = skillBreakdown.get(id);
292
+ return {
293
+ id,
294
+ activation: skillActivation.get(id) ?? 0,
295
+ simUser: breakdown?.simUser ?? 0,
296
+ simAssistant: breakdown?.simAssistant ?? 0,
297
+ simNow: breakdown?.simNow ?? 0,
298
+ status: topSkillIdSet.has(id) ? "injected" : "not_injected",
299
+ };
300
+ });
301
+ skillRows.sort((a, b) => b.activation - a.activation);
302
+
303
+ const v2Cfg = config.memory.v2;
304
+ try {
305
+ recordMemoryV2ActivationLog({
306
+ conversationId,
307
+ turn: currentTurn,
308
+ mode,
309
+ concepts: conceptRows,
310
+ skills: skillRows,
311
+ config: {
312
+ d: v2Cfg.d,
313
+ c_user: v2Cfg.c_user,
314
+ c_assistant: v2Cfg.c_assistant,
315
+ c_now: v2Cfg.c_now,
316
+ k: v2Cfg.k,
317
+ hops: v2Cfg.hops,
318
+ top_k: v2Cfg.top_k,
319
+ top_k_skills: v2Cfg.top_k_skills,
320
+ epsilon: v2Cfg.epsilon,
321
+ },
322
+ });
323
+ } catch (err) {
324
+ log.warn(
325
+ { err, conversationId, turn: currentTurn },
326
+ "Failed to record memory v2 activation telemetry — continuing",
327
+ );
328
+ }
329
+
330
+ // (7) Cache-stable empty path: nothing to render AND no ranked skills.
331
+ if (slugsToRender.length === 0 && topSkillIds.length === 0) {
221
332
  return { block: null, toInject: [] };
222
333
  }
223
334
 
224
- // (8) Render. `toInject` is already activation-descending (selectInjections
225
- // returns it as a filter of the sorted `topNow`), so it doubles as our
226
- // render order. Prior slugs sit unchanged on prior user messages. Skills
227
- // are appended after concept-page sections under the same header.
228
- const block = await renderInjectionBlock(workspaceDir, toInject, topSkillIds);
335
+ // (8) Render. Both `topNow` and `toInject` are activation-descending
336
+ // (selectInjections sorts before slicing), so `slugsToRender` doubles as
337
+ // the render order. Per-turn: only the new slugs render (prior turns'
338
+ // attachments stay cached on prior user messages). Context-load: full
339
+ // top-K renders so the fresh user message gets a complete activation dump.
340
+ // Skills are appended after concept-page sections.
341
+ const block = await renderInjectionBlock(
342
+ workspaceDir,
343
+ slugsToRender,
344
+ topSkillIds,
345
+ );
229
346
 
230
- return { block, toInject };
347
+ return { block, toInject: newlyInjected };
231
348
  }
232
349
 
233
350
  // ---------------------------------------------------------------------------
@@ -235,7 +352,7 @@ export async function injectMemoryV2Block(
235
352
  // ---------------------------------------------------------------------------
236
353
 
237
354
  /**
238
- * Render the `<memory __injected>` block for a list of slugs and a list of
355
+ * Render the `<memory>` block for a list of slugs and a list of
239
356
  * ranked skill ids.
240
357
  *
241
358
  * Concept pages are read in parallel via `readPage`. Pages whose file has
@@ -248,14 +365,26 @@ export async function injectMemoryV2Block(
248
365
  * the missing-pages behavior.
249
366
  *
250
367
  * The block shape is the §5 layout from the design doc, with an optional
251
- * trailing skills subsection:
368
+ * trailing skills subsection. Each concept-page section reproduces the page
369
+ * as it lives on disk — frontmatter (`edges`, `ref_files`) plus body — so
370
+ * the agent sees the page's edges and any referenced media paths alongside
371
+ * the prose:
252
372
  *
253
- * <memory __injected>
254
- * ## What I Remember Right Now
373
+ * <memory>
255
374
  * ### <slug-1>
375
+ * ---
376
+ * edges:
377
+ * - <neighbor-slug>
378
+ * ref_files:
379
+ * - <path/to/asset>
380
+ * ---
256
381
  * <body-1>
257
382
  *
258
383
  * ### <slug-2>
384
+ * ---
385
+ * edges: []
386
+ * ref_files: []
387
+ * ---
259
388
  * <body-2>
260
389
  *
261
390
  * ### Skills You Can Use
@@ -263,13 +392,9 @@ export async function injectMemoryV2Block(
263
392
  * - <skill-2 content>
264
393
  * </memory>
265
394
  *
266
- * The same `## What I Remember Right Now` header wraps the block whether
267
- * the skills section is alone, the concept-page sections are alone, or
268
- * both are present — keeping the renderer one shape.
269
- *
270
395
  * Returns `null` when both lists collapse to empty after cache misses so
271
396
  * the caller can fall through to its empty-block path instead of attaching
272
- * a header with no contents.
397
+ * an empty `<memory>` wrapper.
273
398
  */
274
399
  async function renderInjectionBlock(
275
400
  workspaceDir: string,
@@ -279,14 +404,14 @@ async function renderInjectionBlock(
279
404
  const pages = await Promise.all(
280
405
  slugs.map(async (slug) => {
281
406
  const page = await readPage(workspaceDir, slug);
282
- return page ? { slug, body: page.body.trim() } : null;
407
+ return page ? { slug, content: renderPageContent(page).trim() } : null;
283
408
  }),
284
409
  );
285
410
 
286
411
  const sections: string[] = [];
287
412
  for (const entry of pages) {
288
- if (!entry || entry.body.length === 0) continue;
289
- sections.push(`### ${entry.slug}\n${entry.body}`);
413
+ if (!entry || entry.content.length === 0) continue;
414
+ sections.push(`### ${entry.slug}\n${entry.content}`);
290
415
  }
291
416
 
292
417
  // v2's skills collection is skills-only, so the activation suffix always applies.
@@ -302,6 +427,5 @@ async function renderInjectionBlock(
302
427
 
303
428
  if (sections.length === 0) return null;
304
429
 
305
- const inner = `## What I Remember Right Now\n\n${sections.join("\n\n")}`;
306
- return `<memory __injected>\n${inner}\n</memory>`;
430
+ return `<memory>\n${sections.join("\n\n")}\n</memory>`;
307
431
  }
@@ -5,9 +5,9 @@
5
5
  * synthesizes a concept page per cluster via the configured LLM, promotes
6
6
  * high-significance nodes to `essentials.md` / active follow-ups to
7
7
  * `threads.md` / low-significance episodes to `archive/migrated-<date>.md`,
8
- * collapses v1 weighted directional edges into the v2 unweighted-undirected
9
- * `memory/edges.json`, and enqueues `embed_concept_page` jobs for each new
10
- * page. A sentinel file at `memory/.v2-state/.migration-complete-v1-to-v2`
8
+ * preserves v1 weighted directional edges as outgoing-edge entries on each
9
+ * source page's frontmatter, and enqueues `embed_concept_page` jobs for each
10
+ * new page. A sentinel file at `memory/.v2-state/.migration-complete-v1-to-v2`
11
11
  * gates re-runs — `force: true` is required to overwrite.
12
12
  *
13
13
  * The migration is structured as a sequence of small helpers — `gatherV1State`,
@@ -31,9 +31,8 @@ import type { Provider } from "../../providers/types.js";
31
31
  import { getLogger } from "../../util/logger.js";
32
32
  import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
33
33
  import { enqueueMemoryJob } from "../jobs-store.js";
34
- import { writeEdges } from "./edges.js";
35
34
  import { slugify, writePage } from "./page-store.js";
36
- import type { ConceptPage, EdgesIndex } from "./types.js";
35
+ import type { ConceptPage } from "./types.js";
37
36
 
38
37
  const log = getLogger("memory-v2-migration");
39
38
 
@@ -56,7 +55,6 @@ export interface MigrationResult {
56
55
  threadsLines: number;
57
56
  archiveLines: number;
58
57
  embedsEnqueued: number;
59
- rebuildEdgesJobId: string;
60
58
  sentinelWritten: boolean;
61
59
  }
62
60
 
@@ -86,8 +84,9 @@ export interface V1Item {
86
84
  }
87
85
 
88
86
  /**
89
- * v1 weighted directional edge collapsed in stage 5 into v2's unweighted
90
- * undirected canonical pairs.
87
+ * v1 weighted directional edge. v2 preserves direction (an edge A→B in v1
88
+ * becomes an outgoing-edge entry on A's page in v2), so the migration just
89
+ * has to map node ids to slugs and group by source.
91
90
  */
92
91
  export interface V1Edge {
93
92
  sourceNodeId: string;
@@ -409,31 +408,38 @@ function formatPromotionLine(item: V1Item): string {
409
408
  }
410
409
 
411
410
  // ---------------------------------------------------------------------------
412
- // Stage 5 — Collapse v1 edges into v2 edges.json
411
+ // Stage 5 — Map v1 edges to per-page outgoing edges
413
412
  // ---------------------------------------------------------------------------
414
413
 
415
414
  /**
416
- * Map every v1 graph-node id to a v2 concept-page slug, then rewrite v1
417
- * edges as canonical v2 tuples. Edges with either endpoint missing from
418
- * `slugMap` are dropped silently — those endpoints didn't survive
419
- * synthesis (e.g. their cluster produced no usable page).
415
+ * Map every v1 graph-node id to a v2 concept-page slug and group v1 edges by
416
+ * source slug. Edges with either endpoint missing from `slugMap` are dropped
417
+ * silently — those endpoints didn't survive synthesis (e.g. their cluster
418
+ * produced no usable page). Self-loops are dropped; duplicate `(source, target)`
419
+ * pairs collapse via the `Set<string>`.
420
420
  *
421
- * The returned `EdgesIndex` is canonicalized + deduped by `writeEdges`'s
422
- * own write-time normalization, so callers can pass it straight through.
421
+ * The returned map keys are source slugs and the values are sets of target
422
+ * slugs i.e. each entry is a page's outgoing-edge list. The runner writes
423
+ * these into the source page's frontmatter.
423
424
  */
424
425
  export function collapseEdges(
425
426
  v1Edges: V1Edge[],
426
427
  slugMap: Map<string, string>,
427
- ): EdgesIndex {
428
- const tuples: [string, string][] = [];
428
+ ): Map<string, Set<string>> {
429
+ const outgoing = new Map<string, Set<string>>();
429
430
  for (const edge of v1Edges) {
430
- const a = slugMap.get(edge.sourceNodeId);
431
- const b = slugMap.get(edge.targetNodeId);
432
- if (!a || !b) continue;
433
- if (a === b) continue;
434
- tuples.push([a, b]);
431
+ const from = slugMap.get(edge.sourceNodeId);
432
+ const to = slugMap.get(edge.targetNodeId);
433
+ if (!from || !to) continue;
434
+ if (from === to) continue;
435
+ let targets = outgoing.get(from);
436
+ if (!targets) {
437
+ targets = new Set<string>();
438
+ outgoing.set(from, targets);
439
+ }
440
+ targets.add(to);
435
441
  }
436
- return { version: 1, edges: tuples };
442
+ return outgoing;
437
443
  }
438
444
 
439
445
  // ---------------------------------------------------------------------------
@@ -476,8 +482,8 @@ export interface RunMemoryV2MigrationParams {
476
482
  * Re-runs are gated by the sentinel file
477
483
  * `memory/.v2-state/.migration-complete-v1-to-v2`. Without `force: true`, a
478
484
  * second invocation throws `MigrationAlreadyAppliedError` without mutating
479
- * anything; with `force: true`, the migration overwrites pages and
480
- * `edges.json` and re-appends to the prose files.
485
+ * anything; with `force: true`, the migration overwrites pages and re-appends
486
+ * to the prose files.
481
487
  */
482
488
  export class MigrationAlreadyAppliedError extends Error {
483
489
  constructor() {
@@ -548,41 +554,46 @@ export async function runMemoryV2Migration(
548
554
  }
549
555
  }
550
556
 
557
+ // Resolve outgoing edges per source slug, then attach them to each page's
558
+ // frontmatter before writing. The page is the source of truth for its own
559
+ // outgoing edges — there is no separate edges-index file.
560
+ const outgoingBySource = collapseEdges(v1Edges, slugMap);
561
+ const finalizedPages: ConceptPage[] = pages.map((page) => {
562
+ const targets = outgoingBySource.get(page.slug);
563
+ if (!targets || targets.size === 0) return page;
564
+ return {
565
+ ...page,
566
+ frontmatter: {
567
+ ...page.frontmatter,
568
+ edges: [...targets].sort(),
569
+ },
570
+ };
571
+ });
572
+
551
573
  // Page writes hit different filenames so they're safe to fan out.
552
- await Promise.all(pages.map((page) => writePage(workspaceDir, page)));
574
+ await Promise.all(
575
+ finalizedPages.map((page) => writePage(workspaceDir, page)),
576
+ );
553
577
 
554
578
  const promotions = derivePromotions(items);
555
579
  await appendPromotions(workspaceDir, promotions);
556
580
 
557
- const edgesIdx = collapseEdges(v1Edges, slugMap);
558
- await writeEdges(workspaceDir, edgesIdx);
559
-
560
- const embedsEnqueued = enqueueEmbeds(pages.map((p) => p.slug));
561
-
562
- // Page bodies are written with empty `edges:` frontmatter (the schema is a
563
- // derived view of `edges.json`). Without this enqueue the frontmatter would
564
- // stay empty until the next consolidation run, but consolidation bails on an
565
- // empty buffer — so a freshly-migrated workspace can sit indefinitely with
566
- // out-of-date frontmatter. The rebuild-edges job propagates `edges.json` into
567
- // every page's frontmatter and is idempotent, so pairing it with the
568
- // migration is safe even when nothing else has run yet.
569
- const rebuildEdgesJobId = enqueueMemoryJob("memory_v2_rebuild_edges", {});
581
+ const embedsEnqueued = enqueueEmbeds(finalizedPages.map((p) => p.slug));
570
582
 
571
583
  await writeSentinel(workspaceDir);
572
584
 
573
- // Re-read after writeEdges so the count reflects post-canonicalization
574
- // dedup (collapseEdges can produce duplicate tuples when v1 had multiple
575
- // weighted edges between the same pair).
576
- const finalEdges = await readPersistedEdgeCount(workspaceDir);
585
+ let edgesWritten = 0;
586
+ for (const targets of outgoingBySource.values()) {
587
+ edgesWritten += targets.size;
588
+ }
577
589
 
578
590
  return {
579
- pagesCreated: pages.length,
580
- edgesWritten: finalEdges,
591
+ pagesCreated: finalizedPages.length,
592
+ edgesWritten,
581
593
  essentialsLines: promotions.essentials.length,
582
594
  threadsLines: promotions.threads.length,
583
595
  archiveLines: promotions.archive.length,
584
596
  embedsEnqueued,
585
- rebuildEdgesJobId,
586
597
  sentinelWritten: true,
587
598
  };
588
599
  }
@@ -634,21 +645,3 @@ async function writeSentinel(workspaceDir: string): Promise<void> {
634
645
  await mkdir(join(workspaceDir, "memory", ".v2-state"), { recursive: true });
635
646
  await writeFile(sentinelPath, `${new Date().toISOString()}\n`, "utf-8");
636
647
  }
637
-
638
- /**
639
- * Read `memory/edges.json` after writing and return the edge count. Used
640
- * only to populate the result summary — the file has already been
641
- * canonicalized by `writeEdges`, so this is just a count, not validation.
642
- */
643
- async function readPersistedEdgeCount(workspaceDir: string): Promise<number> {
644
- try {
645
- const raw = await readFile(
646
- join(workspaceDir, "memory", "edges.json"),
647
- "utf-8",
648
- );
649
- const parsed = JSON.parse(raw) as { edges?: unknown[] };
650
- return Array.isArray(parsed.edges) ? parsed.edges.length : 0;
651
- } catch {
652
- return 0;
653
- }
654
- }
@@ -3,8 +3,7 @@
3
3
  // ---------------------------------------------------------------------------
4
4
  //
5
5
  // The activation formula's `c_now` term needs a snapshot of the prose meta
6
- // files (`essentials.md`, `threads.md`, `recent.md`) that the system prompt
7
- // also autoloads (see `prompts/system-prompt.ts buildMemoryV2Section`).
6
+ // files (`essentials.md`, `threads.md`, `recent.md`).
8
7
  // Missing or unreadable files are treated as empty so a fresh workspace
9
8
  // (no consolidation has run yet) still reaches the v2 injector with a
10
9
  // well-defined `nowText`.
@@ -16,7 +15,7 @@ const NOW_FILES = ["essentials.md", "threads.md", "recent.md"] as const;
16
15
 
17
16
  /**
18
17
  * Read `memory/{essentials,threads,recent}.md` and concatenate the trimmed
19
- * non-empty contents (in the same order the system prompt autoloads them).
18
+ * non-empty contents.
20
19
  *
21
20
  * Returns an empty string when none of the files exist or all are empty.
22
21
  */