vellum 0.2.0 → 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 (361) 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 +161 -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__/app-bundler.test.ts +12 -33
  11. package/src/__tests__/asset-materialize-tool.test.ts +16 -15
  12. package/src/__tests__/asset-search-tool.test.ts +23 -22
  13. package/src/__tests__/attachments-store.test.ts +56 -127
  14. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
  15. package/src/__tests__/browser-skill-endstate.test.ts +5 -8
  16. package/src/__tests__/call-bridge.test.ts +385 -0
  17. package/src/__tests__/call-constants.test.ts +40 -0
  18. package/src/__tests__/call-orchestrator.test.ts +454 -0
  19. package/src/__tests__/call-recovery.test.ts +518 -0
  20. package/src/__tests__/call-routes-http.test.ts +459 -0
  21. package/src/__tests__/call-state-machine.test.ts +143 -0
  22. package/src/__tests__/call-state.test.ts +133 -0
  23. package/src/__tests__/call-store.test.ts +691 -0
  24. package/src/__tests__/cli-discover.test.ts +1 -1
  25. package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
  26. package/src/__tests__/compaction.benchmark.test.ts +176 -0
  27. package/src/__tests__/computer-use-tools.test.ts +250 -0
  28. package/src/__tests__/config-schema.test.ts +348 -3
  29. package/src/__tests__/conflict-store.test.ts +2 -1
  30. package/src/__tests__/contacts-tools.test.ts +331 -0
  31. package/src/__tests__/conversation-store.test.ts +30 -32
  32. package/src/__tests__/credential-security-invariants.test.ts +4 -0
  33. package/src/__tests__/date-context.test.ts +373 -0
  34. package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
  35. package/src/__tests__/doordash-session.test.ts +9 -0
  36. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
  37. package/src/__tests__/followup-tools.test.ts +303 -0
  38. package/src/__tests__/handlers-twitter-config.test.ts +718 -0
  39. package/src/__tests__/intent-routing.test.ts +64 -57
  40. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
  41. package/src/__tests__/ipc-snapshot.test.ts +96 -28
  42. package/src/__tests__/llm-usage-store.test.ts +3 -8
  43. package/src/__tests__/media-generate-image.test.ts +1 -1
  44. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
  45. package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
  46. package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
  47. package/src/__tests__/playbook-tools.test.ts +342 -0
  48. package/src/__tests__/profile-compiler.test.ts +2 -1
  49. package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
  50. package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
  51. package/src/__tests__/recurrence-engine.test.ts +69 -0
  52. package/src/__tests__/recurrence-types.test.ts +71 -0
  53. package/src/__tests__/registry.test.ts +17 -10
  54. package/src/__tests__/relay-server.test.ts +633 -0
  55. package/src/__tests__/reminder-store.test.ts +6 -3
  56. package/src/__tests__/reminder.test.ts +43 -77
  57. package/src/__tests__/run-orchestrator-assistant-events.test.ts +222 -0
  58. package/src/__tests__/run-orchestrator.test.ts +7 -7
  59. package/src/__tests__/runtime-attachment-metadata.test.ts +19 -20
  60. package/src/__tests__/runtime-runs-http.test.ts +5 -23
  61. package/src/__tests__/runtime-runs.test.ts +11 -11
  62. package/src/__tests__/schedule-store.test.ts +482 -0
  63. package/src/__tests__/schedule-tools.test.ts +700 -0
  64. package/src/__tests__/scheduler-recurrence.test.ts +329 -0
  65. package/src/__tests__/server-history-render.test.ts +14 -13
  66. package/src/__tests__/session-error.test.ts +28 -0
  67. package/src/__tests__/session-init.benchmark.test.ts +462 -0
  68. package/src/__tests__/session-queue.test.ts +89 -16
  69. package/src/__tests__/session-runtime-assembly.test.ts +161 -0
  70. package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
  71. package/src/__tests__/signup-e2e.test.ts +2 -1
  72. package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
  73. package/src/__tests__/skill-script-runner.test.ts +159 -0
  74. package/src/__tests__/speaker-identification.test.ts +52 -0
  75. package/src/__tests__/subagent-manager-notify.test.ts +42 -10
  76. package/src/__tests__/subagent-tools.test.ts +141 -41
  77. package/src/__tests__/task-compiler.test.ts +2 -1
  78. package/src/__tests__/task-runner.test.ts +2 -1
  79. package/src/__tests__/task-scheduler.test.ts +2 -1
  80. package/src/__tests__/task-tools.test.ts +49 -56
  81. package/src/__tests__/tool-audit-listener.test.ts +1 -0
  82. package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
  83. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
  84. package/src/__tests__/tool-executor.test.ts +13 -17
  85. package/src/__tests__/turn-commit.test.ts +273 -2
  86. package/src/__tests__/twilio-provider.test.ts +143 -0
  87. package/src/__tests__/twilio-routes.test.ts +789 -0
  88. package/src/__tests__/twitter-auth-handler.test.ts +581 -0
  89. package/src/__tests__/view-image-tool.test.ts +217 -0
  90. package/src/__tests__/workspace-git-service.test.ts +403 -0
  91. package/src/__tests__/workspace-heartbeat-service.test.ts +141 -2
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
  93. package/src/bundler/app-bundler.ts +35 -14
  94. package/src/calls/call-bridge.ts +95 -0
  95. package/src/calls/call-constants.ts +48 -0
  96. package/src/calls/call-domain.ts +276 -0
  97. package/src/calls/call-orchestrator.ts +390 -0
  98. package/src/calls/call-recovery.ts +207 -0
  99. package/src/calls/call-state-machine.ts +68 -0
  100. package/src/calls/call-state.ts +64 -0
  101. package/src/calls/call-store.ts +416 -0
  102. package/src/calls/relay-server.ts +335 -0
  103. package/src/calls/speaker-identification.ts +213 -0
  104. package/src/calls/twilio-config.ts +34 -0
  105. package/src/calls/twilio-provider.ts +173 -0
  106. package/src/calls/twilio-routes.ts +250 -0
  107. package/src/calls/types.ts +37 -0
  108. package/src/calls/voice-provider.ts +14 -0
  109. package/src/cli/config-commands.ts +334 -0
  110. package/src/cli/core-commands.ts +776 -0
  111. package/src/cli/doordash.ts +256 -25
  112. package/src/cli/ipc-client.ts +82 -0
  113. package/src/cli/map.ts +246 -0
  114. package/src/cli/twitter.ts +575 -0
  115. package/src/cli.ts +7 -5
  116. package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
  117. package/src/commands/cc-command-registry.ts +209 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +39 -0
  119. package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
  120. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
  121. package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
  122. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
  123. package/src/config/bundled-skills/document/SKILL.md +18 -0
  124. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  125. package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
  126. package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
  127. package/src/config/bundled-skills/doordash/SKILL.md +163 -0
  128. package/src/config/bundled-skills/followups/SKILL.md +32 -0
  129. package/src/config/bundled-skills/followups/TOOLS.json +100 -0
  130. package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
  131. package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
  132. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
  133. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  134. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -24
  135. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
  136. package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
  137. package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
  138. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
  139. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
  140. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
  141. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
  142. package/src/config/bundled-skills/reminder/SKILL.md +20 -0
  143. package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
  144. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
  145. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
  146. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +74 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
  149. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
  150. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
  151. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
  152. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
  153. package/src/config/bundled-skills/subagent/SKILL.md +25 -0
  154. package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
  155. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
  156. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
  157. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
  158. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
  159. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
  160. package/src/config/bundled-skills/tasks/SKILL.md +28 -0
  161. package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
  162. package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
  163. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
  164. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
  165. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
  166. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
  167. package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
  168. package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
  169. package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
  170. package/src/config/bundled-skills/twitter/SKILL.md +134 -0
  171. package/src/config/bundled-skills/watcher/SKILL.md +27 -0
  172. package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
  173. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
  174. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
  175. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
  176. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
  177. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
  178. package/src/config/defaults.ts +44 -0
  179. package/src/config/loader.ts +4 -1
  180. package/src/config/schema.ts +218 -1
  181. package/src/config/system-prompt.ts +100 -6
  182. package/src/config/templates/IDENTITY.md +7 -0
  183. package/src/config/types.ts +5 -0
  184. package/src/contacts/contact-store.ts +4 -4
  185. package/src/daemon/assistant-attachments.ts +10 -0
  186. package/src/daemon/classifier.ts +3 -1
  187. package/src/daemon/computer-use-session.ts +3 -1
  188. package/src/daemon/date-context.ts +136 -0
  189. package/src/daemon/handlers/apps.ts +16 -1
  190. package/src/daemon/handlers/browser.ts +54 -0
  191. package/src/daemon/handlers/computer-use.ts +7 -1
  192. package/src/daemon/handlers/config.ts +192 -4
  193. package/src/daemon/handlers/diagnostics.ts +5 -1
  194. package/src/daemon/handlers/documents.ts +18 -29
  195. package/src/daemon/handlers/home-base.ts +5 -1
  196. package/src/daemon/handlers/index.ts +40 -271
  197. package/src/daemon/handlers/misc.ts +9 -1
  198. package/src/daemon/handlers/publish.ts +6 -1
  199. package/src/daemon/handlers/sessions.ts +65 -12
  200. package/src/daemon/handlers/shared.ts +36 -1
  201. package/src/daemon/handlers/signing.ts +37 -0
  202. package/src/daemon/handlers/skills.ts +20 -6
  203. package/src/daemon/handlers/subagents.ts +8 -3
  204. package/src/daemon/handlers/twitter-auth.ts +169 -0
  205. package/src/daemon/handlers/work-items.ts +495 -39
  206. package/src/daemon/ipc-contract-inventory.json +40 -4
  207. package/src/daemon/ipc-contract.ts +185 -37
  208. package/src/daemon/ipc-protocol.ts +7 -2
  209. package/src/daemon/lifecycle.ts +48 -5
  210. package/src/daemon/main.ts +10 -4
  211. package/src/daemon/ride-shotgun-handler.ts +74 -10
  212. package/src/daemon/server.ts +144 -29
  213. package/src/daemon/session-agent-loop.ts +887 -0
  214. package/src/daemon/session-attachments.ts +28 -5
  215. package/src/daemon/session-error.ts +24 -3
  216. package/src/daemon/session-lifecycle.ts +147 -0
  217. package/src/daemon/session-media-retry.ts +147 -0
  218. package/src/daemon/session-messaging.ts +145 -0
  219. package/src/daemon/session-notifiers.ts +164 -0
  220. package/src/daemon/session-process.ts +2 -2
  221. package/src/daemon/session-queue-manager.ts +1 -0
  222. package/src/daemon/session-runtime-assembly.ts +52 -0
  223. package/src/daemon/session-skill-tools.ts +124 -5
  224. package/src/daemon/session-slash.ts +3 -0
  225. package/src/daemon/session-surfaces.ts +77 -2
  226. package/src/daemon/session-tool-setup.ts +222 -2
  227. package/src/daemon/session-usage.ts +0 -2
  228. package/src/daemon/session.ts +114 -1365
  229. package/src/daemon/video-thumbnail.ts +60 -0
  230. package/src/doordash/client.ts +121 -27
  231. package/src/doordash/queries.ts +1 -2
  232. package/src/export/formatter.ts +3 -1
  233. package/src/followups/followup-store.ts +4 -2
  234. package/src/followups/types.ts +6 -0
  235. package/src/hooks/templates.ts +1 -1
  236. package/src/index.ts +32 -1151
  237. package/src/media/gemini-image-service.ts +1 -1
  238. package/src/memory/attachments-store.ts +28 -83
  239. package/src/memory/channel-delivery-store.ts +7 -21
  240. package/src/memory/clarification-resolver.ts +6 -5
  241. package/src/memory/contradiction-checker.ts +3 -2
  242. package/src/memory/conversation-key-store.ts +10 -29
  243. package/src/memory/conversation-store.ts +2 -1
  244. package/src/memory/db.ts +362 -2
  245. package/src/memory/entity-extractor.ts +6 -3
  246. package/src/memory/items-extractor.ts +5 -4
  247. package/src/memory/jobs-store.ts +3 -2
  248. package/src/memory/llm-usage-store.ts +1 -2
  249. package/src/memory/runs-store.ts +1 -2
  250. package/src/memory/schema.ts +65 -2
  251. package/src/messaging/style-analyzer.ts +3 -2
  252. package/src/messaging/thread-summarizer.ts +8 -12
  253. package/src/messaging/triage-engine.ts +4 -2
  254. package/src/providers/openrouter/client.ts +20 -0
  255. package/src/providers/registry.ts +8 -0
  256. package/src/runtime/http-server.ts +277 -25
  257. package/src/runtime/http-types.ts +0 -2
  258. package/src/runtime/routes/attachment-routes.ts +5 -6
  259. package/src/runtime/routes/call-routes.ts +140 -0
  260. package/src/runtime/routes/channel-routes.ts +12 -19
  261. package/src/runtime/routes/conversation-routes.ts +5 -9
  262. package/src/runtime/routes/run-routes.ts +4 -8
  263. package/src/runtime/run-orchestrator.ts +39 -6
  264. package/src/schedule/recurrence-engine.ts +138 -0
  265. package/src/schedule/recurrence-types.ts +67 -0
  266. package/src/schedule/schedule-store.ts +102 -57
  267. package/src/schedule/scheduler.ts +9 -6
  268. package/src/security/oauth2.ts +29 -4
  269. package/src/security/secret-allowlist.ts +46 -0
  270. package/src/skills/clawhub.ts +1 -1
  271. package/src/subagent/manager.ts +40 -8
  272. package/src/swarm/backend-claude-code.ts +64 -9
  273. package/src/swarm/worker-prompts.ts +2 -1
  274. package/src/tasks/SPEC.md +34 -28
  275. package/src/tasks/ephemeral-permissions.ts +16 -7
  276. package/src/tasks/task-compiler.ts +5 -4
  277. package/src/tasks/task-runner.ts +10 -5
  278. package/src/tasks/task-scheduler.ts +1 -1
  279. package/src/tasks/tool-sanitizer.ts +36 -0
  280. package/src/tools/assets/search.ts +4 -4
  281. package/src/tools/browser/api-map.ts +220 -0
  282. package/src/tools/browser/auto-navigate.ts +270 -0
  283. package/src/tools/browser/browser-execution.ts +2 -1
  284. package/src/tools/browser/browser-manager.ts +2 -2
  285. package/src/tools/browser/network-recorder.ts +5 -4
  286. package/src/tools/browser/x-auto-navigate.ts +207 -0
  287. package/src/tools/calls/call-end.ts +67 -0
  288. package/src/tools/calls/call-start.ts +73 -0
  289. package/src/tools/calls/call-status.ts +81 -0
  290. package/src/tools/claude-code/claude-code.ts +77 -11
  291. package/src/tools/contacts/contact-merge.ts +46 -78
  292. package/src/tools/contacts/contact-search.ts +35 -79
  293. package/src/tools/contacts/contact-upsert.ts +35 -108
  294. package/src/tools/credentials/vault.ts +21 -5
  295. package/src/tools/document/document-tool.ts +71 -144
  296. package/src/tools/executor.ts +129 -10
  297. package/src/tools/followups/followup_create.ts +46 -88
  298. package/src/tools/followups/followup_list.ts +34 -74
  299. package/src/tools/followups/followup_resolve.ts +31 -66
  300. package/src/tools/host-terminal/cli-discover.ts +2 -1
  301. package/src/tools/host-terminal/host-shell.ts +10 -0
  302. package/src/tools/memory/handlers.ts +5 -4
  303. package/src/tools/network/__tests__/web-search.test.ts +427 -0
  304. package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
  305. package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
  306. package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
  307. package/src/tools/network/web-fetch.ts +18 -6
  308. package/src/tools/playbooks/index.ts +4 -5
  309. package/src/tools/playbooks/playbook-create.ts +3 -47
  310. package/src/tools/playbooks/playbook-delete.ts +1 -25
  311. package/src/tools/playbooks/playbook-list.ts +1 -28
  312. package/src/tools/playbooks/playbook-update.ts +3 -51
  313. package/src/tools/registry.ts +2 -4
  314. package/src/tools/reminder/reminder.ts +5 -78
  315. package/src/tools/schedule/create.ts +69 -74
  316. package/src/tools/schedule/delete.ts +21 -47
  317. package/src/tools/schedule/list.ts +55 -74
  318. package/src/tools/schedule/update.ts +77 -84
  319. package/src/tools/subagent/abort.ts +29 -58
  320. package/src/tools/subagent/message.ts +30 -63
  321. package/src/tools/subagent/read.ts +53 -84
  322. package/src/tools/subagent/spawn.ts +43 -82
  323. package/src/tools/subagent/status.ts +42 -71
  324. package/src/tools/swarm/delegate.ts +2 -1
  325. package/src/tools/tasks/index.ts +8 -6
  326. package/src/tools/tasks/task-delete.ts +69 -56
  327. package/src/tools/tasks/task-list.ts +31 -52
  328. package/src/tools/tasks/task-run.ts +74 -102
  329. package/src/tools/tasks/task-save.ts +33 -65
  330. package/src/tools/tasks/work-item-enqueue.ts +192 -134
  331. package/src/tools/tasks/work-item-list.ts +33 -78
  332. package/src/tools/tasks/work-item-remove.ts +60 -0
  333. package/src/tools/tasks/work-item-update.ts +114 -0
  334. package/src/tools/terminal/backends/native.ts +3 -1
  335. package/src/tools/tool-manifest.ts +20 -74
  336. package/src/tools/types.ts +6 -0
  337. package/src/tools/ui-surface/definitions.ts +6 -1
  338. package/src/tools/watch/screen-watch.ts +3 -1
  339. package/src/tools/watcher/create.ts +52 -98
  340. package/src/tools/watcher/delete.ts +20 -46
  341. package/src/tools/watcher/digest.ts +36 -70
  342. package/src/tools/watcher/list.ts +49 -79
  343. package/src/tools/watcher/update.ts +45 -91
  344. package/src/twitter/client.ts +690 -0
  345. package/src/twitter/session.ts +91 -0
  346. package/src/usage/types.ts +0 -1
  347. package/src/util/truncate.ts +6 -0
  348. package/src/watcher/providers/slack.ts +2 -1
  349. package/src/watcher/watcher-store.ts +3 -2
  350. package/src/work-items/work-item-store.ts +236 -2
  351. package/src/workspace/commit-message-enrichment-service.ts +284 -0
  352. package/src/workspace/commit-message-provider.ts +95 -0
  353. package/src/workspace/git-service.ts +272 -52
  354. package/src/workspace/heartbeat-service.ts +70 -13
  355. package/src/workspace/provider-commit-message-generator.ts +242 -0
  356. package/src/workspace/turn-commit.ts +100 -51
  357. package/src/tools/contacts/index.ts +0 -4
  358. package/src/tools/document/index.ts +0 -5
  359. package/src/tools/followups/index.ts +0 -3
  360. package/src/tools/subagent/index.ts +0 -5
  361. /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
