@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
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Tests for `readMemoryV2StaticContent` — the loader that powers the
3
+ * `memory-v2-static` user-message auto-injection. Mirrors the coverage that
4
+ * lived in the deprecated `system-prompt-memory-v2.test.ts`:
5
+ * - Returns null when the v2 flag is off.
6
+ * - Returns null when `config.memory.v2.enabled` is off.
7
+ * - Reads the four files in canonical order and joins them under headings.
8
+ * - Skips empty / missing files.
9
+ * - Returns null when every file is empty or missing.
10
+ */
11
+
12
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
15
+
16
+ const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
17
+
18
+ const noopLogger: Record<string, unknown> = new Proxy(
19
+ {} as Record<string, unknown>,
20
+ {
21
+ get: (_target, prop) => (prop === "child" ? () => noopLogger : () => {}),
22
+ },
23
+ );
24
+
25
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
26
+ const realLogger = require("../../../util/logger.js");
27
+ mock.module("../../../util/logger.js", () => ({
28
+ ...realLogger,
29
+ getLogger: () => noopLogger,
30
+ getCliLogger: () => noopLogger,
31
+ truncateForLog: (v: string) => v,
32
+ initLogger: () => {},
33
+ pruneOldLogFiles: () => 0,
34
+ }));
35
+
36
+ let configMemoryV2Enabled = true;
37
+
38
+ mock.module("../../../config/loader.js", () => ({
39
+ getConfig: () => ({}),
40
+ loadConfig: () => ({
41
+ memory: { v2: { enabled: configMemoryV2Enabled } },
42
+ }),
43
+ loadRawConfig: () => ({}),
44
+ saveConfig: () => {},
45
+ saveRawConfig: () => {},
46
+ invalidateConfigCache: () => {},
47
+ getNestedValue: () => undefined,
48
+ setNestedValue: () => {},
49
+ }));
50
+
51
+ const { _setOverridesForTesting } =
52
+ await import("../../../config/assistant-feature-flags.js");
53
+ const { readMemoryV2StaticContent } = await import("../static-context.js");
54
+
55
+ const MEMORY_FILES = [
56
+ "essentials.md",
57
+ "threads.md",
58
+ "recent.md",
59
+ "buffer.md",
60
+ ] as const;
61
+
62
+ function writeMemoryFile(name: string, body: string): void {
63
+ const memoryDir = join(TEST_DIR, "memory");
64
+ mkdirSync(memoryDir, { recursive: true });
65
+ writeFileSync(join(memoryDir, name), body);
66
+ }
67
+
68
+ function cleanupMemoryDir(): void {
69
+ const memoryDir = join(TEST_DIR, "memory");
70
+ if (existsSync(memoryDir))
71
+ rmSync(memoryDir, { recursive: true, force: true });
72
+ }
73
+
74
+ describe("readMemoryV2StaticContent", () => {
75
+ beforeEach(() => {
76
+ mkdirSync(TEST_DIR, { recursive: true });
77
+ configMemoryV2Enabled = true;
78
+ _setOverridesForTesting({ "memory-v2-enabled": true });
79
+ });
80
+
81
+ afterEach(() => {
82
+ cleanupMemoryDir();
83
+ _setOverridesForTesting({});
84
+ });
85
+
86
+ test("returns null when the feature flag is off", () => {
87
+ _setOverridesForTesting({ "memory-v2-enabled": false });
88
+ for (const file of MEMORY_FILES) writeMemoryFile(file, `Content ${file}`);
89
+ expect(readMemoryV2StaticContent()).toBeNull();
90
+ });
91
+
92
+ test("returns null when config.memory.v2.enabled is off", () => {
93
+ configMemoryV2Enabled = false;
94
+ for (const file of MEMORY_FILES) writeMemoryFile(file, `Content ${file}`);
95
+ expect(readMemoryV2StaticContent()).toBeNull();
96
+ });
97
+
98
+ test("returns headed sections in canonical order when all files have content", () => {
99
+ writeMemoryFile("essentials.md", "Alice prefers dark mode.");
100
+ writeMemoryFile("threads.md", "Open thread: ship PR-123 review.");
101
+ writeMemoryFile(
102
+ "recent.md",
103
+ "Yesterday Alice asked about Postgres tuning.",
104
+ );
105
+ writeMemoryFile(
106
+ "buffer.md",
107
+ "Bob mentioned a pager rotation conflict on Friday.",
108
+ );
109
+
110
+ const result = readMemoryV2StaticContent();
111
+ expect(result).not.toBeNull();
112
+ const text = result!;
113
+
114
+ expect(text).toContain("## Essentials");
115
+ expect(text).toContain("## Threads");
116
+ expect(text).toContain("## Recent");
117
+ expect(text).toContain("## Buffer");
118
+ expect(text).toContain("Alice prefers dark mode.");
119
+ expect(text).toContain(
120
+ "Bob mentioned a pager rotation conflict on Friday.",
121
+ );
122
+
123
+ expect(text.indexOf("## Essentials")).toBeLessThan(
124
+ text.indexOf("## Threads"),
125
+ );
126
+ expect(text.indexOf("## Threads")).toBeLessThan(text.indexOf("## Recent"));
127
+ expect(text.indexOf("## Recent")).toBeLessThan(text.indexOf("## Buffer"));
128
+ });
129
+
130
+ test("omits empty files but keeps populated ones", () => {
131
+ writeMemoryFile("essentials.md", "Alice prefers VS Code.");
132
+ writeMemoryFile("threads.md", "");
133
+ writeMemoryFile("recent.md", "Recent topic: GraphQL pagination.");
134
+ writeMemoryFile("buffer.md", "");
135
+
136
+ const text = readMemoryV2StaticContent();
137
+ expect(text).not.toBeNull();
138
+ expect(text).toContain("## Essentials");
139
+ expect(text).toContain("## Recent");
140
+ expect(text).not.toContain("## Threads");
141
+ expect(text).not.toContain("## Buffer");
142
+ });
143
+
144
+ test("returns null when every file is empty", () => {
145
+ for (const file of MEMORY_FILES) writeMemoryFile(file, "");
146
+ expect(readMemoryV2StaticContent()).toBeNull();
147
+ });
148
+
149
+ test("returns null when memory directory is missing entirely", () => {
150
+ cleanupMemoryDir();
151
+ expect(readMemoryV2StaticContent()).toBeNull();
152
+ });
153
+ });
@@ -10,11 +10,15 @@
10
10
  // + c_now · sim(NOW.md, n)
