vellum 0.2.1 → 0.2.2

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 (349) hide show
  1. package/README.md +15 -2
  2. package/bun.lock +5 -2
  3. package/package.json +4 -2
  4. package/scripts/capture-x-graphql.ts +562 -0
  5. package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
  6. package/scripts/test.sh +5 -0
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +133 -34
  8. package/src/__tests__/account-registry.test.ts +2 -1
  9. package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
  10. package/src/__tests__/asset-materialize-tool.test.ts +16 -15
  11. package/src/__tests__/asset-search-tool.test.ts +23 -22
  12. package/src/__tests__/attachments-store.test.ts +56 -127
  13. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
  14. package/src/__tests__/browser-skill-endstate.test.ts +4 -3
  15. package/src/__tests__/call-bridge.test.ts +385 -0
  16. package/src/__tests__/call-constants.test.ts +40 -0
  17. package/src/__tests__/call-orchestrator.test.ts +130 -4
  18. package/src/__tests__/call-recovery.test.ts +518 -0
  19. package/src/__tests__/call-routes-http.test.ts +459 -0
  20. package/src/__tests__/call-state-machine.test.ts +143 -0
  21. package/src/__tests__/call-store.test.ts +216 -1
  22. package/src/__tests__/cli-discover.test.ts +1 -1
  23. package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
  24. package/src/__tests__/compaction.benchmark.test.ts +176 -0
  25. package/src/__tests__/computer-use-tools.test.ts +250 -0
  26. package/src/__tests__/config-schema.test.ts +299 -3
  27. package/src/__tests__/conflict-store.test.ts +2 -1
  28. package/src/__tests__/contacts-tools.test.ts +331 -0
  29. package/src/__tests__/conversation-store.test.ts +30 -32
  30. package/src/__tests__/credential-security-invariants.test.ts +4 -0
  31. package/src/__tests__/date-context.test.ts +373 -0
  32. package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
  33. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
  34. package/src/__tests__/followup-tools.test.ts +303 -0
  35. package/src/__tests__/handlers-twitter-config.test.ts +718 -0
  36. package/src/__tests__/intent-routing.test.ts +64 -57
  37. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +62 -28
  39. package/src/__tests__/llm-usage-store.test.ts +3 -8
  40. package/src/__tests__/media-generate-image.test.ts +1 -1
  41. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
  42. package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
  43. package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
  44. package/src/__tests__/playbook-tools.test.ts +342 -0
  45. package/src/__tests__/profile-compiler.test.ts +2 -1
  46. package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
  47. package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
  48. package/src/__tests__/recurrence-engine.test.ts +69 -0
  49. package/src/__tests__/recurrence-types.test.ts +71 -0
  50. package/src/__tests__/registry.test.ts +5 -3
  51. package/src/__tests__/relay-server.test.ts +633 -0
  52. package/src/__tests__/reminder-store.test.ts +6 -3
  53. package/src/__tests__/reminder.test.ts +43 -77
  54. package/src/__tests__/run-orchestrator-assistant-events.test.ts +8 -4
  55. package/src/__tests__/run-orchestrator.test.ts +4 -4
  56. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
  57. package/src/__tests__/runtime-runs-http.test.ts +4 -4
  58. package/src/__tests__/runtime-runs.test.ts +4 -4
  59. package/src/__tests__/schedule-store.test.ts +482 -0
  60. package/src/__tests__/schedule-tools.test.ts +700 -0
  61. package/src/__tests__/scheduler-recurrence.test.ts +329 -0
  62. package/src/__tests__/server-history-render.test.ts +14 -13
  63. package/src/__tests__/session-error.test.ts +28 -0
  64. package/src/__tests__/session-init.benchmark.test.ts +462 -0
  65. package/src/__tests__/session-queue.test.ts +71 -48
  66. package/src/__tests__/session-runtime-assembly.test.ts +161 -0
  67. package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
  68. package/src/__tests__/signup-e2e.test.ts +2 -1
  69. package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
  70. package/src/__tests__/skill-script-runner.test.ts +159 -0
  71. package/src/__tests__/speaker-identification.test.ts +52 -0
  72. package/src/__tests__/subagent-manager-notify.test.ts +42 -10
  73. package/src/__tests__/subagent-tools.test.ts +141 -41
  74. package/src/__tests__/task-compiler.test.ts +2 -1
  75. package/src/__tests__/task-runner.test.ts +2 -1
  76. package/src/__tests__/task-scheduler.test.ts +2 -1
  77. package/src/__tests__/task-tools.test.ts +49 -56
  78. package/src/__tests__/tool-audit-listener.test.ts +1 -0
  79. package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
  80. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
  81. package/src/__tests__/tool-executor.test.ts +13 -17
  82. package/src/__tests__/turn-commit.test.ts +218 -3
  83. package/src/__tests__/twilio-provider.test.ts +143 -0
  84. package/src/__tests__/twilio-routes.test.ts +789 -0
  85. package/src/__tests__/twitter-auth-handler.test.ts +581 -0
  86. package/src/__tests__/view-image-tool.test.ts +217 -0
  87. package/src/__tests__/workspace-git-service.test.ts +186 -0
  88. package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
  89. package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
  90. package/src/bundler/app-bundler.ts +12 -8
  91. package/src/calls/call-bridge.ts +95 -0
  92. package/src/calls/call-constants.ts +43 -5
  93. package/src/calls/call-domain.ts +276 -0
  94. package/src/calls/call-orchestrator.ts +43 -17
  95. package/src/calls/call-recovery.ts +207 -0
  96. package/src/calls/call-state-machine.ts +68 -0
  97. package/src/calls/call-store.ts +192 -5
  98. package/src/calls/relay-server.ts +41 -4
  99. package/src/calls/speaker-identification.ts +213 -0
  100. package/src/calls/twilio-provider.ts +10 -6
  101. package/src/calls/twilio-routes.ts +90 -76
  102. package/src/calls/types.ts +1 -1
  103. package/src/cli/config-commands.ts +334 -0
  104. package/src/cli/core-commands.ts +776 -0
  105. package/src/cli/doordash.ts +251 -1
  106. package/src/cli/ipc-client.ts +82 -0
  107. package/src/cli/map.ts +246 -0
  108. package/src/cli/twitter.ts +575 -0
  109. package/src/cli.ts +7 -5
  110. package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
  111. package/src/commands/cc-command-registry.ts +209 -0
  112. package/src/config/bundled-skills/contacts/SKILL.md +39 -0
  113. package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
  114. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
  115. package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
  116. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
  117. package/src/config/bundled-skills/document/SKILL.md +18 -0
  118. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  119. package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
  120. package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
  121. package/src/config/bundled-skills/doordash/SKILL.md +82 -23
  122. package/src/config/bundled-skills/followups/SKILL.md +32 -0
  123. package/src/config/bundled-skills/followups/TOOLS.json +100 -0
  124. package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
  125. package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
  126. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
  127. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -23
  128. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
  129. package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
  130. package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
  131. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
  132. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
  133. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
  134. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
  135. package/src/config/bundled-skills/reminder/SKILL.md +20 -0
  136. package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
  137. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
  138. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
  139. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
  140. package/src/config/bundled-skills/schedule/SKILL.md +74 -0
  141. package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
  142. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
  143. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
  144. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
  145. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
  146. package/src/config/bundled-skills/subagent/SKILL.md +25 -0
  147. package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
  148. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
  149. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
  150. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
  151. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
  152. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
  153. package/src/config/bundled-skills/tasks/SKILL.md +28 -0
  154. package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
  155. package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
  156. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
  157. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
  158. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
  159. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
  160. package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
  161. package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
  162. package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
  163. package/src/config/bundled-skills/twitter/SKILL.md +134 -0
  164. package/src/config/bundled-skills/watcher/SKILL.md +27 -0
  165. package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
  166. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
  167. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
  168. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
  169. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
  170. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
  171. package/src/config/defaults.ts +33 -0
  172. package/src/config/loader.ts +4 -1
  173. package/src/config/schema.ts +161 -1
  174. package/src/config/system-prompt.ts +61 -16
  175. package/src/config/templates/IDENTITY.md +7 -0
  176. package/src/config/types.ts +4 -0
  177. package/src/contacts/contact-store.ts +4 -4
  178. package/src/daemon/assistant-attachments.ts +10 -0
  179. package/src/daemon/classifier.ts +3 -1
  180. package/src/daemon/computer-use-session.ts +3 -1
  181. package/src/daemon/date-context.ts +136 -0
  182. package/src/daemon/handlers/apps.ts +16 -1
  183. package/src/daemon/handlers/browser.ts +54 -0
  184. package/src/daemon/handlers/computer-use.ts +7 -1
  185. package/src/daemon/handlers/config.ts +163 -5
  186. package/src/daemon/handlers/diagnostics.ts +5 -1
  187. package/src/daemon/handlers/documents.ts +18 -29
  188. package/src/daemon/handlers/home-base.ts +5 -1
  189. package/src/daemon/handlers/index.ts +40 -277
  190. package/src/daemon/handlers/misc.ts +9 -1
  191. package/src/daemon/handlers/publish.ts +6 -1
  192. package/src/daemon/handlers/sessions.ts +65 -12
  193. package/src/daemon/handlers/shared.ts +36 -1
  194. package/src/daemon/handlers/signing.ts +37 -0
  195. package/src/daemon/handlers/skills.ts +20 -6
  196. package/src/daemon/handlers/subagents.ts +8 -3
  197. package/src/daemon/handlers/twitter-auth.ts +169 -0
  198. package/src/daemon/handlers/work-items.ts +384 -68
  199. package/src/daemon/ipc-contract-inventory.json +28 -4
  200. package/src/daemon/ipc-contract.ts +133 -37
  201. package/src/daemon/ipc-protocol.ts +7 -2
  202. package/src/daemon/lifecycle.ts +21 -0
  203. package/src/daemon/main.ts +10 -4
  204. package/src/daemon/ride-shotgun-handler.ts +74 -10
  205. package/src/daemon/server.ts +143 -26
  206. package/src/daemon/session-agent-loop.ts +887 -0
  207. package/src/daemon/session-attachments.ts +28 -5
  208. package/src/daemon/session-error.ts +24 -3
  209. package/src/daemon/session-lifecycle.ts +147 -0
  210. package/src/daemon/session-media-retry.ts +147 -0
  211. package/src/daemon/session-messaging.ts +145 -0
  212. package/src/daemon/session-notifiers.ts +164 -0
  213. package/src/daemon/session-process.ts +2 -2
  214. package/src/daemon/session-queue-manager.ts +1 -0
  215. package/src/daemon/session-runtime-assembly.ts +52 -0
  216. package/src/daemon/session-skill-tools.ts +124 -5
  217. package/src/daemon/session-slash.ts +3 -0
  218. package/src/daemon/session-surfaces.ts +77 -2
  219. package/src/daemon/session-tool-setup.ts +216 -2
  220. package/src/daemon/session-usage.ts +0 -2
  221. package/src/daemon/session.ts +114 -1404
  222. package/src/daemon/video-thumbnail.ts +60 -0
  223. package/src/doordash/client.ts +121 -27
  224. package/src/doordash/queries.ts +1 -2
  225. package/src/export/formatter.ts +3 -1
  226. package/src/followups/followup-store.ts +4 -2
  227. package/src/followups/types.ts +6 -0
  228. package/src/hooks/templates.ts +1 -1
  229. package/src/index.ts +32 -1153
  230. package/src/memory/attachments-store.ts +28 -83
  231. package/src/memory/channel-delivery-store.ts +7 -21
  232. package/src/memory/clarification-resolver.ts +6 -5
  233. package/src/memory/contradiction-checker.ts +3 -2
  234. package/src/memory/conversation-key-store.ts +10 -29
  235. package/src/memory/conversation-store.ts +2 -1
  236. package/src/memory/db.ts +96 -2
  237. package/src/memory/entity-extractor.ts +6 -3
  238. package/src/memory/items-extractor.ts +5 -4
  239. package/src/memory/jobs-store.ts +3 -2
  240. package/src/memory/llm-usage-store.ts +1 -2
  241. package/src/memory/runs-store.ts +1 -2
  242. package/src/memory/schema.ts +23 -2
  243. package/src/messaging/style-analyzer.ts +3 -2
  244. package/src/messaging/thread-summarizer.ts +8 -12
  245. package/src/messaging/triage-engine.ts +4 -2
  246. package/src/providers/openrouter/client.ts +20 -0
  247. package/src/providers/registry.ts +8 -0
  248. package/src/runtime/http-server.ts +108 -20
  249. package/src/runtime/routes/attachment-routes.ts +2 -3
  250. package/src/runtime/routes/call-routes.ts +140 -0
  251. package/src/runtime/routes/channel-routes.ts +5 -10
  252. package/src/runtime/routes/conversation-routes.ts +5 -5
  253. package/src/runtime/routes/run-routes.ts +2 -2
  254. package/src/runtime/run-orchestrator.ts +9 -3
  255. package/src/schedule/recurrence-engine.ts +138 -0
  256. package/src/schedule/recurrence-types.ts +67 -0
  257. package/src/schedule/schedule-store.ts +102 -57
  258. package/src/schedule/scheduler.ts +9 -6
  259. package/src/security/oauth2.ts +29 -4
  260. package/src/security/secret-allowlist.ts +46 -0
  261. package/src/skills/clawhub.ts +1 -1
  262. package/src/subagent/manager.ts +40 -8
  263. package/src/swarm/backend-claude-code.ts +64 -9
  264. package/src/swarm/worker-prompts.ts +2 -1
  265. package/src/tasks/SPEC.md +34 -28
  266. package/src/tasks/ephemeral-permissions.ts +16 -7
  267. package/src/tasks/task-compiler.ts +5 -4
  268. package/src/tasks/task-runner.ts +10 -5
  269. package/src/tasks/task-scheduler.ts +1 -1
  270. package/src/tasks/tool-sanitizer.ts +36 -0
  271. package/src/tools/assets/search.ts +4 -4
  272. package/src/tools/browser/api-map.ts +220 -0
  273. package/src/tools/browser/auto-navigate.ts +270 -0
  274. package/src/tools/browser/browser-execution.ts +2 -1
  275. package/src/tools/browser/browser-manager.ts +2 -2
  276. package/src/tools/browser/network-recorder.ts +5 -4
  277. package/src/tools/browser/x-auto-navigate.ts +207 -0
  278. package/src/tools/calls/call-end.ts +17 -67
  279. package/src/tools/calls/call-start.ts +24 -85
  280. package/src/tools/calls/call-status.ts +35 -51
  281. package/src/tools/claude-code/claude-code.ts +77 -11
  282. package/src/tools/contacts/contact-merge.ts +46 -78
  283. package/src/tools/contacts/contact-search.ts +35 -79
  284. package/src/tools/contacts/contact-upsert.ts +35 -108
  285. package/src/tools/credentials/vault.ts +20 -4
  286. package/src/tools/document/document-tool.ts +71 -144
  287. package/src/tools/executor.ts +129 -10
  288. package/src/tools/followups/followup_create.ts +46 -88
  289. package/src/tools/followups/followup_list.ts +34 -74
  290. package/src/tools/followups/followup_resolve.ts +31 -66
  291. package/src/tools/host-terminal/cli-discover.ts +2 -1
  292. package/src/tools/host-terminal/host-shell.ts +10 -0
  293. package/src/tools/memory/handlers.ts +5 -4
  294. package/src/tools/network/__tests__/web-search.test.ts +427 -0
  295. package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
  296. package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
  297. package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
  298. package/src/tools/network/web-fetch.ts +18 -6
  299. package/src/tools/playbooks/index.ts +4 -5
  300. package/src/tools/playbooks/playbook-create.ts +3 -47
  301. package/src/tools/playbooks/playbook-delete.ts +1 -25
  302. package/src/tools/playbooks/playbook-list.ts +1 -28
  303. package/src/tools/playbooks/playbook-update.ts +3 -51
  304. package/src/tools/reminder/reminder.ts +5 -78
  305. package/src/tools/schedule/create.ts +69 -74
  306. package/src/tools/schedule/delete.ts +21 -47
  307. package/src/tools/schedule/list.ts +55 -74
  308. package/src/tools/schedule/update.ts +77 -84
  309. package/src/tools/subagent/abort.ts +29 -58
  310. package/src/tools/subagent/message.ts +30 -63
  311. package/src/tools/subagent/read.ts +53 -84
  312. package/src/tools/subagent/spawn.ts +43 -82
  313. package/src/tools/subagent/status.ts +42 -71
  314. package/src/tools/swarm/delegate.ts +2 -1
  315. package/src/tools/tasks/index.ts +8 -8
  316. package/src/tools/tasks/task-delete.ts +60 -88
  317. package/src/tools/tasks/task-list.ts +31 -52
  318. package/src/tools/tasks/task-run.ts +72 -108
  319. package/src/tools/tasks/task-save.ts +33 -65
  320. package/src/tools/tasks/work-item-enqueue.ts +183 -215
  321. package/src/tools/tasks/work-item-list.ts +33 -63
  322. package/src/tools/tasks/work-item-remove.ts +45 -97
  323. package/src/tools/tasks/work-item-update.ts +91 -163
  324. package/src/tools/terminal/backends/native.ts +3 -1
  325. package/src/tools/tool-manifest.ts +0 -62
  326. package/src/tools/types.ts +6 -0
  327. package/src/tools/ui-surface/definitions.ts +3 -1
  328. package/src/tools/watch/screen-watch.ts +3 -1
  329. package/src/tools/watcher/create.ts +52 -98
  330. package/src/tools/watcher/delete.ts +20 -46
  331. package/src/tools/watcher/digest.ts +36 -70
  332. package/src/tools/watcher/list.ts +49 -79
  333. package/src/tools/watcher/update.ts +45 -91
  334. package/src/twitter/client.ts +690 -0
  335. package/src/twitter/session.ts +91 -0
  336. package/src/usage/types.ts +0 -1
  337. package/src/util/truncate.ts +6 -0
  338. package/src/watcher/providers/slack.ts +2 -1
  339. package/src/watcher/watcher-store.ts +3 -2
  340. package/src/work-items/work-item-store.ts +27 -2
  341. package/src/workspace/commit-message-enrichment-service.ts +31 -7
  342. package/src/workspace/git-service.ts +87 -22
  343. package/src/workspace/provider-commit-message-generator.ts +242 -0
  344. package/src/workspace/turn-commit.ts +62 -3
  345. package/src/tools/contacts/index.ts +0 -4
  346. package/src/tools/document/index.ts +0 -5
  347. package/src/tools/followups/index.ts +0 -3
  348. package/src/tools/subagent/index.ts +0 -5
  349. /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeContactMerge } from '../../../../tools/contacts/contact-merge.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeContactMerge(input, context);
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeContactSearch } from '../../../../tools/contacts/contact-search.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeContactSearch(input, context);
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeContactUpsert } from '../../../../tools/contacts/contact-upsert.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeContactUpsert(input, context);
9
+ }
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: "Document"
3
+ description: "Document creation and editing for UI surfaces"
4
+ metadata: {"vellum": {"emoji": "📄"}}
5
+ ---
6
+
7
+ Create and edit long-form documents using the built-in rich text editor. Documents open in workspace mode with chat docked to the side.
8
+
9
+ ## Tools
10
+
11
+ - **document_create** — Opens a new document editor with an optional title and initial Markdown content. Returns a `surface_id` for subsequent updates.
12
+ - **document_update** — Updates content in an open document editor by `surface_id`. Supports `replace` (overwrite) and `append` (add to end) modes.
13
+
14
+ ## Usage Notes
15
+
16
+ - Use `document_create` when the user asks to write a blog post, article, or any long-form content.
17
+ - After creating a document, use `document_update` with the returned `surface_id` to stream or edit content.
18
+ - The `mode` parameter on `document_update` defaults to `append`.
@@ -0,0 +1,53 @@
1
+ {
2
+ "version": 1,
3
+ "tools": [
4
+ {
5
+ "name": "document_create",
6
+ "description": "Create a new long-form document with a rich text editor. Use this when the user asks to write a blog post, article, or any long-form content. The editor opens in workspace mode with chat docked to the side.",
7
+ "category": "document",
8
+ "risk": "low",
9
+ "input_schema": {
10
+ "type": "object",
11
+ "properties": {
12
+ "title": {
13
+ "type": "string",
14
+ "description": "Initial title for the document (optional, can be updated later)"
15
+ },
16
+ "initial_content": {
17
+ "type": "string",
18
+ "description": "Initial Markdown content to populate the editor (optional)"
19
+ }
20
+ }
21
+ },
22
+ "executor": "tools/document-create.ts",
23
+ "execution_target": "host"
24
+ },
25
+ {
26
+ "name": "document_update",
27
+ "description": "Update content in an open document editor. Use this to stream generated content or apply edits.",
28
+ "category": "document",
29
+ "risk": "low",
30
+ "input_schema": {
31
+ "type": "object",
32
+ "properties": {
33
+ "surface_id": {
34
+ "type": "string",
35
+ "description": "The ID of the document surface to update"
36
+ },
37
+ "content": {
38
+ "type": "string",
39
+ "description": "Markdown content to set or append"
40
+ },
41
+ "mode": {
42
+ "type": "string",
43
+ "enum": ["replace", "append"],
44
+ "description": "Whether to replace all content or append to the end. Defaults to append."
45
+ }
46
+ },
47
+ "required": ["surface_id", "content"]
48
+ },
49
+ "executor": "tools/document-update.ts",
50
+ "execution_target": "host"
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeDocumentCreate } from '../../../../tools/document/document-tool.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeDocumentCreate(input, context);
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeDocumentUpdate } from '../../../../tools/document/document-tool.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeDocumentUpdate(input, context);
9
+ }
@@ -7,33 +7,23 @@ metadata: {"vellum": {"emoji": "\uD83C\uDF55"}}
7
7
 
