@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,15 +1,17 @@
1
1
  /**
2
- * Unified secure key storage — single-writer routing through CredentialBackend
2
+ * Unified secure key storage — single-backend routing through CredentialBackend
3
3
  * adapters.
4
4
  *
5
- * Backend selection (`resolveBackend`) is the single decision point:
6
- * - Containerized (IS_CONTAINERIZED + CES_CREDENTIAL_URL set): CES HTTP client.
7
- * - Production (VELLUM_DEV unset or "0"): keychain backend when available.
8
- * - Dev mode (VELLUM_DEV=1): encrypted file store always.
5
+ * Backend selection (`resolveBackendAsync`) is the single async decision point:
6
+ * 1. CES RPC (primary) injected via `setCesClient()`: delegates credential
7
+ * operations to the CES process over stdio RPC. This is the default path
8
+ * for all local modes (desktop app, dev, CLI).
9
+ * 2. CES HTTP — containerized mode (IS_CONTAINERIZED + CES_CREDENTIAL_URL):
10
+ * delegates to the CES sidecar over HTTP. Used in Docker/managed mode.
11
+ * 3. Encrypted file store (fallback) — used when CES is unavailable.
9
12
  *
10
- * Writes go to exactly one backend (no dual-writing). Reads in keychain mode
11
- * fall back to the encrypted store for keys that haven't been migrated yet.
12
- * Deletes clean up both stores regardless of mode.
13
+ * All operations (reads, writes, lists, deletes) go to exactly one backend.
14
+ * There are no cross-backend fallbacks or merges.
13
15
  */
14
16
 