11
11
  //
12
12
  // A(n, t+1) = [ A_o(n)
13
- // + k · Σ_{m∈1hop} A_o(m)
14
- // + k² · Σ_{m∈2hop} A_o(m) ]
15
- // / (1 + k · #1hop(n) + k² · #2hop(n))
13
+ // + k · Σ_{m∈in1(n)} A_o(m)
14
+ // + k² · Σ_{m∈in2(n)} A_o(m) ]
15
+ // / (1 + k · #in1(n) + k² · #in2(n))
16
16
  //
17
- // Bounded in [0, 1]. Orphan nodes (no neighbors within `hops`) reduce to
17
+ // Edges are directed: edge A→B means A's activation contributes to B's. The
18
+ // per-target BFS walks *incoming* adjacency, so `in1(n)` is the set of nodes
19
+ // with an edge A→n and `in2(n)` adds another hop in the same direction.
20
+ //
21
+ // Bounded in [0, 1]. Pure sources (no incoming edges within `hops`) reduce to
18
22
  // A == A_o because both numerator and denominator collapse to `A_o(n)` and
19
23
  // `1`, respectively.
20
24
  //
@@ -33,14 +37,11 @@ import {
33
37
  generateSparseEmbedding,
34
38
  } from "../embedding-backend.js";
35
39
  import { clampUnitInterval } from "../validation.js";
