@vellumai/assistant 0.7.0 → 0.7.2

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 (989) hide show
  1. package/ARCHITECTURE.md +38 -56
  2. package/Dockerfile +2 -0
  3. package/README.md +3 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +88 -142
  5. package/bun.lock +29 -26
  6. package/docs/architecture/security.md +38 -16
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +2 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  19. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -5
  20. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  21. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  22. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  23. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  24. package/node_modules/@vellumai/slack-text/package.json +18 -0
  25. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  26. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  27. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  28. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  29. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  30. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  31. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  32. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  33. package/openapi.yaml +869 -129
  34. package/package.json +8 -3
  35. package/scripts/generate-openapi.ts +16 -111
  36. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  37. package/src/__tests__/anthropic-provider.test.ts +56 -13
  38. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  39. package/src/__tests__/app-bundler.test.ts +170 -1
  40. package/src/__tests__/app-control-flow.test.ts +374 -0
  41. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  42. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  43. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  44. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  45. package/src/__tests__/app-executors.test.ts +30 -43
  46. package/src/__tests__/approval-cascade.test.ts +0 -15
  47. package/src/__tests__/approval-routes-http.test.ts +29 -23
  48. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  49. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  50. package/src/__tests__/assistant-event-hub.test.ts +235 -79
  51. package/src/__tests__/assistant-event.test.ts +10 -5
  52. package/src/__tests__/assistant-events-sse-hardening.test.ts +44 -17
  53. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -36
  54. package/src/__tests__/background-shell-host-bash.test.ts +46 -56
  55. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  56. package/src/__tests__/btw-routes.test.ts +13 -4
  57. package/src/__tests__/call-controller.test.ts +50 -2
  58. package/src/__tests__/call-domain.test.ts +0 -2
  59. package/src/__tests__/call-routes-http.test.ts +0 -2
  60. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  61. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  62. package/src/__tests__/channel-approvals.test.ts +25 -17
  63. package/src/__tests__/channel-guardian.test.ts +100 -146
  64. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  65. package/src/__tests__/checker.test.ts +23 -38
  66. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  67. package/src/__tests__/compaction-events.test.ts +2 -0
  68. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  69. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  70. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  71. package/src/__tests__/config-schema.test.ts +6 -48
  72. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  73. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  74. package/src/__tests__/config-watcher.test.ts +14 -2
  75. package/src/__tests__/connection-policy.test.ts +1 -52
  76. package/src/__tests__/contacts-write.test.ts +2 -64
  77. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  78. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  79. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  80. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  81. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  82. package/src/__tests__/context-window-manager.test.ts +46 -0
  83. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  84. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  85. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  86. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  87. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  88. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  89. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  90. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  91. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  92. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  93. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  94. package/src/__tests__/conversation-lifecycle.test.ts +40 -4
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  96. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  97. package/src/__tests__/conversation-queue.test.ts +3 -8
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -161
  99. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -104
  100. package/src/__tests__/conversation-routes-slash-commands.test.ts +76 -66
  101. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  102. package/src/__tests__/conversation-slash-commands.test.ts +24 -8
  103. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  104. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  105. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  106. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  107. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  108. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  109. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  110. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  111. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  112. package/src/__tests__/conversation-usage.test.ts +253 -3
  113. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  114. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  115. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  116. package/src/__tests__/credential-health-service.test.ts +68 -0
  117. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  118. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  119. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  120. package/src/__tests__/credentials-cli.test.ts +5 -12
  121. package/src/__tests__/cu-unified-flow.test.ts +206 -27
  122. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  123. package/src/__tests__/daemon-credential-client.test.ts +102 -17
  124. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  125. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  126. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  127. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  128. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  129. package/src/__tests__/document-conversations.test.ts +332 -0
  130. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  131. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  132. package/src/__tests__/emit-event-signal.test.ts +4 -6
  133. package/src/__tests__/events-client-registration.test.ts +193 -49
  134. package/src/__tests__/filing-service.test.ts +58 -7
  135. package/src/__tests__/first-greeting.test.ts +156 -150
  136. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  137. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  138. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  139. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  140. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  141. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  142. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  143. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  144. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  145. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +30 -11
  146. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -84
  147. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  148. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  149. package/src/__tests__/heartbeat-service.test.ts +1007 -8
  150. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  151. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  152. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  153. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  154. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  155. package/src/__tests__/host-bash-proxy.test.ts +270 -147
  156. package/src/__tests__/host-bash-routes.test.ts +294 -0
  157. package/src/__tests__/host-browser-proxy.test.ts +126 -198
  158. package/src/__tests__/host-browser-routes.test.ts +50 -54
  159. package/src/__tests__/host-cu-proxy.test.ts +78 -144
  160. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  161. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  162. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  163. package/src/__tests__/host-file-proxy.test.ts +62 -122
  164. package/src/__tests__/host-file-read-tool.test.ts +59 -21
  165. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  166. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  167. package/src/__tests__/host-proxy-base.test.ts +312 -0
  168. package/src/__tests__/host-shell-tool.test.ts +53 -70
  169. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  170. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  171. package/src/__tests__/host-transfer-proxy.test.ts +145 -56
  172. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  173. package/src/__tests__/http-user-message-parity.test.ts +1 -6
  174. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  175. package/src/__tests__/identity-routes.test.ts +103 -1
  176. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  177. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  178. package/src/__tests__/injector-chain.test.ts +10 -5
  179. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  180. package/src/__tests__/inline-command-runner.test.ts +0 -67
  181. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -13
  182. package/src/__tests__/install-skill-routing.test.ts +1 -13
  183. package/src/__tests__/integration-status.test.ts +85 -5
  184. package/src/__tests__/intent-routing.test.ts +0 -1
  185. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  186. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  187. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  188. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  189. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  190. package/src/__tests__/llm-resolver.test.ts +80 -12
  191. package/src/__tests__/llm-usage-store.test.ts +269 -4
  192. package/src/__tests__/log-export-routes.test.ts +89 -0
  193. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  194. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -11
  195. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  196. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  197. package/src/__tests__/mcp-cli.test.ts +338 -2
  198. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  199. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  200. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  201. package/src/__tests__/migration-export-http.test.ts +33 -26
  202. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  203. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  204. package/src/__tests__/migration-import-commit-http.test.ts +172 -21
  205. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  206. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  207. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  208. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  209. package/src/__tests__/migration-transport.test.ts +115 -23
  210. package/src/__tests__/migration-validate-http.test.ts +105 -80
  211. package/src/__tests__/migration-wizard.test.ts +133 -27
  212. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  213. package/src/__tests__/non-member-access-request.test.ts +1 -1
  214. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  215. package/src/__tests__/oauth-cli.test.ts +0 -2
  216. package/src/__tests__/oauth-store.test.ts +19 -0
  217. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  218. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  219. package/src/__tests__/platform-bash-auto-approve.test.ts +26 -21
  220. package/src/__tests__/prechat-onboarding-contract.test.ts +34 -8
  221. package/src/__tests__/pricing.test.ts +68 -4
  222. package/src/__tests__/process-message-background-slack.test.ts +333 -0
  223. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  224. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  225. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  226. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  227. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  228. package/src/__tests__/reaction-persistence.test.ts +9 -6
  229. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  230. package/src/__tests__/recording-handler.test.ts +64 -81
  231. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  232. package/src/__tests__/relay-server.test.ts +18 -13
  233. package/src/__tests__/require-fresh-approval.test.ts +13 -23
  234. package/src/__tests__/retry-backoff.test.ts +87 -0
  235. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  236. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  237. package/src/__tests__/runtime-events-sse.test.ts +13 -18
  238. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  239. package/src/__tests__/schedule-retry.test.ts +715 -0
  240. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  241. package/src/__tests__/search-skills-unified.test.ts +9 -15
  242. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  243. package/src/__tests__/secret-ingress-http.test.ts +1 -4
  244. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  245. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  246. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  247. package/src/__tests__/secret-response-routing.test.ts +29 -15
  248. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  249. package/src/__tests__/secret-scanner.test.ts +2 -545
  250. package/src/__tests__/send-endpoint-busy.test.ts +12 -24
  251. package/src/__tests__/settings-routes.test.ts +1 -1
  252. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  253. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -57
  254. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  255. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  256. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  257. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  258. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  259. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -12
  260. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  261. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  262. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  263. package/src/__tests__/slack-channel-config.test.ts +9 -14
  264. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  265. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  266. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  267. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  268. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  269. package/src/__tests__/system-prompt.test.ts +115 -14
  270. package/src/__tests__/telegram-config.test.ts +0 -1
  271. package/src/__tests__/terminal-tools.test.ts +0 -89
  272. package/src/__tests__/test-preload.ts +8 -0
  273. package/src/__tests__/thread-backfill.test.ts +945 -31
  274. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  275. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  276. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  277. package/src/__tests__/tool-execute-pipeline.test.ts +0 -7
  278. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -17
  279. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  280. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -8
  281. package/src/__tests__/tool-executor.test.ts +12 -20
  282. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  283. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  284. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  285. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  286. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  287. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  288. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  289. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  290. package/src/__tests__/twilio-config.test.ts +3 -16
  291. package/src/__tests__/twilio-routes.test.ts +3 -5
  292. package/src/__tests__/twilio-validation.test.ts +93 -0
  293. package/src/__tests__/usage-attribution.test.ts +247 -0
  294. package/src/__tests__/usage-cli.test.ts +143 -0
  295. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  296. package/src/__tests__/usage-routes.test.ts +150 -0
  297. package/src/__tests__/validation-results-screen.test.ts +39 -16
  298. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  299. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +47 -138
  300. package/src/__tests__/verification-control-plane-policy.test.ts +6 -11
  301. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  302. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  303. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  304. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  305. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  306. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  307. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  308. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  309. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  310. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  311. package/src/acp/index.ts +0 -15
  312. package/src/acp/session-manager.ts +37 -34
  313. package/src/agent/loop.ts +16 -1
  314. package/src/approvals/AGENTS.md +4 -0
  315. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  316. package/src/approvals/guardian-request-resolvers.ts +10 -2
  317. package/src/backup/__tests__/paths.test.ts +0 -22
  318. package/src/backup/__tests__/restore.test.ts +94 -177
  319. package/src/backup/paths.ts +2 -15
  320. package/src/backup/restore.ts +107 -231
  321. package/src/browser-session/events.ts +0 -9
  322. package/src/bundler/app-bundler.ts +51 -3
  323. package/src/calls/call-store.ts +1 -34
  324. package/src/calls/guardian-question-copy.ts +0 -108
  325. package/src/calls/relay-server.ts +4 -68
  326. package/src/calls/twilio-config.ts +2 -17
  327. package/src/calls/twilio-rest.ts +31 -141
  328. package/src/calls/twilio-routes.ts +12 -13
  329. package/src/calls/voice-session-bridge.ts +7 -38
  330. package/src/channels/types.ts +8 -42
  331. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  332. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  333. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  334. package/src/cli/commands/__tests__/memory-v2.test.ts +18 -28
  335. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  336. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  337. package/src/cli/commands/backup.ts +6 -331
  338. package/src/cli/commands/cache-fs.ts +8 -0
  339. package/src/cli/commands/cache.ts +153 -82
  340. package/src/cli/commands/clients.ts +64 -7
  341. package/src/cli/commands/completions.ts +3 -3
  342. package/src/cli/commands/contacts.ts +304 -76
  343. package/src/cli/commands/conversations.ts +2 -5
  344. package/src/cli/commands/credentials.ts +15 -7
  345. package/src/cli/commands/domain.ts +66 -15
  346. package/src/cli/commands/gateway.ts +183 -0
  347. package/src/cli/commands/keys.ts +13 -7
  348. package/src/cli/commands/mcp.ts +116 -156
  349. package/src/cli/commands/memory-v2.ts +320 -53
  350. package/src/cli/commands/oauth/shared.ts +2 -29
  351. package/src/cli/commands/pending.ts +102 -0
  352. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  353. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  354. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  355. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  356. package/src/cli/commands/platform/disconnect.ts +5 -4
  357. package/src/cli/commands/platform/index.ts +0 -18
  358. package/src/cli/commands/skills.ts +77 -35
  359. package/src/cli/commands/trust.ts +70 -430
  360. package/src/cli/commands/usage.ts +25 -16
  361. package/src/cli/lib/daemon-credential-client.ts +115 -19
  362. package/src/cli/program.ts +4 -0
  363. package/src/cli.ts +0 -21
  364. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  365. package/src/config/assistant-feature-flags.ts +67 -10
  366. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  367. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  368. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  369. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  370. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  371. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  372. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  373. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  374. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  375. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  376. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  377. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  378. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  379. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  380. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  381. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  382. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  383. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  384. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  385. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  386. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  387. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  388. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  389. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  390. package/src/config/bundled-skills/messaging/TOOLS.json +14 -44
  391. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  392. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  393. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  394. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  395. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  396. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  397. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  398. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  399. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  400. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  401. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  402. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  403. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  404. package/src/config/bundled-tool-registry.ts +21 -0
  405. package/src/config/env-registry.ts +12 -4
  406. package/src/config/env.ts +22 -26
  407. package/src/config/feature-flag-registry.json +40 -152
  408. package/src/config/llm-callsite-catalog.ts +12 -0
  409. package/src/config/llm-context-resolution.ts +80 -0
  410. package/src/config/llm-resolver.ts +58 -22
  411. package/src/config/loader.ts +76 -102
  412. package/src/config/sanitize-for-transfer.ts +2 -0
  413. package/src/config/schema.ts +2 -158
  414. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  415. package/src/config/schemas/__tests__/memory-v2.test.ts +8 -4
  416. package/src/config/schemas/call-site-catalog.ts +271 -0
  417. package/src/config/schemas/calls.ts +5 -14
  418. package/src/config/schemas/heartbeat.ts +63 -0
  419. package/src/config/schemas/inference.ts +1 -1
  420. package/src/config/schemas/ingress.ts +11 -7
  421. package/src/config/schemas/llm.ts +34 -11
  422. package/src/config/schemas/memory-lifecycle.ts +77 -24
  423. package/src/config/schemas/memory-retrieval.ts +2 -2
  424. package/src/config/schemas/memory-v2.ts +57 -4
  425. package/src/config/schemas/platform.ts +6 -0
  426. package/src/config/schemas/security.ts +1 -42
  427. package/src/config/schemas/services.ts +7 -21
  428. package/src/config/schemas/skills.ts +5 -11
  429. package/src/config/schemas/tts.ts +1 -1
  430. package/src/config/seed-inference-profiles.ts +117 -0
  431. package/src/config/skills.ts +0 -90
  432. package/src/config/types.ts +3 -6
  433. package/src/contacts/contact-store.ts +0 -47
  434. package/src/contacts/contacts-write.ts +1 -132
  435. package/src/context/window-manager.ts +43 -5
  436. package/src/credential-execution/feature-gates.ts +10 -10
  437. package/src/credential-execution/process-manager.ts +46 -51
  438. package/src/credential-health/credential-health-service.ts +21 -16
  439. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  440. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  441. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  442. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  443. package/src/daemon/config-watcher.ts +4 -3
  444. package/src/daemon/connection-policy.ts +1 -26
  445. package/src/daemon/conversation-agent-loop-handlers.ts +74 -7
  446. package/src/daemon/conversation-agent-loop.ts +309 -64
  447. package/src/daemon/conversation-history.ts +8 -8
  448. package/src/daemon/conversation-launch.ts +20 -135
  449. package/src/daemon/conversation-lifecycle.ts +8 -1
  450. package/src/daemon/conversation-messaging.ts +1 -0
  451. package/src/daemon/conversation-process.ts +97 -172
  452. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  453. package/src/daemon/conversation-slash.ts +47 -5
  454. package/src/daemon/conversation-store.ts +7 -31
  455. package/src/daemon/conversation-surfaces.ts +144 -29
  456. package/src/daemon/conversation-tool-setup.ts +18 -87
  457. package/src/daemon/conversation-usage.ts +36 -0
  458. package/src/daemon/conversation.ts +134 -231
  459. package/src/daemon/daemon-control.ts +3 -71
  460. package/src/daemon/daemon-skill-host.ts +8 -11
  461. package/src/daemon/dictation-profile-store.ts +2 -26
  462. package/src/daemon/doordash-steps.ts +1 -1
  463. package/src/daemon/first-greeting.ts +44 -156
  464. package/src/daemon/handlers/config-channels.ts +12 -12
  465. package/src/daemon/handlers/config-ingress.ts +4 -165
  466. package/src/daemon/handlers/config-model.ts +1 -1
  467. package/src/daemon/handlers/config-voice.ts +0 -42
  468. package/src/daemon/handlers/conversations.ts +11 -190
  469. package/src/daemon/handlers/recording.ts +26 -158
  470. package/src/daemon/handlers/shared.ts +27 -72
  471. package/src/daemon/handlers/skills.ts +42 -93
  472. package/src/daemon/host-app-control-proxy.ts +293 -0
  473. package/src/daemon/host-bash-proxy.ts +124 -92
  474. package/src/daemon/host-browser-proxy.ts +111 -88
  475. package/src/daemon/host-cu-proxy.ts +100 -104
  476. package/src/daemon/host-file-proxy.ts +136 -91
  477. package/src/daemon/host-proxy-base.ts +294 -0
  478. package/src/daemon/host-proxy-preactivation.ts +82 -0
  479. package/src/daemon/host-transfer-proxy.ts +303 -147
  480. package/src/daemon/lifecycle.ts +164 -132
  481. package/src/daemon/message-protocol.ts +3 -8
  482. package/src/daemon/message-types/contacts.ts +23 -1
  483. package/src/daemon/message-types/conversations.ts +18 -8
  484. package/src/daemon/message-types/host-app-control.ts +150 -0
  485. package/src/daemon/message-types/host-bash.ts +5 -0
  486. package/src/daemon/message-types/host-cu.ts +3 -0
  487. package/src/daemon/message-types/host-file.ts +5 -0
  488. package/src/daemon/message-types/host-transfer.ts +4 -0
  489. package/src/daemon/message-types/messages.ts +10 -9
  490. package/src/daemon/message-types/schedules.ts +8 -3
  491. package/src/daemon/message-types/skills.ts +2 -2
  492. package/src/daemon/message-types/workspace.ts +1 -1
  493. package/src/daemon/process-message.ts +119 -239
  494. package/src/daemon/server.ts +13 -462
  495. package/src/daemon/shutdown-handlers.ts +2 -5
  496. package/src/daemon/tool-setup-types.ts +51 -0
  497. package/src/daemon/tool-side-effects.ts +126 -108
  498. package/src/daemon/trust-context.ts +13 -0
  499. package/src/daemon/wake-target-adapter.ts +4 -9
  500. package/src/events/domain-events.ts +0 -8
  501. package/src/events/tool-audit-listener.ts +5 -2
  502. package/src/events/tool-domain-event-publisher.ts +0 -10
  503. package/src/events/tool-metrics-listener.ts +0 -17
  504. package/src/events/tool-trace-listener.ts +0 -14
  505. package/src/filing/filing-service.ts +13 -1
  506. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +21 -9
  507. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  508. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  509. package/src/heartbeat/heartbeat-service.ts +303 -54
  510. package/src/home/__tests__/feed-writer.test.ts +0 -4
  511. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  512. package/src/home/__tests__/relationship-state-writer.test.ts +41 -9
  513. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  514. package/src/home/feed-writer.ts +1 -2
  515. package/src/home/post-connect-feed.ts +68 -0
  516. package/src/home/relationship-state-writer.ts +33 -95
  517. package/src/home/suggested-prompts.ts +46 -10
  518. package/src/inbound/public-ingress-urls.ts +32 -34
  519. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  520. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  521. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  522. package/src/ipc/assistant-server.ts +17 -11
  523. package/src/ipc/cli-client.ts +32 -1
  524. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  525. package/src/ipc/routes/route-adapter.ts +1 -1
  526. package/src/ipc/routes/trust-rules.test.ts +0 -95
  527. package/src/ipc/skill-ipc-types.ts +41 -0
  528. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  529. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  530. package/src/ipc/skill-routes/events.ts +12 -23
  531. package/src/ipc/skill-routes/identity.ts +4 -17
  532. package/src/ipc/skill-routes/index.ts +1 -1
  533. package/src/ipc/skill-server.ts +6 -39
  534. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  535. package/src/live-voice/live-voice-metrics.ts +10 -10
  536. package/src/live-voice/protocol.ts +4 -13
  537. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  538. package/src/mcp/manager.ts +0 -5
  539. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  540. package/src/mcp/mcp-auth-state.ts +133 -0
  541. package/src/mcp/mcp-oauth-provider.ts +19 -0
  542. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  543. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  544. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  545. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  546. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  547. package/src/memory/anisotropy.test.ts +247 -0
  548. package/src/memory/anisotropy.ts +443 -0
  549. package/src/memory/app-git-service.ts +0 -32
  550. package/src/memory/app-store.ts +154 -0
  551. package/src/memory/attachments-store.ts +6 -0
  552. package/src/memory/auto-analysis-constants.ts +17 -0
  553. package/src/memory/auto-analysis-guard.ts +5 -15
  554. package/src/memory/canonical-guardian-store.ts +7 -7
  555. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  556. package/src/memory/context-search/agent-protocol.ts +6 -6
  557. package/src/memory/context-search/agent-runner.ts +32 -7
  558. package/src/memory/context-search/sources/memory-v2.ts +590 -0
  559. package/src/memory/context-search/sources/memory.ts +5 -0
  560. package/src/memory/context-search/sources/pkb.ts +10 -1
  561. package/src/memory/context-search/sources/workspace.ts +3 -2
  562. package/src/memory/conversation-crud.ts +30 -5
  563. package/src/memory/conversation-disk-view.ts +1 -5
  564. package/src/memory/conversation-key-store.ts +2 -15
  565. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  566. package/src/memory/db-connection.ts +62 -0
  567. package/src/memory/db-init.ts +18 -0
  568. package/src/memory/embedding-backend.ts +12 -42
  569. package/src/memory/embedding-gemini.ts +0 -2
  570. package/src/memory/embedding-local.ts +6 -6
  571. package/src/memory/embedding-ollama.ts +6 -6
  572. package/src/memory/embedding-openai.ts +6 -6
  573. package/src/memory/embedding-types.ts +21 -0
  574. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -8
  575. package/src/memory/graph/conversation-graph-memory.ts +35 -36
  576. package/src/memory/graph/graph-search.ts +8 -0
  577. package/src/memory/graph/injection.test.ts +2 -2
  578. package/src/memory/graph/injection.ts +1 -1
  579. package/src/memory/graph/retriever.ts +28 -0
  580. package/src/memory/graph/tools.ts +1 -1
  581. package/src/memory/guardian-action-store.ts +0 -83
  582. package/src/memory/guardian-approvals.ts +0 -48
  583. package/src/memory/indexer.ts +1 -15
  584. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  585. package/src/memory/job-utils.ts +0 -6
  586. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  587. package/src/memory/jobs/embed-concept-page.ts +28 -2
  588. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  589. package/src/memory/jobs-store.ts +66 -23
  590. package/src/memory/jobs-worker.ts +114 -79
  591. package/src/memory/llm-request-log-store.ts +0 -41
  592. package/src/memory/llm-usage-store.ts +129 -43
  593. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  594. package/src/memory/migrations/233-document-conversations.ts +54 -0
  595. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  596. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  597. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  598. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  599. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  600. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  601. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  602. package/src/memory/migrations/index.ts +19 -0
  603. package/src/memory/migrations/registry.ts +32 -0
  604. package/src/memory/pkb/pkb-search.ts +7 -0
  605. package/src/memory/qdrant-client.ts +50 -20
  606. package/src/memory/raw-query.ts +2 -68
  607. package/src/memory/schema/conversations.ts +7 -0
  608. package/src/memory/schema/infrastructure.ts +40 -0
  609. package/src/memory/search/semantic.ts +12 -16
  610. package/src/memory/sparse-tokenize.ts +49 -0
  611. package/src/memory/tool-usage-store.ts +2 -0
  612. package/src/memory/usage-buckets.ts +40 -1
  613. package/src/memory/usage-grouped-buckets.ts +127 -0
  614. package/src/memory/v2/__tests__/activation.test.ts +361 -180
  615. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  616. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  617. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  618. package/src/memory/v2/__tests__/injection.test.ts +424 -33
  619. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  620. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  621. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  622. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  623. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  624. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  625. package/src/memory/v2/__tests__/static-context.test.ts +152 -0
  626. package/src/memory/v2/activation.ts +215 -163
  627. package/src/memory/v2/backfill-jobs.ts +15 -100
  628. package/src/memory/v2/consolidation-job.ts +17 -17
  629. package/src/memory/v2/constants.ts +7 -0
  630. package/src/memory/v2/edge-index.ts +191 -0
  631. package/src/memory/v2/injection.ts +241 -84
  632. package/src/memory/v2/migration.ts +57 -64
  633. package/src/memory/v2/now-text.ts +2 -3
  634. package/src/memory/v2/page-store.ts +168 -31
  635. package/src/memory/v2/prompts/consolidation.ts +385 -88
  636. package/src/memory/v2/prompts/sweep.ts +3 -3
  637. package/src/memory/v2/qdrant.ts +99 -1
  638. package/src/memory/v2/sim.ts +126 -16
  639. package/src/memory/v2/skill-qdrant.ts +12 -3
  640. package/src/memory/v2/skill-store.ts +71 -8
  641. package/src/memory/v2/sparse-bm25.ts +245 -0
  642. package/src/memory/v2/static-context.ts +63 -0
  643. package/src/memory/v2/types.ts +10 -20
  644. package/src/memory/validation.ts +0 -11
  645. package/src/messaging/draft-store.ts +0 -6
  646. package/src/messaging/provider-types.ts +8 -0
  647. package/src/messaging/provider.ts +7 -0
  648. package/src/messaging/providers/gmail/client.ts +1 -121
  649. package/src/messaging/providers/gmail/types.ts +0 -49
  650. package/src/messaging/providers/outlook/client.ts +0 -73
  651. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  652. package/src/messaging/providers/slack/adapter.ts +123 -52
  653. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  654. package/src/messaging/providers/slack/backfill.ts +89 -11
  655. package/src/messaging/providers/slack/client.ts +10 -124
  656. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  657. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  658. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  659. package/src/messaging/providers/slack/types.ts +1 -32
  660. package/src/notifications/README.md +10 -10
  661. package/src/notifications/broadcaster.ts +1 -1
  662. package/src/notifications/guardian-question-mode.ts +5 -5
  663. package/src/oauth/connect-orchestrator.ts +4 -0
  664. package/src/oauth/connection-resolver.test.ts +8 -0
  665. package/src/oauth/connection-resolver.ts +8 -16
  666. package/src/oauth/credential-token-resolver.ts +95 -0
  667. package/src/oauth/manual-token-connection.ts +26 -34
  668. package/src/oauth/oauth-store.ts +6 -4
  669. package/src/outbound-proxy/certs.ts +0 -7
  670. package/src/outbound-proxy/index.ts +1 -59
  671. package/src/outbound-proxy/logging.ts +1 -1
  672. package/src/outbound-proxy/policy.ts +6 -5
  673. package/src/outbound-proxy/router.ts +2 -1
  674. package/src/permissions/approval-policy.test.ts +6 -275
  675. package/src/permissions/approval-policy.ts +0 -51
  676. package/src/permissions/approval-provenance.test.ts +184 -0
  677. package/src/permissions/approval-provenance.ts +70 -0
  678. package/src/permissions/checker.test.ts +0 -1
  679. package/src/permissions/checker.ts +7 -18
  680. package/src/permissions/gateway-threshold-reader.ts +6 -1
  681. package/src/permissions/prompter.ts +43 -3
  682. package/src/permissions/secret-prompter.ts +25 -48
  683. package/src/permissions/types.ts +33 -0
  684. package/src/permissions/workspace-policy.ts +0 -5
  685. package/src/platform/sync-identity.ts +0 -8
  686. package/src/plugins/defaults/injectors.ts +69 -2
  687. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  688. package/src/plugins/types.ts +8 -0
  689. package/src/prompts/bootstrap-cleanup.ts +27 -0
  690. package/src/prompts/system-prompt.ts +37 -88
  691. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  692. package/src/prompts/templates/SOUL.md +13 -1
  693. package/src/prompts/update-bulletin-job.ts +2 -0
  694. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  695. package/src/providers/anthropic/client.ts +72 -33
  696. package/src/providers/call-site-routing.ts +42 -3
  697. package/src/providers/gemini/client.ts +18 -2
  698. package/src/providers/managed-proxy/context.ts +0 -5
  699. package/src/providers/model-catalog.ts +105 -19
  700. package/src/providers/openai/chat-completions-provider.ts +6 -0
  701. package/src/providers/openai/responses-provider.ts +7 -1
  702. package/src/providers/provider-send-message.ts +45 -2
  703. package/src/providers/ratelimit.ts +7 -2
  704. package/src/providers/registry.ts +14 -9
  705. package/src/providers/retry.ts +96 -8
  706. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  707. package/src/providers/types.ts +13 -0
  708. package/src/providers/usage-tracking.ts +96 -0
  709. package/src/runtime/AGENTS.md +10 -6
  710. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  711. package/src/runtime/agent-wake.ts +39 -2
  712. package/src/runtime/assistant-event-hub.ts +570 -52
  713. package/src/runtime/assistant-event.ts +2 -6
  714. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  715. package/src/runtime/auth/context.ts +0 -9
  716. package/src/runtime/auth/middleware.ts +1 -97
  717. package/src/runtime/auth/route-policy.ts +30 -9
  718. package/src/runtime/auth/token-service.ts +0 -11
  719. package/src/runtime/btw-sidechain.ts +2 -3
  720. package/src/runtime/channel-approvals.ts +6 -2
  721. package/src/runtime/channel-invite-transport.ts +2 -48
  722. package/src/runtime/channel-invite-transports/email.ts +1 -1
  723. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  724. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  725. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  726. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  727. package/src/runtime/channel-invite-types.ts +54 -0
  728. package/src/runtime/channel-readiness-service.ts +32 -13
  729. package/src/runtime/channel-verification-service.ts +3 -5
  730. package/src/runtime/http-errors.ts +0 -34
  731. package/src/runtime/http-router.ts +6 -3
  732. package/src/runtime/http-server.ts +16 -402
  733. package/src/runtime/http-types.ts +5 -5
  734. package/src/runtime/interactive-ui.ts +0 -1
  735. package/src/runtime/middleware/auth.ts +0 -20
  736. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  737. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  738. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  739. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  740. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  741. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  742. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  743. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  744. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  745. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +296 -80
  746. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  747. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  748. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  749. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  750. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  751. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  752. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  753. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +421 -0
  754. package/src/runtime/migrations/migration-transport.ts +49 -16
  755. package/src/runtime/migrations/migration-wizard.ts +2 -2
  756. package/src/runtime/migrations/origin-mode.ts +40 -0
  757. package/src/runtime/migrations/vbundle-builder.ts +457 -136
  758. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -11
  759. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  760. package/src/runtime/migrations/vbundle-importer.ts +251 -74
  761. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  762. package/src/runtime/migrations/vbundle-streaming-importer.ts +329 -38
  763. package/src/runtime/migrations/vbundle-streaming-validator.ts +203 -28
  764. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  765. package/src/runtime/migrations/vbundle-validator.ts +328 -41
  766. package/src/runtime/pending-interactions.ts +48 -13
  767. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  768. package/src/runtime/routes/__tests__/backup-routes.test.ts +49 -168
  769. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +333 -0
  770. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  771. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  772. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  773. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  774. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  775. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  776. package/src/runtime/routes/acp-routes.test.ts +0 -3
  777. package/src/runtime/routes/acp-routes.ts +3 -7
  778. package/src/runtime/routes/app-management-routes.ts +18 -9
  779. package/src/runtime/routes/approval-interception-types.ts +13 -0
  780. package/src/runtime/routes/approval-routes.ts +55 -14
  781. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  782. package/src/runtime/routes/avatar-routes.ts +3 -5
  783. package/src/runtime/routes/backup-routes.ts +15 -38
  784. package/src/runtime/routes/browser-routes.ts +1 -15
  785. package/src/runtime/routes/btw-routes.ts +14 -37
  786. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  787. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  788. package/src/runtime/routes/channel-route-shared.ts +2 -28
  789. package/src/runtime/routes/client-routes.ts +46 -12
  790. package/src/runtime/routes/consolidation-routes.ts +115 -0
  791. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  792. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  793. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  794. package/src/runtime/routes/conversation-query-routes.ts +156 -9
  795. package/src/runtime/routes/conversation-routes.ts +72 -539
  796. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  797. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  798. package/src/runtime/routes/documents-routes.ts +83 -18
  799. package/src/runtime/routes/errors.ts +19 -4
  800. package/src/runtime/routes/events-routes.ts +68 -94
  801. package/src/runtime/routes/filing-routes.ts +18 -1
  802. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  803. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  804. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  805. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  806. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  807. package/src/runtime/routes/host-bash-routes.ts +37 -6
  808. package/src/runtime/routes/host-browser-routes.ts +96 -25
  809. package/src/runtime/routes/host-cu-routes.ts +48 -13
  810. package/src/runtime/routes/host-file-routes.ts +35 -11
  811. package/src/runtime/routes/host-transfer-routes.ts +73 -37
  812. package/src/runtime/routes/http-adapter.ts +1 -0
  813. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  814. package/src/runtime/routes/identity-routes.ts +93 -49
  815. package/src/runtime/routes/inbound-message-handler.ts +581 -146
  816. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -95
  817. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  818. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  819. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  820. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  821. package/src/runtime/routes/index.ts +12 -0
  822. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  823. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  824. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  825. package/src/runtime/routes/memory-item-routes.ts +10 -12
  826. package/src/runtime/routes/memory-v2-routes.ts +451 -16
  827. package/src/runtime/routes/migration-routes.ts +284 -31
  828. package/src/runtime/routes/playground/guard.ts +1 -1
  829. package/src/runtime/routes/playground/index.ts +0 -2
  830. package/src/runtime/routes/recording-routes.ts +4 -24
  831. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  832. package/src/runtime/routes/schedule-routes.ts +10 -6
  833. package/src/runtime/routes/secret-routes.ts +87 -18
  834. package/src/runtime/routes/settings-routes.ts +29 -28
  835. package/src/runtime/routes/skills-routes.ts +12 -31
  836. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  837. package/src/runtime/routes/task-routes.ts +6 -6
  838. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  839. package/src/runtime/routes/types.ts +4 -4
  840. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  841. package/src/runtime/routes/usage-routes.ts +87 -10
  842. package/src/runtime/routes/user-routes.ts +17 -31
  843. package/src/runtime/routes/work-items-routes.ts +1 -4
  844. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  845. package/src/runtime/services/analyze-conversation.ts +7 -17
  846. package/src/runtime/services/conversation-serializer.ts +2 -4
  847. package/src/runtime/verification-outbound-actions.ts +1 -1
  848. package/src/runtime/verification-rate-limiter.ts +1 -1
  849. package/src/runtime/verification-templates.ts +4 -7
  850. package/src/schedule/integration-status.ts +66 -2
  851. package/src/schedule/recurrence-engine.ts +4 -1
  852. package/src/schedule/retry-backoff.ts +18 -0
  853. package/src/schedule/retry-policy.ts +82 -0
  854. package/src/schedule/schedule-recovery.ts +64 -0
  855. package/src/schedule/schedule-store.ts +106 -18
  856. package/src/schedule/scheduler-types.ts +25 -0
  857. package/src/schedule/scheduler.ts +63 -38
  858. package/src/security/oauth-callback-registry.ts +8 -0
  859. package/src/security/secret-scanner.ts +14 -547
  860. package/src/security/secure-keys.ts +31 -11
  861. package/src/security/token-manager.ts +7 -3
  862. package/src/sequence/analytics.ts +5 -5
  863. package/src/sequence/engine.ts +1 -1
  864. package/src/signals/cancel.ts +16 -25
  865. package/src/signals/conversation-undo.ts +2 -27
  866. package/src/signals/emit-event.ts +1 -2
  867. package/src/signals/user-message.ts +108 -22
  868. package/src/skills/catalog-files.ts +2 -8
  869. package/src/skills/catalog-install.ts +1 -0
  870. package/src/skills/clawhub.ts +2 -2
  871. package/src/skills/include-graph.ts +5 -5
  872. package/src/skills/inline-command-runner.ts +1 -7
  873. package/src/skills/remote-skill-policy.ts +5 -5
  874. package/src/skills/skill-file-provider.ts +1 -1
  875. package/src/skills/skill-file-types.ts +13 -0
  876. package/src/skills/skillssh-audit-types.ts +28 -0
  877. package/src/skills/skillssh-registry.ts +8 -21
  878. package/src/subagent/manager.ts +67 -84
  879. package/src/tasks/task-store.ts +1 -28
  880. package/src/telemetry/types.ts +8 -0
  881. package/src/telemetry/usage-telemetry-reporter.test.ts +59 -15
  882. package/src/telemetry/usage-telemetry-reporter.ts +4 -5
  883. package/src/tools/acp/spawn.test.ts +1 -2
  884. package/src/tools/acp/steer.test.ts +1 -2
  885. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  886. package/src/tools/apps/executors.ts +56 -69
  887. package/src/tools/browser/__tests__/browser-status.test.ts +55 -135
  888. package/src/tools/browser/browser-execution.ts +31 -147
  889. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +145 -70
  890. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  891. package/src/tools/browser/cdp-client/factory.ts +62 -91
  892. package/src/tools/browser/cdp-client/index.ts +1 -27
  893. package/src/tools/computer-use/definitions.ts +42 -20
  894. package/src/tools/executor.ts +46 -31
  895. package/src/tools/host-filesystem/edit.ts +29 -2
  896. package/src/tools/host-filesystem/read.ts +29 -2
  897. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  898. package/src/tools/host-filesystem/transfer.ts +35 -4
  899. package/src/tools/host-filesystem/write.ts +29 -2
  900. package/src/tools/host-terminal/host-shell.ts +62 -3
  901. package/src/tools/network/script-proxy/index.ts +1 -10
  902. package/src/tools/permission-checker.ts +66 -1
  903. package/src/tools/schedule/create.ts +6 -0
  904. package/src/tools/schedule/list.ts +2 -0
  905. package/src/tools/schedule/update.ts +10 -0
  906. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  907. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  908. package/src/tools/skills/load.ts +0 -32
  909. package/src/tools/skills/sandbox-runner.ts +1 -6
  910. package/src/tools/skills/skill-tool-factory.ts +32 -0
  911. package/src/tools/terminal/safe-env.ts +1 -0
  912. package/src/tools/terminal/shell.ts +2 -78
  913. package/src/tools/tool-approval-handler.ts +1 -5
  914. package/src/tools/types.ts +16 -39
  915. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  916. package/src/tts/provider-catalog.ts +1 -1
  917. package/src/usage/actors.ts +2 -1
  918. package/src/usage/attribution.ts +185 -0
  919. package/src/usage/pricing.ts +166 -0
  920. package/src/usage/types.ts +14 -0
  921. package/src/util/json.ts +13 -0
  922. package/src/util/logger.ts +3 -3
  923. package/src/util/pricing.ts +50 -3
  924. package/src/work-items/work-item-runner.ts +15 -42
  925. package/src/workspace/hatched-date.ts +86 -0
  926. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  927. package/src/workspace/migrations/006-services-config.ts +8 -5
  928. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  929. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  930. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  931. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  932. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  933. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  934. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +6 -4
  935. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  936. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  937. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  938. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +54 -0
  939. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  940. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  941. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  942. package/src/workspace/migrations/AGENTS.md +1 -1
  943. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  944. package/src/workspace/migrations/registry.ts +8 -0
  945. package/src/workspace/migrations/utils.ts +21 -0
  946. package/src/workspace/provider-commit-message-generator.ts +3 -3
  947. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -904
  948. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -296
  949. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -431
  950. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  951. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  952. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  953. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  954. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  955. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  956. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  957. package/src/__tests__/twilio-rest.test.ts +0 -34
  958. package/src/backup/__tests__/backup-key.test.ts +0 -152
  959. package/src/backup/__tests__/backup-worker.test.ts +0 -754
  960. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  961. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  962. package/src/backup/backup-key.ts +0 -137
  963. package/src/backup/backup-worker.ts +0 -438
  964. package/src/backup/offsite-writer.ts +0 -222
  965. package/src/backup/stream-crypt.ts +0 -263
  966. package/src/context/__tests__/microcompact.test.ts +0 -805
  967. package/src/context/microcompact.ts +0 -443
  968. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  969. package/src/daemon/message-types/pairing.ts +0 -58
  970. package/src/events/tool-notification-listener.ts +0 -17
  971. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  972. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  973. package/src/memory/v2/edges.ts +0 -217
  974. package/src/outbound-proxy/config.ts +0 -94
  975. package/src/outbound-proxy/health.ts +0 -62
  976. package/src/outbound-proxy/types.ts +0 -150
  977. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  978. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  979. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  980. package/src/runtime/capability-tokens.ts +0 -190
  981. package/src/runtime/chrome-extension-registry.ts +0 -368
  982. package/src/runtime/client-registry.ts +0 -254
  983. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  984. package/src/signals/mcp-reload.ts +0 -18
  985. package/src/tools/secret-detection-handler.ts +0 -269
  986. package/src/tools/terminal/backends/native.ts +0 -327
  987. package/src/tools/terminal/backends/types.ts +0 -37
  988. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  989. package/src/tools/terminal/sandbox.ts +0 -40
