@vellumai/assistant 0.7.1 → 0.7.3

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 (739) hide show
  1. package/ARCHITECTURE.md +48 -50
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/memory.md +5 -2
  7. package/docs/architecture/security.md +20 -0
  8. package/docs/plugins.md +7 -9
  9. package/knip.json +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  11. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
  12. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  13. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  15. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  16. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  17. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  18. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  20. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  21. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  22. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  23. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  24. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  25. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  26. package/openapi.yaml +1020 -40
  27. package/package.json +6 -3
  28. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  29. package/src/__tests__/app-bundler.test.ts +170 -1
  30. package/src/__tests__/app-control-flow.test.ts +384 -0
  31. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  32. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  33. package/src/__tests__/app-executors.test.ts +30 -43
  34. package/src/__tests__/approval-routes-http.test.ts +23 -6
  35. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +157 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
  39. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  40. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  41. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  42. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  43. package/src/__tests__/btw-routes.test.ts +13 -4
  44. package/src/__tests__/call-controller.test.ts +49 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  46. package/src/__tests__/call-domain.test.ts +0 -2
  47. package/src/__tests__/call-routes-http.test.ts +0 -2
  48. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  49. package/src/__tests__/channel-readiness-service.test.ts +62 -2
  50. package/src/__tests__/checker.test.ts +3 -4
  51. package/src/__tests__/config-loader-backfill.test.ts +461 -147
  52. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  53. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  54. package/src/__tests__/config-schema.test.ts +1 -0
  55. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  56. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
  57. package/src/__tests__/config-watcher.test.ts +142 -71
  58. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  59. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  60. package/src/__tests__/context-search-fanout.test.ts +0 -1
  61. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  62. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  63. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  64. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  65. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  66. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  67. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  68. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  69. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  70. package/src/__tests__/conversation-error.test.ts +150 -3
  71. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  72. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  74. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  80. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  81. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  82. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  83. package/src/__tests__/conversation-store.test.ts +0 -18
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  85. package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
  86. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  87. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  88. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  89. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  90. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  91. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  92. package/src/__tests__/credentials-cli.test.ts +12 -12
  93. package/src/__tests__/cu-unified-flow.test.ts +351 -23
  94. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  95. package/src/__tests__/date-context.test.ts +164 -2
  96. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  97. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  98. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  99. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  100. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  101. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  102. package/src/__tests__/disk-usage.test.ts +150 -0
  103. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  104. package/src/__tests__/events-client-registration.test.ts +52 -0
  105. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  106. package/src/__tests__/file-write-tool.test.ts +4 -10
  107. package/src/__tests__/filing-service.test.ts +3 -4
  108. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  109. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  110. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  111. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  112. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  113. package/src/__tests__/heartbeat-service.test.ts +968 -2
  114. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  115. package/src/__tests__/host-app-control-proxy.test.ts +772 -0
  116. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +439 -47
  118. package/src/__tests__/host-bash-routes.test.ts +459 -0
  119. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  120. package/src/__tests__/host-browser-routes.test.ts +39 -13
  121. package/src/__tests__/host-cu-proxy.test.ts +248 -52
  122. package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
  123. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  124. package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
  125. package/src/__tests__/host-file-proxy.test.ts +301 -45
  126. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  127. package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
  128. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  129. package/src/__tests__/host-proxy-base.test.ts +312 -0
  130. package/src/__tests__/host-shell-tool.test.ts +22 -4
  131. package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
  132. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  133. package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
  134. package/src/__tests__/http-user-message-parity.test.ts +108 -1
  135. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  136. package/src/__tests__/identity-routes.test.ts +103 -1
  137. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  138. package/src/__tests__/injector-chain.test.ts +18 -6
  139. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  140. package/src/__tests__/inline-command-runner.test.ts +0 -1
  141. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  142. package/src/__tests__/integration-status.test.ts +85 -5
  143. package/src/__tests__/intent-routing.test.ts +0 -1
  144. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  145. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  148. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  149. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  150. package/src/__tests__/mcp-cli.test.ts +338 -2
  151. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  153. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  155. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  156. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  157. package/src/__tests__/oauth-cli.test.ts +0 -2
  158. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  160. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  161. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  162. package/src/__tests__/openai-provider.test.ts +45 -8
  163. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  164. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  165. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  166. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  167. package/src/__tests__/platform.test.ts +2 -1
  168. package/src/__tests__/playbook-execution.test.ts +0 -43
  169. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  170. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
  171. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  172. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  173. package/src/__tests__/provider-tool-name.test.ts +23 -0
  174. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  175. package/src/__tests__/relay-server.test.ts +15 -4
  176. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  177. package/src/__tests__/retry-backoff.test.ts +87 -0
  178. package/src/__tests__/runtime-events-sse.test.ts +2 -2
  179. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  180. package/src/__tests__/schedule-retry.test.ts +715 -0
  181. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  182. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  183. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  184. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  185. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  186. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  187. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  188. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  189. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  190. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  191. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  192. package/src/__tests__/slack-channel-config.test.ts +9 -14
  193. package/src/__tests__/suggestion-routes.test.ts +46 -0
  194. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  195. package/src/__tests__/system-prompt.test.ts +0 -1
  196. package/src/__tests__/telegram-config.test.ts +0 -1
  197. package/src/__tests__/test-preload.ts +8 -0
  198. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  199. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  200. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  201. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  202. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  203. package/src/__tests__/tool-executor.test.ts +0 -1
  204. package/src/__tests__/twilio-config.test.ts +3 -16
  205. package/src/__tests__/twilio-routes.test.ts +3 -5
  206. package/src/__tests__/twilio-validation.test.ts +93 -0
  207. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  208. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  209. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  210. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  211. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  212. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  213. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  214. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  215. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  216. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  217. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  218. package/src/approvals/guardian-decision-primitive.ts +13 -0
  219. package/src/approvals/guardian-request-resolvers.ts +16 -17
  220. package/src/backup/__tests__/paths.test.ts +0 -22
  221. package/src/backup/__tests__/restore.test.ts +51 -151
  222. package/src/backup/paths.ts +2 -18
  223. package/src/backup/restore.ts +107 -231
  224. package/src/backup/snapshot-lock.ts +2 -27
  225. package/src/bundler/app-bundler.ts +51 -3
  226. package/src/bundler/compiler-tools.ts +3 -2
  227. package/src/calls/call-conversation-messages.ts +46 -10
  228. package/src/calls/relay-server.ts +4 -44
  229. package/src/calls/twilio-config.ts +2 -17
  230. package/src/calls/twilio-rest.ts +33 -105
  231. package/src/calls/twilio-routes.ts +11 -12
  232. package/src/channels/types.ts +8 -7
  233. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  234. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  235. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  236. package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
  237. package/src/cli/commands/backup.ts +6 -331
  238. package/src/cli/commands/bash.ts +35 -108
  239. package/src/cli/commands/clients.ts +36 -37
  240. package/src/cli/commands/contacts.ts +137 -25
  241. package/src/cli/commands/conversations.ts +2 -5
  242. package/src/cli/commands/credentials.ts +71 -7
  243. package/src/cli/commands/domain.ts +66 -15
  244. package/src/cli/commands/gateway.ts +183 -0
  245. package/src/cli/commands/keys.ts +9 -6
  246. package/src/cli/commands/mcp.ts +116 -156
  247. package/src/cli/commands/memory-v2.ts +303 -7
  248. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  249. package/src/cli/commands/oauth/connect.ts +127 -1
  250. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
  251. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
  252. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
  253. package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
  254. package/src/cli/commands/platform/disconnect.ts +5 -4
  255. package/src/cli/commands/platform/index.ts +16 -25
  256. package/src/cli/commands/status.ts +57 -0
  257. package/src/cli/lib/daemon-credential-client.ts +110 -28
  258. package/src/cli/program.ts +6 -2
  259. package/src/config/assistant-feature-flags.ts +79 -12
  260. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  261. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  262. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  263. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  264. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  265. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  266. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  267. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  268. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  269. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  270. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  271. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  272. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  273. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  274. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  275. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  276. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  277. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  278. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  279. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  280. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  281. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  282. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  283. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  284. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  285. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  286. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  287. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
  288. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  289. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  290. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  291. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  292. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  293. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  294. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  295. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  296. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  297. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  298. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  299. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  300. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  301. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  302. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  303. package/src/config/bundled-tool-registry.ts +21 -0
  304. package/src/config/env-registry.ts +0 -2
  305. package/src/config/env.ts +19 -20
  306. package/src/config/feature-flag-registry.json +47 -135
  307. package/src/config/loader.ts +197 -104
  308. package/src/config/sanitize-for-transfer.ts +2 -0
  309. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  310. package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
  311. package/src/config/schemas/call-site-catalog.ts +14 -0
  312. package/src/config/schemas/calls.ts +0 -9
  313. package/src/config/schemas/channels.ts +0 -5
  314. package/src/config/schemas/heartbeat.ts +64 -1
  315. package/src/config/schemas/ingress.ts +10 -6
  316. package/src/config/schemas/llm.ts +7 -10
  317. package/src/config/schemas/memory-lifecycle.ts +90 -24
  318. package/src/config/schemas/memory-v2.ts +121 -13
  319. package/src/config/schemas/platform.ts +49 -3
  320. package/src/config/schemas/services.ts +29 -15
  321. package/src/config/schemas/skills.ts +0 -6
  322. package/src/config/seed-inference-profiles.ts +230 -33
  323. package/src/contacts/contact-store.ts +0 -55
  324. package/src/contacts/contacts-write.ts +0 -27
  325. package/src/context/window-manager.ts +1 -2
  326. package/src/credential-execution/feature-gates.ts +10 -10
  327. package/src/credential-execution/process-manager.ts +12 -41
  328. package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
  329. package/src/daemon/assistant-attachments.ts +4 -4
  330. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  331. package/src/daemon/config-watcher.ts +89 -60
  332. package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
  333. package/src/daemon/conversation-agent-loop.ts +202 -61
  334. package/src/daemon/conversation-error.ts +87 -15
  335. package/src/daemon/conversation-lifecycle.ts +9 -4
  336. package/src/daemon/conversation-process.ts +24 -11
  337. package/src/daemon/conversation-runtime-assembly.ts +28 -2
  338. package/src/daemon/conversation-store.ts +2 -2
  339. package/src/daemon/conversation-surfaces.ts +305 -4
  340. package/src/daemon/conversation-tool-setup.ts +66 -62
  341. package/src/daemon/conversation.ts +38 -24
  342. package/src/daemon/date-context.ts +71 -22
  343. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  344. package/src/daemon/disk-pressure-guard.ts +343 -0
  345. package/src/daemon/disk-pressure-policy.ts +163 -0
  346. package/src/daemon/doordash-steps.ts +1 -1
  347. package/src/daemon/handlers/shared.ts +4 -2
  348. package/src/daemon/handlers/skills.ts +3 -4
  349. package/src/daemon/host-app-control-proxy.ts +389 -0
  350. package/src/daemon/host-bash-proxy.ts +117 -82
  351. package/src/daemon/host-browser-proxy.ts +67 -82
  352. package/src/daemon/host-cu-proxy.ts +127 -86
  353. package/src/daemon/host-file-proxy.ts +129 -69
  354. package/src/daemon/host-proxy-base.ts +294 -0
  355. package/src/daemon/host-proxy-preactivation.ts +82 -0
  356. package/src/daemon/host-transfer-proxy.ts +338 -129
  357. package/src/daemon/lifecycle.ts +194 -145
  358. package/src/daemon/meet-host-supervisor.ts +4 -4
  359. package/src/daemon/meet-manifest-loader.ts +0 -1
  360. package/src/daemon/memory-v2-startup.ts +14 -4
  361. package/src/daemon/message-protocol.ts +6 -8
  362. package/src/daemon/message-types/contacts.ts +23 -1
  363. package/src/daemon/message-types/conversations.ts +15 -8
  364. package/src/daemon/message-types/disk-pressure.ts +9 -0
  365. package/src/daemon/message-types/host-app-control.ts +150 -0
  366. package/src/daemon/message-types/host-bash.ts +4 -0
  367. package/src/daemon/message-types/host-cu.ts +2 -0
  368. package/src/daemon/message-types/host-file.ts +4 -0
  369. package/src/daemon/message-types/host-transfer.ts +3 -0
  370. package/src/daemon/message-types/messages.ts +3 -0
  371. package/src/daemon/message-types/schedules.ts +8 -3
  372. package/src/daemon/message-types/skills.ts +2 -2
  373. package/src/daemon/process-message.ts +18 -1
  374. package/src/daemon/profiler-run-store.ts +5 -5
  375. package/src/daemon/shutdown-handlers.ts +0 -3
  376. package/src/daemon/tool-setup-types.ts +51 -0
  377. package/src/daemon/tool-side-effects.ts +1 -1
  378. package/src/documents/document-store.ts +85 -0
  379. package/src/events/tool-audit-listener.ts +2 -1
  380. package/src/filing/filing-service.ts +30 -5
  381. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
  382. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
  383. package/src/heartbeat/heartbeat-run-store.ts +249 -0
  384. package/src/heartbeat/heartbeat-service.ts +459 -54
  385. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  386. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  387. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  388. package/src/home/feed-scheduler.ts +18 -0
  389. package/src/home/post-connect-feed.ts +68 -0
  390. package/src/home/relationship-state-writer.ts +17 -92
  391. package/src/home/suggested-prompts.ts +46 -10
  392. package/src/inbound/platform-callback-registration.ts +8 -15
  393. package/src/inbound/public-ingress-urls.ts +32 -34
  394. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  395. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  396. package/src/ipc/assistant-server.ts +70 -3
  397. package/src/ipc/cli-client.ts +32 -1
  398. package/src/ipc/gateway-client.ts +37 -3
  399. package/src/live-voice/live-voice-archive.ts +4 -4
  400. package/src/live-voice/live-voice-metrics.ts +10 -10
  401. package/src/live-voice/protocol.ts +5 -7
  402. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  403. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  404. package/src/mcp/mcp-auth-state.ts +133 -0
  405. package/src/mcp/mcp-oauth-provider.ts +19 -0
  406. package/src/media/image-service.ts +1 -7
  407. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  408. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  409. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  412. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  413. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  414. package/src/memory/admin.ts +5 -9
  415. package/src/memory/anisotropy.test.ts +247 -0
  416. package/src/memory/anisotropy.ts +443 -0
  417. package/src/memory/auto-analysis-constants.ts +17 -0
  418. package/src/memory/auto-analysis-guard.ts +5 -15
  419. package/src/memory/canonical-guardian-store.ts +7 -7
  420. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  421. package/src/memory/context-search/agent-protocol.ts +6 -6
  422. package/src/memory/context-search/agent-runner.ts +51 -9
  423. package/src/memory/context-search/sources/conversations.ts +2 -11
  424. package/src/memory/context-search/sources/memory-v2.ts +22 -9
  425. package/src/memory/context-search/sources/memory.ts +0 -1
  426. package/src/memory/context-search/types.ts +0 -1
  427. package/src/memory/conversation-crud.ts +5 -13
  428. package/src/memory/conversation-key-store.ts +2 -15
  429. package/src/memory/db-init.ts +6 -0
  430. package/src/memory/embedding-backend.ts +9 -21
  431. package/src/memory/embedding-runtime-manager.ts +119 -5
  432. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
  433. package/src/memory/graph/conversation-graph-memory.ts +43 -78
  434. package/src/memory/graph/extraction.ts +1 -3
  435. package/src/memory/graph/graph-search.test.ts +10 -67
  436. package/src/memory/graph/graph-search.ts +9 -20
  437. package/src/memory/graph/retriever.test.ts +6 -0
  438. package/src/memory/graph/retriever.ts +34 -10
  439. package/src/memory/graph/tools.ts +1 -1
  440. package/src/memory/indexer.ts +54 -45
  441. package/src/memory/job-handlers/backfill.ts +2 -11
  442. package/src/memory/job-handlers/cleanup.ts +43 -0
  443. package/src/memory/job-handlers/embedding.ts +6 -8
  444. package/src/memory/job-handlers/summarization.ts +2 -7
  445. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  446. package/src/memory/jobs/embed-concept-page.ts +28 -2
  447. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  448. package/src/memory/jobs-store.ts +114 -22
  449. package/src/memory/jobs-worker.ts +193 -106
  450. package/src/memory/memory-v2-activation-log-store.ts +33 -15
  451. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  452. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  453. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  454. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  455. package/src/memory/migrations/index.ts +6 -0
  456. package/src/memory/migrations/registry.ts +8 -0
  457. package/src/memory/pkb/pkb-search.test.ts +6 -0
  458. package/src/memory/pkb/pkb-search.ts +7 -0
  459. package/src/memory/qdrant-client.ts +49 -32
  460. package/src/memory/rerank-local.ts +374 -0
  461. package/src/memory/schema/infrastructure.ts +15 -0
  462. package/src/memory/search/semantic.ts +13 -67
  463. package/src/memory/sparse-tokenize.ts +49 -0
  464. package/src/memory/trace-event-store.ts +1 -17
  465. package/src/memory/v2/__tests__/activation.test.ts +387 -344
  466. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  467. package/src/memory/v2/__tests__/injection.test.ts +181 -169
  468. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  469. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  470. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  471. package/src/memory/v2/__tests__/sim.test.ts +154 -188
  472. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  473. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  474. package/src/memory/v2/__tests__/static-context.test.ts +76 -2
  475. package/src/memory/v2/activation.ts +213 -239
  476. package/src/memory/v2/consolidation-job.ts +65 -17
  477. package/src/memory/v2/constants.ts +7 -0
  478. package/src/memory/v2/injection.ts +123 -103
  479. package/src/memory/v2/prompts/consolidation.ts +348 -92
  480. package/src/memory/v2/qdrant.ts +198 -1
  481. package/src/memory/v2/reranker.ts +177 -0
  482. package/src/memory/v2/sim.ts +113 -77
  483. package/src/memory/v2/skill-content.ts +4 -3
  484. package/src/memory/v2/skill-store.ts +91 -53
  485. package/src/memory/v2/sparse-bm25.ts +245 -0
  486. package/src/memory/v2/static-context.ts +28 -5
  487. package/src/memory/v2/types.ts +10 -10
  488. package/src/messaging/providers/gmail/types.ts +0 -49
  489. package/src/messaging/providers/slack/adapter.ts +1 -31
  490. package/src/messaging/providers/slack/types.ts +0 -32
  491. package/src/notifications/README.md +10 -10
  492. package/src/notifications/broadcaster.ts +1 -1
  493. package/src/notifications/copy-composer.ts +13 -0
  494. package/src/notifications/guardian-question-mode.ts +5 -5
  495. package/src/notifications/signal.ts +4 -0
  496. package/src/oauth/AGENTS.md +3 -1
  497. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  498. package/src/oauth/connect-orchestrator.ts +6 -0
  499. package/src/oauth/connection-resolver.test.ts +66 -1
  500. package/src/oauth/connection-resolver.ts +55 -1
  501. package/src/oauth/credential-token-resolver.ts +1 -3
  502. package/src/oauth/manual-token-connection.ts +0 -4
  503. package/src/oauth/oauth-connect-state.ts +77 -0
  504. package/src/oauth/seed-providers.ts +58 -1
  505. package/src/outbound-proxy/index.ts +1 -37
  506. package/src/outbound-proxy/logging.ts +1 -1
  507. package/src/outbound-proxy/policy.ts +6 -5
  508. package/src/outbound-proxy/router.ts +2 -1
  509. package/src/permissions/approval-policy.test.ts +6 -275
  510. package/src/permissions/approval-policy.ts +0 -51
  511. package/src/permissions/checker.test.ts +0 -1
  512. package/src/permissions/checker.ts +3 -17
  513. package/src/permissions/gateway-threshold-reader.ts +2 -0
  514. package/src/permissions/prompter.ts +34 -1
  515. package/src/permissions/secret-prompter.ts +6 -2
  516. package/src/plugins/defaults/injectors.ts +35 -2
  517. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  518. package/src/plugins/types.ts +7 -0
  519. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  520. package/src/proactive-artifact/decision.test.ts +226 -0
  521. package/src/proactive-artifact/decision.ts +165 -0
  522. package/src/proactive-artifact/index.ts +7 -0
  523. package/src/proactive-artifact/job.test.ts +867 -0
  524. package/src/proactive-artifact/job.ts +352 -0
  525. package/src/proactive-artifact/message-copy.ts +41 -0
  526. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  527. package/src/proactive-artifact/trigger-state.ts +119 -0
  528. package/src/prompts/bootstrap-cleanup.ts +27 -0
  529. package/src/prompts/normalize-onboarding.ts +80 -0
  530. package/src/prompts/persona-resolver.ts +101 -9
  531. package/src/prompts/system-prompt.ts +23 -24
  532. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  533. package/src/prompts/templates/SOUL.md +13 -1
  534. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  535. package/src/providers/model-intents.ts +7 -0
  536. package/src/providers/openrouter/client.ts +8 -0
  537. package/src/providers/retry.ts +50 -0
  538. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  539. package/src/providers/types.ts +1 -0
  540. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  541. package/src/runtime/agent-wake.ts +238 -100
  542. package/src/runtime/assistant-event-hub.ts +151 -99
  543. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  544. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  545. package/src/runtime/auth/middleware.ts +0 -96
  546. package/src/runtime/auth/route-policy.ts +32 -0
  547. package/src/runtime/auth/same-actor.ts +216 -0
  548. package/src/runtime/btw-sidechain.ts +2 -3
  549. package/src/runtime/channel-invite-transport.ts +2 -48
  550. package/src/runtime/channel-invite-transports/email.ts +1 -1
  551. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  552. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  553. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  554. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  555. package/src/runtime/channel-invite-types.ts +54 -0
  556. package/src/runtime/channel-readiness-service.ts +32 -13
  557. package/src/runtime/channel-retry-sweep.ts +65 -1
  558. package/src/runtime/guardian-reply-router.ts +10 -0
  559. package/src/runtime/http-server.ts +3 -329
  560. package/src/runtime/http-types.ts +0 -5
  561. package/src/runtime/local-actor-identity.ts +52 -11
  562. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  563. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  564. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  565. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  566. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  567. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  568. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  569. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  570. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  571. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  572. package/src/runtime/migrations/migration-transport.ts +7 -7
  573. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  574. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  575. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  576. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  577. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  578. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  579. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  580. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  581. package/src/runtime/pending-interactions.ts +43 -9
  582. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  583. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  584. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
  585. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  586. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  587. package/src/runtime/routes/approval-interception-types.ts +13 -0
  588. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  589. package/src/runtime/routes/backup-routes.ts +15 -38
  590. package/src/runtime/routes/btw-routes.ts +14 -37
  591. package/src/runtime/routes/client-routes.ts +21 -2
  592. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  593. package/src/runtime/routes/contact-routes.ts +0 -25
  594. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  595. package/src/runtime/routes/conversation-routes.ts +65 -39
  596. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  597. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  598. package/src/runtime/routes/document-pdf-renderer.ts +169 -0
  599. package/src/runtime/routes/documents-routes.ts +32 -75
  600. package/src/runtime/routes/errors.ts +19 -4
  601. package/src/runtime/routes/events-routes.ts +38 -0
  602. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  603. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  604. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  605. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  606. package/src/runtime/routes/host-bash-routes.ts +56 -6
  607. package/src/runtime/routes/host-browser-routes.ts +108 -13
  608. package/src/runtime/routes/host-cu-routes.ts +66 -9
  609. package/src/runtime/routes/host-file-routes.ts +54 -5
  610. package/src/runtime/routes/host-transfer-routes.ts +122 -19
  611. package/src/runtime/routes/http-adapter.ts +1 -0
  612. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  613. package/src/runtime/routes/identity-routes.ts +21 -180
  614. package/src/runtime/routes/inbound-message-handler.ts +78 -21
  615. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  616. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  617. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  618. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  619. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  620. package/src/runtime/routes/index.ts +14 -0
  621. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  622. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  623. package/src/runtime/routes/memory-item-routes.ts +10 -12
  624. package/src/runtime/routes/memory-v2-routes.ts +474 -1
  625. package/src/runtime/routes/migration-routes.ts +96 -0
  626. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  627. package/src/runtime/routes/schedule-routes.ts +7 -0
  628. package/src/runtime/verification-outbound-actions.ts +4 -4
  629. package/src/runtime/verification-templates.ts +4 -7
  630. package/src/schedule/integration-status.ts +66 -2
  631. package/src/schedule/recurrence-engine.ts +4 -1
  632. package/src/schedule/retry-backoff.ts +18 -0
  633. package/src/schedule/retry-policy.ts +82 -0
  634. package/src/schedule/run-script.ts +37 -5
  635. package/src/schedule/schedule-recovery.ts +64 -0
  636. package/src/schedule/schedule-store.ts +106 -2
  637. package/src/schedule/scheduler-types.ts +25 -0
  638. package/src/schedule/scheduler.ts +83 -39
  639. package/src/security/encrypted-store.ts +2 -0
  640. package/src/security/oauth-callback-registry.ts +8 -0
  641. package/src/security/secure-keys.ts +55 -0
  642. package/src/sequence/analytics.ts +5 -5
  643. package/src/sequence/engine.ts +1 -1
  644. package/src/skills/catalog-files.ts +2 -8
  645. package/src/skills/include-graph.ts +5 -5
  646. package/src/skills/remote-skill-policy.ts +10 -16
  647. package/src/skills/skill-file-provider.ts +1 -1
  648. package/src/skills/skill-file-types.ts +13 -0
  649. package/src/skills/skillssh-audit-types.ts +28 -0
  650. package/src/skills/skillssh-registry.ts +8 -21
  651. package/src/subagent/index.ts +1 -7
  652. package/src/subagent/manager.ts +1 -15
  653. package/src/tasks/task-runner.ts +0 -1
  654. package/src/tasks/task-store.ts +0 -3
  655. package/src/telemetry/types.ts +2 -0
  656. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  657. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  658. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  659. package/src/tools/apps/executors.ts +56 -69
  660. package/src/tools/background-tool-registry.ts +17 -3
  661. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  662. package/src/tools/browser/browser-execution.ts +2 -2
  663. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  664. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  665. package/src/tools/browser/cdp-client/factory.ts +23 -24
  666. package/src/tools/browser/cdp-client/index.ts +1 -14
  667. package/src/tools/computer-use/definitions.ts +42 -20
  668. package/src/tools/executor.ts +2 -0
  669. package/src/tools/host-filesystem/edit.test.ts +151 -0
  670. package/src/tools/host-filesystem/edit.ts +68 -0
  671. package/src/tools/host-filesystem/read.test.ts +129 -0
  672. package/src/tools/host-filesystem/read.ts +68 -0
  673. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  674. package/src/tools/host-filesystem/transfer.ts +78 -3
  675. package/src/tools/host-filesystem/write.test.ts +134 -0
  676. package/src/tools/host-filesystem/write.ts +68 -0
  677. package/src/tools/host-terminal/host-shell.ts +66 -1
  678. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  679. package/src/tools/memory/register.test.ts +12 -9
  680. package/src/tools/memory/register.ts +1 -2
  681. package/src/tools/provider-tool-name.ts +28 -0
  682. package/src/tools/registry.ts +30 -9
  683. package/src/tools/schedule/create.ts +6 -0
  684. package/src/tools/schedule/list.ts +2 -0
  685. package/src/tools/schedule/update.ts +10 -0
  686. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  687. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  688. package/src/tools/skills/load.ts +0 -32
  689. package/src/tools/terminal/shell.ts +9 -1
  690. package/src/tools/tool-approval-handler.ts +32 -11
  691. package/src/tools/types.ts +28 -2
  692. package/src/tts/provider-catalog.ts +3 -5
  693. package/src/usage/pricing.ts +1 -1
  694. package/src/util/disk-usage.ts +138 -0
  695. package/src/util/platform.ts +21 -11
  696. package/src/util/process-liveness.ts +26 -0
  697. package/src/workspace/hatched-date.ts +86 -0
  698. package/src/workspace/heartbeat-service.ts +19 -0
  699. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  700. package/src/workspace/migrations/006-services-config.ts +8 -5
  701. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  702. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  703. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  704. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  705. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  706. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  707. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  708. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  709. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  710. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  711. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  712. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  713. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  714. package/src/workspace/migrations/AGENTS.md +1 -1
  715. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  716. package/src/workspace/migrations/registry.ts +8 -0
  717. package/src/workspace/migrations/utils.ts +21 -0
  718. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  719. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  720. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  721. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  722. package/src/__tests__/twilio-rest.test.ts +0 -34
  723. package/src/backup/__tests__/backup-key.test.ts +0 -152
  724. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  725. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  726. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  727. package/src/backup/backup-key.ts +0 -137
  728. package/src/backup/backup-worker.ts +0 -472
  729. package/src/backup/offsite-writer.ts +0 -222
  730. package/src/backup/stream-crypt.ts +0 -263
  731. package/src/daemon/message-types/pairing.ts +0 -58
  732. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  733. package/src/memory/v2/skill-qdrant.ts +0 -395
  734. package/src/outbound-proxy/config.ts +0 -20
  735. package/src/outbound-proxy/health.ts +0 -18
  736. package/src/outbound-proxy/types.ts +0 -150
  737. package/src/runtime/capability-tokens.ts +0 -190
  738. package/src/signals/bash.ts +0 -198
  739. package/src/signals/mcp-reload.ts +0 -18