8
8
  You can order food from DoorDash for the user using the `vellum doordash` CLI.
9
9
 
10
+ ## CLI Setup
11
+
12
+ **IMPORTANT: Always use `host_bash` (not `bash`) for all `vellum doordash` commands.** The DoorDash CLI needs host access for Chrome CDP, session cookies, and the `vellum` binary — none of which are available inside the sandbox.
13
+
14
+ `vellum doordash` is a built-in subcommand of the Vellum assistant CLI — it is NOT a separate tool you need to find or install. It should already be on your PATH. If `vellum` is not found, prepend `PATH="$HOME/.local/bin:$PATH"` to the command. Do NOT search for the binary, inspect wrapper scripts, or try to discover how the CLI works. Just run the commands as documented below.
15
+
10
16
  ## Task Progress Widget
11
17
 
12
- When executing a food ordering flow, show live progress using the `task_progress` card template. Before starting, call `ui_show` with:
13
- ```json
14
- {
15
- "surface_type": "card",
16
- "template": "task_progress",
17
- "templateData": {
18
- "title": "Ordering from DoorDash",
19
- "status": "in_progress",
20
- "steps": [
21
- { "label": "Check session", "status": "in_progress" },
22
- { "label": "Search restaurants", "status": "pending" },
23
- { "label": "Browse menu", "status": "pending" },
24
- { "label": "Add to cart", "status": "pending" },
25
- { "label": "Place order", "status": "pending" }
26
- ]
27
- }
28
- }
29
- ```
30
- As each step completes, call `ui_update` with the same surface ID to update step statuses. Add `detail` to completed steps (e.g. `"detail": "Found Andiamo's"`). Adapt the steps to the actual flow (e.g. skip "Search restaurants" if the user named a specific store).
18
+ A task progress card is shown automatically when you run your first `vellum doordash` command. Its surface ID is `doordash-progress`. As each step completes, call `ui_update` with surface ID `doordash-progress` to update step statuses. Update `data.templateData.steps` — set completed steps to `"status": "completed"` with a `"detail"` string, the current step to `"status": "in_progress"`, and future steps to `"status": "pending"`. Adapt the steps to the actual flow (e.g. skip "Search restaurants" if the user named a specific store).
31
19
 
