@vellumai/assistant 0.5.0 → 0.5.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 (347) hide show
  1. package/ARCHITECTURE.md +54 -54
  2. package/docs/architecture/integrations.md +62 -67
  3. package/docs/credential-execution-service.md +3 -3
  4. package/package.json +1 -1
  5. package/src/__tests__/agent-loop.test.ts +111 -0
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
  7. package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
  8. package/src/__tests__/app-dir-path-guard.test.ts +78 -0
  9. package/src/__tests__/app-executors.test.ts +1 -291
  10. package/src/__tests__/app-git-history.test.ts +4 -4
  11. package/src/__tests__/app-routes-csp.test.ts +1 -0
  12. package/src/__tests__/app-store-dir-names.test.ts +426 -0
  13. package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -9
  14. package/src/__tests__/attachments-store.test.ts +169 -21
  15. package/src/__tests__/attachments.test.ts +115 -1
  16. package/src/__tests__/btw-routes.test.ts +1 -0
  17. package/src/__tests__/canonical-guardian-store.test.ts +38 -0
  18. package/src/__tests__/channel-reply-delivery.test.ts +55 -0
  19. package/src/__tests__/checker.test.ts +54 -0
  20. package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
  21. package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
  22. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  23. package/src/__tests__/config-schema-cmd.test.ts +68 -21
  24. package/src/__tests__/config-schema.test.ts +1 -1
  25. package/src/__tests__/conversation-agent-loop-overflow.test.ts +149 -5
  26. package/src/__tests__/conversation-agent-loop.test.ts +290 -2
  27. package/src/__tests__/conversation-attachments.test.ts +17 -19
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
  29. package/src/__tests__/conversation-disk-view.test.ts +810 -0
  30. package/src/__tests__/conversation-error.test.ts +1 -1
  31. package/src/__tests__/conversation-fork-crud.test.ts +551 -0
  32. package/src/__tests__/conversation-fork-route.test.ts +386 -0
  33. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  34. package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
  35. package/src/__tests__/conversation-media-retry.test.ts +8 -2
  36. package/src/__tests__/conversation-queue.test.ts +36 -1
  37. package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
  38. package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
  39. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
  41. package/src/__tests__/conversation-skill-tools.test.ts +4 -9
  42. package/src/__tests__/conversation-slash-commands.test.ts +149 -0
  43. package/src/__tests__/conversation-store.test.ts +24 -21
  44. package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
  45. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
  46. package/src/__tests__/conversation-title-service.test.ts +137 -0
  47. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
  48. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
  49. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
  50. package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
  51. package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
  52. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  53. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  54. package/src/__tests__/credential-vault-unit.test.ts +5 -10
  55. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  56. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
  57. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
  58. package/src/__tests__/diagnostics-export.test.ts +70 -1
  59. package/src/__tests__/filesystem-tools.test.ts +4 -2
  60. package/src/__tests__/first-greeting.test.ts +80 -0
  61. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  62. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
  63. package/src/__tests__/history-repair.test.ts +103 -10
  64. package/src/__tests__/http-conversation-lineage.test.ts +251 -0
  65. package/src/__tests__/image-source-path-reinject.test.ts +136 -0
  66. package/src/__tests__/llm-context-normalization.test.ts +1116 -0
  67. package/src/__tests__/llm-context-route-provider.test.ts +217 -0
  68. package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
  69. package/src/__tests__/media-generate-image.test.ts +47 -94
  70. package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
  71. package/src/__tests__/memory-recall-quality.test.ts +5 -5
  72. package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
  73. package/src/__tests__/migration-export-http.test.ts +3 -1
  74. package/src/__tests__/migration-import-commit-http.test.ts +18 -4
  75. package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
  76. package/src/__tests__/mime-builder.test.ts +3 -2
  77. package/src/__tests__/non-member-access-request.test.ts +12 -1
  78. package/src/__tests__/notification-decision-identity.test.ts +52 -0
  79. package/src/__tests__/oauth-apps-routes.test.ts +103 -0
  80. package/src/__tests__/oauth-store.test.ts +115 -0
  81. package/src/__tests__/provider-error-scenarios.test.ts +1 -3
  82. package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
  83. package/src/__tests__/recording-handler.test.ts +17 -0
  84. package/src/__tests__/registry.test.ts +3 -8
  85. package/src/__tests__/relay-server.test.ts +1 -1
  86. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
  87. package/src/__tests__/schema-transforms.test.ts +165 -5
  88. package/src/__tests__/server-history-render.test.ts +2 -2
  89. package/src/__tests__/skill-feature-flags-integration.test.ts +18 -17
  90. package/src/__tests__/skill-feature-flags.test.ts +13 -13
  91. package/src/__tests__/skill-load-feature-flag.test.ts +4 -4
  92. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  93. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  94. package/src/__tests__/starter-task-flow.test.ts +1 -0
  95. package/src/__tests__/suggestion-routes.test.ts +443 -0
  96. package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
  97. package/src/__tests__/swarm-recursion.test.ts +1 -0
  98. package/src/__tests__/swarm-tool.test.ts +1 -0
  99. package/src/__tests__/system-prompt.test.ts +8 -0
  100. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
  101. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
  102. package/src/__tests__/top-level-renderer.test.ts +22 -0
  103. package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
  104. package/src/__tests__/web-fetch.test.ts +6 -2
  105. package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
  106. package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
  107. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
  108. package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
  109. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
  110. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
  111. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
  112. package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
  113. package/src/agent/attachments.ts +27 -1
  114. package/src/agent/loop.ts +29 -1
  115. package/src/avatar/traits-png-sync.ts +80 -25
  116. package/src/bundler/app-bundler.ts +4 -4
  117. package/src/calls/call-domain.ts +1 -0
  118. package/src/calls/voice-session-bridge.ts +1 -0
  119. package/src/cli/commands/auth.ts +92 -0
  120. package/src/cli/commands/avatar.ts +7 -6
  121. package/src/cli/commands/config.ts +2 -0
  122. package/src/cli/commands/oauth/providers.ts +29 -0
  123. package/src/cli/program.ts +12 -0
  124. package/src/cli.ts +15 -48
  125. package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
  126. package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
  127. package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
  128. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
  129. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
  130. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
  131. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
  132. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
  133. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
  134. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
  135. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
  136. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
  137. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
  138. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
  139. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
  140. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
  141. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
  142. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  143. package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
  144. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  145. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
  146. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  148. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
  149. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  150. package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
  151. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
  152. package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
  153. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
  154. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
  155. package/src/config/bundled-tool-registry.ts +2 -14
  156. package/src/config/feature-flag-registry.json +16 -0
  157. package/src/config/loader.ts +64 -0
  158. package/src/config/raw-config-utils.ts +30 -0
  159. package/src/config/schema-utils.ts +28 -7
  160. package/src/config/schema.ts +8 -0
  161. package/src/config/schemas/elevenlabs.ts +18 -0
  162. package/src/config/schemas/memory-lifecycle.ts +4 -2
  163. package/src/config/schemas/memory-storage.ts +1 -1
  164. package/src/config/schemas/services.ts +8 -6
  165. package/src/contacts/contact-store.ts +13 -6
  166. package/src/contacts/contacts-write.ts +0 -1
  167. package/src/context/window-manager.ts +13 -2
  168. package/src/daemon/conversation-agent-loop-handlers.ts +46 -42
  169. package/src/daemon/conversation-agent-loop.ts +56 -19
  170. package/src/daemon/conversation-attachments.ts +18 -36
  171. package/src/daemon/conversation-error.ts +2 -1
  172. package/src/daemon/conversation-history.ts +18 -4
  173. package/src/daemon/conversation-lifecycle.ts +39 -15
  174. package/src/daemon/conversation-messaging.ts +70 -26
  175. package/src/daemon/conversation-process.ts +58 -34
  176. package/src/daemon/conversation-runtime-assembly.ts +21 -38
  177. package/src/daemon/conversation-slash.ts +121 -256
  178. package/src/daemon/conversation-surfaces.ts +143 -20
  179. package/src/daemon/conversation-tool-setup.ts +0 -6
  180. package/src/daemon/conversation-workspace.ts +21 -1
  181. package/src/daemon/conversation.ts +51 -29
  182. package/src/daemon/first-greeting.ts +35 -0
  183. package/src/daemon/handlers/config-embeddings.ts +148 -0
  184. package/src/daemon/handlers/config-model.ts +71 -26
  185. package/src/daemon/handlers/conversations.ts +0 -23
  186. package/src/daemon/handlers/recording.ts +26 -21
  187. package/src/daemon/history-repair.ts +28 -8
  188. package/src/daemon/host-cu-proxy.ts +2 -2
  189. package/src/daemon/lifecycle.ts +106 -64
  190. package/src/daemon/message-protocol.ts +3 -0
  191. package/src/daemon/message-types/conversations.ts +19 -0
  192. package/src/daemon/message-types/messages.ts +1 -0
  193. package/src/daemon/message-types/shared.ts +2 -0
  194. package/src/daemon/message-types/surfaces.ts +2 -0
  195. package/src/daemon/message-types/upgrades.ts +23 -0
  196. package/src/daemon/server.ts +83 -12
  197. package/src/daemon/shutdown-handlers.ts +8 -5
  198. package/src/daemon/startup-error.ts +9 -0
  199. package/src/daemon/tool-side-effects.ts +11 -28
  200. package/src/events/tool-permission-telemetry-listener.ts +1 -3
  201. package/src/instrument.ts +0 -4
  202. package/src/media/app-icon-generator.ts +2 -2
  203. package/src/memory/app-git-service.ts +28 -16
  204. package/src/memory/app-store.ts +230 -41
  205. package/src/memory/attachments-store.ts +558 -130
  206. package/src/memory/conversation-attention-store.ts +70 -0
  207. package/src/memory/conversation-crud.ts +442 -3
  208. package/src/memory/conversation-directories.ts +125 -0
  209. package/src/memory/conversation-disk-view.ts +390 -0
  210. package/src/memory/conversation-key-store.ts +17 -5
  211. package/src/memory/conversation-queries.ts +5 -1
  212. package/src/memory/conversation-title-service.ts +21 -49
  213. package/src/memory/db-init.ts +28 -0
  214. package/src/memory/embedding-backend.ts +42 -53
  215. package/src/memory/embedding-gemini.test.ts +4 -4
  216. package/src/memory/embedding-local.ts +1 -3
  217. package/src/memory/embedding-ollama.ts +1 -3
  218. package/src/memory/embedding-openai.ts +1 -3
  219. package/src/memory/indexer.ts +9 -7
  220. package/src/memory/items-extractor.ts +42 -13
  221. package/src/memory/job-handlers/conversation-starters.ts +6 -1
  222. package/src/memory/job-handlers/embedding.test.ts +1 -4
  223. package/src/memory/llm-request-log-store.ts +100 -1
  224. package/src/memory/migrations/102-alter-table-columns.ts +5 -0
  225. package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
  226. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
  227. package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
  228. package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
  229. package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
  230. package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
  231. package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
  232. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
  233. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
  234. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
  235. package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
  236. package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
  237. package/src/memory/migrations/index.ts +7 -0
  238. package/src/memory/migrations/registry.ts +13 -0
  239. package/src/memory/retriever.test.ts +601 -2
  240. package/src/memory/retriever.ts +85 -9
  241. package/src/memory/schema/conversations.ts +6 -0
  242. package/src/memory/schema/infrastructure.ts +13 -7
  243. package/src/memory/schema/oauth.ts +6 -0
  244. package/src/messaging/providers/gmail/mime-builder.ts +3 -1
  245. package/src/notifications/copy-composer.ts +26 -0
  246. package/src/notifications/decision-engine.ts +14 -1
  247. package/src/notifications/emit-signal.ts +1 -1
  248. package/src/notifications/signal.ts +36 -0
  249. package/src/oauth/byo-connection.test.ts +1 -45
  250. package/src/oauth/byo-connection.ts +2 -8
  251. package/src/oauth/connect-orchestrator.ts +15 -11
  252. package/src/oauth/connection-resolver.test.ts +191 -0
  253. package/src/oauth/connection-resolver.ts +66 -38
  254. package/src/oauth/connection.ts +0 -1
  255. package/src/oauth/oauth-store.ts +97 -47
  256. package/src/oauth/platform-connection.test.ts +0 -1
  257. package/src/oauth/platform-connection.ts +11 -3
  258. package/src/oauth/seed-providers.ts +78 -3
  259. package/src/oauth/token-persistence.ts +16 -10
  260. package/src/permissions/checker.ts +62 -19
  261. package/src/prompts/system-prompt.ts +2 -0
  262. package/src/prompts/templates/BOOTSTRAP.md +2 -0
  263. package/src/providers/anthropic/client.ts +8 -1
  264. package/src/providers/failover.ts +4 -1
  265. package/src/providers/gemini/client.ts +50 -0
  266. package/src/providers/model-catalog.ts +92 -0
  267. package/src/providers/model-intents.ts +29 -20
  268. package/src/providers/openai/client.ts +49 -0
  269. package/src/providers/types.ts +2 -0
  270. package/src/runtime/access-request-helper.ts +16 -7
  271. package/src/runtime/auth/credential-service.ts +3 -1
  272. package/src/runtime/auth/route-policy.ts +14 -1
  273. package/src/runtime/btw-sidechain.ts +101 -0
  274. package/src/runtime/channel-reply-delivery.ts +17 -1
  275. package/src/runtime/http-router.ts +3 -1
  276. package/src/runtime/http-server.ts +196 -141
  277. package/src/runtime/http-types.ts +1 -0
  278. package/src/runtime/migrations/vbundle-builder.ts +5 -1
  279. package/src/runtime/routes/access-request-decision.ts +41 -0
  280. package/src/runtime/routes/app-management-routes.ts +6 -3
  281. package/src/runtime/routes/app-routes.ts +7 -3
  282. package/src/runtime/routes/approval-routes.ts +1 -0
  283. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
  284. package/src/runtime/routes/attachment-routes.ts +45 -15
  285. package/src/runtime/routes/btw-routes.ts +21 -61
  286. package/src/runtime/routes/conversation-management-routes.ts +68 -0
  287. package/src/runtime/routes/conversation-query-routes.ts +180 -10
  288. package/src/runtime/routes/conversation-routes.ts +222 -28
  289. package/src/runtime/routes/conversation-starter-routes.ts +9 -11
  290. package/src/runtime/routes/diagnostics-routes.ts +1 -0
  291. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
  292. package/src/runtime/routes/llm-context-normalization.ts +1199 -0
  293. package/src/runtime/routes/log-export-routes.ts +3 -0
  294. package/src/runtime/routes/memory-item-routes.test.ts +34 -0
  295. package/src/runtime/routes/memory-item-routes.ts +4 -0
  296. package/src/runtime/routes/migration-routes.ts +4 -1
  297. package/src/runtime/routes/oauth-apps.ts +291 -0
  298. package/src/runtime/routes/secret-routes.ts +28 -1
  299. package/src/runtime/routes/settings-routes.ts +14 -0
  300. package/src/runtime/routes/trace-event-routes.ts +4 -1
  301. package/src/schedule/schedule-store.ts +9 -21
  302. package/src/security/secure-keys.ts +21 -0
  303. package/src/signals/bash.ts +1 -1
  304. package/src/swarm/backend-claude-code.ts +3 -6
  305. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  306. package/src/telemetry/usage-telemetry-reporter.ts +3 -1
  307. package/src/tools/AGENTS.md +6 -10
  308. package/src/tools/apps/executors.ts +17 -232
  309. package/src/tools/claude-code/claude-code.ts +2 -3
  310. package/src/tools/credentials/vault.ts +7 -12
  311. package/src/tools/host-filesystem/read.ts +13 -10
  312. package/src/tools/network/__tests__/web-search.test.ts +4 -2
  313. package/src/tools/schedule/list.ts +2 -7
  314. package/src/tools/schema-transforms.ts +5 -0
  315. package/src/tools/shared/filesystem/format-diff.ts +4 -21
  316. package/src/tools/skills/execute.ts +1 -1
  317. package/src/tools/tool-manifest.ts +0 -6
  318. package/src/tools/ui-surface/definitions.ts +2 -2
  319. package/src/util/device-id.ts +28 -5
  320. package/src/util/platform.ts +6 -0
  321. package/src/util/pricing.ts +1 -0
  322. package/src/util/retry.ts +1 -3
  323. package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
  324. package/src/workspace/migrations/003-seed-device-id.ts +3 -4
  325. package/src/workspace/migrations/006-services-config.ts +5 -0
  326. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
  327. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
  328. package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
  329. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
  330. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
  331. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
  332. package/src/workspace/migrations/registry.ts +10 -0
  333. package/src/workspace/top-level-renderer.ts +12 -0
  334. package/src/__tests__/asset-materialize-tool.test.ts +0 -523
  335. package/src/__tests__/asset-search-tool.test.ts +0 -536
  336. package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
  337. package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
  338. package/src/__tests__/media-visibility-policy.test.ts +0 -190
  339. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
  340. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
  341. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
  342. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
  343. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
  344. package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
  345. package/src/daemon/media-visibility-policy.ts +0 -59
  346. package/src/tools/assets/materialize.ts +0 -248
  347. package/src/tools/assets/search.ts +0 -400