@@ -68,17 +68,6 @@ const state = {
68
68
  points: Array<{ score?: number; payload: Record<string, unknown> }>;
69
69
  }>,
70
70
  },
71
- // Separate response queue for the dedicated `memory_v2_skills` collection
72
- // so a test asserting on skill activation does not have to interleave
73
- // responses with concept-page queries.
74
- skillQueryResponses: {
75
- dense: [] as Array<{
76
- points: Array<{ score?: number; payload: Record<string, unknown> }>;
77
- }>,
78
- sparse: [] as Array<{
79
- points: Array<{ score?: number; payload: Record<string, unknown> }>;
80
- }>,
81
- },
82
71
  queryCalls: [] as Array<{
83
72
  collection: string;
84
73
  using: string;
@@ -126,11 +115,7 @@ class MockQdrantClient {
126
115
  filter: params.filter,
127
116
  });
128
117
  const channel = params.using as "dense" | "sparse";
129
- const queue =
130
- name === "memory_v2_skills"
131
- ? state.skillQueryResponses[channel]
132
- : state.queryResponses[channel];
133
- return queue.shift() ?? { points: [] };
118
+ return state.queryResponses[channel].shift() ?? { points: [] };
134
119
  }
135
120
  }
136
121
 
@@ -138,6 +123,37 @@ mock.module("@qdrant/js-client-rest", () => ({
138
123
  QdrantClient: MockQdrantClient,
139
124
  }));