32
20
  ## Typical Flow
33
21
 
34
22
  When the user asks you to order food (e.g. "Order pizza from Andiamo's"):
35
23
 
36
- 1. **Check session** — run `vellum doordash status --json`. If `loggedIn` is false or the session is expired, tell the user: "I need to capture your DoorDash session. A separate Chrome window will open your existing Chrome and tabs are not affected. Please sign in to DoorDash when it opens, and I'll take it from there." Then run `vellum doordash refresh --json`. This starts a Ride Shotgun learn session that records your login and auto-stops once it detects you've signed in. The session is imported automatically. **This command blocks until login is complete — just wait for it.**
24
+ 1. **Check session** — run `vellum doordash status --json`. If `loggedIn` is false or the session is expired, tell the user: "A Chrome window will open to the DoorDash login page. Please sign in there I'll detect your login automatically and minimize the window." Then run `vellum doordash refresh --json`. This starts a Ride Shotgun learn session that records your login and auto-stops once it detects you've signed in. The session is imported automatically. **This command blocks until login is complete — just wait for it.**
25
+
26
+ Keep the DoorDash Chrome window open in the background — it's needed for API requests.
37
27
 
38
28
  2. **Search** — run `vellum doordash search "<query>" --json` to find matching restaurants. Present the top results to the user with name, rating, and delivery info. If the user named a specific restaurant, pick the best match. If ambiguous, ask.
