@vellumai/assistant 0.8.1 → 0.8.3

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 (630) hide show
  1. package/ARCHITECTURE.md +13 -19
  2. package/Dockerfile +75 -1
  3. package/bun.lock +11 -1
  4. package/docker-entrypoint.sh +17 -0
  5. package/docker-init-apt-root.sh +167 -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 +642 -5
  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-loop-exit-reason.test.ts +272 -0
  21. package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  23. package/src/__tests__/anthropic-provider.test.ts +45 -0
  24. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  25. package/src/__tests__/app-executors.test.ts +220 -4
  26. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  27. package/src/__tests__/bundled-asset.test.ts +6 -6
  28. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  29. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  30. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  31. package/src/__tests__/clawhub.test.ts +75 -16
  32. package/src/__tests__/compactor-tail-resolution.test.ts +147 -0
  33. package/src/__tests__/config-get-vision-flag.test.ts +136 -0
  34. package/src/__tests__/config-loader-backfill.test.ts +115 -18
  35. package/src/__tests__/config-schema.test.ts +21 -0
  36. package/src/__tests__/config-set-route.test.ts +80 -0
  37. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  38. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  39. package/src/__tests__/context-search-conversations-source.test.ts +117 -2
  40. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  41. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  42. package/src/__tests__/context-token-estimator.test.ts +31 -65
  43. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  44. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  45. package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
  46. package/src/__tests__/conversation-agent-loop.test.ts +59 -1
  47. package/src/__tests__/conversation-error.test.ts +42 -3
  48. package/src/__tests__/conversation-fork-crud.test.ts +82 -0
  49. package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
  50. package/src/__tests__/conversation-lifecycle.test.ts +173 -0
  51. package/src/__tests__/conversation-media-retry.test.ts +19 -8
  52. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  53. package/src/__tests__/conversation-pairing.test.ts +54 -0
  54. package/src/__tests__/conversation-process-callsite.test.ts +4 -1
  55. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  56. package/src/__tests__/conversation-queue.test.ts +4 -1
  57. package/src/__tests__/conversation-runtime-assembly.test.ts +102 -13
  58. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  59. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  60. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  61. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  62. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  63. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  64. package/src/__tests__/credential-security-invariants.test.ts +3 -2
  65. package/src/__tests__/date-context.test.ts +45 -0
  66. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  67. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  68. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  69. package/src/__tests__/dm-backfill.test.ts +121 -10
  70. package/src/__tests__/document-tool-security.test.ts +258 -0
  71. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  72. package/src/__tests__/edit-propagation.test.ts +33 -0
  73. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  74. package/src/__tests__/external-plugin-loader.test.ts +151 -55
  75. package/src/__tests__/filing-service.test.ts +140 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  77. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
  78. package/src/__tests__/guardian-dispatch.test.ts +1 -0
  79. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
  80. package/src/__tests__/heartbeat-service.test.ts +24 -164
  81. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  82. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  83. package/src/__tests__/helpers/wait-for.ts +21 -0
  84. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  85. package/src/__tests__/history-repair.test.ts +73 -0
  86. package/src/__tests__/host-app-control-proxy.test.ts +507 -10
  87. package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
  88. package/src/__tests__/image-credentials.test.ts +1 -1
  89. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  90. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
  91. package/src/__tests__/inference-profile-reaper.test.ts +4 -2
  92. package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
  93. package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
  94. package/src/__tests__/injector-background-turn.test.ts +153 -0
  95. package/src/__tests__/injector-chain.test.ts +15 -8
  96. package/src/__tests__/install-skill-routing.test.ts +155 -37
  97. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +99 -3
  98. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  99. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  100. package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
  101. package/src/__tests__/llm-catalog-parity.test.ts +58 -13
  102. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
  103. package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
  104. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +36 -0
  105. package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
  106. package/src/__tests__/llm-resolver.test.ts +255 -2
  107. package/src/__tests__/llm-usage-store.test.ts +114 -0
  108. package/src/__tests__/managed-profile-guard.test.ts +41 -29
  109. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  110. package/src/__tests__/managed-store.test.ts +84 -192
  111. package/src/__tests__/media-generate-image.test.ts +1 -1
  112. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  113. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  114. package/src/__tests__/notification-decision-fallback.test.ts +0 -91
  115. package/src/__tests__/notification-decision-strategy.test.ts +14 -31
  116. package/src/__tests__/notification-deep-link.test.ts +15 -0
  117. package/src/__tests__/notification-guardian-path.test.ts +1 -2
  118. package/src/__tests__/notification-platform-adapter.test.ts +5 -4
  119. package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
  120. package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
  121. package/src/__tests__/oauth-commands-routes.test.ts +168 -16
  122. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  123. package/src/__tests__/openai-provider.test.ts +242 -3
  124. package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
  125. package/src/__tests__/openrouter-provider-only.test.ts +51 -3
  126. package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
  127. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  128. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  129. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +7 -2
  130. package/src/__tests__/platform.test.ts +2 -0
  131. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  132. package/src/__tests__/plugin-bootstrap.test.ts +10 -36
  133. package/src/__tests__/plugin-external-api.test.ts +68 -0
  134. package/src/__tests__/plugin-registry.test.ts +0 -77
  135. package/src/__tests__/plugin-route-contribution.test.ts +0 -1
  136. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  137. package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
  138. package/src/__tests__/plugin-types.test.ts +3 -13
  139. package/src/__tests__/process-message-background-slack.test.ts +8 -1
  140. package/src/__tests__/process-message-display-content.test.ts +421 -0
  141. package/src/__tests__/provider-catalog-visibility.test.ts +158 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  143. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +33 -31
  144. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  145. package/src/__tests__/schedule-routes.test.ts +50 -3
  146. package/src/__tests__/schedule-store.test.ts +94 -0
  147. package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
  148. package/src/__tests__/schema-transforms.test.ts +20 -0
  149. package/src/__tests__/search-skills-unified.test.ts +0 -5
  150. package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +1 -1
  151. package/src/__tests__/server-history-render.test.ts +43 -0
  152. package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
  153. package/src/__tests__/skill-load-tool.test.ts +27 -89
  154. package/src/__tests__/skill-memory.test.ts +23 -3
  155. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  156. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  157. package/src/__tests__/skills-install-extract.test.ts +49 -38
  158. package/src/__tests__/skills-install-staging.test.ts +159 -0
  159. package/src/__tests__/skills-uninstall.test.ts +9 -41
  160. package/src/__tests__/skills.test.ts +51 -58
  161. package/src/__tests__/slack-channel-config.test.ts +9 -0
  162. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  163. package/src/__tests__/system-prompt.test.ts +670 -63
  164. package/src/__tests__/terminal-tools.test.ts +28 -1
  165. package/src/__tests__/thread-backfill.test.ts +557 -27
  166. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  167. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  168. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  169. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  170. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  171. package/src/__tests__/tool-executor.test.ts +16 -4
  172. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  173. package/src/__tests__/turn-events-store.test.ts +256 -0
  174. package/src/__tests__/twilio-routes.test.ts +4 -0
  175. package/src/__tests__/user-plugin-loader.test.ts +0 -7
  176. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  177. package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
  178. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
  179. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
  180. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  181. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  182. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  183. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
  184. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  185. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  186. package/src/a2a/__tests__/agent-card.test.ts +98 -0
  187. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
  188. package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
  189. package/src/a2a/__tests__/task-store.test.ts +246 -0
  190. package/src/a2a/agent-card.ts +58 -0
  191. package/src/a2a/feature-gate.ts +8 -0
  192. package/src/a2a/protocol-constants.ts +21 -0
  193. package/src/a2a/protocol-errors.ts +50 -0
  194. package/src/a2a/protocol-types.ts +162 -0
  195. package/src/a2a/task-store.ts +168 -0
  196. package/src/acp/resolve-agent.ts +1 -1
  197. package/src/agent/image-optimize.ts +13 -5
  198. package/src/agent/loop.ts +167 -18
  199. package/src/calls/voice-session-bridge.ts +61 -42
  200. package/src/channels/config.ts +9 -0
  201. package/src/channels/types.ts +122 -0
  202. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  203. package/src/cli/commands/__tests__/changelog.test.ts +304 -319
  204. package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
  205. package/src/cli/commands/__tests__/schedules.test.ts +960 -0
  206. package/src/cli/commands/changelog.ts +106 -42
  207. package/src/cli/commands/conversations.ts +102 -17
  208. package/src/cli/commands/default-action.ts +10 -53
  209. package/src/cli/commands/notifications.ts +388 -346
  210. package/src/cli/commands/plugins.ts +252 -0
  211. package/src/cli/commands/schedules.ts +683 -0
  212. package/src/cli/commands/telemetry.ts +40 -0
  213. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  214. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  215. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  216. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  217. package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
  218. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  219. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  220. package/src/cli/lib/cli-colors.ts +12 -0
  221. package/src/cli/lib/confirm-prompt.ts +79 -0
  222. package/src/cli/lib/install-from-github.ts +303 -0
  223. package/src/cli/lib/list-installed-plugins.ts +137 -0
  224. package/src/cli/lib/search-plugins.ts +163 -0
  225. package/src/cli/lib/uninstall-plugin.ts +82 -0
  226. package/src/cli/lib/unknown-command.ts +111 -0
  227. package/src/cli/program.ts +52 -2
  228. package/src/config/assistant-feature-flags.ts +24 -54
  229. package/src/config/bundled-skills/app-builder/SKILL.md +140 -22
  230. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  231. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  232. package/src/config/bundled-skills/document/SKILL.md +23 -3
  233. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  234. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  235. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  236. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  237. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  238. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  239. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  240. package/src/config/bundled-tool-registry.ts +6 -0
  241. package/src/config/call-site-defaults.ts +105 -0
  242. package/src/config/feature-flag-registry.json +41 -9
  243. package/src/config/llm-resolver.ts +52 -1
  244. package/src/config/loader.ts +64 -38
  245. package/src/config/schema.ts +9 -10
  246. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  247. package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
  248. package/src/config/schemas/channels.ts +17 -0
  249. package/src/config/schemas/compaction.ts +28 -0
  250. package/src/config/schemas/conversations.ts +10 -0
  251. package/src/config/schemas/heartbeat.ts +23 -0
  252. package/src/config/schemas/llm-request-logs.ts +31 -7
  253. package/src/config/schemas/llm.ts +1 -0
  254. package/src/config/schemas/memory-retrieval.ts +18 -0
  255. package/src/config/schemas/memory-retrospective.ts +1 -1
  256. package/src/config/schemas/memory-v2.ts +4 -4
  257. package/src/config/schemas/memory.ts +3 -1
  258. package/src/config/schemas/tools.ts +14 -0
  259. package/src/config/seed-inference-profiles.ts +99 -29
  260. package/src/config/skills.ts +3 -96
  261. package/src/context/compactor.ts +1107 -0
  262. package/src/context/token-estimator.ts +34 -36
  263. package/src/context/window-manager.ts +197 -1520
  264. package/src/credential-execution/managed-catalog.ts +37 -0
  265. package/src/credential-health/credential-health-service.ts +280 -19
  266. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +33 -18
  267. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  268. package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
  269. package/src/daemon/approval-generators.ts +8 -6
  270. package/src/daemon/config-watcher.ts +94 -31
  271. package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
  272. package/src/daemon/conversation-agent-loop.ts +198 -11
  273. package/src/daemon/conversation-error.ts +171 -37
  274. package/src/daemon/conversation-lifecycle.ts +53 -40
  275. package/src/daemon/conversation-messaging.ts +25 -6
  276. package/src/daemon/conversation-process.ts +49 -12
  277. package/src/daemon/conversation-runtime-assembly.ts +25 -1
  278. package/src/daemon/conversation-slash.ts +12 -5
  279. package/src/daemon/conversation-store.ts +11 -4
  280. package/src/daemon/conversation-tool-setup.ts +39 -7
  281. package/src/daemon/conversation.ts +33 -8
  282. package/src/daemon/date-context.ts +40 -0
  283. package/src/daemon/external-plugins-bootstrap.ts +217 -181
  284. package/src/daemon/first-greeting.ts +22 -2
  285. package/src/daemon/guardian-action-generators.ts +1 -125
  286. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
  287. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
  288. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
  289. package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
  290. package/src/daemon/handlers/config-a2a.ts +289 -0
  291. package/src/daemon/handlers/config-model.ts +6 -5
  292. package/src/daemon/handlers/config-slack-channel.ts +15 -3
  293. package/src/daemon/handlers/conversations.ts +1 -0
  294. package/src/daemon/handlers/shared.ts +14 -5
  295. package/src/daemon/handlers/skills.ts +111 -108
  296. package/src/daemon/history-repair.ts +28 -1
  297. package/src/daemon/host-app-control-proxy.ts +153 -27
  298. package/src/daemon/host-proxy-preactivation.ts +85 -18
  299. package/src/daemon/lifecycle.ts +89 -91
  300. package/src/daemon/meet-host-supervisor.ts +5 -4
  301. package/src/daemon/memory-v2-startup.ts +85 -0
  302. package/src/daemon/message-protocol.ts +1 -0
  303. package/src/daemon/message-types/conversations.ts +25 -0
  304. package/src/daemon/message-types/messages.ts +61 -0
  305. package/src/daemon/message-types/notifications.ts +21 -0
  306. package/src/daemon/message-types/subagents.ts +1 -0
  307. package/src/daemon/message-types/sync.ts +1 -0
  308. package/src/daemon/pkb-reminder-builder.test.ts +11 -54
  309. package/src/daemon/pkb-reminder-builder.ts +5 -20
  310. package/src/daemon/plugin-source-watcher.ts +146 -0
  311. package/src/daemon/process-message.ts +24 -3
  312. package/src/daemon/server.ts +11 -2
  313. package/src/daemon/skill-memory-refresh.ts +33 -0
  314. package/src/daemon/wake-target-adapter.ts +2 -0
  315. package/src/documents/document-store.ts +221 -3
  316. package/src/embedded/plugin-api.ts +40 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +121 -0
  318. package/src/export/transcript-formatter.ts +54 -20
  319. package/src/filing/filing-service.ts +39 -0
  320. package/src/heartbeat/__tests__/heartbeat-service.test.ts +135 -6
  321. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  322. package/src/heartbeat/heartbeat-service.ts +73 -189
  323. package/src/home/__tests__/feed-types.test.ts +80 -0
  324. package/src/home/feed-types.ts +36 -2
  325. package/src/home/post-connect-feed.ts +1 -0
  326. package/src/index.ts +18 -1
  327. package/src/ipc/cli-client.ts +147 -45
  328. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  329. package/src/mcp/client.ts +20 -4
  330. package/src/media/image-credentials.ts +3 -3
  331. package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
  332. package/src/memory/__tests__/conversation-queries.test.ts +483 -0
  333. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  334. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
  335. package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
  336. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
  337. package/src/memory/__tests__/message-content.test.ts +35 -0
  338. package/src/memory/bookmark-crud.ts +42 -10
  339. package/src/memory/context-search/sources/conversations.ts +62 -2
  340. package/src/memory/context-search/sources/workspace.ts +4 -0
  341. package/src/memory/conversation-crud.ts +63 -19
  342. package/src/memory/conversation-queries.ts +197 -11
  343. package/src/memory/conversation-title-service.ts +26 -4
  344. package/src/memory/db-init.ts +12 -0
  345. package/src/memory/delivery-crud.ts +152 -5
  346. package/src/memory/embedding-backend.ts +4 -4
  347. package/src/memory/external-conversation-store.ts +66 -5
  348. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +150 -12
  349. package/src/memory/graph/conversation-graph-memory.ts +49 -21
  350. package/src/memory/graph/tools.ts +9 -40
  351. package/src/memory/indexer.ts +34 -29
  352. package/src/memory/invite-store.ts +53 -0
  353. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
  354. package/src/memory/jobs/embed-concept-page.ts +20 -11
  355. package/src/memory/jobs-worker.ts +6 -1
  356. package/src/memory/llm-request-log-source-clickhouse.ts +24 -12
  357. package/src/memory/llm-request-log-source.ts +19 -52
  358. package/src/memory/llm-request-log-store.ts +92 -1
  359. package/src/memory/llm-usage-store.ts +125 -5
  360. package/src/memory/memory-retrospective-enqueue.ts +1 -20
  361. package/src/memory/memory-retrospective-job.ts +33 -6
  362. package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
  363. package/src/memory/message-content.ts +1 -1
  364. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  365. package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
  366. package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
  367. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  368. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  369. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  370. package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
  371. package/src/memory/migrations/251-a2a-tasks.ts +49 -0
  372. package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
  373. package/src/memory/migrations/index.ts +9 -0
  374. package/src/memory/migrations/registry.ts +16 -0
  375. package/src/memory/onboarding-events-store.ts +106 -0
  376. package/src/memory/schema/a2a.ts +15 -0
  377. package/src/memory/schema/bookmarks.ts +0 -2
  378. package/src/memory/schema/calls.ts +1 -0
  379. package/src/memory/schema/index.ts +1 -0
  380. package/src/memory/schema/inference.ts +3 -3
  381. package/src/memory/schema/infrastructure.ts +13 -0
  382. package/src/memory/turn-events-store.ts +127 -2
  383. package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
  384. package/src/memory/v2/__tests__/activation.test.ts +0 -8
  385. package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
  386. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
  387. package/src/memory/v2/__tests__/injection.test.ts +288 -11
  388. package/src/memory/v2/__tests__/migration.test.ts +87 -0
  389. package/src/memory/v2/__tests__/page-index.test.ts +83 -0
  390. package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
  391. package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
  392. package/src/memory/v2/__tests__/router.test.ts +15 -0
  393. package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
  394. package/src/memory/v2/__tests__/static-context.test.ts +12 -1
  395. package/src/memory/v2/activation-store.ts +14 -16
  396. package/src/memory/v2/cli-command-content.ts +19 -0
  397. package/src/memory/v2/cli-command-store.ts +304 -0
  398. package/src/memory/v2/frontmatter-sweep.ts +7 -1
  399. package/src/memory/v2/injection.ts +81 -26
  400. package/src/memory/v2/migration.ts +49 -19
  401. package/src/memory/v2/page-index.ts +63 -8
  402. package/src/memory/v2/prompts/router.ts +11 -8
  403. package/src/memory/v2/prompts/sweep.ts +2 -2
  404. package/src/memory/v2/qdrant.ts +135 -7
  405. package/src/memory/v2/router.ts +9 -8
  406. package/src/memory/v2/skill-store.ts +120 -35
  407. package/src/memory/v2/static-context.ts +4 -4
  408. package/src/memory/v2/types.ts +23 -0
  409. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
  410. package/src/messaging/providers/a2a/deliver.ts +156 -0
  411. package/src/messaging/providers/gmail/client.ts +9 -2
  412. package/src/messaging/providers/index.ts +11 -2
  413. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  414. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  415. package/src/messaging/providers/slack/adapter.ts +43 -5
  416. package/src/messaging/providers/slack/client.ts +27 -0
  417. package/src/messaging/providers/slack/deep-link.ts +65 -0
  418. package/src/messaging/providers/slack/download.ts +104 -0
  419. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  420. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  421. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  422. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  423. package/src/messaging/providers/slack/types.ts +20 -1
  424. package/src/notifications/__tests__/broadcaster.test.ts +203 -0
  425. package/src/notifications/__tests__/decision-engine.test.ts +283 -0
  426. package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
  427. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  428. package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
  429. package/src/notifications/adapters/macos.ts +12 -2
  430. package/src/notifications/broadcaster.ts +29 -4
  431. package/src/notifications/conversation-pairing.ts +2 -1
  432. package/src/notifications/copy-composer.ts +17 -64
  433. package/src/notifications/decision-engine.ts +113 -45
  434. package/src/notifications/deterministic-checks.ts +96 -0
  435. package/src/notifications/emit-signal.ts +21 -1
  436. package/src/notifications/home-feed-side-effect.ts +138 -5
  437. package/src/notifications/signal.ts +3 -5
  438. package/src/notifications/types.ts +8 -0
  439. package/src/oauth/connection-resolver.ts +8 -4
  440. package/src/oauth/platform-connection.test.ts +43 -3
  441. package/src/oauth/platform-connection.ts +19 -6
  442. package/src/oauth/seed-providers.ts +10 -1
  443. package/src/permissions/checker.ts +2 -0
  444. package/src/permissions/ipc-risk-types.ts +1 -0
  445. package/src/permissions/question-prompter.test.ts +416 -0
  446. package/src/permissions/question-prompter.ts +294 -0
  447. package/src/platform/client.test.ts +1 -1
  448. package/src/platform/client.ts +1 -1
  449. package/src/plugin-api/constants.ts +26 -0
  450. package/src/plugin-api/index.ts +34 -1
  451. package/src/plugin-api/types.ts +104 -22
  452. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  453. package/src/plugins/defaults/compaction.ts +0 -4
  454. package/src/plugins/defaults/empty-response.ts +0 -2
  455. package/src/plugins/defaults/history-repair.ts +0 -2
  456. package/src/plugins/defaults/injectors.ts +74 -22
  457. package/src/plugins/defaults/llm-call.ts +0 -2
  458. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  459. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  460. package/src/plugins/defaults/persistence.ts +0 -2
  461. package/src/plugins/defaults/title-generate.ts +0 -5
  462. package/src/plugins/defaults/token-estimate.ts +0 -2
  463. package/src/plugins/defaults/tool-error.ts +0 -7
  464. package/src/plugins/defaults/tool-execute.ts +0 -2
  465. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  466. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  467. package/src/plugins/external-api.ts +104 -0
  468. package/src/plugins/external-plugin-loader.ts +187 -42
  469. package/src/plugins/feature-gate.ts +22 -0
  470. package/src/plugins/pipeline.ts +37 -0
  471. package/src/plugins/registry.ts +48 -80
  472. package/src/plugins/types.ts +40 -26
  473. package/src/plugins/user-loader.ts +21 -2
  474. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  475. package/src/proactive-artifact/job.test.ts +37 -5
  476. package/src/prompts/__tests__/system-prompt.test.ts +10 -43
  477. package/src/prompts/__tests__/task-progress-hint-section.test.ts +95 -0
  478. package/src/prompts/normalize-onboarding.ts +27 -0
  479. package/src/prompts/sections.ts +302 -0
  480. package/src/prompts/system-prompt.ts +63 -174
  481. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  482. package/src/prompts/templates/system-sections.ts +164 -0
  483. package/src/providers/__tests__/inference.test.ts +24 -7
  484. package/src/providers/anthropic/client.ts +28 -28
  485. package/src/providers/call-site-routing.ts +24 -6
  486. package/src/providers/connection-resolution.ts +68 -11
  487. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
  488. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
  489. package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
  490. package/src/providers/inference/adapter-factory.ts +32 -6
  491. package/src/providers/inference/auth.ts +12 -0
  492. package/src/providers/inference/backfill.ts +14 -1
  493. package/src/providers/inference/connections.ts +159 -34
  494. package/src/providers/inference/resolve-auth.ts +14 -4
  495. package/src/providers/model-catalog.ts +249 -12
  496. package/src/providers/model-intents.ts +3 -3
  497. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
  498. package/src/providers/openai/chat-completions-provider.ts +169 -8
  499. package/src/providers/openrouter/client.ts +49 -4
  500. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -2
  501. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  502. package/src/providers/provider-availability.ts +17 -2
  503. package/src/providers/provider-catalog-visibility.ts +38 -0
  504. package/src/providers/provider-send-message.ts +27 -12
  505. package/src/providers/registry.ts +52 -15
  506. package/src/providers/retry.ts +47 -1
  507. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  508. package/src/runtime/agent-wake.ts +103 -15
  509. package/src/runtime/auth/route-policy.ts +21 -1
  510. package/src/runtime/btw-sidechain.ts +2 -0
  511. package/src/runtime/http-server.ts +7 -16
  512. package/src/runtime/http-types.ts +19 -47
  513. package/src/runtime/migrations/origin-mode.ts +1 -1
  514. package/src/runtime/pending-interactions.ts +1 -0
  515. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
  516. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
  517. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
  518. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +172 -23
  519. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
  520. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
  521. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  522. package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
  523. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  524. package/src/runtime/routes/acp-routes.ts +5 -3
  525. package/src/runtime/routes/auth-routes.ts +1 -1
  526. package/src/runtime/routes/bookmark-routes.ts +5 -3
  527. package/src/runtime/routes/btw-routes.ts +5 -1
  528. package/src/runtime/routes/channel-availability-routes.ts +126 -0
  529. package/src/runtime/routes/consolidation-routes.ts +100 -0
  530. package/src/runtime/routes/conversation-cli-routes.ts +44 -3
  531. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  532. package/src/runtime/routes/conversation-management-routes.ts +17 -42
  533. package/src/runtime/routes/conversation-query-routes.ts +99 -35
  534. package/src/runtime/routes/conversation-routes.ts +97 -11
  535. package/src/runtime/routes/documents-routes.ts +25 -86
  536. package/src/runtime/routes/group-routes.ts +5 -0
  537. package/src/runtime/routes/inbound-conversation.ts +28 -8
  538. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  539. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
  540. package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
  541. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  542. package/src/runtime/routes/index.ts +8 -0
  543. package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
  544. package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
  545. package/src/runtime/routes/inference-provider-connection-routes.ts +199 -22
  546. package/src/runtime/routes/integrations/a2a.ts +235 -0
  547. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  548. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  549. package/src/runtime/routes/integrations/twilio.ts +6 -13
  550. package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
  551. package/src/runtime/routes/notification-routes.ts +1 -1
  552. package/src/runtime/routes/oauth-commands-routes.ts +105 -15
  553. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  554. package/src/runtime/routes/question-routes.ts +259 -0
  555. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  556. package/src/runtime/routes/schedule-routes.ts +4 -7
  557. package/src/runtime/routes/subagents-routes.ts +98 -18
  558. package/src/runtime/routes/telemetry-routes.ts +27 -0
  559. package/src/runtime/routes/tts-routes.ts +27 -2
  560. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  561. package/src/runtime/routes/workspace-routes.ts +28 -0
  562. package/src/runtime/services/conversation-serializer.ts +39 -7
  563. package/src/runtime/sync/resource-sync-events.ts +93 -1
  564. package/src/schedule/schedule-store.ts +27 -2
  565. package/src/schedule/scheduler.ts +9 -1
  566. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  567. package/src/security/untrusted-content.ts +93 -8
  568. package/src/skills/catalog-files.ts +1 -1
  569. package/src/skills/catalog-install.ts +233 -116
  570. package/src/skills/clawhub.ts +70 -13
  571. package/src/skills/managed-store.ts +4 -119
  572. package/src/skills/skillssh-registry.ts +27 -48
  573. package/src/subagent/manager.ts +17 -7
  574. package/src/telemetry/types.ts +113 -1
  575. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  576. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  577. package/src/tools/apps/executors.ts +58 -7
  578. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  579. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  580. package/src/tools/browser/browser-execution.ts +15 -11
  581. package/src/tools/computer-use/definitions.ts +3 -3
  582. package/src/tools/credentials/vault.ts +1 -1
  583. package/src/tools/document/document-tool.ts +124 -1
  584. package/src/tools/filesystem/edit.ts +1 -1
  585. package/src/tools/filesystem/list.ts +1 -1
  586. package/src/tools/filesystem/read.ts +1 -1
  587. package/src/tools/filesystem/write.ts +5 -2
  588. package/src/tools/host-filesystem/transfer.ts +1 -1
  589. package/src/tools/host-terminal/host-shell.ts +1 -1
  590. package/src/tools/memory/register.ts +1 -9
  591. package/src/tools/permission-checker.ts +1 -1
  592. package/src/tools/registry.ts +17 -7
  593. package/src/tools/schedule/create.ts +2 -2
  594. package/src/tools/schema-transforms.ts +7 -2
  595. package/src/tools/side-effects.ts +1 -0
  596. package/src/tools/skills/delete-managed.ts +4 -4
  597. package/src/tools/skills/execute.ts +1 -1
  598. package/src/tools/skills/scaffold-managed.ts +3 -2
  599. package/src/tools/subagent/notify-parent.ts +1 -1
  600. package/src/tools/system/request-permission.ts +2 -2
  601. package/src/tools/terminal/safe-env.ts +60 -1
  602. package/src/tools/tool-manifest.ts +2 -0
  603. package/src/tools/types.ts +107 -21
  604. package/src/tools/ui-surface/definitions.ts +6 -5
  605. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  606. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  607. package/src/types/onboarding-context.ts +2 -0
  608. package/src/util/errors.ts +17 -0
  609. package/src/util/platform.ts +10 -0
  610. package/src/watcher/__tests__/engine.test.ts +22 -0
  611. package/src/watcher/engine.ts +6 -2
  612. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
  613. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
  614. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
  615. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  616. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  617. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  618. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  619. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
  620. package/src/workspace/migrations/registry.ts +10 -0
  621. package/src/workspace/migrations/runner.ts +39 -9
  622. package/src/workspace/migrations/types.ts +4 -0
  623. package/examples/plugins/echo/bun.lock +0 -25
  624. package/src/__tests__/context-window-manager.test.ts +0 -2481
  625. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
  626. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  627. package/src/context/prompts/compact.md +0 -26
  628. package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
  629. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  630. package/src/runtime/guardian-action-conversation-turn.ts +0 -99