140
125
 
126
+ // Reranker mock — keeps the activation tests hermetic when rerank.enabled is
127
+ // flipped on by an integration case. Tests stage `rerankState.scores` to
128
+ // program the boost outcome. The activation pipeline now passes both the
129
+ // user-channel and assistant-channel queries into a single rerank call, so
130
+ // `rerankState.calls` records the full `queries` array per invocation.
131
+ const rerankState = {
132
+ scores: null as Map<string, number> | null,
133
+ calls: [] as Array<{ queries: string[]; candidates: string[] }>,
134
+ };
135
+ mock.module("../reranker.js", () => ({
136
+ rerankCandidates: async (
137
+ queries: readonly string[],
138
+ candidates: readonly string[],
139
+ ): Promise<Array<Map<string, number>>> => {
140
+ rerankState.calls.push({
141
+ queries: [...queries],
142
+ candidates: [...candidates],
143
+ });
144
+ return queries.map(() => {
145
+ if (rerankState.scores === null) return new Map();
146
+ const out = new Map<string, number>();
147
+ for (const slug of candidates) {
148
+ const v = rerankState.scores.get(slug);
149
+ if (v !== undefined) out.set(slug, v);
150
+ }
151
+ return out;
152
+ });
153
+ },
154
+ _resetRerankCacheForTests: () => {},
155
+ }));
156
+
141
157
  // Static `import type` is fine — types erase, so they don't run module-init