39
29
 
@@ -41,9 +31,14 @@ When the user asks you to order food (e.g. "Order pizza from Andiamo's"):
41
31
 
42
32
  3b. **Search within a retail store** — for convenience/pharmacy stores, run `vellum doordash store-search <storeId> "<query>" --json` to find specific products. This returns items with IDs, prices, and menuIds that can be added to cart directly.
43
33
 
44
- 4. **Get item details** (if needed) — run `vellum doordash item <storeId> <itemId> --json` to see options/customizations. If the item has required options (like size or toppings), ask the user or pick sensible defaults.
34
+ 4. **Get item details** (if needed) — run `vellum doordash item <storeId> <itemId> --json` to see options/customizations. The response includes:
35
+ - `options`: each option group has `minSelections`/`maxSelections` indicating how many choices are required
36
+ - Each choice has `unitAmount` (price impact in cents), `defaultQuantity`, and possibly `nestedOptions` (sub-choices like milk type within a size selection)
37
+ - `specialInstructionsConfig`: whether special instructions are accepted, max length, and placeholder text
38
+
39
+ If the item has required options (like size or toppings), construct the `nestedOptions` JSON from the option/choice IDs and pass it via `--options`. Ask the user for preferences or pick sensible defaults.
45
40
 
46
- 5. **Add to cart** — run `vellum doordash cart add --store-id <id> --menu-id <id> --item-id <id> --item-name "<name>" --unit-price <cents> --json`. For subsequent items at the same store, pass `--cart-id <id>` from the first add response.
41
+ 5. **Add to cart** — run `vellum doordash cart add --store-id <id> --menu-id <id> --item-id <id> --item-name "<name>" --unit-price <cents> [--options '<json>'] [--special-instructions "<text>"] --json`. For subsequent items at the same store, pass `--cart-id <id>` from the first add response. Use `--special-instructions` for requests like "extra hot", "no ice", etc. Use `--options` to pass customization choices (see Customization Options below).
47
42
 
