@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
@@ -2,6 +2,7 @@ import { v4 as uuid } from "uuid";
2
2
 
3
3
  import { getConfig } from "../config/loader.js";
4
4
  import type { ServerMessage } from "../daemon/message-protocol.js";
5
+ import * as pendingInteractions from "../runtime/pending-interactions.js";
5
6
  import { redactSensitiveFields } from "../security/redaction.js";
6
7
  import type { ExecutionTarget } from "../tools/types.js";
7
8
  import { AssistantError, ErrorCode } from "../util/errors.js";
@@ -81,10 +82,36 @@ export class PermissionPrompter {
81
82
 
82
83
  const requestId = uuid();
83
84
 
85
+ // Self-register in pendingInteractions so /v1/confirm can route the
86
+ // response to this conversation without going through broadcastMessage.
87
+ if (conversationId) {
88
+ pendingInteractions.register(requestId, {
89
+ conversationId,
90
+ kind: "confirmation",
91
+ confirmationDetails: {
92
+ toolName,
93
+ input: redactSensitiveFields(input),
94
+ riskLevel,
95
+ executionTarget,
96
+ allowlistOptions: allowlistOptions.map((o) => ({
97
+ label: o.label,
98
+ description: o.description,
99
+ pattern: o.pattern,
100
+ })),
101
+ scopeOptions: scopeOptions.map((o) => ({
102
+ label: o.label,
103
+ scope: o.scope,
104
+ })),
105
+ persistentDecisionsAllowed: persistentDecisionsAllowed ?? true,
106
+ },
107
+ });
108
+ }
109
+
84
110
  return new Promise((resolve, reject) => {
85
111
  const timeoutMs = getConfig().timeouts.permissionTimeoutSec * 1000;
86
112
  const timer = setTimeout(() => {
87
113
  this.pending.delete(requestId);
114
+ pendingInteractions.resolve(requestId);
88
115
  log.warn(
89
116
  { requestId, toolName },
90
117
  "Permission prompt timed out, defaulting to deny",
@@ -109,6 +136,7 @@ export class PermissionPrompter {
109
136
  if (this.pending.has(requestId)) {
110
137
  clearTimeout(timer);
111
138
  this.pending.delete(requestId);
139
+ pendingInteractions.resolve(requestId);
112
140
  resolve({ decision: "deny", wasAbort: true });
113
141
  }
114
142
  };
@@ -174,6 +202,9 @@ export class PermissionPrompter {
174
202
  }
175
203
  clearTimeout(pending.timer);
176
204
  this.pending.delete(requestId);
205
+ // Idempotent — approval-routes already calls pendingInteractions.resolve()
206
+ // before routing here, but we call it defensively for non-route paths.
207
+ pendingInteractions.resolve(requestId);
177
208
  pending.resolve({
178
209
  decision,
179
210
  selectedPattern,
@@ -191,6 +222,7 @@ export class PermissionPrompter {
191
222
  for (const [requestId, pending] of this.pending) {
192
223
  clearTimeout(pending.timer);
193
224
  this.pending.delete(requestId);
225
+ pendingInteractions.resolve(requestId);
194
226
  pending.resolve({
195
227
  decision: "deny",
196
228
  wasSystemCancel: true,
@@ -205,8 +237,9 @@ export class PermissionPrompter {
205
237
  }
206
238
 
207
239
  dispose(): void {
208
- for (const [, pending] of this.pending) {
240
+ for (const [requestId, pending] of this.pending) {
209
241
  clearTimeout(pending.timer);
242
+ pendingInteractions.resolve(requestId);
210
243
  pending.reject(
211
244
  new AssistantError("Prompter disposed", ErrorCode.INTERNAL_ERROR),
212
245
  );
@@ -81,8 +81,12 @@ export class SecretPrompter {
81
81
 
82
82
  this.pending.set(requestId, { resolve, reject, timer });
83
83
 
84
- // pendingInteractions.register is now handled by broadcastMessage
85
- // when the secret_request event is published to the hub.
84
+ // Self-register in pendingInteractions so /v1/secret can route the
85
+ // response to this conversation without relying on broadcastMessage.
86
+ pendingInteractions.register(requestId, {
87
+ conversationId: effectiveConversationId,
88
+ kind: "secret",
89
+ });
86
90
 
87
91
  const config = getConfig();
88
92
  const msg: SecretRequestMessage = {
@@ -3,7 +3,7 @@
3
3
  * drives the per-turn injection sequence consumed by
4
4
  * `applyRuntimeInjections`.
5
5
  *
6
- * Each of the eight default injectors reads its per-turn inputs from
6
+ * Each default injector reads its per-turn inputs from
7
7
  * `ctx.injectionInputs` (see {@link TurnInjectionInputs}), runs its gating
8
8
  * conditions (injection mode, feature flags, channel type, null-input
9
9
  * short-circuits), and returns an {@link InjectionBlock} with a
@@ -12,6 +12,7 @@
12
12
  *
13
13
  * | name | order | placement |
14
14
  * | ------------------------ | ----- | ----------------------- |
15
+ * | `disk-pressure-warning` | 5 | prepend-user-tail |
15
16
  * | `workspace-context` | 10 | prepend-user-tail |
16
17
  * | `unified-turn-context` | 20 | prepend-user-tail |
17
18
  * | `pkb-context` | 30 | after-memory-prefix |
@@ -45,6 +46,7 @@
45
46
 
46
47
  import { resolve } from "node:path";
47
48
 
49
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
48
50
  import { getConfig } from "../../config/loader.js";
49
51
  import { getInContextPkbPaths } from "../../daemon/pkb-context-tracker.js";
50
52
  import { buildPkbReminder } from "../../daemon/pkb-reminder-builder.js";
@@ -74,7 +76,7 @@ const PKB_HINT_THRESHOLD = 0.5;
74
76
  const PKB_HINT_ARCHIVE_THRESHOLD = 0.7;
75
77
 
76
78
  /**
77
- * Fixed order values for the eight default injectors. Exported so tests —
79
+ * Fixed order values for the default injectors. Exported so tests —
78
80
  * and any future integration code — can assert ordering without re-deriving
79
81
  * the constants.
80
82
  *
@@ -83,6 +85,7 @@ const PKB_HINT_ARCHIVE_THRESHOLD = 0.7;
83
85
  * without renumbering the defaults.
84
86
  */
85
87
  export const DEFAULT_INJECTOR_ORDER = {
88
+ diskPressureWarning: 5,
86
89
  workspaceContext: 10,
87
90
  unifiedTurnContext: 20,
88
91
  pkbContext: 30,
@@ -98,6 +101,35 @@ function readInjectionInputs(ctx: TurnContext): TurnInjectionInputs {
98
101
  return ctx.injectionInputs ?? {};
99
102
  }
100
103
 
104
+ export const DISK_PRESSURE_WARNING_PROMPT = `<disk_pressure_warning>
105
+ Disk usage is critically low: this assistant is in storage cleanup mode because the workspace volume is at least 95% full.
106
+
107
+ In your first paragraph, warn the user that storage is critically low and that normal work is suspended until space is freed.
108
+
109
+ Then help the user clean up storage. Prefer safe inspection steps first, such as checking available space and finding large directories. Ask before deleting files or caches unless the user has already clearly approved the specific cleanup action.
110
+
111
+ Do not work on unrelated tasks until disk usage drops below the critical threshold or the user explicitly overrides the lock. Background processes and messages from trusted contacts are blocked while this cleanup mode is active.
112
+ </disk_pressure_warning>`;
113
+
114
+ function isSafeStorageLimitsEnabled(): boolean {
115
+ return isAssistantFeatureFlagEnabled("safe-storage-limits", getConfig());
116
+ }
117
+
118
+ const diskPressureWarningInjector: Injector = {
119
+ name: "disk-pressure-warning",
120
+ order: DEFAULT_INJECTOR_ORDER.diskPressureWarning,
121
+ async produce(ctx: TurnContext): Promise<InjectionBlock | null> {
122
+ if (!isSafeStorageLimitsEnabled()) return null;
123
+ const inputs = readInjectionInputs(ctx);
124
+ if (!inputs.diskPressureContext?.cleanupModeActive) return null;
125
+ return {
126
+ id: "disk-pressure-warning",
127
+ text: DISK_PRESSURE_WARNING_PROMPT,
128
+ placement: "prepend-user-tail",
129
+ };
130
+ },
131
+ };
132
+
101
133
  /**
102
134
  * v2 read-side cutover guard. The `pkb-context` injector silences itself
103
135
  * under v2 because the `<knowledge_base>` block surfaces PKB content the v2
@@ -520,6 +552,7 @@ export const defaultInjectorsPlugin: Plugin = {
520
552
  },
521
553
  },
522
554
  injectors: [
555
+ diskPressureWarningInjector,
523
556
  workspaceContextInjector,
524
557
  unifiedTurnContextInjector,
525
558
  pkbContextInjector,
@@ -72,12 +72,6 @@ export interface GraphMemoryPayload {
72
72
  * Passed as a second argument to {@link runDefaultMemoryRetrieval} rather
73
73
  * than threaded through {@link MemoryArgs} to keep the plugin-facing
74
74
  * pipeline surface minimal.
75
- *
76
- * The per-turn abort signal lives on {@link MemoryArgs.signal} instead of
77
- * here so the pipeline runner's `linkAbortSignal` can swap it for an
78
- * internally-linked signal — that way a plugin timeout actually cancels
79
- * the underlying `prepareMemory` work instead of letting it run after
80
- * `Promise.race` has already rejected.
81
75
  */
82
76
  export interface DefaultMemoryRetrievalDeps {
83
77
  /** Live message list for this turn (pre-injection). */
@@ -101,6 +95,11 @@ export interface DefaultMemoryRetrievalDeps {
101
95
  * trusted) or a single {@link GraphMemoryPayload} wrapping the graph
102
96
  * retriever's full output. The agent loop narrows via
103
97
  * {@link DEFAULT_MEMORY_GRAPH_KIND} to consume it.
98
+ *
99
+ * Memory retrieval blocks the turn — there is no soft timeout here. Memory
100
+ * is critical context, and silently dropping it produces a worse outcome
101
+ * than a slower turn. Cancellation still works via `args.signal`, which is
102
+ * threaded into `prepareMemory`.
104
103
  */
105
104
  export async function runDefaultMemoryRetrieval(
106
105
  args: MemoryArgs,
@@ -784,6 +784,8 @@ export interface TurnInjectionInputs {
784
784
  * context (unified turn context, etc.). Drives per-injector gating.
785
785
  */
786
786
  readonly mode?: InjectionMode;
787
+ /** Disk-pressure cleanup-mode context or null to skip the warning. */
788
+ readonly diskPressureContext?: DiskPressureInjectionContext | null;
787
789
  /** Workspace top-level context text (`<workspace>...`) or null to skip. */
788
790
  readonly workspaceTopLevelContext?: string | null;
789
791
  /** Pre-built unified-turn-context text (`<turn_context>...`) or null to skip. */
@@ -860,6 +862,11 @@ export interface TurnInjectionInputs {
860
862
  readonly isNonInteractive?: boolean;
861
863
  }
862
864
 
865
+ export interface DiskPressureInjectionContext {
866
+ /** True when the current turn is allowed to run only for storage cleanup. */
867
+ readonly cleanupModeActive: boolean;
868
+ }
869
+
863
870
  /**
864
871
  * Per-turn execution context threaded through every middleware invocation.
865
872
  *
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Auxiliary message injection for proactive artifacts.
3
+ *
4
+ * Injects an assistant message into a conversation without going through
5
+ * the normal agent loop. Defers injection while the conversation is
6
+ * actively processing to preserve chronological message ordering.
7
+ */
8
+
9
+ import { createAssistantMessage } from "../agent/message-types.js";
10
+ import { findConversation } from "../daemon/conversation-store.js";
11
+ import { addMessage } from "../memory/conversation-crud.js";
12
+ import type { BroadcastFn } from "../notifications/adapters/macos.js";
13
+ import { getLogger } from "../util/logger.js";
14
+
15
+ const log = getLogger("aux-message-injector");
16
+ const IDLE_POLL_MS = 200;
17
+ const IDLE_TIMEOUT_MS = 60_000;
18
+
19
+ async function waitForIdle(conversationId: string): Promise<boolean> {
20
+ const start = Date.now();
21
+ while (Date.now() - start < IDLE_TIMEOUT_MS) {
22
+ const conv = findConversation(conversationId);
23
+ if (!conv || !conv.processing) return true;
24
+ await new Promise((resolve) => setTimeout(resolve, IDLE_POLL_MS));
25
+ }
26
+ return false;
27
+ }
28
+
29
+ export async function injectAuxAssistantMessage(params: {
30
+ conversationId: string;
31
+ text: string;
32
+ broadcastMessage: BroadcastFn;
33
+ }): Promise<void> {
34
+ const conv = findConversation(params.conversationId);
35
+ if (conv?.processing) {
36
+ const reachedIdle = await waitForIdle(params.conversationId);
37
+ if (!reachedIdle) {
38
+ log.warn(
39
+ { conversationId: params.conversationId },
40
+ "Timed out waiting for conversation idle; injecting anyway",
41
+ );
42
+ }
43
+ }
44
+
45
+ const msg = await addMessage(
46
+ params.conversationId,
47
+ "assistant",
48
+ JSON.stringify([{ type: "text", text: params.text }]),
49
+ undefined,
50
+ { skipIndexing: true },
51
+ );
52
+
53
+ const current = findConversation(params.conversationId);
54
+ if (current && !current.processing) {
55
+ current.getMessages().push(createAssistantMessage(params.text));
56
+
57
+ params.broadcastMessage({
58
+ type: "assistant_text_delta",
59
+ text: params.text,
60
+ conversationId: params.conversationId,
61
+ });
62
+ params.broadcastMessage({
63
+ type: "message_complete",
64
+ conversationId: params.conversationId,
65
+ messageId: msg.id,
66
+ source: "aux",
67
+ });
68
+ }
69
+
70
+ params.broadcastMessage({
71
+ type: "conversation_list_invalidated",
72
+ reason: "reordered",
73
+ });
74
+ }
@@ -0,0 +1,226 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ type DecisionOutput,
5
+ formatTranscript,
6
+ parseDecisionOutput,
7
+ } from "./decision.js";
8
+
9
+ describe("parseDecisionOutput", () => {
10
+ test("parses SHOULD_BUILD: yes with all fields correctly", () => {
11
+ const text = `SHOULD_BUILD: yes
12
+ ARTIFACT_TYPE: app
13
+ ARTIFACT_TITLE: Sarah's Marathon Training Pace Calculator
14
+ ARTIFACT_DESCRIPTION: An interactive pace calculator that accounts for Sarah's goal of a sub-4-hour marathon, her current 9:30/mile easy pace, and the hilly terrain of the Boston course.`;
15
+
16
+ const result = parseDecisionOutput(text);
17
+ expect(result).toEqual({
18
+ shouldBuild: true,
19
+ artifactType: "app",
20
+ artifactTitle: "Sarah's Marathon Training Pace Calculator",
21
+ artifactDescription:
22
+ "An interactive pace calculator that accounts for Sarah's goal of a sub-4-hour marathon, her current 9:30/mile easy pace, and the hilly terrain of the Boston course.",
23
+ });
24
+ });
25
+
26
+ test("parses SHOULD_BUILD: no with skip reason", () => {
27
+ const text = `SHOULD_BUILD: no
28
+ SKIP_REASON: The conversation is too early and generic — the user has only asked a factual question with no personal context.`;
29
+
30
+ const result = parseDecisionOutput(text);
31
+ expect(result).toEqual({
32
+ shouldBuild: false,
33
+ skipReason:
34
+ "The conversation is too early and generic — the user has only asked a factual question with no personal context.",
35
+ });
36
+ });
37
+
38
+ test("parses SHOULD_BUILD: no without skip reason defaults to 'no reason given'", () => {
39
+ const text = `SHOULD_BUILD: no`;
40
+
41
+ const result = parseDecisionOutput(text);
42
+ expect(result).toEqual({
43
+ shouldBuild: false,
44
+ skipReason: "no reason given",
45
+ });
46
+ });
47
+
48
+ test("returns null for missing SHOULD_BUILD line", () => {
49
+ const text = `ARTIFACT_TYPE: app
50
+ ARTIFACT_TITLE: Some Title
51
+ ARTIFACT_DESCRIPTION: Some description.`;
52
+
53
+ const result = parseDecisionOutput(text);
54
+ expect(result).toBeNull();
55
+ });
56
+
57
+ test("returns null when yes but ARTIFACT_TYPE is missing", () => {
58
+ const text = `SHOULD_BUILD: yes
59
+ ARTIFACT_TITLE: Some Title
60
+ ARTIFACT_DESCRIPTION: Some description.`;
61
+
62
+ const result = parseDecisionOutput(text);
63
+ expect(result).toBeNull();
64
+ });
65
+
66
+ test("returns null when yes but ARTIFACT_TYPE is invalid", () => {
67
+ const text = `SHOULD_BUILD: yes
68
+ ARTIFACT_TYPE: widget
69
+ ARTIFACT_TITLE: Some Title
70
+ ARTIFACT_DESCRIPTION: Some description.`;
71
+
72
+ const result = parseDecisionOutput(text);
73
+ expect(result).toBeNull();
74
+ });
75
+
76
+ test("returns null when yes but ARTIFACT_TITLE is missing", () => {
77
+ const text = `SHOULD_BUILD: yes
78
+ ARTIFACT_TYPE: document
79
+ ARTIFACT_DESCRIPTION: Some description.`;
80
+
81
+ const result = parseDecisionOutput(text);
82
+ expect(result).toBeNull();
83
+ });
84
+
85
+ test("returns null when yes but ARTIFACT_DESCRIPTION is missing", () => {
86
+ const text = `SHOULD_BUILD: yes
87
+ ARTIFACT_TYPE: document
88
+ ARTIFACT_TITLE: Some Title`;
89
+
90
+ const result = parseDecisionOutput(text);
91
+ expect(result).toBeNull();
92
+ });
93
+
94
+ test("returns null when yes but ARTIFACT_TITLE is empty", () => {
95
+ const text = `SHOULD_BUILD: yes
96
+ ARTIFACT_TYPE: app
97
+ ARTIFACT_TITLE:
98
+ ARTIFACT_DESCRIPTION: Some description.`;
99
+
100
+ const result = parseDecisionOutput(text);
101
+ expect(result).toBeNull();
102
+ });
103
+
104
+ test("handles multi-line ARTIFACT_DESCRIPTION", () => {
105
+ const text = `SHOULD_BUILD: yes
106
+ ARTIFACT_TYPE: document
107
+ ARTIFACT_TITLE: Jake's Q3 OKR Tracker
108
+ ARTIFACT_DESCRIPTION: A structured comparison table for Jake's three competing priorities:
109
+ scaling the data pipeline from 10M to 50M events/day,
110
+ hiring two senior engineers by September,
111
+ and reducing p99 latency below 200ms.`;
112
+
113
+ const result = parseDecisionOutput(text) as DecisionOutput & {
114
+ shouldBuild: true;
115
+ };
116
+ expect(result).not.toBeNull();
117
+ expect(result.shouldBuild).toBe(true);
118
+ expect(result.artifactType).toBe("document");
119
+ expect(result.artifactTitle).toBe("Jake's Q3 OKR Tracker");
120
+ expect(result.artifactDescription).toContain(
121
+ "A structured comparison table",
122
+ );
123
+ expect(result.artifactDescription).toContain(
124
+ "reducing p99 latency below 200ms",
125
+ );
126
+ });
127
+
128
+ test("handles case-insensitive SHOULD_BUILD value", () => {
129
+ const text = `SHOULD_BUILD: Yes
130
+ ARTIFACT_TYPE: app
131
+ ARTIFACT_TITLE: Test Title
132
+ ARTIFACT_DESCRIPTION: Test description.`;
133
+
134
+ const result = parseDecisionOutput(text);
135
+ expect(result).not.toBeNull();
136
+ expect(result!.shouldBuild).toBe(true);
137
+ });
138
+
139
+ test("handles case-insensitive ARTIFACT_TYPE value", () => {
140
+ const text = `SHOULD_BUILD: yes
141
+ ARTIFACT_TYPE: Document
142
+ ARTIFACT_TITLE: Test Title
143
+ ARTIFACT_DESCRIPTION: Test description.`;
144
+
145
+ const result = parseDecisionOutput(text);
146
+ expect(result).not.toBeNull();
147
+ expect((result as { artifactType: string }).artifactType).toBe("document");
148
+ });
149
+ });
150
+
151
+ describe("formatTranscript", () => {
152
+ test("formats plain text messages correctly", () => {
153
+ const messages = [
154
+ { role: "user", content: "Hello, I need help with my project" },
155
+ {
156
+ role: "assistant",
157
+ content: "I'd be happy to help! What kind of project?",
158
+ },
159
+ {
160
+ role: "user",
161
+ content: "I'm building a fitness tracker for marathon training",
162
+ },
163
+ ];
164
+
165
+ const result = formatTranscript(messages);
166
+ expect(result).toBe(
167
+ `[User]: Hello, I need help with my project
168
+
169
+ [Assistant]: I'd be happy to help! What kind of project?
170
+
171
+ [User]: I'm building a fitness tracker for marathon training`,
172
+ );
173
+ });
174
+
175
+ test("handles JSON content blocks", () => {
176
+ const messages = [
177
+ {
178
+ role: "user",
179
+ content: JSON.stringify([{ type: "text", text: "What is 2+2?" }]),
180
+ },
181
+ {
182
+ role: "assistant",
183
+ content: JSON.stringify([
184
+ { type: "text", text: "The answer is 4." },
185
+ { type: "text", text: "Would you like to know more?" },
186
+ ]),
187
+ },
188
+ ];
189
+
190
+ const result = formatTranscript(messages);
191
+ expect(result).toBe(
192
+ `[User]: What is 2+2?
193
+
194
+ [Assistant]: The answer is 4.
195
+ Would you like to know more?`,
196
+ );
197
+ });
198
+
199
+ test("handles mixed JSON and plain text messages", () => {
200
+ const messages = [
201
+ {
202
+ role: "user",
203
+ content: JSON.stringify([
204
+ { type: "text", text: "Help me plan my week" },
205
+ ]),
206
+ },
207
+ { role: "assistant", content: "Sure, what do you have coming up?" },
208
+ ];
209
+
210
+ const result = formatTranscript(messages);
211
+ expect(result).toBe(
212
+ `[User]: Help me plan my week
213
+
214
+ [Assistant]: Sure, what do you have coming up?`,
215
+ );
216
+ });
217
+
218
+ test("handles unknown roles", () => {
219
+ const messages = [
220
+ { role: "system", content: "You are a helpful assistant" },
221
+ ];
222
+
223
+ const result = formatTranscript(messages);
224
+ expect(result).toBe("[system]: You are a helpful assistant");
225
+ });
226
+ });
@@ -0,0 +1,165 @@
1
+ export type DecisionOutput =
2
+ | { shouldBuild: false; skipReason: string }
3
+ | {
4
+ shouldBuild: true;
5
+ artifactType: "app" | "document";
6
+ artifactTitle: string;
7
+ artifactDescription: string;
8
+ };
9
+
10
+ export function buildDecisionPrompt(transcript: string): string {
11
+ return `You are deciding whether to proactively build a personalized artifact for the user based on their conversation so far.
12
+
13
+ Read the conversation below carefully. Your job:
14
+ 1. Identify what the user cares about — their goals, context, specific details they've shared.
15
+ 2. Decide: should we build a small interactive app or document that would delight this specific user?
16
+ 3. Quality test: Could you have built the same thing for any random person? If yes, too generic — output SHOULD_BUILD: no.
17
+
18
+ Rules:
19
+ - Only say yes if you can build something SPECIFIC to this user's situation, using details from their conversation.
20
+ - An "app" is a small interactive web application (calculator, tracker, visualizer, planner, etc.)
21
+ - A "document" is a structured reference (checklist, guide, comparison table, template, etc.)
22
+ - The title and description must reference specifics from the conversation — names, numbers, goals, constraints the user mentioned.
23
+ - Do NOT include a MESSAGE field.
24
+
25
+ Conversation:
26
+ ${transcript}
27
+
28
+ Respond in EXACTLY this format (no extra text before or after):
29
+
30
+ SHOULD_BUILD: [yes|no]
31
+ SKIP_REASON: [required if no — why this conversation isn't a good fit]
32
+ ARTIFACT_TYPE: [app|document]
33
+ ARTIFACT_TITLE: [specific title seeded with user context]
34
+ ARTIFACT_DESCRIPTION: [1-3 sentence build spec with user-specific details]
35
+
36
+ If SHOULD_BUILD is no, omit ARTIFACT_TYPE, ARTIFACT_TITLE, and ARTIFACT_DESCRIPTION.
37
+ If SHOULD_BUILD is yes, omit SKIP_REASON.`;
38
+ }
39
+
40
+ export function parseDecisionOutput(text: string): DecisionOutput | null {
41
+ const lines = text.trim().split("\n");
42
+
43
+ const shouldBuildLine = lines.find((line) =>
44
+ line.trim().startsWith("SHOULD_BUILD:"),
45
+ );
46
+ if (!shouldBuildLine) return null;
47
+
48
+ const shouldBuildValue = shouldBuildLine
49
+ .split(":")
50
+ .slice(1)
51
+ .join(":")
52
+ .trim()
53
+ .toLowerCase();
54
+
55
+ if (shouldBuildValue === "no") {
56
+ const skipReasonLine = lines.find((line) =>
57
+ line.trim().startsWith("SKIP_REASON:"),
58
+ );
59
+ const skipReason = skipReasonLine
60
+ ? skipReasonLine.split(":").slice(1).join(":").trim()
61
+ : "no reason given";
62
+ return { shouldBuild: false, skipReason };
63
+ }
64
+
65
+ if (shouldBuildValue === "yes") {
66
+ const artifactTypeLine = lines.find((line) =>
67
+ line.trim().startsWith("ARTIFACT_TYPE:"),
68
+ );
69
+ if (!artifactTypeLine) return null;
70
+ const artifactType = artifactTypeLine
71
+ .split(":")
72
+ .slice(1)
73
+ .join(":")
74
+ .trim()
75
+ .toLowerCase();
76
+ if (artifactType !== "app" && artifactType !== "document") return null;
77
+
78
+ const artifactTitleLine = lines.find((line) =>
79
+ line.trim().startsWith("ARTIFACT_TITLE:"),
80
+ );
81
+ if (!artifactTitleLine) return null;
82
+ const artifactTitle = artifactTitleLine
83
+ .split(":")
84
+ .slice(1)
85
+ .join(":")
86
+ .trim();
87
+ if (!artifactTitle) return null;
88
+
89
+ const artifactDescriptionStartIndex = lines.findIndex((line) =>
90
+ line.trim().startsWith("ARTIFACT_DESCRIPTION:"),
91
+ );
92
+ if (artifactDescriptionStartIndex === -1) return null;
93
+
94
+ const firstDescLine = lines[artifactDescriptionStartIndex]
95
+ .split(":")
96
+ .slice(1)
97
+ .join(":")
98
+ .trim();
99
+
100
+ // Collect continuation lines (lines after ARTIFACT_DESCRIPTION that aren't other fields)
101
+ const descriptionParts = [firstDescLine];
102
+ for (let i = artifactDescriptionStartIndex + 1; i < lines.length; i++) {
103
+ const line = lines[i].trim();
104
+ if (
105
+ line.startsWith("SHOULD_BUILD:") ||
106
+ line.startsWith("SKIP_REASON:") ||
107
+ line.startsWith("ARTIFACT_TYPE:") ||
108
+ line.startsWith("ARTIFACT_TITLE:")
109
+ ) {
110
+ break;
111
+ }
112
+ descriptionParts.push(line);
113
+ }
114
+
115
+ const artifactDescription = descriptionParts.join("\n").trim();
116
+ if (!artifactDescription) return null;
117
+
118
+ return {
119
+ shouldBuild: true,
120
+ artifactType: artifactType as "app" | "document",
121
+ artifactTitle,
122
+ artifactDescription,
123
+ };
124
+ }
125
+
126
+ return null;
127
+ }
128
+
129
+ export function formatTranscript(
130
+ messages: Array<{ role: string; content: string }>,
131
+ ): string {
132
+ return messages
133
+ .map((msg) => {
134
+ const label =
135
+ msg.role === "user"
136
+ ? "[User]"
137
+ : msg.role === "assistant"
138
+ ? "[Assistant]"
139
+ : `[${msg.role}]`;
140
+ const content = parseContent(msg.content);
141
+ return `${label}: ${content}`;
142
+ })
143
+ .join("\n\n");
144
+ }
145
+
146
+ function parseContent(content: string): string {
147
+ // Try to parse as JSON content block array
148
+ try {
149
+ const parsed = JSON.parse(content);
150
+ if (Array.isArray(parsed)) {
151
+ return parsed
152
+ .map((block) => {
153
+ if (typeof block === "string") return block;
154
+ if (block.type === "text" && typeof block.text === "string")
155
+ return block.text;
156
+ return "";
157
+ })
158
+ .filter(Boolean)
159
+ .join("\n");
160
+ }
161
+ } catch {
162
+ // Not JSON, treat as plain text
163
+ }
164
+ return content;
165
+ }