@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
@@ -59,6 +59,7 @@ import { INTERNAL_GUARDIAN_TRUST_CONTEXT } from "../../daemon/trust-context.js";
59
59
  import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
60
60
  import { getLogger } from "../../util/logger.js";
61
61
  import { getWorkspaceDir } from "../../util/platform.js";
62
+ import { isProcessAlive } from "../../util/process-liveness.js";
62
63
  import { bootstrapConversation } from "../conversation-bootstrap.js";
63
64
  import { deleteConversation } from "../conversation-crud.js";
64
65
  import {
@@ -66,13 +67,11 @@ import {
66
67
  type MemoryJob,
67
68
  type MemoryJobType,
68
69
  } from "../jobs-store.js";
70
+ import { MEMORY_V2_CONSOLIDATION_SOURCE } from "./constants.js";
69
71
  import { resolveConsolidationPrompt } from "./prompts/consolidation.js";
70
72
 
71
73
  const log = getLogger("memory-v2-consolidate");
72
74
 
73
- /** Source string identifying this wake in `agent-wake` logs and surfaces. */
74
- const WAKE_SOURCE = "memory_v2_consolidation";
75
-
76
75
  /**
77
76
  * Follow-up jobs to fan out after a successful consolidation.
78
77
  *
@@ -144,7 +143,7 @@ export async function memoryV2ConsolidateJob(
144
143
  // writes in the assistant's voice.
145
144
  const conversation = bootstrapConversation({
146
145
  conversationType: "background",
147
- source: WAKE_SOURCE,
146
+ source: MEMORY_V2_CONSOLIDATION_SOURCE,
148
147
  origin: "memory_consolidation",
149
148
  systemHint: "Running memory consolidation",
150
149
  groupId: "system:background",
@@ -159,7 +158,7 @@ export async function memoryV2ConsolidateJob(
159
158
  config.memory.v2.consolidation_prompt_path,
160
159
  cutoff,
161
160
  ),
162
- source: WAKE_SOURCE,
161
+ source: MEMORY_V2_CONSOLIDATION_SOURCE,
163
162
  trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT,
164
163
  });
165
164
  wakeInvoked = result.invoked;
@@ -242,14 +241,20 @@ function readBufferContent(bufferPath: string): string {
242
241
  /**
243
242
  * Atomically create the lock file with `wx` (O_CREAT | O_EXCL) flags. Returns
244
243
  * `null` on success, or the current holder string (file contents, typically
245
- * `pid timestamp`) when the file already exists the holder is surfaced for
246
- * log diagnostics so operators can identify a stuck lock without re-reading.
244
+ * `pid timestamp`) when the file already exists and the holder is still alive.
245
+ *
246
+ * Stale-lock takeover: if the file exists but its holder PID is not running,
247
+ * unlink the stale file and retry the create exactly once. This recovers
248
+ * automatically from a crashed daemon that died with the lock held —
249
+ * otherwise every subsequent scheduled consolidation would skip with `locked`
250
+ * indefinitely until an operator manually removed the file.
247
251
  *
248
- * Crash recovery: if the prior daemon died with the lock held, the file will
249
- * still be on disk on the next start. PR 20 keeps the lock simple per the
250
- * plan instructions; a future iteration can probe liveness via `kill(pid, 0)`
251
- * the way `snapshot-lock.ts` does. Until then, an operator can clear a
252
- * stale lock by removing the file.
252
+ * The simple takeover-then-retry is safe here (unlike `snapshot-lock.ts`'s
253
+ * full rename-aside dance) because only the assistant's jobs worker calls
254
+ * this lock, and at most one assistant process runs per workspace at any
255
+ * time. A holder with an unparseable / empty payload is treated as stale —
256
+ * the only writers ever produce a `<pid> <timestamp>` line, so an
257
+ * unparseable file is corruption from a partial write that crashed.
253
258
  */
254
259
  function tryAcquireLock(lockPath: string): string | null {
255
260
  // The workspace migration seeds `memory/.v2-state/`, but tests and
@@ -257,9 +262,40 @@ function tryAcquireLock(lockPath: string): string | null {
257
262
  // is idempotent, so the call is cheap when the dir already exists.
258
263
  mkdirSync(dirname(lockPath), { recursive: true });
259
264
 
265
+ const firstHolder = tryCreate(lockPath);
266
+ if (firstHolder === null) return null;
267
+ if (!isHolderStale(firstHolder)) return firstHolder;
268
+
269
+ log.info(
270
+ { lockPath, holder: firstHolder },
271
+ "consolidation: taking over stale lock (holder not running)",
272
+ );
273
+ try {
274
+ unlinkSync(lockPath);
275
+ } catch (err) {
276
+ const code = (err as NodeJS.ErrnoException).code;
277
+ if (code !== "ENOENT") {
278
+ log.warn(
279
+ { err, lockPath },
280
+ "consolidation: failed to unlink stale lock; reporting as locked",
281
+ );
282
+ return firstHolder;
283
+ }
284
+ }
285
+ // After unlink, the next `wx` create should succeed. If a third party
286
+ // raced in and re-acquired (vanishingly unlikely with one writer per
287
+ // workspace), surface their holder string rather than overwriting.
288
+ return tryCreate(lockPath);
289
+ }
290
+
291
+ /**
292
+ * Atomically create the lock file. Returns `null` on success, or the holder
293
+ * string read from the file when it already exists (`"unknown"` if the read
294
+ * itself fails). Rethrows any non-EEXIST errno from `openSync`.
295
+ */
296
+ function tryCreate(lockPath: string): string | null {
260
297
  let fd: number;
261
298
  try {
262
- // `wx` = create-if-not-exists, fail with EEXIST if it does.
263
299
  fd = openSync(lockPath, "wx");
264
300
  } catch (err) {
265
301
  if ((err as NodeJS.ErrnoException).code !== "EEXIST") throw err;
@@ -269,13 +305,10 @@ function tryAcquireLock(lockPath: string): string | null {
269
305
  return "unknown";
270
306
  }
271
307
  }
272
-
273
- // Best-effort PID + timestamp payload so a stale lock can be diagnosed.
274
- // The worker only cares that the file exists; the contents are advisory.
275
308
  try {
276
309
  writeSync(fd, `${process.pid} ${Date.now()}\n`);
277
310
  } catch {
278
- // best-effort
311
+ // best-effort — payload is advisory, the file's existence is the lock
279
312
  } finally {
280
313
  try {
281
314
  closeSync(fd);
@@ -286,6 +319,21 @@ function tryAcquireLock(lockPath: string): string | null {
286
319
  return null;
287
320
  }
288
321
 
322
+ /**
323
+ * A holder string is stale when its PID parses to a non-running process.
324
+ * The payload format is `<pid> <timestamp>` (see `tryCreate`'s write), but
325
+ * an unparseable / empty / `"unknown"` payload is also treated as stale:
326
+ * the only writer is `tryCreate` itself, so corruption indicates a partial
327
+ * write from a crashed prior holder rather than a live writer mid-flush.
328
+ */
329
+ function isHolderStale(holder: string): boolean {
330
+ const match = /^\d+/.exec(holder);
331
+ if (!match) return true;
332
+ const pid = Number.parseInt(match[0], 10);
333
+ if (!Number.isFinite(pid) || pid <= 0) return true;
334
+ return !isProcessAlive(pid);
335
+ }
336
+
289
337
  /**
290
338
  * Idempotent unlink of the lock file. Called from the `finally` block so a
291
339
  * crash in the wake path doesn't leave the lock stranded. ENOENT is swallowed
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Canonical `conversations.source` string for background memory v2
3
+ * consolidation runs. Lives in a tiny constants module so the route layer can
4
+ * recognize consolidation conversations without importing the consolidation
5
+ * job (which pulls in agent-wake + bootstrap dependencies).
6
+ */
7
+ export const MEMORY_V2_CONSOLIDATION_SOURCE = "memory_v2_consolidation";
@@ -29,22 +29,18 @@ import { getWorkspaceDir } from "../../util/platform.js";
29
29
  import type { DrizzleDb } from "../db-connection.js";
30
30
  import {
31
31
  type MemoryV2ConceptRowRecord,
32
- type MemoryV2SkillRowRecord,
33
32
  recordMemoryV2ActivationLog,
34
33
  } from "../memory-v2-activation-log-store.js";
35
34
  import {
36
35
  computeOwnActivation,
37
- computeSkillActivation,
38
36
  selectCandidates,
39
37
  selectInjections,
40
- selectSkillCandidates,
41
- selectSkillInjections,
42
38
  spreadActivation,
43
39
  } from "./activation.js";
44
40
  import { hydrate, save } from "./activation-store.js";
45
41
  import { getEdgeIndex } from "./edge-index.js";
46
42
  import { readPage, renderPageContent } from "./page-store.js";
47
- import { getSkillCapability } from "./skill-store.js";
43
+ import { getSkillCapability, isSkillSlug } from "./skill-store.js";
48
44
  import type { ActivationState, EverInjectedEntry } from "./types.js";
49
45
 
50
46
  const log = getLogger("memory-v2-injection");
@@ -85,14 +81,16 @@ export interface InjectMemoryV2BlockParams {
85
81
  */
86
82
  mode?: InjectMemoryV2Mode;
87
83
  config: AssistantConfig;
84
+ signal?: AbortSignal;
88
85
  }
89
86
 
90
87
  export interface InjectMemoryV2BlockResult {
91
88
  /**
92
- * Rendered `<memory>` block, ready to prepend to the current
93
- * user message — or `null` when nothing new is eligible for injection.
94
- * `null` is the cache-stable default: the caller adds nothing to the new
95
- * user message and prior attachments stay byte-identical.
89
+ * Inner content for the `<memory>` block, ready for the caller to wrap
90
+ * exactly once at injection time — or `null` when nothing new is eligible
91
+ * for injection. `null` is the cache-stable default: the caller adds
92
+ * nothing to the new user message and prior attachments stay
93
+ * byte-identical.
96
94
  */
97
95
  block: string | null;
98
96
  /**
@@ -127,30 +125,36 @@ export async function injectMemoryV2Block(
127
125
  nowText,
128
126
  messageId,
129
127
  config,
128
+ signal,
130
129
  } = params;
131
130
 
132
131
  const workspaceDir = getWorkspaceDir();
133
132
 
134
133
  // (1) Hydrate. Missing rows are normal at conversation start — proceed
135
134
  // with an effective empty prior state so the first turn can still inject.
135
+ throwIfAborted(signal);
136
136
  const priorState = await hydrate(database, conversationId);
137
137
 
138
138
  // (2) Topology. `getEdgeIndex` walks concept-page frontmatter and caches
139
139
  // the result module-locally; an empty workspace yields an empty index.
140
+ throwIfAborted(signal);
140
141
  const edgeIndex = await getEdgeIndex(workspaceDir);
141
142
 
142
143
  // (3) Candidate set: prior-state survivors above epsilon ∪ ANN top-50.
143
144
  // `selectCandidates` also returns `fromPrior` / `fromAnn` provenance sets so
144
145
  // telemetry can attribute each candidate back to its source.
146
+ throwIfAborted(signal);
145
147
  const { candidates, fromPrior, fromAnn } = await selectCandidates({
146
148
  priorState,
147
149
  userText: userMessage,
148
150
  assistantText: assistantMessage,
149
151
  nowText,
150
152
  config,
153
+ signal,
151
154
  });
152
155
 
153
156
  // (4) Own activation: A_o = d·prev + c_user·sim_u + c_a·sim_a + c_now·sim_n.
157
+ throwIfAborted(signal);
154
158
  const { activation: ownActivation, breakdown: ownBreakdown } =
155
159
  await computeOwnActivation({
156
160
  candidates,
@@ -159,9 +163,11 @@ export async function injectMemoryV2Block(
159
163
  assistantText: assistantMessage,
160
164
  nowText,
161
165
  config,
166
+ signal,
162
167
  });
163
168
 
164
169
  // (5) Spreading activation across the edge graph (k, hops from config).
170
+ throwIfAborted(signal);
165
171
  const { k, hops, top_k, epsilon } = config.memory.v2;
166
172
  const { final: finalActivation, contribution: spreadContribution } =
167
173
  spreadActivation(ownActivation, edgeIndex, k, hops);
@@ -182,30 +188,6 @@ export async function injectMemoryV2Block(
182
188
  });
183
189
  const slugsToRender = mode === "context-load" ? topNow : toInject;
184
190
 
185
- // (6b) Skill pipeline — a sibling pipeline to the concept-page one above.
186
- // Skills are stateless: no decay carry-over, no spread, no `everInjected`
187
- // dedup. The top-K relevant skills are re-presented every turn so the
188
- // agent can drop and pick them up freely.
189
- const skillCandidates = await selectSkillCandidates({
190
- userText: userMessage,
191
- assistantText: assistantMessage,
192
- nowText,
193
- config,
194
- topK: config.memory.v2.top_k_skills,
195
- });
196
- const { activation: skillActivation, breakdown: skillBreakdown } =
197
- await computeSkillActivation({
198
- candidates: skillCandidates,
199
- userText: userMessage,
200
- assistantText: assistantMessage,
201
- nowText,
202
- config,
203
- });
204
- const { topNow: topSkillIds } = selectSkillInjections({
205
- A: skillActivation,
206
- topK: config.memory.v2.top_k_skills,
207
- });
208
-
209
191
  // Build the next persisted state regardless of whether we render anything:
210
192
  // even on a "no new injection" turn, prior-state activations decay via the
211
193
  // candidate-set carry-forward and need to be rewritten so `epsilon`-trimmed
@@ -220,8 +202,10 @@ export async function injectMemoryV2Block(
220
202
  // just rendered all of them); on per-turn it's just the newly added slugs.
221
203
  // We append rather than reset so that compaction-driven eviction
222
204
  // (`evictCompactedTurns`) is the only path that can re-enable a previously-
223
- // injected slug. Skills do NOT enter `everInjected` they are stateless
224
- // and re-presented every turn.
205
+ // injected slug. Skill slugs (`skills/<id>`) participate in this dedup just
206
+ // like concept slugs — once attached on a turn, the cached attachment lives
207
+ // on that user message and the agent keeps seeing it across subsequent turns
208
+ // until compaction evicts the turn.
225
209
  const everInjectedSet = new Set(priorEverInjected.map((entry) => entry.slug));
226
210
  const newlyInjected = slugsToRender.filter(
227
211
  (slug) => !everInjectedSet.has(slug),
@@ -241,12 +225,31 @@ export async function injectMemoryV2Block(
241
225
 
242
226
  await save(database, conversationId, nextActivationState);
243
227
 
244
- // Record per-turn activation telemetry. This runs *before* the cache-stable
245
- // empty-block return so we capture diagnostics even on no-op turns. Failures
246
- // are warn-logged and never block memory injection.
228
+ // Render before recording telemetry so the activation log can mark slugs
229
+ // whose backing file is gone those are no-op renders that would otherwise
230
+ // be indistinguishable from successful "injected" rows in the log.
231
+ // `renderInjectionBlock` itself short-circuits on empty inputs.
232
+ const { block, missingSlugs } = await renderInjectionBlock(
233
+ workspaceDir,
234
+ slugsToRender,
235
+ );
236
+ const missingSlugSet = new Set(missingSlugs);
237
+ if (missingSlugs.length > 0) {
238
+ log.warn(
239
+ {
240
+ conversationId,
241
+ turn: currentTurn,
242
+ missingSlugs,
243
+ renderedCount: slugsToRender.length - missingSlugs.length,
244
+ },
245
+ "Memory v2 injection skipped slugs whose page was missing on disk — Qdrant index may be stale; consider reembed",
246
+ );
247
+ }
248
+
249
+ // Record per-turn activation telemetry. Failures are warn-logged and never
250
+ // block memory injection.
247
251
  const toInjectSet = new Set(toInject);
248
252
  const renderedSet = new Set(slugsToRender);
249
- const topSkillIdSet = new Set(topSkillIds);
250
253
  const conceptRows: MemoryV2ConceptRowRecord[] = [...candidates].map(
251
254
  (slug) => {
252
255
  const breakdown = ownBreakdown.get(slug);
@@ -260,6 +263,10 @@ export async function injectMemoryV2Block(
260
263
  // - per-turn: cached attachments from prior turns are still on the
261
264
  // user message, so prior-everInjected slugs are `in_context` and
262
265
  // the delta (`toInject`) is `injected`.
266
+ // `page_missing` overrides any "would-have-been-injected" status when
267
+ // `readPage` returned null for the slug — telemetry surfaces stale
268
+ // ANN/edge entries instead of silently masquerading as a successful
269
+ // injection.
263
270
  let status: MemoryV2ConceptRowRecord["status"];
264
271
  if (mode === "context-load") {
265
272
  status = renderedSet.has(slug) ? "injected" : "not_injected";
@@ -270,6 +277,9 @@ export async function injectMemoryV2Block(
270
277
  } else {
271
278
  status = "not_injected";
272
279
  }
280
+ if (status === "injected" && missingSlugSet.has(slug)) {
281
+ status = "page_missing";
282
+ }
273
283
  return {
274
284
  slug,
275
285
  finalActivation: finalActivation.get(slug) ?? 0,
@@ -278,6 +288,9 @@ export async function injectMemoryV2Block(
278
288
  simUser: breakdown?.simUser ?? 0,
279
289
  simAssistant: breakdown?.simAssistant ?? 0,
280
290
  simNow: breakdown?.simNow ?? 0,
291
+ simUserRerankBoost: breakdown?.simUserRerankBoost ?? 0,
292
+ simAssistantRerankBoost: breakdown?.simAssistantRerankBoost ?? 0,
293
+ inRerankPool: breakdown?.inRerankPool ?? false,
281
294
  spreadContribution: spreadContribution.get(slug) ?? 0,
282
295
  source:
283
296
  inPrior && inAnn ? "both" : inPrior ? "prior_state" : "ann_top50",
@@ -287,19 +300,6 @@ export async function injectMemoryV2Block(
287
300
  );
288
301
  conceptRows.sort((a, b) => b.finalActivation - a.finalActivation);
289
302
 
290
- const skillRows: MemoryV2SkillRowRecord[] = [...skillCandidates].map((id) => {
291
- const breakdown = skillBreakdown.get(id);
292
- return {
293
- id,
294
- activation: skillActivation.get(id) ?? 0,
295
- simUser: breakdown?.simUser ?? 0,
296
- simAssistant: breakdown?.simAssistant ?? 0,
297
- simNow: breakdown?.simNow ?? 0,
298
- status: topSkillIdSet.has(id) ? "injected" : "not_injected",
299
- };
300
- });
301
- skillRows.sort((a, b) => b.activation - a.activation);
302
-
303
303
  const v2Cfg = config.memory.v2;
304
304
  try {
305
305
  recordMemoryV2ActivationLog({
@@ -307,7 +307,6 @@ export async function injectMemoryV2Block(
307
307
  turn: currentTurn,
308
308
  mode,
309
309
  concepts: conceptRows,
310
- skills: skillRows,
311
310
  config: {
312
311
  d: v2Cfg.d,
313
312
  c_user: v2Cfg.c_user,
@@ -316,7 +315,6 @@ export async function injectMemoryV2Block(
316
315
  k: v2Cfg.k,
317
316
  hops: v2Cfg.hops,
318
317
  top_k: v2Cfg.top_k,
319
- top_k_skills: v2Cfg.top_k_skills,
320
318
  epsilon: v2Cfg.epsilon,
321
319
  },
322
320
  });
@@ -327,51 +325,68 @@ export async function injectMemoryV2Block(
327
325
  );
328
326
  }
329
327
 
330
- // (7) Cache-stable empty path: nothing to render AND no ranked skills.
331
- if (slugsToRender.length === 0 && topSkillIds.length === 0) {
332
- return { block: null, toInject: [] };
333
- }
334
-
335
- // (8) Render. Both `topNow` and `toInject` are activation-descending
336
- // (selectInjections sorts before slicing), so `slugsToRender` doubles as
337
- // the render order. Per-turn: only the new slugs render (prior turns'
338
- // attachments stay cached on prior user messages). Context-load: full
339
- // top-K renders so the fresh user message gets a complete activation dump.
340
- // Skills are appended after concept-page sections.
341
- const block = await renderInjectionBlock(
342
- workspaceDir,
343
- slugsToRender,
344
- topSkillIds,
345
- );
346
-
347
328
  return { block, toInject: newlyInjected };
348
329
  }
349
330
 
331
+ function throwIfAborted(signal: AbortSignal | undefined): void {
332
+ if (signal?.aborted) {
333
+ throw new DOMException("Aborted", "AbortError");
334
+ }
335
+ }
336
+
350
337
  // ---------------------------------------------------------------------------
351
338
  // Internal helpers
352
339
  // ---------------------------------------------------------------------------
353
340
 
341
+ interface RenderInjectionBlockResult {
342
+ /**
343
+ * Inner content for the `<memory>` block (concept-page sections + optional
344
+ * skills suffix), or `null` when both the concept-page list and the skill
345
+ * list collapse to empty after cache misses (no on-disk pages, no
346
+ * resolvable skill ids). Returned unwrapped so the caller can wrap it
347
+ * exactly once at injection time, matching v1's contract: callers that
348
+ * cache the value (`lastInjectedBlock`) or persist it (`memoryInjectedBlock`
349
+ * in message metadata) re-wrap on use, and storing the wrapped form here
350
+ * caused a double wrap on reinject after compaction and on rehydrate from
351
+ * DB.
352
+ */
353
+ block: string | null;
354
+ /**
355
+ * Slugs that `readPage` returned null for. Surfaced so the caller can
356
+ * mark them in the activation log (`status: "page_missing"`) and emit
357
+ * a warning — silent drops here previously masked stale Qdrant /
358
+ * edge-index entries that pointed at pages no longer on disk.
359
+ */
360
+ missingSlugs: string[];
361
+ }
362
+
354
363
  /**
355
- * Render the `<memory>` block for a list of slugs and a list of
356
- * ranked skill ids.
364
+ * Render the inner content of the `<memory>` block for a list of slugs.
365
+ * The caller wraps the result in `<memory>...</memory>` exactly once at
366
+ * injection time.
367
+ *
368
+ * The slug list is partitioned by prefix: slugs starting with `skills/`
369
+ * resolve to a `SkillEntry` via `getSkillCapability` and render under the
370
+ * trailing `### Skills You Can Use` subsection; everything else is read
371
+ * from disk via `readPage` and rendered as a concept-page section.
357
372
  *
358
373
  * Concept pages are read in parallel via `readPage`. Pages whose file has
359
374
  * gone missing between selection and render (e.g. consolidation deleted
360
- * them) are silently dropped the activation state still records them in
361
- * `everInjected` so we don't keep re-attempting on every turn.
375
+ * them, folder reorg renamed the slug) are dropped from the rendered
376
+ * block but reported back via `missingSlugs` so callers can surface the
377
+ * divergence.
362
378
  *
363
- * Skill ids are looked up via `getSkillCapability`. Ids that the cache no
364
- * longer knows (e.g. uninstalled mid-run) are silently dropped, mirroring
365
- * the missing-pages behavior.
379
+ * Skill slugs whose entry the cache no longer knows (e.g. uninstalled
380
+ * mid-run) are silently dropped, mirroring the missing-pages behavior but
381
+ * without entering `missingSlugs` — the skill catalog is the source of
382
+ * truth for skill availability, not on-disk concept pages, so a missing
383
+ * skill is an expected catalog-level outcome rather than a stale-index
384
+ * bug.
366
385
  *
367
- * The block shape is the §5 layout from the design doc, with an optional
368
- * trailing skills subsection. Each concept-page section reproduces the page
369
- * as it lives on disk — frontmatter (`edges`, `ref_files`) plus body — so
370
- * the agent sees the page's edges and any referenced media paths alongside
371
- * the prose:
386
+ * The block shape mirrors the §5 layout concept-page sections first,
387
+ * skills subsection last preserving the prompt format the agent sees:
372
388
  *
373
- * <memory>
374
- * ### <slug-1>
389
+ * ### <concept-slug-1>
375
390
  * ---
376
391
  * edges:
377
392
  * - <neighbor-slug>
@@ -380,7 +395,7 @@ export async function injectMemoryV2Block(
380
395
  * ---
381
396
  * <body-1>
382
397
  *
383
- * ### <slug-2>
398
+ * ### <concept-slug-2>
384
399
  * ---
385
400
  * edges: []
386
401
  * ref_files: []
@@ -390,34 +405,36 @@ export async function injectMemoryV2Block(
390
405
  * ### Skills You Can Use
391
406
  * - <skill-1 content>
392
407
  * - <skill-2 content>
393
- * </memory>
394
- *
395
- * Returns `null` when both lists collapse to empty after cache misses so
396
- * the caller can fall through to its empty-block path instead of attaching
397
- * an empty `<memory>` wrapper.
398
408
  */
399
409
  async function renderInjectionBlock(
400
410
  workspaceDir: string,
401
411
  slugs: string[],
402
- skillIds: string[],
403
- ): Promise<string | null> {
412
+ ): Promise<RenderInjectionBlockResult> {
413
+ const conceptSlugs = slugs.filter((s) => !isSkillSlug(s));
414
+ const skillSlugs = slugs.filter((s) => isSkillSlug(s));
415
+
404
416
  const pages = await Promise.all(
405
- slugs.map(async (slug) => {
417
+ conceptSlugs.map(async (slug) => {
406
418
  const page = await readPage(workspaceDir, slug);
407
- return page ? { slug, content: renderPageContent(page).trim() } : null;
419
+ return { slug, page };
408
420
  }),
409
421
  );
410
422
 
411
423
  const sections: string[] = [];
412
- for (const entry of pages) {
413
- if (!entry || entry.content.length === 0) continue;
414
- sections.push(`### ${entry.slug}\n${entry.content}`);
424
+ const missingSlugs: string[] = [];
425
+ for (const { slug, page } of pages) {
426
+ if (!page) {
427
+ missingSlugs.push(slug);
428
+ continue;
429
+ }
430
+ const content = renderPageContent(page).trim();
431
+ if (content.length === 0) continue;
432
+ sections.push(`### ${slug}\n${content}`);
415
433
  }
416
434
 
417
- // v2's skills collection is skills-only, so the activation suffix always applies.
418
435
  const skillLines: string[] = [];
419
- for (const id of skillIds) {
420
- const entry = getSkillCapability(id);
436
+ for (const slug of skillSlugs) {
437
+ const entry = getSkillCapability(slug);
421
438
  if (!entry) continue;
422
439
  skillLines.push(`- ${entry.content} → use skill_load to activate`);
423
440
  }
@@ -425,7 +442,10 @@ async function renderInjectionBlock(
425
442
  sections.push(`### Skills You Can Use\n${skillLines.join("\n")}`);
426
443
  }
427
444
 
428
- if (sections.length === 0) return null;
445
+ if (sections.length === 0) return { block: null, missingSlugs };
429
446
 
430
- return `<memory>\n${sections.join("\n\n")}\n</memory>`;
447
+ return {
448
+ block: sections.join("\n\n"),
449
+ missingSlugs,
450
+ };
431
451
  }