48
43
  6. **Review cart** — run `vellum doordash cart view <cartId> --json` and show the user what's in their cart with prices. Ask if they want to add anything else or proceed.
49
44
 
@@ -61,6 +56,68 @@ When the user asks you to order food (e.g. "Order pizza from Andiamo's"):
61
56
  - **Show prices.** Always show prices when presenting items or the cart summary.
62
57
  - **Use `--json` flag** on all commands for reliable parsing.
63
58
  - **Do NOT use the browser skill.** All DoorDash interaction goes through the CLI, not browser automation.
59
+ - **Rate limiting.** DoorDash rate-limits rapid sequential requests. When adding multiple items (e.g. a team order), wait 8–10 seconds between `cart add` calls. If you get a 403 error, wait 15–20 seconds and retry. For large orders (5+ items), consider running `vellum doordash refresh --json` midway through if you hit repeated 403s.
60
+ - **Special instructions are unreliable.** Some merchants disable special instructions entirely. Always prefer `--options` for customizations (size, milk type, etc.). Only use `--special-instructions` for free-text requests that aren't covered by the item's option groups. If the merchant rejects special instructions, drop them and proceed without.
61
+ - **Customization fallback.** If `cart add` with `--options` fails, or if the item details show options that are hard to construct (deeply nested, unusual format), proactively offer to use `cart learn` so the user can customize the item visually in the browser. Don't silently drop customizations — tell the user what happened and offer alternatives.
62
+ - **Always-allow tip.** At the start of an ordering flow, suggest the user enable "always allow" for `vellum doordash` commands: "Tip: You can type 'a' to always allow `vellum doordash` commands for this session so you won't be prompted each time."
63
+ - **Error attribution.** When errors occur, assume it's more likely a bug in our query/parsing than a DoorDash API change. Suggest running `vellum doordash record` to capture fresh queries before assuming the schema changed.
64
+
65
+ ## Customization Options
66
+
67
+ Many items (especially coffee, boba, sandwiches) have required customization options like size, milk type, or toppings. Here's how to handle them:
68
+
69
+ ### Constructing nestedOptions JSON
70
+
71
+ 1. Run `vellum doordash item <storeId> <itemId> --json` to get the item's option groups
72
+ 2. Each option group has `id`, `name`, `required`, `minSelections`, `maxSelections`, and `choices`
73
+ 3. Build a JSON array of selections matching the DoorDash format:
74
+
75
+ ```json
76
+ [
77
+ {
78
+ "optionId": "<option-group-id>",
79
+ "optionChoiceId": "<choice-id>",
80
+ "quantity": 1,
81
+ "nestedOptions": []
82
+ }
83
+ ]
84
+ ```
85
+
86
+ For choices with nested sub-options (e.g., selecting "Oat Milk" under the "Milk" option within a size), add them to the `nestedOptions` array of the parent choice.
87
+
88
+ 4. Pass the JSON string to `cart add --options '<json>'`
89
+
90
+ ### Special Instructions
91
+
92
+ Use `--special-instructions` on `cart add` for free-text requests like "extra hot", "no ice", "light foam". The `item` command response includes `specialInstructionsConfig` with the max length and whether instructions are supported.
93
+
94
+ **Warning:** Some merchants disable special instructions entirely. If `specialInstructionsConfig.isEnabled` is false, or if the add-to-cart call returns an error about special requests, drop the instructions and retry without them. Always prefer `--options` for customizations — special instructions are a last resort for requests not covered by the item's option groups.
95
+
96
+ ### Learning Customizations via Ride Shotgun
97
+
98
+ For complex items where constructing the JSON manually is difficult, use `cart learn`:
99
+
100
+ 1. Run `vellum doordash cart learn --json`
101
+ 2. A Chrome window opens — navigate to the item, customize it visually, and click "Add to Cart"
102
+ 3. The command auto-detects the `updateCartItem` operation and extracts the exact `nestedOptions` and `specialInstructions`
103
+ 4. Use the extracted options directly with `cart add --options '<json>'`
104
+
105
+ You can also extract options from an existing recording with `vellum doordash inspect <recordingId> --extract-options --json`.
106
+
107
+ ### Coffee Order Example
108
+
109
+ **User**: "Order a large oat milk latte with an extra shot from Blue Bottle"
110
+
111
+ 1. `vellum doordash search "Blue Bottle" --json` -> finds store
112
+ 2. `vellum doordash menu <storeId> --json` -> finds "Latte" item
113
+ 3. `vellum doordash item <storeId> <latteItemId> --json` -> returns options:
114
+ - Size (required, min:1, max:1): Small (id:101), Medium (id:102), Large (id:103, +$1.00)
115
+ - Milk (required, min:1, max:1): Whole (id:201), Oat (id:202, +$0.70), Almond (id:203, +$0.70)
116
+ - Extras (optional, min:0, max:5): Extra Shot (id:301, +$0.90), Vanilla Syrup (id:302, +$0.60)
117
+ 4. Construct options JSON and add to cart:
118
+ ```
119
+ vellum doordash cart add --store-id <id> --menu-id <id> --item-id <id> --item-name "Latte" --unit-price 550 --options '[{"optionId":"size-group-id","optionChoiceId":"103","quantity":1,"nestedOptions":[]},{"optionId":"milk-group-id","optionChoiceId":"202","quantity":1,"nestedOptions":[]},{"optionId":"extras-group-id","optionChoiceId":"301","quantity":1,"nestedOptions":[]}]' --special-instructions "Extra hot" --json
120
+ ```
64
121
 