142
158
  // code that would race the mocks above.
143
159
  import type { EdgeIndex } from "../edge-index.js";
@@ -145,16 +161,11 @@ import type { ActivationState } from "../types.js";
145
161
 
146
162
  const {
147
163
  computeOwnActivation,
148
- computeSkillActivation,
149
164
  selectCandidates,
150
165
  selectInjections,
151
- selectSkillCandidates,
152
- selectSkillInjections,
153
166
  spreadActivation,
154
167
  } = await import("../activation.js");
155
168
  const { _resetMemoryV2QdrantForTests } = await import("../qdrant.js");
156
- const { _resetMemoryV2SkillQdrantForTests } =
157
- await import("../skill-qdrant.js");
158
169
 
159
170
  // ---------------------------------------------------------------------------
160
171
  // Helpers
@@ -167,16 +178,15 @@ function resetState(): void {
167
178
  state.sparseReturn = { indices: [1, 2, 3], values: [0.5, 0.5, 0.5] };
168
179
  state.queryResponses.dense.length = 0;
169
180
  state.queryResponses.sparse.length = 0;
170
- state.skillQueryResponses.dense.length = 0;
171
- state.skillQueryResponses.sparse.length = 0;
172
181
  state.queryCalls.length = 0;
182
+ rerankState.scores = null;
183
+ rerankState.calls.length = 0;
173
184
  // Bun's `mock.module` persists across files in the same process, so the
174
- // qdrant modules' `_client` singletons may already hold a MockQdrantClient
175
- // instance from a sibling test file (e.g. sim.test.ts). Resetting both the
185
+ // qdrant module's `_client` singleton may already hold a MockQdrantClient
186
+ // instance from a sibling test file (e.g. sim.test.ts). Resetting the
176
187
  // cache AND any latched readiness forces a fresh `new QdrantClient()` —
177
188
  // which under our mock above resolves to *this* file's MockQdrantClient.
178
189
  _resetMemoryV2QdrantForTests();
179
- _resetMemoryV2SkillQdrantForTests();
180
190
  }