15
17
  import type {
@@ -19,13 +21,12 @@ import type {
19
21
 
20
22
  import providerEnvVarsRegistry from "../../../meta/provider-env-vars.json" with { type: "json" };
21
23
  import { getIsContainerized } from "../config/env-registry.js";
24
+ import type { CesClient } from "../credential-execution/client.js";
22
25
  import { getLogger } from "../util/logger.js";
23
26
  import { createCesCredentialBackend } from "./ces-credential-client.js";
27
+ import { CesRpcCredentialBackend } from "./ces-rpc-credential-backend.js";
24
28
  import type { CredentialBackend, DeleteResult } from "./credential-backend.js";
25
- import {
26
- createEncryptedStoreBackend,
27
- createKeychainBackend,
28
- } from "./credential-backend.js";
29
+ import { createEncryptedStoreBackend } from "./credential-backend.js";
29
30
 
30
31
  export type { DeleteResult } from "./credential-backend.js";
31
32
 
@@ -36,15 +37,24 @@ export type { DeleteResult } from "./credential-backend.js";
36
37
  */
37
38
  export type { SecureKeyBackend, SecureKeyDeleteResult };
38
39
 
40
+ export interface SecureKeyResult {
41
+ value: string | undefined;
42
+ unreachable: boolean;
43
+ }
44
+
39
45
  const log = getLogger("secure-keys");
40
46
 
41
- let _keychain: CredentialBackend | undefined;
47
+ let _cesClient: CesClient | undefined;
42
48
  let _encryptedStore: CredentialBackend | undefined;
43
49
  let _resolvedBackend: CredentialBackend | undefined;
50
+ let _resolvePromise: Promise<CredentialBackend> | undefined;
44
51
 
45
- function getKeychainBackend(): CredentialBackend {
46
- if (!_keychain) _keychain = createKeychainBackend();
47
- return _keychain;
52
+ /** Inject a CES RPC client for credential routing. Resets the resolved backend. */
53
+ export function setCesClient(client: CesClient | undefined): void {
54
+ _cesClient = client;
55
+ // Reset resolved backend so next call picks up CES
56
+ _resolvedBackend = undefined;
57
+ _resolvePromise = undefined;
48
58
  }
49
59
 
50
60
  function getEncryptedStoreBackend(): CredentialBackend {
@@ -53,101 +63,96 @@ function getEncryptedStoreBackend(): CredentialBackend {
53
63
  }
54
64
 
55
65
  /**
56
- * Resolve the primary credential backend for this process.
66
+ * Resolve the primary credential backend for this process (async).
57
67
  *
58
68
  * Priority:
59
- * 1. Containerized + CES_CREDENTIAL_URLCES HTTP client (skip keychain
60
- * and encrypted store entirely the sidecar owns credential storage).
61
- * 2. Production (VELLUM_DEV unset or "0") keychain when available.
62
- * 3. Dev mode (VELLUM_DEV=1) → encrypted file store always.
69
+ * 1. CES RPC clientprimary path for all local modes.
70
+ * 2. Containerized + CES_CREDENTIAL_URL CES HTTP client (Docker/managed).
71
+ * 3. Encrypted file storefallback when CES is unavailable.
63
72
  *
64
73
  * Once resolved, the backend does not change during the process lifetime.
65
74
  * Call `_resetBackend()` in tests to clear the cached resolution.
66
75
  */
67
- function resolveBackend(): CredentialBackend {
68
- if (!_resolvedBackend) {
69
- if (getIsContainerized() && process.env.CES_CREDENTIAL_URL) {
70
- const ces = createCesCredentialBackend();
71
- if (ces.isAvailable()) {
72
- _resolvedBackend = ces;
73
- } else {
74
- log.warn(
75
- "CES_CREDENTIAL_URL is set but CES backend is not available — " +
76
- "falling back to local credential store",
77
- );
78
- }
76
+ async function resolveBackendAsync(): Promise<CredentialBackend> {
77
+ if (_resolvedBackend) return _resolvedBackend;
78
+ if (!_resolvePromise) {
79
+ _resolvePromise = doResolveBackend();
80
+ }
81
+ return _resolvePromise;
82
+ }
83
+
84
+ async function doResolveBackend(): Promise<CredentialBackend> {
85
+ // 1. CES RPC — primary credential backend for all local modes
86
+ if (_cesClient) {
87
+ const cesRpc = new CesRpcCredentialBackend(_cesClient);
88
+ if (cesRpc.isAvailable()) {
89
+ _resolvedBackend = cesRpc;
90
+ return cesRpc;
79
91
  }
92
+ log.warn("CES RPC client is set but not ready — falling back to local credential store");
93
+ }
80
94
 
81
- if (!_resolvedBackend) {
82
- if (
83
- process.env.VELLUM_DEV !== "1" &&
84
- getKeychainBackend().isAvailable()
85
- ) {
86
- _resolvedBackend = getKeychainBackend();
87
- } else {
88
- _resolvedBackend = getEncryptedStoreBackend();
89
- }
95
+ // 2. CES HTTP — containerized / Docker / managed mode
96
+ if (getIsContainerized() && process.env.CES_CREDENTIAL_URL) {
97
+ const ces = createCesCredentialBackend();
98
+ if (ces.isAvailable()) {
99
+ _resolvedBackend = ces;
100
+ return ces;
90
101
  }
102
+ log.warn(
103
+ "CES_CREDENTIAL_URL is set but CES backend is not available — " +
104
+ "falling back to local credential store",
105
+ );
91
106
  }
107
+
108
+ // 3. Encrypted file store — fallback when CES is unavailable
109
+ _resolvedBackend = getEncryptedStoreBackend();
92
110
  return _resolvedBackend;
93
111
  }
94
112
 
95
113
  /**
96
- * List all account names across both backends (async).
97
- *
98
- * In CES mode, only the CES backend is queried — there are no local stores.
114
+ * List all account names from the resolved backend (async).
99
115
  *
100
- * When the primary backend is the keychain, this merges keys from the keychain
101
- * and the encrypted store (for legacy keys that haven't been migrated). The
102
- * result is deduplicated. When the primary backend is already the encrypted
103
- * store, only that store is queried.
116
+ * Queries exactly one backend no cross-store merge.
104
117
  */
105
118
  export async function listSecureKeysAsync(): Promise<string[]> {
106
- const backend = resolveBackend();
107
- const primaryKeys = await backend.list();
108
-
109
- // CES mode — the sidecar is the single source of truth, no local merge.
110
- if (backend.name === "ces-http") return primaryKeys;
111
-
112
- // If primary backend is NOT the encrypted store, also check
113
- // the encrypted store for legacy keys that haven't been migrated.
114
- if (backend !== getEncryptedStoreBackend()) {
115
- const encKeys = await getEncryptedStoreBackend().list();
116
- const merged = new Set([...primaryKeys, ...encKeys]);
117
- return Array.from(merged);
118
- }
119
-
120
- return primaryKeys;
119
+ const backend = await resolveBackendAsync();
120
+ return backend.list();
121
121
  }
122
122
 
123
123
  // ---------------------------------------------------------------------------
124
- // Async CRUD — single-writer routing
124
+ // Async CRUD — single-backend routing
125
125
  // ---------------------------------------------------------------------------
126
126
 
127
127
  /**
128
- * Retrieve a secret from secure storage. Reads from the primary backend
129
- * first. In CES mode, the sidecar is the single source of truth — no
130
- * local fallback. In local mode, if the primary backend is the keychain,
131
- * falls back to the encrypted store for legacy keys that haven't been
132
- * migrated.
128
+ * Retrieve a secret from secure storage with richer result metadata.
129
+ *
130
+ * Returns both the value (if found) and whether the backend was
131
+ * unreachable. Callers that need to distinguish "not found" from
132
+ * "backend down" should use this instead of `getSecureKeyAsync`.
133
+ *
134
+ * Reads from exactly one backend — no cross-store fallback.
133
135
  */
134
- export async function getSecureKeyAsync(
136
+ export async function getSecureKeyResultAsync(
135
137
  account: string,
136
- ): Promise<string | undefined> {
137
- const backend = resolveBackend();
138
+ ): Promise<SecureKeyResult> {
139
+ const backend = await resolveBackendAsync();
138
140
  const result = await backend.get(account);
139
- if (result != null) return result;
140
-
141
- // CES mode — no local fallback.
142
- if (backend.name === "ces-http") return undefined;
143
-
144
- // Legacy fallback: if primary backend is NOT the encrypted store,
145
- // check the encrypted store for keys that haven't been migrated.
146
- if (backend !== getEncryptedStoreBackend()) {
147
- return await getEncryptedStoreBackend().get(account);
141
+ if (result.value != null) {
142
+ return { value: result.value, unreachable: false };
148
143
  }
144
+ return { value: undefined, unreachable: result.unreachable };
145
+ }
149
146
 
150
- return undefined;
147
+ /**
148
+ * Retrieve a secret from secure storage. Convenience wrapper over
149
+ * `getSecureKeyResultAsync` that returns only the value.
150
+ */
151
+ export async function getSecureKeyAsync(
152
+ account: string,
153
+ ): Promise<string | undefined> {
154
+ const result = await getSecureKeyResultAsync(account);
155
+ return result.value;
151
156
  }
152
157
 
153
158
  /**
@@ -158,7 +163,7 @@ export async function setSecureKeyAsync(
158
163
  account: string,
159
164
  value: string,
160
165
  ): Promise<boolean> {
161
- const backend = resolveBackend();
166
+ const backend = await resolveBackendAsync();
162
167
  const ok = await backend.set(account, value);
163
168
  if (!ok) {
164
169
  log.warn(
@@ -172,38 +177,13 @@ export async function setSecureKeyAsync(
172
177
  /**
173
178
  * Delete a secret from secure storage.
174
179
  *
175
- * In containerized mode with CES, deletion is routed exclusively through the
176
- * CES backend — there are no local stores to clean up.
177
- *
178
- * In local mode, always attempts deletion on both the keychain backend (if
179
- * available) and the encrypted store backend, regardless of routing mode.
180
- * This cleans up legacy data from both stores.
180
+ * Deletes from exactly one backend no cross-store cleanup.
181
181
  */
182
182
  export async function deleteSecureKeyAsync(
183
183
  account: string,
184
184
  ): Promise<DeleteResult> {
185
- const backend = resolveBackend();
186
-
187
- // In CES mode, the sidecar is the only store — no local cleanup needed.
188
- if (backend.name === "ces-http") {
189
- return backend.delete(account);
190
- }
191
-
192
- const keychain = getKeychainBackend();
193
- const enc = getEncryptedStoreBackend();
194
-
195
- let keychainResult: DeleteResult = "not-found";
196
- if (keychain.isAvailable()) {
197
- keychainResult = await keychain.delete(account);
198
- }
199
-
200
- const encResult = await enc.delete(account);
201
-
202
- // Return "error" if either errored
203
- if (keychainResult === "error" || encResult === "error") return "error";
204
- // Return "deleted" if either deleted
205
- if (keychainResult === "deleted" || encResult === "deleted") return "deleted";
206
- return "not-found";
185
+ const backend = await resolveBackendAsync();
186
+ return backend.delete(account);
207
187
  }
208
188
 
209
189
  // ---------------------------------------------------------------------------
@@ -263,7 +243,8 @@ export async function getMaskedProviderKey(
263
243
 
264
244
  /** @internal Test-only: reset the cached backends so they're re-created. */
265
245
  export function _resetBackend(): void {
266
- _keychain = undefined;
246
+ _cesClient = undefined;
267
247
  _encryptedStore = undefined;
268
248
  _resolvedBackend = undefined;
249
+ _resolvePromise = undefined;
269
250
  }
@@ -88,11 +88,7 @@ function getConfigPlatformUrl(): string | undefined {
88
88
  }
89
89
 
90
90
  function getPlatformUrl(): string {
91
- return (
92
- process.env.VELLUM_PLATFORM_URL ??
93
- getConfigPlatformUrl() ??
94
- "https://platform.vellum.ai"
95
- );
91
+ return process.env.VELLUM_PLATFORM_URL ?? getConfigPlatformUrl() ?? "";
96
92
  }
97
93
 
98
94
  function buildHeaders(): Record<string, string> {
@@ -107,7 +103,11 @@ function buildHeaders(): Record<string, string> {
107
103
  // ─── Catalog operations ──────────────────────────────────────────────────────
108
104
 
109
105
  export async function fetchCatalog(): Promise<CatalogSkill[]> {
110
- const url = `${getPlatformUrl()}/v1/skills/`;
106
+ const platformUrl = getPlatformUrl();
107
+ if (!platformUrl) {
108
+ return [];
109
+ }
110
+ const url = `${platformUrl}/v1/skills/`;
111
111
  const response = await fetch(url, {
112
112
  headers: buildHeaders(),
113
113
  signal: AbortSignal.timeout(10000),
@@ -214,7 +214,13 @@ export async function fetchAndExtractSkill(
214
214
  skillId: string,
215
215
  destDir: string,
216
216
  ): Promise<void> {
217
- const url = `${getPlatformUrl()}/v1/skills/${encodeURIComponent(skillId)}/`;
217
+ const platformUrl = getPlatformUrl();
218
+ if (!platformUrl) {
219
+ throw new Error(
220
+ `Cannot fetch skill "${skillId}": VELLUM_PLATFORM_URL is not configured.`,
221
+ );
222
+ }
223
+ const url = `${platformUrl}/v1/skills/${encodeURIComponent(skillId)}/`;
218
224
  const response = await fetch(url, {
219
225
  headers: buildHeaders(),
220
226
  signal: AbortSignal.timeout(15000),
@@ -14,6 +14,7 @@
14
14
  */
15
15
 
16
16
  import { getLogger } from "../util/logger.js";
17
+ import { escapeXmlContent } from "../util/xml.js";
17
18
  import type { InlineCommandExpansion } from "./inline-command-expansions.js";
18
19
  import type { InlineCommandResult } from "./inline-command-runner.js";
19
20
  import { runInlineCommand } from "./inline-command-runner.js";
@@ -91,7 +92,10 @@ export async function renderInlineCommands(
91
92
 
92
93
  let replacement: string;
93
94
  if (commandResult.ok) {
94
- replacement = wrapInXml(expansion.placeholderId, commandResult.output);
95
+ replacement = wrapInXml(
96
+ expansion.placeholderId,
97
+ escapeXmlContent(commandResult.output),
98
+ );
95
99
  expandedCount++;
96
100
  } else {
97
101
  const stub = failureReasonToStub(commandResult);
@@ -37,6 +37,15 @@ const DEFAULT_TIMEOUT_MS = 10_000;
37
37
  /** Maximum output characters before truncation. */
38
38
  const MAX_OUTPUT_CHARS = 20_000;
39
39
 
40
+ /**
41
+ * Maximum bytes to buffer from stdout during streaming. Once this limit is
42
+ * reached we stop accepting data so a long-running command (e.g. `yes`) cannot
43
+ * grow memory unbounded before the timeout fires. Set generously above
44
+ * MAX_OUTPUT_CHARS to account for multi-byte UTF-8 and ANSI sequences that will
45
+ * be stripped before the character-level clamp.
46
+ */
47
+ const MAX_STDOUT_BUFFER_BYTES = MAX_OUTPUT_CHARS * 4;
48
+
40
49
  /**
41
50
  * ANSI escape sequence pattern (covers SGR, cursor movement, erase, etc.).
42
51
  * Matches: ESC[ ... final_byte and ESC] ... ST (OSC sequences).
@@ -115,7 +124,9 @@ export async function runInlineCommand(
115
124
 
116
125
  return new Promise<InlineCommandResult>((resolve) => {
117
126
  let timedOut = false;
127
+ let stdoutCapped = false;
118
128
  const stdoutChunks: Buffer[] = [];
129
+ let stdoutBytes = 0;
119
130
 
120
131
  let child: ReturnType<typeof spawn>;
121
132
  try {
@@ -140,7 +151,19 @@ export async function runInlineCommand(
140
151
  child.kill("SIGKILL");
141
152
  }, timeoutMs);
142
153
 
143
- child.stdout!.on("data", (data: Buffer) => stdoutChunks.push(data));
154
+ child.stdout!.on("data", (data: Buffer) => {
155
+ if (stdoutBytes >= MAX_STDOUT_BUFFER_BYTES) return;
156
+ stdoutChunks.push(data);
157
+ stdoutBytes += data.length;
158
+ if (stdoutBytes >= MAX_STDOUT_BUFFER_BYTES) {
159
+ // Stop reading to release backpressure on the child process.
160
+ // This destroys the read end of the pipe, which may cause the
161
+ // child to receive SIGPIPE and exit with code=null. The
162
+ // stdoutCapped flag lets the close handler treat this as success.
163
+ stdoutCapped = true;
164
+ child.stdout!.destroy();
165
+ }
166
+ });
144
167
 
145
168
  child.on("close", (code) => {
146
169
  clearTimeout(timer);
@@ -157,7 +180,12 @@ export async function runInlineCommand(
157
180
  }
158
181
 
159
182
  // ── Non-zero exit ────────────────────────────────────────────────
160
- if (code !== 0) {
183
+ // When stdout was capped we destroyed the read end of the pipe,
184
+ // which typically causes SIGPIPE — the process is killed by the
185
+ // signal so the exit code is null. Only suppress the error in that
186
+ // specific case; a command that outputs a lot but exits with a
187
+ // genuine non-zero code (e.g. exit 1) should still be an error.
188
+ if (code !== 0 && !(stdoutCapped && code == null)) {
161
189
  log.debug(
162
190
  { command, exitCode: code },
163
191
  "Inline command exited with non-zero code",
@@ -140,7 +140,7 @@ export class UsageTelemetryReporter {
140
140
 
141
141
  // Resolve auth context — skip flush when neither auth mode is viable
142
142
  const client = await VellumPlatformClient.create();
143
- if (!client && !getTelemetryAppToken()) {
143
+ if (!client && (!getTelemetryAppToken() || !getTelemetryPlatformUrl())) {
144
144
  return;
145
145
  }
146
146
 
@@ -203,7 +203,9 @@ export class UsageTelemetryReporter {
203
203
  if (client) {
204
204
  resp = await client.fetch(TELEMETRY_PATH, fetchInit);
205
205
  } else {
206
- const url = `${getTelemetryPlatformUrl()}${TELEMETRY_PATH}`;
206
+ const platformUrl = getTelemetryPlatformUrl();
207
+ if (!platformUrl) return;
208
+ const url = `${platformUrl}${TELEMETRY_PATH}`;
207
209
  resp = await fetch(url, {
208
210
  ...fetchInit,
209
211
  headers: {
@@ -46,6 +46,7 @@ export async function executeCallStart(
46
46
  | "assistant_number"
47
47
  | "user_number"
48
48
  | undefined,
49
+ skipDisclosure: input.skip_disclosure === true,
49
50
  });
50
51
 
51
52
  if (!result.ok) {
@@ -183,10 +183,6 @@ export class ToolExecutor {
183
183
  );
184
184
  // Buffer so the shell's own timeout fires first and handles cleanup
185
185
  toolTimeoutMs = (shellTimeoutSec + 5) * 1000;
186
- } else if (name === "claude_code") {
187
- // Claude Code spawns a subprocess that manages its own turn limits
188
- // (maxTurns). Give it a generous timeout so it isn't killed mid-task.
189
- toolTimeoutMs = 10 * 60 * 1000; // 10 minutes
190
186
  } else {
191
187
  const rawTimeoutSec = getConfig().timeouts.toolExecutionTimeoutSec;
192
188
  toolTimeoutMs = safeTimeoutMs(rawTimeoutSec);
@@ -2,8 +2,6 @@ import { and, eq, ne } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import type { AssistantConfig } from "../../config/types.js";
5
- import { buildArchiveRecall } from "../../memory/archive-recall.js";
6
- import { insertObservation } from "../../memory/archive-store.js";
7
5
  import { getDb } from "../../memory/db.js";
8
6
  import { computeMemoryFingerprint } from "../../memory/fingerprint.js";
9
7
  import { enqueueMemoryJob } from "../../memory/jobs-store.js";
@@ -20,7 +18,7 @@ const log = getLogger("memory-tools");
20
18
 
21
19
  export async function handleMemorySave(
22
20
  args: Record<string, unknown>,
23
- config: AssistantConfig,
21
+ _config: AssistantConfig,
24
22
  conversationId: string,
25
23
  messageId: string | undefined,
26
24
  scopeId: string = "default",
@@ -65,19 +63,6 @@ export async function handleMemorySave(
65
63
  ? truncate(args.subject.trim(), 80, "")
66
64
  : inferSubjectFromStatement(statement.trim());
67
65
 
68
- // When simplified memory is enabled, save directly to the simplified
69
- // observation/chunk tables instead of the legacy memory_items table.
70
- if (config.memory.simplified.enabled) {
71
- return handleSimplifiedMemorySave(
72
- kind,
73
- subject,
74
- statement.trim(),
75
- conversationId,
76
- messageId,
77
- scopeId,
78
- );
79
- }
80
-
81
66
  try {
82
67
  const db = getDb();
83
68
  const id = uuid();
@@ -290,12 +275,6 @@ export async function handleMemoryRecall(
290
275
  ? args.scope.trim()
291
276
  : "default";
292
277
 
293
- // When simplified memory is enabled, use the archive recall path
294
- // instead of the legacy hybrid retriever.
295
- if (config.memory.simplified.enabled) {
296
- return handleSimplifiedMemoryRecall(query.trim(), scopeId ?? "default");
297
- }
298
-
299
278
  // Scope policy: "conversation" means strict (only that scope),
300
279
  // anything else allows fallback to the default scope.
301
280
  const scopePolicyOverride: ScopePolicyOverride | undefined = scopeId
@@ -432,113 +411,6 @@ export async function handleMemoryDelete(
432
411
  }
433
412
  }
434
413
 
435
- // ── Simplified memory helpers ────────────────────────────────────────
436
-
437
- /**
438
- * Save a memory item as an observation + chunk in the simplified system.
439
- * This is used when simplified memory is enabled instead of writing to
440
- * the legacy memory_items table.
441
- */
442
- function handleSimplifiedMemorySave(
443
- kind: string,
444
- subject: string,
445
- statement: string,
446
- conversationId: string,
447
- messageId: string | undefined,
448
- scopeId: string,
449
- ): ToolExecutionResult {
450
- try {
451
- const trimmedStatement = truncate(statement, 500, "");
452
- const content = `[${kind}] ${subject}: ${trimmedStatement}`;
453
-
454
- const result = insertObservation({
455
- conversationId,
456
- messageId: messageId ?? null,
457
- role: "user",
458
- content,
459
- scopeId,
460
- modality: "text",
461
- source: "tool:memory_save",
462
- });
463
-
464
- log.debug(
465
- {
466
- observationId: result.observationId,
467
- chunkId: result.chunkId,
468
- kind,
469
- subject,
470
- conversationId,
471
- messageId,
472
- },
473
- "Memory saved via simplified system",
474
- );
475
-
476
- return {
477
- content: `Saved to memory (ID: ${result.observationId}).\nKind: ${kind}\nSubject: ${subject}\nStatement: ${trimmedStatement}`,
478
- isError: false,
479
- };
480
- } catch (err) {
481
- const msg = err instanceof Error ? err.message : String(err);
482
- log.error({ err }, "simplified memory_save failed");
483
- return { content: `Error: Failed to save memory: ${msg}`, isError: true };
484
- }
485
- }
486
-
487
- /**
488
- * Recall memories using the simplified archive recall path instead of
489
- * the legacy hybrid retriever.
490
- */
491
- function handleSimplifiedMemoryRecall(
492
- query: string,
493
- scopeId: string,
494
- ): ToolExecutionResult {
495
- try {
496
- const recallResult = buildArchiveRecall(scopeId, query);
497
-
498
- if (recallResult.bullets.length === 0) {
499
- return {
500
- content: JSON.stringify({
501
- text: "No matching memories found.",
502
- resultCount: 0,
503
- degraded: false,
504
- items: [],
505
- sources: { semantic: 0, recency: 0 },
506
- }),
507
- isError: false,
508
- };
509
- }
510
-
511
- const items = recallResult.bullets.map((b) => ({
512
- id: b.sourceId,
513
- type: b.source,
514
- kind: b.source,
515
- }));
516
-
517
- const result = {
518
- text: recallResult.text,
519
- resultCount: recallResult.bullets.length,
520
- degraded: false,
521
- items,
522
- sources: {
523
- semantic: recallResult.prefetchHitCount,
524
- recency: 0,
525
- },
526
- };
527
-
528
- return {
529
- content: JSON.stringify(result),
530
- isError: false,
531
- };
532
- } catch (err) {
533
- const msg = err instanceof Error ? err.message : String(err);
534
- log.error({ err, query }, "simplified memory_recall failed");
535
- return {
536
- content: `Error: Memory recall failed: ${msg}`,
537
- isError: true,
538
- };
539
- }
540
- }
541
-
542
414
  // ── Helpers ──────────────────────────────────────────────────────────
543
415
 
544
416
  function inferSubjectFromStatement(statement: string): string {
@@ -61,10 +61,25 @@ const store = new SessionStore();
61
61
  /**
62
62
  * Host patterns that are allowed by default through the proxy policy engine,
63
63
  * regardless of session configuration. Supports exact matches (e.g.
64
- * `"localhost"`) and wildcard subdomain patterns (e.g. `"*.vellum.ai"`
65
- * matches `platform.vellum.ai`, `dev-platform.vellum.ai`, etc.).
64
+ * `"localhost"`) and wildcard subdomain patterns (e.g. `"*.example.com"`
65
+ * matches `api.example.com`, `dev.example.com`, etc.).
66
+ *
67
+ * Additional patterns can be added via the `PROXY_ALLOWED_HOSTS` env var
68
+ * (comma-separated, e.g. `"*.example.com,api.foo.bar"`).
66
69
  */
67
- const ALLOWED_HOST_PATTERNS: readonly string[] = ["*.vellum.ai", "localhost"];
70
+ const ALLOWED_HOST_PATTERNS: readonly string[] = (() => {
71
+ const extra = process.env.PROXY_ALLOWED_HOSTS?.trim();
72
+ const defaults = ["localhost"];
73
+ if (extra) {
74
+ defaults.push(
75
+ ...extra
76
+ .split(",")
77
+ .map((h) => h.trim())
78
+ .filter(Boolean),
79
+ );
80
+ }
81
+ return defaults;
82
+ })();
68
83
 
69
84
  /**
70
85
  * Returns `true` when `hostname` matches any entry in
@@ -73,7 +88,7 @@ const ALLOWED_HOST_PATTERNS: readonly string[] = ["*.vellum.ai", "localhost"];
73
88
  function isAllowedHost(hostname: string): boolean {
74
89
  for (const pattern of ALLOWED_HOST_PATTERNS) {
75
90
  if (pattern.startsWith("*.")) {
76
- const suffix = pattern.slice(1); // e.g. ".vellum.ai"
91
+ const suffix = pattern.slice(1); // e.g. ".example.com"
77
92
  if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {
78
93
  return true;
79
94
  }
@@ -573,7 +573,9 @@ export async function executeWebFetch(
573
573
  Accept:
574
574
  "text/markdown, text/html;q=0.9, application/xhtml+xml;q=0.9, text/plain;q=0.8, application/json;q=0.7, */*;q=0.6",
575
575
  "Accept-Encoding": "identity",
576
- "User-Agent": "VellumAssistant/1.0 (+https://vellum.ai)",
576
+ "User-Agent":
577
+ process.env.HTTP_USER_AGENT ||
578
+ "VellumAssistant/1.0 (+https://vellum.ai)",
577
579
  };
578
580
 
579
581
  let currentUrl = new URL(requestedUrl);