65
122
  ## Command Reference
66
123
 
@@ -73,10 +130,12 @@ vellum doordash search "<query>" --json # Search restaurants
73
130
  vellum doordash menu <storeId> --json # Get store menu (auto-detects retail stores)
74
131
  vellum doordash store-search <storeId> "<query>" --json # Search items within a convenience/pharmacy store
75
132
  vellum doordash item <storeId> <itemId> --json # Get item details + options
76
- vellum doordash cart add --store-id <id> --menu-id <id> --item-id <id> --item-name "<name>" --unit-price <cents> [--quantity <n>] [--cart-id <id>] --json
133
+ vellum doordash cart add --store-id <id> --menu-id <id> --item-id <id> --item-name "<name>" --unit-price <cents> [--quantity <n>] [--cart-id <id>] [--options '<json>'] [--special-instructions "<text>"] --json
77
134
  vellum doordash cart remove --cart-id <id> --item-id <orderItemId> --json
78
135
  vellum doordash cart view <cartId> --json
79
136
  vellum doordash cart list [--store-id <id>] --json
137
+ vellum doordash cart learn --json # Learn customization options by recording browser interaction
138
+ vellum doordash inspect <recordingId> --extract-options --json # Extract nestedOptions from a recording
80
139
  vellum doordash checkout <cartId> [--address-id <id>] --json