181
191
 
182
192
  /**
@@ -193,6 +203,7 @@ function makeConfig(
193
203
  epsilon: number;
194
204
  dense_weight: number;
195
205
  sparse_weight: number;
206
+ ann_candidate_limit: number | null;
196
207
  }> = {},
197
208
  ): AssistantConfig {
198
209
  return {
@@ -205,6 +216,7 @@ function makeConfig(
205
216
  epsilon: 0.01,
206
217
  dense_weight: 1.0,
207
218
  sparse_weight: 0.0,
219
+ ann_candidate_limit: null,
208
220
  ...overrides,
209
221
  },
210
222
  },
@@ -342,7 +354,13 @@ describe("selectCandidates", () => {
342
354
  expect(out.fromAnn).toEqual(new Set(["alice-vscode", "delta-recipe"]));
343
355
  });
344
356
 
345
- test("ANN top-K limit equals 50 and runs without slug restriction", async () => {
357
+ test("ANN candidate query honors `config.memory.v2.ann_candidate_limit` and runs without slug restriction", async () => {
358
+ // Default `ann_candidate_limit: null` → unlimited, so the unlimited
359
+ // sentinel (1_000_000 — a Qdrant-safe stand-in for "every page") is
360
+ // passed to both channels. We don't pin to `MAX_SAFE_INTEGER` here:
361
+ // Qdrant's sparse `SearchContext` pre-allocates `limit * 16` bytes,
362
+ // and `MAX_SAFE_INTEGER` triggers a ~144 PB alloc that SIGABRTs the
363
+ // Qdrant process — so the constant deliberately undercuts it.
346
364
  stageHybridResponse([{ slug: "alpha", denseScore: 0.5, sparseScore: 1 }]);
347
365
  await selectCandidates({
348
366
  priorState: null,
@@ -351,10 +369,25 @@ describe("selectCandidates", () => {
351
369
  nowText: "",
352
370
  config: makeConfig(),
353
371
  });
354
- // Both channels (dense + sparse) ran with limit=50 and no filter.
355
372
  expect(state.queryCalls).toHaveLength(2);
356
373
  for (const call of state.queryCalls) {
357
- expect(call.limit).toBe(50);
374
+ expect(call.limit).toBe(1_000_000);
375
+ expect(call.filter).toBeUndefined();
376
+ }
377
+
378
+ // Explicit override flows through both channels verbatim.
379
+ state.queryCalls.length = 0;
380
+ stageHybridResponse([{ slug: "beta", denseScore: 0.5, sparseScore: 1 }]);
381
+ await selectCandidates({
382
+ priorState: null,
383
+ userText: "hello",
384
+ assistantText: "",
385
+ nowText: "",
386
+ config: makeConfig({ ann_candidate_limit: 25 }),
387
+ });
388
+ expect(state.queryCalls).toHaveLength(2);
389
+ for (const call of state.queryCalls) {
390
+ expect(call.limit).toBe(25);
358
391
  expect(call.filter).toBeUndefined();
359
392
  }
360
393
  });
@@ -532,6 +565,257 @@ describe("computeOwnActivation", () => {
532
565
  // No prior state → prev=0 → priorContribution=0 regardless of `d`.
533
566
  expect(out.breakdown.get("fresh")?.priorContribution).toBe(0);
534
567
  });
568
+
569
+ test("rerank boost on user/assistant flips top-1 when fused had it second", async () => {
570
+ // Three Qdrant queries fire in parallel inside computeOwnActivation:
571
+ // user, assistant, now. Stage identical hits for each so the only signal
572
+ // separating slugs is the rerank boost on the user + assistant channels.
573
+ const stagedHits = [
574
+ { slug: "lexical", denseScore: 0.6, sparseScore: 0 },
575
+ { slug: "semantic", denseScore: 0.5, sparseScore: 0 },
576
+ ];
577
+ stageHybridResponse(stagedHits); // user channel
578
+ stageHybridResponse(stagedHits); // assistant channel
579
+ stageHybridResponse(stagedHits); // now channel
580
+ rerankState.scores = new Map([
581
+ ["lexical", 0.05],
582
+ ["semantic", 0.95],
583
+ ]);
584
+
585
+ const config = {
586
+ memory: {
587
+ v2: {
588
+ d: 0.0,
589
+ c_user: 0.5,
590
+ c_assistant: 0.5,
591
+ c_now: 0.0,
592
+ dense_weight: 1.0,
593
+ sparse_weight: 0.0,
594
+ rerank: {
595
+ enabled: true,
596
+ top_k: 50,
597
+ alpha: 0.5,
598
+ model: "test-model",
599
+ },
600
+ },
601
+ },
602
+ } as unknown as AssistantConfig;
603
+
604
+ const out = await computeOwnActivation({
605
+ candidates: new Set(["lexical", "semantic"]),
606
+ priorState: null,
607
+ userText: "u",
608
+ assistantText: "a",
609
+ nowText: "n",
610
+ config,
611
+ });
612
+
613
+ // Without rerank: lexical (0.6) would beat semantic (0.5) on both
614
+ // user and assistant channels.
615
+ // With rerank (alpha=0.5):
616
+ // lexical: 0.6 + 0.5 · (0.05/0.95) ≈ 0.626
617
+ // semantic: 0.5 + 0.5 · 1.0 = 1.0
618
+ // The semantic candidate now wins on both rerank-boosted channels.
619
+ expect(out.activation.get("semantic")!).toBeGreaterThan(
620
+ out.activation.get("lexical")!,
621
+ );
622
+ // Both rerank-enabled channels ride in a single batched rerank call.
623
+ expect(rerankState.calls).toHaveLength(1);
624
+ expect(rerankState.calls[0].queries).toEqual(["u", "a"]);
625
+ });
626
+
627
+ test("rerank pool is the unified top-K by pre-rerank A_o, not per-channel fused", async () => {
628
+ // Three candidates. The per-channel fused-sim top-2s would have picked
629
+ // different sets:
630
+ // user channel: a=0.9, b=0.5, c=0.4 → per-channel top-2 = [a, b]
631
+ // assistant channel: a=0.5, b=0.4, c=0.9 → per-channel top-2 = [c, a]
632
+ // But pre-rerank A_o (c_user=c_assistant=0.5) is:
633
+ // a = 0.5·0.9 + 0.5·0.5 = 0.70
634
+ // b = 0.5·0.5 + 0.5·0.4 = 0.45
635
+ // c = 0.5·0.4 + 0.5·0.9 = 0.65
636
+ // → unified top-2 = [a, c]. b drops out, even though it would have made
637
+ // the user-channel pool under the old per-channel selection.
638
+ stageHybridResponse([
639
+ { slug: "a", denseScore: 0.9 },
640
+ { slug: "b", denseScore: 0.5 },
641
+ { slug: "c", denseScore: 0.4 },
642
+ ]); // user
643
+ stageHybridResponse([
644
+ { slug: "a", denseScore: 0.5 },
645
+ { slug: "b", denseScore: 0.4 },
646
+ { slug: "c", denseScore: 0.9 },
647
+ ]); // assistant
648
+ stageHybridResponse([]); // now (no signal)
649
+ rerankState.scores = new Map([
650
+ ["a", 0.5],
651
+ ["b", 0.5],
652
+ ["c", 0.5],
653
+ ]);
654
+
655
+ const config = {
656
+ memory: {
657
+ v2: {
658
+ d: 0.0,
659
+ c_user: 0.5,
660
+ c_assistant: 0.5,
661
+ c_now: 0.0,
662
+ dense_weight: 1.0,
663
+ sparse_weight: 0.0,
664
+ rerank: {
665
+ enabled: true,
666
+ top_k: 2,
667
+ alpha: 0.3,
668
+ model: "test-model",
669
+ },
670
+ },
671
+ },
672
+ } as unknown as AssistantConfig;
673
+
674
+ await computeOwnActivation({
675
+ candidates: new Set(["a", "b", "c"]),
676
+ priorState: null,
677
+ userText: "u",
678
+ assistantText: "a",
679
+ nowText: "",
680
+ config,
681
+ });
682
+
683
+ // Single batched rerank call carrying both channel queries against the
684
+ // unified slug set, sorted by pre-rerank A_o descending.
685
+ expect(rerankState.calls).toHaveLength(1);
686
+ expect(rerankState.calls[0].queries).toEqual(["u", "a"]);
687
+ expect(rerankState.calls[0].candidates).toEqual(["a", "c"]);
688
+ });
689
+
690
+ test("rerank-disabled candidates outside the unified pool get zero boost", async () => {
691
+ // Two candidates, top_k=1. The lower pre-rerank A_o slug must end up
692
+ // with simUserRerankBoost=0 / simAssistantRerankBoost=0 in the breakdown.
693
+ stageHybridResponse([
694
+ { slug: "winner", denseScore: 0.9 },
695
+ { slug: "loser", denseScore: 0.2 },
696
+ ]); // user
697
+ stageHybridResponse([
698
+ { slug: "winner", denseScore: 0.9 },
699
+ { slug: "loser", denseScore: 0.2 },
700
+ ]); // assistant
701
+ stageHybridResponse([]); // now
702
+ // The mocked reranker hands back scores for whatever slugs it's
703
+ // called with. Stage scores for both; the assertion below is that
704
+ // the loser still receives 0 because it's never sent to the
705
+ // reranker — top_k=1 cuts it off.
706
+ rerankState.scores = new Map([
707
+ ["winner", 0.5],
708
+ ["loser", 0.5],
709
+ ]);
710
+
711
+ const config = {
712
+ memory: {
713
+ v2: {
714
+ d: 0.0,
715
+ c_user: 0.5,
716
+ c_assistant: 0.5,
717
+ c_now: 0.0,
718
+ dense_weight: 1.0,
719
+ sparse_weight: 0.0,
720
+ rerank: {
721
+ enabled: true,
722
+ top_k: 1,
723
+ alpha: 0.3,
724
+ model: "test-model",
725
+ },
726
+ },
727
+ },
728
+ } as unknown as AssistantConfig;
729
+
730
+ const out = await computeOwnActivation({
731
+ candidates: new Set(["winner", "loser"]),
732
+ priorState: null,
733
+ userText: "u",
734
+ assistantText: "a",
735
+ nowText: "",
736
+ config,
737
+ });
738
+
739
+ expect(out.breakdown.get("loser")?.simUserRerankBoost).toBe(0);
740
+ expect(out.breakdown.get("loser")?.simAssistantRerankBoost).toBe(0);
741
+ expect(out.breakdown.get("winner")?.simUserRerankBoost).toBeGreaterThan(0);
742
+ expect(
743
+ out.breakdown.get("winner")?.simAssistantRerankBoost,
744
+ ).toBeGreaterThan(0);
745
+ // inRerankPool tags pool membership independently of the boost value, so
746
+ // the inspector can keep the rerank rows visible even when the channel
747
+ // max happened to normalise to 0.
748
+ expect(out.breakdown.get("winner")?.inRerankPool).toBe(true);
749
+ expect(out.breakdown.get("loser")?.inRerankPool).toBe(false);
750
+ });
751
+
752
+ test("inRerankPool is false for every slug when rerank is disabled", async () => {
753
+ stageHybridResponse([{ slug: "alice", denseScore: 0.5 }]);
754
+ stageHybridResponse([{ slug: "alice", denseScore: 0.4 }]);
755
+ stageHybridResponse([{ slug: "alice", denseScore: 0.2 }]);
756
+
757
+ // No `rerank` block at all → rerankCfg is undefined and the rerank
758
+ // branch never runs, so no slug is in the pool.
759
+ const out = await computeOwnActivation({
760
+ candidates: new Set(["alice"]),
761
+ priorState: null,
762
+ userText: "u",
763
+ assistantText: "a",
764
+ nowText: "n",
765
+ config: makeConfig(),
766
+ });
767
+
768
+ expect(out.breakdown.get("alice")?.inRerankPool).toBe(false);
769
+ expect(out.breakdown.get("alice")?.simUserRerankBoost).toBe(0);
770
+ expect(out.breakdown.get("alice")?.simAssistantRerankBoost).toBe(0);
771
+ });
772
+
773
+ test("rerank boost is additive on A_o and leaves raw simUser / simAssistant untouched", async () => {
774
+ stageHybridResponse([{ slug: "a", denseScore: 0.5 }]); // user
775
+ stageHybridResponse([{ slug: "a", denseScore: 0.4 }]); // assistant
776
+ stageHybridResponse([]); // now
777
+ rerankState.scores = new Map([["a", 0.8]]);
778
+
779
+ const config = {
780
+ memory: {
781
+ v2: {
782
+ d: 0.0,
783
+ c_user: 0.5,
784
+ c_assistant: 0.5,
785
+ c_now: 0.0,
786
+ dense_weight: 1.0,
787
+ sparse_weight: 0.0,
788
+ rerank: {
789
+ enabled: true,
790
+ top_k: 50,
791
+ alpha: 0.4,
792
+ model: "test-model",
793
+ },
794
+ },
795
+ },
796
+ } as unknown as AssistantConfig;
797
+
798
+ const out = await computeOwnActivation({
799
+ candidates: new Set(["a"]),
800
+ priorState: null,
801
+ userText: "u",
802
+ assistantText: "a",
803
+ nowText: "",
804
+ config,
805
+ });
806
+
807
+ const breakdown = out.breakdown.get("a");
808
+ // Raw fused similarities are reported untouched by rerank.
809
+ expect(breakdown?.simUser).toBeCloseTo(0.5, 6);
810
+ expect(breakdown?.simAssistant).toBeCloseTo(0.4, 6);
811
+ // Both rerank deltas are alpha · r_norm = 0.4 · 1.0 = 0.4 (single
812
+ // candidate normalises to 1.0 in each channel).
813
+ expect(breakdown?.simUserRerankBoost).toBeCloseTo(0.4, 6);
814
+ expect(breakdown?.simAssistantRerankBoost).toBeCloseTo(0.4, 6);
815
+ // Final A_o = c_user·simU + c_assistant·simA + c_user·boostU + c_assistant·boostA
816
+ // = 0.5·0.5 + 0.5·0.4 + 0.5·0.4 + 0.5·0.4 = 0.25+0.20+0.20+0.20 = 0.85
817
+ expect(out.activation.get("a")).toBeCloseTo(0.85, 6);
818
+ });
535
819
  });
536
820
 
537
821
  // ---------------------------------------------------------------------------
@@ -682,15 +966,59 @@ describe("spreadActivation", () => {
682
966
  expect(out.final.get("bob")).toBeCloseTo(0.9, 6);
683
967
  });
684
968
 
685
- test("missing predecessor activation contributes 0 to the numerator", () => {
686
- // Edge alice→bob: bob has predecessor alice. alice is not in
687
- // `ownActivation`, so it contributes 0 to the numerator while the
688
- // denominator still counts the structural predecessor.
969
+ test("predecessors not in the candidate set are dropped from both numerator and denominator", () => {
970
+ // Edge alice→bob: bob has structural predecessor alice, but alice is not
971
+ // in `ownActivation`. With the new formula she contributes nothing
972
+ // hop1 has no active predecessors so the whole hop drops out of both
973
+ // sides of the ratio. Bob therefore stays at his own activation.
689
974
  const edges = buildEdgeIndex([["alice", "bob"]]);
690
975
  const own = new Map([["bob", 0.6]]);
691
976
  const out = spreadActivation(own, edges, 0.5, 2);
692
- // numerator = 0.6 + 0.5*0 = 0.6. denominator = 1 + 0.5*1 = 1.5.
693
- expect(out.final.get("bob")).toBeCloseTo(0.4, 6);
977
+ expect(out.final.get("bob")).toBeCloseTo(0.6, 6);
978
+ });
979
+
980
+ test("L_2 norm over multiple active predecessors rewards strong outliers more than avg would", () => {
981
+ // bob has 4 predecessors in the candidate set: one strong, three weak.
982
+ // L_2 = √((0.8² + 0.1² + 0.1² + 0.1²) / 4) = √(0.1675) ≈ 0.40927
983
+ // Plain avg of the same set = 0.275, so L_2 lifts bob more than avg
984
+ // would — the design goal of preferring quality over quantity.
985
+ const edges = buildEdgeIndex([
986
+ ["a1", "bob"],
987
+ ["a2", "bob"],
988
+ ["a3", "bob"],
989
+ ["a4", "bob"],
990
+ ]);
991
+ const own = new Map([
992
+ ["a1", 0.8],
993
+ ["a2", 0.1],
994
+ ["a3", 0.1],
995
+ ["a4", 0.1],
996
+ ["bob", 0.0],
997
+ ]);
998
+ const out = spreadActivation(own, edges, 0.5, 2);
999
+ const rms = Math.sqrt((0.8 * 0.8 + 3 * 0.1 * 0.1) / 4);
1000
+ // numerator = 0 + 0.5 · rms
1001
+ // denominator = 1 + 0.5
1002
+ expect(out.final.get("bob")).toBeCloseTo((0.5 * rms) / 1.5, 6);
1003
+ });
1004
+
1005
+ test("high-in-degree hub with mostly-inactive predecessors stays near A_o", () => {
1006
+ // 100 structural predecessors point at hub; only one (`pred0`) is in
1007
+ // the candidate set. The old formula would crush hub by the structural
1008
+ // count (denominator ≈ 51); the new formula folds the empty bulk out
1009
+ // and the L_2 averages over the single active predecessor only.
1010
+ const rawEdges: Array<[string, string]> = [];
1011
+ for (let i = 0; i < 100; i++) rawEdges.push([`pred${i}`, "hub"]);
1012
+ const edges = buildEdgeIndex(rawEdges);
1013
+ const own = new Map([
1014
+ ["hub", 0.6],
1015
+ ["pred0", 0.5],
1016
+ ]);
1017
+ const out = spreadActivation(own, edges, 0.5, 2);
1018
+ // hop1 active = {pred0}, L_2([0.5]) = 0.5.
1019
+ // numerator = 0.6 + 0.5 · 0.5 = 0.85
1020
+ // denominator = 1 + 0.5 = 1.5
1021
+ expect(out.final.get("hub")).toBeCloseTo(0.85 / 1.5, 6);
694
1022
  });
695
1023
 
696
1024
  test("empty own-activation map returns empty result", () => {
@@ -829,132 +1157,26 @@ describe("selectInjections", () => {
829
1157
  });
830
1158
 
831
1159
  // ---------------------------------------------------------------------------
832
- // selectSkillCandidates
833
- // ---------------------------------------------------------------------------
834
-
835
- /** Stage a single hybrid response on the skills queues (payload key = `id`). */
836
- function stageSkillHybridResponse(
837
- hits: Array<{ id: string; denseScore?: number; sparseScore?: number }>,
838
- ): void {
839
- state.skillQueryResponses.dense.push({
840
- points: hits
841
- .filter((h) => h.denseScore !== undefined)
842
- .map((h) => ({ score: h.denseScore, payload: { id: h.id } })),
843
- });
844
- state.skillQueryResponses.sparse.push({
845
- points: hits
846
- .filter((h) => h.sparseScore !== undefined)
847
- .map((h) => ({ score: h.sparseScore, payload: { id: h.id } })),
848
- });
849
- }
850
-
851
- describe("selectSkillCandidates", () => {
852
- test("returns hit ids from the skills collection", async () => {
853
- stageSkillHybridResponse([
854
- { id: "example-skill-a", denseScore: 0.5, sparseScore: 1 },
855
- { id: "example-skill-b", denseScore: 0.3, sparseScore: 1 },
856
- ]);
857
- const out = await selectSkillCandidates({
858
- userText: "user said hello",
859
- assistantText: "",
860
- nowText: "",
861
- config: makeConfig(),
862
- topK: 10,
863
- });
864
- expect(out).toEqual(new Set(["example-skill-a", "example-skill-b"]));
865
- });
866
-
867
- test("empty turn text short-circuits without backend calls", async () => {
868
- const out = await selectSkillCandidates({
869
- userText: "",
870
- assistantText: "",
871
- nowText: "",
872
- config: makeConfig(),
873
- topK: 10,
874
- });
875
- expect(out.size).toBe(0);
876
- expect(state.embedCalls).toHaveLength(0);
877
- expect(state.queryCalls).toHaveLength(0);
878
- });
879
-
880
- test("topK=0 short-circuits without backend calls", async () => {
881
- const out = await selectSkillCandidates({
882
- userText: "anything",
883
- assistantText: "anything",
884
- nowText: "anything",
885
- config: makeConfig(),
886
- topK: 0,
887
- });
888
- expect(out.size).toBe(0);
889
- expect(state.embedCalls).toHaveLength(0);
890
- expect(state.queryCalls).toHaveLength(0);
891
- });
892
-
893
- test("forwards topK and queries the skills collection unrestricted", async () => {
894
- stageSkillHybridResponse([
895
- { id: "example-skill-a", denseScore: 0.5, sparseScore: 1 },
896
- ]);
897
- await selectSkillCandidates({
898
- userText: "hello",
899
- assistantText: "",
900
- nowText: "",
901
- config: makeConfig(),
902
- topK: 7,
903
- });
904
- // Both channels (dense + sparse) ran with limit=7 and no slug/id filter,
905
- // against the dedicated skills collection.
906
- expect(state.queryCalls).toHaveLength(2);
907
- for (const call of state.queryCalls) {
908
- expect(call.collection).toBe("memory_v2_skills");
909
- expect(call.limit).toBe(7);
910
- expect(call.filter).toBeUndefined();
911
- }
912
- });
913
-
914
- test("embeds concatenated turn text exactly once", async () => {
915
- stageSkillHybridResponse([]);
916
- await selectSkillCandidates({
917
- userText: "user line",
918
- assistantText: "assistant line",
919
- nowText: "now line",
920
- config: makeConfig(),
921
- topK: 5,
922
- });
923
- expect(state.embedCalls).toHaveLength(1);
924
- expect(state.embedCalls[0].inputs).toEqual([
925
- "user line\nassistant line\nnow line",
926
- ]);
927
- expect(state.sparseCalls).toEqual(["user line\nassistant line\nnow line"]);
928
- });
929
- });
930
-
931
- // ---------------------------------------------------------------------------
932
- // computeSkillActivation
1160
+ // Skills as concept slugs — the unified pool
933
1161
  // ---------------------------------------------------------------------------
