@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
@@ -29,6 +29,7 @@ mock.module("../../../util/logger.js", () => ({
29
29
 
30
30
  // ── Real imports (after mocks) ────────────────────────────────────────────────
31
31
 
32
+ import { _setOverridesForTesting } from "../../../config/assistant-feature-flags.js";
32
33
  import { getDb } from "../../../memory/db-connection.js";
33
34
  import { initializeDb } from "../../../memory/db-init.js";
34
35
  import { providerConnections } from "../../../memory/schema/inference.js";
@@ -89,6 +90,7 @@ function seedConnection(opts: {
89
90
  beforeEach(() => {
90
91
  clearConnections();
91
92
  fakeConfig = {};
93
+ _setOverridesForTesting({ "openai-compatible-endpoints": true });
92
94
  });
93
95
 
94
96
  // ── GET list ─────────────────────────────────────────────────────────────────
@@ -103,8 +105,16 @@ describe("GET inference/provider-connections (list)", () => {
103
105
  });
104
106
 
105
107
  test("returns all connections when no filter", async () => {
106
- seedConnection({ name: "conn-a", provider: "anthropic", auth: { type: "platform" } });
107
- seedConnection({ name: "conn-b", provider: "openai", auth: { type: "none" } });
108
+ seedConnection({
109
+ name: "conn-a",
110
+ provider: "anthropic",
111
+ auth: { type: "platform" },
112
+ });
113
+ seedConnection({
114
+ name: "conn-b",
115
+ provider: "openai",
116
+ auth: { type: "none" },
117
+ });
108
118
 
109
119
  const result = (await call(
110
120
  findHandler("inference_provider_connections_list"),
@@ -115,8 +125,16 @@ describe("GET inference/provider-connections (list)", () => {
115
125
  });
116
126
 
117
127
  test("filters by ?provider= query param", async () => {
118
- seedConnection({ name: "ant-1", provider: "anthropic", auth: { type: "platform" } });
119
- seedConnection({ name: "oai-1", provider: "openai", auth: { type: "platform" } });
128
+ seedConnection({
129
+ name: "ant-1",
130
+ provider: "anthropic",
131
+ auth: { type: "platform" },
132
+ });
133
+ seedConnection({
134
+ name: "oai-1",
135
+ provider: "openai",
136
+ auth: { type: "platform" },
137
+ });
120
138
 
121
139
  const result = (await call(
122
140
  findHandler("inference_provider_connections_list"),
@@ -128,7 +146,11 @@ describe("GET inference/provider-connections (list)", () => {
128
146
  });
129
147
 
130
148
  test("returns empty list when provider filter matches nothing", async () => {
131
- seedConnection({ name: "ant-1", provider: "anthropic", auth: { type: "platform" } });
149
+ seedConnection({
150
+ name: "ant-1",
151
+ provider: "anthropic",
152
+ auth: { type: "platform" },
153
+ });
132
154
 
133
155
  const result = (await call(
134
156
  findHandler("inference_provider_connections_list"),
@@ -136,13 +158,48 @@ describe("GET inference/provider-connections (list)", () => {
136
158
  )) as { connections: unknown[] };
137
159
  expect(result.connections).toEqual([]);
138
160
  });
161
+
162
+ test("hides openai-compatible rows when the feature flag is disabled", async () => {
163
+ _setOverridesForTesting({ "openai-compatible-endpoints": false });
164
+ seedConnection({
165
+ name: "my-openai",
166
+ provider: "openai",
167
+ auth: { type: "platform" },
168
+ });
169
+ seedConnection({
170
+ name: "my-compatible",
171
+ provider: "openai-compatible",
172
+ auth: { type: "api_key", credential: "ref/k" },
173
+ });
174
+
175
+ const result = (await call(
176
+ findHandler("inference_provider_connections_list"),
177
+ {},
178
+ )) as { connections: Array<{ name: string }> };
179
+
180
+ expect(result.connections.map((c) => c.name)).toEqual(["my-openai"]);
181
+ });
182
+
183
+ test("rejects openai-compatible provider filter when the feature flag is disabled", async () => {
184
+ _setOverridesForTesting({ "openai-compatible-endpoints": false });
185
+
186
+ await expect(
187
+ call(findHandler("inference_provider_connections_list"), {
188
+ queryParams: { provider: "openai-compatible" },
189
+ }),
190
+ ).rejects.toBeInstanceOf(BadRequestError);
191
+ });
139
192
  });
140
193
 
141
194
  // ── GET single ────────────────────────────────────────────────────────────────
142
195
 
143
196
  describe("GET inference/provider-connections/:name (single)", () => {
144
197
  test("returns connection when it exists", async () => {
145
- seedConnection({ name: "my-conn", provider: "anthropic", auth: { type: "platform" } });
198
+ seedConnection({
199
+ name: "my-conn",
200
+ provider: "anthropic",
201
+ auth: { type: "platform" },
202
+ });
146
203
 
147
204
  const result = (await call(
148
205
  findHandler("inference_provider_connections_get"),
@@ -160,6 +217,21 @@ describe("GET inference/provider-connections/:name (single)", () => {
160
217
  }),
161
218
  ).rejects.toBeInstanceOf(NotFoundError);
162
219
  });
220
+
221
+ test("throws 404 for openai-compatible row when the feature flag is disabled", async () => {
222
+ _setOverridesForTesting({ "openai-compatible-endpoints": false });
223
+ seedConnection({
224
+ name: "my-compatible",
225
+ provider: "openai-compatible",
226
+ auth: { type: "api_key", credential: "ref/k" },
227
+ });
228
+
229
+ await expect(
230
+ call(findHandler("inference_provider_connections_get"), {
231
+ pathParams: { name: "my-compatible" },
232
+ }),
233
+ ).rejects.toBeInstanceOf(NotFoundError);
234
+ });
163
235
  });
164
236
 
165
237
  // ── POST create ───────────────────────────────────────────────────────────────
@@ -179,7 +251,10 @@ describe("POST inference/provider-connections (create)", () => {
179
251
 
180
252
  expect(result.name).toBe("my-anthropic");
181
253
  expect(result.provider).toBe("anthropic");
182
- expect(result.auth).toEqual({ type: "api_key", credential: "vault/anthropic/key" });
254
+ expect(result.auth).toEqual({
255
+ type: "api_key",
256
+ credential: "vault/anthropic/key",
257
+ });
183
258
  expect(typeof result.createdAt).toBe("number");
184
259
  });
185
260
 
@@ -187,7 +262,11 @@ describe("POST inference/provider-connections (create)", () => {
187
262
  const result = (await call(
188
263
  findHandler("inference_provider_connections_create"),
189
264
  {
190
- body: { name: "managed-openai", provider: "openai", auth: { type: "platform" } },
265
+ body: {
266
+ name: "managed-openai",
267
+ provider: "openai",
268
+ auth: { type: "platform" },
269
+ },
191
270
  },
192
271
  )) as { auth: object };
193
272
  expect(result.auth).toEqual({ type: "platform" });
@@ -197,18 +276,30 @@ describe("POST inference/provider-connections (create)", () => {
197
276
  const result = (await call(
198
277
  findHandler("inference_provider_connections_create"),
199
278
  {
200
- body: { name: "ollama-local", provider: "ollama", auth: { type: "none" } },
279
+ body: {
280
+ name: "ollama-local",
281
+ provider: "ollama",
282
+ auth: { type: "none" },
283
+ },
201
284
  },
202
285
  )) as { auth: object };
203
286
  expect(result.auth).toEqual({ type: "none" });
204
287
  });
205
288
 
206
289
  test("throws 409 when connection name already exists", async () => {
207
- seedConnection({ name: "dup-name", provider: "anthropic", auth: { type: "platform" } });
290
+ seedConnection({
291
+ name: "dup-name",
292
+ provider: "anthropic",
293
+ auth: { type: "platform" },
294
+ });
208
295
 
209
296
  await expect(
210
297
  call(findHandler("inference_provider_connections_create"), {
211
- body: { name: "dup-name", provider: "openai", auth: { type: "platform" } },
298
+ body: {
299
+ name: "dup-name",
300
+ provider: "openai",
301
+ auth: { type: "platform" },
302
+ },
212
303
  }),
213
304
  ).rejects.toBeInstanceOf(ConflictError);
214
305
  });
@@ -216,7 +307,27 @@ describe("POST inference/provider-connections (create)", () => {
216
307
  test("throws 400 when provider is invalid", async () => {
217
308
  await expect(
218
309
  call(findHandler("inference_provider_connections_create"), {
219
- body: { name: "test", provider: "bogus-provider", auth: { type: "platform" } },
310
+ body: {
311
+ name: "test",
312
+ provider: "bogus-provider",
313
+ auth: { type: "platform" },
314
+ },
315
+ }),
316
+ ).rejects.toBeInstanceOf(BadRequestError);
317
+ });
318
+
319
+ test("rejects openai-compatible creation when the feature flag is disabled", async () => {
320
+ _setOverridesForTesting({ "openai-compatible-endpoints": false });
321
+
322
+ await expect(
323
+ call(findHandler("inference_provider_connections_create"), {
324
+ body: {
325
+ name: "my-compatible",
326
+ provider: "openai-compatible",
327
+ auth: { type: "api_key", credential: "ref/k" },
328
+ base_url: "http://localhost:8080/v1",
329
+ models: [{ id: "local-model" }],
330
+ },
220
331
  }),
221
332
  ).rejects.toBeInstanceOf(BadRequestError);
222
333
  });
@@ -224,7 +335,11 @@ describe("POST inference/provider-connections (create)", () => {
224
335
  test("throws 400 when auth schema is invalid (api_key without credential)", async () => {
225
336
  await expect(
226
337
  call(findHandler("inference_provider_connections_create"), {
227
- body: { name: "test", provider: "anthropic", auth: { type: "api_key" } },
338
+ body: {
339
+ name: "test",
340
+ provider: "anthropic",
341
+ auth: { type: "api_key" },
342
+ },
228
343
  }),
229
344
  ).rejects.toBeInstanceOf(BadRequestError);
230
345
  });
@@ -232,7 +347,11 @@ describe("POST inference/provider-connections (create)", () => {
232
347
  test("throws 400 when auth type is unknown", async () => {
233
348
  await expect(
234
349
  call(findHandler("inference_provider_connections_create"), {
235
- body: { name: "test", provider: "anthropic", auth: { type: "magic_beans" } },
350
+ body: {
351
+ name: "test",
352
+ provider: "anthropic",
353
+ auth: { type: "magic_beans" },
354
+ },
236
355
  }),
237
356
  ).rejects.toBeInstanceOf(BadRequestError);
238
357
  });
@@ -250,7 +369,11 @@ describe("POST inference/provider-connections (create)", () => {
250
369
 
251
370
  describe("PATCH inference/provider-connections/:name (update)", () => {
252
371
  test("updates auth on existing connection", async () => {
253
- seedConnection({ name: "upd-conn", provider: "anthropic", auth: { type: "platform" } });
372
+ seedConnection({
373
+ name: "upd-conn",
374
+ provider: "anthropic",
375
+ auth: { type: "platform" },
376
+ });
254
377
 
255
378
  const result = (await call(
256
379
  findHandler("inference_provider_connections_update"),
@@ -273,7 +396,11 @@ describe("PATCH inference/provider-connections/:name (update)", () => {
273
396
  });
274
397
 
275
398
  test("throws 400 when auth schema is invalid", async () => {
276
- seedConnection({ name: "bad-auth", provider: "openai", auth: { type: "platform" } });
399
+ seedConnection({
400
+ name: "bad-auth",
401
+ provider: "openai",
402
+ auth: { type: "platform" },
403
+ });
277
404
 
278
405
  await expect(
279
406
  call(findHandler("inference_provider_connections_update"), {
@@ -288,7 +415,11 @@ describe("PATCH inference/provider-connections/:name (update)", () => {
288
415
 
289
416
  describe("DELETE inference/provider-connections/:name (delete)", () => {
290
417
  test("deletes an unreferenced connection", async () => {
291
- seedConnection({ name: "del-me", provider: "gemini", auth: { type: "platform" } });
418
+ seedConnection({
419
+ name: "del-me",
420
+ provider: "gemini",
421
+ auth: { type: "platform" },
422
+ });
292
423
 
293
424
  const result = (await call(
294
425
  findHandler("inference_provider_connections_delete"),
@@ -313,11 +444,18 @@ describe("DELETE inference/provider-connections/:name (delete)", () => {
313
444
  });
314
445
 
315
446
  test("throws 409 when a profile references the connection", async () => {
316
- seedConnection({ name: "ref-conn", provider: "anthropic", auth: { type: "platform" } });
447
+ seedConnection({
448
+ name: "ref-conn",
449
+ provider: "anthropic",
450
+ auth: { type: "platform" },
451
+ });
317
452
  fakeConfig = {
318
453
  llm: {
319
454
  profiles: {
320
- "my-profile": { provider_connection: "ref-conn", model: "claude-opus-4-7" },
455
+ "my-profile": {
456
+ provider_connection: "ref-conn",
457
+ model: "claude-opus-4-7",
458
+ },
321
459
  },
322
460
  },
323
461
  };
@@ -332,7 +470,11 @@ describe("DELETE inference/provider-connections/:name (delete)", () => {
332
470
  });
333
471
 
334
472
  test("throws 409 when llm.default references the connection", async () => {
335
- seedConnection({ name: "default-conn", provider: "anthropic", auth: { type: "platform" } });
473
+ seedConnection({
474
+ name: "default-conn",
475
+ provider: "anthropic",
476
+ auth: { type: "platform" },
477
+ });
336
478
  fakeConfig = {
337
479
  llm: {
338
480
  default: { provider_connection: "default-conn" },
@@ -366,7 +508,11 @@ describe("DELETE inference/provider-connections/:name (delete)", () => {
366
508
  });
367
509
 
368
510
  test("throws 409 when both llm.default and a profile reference the connection", async () => {
369
- seedConnection({ name: "shared-conn", provider: "anthropic", auth: { type: "none" } });
511
+ seedConnection({
512
+ name: "shared-conn",
513
+ provider: "anthropic",
514
+ auth: { type: "none" },
515
+ });
370
516
  fakeConfig = {
371
517
  llm: {
372
518
  default: { provider_connection: "shared-conn" },
@@ -409,7 +555,11 @@ describe("POST with label and status", () => {
409
555
  const result = (await call(
410
556
  findHandler("inference_provider_connections_create"),
411
557
  {
412
- body: { name: "no-label-conn", provider: "openai", auth: { type: "platform" } },
558
+ body: {
559
+ name: "no-label-conn",
560
+ provider: "openai",
561
+ auth: { type: "platform" },
562
+ },
413
563
  },
414
564
  )) as { label: string | null; status: string };
415
565
  expect(result.label).toBeNull();
@@ -419,7 +569,11 @@ describe("POST with label and status", () => {
419
569
 
420
570
  describe("PATCH with status and label", () => {
421
571
  test("updates status to disabled", async () => {
422
- seedConnection({ name: "toggleable", provider: "anthropic", auth: { type: "platform" } });
572
+ seedConnection({
573
+ name: "toggleable",
574
+ provider: "anthropic",
575
+ auth: { type: "platform" },
576
+ });
423
577
 
424
578
  const result = (await call(
425
579
  findHandler("inference_provider_connections_update"),
@@ -432,7 +586,11 @@ describe("PATCH with status and label", () => {
432
586
  });
433
587
 
434
588
  test("updates label to a string", async () => {
435
- seedConnection({ name: "set-label", provider: "openai", auth: { type: "platform" } });
589
+ seedConnection({
590
+ name: "set-label",
591
+ provider: "openai",
592
+ auth: { type: "platform" },
593
+ });
436
594
 
437
595
  const result = (await call(
438
596
  findHandler("inference_provider_connections_update"),
@@ -445,7 +603,11 @@ describe("PATCH with status and label", () => {
445
603
  });
446
604
 
447
605
  test("clears label by setting it to null", async () => {
448
- seedConnection({ name: "clear-label", provider: "gemini", auth: { type: "platform" } });
606
+ seedConnection({
607
+ name: "clear-label",
608
+ provider: "gemini",
609
+ auth: { type: "platform" },
610
+ });
449
611
  // First set a label.
450
612
  await call(findHandler("inference_provider_connections_update"), {
451
613
  pathParams: { name: "clear-label" },
@@ -463,7 +625,11 @@ describe("PATCH with status and label", () => {
463
625
  });
464
626
 
465
627
  test("rejects label: empty string with 400", async () => {
466
- seedConnection({ name: "reject-empty", provider: "anthropic", auth: { type: "platform" } });
628
+ seedConnection({
629
+ name: "reject-empty",
630
+ provider: "anthropic",
631
+ auth: { type: "platform" },
632
+ });
467
633
 
468
634
  await expect(
469
635
  call(findHandler("inference_provider_connections_update"), {
@@ -477,12 +643,20 @@ describe("PATCH with status and label", () => {
477
643
  // ── Managed-connection write protection ──────────────────────────────────────
478
644
 
479
645
  describe("Managed connection write protection", () => {
480
- const MANAGED_NAMES = ["anthropic-managed", "openai-managed", "gemini-managed"] as const;
646
+ const MANAGED_NAMES = [
647
+ "anthropic-managed",
648
+ "openai-managed",
649
+ "gemini-managed",
650
+ ] as const;
481
651
 
482
652
  describe("DELETE", () => {
483
653
  for (const name of MANAGED_NAMES) {
484
654
  test(`rejects DELETE on ${name} with 400`, async () => {
485
- seedConnection({ name, provider: name.replace("-managed", ""), auth: { type: "platform" } });
655
+ seedConnection({
656
+ name,
657
+ provider: name.replace("-managed", ""),
658
+ auth: { type: "platform" },
659
+ });
486
660
 
487
661
  const err = await call(
488
662
  findHandler("inference_provider_connections_delete"),
@@ -498,11 +672,15 @@ describe("Managed connection write protection", () => {
498
672
  test("managed protection short-circuits before reference checks", async () => {
499
673
  // Even though a profile references the managed connection, the error
500
674
  // should be the managed-protection 400, not the references-409.
501
- seedConnection({ name: "anthropic-managed", provider: "anthropic", auth: { type: "platform" } });
675
+ seedConnection({
676
+ name: "anthropic-managed",
677
+ provider: "anthropic",
678
+ auth: { type: "platform" },
679
+ });
502
680
  fakeConfig = {
503
681
  llm: {
504
682
  profiles: {
505
- "balanced": { provider_connection: "anthropic-managed" },
683
+ balanced: { provider_connection: "anthropic-managed" },
506
684
  },
507
685
  },
508
686
  };
@@ -520,7 +698,11 @@ describe("Managed connection write protection", () => {
520
698
  describe("PATCH auth", () => {
521
699
  for (const name of MANAGED_NAMES) {
522
700
  test(`rejects auth change on ${name} from platform to api_key with 400`, async () => {
523
- seedConnection({ name, provider: name.replace("-managed", ""), auth: { type: "platform" } });
701
+ seedConnection({
702
+ name,
703
+ provider: name.replace("-managed", ""),
704
+ auth: { type: "platform" },
705
+ });
524
706
 
525
707
  const err = await call(
526
708
  findHandler("inference_provider_connections_update"),
@@ -536,7 +718,11 @@ describe("Managed connection write protection", () => {
536
718
  });
537
719
 
538
720
  test(`rejects auth change on ${name} from platform to none with 400`, async () => {
539
- seedConnection({ name, provider: name.replace("-managed", ""), auth: { type: "platform" } });
721
+ seedConnection({
722
+ name,
723
+ provider: name.replace("-managed", ""),
724
+ auth: { type: "platform" },
725
+ });
540
726
 
541
727
  const err = await call(
542
728
  findHandler("inference_provider_connections_update"),
@@ -552,13 +738,20 @@ describe("Managed connection write protection", () => {
552
738
  }
553
739
 
554
740
  test("allows PATCH with auth still set to platform (no-op auth change)", async () => {
555
- seedConnection({ name: "anthropic-managed", provider: "anthropic", auth: { type: "platform" } });
741
+ seedConnection({
742
+ name: "anthropic-managed",
743
+ provider: "anthropic",
744
+ auth: { type: "platform" },
745
+ });
556
746
 
557
747
  const result = (await call(
558
748
  findHandler("inference_provider_connections_update"),
559
749
  {
560
750
  pathParams: { name: "anthropic-managed" },
561
- body: { auth: { type: "platform" }, label: "Vellum-managed Anthropic" },
751
+ body: {
752
+ auth: { type: "platform" },
753
+ label: "Vellum-managed Anthropic",
754
+ },
562
755
  },
563
756
  )) as { label: string | null };
564
757
  expect(result.label).toBe("Vellum-managed Anthropic");
@@ -567,7 +760,11 @@ describe("Managed connection write protection", () => {
567
760
 
568
761
  describe("PATCH status + label (allowed)", () => {
569
762
  test("allows disabling a managed connection", async () => {
570
- seedConnection({ name: "anthropic-managed", provider: "anthropic", auth: { type: "platform" } });
763
+ seedConnection({
764
+ name: "anthropic-managed",
765
+ provider: "anthropic",
766
+ auth: { type: "platform" },
767
+ });
571
768
 
572
769
  const result = (await call(
573
770
  findHandler("inference_provider_connections_update"),
@@ -580,7 +777,11 @@ describe("Managed connection write protection", () => {
580
777
  });
581
778
 
582
779
  test("allows relabeling a managed connection", async () => {
583
- seedConnection({ name: "openai-managed", provider: "openai", auth: { type: "platform" } });
780
+ seedConnection({
781
+ name: "openai-managed",
782
+ provider: "openai",
783
+ auth: { type: "platform" },
784
+ });
584
785
 
585
786
  const result = (await call(
586
787
  findHandler("inference_provider_connections_update"),
@@ -597,21 +798,35 @@ describe("Managed connection write protection", () => {
597
798
  // ── isManaged response flag ───────────────────────────────────────────────────
598
799
 
599
800
  describe("isManaged flag on connection responses", () => {
600
- const MANAGED_NAMES = ["anthropic-managed", "openai-managed", "gemini-managed"] as const;
801
+ const MANAGED_NAMES = [
802
+ "anthropic-managed",
803
+ "openai-managed",
804
+ "gemini-managed",
805
+ ] as const;
601
806
 
602
807
  describe("GET list", () => {
603
808
  test("returns isManaged: true for canonical names and false for user-created rows", async () => {
604
809
  for (const name of MANAGED_NAMES) {
605
- seedConnection({ name, provider: name.replace("-managed", ""), auth: { type: "platform" } });
810
+ seedConnection({
811
+ name,
812
+ provider: name.replace("-managed", ""),
813
+ auth: { type: "platform" },
814
+ });
606
815
  }
607
- seedConnection({ name: "my-custom-anthropic", provider: "anthropic", auth: { type: "api_key", credential: "ref/k" } });
816
+ seedConnection({
817
+ name: "my-custom-anthropic",
818
+ provider: "anthropic",
819
+ auth: { type: "api_key", credential: "ref/k" },
820
+ });
608
821
 
609
822
  const result = (await call(
610
823
  findHandler("inference_provider_connections_list"),
611
824
  {},
612
825
  )) as { connections: Array<{ name: string; isManaged: boolean }> };
613
826
 
614
- const byName = Object.fromEntries(result.connections.map((c) => [c.name, c.isManaged]));
827
+ const byName = Object.fromEntries(
828
+ result.connections.map((c) => [c.name, c.isManaged]),
829
+ );
615
830
  expect(byName["anthropic-managed"]).toBe(true);
616
831
  expect(byName["openai-managed"]).toBe(true);
617
832
  expect(byName["gemini-managed"]).toBe(true);
@@ -621,7 +836,11 @@ describe("isManaged flag on connection responses", () => {
621
836
 
622
837
  describe("GET single", () => {
623
838
  test("returns isManaged: true for a managed name", async () => {
624
- seedConnection({ name: "anthropic-managed", provider: "anthropic", auth: { type: "platform" } });
839
+ seedConnection({
840
+ name: "anthropic-managed",
841
+ provider: "anthropic",
842
+ auth: { type: "platform" },
843
+ });
625
844
 
626
845
  const result = (await call(
627
846
  findHandler("inference_provider_connections_get"),
@@ -632,7 +851,11 @@ describe("isManaged flag on connection responses", () => {
632
851
  });
633
852
 
634
853
  test("returns isManaged: false for a user-created name", async () => {
635
- seedConnection({ name: "my-openai", provider: "openai", auth: { type: "api_key", credential: "ref/k" } });
854
+ seedConnection({
855
+ name: "my-openai",
856
+ provider: "openai",
857
+ auth: { type: "api_key", credential: "ref/k" },
858
+ });
636
859
 
637
860
  const result = (await call(
638
861
  findHandler("inference_provider_connections_get"),
@@ -662,7 +885,11 @@ describe("isManaged flag on connection responses", () => {
662
885
 
663
886
  describe("PATCH update", () => {
664
887
  test("returns isManaged: true after relabeling a managed connection", async () => {
665
- seedConnection({ name: "anthropic-managed", provider: "anthropic", auth: { type: "platform" } });
888
+ seedConnection({
889
+ name: "anthropic-managed",
890
+ provider: "anthropic",
891
+ auth: { type: "platform" },
892
+ });
666
893
 
667
894
  const result = (await call(
668
895
  findHandler("inference_provider_connections_update"),
@@ -676,7 +903,11 @@ describe("isManaged flag on connection responses", () => {
676
903
  });
677
904
 
678
905
  test("returns isManaged: false after updating a user connection", async () => {
679
- seedConnection({ name: "my-openai", provider: "openai", auth: { type: "api_key", credential: "ref/k" } });
906
+ seedConnection({
907
+ name: "my-openai",
908
+ provider: "openai",
909
+ auth: { type: "api_key", credential: "ref/k" },
910
+ });
680
911
 
681
912
  const result = (await call(
682
913
  findHandler("inference_provider_connections_update"),
@@ -45,6 +45,18 @@ describe("llm-call-sites-routes", () => {
45
45
  }
46
46
  });
47
47
 
48
+ test("defaultProfile is a non-empty string or undefined per call site", async () => {
49
+ const result = (await route.handler({})) as {
50
+ callSites: Array<{ id: string; defaultProfile?: string }>;
51
+ };
52
+ for (const site of result.callSites) {
53
+ if (site.defaultProfile != null) {
54
+ expect(typeof site.defaultProfile).toBe("string");
55
+ expect(site.defaultProfile.length).toBeGreaterThan(0);
56
+ }
57
+ }
58
+ });
59
+
48
60
  test("domains have non-empty id and displayName", async () => {
49
61
  const result = (await route.handler({})) as {
50
62
  domains: Array<{ id: string; displayName: string }>;