81
140
  vellum doordash payment-methods --json # List saved payment methods
82
141
  vellum doordash order place --cart-id <id> --store-id <id> --total <cents> [--tip <cents>] [--delivery-option <type>] [--dropoff-option <id>] [--payment-uuid <uuid>] --json
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: "Followups"
3
+ description: "Track sent messages awaiting responses across communication channels"
4
+ metadata: {"vellum": {"emoji": "\ud83d\udce8"}}
5
+ ---
6
+
7
+ Track messages sent on external channels (email, Slack, WhatsApp, etc.) that are awaiting a response.
8
+
9
+ ## Lifecycle
10
+
11
+ Each follow-up moves through these states:
12
+
13
+ - **pending** -- waiting for a response
14
+ - **overdue** -- past the expected response deadline with no reply
15
+ - **nudged** -- a reminder was sent after becoming overdue
16
+ - **resolved** -- a response was received or the follow-up was manually closed
17
+
18
+ ## Auto-Deadline
19
+
20
+ When `expected_response_hours` is set, the follow-up automatically becomes overdue after that window. If a `contact_id` is provided, the contact's importance score can inform grace period decisions.
21
+
22
+ ## Resolution
23
+
24
+ Follow-ups can be resolved in two ways:
25
+ 1. **By ID** -- resolve a specific follow-up directly
26
+ 2. **By thread** -- provide channel + thread_id to auto-resolve all matching pending follow-ups (useful when a response arrives on a thread)
27
+
28
+ ## Tips
29
+
30
+ - Use `followup_list` with `overdue_only: true` to find conversations that need attention.
31
+ - Attach a `reminder_schedule_id` to link a recurring reminder schedule to a follow-up.
32
+ - Filter by channel, status, or contact to narrow results.
@@ -0,0 +1,100 @@
1
+ {
2
+ "version": 1,
3
+ "tools": [
4
+ {
5
+ "name": "followup_create",
6
+ "description": "Create a follow-up tracker for a sent message. Tracks conversations awaiting a response across channels (email, Slack, WhatsApp, etc.).",
7
+ "category": "followups",
8
+ "risk": "low",
9
+ "input_schema": {
10
+ "type": "object",
11
+ "properties": {
12
+ "channel": {
13
+ "type": "string",
14
+ "description": "Communication channel (e.g. email, slack, whatsapp)"
15
+ },
16
+ "thread_id": {
17
+ "type": "string",
18
+ "description": "External thread or conversation identifier on that channel"
19
+ },
20
+ "contact_id": {
21
+ "type": "string",
22
+ "description": "Optional contact ID from the contact graph. Used for grace period context."
23
+ },
24
+ "expected_response_hours": {
25
+ "type": "number",
26
+ "description": "Hours to wait for a response before marking as overdue. If omitted, no deadline is set."
27
+ },
28
+ "reminder_schedule_id": {
29
+ "type": "string",
30
+ "description": "Optional recurrence schedule ID to fire a reminder when overdue"
31
+ },
32
+ "reminder_cron_id": {
33
+ "type": "string",
34
+ "description": "Deprecated alias for reminder_schedule_id. Use reminder_schedule_id instead."
35
+ }
36
+ },
37
+ "required": ["channel", "thread_id"]
38
+ },
39
+ "executor": "tools/followup-create.ts",
40
+ "execution_target": "host"
41
+ },
42
+ {
43
+ "name": "followup_list",
44
+ "description": "List follow-ups with optional filters by status, channel, or contact. Can also show only overdue follow-ups.",
45
+ "category": "followups",
46
+ "risk": "low",
47
+ "input_schema": {
48
+ "type": "object",
49
+ "properties": {
50
+ "status": {
51
+ "type": "string",
52
+ "enum": ["pending", "resolved", "overdue", "nudged"],
53
+ "description": "Filter by status (pending, resolved, overdue, nudged)"
54
+ },
55
+ "channel": {
56
+ "type": "string",
57
+ "description": "Filter by communication channel (e.g. email, slack)"
58
+ },
59
+ "contact_id": {
60
+ "type": "string",
61
+ "description": "Filter by contact ID"
62
+ },
63
+ "overdue_only": {
64
+ "type": "boolean",
65
+ "description": "When true, return only pending follow-ups past their expected response deadline"
66
+ }
67
+ },
68
+ "required": []
69
+ },
70
+ "executor": "tools/followup-list.ts",
71
+ "execution_target": "host"
72
+ },
73
+ {
74
+ "name": "followup_resolve",
75
+ "description": "Manually resolve a follow-up by ID, or auto-resolve by channel + thread ID when a response is received.",
76
+ "category": "followups",
77
+ "risk": "low",
78
+ "input_schema": {
79
+ "type": "object",
80
+ "properties": {
81
+ "id": {
82
+ "type": "string",
83
+ "description": "Follow-up ID to resolve directly"
84
+ },
85
+ "channel": {
86
+ "type": "string",
87
+ "description": "Channel to match (used with thread_id for auto-resolution)"
88
+ },
89
+ "thread_id": {
90
+ "type": "string",
91
+ "description": "Thread ID to match (used with channel for auto-resolution)"
92
+ }
93
+ },
94
+ "required": []
95
+ },
96
+ "executor": "tools/followup-resolve.ts",
97
+ "execution_target": "host"
98
+ }
99
+ ]
100
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeFollowupCreate } from '../../../../tools/followups/followup_create.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeFollowupCreate(input, context);
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeFollowupList } from '../../../../tools/followups/followup_list.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeFollowupList(input, context);
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
+ import { executeFollowupResolve } from '../../../../tools/followups/followup_resolve.js';
3
+
4
+ export async function run(
5
+ input: Record<string, unknown>,
6
+ context: ToolContext,
7
+ ): Promise<ToolExecutionResult> {
8
+ return executeFollowupResolve(input, context);
9
+ }
@@ -1,11 +1,8 @@
1
1
  import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