40
+ import type { EdgeIndex } from "./edge-index.js";
36
41
  import { hybridQueryConceptPages } from "./qdrant.js";
37
42
  import { simBatch, simSkillBatch } from "./sim.js";
38
43
  import { hybridQuerySkills } from "./skill-qdrant.js";
39
- import type {
40
- ActivationState,
41
- EdgesIndex,
42
- EverInjectedEntry,
43
- } from "./types.js";
44
+ import type { ActivationState, EverInjectedEntry } from "./types.js";
44
45
 
45
46
  /**
46
47
  * Top-K size for the un-restricted ANN candidate query against the v2
@@ -70,27 +71,41 @@ export interface SelectCandidatesParams {
70
71
  config: AssistantConfig;
71
72
  }
72
73
 
74
+ export interface SelectCandidatesResult {
75
+ /** Union of `fromPrior` and `fromAnn` — the per-turn candidate set. */
76
+ candidates: Set<string>;
77
+ /** Slugs carried forward from `priorState` because their activation > epsilon. */
78
+ fromPrior: Set<string>;
79
+ /** Slugs surfaced by the unrestricted ANN top-50 against the joined turn text. */
80
+ fromAnn: Set<string>;
81
+ }
82
+
73
83
  /**
74
84
  * Build the per-turn candidate set: the union of slugs in the prior state
75
85
  * (above epsilon) and the top-50 ANN hits against the concatenated turn
76
86
  * text. The ANN call runs un-restricted (no slug filter) so it can surface
77
87
  * pages outside the active set.
78
88
  *
89
+ * Returns the union plus the two source sets separately so downstream
90
+ * telemetry can attribute each candidate to `prior_state`, `ann_top50`, or
91
+ * both. A slug present in both sources appears in `fromPrior ∩ fromAnn`.
92
+ *
79
93
  * Empty candidate sets are valid and propagate downstream — both
80
94
  * `computeOwnActivation` and `spreadActivation` short-circuit on them.
81
95
  */
82
96
  export async function selectCandidates(
83
97
  params: SelectCandidatesParams,
84
- ): Promise<Set<string>> {
98
+ ): Promise<SelectCandidatesResult> {
85
99
  const { priorState, userText, assistantText, nowText, config } = params;
86
100
 
87
- const candidates = new Set<string>();
101
+ const fromPrior = new Set<string>();
102
+ const fromAnn = new Set<string>();
88
103
 
89
104
  // (1) Carry forward prior-state slugs above epsilon.
90
105
  if (priorState) {
91
106
  const epsilon = config.memory.v2.epsilon;
92
107
  for (const [slug, activation] of Object.entries(priorState.state)) {
93
- if (activation > epsilon) candidates.add(slug);
108
+ if (activation > epsilon) fromPrior.add(slug);
94
109
  }
95
110
  }
96
111
 
@@ -110,10 +125,12 @@ export async function selectCandidates(
110
125
  sparse,
111
126
  ANN_CANDIDATE_LIMIT,
112
127
  );
113
- for (const hit of hits) candidates.add(hit.slug);
128
+ for (const hit of hits) fromAnn.add(hit.slug);
114
129
  }
115
130
 
116
- return candidates;
131
+ const candidates = new Set<string>([...fromPrior, ...fromAnn]);
132
+
133
+ return { candidates, fromPrior, fromAnn };
117
134
  }
118
135
 
119
136
  // ---------------------------------------------------------------------------
@@ -129,24 +146,50 @@ export interface ComputeOwnActivationParams {
129
146
  config: AssistantConfig;
130
147
  }
131
148
 
