@vellumai/assistant 0.4.56 → 0.5.0

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 (457) hide show
  1. package/ARCHITECTURE.md +10 -10
  2. package/Dockerfile +3 -0
  3. package/README.md +11 -11
  4. package/docs/architecture/integrations.md +2 -2
  5. package/docs/architecture/memory.md +3 -4
  6. package/docs/credential-execution-service.md +13 -20
  7. package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
  8. package/package.json +1 -1
  9. package/src/__tests__/actor-token-service.test.ts +7 -7
  10. package/src/__tests__/anthropic-provider.test.ts +172 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
  12. package/src/__tests__/approval-cascade.test.ts +2 -2
  13. package/src/__tests__/approval-routes-http.test.ts +3 -4
  14. package/src/__tests__/asset-materialize-tool.test.ts +5 -5
  15. package/src/__tests__/asset-search-tool.test.ts +1 -1
  16. package/src/__tests__/assistant-attachments.test.ts +5 -5
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
  19. package/src/__tests__/attachments-store.test.ts +2 -2
  20. package/src/__tests__/avatar-e2e.test.ts +5 -3
  21. package/src/__tests__/browser-skill-endstate.test.ts +0 -1
  22. package/src/__tests__/call-routes-http.test.ts +2 -2
  23. package/src/__tests__/callback-handoff-copy.test.ts +1 -1
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
  25. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  26. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  27. package/src/__tests__/checker.test.ts +31 -32
  28. package/src/__tests__/chrome-cdp.test.ts +47 -18
  29. package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
  30. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  31. package/src/__tests__/config-schema.test.ts +9 -18
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
  34. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
  35. package/src/__tests__/conversation-agent-loop.test.ts +11 -4
  36. package/src/__tests__/conversation-attachments.test.ts +1 -1
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
  38. package/src/__tests__/conversation-error.test.ts +33 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
  40. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  41. package/src/__tests__/conversation-pairing.test.ts +1 -1
  42. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
  44. package/src/__tests__/conversation-queue.test.ts +23 -14
  45. package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
  47. package/src/__tests__/conversation-seed-composer.test.ts +1 -1
  48. package/src/__tests__/conversation-slash-queue.test.ts +4 -4
  49. package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
  50. package/src/__tests__/conversation-starter-routes.test.ts +291 -0
  51. package/src/__tests__/conversation-wipe.test.ts +438 -0
  52. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
  53. package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
  54. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
  55. package/src/__tests__/credential-security-e2e.test.ts +20 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault-unit.test.ts +227 -0
  58. package/src/__tests__/credentials-cli.test.ts +3 -0
  59. package/src/__tests__/date-context.test.ts +59 -377
  60. package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
  61. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
  62. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
  63. package/src/__tests__/encrypted-store.test.ts +249 -15
  64. package/src/__tests__/ephemeral-permissions.test.ts +4 -5
  65. package/src/__tests__/event-bus.test.ts +3 -3
  66. package/src/__tests__/file-read-tool.test.ts +40 -0
  67. package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
  68. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  69. package/src/__tests__/gemini-image-service.test.ts +4 -4
  70. package/src/__tests__/gemini-provider.test.ts +6 -9
  71. package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
  72. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  73. package/src/__tests__/host-file-read-tool.test.ts +87 -0
  74. package/src/__tests__/host-shell-tool.test.ts +6 -6
  75. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  76. package/src/__tests__/identity-intro-cache.test.ts +209 -0
  77. package/src/__tests__/intent-routing.test.ts +51 -99
  78. package/src/__tests__/invite-routes-http.test.ts +5 -0
  79. package/src/__tests__/list-messages-attachments.test.ts +1 -1
  80. package/src/__tests__/managed-proxy-context.test.ts +2 -5
  81. package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
  82. package/src/__tests__/media-generate-image.test.ts +32 -15
  83. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  84. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
  86. package/src/__tests__/memory-recall-quality.test.ts +4 -3
  87. package/src/__tests__/memory-regressions.test.ts +86 -90
  88. package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
  89. package/src/__tests__/migration-export-http.test.ts +26 -27
  90. package/src/__tests__/migration-import-commit-http.test.ts +165 -37
  91. package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
  92. package/src/__tests__/migration-validate-http.test.ts +16 -16
  93. package/src/__tests__/model-intents.test.ts +2 -2
  94. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
  95. package/src/__tests__/non-member-access-request.test.ts +3 -3
  96. package/src/__tests__/notification-broadcaster.test.ts +1 -1
  97. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  98. package/src/__tests__/notification-decision-identity.test.ts +8 -9
  99. package/src/__tests__/notification-decision-strategy.test.ts +1 -1
  100. package/src/__tests__/notification-deep-link.test.ts +1 -1
  101. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  102. package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
  103. package/src/__tests__/oauth-store.test.ts +1 -3
  104. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
  105. package/src/__tests__/onboarding-template-contract.test.ts +23 -59
  106. package/src/__tests__/provider-error-scenarios.test.ts +154 -0
  107. package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
  108. package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
  109. package/src/__tests__/provider-registry-ollama.test.ts +5 -2
  110. package/src/__tests__/qdrant-manager.test.ts +7 -7
  111. package/src/__tests__/ratelimit.test.ts +0 -74
  112. package/src/__tests__/recording-handler.test.ts +0 -1
  113. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  114. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  115. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  116. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  117. package/src/__tests__/scheduler-recurrence.test.ts +46 -2
  118. package/src/__tests__/schema-transforms.test.ts +114 -54
  119. package/src/__tests__/secret-onetime-send.test.ts +20 -0
  120. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
  121. package/src/__tests__/secret-scanner-executor.test.ts +1 -2
  122. package/src/__tests__/send-endpoint-busy.test.ts +63 -4
  123. package/src/__tests__/send-notification-tool.test.ts +2 -2
  124. package/src/__tests__/shell-credential-ref.test.ts +0 -1
  125. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
  126. package/src/__tests__/skill-memory.test.ts +549 -0
  127. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
  128. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
  129. package/src/__tests__/slack-channel-config.test.ts +109 -94
  130. package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
  131. package/src/__tests__/swarm-recursion.test.ts +2 -2
  132. package/src/__tests__/swarm-tool.test.ts +2 -2
  133. package/src/__tests__/system-prompt.test.ts +19 -66
  134. package/src/__tests__/telegram-config.test.ts +121 -0
  135. package/src/__tests__/terminal-tools.test.ts +1 -1
  136. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  138. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  139. package/src/__tests__/tool-executor.test.ts +1 -1
  140. package/src/__tests__/trace-emitter.test.ts +8 -1
  141. package/src/__tests__/trust-store.test.ts +7 -8
  142. package/src/__tests__/twilio-routes.test.ts +1 -18
  143. package/src/__tests__/user-reference.test.ts +82 -2
  144. package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
  145. package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
  146. package/src/approvals/guardian-request-resolvers.ts +3 -3
  147. package/src/avatar/ascii-renderer.ts +2 -2
  148. package/src/avatar/png-renderer.ts +2 -2
  149. package/src/avatar/resvg-lazy.ts +21 -0
  150. package/src/calls/guardian-dispatch.ts +1 -1
  151. package/src/calls/relay-access-wait.ts +2 -2
  152. package/src/calls/twilio-rest.ts +0 -248
  153. package/src/cli/AGENTS.md +5 -8
  154. package/src/cli/__tests__/notifications.test.ts +5 -5
  155. package/src/cli/commands/avatar.ts +64 -2
  156. package/src/cli/commands/conversations.ts +131 -1
  157. package/src/cli/commands/credentials.ts +2 -0
  158. package/src/cli/commands/notifications.ts +3 -3
  159. package/src/cli.ts +10 -0
  160. package/src/config/bundled-skills/acp/SKILL.md +5 -5
  161. package/src/config/bundled-skills/acp/TOOLS.json +6 -6
  162. package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
  163. package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
  164. package/src/config/bundled-skills/browser/SKILL.md +15 -15
  165. package/src/config/bundled-skills/browser/TOOLS.json +14 -14
  166. package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
  167. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
  168. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  169. package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
  170. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  171. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
  172. package/src/config/bundled-skills/contacts/SKILL.md +3 -3
  173. package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
  174. package/src/config/bundled-skills/document/SKILL.md +4 -4
  175. package/src/config/bundled-skills/document/TOOLS.json +2 -2
  176. package/src/config/bundled-skills/followups/TOOLS.json +3 -3
  177. package/src/config/bundled-skills/gmail/SKILL.md +32 -32
  178. package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
  179. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
  180. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  181. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
  182. package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
  183. package/src/config/bundled-skills/google-calendar/types.ts +1 -1
  184. package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
  185. package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
  186. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
  187. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
  188. package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
  189. package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
  190. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
  191. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
  192. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
  193. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
  194. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
  195. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
  196. package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
  197. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  198. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
  199. package/src/config/bundled-skills/messaging/SKILL.md +29 -25
  200. package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
  201. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  202. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  203. package/src/config/bundled-skills/notifications/SKILL.md +3 -3
  204. package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
  205. package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
  206. package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
  207. package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
  208. package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
  209. package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
  210. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
  211. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
  212. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
  213. package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
  214. package/src/config/bundled-skills/schedule/SKILL.md +26 -26
  215. package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
  216. package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
  217. package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
  218. package/src/config/bundled-skills/sequences/SKILL.md +2 -2
  219. package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
  220. package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
  221. package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
  222. package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
  223. package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
  224. package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
  225. package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
  226. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
  227. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  228. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  229. package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
  230. package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
  231. package/src/config/bundled-skills/slack/SKILL.md +2 -2
  232. package/src/config/bundled-skills/slack/TOOLS.json +8 -8
  233. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
  234. package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
  235. package/src/config/bundled-skills/tasks/SKILL.md +1 -1
  236. package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
  237. package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
  238. package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
  240. package/src/config/bundled-skills/watcher/SKILL.md +4 -4
  241. package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
  242. package/src/config/feature-flag-registry.json +33 -17
  243. package/src/config/schemas/sandbox.ts +1 -1
  244. package/src/config/schemas/services.ts +13 -3
  245. package/src/config/schemas/timeouts.ts +0 -10
  246. package/src/contacts/contact-store.ts +63 -0
  247. package/src/contacts/contacts-write.ts +1 -1
  248. package/src/daemon/assistant-attachments.ts +2 -2
  249. package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
  250. package/src/daemon/conversation-agent-loop.ts +7 -30
  251. package/src/daemon/conversation-error.ts +24 -0
  252. package/src/daemon/conversation-memory.ts +8 -7
  253. package/src/daemon/conversation-runtime-assembly.ts +141 -275
  254. package/src/daemon/conversation-slash.ts +7 -26
  255. package/src/daemon/conversation-surfaces.ts +14 -0
  256. package/src/daemon/conversation-tool-setup.ts +9 -8
  257. package/src/daemon/conversation.ts +2 -0
  258. package/src/daemon/daemon-control.ts +1 -1
  259. package/src/daemon/date-context.ts +10 -83
  260. package/src/daemon/handlers/config-channels.ts +12 -2
  261. package/src/daemon/handlers/config-slack-channel.ts +7 -1
  262. package/src/daemon/handlers/config-telegram.ts +6 -1
  263. package/src/daemon/handlers/conversations.ts +2 -2
  264. package/src/daemon/handlers/skills.ts +4 -0
  265. package/src/daemon/lifecycle.ts +28 -4
  266. package/src/daemon/providers-setup.ts +1 -1
  267. package/src/daemon/server.ts +1 -5
  268. package/src/daemon/shutdown-handlers.ts +9 -3
  269. package/src/daemon/tool-side-effects.ts +40 -0
  270. package/src/daemon/trace-emitter.ts +26 -2
  271. package/src/events/domain-events.ts +1 -1
  272. package/src/events/tool-permission-telemetry-listener.ts +46 -0
  273. package/src/inbound/platform-callback-registration.ts +0 -18
  274. package/src/media/app-icon-generator.ts +15 -8
  275. package/src/media/avatar-router.ts +15 -8
  276. package/src/media/gemini-image-service.ts +125 -21
  277. package/src/memory/attachments-store.ts +3 -3
  278. package/src/memory/channel-verification-sessions.ts +6 -6
  279. package/src/memory/conversation-crud.ts +196 -1
  280. package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
  281. package/src/memory/conversation-title-service.ts +2 -3
  282. package/src/memory/db-init.ts +25 -1
  283. package/src/memory/invite-store.ts +4 -4
  284. package/src/memory/items-extractor.ts +4 -4
  285. package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
  286. package/src/memory/jobs-store.ts +3 -2
  287. package/src/memory/jobs-worker.ts +7 -5
  288. package/src/memory/lifecycle-events-store.ts +63 -0
  289. package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
  290. package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
  291. package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
  292. package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
  293. package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
  294. package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
  295. package/src/memory/migrations/index.ts +6 -0
  296. package/src/memory/migrations/registry.ts +13 -0
  297. package/src/memory/retriever.test.ts +223 -96
  298. package/src/memory/retriever.ts +115 -138
  299. package/src/memory/schema/calls.ts +1 -1
  300. package/src/memory/schema/contacts.ts +1 -1
  301. package/src/memory/schema/infrastructure.ts +29 -0
  302. package/src/memory/schema/memory-core.ts +7 -17
  303. package/src/memory/schema/notifications.ts +1 -1
  304. package/src/memory/search/formatting.ts +23 -6
  305. package/src/memory/search/lexical.ts +2 -0
  306. package/src/memory/search/semantic.ts +2 -0
  307. package/src/memory/search/staleness.ts +5 -1
  308. package/src/memory/search/types.ts +4 -0
  309. package/src/memory/task-memory-cleanup.ts +96 -6
  310. package/src/memory/trace-event-store.ts +148 -0
  311. package/src/notifications/README.md +1 -1
  312. package/src/notifications/decision-engine.ts +45 -4
  313. package/src/notifications/emit-signal.ts +5 -4
  314. package/src/notifications/events-store.ts +4 -4
  315. package/src/notifications/signal.ts +1 -1
  316. package/src/oauth/manual-token-connection.ts +49 -25
  317. package/src/permissions/checker.ts +6 -5
  318. package/src/permissions/defaults.ts +4 -4
  319. package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
  320. package/src/prompts/cache-boundary.ts +8 -0
  321. package/src/prompts/system-prompt.ts +105 -634
  322. package/src/prompts/templates/BOOTSTRAP.md +172 -33
  323. package/src/prompts/templates/IDENTITY.md +8 -24
  324. package/src/prompts/templates/SOUL.md +20 -41
  325. package/src/prompts/templates/USER.md +3 -19
  326. package/src/prompts/user-reference.ts +14 -16
  327. package/src/providers/anthropic/client.ts +51 -19
  328. package/src/providers/gemini/client.ts +6 -9
  329. package/src/providers/managed-proxy/constants.ts +1 -7
  330. package/src/providers/managed-proxy/context.ts +0 -1
  331. package/src/providers/model-intents.ts +5 -5
  332. package/src/providers/openai/client.ts +10 -1
  333. package/src/providers/openrouter/client.ts +1 -0
  334. package/src/providers/ratelimit.ts +0 -35
  335. package/src/providers/registry.ts +3 -5
  336. package/src/providers/retry.ts +18 -1
  337. package/src/runtime/access-request-helper.ts +16 -2
  338. package/src/runtime/auth/route-policy.ts +7 -0
  339. package/src/runtime/channel-verification-service.ts +1 -1
  340. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  341. package/src/runtime/guardian-vellum-migration.ts +61 -1
  342. package/src/runtime/http-server.ts +8 -4
  343. package/src/runtime/migrations/vbundle-builder.ts +212 -32
  344. package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
  345. package/src/runtime/migrations/vbundle-importer.ts +66 -1
  346. package/src/runtime/migrations/vbundle-validator.ts +17 -3
  347. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
  348. package/src/runtime/routes/attachment-routes.ts +2 -2
  349. package/src/runtime/routes/btw-routes.ts +93 -0
  350. package/src/runtime/routes/channel-verification-routes.ts +19 -2
  351. package/src/runtime/routes/conversation-management-routes.ts +55 -1
  352. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-routes.ts +49 -5
  354. package/src/runtime/routes/conversation-starter-routes.ts +207 -0
  355. package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
  356. package/src/runtime/routes/identity-intro-cache.ts +105 -0
  357. package/src/runtime/routes/identity-routes.ts +51 -0
  358. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
  359. package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
  360. package/src/runtime/routes/migration-routes.ts +25 -13
  361. package/src/runtime/routes/secret-routes.ts +18 -0
  362. package/src/runtime/routes/settings-routes.ts +9 -9
  363. package/src/runtime/routes/telemetry-routes.ts +53 -0
  364. package/src/runtime/routes/trace-event-routes.ts +62 -0
  365. package/src/runtime/tool-grant-request-helper.ts +1 -1
  366. package/src/runtime/verification-outbound-actions.ts +47 -31
  367. package/src/security/encrypted-store.ts +262 -78
  368. package/src/skills/catalog-install.ts +10 -0
  369. package/src/skills/managed-store.ts +2 -0
  370. package/src/skills/skill-memory.ts +222 -0
  371. package/src/subagent/manager.ts +1 -4
  372. package/src/telemetry/types.ts +10 -1
  373. package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
  374. package/src/telemetry/usage-telemetry-reporter.ts +53 -4
  375. package/src/tools/AGENTS.md +11 -11
  376. package/src/tools/acp/spawn.ts +1 -1
  377. package/src/tools/apps/executors.ts +8 -8
  378. package/src/tools/apps/registry.ts +1 -1
  379. package/src/tools/assets/materialize.ts +6 -6
  380. package/src/tools/assets/search.ts +10 -10
  381. package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
  382. package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
  383. package/src/tools/browser/auth-detector.ts +6 -6
  384. package/src/tools/browser/browser-execution.ts +13 -13
  385. package/src/tools/browser/browser-manager.ts +3 -3
  386. package/src/tools/browser/chrome-cdp.ts +5 -5
  387. package/src/tools/browser/jit-auth.ts +2 -2
  388. package/src/tools/browser/network-recorder.test.ts +2 -2
  389. package/src/tools/browser/network-recorder.ts +3 -3
  390. package/src/tools/browser/runtime-check.ts +3 -3
  391. package/src/tools/claude-code/claude-code.ts +2 -2
  392. package/src/tools/computer-use/definitions.ts +18 -18
  393. package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
  394. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
  395. package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
  396. package/src/tools/credentials/broker-types.ts +5 -5
  397. package/src/tools/credentials/broker.ts +15 -15
  398. package/src/tools/credentials/metadata-store.ts +2 -2
  399. package/src/tools/credentials/resolve.ts +1 -1
  400. package/src/tools/credentials/selection.ts +1 -1
  401. package/src/tools/credentials/tool-policy.ts +1 -1
  402. package/src/tools/credentials/vault.ts +115 -25
  403. package/src/tools/execution-target.ts +2 -2
  404. package/src/tools/executor.ts +7 -7
  405. package/src/tools/filesystem/edit.ts +2 -2
  406. package/src/tools/filesystem/read.ts +15 -4
  407. package/src/tools/filesystem/write.ts +1 -1
  408. package/src/tools/host-filesystem/edit.ts +2 -1
  409. package/src/tools/host-filesystem/read.ts +18 -1
  410. package/src/tools/host-filesystem/write.ts +1 -1
  411. package/src/tools/host-terminal/host-shell.ts +9 -8
  412. package/src/tools/mcp/mcp-tool-factory.ts +7 -6
  413. package/src/tools/memory/definitions.ts +6 -5
  414. package/src/tools/memory/handlers.test.ts +1 -1
  415. package/src/tools/network/__tests__/web-search.test.ts +3 -3
  416. package/src/tools/network/domain-normalize.ts +2 -2
  417. package/src/tools/network/script-proxy/session-manager.ts +10 -10
  418. package/src/tools/network/web-fetch.ts +1 -1
  419. package/src/tools/network/web-search.ts +3 -3
  420. package/src/tools/permission-checker.ts +8 -8
  421. package/src/tools/registry.ts +7 -7
  422. package/src/tools/schedule/list.ts +2 -2
  423. package/src/tools/schema-transforms.ts +31 -21
  424. package/src/tools/secret-detection-handler.ts +1 -1
  425. package/src/tools/sensitive-output-placeholders.ts +1 -1
  426. package/src/tools/shared/filesystem/edit-engine.ts +1 -1
  427. package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
  428. package/src/tools/shared/filesystem/image-read.ts +25 -5
  429. package/src/tools/shared/filesystem/path-policy.ts +2 -2
  430. package/src/tools/shared/shell-output.ts +1 -1
  431. package/src/tools/side-effects.ts +1 -1
  432. package/src/tools/skills/execute.ts +1 -1
  433. package/src/tools/skills/load.ts +3 -3
  434. package/src/tools/skills/sandbox-runner.ts +3 -3
  435. package/src/tools/subagent/read.ts +1 -1
  436. package/src/tools/subagent/spawn.ts +2 -2
  437. package/src/tools/swarm/delegate.ts +3 -3
  438. package/src/tools/system/request-permission.ts +5 -4
  439. package/src/tools/terminal/backends/native.ts +4 -4
  440. package/src/tools/terminal/parser.ts +6 -6
  441. package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
  442. package/src/tools/terminal/shell.ts +16 -16
  443. package/src/tools/tool-approval-handler.ts +21 -12
  444. package/src/tools/tool-manifest.ts +4 -4
  445. package/src/tools/types.ts +3 -3
  446. package/src/tools/ui-surface/definitions.ts +9 -37
  447. package/src/tools/watcher/list.ts +1 -1
  448. package/src/util/logger.ts +7 -2
  449. package/src/util/pricing.ts +4 -0
  450. package/src/util/retry.ts +29 -1
  451. package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
  452. package/src/workspace/migrations/registry.ts +2 -0
  453. package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
  454. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
  455. package/src/cli/reference.ts +0 -38
  456. package/src/memory/job-handlers/capability-cards.ts +0 -420
  457. package/src/runtime/routes/thread-starter-routes.ts +0 -294