2
  import type { ImageContent } from '../../../../providers/types.js';
3
- import { eq } from 'drizzle-orm';
4
3
  import { getConfig } from '../../../../config/loader.js';
5
4
  import { generateImage, mapGeminiError } from '../../../../media/gemini-image-service.js';
6
5
  import { getAttachmentsByIds } from '../../../../memory/attachments-store.js';
7
- import { getDb } from '../../../../memory/db.js';
8
- import { conversationKeys } from '../../../../memory/schema.js';
9
6
  import { isAttachmentVisible, type AttachmentContext } from '../../../../daemon/media-visibility-policy.js';
10
7
  import { getConversationThreadType } from '../../../../memory/conversation-store.js';
11
8
  import { getAttachmentSourceConversations } from '../../../../tools/assets/search.js';
@@ -29,17 +26,6 @@ function isAttachmentAccessible(attachmentId: string, currentContext: Attachment
29
26
  );
30
27
  }
31
28
 
32
- /** Resolve the assistantId for the current conversation. */
33
- function getAssistantIdForConversation(conversationId: string): string | null {
34
- const db = getDb();
35
- const row = db
36
- .select({ assistantId: conversationKeys.assistantId })
37
- .from(conversationKeys)
38
- .where(eq(conversationKeys.conversationId, conversationId))
39
- .get();
40
- return row?.assistantId ?? null;
41
- }
42
-
43
29
  export async function run(
44
30
  input: Record<string, unknown>,
45
31
  context: ToolContext,
@@ -64,15 +50,7 @@ export async function run(
64
50
  let sourceImages: Array<{ mimeType: string; dataBase64: string }> | undefined;
65
51
 
66
52
  if (attachmentIds && attachmentIds.length > 0) {
67
- const assistantId = getAssistantIdForConversation(context.conversationId);
68
- if (!assistantId) {
69
- return {
70
- content: 'Could not resolve assistant context for attachment lookup.',
71
- isError: true,
72
- };
73
- }
74
-
75
- const attachments = getAttachmentsByIds(assistantId, attachmentIds);
53
+ const attachments = getAttachmentsByIds(attachmentIds);
76
54
 
77
55
  // Build visibility context for the current conversation
78
56
  const threadType = getConversationThreadType(context.conversationId);
@@ -6,6 +6,7 @@ import { computeMemoryFingerprint } from '../../../../memory/fingerprint.js';
6
6
  import { memoryItems } from '../../../../memory/schema.js';
7
7
  import { enqueueMemoryJob } from '../../../../memory/jobs-store.js';
8
8
  import { extractStylePatterns } from '../../../../messaging/style-analyzer.js';
9
+ import { truncate } from '../../../../util/truncate.js';
9
10
  import { resolveProvider, withProviderToken, ok, err } from './shared.js';
10
11
 
11
12
  function clamp(value: number, min: number, max: number): number {
@@ -100,7 +101,7 @@ export async function run(input: Record<string, unknown>, context: ToolContext):
100
101
  upsertMemoryItem({
101
102
  kind: 'relationship',
102
103
  subject,
103
- statement: `${contact.name} (${contact.email}): ${contact.toneNote}`.slice(0, 500),
104
+ statement: truncate(`${contact.name} (${contact.email}): ${contact.toneNote}`, 500, ''),
104
105
  importance: 0.6,
105
106
  scopeId,
106
107
  });
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: "Playbooks"
3
+ description: "Trigger-action automation rules for handling incoming messages"
4
+ metadata: {"vellum": {"emoji": "\ud83d\udcd6"}}
5
+ ---
6
+
7
+ Playbooks are trigger-action automation rules that tell the assistant how to handle incoming messages matching a pattern.
8
+
9
+ ## Structure
10
+
11
+ Each playbook has:
12
+
13
+ - **Trigger**: Pattern or description that activates the rule (e.g. "meeting request", "from:ceo@*")
14
+ - **Action**: What to do when triggered (natural language description)
15
+ - **Channel**: Which channel the rule applies to ("*" = all channels, or specific like "email", "slack")
16
+ - **Category**: Free-form grouping label (e.g. "scheduling", "triage")
17
+ - **Autonomy level**: How much autonomy the assistant has
18
+ - `auto` -- execute immediately without asking
19
+ - `draft` -- prepare a response for user review (default)
20
+ - `notify` -- alert the user only
21
+ - **Priority**: Numeric priority for overlapping rules (higher = takes precedence)
22
+
23
+ ## Lifecycle
24
+
25
+ 1. Create a playbook with `playbook_create` specifying trigger and action.
26
+ 2. List existing playbooks with `playbook_list`, optionally filtering by channel or category.
27
+ 3. Update rules with `playbook_update` or remove them with `playbook_delete`.
28
+
29
+ ## Storage
30
+
31
+ Playbooks are stored as memory items with semantic retrieval, enabling fuzzy matching of incoming messages against trigger patterns.