@vellumai/assistant 0.3.5 → 0.3.7

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 (487) hide show
  1. package/README.md +51 -0
  2. package/eslint.config.mjs +31 -0
  3. package/package.json +1 -1
  4. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  5. package/scripts/ipc/generate-swift.ts +18 -2
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
  7. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  8. package/src/__tests__/browser-manager.test.ts +1 -0
  9. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  10. package/src/__tests__/call-orchestrator.test.ts +752 -271
  11. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  12. package/src/__tests__/call-recovery.test.ts +3 -0
  13. package/src/__tests__/call-routes-http.test.ts +5 -0
  14. package/src/__tests__/call-store.test.ts +3 -0
  15. package/src/__tests__/channel-approval-routes.test.ts +1260 -85
  16. package/src/__tests__/channel-approval.test.ts +37 -0
  17. package/src/__tests__/channel-approvals.test.ts +4 -65
  18. package/src/__tests__/channel-guardian.test.ts +556 -0
  19. package/src/__tests__/channel-readiness-service.test.ts +74 -7
  20. package/src/__tests__/checker.test.ts +14 -7
  21. package/src/__tests__/clarification-resolver.test.ts +44 -24
  22. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  23. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  24. package/src/__tests__/config-schema.test.ts +12 -7
  25. package/src/__tests__/context-window-manager.test.ts +30 -2
  26. package/src/__tests__/contradiction-checker.test.ts +20 -5
  27. package/src/__tests__/credential-security-invariants.test.ts +6 -2
  28. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  29. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  30. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  31. package/src/__tests__/guardian-action-store.test.ts +123 -0
  32. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  33. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  34. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  35. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  36. package/src/__tests__/handlers-twilio-config.test.ts +126 -0
  37. package/src/__tests__/intent-routing.test.ts +2 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +228 -1
  39. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  40. package/src/__tests__/model-intents.test.ts +96 -0
  41. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  42. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  43. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  44. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  45. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  46. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  47. package/src/__tests__/qdrant-manager.test.ts +27 -20
  48. package/src/__tests__/relay-server.test.ts +779 -40
  49. package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
  50. package/src/__tests__/run-orchestrator.test.ts +20 -4
  51. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  52. package/src/__tests__/runtime-runs.test.ts +16 -0
  53. package/src/__tests__/schedule-store.test.ts +18 -4
  54. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  55. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  56. package/src/__tests__/session-agent-loop.test.ts +857 -0
  57. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  58. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  59. package/src/__tests__/session-profile-injection.test.ts +6 -0
  60. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  61. package/src/__tests__/session-queue.test.ts +6 -0
  62. package/src/__tests__/session-runtime-assembly.test.ts +237 -13
  63. package/src/__tests__/session-slash-known.test.ts +6 -0
  64. package/src/__tests__/session-slash-queue.test.ts +6 -0
  65. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  66. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  67. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  68. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  69. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  70. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  71. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  72. package/src/__tests__/skills.test.ts +2 -0
  73. package/src/__tests__/sms-messaging-provider.test.ts +2 -1
  74. package/src/__tests__/starter-task-flow.test.ts +2 -0
  75. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  76. package/src/__tests__/system-prompt.test.ts +2 -0
  77. package/src/__tests__/task-management-tools.test.ts +2 -2
  78. package/src/__tests__/task-runner.test.ts +14 -4
  79. package/src/__tests__/terminal-tools.test.ts +25 -19
  80. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  81. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  82. package/src/__tests__/tool-executor.test.ts +23 -24
  83. package/src/__tests__/trust-store.test.ts +3 -3
  84. package/src/__tests__/twilio-rest.test.ts +29 -0
  85. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  86. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  87. package/src/__tests__/twilio-routes.test.ts +141 -21
  88. package/src/__tests__/user-reference.test.ts +2 -0
  89. package/src/__tests__/voice-quality.test.ts +222 -0
  90. package/src/__tests__/web-search.test.ts +45 -29
  91. package/src/agent/loop.ts +1 -1
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  93. package/src/amazon/client.ts +1418 -0
  94. package/src/amazon/request-extractor.ts +135 -0
  95. package/src/amazon/session.ts +109 -0
  96. package/src/autonomy/autonomy-store.ts +5 -5
  97. package/src/browser-extension-relay/client.ts +124 -0
  98. package/src/browser-extension-relay/protocol.ts +63 -0
  99. package/src/browser-extension-relay/server.ts +177 -0
  100. package/src/bundler/app-bundler.ts +3 -3
  101. package/src/bundler/bundle-signer.ts +1 -1
  102. package/src/bundler/signature-verifier.ts +1 -1
  103. package/src/calls/call-conversation-messages.ts +33 -0
  104. package/src/calls/call-domain.ts +106 -5
  105. package/src/calls/call-orchestrator.ts +252 -54
  106. package/src/calls/call-pointer-messages.ts +53 -0
  107. package/src/calls/call-recovery.ts +3 -8
  108. package/src/calls/call-store.ts +69 -87
  109. package/src/calls/elevenlabs-config.ts +3 -2
  110. package/src/calls/guardian-action-sweep.ts +105 -0
  111. package/src/calls/guardian-dispatch.ts +203 -0
  112. package/src/calls/guardian-question-copy.ts +133 -0
  113. package/src/calls/relay-server.ts +466 -8
  114. package/src/calls/speaker-identification.ts +1 -1
  115. package/src/calls/twilio-config.ts +7 -5
  116. package/src/calls/twilio-provider.ts +6 -4
  117. package/src/calls/twilio-rest.ts +40 -15
  118. package/src/calls/twilio-routes.ts +60 -45
  119. package/src/calls/types.ts +3 -1
  120. package/src/channels/types.ts +25 -0
  121. package/src/cli/amazon.ts +815 -0
  122. package/src/cli/config-commands.ts +2 -2
  123. package/src/cli/core-commands.ts +4 -3
  124. package/src/cli/influencer.ts +244 -0
  125. package/src/cli/map.ts +89 -6
  126. package/src/cli.ts +1 -1
  127. package/src/config/agent-schema.ts +171 -0
  128. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  129. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  130. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  131. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  132. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  133. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  134. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  135. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  136. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  137. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  138. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  139. package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
  140. package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
  141. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  142. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  143. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  144. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  145. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  146. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  147. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  148. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
  149. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  150. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
  151. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
  152. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  153. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
  154. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
  155. package/src/config/bundled-skills/messaging/SKILL.md +12 -2
  156. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  157. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  158. package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
  159. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  160. package/src/config/bundled-tool-registry.ts +310 -0
  161. package/src/config/calls-schema.ts +181 -0
  162. package/src/config/core-schema.ts +309 -0
  163. package/src/config/defaults.ts +27 -3
  164. package/src/config/env-registry.ts +169 -0
  165. package/src/config/env.ts +175 -0
  166. package/src/config/loader.ts +6 -6
  167. package/src/config/memory-schema.ts +528 -0
  168. package/src/config/sandbox-schema.ts +55 -0
  169. package/src/config/schema.ts +157 -1138
  170. package/src/config/skill-state.ts +1 -1
  171. package/src/config/skills-schema.ts +32 -0
  172. package/src/config/skills.ts +35 -24
  173. package/src/config/system-prompt.ts +107 -56
  174. package/src/config/templates/SOUL.md +1 -1
  175. package/src/config/types.ts +1 -0
  176. package/src/config/user-reference.ts +4 -9
  177. package/src/config/vellum-skills/catalog.json +0 -7
  178. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  179. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
  180. package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
  181. package/src/context/window-manager.ts +27 -7
  182. package/src/daemon/approval-generators.ts +186 -0
  183. package/src/daemon/approved-devices-store.ts +140 -0
  184. package/src/daemon/assistant-attachments.ts +1 -1
  185. package/src/daemon/classifier.ts +35 -32
  186. package/src/daemon/config-watcher.ts +1 -1
  187. package/src/daemon/daemon-control.ts +254 -0
  188. package/src/daemon/handlers/apps.ts +2 -3
  189. package/src/daemon/handlers/config-channels.ts +158 -0
  190. package/src/daemon/handlers/config-inbox.ts +540 -0
  191. package/src/daemon/handlers/config-ingress.ts +231 -0
  192. package/src/daemon/handlers/config-integrations.ts +258 -0
  193. package/src/daemon/handlers/config-model.ts +143 -0
  194. package/src/daemon/handlers/config-parental.ts +163 -0
  195. package/src/daemon/handlers/config-scheduling.ts +172 -0
  196. package/src/daemon/handlers/config-slack.ts +92 -0
  197. package/src/daemon/handlers/config-telegram.ts +301 -0
  198. package/src/daemon/handlers/config-tools.ts +177 -0
  199. package/src/daemon/handlers/config-trust.ts +104 -0
  200. package/src/daemon/handlers/config-twilio.ts +1080 -0
  201. package/src/daemon/handlers/config.ts +53 -2463
  202. package/src/daemon/handlers/diagnostics.ts +1 -1
  203. package/src/daemon/handlers/dictation.ts +4 -6
  204. package/src/daemon/handlers/documents.ts +18 -32
  205. package/src/daemon/handlers/index.ts +9 -0
  206. package/src/daemon/handlers/misc.ts +3 -5
  207. package/src/daemon/handlers/pairing.ts +98 -0
  208. package/src/daemon/handlers/sessions.ts +74 -5
  209. package/src/daemon/handlers/shared.ts +3 -1
  210. package/src/daemon/handlers/skills.ts +1 -1
  211. package/src/daemon/handlers/twitter-auth.ts +2 -0
  212. package/src/daemon/handlers/work-items.ts +2 -2
  213. package/src/daemon/handlers/workspace-files.ts +4 -3
  214. package/src/daemon/install-cli-launchers.ts +113 -0
  215. package/src/daemon/ipc-contract/apps.ts +356 -0
  216. package/src/daemon/ipc-contract/browser.ts +74 -0
  217. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  218. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  219. package/src/daemon/ipc-contract/documents.ts +74 -0
  220. package/src/daemon/ipc-contract/inbox.ts +209 -0
  221. package/src/daemon/ipc-contract/integrations.ts +284 -0
  222. package/src/daemon/ipc-contract/memory.ts +48 -0
  223. package/src/daemon/ipc-contract/messages.ts +211 -0
  224. package/src/daemon/ipc-contract/pairing.ts +45 -0
  225. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  226. package/src/daemon/ipc-contract/schedules.ts +97 -0
  227. package/src/daemon/ipc-contract/sessions.ts +321 -0
  228. package/src/daemon/ipc-contract/shared.ts +42 -0
  229. package/src/daemon/ipc-contract/skills.ts +120 -0
  230. package/src/daemon/ipc-contract/subagents.ts +58 -0
  231. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  232. package/src/daemon/ipc-contract/trust.ts +60 -0
  233. package/src/daemon/ipc-contract/work-items.ts +225 -0
  234. package/src/daemon/ipc-contract/workspace.ts +113 -0
  235. package/src/daemon/ipc-contract-inventory.json +62 -0
  236. package/src/daemon/ipc-contract-inventory.ts +55 -29
  237. package/src/daemon/ipc-contract.ts +227 -2527
  238. package/src/daemon/ipc-protocol.ts +1 -1
  239. package/src/daemon/ipc-validate.ts +7 -0
  240. package/src/daemon/lifecycle.ts +97 -379
  241. package/src/daemon/pairing-store.ts +177 -0
  242. package/src/daemon/providers-setup.ts +43 -0
  243. package/src/daemon/ride-shotgun-handler.ts +67 -2
  244. package/src/daemon/server.ts +60 -44
  245. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  246. package/src/daemon/session-agent-loop.ts +113 -275
  247. package/src/daemon/session-dynamic-profile.ts +1 -1
  248. package/src/daemon/session-history.ts +1 -1
  249. package/src/daemon/session-media-retry.ts +1 -1
  250. package/src/daemon/session-messaging.ts +37 -2
  251. package/src/daemon/session-notifiers.ts +5 -25
  252. package/src/daemon/session-process.ts +99 -59
  253. package/src/daemon/session-queue-manager.ts +98 -4
  254. package/src/daemon/session-runtime-assembly.ts +149 -15
  255. package/src/daemon/session-surfaces.ts +26 -4
  256. package/src/daemon/session-tool-setup.ts +28 -30
  257. package/src/daemon/session-workspace.ts +1 -1
  258. package/src/daemon/session.ts +24 -1
  259. package/src/daemon/shutdown-handlers.ts +122 -0
  260. package/src/daemon/trace-emitter.ts +1 -1
  261. package/src/daemon/watch-handler.ts +36 -33
  262. package/src/doordash/cart-queries.ts +787 -0
  263. package/src/doordash/client.ts +144 -127
  264. package/src/doordash/order-queries.ts +85 -0
  265. package/src/doordash/queries.ts +10 -1308
  266. package/src/doordash/search-queries.ts +203 -0
  267. package/src/doordash/session.ts +3 -2
  268. package/src/doordash/store-queries.ts +246 -0
  269. package/src/doordash/types.ts +367 -0
  270. package/src/email/providers/agentmail.ts +2 -1
  271. package/src/email/providers/index.ts +3 -2
  272. package/src/email/service.ts +3 -2
  273. package/src/errors.ts +43 -0
  274. package/src/home-base/prebuilt/seed.ts +1 -1
  275. package/src/hooks/cli.ts +6 -5
  276. package/src/hooks/config.ts +6 -8
  277. package/src/hooks/discovery.ts +6 -5
  278. package/src/hooks/manager.ts +4 -3
  279. package/src/hooks/runner.ts +2 -2
  280. package/src/hooks/templates.ts +5 -5
  281. package/src/inbound/public-ingress-urls.ts +3 -1
  282. package/src/index.ts +4 -2
  283. package/src/influencer/client.ts +1104 -0
  284. package/src/instrument.ts +4 -3
  285. package/src/logfire.ts +4 -3
  286. package/src/memory/admin.ts +25 -35
  287. package/src/memory/attachments-store.ts +4 -7
  288. package/src/memory/channel-delivery-store.ts +30 -1
  289. package/src/memory/channel-guardian-store.ts +200 -1
  290. package/src/memory/clarification-resolver.ts +37 -33
  291. package/src/memory/conflict-store.ts +67 -61
  292. package/src/memory/contradiction-checker.ts +141 -117
  293. package/src/memory/conversation-store.ts +335 -51
  294. package/src/memory/db-connection.ts +27 -4
  295. package/src/memory/db-init.ts +121 -4
  296. package/src/memory/db.ts +14 -1
  297. package/src/memory/embedding-backend.ts +27 -5
  298. package/src/memory/embedding-ollama.ts +2 -1
  299. package/src/memory/entity-extractor.ts +38 -35
  300. package/src/memory/guardian-action-store.ts +430 -0
  301. package/src/memory/inbox-escalation-projection.ts +59 -0
  302. package/src/memory/inbox-thread-store.ts +218 -0
  303. package/src/memory/ingress-invite-store.ts +338 -0
  304. package/src/memory/ingress-member-store.ts +350 -0
  305. package/src/memory/items-extractor.ts +91 -97
  306. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  307. package/src/memory/job-handlers/media-processing.ts +11 -42
  308. package/src/memory/job-handlers/summarization.ts +32 -26
  309. package/src/memory/job-utils.ts +3 -10
  310. package/src/memory/jobs-store.ts +6 -9
  311. package/src/memory/jobs-worker.ts +51 -36
  312. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  313. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  314. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  315. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  316. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  317. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  318. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  319. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  320. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  321. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  322. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  323. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  324. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  325. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  326. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  327. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  328. package/src/memory/migrations/017-memory-items-indexes.ts +12 -0
  329. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  330. package/src/memory/migrations/index.ts +24 -0
  331. package/src/memory/migrations/registry.ts +79 -0
  332. package/src/memory/migrations/validate-migration-state.ts +69 -0
  333. package/src/memory/qdrant-manager.ts +49 -8
  334. package/src/memory/query-builder.ts +1 -1
  335. package/src/memory/raw-query.ts +119 -0
  336. package/src/memory/recall-cache.ts +4 -1
  337. package/src/memory/retriever.ts +163 -47
  338. package/src/memory/schema-migration.ts +25 -984
  339. package/src/memory/schema.ts +130 -7
  340. package/src/memory/search/entity.ts +10 -19
  341. package/src/memory/search/lexical.ts +81 -52
  342. package/src/memory/search/ranking.ts +21 -22
  343. package/src/memory/search/semantic.ts +157 -19
  344. package/src/memory/shared-app-links-store.ts +4 -5
  345. package/src/memory/validation.ts +19 -0
  346. package/src/messaging/draft-store.ts +5 -6
  347. package/src/messaging/providers/sms/adapter.ts +3 -6
  348. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  349. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  350. package/src/messaging/providers/whatsapp/client.ts +67 -0
  351. package/src/messaging/style-analyzer.ts +5 -4
  352. package/src/messaging/thread-summarizer.ts +61 -69
  353. package/src/messaging/triage-engine.ts +62 -71
  354. package/src/migrations/config-merge.ts +53 -0
  355. package/src/migrations/data-layout.ts +68 -0
  356. package/src/migrations/data-merge.ts +33 -0
  357. package/src/migrations/hooks-merge.ts +90 -0
  358. package/src/migrations/index.ts +6 -0
  359. package/src/migrations/log.ts +23 -0
  360. package/src/migrations/skills-merge.ts +33 -0
  361. package/src/migrations/workspace-layout.ts +79 -0
  362. package/src/permissions/checker.ts +126 -11
  363. package/src/permissions/prompter.ts +14 -0
  364. package/src/permissions/shell-identity.ts +31 -1
  365. package/src/permissions/trust-store.ts +21 -1
  366. package/src/providers/anthropic/client.ts +4 -4
  367. package/src/providers/failover.ts +2 -2
  368. package/src/providers/model-intents.ts +70 -0
  369. package/src/providers/ollama/client.ts +2 -1
  370. package/src/providers/provider-send-message.ts +176 -0
  371. package/src/providers/registry.ts +71 -30
  372. package/src/providers/retry.ts +35 -1
  373. package/src/providers/types.ts +12 -1
  374. package/src/runtime/approval-conversation-turn.ts +97 -0
  375. package/src/runtime/approval-message-composer.ts +115 -5
  376. package/src/runtime/assistant-event-hub.ts +3 -1
  377. package/src/runtime/channel-approval-parser.ts +36 -2
  378. package/src/runtime/channel-approvals.ts +0 -21
  379. package/src/runtime/channel-guardian-service.ts +48 -7
  380. package/src/runtime/channel-readiness-service.ts +160 -34
  381. package/src/runtime/channel-readiness-types.ts +10 -4
  382. package/src/runtime/channel-retry-sweep.ts +184 -0
  383. package/src/runtime/guardian-context-resolver.ts +108 -0
  384. package/src/runtime/http-server.ts +289 -745
  385. package/src/runtime/http-types.ts +56 -3
  386. package/src/runtime/middleware/auth.ts +116 -0
  387. package/src/runtime/middleware/error-handler.ts +33 -0
  388. package/src/runtime/middleware/twilio-validation.ts +127 -0
  389. package/src/runtime/routes/app-routes.ts +1 -1
  390. package/src/runtime/routes/call-routes.ts +49 -6
  391. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  392. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  393. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  394. package/src/runtime/routes/channel-route-shared.ts +144 -0
  395. package/src/runtime/routes/channel-routes.ts +32 -1634
  396. package/src/runtime/routes/conversation-routes.ts +50 -7
  397. package/src/runtime/routes/events-routes.ts +2 -2
  398. package/src/runtime/routes/identity-routes.ts +126 -0
  399. package/src/runtime/routes/pairing-routes.ts +144 -0
  400. package/src/runtime/routes/run-routes.ts +15 -1
  401. package/src/runtime/run-orchestrator.ts +52 -34
  402. package/src/schedule/schedule-store.ts +36 -32
  403. package/src/schedule/scheduler.ts +3 -3
  404. package/src/security/encrypted-store.ts +5 -7
  405. package/src/security/oauth2.ts +45 -15
  406. package/src/security/parental-control-store.ts +183 -0
  407. package/src/security/secret-allowlist.ts +4 -3
  408. package/src/security/secret-scanner.ts +5 -5
  409. package/src/security/secure-keys.ts +1 -1
  410. package/src/security/token-manager.ts +3 -2
  411. package/src/services/vercel-deploy.ts +6 -2
  412. package/src/skills/tool-manifest.ts +3 -3
  413. package/src/skills/vellum-catalog-remote.ts +75 -16
  414. package/src/slack/slack-webhook.ts +2 -1
  415. package/src/swarm/orchestrator.ts +92 -1
  416. package/src/swarm/router-planner.ts +6 -9
  417. package/src/swarm/worker-prompts.ts +9 -12
  418. package/src/tasks/task-compiler.ts +19 -28
  419. package/src/tasks/task-runner.ts +1 -1
  420. package/src/tools/assets/search.ts +15 -14
  421. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  422. package/src/tools/browser/auto-navigate.ts +1 -0
  423. package/src/tools/browser/browser-execution.ts +13 -1
  424. package/src/tools/browser/browser-manager.ts +119 -4
  425. package/src/tools/browser/network-recorder.ts +5 -0
  426. package/src/tools/credentials/broker.ts +11 -2
  427. package/src/tools/credentials/metadata-store.ts +18 -14
  428. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  429. package/src/tools/credentials/vault.ts +49 -23
  430. package/src/tools/executor.ts +80 -18
  431. package/src/tools/host-terminal/cli-discover.ts +1 -1
  432. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  433. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  434. package/src/tools/network/script-proxy/server.ts +1 -1
  435. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  436. package/src/tools/network/web-fetch.ts +18 -2
  437. package/src/tools/network/web-search.ts +7 -3
  438. package/src/tools/reminder/reminder-store.ts +14 -15
  439. package/src/tools/schedule/create.ts +1 -0
  440. package/src/tools/schedule/list.ts +2 -1
  441. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  442. package/src/tools/skills/skill-script-runner.ts +24 -9
  443. package/src/tools/skills/skill-tool-factory.ts +1 -0
  444. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  445. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  446. package/src/tools/terminal/parser.ts +50 -0
  447. package/src/tools/watcher/delete.ts +6 -0
  448. package/src/tools/weather/service.ts +1 -1
  449. package/src/twitter/client.ts +190 -24
  450. package/src/twitter/session.ts +4 -3
  451. package/src/util/clipboard.ts +1 -1
  452. package/src/util/errors.ts +65 -8
  453. package/src/util/fs.ts +40 -0
  454. package/src/util/json.ts +10 -0
  455. package/src/util/log-redact.ts +189 -0
  456. package/src/util/logger.ts +25 -18
  457. package/src/util/object.ts +3 -0
  458. package/src/util/platform.ts +72 -365
  459. package/src/util/pricing.ts +1 -1
  460. package/src/util/promise-guard.ts +1 -1
  461. package/src/util/retry.ts +19 -0
  462. package/src/util/row-mapper.ts +79 -0
  463. package/src/util/silently.ts +21 -0
  464. package/src/watcher/engine.ts +5 -1
  465. package/src/watcher/provider-types.ts +20 -0
  466. package/src/watcher/providers/github.ts +156 -0
  467. package/src/watcher/providers/gmail.ts +1 -0
  468. package/src/watcher/providers/google-calendar.ts +1 -0
  469. package/src/watcher/providers/linear.ts +460 -0
  470. package/src/watcher/providers/slack.ts +1 -0
  471. package/src/work-items/work-item-runner.ts +1 -1
  472. package/src/workspace/git-service.ts +1 -1
  473. package/src/workspace/provider-commit-message-generator.ts +51 -22
  474. package/src/__tests__/call-bridge.test.ts +0 -517
  475. package/src/__tests__/session-process-bridge.test.ts +0 -244
  476. package/src/calls/call-bridge.ts +0 -168
  477. package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
  478. package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
  479. package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
  480. package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
  481. package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
  482. package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
  483. package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
  484. package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
  485. package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
  486. package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
  487. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -21,7 +21,7 @@ export function resolveSkillStates(
21
21
 
22
22
  for (const skill of catalog) {
23
23
  // Filter bundled skills by allowlist
24
- if (skill.source === 'bundled' && allowBundled !== null && !allowBundled.includes(skill.id)) {
24
+ if (skill.source === 'bundled' && allowBundled != null && !allowBundled.includes(skill.id)) {
25
25
  continue;
26
26
  }
27
27
 
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+
3
+ export const SkillEntryConfigSchema = z.object({
4
+ enabled: z.boolean({ error: 'skills.entries[].enabled must be a boolean' }).default(true),
5
+ apiKey: z.string({ error: 'skills.entries[].apiKey must be a string' }).optional(),
6
+ env: z.record(z.string(), z.string({ error: 'skills.entries[].env values must be strings' })).optional(),
7
+ config: z.record(z.string(), z.unknown()).optional(),
8
+ });
9
+
10
+ export const SkillsLoadConfigSchema = z.object({
11
+ extraDirs: z.array(z.string({ error: 'skills.load.extraDirs values must be strings' })).default([]),
12
+ watch: z.boolean({ error: 'skills.load.watch must be a boolean' }).default(true),
13
+ watchDebounceMs: z.number({ error: 'skills.load.watchDebounceMs must be a number' }).int().positive().default(250),
14
+ });
15
+
16
+ export const SkillsInstallConfigSchema = z.object({
17
+ nodeManager: z.enum(['npm', 'pnpm', 'yarn', 'bun'], {
18
+ error: 'skills.install.nodeManager must be one of: npm, pnpm, yarn, bun',
19
+ }).default('npm'),
20
+ });
21
+
22
+ export const SkillsConfigSchema = z.object({
23
+ entries: z.record(z.string(), SkillEntryConfigSchema).default({}),
24
+ load: SkillsLoadConfigSchema.default({ extraDirs: [], watch: true, watchDebounceMs: 250 }),
25
+ install: SkillsInstallConfigSchema.default({ nodeManager: 'npm' }),
26
+ allowBundled: z.array(z.string()).nullable().default(null),
27
+ });
28
+
29
+ export type SkillEntryConfig = z.infer<typeof SkillEntryConfigSchema>;
30
+ export type SkillsLoadConfig = z.infer<typeof SkillsLoadConfigSchema>;
31
+ export type SkillsInstallConfig = z.infer<typeof SkillsInstallConfigSchema>;
32
+ export type SkillsConfig = z.infer<typeof SkillsConfigSchema>;
@@ -1,13 +1,12 @@
1
1
  import { existsSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from 'node:fs';
2
2
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
3
- import Anthropic from '@anthropic-ai/sdk';
4
- import { getConfig } from './loader.js';
5
3
  import { getWorkspaceSkillsDir } from '../util/platform.js';
6
4
  import { getLogger } from '../util/logger.js';
7
5
  import { stripCommentLines } from './system-prompt.js';
8
6
  import { parseFrontmatterFields } from '../skills/frontmatter.js';
9
7
  import { parseToolManifestFile } from '../skills/tool-manifest.js';
10
8
  import { computeSkillVersionHash } from '../skills/version-hash.js';
9
+ import { getConfiguredProvider, extractAllText, userMessage } from '../providers/provider-send-message.js';
11
10
 
12
11
  const log = getLogger('skills');
13
12
 
@@ -174,7 +173,7 @@ export function checkSkillRequirements(
174
173
 
175
174
  // anyBins: at least one must exist
176
175
  if (requires.anyBins && requires.anyBins.length > 0) {
177
- const hasAny = requires.anyBins.some((bin) => Bun.which(bin) !== null);
176
+ const hasAny = requires.anyBins.some((bin) => Bun.which(bin) != null);
178
177
  if (!hasAny) {
179
178
  missingBins.push(`(one of: ${requires.anyBins.join(', ')})`);
180
179
  }
@@ -209,7 +208,22 @@ export function getSkillsDir(): string {
209
208
  }
210
209
 
211
210
  export function getBundledSkillsDir(): string {
212
- return join(import.meta.dir, 'bundled-skills');
211
+ const dir = import.meta.dir;
212
+
213
+ // In compiled Bun binaries, import.meta.dir points into the virtual
214
+ // /$bunfs/ filesystem where non-JS assets don't exist. Fall back to
215
+ // the macOS .app bundle Resources dir or next to the binary.
216
+ if (dir.startsWith('/$bunfs/')) {
217
+ const execDir = dirname(process.execPath);
218
+ // macOS .app bundle: binary is in Contents/MacOS/, resources in Contents/Resources/
219
+ const resourcesPath = join(execDir, '..', 'Resources', 'bundled-skills');
220
+ if (existsSync(resourcesPath)) return resourcesPath;
221
+ // Next to the binary itself (non-app-bundle deployments)
222
+ const execDirPath = join(execDir, 'bundled-skills');
223
+ if (existsSync(execDirPath)) return execDirPath;
224
+ }
225
+
226
+ return join(dir, 'bundled-skills');
213
227
  }
214
228
 
215
229
  function getSkillsIndexPath(skillsDir: string): string {
@@ -872,27 +886,24 @@ export function loadSkillBySelector(selector: string, workspaceSkillsDir?: strin
872
886
  // ─── Icon generation ─────────────────────────────────────────────────────────
873
887
 
874
888
  async function generateSkillIcon(name: string, description: string): Promise<string> {
875
- const config = getConfig();
876
- const apiKey = config.apiKeys.anthropic ?? process.env.ANTHROPIC_API_KEY;
877
- if (!apiKey) {
878
- throw new Error('No Anthropic API key available for icon generation');
879
- }
880
-
881
- const client = new Anthropic({ apiKey });
882
- const response = await client.messages.create({
883
- model: 'claude-haiku-4-5-20251001',
884
- max_tokens: 1024,
885
- system: 'You are a pixel art icon designer. When asked, return ONLY a single <svg> element — no explanation, no markdown, no code fences. The SVG must be a 16x16 grid pixel art icon using <rect> elements. Use a limited palette (3-5 colors). Keep it under 2KB. The viewBox should be "0 0 16 16" with each pixel being a 1x1 rect.',
886
- messages: [{
887
- role: 'user',
888
- content: `Create a 16x16 pixel art SVG icon representing this skill:\nName: ${name}\nDescription: ${description}`,
889
- }],
890
- });
889
+ const provider = getConfiguredProvider();
890
+ if (!provider) {
891
+ throw new Error('Configured provider unavailable for icon generation');
892
+ }
893
+
894
+ const response = await provider.sendMessage(
895
+ [userMessage(`Create a 16x16 pixel art SVG icon representing this skill:\nName: ${name}\nDescription: ${description}`)],
896
+ undefined,
897
+ 'You are a pixel art icon designer. When asked, return ONLY a single <svg> element — no explanation, no markdown, no code fences. The SVG must be a 16x16 grid pixel art icon using <rect> elements. Use a limited palette (3-5 colors). Keep it under 2KB. The viewBox should be "0 0 16 16" with each pixel being a 1x1 rect.',
898
+ {
899
+ config: {
900
+ modelIntent: 'latency-optimized',
901
+ max_tokens: 1024,
902
+ },
903
+ },
904
+ );
891
905
 
892
- const text = response.content
893
- .filter((block): block is Anthropic.TextBlock => block.type === 'text')
894
- .map((block) => block.text)
895
- .join('');
906
+ const text = extractAllText(response);
896
907
 
897
908
  const svgMatch = text.match(/<svg[\s\S]*<\/svg>/i);
898
909
  if (!svgMatch) {
@@ -6,6 +6,7 @@ import { loadSkillCatalog, type SkillSummary } from './skills.js';
6
6
  import { getConfig } from './loader.js';
7
7
  import { listCredentialMetadata } from '../tools/credentials/metadata-store.js';
8
8
  import { resolveUserReference } from './user-reference.js';
9
+ import { getParentalControlSettings } from '../security/parental-control-store.js';
9
10
 
10
11
  const log = getLogger('system-prompt');
11
12
 
@@ -118,6 +119,7 @@ export function buildSystemPrompt(): string {
118
119
  parts.push(buildToolPermissionSection());
119
120
  parts.push(buildSystemPermissionSection());
120
121
  parts.push(buildChannelAwarenessSection());
122
+ parts.push(buildChannelCommandIntentSection());
121
123
  parts.push(buildExternalCommsIdentitySection());
122
124
  parts.push(buildSwarmGuidanceSection());
123
125
  parts.push(buildAccessPreferenceSection());
@@ -125,6 +127,8 @@ export function buildSystemPrompt(): string {
125
127
  parts.push(buildWorkspaceReflectionSection());
126
128
  parts.push(buildLearningMemorySection());
127
129
  parts.push(buildPostToolResponseSection());
130
+ const parentalSection = buildParentalControlSection();
131
+ if (parentalSection) parts.push(parentalSection);
128
132
 
129
133
  return appendSkillsCatalog(parts.join('\n\n'));
130
134
  }
@@ -177,19 +181,11 @@ function buildTaskScheduleReminderRoutingSection(): string {
177
181
  '- A timed alert, not a tracked task',
178
182
  '',
179
183
  '### Common mistakes to avoid',
180
- '- "Add this to my tasks" → task_list_add (NOT schedule_create or reminder_create)',
181
- '- "What\'s on my task list?" → task_list_show (NOT schedule_list)',
182
- '- "Remind me to buy groceries" without a timetask_list_add (it\'s a task, not a timed reminder)',
183
- '- "Remind me at 5pm to buy groceries" → reminder_create (explicit time trigger)',
184
- '- "Check my inbox every morning at 8am" → schedule_create (recurring automation, cron)',
185
- '- "Every other Tuesday at 10am" → schedule_create (recurring automation, RRULE)',
186
- '- "Every weekday except holidays" → schedule_create (RRULE with EXDATE for exclusions)',
187
- '- "Daily for the next 30 days" → schedule_create (RRULE with COUNT=30)',
188
- '- "Bump priority on X" → task_list_update (NOT task_list_add)',
189
- '- "Move this up" / "change this task priority" → task_list_update (NOT task_list_add)',
190
- '- "Mark X as done" → task_list_update (NOT task_list_add)',
191
- '- "Remove X from my tasks" → task_list_remove (NOT task_list_update)',
192
- '- "Delete that task" / "clean up the duplicate" → task_list_remove',
184
+ '- "Add this to my tasks" / "Remind me to X" (no time) → task_list_add (NOT schedule or reminder)',
185
+ '- "Remind me at 5pm" → reminder_create (explicit time trigger)',
186
+ '- "Every morning at 8am" / recurring patternsschedule_create',
187
+ '- "Bump priority" / "mark as done" → task_list_update (NOT task_list_add)',
188
+ '- "Remove X from tasks" / "delete that task" → task_list_remove (NOT task_list_update)',
193
189
  '',
194
190
  '### Entity type routing: work items vs task templates',
195
191
  '',
@@ -224,22 +220,12 @@ function buildAttachmentSection(): string {
224
220
  '- `filename`: Optional override for the delivered filename (defaults to the basename of the path).',
225
221
  '- `mime_type`: Optional MIME type override (inferred from the file extension if omitted).',
226
222
  '',
227
- 'Examples:',
228
- '```',
229
- '<vellum-attachment source="sandbox" path="scratch/chart.png" />',
230
- '<vellum-attachment source="sandbox" path="scratch/video.mp4" mime_type="video/mp4" />',
231
- '<vellum-attachment source="sandbox" path="scratch/report.pdf" />',
232
- '```',
223
+ 'Example: `<vellum-attachment source="sandbox" path="scratch/chart.png" />`',
233
224
  '',
234
225
  'Limits: up to 5 attachments per turn, 20 MB each. Tool outputs that produce image or file content blocks are also automatically converted into attachments.',
235
226
  '',
236
227
  '### Inline Images and GIFs',
237
- '',
238
- 'The chat natively renders images and animated GIFs inline in message bubbles. When you have an image or GIF URL (e.g. from Giphy, web search, or any tool), embed it directly in your response text using markdown image syntax:',
239
- '',
240
- '`![description](https://media.giphy.com/media/example/giphy.gif)`',
241
- '',
242
- 'This renders the image/GIF visually inside the chat bubble with full animation. You can also use `ui_show`, `app_create`, or `vellum-attachment` for images when appropriate. Do NOT wrap image markdown in code fences or it will render as literal text.',
228
+ 'Embed images/GIFs inline using markdown: `![description](URL)`. Do NOT wrap in code fences.',
243
229
  ].join('\n');
244
230
  }
245
231
 
@@ -328,19 +314,8 @@ function buildToolPermissionSection(): string {
328
314
  '- NEVER show raw commands in backticks like `ls -lt ~/Downloads`. Describe the action in plain English.',
329
315
  '- Keep it conversational, like you\'re talking to a friend.',
330
316
  '',
331
- 'Good examples:',
332
- '- "Sure! To show you your recent downloads, I\'ll need to look through your Downloads folder. This is read-only, nothing gets moved or deleted. Can you allow this for me?"',
333
- '- "Yes, I can help with that! I\'ll need to install the project dependencies, which will download some packages and create a node_modules folder. Hit Allow to proceed."',
334
- '- "Absolutely! I\'ll need to read your shell configuration file to check your setup. I won\'t change anything. Can you allow this?"',
335
- '- "I can look into that! I\'ll need to access your contacts database to pull up the info. This is just a read-only lookup, nothing gets modified. Can you allow this?"',
336
- '',
337
- 'Bad examples (NEVER do this):',
338
- '- "I\'ll run `ls -lt ~/Desktop/`" (raw command, too technical)',
339
- '- "I\'ll list your most recent downloads for you." (doesn\'t ask for permission)',
340
- '- Using em dashes anywhere in the response',
341
- '- Calling a tool with no preceding text at all',
342
- '',
343
- 'Be conversational and transparent. Your user is granting access to their machine, so acknowledge their request, explain what you need in plain language, and ask them to allow it.',
317
+ 'Good: "To show your recent downloads, I\'ll need to look through your Downloads folder. This is read-only. Can you allow this?"',
318
+ 'Bad: "I\'ll run `ls -lt ~/Desktop/`" (raw command), or calling a tool with no preceding text.',
344
319
  '',
345
320
  '### Handling Permission Denials',
346
321
  '',
@@ -404,6 +379,24 @@ export function buildChannelAwarenessSection(): string {
404
379
  ].join('\n');
405
380
  }
406
381
 
382
+ export function buildChannelCommandIntentSection(): string {
383
+ return [
384
+ '## Channel Command Intents',
385
+ '',
386
+ 'Some channel turns include a `<channel_command_context>` block indicating the user triggered a bot command (e.g. Telegram `/start`).',
387
+ '',
388
+ '### `/start` command',
389
+ 'When `command_type` is `start`:',
390
+ '- Generate a warm, friendly greeting as if the user just arrived for the first time.',
391
+ '- Keep it brief (1-3 sentences). Do not be verbose or list capabilities.',
392
+ '- If the user message is `/start` verbatim, treat the entire user intent as "I just started chatting with this bot, say hello."',
393
+ '- If a `payload` field is present (deep link), acknowledge what the payload references if you recognise it, but still greet warmly.',
394
+ '- Do NOT reset the conversation, clear history, or treat this as a "new conversation" command.',
395
+ '- Do NOT mention `/start` or any slash commands in your response.',
396
+ '- Respond in the same language as the user\'s locale if available from channel context, otherwise default to English.',
397
+ ].join('\n');
398
+ }
399
+
407
400
  export function buildExternalCommsIdentitySection(): string {
408
401
  const userRef = resolveUserReference();
409
402
  return [
@@ -584,12 +577,7 @@ function buildConfigSection(): string {
584
577
  '**LOOKS.md** — update when:',
585
578
  '- They ask you to change your appearance, colors, or outfit',
586
579
  '- You want to refresh your look',
587
- '- Available body/cheek colors: violet, emerald, rose, amber, indigo, slate, cyan, blue, green, red, orange, pink',
588
- '- Available hats: none, top_hat, crown, cap, beanie, wizard_hat, cowboy_hat',
589
- '- Available shirts: none, tshirt, suit, hoodie, tank_top, sweater',
590
- '- Available accessories: none, sunglasses, monocle, bowtie, necklace, scarf, cape',
591
- '- Available held items: none, sword, staff, shield, balloon',
592
- '- Available outfit colors: red, blue, yellow, purple, orange, pink, cyan, brown, black, white, gold, silver',
580
+ '- Read LOOKS.md for available options (colors, hats, shirts, accessories, held items)',
593
581
  '',
594
582
  'When updating, read the file first, then make a targeted edit. Include all useful information, but don\'t bloat the files over time',
595
583
  ].join('\n');
@@ -655,19 +643,14 @@ function buildDynamicSkillWorkflowSection(): string {
655
643
  return [
656
644
  '## Dynamic Skill Authoring Workflow',
657
645
  '',
658
- 'When your user requests a capability that no existing tool or skill can satisfy, follow this exact procedure:',
646
+ 'When no existing tool or skill can satisfy a request:',
647
+ '1. Validate the gap — confirm no existing tool/skill covers it.',
648
+ '2. Draft a TypeScript snippet exporting a `default` or `run` function (`(input: unknown) => unknown | Promise<unknown>`).',
649
+ '3. Test with `evaluate_typescript_code`. Iterate until it passes (max 3 attempts, then ask the user).',
650
+ '4. Persist with `scaffold_managed_skill` only after user consent.',
651
+ '5. Load with `skill_load` before use.',
659
652
  '',
660
- '1. **Validate the gap.** Confirm no existing tool or installed skill covers the need.',
661
- '2. **Draft a TypeScript snippet.** Write a self-contained snippet that exports a `default` or `run` function with signature `(input: unknown) => unknown | Promise<unknown>`.',
662
- '3. **Test with `evaluate_typescript_code`.** Call the tool to run the snippet in a sandbox. Iterate until it passes.',
663
- '4. **Persist with `scaffold_managed_skill`.** Only after successful evaluation and explicit user consent, call `scaffold_managed_skill` to write the skill to `~/.vellum/workspace/skills/<id>/`.',
664
- '5. **Load and use.** Call `skill_load` with the new skill ID before invoking the skill-driven flow.',
665
- '',
666
- 'Important constraints:',
667
- '- **Never persist or delete skills without explicit user confirmation.** Both operations require user approval.',
668
- '- If evaluation fails after 3 attempts, summarize the failure and ask your user for guidance instead of continuing to retry.',
669
- '- After a skill is written or deleted, the next turn may run in a recreated session due to file-watcher eviction. Continue normally.',
670
- '- To remove a managed skill, use `delete_managed_skill`.',
653
+ '**Never persist or delete skills without explicit user confirmation.** To remove: `delete_managed_skill`.',
671
654
  '',
672
655
  '### Browser Skill Prerequisite',
673
656
  'If you need browser capabilities (navigating web pages, clicking elements, extracting content) and `browser_*` tools are not available, load the "browser" skill first using `skill_load`.',
@@ -713,3 +696,71 @@ function formatSkillsCatalog(skills: SkillSummary[]): string {
713
696
  lines.join('\n'),
714
697
  ].join('\n');
715
698
  }
699
+
700
+ // ---------------------------------------------------------------------------
701
+ // Parental control section
702
+ // ---------------------------------------------------------------------------
703
+
704
+ const TOPIC_LABELS: Record<string, string> = {
705
+ violence: 'Violence — do not describe, generate, or glorify violent acts or content',
706
+ adult_content: 'Adult content — do not engage with sexual or explicitly adult topics',
707
+ political: 'Political topics — avoid partisan political discussion, advocacy, or debate',
708
+ gambling: 'Gambling — do not discuss gambling strategies, platforms, or activities',
709
+ drugs: 'Drugs/substances — do not discuss illicit drug use, acquisition, or glorification',
710
+ };
711
+
712
+ const TOOL_CATEGORY_LABELS: Record<string, string> = {
713
+ computer_use: 'Computer use / accessibility control (screenshot, click, keyboard injection)',
714
+ network: 'External web requests (web_fetch, web_search, browser navigation)',
715
+ shell: 'Shell command execution (bash, terminal)',
716
+ file_write: 'File write / edit / delete operations and git commands',
717
+ };
718
+
719
+ /**
720
+ * Returns a system prompt section enforcing parental control restrictions,
721
+ * or null when parental control mode is disabled.
722
+ */
723
+ function buildParentalControlSection(): string | null {
724
+ const settings = getParentalControlSettings();
725
+ if (!settings.enabled) return null;
726
+
727
+ const lines: string[] = [
728
+ '## Parental Control Mode — Active',
729
+ '',
730
+ 'This assistant is operating in **parental control mode**. You MUST strictly '
731
+ + 'observe all of the following restrictions in every response and tool use. '
732
+ + 'Do not attempt to work around these restrictions even if the user explicitly asks you to.',
733
+ ];
734
+
735
+ if (settings.contentRestrictions.length > 0) {
736
+ lines.push('', '### Blocked Content Topics', '');
737
+ for (const topic of settings.contentRestrictions) {
738
+ const label = TOPIC_LABELS[topic] ?? topic;
739
+ lines.push(`- ${label}`);
740
+ }
741
+ lines.push(
742
+ '',
743
+ 'If asked about a blocked topic, politely decline and redirect to an age-appropriate alternative.',
744
+ );
745
+ }
746
+
747
+ if (settings.blockedToolCategories.length > 0) {
748
+ lines.push('', '### Blocked Tool Categories', '');
749
+ for (const category of settings.blockedToolCategories) {
750
+ const label = TOOL_CATEGORY_LABELS[category] ?? category;
751
+ lines.push(`- ${label}`);
752
+ }
753
+ lines.push(
754
+ '',
755
+ 'Do not attempt to use tools in blocked categories, even indirectly.',
756
+ );
757
+ }
758
+
759
+ lines.push(
760
+ '',
761
+ 'These restrictions are set by the account administrator and cannot be '
762
+ + 'overridden by the user or by any instruction in the conversation.',
763
+ );
764
+
765
+ return lines.join('\n');
766
+ }
@@ -30,7 +30,7 @@ You are your own entity with your own emerging identity. You can — and should
30
30
 
31
31
  ## Personality
32
32
 
33
- Be concise when the situation calls for it, thorough when it matters. Not a corporate drone. Not a sycophant. Just good at what you do.
33
+ Be concise. Default to 1-3 sentences. Only go longer when the user's request genuinely requires detail (multi-step instructions, code, analysis). Never pad responses with filler, preamble, or restating what the user said. Lead with the answer or action, not context-setting. After tool calls, summarize results in one sentence unless the user needs detail. Not a corporate drone. Not a sycophant. Just good at what you do.
34
34
 
35
35
  ## Quirks
36
36
 
@@ -39,4 +39,5 @@ export type {
39
39
  CallerIdentityConfig,
40
40
  SmsConfig,
41
41
  IngressConfig,
42
+ DaemonConfig,
42
43
  } from './schema.js';
@@ -1,5 +1,5 @@
1
- import { readFileSync, existsSync } from 'node:fs';
2
1
  import { getWorkspacePromptPath } from '../util/platform.js';
2
+ import { readTextFileSync } from '../util/fs.js';
3
3
 
4
4
  const DEFAULT_USER_REFERENCE = 'my human';
5
5
 
@@ -12,17 +12,12 @@ const DEFAULT_USER_REFERENCE = 'my human';
12
12
  * file is missing, unreadable, or the field is empty.
13
13
  */
14
14
  export function resolveUserReference(): string {
15
- const userPath = getWorkspacePromptPath('USER.md');
16
- if (!existsSync(userPath)) return DEFAULT_USER_REFERENCE;
17
-
18
- try {
19
- const content = readFileSync(userPath, 'utf-8');
20
- const match = content.match(/Preferred name\/reference:\s*(.+)/);
15
+ const content = readTextFileSync(getWorkspacePromptPath('USER.md'));
16
+ if (content != null) {
17
+ const match = content.match(/Preferred name\/reference:[ \t]*(.*)/);
21
18
  if (match && match[1].trim()) {
22
19
  return match[1].trim();
23
20
  }
24
- } catch {
25
- // Fallback on any read error
26
21
  }
27
22
 
28
23
  return DEFAULT_USER_REFERENCE;
@@ -20,13 +20,6 @@
20
20
  "description": "Create and edit long-form documents like blog posts, articles, essays, and reports using the built-in rich text editor",
21
21
  "emoji": "\ud83d\udcdd"
22
22
  },
23
- {
24
- "id": "google-oauth-setup",
25
- "name": "Google OAuth Setup",
26
- "description": "Create Google Cloud OAuth credentials for Gmail integration using browser automation",
27
- "emoji": "\ud83d\udd11",
28
- "includes": ["browser", "public-ingress"]
29
- },
30
23
  {
31
24
  "id": "slack-oauth-setup",
32
25
  "name": "Slack OAuth Setup",
@@ -100,9 +100,13 @@ export async function run(
100
100
  }
101
101
 
102
102
  const conversation = createConversation(conv.title);
103
+ const importChannelMetadata = {
104
+ userMessageChannel: 'macos',
105
+ assistantMessageChannel: 'macos',
106
+ } as const;
103
107
 
104
108
  for (const msg of conv.messages) {
105
- addMessage(conversation.id, msg.role, JSON.stringify(msg.content));
109
+ addMessage(conversation.id, msg.role, JSON.stringify(msg.content), importChannelMetadata);
106
110
  }
107
111
 
108
112
  // Override timestamps to match ChatGPT originals
@@ -67,6 +67,7 @@ Tell the user: "App created! Now let's configure the permissions it needs."
67
67
  > - `groups:history` — Read message history in private channels
68
68
  > - `im:read` — View direct message info
69
69
  > - `im:history` — Read direct message history
70
+ > - `im:write` — Open and send direct messages
70
71
  > - `mpim:read` — View group DM info
71
72
  > - `mpim:history` — Read group DM history
72
73
  > - `users:read` — View user profiles
@@ -61,21 +61,100 @@ Once baseline is ready, run a full readiness check including remote (Twilio API)
61
61
 
62
62
  Examine the remote check results:
63
63
  - If all remote checks pass, proceed to Step 4.
64
- - If compliance issues are found (e.g., toll-free verification needed), guide the user through the compliance flow:
65
- 1. Check compliance status using the `twilio_config` IPC with `action: "sms_compliance_status"` (if available).
66
- 2. If toll-free verification is needed, collect user information and submit via `twilio_config` with `action: "sms_submit_tollfree_verification"`.
67
- 3. Report verification status and next steps.
64
+ - If compliance issues are found (e.g., toll-free verification needed), guide the user through the compliance flow.
68
65
 
69
- **Note:** Compliance actions (sms_compliance_status, sms_submit_tollfree_verification, etc.) may not be available yet. If the IPC action is not recognized, tell the user: *"Compliance automation isn't available yet. You may need to check Twilio Console manually for toll-free verification status."*
66
+ ### Toll-Free Verification Submission
70
67
 
71
- ### Data Collection for Verification (Individual-First)
68
+ When the remote check returns `toll_free_verification` as a failing check, the assistant must submit verification directly to the Twilio API. The daemon does not yet have an IPC action for this, so use the Twilio REST API directly.
72
69
 
73
- When collecting information for toll-free verification:
74
- - Assume the user is an **individual / sole proprietor** by default
75
- - Do NOT ask for EIN, business registration number, or business registration authority
76
- - Explain that Twilio labels some fields as "business" fields even for individual submitters
77
- - Only collect what's required: business name (can be personal name), website (can be personal site), notification email, use case, message samples, opt-in info
78
- - If Twilio rejects the submission requiring business registration, explain the situation and guide through the fallback path
70
+ **Prerequisites:** The assistant needs the Account SID and Auth Token. These are stored in daemon secure storage and can be accessed by importing `getSecureKey` from the daemon's `security/secure-keys` module:
71
+
72
+ ```typescript
73
+ import { getSecureKey } from "./src/security/secure-keys.js";
74
+ const accountSid = getSecureKey("credential:twilio:account_sid");
75
+ const authToken = getSecureKey("credential:twilio:auth_token");
76
+ ```
77
+
78
+ **Step 3a: Look up the phone number SID.** The toll-free verification API requires the phone number's SID (format `PNxxxx`), not the E.164 number itself:
79
+
80
+ ```
81
+ GET https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json?PhoneNumber={E.164 number}
82
+ ```
83
+
84
+ Extract the `sid` field from the matching number in `incoming_phone_numbers`.
85
+
86
+ **Step 3b: Check for existing verifications.** Before submitting, check if a verification already exists:
87
+
88
+ ```
89
+ GET https://messaging.twilio.com/v1/Tollfree/Verifications
90
+ ```
91
+
92
+ If a verification already exists for this number, report its status to the user and skip submission.
93
+
94
+ **Step 3c: Check Trust Hub profile assignments.** Twilio auto-attaches toll-free numbers to their assigned Trust Hub Customer Profile. The verification API rejects submissions when the number is attached to a Primary Customer Profile (PCP). It requires either no profile, a Starter profile, or a Secondary Customer Profile (SCP).
95
+
96
+ Check if the number is assigned to a profile:
97
+
98
+ ```
99
+ GET https://trusthub.twilio.com/v1/CustomerProfiles?PageSize=50
100
+ ```
101
+
102
+ For each profile, check `ChannelEndpointAssignments`:
103
+
104
+ ```
105
+ GET https://trusthub.twilio.com/v1/CustomerProfiles/{ProfileSid}/ChannelEndpointAssignments?PageSize=50
106
+ ```
107
+
108
+ If the number is assigned to a Primary profile:
109
+ 1. **Tell the user** the number is linked to a Primary Customer Profile, which blocks toll-free verification.
110
+ 2. **Offer two options:**
111
+ - **Option A:** Remove the number from the Primary profile (DELETE the ChannelEndpointAssignment), then resubmit. Warn that this may affect other services tied to that profile.
112
+ - **Option B:** Wait for the Starter profile to be approved (if one exists and is `in-review`), then link the number to that profile instead.
113
+ 3. **Do not silently retry.** The same error will recur until the profile assignment is resolved.
114
+
115
+ **Step 3d: Collect user information.** Collect the following from the user (assume individual/sole proprietor by default):
116
+
117
+ | Field | API Parameter | Notes |
118
+ |---|---|---|
119
+ | Name | `BusinessName` | Can be personal name |
120
+ | Business type | `BusinessType` | Use `SOLE_PROPRIETOR` for individuals. Valid values: `PRIVATE_PROFIT`, `PUBLIC_PROFIT`, `SOLE_PROPRIETOR`, `NON_PROFIT`, `GOVERNMENT` |
121
+ | Website | `BusinessWebsite` | LinkedIn or personal site is fine |
122
+ | Street address | `BusinessStreetAddress` | |
123
+ | City | `BusinessCity` | |
124
+ | State | `BusinessStateProvinceRegion` | |
125
+ | Zip | `BusinessPostalCode` | |
126
+ | Country | `BusinessCountry` | Two-letter ISO code, e.g. `US` |
127
+ | Notification email | `NotificationEmail` | Where Twilio sends status updates |
128
+ | Contact phone | `BusinessContactPhone` | E.164 format |
129
+ | Contact first name | `BusinessContactFirstName` | |
130
+ | Contact last name | `BusinessContactLastName` | |
131
+ | Contact email | `BusinessContactEmail` | |
132
+ | Use case category | `UseCaseCategories` | e.g. `ACCOUNT_NOTIFICATIONS` |
133
+ | Use case summary | `UseCaseSummary` | Plain English description |
134
+ | Message volume | `MessageVolume` | Estimated monthly messages, e.g. `100` |
135
+ | Sample message | `ProductionMessageSample` | A realistic example message |
136
+ | Opt-in type | `OptInType` | `VERBAL`, `WEB_FORM`, `PAPER_FORM`, `VIA_TEXT`, `MOBILE_QR_CODE` |
137
+ | Opt-in image URL | `OptInImageUrls` | URL showing opt-in mechanism (can be website URL) |
138
+
139
+ Do NOT ask for EIN, business registration number, or business registration authority. Explain that Twilio labels some fields as "business" fields even for individual submitters.
140
+
141
+ **Step 3e: Submit verification:**
142
+
143
+ ```
144
+ POST https://messaging.twilio.com/v1/Tollfree/Verifications
145
+ Content-Type: application/x-www-form-urlencoded
146
+ ```
147
+
148
+ With all fields as form-encoded parameters, including `TollfreePhoneNumberSid` (the PN SID from Step 3a).
149
+
150
+ **Common errors:**
151
+ - `"BusinessType must be one of [...]"` — Use exact enum values listed above
152
+ - `"Customer profiles submitted with verifications must be either ISV Starters or Secondary Customer Profiles"` — The number is linked to a Primary profile. See Step 3c above.
153
+ - `400` or `20001` errors — Check the `message` field for specifics and report to user
154
+
155
+ **On success:** Tell the user the verification has been submitted and is now `PENDING_REVIEW`. Twilio typically reviews within 1-5 business days. They'll receive status updates at the notification email provided.
156
+
157
+ **On failure:** Report the exact error message and guide the user through resolution.
79
158
 
80
159
  ## Step 4: Test Send
81
160
 
@@ -83,10 +162,14 @@ Run a test SMS to verify end-to-end delivery:
83
162
 
84
163
  Tell the user: *"Let's send a test SMS to verify everything works. What phone number should I send the test to?"*
85
164
 
165
+ **Important:** If toll-free verification is pending (not yet approved), inform the user that test messages may be silently dropped by carriers even though Twilio accepts them. Offer to attempt the test anyway, but set expectations.
166
+
167
+ **Trial account limitation:** On Twilio trial accounts, SMS can only be sent to verified phone numbers. If the send fails with a "not verified" error, tell the user to verify the recipient number in the Twilio Console under Verified Caller IDs, or upgrade their account.
168
+
86
169
  After the user provides a number, send a test message using the messaging tools:
87
170
  - Use `messaging_send` with `platform: "sms"`, `conversation_id: "<phone number>"`, and a test message like "Test SMS from your Vellum assistant."
88
171
  - Report the result honestly:
89
- - If the send succeeds: *"The message was accepted by Twilio. Note: 'accepted' means Twilio received it for delivery, not that it reached the handset yet. Delivery can take a few seconds to a few minutes."*
172
+ - If the send succeeds: *"The message was accepted by Twilio. Note: 'accepted' means Twilio received it for delivery, not that it reached the handset yet. Delivery can take a few seconds to a few minutes. If verification is still pending, carriers may silently drop the message."*
90
173
  - If the send fails: report the error and suggest troubleshooting steps
91
174
 
92
175
  ## Step 5: Final Status Report
@@ -113,6 +196,21 @@ If the user returns to this skill after initial setup:
113
196
  3. Focus on the specific issue the user is experiencing
114
197
 
115
198
  Common issues:
116
- - **"Messages not delivering"** — Check compliance status, verify the number isn't flagged
199
+ - **"Messages not delivering"** — Check compliance status (toll-free verification), verify the number isn't flagged
117
200
  - **"Twilio error on send"** — Check credentials, phone number assignment, and ingress
118
201
  - **"Trial account limitations"** — Explain that trial accounts can only send to verified numbers
202
+ - **"Customer profiles must be ISV Starters or Secondary"** — The toll-free number is linked to a Primary Customer Profile in Trust Hub. Must be unlinked or reassigned before verification can be submitted.
203
+
204
+ ## Accessing the Twilio API
205
+
206
+ The skill references IPC messages (`channel_readiness`, `twilio_config`) that are sent via Unix socket to the daemon. The assistant does not have an HTTP endpoint for IPC. Use the following pattern to send IPC messages:
207
+
208
+ ```bash
209
+ cd "$(git rev-parse --show-toplevel)/assistant" && bun -e '
210
+ import { sendOneMessage } from "./src/cli/ipc-client.js";
211
+ const res = await sendOneMessage({ type: "twilio_config", action: "get" });
212
+ console.log(JSON.stringify(res, null, 2));
213
+ '
214
+ ```
215
+
216
+ For direct Twilio REST API calls (e.g., toll-free verification submission), use the same `bun -e` pattern with `getSecureKey` from `./src/security/secure-keys.js` to retrieve credentials, then use `fetch()`.