@vellumai/assistant 0.8.1 → 0.8.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 (506) hide show
  1. package/ARCHITECTURE.md +2 -7
  2. package/Dockerfile +75 -1
  3. package/bun.lock +11 -1
  4. package/docker-entrypoint.sh +5 -0
  5. package/docker-init-apt-root.sh +94 -0
  6. package/docker-kata-apt-env.sh +39 -0
  7. package/docs/plugins.md +88 -47
  8. package/docs/skills.md +9 -7
  9. package/examples/plugins/echo/README.md +27 -27
  10. package/examples/plugins/echo/package.json +3 -0
  11. package/examples/plugins/echo/register.ts +31 -31
  12. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  13. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  14. package/openapi.yaml +325 -3
  15. package/package.json +3 -1
  16. package/scripts/generate-openapi.ts +83 -10
  17. package/scripts/sync-llm-catalog.ts +2 -2
  18. package/scripts/sync-web-search-catalog.ts +47 -25
  19. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  20. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  21. package/src/__tests__/anthropic-provider.test.ts +45 -0
  22. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  23. package/src/__tests__/app-executors.test.ts +220 -4
  24. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  25. package/src/__tests__/bundled-asset.test.ts +6 -6
  26. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  27. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  28. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  29. package/src/__tests__/clawhub.test.ts +75 -16
  30. package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
  31. package/src/__tests__/config-schema.test.ts +21 -0
  32. package/src/__tests__/config-set-route.test.ts +80 -0
  33. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  34. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  35. package/src/__tests__/context-search-conversations-source.test.ts +117 -2
  36. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  37. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  38. package/src/__tests__/context-token-estimator.test.ts +1 -0
  39. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
  42. package/src/__tests__/conversation-agent-loop.test.ts +2 -0
  43. package/src/__tests__/conversation-error.test.ts +42 -3
  44. package/src/__tests__/conversation-fork-crud.test.ts +82 -0
  45. package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
  46. package/src/__tests__/conversation-lifecycle.test.ts +173 -0
  47. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  48. package/src/__tests__/conversation-pairing.test.ts +54 -0
  49. package/src/__tests__/conversation-process-callsite.test.ts +4 -1
  50. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-queue.test.ts +4 -1
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
  53. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  54. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  55. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  56. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  59. package/src/__tests__/credential-security-invariants.test.ts +3 -2
  60. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  61. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  62. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  63. package/src/__tests__/dm-backfill.test.ts +121 -10
  64. package/src/__tests__/document-tool-security.test.ts +258 -0
  65. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  66. package/src/__tests__/edit-propagation.test.ts +33 -0
  67. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  68. package/src/__tests__/external-plugin-loader.test.ts +60 -36
  69. package/src/__tests__/filing-service.test.ts +140 -0
  70. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  71. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
  72. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  73. package/src/__tests__/helpers/wait-for.ts +21 -0
  74. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  75. package/src/__tests__/history-repair.test.ts +73 -0
  76. package/src/__tests__/host-app-control-proxy.test.ts +266 -10
  77. package/src/__tests__/image-credentials.test.ts +1 -1
  78. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  79. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
  80. package/src/__tests__/inference-profile-reaper.test.ts +4 -2
  81. package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
  82. package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
  83. package/src/__tests__/injector-chain.test.ts +10 -8
  84. package/src/__tests__/install-skill-routing.test.ts +155 -37
  85. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
  86. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  87. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  88. package/src/__tests__/llm-catalog-parity.test.ts +55 -13
  89. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
  90. package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
  91. package/src/__tests__/llm-usage-store.test.ts +114 -0
  92. package/src/__tests__/managed-profile-guard.test.ts +31 -29
  93. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  94. package/src/__tests__/managed-store.test.ts +84 -192
  95. package/src/__tests__/media-generate-image.test.ts +1 -1
  96. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  97. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  98. package/src/__tests__/oauth-commands-routes.test.ts +168 -16
  99. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  100. package/src/__tests__/openai-provider.test.ts +24 -0
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
  102. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  103. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  104. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
  105. package/src/__tests__/platform.test.ts +2 -0
  106. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  107. package/src/__tests__/plugin-bootstrap.test.ts +10 -36
  108. package/src/__tests__/plugin-external-api.test.ts +68 -0
  109. package/src/__tests__/plugin-registry.test.ts +0 -77
  110. package/src/__tests__/plugin-route-contribution.test.ts +0 -1
  111. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  112. package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
  113. package/src/__tests__/plugin-types.test.ts +3 -13
  114. package/src/__tests__/process-message-background-slack.test.ts +8 -1
  115. package/src/__tests__/process-message-display-content.test.ts +421 -0
  116. package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
  117. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  118. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
  119. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  120. package/src/__tests__/schedule-routes.test.ts +50 -3
  121. package/src/__tests__/schedule-store.test.ts +94 -0
  122. package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
  123. package/src/__tests__/schema-transforms.test.ts +20 -0
  124. package/src/__tests__/search-skills-unified.test.ts +0 -5
  125. package/src/__tests__/server-history-render.test.ts +43 -0
  126. package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
  127. package/src/__tests__/skill-load-tool.test.ts +27 -89
  128. package/src/__tests__/skill-memory.test.ts +23 -3
  129. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  130. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  131. package/src/__tests__/skills-install-extract.test.ts +49 -38
  132. package/src/__tests__/skills-install-staging.test.ts +159 -0
  133. package/src/__tests__/skills-uninstall.test.ts +9 -41
  134. package/src/__tests__/skills.test.ts +51 -58
  135. package/src/__tests__/slack-channel-config.test.ts +9 -0
  136. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  137. package/src/__tests__/system-prompt.test.ts +737 -63
  138. package/src/__tests__/terminal-tools.test.ts +28 -1
  139. package/src/__tests__/thread-backfill.test.ts +557 -27
  140. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  141. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  142. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  143. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  145. package/src/__tests__/tool-executor.test.ts +16 -4
  146. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  147. package/src/__tests__/turn-events-store.test.ts +256 -0
  148. package/src/__tests__/twilio-routes.test.ts +4 -0
  149. package/src/__tests__/user-plugin-loader.test.ts +0 -7
  150. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  151. package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
  152. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
  153. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
  154. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  155. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  156. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  157. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  158. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  159. package/src/acp/resolve-agent.ts +1 -1
  160. package/src/agent/image-optimize.ts +13 -5
  161. package/src/calls/voice-session-bridge.ts +61 -42
  162. package/src/channels/types.ts +108 -0
  163. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  164. package/src/cli/commands/__tests__/changelog.test.ts +304 -319
  165. package/src/cli/commands/__tests__/schedules.test.ts +491 -0
  166. package/src/cli/commands/changelog.ts +106 -42
  167. package/src/cli/commands/conversations.ts +102 -17
  168. package/src/cli/commands/default-action.ts +10 -53
  169. package/src/cli/commands/notifications.ts +329 -317
  170. package/src/cli/commands/plugins.ts +185 -0
  171. package/src/cli/commands/schedules.ts +391 -0
  172. package/src/cli/commands/telemetry.ts +40 -0
  173. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  174. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  177. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  178. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  179. package/src/cli/lib/cli-colors.ts +12 -0
  180. package/src/cli/lib/confirm-prompt.ts +79 -0
  181. package/src/cli/lib/install-from-github.ts +304 -0
  182. package/src/cli/lib/list-installed-plugins.ts +137 -0
  183. package/src/cli/lib/uninstall-plugin.ts +82 -0
  184. package/src/cli/lib/unknown-command.ts +111 -0
  185. package/src/cli/program.ts +38 -2
  186. package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
  187. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  188. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  189. package/src/config/bundled-skills/document/SKILL.md +23 -3
  190. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  191. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  192. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  193. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  194. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  195. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  196. package/src/config/bundled-tool-registry.ts +6 -0
  197. package/src/config/feature-flag-registry.json +41 -1
  198. package/src/config/loader.ts +64 -38
  199. package/src/config/schema.ts +7 -10
  200. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  201. package/src/config/schemas/channels.ts +8 -0
  202. package/src/config/schemas/compaction.ts +28 -0
  203. package/src/config/schemas/heartbeat.ts +9 -0
  204. package/src/config/schemas/llm-request-logs.ts +31 -7
  205. package/src/config/schemas/llm.ts +3 -0
  206. package/src/config/schemas/memory-retrieval.ts +18 -0
  207. package/src/config/schemas/tools.ts +14 -0
  208. package/src/config/skills.ts +3 -96
  209. package/src/context/compactor.ts +1047 -0
  210. package/src/context/token-estimator.ts +2 -2
  211. package/src/context/window-manager.ts +197 -1520
  212. package/src/credential-execution/managed-catalog.ts +37 -0
  213. package/src/credential-health/credential-health-service.ts +280 -19
  214. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
  215. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  216. package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
  217. package/src/daemon/approval-generators.ts +8 -6
  218. package/src/daemon/config-watcher.ts +94 -31
  219. package/src/daemon/conversation-agent-loop.ts +169 -9
  220. package/src/daemon/conversation-error.ts +171 -37
  221. package/src/daemon/conversation-lifecycle.ts +53 -40
  222. package/src/daemon/conversation-messaging.ts +25 -6
  223. package/src/daemon/conversation-process.ts +49 -12
  224. package/src/daemon/conversation-runtime-assembly.ts +16 -1
  225. package/src/daemon/conversation-slash.ts +12 -5
  226. package/src/daemon/conversation-store.ts +11 -4
  227. package/src/daemon/conversation-tool-setup.ts +39 -7
  228. package/src/daemon/conversation.ts +33 -1
  229. package/src/daemon/external-plugins-bootstrap.ts +217 -181
  230. package/src/daemon/first-greeting.ts +22 -2
  231. package/src/daemon/handlers/config-model.ts +6 -5
  232. package/src/daemon/handlers/config-slack-channel.ts +15 -3
  233. package/src/daemon/handlers/shared.ts +14 -5
  234. package/src/daemon/handlers/skills.ts +111 -108
  235. package/src/daemon/history-repair.ts +28 -1
  236. package/src/daemon/host-app-control-proxy.ts +98 -23
  237. package/src/daemon/lifecycle.ts +45 -35
  238. package/src/daemon/meet-host-supervisor.ts +5 -4
  239. package/src/daemon/memory-v2-startup.ts +49 -0
  240. package/src/daemon/message-protocol.ts +1 -0
  241. package/src/daemon/message-types/conversations.ts +25 -0
  242. package/src/daemon/message-types/messages.ts +61 -0
  243. package/src/daemon/message-types/subagents.ts +1 -0
  244. package/src/daemon/message-types/sync.ts +1 -0
  245. package/src/daemon/pkb-reminder-builder.test.ts +1 -1
  246. package/src/daemon/pkb-reminder-builder.ts +1 -1
  247. package/src/daemon/plugin-source-watcher.ts +146 -0
  248. package/src/daemon/process-message.ts +21 -3
  249. package/src/daemon/server.ts +11 -2
  250. package/src/daemon/skill-memory-refresh.ts +29 -0
  251. package/src/documents/document-store.ts +221 -3
  252. package/src/embedded/plugin-api.ts +40 -0
  253. package/src/filing/filing-service.ts +39 -0
  254. package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
  255. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  256. package/src/heartbeat/heartbeat-service.ts +41 -0
  257. package/src/home/__tests__/feed-types.test.ts +40 -0
  258. package/src/home/feed-types.ts +22 -0
  259. package/src/home/post-connect-feed.ts +1 -0
  260. package/src/index.ts +18 -1
  261. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  262. package/src/mcp/client.ts +20 -4
  263. package/src/media/image-credentials.ts +3 -3
  264. package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
  265. package/src/memory/__tests__/conversation-queries.test.ts +263 -0
  266. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  267. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
  268. package/src/memory/__tests__/message-content.test.ts +35 -0
  269. package/src/memory/bookmark-crud.ts +42 -10
  270. package/src/memory/context-search/sources/conversations.ts +62 -2
  271. package/src/memory/context-search/sources/workspace.ts +4 -0
  272. package/src/memory/conversation-crud.ts +63 -19
  273. package/src/memory/conversation-queries.ts +110 -10
  274. package/src/memory/db-init.ts +6 -0
  275. package/src/memory/delivery-crud.ts +152 -5
  276. package/src/memory/embedding-backend.ts +4 -4
  277. package/src/memory/external-conversation-store.ts +66 -5
  278. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
  279. package/src/memory/graph/conversation-graph-memory.ts +31 -15
  280. package/src/memory/graph/tools.ts +3 -3
  281. package/src/memory/indexer.ts +34 -29
  282. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
  283. package/src/memory/jobs/embed-concept-page.ts +20 -11
  284. package/src/memory/jobs-worker.ts +6 -1
  285. package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
  286. package/src/memory/llm-request-log-source.ts +19 -52
  287. package/src/memory/llm-usage-store.ts +125 -5
  288. package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
  289. package/src/memory/message-content.ts +1 -1
  290. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  291. package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
  292. package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
  293. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  294. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  295. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  296. package/src/memory/migrations/index.ts +6 -0
  297. package/src/memory/migrations/registry.ts +8 -0
  298. package/src/memory/onboarding-events-store.ts +106 -0
  299. package/src/memory/schema/bookmarks.ts +0 -2
  300. package/src/memory/schema/calls.ts +1 -0
  301. package/src/memory/schema/inference.ts +1 -3
  302. package/src/memory/schema/infrastructure.ts +12 -0
  303. package/src/memory/turn-events-store.ts +127 -2
  304. package/src/memory/v2/__tests__/activation.test.ts +0 -8
  305. package/src/memory/v2/__tests__/injection.test.ts +98 -8
  306. package/src/memory/v2/__tests__/migration.test.ts +87 -0
  307. package/src/memory/v2/__tests__/page-index.test.ts +83 -0
  308. package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
  309. package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
  310. package/src/memory/v2/__tests__/router.test.ts +15 -0
  311. package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
  312. package/src/memory/v2/injection.ts +32 -6
  313. package/src/memory/v2/migration.ts +49 -19
  314. package/src/memory/v2/page-index.ts +35 -5
  315. package/src/memory/v2/prompts/router.ts +11 -8
  316. package/src/memory/v2/prompts/sweep.ts +2 -2
  317. package/src/memory/v2/qdrant.ts +135 -7
  318. package/src/memory/v2/router.ts +9 -8
  319. package/src/memory/v2/skill-store.ts +120 -35
  320. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  321. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  322. package/src/messaging/providers/slack/adapter.ts +43 -5
  323. package/src/messaging/providers/slack/client.ts +27 -0
  324. package/src/messaging/providers/slack/deep-link.ts +65 -0
  325. package/src/messaging/providers/slack/download.ts +104 -0
  326. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  327. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  328. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  329. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  330. package/src/messaging/providers/slack/types.ts +20 -1
  331. package/src/notifications/conversation-pairing.ts +2 -1
  332. package/src/notifications/decision-engine.ts +2 -1
  333. package/src/notifications/emit-signal.ts +20 -1
  334. package/src/notifications/home-feed-side-effect.ts +54 -0
  335. package/src/notifications/signal.ts +3 -1
  336. package/src/oauth/connection-resolver.ts +8 -4
  337. package/src/oauth/platform-connection.ts +6 -2
  338. package/src/oauth/seed-providers.ts +10 -1
  339. package/src/permissions/checker.ts +2 -0
  340. package/src/permissions/ipc-risk-types.ts +1 -0
  341. package/src/permissions/question-prompter.test.ts +416 -0
  342. package/src/permissions/question-prompter.ts +294 -0
  343. package/src/platform/client.test.ts +1 -1
  344. package/src/platform/client.ts +1 -1
  345. package/src/plugin-api/constants.ts +26 -0
  346. package/src/plugin-api/index.ts +34 -1
  347. package/src/plugin-api/types.ts +104 -22
  348. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  349. package/src/plugins/defaults/compaction.ts +0 -4
  350. package/src/plugins/defaults/empty-response.ts +0 -2
  351. package/src/plugins/defaults/history-repair.ts +0 -2
  352. package/src/plugins/defaults/injectors.ts +36 -3
  353. package/src/plugins/defaults/llm-call.ts +0 -2
  354. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  355. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  356. package/src/plugins/defaults/persistence.ts +0 -2
  357. package/src/plugins/defaults/title-generate.ts +0 -5
  358. package/src/plugins/defaults/token-estimate.ts +0 -2
  359. package/src/plugins/defaults/tool-error.ts +0 -7
  360. package/src/plugins/defaults/tool-execute.ts +0 -2
  361. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  362. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  363. package/src/plugins/external-api.ts +104 -0
  364. package/src/plugins/external-plugin-loader.ts +105 -32
  365. package/src/plugins/feature-gate.ts +22 -0
  366. package/src/plugins/pipeline.ts +37 -0
  367. package/src/plugins/registry.ts +48 -80
  368. package/src/plugins/types.ts +31 -26
  369. package/src/plugins/user-loader.ts +21 -2
  370. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  371. package/src/proactive-artifact/job.test.ts +37 -5
  372. package/src/prompts/__tests__/system-prompt.test.ts +12 -0
  373. package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
  374. package/src/prompts/normalize-onboarding.ts +27 -0
  375. package/src/prompts/sections.ts +302 -0
  376. package/src/prompts/system-prompt.ts +63 -166
  377. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  378. package/src/prompts/templates/system-sections.ts +173 -0
  379. package/src/providers/__tests__/inference.test.ts +22 -7
  380. package/src/providers/anthropic/client.ts +28 -28
  381. package/src/providers/connection-resolution.ts +7 -0
  382. package/src/providers/inference/adapter-factory.ts +41 -4
  383. package/src/providers/inference/connections.ts +74 -29
  384. package/src/providers/inference/resolve-auth.ts +12 -4
  385. package/src/providers/model-catalog.ts +294 -12
  386. package/src/providers/openai/chat-completions-provider.ts +10 -2
  387. package/src/providers/openrouter/client.ts +7 -0
  388. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
  389. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  390. package/src/providers/provider-availability.ts +17 -2
  391. package/src/providers/provider-catalog-visibility.ts +36 -0
  392. package/src/providers/registry.ts +22 -14
  393. package/src/providers/retry.ts +47 -1
  394. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  395. package/src/runtime/agent-wake.ts +42 -14
  396. package/src/runtime/auth/route-policy.ts +8 -1
  397. package/src/runtime/btw-sidechain.ts +2 -0
  398. package/src/runtime/http-types.ts +19 -0
  399. package/src/runtime/migrations/origin-mode.ts +1 -1
  400. package/src/runtime/pending-interactions.ts +1 -0
  401. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
  402. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
  403. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
  404. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  405. package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
  406. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  407. package/src/runtime/routes/acp-routes.ts +5 -3
  408. package/src/runtime/routes/auth-routes.ts +1 -1
  409. package/src/runtime/routes/bookmark-routes.ts +5 -3
  410. package/src/runtime/routes/btw-routes.ts +5 -1
  411. package/src/runtime/routes/channel-availability-routes.ts +121 -0
  412. package/src/runtime/routes/conversation-cli-routes.ts +44 -3
  413. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  414. package/src/runtime/routes/conversation-management-routes.ts +17 -42
  415. package/src/runtime/routes/conversation-query-routes.ts +40 -35
  416. package/src/runtime/routes/conversation-routes.ts +90 -11
  417. package/src/runtime/routes/documents-routes.ts +25 -86
  418. package/src/runtime/routes/group-routes.ts +5 -0
  419. package/src/runtime/routes/inbound-conversation.ts +28 -8
  420. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  421. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
  422. package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
  423. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  424. package/src/runtime/routes/index.ts +6 -0
  425. package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
  426. package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
  427. package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
  428. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  429. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  430. package/src/runtime/routes/integrations/twilio.ts +6 -13
  431. package/src/runtime/routes/notification-routes.ts +1 -1
  432. package/src/runtime/routes/oauth-commands-routes.ts +105 -15
  433. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  434. package/src/runtime/routes/question-routes.ts +259 -0
  435. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  436. package/src/runtime/routes/schedule-routes.ts +4 -7
  437. package/src/runtime/routes/subagents-routes.ts +57 -18
  438. package/src/runtime/routes/telemetry-routes.ts +27 -0
  439. package/src/runtime/routes/tts-routes.ts +27 -2
  440. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  441. package/src/runtime/routes/workspace-routes.ts +28 -0
  442. package/src/runtime/services/conversation-serializer.ts +39 -7
  443. package/src/runtime/sync/resource-sync-events.ts +93 -1
  444. package/src/schedule/schedule-store.ts +27 -2
  445. package/src/schedule/scheduler.ts +9 -1
  446. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  447. package/src/security/untrusted-content.ts +93 -8
  448. package/src/skills/catalog-files.ts +1 -1
  449. package/src/skills/catalog-install.ts +233 -116
  450. package/src/skills/clawhub.ts +70 -13
  451. package/src/skills/managed-store.ts +4 -119
  452. package/src/skills/skillssh-registry.ts +27 -48
  453. package/src/subagent/manager.ts +15 -7
  454. package/src/telemetry/types.ts +113 -1
  455. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  456. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  457. package/src/tools/apps/executors.ts +58 -7
  458. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  459. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  460. package/src/tools/browser/browser-execution.ts +15 -11
  461. package/src/tools/computer-use/definitions.ts +3 -3
  462. package/src/tools/credentials/vault.ts +1 -1
  463. package/src/tools/document/document-tool.ts +124 -1
  464. package/src/tools/filesystem/edit.ts +1 -1
  465. package/src/tools/filesystem/list.ts +1 -1
  466. package/src/tools/filesystem/read.ts +1 -1
  467. package/src/tools/filesystem/write.ts +5 -2
  468. package/src/tools/host-filesystem/transfer.ts +1 -1
  469. package/src/tools/host-terminal/host-shell.ts +1 -1
  470. package/src/tools/permission-checker.ts +1 -1
  471. package/src/tools/registry.ts +17 -7
  472. package/src/tools/schedule/create.ts +2 -2
  473. package/src/tools/schema-transforms.ts +7 -2
  474. package/src/tools/side-effects.ts +1 -0
  475. package/src/tools/skills/delete-managed.ts +4 -4
  476. package/src/tools/skills/execute.ts +1 -1
  477. package/src/tools/skills/scaffold-managed.ts +3 -2
  478. package/src/tools/subagent/notify-parent.ts +1 -1
  479. package/src/tools/system/request-permission.ts +2 -2
  480. package/src/tools/terminal/safe-env.ts +60 -1
  481. package/src/tools/tool-manifest.ts +2 -0
  482. package/src/tools/types.ts +72 -21
  483. package/src/tools/ui-surface/definitions.ts +6 -5
  484. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  485. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  486. package/src/types/onboarding-context.ts +2 -0
  487. package/src/util/errors.ts +17 -0
  488. package/src/util/platform.ts +10 -0
  489. package/src/watcher/__tests__/engine.test.ts +22 -0
  490. package/src/watcher/engine.ts +6 -2
  491. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
  492. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
  493. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
  494. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  495. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  496. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  497. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  498. package/src/workspace/migrations/registry.ts +8 -0
  499. package/src/workspace/migrations/runner.ts +39 -9
  500. package/src/workspace/migrations/types.ts +4 -0
  501. package/examples/plugins/echo/bun.lock +0 -25
  502. package/src/__tests__/context-window-manager.test.ts +0 -2481
  503. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  504. package/src/context/prompts/compact.md +0 -26
  505. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  506. /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
