@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
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Caching layer for the LLM-generated identity intro text.
3
+ *
4
+ * The intro (a short identity tagline) is generated via the
5
+ * /v1/btw endpoint and displayed on the Identity panel. To avoid redundant LLM
6
+ * calls, we cache the result for 4 hours with content-hash-based invalidation:
7
+ * when USER.md, IDENTITY.md, or SOUL.md change, the cache is busted.
8
+ *
9
+ * Storage uses the existing `memory_checkpoints` table (simple key-value store).
10
+ */
11
+
12
+ import { createHash } from "node:crypto";
13
+ import { existsSync, readFileSync } from "node:fs";
14
+
15
+ import {
16
+ getMemoryCheckpoint,
17
+ setMemoryCheckpoint,
18
+ } from "../../memory/checkpoints.js";
19
+ import { getWorkspacePromptPath } from "../../util/platform.js";
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Constants
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const CACHE_TTL_MS = 4 * 60 * 60 * 1000; // 4 hours
26
+
27
+ const CHECKPOINT_KEY_TEXT = "identity:intro:text";
28
+ const CHECKPOINT_KEY_HASH = "identity:intro:content_hash";
29
+ const CHECKPOINT_KEY_TIMESTAMP = "identity:intro:cached_at";
30
+
31
+ /** Workspace files whose content influences the identity intro. */
32
+ const IDENTITY_FILES = ["USER.md", "IDENTITY.md", "SOUL.md"] as const;
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Helpers
36
+ // ---------------------------------------------------------------------------
37
+
38
+ /** Read a workspace prompt file, returning empty string if missing. */
39
+ function readWorkspaceFile(name: string): string {
40
+ try {
41
+ const path = getWorkspacePromptPath(name);
42
+ if (!existsSync(path)) return "";
43
+ return readFileSync(path, "utf-8");
44
+ } catch {
45
+ return "";
46
+ }
47
+ }
48
+
49
+ /** Compute a SHA-256 hex hash of the concatenated identity file contents. */
50
+ export function computeIdentityContentHash(): string {
51
+ const combined = IDENTITY_FILES.map(readWorkspaceFile).join("\n---\n");
52
+ return createHash("sha256").update(combined).digest("hex");
53
+ }
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Public API
57
+ // ---------------------------------------------------------------------------
58
+
59
+ export interface CachedIntro {
60
+ text: string;
61
+ }
62
+
63
+ /**
64
+ * Retrieve the cached identity intro if it exists, is within the TTL window,
65
+ * and the identity files have not changed since it was generated.
66
+ *
67
+ * Returns `null` when the cache is missing, expired, or invalidated.
68
+ */
69
+ export function getCachedIntro(): CachedIntro | null {
70
+ try {
71
+ const text = getMemoryCheckpoint(CHECKPOINT_KEY_TEXT);
72
+ const hash = getMemoryCheckpoint(CHECKPOINT_KEY_HASH);
73
+ const timestampStr = getMemoryCheckpoint(CHECKPOINT_KEY_TIMESTAMP);
74
+
75
+ if (!text || !hash || !timestampStr) return null;
76
+
77
+ // TTL check
78
+ const cachedAt = Number(timestampStr);
79
+ if (isNaN(cachedAt) || Date.now() - cachedAt > CACHE_TTL_MS) return null;
80
+
81
+ // Content-hash check — bust cache when identity files change
82
+ const currentHash = computeIdentityContentHash();
83
+ if (currentHash !== hash) return null;
84
+
85
+ return { text };
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Store the generated identity intro text in the cache along with
93
+ * the current content hash and timestamp.
94
+ */
95
+ export function setCachedIntro(text: string): void {
96
+ try {
97
+ const hash = computeIdentityContentHash();
98
+ const now = String(Date.now());
99
+ setMemoryCheckpoint(CHECKPOINT_KEY_TEXT, text);
100
+ setMemoryCheckpoint(CHECKPOINT_KEY_HASH, hash);
101
+ setMemoryCheckpoint(CHECKPOINT_KEY_TIMESTAMP, now);
102
+ } catch {
103
+ // Cache write failure is non-fatal — next request will regenerate.
104
+ }
105
+ }
@@ -11,6 +11,7 @@ import { getBaseDataDir } from "../../config/env-registry.js";
11
11
  import { getWorkspacePromptPath, readLockfile } from "../../util/platform.js";
12
12
  import { httpError } from "../http-errors.js";
13
13
  import type { RouteDefinition } from "../http-router.js";
14
+ import { getCachedIntro } from "./identity-intro-cache.js";
14
15
 
15
16
  interface DiskSpaceInfo {
16
17
  path: string;
@@ -233,6 +234,51 @@ export function handleGetIdentity(): Response {
233
234
  });
234
235
  }
235
236
 
237
+ // ---------------------------------------------------------------------------
238
+ // Identity intro cache
239
+ // ---------------------------------------------------------------------------
240
+
241
+ /**
242
+ * Parse the `## Identity Intro` section from SOUL.md.
243
+ * Returns the first non-empty line under that heading, or null.
244
+ */
245
+ function readSoulIdentityIntro(): string | null {
246
+ try {
247
+ const soulPath = getWorkspacePromptPath("SOUL.md");
248
+ if (!existsSync(soulPath)) return null;
249
+ const content = readFileSync(soulPath, "utf-8");
250
+
251
+ let inSection = false;
252
+ for (const line of content.split("\n")) {
253
+ const trimmed = line.trim();
254
+ if (/^#+\s/.test(trimmed)) {
255
+ inSection = trimmed.toLowerCase().includes("identity intro");
256
+ continue;
257
+ }
258
+ if (inSection && trimmed.length > 0) {
259
+ return trimmed;
260
+ }
261
+ }
262
+ } catch {
263
+ // Fall through to cache/fallback
264
+ }
265
+ return null;
266
+ }
267
+
268
+ export function handleGetIdentityIntro(): Response {
269
+ // Prefer SOUL.md persisted intro over LLM-generated cache
270
+ const soulIntro = readSoulIdentityIntro();
271
+ if (soulIntro) {
272
+ return Response.json({ text: soulIntro });
273
+ }
274
+
275
+ const cached = getCachedIntro();
276
+ if (!cached) {
277
+ return httpError("NOT_FOUND", "No cached identity intro available", 404);
278
+ }
279
+ return Response.json({ text: cached.text });
280
+ }
281
+
236
282
  // ---------------------------------------------------------------------------
237
283
  // Route definitions
238
284
  // ---------------------------------------------------------------------------
@@ -249,5 +295,10 @@ export function identityRouteDefinitions(): RouteDefinition[] {
249
295
  method: "GET",
250
296
  handler: () => handleGetIdentity(),
251
297
  },
298
+ {
299
+ endpoint: "identity/intro",
300
+ method: "GET",
301
+ handler: () => handleGetIdentityIntro(),
302
+ },
252
303
  ];