@@ -7,8 +7,9 @@
7
7
  * - `computeOwnActivation`: applies `A_o = d·prev + c_user·simU + c_a·simA +
8
8
  * c_now·simN`; clamps to [0,1]; orphan in candidates returns 0 when no
9
9
  * sim hits.
10
- * - `spreadActivation`: orphan yields A == A_o; symmetric two-node ring is
11
- * symmetric; hops=2 reaches second-degree but not third; bounded in [0,1].
10
+ * - `spreadActivation`: orphan yields A == A_o; spread walks incoming edges
11
+ * only (A→B boosts B but not A); hops=2 reaches second-degree predecessors
12
+ * but not third; bounded in [0,1].
12
13
  * - `selectInjections`: top-K rank, deterministic tie-break, delta against
13
14
  * `everInjected`.
14
15
  *
@@ -139,14 +140,14 @@ mock.module("@qdrant/js-client-rest", () => ({
139
140
 
140
141
  // Static `import type` is fine — types erase, so they don't run module-init
141
142
  // code that would race the mocks above.
142
- import type { ActivationState, EdgesIndex } from "../types.js";
143
+ import type { EdgeIndex } from "../edge-index.js";
144
+ import type { ActivationState } from "../types.js";
143
145
 
144
146
  const {
145
147
  computeOwnActivation,
146
148
  computeSkillActivation,
147
149
  selectCandidates,
148
150
  selectInjections,
149
- selectSkillCandidates,
150
151
  selectSkillInjections,
151
152
  spreadActivation,
152
153
  } = await import("../activation.js");
@@ -191,6 +192,7 @@ function makeConfig(
191
192
  epsilon: number;
192
193
  dense_weight: number;
193
194
  sparse_weight: number;
195
+ ann_candidate_limit: number | null;
194
196
  }> = {},
195
197
  ): AssistantConfig {
196
198
  return {
@@ -203,6 +205,7 @@ function makeConfig(
203
205
  epsilon: 0.01,
204
206
  dense_weight: 1.0,
205
207
  sparse_weight: 0.0,
208
+ ann_candidate_limit: null,
206
209
  ...overrides,
207
210
  },
208
211
  },
@@ -241,7 +244,9 @@ describe("selectCandidates", () => {
241
244
  nowText: "",
242
245
  config: makeConfig(),
243
246
  });
244
- expect(out.size).toBe(0);
247
+ expect(out.candidates.size).toBe(0);
248
+ expect(out.fromPrior.size).toBe(0);
249
+ expect(out.fromAnn.size).toBe(0);
245
250
  // No turn text → no embedding call, no Qdrant call.
246
251
  expect(state.embedCalls).toHaveLength(0);
247
252
  expect(state.queryCalls).toHaveLength(0);
@@ -266,7 +271,9 @@ describe("selectCandidates", () => {
266
271
  nowText: "",
267
272
  config: makeConfig({ epsilon: 0.01 }),
268
273
  });
269
- expect(out).toEqual(new Set(["alice-vscode", "carol-jazz"]));
274
+ expect(out.candidates).toEqual(new Set(["alice-vscode", "carol-jazz"]));
275
+ expect(out.fromPrior).toEqual(new Set(["alice-vscode", "carol-jazz"]));
276
+ expect(out.fromAnn).toEqual(new Set());
270
277
  });
271
278
 
272
279
  test("unions ANN hits with prior-state survivors", async () => {
@@ -289,10 +296,60 @@ describe("selectCandidates", () => {
289
296
  nowText: "",
290
297
  config: makeConfig(),
291
298
  });
292
- expect(out).toEqual(new Set(["alice-vscode", "delta-recipe"]));
299
+ expect(out.candidates).toEqual(new Set(["alice-vscode", "delta-recipe"]));
300
+ expect(out.fromPrior).toEqual(new Set(["alice-vscode"]));
301
+ expect(out.fromAnn).toEqual(new Set(["alice-vscode", "delta-recipe"]));
293
302
  });
294
303
 
295
- test("ANN top-K limit equals 50 and runs without slug restriction", async () => {
304
+ test("tags overlap: a slug in both sources lands in fromPrior ∩ fromAnn", async () => {
305
+ const priorState: ActivationState = {
306
+ messageId: "msg-1",
307
+ state: {
308
+ "alice-vscode": 0.5, // in prior AND in ANN
309
+ "carol-jazz": 0.3, // prior only
310
+ },
311
+ everInjected: [],
312
+ currentTurn: 1,
313
+ updatedAt: 1,
314
+ };
315
+ stageHybridResponse([
316
+ { slug: "alice-vscode", denseScore: 0.7, sparseScore: 1 }, // overlap
317
+ { slug: "delta-recipe", denseScore: 0.4, sparseScore: 1 }, // ANN only
318
+ ]);
319
+
320
+ const out = await selectCandidates({
321
+ priorState,
322
+ userText: "hello",
323
+ assistantText: "",
324
+ nowText: "",
325
+ config: makeConfig(),
326
+ });
327
+
328
+ // Overlap: alice-vscode appears in both source sets.
329
+ const overlap = new Set(
330
+ [...out.fromPrior].filter((slug) => out.fromAnn.has(slug)),
331
+ );
332
+ expect(overlap).toEqual(new Set(["alice-vscode"]));
333
+
334
+ // candidates = fromPrior ∪ fromAnn.
335
+ const union = new Set<string>([...out.fromPrior, ...out.fromAnn]);
336
+ expect(out.candidates).toEqual(union);
337
+ expect(out.candidates).toEqual(
338
+ new Set(["alice-vscode", "carol-jazz", "delta-recipe"]),
339
+ );
340
+
341
+ // Source-set membership matches each slug's actual provenance.
342
+ expect(out.fromPrior).toEqual(new Set(["alice-vscode", "carol-jazz"]));
343
+ expect(out.fromAnn).toEqual(new Set(["alice-vscode", "delta-recipe"]));
344
+ });
345
+
346
+ test("ANN candidate query honors `config.memory.v2.ann_candidate_limit` and runs without slug restriction", async () => {
347
+ // Default `ann_candidate_limit: null` → unlimited, so the unlimited
348
+ // sentinel (1_000_000 — a Qdrant-safe stand-in for "every page") is
349
+ // passed to both channels. We don't pin to `MAX_SAFE_INTEGER` here:
350
+ // Qdrant's sparse `SearchContext` pre-allocates `limit * 16` bytes,
351
+ // and `MAX_SAFE_INTEGER` triggers a ~144 PB alloc that SIGABRTs the
352
+ // Qdrant process — so the constant deliberately undercuts it.
296
353
  stageHybridResponse([{ slug: "alpha", denseScore: 0.5, sparseScore: 1 }]);
297
354
  await selectCandidates({
298
355
  priorState: null,
@@ -301,10 +358,25 @@ describe("selectCandidates", () => {
301
358
  nowText: "",
302
359
  config: makeConfig(),
303
360
  });
304
- // Both channels (dense + sparse) ran with limit=50 and no filter.
305
361
  expect(state.queryCalls).toHaveLength(2);
306
362
  for (const call of state.queryCalls) {
307
- expect(call.limit).toBe(50);
363
+ expect(call.limit).toBe(1_000_000);
364
+ expect(call.filter).toBeUndefined();
365
+ }
366
+
367
+ // Explicit override flows through both channels verbatim.
368
+ state.queryCalls.length = 0;
369
+ stageHybridResponse([{ slug: "beta", denseScore: 0.5, sparseScore: 1 }]);
370
+ await selectCandidates({
371
+ priorState: null,
372
+ userText: "hello",
373
+ assistantText: "",
374
+ nowText: "",
375
+ config: makeConfig({ ann_candidate_limit: 25 }),
376
+ });
377
+ expect(state.queryCalls).toHaveLength(2);
378
+ for (const call of state.queryCalls) {
379
+ expect(call.limit).toBe(25);
308
380
  expect(call.filter).toBeUndefined();
309
381
  }
310
382
  });
@@ -324,7 +396,8 @@ describe("computeOwnActivation", () => {
324
396
  nowText: "now",
325
397
  config: makeConfig(),
326
398
  });
327
- expect(out.size).toBe(0);
399
+ expect(out.activation.size).toBe(0);
400
+ expect(out.breakdown.size).toBe(0);
328
401
  expect(state.embedCalls).toHaveLength(0);
329
402
  expect(state.queryCalls).toHaveLength(0);
330
403
  });
@@ -357,7 +430,7 @@ describe("computeOwnActivation", () => {
357
430
  }),
358
431
  });
359
432
  // Expected: 0.3*0.6 + 0.3*0.5 + 0.2*0.4 + 0.2*0.2 = 0.18+0.15+0.08+0.04 = 0.45
360
- expect(out.get("alice")).toBeCloseTo(0.45, 6);
433
+ expect(out.activation.get("alice")).toBeCloseTo(0.45, 6);
361
434
  });