@@ -10,7 +10,7 @@ import { hostFileWriteTool } from "./host-filesystem/write.js";
10
10
  import { hostShellTool } from "./host-terminal/host-shell.js";
11
11
  import { toProviderSafeToolName } from "./provider-tool-name.js";
12
12
  import { registerSystemTools } from "./system/register.js";
13
- import type { Tool } from "./types.js";
13
+ import type { PluginTool, Tool } from "./types.js";
14
14
  import { allUiSurfaceTools } from "./ui-surface/definitions.js";
15
15
  import { registerUiSurfaceTools } from "./ui-surface/registry.js";
16
16
 
@@ -193,19 +193,29 @@ export function registerSkillTools(newTools: Tool[]): Tool[] {
193
193
  */
194
194
  export function registerPluginTools(
195
195
  pluginName: string,
196
- newTools: Tool[],
196
+ newTools: PluginTool[],
197
197
  ): Tool[] {
198
- const stamped: Tool[] = newTools.map((tool) =>
199
- withProviderSafeToolName({
200
- ...tool,
198
+ const stamped: Tool[] = newTools.map((pluginTool) => {
199
+ const { input_schema, ...rest } = pluginTool;
200
+ const tool: Tool = {
201
+ ...rest,
202
+ category: "plugin",
201
203
  origin: "plugin" as const,
202
204
  ownerPluginId: pluginName,
203
205
  ownerSkillId: undefined,
204
206
  ownerMcpServerId: undefined,
205
207
  ownerSkillBundled: undefined,
206
208
  ownerSkillVersionHash: undefined,
207
- }),
208
- );
209
+ getDefinition(): ToolDefinition {
210
+ return {
211
+ name: pluginTool.name,
212
+ description: pluginTool.description,
213
+ input_schema,
214
+ };
215
+ },
216
+ };
217
+ return withProviderSafeToolName(tool);
218
+ });
209
219
 
210
220
  const accepted: Tool[] = [];
211
221
  for (const tool of stamped) {
@@ -150,7 +150,7 @@ export async function executeScheduleCreate(
150
150
  ` Status: ${job.status}`,
151
151
  ``,
152
152
  `Integrations: ${integrations}`,
153
- `\u26a0 If this schedule requires an integration that isn't connected, it will fail at runtime. Warn the user about any missing capabilities before confirming the schedule is ready.`,
153
+ `\u26a0 If this schedule requires an integration that isn't connected, it will fail at runtime. Warn about any missing capabilities before confirming the schedule is ready.`,
154
154
  ].join("\n"),
155
155
  isError: false,
156
156
  };
@@ -239,7 +239,7 @@ export async function executeScheduleCreate(
239
239
  ` Next run: ${nextRunDate}`,
240
240
  ``,
241
241
  `Integrations: ${integrations}`,
242
- `\u26a0 If this schedule requires an integration that isn't connected, it will fail at runtime. Warn the user about any missing capabilities before confirming the schedule is ready.`,
242
+ `\u26a0 If this schedule requires an integration that isn't connected, it will fail at runtime. Warn about any missing capabilities before confirming the schedule is ready.`,
243
243
  ].join("\n"),
244
244
  isError: false,
245
245
  };
@@ -23,8 +23,13 @@ export function injectActivityField(
23
23
  return def;
24
24
  }
25
25
 
26
- const schema = def.input_schema as Record<string, unknown>;
27
- if (schema.type !== "object" || !schema.properties) {
26
+ const schema = def.input_schema as Record<string, unknown> | undefined;
27
+ if (
28
+ schema == null ||
29
+ typeof schema !== "object" ||
30
+ schema.type !== "object" ||
31
+ !schema.properties
32
+ ) {
28
33
  return def;
29
34
  }
30
35
 
@@ -14,6 +14,7 @@ const SIDE_EFFECT_TOOLS: ReadonlySet<string> = new Set([
14
14
  "web_fetch",
15
15
  "document_create",
16
16
  "document_update",
17
+ "document_delete",
17
18
  "schedule_create",
18
19
  "schedule_update",
19
20
  "schedule_delete",
@@ -1,3 +1,4 @@
1
+ import { refreshSkillCapabilityMemories } from "../../daemon/skill-memory-refresh.js";
1
2
  import { deleteManagedSkill } from "../../skills/managed-store.js";
2
3
  import type { ToolContext, ToolExecutionResult } from "../types.js";
3
4
 
@@ -17,19 +18,18 @@ export async function executeDeleteManagedSkill(
17
18
  };
18
19
  }
19
20
 
20
- const removeFromIndex = input.remove_from_index !== false;
21
-
22
- const result = deleteManagedSkill(skillId.trim(), removeFromIndex);
21
+ const result = deleteManagedSkill(skillId.trim());
23
22
 
24
23
  if (!result.deleted) {
25
24
  return { content: `Error: ${result.error}`, isError: true };
26
25
  }
27
26
 
27
+ refreshSkillCapabilityMemories();
28
+
28
29
  return {
29
30
  content: JSON.stringify({
30
31
  deleted: true,
31
32
  skill_id: skillId.trim(),
32
- index_updated: result.indexUpdated,
33
33
  }),
34
34
  isError: false,
35
35
  };
@@ -30,7 +30,7 @@ class SkillExecuteTool implements Tool {
30
30
  activity: {
31
31
  type: "string",
32
32
  description:
33
- "Brief non-technical explanation of what you are doing and why, shown to the user as a progress update.",
33
+ "Brief non-technical explanation of what you are doing and why, shown as a progress update.",
34
34
  },
35
35
  },
36
36
  required: ["tool", "input", "activity"],
@@ -1,3 +1,4 @@
1
+ import { refreshSkillCapabilityMemories } from "../../daemon/skill-memory-refresh.js";
1
2
  import { createManagedSkill } from "../../skills/managed-store.js";
2
3
  import type { ToolContext, ToolExecutionResult } from "../types.js";
3
4
 
@@ -93,7 +94,6 @@ export async function executeScaffoldManagedSkill(
93
94
  ? sanitizeFrontmatterValue(input.emoji)
94
95
  : undefined,
95
96
  overwrite: input.overwrite === true,
96
- addToIndex: input.add_to_index !== false,
97
97
  includes,
98
98
  });
99
99
 
@@ -101,12 +101,13 @@ export async function executeScaffoldManagedSkill(
101
101
  return { content: `Error: ${result.error}`, isError: true };
102
102
  }
103
103
 
104
+ refreshSkillCapabilityMemories();
105
+
104
106
  return {
105
107
  content: JSON.stringify({
106
108
  created: true,
107
109
  skill_id: skillId.trim(),
108
110
  path: result.path,
109
- index_updated: result.indexUpdated,
110
111
  }),
111
112
  isError: false,
112
113
  };
@@ -59,7 +59,7 @@ class NotifyParentTool implements Tool {
59
59
  activity: {
60
60
  type: "string",
61
61
  description:
62
- "Brief non-technical explanation of what you are doing and why, shown to the user as a status update.",
62
+ "Brief non-technical explanation of what you are doing and why, shown as a status update.",
63
63
  },
64
64
  },
65
65
  required: ["message", "activity"],
@@ -53,7 +53,7 @@ const FRIENDLY_NAMES: Record<PermissionType, string> = {
53
53
  class RequestSystemPermissionTool implements Tool {
54
54
  name = "request_system_permission";
55
55
  description =
56
- "Ask the user to grant a macOS system permission via System Settings. " +
56
+ "Request a macOS system permission via System Settings. " +
57
57
  "Use when a tool fails with a permission/access error (e.g. 'Operation not permitted', 'EACCES', sandbox denial). " +
58
58
  "Do not explain how to open System Settings manually - this tool handles it with a clickable button.";
59
59
  category = "system";
@@ -74,7 +74,7 @@ class RequestSystemPermissionTool implements Tool {
74
74
  activity: {
75
75
  type: "string",
76
76
  description:
77
- "Short explanation of why this permission is needed (shown to the user)",
77
+ "Short explanation of why this permission is needed (shown in the prompt)",
78
78
  },
79
79
  },
80
80
  required: ["permission_type", "activity"],
@@ -46,6 +46,7 @@ export const SAFE_ENV_VARS = [
46
46
  "IS_CONTAINERIZED",
47
47
  "IS_PLATFORM",
48
48
  "VELLUM_CLOUD",
49
+ "VELLUM_SANDBOX_RUNTIME",
49
50
  "CES_SERVICE_TOKEN",
50
51
  "VELLUM_PROFILER_RUN_ID",
51
52
  "VELLUM_PROFILER_MODE",
@@ -59,6 +60,37 @@ export const SAFE_ENV_VARS = [
59
60
  "VELLUM_BACKUP_KEY_PATH",
60
61
  ] as const;
61
62
 
63
+ export const KATA_SAFE_ENV_VARS = [
64
+ "LD_LIBRARY_PATH",
65
+ "VELLUM_APT_DATA_ROOT",
66
+ "VELLUM_APT_DATA_SUITE",
67
+ "VELLUM_APT_DATA_MIRROR",
68
+ ] as const;
69
+
70
+ const KATA_APT_DATA_ROOT = "/data/system";
71
+
72
+ function kataAptPaths(dataRoot: string): string[] {
73
+ return [
74
+ `${dataRoot}/bin`,
75
+ `${dataRoot}/usr/local/sbin`,
76
+ `${dataRoot}/usr/local/bin`,
77
+ `${dataRoot}/usr/sbin`,
78
+ `${dataRoot}/usr/bin`,
79
+ `${dataRoot}/sbin`,
80
+ `${dataRoot}/usr/games`,
81
+ `${dataRoot}/games`,
82
+ ];
83
+ }
84
+
85
+ function kataAptLibraryPaths(dataRoot: string): string[] {
86
+ return [
87
+ `${dataRoot}/usr/local/lib`,
88
+ `${dataRoot}/usr/lib`,
89
+ `${dataRoot}/usr/lib/x86_64-linux-gnu`,
90
+ `${dataRoot}/usr/lib/aarch64-linux-gnu`,
91
+ ];
92
+ }
93
+
62
94
  /**
63
95
  * Keys that buildSanitizedEnv always injects into the returned env,
64
96
  * independent of what is present in process.env.
@@ -70,13 +102,40 @@ export const ALWAYS_INJECTED_ENV_VARS = [
70
102
  "VELLUM_WORKSPACE_DIR",
71
103
  ] as const;
72
104
 
105
+ function appendUniquePathEntries(
106
+ value: string | undefined,
107
+ entries: readonly string[],
108
+ ): string {
109
+ const parts = value ? value.split(":").filter(Boolean) : [];
110
+ for (const entry of entries) {
111
+ if (!parts.includes(entry)) {
112
+ parts.push(entry);
113
+ }
114
+ }
115
+ return parts.join(":");
116
+ }
117
+
73
118
  export function buildSanitizedEnv(): Record<string, string> {
74
119
  const env: Record<string, string> = {};
75
- for (const key of SAFE_ENV_VARS) {
120
+ const isKataRuntime = process.env.VELLUM_SANDBOX_RUNTIME === "kata";
121
+ const safeEnvVars = isKataRuntime
122
+ ? [...SAFE_ENV_VARS, ...KATA_SAFE_ENV_VARS]
123
+ : SAFE_ENV_VARS;
124
+
125
+ for (const key of safeEnvVars) {
76
126
  if (process.env[key] != null) {
77
127
  env[key] = process.env[key]!;
78
128
  }
79
129
  }
130
+ if (isKataRuntime) {
131
+ const kataAptDataRoot = env.VELLUM_APT_DATA_ROOT ?? KATA_APT_DATA_ROOT;
132
+ env.VELLUM_APT_DATA_ROOT = kataAptDataRoot;
133
+ env.PATH = appendUniquePathEntries(env.PATH, kataAptPaths(kataAptDataRoot));
134
+ env.LD_LIBRARY_PATH = appendUniquePathEntries(
135
+ env.LD_LIBRARY_PATH,
136
+ kataAptLibraryPaths(kataAptDataRoot),
137
+ );
138
+ }
80
139
  // Always inject an internal gateway base for local control-plane/API calls.
81
140
  const internalGatewayBase = getGatewayInternalBaseUrl();
82
141
  env.INTERNAL_GATEWAY_BASE_URL = internalGatewayBase;
@@ -11,6 +11,7 @@ import {
11
11
  isCesSecureInstallEnabled,
12
12
  isCesToolsEnabled,
13
13
  } from "../credential-execution/feature-gates.js";
14
+ import { askQuestionTool } from "./ask-question/ask-question-tool.js";
14
15
  import { makeAuthenticatedRequestTool } from "./credential-execution/make-authenticated-request.js";
15
16
  import { manageSecureCommandTool } from "./credential-execution/manage-secure-command-tool.js";
16
17
  import { runAuthenticatedCommandTool } from "./credential-execution/run-authenticated-command.js";
@@ -91,6 +92,7 @@ export const explicitTools: Tool[] = [
91
92
  recallTool,
92
93
  credentialStoreTool,
93
94
  notifyParentTool,
95
+ askQuestionTool,
94
96
  // NOTE: external skill tools (registered via registerExternalTools in
95
97
  // registry.ts) are intentionally NOT included here. `explicitTools` is a
96
98
  // module-level const whose value is fixed at first evaluation, so
@@ -75,22 +75,25 @@ export { RiskLevel } from "@vellumai/skill-host-contracts";
75
75
  // Assistant-side concrete overlays
76
76
  // ---------------------------------------------------------------------------
77
77
 
78
- export interface ToolExecutionResult {
78
+ /**
79
+ * Public, narrow subset of {@link ToolExecutionResult} that plugin-authored
80
+ * tools are responsible for producing. Re-exported from
81
+ * `@vellumai/plugin-api` as `ToolExecutionResult` — the type name plugin
82
+ * authors actually import. The daemon-internal version below extends
83
+ * this and adds runtime-only fields (risk metadata, approval
84
+ * bookkeeping, sensitive-output bindings, etc.) that the executor
85
+ * populates around the call — plugins MUST NOT set those.
86
+ *
87
+ * Adding fields here is a non-breaking change; renaming or removing
88
+ * fields is breaking and gated on a major bump of `@vellumai/plugin-api`.
89
+ */
90
+ export interface PluginToolExecutionResult {
91
+ /** Textual result shown to the model in the tool-result block. Empty string is valid. */
79
92
  content: string;
93
+ /** When true, the agent loop treats `content` as an error and may surface it / retry. */
80
94
  isError: boolean;
81
- diff?: DiffInfo;
82
- /** Optional status message for display (e.g. timeout, truncation). */
95
+ /** Optional short status message for client display (e.g. `"truncated"`, `"timed out"`). */
83
96
  status?: string;
84
- /** Optional rich content blocks (e.g. images) to include alongside text in the tool result. */
85
- contentBlocks?: ContentBlock[];
86
- /**
87
- * Runtime-internal sensitive output bindings (placeholder -> real value).
88
- * Populated by the executor when tool output contains
89
- * `<vellum-sensitive-output>` directives. The agent loop merges these
90
- * into a per-run substitution map for deterministic post-generation
91
- * replacement. MUST NOT be emitted in client-facing events or logs.
92
- */
93
- sensitiveBindings?: SensitiveOutputBinding[];
94
97
  /**
95
98
  * When true, the agent loop should yield control back to the user after
96
99
  * returning this result — tool results are pushed to history and the loop
@@ -101,6 +104,20 @@ export interface ToolExecutionResult {
101
104
  * the LLM voluntarily end its turn.
102
105
  */
103
106
  yieldToUser?: boolean;
107
+ }
108
+
109
+ export interface ToolExecutionResult extends PluginToolExecutionResult {
110
+ diff?: DiffInfo;
111
+ /** Optional rich content blocks (e.g. images) to include alongside text in the tool result. */
112
+ contentBlocks?: ContentBlock[];
113
+ /**
114
+ * Runtime-internal sensitive output bindings (placeholder -> real value).
115
+ * Populated by the executor when tool output contains
116
+ * `<vellum-sensitive-output>` directives. The agent loop merges these
117
+ * into a per-run substitution map for deterministic post-generation
118
+ * replacement. MUST NOT be emitted in client-facing events or logs.
119
+ */
120
+ sensitiveBindings?: SensitiveOutputBinding[];
104
121
  /** Risk level from the classifier (populated during permission check). */
105
122
  riskLevel?: string;
106
123
  /** Human-readable reason for the risk classification. */
@@ -190,19 +207,37 @@ export type ToolLifecycleEventHandler = (
190
207
  event: ToolLifecycleEvent,
191
208
  ) => void | Promise<void>;
192
209
 
193
- export interface ToolContext {
194
- workingDir: string;
210
+ /**
211
+ * Public, narrow subset of {@link ToolContext} handed to plugin-authored
212
+ * tools. Re-exported from `@vellumai/plugin-api` as `ToolContext` — the
213
+ * type name plugin authors actually import. The daemon-internal version
214
+ * below extends this and adds host-only fields (CES client, trust class,
215
+ * lifecycle handlers, requester metadata, host-bash proxy, etc.). Plugin
216
+ * tools see this shape only — the runtime still hands them the full
217
+ * {@link ToolContext} value, but the structural extension here guarantees
218
+ * the assignment without a manual cast.
219
+ *
220
+ * Adding fields here is a non-breaking change; renaming or removing
221
+ * fields is breaking and gated on a major bump of `@vellumai/plugin-api`.
222
+ */
223
+ export interface PluginToolContext {
224
+ /** Identifier of the conversation this tool invocation belongs to. */
195
225
  conversationId: string;
226
+ /** Working directory the daemon was launched from. */
227
+ workingDir: string;
228
+ /** Per-turn request id for cross-component log correlation. */
229
+ requestId?: string;
230
+ /** Cooperative cancellation signal for long-running tools. Tools should check `signal.aborted` periodically (or forward `signal` to fetch / child-process options). */
231
+ signal?: AbortSignal;
232
+ /** Optional incremental-output callback for streaming tools. Streaming tools should fall back to returning the full result in `content` when this is absent. */
233
+ onOutput?: (chunk: string) => void;
234
+ }
235
+
236
+ export interface ToolContext extends PluginToolContext {
196
237
  /** Logical assistant scope for multi-assistant routing. */
197
238
  assistantId?: string;
198
239
  /** When set, the tool execution is part of a task run. Used to retrieve ephemeral permission rules. */
199
240
  taskRunId?: string;
200
- /** Per-message request ID for log correlation across conversation/connection boundaries. */
201
- requestId?: string;
202
- /** Optional callback for streaming incremental output to the client. */
203
- onOutput?: (chunk: string) => void;
204
- /** Abort signal for cooperative cancellation. Tools should check this periodically. */
205
- signal?: AbortSignal;
206
241
  /** Optional callback for tool lifecycle events (start/prompt/deny/execute/error). */
207
242
  onToolLifecycleEvent?: ToolLifecycleEventHandler;
208
243
  /** Optional resolver for proxy tools - delegates execution to an external client. */
@@ -338,3 +373,19 @@ export interface Tool {
338
373
  context: ToolContext,
339
374
  ): Promise<ToolExecutionResult>;
340
375
  }
376
+
377
+ /**
378
+ * Plugin-facing tool shape. The narrow surface plugin authors implement;
379
+ * differs from {@link Tool} in three ways:
380
+ * - Plugins declare `input_schema` as a top-level field instead of
381
+ * implementing `getDefinition()`. The registration boundary synthesizes
382
+ * `getDefinition()` from `{name, description, input_schema}` before the
383
+ * tool enters the internal registry.
384
+ * - `category` is registry-owned and stamped to `"plugin"` when the tool is
385
+ * registered.
386
+ * - All ownership stamps (`origin`, `ownerPluginId`, etc.) are set
387
+ * authoritatively by the bootstrap; plugin authors leave them blank.
388
+ */
389
+ export type PluginTool = Omit<Tool, "category" | "getDefinition"> & {
390
+ input_schema: object;
391
+ };
@@ -28,7 +28,7 @@ function proxyExecute(): Promise<ToolExecutionResult> {
28
28
  export const uiShowTool: Tool = {
29
29
  name: "ui_show",
30
30
  description:
31
- "Show structured data or UI to the user. For long-form writing use the document skill; for interactive apps use the app-builder skill.\n\n" +
31
+ "Surface structured data or UI in the conversation. For long-form writing use the document skill; for interactive apps use the app-builder skill.\n\n" +
32
32
  "Surface types (data shapes):\n" +
33
33
  '- card: { title, subtitle?, body, metadata?: [{ label, value }], template?, templateData? }. Templates: "weather_forecast" (native weather widget), "task_progress" (live step tracker - update via ui_update on data.templateData; shape: { title, status: "in_progress"|"completed"|"failed", steps: [{ label, status: "pending"|"in_progress"|"completed"|"failed", detail? }] })\n' +
34
34
  '- table: { columns: [{ id, label }], rows: [{ id, cells: Record<id, string | { text, icon?, iconColor?: "success"|"warning"|"error"|"muted" }>, selectable?, selected? }], selectionMode?: "none"|"single"|"multiple", caption? }\n' +
@@ -36,7 +36,8 @@ export const uiShowTool: Tool = {
36
36
  '- list: { items: [{ id, title, subtitle?, icon?, selected? }], selectionMode: "single"|"multiple"|"none" }\n' +
37
37
  "- confirmation: { message, detail?, confirmLabel?, confirmedLabel?, cancelLabel?, destructive? }\n" +
38
38
  "- dynamic_page: { html, width?, height?, preview?: { title, subtitle?, description?, icon?, metrics?: [{ label, value }] } }\n" +
39
- "- file_upload: { prompt, acceptedTypes?, maxFiles? }",
39
+ "- file_upload: { prompt, acceptedTypes?, maxFiles? }\n\n" +
40
+ "Proactively show a task_progress card before multi-step or long-running work (web searches, file operations, research). Show it before your first tool call, then update steps as work progresses.",
40
41
  category: "ui-surface",
41
42
  defaultRiskLevel: RiskLevel.Low,
42
43
  executionMode: "proxy",
@@ -91,17 +92,17 @@ export const uiShowTool: Tool = {
91
92
  type: "string",
92
93
  enum: ["inline", "panel"],
93
94
  description:
94
- 'Where to render the surface. "inline" embeds it in the chat message. "panel" shows a floating window. Defaults to "inline". Prefer inline — only use panel when the user explicitly asks for a separate window.',
95
+ 'Where to render the surface. "inline" embeds it in the chat message. "panel" shows a floating window. Defaults to "inline". Prefer inline — only use panel when a separate window is explicitly requested.',
95
96
  },
96
97
  await_action: {
97
98
  type: "boolean",
98
99
  description:
99
- "Whether to block until the user interacts with an action. Defaults to true when actions are provided.",
100
+ "Whether to block until an action is selected. Defaults to true when actions are provided.",
100
101
  },
101
102
  persistent: {
102
103
  type: "boolean",
103
104
  description:
104
- "When true, clicking an action does not dismiss the surface — the card stays visible and only the clicked action is marked as spent. Use for launcher or menu-style cards where the user may click multiple buttons. Defaults to false.",
105
+ "When true, clicking an action does not dismiss the surface — the card stays visible and only the clicked action is marked as spent. Use for launcher or menu-style cards where multiple buttons may be clicked. Defaults to false.",
105
106
  },
106
107
  },
107
108
  required: ["surface_type", "data"],
@@ -114,8 +114,11 @@ import {
114
114
  createDeepgramProvider,
115
115
  DeepgramTtsError,
116
116
  } from "../providers/deepgram-provider.js";
117
- import { createElevenLabsProvider } from "../providers/elevenlabs-provider.js";
118
- import { ElevenLabsTtsError } from "../providers/elevenlabs-provider.js";
117
+ import {
118
+ createElevenLabsProvider,
119
+ ElevenLabsTtsError,
120
+ extractElevenLabsErrorMessage,
121
+ } from "../providers/elevenlabs-provider.js";
119
122
  import { createFishAudioProvider } from "../providers/fish-audio-provider.js";
120
123
  import { FishAudioTtsError } from "../providers/fish-audio-provider.js";
121
124
  import { providerFactories } from "../providers/index.js";
@@ -396,6 +399,77 @@ describe("ElevenLabs TTS provider adapter", () => {
396
399
  );
397
400
  }
398
401
  });
402
+
403
+ // -- Upstream error-body extraction --------------------------------------
404
+
405
+ describe("extractElevenLabsErrorMessage", () => {
406
+ test("extracts message from standard { detail: { message } } shape", () => {
407
+ const body = JSON.stringify({
408
+ detail: {
409
+ type: "payment_required",
410
+ code: "paid_plan_required",
411
+ message:
412
+ "Free users cannot use library voices via the API. Please upgrade your subscription to use this voice.",
413
+ status: "payment_required",
414
+ },
415
+ });
416
+ expect(extractElevenLabsErrorMessage(body)).toBe(
417
+ "Free users cannot use library voices via the API. Please upgrade your subscription to use this voice.",
418
+ );
419
+ });
420
+
421
+ test("falls back to { detail: '...' } when detail is a string", () => {
422
+ const body = JSON.stringify({ detail: "Voice not found" });
423
+ expect(extractElevenLabsErrorMessage(body)).toBe("Voice not found");
424
+ });
425
+
426
+ test("falls back to { message: '...' } when present", () => {
427
+ const body = JSON.stringify({ message: "Quota exceeded" });
428
+ expect(extractElevenLabsErrorMessage(body)).toBe("Quota exceeded");
429
+ });
430
+
431
+ test("returns trimmed raw body when not JSON", () => {
432
+ expect(extractElevenLabsErrorMessage(" upstream timeout ")).toBe(
433
+ "upstream timeout",
434
+ );
435
+ });
436
+
437
+ test("truncates oversized raw bodies", () => {
438
+ const long = "x".repeat(1000);
439
+ const result = extractElevenLabsErrorMessage(long);
440
+ expect(result).not.toBeUndefined();
441
+ // 200-char limit plus an ellipsis character.
442
+ expect(result!.length).toBeLessThanOrEqual(201);
443
+ expect(result!.endsWith("…")).toBe(true);
444
+ });
445
+
446
+ test("returns undefined for empty input", () => {
447
+ expect(extractElevenLabsErrorMessage("")).toBeUndefined();
448
+ expect(extractElevenLabsErrorMessage(" \n ")).toBeUndefined();
449
+ });
450
+
451
+ test("returns truncated raw body when JSON is malformed", () => {
452
+ // Not valid JSON despite the leading `{` — falls through to raw fallback.
453
+ const body = "{not really json}";
454
+ expect(extractElevenLabsErrorMessage(body)).toBe("{not really json}");
455
+ });
456
+
457
+ test("ignores empty-string message fields", () => {
458
+ const body = JSON.stringify({ detail: { message: " " } });
459
+ // Falls through to top-level message — also absent — then to raw body.
460
+ const result = extractElevenLabsErrorMessage(body);
461
+ expect(result).not.toBeUndefined();
462
+ // Raw body fallback contains the JSON text itself.
463
+ expect(result).toContain("detail");
464
+ });
465
+
466
+ test("trims whitespace from extracted messages", () => {
467
+ const body = JSON.stringify({
468
+ detail: { message: " hello world " },
469
+ });
470
+ expect(extractElevenLabsErrorMessage(body)).toBe("hello world");
471
+ });
472
+ });
399
473
  });
400
474
 
401
475
  // ===========================================================================
@@ -49,6 +49,73 @@ export class ElevenLabsTtsError extends Error {
49
49
  }
50
50
  }
51
51
 
52
+ // ---------------------------------------------------------------------------
53
+ // Error-body parser
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /** Maximum number of characters of a fallback raw body to surface in an error message. */
57
+ const MAX_RAW_ERROR_BODY_CHARS = 200;
58
+
59
+ /**
60
+ * Best-effort extraction of a user-facing error message from an ElevenLabs
61
+ * error response body.
62
+ *
63
+ * ElevenLabs returns structured errors in the shape:
64
+ * ```json
65
+ * { "detail": { "status": "...", "code": "...", "message": "..." } }
66
+ * ```
67
+ * but also occasionally returns `{ "message": "..." }`, `{ "detail": "..." }`,
68
+ * HTML pages (502/503 from their CDN), or free-form text. We try the
69
+ * structured shapes first, fall back to a trimmed/truncated raw body, and
70
+ * return `undefined` when nothing useful is present.
71
+ *
72
+ * Exported for unit testing.
73
+ */
74
+ export function extractElevenLabsErrorMessage(
75
+ body: string,
76
+ ): string | undefined {
77
+ if (!body) return undefined;
78
+ const trimmed = body.trim();
79
+ if (!trimmed) return undefined;
80
+
81
+ // Try JSON envelopes first.
82
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
83
+ try {
84
+ const parsed = JSON.parse(trimmed) as unknown;
85
+ if (parsed && typeof parsed === "object") {
86
+ const root = parsed as { detail?: unknown; message?: unknown };
87
+
88
+ // Standard ElevenLabs shape: { detail: { message } }
89
+ if (root.detail && typeof root.detail === "object") {
90
+ const detailMessage = (root.detail as { message?: unknown }).message;
91
+ if (typeof detailMessage === "string" && detailMessage.trim()) {
92
+ return detailMessage.trim();
93
+ }
94
+ }
95
+
96
+ // Fallback shape: { detail: "..." }
97
+ if (typeof root.detail === "string" && root.detail.trim()) {
98
+ return root.detail.trim();
99
+ }
100
+
101
+ // Fallback shape: { message: "..." }
102
+ if (typeof root.message === "string" && root.message.trim()) {
103
+ return root.message.trim();
104
+ }
105
+ }
106
+ } catch {
107
+ // Not valid JSON — fall through to the raw-body fallback.
108
+ }
109
+ }
110
+
111
+ // Raw body fallback (HTML pages, plain text). Truncate to keep error
112
+ // messages reasonable when surfaced to UI clients.
113
+ if (trimmed.length > MAX_RAW_ERROR_BODY_CHARS) {
114
+ return `${trimmed.slice(0, MAX_RAW_ERROR_BODY_CHARS)}…`;
115
+ }
116
+ return trimmed;
117
+ }
118
+
52
119
  // ---------------------------------------------------------------------------
53
120
  // Constants
54
121
  // ---------------------------------------------------------------------------
@@ -180,9 +247,16 @@ export function createElevenLabsProvider(): TtsProvider {
180
247
 
181
248
  if (!response.ok) {
182
249
  const errorText = await response.text().catch(() => "");
250
+ // Surface the upstream provider message verbatim when extractable —
251
+ // the daemon route wraps it with a single "TTS synthesis failed:"
252
+ // prefix on the way out. The HTTP status is preserved on `statusCode`
253
+ // and logged by the daemon, so we don't embed it in the message text.
254
+ const message =
255
+ extractElevenLabsErrorMessage(errorText) ??
256
+ `ElevenLabs returned HTTP ${response.status}`;
183
257
  throw new ElevenLabsTtsError(
184
258
  "ELEVENLABS_TTS_HTTP_ERROR",
185
- `ElevenLabs TTS returned ${response.status}: ${errorText}`,
259
+ message,
186
260
  response.status,
187
261
  );
188
262
  }
@@ -4,4 +4,6 @@ export interface OnboardingContext {
4
4
  tone: string;
5
5
  userName?: string;
6
6
  assistantName?: string;
7
+ googleConnected?: boolean;
8
+ googleScopes?: string[];
7
9
  }