@@ -49,6 +49,7 @@ export interface VoiceBridgeDeps {
49
49
  filename: string;
50
50
  mimeType: string;
51
51
  data: string;
52
+ filePath?: string;
52
53
  }>;
53
54
  deriveDefaultStrictSideEffects: (conversationId: string) => boolean;
54
55
  }
@@ -0,0 +1,92 @@
1
+ import type { Command } from "commander";
2
+
3
+ import {
4
+ getPlatformAssistantId,
5
+ getPlatformBaseUrl,
6
+ getPlatformOrganizationId,
7
+ getPlatformUserId,
8
+ } from "../../config/env.js";
9
+ import { resolveManagedProxyContext } from "../../providers/managed-proxy/context.js";
10
+ import { log } from "../logger.js";
11
+ import { shouldOutputJson, writeOutput } from "../output.js";
12
+
13
+ export function registerAuthCommand(program: Command): void {
14
+ const auth = program
15
+ .command("auth")
16
+ .description("Manage platform authentication and identity")
17
+ .option("--json", "Machine-readable compact JSON output");
18
+
19
+ auth.addHelpText(
20
+ "after",
21
+ `
22
+ The auth namespace manages the assistant's authentication state with the
23
+ Vellum platform. It provides commands to inspect identity and connection
24
+ status, helping diagnose configuration issues.
25
+
26
+ Examples:
27
+ $ assistant auth info
28
+ $ assistant auth info --json`,
29
+ );
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // info
33
+ // ---------------------------------------------------------------------------
34
+
35
+ auth
36
+ .command("info")
37
+ .description("Show platform identity and authentication status")
38
+ .addHelpText(
39
+ "after",
40
+ `
41
+ Fields:
42
+ platformUrl The Vellum platform base URL this assistant connects to
43
+ assistantId This assistant's platform UUID (from PLATFORM_ASSISTANT_ID)
44
+ organizationId The organization this assistant belongs to (from PLATFORM_ORGANIZATION_ID)
45
+ userId The user who owns this assistant (from PLATFORM_USER_ID)
46
+ authenticated Whether all prerequisites for platform authentication are met
47
+ (platform URL and assistant API key both present)
48
+
49
+ When not authenticated, a message field provides guidance on next steps.
50
+
51
+ Examples:
52
+ $ assistant auth info
53
+ $ assistant auth info --json`,
54
+ )
55
+ .action(async (_opts: Record<string, unknown>, cmd: Command) => {
56
+ const ctx = await resolveManagedProxyContext();
57
+
58
+ const platformUrl = getPlatformBaseUrl();
59
+ const assistantId = getPlatformAssistantId();
60
+ const organizationId = getPlatformOrganizationId();
61
+ const userId = getPlatformUserId();
62
+ const authenticated = ctx.enabled;
63
+
64
+ const result: Record<string, unknown> = {
65
+ platformUrl: platformUrl || null,
66
+ assistantId: assistantId || null,
67
+ organizationId: organizationId || null,
68
+ userId: userId || null,
69
+ authenticated,
70
+ };
71
+
72
+ if (!authenticated) {
73
+ result.message = !platformUrl
74
+ ? "Platform URL not configured. Run assistant config set platform.baseUrl <url>"
75
+ : "Assistant API key not found. Store one with: assistant keys set credential/vellum/assistant_api_key <key>";
76
+ }
77
+
78
+ writeOutput(cmd, result);
79
+
80
+ if (!shouldOutputJson(cmd)) {
81
+ log.info(`Platform URL: ${platformUrl || "(not set)"}`);
82
+ log.info(`Assistant ID: ${assistantId || "(not set)"}`);
83
+ log.info(`Organization ID: ${organizationId || "(not set)"}`);
84
+ log.info(`User ID: ${userId || "(not set)"}`);
85
+ log.info(`Authenticated: ${authenticated ? "yes" : "no"}`);
86
+ if (!authenticated && result.message) {
87
+ log.info("");
88
+ log.info(result.message as string);
89
+ }
90
+ }
91
+ });
92
+ }
@@ -38,7 +38,7 @@ The avatar system supports two modes:
38
38
  Files are stored in ~/.vellum/workspace/data/avatar/:
39
39
  character-traits.json Current trait selection (bodyShape, eyeStyle, color)
40
40
  avatar-image.png Rendered PNG of the character
41
- character-ascii.txt ASCII art representation of the character
41
+ character-ascii.txt ASCII art representation (best-effort; may not be written)
42
42
 
43
43
  Examples:
44
44
  $ assistant avatar character update --body-shape blob --eye-style curious --color green
@@ -141,8 +141,8 @@ Examples:
141
141
  .addHelpText(
142
142
  "after",
143
143
  `
144
- Sets the three character traits and regenerates all avatar files (PNG image,
145
- ASCII art, and traits JSON). Each trait value must be a valid ID from the
144
+ Sets the three character traits and regenerates avatar files (PNG image,
145
+ traits JSON, and optionally ASCII art). Each trait value must be a valid ID from the
146
146
  component set — use "assistant avatar character components" to list valid IDs.
147
147
 
148
148
  The --body-shape flag sets the character silhouette. Valid values:
@@ -154,8 +154,9 @@ The --eye-style flag sets the eye expression. Valid values:
154
154
  The --color flag sets the body fill color. Valid values:
155
155
  green, orange, pink, purple, teal, yellow
156
156
 
157
- On success, writes three files to ~/.vellum/workspace/data/avatar/:
158
- character-traits.json, avatar-image.png, character-ascii.txt
157
+ On success, writes character-traits.json and avatar-image.png to
158
+ ~/.vellum/workspace/data/avatar/. character-ascii.txt is written on a
159
+ best-effort basis and may be skipped if ASCII rendering fails.
159
160
 
160
161
  Examples:
161
162
  $ assistant avatar character update --body-shape blob --eye-style curious --color green
@@ -323,7 +324,7 @@ Examples:
323
324
  }
324
325
 
325
326
  const width = parseInt(opts.width, 10);
326
- if (width < 1) {
327
+ if (!Number.isFinite(width) || width < 1) {
327
328
  log.error(
328
329
  `Invalid width: "${opts.width}". Must be a positive integer.`,
329
330
  );
@@ -152,6 +152,7 @@ Examples:
152
152
  if (!path) {
153
153
  const jsonSchema = z.toJSONSchema(AssistantConfigSchema, {
154
154
  unrepresentable: "any",
155
+ io: "input",
155
156
  });
156
157
  log.info(JSON.stringify(jsonSchema, null, 2));
157
158
  return;
@@ -165,6 +166,7 @@ Examples:
165
166
 
166
167
  const jsonSchema = z.toJSONSchema(subSchema, {
167
168
  unrepresentable: "any",
169
+ io: "input",
168
170
  });
169
171
  log.info(JSON.stringify(jsonSchema, null, 2));
170
172
  });
@@ -51,6 +51,11 @@ function parseProviderRow(row: ReturnType<typeof getProvider>) {
51
51
  if (!row) return row;
52
52
  return {
53
53
  ...row,
54
+ displayName: row.displayName ?? null,
55
+ description: row.description ?? null,
56
+ dashboardUrl: row.dashboardUrl ?? null,
57
+ clientIdPlaceholder: row.clientIdPlaceholder ?? null,
58
+ requiresClientSecret: row.requiresClientSecret ?? 1,
54
59
  defaultScopes: row.defaultScopes ? JSON.parse(row.defaultScopes) : [],
55
60
  scopePolicy: row.scopePolicy ? JSON.parse(row.scopePolicy) : {},
56
61
  extraParams: row.extraParams ? JSON.parse(row.extraParams) : null,
@@ -203,6 +208,14 @@ Examples:
203
208
  "--ping-url <url>",
204
209
  "Health-check endpoint URL for token validation",
205
210
  )
211
+ .option("--display-name <name>", "Display name for the provider")
212
+ .option("--description <text>", "Short description")
213
+ .option("--dashboard-url <url>", "Developer console URL")
214
+ .option("--client-id-placeholder <text>", "Placeholder for client ID field")
215
+ .option(
216
+ "--no-client-secret",
217
+ "Set requires_client_secret to false (default is true)",
218
+ )
206
219
  .addHelpText(
207
220
  "after",
208
221
  `
@@ -220,6 +233,12 @@ Arguments (via options):
220
233
  --ping-url Optional URL for a lightweight health-check endpoint.
221
234
  Used by "connections ping" to validate that a stored token
222
235
  is still functional (e.g. "https://api.example.com/user").
236
+ --display-name Optional human-readable display name for the provider.
237
+ --description Optional short description of the provider.
238
+ --dashboard-url Optional URL to the provider's developer console / dashboard.
239
+ --client-id-placeholder Optional placeholder text for the client ID input field.
240
+ --no-client-secret If set, marks the provider as not requiring a client secret
241
+ (sets requires_client_secret to 0). Default is true (1).
223
242
 
224
243
  Registers a new OAuth provider configuration in the local store. This is
225
244
  used for custom integrations not covered by the built-in provider seeds.
@@ -253,6 +272,11 @@ Examples:
253
272
  tokenAuthMethod?: string;
254
273
  callbackTransport?: string;
255
274
  pingUrl?: string;
275
+ displayName?: string;
276
+ description?: string;
277
+ dashboardUrl?: string;
278
+ clientIdPlaceholder?: string;
279
+ clientSecret: boolean;
256
280
  },