@@ -30,6 +30,7 @@ import { createToolAuditListener } from "../events/tool-audit-listener.js";
30
30
  import { createToolDomainEventPublisher } from "../events/tool-domain-event-publisher.js";
31
31
  import { registerToolMetricsLoggingListener } from "../events/tool-metrics-listener.js";
32
32
  import { registerToolNotificationListener } from "../events/tool-notification-listener.js";
33
+ import { registerToolPermissionTelemetryListener } from "../events/tool-permission-telemetry-listener.js";
33
34
  import {
34
35
  registerToolProfilingListener,
35
36
  ToolProfiler,
@@ -294,6 +295,7 @@ export class Conversation {
294
295
  );
295
296
  registerToolTraceListener(this.eventBus, this.traceEmitter);
296
297
  registerToolProfilingListener(this.eventBus, this.profiler);
298
+ registerToolPermissionTelemetryListener(this.eventBus);
297
299
  const auditToolLifecycleEvent = createToolAuditListener();
298
300
  const publishToolDomainEvent = createToolDomainEventPublisher(
299
301
  this.eventBus,
@@ -133,7 +133,7 @@ function isVellumDaemonProcess(pid: number): boolean {
133
133
  * Wildcard addresses (0.0.0.0, ::) bind all interfaces but aren't
134
134
  * connectable on all platforms — substitute loopback. IPv6 literals
135
135
  * need brackets in URLs. */
136
- function healthCheckHost(host: string): string {
136
+ export function healthCheckHost(host: string): string {
137
137
  if (host === "0.0.0.0") return "127.0.0.1";
138
138
  if (host === "::") return "[::1]";
139
139
  if (host.includes(":")) return `[${host}]`;
@@ -1,9 +1,8 @@
1
1
  /**
2
- * Temporal context formatter for future weekday/weekend grounding.
2
+ * Temporal context formatter for date/time grounding.
3
3
  *
4
4
  * Produces a compact, deterministic payload describing the current date,
5
- * upcoming weekend/work-week windows, and a short horizon of labelled
6
- * future dates. Intended for runtime injection into the model context.
5
+ * time, and timezone. Intended for runtime injection into the model context.
7
6
  */
8
7
 
9
8
  export interface TemporalContextOptions {
@@ -17,13 +16,8 @@ export interface TemporalContextOptions {
17
16
  configuredUserTimeZone?: string | null;
18
17
  /** IANA timezone inferred from user profile/memory (if available). */
19
18
  userTimeZone?: string | null;
20
- /** Number of future days to list (default 14, hard-capped at 14). */
21
- horizonDays?: number;
22
19
  }
23
20
 
24
- const MAX_OUTPUT_CHARS = 1500;
25
- const MAX_HORIZON_ENTRIES = 14;
26
-
27
21
  const WEEKDAY_NAMES = [
28
22
  "Sunday",
29
23
  "Monday",
@@ -316,35 +310,8 @@ function formatLocalIsoWithOffset(date: Date, timeZone: string): string {
316
310
  return `${year}-${month}-${day}T${hour}:${minute}:${second}${offset}`;
317
311
  }
318
312
 
319
- /**
320
- * Advance a date by `days` calendar days in the given timezone.
321
- *
322
- * Computes the local date, adds days to the day component, then anchors
323
- * the result at noon local time to avoid DST-transition edge cases.
324
- */
325
- function addDays(date: Date, days: number, timeZone: string): Date {
326
- const parts = localDateParts(date, timeZone);
327
- // Use Date.UTC for calendar overflow (e.g. Jan 32 → Feb 1).
328
- const ref = new Date(Date.UTC(parts.year, parts.month - 1, parts.day + days));
329
- const tY = ref.getUTCFullYear();
330
- const tM = ref.getUTCMonth() + 1;
331
- const tD = ref.getUTCDate();
332
- // Noon UTC covers UTC-12 through ~UTC+11. For far-east timezones
333
- // (UTC+12/+13/+14) noon UTC is already the next local day, so fall
334
- // back to midnight UTC which resolves correctly there.
335
- const noonUTC = new Date(Date.UTC(tY, tM - 1, tD, 12, 0, 0));
336
- const r = localDateParts(noonUTC, timeZone);
337
- if (r.year === tY && r.month === tM && r.day === tD) {
338
- return noonUTC;
339
- }
340
- return new Date(Date.UTC(tY, tM - 1, tD, 0, 0, 0));
341
- }
342
-
343
313
  /**
344
314
  * Build a compact temporal context string for model injection.
345
- *
346
- * Output is hard-capped at {@link MAX_OUTPUT_CHARS} characters and
347
- * {@link MAX_HORIZON_ENTRIES} horizon entries.
348
315
  */
349
316
  export function buildTemporalContext(
350
317
  options: TemporalContextOptions = {},
@@ -376,67 +343,27 @@ export function buildTemporalContext(
376
343
  : resolvedUserTimeZone
377
344
  ? "user_profile_memory"
378
345
  : "assistant_host_fallback";
379
- const horizonDays = Math.min(
380
- options.horizonDays ?? MAX_HORIZON_ENTRIES,
381
- MAX_HORIZON_ENTRIES,
382
- );
383
-
384
346
  const todayParts = localDateParts(now, timeZone);
385
347
  const todayStr = formatLocalDate(now, timeZone);
386
348
  const todayWeekday = WEEKDAY_NAMES[todayParts.weekday];
387
349
 
388
- // ── Next weekend (Saturday-Sunday) ──
389
- const daysUntilSaturday = (6 - todayParts.weekday + 7) % 7 || 7;
390
- const nextSaturday = addDays(now, daysUntilSaturday, timeZone);
391
- const nextSunday = addDays(now, daysUntilSaturday + 1, timeZone);
392
-
393
- // ── Next work week (Monday-Friday) ──
394
- const daysUntilMonday = (1 - todayParts.weekday + 7) % 7 || 7;
395
- const nextMonday = addDays(now, daysUntilMonday, timeZone);
396
- const nextFriday = addDays(now, daysUntilMonday + 4, timeZone);
397
-
398
- // ── Horizon list ──
399
- const horizonLines: string[] = [];
400
- for (let i = 1; i <= horizonDays; i++) {
401
- const futureDate = addDays(now, i, timeZone);
402
- const futureParts = localDateParts(futureDate, timeZone);
403
- const label = WEEKDAY_NAMES[futureParts.weekday];
404
- horizonLines.push(` ${formatLocalDate(futureDate, timeZone)} ${label}`);
405
- }
406
-
407
350
  const lines = [
408
351
  `<temporal_context>`,
409
352
  `Today: ${todayStr} (${todayWeekday})`,
410
353
  `Timezone: ${timeZone}`,
411
354
  `Current local time: ${formatLocalIsoWithOffset(now, timeZone)}`,
412
355
  `Current UTC time: ${now.toISOString()}`,
413
- `Clock source: assistant host machine`,
414
- `Assistant host timezone: ${resolvedHostTimeZone}`,
415
- `User timezone: ${userTimeZone ?? "unknown"}`,
416
356
  `Timezone source: ${timeZoneSource}`,
417
- ``,
418
- `Week definitions: work week = Monday–Friday, weekend = Saturday–Sunday`,
419
- ``,
420
- `Next weekend: ${formatLocalDate(
421
- nextSaturday,
422
- timeZone,
423
- )} – ${formatLocalDate(nextSunday, timeZone)}`,
424
- `Next work week: ${formatLocalDate(
425
- nextMonday,
426
- timeZone,
427
- )} – ${formatLocalDate(nextFriday, timeZone)}`,
428
- ``,
429
- `Upcoming dates:`,
430
- ...horizonLines,
431
- `</temporal_context>`,
432
357
  ];
433
358
 
434
- let output = lines.join("\n");
435
-
436
- // Hard cap: truncate if somehow over budget (shouldn't happen with 14 entries).
437
- if (output.length > MAX_OUTPUT_CHARS) {
438
- output = output.slice(0, MAX_OUTPUT_CHARS - 25) + "\n</temporal_context>";
359
+ if (userTimeZone && userTimeZone !== timeZone) {
360
+ lines.push(`User timezone: ${userTimeZone}`);
439
361
  }
362
+ if (resolvedHostTimeZone !== timeZone) {
363
+ lines.push(`Assistant host timezone: ${resolvedHostTimeZone}`);
364
+ }
365
+
366
+ lines.push(`</temporal_context>`);
440
367
 
441
- return output;
368
+ return lines.join("\n");
442
369
  }
@@ -551,9 +551,14 @@ export async function handleChannelVerificationSession(
551
551
  rebind: msg.rebind,
552
552
  originConversationId: msg.originConversationId,
553
553
  });
554
+ if (result._pendingSlackDm) {
555
+ const { userId, text, assistantId: aid } = result._pendingSlackDm;
556
+ deliverVerificationSlack(userId, text, aid);
557
+ }
558
+ const { _pendingSlackDm: _, ...publicResult } = result;
554
559
  ctx.send({
555
560
  type: "channel_verification_session_response",
556
- ...result,
561
+ ...publicResult,
557
562
  });
558
563
  } else {
559
564
  const result = createInboundChallenge(
@@ -591,9 +596,14 @@ export async function handleChannelVerificationSession(
591
596
  channel,
592
597
  originConversationId: msg.originConversationId,
593
598
  });
599
+ if (result._pendingSlackDm) {
600
+ const { userId, text, assistantId: aid } = result._pendingSlackDm;
601
+ deliverVerificationSlack(userId, text, aid);
602
+ }
603
+ const { _pendingSlackDm: _, ...publicResult } = result;
594
604
  ctx.send({
595
605
  type: "channel_verification_session_response",
596
- ...result,
606
+ ...publicResult,
597
607
  });
598
608
  } else {
599
609
  ctx.send({
@@ -8,6 +8,7 @@ import {
8
8
  import {
9
9
  ensureManualTokenConnection,
10
10
  removeManualTokenConnection,
11
+ syncManualTokenConnection,
11
12
  } from "../../oauth/manual-token-connection.js";
12
13
  import { getConnectionByProvider } from "../../oauth/oauth-store.js";
13
14
  import { credentialKey } from "../../security/credential-key.js";
@@ -40,6 +41,12 @@ export interface SlackChannelConfigResult {
40
41
  // -- Business logic --
41
42
 
42
43
  export async function getSlackChannelConfig(): Promise<SlackChannelConfigResult> {
44
+ const { teamId, teamName, botUserId, botUsername } = getConfig().slack;
45
+ const accountInfo = teamName
46
+ ? `${teamName}${botUsername ? ` (@${botUsername})` : ""}`
47
+ : undefined;
48
+ await syncManualTokenConnection("slack_channel", accountInfo);
49
+
43
50
  const hasBotToken = !!(await getSecureKeyAsync(
44
51
  credentialKey("slack_channel", "bot_token"),
45
52
  ));
@@ -49,7 +56,6 @@ export async function getSlackChannelConfig(): Promise<SlackChannelConfigResult>
49
56
  const conn = getConnectionByProvider("slack_channel");
50
57
  const connected =
51
58
  !!(conn && conn.status === "active") && hasBotToken && hasAppToken;
52
- const { teamId, teamName, botUserId, botUsername } = getConfig().slack;
53
59
  return {
54
60
  success: true,
55
61
  hasBotToken,
@@ -11,6 +11,7 @@ import {
11
11
  import {
12
12
  ensureManualTokenConnection,
13
13
  removeManualTokenConnection,
14
+ syncManualTokenConnection,
14
15
  } from "../../oauth/manual-token-connection.js";
15
16
  import { getConnectionByProvider } from "../../oauth/oauth-store.js";
16
17
  import { credentialKey } from "../../security/credential-key.js";
@@ -69,6 +70,11 @@ export type TelegramConfigResult = Omit<TelegramConfigResponse, "type">;
69
70
  // -- Extracted business logic functions --
70
71
 
71
72
  export async function getTelegramConfig(): Promise<TelegramConfigResult> {
73
+ const botUsername = getTelegramBotUsername();
74
+ await syncManualTokenConnection(
75
+ "telegram",
76
+ botUsername ? `@${botUsername}` : undefined,
77
+ );
72
78
  const hasBotToken = !!(await getSecureKeyAsync(
73
79
  credentialKey("telegram", "bot_token"),
74
80
  ));
@@ -78,7 +84,6 @@ export async function getTelegramConfig(): Promise<TelegramConfigResult> {
78
84
  const conn = getConnectionByProvider("telegram");
79
85
  const connected = !!(conn && conn.status === "active");
80
86
  const botId = getTelegramBotId();
81
- const botUsername = getTelegramBotUsername();
82
87
  return {
83
88
  success: true,
84
89
  hasBotToken,
@@ -581,14 +581,14 @@ export function deleteQueuedMessage(
581
581
  ) => { removeQueuedMessage(requestId: string): boolean } | undefined,
582
582
  ):
583
583
  | { removed: true }
584
- | { removed: false; reason: "session_not_found" | "message_not_found" } {
584
+ | { removed: false; reason: "conversation_not_found" | "message_not_found" } {
585
585
  const conversation = findConversation(conversationId);
586
586
  if (!conversation) {
587
587
  log.warn(
588
588
  { conversationId, requestId },
589
589
  "No conversation found for delete_queued_message",
590
590
  );
591
- return { removed: false, reason: "session_not_found" };
591
+ return { removed: false, reason: "conversation_not_found" };
592
592
  }
593
593
  const removed = conversation.removeQueuedMessage(requestId);
594
594
  if (removed) {
@@ -38,6 +38,7 @@ import {
38
38
  removeSkillsIndexEntry,
39
39
  validateManagedSkillId,
40
40
  } from "../../skills/managed-store.js";
41
+ import { deleteSkillCapabilityMemory } from "../../skills/skill-memory.js";
41
42
  import { getWorkspaceSkillsDir } from "../../util/platform.js";
42
43
  import {
43
44
  CONFIG_RELOAD_DEBOUNCE_MS,
@@ -603,6 +604,9 @@ export async function uninstallSkill(
603
604
  } catch {
604
605
  /* best effort */
605
606
  }
607
+ // Best-effort cleanup of capability memory for uninstalled skill
608
+ // (managed path handles this internally via deleteManagedSkill)
609
+ deleteSkillCapabilityMemory(skillId);
606
610
  }
607
611
 
608
612
  // Clean config entry
@@ -42,6 +42,7 @@ import { startMemoryJobsWorker } from "../memory/jobs-worker.js";
42
42
  import { initQdrantClient } from "../memory/qdrant-client.js";
43
43
  import { QdrantManager } from "../memory/qdrant-manager.js";
44
44
  import { rotateToolInvocations } from "../memory/tool-usage-store.js";
45
+ import { deleteOldTraceEvents } from "../memory/trace-event-store.js";
45
46
  import {
46
47
  emitNotificationSignal,
47
48
  registerBroadcastFn,
@@ -61,6 +62,7 @@ import {
61
62
  import { ensureVellumGuardianBinding } from "../runtime/guardian-vellum-migration.js";
62
63
  import { RuntimeHttpServer } from "../runtime/http-server.js";
63
64
  import { startScheduler } from "../schedule/scheduler.js";
65
+ import { seedCatalogSkillMemories } from "../skills/skill-memory.js";
64
66
  import { UsageTelemetryReporter } from "../telemetry/usage-telemetry-reporter.js";
65
67
  import { getLogger, initLogger } from "../util/logger.js";
66
68
  import {
@@ -373,6 +375,12 @@ export async function runDaemon(): Promise<void> {
373
375
  log.info("Daemon startup: starting memory worker");
374
376
  const memoryWorker = startMemoryJobsWorker();
375
377
 
378
+ // Seed capability memories for first-party catalog skills so the memory
379
+ // pipeline can surface relevant skills via semantic search.
380
+ void seedCatalogSkillMemories().catch((err) =>
381
+ log.warn({ err }, "Catalog skill memory seeding failed — continuing"),
382
+ );
383
+
376
384
  registerWatcherProviders();
377
385
  registerMessagingProviders();
378
386
 
@@ -400,7 +408,7 @@ export async function runDaemon(): Promise<void> {
400
408
  await emitNotificationSignal({
401
409
  sourceEventName: "schedule.notify",
402
410
  sourceChannel: "scheduler",
403
- sourceSessionId: schedule.id,
411
+ sourceContextId: schedule.id,
404
412
  attentionHints: {
405
413
  requiresAction: true,
406
414
  urgency: "high",
@@ -422,7 +430,7 @@ export async function runDaemon(): Promise<void> {
422
430
  void emitNotificationSignal({
423
431
  sourceEventName: "schedule.complete",
424
432
  sourceChannel: "scheduler",
425
- sourceSessionId: schedule.id,
433
+ sourceContextId: schedule.id,
426
434
  attentionHints: {
427
435
  requiresAction: false,
428
436
  urgency: "medium",
@@ -440,7 +448,7 @@ export async function runDaemon(): Promise<void> {
440
448
  void emitNotificationSignal({
441
449
  sourceEventName: "watcher.notification",
442
450
  sourceChannel: "watcher",
443
- sourceSessionId: `watcher-${Date.now()}`,
451
+ sourceContextId: `watcher-${Date.now()}`,
444
452
  attentionHints: {
445
453
  requiresAction: false,
446
454
  urgency: "low",
@@ -458,7 +466,7 @@ export async function runDaemon(): Promise<void> {
458
466
  void emitNotificationSignal({
459
467
  sourceEventName: "watcher.escalation",
460
468
  sourceChannel: "watcher",
461
- sourceSessionId: `watcher-escalation-${Date.now()}`,
469
+ sourceContextId: `watcher-escalation-${Date.now()}`,
462
470
  attentionHints: {
463
471
  requiresAction: true,
464
472
  urgency: "high",
@@ -824,6 +832,22 @@ export async function runDaemon(): Promise<void> {
824
832
  }
825
833
  }
826
834
 
835
+ // Prune trace events older than 7 days to keep the database lean.
836
+ // Deferred so synchronous cleanup doesn't block the startup path.
837
+ setTimeout(() => {
838
+ try {
839
+ const deletedTraceEvents = deleteOldTraceEvents(7);
840
+ if (deletedTraceEvents > 0) {
841
+ log.debug(
842
+ { deletedTraceEvents },
843
+ `Pruned ${deletedTraceEvents} trace event(s) older than 7 days`,
844
+ );
845
+ }
846
+ } catch (err) {
847
+ log.warn({ err }, "Trace event cleanup failed");
848
+ }
849
+ }, 0);
850
+
827
851
  const workspaceHeartbeat = new WorkspaceHeartbeatService();
828
852
  workspaceHeartbeat.start();
829
853
 
@@ -49,7 +49,7 @@ export async function initializeProvidersAndTools(
49
49
  }
50
50
 
51
51
  // Rehydrate the platform assistant ID from the credential store so
52
- // isPlatformManaged() works after assistant restarts.
52
+ // shouldUsePlatformCallbacks() works after assistant restarts.
53
53
  try {
54
54
  const key = credentialKey("vellum", "platform_assistant_id");
55
55
  const persisted = await getSecureKeyAsync(key);
@@ -758,10 +758,7 @@ export class DaemonServer {
758
758
  config.providerOrder,
759
759
  );
760
760
  const { rateLimit } = config;
761
- if (
762
- rateLimit.maxRequestsPerMinute > 0 ||
763
- rateLimit.maxTokensPerSession > 0
764
- ) {
761
+ if (rateLimit.maxRequestsPerMinute > 0) {
765
762
  provider = new RateLimitProvider(
766
763
  provider,
767
764
  rateLimit,
@@ -915,7 +912,6 @@ export class DaemonServer {
915
912
  resolveChannelCapabilities(
916
913
  sourceChannel,
917
914
  sourceInterface,
918
- null,
919
915
  options?.transport?.chatType,
920
916
  ),
921
917
  );
@@ -30,6 +30,7 @@ export interface ShutdownDeps {
30
30
 
31
31
  export function installShutdownHandlers(deps: ShutdownDeps): void {
32
32
  let shuttingDown = false;
33
+ let exitCode = 0;
33
34
 
34
35
  const shutdown = async () => {
35
36
  if (shuttingDown) return;
@@ -134,19 +135,24 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
134
135
  await Sentry.flush(2000);
135
136
  clearTimeout(forceTimer);
136
137
  deps.cleanupPidFile();
137
- process.exit(0);
138
+ process.exit(exitCode);
138
139
  };
139
140
 
140
141
  process.on("SIGTERM", shutdown);
141
142
  process.on("SIGINT", shutdown);
143
+ process.on("SIGHUP", shutdown);
142
144
 
143
145
  process.on("unhandledRejection", (reason) => {
144
- log.error({ err: reason }, "Unhandled promise rejection");
146
+ log.error({ err: reason }, "Unhandled promise rejection — initiating shutdown");
145
147
  Sentry.captureException(reason);
148
+ exitCode = 1;
149
+ void shutdown();
146
150
  });
147
151
 
148
152
  process.on("uncaughtException", (err) => {
149
- log.error({ err }, "Uncaught exception");
153
+ log.error({ err }, "Uncaught exception — initiating shutdown");
150
154
  Sentry.captureException(err);
155
+ exitCode = 1;
156
+ void shutdown();
151
157
  });
152
158
  }
@@ -12,6 +12,7 @@ import { join } from "node:path";
12
12
  import { compileApp } from "../bundler/app-compiler.js";
13
13
  import { generateAppIcon } from "../media/app-icon-generator.js";
14
14
  import { getApp, getAppsDir, isMultifileApp } from "../memory/app-store.js";
15
+ import { deliverVerificationSlack } from "../runtime/verification-outbound-actions.js";
15
16
  import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
16
17
  import type { ToolExecutionResult } from "../tools/types.js";
17
18
  import { getLogger } from "../util/logger.js";
@@ -226,6 +227,45 @@ registerHook(
226
227
  },
227
228
  );
228
229
 
230
+ // Dispatch pending Slack DM delivery when a CLI verification command
231
+ // completes. The CLI subprocess is sandboxed and cannot reach the
232
+ // gateway, so it includes a `_pendingSlackDm` field in its JSON output.
233
+ // This hook runs in the unsandboxed daemon process and delivers the DM.
234
+ registerHook("bash", (_name, input, result) => {
235
+ const command = (input.command ?? "") as string;
236
+ if (!command.includes("channel-verification-sessions")) return;
237
+ if (!result.content.includes("_pendingSlackDm")) return;
238
+
239
+ type PendingDm = { userId: string; text: string; assistantId: string };
240
+ type Parsed = { _pendingSlackDm?: PendingDm };
241
+
242
+ const dispatch = (parsed: Parsed) => {
243
+ if (parsed._pendingSlackDm) {
244
+ const { userId, text, assistantId } = parsed._pendingSlackDm;
245
+ deliverVerificationSlack(userId, text, assistantId);
246
+ return true;
247
+ }
248
+ return false;
249
+ };
250
+
251
+ // Try full content first (handles pretty-printed single-object JSON)
252
+ try {
253
+ if (dispatch(JSON.parse(result.content.trim()) as Parsed)) return;
254
+ } catch {
255
+ // Not a single JSON object — fall back to line-by-line for
256
+ // multi-object output (e.g. cancel + create chained with &&).
257
+ }
258
+ for (const line of result.content.split("\n")) {
259
+ const trimmed = line.trim();
260
+ if (!trimmed.startsWith("{")) continue;
261
+ try {
262
+ if (dispatch(JSON.parse(trimmed) as Parsed)) return;
263
+ } catch {
264
+ continue;
265
+ }
266
+ }
267
+ });
268
+
229
269
  // ── Runner ───────────────────────────────────────────────────────────
230
270
 
231
271
  /**
@@ -1,9 +1,17 @@
1
1
  import { v4 as uuid } from "uuid";
2
2
 
3
+ import {
4
+ getMaxSequence,
5
+ persistTraceEvent,
6
+ } from "../memory/trace-event-store.js";
7
+ import { getLogger } from "../util/logger.js";
3
8
  import type { ServerMessage, TraceEventKind } from "./message-protocol.js";
9
+ import type { TraceEvent } from "./message-types/messages.js";
4
10
 
5
11
  export type TraceEventStatus = "info" | "success" | "warning" | "error";
6
12
 
13
+ const log = getLogger("trace-emitter");
14
+
7
15
  const SUMMARY_MAX_LENGTH = 200;
8
16
  const ATTRIBUTE_VALUE_MAX_LENGTH = 500;
9
17
 
@@ -19,12 +27,21 @@ export interface TraceEmitOptions {
19
27
  * even if timestamps collide.
20
28
  */
21
29
  export class TraceEmitter {
22
- private sequence = 0;
30
+ private sequence: number;
23
31
 
24
32
  constructor(
25
33
  private readonly conversationId: string,
26
34
  private sendToClient: (msg: ServerMessage) => void,
27
- ) {}
35
+ ) {
36
+ // Seed from the highest persisted sequence so that new events always
37
+ // have strictly higher sequence numbers, even across daemon restarts.
38
+ try {
39
+ const maxPersisted = getMaxSequence(conversationId);
40
+ this.sequence = maxPersisted + 1;
41
+ } catch {
42
+ this.sequence = 0;
43
+ }
44
+ }
28
45
 
29
46
  updateSender(sendToClient: (msg: ServerMessage) => void): void {
30
47
  this.sendToClient = sendToClient;
@@ -50,7 +67,14 @@ export class TraceEmitter {
50
67
  attributes,
51
68
  };
52
69
 
70
+ // Send to client first so synchronous DB writes don't block SSE delivery.
53
71
  this.sendToClient(event);
72
+
73
+ try {
74
+ persistTraceEvent(event as TraceEvent);
75
+ } catch (err) {
76
+ log.warn({ err, eventId }, "Failed to persist trace event");
77
+ }
54
78
  }
55
79
  }
56
80
 
@@ -70,7 +70,7 @@ export interface DaemonDomainEvents {
70
70
  "daemon.lifecycle.stopped": {
71
71
  stoppedAtMs: number;
72
72
  };
73
- "daemon.session.created": {
73
+ "daemon.conversation.created": {
74
74
  conversationId: string;
75
75
  createdAtMs: number;
76
76
  };
@@ -0,0 +1,46 @@
1
+ import { recordLifecycleEvent } from "../memory/lifecycle-events-store.js";
2
+ import { getLogger } from "../util/logger.js";
3
+ import type { EventBus, Subscription } from "./bus.js";
4
+ import type { AssistantDomainEvents } from "./domain-events.js";
5
+
6
+ const log = getLogger("tool-permission-telemetry");
7
+
8
+ export function registerToolPermissionTelemetryListener(
9
+ eventBus: EventBus<AssistantDomainEvents>,
10
+ ): Subscription {
11
+ // Track which tool calls were actually prompted so we only record
12
+ // decided telemetry for real user interactions, not auto-allowed tools.
13
+ // Uses a composite key (requestId:toolName) because requestId is per-message,
14
+ // not per-tool-call — parallel tool_use blocks share the same requestId.
15
+ const promptedToolCalls = new Set<string>();
16
+
17
+ return eventBus.onAny((event) => {
18
+ try {
19
+ switch (event.type) {
20
+ case "tool.permission.requested": {
21
+ const { requestId, toolName } = event.payload;
22
+ if (requestId) {
23
+ promptedToolCalls.add(`${requestId}:${toolName}`);
24
+ }
25
+ recordLifecycleEvent(`permission_prompt:${toolName}`);
26
+ return;
27
+ }
28
+ case "tool.permission.decided": {
29
+ const { requestId, toolName, decision } = event.payload;
30
+ const key = requestId ? `${requestId}:${toolName}` : undefined;
31
+ if (key && promptedToolCalls.has(key)) {
32
+ promptedToolCalls.delete(key);
33
+ recordLifecycleEvent(
34
+ `permission_decided:${toolName}:${decision}`,
35
+ );
36
+ }
37
+ return;
38
+ }
39
+ default:
40
+ return;
41
+ }
42
+ } catch (err) {
43
+ log.warn({ err }, "Failed to record permission telemetry event");
44
+ }
45
+ });
46
+ }
@@ -24,28 +24,10 @@ import {
24
24
  getPlatformInternalApiKey,
25
25
  } from "../config/env.js";
26
26
  import { getIsContainerized } from "../config/env-registry.js";
27
- import { isManagedProxyEnabledSync } from "../providers/managed-proxy/context.js";
28
27
  import { getLogger } from "../util/logger.js";
29
28
 
30
29
  const log = getLogger("platform-callback-registration");
31
30
 
32
- /**
33
- * Whether this is a platform-managed deployment with usable managed credentials.
34
- *
35
- * True when PLATFORM_BASE_URL and PLATFORM_ASSISTANT_ID are both set **and**
36
- * the managed proxy prerequisites (including the assistant API key) were
37
- * satisfied the last time `resolveManagedProxyContext()` ran. This prevents
38
- * the system prompt from claiming managed credentials are available during
39
- * partial/failed platform bootstrap where the API key is missing.
40
- */
41
- export function isPlatformManaged(): boolean {
42
- return (
43
- !!getPlatformBaseUrl() &&
44
- !!getPlatformAssistantId() &&
45
- isManagedProxyEnabledSync()
46
- );
47
- }
48
-
49
31
  /**
50
32
  * Whether the daemon should register callback routes with the platform.
51
33
  * True when IS_CONTAINERIZED, PLATFORM_BASE_URL, and PLATFORM_ASSISTANT_ID