@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
@@ -42,9 +42,13 @@ export function isConversationFailed(conversationId: string): boolean {
42
42
  export function invalidateAssistantInferredItemsForConversation(
43
43
  conversationId: string,
44
44
  ): number {
45
- // Cancel pending extract_items jobs for this conversation's messages
45
+ // Cancel pending extraction jobs for this conversation's messages
46
46
  // so the worker never processes them. Jobs already running will be
47
47
  // caught by the isConversationFailed check in the extraction handler.
48
+ // NOTE: Only extract_items jobs are cancelled here — not embed_item or
49
+ // other job types. Multi-sourced items may still be valid (corroborated
50
+ // by other conversations), and their embedding jobs must not be killed.
51
+ // The broader cancelPendingJobsForConversation is used by the wipe path.
48
52
  cancelPendingExtractionJobsForConversation(conversationId);
49
53
 
50
54
  const affected = rawRun(
@@ -94,9 +98,95 @@ export function invalidateAssistantInferredItemsForConversation(
94
98
  }
95
99
 
96
100
  /**
97
- * Cancel pending `extract_items` jobs whose messageId belongs to the given
98
- * conversation. This drains the queue so the worker never processes them,
99
- * complementing the runtime check in the extraction handler.
101
+ * Cancel all pending/running memory jobs referencing the given conversation.
102
+ * Covers every job type: `extract_items`, `embed_attachment` (keyed by messageId),
103
+ * `embed_segment` (keyed by segmentId via memory_segments),
104
+ * `build_conversation_summary` (keyed by conversationId),
105
+ * and `embed_item` (keyed by itemId sourced from the conversation's messages).
106
+ */
107
+ export function cancelPendingJobsForConversation(
108
+ conversationId: string,
109
+ reason: string = "conversation_wiped",
110
+ ): number {
111
+ const now = Date.now();
112
+ let total = 0;
113
+
114
+ // Jobs keyed by messageId: extract_items, embed_attachment
115
+ total += rawRun(
116
+ `UPDATE memory_jobs
117
+ SET status = 'failed',
118
+ last_error = ?,
119
+ updated_at = ?
120
+ WHERE status IN ('pending', 'running')
121
+ AND json_extract(payload, '$.messageId') IN (
122
+ SELECT id FROM messages WHERE conversation_id = ?
123
+ )`,
124
+ reason,
125
+ now,
126
+ conversationId,
127
+ );
128
+
129
+ // Jobs keyed by conversationId: build_conversation_summary
130
+ total += rawRun(
131
+ `UPDATE memory_jobs
132
+ SET status = 'failed',
133
+ last_error = ?,
134
+ updated_at = ?
135
+ WHERE status IN ('pending', 'running')
136
+ AND json_extract(payload, '$.conversationId') = ?`,
137
+ reason,
138
+ now,
139
+ conversationId,
140
+ );
141
+
142
+ // Jobs keyed by segmentId: embed_segment (segments belong to the conversation)
143
+ total += rawRun(
144
+ `UPDATE memory_jobs
145
+ SET status = 'failed',
146
+ last_error = ?,
147
+ updated_at = ?
148
+ WHERE status IN ('pending', 'running')
149
+ AND json_extract(payload, '$.segmentId') IN (
150
+ SELECT id FROM memory_segments WHERE conversation_id = ?
151
+ )`,
152
+ reason,
153
+ now,
154
+ conversationId,
155
+ );
156
+
157
+ // Jobs keyed by itemId: embed_item (items sourced from this conversation)
158
+ total += rawRun(
159
+ `UPDATE memory_jobs
160
+ SET status = 'failed',
161
+ last_error = ?,
162
+ updated_at = ?
163
+ WHERE status IN ('pending', 'running')
164
+ AND json_extract(payload, '$.itemId') IN (
165
+ SELECT mis.memory_item_id
166
+ FROM memory_item_sources mis
167
+ JOIN messages m ON m.id = mis.message_id
168
+ WHERE m.conversation_id = ?
169
+ )`,
170
+ reason,
171
+ now,
172
+ conversationId,
173
+ );
174
+
175
+ if (total > 0) {
176
+ log.info(
177
+ { conversationId, cancelled: total },
178
+ "Cancelled pending memory jobs for conversation",
179
+ );
180
+ }
181
+
182
+ return total;
183
+ }
184
+
185
+ /**
186
+ * Cancel only pending/running `extract_items` jobs for messages in the
187
+ * given conversation. Used by the task-failure path where we want to
188
+ * stop new extractions but must NOT cancel `embed_item` jobs — those
189
+ * items may be multi-sourced and still valid.
100
190
  */
101
191
  function cancelPendingExtractionJobsForConversation(
102
192
  conversationId: string,
@@ -107,8 +197,8 @@ function cancelPendingExtractionJobsForConversation(
107
197
  SET status = 'failed',
108
198
  last_error = 'conversation_failed',
109
199
  updated_at = ?
110
- WHERE type IN ('extract_items')
111
- AND status IN ('pending', 'running')
200
+ WHERE status IN ('pending', 'running')
201
+ AND type = 'extract_items'
112
202
  AND json_extract(payload, '$.messageId') IN (
113
203
  SELECT id FROM messages WHERE conversation_id = ?
114
204
  )`,
@@ -0,0 +1,148 @@
1
+ import { and, asc, eq, gt, lt, sql } from "drizzle-orm";
2
+
3
+ import type {
4
+ TraceEvent,
5
+ TraceEventKind,
6
+ } from "../daemon/message-types/messages.js";
7
+ import { getDb, rawChanges } from "./db.js";
8
+ import { traceEvents } from "./schema.js";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Types
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export interface TraceEventRow {
15
+ eventId: string;
16
+ conversationId: string;
17
+ requestId?: string;
18
+ timestampMs: number;
19
+ sequence: number;
20
+ kind: TraceEventKind;
21
+ status?: "info" | "success" | "warning" | "error";
22
+ summary: string;
23
+ attributes?: Record<string, string | number | boolean | null>;
24
+ }
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Write
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /** Insert a single trace event row. Duplicate eventIds are silently ignored. */
31
+ export function persistTraceEvent(event: TraceEvent): void {
32
+ const db = getDb();
33
+ db.insert(traceEvents)
34
+ .values({
35
+ eventId: event.eventId,
36
+ conversationId: event.conversationId,
37
+ requestId: event.requestId ?? null,
38
+ timestampMs: event.timestampMs,
39
+ sequence: event.sequence,
40
+ kind: event.kind,
41
+ status: event.status ?? null,
42
+ summary: event.summary,
43
+ attributesJson: event.attributes
44
+ ? JSON.stringify(event.attributes)
45
+ : null,
46
+ createdAt: Date.now(),
47
+ })
48
+ .onConflictDoNothing()
49
+ .run();
50
+ }
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Read
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /** Parse a raw DB row into a TraceEventRow with deserialized attributes. */
57
+ function rowToTraceEventRow(row: {
58
+ eventId: string;
59
+ conversationId: string;
60
+ requestId: string | null;
61
+ timestampMs: number;
62
+ sequence: number;
63
+ kind: string;
64
+ status: string | null;
65
+ summary: string;
66
+ attributesJson: string | null;
67
+ }): TraceEventRow {
68
+ return {
69
+ eventId: row.eventId,
70
+ conversationId: row.conversationId,
71
+ requestId: row.requestId ?? undefined,
72
+ timestampMs: row.timestampMs,
73
+ sequence: row.sequence,
74
+ kind: row.kind as TraceEventKind,
75
+ status: (row.status as TraceEventRow["status"]) ?? undefined,
76
+ summary: row.summary,
77
+ attributes: row.attributesJson
78
+ ? (JSON.parse(row.attributesJson) as Record<
79
+ string,
80
+ string | number | boolean | null
81
+ >)
82
+ : undefined,
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Query trace events for a conversation, ordered by sequence ASC, timestamp_ms ASC.
88
+ * Default limit of 5000 (matching the client's retention cap).
89
+ * Supports `afterSequence` for incremental fetching.
90
+ */
91
+ export function getTraceEvents(
92
+ conversationId: string,
93
+ opts?: { limit?: number; afterSequence?: number },
94
+ ): TraceEventRow[] {
95
+ const db = getDb();
96
+ const limit = opts?.limit ?? 5000;
97
+
98
+ const where =
99
+ opts?.afterSequence != null
100
+ ? and(
101
+ eq(traceEvents.conversationId, conversationId),
102
+ gt(traceEvents.sequence, opts.afterSequence),
103
+ )
104
+ : eq(traceEvents.conversationId, conversationId);
105
+
106
+ const rows = db
107
+ .select()
108
+ .from(traceEvents)
109
+ .where(where)
110
+ .orderBy(asc(traceEvents.sequence), asc(traceEvents.timestampMs))
111
+ .limit(limit)
112
+ .all();
113
+
114
+ return rows.map(rowToTraceEventRow);
115
+ }
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // Cleanup
119
+ // ---------------------------------------------------------------------------
120
+
121
+ /**
122
+ * Delete trace events older than `maxAgeDays` based on `created_at`.
123
+ * Returns the count of deleted rows.
124
+ */
125
+ export function deleteOldTraceEvents(maxAgeDays: number): number {
126
+ const db = getDb();
127
+ const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
128
+ db.delete(traceEvents).where(lt(traceEvents.createdAt, cutoff)).run();
129
+ return rawChanges();
130
+ }
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // Sequence
134
+ // ---------------------------------------------------------------------------
135
+
136
+ /**
137
+ * Return the highest sequence number persisted for a conversation,
138
+ * or -1 if no events exist yet.
139
+ */
140
+ export function getMaxSequence(conversationId: string): number {
141
+ const db = getDb();
142
+ const row = db
143
+ .select({ maxSeq: sql<number>`MAX(${traceEvents.sequence})` })
144
+ .from(traceEvents)
145
+ .where(eq(traceEvents.conversationId, conversationId))
146
+ .get();
147
+ return row?.maxSeq ?? -1;
148
+ }
@@ -441,7 +441,7 @@ import { emitNotificationSignal } from "../notifications/emit-signal.js";
441
441
  await emitNotificationSignal({
442
442
  sourceEventName: "your_event_name",
443
443
  sourceChannel: "scheduler", // where the event originated
444
- sourceSessionId: conversationId,
444
+ sourceContextId: conversationId,
445
445
  attentionHints: {
446
446
  requiresAction: true,
447
447
  urgency: "high",
@@ -319,7 +319,7 @@ function buildFallbackDecision(
319
319
  selectedChannels: [],
320
320
  reasoningSummary: "Fallback: suppressed (vellum channel not available)",
321
321
  renderedCopy: {},
322
- dedupeKey: `fallback:${signal.sourceEventName}:${signal.sourceSessionId}:${signal.createdAt}`,
322
+ dedupeKey: `fallback:${signal.sourceEventName}:${signal.sourceContextId}:${signal.createdAt}`,
323
323
  confidence: 0.3,
324
324
  fallbackUsed: true,
325
325
  };
@@ -334,7 +334,7 @@ function buildFallbackDecision(
334
334
  ? "Fallback: high urgency + requires action — all channels"
335
335
  : "Fallback: vellum-only (local, always delivered)",
336
336
  renderedCopy: copy,
337
- dedupeKey: `fallback:${signal.sourceEventName}:${signal.sourceSessionId}:${signal.createdAt}`,
337
+ dedupeKey: `fallback:${signal.sourceEventName}:${signal.sourceContextId}:${signal.createdAt}`,
338
338
  confidence: 0.3,
339
339
  fallbackUsed: true,
340
340
  };
@@ -852,17 +852,58 @@ async function classifyWithLLM(
852
852
  *
853
853
  * - `all_channels`: force selected channels to all connected channels.
854
854
  * - `multi_channel`: ensure at least 2 channels when 2+ are connected.
855
- * - `single_channel`: no override (default behavior).
855
+ * - `single_channel`: cap to a single channel. When explicitly set, reduces
856
+ * selected channels to one — preferring the source channel if present.
856
857
  */
857
858
  export function enforceRoutingIntent(
858
859
  decision: NotificationDecision,
859
860
  routingIntent: RoutingIntent | undefined,
860
861
  connectedChannels: NotificationChannel[],
862
+ sourceChannel?: string,
861
863
  ): NotificationDecision {
862
- if (!routingIntent || routingIntent === "single_channel") {
864
+ if (!routingIntent) {
863
865
  return decision;
864
866
  }
865
867
 
868
+ if (routingIntent === "single_channel") {
869
+ if (!decision.shouldNotify) {
870
+ return decision;
871
+ }
872
+
873
+ // Force delivery to the source channel only. If the source channel
874
+ // is among the connected channels, use it regardless of what the LLM
875
+ // picked (even if the LLM picked exactly one wrong channel).
876
+ // Otherwise fall back to capping at the first selected channel.
877
+ const sourceIsConnected =
878
+ sourceChannel &&
879
+ connectedChannels.includes(sourceChannel as NotificationChannel);
880
+ const preferred = sourceIsConnected
881
+ ? (sourceChannel as NotificationChannel)
882
+ : decision.selectedChannels[0];
883
+
884
+ // No change needed if the decision already matches.
885
+ if (
886
+ decision.selectedChannels.length === 1 &&
887
+ decision.selectedChannels[0] === preferred
888
+ ) {
889
+ return decision;
890
+ }
891
+
892
+ const enforced = { ...decision };
893
+ enforced.selectedChannels = [preferred];
894
+ enforced.reasoningSummary = `${decision.reasoningSummary} [routing_intent=single_channel enforced: capped to ${preferred}]`;
895
+ log.info(
896
+ {
897
+ routingIntent,
898
+ sourceChannel,
899
+ originalChannels: decision.selectedChannels,
900
+ enforcedChannel: preferred,
901
+ },
902
+ "Routing intent enforcement: single_channel → capped to one channel",
903
+ );
904
+ return enforced;
905
+ }
906
+
866
907
  if (!decision.shouldNotify) {
867
908
  return decision;
868
909
  }
@@ -148,8 +148,8 @@ export interface EmitSignalParams<TEventName extends string = string> {
148
148
  sourceEventName: TEventName;
149
149
  /** Source channel that produced the event — must be a registered channel. */
150
150
  sourceChannel: NotificationSourceChannel;
151
- /** Conversation or conversation ID from the source context. */
152
- sourceSessionId: string;
151
+ /** Opaque identifier for the source context (conversation ID, schedule ID, call session ID, etc.). */
152
+ sourceContextId: string;
153
153
  /** Attention hints for the decision engine. */
154
154
  attentionHints: AttentionHints;
155
155
  /** Arbitrary context payload passed to the decision engine. */
@@ -202,7 +202,7 @@ export async function emitNotificationSignal<TEventName extends string>(
202
202
  signalId,
203
203
  createdAt: Date.now(),
204
204
  sourceChannel: params.sourceChannel,
205
- sourceSessionId: params.sourceSessionId,
205
+ sourceContextId: params.sourceContextId,
206
206
  sourceEventName: params.sourceEventName,
207
207
  contextPayload: (params.contextPayload ??
208
208
  {}) as NotificationContextPayload<TEventName>,
@@ -218,7 +218,7 @@ export async function emitNotificationSignal<TEventName extends string>(
218
218
  id: signalId,
219
219
  sourceEventName: params.sourceEventName,
220
220
  sourceChannel: params.sourceChannel,
221
- sourceSessionId: params.sourceSessionId,
221
+ sourceContextId: params.sourceContextId,
222
222
  attentionHints: params.attentionHints,
223
223
  payload: params.contextPayload ?? {},
224
224
  dedupeKey: params.dedupeKey,
@@ -256,6 +256,7 @@ export async function emitNotificationSignal<TEventName extends string>(
256
256
  decision,
257
257
  signal.routingIntent,
258
258
  connectedChannels,
259
+ signal.sourceChannel,
259
260
  );
260
261
 
261
262
  // Re-persist the decision if routing intent enforcement changed it,
@@ -16,7 +16,7 @@ export interface NotificationEventRow {
16
16
  id: string;
17
17
  sourceEventName: string;
18
18
  sourceChannel: string;
19
- sourceSessionId: string;
19
+ sourceContextId: string;
20
20
  attentionHintsJson: string;
21
21
  payloadJson: string;
22
22
  dedupeKey: string | null;
@@ -31,7 +31,7 @@ function rowToEvent(
31
31
  id: row.id,
32
32
  sourceEventName: row.sourceEventName,
33
33
  sourceChannel: row.sourceChannel,
34
- sourceSessionId: row.sourceSessionId,
34
+ sourceContextId: row.sourceContextId,
35
35
  attentionHintsJson: row.attentionHintsJson,
36
36
  payloadJson: row.payloadJson,
37
37
  dedupeKey: row.dedupeKey,
@@ -44,7 +44,7 @@ export interface CreateEventParams {
44
44
  id: string;
45
45
  sourceEventName: string;
46
46
  sourceChannel: string;
47
- sourceSessionId: string;
47
+ sourceContextId: string;
48
48
  attentionHints: AttentionHints;
49
49
  payload: Record<string, unknown>;
50
50
  dedupeKey?: string;
@@ -76,7 +76,7 @@ export function createEvent(
76
76
  id: params.id,
77
77
  sourceEventName: params.sourceEventName,
78
78
  sourceChannel: params.sourceChannel,
79
- sourceSessionId: params.sourceSessionId,
79
+ sourceContextId: params.sourceContextId,
80
80
  attentionHintsJson: JSON.stringify(params.attentionHints),
81
81
  payloadJson: JSON.stringify(params.payload),
82
82
  dedupeKey: normalizedDedupeKey,
@@ -131,7 +131,7 @@ export interface NotificationSignal<TEventName extends string = string> {
131
131
  signalId: string;
132
132
  createdAt: number; // epoch ms
133
133
  sourceChannel: NotificationSourceChannel; // see NOTIFICATION_SOURCE_CHANNELS registry
134
- sourceSessionId: string;
134
+ sourceContextId: string;
135
135
  sourceEventName: TEventName; // free-form: 'reminder_fired', 'schedule_complete', 'guardian_question', etc.
136
136
  contextPayload: NotificationContextPayload<TEventName>;
137
137
  attentionHints: AttentionHints;
@@ -65,6 +65,53 @@ export function removeManualTokenConnection(providerKey: string): void {
65
65
  deleteConnection(conn.id);
66
66
  }
67
67
 
68
+ /**
69
+ * Reconcile the synthetic oauth_connection row for a manual-token provider
70
+ * with whatever credentials are currently present in secure storage.
71
+ *
72
+ * This lets generic credential entry paths (chat setup, CLI, secure prompt)
73
+ * keep connection status in sync without duplicating per-provider rules.
74
+ */
75
+ export async function syncManualTokenConnection(
76
+ providerKey: string,
77
+ accountInfo?: string,
78
+ ): Promise<void> {
79
+ switch (providerKey) {
80
+ case "telegram": {
81
+ const hasBotToken = !!(await getSecureKeyAsync(
82
+ credentialKey("telegram", "bot_token"),
83
+ ));
84
+ const hasWebhookSecret = !!(await getSecureKeyAsync(
85
+ credentialKey("telegram", "webhook_secret"),
86
+ ));
87
+ if (hasBotToken && hasWebhookSecret) {
88
+ await ensureManualTokenConnection(providerKey, accountInfo);
89
+ } else {
90
+ removeManualTokenConnection(providerKey);
91
+ }
92
+ return;
93
+ }
94
+
95
+ case "slack_channel": {
96
+ const hasBotToken = !!(await getSecureKeyAsync(
97
+ credentialKey("slack_channel", "bot_token"),
98
+ ));
99
+ const hasAppToken = !!(await getSecureKeyAsync(
100
+ credentialKey("slack_channel", "app_token"),
101
+ ));
102
+ if (hasBotToken && hasAppToken) {
103
+ await ensureManualTokenConnection(providerKey, accountInfo);
104
+ } else {
105
+ removeManualTokenConnection(providerKey);
106
+ }
107
+ return;
108
+ }
109
+
110
+ default:
111
+ return;
112
+ }
113
+ }
114
+
68
115
  /**
69
116
  * Backfill oauth_connection rows for manual-token providers that already
70
117
  * have valid keychain credentials but are missing connection records.
@@ -78,29 +125,6 @@ export function removeManualTokenConnection(providerKey: string): void {
78
125
  * connection row.
79
126
  */
80
127
  export async function backfillManualTokenConnections(): Promise<void> {
81
- // Telegram: requires both bot_token and webhook_secret
82
- if (!getConnectionByProvider("telegram")) {
83
- const hasBotToken = !!(await getSecureKeyAsync(
84
- credentialKey("telegram", "bot_token"),
85
- ));
86
- const hasWebhookSecret = !!(await getSecureKeyAsync(
87
- credentialKey("telegram", "webhook_secret"),
88
- ));
89
- if (hasBotToken && hasWebhookSecret) {
90
- await ensureManualTokenConnection("telegram");
91
- }
92
- }
93
-
94
- // Slack channel: requires both bot_token and app_token
95
- if (!getConnectionByProvider("slack_channel")) {
96
- const hasBotToken = !!(await getSecureKeyAsync(
97
- credentialKey("slack_channel", "bot_token"),
98
- ));
99
- const hasAppToken = !!(await getSecureKeyAsync(
100
- credentialKey("slack_channel", "app_token"),
101
- ));
102
- if (hasBotToken && hasAppToken) {
103
- await ensureManualTokenConnection("slack_channel");
104
- }
105
- }
128
+ await syncManualTokenConnection("telegram");
129
+ await syncManualTokenConnection("slack_channel");
106
130
  }
@@ -48,10 +48,10 @@ function riskCacheKey(
48
48
  workingDir?: string,
49
49
  manifestOverride?: ManifestOverride,
50
50
  ): string {
51
- // Strip `reason` before computing the cache key — it is cosmetic and varies
52
- // per invocation even for identical tool operations, causing unnecessary
53
- // cache misses.
54
- const { reason: _reason, ...cacheableInput } = input;
51
+ // Strip `reason` and `activity` before computing the cache key — they are
52
+ // cosmetic status text that varies per invocation even for identical tool
53
+ // operations, causing unnecessary cache misses.
54
+ const { reason: _reason, activity: _activity, ...cacheableInput } = input;
55
55
  const inputJson = JSON.stringify(cacheableInput);
56
56
  const hash = createHash("sha256")
57
57
  .update(inputJson)
@@ -143,6 +143,7 @@ const LOW_RISK_PROGRAMS = new Set([
143
143
  "tree",
144
144
  "du",
145
145
  "df",
146
+ "assistant",
146
147
  ]);
147
148
 
148
149
  // High-risk shell programs / patterns
@@ -544,7 +545,7 @@ async function classifyRiskUncached(
544
545
  ) {
545
546
  return RiskLevel.High;
546
547
  }
547
- return RiskLevel.Medium;
548
+ return RiskLevel.Low;
548
549
  }
549
550
  if (toolName === "web_search") return RiskLevel.Low;
550
551
  if (toolName === "web_fetch") {
@@ -259,10 +259,10 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
259
259
  }),
260
260
  );
261
261
 
262
- // ui_update and ui_dismiss are purely passive operations (modify/remove existing
263
- // surfaces). ui_show is excluded because it can create forms that collect user
264
- // inputit goes through normal permission checking instead.
265
- const UI_SURFACE_TOOLS = ["ui_update", "ui_dismiss"] as const;
262
+ // All three UI surface tools are passive, user-visible operations. ui_show
263
+ // creates surfaces (cards, forms, tables) but user input is voluntary and
264
+ // user-controlledsafe to auto-approve like ui_update and ui_dismiss.
265
+ const UI_SURFACE_TOOLS = ["ui_show", "ui_update", "ui_dismiss"] as const;
266
266
  const uiSurfaceRules: DefaultRuleTemplate[] = UI_SURFACE_TOOLS.map(
267
267
  (tool) => ({
268
268
  id: `default:allow-${tool}-global`,