149
+ /**
150
+ * Per-slug breakdown of the own-activation inputs, captured before any
151
+ * coefficient weighting is applied. Surfaced for telemetry / inspector views
152
+ * so the UI can show how each term contributed to the final value.
153
+ */
154
+ export interface OwnActivationBreakdown {
155
+ /** `d * prev(slug)` — the decayed prior-turn activation contribution. */
156
+ priorContribution: number;
157
+ /** Raw `sim(user, slug)` similarity, before `c_user` weighting. */
158
+ simUser: number;
159
+ /** Raw `sim(assistant, slug)` similarity, before `c_assistant` weighting. */
160
+ simAssistant: number;
161
+ /** Raw `sim(now, slug)` similarity, before `c_now` weighting. */
162
+ simNow: number;
163
+ }
164
+
165
+ export interface ComputeOwnActivationResult {
166
+ /** Final clamped own-activation value per slug. */
167
+ activation: Map<string, number>;
168
+ /** Per-slug breakdown of the inputs that fed into `activation`. */
169
+ breakdown: Map<string, OwnActivationBreakdown>;
170
+ }
171
+
132
172
  /**
133
173
  * Apply the own-activation formula
134
174
  * A_o(n) = d · prev(n) + c_user · sim_u + c_assistant · sim_a + c_now · sim_n
135
175
  * over the candidate set. Returns a sparse map keyed by slug; slugs whose
136
176
  * computed value rounds to 0 are still included so callers can see the
137
- * candidate set explicitly.
177
+ * candidate set explicitly. Also returns a per-slug breakdown of the raw
178
+ * inputs (decayed prior + raw sims) so callers can render contribution
179
+ * diagnostics without re-running the math.
138
180
  *
139
181
  * The three `simBatch` calls run concurrently — they hit independent named
140
182
  * vectors and embed independent query texts.
141
183
  */