253
304
  }
@@ -134,7 +134,7 @@ export function handleEscalationIntercept(
134
134
  void emitNotificationSignal({
135
135
  sourceEventName: "ingress.escalation",
136
136
  sourceChannel: sourceChannel as NotificationSourceChannel,
137
- sourceSessionId: conversationId,
137
+ sourceContextId: conversationId,
138
138
  attentionHints: {
139
139
  requiresAction: true,
140
140
  urgency: "high",
@@ -231,7 +231,7 @@ export async function handleVerificationIntercept(
231
231
  void emitNotificationSignal({
232
232
  sourceEventName: "ingress.trusted_contact.activated",
233
233
  sourceChannel: sourceChannel as NotificationSourceChannel,
234
- sourceSessionId: conversationId,
234
+ sourceContextId: conversationId,
235
235
  attentionHints: {
236
236
  requiresAction: false,
237
237
  urgency: "low",
@@ -11,12 +11,19 @@
11
11
  * results with is_valid flag and detailed error descriptions.
12
12
  */
13
13
 
14
+ import { join } from "node:path";
14
15
  import { Database } from "bun:sqlite";
15
16
 
16
17
  import { invalidateConfigCache } from "../../config/loader.js";
17
18
  import { resetDb } from "../../memory/db-connection.js";
19
+ import { clearCache as clearTrustCache } from "../../permissions/trust-store.js";
18
20
  import { getLogger } from "../../util/logger.js";
19
- import { getDbPath, getWorkspaceConfigPath } from "../../util/platform.js";
21
+ import {
22
+ getDbPath,
23
+ getHooksDir,
24
+ getRootDir,
25
+ getWorkspaceDir,
26
+ } from "../../util/platform.js";
20
27
  import { httpError } from "../http-errors.js";
21
28
  import type { RouteDefinition } from "../http-router.js";
22
29
  import { buildExportVBundle } from "../migrations/vbundle-builder.js";
@@ -135,13 +142,14 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
135
142
 
136
143
  try {
137
144
  const { archive, manifest } = buildExportVBundle({
138
- dbPath: getDbPath(),
139
- configPath: getWorkspaceConfigPath(),
145
+ trustPath: join(getRootDir(), "protected", "trust.json"),
146
+ hooksDir: getHooksDir(),
147
+ workspaceDir: getWorkspaceDir(),
140
148
  source: "runtime-export",
141
149
  description,
142
150
  checkpoint: () => {
151
+ const dbPath = getDbPath();
143
152
  try {
144
- const dbPath = getDbPath();
145
153
  const db = new Database(dbPath);
146
154
  try {
147
155
  db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
@@ -149,10 +157,10 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
149
157
  db.close();
150
158
  }
151
159
  } catch (err) {
152
- log.warn(
153
- { err },
154
- "WAL checkpoint failed exporting without checkpoint",
155
- );
160
+ // Best-effort: if the DB can't be checkpointed (e.g. not a valid
161
+ // SQLite file, missing WAL, etc.) we still proceed with the export
162
+ // using whatever is on disk.
163
+ log.warn({ err }, "WAL checkpoint failed — exporting without checkpoint");
156
164
  }
157
165
  },
158
166
  });
@@ -289,8 +297,9 @@ export async function handleMigrationImportPreflight(
289
297
 
290
298
  // Step 2: Analyze what would change on import
291
299
  const pathResolver = new DefaultPathResolver(
292
- getDbPath(),
293
- getWorkspaceConfigPath(),
300
+ join(getRootDir(), "protected"),
301
+ getWorkspaceDir(),
302
+ getHooksDir(),
294
303
  );
295
304
 
296
305
  const report = analyzeImport({
@@ -371,8 +380,9 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
371
380
  }
372
381
 
373
382
  const pathResolver = new DefaultPathResolver(
374
- getDbPath(),
375
- getWorkspaceConfigPath(),
383
+ join(getRootDir(), "protected"),
384
+ getWorkspaceDir(),
385
+ getHooksDir(),
376
386
  );
377
387
 
378
388
  // Close the live SQLite connection before overwriting assistant.db on disk.
@@ -384,6 +394,7 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
384
394
  pathResolver,
385
395
  preValidatedManifest: validation.manifest,
386
396
  preValidatedEntries: validation.entries,
397
+ workspaceDir: getWorkspaceDir(),
387
398
  });
388
399
 
389
400
  if (!result.ok) {
@@ -420,8 +431,9 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
420
431
  );
421
432
  }
422
433
 
423
- // Invalidate in-process config cache so imported settings.json takes effect
434
+ // Invalidate in-process caches so imported settings.json and trust.json take effect
424
435
  invalidateConfigCache();
436
+ clearTrustCache();
425
437
 
426
438
  return Response.json(result.report);
427
439
  } catch (err) {
@@ -11,6 +11,8 @@ import {
11
11
  } from "../../config/loader.js";
12
12
  import type { CesClient } from "../../credential-execution/client.js";
13
13
  import { setSentryOrganizationId } from "../../instrument.js";
14
+ import { syncManualTokenConnection } from "../../oauth/manual-token-connection.js";
15
+ import { validateAnthropicApiKey } from "../../providers/anthropic/client.js";
14
16
  import { initializeProviders } from "../../providers/registry.js";
15
17
  import { credentialKey } from "../../security/credential-key.js";
16
18
  import {
@@ -129,6 +131,21 @@ export async function handleAddSecret(
129
131
  400,
130
132
  );
131
133
  }
134
+ // Validate Anthropic API keys before storing
135
+ if (name === "anthropic") {
136
+ const validation = await validateAnthropicApiKey(value);
137
+ if (!validation.valid) {
138
+ log.warn(
139
+ { provider: name, reason: validation.reason },
140
+ "API key validation failed",
141
+ );
142
+ return Response.json(
143
+ { success: false, error: validation.reason },
144
+ { status: 422 },
145
+ );
146
+ }
147
+ }
148
+
132
149
  const stored = await setSecureKeyAsync(name, value);
133
150
  if (!stored) {
134
151
  return httpError(
@@ -201,6 +218,7 @@ export async function handleAddSecret(
201
218
  );
202
219
  }
203
220
  upsertCredentialMetadata(service, field, {});
221
+ await syncManualTokenConnection(service);
204
222
  if (service === "vellum" && field === "platform_base_url") {
205
223
  setPlatformBaseUrl(effectiveValue);
206
224
  }
@@ -43,8 +43,8 @@ import {
43
43
  } from "../../tools/execution-target.js";
44
44
  import { getAllTools, getTool } from "../../tools/registry.js";
45
45
  import {
46
- injectReasonField,
47
- REASON_SKIP_SET,
46
+ ACTIVITY_SKIP_SET,
47
+ injectActivityField,
48
48
  } from "../../tools/schema-transforms.js";
49
49
  import { isSideEffectTool } from "../../tools/side-effects.js";
50
50
  import { generateAndSaveAvatar } from "../../tools/system/avatar-generator.js";
@@ -400,17 +400,17 @@ function handleToolNamesList(): Response {
400
400
  }
401
401
  }
402
402
 
403
- // Apply reason injection so settings/debug schemas match runtime behavior.
404
- const transformedDefs = injectReasonField(rawDefs, REASON_SKIP_SET);
403
+ // Apply activity injection so settings/debug schemas match runtime behavior.
404
+ const transformedDefs = injectActivityField(rawDefs, ACTIVITY_SKIP_SET);
405
405
  for (const def of transformedDefs) {
406
406
  schemas[def.name] = def.input_schema as SchemaShape;
407
407
  }
408
408
 
409
409
  // Skill manifest schemas are served raw (untransformed). Unlike runtime tool
410
- // schemas which have `reason` injected via injectReasonField(), skill manifests
411
- // reflect the original TOOLS.json content. This is intentional: skill tools are
412
- // invoked through skill_execute (which has its own reason field), so their
413
- // individual schemas are never sent to the LLM directly.
410
+ // schemas which have `activity` injected via injectActivityField(), skill
411
+ // manifests reflect the original TOOLS.json content. This is intentional:
412
+ // skill tools are invoked through skill_execute (which has its own activity
413
+ // field), so their individual schemas are never sent to the LLM directly.
414
414
  try {
415
415
  const catalog = loadSkillCatalog();
416
416
  for (const skill of catalog) {
@@ -522,7 +522,7 @@ async function handleToolPermissionSimulate(body: {
522
522
  }
523
523
 
524
524
  return Response.json({
525
- ok: true,
525
+ success: true,
526
526
  decision: result.decision,
527
527
  riskLevel,
528
528
  reason: result.reason,
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Route handlers for telemetry lifecycle events.
3
+ *
4
+ * POST /v1/telemetry/lifecycle — record a lifecycle event (app_open, hatch).
5
+ */
6
+
7
+ import { recordLifecycleEvent } from "../../memory/lifecycle-events-store.js";
8
+ import { getLogger } from "../../util/logger.js";
9
+ import { httpError } from "../http-errors.js";
10
+ import type { RouteDefinition } from "../http-router.js";
11
+
12
+ const log = getLogger("telemetry-routes");
13
+
14
+ const VALID_EVENT_NAMES = new Set(["app_open", "hatch"]);
15
+
16
+ export async function handleRecordLifecycleEvent(
17
+ req: Request,
18
+ ): Promise<Response> {
19
+ let body: { event_name?: string };
20
+ try {
21
+ body = (await req.json()) as { event_name?: string };
22
+ } catch {
23
+ return httpError("BAD_REQUEST", "Invalid JSON body", 400);
24
+ }
25
+
26
+ const eventName = body.event_name;
27
+ if (!eventName || !VALID_EVENT_NAMES.has(eventName)) {
28
+ return httpError(
29
+ "BAD_REQUEST",
30
+ `event_name must be one of: ${[...VALID_EVENT_NAMES].join(", ")}`,
31
+ 400,
32
+ );
33
+ }
34
+
35
+ const event = recordLifecycleEvent(eventName);
36
+ log.info({ eventName, eventId: event.id }, "Recorded lifecycle event");
37
+
38
+ return Response.json({ id: event.id, event_name: event.eventName });
39
+ }
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Route definitions
43
+ // ---------------------------------------------------------------------------
44
+
45
+ export function telemetryRouteDefinitions(): RouteDefinition[] {
46
+ return [
47
+ {
48
+ endpoint: "telemetry/lifecycle",
49
+ method: "POST",
50
+ handler: async ({ req }) => handleRecordLifecycleEvent(req),
51
+ },
52
+ ];
53
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * HTTP route handlers for trace event retrieval.
3
+ *
4
+ * GET /v1/trace-events — Returns persisted trace events for a conversation.
5
+ */
6
+
7
+ import { getTraceEvents } from "../../memory/trace-event-store.js";
8
+ import { httpError } from "../http-errors.js";
9
+ import type { RouteDefinition } from "../http-router.js";
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Route definitions
13
+ // ---------------------------------------------------------------------------
14
+
15
+ export function traceEventRouteDefinitions(): RouteDefinition[] {
16
+ return [
17
+ {
18
+ endpoint: "trace-events",
19
+ method: "GET",
20
+ handler: ({ url }) => {
21
+ const conversationId = url.searchParams.get("conversationId");
22
+ if (!conversationId) {
23
+ return httpError(
24
+ "BAD_REQUEST",
25
+ "conversationId query parameter is required",
26
+ 400,
27
+ );
28
+ }
29
+
30
+ const limitParam = url.searchParams.get("limit");
31
+ const afterSequenceParam = url.searchParams.get("afterSequence");
32
+
33
+ const limit = limitParam ? parseInt(limitParam, 10) : undefined;
34
+ if (limitParam && (isNaN(limit!) || limit! <= 0)) {
35
+ return httpError(
36
+ "BAD_REQUEST",
37
+ "limit must be a positive integer",
38
+ 400,
39
+ );
40
+ }
41
+
42
+ const afterSequence = afterSequenceParam
43
+ ? parseInt(afterSequenceParam, 10)
44
+ : undefined;
45
+ if (afterSequenceParam && (isNaN(afterSequence!) || afterSequence! < 0)) {
46
+ return httpError(
47
+ "BAD_REQUEST",
48
+ "afterSequence must be a non-negative integer",
49
+ 400,
50
+ );
51
+ }
52
+
53
+ const events = getTraceEvents(conversationId, {
54
+ limit,
55
+ afterSequence,
56
+ });
57
+
58
+ return Response.json({ events });
59
+ },
60
+ },
61
+ ];
62
+ }
@@ -146,7 +146,7 @@ export function createOrReuseToolGrantRequest(
146
146
  const signalPromise = emitNotificationSignal({
147
147
  sourceEventName: "guardian.question",
148
148
  sourceChannel: sourceChannel as NotificationSourceChannel,
149
- sourceSessionId: conversationId,
149
+ sourceContextId: conversationId,
150
150
  attentionHints: {
151
151
  requiresAction: true,
152
152
  urgency: "high",
@@ -116,6 +116,12 @@ export interface OutboundActionResult {
116
116
  pendingBootstrap?: boolean;
117
117
  /** Echoed back so consumers know which conversation to target for pointers. */
118
118
  originConversationId?: string;
119
+ /** Internal: Slack DM delivery payload for the caller to dispatch.
120
+ * The shared startOutbound/resendOutbound functions no longer fire the
121
+ * delivery themselves because CLI subprocesses are sandboxed and cannot
122
+ * reach the gateway. The daemon HTTP route handler calls
123
+ * deliverVerificationSlack() after receiving this payload. */
124
+ _pendingSlackDm?: { userId: string; text: string; assistantId: string };
119
125
  }
120
126
 
121
127
  // ---------------------------------------------------------------------------
@@ -486,42 +492,52 @@ function startOutboundVoice(
486
492
 
487
493
  /**
488
494
  * Deliver a verification Slack DM via the gateway's /deliver/slack endpoint.
489
- * Fire-and-forget with error logging.
495
+ * Returns a promise that resolves when the delivery attempt completes.
490
496
  */
491
- export function deliverVerificationSlack(
497
+ export async function deliverVerificationSlackAsync(
492
498
  userId: string,
493
499
  text: string,
494
500
  assistantId: string,
495
- ): void {
496
- (async () => {
497
- try {
498
- const gatewayUrl = getGatewayInternalBaseUrl();
499
- const bearerToken = mintDaemonDeliveryToken();
500
- const url = `${gatewayUrl}/deliver/slack`;
501
- const resp = await fetch(url, {
502
- method: "POST",
503
- headers: {
504
- "Content-Type": "application/json",
505
- Authorization: `Bearer ${bearerToken}`,
506
- },
507
- body: JSON.stringify({ chatId: userId, text, assistantId }),
508
- });
509
- if (!resp.ok) {
510
- const body = await resp.text().catch(() => "<unreadable>");
511
- log.error(
512
- { userId, assistantId, status: resp.status, body },
513
- "Gateway /deliver/slack failed for verification",
514
- );
515
- } else {
516
- log.info({ userId, assistantId }, "Verification Slack DM delivered");
517
- }
518
- } catch (err) {
501
+ ): Promise<void> {
502
+ try {
503
+ const gatewayUrl = getGatewayInternalBaseUrl();
504
+ const bearerToken = mintDaemonDeliveryToken();
505
+ const url = `${gatewayUrl}/deliver/slack`;
506
+ const resp = await fetch(url, {
507
+ method: "POST",
508
+ headers: {
509
+ "Content-Type": "application/json",
510
+ Authorization: `Bearer ${bearerToken}`,
511
+ },
512
+ body: JSON.stringify({ chatId: userId, text, assistantId }),
513
+ });
514
+ if (!resp.ok) {
515
+ const body = await resp.text().catch(() => "<unreadable>");
519
516
  log.error(
520
- { err, userId, assistantId },
521
- "Failed to deliver verification Slack DM",
517
+ { userId, assistantId, status: resp.status, body },
518
+ "Gateway /deliver/slack failed for verification",
522
519
  );
520
+ } else {
521
+ log.info({ userId, assistantId }, "Verification Slack DM delivered");
523
522
  }
524
- })();
523
+ } catch (err) {
524
+ log.error(
525
+ { err, userId, assistantId },
526
+ "Failed to deliver verification Slack DM",
527
+ );
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Deliver a verification Slack DM via the gateway's /deliver/slack endpoint.
533
+ * Fire-and-forget wrapper for use in the daemon process (HTTP route handlers).
534
+ */
535
+ export function deliverVerificationSlack(
536
+ userId: string,
537
+ text: string,
538
+ assistantId: string,
539
+ ): void {
540
+ deliverVerificationSlackAsync(userId, text, assistantId);
525
541
  }
526
542
 
527
543
  function startOutboundSlack(
@@ -588,7 +604,6 @@ function startOutboundSlack(
588
604
  const sendCount = 1;
589
605
 
590
606
  updateSessionDelivery(sessionResult.sessionId, now, sendCount, nextResendAt);
591
- deliverVerificationSlack(destination, slackBody, assistantId);
592
607
 
593
608
  return {
594
609
  success: true,
@@ -599,6 +614,7 @@ function startOutboundSlack(
599
614
  sendCount,
600
615
  channel,
601
616
  originConversationId,
617
+ _pendingSlackDm: { userId: destination, text: slackBody, assistantId },
602
618
  };
603
619
  }
604
620
 
@@ -788,7 +804,6 @@ export function resendOutbound(
788
804
  newSendCount,
789
805
  nextResendAt,
790
806
  );
791
- deliverVerificationSlack(destination, slackBody, assistantId);
792
807
 
793
808
  return {
794
809
  success: true,
@@ -798,6 +813,7 @@ export function resendOutbound(
798
813
  sendCount: newSendCount,
799
814
  channel,
800
815
  originConversationId,
816
+ _pendingSlackDm: { userId: destination, text: slackBody, assistantId },
801
817
  };
802
818
  }
803
819