@vellumai/assistant 0.5.5 → 0.5.7

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 (382) hide show
  1. package/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +4 -5
  4. package/README.md +0 -2
  5. package/bun.lock +0 -414
  6. package/docs/architecture/keychain-broker.md +45 -240
  7. package/docs/architecture/security.md +0 -17
  8. package/docs/credential-execution-service.md +2 -2
  9. package/node_modules/@vellumai/ces-contracts/package.json +1 -0
  10. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
  11. package/node_modules/@vellumai/credential-storage/package.json +1 -0
  12. package/node_modules/@vellumai/egress-proxy/package.json +1 -0
  13. package/package.json +2 -3
  14. package/src/__tests__/actor-token-service.test.ts +1 -2
  15. package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
  16. package/src/__tests__/browser-skill-endstate.test.ts +6 -5
  17. package/src/__tests__/btw-routes.test.ts +0 -39
  18. package/src/__tests__/call-domain.test.ts +0 -128
  19. package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
  20. package/src/__tests__/channel-approval-routes.test.ts +0 -5
  21. package/src/__tests__/channel-readiness-service.test.ts +1 -60
  22. package/src/__tests__/checker.test.ts +4 -2
  23. package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
  24. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  25. package/src/__tests__/config-schema.test.ts +3 -3
  26. package/src/__tests__/context-window-manager.test.ts +78 -0
  27. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  28. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  29. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  30. package/src/__tests__/conversation-title-service.test.ts +117 -1
  31. package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
  32. package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
  33. package/src/__tests__/credential-security-e2e.test.ts +0 -66
  34. package/src/__tests__/credential-security-invariants.test.ts +4 -45
  35. package/src/__tests__/credentials-cli.test.ts +78 -0
  36. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  37. package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
  38. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  39. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  40. package/src/__tests__/host-shell-tool.test.ts +6 -7
  41. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  42. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  43. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  44. package/src/__tests__/intent-routing.test.ts +0 -13
  45. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  46. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  47. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  48. package/src/__tests__/memory-regressions.test.ts +8 -30
  49. package/src/__tests__/migration-export-http.test.ts +2 -2
  50. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  51. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  52. package/src/__tests__/migration-validate-http.test.ts +2 -2
  53. package/src/__tests__/non-member-access-request.test.ts +0 -5
  54. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  55. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  56. package/src/__tests__/permission-types.test.ts +1 -0
  57. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  58. package/src/__tests__/qdrant-manager.test.ts +28 -2
  59. package/src/__tests__/registry.test.ts +0 -6
  60. package/src/__tests__/require-fresh-approval.test.ts +4 -0
  61. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  62. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  63. package/src/__tests__/secure-keys.test.ts +83 -263
  64. package/src/__tests__/shell-identity.test.ts +96 -6
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  66. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  67. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  68. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  69. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  70. package/src/__tests__/skill-load-tool.test.ts +0 -2
  71. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  72. package/src/__tests__/skills.test.ts +0 -2
  73. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  74. package/src/__tests__/suggestion-routes.test.ts +1 -32
  75. package/src/__tests__/system-prompt.test.ts +0 -1
  76. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
  77. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  78. package/src/__tests__/tool-executor.test.ts +4 -0
  79. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  80. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  81. package/src/__tests__/update-bulletin.test.ts +0 -2
  82. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  83. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
  84. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  85. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
  86. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  87. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  88. package/src/calls/audio-store.test.ts +97 -0
  89. package/src/calls/audio-store.ts +205 -0
  90. package/src/calls/call-controller.ts +85 -7
  91. package/src/calls/call-domain.ts +3 -0
  92. package/src/calls/call-store.ts +10 -3
  93. package/src/calls/fish-audio-client.ts +117 -0
  94. package/src/calls/relay-server.ts +27 -0
  95. package/src/calls/twilio-routes.ts +2 -1
  96. package/src/calls/types.ts +1 -0
  97. package/src/calls/voice-ingress-preflight.ts +0 -42
  98. package/src/calls/voice-quality.ts +26 -5
  99. package/src/calls/voice-session-bridge.ts +6 -12
  100. package/src/cli/commands/config.ts +1 -4
  101. package/src/cli/commands/conversations.ts +0 -18
  102. package/src/cli/commands/credentials.ts +34 -4
  103. package/src/cli/commands/oauth/index.ts +7 -0
  104. package/src/cli/commands/oauth/platform.ts +179 -0
  105. package/src/cli/commands/platform.ts +3 -3
  106. package/src/config/assistant-feature-flags.ts +186 -5
  107. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  108. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  109. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  110. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  111. package/src/config/bundled-tool-registry.ts +1 -11
  112. package/src/config/env-registry.ts +1 -1
  113. package/src/config/env.ts +16 -16
  114. package/src/config/feature-flag-registry.json +48 -16
  115. package/src/config/loader.ts +98 -31
  116. package/src/config/schema.ts +4 -25
  117. package/src/config/schemas/calls.ts +13 -0
  118. package/src/config/schemas/fish-audio.ts +39 -0
  119. package/src/config/schemas/memory.ts +0 -4
  120. package/src/config/schemas/platform.ts +1 -1
  121. package/src/config/schemas/security.ts +4 -4
  122. package/src/config/types.ts +0 -1
  123. package/src/contacts/contact-store.ts +39 -0
  124. package/src/contacts/types.ts +2 -0
  125. package/src/context/window-manager.ts +53 -2
  126. package/src/credential-execution/approval-bridge.ts +1 -0
  127. package/src/credential-execution/executable-discovery.ts +28 -4
  128. package/src/credential-execution/feature-gates.ts +16 -0
  129. package/src/credential-execution/process-manager.ts +38 -0
  130. package/src/daemon/assistant-attachments.ts +9 -0
  131. package/src/daemon/config-watcher.ts +6 -4
  132. package/src/daemon/conversation-agent-loop.ts +0 -60
  133. package/src/daemon/conversation-memory.ts +0 -117
  134. package/src/daemon/conversation-runtime-assembly.ts +0 -2
  135. package/src/daemon/conversation-tool-setup.ts +0 -105
  136. package/src/daemon/conversation.ts +10 -1
  137. package/src/daemon/handlers/config-vercel.ts +92 -0
  138. package/src/daemon/handlers/conversations.ts +0 -11
  139. package/src/daemon/handlers/skills.ts +2 -15
  140. package/src/daemon/install-symlink.ts +195 -0
  141. package/src/daemon/lifecycle.ts +229 -96
  142. package/src/daemon/message-types/conversations.ts +3 -4
  143. package/src/daemon/message-types/diagnostics.ts +3 -22
  144. package/src/daemon/message-types/messages.ts +0 -2
  145. package/src/daemon/message-types/upgrades.ts +8 -0
  146. package/src/daemon/server.ts +30 -92
  147. package/src/events/domain-events.ts +2 -1
  148. package/src/followups/followup-store.ts +5 -2
  149. package/src/inbound/platform-callback-registration.ts +3 -3
  150. package/src/instrument.ts +8 -5
  151. package/src/memory/conversation-crud.ts +0 -236
  152. package/src/memory/conversation-title-service.ts +76 -11
  153. package/src/memory/db-init.ts +15 -11
  154. package/src/memory/indexer.ts +15 -106
  155. package/src/memory/items-extractor.ts +15 -1
  156. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  157. package/src/memory/job-handlers/embedding.ts +0 -79
  158. package/src/memory/job-utils.ts +1 -1
  159. package/src/memory/jobs-store.ts +30 -13
  160. package/src/memory/jobs-worker.ts +31 -27
  161. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  162. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  163. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  164. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  165. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  166. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  167. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  168. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  169. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  170. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  171. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  172. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  173. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  174. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  175. package/src/memory/migrations/116-messages-fts.ts +106 -1
  176. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  177. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  178. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  179. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  180. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  181. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  182. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  183. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  184. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  185. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  186. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  187. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  188. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  189. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  190. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  191. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  192. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  193. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  194. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  195. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  196. package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
  197. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  198. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  199. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  200. package/src/memory/migrations/index.ts +5 -3
  201. package/src/memory/migrations/registry.ts +90 -0
  202. package/src/memory/migrations/validate-migration-state.ts +137 -11
  203. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  204. package/src/memory/qdrant-client.ts +4 -6
  205. package/src/memory/qdrant-manager.ts +64 -7
  206. package/src/memory/schema/calls.ts +1 -0
  207. package/src/memory/schema/contacts.ts +1 -0
  208. package/src/memory/schema/conversations.ts +0 -3
  209. package/src/memory/schema/index.ts +0 -2
  210. package/src/messaging/draft-store.ts +2 -2
  211. package/src/notifications/decision-engine.ts +4 -1
  212. package/src/oauth/connection-resolver.ts +6 -4
  213. package/src/permissions/checker.ts +0 -38
  214. package/src/permissions/defaults.ts +3 -3
  215. package/src/permissions/shell-identity.ts +76 -22
  216. package/src/permissions/trust-client.ts +2 -13
  217. package/src/permissions/trust-store.ts +8 -3
  218. package/src/permissions/types.ts +4 -2
  219. package/src/platform/client.ts +35 -7
  220. package/src/prompts/persona-resolver.ts +138 -0
  221. package/src/prompts/system-prompt.ts +36 -4
  222. package/src/prompts/templates/users/default.md +1 -0
  223. package/src/providers/registry.ts +27 -40
  224. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  225. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  226. package/src/runtime/auth/external-assistant-id.ts +13 -59
  227. package/src/runtime/auth/route-policy.ts +29 -1
  228. package/src/runtime/auth/token-service.ts +53 -15
  229. package/src/runtime/channel-readiness-service.ts +1 -16
  230. package/src/runtime/http-server.ts +29 -2
  231. package/src/runtime/middleware/error-handler.ts +1 -9
  232. package/src/runtime/routes/audio-routes.ts +40 -0
  233. package/src/runtime/routes/btw-routes.ts +0 -17
  234. package/src/runtime/routes/conversation-management-routes.ts +0 -36
  235. package/src/runtime/routes/conversation-query-routes.ts +106 -2
  236. package/src/runtime/routes/conversation-routes.ts +4 -43
  237. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  238. package/src/runtime/routes/identity-routes.ts +18 -29
  239. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  240. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  241. package/src/runtime/routes/integrations/vercel.ts +89 -0
  242. package/src/runtime/routes/log-export-routes.ts +5 -0
  243. package/src/runtime/routes/memory-item-routes.test.ts +221 -3
  244. package/src/runtime/routes/memory-item-routes.ts +144 -4
  245. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  246. package/src/runtime/routes/migration-routes.ts +17 -1
  247. package/src/runtime/routes/notification-routes.ts +58 -0
  248. package/src/runtime/routes/schedule-routes.ts +65 -0
  249. package/src/runtime/routes/settings-routes.ts +41 -1
  250. package/src/runtime/routes/tts-routes.ts +86 -0
  251. package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
  252. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  253. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  254. package/src/runtime/routes/workspace-routes.ts +1 -1
  255. package/src/runtime/routes/workspace-utils.ts +86 -2
  256. package/src/schedule/schedule-store.ts +0 -21
  257. package/src/security/ces-credential-client.ts +59 -22
  258. package/src/security/ces-rpc-credential-backend.ts +85 -0
  259. package/src/security/credential-backend.ts +12 -88
  260. package/src/security/keychain-broker-client.ts +10 -2
  261. package/src/security/secure-keys.ts +94 -113
  262. package/src/skills/catalog-install.ts +13 -7
  263. package/src/skills/inline-command-render.ts +5 -1
  264. package/src/skills/inline-command-runner.ts +30 -2
  265. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  266. package/src/tools/calls/call-start.ts +1 -0
  267. package/src/tools/executor.ts +0 -4
  268. package/src/tools/memory/handlers.ts +1 -129
  269. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  270. package/src/tools/network/web-fetch.ts +3 -1
  271. package/src/tools/permission-checker.ts +18 -0
  272. package/src/tools/skills/execute.ts +1 -1
  273. package/src/tools/skills/load.ts +9 -2
  274. package/src/tools/types.ts +0 -8
  275. package/src/util/errors.ts +0 -12
  276. package/src/util/platform.ts +8 -55
  277. package/src/util/xml.ts +8 -0
  278. package/src/workspace/git-service.ts +5 -2
  279. package/src/workspace/heartbeat-service.ts +5 -24
  280. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  281. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  282. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  283. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  284. package/src/workspace/migrations/006-services-config.ts +49 -0
  285. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  286. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  287. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  288. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  289. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  290. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  291. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  292. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  293. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  294. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  295. package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
  296. package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
  297. package/src/workspace/migrations/registry.ts +8 -0
  298. package/src/workspace/migrations/runner.ts +106 -2
  299. package/src/workspace/migrations/types.ts +4 -0
  300. package/src/__tests__/archive-recall.test.ts +0 -560
  301. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  302. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  303. package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
  304. package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
  305. package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
  306. package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
  307. package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
  308. package/src/__tests__/diagnostics-export.test.ts +0 -288
  309. package/src/__tests__/local-gateway-health.test.ts +0 -209
  310. package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
  311. package/src/__tests__/memory-brief-time.test.ts +0 -285
  312. package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
  313. package/src/__tests__/memory-chunk-archive.test.ts +0 -400
  314. package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
  315. package/src/__tests__/memory-episode-archive.test.ts +0 -370
  316. package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
  317. package/src/__tests__/memory-observation-archive.test.ts +0 -375
  318. package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
  319. package/src/__tests__/memory-reducer-job.test.ts +0 -538
  320. package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
  321. package/src/__tests__/memory-reducer-store.test.ts +0 -728
  322. package/src/__tests__/memory-reducer-types.test.ts +0 -707
  323. package/src/__tests__/memory-reducer.test.ts +0 -704
  324. package/src/__tests__/memory-simplified-config.test.ts +0 -281
  325. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  326. package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
  327. package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
  328. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  329. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  330. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  331. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  332. package/src/__tests__/swarm-recursion.test.ts +0 -197
  333. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  334. package/src/__tests__/swarm-tool.test.ts +0 -185
  335. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  336. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  337. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  338. package/src/commands/cc-command-registry.ts +0 -248
  339. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  340. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  341. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  342. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  343. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  344. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  345. package/src/config/schemas/memory-simplified.ts +0 -101
  346. package/src/config/schemas/swarm.ts +0 -82
  347. package/src/logfire.ts +0 -135
  348. package/src/memory/archive-recall.ts +0 -516
  349. package/src/memory/archive-store.ts +0 -400
  350. package/src/memory/brief-formatting.ts +0 -33
  351. package/src/memory/brief-open-loops.ts +0 -266
  352. package/src/memory/brief-time.ts +0 -162
  353. package/src/memory/brief.ts +0 -75
  354. package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
  355. package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
  356. package/src/memory/migrations/185-memory-brief-state.ts +0 -52
  357. package/src/memory/migrations/186-memory-archive.ts +0 -109
  358. package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
  359. package/src/memory/reducer-scheduler.ts +0 -242
  360. package/src/memory/reducer-store.ts +0 -271
  361. package/src/memory/reducer-types.ts +0 -106
  362. package/src/memory/reducer.ts +0 -467
  363. package/src/memory/schema/memory-archive.ts +0 -121
  364. package/src/memory/schema/memory-brief.ts +0 -55
  365. package/src/runtime/local-gateway-health.ts +0 -275
  366. package/src/security/secret-ingress.ts +0 -68
  367. package/src/swarm/backend-claude-code.ts +0 -225
  368. package/src/swarm/checkpoint.ts +0 -137
  369. package/src/swarm/graph-utils.ts +0 -53
  370. package/src/swarm/index.ts +0 -55
  371. package/src/swarm/limits.ts +0 -66
  372. package/src/swarm/orchestrator.ts +0 -424
  373. package/src/swarm/plan-validator.ts +0 -117
  374. package/src/swarm/router-planner.ts +0 -162
  375. package/src/swarm/router-prompts.ts +0 -39
  376. package/src/swarm/synthesizer.ts +0 -81
  377. package/src/swarm/types.ts +0 -72
  378. package/src/swarm/worker-backend.ts +0 -131
  379. package/src/swarm/worker-prompts.ts +0 -80
  380. package/src/swarm/worker-runner.ts +0 -170
  381. package/src/tools/claude-code/claude-code.ts +0 -610
  382. package/src/tools/swarm/delegate.ts +0 -205