257
281
  cmd: Command,
258
282
  ) => {
@@ -268,6 +292,11 @@ Examples:
268
292
  tokenEndpointAuthMethod: opts.tokenAuthMethod,
269
293
  callbackTransport: opts.callbackTransport,
270
294
  pingUrl: opts.pingUrl,
295
+ displayName: opts.displayName,
296
+ description: opts.description,
297
+ dashboardUrl: opts.dashboardUrl,
298
+ clientIdPlaceholder: opts.clientIdPlaceholder,
299
+ requiresClientSecret: opts.clientSecret ? 1 : 0,
271
300
  });
272
301
 
273
302
  writeOutput(cmd, parseProviderRow(row));
@@ -5,6 +5,7 @@ import { isEmailEnabled } from "../email/feature-gate.js";
5
5
  import { registerHooksCommand } from "../hooks/cli.js";
6
6
  import { APP_VERSION } from "../version.js";
7
7
  import { registerAuditCommand } from "./commands/audit.js";
8
+ import { registerAuthCommand } from "./commands/auth.js";
8
9
  import { registerAutonomyCommand } from "./commands/autonomy.js";
9
10
  import { registerAvatarCommand } from "./commands/avatar.js";
10
11
  import { registerBashCommand } from "./commands/bash.js";
@@ -39,6 +40,16 @@ export function buildCliProgram(): Command {
39
40
  .description("Local AI assistant")
40
41
  .version(APP_VERSION);
41
42
 
43
+ program.addHelpText(
44
+ "after",
45
+ `
46
+ Examples:
47
+ $ assistant auth info Show platform identity and auth status
48
+ $ assistant config list List all configuration values
49
+ $ assistant keys list List stored API keys
50
+ $ assistant doctor Run diagnostic checks`,
51
+ );
52
+
42
53
  registerDefaultAction(program);
43
54
  registerBashCommand(program);
44
55
  registerConversationsCommand(program);
@@ -49,6 +60,7 @@ export function buildCliProgram(): Command {
49
60
  registerTrustCommand(program);
50
61
  registerMemoryCommand(program);
51
62
  registerAuditCommand(program);
63
+ registerAuthCommand(program);
52
64
  registerAvatarCommand(program);
53
65
  registerDoctorCommand(program);
54
66
  registerHooksCommand(program);
package/src/cli.ts CHANGED
@@ -17,10 +17,6 @@ import {
17
17
  updateDaemonText,
18
18
  updateStatusText,
19
19
  } from "./cli/main-screen.jsx";
20
- import { loadRawConfig, saveRawConfig } from "./config/loader.js";
21
- import { setServiceField } from "./config/raw-config-utils.js";
22
- import { MODEL_TO_PROVIDER } from "./daemon/conversation-slash.js";
23
- import { getModelInfo } from "./daemon/handlers/config-model.js";
24
20
  import { renderHistoryContent } from "./daemon/handlers/shared.js";
25
21
  import type {
26
22
  ConfirmationRequest,
@@ -1030,7 +1026,7 @@ export async function startCli(): Promise<void> {
1030
1026
  return;
1031
1027
  }
1032
1028
 
1033
- if (content === "/sessions" || content === "/conversations") {
1029
+ if (content === "/conversations") {
1034
1030
  pendingSessionPick = true;
1035
1031
  try {
1036
1032
  const rows = listConversations(20);
@@ -1064,7 +1060,7 @@ export async function startCli(): Promise<void> {
1064
1060
  return;
1065
1061
  }
1066
1062
 
1067
- if (content === "/copy-session" || content === "/copy-conversation") {
1063
+ if (content === "/copy-conversation") {
1068
1064
  try {
1069
1065
  const mapping = getConversationByKey(conversationKey);
1070
1066
  if (!mapping) {
@@ -1133,37 +1129,9 @@ export async function startCli(): Promise<void> {
1133
1129
  }
1134
1130
 
1135
1131
  if (content === "/model" || content.startsWith("/model ")) {
1136
- const modelArg = content.slice("/model".length).trim();
1137
- if (modelArg) {
1138
- try {
1139
- const raw = loadRawConfig();
1140
- const provider = MODEL_TO_PROVIDER[modelArg];
1141
- setServiceField(raw, "inference", "model", modelArg);
1142
- if (provider) setServiceField(raw, "inference", "provider", provider);
1143
- saveRawConfig(raw);
1144
- const existingProvider = (
1145
- raw.services as Record<string, Record<string, unknown>>
1146
- )?.inference?.provider as string | undefined;
1147
- process.stdout.write(
1148
- `\n Model: ${modelArg} (${provider ?? existingProvider})\n\n`,
1149
- );
1150
- } catch {
1151
- process.stdout.write("[Failed to set model]\n");
1152
- }
1153
- } else {
1154
- getModelInfo()
1155
- .then((info) => {
1156
- process.stdout.write(
1157
- `\n Model: ${info.model} (${info.provider})\n\n`,
1158
- );
1159
- prompt();
1160
- })
1161
- .catch(() => {
1162
- process.stdout.write("[Failed to get model info]\n");
1163
- prompt();
1164
- });
1165
- return;
1166
- }
1132
+ process.stdout.write(
1133
+ "\n The /model command has been removed. Use Settings to change your model and provider.\n\n",
1134
+ );
1167
1135
  prompt();
1168
1136
  return;
1169
1137
  }
@@ -1295,27 +1263,26 @@ export async function startCli(): Promise<void> {
1295
1263
 
1296
1264
  if (content === "/help") {
1297
1265
  process.stdout.write("\n Available commands:\n");
1298
- process.stdout.write(" /new Start a new conversation\n");
1266
+ process.stdout.write(" /new Start a new conversation\n");
1299
1267
  process.stdout.write(
1300
- " /conversations Switch between conversations\n",
1268
+ " /conversations Switch between conversations\n",
1301
1269
  );
1302
- process.stdout.write(" /clear Clear the screen\n");
1303
- process.stdout.write(" /model [name] Show or change the model\n");
1304
- process.stdout.write(" /history Show conversation history\n");
1270
+ process.stdout.write(" /clear Clear the screen\n");
1271
+ process.stdout.write(" /history Show conversation history\n");
1305
1272
  process.stdout.write(
1306
- " /undo Remove last message exchange\n",
1273
+ " /undo Remove last message exchange\n",
1307
1274
  );
1308
- process.stdout.write(" /usage Show token usage and cost\n");
1275
+ process.stdout.write(" /usage Show token usage and cost\n");
1309
1276
  process.stdout.write(
1310
- " /copy Copy last response to clipboard\n",
1277
+ " /copy Copy last response to clipboard\n",
1311
1278
  );
1312
1279
  process.stdout.write(
1313
- " /copy-code Copy last code block to clipboard\n",
1280
+ " /copy-code Copy last code block to clipboard\n",
1314
1281
  );
1315
1282
  process.stdout.write(
1316
- " /copy-conversation Copy entire conversation to clipboard\n",
1283
+ " /copy-conversation Copy entire conversation to clipboard\n",
1317
1284
  );
1318
- process.stdout.write(" /help Show this help\n");
1285
+ process.stdout.write(" /help Show this help\n");
1319
1286
  process.stdout.write("\n");
1320
1287
  prompt();
1321
1288
  return;
@@ -18,6 +18,40 @@ You are an expert app builder and visual designer. When the user asks you to cre
18
18
 
19
19
  **Design quality is delegated to the `frontend-design` skill.** That skill defines your aesthetic principles: typography, color strategy, motion, spatial composition, and visual detail. Follow it completely for every build. This skill (app-builder) handles the technical infrastructure: sandbox constraints, data bridge, widget API, app lifecycle, and interaction patterns.
20
20
 
21
+ ## Filesystem Layout
22
+
23
+ Apps live under `~/.vellum/workspace/data/apps/`. Each app has a slug-based layout:
24
+
25
+ ```
26
+ ~/.vellum/workspace/data/apps/
27
+ <slug>.json # App metadata
28
+ <slug>/ # App directory (contains all app files)
29
+ index.html # Main page (entry point rendered in WebView)
30
+ pages/ # Additional pages
31
+ records/ # Data records (one JSON file per record)
32
+ src/ # Source files (multifile TSX apps, formatVersion: 2)
33
+ dist/ # Compiled output (multifile TSX apps)
34
+ <slug>.preview # Preview image (auto-generated)
35
+ ```
36
+
37
+ ### Metadata JSON (`<slug>.json`)
38
+
39
+ Fields: `id`, `name`, `description`, `icon`, `schemaJson`, `createdAt`, `updatedAt`, `formatVersion`, `dirName`.
40
+
41
+ **Important:** `htmlDefinition` and `pages` are NOT stored in the metadata JSON — they live as separate files inside the app directory (`index.html` and `pages/`).
42
+
43
+ ### Records
44
+
45
+ Each record is a JSON file at `<slug>/records/<uuid>.json` with shape:
46
+
47
+ ```json
48
+ { "id": "<uuid>", "appId": "<app-id>", "data": { ... }, "createdAt": "...", "updatedAt": "..." }
49
+ ```
50
+
51
+ ### Multifile TSX Apps
52
+
53
+ For `formatVersion: 2` apps, source files live under `src/` and compiled output under `dist/`. The build system compiles TSX → JS automatically when `app_refresh` is called.
54
+
21
55
  ## Workflow
22
56
 
23
57
  ### 1. Gather Requirements
@@ -44,7 +78,7 @@ You are an expert app builder and visual designer. When the user asks you to cre
44
78
 
45
79
  **Only ask questions when the request is genuinely ambiguous** - e.g., "build me an app" with no indication of what kind. Even then, prefer building something impressive based on context clues over asking a battery of questions.
46
80
 
47
- **When in doubt, build something impressive** and let the user refine with `app_update`. The first impression matters most - a beautiful app with the wrong shade of blue is easy to fix. A correct but ugly app is hard to come back from.
81
+ **When in doubt, build something impressive** and let the user refine. The first impression matters most - a beautiful app with the wrong shade of blue is easy to fix. A correct but ugly app is hard to come back from.
48
82
 
49
83
  **There are no "quick" builds.** Every app, regardless of complexity, gets the full design treatment. A 3-field form and a 20-section dashboard get the same design care. The only difference is scope, not quality.
50
84
 
@@ -149,27 +183,27 @@ useEffect(() => {
149
183
  }, []);
150
184
  ```
151
185
 
152
- **File workflow:** Use `app_file_write` for each source file. Each write automatically triggers a recompile of the project.
186
+ **File workflow:** Use `file_write` for each source file. After writing all files, call `app_refresh` once to compile and refresh the UI.
153
187
 
154
188
  **Allowed third-party packages:** `date-fns`, `chart.js`, `lodash-es`, `zod`, `clsx`, `lucide`. Import them directly - esbuild resolves them at build time. No CDN imports. Note: `lucide` is the vanilla JS icon library (not `lucide-react`). Use its `createElement` or `createIcons` API, or manually inline SVG - do not import JSX icon components.
155
189
 
156
- **Example - creating a multi-file project:**
190
+ **Example - creating a multi-file project** (assuming app slug is `project-tracker`):
157
191
 
158
192
  ```
159
- app_file_write(app_id, "src/index.html", `<!DOCTYPE html>
193
+ file_write("~/.vellum/workspace/data/apps/project-tracker/src/index.html", `<!DOCTYPE html>
160
194
  <html lang="en">
161
195
  <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
162
196
  <title>Project Tracker</title></head>
163
197
  <body><div id="app"></div></body>
164
198
  </html>`)
165
199
 
166
- app_file_write(app_id, "src/main.tsx", `import { render } from 'preact';
200
+ file_write("~/.vellum/workspace/data/apps/project-tracker/src/main.tsx", `import { render } from 'preact';
167
201
  import { App } from './components/App';
168
202
  import './styles.css';
169
203
 
170
204
  render(<App />, document.getElementById('app')!);`)
171
205
 
172
- app_file_write(app_id, "src/components/App.tsx", `import { FunctionComponent } from 'preact';
206
+ file_write("~/.vellum/workspace/data/apps/project-tracker/src/components/App.tsx", `import { FunctionComponent } from 'preact';
173
207
  import { useState, useEffect } from 'preact/hooks';
174
208
  import { Header } from './Header';
175
209
 
@@ -188,7 +222,7 @@ export const App: FunctionComponent = () => {
188
222
  );
189
223
  };`)
190
224
 
191
- app_file_write(app_id, "src/components/Header.tsx", `import { FunctionComponent } from 'preact';
225
+ file_write("~/.vellum/workspace/data/apps/project-tracker/src/components/Header.tsx", `import { FunctionComponent } from 'preact';
192
226
 
193
227
  interface HeaderProps {
194
228
  title: string;
@@ -202,9 +236,12 @@ export const Header: FunctionComponent<HeaderProps> = ({ title, count }) => (
202
236
  </header>
203
237
  );`)
204
238
 
205
- app_file_write(app_id, "src/styles.css", `.app { padding: var(--v-spacing-lg); }
239
+ file_write("~/.vellum/workspace/data/apps/project-tracker/src/styles.css", `.app { padding: var(--v-spacing-lg); }
206
240
  .header { display: flex; justify-content: space-between; align-items: center; }
207
241
  .badge { background: var(--v-accent); color: white; padding: var(--v-spacing-xs) var(--v-spacing-sm); border-radius: var(--v-radius-pill); }`)
242
+
243
+ # After all files are written, compile and refresh:
244
+ app_refresh(app_id)
208
245
  ```
209
246
 
210
247
  **Technical constraints (multi-file):**
@@ -317,8 +354,6 @@ A CSS/JS widget library is auto-injected alongside the design system. Use these
317
354
  | `.v-gradient-text` | Accent-colored gradient text |
318
355
  | `.v-animate-in` | Staggered fade-in for children |
319
356
 
320
- **Slideshow** (`.v-slideshow`): Presentation slide deck with transitions. Init with `vellum.widgets.slideshow()`. Slide helpers: `.v-slide`, `.v-slide-label`, `.v-slide-title`, `.v-slide-body`, `.v-slide-stats`, `.v-slide-stat`, `.v-slide-quote`, `.v-slide-list`, `.v-slide-columns`.
321
-
322
357
  #### Widget JavaScript utilities
323
358
 
324
359
  Interactive utilities at `window.vellum.widgets.*`:
@@ -384,19 +419,11 @@ vellum.widgets.toast("Saved!", "success", 4000); // Auto-dismiss notification
384
419
  vellum.widgets.countdown("timer-el", "2025-12-31T00:00:00Z", {
385
420
  onComplete: () => {},
386
421
  });
387
- vellum.widgets.slideshow("deck", {
388
- transition: "fade",
389
- showDots: true,
390
- showArrows: true,
391
- showCounter: true,
392
- keyboard: true,
393
- loop: true,
394
- });
395
422
  ```
396
423
 
397
424
  #### When to use widgets vs custom HTML
398
425
 
399
- - **Use widgets** for standard patterns - tables, metrics, timelines, notifications, presentations
426
+ - **Use widgets** for standard patterns - tables, metrics, timelines, notifications
400
427
  - **Use custom HTML** for novel or creative UIs - games, art tools, unique dashboards
401
428
  - **Mix freely** - widgets compose well together and with custom elements
402
429
  - **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts. They handle overflow clipping, bounds, scaling, and dark mode. Hand-coded charts break layouts.
@@ -490,7 +517,7 @@ Call `app_create` with:
490
517
  - `name`: Short descriptive name
491
518
  - `description`: One-sentence summary
492
519
  - `schema_json`: JSON schema as string
493
- - `html`: (optional) Complete HTML document as string for `index.html`. If omitted, a minimal scaffold is created - you can then write `index.html` and other files via `app_file_write`.
520
+ - `html`: (optional) Complete HTML document as string for `index.html`. If omitted, a minimal scaffold is created - you can then write `index.html` and other files via `file_write`.
494
521
  - `auto_open`: (optional, defaults to `true`) Shows an inline preview card in chat
495
522
  - `preview`: Always include - `title` (required), `subtitle`, `description`, `icon` (image URL preferred, emoji fallback), `metrics` (up to 3 key-value pills)
496
523
 
@@ -503,12 +530,14 @@ The app is NOT opened in a workspace panel automatically - users open it via the
503
530
  ### 6. Handle Iteration
504
531
  <!-- feature:app-builder-multifile:alt:end -->
505
532
 
506
- When the user requests changes, prefer **`app_file_edit`** over rewriting the entire file.
533
+ When the user requests changes, prefer **`file_edit`** over rewriting the entire file.
507
534
 
508
- - **`app_file_edit`** - preferred for targeted changes (styles, bugs, features). Provide `app_id`, `path`, `old_string`, `new_string`.
509
- - **`app_file_write`** - use when creating new files or when changes are so extensive a full rewrite is cleaner.
510
- - **`app_update`** - metadata only: `name`, `description`, `schema_json`. Not for code changes.
511
- - Always include a **`status`** parameter describing what you're doing.
535
+ - **`file_edit`** - preferred for targeted changes (styles, bugs, features). Provide the full file path (e.g. `~/.vellum/workspace/data/apps/<slug>/src/components/App.tsx`).
536
+ - **`file_write`** - for creating new files or full rewrites.
537
+ - **`app_refresh`** - call ONCE after all file changes are complete to trigger compilation and surface refresh.
538
+ - For metadata changes (`name`, `description`, `schemaJson`, etc.), edit the `<slug>.json` file directly with `file_edit`, then call `app_refresh`.
539
+
540
+ After making all file changes, call `app_refresh(app_id)` once to compile and refresh the UI. Do NOT call it after every individual file edit — batch your changes first.
512
541
 
513
542
  Apps can have multiple files (`styles.css`, `app.js`, etc.). Link from `index.html` with standard tags.
514
543
 
@@ -524,7 +553,7 @@ Every app must meet these baselines:
524
553
 
525
554
  ## Presentation Slide Design
526
555
 
527
- Slides are a different domain from apps. Skip app-specific patterns (contextual headers, search/filter, toast notifications, form validation, data bridge). Slides are static content.
556
+ Slides are a different domain from apps. Skip app-specific patterns (contextual headers, search/filter, toast notifications, form validation, data bridge). Slides are static content — build navigation and layouts with custom HTML/CSS.
528
557
 
529
558
  **Key principles:**
530
559
 
@@ -535,8 +564,6 @@ Slides are a different domain from apps. Skip app-specific patterns (contextual
535
564
  - Max 6 bullets per slide, max 3 sentences body text
536
565
  - Never go below 15px for any visible text
537
566
 
538
- Init with `vellum.widgets.slideshow()`. Use `.v-slide` with helpers: `.v-slide-label`, `.v-slide-title`, `.v-slide-body`, `.v-slide-stats`, `.v-slide-stat`, `.v-slide-quote`, `.v-slide-list`, `.v-slide-columns`.
539
-
540
567
  ## Error Handling
541
568
 
542
569
  - All `window.vellum.data` calls must be wrapped in `try/catch` with user-friendly feedback.
@@ -544,6 +571,54 @@ Init with `vellum.widgets.slideshow()`. Use `.v-slide` with helpers: `.v-slide-l
544
571
  - If the page loads with no data, show a designed empty state (`.v-empty-state`).
545
572
  - For forms, show validation errors inline next to the relevant field.
546
573
 
574
+ ## App Interaction Hooks
575
+
576
+ When building apps, proactively wire `sendAction` hooks so the assistant stays aware of meaningful user interactions. Two patterns are available:
577
+
578
+ ### Reactive hooks
579
+
580
+ Reactive hooks trigger an assistant response. Use them for moments where the assistant's input adds value - selections that need explanation, completions worth celebrating, or submissions that benefit from feedback.
581
+
582
+ ```javascript
583
+ // User selects a city on a map — assistant can provide insights
584
+ window.vellum.sendAction('city_selected', { city: 'Tokyo' });
585
+
586
+ // User submits a form — assistant can confirm and suggest next steps
587
+ window.vellum.sendAction('form_submitted', { formId: 'signup', email: 'user@example.com' });
588
+
589
+ // User completes a level — assistant can congratulate and hint at what's next
590
+ window.vellum.sendAction('level_complete', { level: 5, score: 2400 });
591
+ ```
592
+
593
+ ### Silent hooks
594
+
595
+ Silent hooks accumulate state without interrupting the user. The state is automatically included as context when the next reactive hook fires.
596
+
597
+ ```javascript
598
+ // User navigates to a new tab — no response needed, but assistant should know
599
+ window.vellum.sendAction('state_update', { currentView: 'forecast', city: 'Tokyo' });
600
+
601
+ // Score changes during gameplay — track silently
602
+ window.vellum.sendAction('state_update', { score: 1250, lives: 2 });
603
+
604
+ // User applies a filter — context for future questions
605
+ window.vellum.sendAction('state_update', { filter: 'last-30-days', sortBy: 'revenue' });
606
+ ```
607
+
608
+ ### When to use reactive vs silent
609
+
610
+ Choose based on whether the assistant's response would genuinely help the user at that moment:
611
+
612
+ | App type | Silent (state accumulation) | Reactive (triggers response) |
613
+ |---|---|---|
614
+ | **Dashboards** | Tab navigation, filter changes, date range selection | Anomaly detected, threshold breached, data export complete |
615
+ | **Games** | Score updates, move tracking, timer ticks | Level complete, achievement unlocked, game over |
616
+ | **Forms & wizards** | Field focus, partial input, step navigation | Form submitted, validation failed on submit |
617
+ | **Trackers** | Incremental progress, status toggles, reordering | Milestone reached, streak achieved, all items complete |
618
+ | **Data explorers** | Sorting, paging, column toggling | Row selected for detail, comparison initiated |
619
+
620
+ Wire hooks during the initial build - don't wait for the user to ask. Apps that communicate state back to the assistant feel alive; apps that don't feel like static pages.
621
+
547
622
  ## Actionable UI
548
623
 
549
624
  When the user wants to triage or bulk-act on items, generate an interactive UI with selectable items and action buttons.