362
435
 
363
436
  test("clamps over-1.0 results down to [0, 1]", async () => {
@@ -388,7 +461,7 @@ describe("computeOwnActivation", () => {
388
461
  c_now: 0.5,
389
462
  }),
390
463
  });
391
- expect(out.get("alice")).toBe(1);
464
+ expect(out.activation.get("alice")).toBe(1);
392
465
  });
393
466
 
394
467
  test("missing prior state defaults `prev` to 0", async () => {
@@ -410,7 +483,7 @@ describe("computeOwnActivation", () => {
410
483
  }),
411
484
  });
412
485
  // 0.3*0 + 0.3*1 + 0.2*0 + 0.2*0 = 0.3
413
- expect(out.get("fresh")).toBeCloseTo(0.3, 6);
486
+ expect(out.activation.get("fresh")).toBeCloseTo(0.3, 6);
414
487
  });
415
488
 
416
489
  test("candidate with no sim hits resolves to 0", async () => {
@@ -426,7 +499,60 @@ describe("computeOwnActivation", () => {
426
499
  nowText: "n",
427
500
  config: makeConfig(),
428
501
  });
429
- expect(out.get("ghost")).toBe(0);
502
+ expect(out.activation.get("ghost")).toBe(0);
503
+ });
504
+
505
+ test("breakdown captures `d * prev` and the raw sims for each candidate", async () => {
506
+ stageHybridResponse([{ slug: "alice", denseScore: 0.5 }]); // simU
507
+ stageHybridResponse([{ slug: "alice", denseScore: 0.4 }]); // simA
508
+ stageHybridResponse([{ slug: "alice", denseScore: 0.2 }]); // simN
509
+
510
+ const priorState: ActivationState = {
511
+ messageId: "msg-1",
512
+ state: { alice: 0.6 },
513
+ everInjected: [],
514
+ currentTurn: 1,
515
+ updatedAt: 1,
516
+ };
517
+ const d = 0.3;
518
+ const out = await computeOwnActivation({
519
+ candidates: new Set(["alice"]),
520
+ priorState,
521
+ userText: "u",
522
+ assistantText: "a",
523
+ nowText: "n",
524
+ config: makeConfig({
525
+ d,
526
+ c_user: 0.3,
527
+ c_assistant: 0.2,
528
+ c_now: 0.2,
529
+ }),
530
+ });
531
+ const breakdown = out.breakdown.get("alice");
532
+ expect(breakdown).toBeDefined();
533
+ // priorContribution is `d * prev`, not the weighted sim term.
534
+ expect(breakdown?.priorContribution).toBeCloseTo(d * 0.6, 6);
535
+ // Raw sims, captured before c_user / c_assistant / c_now weighting.
536
+ expect(breakdown?.simUser).toBeCloseTo(0.5, 6);
537
+ expect(breakdown?.simAssistant).toBeCloseTo(0.4, 6);
538
+ expect(breakdown?.simNow).toBeCloseTo(0.2, 6);
539
+ });
540
+
541
+ test("breakdown defaults priorContribution to 0 when priorState is null", async () => {
542
+ stageHybridResponse([{ slug: "fresh", denseScore: 0.5 }]);
543
+ stageHybridResponse([{ slug: "fresh", denseScore: 0.5 }]);
544
+ stageHybridResponse([{ slug: "fresh", denseScore: 0.5 }]);
545
+
546
+ const out = await computeOwnActivation({
547
+ candidates: new Set(["fresh"]),
548
+ priorState: null,
549
+ userText: "u",
550
+ assistantText: "a",
551
+ nowText: "n",
552
+ config: makeConfig({ d: 0.9 }),
553
+ });
554
+ // No prior state → prev=0 → priorContribution=0 regardless of `d`.
555
+ expect(out.breakdown.get("fresh")?.priorContribution).toBe(0);
430
556
  });