@@ -1,21 +1,7 @@
1
1
  /**
2
- * Tests for getExternalAssistantId resolution order.
2
+ * Tests for getExternalAssistantId.
3
3
  */
4
- import { afterEach, describe, expect, mock, test } from "bun:test";
5
-
6
- mock.module("../../../util/logger.js", () => ({
7
- getLogger: () =>
8
- new Proxy({} as Record<string, unknown>, {
9
- get: () => () => {},
10
- }),
11
- }));
12
-
13
- // Controllable mock for readLockfile — defaults to null (no lockfile data)
14
- const mockReadLockfile = mock(() => null as Record<string, unknown> | null);
15
-
16
- mock.module("../../../util/platform.js", () => ({
17
- readLockfile: mockReadLockfile,
18
- }));
4
+ import { afterEach, describe, expect, test } from "bun:test";
19
5
 
20
6
  import {
21
7
  getExternalAssistantId,
@@ -24,65 +10,24 @@ import {
24
10
 
25
11
  afterEach(() => {
26
12
  resetExternalAssistantIdCache();
27
- mockReadLockfile.mockReset();
28
- mockReadLockfile.mockImplementation(() => null);
29
- delete process.env.BASE_DATA_DIR;
13
+ delete process.env.VELLUM_ASSISTANT_NAME;
30
14
  });
31
15
 
32
16
  describe("getExternalAssistantId", () => {
33
- test("resolves from lockfile assistants array (most recently hatched)", () => {
34
- mockReadLockfile.mockImplementation(() => ({
35
- assistants: [
36
- { assistantId: "vellum-old-fox", hatchedAt: "2025-01-01T00:00:00Z" },
37
- { assistantId: "vellum-new-eel", hatchedAt: "2025-06-15T12:00:00Z" },
38
- ],
39
- }));
40
- expect(getExternalAssistantId()).toBe("vellum-new-eel");
41
- });
42
-
43
- test("resolves from lockfile with single assistant entry", () => {
44
- mockReadLockfile.mockImplementation(() => ({
45
- assistants: [
46
- { assistantId: "vellum-solo-cat", hatchedAt: "2025-03-01T00:00:00Z" },
47
- ],
48
- }));
49
- expect(getExternalAssistantId()).toBe("vellum-solo-cat");
50
- });
51
-
52
- test("resolves from BASE_DATA_DIR when lockfile has no data", () => {
53
- process.env.BASE_DATA_DIR = "/tmp/vellum/assistants/vellum-true-eel";
54
- expect(getExternalAssistantId()).toBe("vellum-true-eel");
55
- });
56
-
57
- test("resolves from BASE_DATA_DIR with trailing slash", () => {
58
- process.env.BASE_DATA_DIR = "/tmp/vellum/assistants/vellum-cool-heron/";
59
- expect(getExternalAssistantId()).toBe("vellum-cool-heron");
60
- });
61
-
62
- test("resolves from BASE_DATA_DIR with Windows-style backslashes", () => {
63
- process.env.BASE_DATA_DIR =
64
- "C:\\Users\\user\\.local\\share\\vellum\\assistants\\vellum-nice-fox";
65
- expect(getExternalAssistantId()).toBe("vellum-nice-fox");
66
- });
67
-
68
- test("resolves from BASE_DATA_DIR with /instances/<name> path", () => {
69
- process.env.BASE_DATA_DIR = "/home/user/.vellum/instances/vellum-swift-owl";
70
- expect(getExternalAssistantId()).toBe("vellum-swift-owl");
71
- });
72
-
73
- test("resolves from BASE_DATA_DIR with /instances/<name> trailing slash", () => {
74
- process.env.BASE_DATA_DIR =
75
- "/home/user/.vellum/instances/vellum-swift-owl/";
76
- expect(getExternalAssistantId()).toBe("vellum-swift-owl");
17
+ test("resolves from VELLUM_ASSISTANT_NAME env var", () => {
18
+ process.env.VELLUM_ASSISTANT_NAME = "vellum-cool-eel";
19
+ expect(getExternalAssistantId()).toBe("vellum-cool-eel");
77
20
  });
78
21
 
79
- test("falls back to undefined when BASE_DATA_DIR does not match known patterns", () => {
80
- process.env.BASE_DATA_DIR = "/tmp/some-other-path";
81
- expect(getExternalAssistantId()).toBe(undefined);
22
+ test("caches the resolved value", () => {
23
+ process.env.VELLUM_ASSISTANT_NAME = "vellum-cool-eel";
24
+ expect(getExternalAssistantId()).toBe("vellum-cool-eel");
25
+ // Change env var — cached value should still be returned
26
+ process.env.VELLUM_ASSISTANT_NAME = "vellum-other-fox";
27
+ expect(getExternalAssistantId()).toBe("vellum-cool-eel");
82
28
  });
83
29
 
84
- test("falls back to undefined when BASE_DATA_DIR is not set", () => {
85
- delete process.env.BASE_DATA_DIR;
30
+ test("returns undefined when env var is not set", () => {
86
31
  expect(getExternalAssistantId()).toBe(undefined);
87
32
  });
88
33
  });
@@ -6,81 +6,35 @@
6
6
  * must identify which assistant the token belongs to, while the daemon
7
7
  * internally uses 'self'.
8
8
  *
9
- * Resolution order:
10
- * 1. Cached in-memory value (populated on first call)
11
- * 2. Most recently hatched entry in lockfile assistants array
12
- * (sorted by `hatchedAt` descending) → assistantId
13
- * 3. BASE_DATA_DIR path matching `/assistants/<name>` or `/instances/<name>` suffix
14
- * 4. `undefined` — callers must handle the missing value
9
+ * Reads from the VELLUM_ASSISTANT_NAME env var, which is set by CLI
10
+ * hatch and Docker setup. Returns `undefined` if the env var is not set.
15
11
  *
16
- * The value is cached in memory after the first successful read.
12
+ * The value is cached in memory after the first read.
17
13
  */
18
14
 
19
- import { getBaseDataDir } from "../../config/env-registry.js";
20
15
  import { getLogger } from "../../util/logger.js";
21
- import { readLockfile } from "../../util/platform.js";
22
16
 
23
17
  const log = getLogger("external-assistant-id");
24
18
 
25
19
  let cached: string | null | undefined;
26
20
 
27
21
  /**
28
- * Get the external assistant ID.
29
- *
30
- * Resolution order:
31
- * 1. Cached in-memory value (populated on first call)
32
- * 2. Most recently hatched entry in lockfile assistants array
33
- * (sorted by `hatchedAt` descending) → assistantId
34
- * 3. BASE_DATA_DIR path matching `/assistants/<name>` or `/instances/<name>` suffix
35
- * 4. `undefined` when resolution fails entirely
22
+ * Get the external assistant ID from the VELLUM_ASSISTANT_NAME env var.
23
+ * Returns `undefined` when the env var is not set.
36
24
  */
37
25
  export function getExternalAssistantId(): string | undefined {
38
26
  if (cached !== undefined) {
39
27
  return cached ?? undefined;
40
28
  }
41
29
 
42
- try {
43
- const lockData = readLockfile();
44
- if (lockData) {
45
- const assistants = lockData.assistants as
46
- | Array<Record<string, unknown>>
47
- | undefined;
48
- if (assistants && assistants.length > 0) {
49
- // Sort by hatchedAt descending to use the most recent entry,
50
- // matching the pattern used elsewhere in the codebase.
51
- const sorted = [...assistants].sort((a, b) => {
52
- const dateA = new Date((a.hatchedAt as string) || 0).getTime();
53
- const dateB = new Date((b.hatchedAt as string) || 0).getTime();
54
- return dateB - dateA;
55
- });
56
- const latest = sorted[0];
57
- if (typeof latest.assistantId === "string") {
58
- cached = latest.assistantId;
59
- log.info(
60
- { externalAssistantId: cached },
61
- "Resolved external assistant ID from lockfile",
62
- );
63
- return cached;
64
- }
65
- }
66
- }
67
- } catch (err) {
68
- log.warn({ err }, "Failed to read lockfile for external assistant ID");
69
- }
70
-
71
- // Fallback: derive from BASE_DATA_DIR path
72
- const base = getBaseDataDir();
73
- if (base && typeof base === "string") {
74
- const normalized = base.replace(/\\/g, "/").replace(/\/+$/, "");
75
- const match = normalized.match(/\/(?:assistants|instances)\/([^/]+)$/);
76
- if (match) {
77
- cached = match[1];
78
- log.info(
79
- { externalAssistantId: cached },
80
- "Resolved external assistant ID from BASE_DATA_DIR",
81
- );
82
- return cached;
83
- }
30
+ const envName = process.env.VELLUM_ASSISTANT_NAME;
31
+ if (envName) {
32
+ cached = envName;
33
+ log.info(
34
+ { externalAssistantId: cached },
35
+ "Resolved external assistant ID from VELLUM_ASSISTANT_NAME",
36
+ );
37
+ return cached;
84
38
  }
85
39
 
86
40
  cached = null;
@@ -176,6 +176,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
176
176
 
177
177
  // Settings / integrations / identity
178
178
  { endpoint: "identity", scopes: ["settings.read"] },
179
+ { endpoint: "identity/intro", scopes: ["settings.read"] },
179
180
  { endpoint: "brain-graph", scopes: ["settings.read"] },
180
181
  { endpoint: "brain-graph-ui", scopes: ["settings.read"] },
181
182
  { endpoint: "contacts", scopes: ["settings.read"] },
@@ -347,6 +348,14 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
347
348
  { endpoint: "config/embeddings:GET", scopes: ["settings.read"] },
348
349
  { endpoint: "config/embeddings:PUT", scopes: ["settings.write"] },
349
350
 
351
+ // Permissions config
352
+ { endpoint: "config/permissions/skip:GET", scopes: ["settings.read"] },
353
+ { endpoint: "config/permissions/skip:PUT", scopes: ["settings.write"] },
354
+
355
+ // Generic config read/patch
356
+ { endpoint: "config:GET", scopes: ["settings.read"] },
357
+ { endpoint: "config:PATCH", scopes: ["settings.write"] },
358
+
350
359
  // Conversation management
351
360
  { endpoint: "conversations:DELETE", scopes: ["chat.write"] },
352
361
  { endpoint: "conversations/wipe", scopes: ["chat.write"] },
@@ -355,9 +364,13 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
355
364
  // Conversation search
356
365
  { endpoint: "conversations/search", scopes: ["chat.read"] },
357
366
 
367
+ // Conversation starters
368
+ { endpoint: "conversation-starters", scopes: ["chat.read"] },
369
+
358
370
  // Message content
359
371
  { endpoint: "messages/content", scopes: ["chat.read"] },
360
372
  { endpoint: "messages/llm-context", scopes: ["chat.read"] },
373
+ { endpoint: "messages/tts", scopes: ["chat.read"] },
361
374
 
362
375
  // Queued message deletion
363
376
  { endpoint: "messages/queued", scopes: ["chat.write"] },
@@ -435,7 +448,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
435
448
 
436
449
  // Diagnostics
437
450
  { endpoint: "export", scopes: ["settings.read"] },
438
- { endpoint: "diagnostics/export", scopes: ["settings.read"] },
439
451
  { endpoint: "diagnostics/env-vars", scopes: ["settings.read"] },
440
452
 
441
453
  // Dictation
@@ -498,3 +510,19 @@ for (const endpoint of INTERNAL_ENDPOINTS) {
498
510
  allowedPrincipalTypes: ["svc_gateway"],
499
511
  });
500
512
  }
513
+
514
+ // Admin control-plane endpoints: gateway-only
515
+ registerPolicy("admin/upgrade-broadcast", {
516
+ requiredScopes: ["internal.write"],
517
+ allowedPrincipalTypes: ["svc_gateway"],
518
+ });
519
+
520
+ registerPolicy("admin/workspace-commit", {
521
+ requiredScopes: ["internal.write"],
522
+ allowedPrincipalTypes: ["svc_gateway"],
523
+ });
524
+
525
+ registerPolicy("admin/rollback-migrations", {
526
+ requiredScopes: ["internal.write"],
527
+ allowedPrincipalTypes: ["svc_gateway"],
528
+ });
@@ -42,28 +42,44 @@ function getSigningKeyPath(): string {
42
42
  return join(getRootDir(), "protected", "actor-token-signing-key");
43
43
  }
44
44
 
45
+ /**
46
+ * Load a signing key from disk. Returns the key buffer if found and valid,
47
+ * or undefined if the file does not exist or is invalid.
48
+ *
49
+ * Used in the Docker 403-fallback path where generating a new key would
50
+ * create a mismatch with the gateway's already-bootstrapped key.
51
+ */
52
+ export function loadSigningKey(): Buffer | undefined {
53
+ const keyPath = getSigningKeyPath();
54
+ if (!existsSync(keyPath)) {
55
+ return undefined;
56
+ }
57
+ try {
58
+ const raw = readFileSync(keyPath);
59
+ if (raw.length === 32) {
60
+ log.info("Auth signing key loaded from disk");
61
+ return raw;
62
+ }
63
+ log.warn("Signing key file has unexpected length");
64
+ return undefined;
65
+ } catch (err) {
66
+ log.warn({ err }, "Failed to read signing key file");
67
+ return undefined;
68
+ }
69
+ }
70
+
45
71
  /**
46
72
  * Load a signing key from disk or generate and persist a new one.
47
73
  * Uses atomic-write + chmod 0o600 for safe persistence.
48
74
  */
49
75
  export function loadOrCreateSigningKey(): Buffer {
50
- const keyPath = getSigningKeyPath();
51
-
52
- // Try to load existing key
53
- if (existsSync(keyPath)) {
54
- try {
55
- const raw = readFileSync(keyPath);
56
- if (raw.length === 32) {
57
- log.info("Auth signing key loaded from disk");
58
- return raw;
59
- }
60
- log.warn("Signing key file has unexpected length, regenerating");
61
- } catch (err) {
62
- log.warn({ err }, "Failed to read signing key file, regenerating");
63
- }
76
+ const existing = loadSigningKey();
77
+ if (existing) {
78
+ return existing;
64
79
  }
65
80
 
66
81
  // Generate and persist a new key
82
+ const keyPath = getSigningKeyPath();
67
83
  const newKey = randomBytes(32);
68
84
  const dir = dirname(keyPath);
69
85
  if (!existsSync(dir)) {
@@ -78,6 +94,28 @@ export function loadOrCreateSigningKey(): Buffer {
78
94
  return newKey;
79
95
  }
80
96
 
97
+ /**
98
+ * Resolve the signing key for the current environment.
99
+ *
100
+ * Resolution order:
101
+ * 1. ACTOR_TOKEN_SIGNING_KEY env var (hex-encoded, set by CLI for Docker)
102
+ * 2. File-based load/create (~/.vellum/protected/actor-token-signing-key)
103
+ */
104
+ export function resolveSigningKey(): Buffer {
105
+ const envKey = process.env.ACTOR_TOKEN_SIGNING_KEY;
106
+ if (envKey) {
107
+ if (!/^[0-9a-f]{64}$/i.test(envKey)) {
108
+ throw new Error(
109
+ `Invalid ACTOR_TOKEN_SIGNING_KEY: expected 64 hex characters, got ${envKey.length} chars`,
110
+ );
111
+ }
112
+ log.info("Signing key loaded from ACTOR_TOKEN_SIGNING_KEY env var");
113
+ return Buffer.from(envKey, "hex");
114
+ }
115
+
116
+ return loadOrCreateSigningKey();
117
+ }
118
+
81
119
  function getSigningKey(): Buffer {
82
120
  if (!_authSigningKey) {
83
121
  if (process.env.NODE_ENV === "test") {
@@ -113,7 +151,7 @@ export function isSigningKeyInitialized(): boolean {
113
151
 
114
152
  /**
115
153
  * Returns a short hex fingerprint of the current signing key.
116
- * Used by daemon_status to let clients detect instance switches.
154
+ * Used by assistant_status to let clients detect instance switches.
117
155
  */
118
156
  export function getSigningKeyFingerprint(): string {
119
157
  return createHash("sha256")
@@ -15,7 +15,6 @@ import type {
15
15
  ReadinessCheckResult,
16
16
  SetupStatus,
17
17
  } from "./channel-readiness-types.js";
18
- import { probeLocalGatewayHealth } from "./local-gateway-health.js";
19
18
 
20
19
  /** Remote check results are cached for 5 minutes before being considered stale. */
21
20
  export const REMOTE_TTL_MS = 5 * 60 * 1000;
@@ -82,7 +81,7 @@ const voiceProbe: ChannelProbe = {
82
81
  const hasPhone = !!resolveTwilioPhoneNumber();
83
82
  const ingress = checkIngress();
84
83
 
85
- const checks: ReadinessCheckResult[] = [
84
+ return [
86
85
  check(
87
86
  "twilio_credentials",
88
87
  hasCreds,
@@ -97,20 +96,6 @@ const voiceProbe: ChannelProbe = {
97
96
  ),
98
97
  ingress,
99
98
  ];
100
-
101
- if (ingress.passed) {
102
- const gw = await probeLocalGatewayHealth();
103
- checks.push(
104
- check(
105
- "gateway_health",
106
- gw.healthy,
107
- `Local gateway is serving requests at ${gw.target}`,
108
- `Local gateway is not serving requests at ${gw.target}${gw.error ? `: ${gw.error}` : ""}`,
109
- ),
110
- );
111
- }
112
-
113
- return checks;
114
99
  },
115
100
  };
116
101
 
@@ -106,6 +106,7 @@ import { handleServePage } from "./routes/app-routes.js";
106
106
  import { appRouteDefinitions } from "./routes/app-routes.js";
107
107
  import { approvalRouteDefinitions } from "./routes/approval-routes.js";
108
108
  import { attachmentRouteDefinitions } from "./routes/attachment-routes.js";
109
+ import { handleGetAudio } from "./routes/audio-routes.js";
109
110
  import { avatarRouteDefinitions } from "./routes/avatar-routes.js";
110
111
  import { brainGraphRouteDefinitions } from "./routes/brain-graph-routes.js";
111
112
  import { btwRouteDefinitions } from "./routes/btw-routes.js";
@@ -144,16 +145,19 @@ import { handleGuardianRefresh } from "./routes/guardian-refresh-routes.js";
144
145
  import { hostBashRouteDefinitions } from "./routes/host-bash-routes.js";
145
146
  import { hostCuRouteDefinitions } from "./routes/host-cu-routes.js";
146
147
  import { hostFileRouteDefinitions } from "./routes/host-file-routes.js";
147
- import { handleHealth } from "./routes/identity-routes.js";
148
+ import { handleHealth, handleReadyz } from "./routes/identity-routes.js";
148
149
  import { identityRouteDefinitions } from "./routes/identity-routes.js";
149
150
  import { slackChannelRouteDefinitions } from "./routes/integrations/slack/channel.js";
150
151
  import { slackShareRouteDefinitions } from "./routes/integrations/slack/share.js";
151
152
  import { telegramRouteDefinitions } from "./routes/integrations/telegram.js";
152
153
  import { twilioRouteDefinitions } from "./routes/integrations/twilio.js";
154
+ import { vercelRouteDefinitions } from "./routes/integrations/vercel.js";
153
155
  import { inviteRouteDefinitions } from "./routes/invite-routes.js";
154
156
  import { logExportRouteDefinitions } from "./routes/log-export-routes.js";
155
157
  import { memoryItemRouteDefinitions } from "./routes/memory-item-routes.js";
158
+ import { migrationRollbackRouteDefinitions } from "./routes/migration-rollback-routes.js";
156
159
  import { migrationRouteDefinitions } from "./routes/migration-routes.js";
160
+ import { notificationRouteDefinitions } from "./routes/notification-routes.js";
157
161
  import { oauthAppsRouteDefinitions } from "./routes/oauth-apps.js";
158
162
  import type { PairingHandlerContext } from "./routes/pairing-routes.js";
159
163
  import {
@@ -172,9 +176,12 @@ import { surfaceContentRouteDefinitions } from "./routes/surface-content-routes.
172
176
  import { telemetryRouteDefinitions } from "./routes/telemetry-routes.js";
173
177
  import { traceEventRouteDefinitions } from "./routes/trace-event-routes.js";
174
178
  import { trustRulesRouteDefinitions } from "./routes/trust-rules-routes.js";
179
+ import { ttsRouteDefinitions } from "./routes/tts-routes.js";
180
+ import { upgradeBroadcastRouteDefinitions } from "./routes/upgrade-broadcast-routes.js";
175
181
  import { usageRouteDefinitions } from "./routes/usage-routes.js";
176
182
  import { watchRouteDefinitions } from "./routes/watch-routes.js";
177
183
  import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
184
+ import { workspaceCommitRouteDefinitions } from "./routes/workspace-commit-routes.js";
178
185
  import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
179
186
 
180
187
  // Re-export for consumers
@@ -463,7 +470,10 @@ export class RuntimeHttpServer {
463
470
  server.timeout(req, 1800);
464
471
  // Skip request logging for health-check probes to reduce log noise.
465
472
  const url = new URL(req.url);
466
- if (url.pathname === "/healthz" && req.method === "GET") {
473
+ if (
474
+ (url.pathname === "/healthz" || url.pathname === "/readyz") &&
475
+ req.method === "GET"
476
+ ) {
467
477
  return this.routeRequest(req, server);
468
478
  }
469
479
  return withRequestLogging(req, () => this.routeRequest(req, server));
@@ -480,6 +490,10 @@ export class RuntimeHttpServer {
480
490
  return handleHealth();
481
491
  }
482
492
 
493
+ if (path === "/readyz" && req.method === "GET") {
494
+ return handleReadyz();
495
+ }
496
+
483
497
  // WebSocket upgrade for the Chrome extension browser relay.
484
498
  if (
485
499
  path === "/v1/browser-relay" &&
@@ -502,6 +516,13 @@ export class RuntimeHttpServer {
502
516
  const twilioResponse = await this.handleTwilioWebhook(req, path);
503
517
  if (twilioResponse) return twilioResponse;
504
518
 
519
+ // Audio serving endpoint — before auth check because Twilio
520
+ // fetches these URLs directly. The audioId is an unguessable UUID.
521
+ const audioMatch = path.match(/^\/v1\/audio\/([^/]+)$/);
522
+ if (audioMatch && req.method === "GET") {
523
+ return handleGetAudio(audioMatch[1]);
524
+ }
525
+
505
526
  // Pairing endpoints (unauthenticated, secret-gated)
506
527
  if (path === "/v1/pairing/request" && req.method === "POST") {
507
528
  return await handlePairingRequest(req, this.pairingContext);
@@ -918,6 +939,9 @@ export class RuntimeHttpServer {
918
939
  getCesClient: this.getCesClient,
919
940
  }),
920
941
  ...identityRouteDefinitions(),
942
+ ...upgradeBroadcastRouteDefinitions(),
943
+ ...workspaceCommitRouteDefinitions(),
944
+ ...migrationRollbackRouteDefinitions(),
921
945
  ...debugRouteDefinitions(),
922
946
  ...usageRouteDefinitions(),
923
947
  ...telemetryRouteDefinitions(),
@@ -929,6 +953,7 @@ export class RuntimeHttpServer {
929
953
  ...scheduleRouteDefinitions({
930
954
  sendMessageDeps: this.sendMessageDeps,
931
955
  }),
956
+ ...notificationRouteDefinitions(),
932
957
  ...diagnosticsRouteDefinitions(),
933
958
  ...logExportRouteDefinitions(),
934
959
  ...documentRouteDefinitions(),
@@ -959,6 +984,7 @@ export class RuntimeHttpServer {
959
984
  }
960
985
  : undefined,
961
986
  }),
987
+ ...ttsRouteDefinitions(),
962
988
 
963
989
  // Browser relay — not extracted into a domain module because
964
990
  // these two routes depend on the in-process extensionRelayServer
@@ -1163,6 +1189,7 @@ export class RuntimeHttpServer {
1163
1189
  ...slackChannelRouteDefinitions(),
1164
1190
  ...slackShareRouteDefinitions(),
1165
1191
  ...twilioRouteDefinitions(),
1192
+ ...vercelRouteDefinitions(),
1166
1193
  ...channelReadinessRouteDefinitions(),
1167
1194
  ...oauthAppsRouteDefinitions(),
1168
1195
  ...attachmentRouteDefinitions(),
@@ -4,7 +4,6 @@
4
4
 
5
5
  import {
6
6
  ConfigError,
7
- IngressBlockedError,
8
7
  ProviderNotConfiguredError,
9
8
  } from "../../util/errors.js";
10
9
  import { getLogger } from "../../util/logger.js";
@@ -14,7 +13,7 @@ const log = getLogger("runtime-http");
14
13
 
15
14
  /**
16
15
  * Wrap an async endpoint handler with standard error handling.
17
- * Catches IngressBlockedError (422), ConfigError (422), and generic errors (500).
16
+ * Catches ConfigError (422) and generic errors (500).
18
17
  */
19
18
  export async function withErrorHandling(
20
19
  endpoint: string,
@@ -23,13 +22,6 @@ export async function withErrorHandling(
23
22
  try {
24
23
  return await handler();
25
24
  } catch (err) {
26
- if (err instanceof IngressBlockedError) {
27
- log.warn(
28
- { endpoint, detectedTypes: err.detectedTypes },
29
- "Blocked HTTP request containing secrets",
30
- );
31
- return httpError("UNPROCESSABLE_ENTITY", err.message, 422);
32
- }
33
25
  if (err instanceof ProviderNotConfiguredError) {
34
26
  log.warn({ err, endpoint }, "No LLM provider configured");
35
27
  return httpError(
@@ -0,0 +1,40 @@
1
+ /**
2
+ * HTTP route handler for serving synthesized TTS audio.
3
+ *
4
+ * GET /v1/audio/:audioId — retrieve a previously stored audio segment.
5
+ *
6
+ * This endpoint is unauthenticated because Twilio fetches audio URLs
7
+ * directly; the audioId itself is an unguessable UUID that acts as a
8
+ * capability token.
9
+ */
10
+
11
+ import { getAudio } from "../../calls/audio-store.js";
12
+ import { httpError } from "../http-errors.js";
13
+
14
+ /**
15
+ * Handle GET /v1/audio/:audioId.
16
+ *
17
+ * Returns the audio with its stored Content-Type. For complete audio,
18
+ * includes Content-Length for efficient playback. For in-progress
19
+ * streaming entries, uses chunked transfer encoding.
20
+ */
21
+ export function handleGetAudio(audioId: string): Response {
22
+ const entry = getAudio(audioId);
23
+ if (!entry) {
24
+ return httpError("NOT_FOUND", "Audio not found", 404);
25
+ }
26
+ if (entry.type === "buffer") {
27
+ return new Response(new Uint8Array(entry.buffer), {
28
+ status: 200,
29
+ headers: {
30
+ "Content-Type": entry.contentType,
31
+ "Content-Length": entry.buffer.length.toString(),
32
+ },
33
+ });
34
+ }
35
+ // Streaming — Content-Length unknown, chunked transfer encoding
36
+ return new Response(entry.stream, {
37
+ status: 200,
38
+ headers: { "Content-Type": entry.contentType },
39
+ });
40
+ }
@@ -15,7 +15,6 @@
15
15
  import { existsSync, readFileSync } from "node:fs";
16
16
 
17
17
  import { getConversationByKey } from "../../memory/conversation-key-store.js";
18
- import { checkIngressForSecrets } from "../../security/secret-ingress.js";
19
18
  import { getLogger } from "../../util/logger.js";
20
19
  import { getWorkspacePromptPath } from "../../util/platform.js";
21
20
  import type { AuthContext } from "../auth/types.js";
@@ -89,22 +88,6 @@ async function handleBtw(
89
88
  }
90
89
 
91
90
  const trimmedContent = content.trim();
92
- const ingressCheck = checkIngressForSecrets(trimmedContent);
93
- if (ingressCheck.blocked) {
94
- log.warn(
95
- { detectedTypes: ingressCheck.detectedTypes },
96
- "Blocked /v1/btw message containing secrets",
97
- );
98
- return Response.json(
99
- {
100
- accepted: false,
101
- error: "secret_blocked",
102
- message: ingressCheck.userNotice,
103
- detectedTypes: ingressCheck.detectedTypes,
104
- },
105
- { status: 422 },
106
- );
107
- }
108
91
 
109
92
  // ----- Identity intro fast-path -----
110
93
  // When the client requests the identity intro, check SOUL.md first (persisted
@@ -275,24 +275,6 @@ export function conversationManagementRouteDefinitions(
275
275
  targetId: summaryId,
276
276
  });
277
277
  }
278
- for (const obsId of result.deletedObservationIds) {
279
- enqueueMemoryJob("delete_qdrant_vectors", {
280
- targetType: "observation",
281
- targetId: obsId,
282
- });
283
- }
284
- for (const chunkId of result.deletedChunkIds) {
285
- enqueueMemoryJob("delete_qdrant_vectors", {
286
- targetType: "chunk",
287
- targetId: chunkId,
288
- });
289
- }
290
- for (const episodeId of result.deletedEpisodeIds) {
291
- enqueueMemoryJob("delete_qdrant_vectors", {
292
- targetType: "episode",
293
- targetId: episodeId,
294
- });
295
- }
296
278
  log.info(
297
279
  {
298
280
  conversationId: resolvedId,
@@ -349,24 +331,6 @@ export function conversationManagementRouteDefinitions(
349
331
  targetId: summaryId,
350
332
  });
351
333
  }
352
- for (const obsId of deleted.deletedObservationIds) {
353
- enqueueMemoryJob("delete_qdrant_vectors", {
354
- targetType: "observation",
355
- targetId: obsId,
356
- });
357
- }
358
- for (const chunkId of deleted.deletedChunkIds) {
359
- enqueueMemoryJob("delete_qdrant_vectors", {
360
- targetType: "chunk",
361
- targetId: chunkId,
362
- });
363
- }
364
- for (const episodeId of deleted.deletedEpisodeIds) {
365
- enqueueMemoryJob("delete_qdrant_vectors", {
366
- targetType: "episode",
367
- targetId: episodeId,
368
- });
369
- }
370
334
  log.info({ conversationId: resolvedId }, "Deleted conversation");
371
335
  return new Response(null, { status: 204 });
372
336
  },