1162
+ //
1163
+ // Skills participate in the concept-page pipeline under the slug prefix
1164
+ // `skills/<id>`. There is no longer a dedicated skill activation function;
1165
+ // the only post-unification behavioral assertion worth preserving here is
1166
+ // that a `skills/<id>` slug flows through `computeOwnActivation` exactly
1167
+ // like a concept slug — same formula, same clamp, same breakdown shape.
1168
+
1169
+ describe("skills participate in the unified pipeline", () => {
1170
+ test("computeOwnActivation scores a `skills/<id>` slug like any concept slug", async () => {
1171
+ // Three simBatch responses, one per channel (user/assistant/now), with
1172
+ // a single skill-prefixed slug as the only candidate.
1173
+ stageHybridResponse([{ slug: "skills/example-skill-a", denseScore: 0.5 }]);
1174
+ stageHybridResponse([{ slug: "skills/example-skill-a", denseScore: 0.4 }]);
1175
+ stageHybridResponse([{ slug: "skills/example-skill-a", denseScore: 0.2 }]);
934
1176
 
935
- describe("computeSkillActivation", () => {
936
- test("empty candidates short-circuits without backend calls", async () => {
937
- const out = await computeSkillActivation({
938
- candidates: new Set(),
939
- userText: "u",
940
- assistantText: "a",
941
- nowText: "n",
942
- config: makeConfig(),
943
- });
944
- expect(out.activation.size).toBe(0);
945
- expect(out.breakdown.size).toBe(0);
946
- expect(state.embedCalls).toHaveLength(0);
947
- expect(state.queryCalls).toHaveLength(0);
948
- });
949
-
950
- test("applies similarity-only formula with no decay term", async () => {
951
- // Stage three skill responses — one per `simSkillBatch` call.
952
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.5 }]); // simU
953
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.4 }]); // simA
954
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.2 }]); // simN
955
-
956
- const out = await computeSkillActivation({
957
- candidates: new Set(["example-skill-a"]),
1177
+ const out = await computeOwnActivation({
1178
+ candidates: new Set(["skills/example-skill-a"]),
1179
+ priorState: null,
958
1180
  userText: "u",
959
1181
  assistantText: "a",
960
1182
  nowText: "n",
@@ -965,191 +1187,12 @@ describe("computeSkillActivation", () => {
965
1187
  c_now: 0.2,
966
1188
  }),
967
1189
  });
968
- // No `d · prev` term: 0.3*0.5 + 0.2*0.4 + 0.2*0.2 = 0.15 + 0.08 + 0.04 = 0.27
969
- expect(out.activation.get("example-skill-a")).toBeCloseTo(0.27, 6);
970
- });
971
-
972
- test("output excludes any decay term — d coefficient is unused", async () => {
973
- // The skill activation formula is `c_user·simU + c_assistant·simA +
974
- // c_now·simN`. Run with d=0.9 and d=0.0 — if the implementation
975
- // accidentally included a `d · prev` term, the two would diverge. The
976
- // function has no priorState parameter, so prev=0; both runs must equal
977
- // the d-free formula exactly. Stage three sim responses per run.
978
- const stage = () => {
979
- stageSkillHybridResponse([{ id: "alpha", denseScore: 0.4 }]);
980
- stageSkillHybridResponse([{ id: "alpha", denseScore: 0.4 }]);
981
- stageSkillHybridResponse([{ id: "alpha", denseScore: 0.4 }]);
982
- };
983
- const baseConfig = { c_user: 0.3, c_assistant: 0.2, c_now: 0.2 };
984
-
985
- stage();
986
- const withHighD = await computeSkillActivation({
987
- candidates: new Set(["alpha"]),
988
- userText: "u",
989
- assistantText: "a",
990
- nowText: "n",
991
- config: makeConfig({ ...baseConfig, d: 0.9 }),
992
- });
993
- stage();
994
- const withZeroD = await computeSkillActivation({
995
- candidates: new Set(["alpha"]),
996
- userText: "u",
997
- assistantText: "a",
998
- nowText: "n",
999
- config: makeConfig({ ...baseConfig, d: 0.0 }),
1000
- });
1001
-
1002
- // Both equal `0.3*0.4 + 0.2*0.4 + 0.2*0.4 = 0.28` — d is ignored.
1003
- expect(withHighD.activation.get("alpha")).toBeCloseTo(0.28, 6);
1004
- expect(withZeroD.activation.get("alpha")).toBeCloseTo(0.28, 6);
1005
- });
1006
-
1007
- test("clamps over-1.0 results down to [0, 1]", async () => {
1008
- stageSkillHybridResponse([{ id: "loud-skill", denseScore: 1.0 }]); // simU
1009
- stageSkillHybridResponse([{ id: "loud-skill", denseScore: 1.0 }]); // simA
1010
- stageSkillHybridResponse([{ id: "loud-skill", denseScore: 1.0 }]); // simN
1011
-
1012
- // Coefficients intentionally sum to > 1 so the unclamped result
1013
- // overshoots — the implementation must still produce <= 1.0.
1014
- const out = await computeSkillActivation({
1015
- candidates: new Set(["loud-skill"]),
1016
- userText: "u",
1017
- assistantText: "a",
1018
- nowText: "n",
1019
- config: makeConfig({
1020
- c_user: 0.5,
1021
- c_assistant: 0.5,
1022
- c_now: 0.5,
1023
- }),
1024
- });
1025
- expect(out.activation.get("loud-skill")).toBe(1);
1026
- });
1027
1190
 