142
184
  export async function computeOwnActivation(
143
185
  params: ComputeOwnActivationParams,
144
- ): Promise<Map<string, number>> {
186
+ ): Promise<ComputeOwnActivationResult> {
145
187
  const { candidates, priorState, userText, assistantText, nowText, config } =
146
188
  params;
147
189
 
148
- const result = new Map<string, number>();
149
- if (candidates.size === 0) return result;
190
+ const activation = new Map<string, number>();
191
+ const breakdown = new Map<string, OwnActivationBreakdown>();
192
+ if (candidates.size === 0) return { activation, breakdown };
150
193
 
151
194
  const { d, c_user, c_assistant, c_now } = config.memory.v2;
152
195
  const slugList = [...candidates];
@@ -159,63 +202,85 @@ export async function computeOwnActivation(
159
202
 
160
203
  for (const slug of slugList) {
161
204
  const prev = priorState?.state[slug] ?? 0;
162
- const value =
163
- d * prev +
164
- c_user * (simUser.get(slug) ?? 0) +
165
- c_assistant * (simAssistant.get(slug) ?? 0) +
166
- c_now * (simNow.get(slug) ?? 0);
167
- result.set(slug, clampUnitInterval(value));
205
+ const simU = simUser.get(slug) ?? 0;
206
+ const simA = simAssistant.get(slug) ?? 0;
207
+ const simN = simNow.get(slug) ?? 0;
208
+ const value = d * prev + c_user * simU + c_assistant * simA + c_now * simN;
209
+ activation.set(slug, clampUnitInterval(value));
210
+ breakdown.set(slug, {
211
+ priorContribution: d * prev,
212
+ simUser: simU,
213
+ simAssistant: simA,
214
+ simNow: simN,
215
+ });
168
216
  }
169
217
 
170
- return result;
218
+ return { activation, breakdown };
171
219
  }
172
220
 
173
221
  // ---------------------------------------------------------------------------
174
222
  // Spreading activation
175
223
  // ---------------------------------------------------------------------------
176
224
 
225
+ export interface SpreadActivationResult {
226
+ /** Final activation value per slug after spreading. */
227
+ final: Map<string, number>;
228
+ /**
229
+ * Per-slug spread delta: `final[slug] - own[slug]`. Captures how much
230
+ * the spread step nudged each node above (or below) its own activation —
231
+ * useful for inspector views that want to show graph contributions
232
+ * separate from raw sim contributions. Always 0 when `hops == 0` or
233
+ * `k == 0` because both short-circuit to `final == own`.
234
+ */
235
+ contribution: Map<string, number>;
236
+ }
237
+
177
238
  /**
178
- * Apply 2-hop spreading activation with neighborhood normalization:
239
+ * Apply 2-hop spreading activation with neighborhood normalization. Edges are
240
+ * directed: an edge A→B means A's activation contributes to B's final value.
179
241
  *
180
- * A(n) = [ A_o(n) + k · Σ_{m∈1hop} A_o(m) + k² · Σ_{m∈2hop} A_o(m) ]
181
- * / (1 + k · #1hop(n) + k² · #2hop(n))
242
+ * A(n) = [ A_o(n) + k · Σ_{m∈in1(n)} A_o(m) + k² · Σ_{m∈in2(n)} A_o(m) ]
243
+ * / (1 + k · #in1(n) + k² · #in2(n))
182
244
  *
183
- * The denominator counts *structural* neighbors at each hop (whether or not
184
- * they appear in `ownActivation`) so an orphan node's denominator collapses
185
- * to 1 and `A == A_o`. Missing neighbors contribute 0 to the numerator.
245
+ * For each candidate slug `n`, BFS walks `incoming` adjacency to gather
246
+ * predecessors at distance 1, 2 (i.e. nodes from which a directed path of
247
+ * that length leads into `n`). The denominator counts those structural
248
+ * predecessors at each hop (whether or not they appear in `ownActivation`)
249
+ * so a pure source — no incoming edges — collapses to `A == A_o`. Missing
250
+ * predecessors contribute 0 to the numerator.
186
251
  *
187
252
  * Bounded in [0, 1]: with `A_o ∈ [0, 1]` and `k ∈ [0, 1]`, the numerator is
188
- * at most `1 + k · #1hop + k² · #2hop` — exactly the denominator — so the
253
+ * at most `1 + k · #in1 + k² · #in2` — exactly the denominator — so the
189
254
  * ratio is at most 1. `clampUnitInterval` guards against numerical drift
190
255
  * and out-of-range inputs.
191
256
  *
192
- * Pure function — no I/O. Builds an adjacency map once from `edgesIdx` and
193
- * runs a per-source BFS bounded by `hops`.
257
+ * Pure function — no I/O. Reads the precomputed `incoming` map from
258
+ * `edgeIndex` and runs a per-source BFS bounded by `hops`.
194
259
  */
195
260
  export function spreadActivation(
196
261
  ownActivation: ReadonlyMap<string, number>,
197
- edgesIdx: EdgesIndex,
262
+ edgeIndex: EdgeIndex,
198
263
  k: number,
199
264
  hops: number,
200
- ): Map<string, number> {
201
- const result = new Map<string, number>();
202
- if (ownActivation.size === 0) return result;
265
+ ): SpreadActivationResult {
266
+ const final = new Map<string, number>();
267
+ const contribution = new Map<string, number>();
268
+ if (ownActivation.size === 0) return { final, contribution };
203
269
 
204
270
  // Short-circuit: with no spread the formula collapses to A == A_o.
205
271
  if (hops <= 0 || k <= 0) {
206
272
  for (const [slug, ownValue] of ownActivation) {
207
- result.set(slug, clampUnitInterval(ownValue));
273
+ final.set(slug, clampUnitInterval(ownValue));
274
+ contribution.set(slug, 0);
208
275
  }
209
- return result;
276
+ return { final, contribution };
210
277
  }
211
278
 
212
- const adjacency = buildAdjacency(edgesIdx);
213
-
214
279
  for (const [slug, ownValue] of ownActivation) {
215
- // Single bounded BFS from `slug`. `distance` maps neighbor → hop count
216
- // (1..hops). Source is excluded so it contributes hop-0 only via
217
- // `numerator = ownValue`.
218
- const distance = bfsDistances(adjacency, slug, hops);
280
+ // Single bounded BFS from `slug` over incoming edges. `distance` maps
281
+ // predecessor → hop count (1..hops). Source is excluded so it contributes
282
+ // hop-0 only via `numerator = ownValue`.
283
+ const distance = bfsPredecessorDistances(edgeIndex.incoming, slug, hops);
219
284
 
220
285
  let numerator = ownValue;
221
286
  let denominator = 1;
@@ -224,9 +289,9 @@ export function spreadActivation(
224
289
  // counts to weight by k^r, so bucket as we go.
225
290
  const ringCounts: number[] = new Array(hops + 1).fill(0);
226
291
  const ringSums: number[] = new Array(hops + 1).fill(0);
227
- for (const [neighbor, hop] of distance) {
292
+ for (const [predecessor, hop] of distance) {
228
293
  ringCounts[hop] += 1;
229
- ringSums[hop] += ownActivation.get(neighbor) ?? 0;
294
+ ringSums[hop] += ownActivation.get(predecessor) ?? 0;
230
295
  }
231
296
  for (let r = 1; r <= hops; r++) {
232
297
  kPow *= k;
@@ -235,10 +300,12 @@ export function spreadActivation(
235
300
  denominator += kPow * ringCounts[r];
236
301
  }
237
302
 
238
- result.set(slug, clampUnitInterval(numerator / denominator));
303
+ const finalValue = clampUnitInterval(numerator / denominator);
304
+ final.set(slug, finalValue);
305
+ contribution.set(slug, finalValue - ownValue);
239
306
  }
240
307
 
241
- return result;
308
+ return { final, contribution };
242
309
  }
243
310
 
244
311
  // ---------------------------------------------------------------------------
@@ -246,50 +313,29 @@ export function spreadActivation(
246
313
  // ---------------------------------------------------------------------------
247
314
 
248
315
  /**
249
- * Build a slug neighbors map from a canonicalized undirected edges index.
250
- * Mirrors `edges.ts#buildAdjacency` but is local so `spreadActivation` can
251
- * stay independent of `edges.ts`'s currently-private helper.
252
- */
253
- function buildAdjacency(idx: EdgesIndex): Map<string, Set<string>> {
254
- const adjacency = new Map<string, Set<string>>();
255
- const ensure = (slug: string): Set<string> => {
256
- let set = adjacency.get(slug);
257
- if (!set) {
258
- set = new Set<string>();
259
- adjacency.set(slug, set);
260
- }
261
- return set;
262
- };
263
- for (const [a, b] of idx.edges) {
264
- if (a === b) continue;
265
- ensure(a).add(b);
266
- ensure(b).add(a);
267
- }
268
- return adjacency;
269
- }
270
-
271
- /**
272
- * Bounded BFS that returns each reachable slug's hop-distance in [1, maxHops]
273
- * from `source`. The source itself is excluded.
316
+ * Bounded BFS over the *incoming* adjacency map. Returns each reachable
317
+ * predecessor's hop-distance in [1, maxHops] from `target` — i.e. nodes from
318
+ * which a directed path of that length leads into `target`. The target itself
319
+ * is excluded.
274
320
  */
275
- function bfsDistances(
276
- adjacency: ReadonlyMap<string, ReadonlySet<string>>,
277
- source: string,
321
+ function bfsPredecessorDistances(
322
+ incoming: ReadonlyMap<string, ReadonlySet<string>>,
323
+ target: string,
278
324
  maxHops: number,
279
325
  ): Map<string, number> {
280
326
  const distance = new Map<string, number>();
281
- let frontier: string[] = [source];
282
- const visited = new Set<string>([source]);
327
+ let frontier: string[] = [target];
328
+ const visited = new Set<string>([target]);
283
329
  for (let hop = 1; hop <= maxHops && frontier.length > 0; hop++) {
284
330
  const next: string[] = [];
285
331
  for (const node of frontier) {
286
- const neighbors = adjacency.get(node);
287
- if (!neighbors) continue;
288
- for (const neighbor of neighbors) {
289
- if (visited.has(neighbor)) continue;
290
- visited.add(neighbor);
291
- distance.set(neighbor, hop);
292
- next.push(neighbor);
332
+ const predecessors = incoming.get(node);
333
+ if (!predecessors) continue;
334
+ for (const predecessor of predecessors) {
335
+ if (visited.has(predecessor)) continue;
336
+ visited.add(predecessor);
337
+ distance.set(predecessor, hop);
338
+ next.push(predecessor);
293
339
  }
294
340
  }
295
341
  frontier = next;
@@ -410,24 +456,48 @@ export interface ComputeSkillActivationParams {
410
456
  config: AssistantConfig;
411
457
  }
412
458
 
459
+ /**
460
+ * Per-skill breakdown of the raw similarity inputs, captured before any
461
+ * coefficient weighting. Skills have no decay term, so the breakdown is just
462
+ * the three raw sims. Surfaced for telemetry / inspector views.
463
+ */
464
+ export interface SkillActivationBreakdown {
465
+ /** Raw `sim(user, skill)` similarity, before `c_user` weighting. */
466
+ simUser: number;
467
+ /** Raw `sim(assistant, skill)` similarity, before `c_assistant` weighting. */
468
+ simAssistant: number;
469
+ /** Raw `sim(now, skill)` similarity, before `c_now` weighting. */
470
+ simNow: number;
471
+ }
472
+
473
+ export interface ComputeSkillActivationResult {
474
+ /** Final clamped skill-activation value per id. */
475
+ activation: Map<string, number>;
476
+ /** Per-skill breakdown of the raw sim inputs that fed into `activation`. */
477
+ breakdown: Map<string, SkillActivationBreakdown>;
478
+ }
479
+
413
480
  /**
414
481
  * Apply the skill-side activation formula (no decay carry-over, no spread):
415
482
  * A_skill(s) = clamp01(c_user · sim_u + c_assistant · sim_a + c_now · sim_n)
416
483
  *
417
484
  * Reuses the activation coefficients from `config.memory.v2`. The three
418
485
  * `simSkillBatch` calls run concurrently — they hit independent named
419
- * vectors and embed independent query texts.
486
+ * vectors and embed independent query texts. Returns a per-skill breakdown
487
+ * of the raw sims alongside the activation map so callers can render
488
+ * contribution diagnostics without re-running the math.
420
489
  *
421
490
  * Empty candidates short-circuits to an empty map without touching the
422
491
  * embedding backend or Qdrant.
423
492
  */
424
493
  export async function computeSkillActivation(
425
494
  params: ComputeSkillActivationParams,
426
- ): Promise<Map<string, number>> {
495
+ ): Promise<ComputeSkillActivationResult> {
427
496
  const { candidates, userText, assistantText, nowText, config } = params;
428
497
 
429
- const result = new Map<string, number>();
430
- if (candidates.size === 0) return result;
498
+ const activation = new Map<string, number>();
499
+ const breakdown = new Map<string, SkillActivationBreakdown>();
500
+ if (candidates.size === 0) return { activation, breakdown };
431
501
 
432
502
  const { c_user, c_assistant, c_now } = config.memory.v2;
433
503
  const idList = [...candidates];
@@ -439,14 +509,15 @@ export async function computeSkillActivation(
439
509
  ]);
440
510
 
441
511
  for (const id of idList) {
442
- const value =
443
- c_user * (simUser.get(id) ?? 0) +
444
- c_assistant * (simAssistant.get(id) ?? 0) +
445
- c_now * (simNow.get(id) ?? 0);
446
- result.set(id, clampUnitInterval(value));
512
+ const simU = simUser.get(id) ?? 0;
513
+ const simA = simAssistant.get(id) ?? 0;
514
+ const simN = simNow.get(id) ?? 0;
515
+ const value = c_user * simU + c_assistant * simA + c_now * simN;
516
+ activation.set(id, clampUnitInterval(value));
517
+ breakdown.set(id, { simUser: simU, simAssistant: simA, simNow: simN });
447
518
  }
448
519
 
449
- return result;
520
+ return { activation, breakdown };
450
521
  }
451
522
 
452
523
  export interface SelectSkillInjectionsParams {