431
557
  });
432
558
 
@@ -434,143 +560,258 @@ describe("computeOwnActivation", () => {
434
560
  // spreadActivation
435
561
  // ---------------------------------------------------------------------------
436
562
 
563
+ /**
564
+ * Build a directed `EdgeIndex` from a flat list of `[from, to]` pairs. Each
565
+ * entry is interpreted as a directed edge `from → to`; self-loops are dropped.
566
+ */
567
+ function buildEdgeIndex(edges: Array<[string, string]>): EdgeIndex {
568
+ const outgoing = new Map<string, Set<string>>();
569
+ const incoming = new Map<string, Set<string>>();
570
+ for (const [from, to] of edges) {
571
+ if (from === to) continue;
572
+ let outSet = outgoing.get(from);
573
+ if (!outSet) {
574
+ outSet = new Set<string>();
575
+ outgoing.set(from, outSet);
576
+ }
577
+ outSet.add(to);
578
+ let inSet = incoming.get(to);
579
+ if (!inSet) {
580
+ inSet = new Set<string>();
581
+ incoming.set(to, inSet);
582
+ }
583
+ inSet.add(from);
584
+ }
585
+ return { outgoing, incoming };
586
+ }
587
+
437
588
  describe("spreadActivation", () => {
438
589
  test("orphan node yields A == A_o", () => {
439
- const edges: EdgesIndex = { version: 1, edges: [] };
590
+ const edges = buildEdgeIndex([]);
440
591
  const own = new Map([["alice", 0.7]]);
441
592
  const out = spreadActivation(own, edges, 0.5, 2);
442
- expect(out.get("alice")).toBeCloseTo(0.7, 6);
593
+ expect(out.final.get("alice")).toBeCloseTo(0.7, 6);
443
594
  });
444
595
 
445
- test("symmetric two-node ring yields symmetric activation", () => {
446
- const edges: EdgesIndex = {
447
- version: 1,
448
- edges: [["alice", "bob"]],
449
- };
596
+ test("directed edge boosts only the target, not the source", () => {
597
+ // Edge alice→bob: alice activation flows into bob; bob does NOT push back
598
+ // into alice. alice (a pure source under this graph) keeps its own value.
599
+ const edges = buildEdgeIndex([["alice", "bob"]]);
450
600
  const own = new Map([
451
601
  ["alice", 0.6],
452
- ["bob", 0.6],
602
+ ["bob", 0.0],
453
603
  ]);
454
604
  const out = spreadActivation(own, edges, 0.5, 2);
455
- // Both nodes have one neighbor, equal own-activation equal final A.
456
- expect(out.get("alice")).toBeCloseTo(out.get("bob") ?? 0, 6);
457
- // Numerator: 0.6 + 0.5*0.6 = 0.9. Denominator: 1 + 0.5*1 = 1.5. A = 0.6.
458
- expect(out.get("alice")).toBeCloseTo(0.6, 6);
605
+ // alice has no incoming edges → final == own.
606
+ expect(out.final.get("alice")).toBeCloseTo(0.6, 6);
607
+ // bob's incoming = {alice}: numerator = 0 + 0.5*0.6 = 0.3, denom = 1.5.
608
+ expect(out.final.get("bob")).toBeCloseTo(0.3 / 1.5, 6);
459
609
  });
460
610
 
461
- test("asymmetric two-node ring picks up neighbor activation", () => {
462
- const edges: EdgesIndex = {
463
- version: 1,
464
- edges: [["alice", "bob"]],
465
- };
611
+ test("two-cycle (A→B and B→A) lets activation flow both ways", () => {
612
+ // With both directions present, each node is the other's predecessor.
613
+ const edges = buildEdgeIndex([
614
+ ["alice", "bob"],
615
+ ["bob", "alice"],
616
+ ]);
466
617
  const own = new Map([
467
618
  ["alice", 0.0],
468
619
  ["bob", 0.8],
469
620
  ]);
470
621
  const out = spreadActivation(own, edges, 0.5, 2);
471
- // alice: numerator = 0 + 0.5*0.8 = 0.4. denominator = 1 + 0.5 = 1.5.
472
- // A = 0.2666...
473
- expect(out.get("alice")).toBeCloseTo(0.4 / 1.5, 6);
474
- // bob: numerator = 0.8 + 0.5*0 = 0.8. denominator = 1.5. A = 0.5333...
475
- expect(out.get("bob")).toBeCloseTo(0.8 / 1.5, 6);
476
- });
477
-
478
- test("hops=2 reaches second-degree neighbors but stops there", () => {
479
- // Path graph: alice -- bob -- carol -- delta
480
- // From alice's perspective: bob is 1-hop, carol is 2-hop, delta is 3-hop.
481
- const edges: EdgesIndex = {
482
- version: 1,
483
- edges: [
484
- ["alice", "bob"],
485
- ["bob", "carol"],
486
- ["carol", "delta"],
487
- ],
488
- };
622
+ // alice: incoming {bob}=0.8 → numerator = 0 + 0.5*0.8 = 0.4, denom = 1.5.
623
+ expect(out.final.get("alice")).toBeCloseTo(0.4 / 1.5, 6);
624
+ // bob: incoming {alice}=0.0 → numerator = 0.8 + 0 = 0.8, denom = 1.5.
625
+ expect(out.final.get("bob")).toBeCloseTo(0.8 / 1.5, 6);
626
+ });
627
+
628
+ test("pure source (high outgoing, zero incoming) collapses to final == own", () => {
629
+ // alice bob carol; alice has no incoming edges.
630
+ const edges = buildEdgeIndex([
631
+ ["alice", "bob"],
632
+ ["bob", "carol"],
633
+ ]);
489
634
  const own = new Map([
490
- ["alice", 0.0],
635
+ ["alice", 0.5],
491
636
  ["bob", 0.0],
492
- ["carol", 1.0], // 2 hops from alice
493
- ["delta", 1.0], // 3 hops from alice — must NOT contribute
637
+ ["carol", 0.0],
494
638
  ]);
495
639
  const out = spreadActivation(own, edges, 0.5, 2);
496
- // alice: 1-hop = {bob} (0), 2-hop = {carol} (1.0).
640
+ expect(out.final.get("alice")).toBeCloseTo(0.5, 6);
641
+ });
642
+
643
+ test("hops=2 reaches second-degree predecessors but stops there", () => {
644
+ // Directed path: alice → bob → carol → delta
645
+ // From delta's perspective: carol is 1-hop predecessor, bob is 2-hop,
646
+ // alice is 3-hop. Activation on bob (2-hop) reaches delta; activation on
647
+ // alice (3-hop) does NOT.
648
+ const edges = buildEdgeIndex([
649
+ ["alice", "bob"],
650
+ ["bob", "carol"],
651
+ ["carol", "delta"],
652
+ ]);
653
+ const own = new Map([
654
+ ["alice", 1.0], // 3-hop predecessor of delta — must NOT contribute
655
+ ["bob", 1.0], // 2-hop predecessor of delta
656
+ ["carol", 0.0],
657
+ ["delta", 0.0],
658
+ ]);
659
+ const out = spreadActivation(own, edges, 0.5, 2);
660
+ // delta: 1-hop {carol}=0, 2-hop {bob}=1.0.
497
661
  // numerator = 0 + 0.5*0 + 0.25*1.0 = 0.25
498
662
  // denominator = 1 + 0.5*1 + 0.25*1 = 1.75
499
663
  // A = 0.25 / 1.75 ≈ 0.142857
500
- expect(out.get("alice")).toBeCloseTo(0.25 / 1.75, 6);
664
+ expect(out.final.get("delta")).toBeCloseTo(0.25 / 1.75, 6);
501
665
  });
502
666
 
503
667
  test("output is bounded in [0, 1] for arbitrary inputs", () => {
504
- const edges: EdgesIndex = {
505
- version: 1,
506
- edges: [
507
- ["alice", "bob"],
508
- ["bob", "carol"],
509
- ["alice", "carol"],
510
- ],
511
- };
668
+ const edges = buildEdgeIndex([
669
+ ["alice", "bob"],
670
+ ["bob", "carol"],
671
+ ["alice", "carol"],
672
+ ]);
512
673
  const own = new Map([
513
674
  ["alice", 1.0],
514
675
  ["bob", 1.0],
515
676
  ["carol", 1.0],
516
677
  ]);
517
678
  const out = spreadActivation(own, edges, 0.99, 2);
518
- for (const [, value] of out) {
679
+ for (const [, value] of out.final) {
519
680
  expect(value).toBeGreaterThanOrEqual(0);
520
681
  expect(value).toBeLessThanOrEqual(1);
521
682
  }
522
683
  });
523
684
 
524
685
  test("hops=0 collapses to A == A_o", () => {
525
- const edges: EdgesIndex = {
526
- version: 1,
527
- edges: [["alice", "bob"]],
528
- };
686
+ const edges = buildEdgeIndex([["alice", "bob"]]);
529
687
  const own = new Map([
530
688
  ["alice", 0.4],
531
689
  ["bob", 0.9],
532
690
  ]);
533
691
  const out = spreadActivation(own, edges, 0.5, 0);
534
- expect(out.get("alice")).toBeCloseTo(0.4, 6);
535
- expect(out.get("bob")).toBeCloseTo(0.9, 6);
692
+ expect(out.final.get("alice")).toBeCloseTo(0.4, 6);
693
+ expect(out.final.get("bob")).toBeCloseTo(0.9, 6);
536
694
  });
537
695
 
538
696
  test("k=0 collapses to A == A_o", () => {
539
- const edges: EdgesIndex = {
540
- version: 1,
541
- edges: [["alice", "bob"]],
542
- };
697
+ const edges = buildEdgeIndex([["alice", "bob"]]);
543
698
  const own = new Map([
544
699
  ["alice", 0.4],
545
700
  ["bob", 0.9],
546
701
  ]);
547
702
  const out = spreadActivation(own, edges, 0, 5);
548
- expect(out.get("alice")).toBeCloseTo(0.4, 6);
549
- expect(out.get("bob")).toBeCloseTo(0.9, 6);
703
+ expect(out.final.get("alice")).toBeCloseTo(0.4, 6);
704
+ expect(out.final.get("bob")).toBeCloseTo(0.9, 6);
550
705
  });
551
706
 
552
- test("missing neighbor activation contributes 0 to the numerator", () => {
553
- // alice and bob are connected, but bob is not in `ownActivation` — so
554
- // bob's contribution is 0, while the denominator still counts the
555
- // structural neighbor.
556
- const edges: EdgesIndex = {
557
- version: 1,
558
- edges: [["alice", "bob"]],
559
- };
560
- const own = new Map([["alice", 0.6]]);
707
+ test("predecessors not in the candidate set are dropped from both numerator and denominator", () => {
708
+ // Edge alice→bob: bob has structural predecessor alice, but alice is not
709
+ // in `ownActivation`. With the new formula she contributes nothing
710
+ // hop1 has no active predecessors so the whole hop drops out of both
711
+ // sides of the ratio. Bob therefore stays at his own activation.
712
+ const edges = buildEdgeIndex([["alice", "bob"]]);
713
+ const own = new Map([["bob", 0.6]]);
714
+ const out = spreadActivation(own, edges, 0.5, 2);
715
+ expect(out.final.get("bob")).toBeCloseTo(0.6, 6);
716
+ });
717
+
718
+ test("L_2 norm over multiple active predecessors rewards strong outliers more than avg would", () => {
719
+ // bob has 4 predecessors in the candidate set: one strong, three weak.
720
+ // L_2 = √((0.8² + 0.1² + 0.1² + 0.1²) / 4) = √(0.1675) ≈ 0.40927
721
+ // Plain avg of the same set = 0.275, so L_2 lifts bob more than avg
722
+ // would — the design goal of preferring quality over quantity.
723
+ const edges = buildEdgeIndex([
724
+ ["a1", "bob"],
725
+ ["a2", "bob"],
726
+ ["a3", "bob"],
727
+ ["a4", "bob"],
728
+ ]);
729
+ const own = new Map([
730
+ ["a1", 0.8],
731
+ ["a2", 0.1],
732
+ ["a3", 0.1],
733
+ ["a4", 0.1],
734
+ ["bob", 0.0],
735
+ ]);
561
736
  const out = spreadActivation(own, edges, 0.5, 2);
562
- // numerator = 0.6 + 0.5*0 = 0.6. denominator = 1 + 0.5*1 = 1.5.
563
- expect(out.get("alice")).toBeCloseTo(0.4, 6);
737
+ const rms = Math.sqrt((0.8 * 0.8 + 3 * 0.1 * 0.1) / 4);
738
+ // numerator = 0 + 0.5 · rms
739
+ // denominator = 1 + 0.5
740
+ expect(out.final.get("bob")).toBeCloseTo((0.5 * rms) / 1.5, 6);
741
+ });
742
+
743
+ test("high-in-degree hub with mostly-inactive predecessors stays near A_o", () => {
744
+ // 100 structural predecessors point at hub; only one (`pred0`) is in
745
+ // the candidate set. The old formula would crush hub by the structural
746
+ // count (denominator ≈ 51); the new formula folds the empty bulk out
747
+ // and the L_2 averages over the single active predecessor only.
748
+ const rawEdges: Array<[string, string]> = [];
749
+ for (let i = 0; i < 100; i++) rawEdges.push([`pred${i}`, "hub"]);
750
+ const edges = buildEdgeIndex(rawEdges);
751
+ const own = new Map([
752
+ ["hub", 0.6],
753
+ ["pred0", 0.5],
754
+ ]);
755
+ const out = spreadActivation(own, edges, 0.5, 2);
756
+ // hop1 active = {pred0}, L_2([0.5]) = 0.5.
757
+ // numerator = 0.6 + 0.5 · 0.5 = 0.85
758
+ // denominator = 1 + 0.5 = 1.5
759
+ expect(out.final.get("hub")).toBeCloseTo(0.85 / 1.5, 6);
564
760
  });
565
761
 
566
762
  test("empty own-activation map returns empty result", () => {
567
763
  const out = spreadActivation(
568
764
  new Map(),
569
- { version: 1, edges: [["a", "b"]] },
765
+ buildEdgeIndex([["a", "b"]]),
570
766
  0.5,
571
767
  2,
572
768
  );
573
- expect(out.size).toBe(0);
769
+ expect(out.final.size).toBe(0);
770
+ expect(out.contribution.size).toBe(0);
771
+ });
772
+
773
+ test("contribution equals final - own for each slug", () => {
774
+ // Two-cycle: A→B and B→A so both nodes have predecessors and the spread
775
+ // moves each off its own value in opposite directions.
776
+ const edges = buildEdgeIndex([
777
+ ["alice", "bob"],
778
+ ["bob", "alice"],
779
+ ]);
780
+ const own = new Map([
781
+ ["alice", 0.0],
782
+ ["bob", 0.8],
783
+ ]);
784
+ const out = spreadActivation(own, edges, 0.5, 2);
785
+ for (const [slug, finalValue] of out.final) {
786
+ const ownValue = own.get(slug) ?? 0;
787
+ expect(out.contribution.get(slug)).toBeCloseTo(finalValue - ownValue, 6);
788
+ }
789
+ // alice gained spread (predecessor bob=0.8); bob lost some (predecessor
790
+ // alice=0 dilutes its own 0.8).
791
+ expect(out.contribution.get("alice")).toBeGreaterThan(0);
792
+ expect(out.contribution.get("bob")).toBeLessThan(0);
793
+ });
794
+
795
+ test("contribution is 0 for every slug when hops == 0", () => {
796
+ const edges = buildEdgeIndex([["alice", "bob"]]);
797
+ const own = new Map([
798
+ ["alice", 0.4],
799
+ ["bob", 0.9],
800
+ ]);
801
+ const out = spreadActivation(own, edges, 0.5, 0);
802
+ expect(out.contribution.get("alice")).toBe(0);
803
+ expect(out.contribution.get("bob")).toBe(0);
804
+ });
805
+
806
+ test("contribution is 0 for every slug when k == 0", () => {
807
+ const edges = buildEdgeIndex([["alice", "bob"]]);
808
+ const own = new Map([
809
+ ["alice", 0.4],
810
+ ["bob", 0.9],
811
+ ]);
812
+ const out = spreadActivation(own, edges, 0, 5);
813
+ expect(out.contribution.get("alice")).toBe(0);
814
+ expect(out.contribution.get("bob")).toBe(0);
574
815
  });
575
816
  });
576
817
 
@@ -654,7 +895,7 @@ describe("selectInjections", () => {
654
895
  });
655
896
 
656
897
  // ---------------------------------------------------------------------------
657
- // selectSkillCandidates
898
+ // computeSkillActivation
658
899
  // ---------------------------------------------------------------------------
659
900
 
660
901
  /** Stage a single hybrid response on the skills queues (payload key = `id`). */
@@ -673,90 +914,6 @@ function stageSkillHybridResponse(
673
914
  });
674
915
  }
675
916
 
676
- describe("selectSkillCandidates", () => {
677
- test("returns hit ids from the skills collection", async () => {
678
- stageSkillHybridResponse([
679
- { id: "example-skill-a", denseScore: 0.5, sparseScore: 1 },
680
- { id: "example-skill-b", denseScore: 0.3, sparseScore: 1 },
681
- ]);
682
- const out = await selectSkillCandidates({
683
- userText: "user said hello",
684
- assistantText: "",
685
- nowText: "",
686
- config: makeConfig(),
687
- topK: 10,
688
- });
689
- expect(out).toEqual(new Set(["example-skill-a", "example-skill-b"]));
690
- });
691
-
692
- test("empty turn text short-circuits without backend calls", async () => {
693
- const out = await selectSkillCandidates({
694
- userText: "",
695
- assistantText: "",
696
- nowText: "",
697
- config: makeConfig(),
698
- topK: 10,
699
- });
700
- expect(out.size).toBe(0);
701
- expect(state.embedCalls).toHaveLength(0);
702
- expect(state.queryCalls).toHaveLength(0);
703
- });
704
-
705
- test("topK=0 short-circuits without backend calls", async () => {
706
- const out = await selectSkillCandidates({
707
- userText: "anything",
708
- assistantText: "anything",
709
- nowText: "anything",
710
- config: makeConfig(),
711
- topK: 0,
712
- });
713
- expect(out.size).toBe(0);
714
- expect(state.embedCalls).toHaveLength(0);
715
- expect(state.queryCalls).toHaveLength(0);
716
- });
717
-
718
- test("forwards topK and queries the skills collection unrestricted", async () => {
719
- stageSkillHybridResponse([
720
- { id: "example-skill-a", denseScore: 0.5, sparseScore: 1 },
721
- ]);
722
- await selectSkillCandidates({
723
- userText: "hello",
724
- assistantText: "",
725
- nowText: "",
726
- config: makeConfig(),
727
- topK: 7,
728
- });
729
- // Both channels (dense + sparse) ran with limit=7 and no slug/id filter,
730
- // against the dedicated skills collection.
731
- expect(state.queryCalls).toHaveLength(2);
732
- for (const call of state.queryCalls) {
733
- expect(call.collection).toBe("memory_v2_skills");
734
- expect(call.limit).toBe(7);
735
- expect(call.filter).toBeUndefined();
736
- }
737
- });
738
-
739
- test("embeds concatenated turn text exactly once", async () => {
740
- stageSkillHybridResponse([]);
741
- await selectSkillCandidates({
742
- userText: "user line",
743
- assistantText: "assistant line",
744
- nowText: "now line",
745
- config: makeConfig(),
746
- topK: 5,
747
- });
748
- expect(state.embedCalls).toHaveLength(1);
749
- expect(state.embedCalls[0].inputs).toEqual([
750
- "user line\nassistant line\nnow line",
751
- ]);
752
- expect(state.sparseCalls).toEqual(["user line\nassistant line\nnow line"]);
753
- });
754
- });
755
-
756
- // ---------------------------------------------------------------------------
757
- // computeSkillActivation
758
- // ---------------------------------------------------------------------------
759
-
760
917
  describe("computeSkillActivation", () => {
761
918
  test("empty candidates short-circuits without backend calls", async () => {
762
919
  const out = await computeSkillActivation({
@@ -766,7 +923,8 @@ describe("computeSkillActivation", () => {
766
923
  nowText: "n",
767
924
  config: makeConfig(),
768
925
  });
769
- expect(out.size).toBe(0);
926
+ expect(out.activation.size).toBe(0);
927
+ expect(out.breakdown.size).toBe(0);
770
928
  expect(state.embedCalls).toHaveLength(0);
771
929
  expect(state.queryCalls).toHaveLength(0);
772
930
  });
@@ -790,7 +948,7 @@ describe("computeSkillActivation", () => {
790
948
  }),
791
949
  });
792
950
  // No `d · prev` term: 0.3*0.5 + 0.2*0.4 + 0.2*0.2 = 0.15 + 0.08 + 0.04 = 0.27
793
- expect(out.get("example-skill-a")).toBeCloseTo(0.27, 6);
951
+ expect(out.activation.get("example-skill-a")).toBeCloseTo(0.27, 6);
794
952
  });
795
953
 
796
954
  test("output excludes any decay term — d coefficient is unused", async () => {
@@ -824,8 +982,8 @@ describe("computeSkillActivation", () => {
824
982
  });
825
983
 
826
984
  // Both equal `0.3*0.4 + 0.2*0.4 + 0.2*0.4 = 0.28` — d is ignored.
827
- expect(withHighD.get("alpha")).toBeCloseTo(0.28, 6);
828
- expect(withZeroD.get("alpha")).toBeCloseTo(0.28, 6);
985
+ expect(withHighD.activation.get("alpha")).toBeCloseTo(0.28, 6);
986
+ expect(withZeroD.activation.get("alpha")).toBeCloseTo(0.28, 6);
829
987
  });
830
988
 
831
989
  test("clamps over-1.0 results down to [0, 1]", async () => {
@@ -846,7 +1004,7 @@ describe("computeSkillActivation", () => {
846
1004
  c_now: 0.5,
847
1005
  }),
848
1006
  });
849
- expect(out.get("loud-skill")).toBe(1);
1007
+ expect(out.activation.get("loud-skill")).toBe(1);
850
1008
  });
851
1009
 
852
1010
  test("candidate with no sim hits resolves to 0", async () => {
@@ -861,7 +1019,30 @@ describe("computeSkillActivation", () => {
861
1019
  nowText: "n",
862
1020
  config: makeConfig(),
863
1021
  });
864
- expect(out.get("ghost-skill")).toBe(0);
1022
+ expect(out.activation.get("ghost-skill")).toBe(0);
1023
+ });
1024
+
1025
+ test("breakdown captures the raw sims for each candidate", async () => {
1026
+ stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.5 }]); // simU
1027
+ stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.4 }]); // simA
1028
+ stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.2 }]); // simN
1029
+
1030
+ const out = await computeSkillActivation({
1031
+ candidates: new Set(["example-skill-a"]),
1032
+ userText: "u",
1033
+ assistantText: "a",
1034
+ nowText: "n",
1035
+ config: makeConfig({
1036
+ c_user: 0.3,
1037
+ c_assistant: 0.2,
1038
+ c_now: 0.2,
1039
+ }),
1040
+ });
1041
+ const breakdown = out.breakdown.get("example-skill-a");
1042
+ expect(breakdown).toBeDefined();
1043
+ expect(breakdown?.simUser).toBeCloseTo(0.5, 6);
1044
+ expect(breakdown?.simAssistant).toBeCloseTo(0.4, 6);
1045
+ expect(breakdown?.simNow).toBeCloseTo(0.2, 6);
865
1046
  });
866
1047
 
867
1048
  test("uses the dedicated skills collection and never queries concept pages", async () => {