1028
- test("candidate with no sim hits resolves to 0", async () => {
1029
- stageSkillHybridResponse([]);
1030
- stageSkillHybridResponse([]);
1031
- stageSkillHybridResponse([]);
1032
-
1033
- const out = await computeSkillActivation({
1034
- candidates: new Set(["ghost-skill"]),
1035
- userText: "u",
1036
- assistantText: "a",
1037
- nowText: "n",
1038
- config: makeConfig(),
1039
- });
1040
- expect(out.activation.get("ghost-skill")).toBe(0);
1041
- });
1042
-
1043
- test("breakdown captures the raw sims for each candidate", async () => {
1044
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.5 }]); // simU
1045
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.4 }]); // simA
1046
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.2 }]); // simN
1047
-
1048
- const out = await computeSkillActivation({
1049
- candidates: new Set(["example-skill-a"]),
1050
- userText: "u",
1051
- assistantText: "a",
1052
- nowText: "n",
1053
- config: makeConfig({
1054
- c_user: 0.3,
1055
- c_assistant: 0.2,
1056
- c_now: 0.2,
1057
- }),
1058
- });
1059
- const breakdown = out.breakdown.get("example-skill-a");
1060
- expect(breakdown).toBeDefined();
1061
- expect(breakdown?.simUser).toBeCloseTo(0.5, 6);
1062
- expect(breakdown?.simAssistant).toBeCloseTo(0.4, 6);
1063
- expect(breakdown?.simNow).toBeCloseTo(0.2, 6);
1064
- });
1065
-
1066
- test("uses the dedicated skills collection and never queries concept pages", async () => {
1067
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.5 }]);
1068
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.5 }]);
1069
- stageSkillHybridResponse([{ id: "example-skill-a", denseScore: 0.5 }]);
1070
-
1071
- await computeSkillActivation({
1072
- candidates: new Set(["example-skill-a"]),
1073
- userText: "u",
1074
- assistantText: "a",
1075
- nowText: "n",
1076
- config: makeConfig(),
1077
- });
1078
-
1079
- // Three simSkillBatch calls × 2 channels = 6 total queries, all against
1080
- // the skills collection. No spread → no extra calls beyond these.
1081
- expect(state.queryCalls).toHaveLength(6);
1082
- for (const call of state.queryCalls) {
1083
- expect(call.collection).toBe("memory_v2_skills");
1084
- }
1085
- });
1086
- });
1087
-
1088
- // ---------------------------------------------------------------------------
1089
- // selectSkillInjections
1090
- // ---------------------------------------------------------------------------
1091
-
1092
- describe("selectSkillInjections", () => {
1093
- test("returns empty when activation is empty", () => {
1094
- const out = selectSkillInjections({ A: new Map(), topK: 5 });
1095
- expect(out).toEqual({ topNow: [] });
1096
- });
1097
-
1098
- test("returns empty when topK is 0", () => {
1099
- const out = selectSkillInjections({
1100
- A: new Map([
1101
- ["example-skill-a", 0.5],
1102
- ["example-skill-b", 0.4],
1103
- ]),
1104
- topK: 0,
1105
- });
1106
- expect(out).toEqual({ topNow: [] });
1107
- });
1108
-
1109
- test("ranks by activation descending and trims to topK", () => {
1110
- const out = selectSkillInjections({
1111
- A: new Map([
1112
- ["example-skill-a", 0.1],
1113
- ["example-skill-b", 0.9],
1114
- ["example-skill-c", 0.5],
1115
- ["example-skill-d", 0.3],
1116
- ]),
1117
- topK: 2,
1118
- });
1119
- expect(out.topNow).toEqual(["example-skill-b", "example-skill-c"]);
1120
- });
1121
-
1122
- test("skills are stateless: the same id may be returned on consecutive turns", () => {
1123
- // No `everInjected` parameter exists — selectSkillInjections takes only
1124
- // the activation map and topK. So calling it twice with the same A map
1125
- // returns the same result; there is no dedup against prior turns.
1126
- const A = new Map([
1127
- ["example-skill-a", 0.9],
1128
- ["example-skill-b", 0.5],
1129
- ]);
1130
- const turn1 = selectSkillInjections({ A, topK: 5 });
1131
- const turn2 = selectSkillInjections({ A, topK: 5 });
1132
- expect(turn1.topNow).toEqual(["example-skill-a", "example-skill-b"]);
1133
- expect(turn2.topNow).toEqual(turn1.topNow);
1134
- });
1135
-
1136
- test("breaks ties by id ascending for deterministic output", () => {
1137
- const out = selectSkillInjections({
1138
- A: new Map([
1139
- ["zeta-skill", 0.5],
1140
- ["example-skill-a", 0.5],
1141
- ["mike-skill", 0.5],
1142
- ]),
1143
- topK: 5,
1144
- });
1145
- expect(out.topNow).toEqual(["example-skill-a", "mike-skill", "zeta-skill"]);
1146
- });
1147
-
1148
- test("topK clamps to the available activation entries", () => {
1149
- const out = selectSkillInjections({
1150
- A: new Map([["only-skill", 0.7]]),
1151
- topK: 100,
1152
- });
1153
- expect(out.topNow).toEqual(["only-skill"]);
1191
+ // No prior state priorContribution = 0.
1192
+ // 0.3*0.5 + 0.2*0.4 + 0.2*0.2 = 0.15 + 0.08 + 0.04 = 0.27
1193
+ expect(out.activation.get("skills/example-skill-a")).toBeCloseTo(0.27, 6);
1194
+ expect(out.breakdown.get("skills/example-skill-a")?.priorContribution).toBe(
1195
+ 0,
1196
+ );
1154
1197
  });
1155
1198
  });