@@ -116,7 +116,7 @@ describe("OpenRouter provider.only plumbing", () => {
116
116
  expect(extras.provider).toBe(undefined);
117
117
  });
118
118
 
119
- test("still carries reasoning flag alongside provider.only", () => {
119
+ test("enables thinking with default detailed summary alongside provider.only", () => {
120
120
  const provider = new ProbeOpenRouterProvider(
121
121
  "fake-key",
122
122
  "x-ai/grok-4.20-beta",
@@ -128,12 +128,12 @@ describe("OpenRouter provider.only plumbing", () => {
128
128
  },
129
129
  });
130
130
  expect(extras).toEqual({
131
- reasoning: { enabled: true },
131
+ reasoning: { enabled: true, summary: "detailed" },
132
132
  provider: { only: ["xAI"] },
133
133
  });
134
134
  });
135
135
 
136
- test("disabled thinking keeps reasoning disabled alongside provider.only", () => {
136
+ test("disabled thinking keeps reasoning disabled and omits summary", () => {
137
137
  const provider = new ProbeOpenRouterProvider(
138
138
  "fake-key",
139
139
  "x-ai/grok-4.20-beta",
@@ -149,5 +149,53 @@ describe("OpenRouter provider.only plumbing", () => {
149
149
  provider: { only: ["xAI"] },
150
150
  });
151
151
  });
152
+
153
+ test("nests effort under reasoning and maps `max` to xhigh", () => {
154
+ const provider = new ProbeOpenRouterProvider(
155
+ "fake-key",
156
+ "moonshotai/kimi-k2.6",
157
+ );
158
+ const extras = provider.probeExtras({
159
+ config: {
160
+ thinking: { enabled: true },
161
+ effort: "max",
162
+ },
163
+ });
164
+ expect(extras).toEqual({
165
+ reasoning: { enabled: true, effort: "xhigh", summary: "detailed" },
166
+ });
167
+ });
168
+
169
+ test("honors a per-call summary override", () => {
170
+ const provider = new ProbeOpenRouterProvider(
171
+ "fake-key",
172
+ "moonshotai/kimi-k2.6",
173
+ );
174
+ const extras = provider.probeExtras({
175
+ config: {
176
+ thinking: { enabled: true },
177
+ openrouter: { reasoning: { summary: "concise" } },
178
+ },
179
+ });
180
+ expect(extras).toEqual({
181
+ reasoning: { enabled: true, summary: "concise" },
182
+ });
183
+ });
184
+
185
+ test("ignores an invalid summary override and falls back to detailed", () => {
186
+ const provider = new ProbeOpenRouterProvider(
187
+ "fake-key",
188
+ "moonshotai/kimi-k2.6",
189
+ );
190
+ const extras = provider.probeExtras({
191
+ config: {
192
+ thinking: { enabled: true },
193
+ openrouter: { reasoning: { summary: "verbose" } },
194
+ },
195
+ });
196
+ expect(extras).toEqual({
197
+ reasoning: { enabled: true, summary: "detailed" },
198
+ });
199
+ });
152
200
  });
153
201
  });
@@ -5,7 +5,11 @@ import { OpenRouterProvider } from "../providers/openrouter/client.js";
5
5
  import type { Message } from "../providers/types.js";
6
6
 
7
7
  /** Build a minimal valid PNG header encoding the given dimensions. */
8
- function makePngBase64(width: number, height: number, paddingBytes = 0): string {
8
+ function makePngBase64(
9
+ width: number,
10
+ height: number,
11
+ paddingBytes = 0,
12
+ ): string {
9
13
  const header = Buffer.alloc(24);
10
14
  header[0] = 0x89;
11
15
  header[1] = 0x50;
@@ -41,13 +45,13 @@ describe("OpenRouterProvider token estimation routing", () => {
41
45
  expect(provider.tokenEstimationProvider).toBe("openrouter");
42
46
  });
43
47
 
44
- test("estimatePromptTokens applies Anthropic image scaling when routed via OpenRouter", () => {
48
+ test("estimatePromptTokens applies dimension-based image scaling when routed via OpenRouter to Anthropic", () => {
45
49
  const provider = new OpenRouterProvider(
46
50
  "fake-key",
47
51
  "anthropic/claude-opus-4-6",
48
52
  );
49
53
  // 1920x1080 screenshot with ~200 KB of pixel data → base64/4 would be ~65k
50
- // tokens; dimension-based Anthropic rules land around 1.6k tokens.
54
+ // tokens; dimension-based rules land around 1.6k tokens.
51
55
  const messages: Message[] = [
52
56
  {
53
57
  role: "user",
@@ -68,33 +72,38 @@ describe("OpenRouterProvider token estimation routing", () => {
68
72
  providerName: provider.tokenEstimationProvider,
69
73
  });
70
74
 
71
- // Dimension-based estimate should be well under 5k; base64/4 would exceed 50k.
72
75
  expect(estimated).toBeLessThan(5_000);
73
76
  });
74
77
 
75
- test("estimatePromptTokens falls back to base64/4 for non-Anthropic OpenRouter models", () => {
76
- const provider = new OpenRouterProvider("fake-key", "x-ai/grok-4.20-beta");
77
- const messages: Message[] = [
78
- {
79
- role: "user",
80
- content: [
81
- {
82
- type: "image",
83
- source: {
84
- type: "base64",
85
- media_type: "image/png",
86
- data: makePngBase64(1920, 1080, 200_000),
78
+ test("estimatePromptTokens applies dimension-based image scaling for non-Anthropic OpenRouter models", () => {
79
+ // A naive base64/4 estimate on a 1920x1080 screenshot (~200 KB) lands near
80
+ // 65k tokens and trips spurious compaction long before the real context
81
+ // window fills. Vision models on OpenRouter — both anthropic/* and
82
+ // non-Anthropic (Kimi K2.6, Grok, etc.) — must use the dimension-based
83
+ // formula.
84
+ for (const model of ["moonshotai/kimi-k2.6", "x-ai/grok-4.20-beta"]) {
85
+ const provider = new OpenRouterProvider("fake-key", model);
86
+ const messages: Message[] = [
87
+ {
88
+ role: "user",
89
+ content: [
90
+ {
91
+ type: "image",
92
+ source: {
93
+ type: "base64",
94
+ media_type: "image/png",
95
+ data: makePngBase64(1920, 1080, 200_000),
96
+ },
87
97
  },
88
- },
89
- ],
90
- },
91
- ];
98
+ ],
99
+ },
100
+ ];
92
101
 
93
- const estimated = estimatePromptTokens(messages, "system", {
94
- providerName: provider.tokenEstimationProvider,
95
- });
102
+ const estimated = estimatePromptTokens(messages, "system", {
103
+ providerName: provider.tokenEstimationProvider,
104
+ });
96
105
 
97
- // Base64/4 heuristic on ~200 KB of image data → far more than 10k tokens.
98
- expect(estimated).toBeGreaterThan(50_000);
106
+ expect(estimated).toBeLessThan(5_000);
107
+ }
99
108
  });
100
109
  });
@@ -453,7 +453,6 @@ describe("overflow-reduce pipeline", () => {
453
453
  manifest: {
454
454
  name: "spy-overflow",
455
455
  version: "0.0.1",
456
- requires: { pluginRuntime: "v1", overflowReduceApi: "v1" },
457
456
  },
458
457
  middleware: { overflowReduce: spy },
459
458
  };
@@ -512,7 +511,6 @@ describe("overflow-reduce pipeline", () => {
512
511
  manifest: {
513
512
  name: "short-circuit-overflow",
514
513
  version: "0.0.1",
515
- requires: { pluginRuntime: "v1", overflowReduceApi: "v1" },
516
514
  },
517
515
  middleware: { overflowReduce: shortCircuit },
518
516
  });
@@ -267,7 +267,6 @@ describe("persistence pipeline", () => {
267
267
  manifest: {
268
268
  name: "mock-persistence",
269
269
  version: "0.0.1",
270
- requires: { pluginRuntime: "v1" },
271
270
  },
272
271
  middleware: { persistence: redirect },
273
272
  };
@@ -352,7 +351,6 @@ describe("persistence pipeline", () => {
352
351
  manifest: {
353
352
  name: "late-user-plugin",
354
353
  version: "0.0.1",
355
- requires: { pluginRuntime: "v1" },
356
354
  },
357
355
  middleware: { persistence: userMiddleware },
358
356
  });
@@ -32,7 +32,7 @@ import {
32
32
  hasManagedProxyPrereqs,
33
33
  managedFallbackEnabledFor,
34
34
  resolveManagedProxyContext,
35
- } from "../providers/managed-proxy/context.js";
35
+ } from "../providers/platform-proxy/context.js";
36
36
 
37
37
  describe("resolveManagedProxyContext", () => {
38
38
  beforeEach(() => {
@@ -117,8 +117,13 @@ describe("buildManagedBaseUrl", () => {
117
117
  );
118
118
  });
119
119
 
120
+ test("returns managed URL for fireworks", async () => {
121
+ expect(await buildManagedBaseUrl("fireworks")).toBe(
122
+ "https://platform.example.com/v1/runtime-proxy/fireworks",
123
+ );
124
+ });
125
+
120
126
  test("returns undefined for non-managed providers", async () => {
121
- expect(await buildManagedBaseUrl("fireworks")).toBeUndefined();
122
127
  expect(await buildManagedBaseUrl("openrouter")).toBeUndefined();
123
128
  expect(await buildManagedBaseUrl("ollama")).toBeUndefined();
124
129
  });
@@ -16,6 +16,7 @@ import {
16
16
  getWorkspaceConfigPath,
17
17
  getWorkspaceDir,
18
18
  getWorkspaceHooksDir,
19
+ getWorkspacePluginsDir,
19
20
  getWorkspacePromptPath,
20
21
  getWorkspaceSkillsDir,
21
22
  getXdgVellumConfigDirName,
@@ -161,6 +162,7 @@ describe("workspace path primitives", () => {
161
162
  expect(getWorkspaceConfigPath()).toBe(join(ws, "config.json"));
162
163
  expect(getWorkspaceSkillsDir()).toBe(join(ws, "skills"));
163
164
  expect(getWorkspaceHooksDir()).toBe(join(ws, "hooks"));
165
+ expect(getWorkspacePluginsDir()).toBe(join(ws, "plugins"));
164
166
  expect(getWorkspacePromptPath("IDENTITY.md")).toBe(join(ws, "IDENTITY.md"));
165
167
  expect(getWorkspacePromptPath("SOUL.md")).toBe(join(ws, "SOUL.md"));
166
168
  });
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Smoke tests for the workspace-level `@vellumai/plugin-api` shim.
3
+ *
4
+ * - shim files are materialized at `<workspaceDir>/node_modules/@vellumai/plugin-api/`
5
+ * - the shim's index.js re-binds each runtime export from globalThis
6
+ * - the shim is idempotent across re-runs
7
+ * - a fake plugin in `<workspaceDir>/plugins/<name>/` can resolve the
8
+ * bare `@vellumai/plugin-api` specifier via Node-style walk-up,
9
+ * proving the end-to-end import path works for real user plugins
10
+ *
11
+ * As plugin-api's runtime surface grows in follow-up PRs, the shim's
12
+ * generated export list expands automatically — the test below covers
13
+ * the generator (`buildShimSource`) directly so we don't need to
14
+ * update assertions every time an export is added.
15
+ */
16
+
17
+ import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
18
+ import { tmpdir } from "node:os";
19
+ import { join } from "node:path";
20
+ import { describe, expect, test } from "bun:test";
21
+
22
+ import {
23
+ PLUGIN_API_EXPORTS,
24
+ PLUGIN_API_REGISTRY_KEY,
25
+ } from "../embedded/plugin-api.js";
26
+ import {
27
+ buildShimSource,
28
+ ensurePluginApiShim,
29
+ } from "../plugins/ensure-plugin-api-shim.js";
30
+
31
+ const SHIM_REL_PATH = "node_modules/@vellumai/plugin-api";
32
+
33
+ describe("buildShimSource", () => {
34
+ test("emits a globalThis trampoline + one binding per export", () => {
35
+ const source = buildShimSource(
36
+ ["foo", "bar"],
37
+ Symbol.for("vellum.plugin-api.v1"),
38
+ );
39
+ expect(source).toBe(
40
+ `const api = globalThis[Symbol.for("vellum.plugin-api.v1")];\n` +
41
+ `export const foo = api.foo;\n` +
42
+ `export const bar = api.bar;\n`,
43
+ );
44
+ });
45
+
46
+ test("handles an empty export list (today's types-only surface)", () => {
47
+ const source = buildShimSource(
48
+ [],
49
+ Symbol.for("vellum.plugin-api.v1"),
50
+ );
51
+ expect(source).toBe(
52
+ `const api = globalThis[Symbol.for("vellum.plugin-api.v1")];\n`,
53
+ );
54
+ });
55
+ });
56
+
57
+ describe("ensurePluginApiShim", () => {
58
+ test("creates a resolvable @vellumai/plugin-api package under workspaceDir", async () => {
59
+ const workspaceDir = await mkdtemp(join(tmpdir(), "plugin-api-shim-"));
60
+ await ensurePluginApiShim({ workspaceDir });
61
+
62
+ const shimDir = join(workspaceDir, SHIM_REL_PATH);
63
+ const indexJs = await readFile(join(shimDir, "index.js"), "utf8");
64
+ expect(indexJs).toBe(buildShimSource());
65
+
66
+ const pkg = JSON.parse(
67
+ await readFile(join(shimDir, "package.json"), "utf8"),
68
+ );
69
+ expect(pkg.name).toBe("@vellumai/plugin-api");
70
+ expect(pkg.type).toBe("module");
71
+ expect(pkg.main).toBe("./index.js");
72
+ expect(typeof pkg.version).toBe("string");
73
+ });
74
+
75
+ test("is idempotent — re-running yields the same shim contents", async () => {
76
+ const workspaceDir = await mkdtemp(join(tmpdir(), "plugin-api-shim-"));
77
+ await ensurePluginApiShim({ workspaceDir });
78
+ const first = await readFile(
79
+ join(workspaceDir, SHIM_REL_PATH, "index.js"),
80
+ "utf8",
81
+ );
82
+
83
+ await ensurePluginApiShim({ workspaceDir });
84
+ const second = await readFile(
85
+ join(workspaceDir, SHIM_REL_PATH, "index.js"),
86
+ "utf8",
87
+ );
88
+ expect(second).toBe(first);
89
+ });
90
+
91
+ test("globalThis is populated with the plugin-api namespace", () => {
92
+ // Importing the embed wrapper has the side effect of installing the
93
+ // namespace on globalThis. By the time this test runs (any earlier
94
+ // test in the file has already imported it), the registry must be
95
+ // populated.
96
+ const namespace = (globalThis as Record<symbol, unknown>)[
97
+ PLUGIN_API_REGISTRY_KEY
98
+ ];
99
+ expect(namespace).toBeDefined();
100
+ // Exports list is non-null but may be empty until runtime exports
101
+ // migrate in later PRs.
102
+ expect(Array.isArray(PLUGIN_API_EXPORTS)).toBe(true);
103
+ });
104
+
105
+ test("a fake user plugin can resolve @vellumai/plugin-api via Node-style walk-up", async () => {
106
+ const workspaceDir = await mkdtemp(join(tmpdir(), "plugin-api-shim-"));
107
+ await ensurePluginApiShim({ workspaceDir });
108
+
109
+ const pluginDir = join(workspaceDir, "plugins", "fake-plugin");
110
+ await mkdir(pluginDir, { recursive: true });
111
+ await writeFile(
112
+ join(pluginDir, "register.js"),
113
+ `import * as api from "@vellumai/plugin-api";\nexport { api };\n`,
114
+ );
115
+
116
+ // Resolution walks up: plugins/fake-plugin → plugins → workspaceDir
117
+ // → workspaceDir/node_modules/@vellumai/plugin-api → shim → globalThis
118
+ // → plugin-api namespace. If any link in that chain is broken, this
119
+ // import throws.
120
+ const mod: { api: Record<string, unknown> } = await import(
121
+ join(pluginDir, "register.js")
122
+ );
123
+ expect(mod.api).toBeDefined();
124
+ });
125
+ });
@@ -43,7 +43,6 @@ import {
43
43
  import { runShutdownHooks } from "../daemon/shutdown-registry.js";
44
44
  import { RiskLevel } from "../permissions/types.js";
45
45
  import {
46
- ASSISTANT_API_VERSIONS,
47
46
  getInjectors,
48
47
  getMiddlewaresFor,
49
48
  registerPlugin,
@@ -84,7 +83,6 @@ function buildPlugin(
84
83
  onShutdown?: () => Promise<void>;
85
84
  } = {},
86
85
  options: {
87
- requires?: Record<string, string>;
88
86
  requiresCredential?: string[];
89
87
  requiresFlag?: string[];
90
88
  } = {},
@@ -111,7 +109,6 @@ function buildPlugin(
111
109
  manifest: {
112
110
  name,
113
111
  version: "0.0.1",
114
- requires: options.requires ?? { pluginRuntime: "v1" },
115
112
  ...(options.requiresCredential
116
113
  ? { requiresCredential: options.requiresCredential }
117
114
  : {}),
@@ -161,10 +158,6 @@ describe("plugin bootstrap", () => {
161
158
  );
162
159
  expect(existsSync(ctx.pluginStorageDir)).toBe(true);
163
160
  expect(ctx.assistantVersion).toBe("9.9.9-test");
164
- // apiVersions must surface the canonical capability table from the
165
- // registry so plugins can negotiate at runtime.
166
- expect(ctx.apiVersions).toBe(ASSISTANT_API_VERSIONS);
167
- expect(ctx.apiVersions.pluginRuntime).toEqual(["v1"]);
168
161
  });
169
162
 
170
163
  test("credential resolution: init receives the resolved value under credentials[key]", async () => {
@@ -215,29 +208,15 @@ describe("plugin bootstrap", () => {
215
208
  expect(msg).toContain("absent-key");
216
209
  });
217
210
 
218
- test("version mismatch: registration surfaces a clear error naming the plugin", () => {
219
- // The assistant only exposes pluginRuntime@v1 asking for v99 must fail
220
- // registration with the plugin name in the message. The error is raised
221
- // at registerPlugin() rather than bootstrap, because the registry is the
222
- // single authoritative point of capability validation.
223
- const plugin = buildPlugin(
224
- "from-the-future",
225
- {},
226
- { requires: { pluginRuntime: "v99" } },
227
- );
228
-
229
- let caught: unknown;
230
- try {
231
- registerPlugin(plugin);
232
- } catch (err) {
233
- caught = err;
234
- }
235
- expect(caught).toBeInstanceOf(PluginExecutionError);
236
- const msg = (caught as PluginExecutionError).message;
237
- expect(msg).toContain("from-the-future");
238
- expect(msg).toContain("pluginRuntime");
239
- expect(msg).toContain("v99");
240
- expect((caught as PluginExecutionError).pluginName).toBe("from-the-future");
211
+ test("version mismatch: external plugin loader rejects when peerDependency unsatisfied", async () => {
212
+ // Host-compat negotiation lives in the external-plugin loader against
213
+ // `peerDependencies["@vellumai/plugin-api"]`. The registry no longer
214
+ // re-validates a manifest-level `requires` block the loader is the
215
+ // single authoritative point. End-to-end coverage of the loader path
216
+ // lives in `external-plugin-loader.test.ts`; this test asserts the
217
+ // bootstrap doesn't gain its own validation surface.
218
+ const plugin = buildPlugin("compat-claim-checked-upstream");
219
+ expect(() => registerPlugin(plugin)).not.toThrow();
241
220
  });
242
221
 
243
222
  test("plugin init throw: bootstrap throws a PluginExecutionError naming the plugin", async () => {
@@ -395,13 +374,8 @@ describe("plugin bootstrap", () => {
395
374
  {
396
375
  name: "gated-off-tool",
397
376
  description: "should not be registered",
398
- category: "plugin-test",
399
377
  defaultRiskLevel: RiskLevel.Low,
400
- getDefinition: () => ({
401
- name: "gated-off-tool",
402
- description: "should not be registered",
403
- input_schema: { type: "object", properties: {}, required: [] },
404
- }),
378
+ input_schema: { type: "object", properties: {}, required: [] },
405
379
  execute: async () => ({ content: "nope", isError: false }),
406
380
  },
407
381
  ],
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Tests for the `globalThis.__vellumPluginRuntime` bridge.
3
+ *
4
+ * The bridge exists so workspace-local plugins (`<workspaceDir>/plugins/*`)
5
+ * can register with the daemon's bundled module instances even when the
6
+ * daemon is a `bun --compile` binary. Absolute-path imports against a
7
+ * compiled binary load fresh disk copies into a disjoint module graph; the
8
+ * bridge sidesteps that by attaching a stable handle to globalThis.
9
+ */
10
+
11
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
12
+
13
+ import {
14
+ getPluginRuntime,
15
+ installPluginRuntime,
16
+ uninstallPluginRuntimeForTests,
17
+ } from "../plugins/external-api.js";
18
+ import { registerPlugin } from "../plugins/registry.js";
19
+ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
20
+ import { getSecureKeyAsync } from "../security/secure-keys.js";
21
+
22
+ describe("plugin external-api bridge", () => {
23
+ beforeEach(() => {
24
+ uninstallPluginRuntimeForTests();
25
+ });
26
+
27
+ afterEach(() => {
28
+ uninstallPluginRuntimeForTests();
29
+ });
30
+
31
+ test("installs a runtime handle on globalThis", () => {
32
+ expect(getPluginRuntime()).toBeUndefined();
33
+ installPluginRuntime();
34
+ const runtime = getPluginRuntime();
35
+ expect(runtime).toBeDefined();
36
+ expect(runtime?.version).toBe(1);
37
+ });
38
+
39
+ test("exposes the canonical registerPlugin / hub / secrets references", () => {
40
+ installPluginRuntime();
41
+ const runtime = getPluginRuntime();
42
+ expect(runtime?.registerPlugin).toBe(registerPlugin);
43
+ expect(runtime?.assistantEventHub).toBe(assistantEventHub);
44
+ expect(runtime?.getSecureKeyAsync).toBe(getSecureKeyAsync);
45
+ });
46
+
47
+ test("plugins can read the runtime via the documented globalThis key", () => {
48
+ installPluginRuntime();
49
+ // Mirror the access pattern documented for plugin authors.
50
+ const runtime = (
51
+ globalThis as { __vellumPluginRuntime?: { version: number } }
52
+ ).__vellumPluginRuntime;
53
+ expect(runtime).toBeDefined();
54
+ expect(runtime?.version).toBe(1);
55
+ });
56
+
57
+ test("install is idempotent — repeat calls preserve the same handle", () => {
58
+ installPluginRuntime();
59
+ const first = getPluginRuntime();
60
+ installPluginRuntime();
61
+ installPluginRuntime();
62
+ expect(getPluginRuntime()).toBe(first);
63
+ });
64
+
65
+ test("getPluginRuntime returns undefined when the bridge is not installed", () => {
66
+ expect(getPluginRuntime()).toBeUndefined();
67
+ });
68
+ });
@@ -9,7 +9,6 @@
9
9
  import { beforeEach, describe, expect, test } from "bun:test";
10
10
 
11
11
  import {
12
- ASSISTANT_API_VERSIONS,
13
12
  closeRegistration,
14
13
  getInjectors,
15
14
  getMiddlewaresFor,
@@ -30,13 +29,11 @@ import {
30
29
  function buildPlugin(
31
30
  name: string,
32
31
  extras: Partial<Omit<Plugin, "manifest">> = {},
33
- requiresOverride?: Record<string, string>,
34
32
  ): Plugin {
35
33
  return {
36
34
  manifest: {
37
35
  name,
38
36
  version: "0.0.1",
39
- requires: requiresOverride ?? { pluginRuntime: "v1" },
40
37
  },
41
38
  ...extras,
42
39
  };
@@ -106,7 +103,6 @@ describe("plugin registry", () => {
106
103
  const bad = {
107
104
  manifest: {
108
105
  version: "0.0.1",
109
- requires: { pluginRuntime: "v1" },
110
106
  },
111
107
  } as unknown as Plugin;
112
108
  expect(() => registerPlugin(bad)).toThrow(/manifest\.name is required/);
@@ -148,84 +144,11 @@ describe("plugin registry", () => {
148
144
  const bad = {
149
145
  manifest: {
150
146
  name: "missing-version",
151
- requires: { pluginRuntime: "v1" },
152
147
  },
153
148
  } as unknown as Plugin;
154
149
  expect(() => registerPlugin(bad)).toThrow(/manifest\.version is required/);
155
150
  });
156
151
 
157
- test("throws when manifest.requires is missing", () => {
158
- const bad = {
159
- manifest: { name: "missing-requires", version: "0.0.1" },
160
- } as unknown as Plugin;
161
- expect(() => registerPlugin(bad)).toThrow(/manifest\.requires is required/);
162
- });
163
-
164
- test("throws when requires.pluginRuntime is missing", () => {
165
- const plugin = buildPlugin(
166
- "no-runtime",
167
- {},
168
- // Valid shape but no pluginRuntime entry.
169
- { memoryApi: "v1" },
170
- );
171
- expect(() => registerPlugin(plugin)).toThrow(PluginExecutionError);
172
- expect(() => registerPlugin(plugin)).toThrow(/pluginRuntime/);
173
- });
174
-
175
- test("throws with version-mismatch message when a required version is not exposed", () => {
176
- // The assistant seeds memoryApi with ["v1"]. Requesting v2 must fail.
177
- const plugin = buildPlugin(
178
- "too-new",
179
- {},
180
- {
181
- pluginRuntime: "v1",
182
- memoryApi: "v2",
183
- },
184
- );
185
-
186
- expect(() => registerPlugin(plugin)).toThrow(PluginExecutionError);
187
-
188
- // Sanity-check the assistant actually exposes only v1 for memoryApi so
189
- // this test fails loudly if the capability table ever adds v2.
190
- expect(ASSISTANT_API_VERSIONS.memoryApi).toEqual(["v1"]);
191
-
192
- try {
193
- registerPlugin(plugin);
194
- throw new Error("expected registerPlugin to throw");
195
- } catch (err) {
196
- expect(err).toBeInstanceOf(PluginExecutionError);
197
- const msg = (err as PluginExecutionError).message;
198
- // Error message must reference plugin name, API, required version,
199
- // and the versions the assistant exposes.
200
- expect(msg).toContain("too-new");
201
- expect(msg).toContain("memoryApi");
202
- expect(msg).toContain("v2");
203
- expect(msg).toContain("v1");
204
- expect((err as PluginExecutionError).pluginName).toBe("too-new");
205
- }
206
- });
207
-
208
- test("throws with clear message when a required capability is unknown", () => {
209
- const plugin = buildPlugin(
210
- "asks-for-mystery",
211
- {},
212
- {
213
- pluginRuntime: "v1",
214
- thisDoesNotExist: "v1",
215
- },
216
- );
217
- expect(() => registerPlugin(plugin)).toThrow(PluginExecutionError);
218
- try {
219
- registerPlugin(plugin);
220
- throw new Error("expected registerPlugin to throw");
221
- } catch (err) {
222
- const msg = (err as PluginExecutionError).message;
223
- expect(msg).toContain("asks-for-mystery");
224
- expect(msg).toContain("thisDoesNotExist");
225
- expect(msg).toContain("(none)");
226
- }
227
- });
228
-
229
152
  test("getInjectors returns injectors sorted by order ascending", () => {
230
153
  const high: Injector = {
231
154
  name: "high-order",
@@ -111,7 +111,6 @@ function buildPlugin(
111
111
  manifest: {
112
112
  name,
113
113
  version: "0.0.1",
114
- requires: { pluginRuntime: "v1" },
115
114
  },
116
115
  ...rest,
117
116
  ...(mergedHooks ? { hooks: mergedHooks } : {}),
@@ -80,7 +80,6 @@ function buildSkillPlugin(
80
80
  manifest: {
81
81
  name,
82
82
  version: "0.0.1",
83
- requires: { pluginRuntime: "v1" },
84
83
  },
85
84
  skills,
86
85
  ...extras,
@@ -204,7 +203,6 @@ describe("plugin skill contributions", () => {
204
203
  manifest: {
205
204
  name: "no-skills-plugin",
206
205
  version: "0.0.1",
207
- requires: { pluginRuntime: "v1" },
208
206
  },
209
207
  });
210
208