+ }
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: "DoorDash"
3
+ description: "Order food, groceries, and convenience items from DoorDash using the built-in CLI integration"
4
+ user-invocable: true
5
+ metadata: {"vellum": {"emoji": "\uD83C\uDF55"}}
6
+ ---
7
+
8
+ You can order food from DoorDash for the user using the `vellum doordash` CLI.
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
+
16
+ ## Task Progress Widget
17
+
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).
19
+
20
+ ## Typical Flow
21
+
22
+ When the user asks you to order food (e.g. "Order pizza from Andiamo's"):
23
+
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.
27
+
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.
29
+
30
+ 3. **Browse menu** — run `vellum doordash menu <storeId> --json` to get the menu. Show the user the categories and items with prices. If the user already said what they want (e.g. "pepperoni pizza"), find the matching item(s). **For convenience/pharmacy stores** (CVS, Duane Reade, Walgreens etc.), the response will have `isRetail: true` and empty items — use `store-search` instead (see step 3b).
31
+
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.
33
+
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.
40
+
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).
42
+
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.
44
+
45
+ 7. **Checkout** — run `vellum doordash checkout <cartId> --json` to get delivery options. Present them to the user.
46
+
47
+ 8. **Payment methods** — run `vellum doordash payment-methods --json` to see saved cards. Show the user which card will be used (the default one).
48
+
49
+ 9. **Place order** — after the user explicitly confirms, run `vellum doordash order place --cart-id <id> --store-id <id> --total <cents> [--tip <cents>] [--dropoff-option <id>] --json`. The command auto-selects the default payment method if `--payment-uuid` is not provided. The response contains `orderUuid` on success.
50
+
51
+ ## Important Behavior
52
+
53
+ - **Always confirm before checkout.** Never place an order without explicit user approval.
54
+ - **Be proactive.** If the user says "order pizza from Andiamo's", don't ask clarifying questions upfront — search, find the store, show the menu, and suggest items. Only ask when you need a choice the user hasn't specified.
55
+ - **Handle expired sessions gracefully.** If any command returns `"error": "session_expired"`, run `vellum doordash refresh --json` to re-capture the session.
56
+ - **Show prices.** Always show prices when presenting items or the cart summary.
57
+ - **Use `--json` flag** on all commands for reliable parsing.
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
+ ```
121
+
122
+ ## Command Reference
123
+
124
+ ```
125
+ vellum doordash status --json # Check if logged in
126
+ vellum doordash refresh --json # Capture fresh session via Ride Shotgun (auto-stops after login)
127
+ vellum doordash login --recording <path> # Import session from a recording file manually
128
+ vellum doordash logout --json # Clear session
129
+ vellum doordash search "<query>" --json # Search restaurants
130
+ vellum doordash menu <storeId> --json # Get store menu (auto-detects retail stores)
131
+ vellum doordash store-search <storeId> "<query>" --json # Search items within a convenience/pharmacy store
132
+ vellum doordash item <storeId> <itemId> --json # Get item details + options
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
134
+ vellum doordash cart remove --cart-id <id> --item-id <orderItemId> --json
135
+ vellum doordash cart view <cartId> --json
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
139
+ vellum doordash checkout <cartId> [--address-id <id>] --json
140
+ vellum doordash payment-methods --json # List saved payment methods
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
142
+ ```
143
+
144
+ ## Example Interaction
145
+
146
+ **User**: "Order a pepperoni pizza from Andiamo's"
147
+
148
+ 1. `vellum doordash status --json` -> logged in
149
+ 2. `vellum doordash search "Andiamo's" --json` -> finds store 22926474
150
+ 3. `vellum doordash menu 22926474 --json` -> finds "Pepperoni Pizza Pie" (item 2956709006, $28.00)
151
+ 4. Tell user: "I found Pepperoni Pizza Pie at Andiamo's for $28.00. Adding it to your cart."
152
+ 5. `vellum doordash cart add --store-id 22926474 --menu-id 12847574 --item-id 2956709006 --item-name "Pepperoni Pizza Pie" --unit-price 2800 --json`
153
+ 6. `vellum doordash cart view <cartId> --json` -> show summary
154
+ 7. "Your cart has 1x Pepperoni Pizza Pie ($28.00), total $28.00. Ready to check out?"
155
+
156
+ **User**: "I need Tylenol from CVS"
157
+
158
+ 1. `vellum doordash status --json` -> logged in
159
+ 2. `vellum doordash search "CVS" --json` -> finds store 1231787
160
+ 3. `vellum doordash menu 1231787 --json` -> isRetail: true, categories but no items
161
+ 4. `vellum doordash store-search 1231787 "tylenol" --json` -> finds results
162
+ 5. Show top results: "Tylenol Extra Strength Gelcaps (24 ct) - $8.79, Tylenol Extra Strength Caplets (100 ct) - $13.49..."
163
+ 6. User picks one -> add to cart with the item's `id`, `menuId`, and `unitAmount`
@@ -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
+ }
@@ -25,8 +25,8 @@
25
25
  },
26
26
  "model": {
27
27
  "type": "string",
28
- "enum": ["gemini-2.5-flash-image", "gemini-3-pro-image"],
29
- "description": "Which model to use for generation (default: gemini-2.5-flash-image)"
28
+ "enum": ["gemini-2.5-flash-image", "gemini-3-pro-image", "gemini-3-pro-image-preview"],
29
+ "description": "Which model to use for generation. If omitted, uses the user's configured preference."
30
30
  },
31
31
  "variants": {
32
32
  "type": "number",
@@ -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,
@@ -57,22 +43,14 @@ export async function run(
57
43
  const prompt = input.prompt as string;
58
44
  const mode = (input.mode as 'generate' | 'edit') ?? 'generate';
59
45
  const attachmentIds = input.attachment_ids as string[] | undefined;
60
- const model = input.model as string | undefined;
46
+ const model = (input.model as string | undefined) ?? config.imageGenModel;
61
47
  const variants = input.variants as number | undefined;
62
48
 
63
49
  // Resolve source images from attachments for edit mode
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.