@vellumai/assistant 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (506) hide show
  1. package/ARCHITECTURE.md +2 -7
  2. package/Dockerfile +75 -1
  3. package/bun.lock +11 -1
  4. package/docker-entrypoint.sh +5 -0
  5. package/docker-init-apt-root.sh +94 -0
  6. package/docker-kata-apt-env.sh +39 -0
  7. package/docs/plugins.md +88 -47
  8. package/docs/skills.md +9 -7
  9. package/examples/plugins/echo/README.md +27 -27
  10. package/examples/plugins/echo/package.json +3 -0
  11. package/examples/plugins/echo/register.ts +31 -31
  12. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  13. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  14. package/openapi.yaml +325 -3
  15. package/package.json +3 -1
  16. package/scripts/generate-openapi.ts +83 -10
  17. package/scripts/sync-llm-catalog.ts +2 -2
  18. package/scripts/sync-web-search-catalog.ts +47 -25
  19. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  20. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  21. package/src/__tests__/anthropic-provider.test.ts +45 -0
  22. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  23. package/src/__tests__/app-executors.test.ts +220 -4
  24. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  25. package/src/__tests__/bundled-asset.test.ts +6 -6
  26. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  27. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  28. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  29. package/src/__tests__/clawhub.test.ts +75 -16
  30. package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
  31. package/src/__tests__/config-schema.test.ts +21 -0
  32. package/src/__tests__/config-set-route.test.ts +80 -0
  33. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  34. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  35. package/src/__tests__/context-search-conversations-source.test.ts +117 -2
  36. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  37. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  38. package/src/__tests__/context-token-estimator.test.ts +1 -0
  39. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
  42. package/src/__tests__/conversation-agent-loop.test.ts +2 -0
  43. package/src/__tests__/conversation-error.test.ts +42 -3
  44. package/src/__tests__/conversation-fork-crud.test.ts +82 -0
  45. package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
  46. package/src/__tests__/conversation-lifecycle.test.ts +173 -0
  47. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  48. package/src/__tests__/conversation-pairing.test.ts +54 -0
  49. package/src/__tests__/conversation-process-callsite.test.ts +4 -1
  50. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-queue.test.ts +4 -1
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
  53. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  54. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  55. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  56. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  59. package/src/__tests__/credential-security-invariants.test.ts +3 -2
  60. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  61. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  62. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  63. package/src/__tests__/dm-backfill.test.ts +121 -10
  64. package/src/__tests__/document-tool-security.test.ts +258 -0
  65. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  66. package/src/__tests__/edit-propagation.test.ts +33 -0
  67. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  68. package/src/__tests__/external-plugin-loader.test.ts +60 -36
  69. package/src/__tests__/filing-service.test.ts +140 -0
  70. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  71. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
  72. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  73. package/src/__tests__/helpers/wait-for.ts +21 -0
  74. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  75. package/src/__tests__/history-repair.test.ts +73 -0
  76. package/src/__tests__/host-app-control-proxy.test.ts +266 -10
  77. package/src/__tests__/image-credentials.test.ts +1 -1
  78. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  79. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
  80. package/src/__tests__/inference-profile-reaper.test.ts +4 -2
  81. package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
  82. package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
  83. package/src/__tests__/injector-chain.test.ts +10 -8
  84. package/src/__tests__/install-skill-routing.test.ts +155 -37
  85. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
  86. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  87. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  88. package/src/__tests__/llm-catalog-parity.test.ts +55 -13
  89. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
  90. package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
  91. package/src/__tests__/llm-usage-store.test.ts +114 -0
  92. package/src/__tests__/managed-profile-guard.test.ts +31 -29
  93. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  94. package/src/__tests__/managed-store.test.ts +84 -192
  95. package/src/__tests__/media-generate-image.test.ts +1 -1
  96. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  97. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  98. package/src/__tests__/oauth-commands-routes.test.ts +168 -16
  99. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  100. package/src/__tests__/openai-provider.test.ts +24 -0
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
  102. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  103. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  104. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
  105. package/src/__tests__/platform.test.ts +2 -0
  106. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  107. package/src/__tests__/plugin-bootstrap.test.ts +10 -36
  108. package/src/__tests__/plugin-external-api.test.ts +68 -0
  109. package/src/__tests__/plugin-registry.test.ts +0 -77
  110. package/src/__tests__/plugin-route-contribution.test.ts +0 -1
  111. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  112. package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
  113. package/src/__tests__/plugin-types.test.ts +3 -13
  114. package/src/__tests__/process-message-background-slack.test.ts +8 -1
  115. package/src/__tests__/process-message-display-content.test.ts +421 -0
  116. package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
  117. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  118. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
  119. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  120. package/src/__tests__/schedule-routes.test.ts +50 -3
  121. package/src/__tests__/schedule-store.test.ts +94 -0
  122. package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
  123. package/src/__tests__/schema-transforms.test.ts +20 -0
  124. package/src/__tests__/search-skills-unified.test.ts +0 -5
  125. package/src/__tests__/server-history-render.test.ts +43 -0
  126. package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
  127. package/src/__tests__/skill-load-tool.test.ts +27 -89
  128. package/src/__tests__/skill-memory.test.ts +23 -3
  129. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  130. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  131. package/src/__tests__/skills-install-extract.test.ts +49 -38
  132. package/src/__tests__/skills-install-staging.test.ts +159 -0
  133. package/src/__tests__/skills-uninstall.test.ts +9 -41
  134. package/src/__tests__/skills.test.ts +51 -58
  135. package/src/__tests__/slack-channel-config.test.ts +9 -0
  136. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  137. package/src/__tests__/system-prompt.test.ts +737 -63
  138. package/src/__tests__/terminal-tools.test.ts +28 -1
  139. package/src/__tests__/thread-backfill.test.ts +557 -27
  140. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  141. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  142. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  143. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  145. package/src/__tests__/tool-executor.test.ts +16 -4
  146. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  147. package/src/__tests__/turn-events-store.test.ts +256 -0
  148. package/src/__tests__/twilio-routes.test.ts +4 -0
  149. package/src/__tests__/user-plugin-loader.test.ts +0 -7
  150. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  151. package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
  152. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
  153. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
  154. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  155. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  156. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  157. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  158. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  159. package/src/acp/resolve-agent.ts +1 -1
  160. package/src/agent/image-optimize.ts +13 -5
  161. package/src/calls/voice-session-bridge.ts +61 -42
  162. package/src/channels/types.ts +108 -0
  163. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  164. package/src/cli/commands/__tests__/changelog.test.ts +304 -319
  165. package/src/cli/commands/__tests__/schedules.test.ts +491 -0
  166. package/src/cli/commands/changelog.ts +106 -42
  167. package/src/cli/commands/conversations.ts +102 -17
  168. package/src/cli/commands/default-action.ts +10 -53
  169. package/src/cli/commands/notifications.ts +329 -317
  170. package/src/cli/commands/plugins.ts +185 -0
  171. package/src/cli/commands/schedules.ts +391 -0
  172. package/src/cli/commands/telemetry.ts +40 -0
  173. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  174. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  177. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  178. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  179. package/src/cli/lib/cli-colors.ts +12 -0
  180. package/src/cli/lib/confirm-prompt.ts +79 -0
  181. package/src/cli/lib/install-from-github.ts +304 -0
  182. package/src/cli/lib/list-installed-plugins.ts +137 -0
  183. package/src/cli/lib/uninstall-plugin.ts +82 -0
  184. package/src/cli/lib/unknown-command.ts +111 -0
  185. package/src/cli/program.ts +38 -2
  186. package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
  187. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  188. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  189. package/src/config/bundled-skills/document/SKILL.md +23 -3
  190. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  191. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  192. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  193. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  194. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  195. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  196. package/src/config/bundled-tool-registry.ts +6 -0
  197. package/src/config/feature-flag-registry.json +41 -1
  198. package/src/config/loader.ts +64 -38
  199. package/src/config/schema.ts +7 -10
  200. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  201. package/src/config/schemas/channels.ts +8 -0
  202. package/src/config/schemas/compaction.ts +28 -0
  203. package/src/config/schemas/heartbeat.ts +9 -0
  204. package/src/config/schemas/llm-request-logs.ts +31 -7
  205. package/src/config/schemas/llm.ts +3 -0
  206. package/src/config/schemas/memory-retrieval.ts +18 -0
  207. package/src/config/schemas/tools.ts +14 -0
  208. package/src/config/skills.ts +3 -96
  209. package/src/context/compactor.ts +1047 -0
  210. package/src/context/token-estimator.ts +2 -2
  211. package/src/context/window-manager.ts +197 -1520
  212. package/src/credential-execution/managed-catalog.ts +37 -0
  213. package/src/credential-health/credential-health-service.ts +280 -19
  214. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
  215. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  216. package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
  217. package/src/daemon/approval-generators.ts +8 -6
  218. package/src/daemon/config-watcher.ts +94 -31
  219. package/src/daemon/conversation-agent-loop.ts +169 -9
  220. package/src/daemon/conversation-error.ts +171 -37
  221. package/src/daemon/conversation-lifecycle.ts +53 -40
  222. package/src/daemon/conversation-messaging.ts +25 -6
  223. package/src/daemon/conversation-process.ts +49 -12
  224. package/src/daemon/conversation-runtime-assembly.ts +16 -1
  225. package/src/daemon/conversation-slash.ts +12 -5
  226. package/src/daemon/conversation-store.ts +11 -4
  227. package/src/daemon/conversation-tool-setup.ts +39 -7
  228. package/src/daemon/conversation.ts +33 -1
  229. package/src/daemon/external-plugins-bootstrap.ts +217 -181
  230. package/src/daemon/first-greeting.ts +22 -2
  231. package/src/daemon/handlers/config-model.ts +6 -5
  232. package/src/daemon/handlers/config-slack-channel.ts +15 -3
  233. package/src/daemon/handlers/shared.ts +14 -5
  234. package/src/daemon/handlers/skills.ts +111 -108
  235. package/src/daemon/history-repair.ts +28 -1
  236. package/src/daemon/host-app-control-proxy.ts +98 -23
  237. package/src/daemon/lifecycle.ts +45 -35
  238. package/src/daemon/meet-host-supervisor.ts +5 -4
  239. package/src/daemon/memory-v2-startup.ts +49 -0
  240. package/src/daemon/message-protocol.ts +1 -0
  241. package/src/daemon/message-types/conversations.ts +25 -0
  242. package/src/daemon/message-types/messages.ts +61 -0
  243. package/src/daemon/message-types/subagents.ts +1 -0
  244. package/src/daemon/message-types/sync.ts +1 -0
  245. package/src/daemon/pkb-reminder-builder.test.ts +1 -1
  246. package/src/daemon/pkb-reminder-builder.ts +1 -1
  247. package/src/daemon/plugin-source-watcher.ts +146 -0
  248. package/src/daemon/process-message.ts +21 -3
  249. package/src/daemon/server.ts +11 -2
  250. package/src/daemon/skill-memory-refresh.ts +29 -0
  251. package/src/documents/document-store.ts +221 -3
  252. package/src/embedded/plugin-api.ts +40 -0
  253. package/src/filing/filing-service.ts +39 -0
  254. package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
  255. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  256. package/src/heartbeat/heartbeat-service.ts +41 -0
  257. package/src/home/__tests__/feed-types.test.ts +40 -0
  258. package/src/home/feed-types.ts +22 -0
  259. package/src/home/post-connect-feed.ts +1 -0
  260. package/src/index.ts +18 -1
  261. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  262. package/src/mcp/client.ts +20 -4
  263. package/src/media/image-credentials.ts +3 -3
  264. package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
  265. package/src/memory/__tests__/conversation-queries.test.ts +263 -0
  266. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  267. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
  268. package/src/memory/__tests__/message-content.test.ts +35 -0
  269. package/src/memory/bookmark-crud.ts +42 -10
  270. package/src/memory/context-search/sources/conversations.ts +62 -2
  271. package/src/memory/context-search/sources/workspace.ts +4 -0
  272. package/src/memory/conversation-crud.ts +63 -19
  273. package/src/memory/conversation-queries.ts +110 -10
  274. package/src/memory/db-init.ts +6 -0
  275. package/src/memory/delivery-crud.ts +152 -5
  276. package/src/memory/embedding-backend.ts +4 -4
  277. package/src/memory/external-conversation-store.ts +66 -5
  278. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
  279. package/src/memory/graph/conversation-graph-memory.ts +31 -15
  280. package/src/memory/graph/tools.ts +3 -3
  281. package/src/memory/indexer.ts +34 -29
  282. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
  283. package/src/memory/jobs/embed-concept-page.ts +20 -11
  284. package/src/memory/jobs-worker.ts +6 -1
  285. package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
  286. package/src/memory/llm-request-log-source.ts +19 -52
  287. package/src/memory/llm-usage-store.ts +125 -5
  288. package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
  289. package/src/memory/message-content.ts +1 -1
  290. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  291. package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
  292. package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
  293. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  294. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  295. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  296. package/src/memory/migrations/index.ts +6 -0
  297. package/src/memory/migrations/registry.ts +8 -0
  298. package/src/memory/onboarding-events-store.ts +106 -0
  299. package/src/memory/schema/bookmarks.ts +0 -2
  300. package/src/memory/schema/calls.ts +1 -0
  301. package/src/memory/schema/inference.ts +1 -3
  302. package/src/memory/schema/infrastructure.ts +12 -0
  303. package/src/memory/turn-events-store.ts +127 -2
  304. package/src/memory/v2/__tests__/activation.test.ts +0 -8
  305. package/src/memory/v2/__tests__/injection.test.ts +98 -8
  306. package/src/memory/v2/__tests__/migration.test.ts +87 -0
  307. package/src/memory/v2/__tests__/page-index.test.ts +83 -0
  308. package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
  309. package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
  310. package/src/memory/v2/__tests__/router.test.ts +15 -0
  311. package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
  312. package/src/memory/v2/injection.ts +32 -6
  313. package/src/memory/v2/migration.ts +49 -19
  314. package/src/memory/v2/page-index.ts +35 -5
  315. package/src/memory/v2/prompts/router.ts +11 -8
  316. package/src/memory/v2/prompts/sweep.ts +2 -2
  317. package/src/memory/v2/qdrant.ts +135 -7
  318. package/src/memory/v2/router.ts +9 -8
  319. package/src/memory/v2/skill-store.ts +120 -35
  320. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  321. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  322. package/src/messaging/providers/slack/adapter.ts +43 -5
  323. package/src/messaging/providers/slack/client.ts +27 -0
  324. package/src/messaging/providers/slack/deep-link.ts +65 -0
  325. package/src/messaging/providers/slack/download.ts +104 -0
  326. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  327. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  328. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  329. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  330. package/src/messaging/providers/slack/types.ts +20 -1
  331. package/src/notifications/conversation-pairing.ts +2 -1
  332. package/src/notifications/decision-engine.ts +2 -1
  333. package/src/notifications/emit-signal.ts +20 -1
  334. package/src/notifications/home-feed-side-effect.ts +54 -0
  335. package/src/notifications/signal.ts +3 -1
  336. package/src/oauth/connection-resolver.ts +8 -4
  337. package/src/oauth/platform-connection.ts +6 -2
  338. package/src/oauth/seed-providers.ts +10 -1
  339. package/src/permissions/checker.ts +2 -0
  340. package/src/permissions/ipc-risk-types.ts +1 -0
  341. package/src/permissions/question-prompter.test.ts +416 -0
  342. package/src/permissions/question-prompter.ts +294 -0
  343. package/src/platform/client.test.ts +1 -1
  344. package/src/platform/client.ts +1 -1
  345. package/src/plugin-api/constants.ts +26 -0
  346. package/src/plugin-api/index.ts +34 -1
  347. package/src/plugin-api/types.ts +104 -22
  348. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  349. package/src/plugins/defaults/compaction.ts +0 -4
  350. package/src/plugins/defaults/empty-response.ts +0 -2
  351. package/src/plugins/defaults/history-repair.ts +0 -2
  352. package/src/plugins/defaults/injectors.ts +36 -3
  353. package/src/plugins/defaults/llm-call.ts +0 -2
  354. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  355. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  356. package/src/plugins/defaults/persistence.ts +0 -2
  357. package/src/plugins/defaults/title-generate.ts +0 -5
  358. package/src/plugins/defaults/token-estimate.ts +0 -2
  359. package/src/plugins/defaults/tool-error.ts +0 -7
  360. package/src/plugins/defaults/tool-execute.ts +0 -2
  361. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  362. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  363. package/src/plugins/external-api.ts +104 -0
  364. package/src/plugins/external-plugin-loader.ts +105 -32
  365. package/src/plugins/feature-gate.ts +22 -0
  366. package/src/plugins/pipeline.ts +37 -0
  367. package/src/plugins/registry.ts +48 -80
  368. package/src/plugins/types.ts +31 -26
  369. package/src/plugins/user-loader.ts +21 -2
  370. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  371. package/src/proactive-artifact/job.test.ts +37 -5
  372. package/src/prompts/__tests__/system-prompt.test.ts +12 -0
  373. package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
  374. package/src/prompts/normalize-onboarding.ts +27 -0
  375. package/src/prompts/sections.ts +302 -0
  376. package/src/prompts/system-prompt.ts +63 -166
  377. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  378. package/src/prompts/templates/system-sections.ts +173 -0
  379. package/src/providers/__tests__/inference.test.ts +22 -7
  380. package/src/providers/anthropic/client.ts +28 -28
  381. package/src/providers/connection-resolution.ts +7 -0
  382. package/src/providers/inference/adapter-factory.ts +41 -4
  383. package/src/providers/inference/connections.ts +74 -29
  384. package/src/providers/inference/resolve-auth.ts +12 -4
  385. package/src/providers/model-catalog.ts +294 -12
  386. package/src/providers/openai/chat-completions-provider.ts +10 -2
  387. package/src/providers/openrouter/client.ts +7 -0
  388. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
  389. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  390. package/src/providers/provider-availability.ts +17 -2
  391. package/src/providers/provider-catalog-visibility.ts +36 -0
  392. package/src/providers/registry.ts +22 -14
  393. package/src/providers/retry.ts +47 -1
  394. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  395. package/src/runtime/agent-wake.ts +42 -14
  396. package/src/runtime/auth/route-policy.ts +8 -1
  397. package/src/runtime/btw-sidechain.ts +2 -0
  398. package/src/runtime/http-types.ts +19 -0
  399. package/src/runtime/migrations/origin-mode.ts +1 -1
  400. package/src/runtime/pending-interactions.ts +1 -0
  401. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
  402. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
  403. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
  404. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  405. package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
  406. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  407. package/src/runtime/routes/acp-routes.ts +5 -3
  408. package/src/runtime/routes/auth-routes.ts +1 -1
  409. package/src/runtime/routes/bookmark-routes.ts +5 -3
  410. package/src/runtime/routes/btw-routes.ts +5 -1
  411. package/src/runtime/routes/channel-availability-routes.ts +121 -0
  412. package/src/runtime/routes/conversation-cli-routes.ts +44 -3
  413. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  414. package/src/runtime/routes/conversation-management-routes.ts +17 -42
  415. package/src/runtime/routes/conversation-query-routes.ts +40 -35
  416. package/src/runtime/routes/conversation-routes.ts +90 -11
  417. package/src/runtime/routes/documents-routes.ts +25 -86
  418. package/src/runtime/routes/group-routes.ts +5 -0
  419. package/src/runtime/routes/inbound-conversation.ts +28 -8
  420. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  421. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
  422. package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
  423. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  424. package/src/runtime/routes/index.ts +6 -0
  425. package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
  426. package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
  427. package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
  428. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  429. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  430. package/src/runtime/routes/integrations/twilio.ts +6 -13
  431. package/src/runtime/routes/notification-routes.ts +1 -1
  432. package/src/runtime/routes/oauth-commands-routes.ts +105 -15
  433. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  434. package/src/runtime/routes/question-routes.ts +259 -0
  435. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  436. package/src/runtime/routes/schedule-routes.ts +4 -7
  437. package/src/runtime/routes/subagents-routes.ts +57 -18
  438. package/src/runtime/routes/telemetry-routes.ts +27 -0
  439. package/src/runtime/routes/tts-routes.ts +27 -2
  440. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  441. package/src/runtime/routes/workspace-routes.ts +28 -0
  442. package/src/runtime/services/conversation-serializer.ts +39 -7
  443. package/src/runtime/sync/resource-sync-events.ts +93 -1
  444. package/src/schedule/schedule-store.ts +27 -2
  445. package/src/schedule/scheduler.ts +9 -1
  446. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  447. package/src/security/untrusted-content.ts +93 -8
  448. package/src/skills/catalog-files.ts +1 -1
  449. package/src/skills/catalog-install.ts +233 -116
  450. package/src/skills/clawhub.ts +70 -13
  451. package/src/skills/managed-store.ts +4 -119
  452. package/src/skills/skillssh-registry.ts +27 -48
  453. package/src/subagent/manager.ts +15 -7
  454. package/src/telemetry/types.ts +113 -1
  455. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  456. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  457. package/src/tools/apps/executors.ts +58 -7
  458. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  459. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  460. package/src/tools/browser/browser-execution.ts +15 -11
  461. package/src/tools/computer-use/definitions.ts +3 -3
  462. package/src/tools/credentials/vault.ts +1 -1
  463. package/src/tools/document/document-tool.ts +124 -1
  464. package/src/tools/filesystem/edit.ts +1 -1
  465. package/src/tools/filesystem/list.ts +1 -1
  466. package/src/tools/filesystem/read.ts +1 -1
  467. package/src/tools/filesystem/write.ts +5 -2
  468. package/src/tools/host-filesystem/transfer.ts +1 -1
  469. package/src/tools/host-terminal/host-shell.ts +1 -1
  470. package/src/tools/permission-checker.ts +1 -1
  471. package/src/tools/registry.ts +17 -7
  472. package/src/tools/schedule/create.ts +2 -2
  473. package/src/tools/schema-transforms.ts +7 -2
  474. package/src/tools/side-effects.ts +1 -0
  475. package/src/tools/skills/delete-managed.ts +4 -4
  476. package/src/tools/skills/execute.ts +1 -1
  477. package/src/tools/skills/scaffold-managed.ts +3 -2
  478. package/src/tools/subagent/notify-parent.ts +1 -1
  479. package/src/tools/system/request-permission.ts +2 -2
  480. package/src/tools/terminal/safe-env.ts +60 -1
  481. package/src/tools/tool-manifest.ts +2 -0
  482. package/src/tools/types.ts +72 -21
  483. package/src/tools/ui-surface/definitions.ts +6 -5
  484. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  485. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  486. package/src/types/onboarding-context.ts +2 -0
  487. package/src/util/errors.ts +17 -0
  488. package/src/util/platform.ts +10 -0
  489. package/src/watcher/__tests__/engine.test.ts +22 -0
  490. package/src/watcher/engine.ts +6 -2
  491. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
  492. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
  493. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
  494. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  495. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  496. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  497. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  498. package/src/workspace/migrations/registry.ts +8 -0
  499. package/src/workspace/migrations/runner.ts +39 -9
  500. package/src/workspace/migrations/types.ts +4 -0
  501. package/examples/plugins/echo/bun.lock +0 -25
  502. package/src/__tests__/context-window-manager.test.ts +0 -2481
  503. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  504. package/src/context/prompts/compact.md +0 -26
  505. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  506. /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
@@ -80,11 +80,6 @@ describe("titleGenerate pipeline", () => {
80
80
  manifest: {
81
81
  name: "default-title-generate",
82
82
  version: "1.0.0",
83
- provides: { titleGenerate: "v1" },
84
- requires: {
85
- pluginRuntime: "v1",
86
- titleGenerateApi: "v1",
87
- },
88
83
  },
89
84
  });
90
85
  });
@@ -149,10 +144,6 @@ describe("titleGenerate pipeline", () => {
149
144
  manifest: {
150
145
  name: "custom-deterministic-title",
151
146
  version: "0.0.1",
152
- requires: {
153
- pluginRuntime: "v1",
154
- titleGenerateApi: "v1",
155
- },
156
147
  },
157
148
  middleware: { titleGenerate: deterministicMw },
158
149
  };
@@ -201,10 +192,6 @@ describe("titleGenerate pipeline", () => {
201
192
  manifest: {
202
193
  name: "observer",
203
194
  version: "0.0.1",
204
- requires: {
205
- pluginRuntime: "v1",
206
- titleGenerateApi: "v1",
207
- },
208
195
  },
209
196
  middleware: { titleGenerate: passthroughMw },
210
197
  });
@@ -338,7 +338,6 @@ describe("tokenEstimate pipeline — custom override", () => {
338
338
  manifest: {
339
339
  name: "custom-token-estimate",
340
340
  version: "1.0.0",
341
- requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
342
341
  },
343
342
  middleware: { tokenEstimate: override },
344
343
  };
@@ -376,7 +375,6 @@ describe("tokenEstimate pipeline — custom override", () => {
376
375
  manifest: {
377
376
  name: "doubling-token-estimate",
378
377
  version: "1.0.0",
379
- requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
380
378
  },
381
379
  middleware: { tokenEstimate: doubler },
382
380
  };
@@ -420,7 +418,6 @@ describe("tokenEstimate pipeline — default does not shadow late plugins", () =
420
418
  manifest: {
421
419
  name: "late-registered-observer",
422
420
  version: "1.0.0",
423
- requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
424
421
  },
425
422
  middleware: { tokenEstimate: observer },
426
423
  };
@@ -150,7 +150,6 @@ describe("toolError pipeline", () => {
150
150
  manifest: {
151
151
  name: "custom-tool-error",
152
152
  version: "0.0.1",
153
- requires: { pluginRuntime: "v1", toolErrorApi: "v1" },
154
153
  },
155
154
  middleware: { toolError: customMiddleware },
156
155
  };
@@ -176,7 +175,6 @@ describe("toolError pipeline", () => {
176
175
  manifest: {
177
176
  name: "no-nudge",
178
177
  version: "0.0.1",
179
- requires: { pluginRuntime: "v1", toolErrorApi: "v1" },
180
178
  },
181
179
  middleware: { toolError: suppressingMiddleware },
182
180
  };
@@ -227,7 +225,6 @@ describe("toolError pipeline", () => {
227
225
  manifest: {
228
226
  name: "late-user-plugin",
229
227
  version: "0.0.1",
230
- requires: { pluginRuntime: "v1", toolErrorApi: "v1" },
231
228
  },
232
229
  middleware: { toolError: userMiddleware },
233
230
  });
@@ -249,7 +249,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
249
249
  manifest: {
250
250
  name: "spy-tool-execute",
251
251
  version: "0.0.1",
252
- requires: { pluginRuntime: "v1" },
253
252
  },
254
253
  middleware: { toolExecute: spyMiddleware },
255
254
  };
@@ -308,7 +307,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
308
307
  manifest: {
309
308
  name: "short-circuit-tool-execute",
310
309
  version: "0.0.1",
311
- requires: { pluginRuntime: "v1" },
312
310
  },
313
311
  middleware: { toolExecute: shortCircuit },
314
312
  };
@@ -342,7 +340,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
342
340
  manifest: {
343
341
  name: "slow-tool-execute",
344
342
  version: "0.0.1",
345
- requires: { pluginRuntime: "v1" },
346
343
  },
347
344
  middleware: { toolExecute: slow },
348
345
  });
@@ -388,7 +385,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
388
385
  manifest: {
389
386
  name: "outer-tool-execute",
390
387
  version: "0.0.1",
391
- requires: { pluginRuntime: "v1" },
392
388
  },
393
389
  middleware: { toolExecute: outer },
394
390
  });
@@ -396,7 +392,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
396
392
  manifest: {
397
393
  name: "inner-tool-execute",
398
394
  version: "0.0.1",
399
- requires: { pluginRuntime: "v1" },
400
395
  },
401
396
  middleware: { toolExecute: inner },
402
397
  });
@@ -242,7 +242,7 @@ describe("ToolExecutor lifecycle events", () => {
242
242
  );
243
243
 
244
244
  expect(result.isError).toBe(true);
245
- expect(result.content).toContain("Permission denied by user");
245
+ expect(result.content).toContain("Permission denied");
246
246
  expect(events.map((event) => event.type)).toEqual([
247
247
  "start",
248
248
  "permission_prompt",
@@ -462,6 +462,7 @@ describe("isSideEffectTool", () => {
462
462
  "web_fetch",
463
463
  "document_create",
464
464
  "document_update",
465
+ "document_delete",
465
466
  "schedule_create",
466
467
  "schedule_update",
467
468
  "schedule_delete",
@@ -670,6 +671,7 @@ describe("ToolExecutor forcePromptSideEffects enforcement", () => {
670
671
  { name: "web_fetch", input: { url: "https://example.com" } },
671
672
  { name: "document_create", input: { title: "doc", content: "body" } },
672
673
  { name: "document_update", input: { id: "doc-1", content: "updated" } },
674
+ { name: "document_delete", input: { surface_id: "doc-1" } },
673
675
  {
674
676
  name: "credential_store",
675
677
  input: { action: "store", name: "api-key", value: "secret" },
@@ -842,8 +844,12 @@ describe("ToolExecutor forcePromptSideEffects enforcement", () => {
842
844
  // ---------------------------------------------------------------------------
843
845
 
844
846
  // Import the real buildSanitizedEnv (not mocked) for baseline credential tests
845
- const { buildSanitizedEnv, SAFE_ENV_VARS, ALWAYS_INJECTED_ENV_VARS } =
846
- await import("../tools/terminal/safe-env.js");
847
+ const {
848
+ buildSanitizedEnv,
849
+ KATA_SAFE_ENV_VARS,
850
+ SAFE_ENV_VARS,
851
+ ALWAYS_INJECTED_ENV_VARS,
852
+ } = await import("../tools/terminal/safe-env.js");
847
853
 
848
854
  describe("buildSanitizedEnv — baseline: credential exclusion", () => {
849
855
  // Credential-like env vars that must never appear in the sanitized env.
@@ -901,7 +907,11 @@ describe("buildSanitizedEnv — baseline: credential exclusion", () => {
901
907
  });
902
908
 
903
909
  test("sanitized env only contains keys from the allowlist", () => {
904
- const allowed: string[] = [...SAFE_ENV_VARS, ...ALWAYS_INJECTED_ENV_VARS];
910
+ const allowed: string[] = [
911
+ ...SAFE_ENV_VARS,
912
+ ...KATA_SAFE_ENV_VARS,
913
+ ...ALWAYS_INJECTED_ENV_VARS,
914
+ ];
905
915
  const env = buildSanitizedEnv();
906
916
  for (const key of Object.keys(env)) {
907
917
  expect(allowed).toContain(key);
@@ -1211,7 +1221,9 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
1211
1221
  cachedAssessmentOverride = {
1212
1222
  riskLevel: "low",
1213
1223
  reason: "GET request to public URL",
1214
- scopeOptions: [{ pattern: "https://example.com/.*", label: "example.com" }],
1224
+ scopeOptions: [
1225
+ { pattern: "https://example.com/.*", label: "example.com" },
1226
+ ],
1215
1227
  // allowlistOptions intentionally omitted — some classifiers don't emit them.
1216
1228
  matchType: "registry",
1217
1229
  };
@@ -236,10 +236,6 @@ describe("toolResultTruncate pipeline", () => {
236
236
  manifest: {
237
237
  name: "short-circuit",
238
238
  version: "1.0.0",
239
- requires: {
240
- pluginRuntime: "v1",
241
- toolResultTruncateApi: "v1",
242
- },
243
239
  },
244
240
  middleware: { toolResultTruncate: shortCircuit },
245
241
  });
@@ -274,10 +270,6 @@ describe("toolResultTruncate pipeline", () => {
274
270
  manifest: {
275
271
  name: "prefixer",
276
272
  version: "1.0.0",
277
- requires: {
278
- pluginRuntime: "v1",
279
- toolResultTruncateApi: "v1",
280
- },
281
273
  },
282
274
  middleware: { toolResultTruncate: prefixer },
283
275
  });
@@ -323,10 +315,6 @@ describe("toolResultTruncate pipeline", () => {
323
315
  manifest: {
324
316
  name: "late-user-plugin",
325
317
  version: "0.0.1",
326
- requires: {
327
- pluginRuntime: "v1",
328
- toolResultTruncateApi: "v1",
329
- },
330
318
  },
331
319
  middleware: { toolResultTruncate: userMiddleware },
332
320
  });
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Tests for queryUnreportedTurnEvents.
3
+ *
4
+ * Verifies that the JOIN to `conversations` correctly attaches the parent
5
+ * conversation's `conversationType` to each returned turn, so analytics
6
+ * downstream (DAU) can filter out background/scheduled prompts.
7
+ */
8
+
9
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
10
+
11
+ import { makeMockLogger } from "./helpers/mock-logger.js";
12
+
13
+ mock.module("../util/logger.js", () => ({
14
+ getLogger: () => makeMockLogger(),
15
+ }));
16
+
17
+ import { addMessage, createConversation } from "../memory/conversation-crud.js";
18
+ import { getDb } from "../memory/db-connection.js";
19
+ import { initializeDb } from "../memory/db-init.js";
20
+ import { messages } from "../memory/schema.js";
21
+ import { queryUnreportedTurnEvents } from "../memory/turn-events-store.js";
22
+
23
+ initializeDb();
24
+
25
+ function purge(): void {
26
+ const db = getDb();
27
+ // Wipe messages then conversations to keep tests independent. FK cascade
28
+ // also removes any dependent rows.
29
+ db.run("DELETE FROM messages");
30
+ db.run("DELETE FROM conversations");
31
+ }
32
+
33
+ beforeEach(() => {
34
+ purge();
35
+ });
36
+
37
+ /**
38
+ * Insert a user message at a specific epoch-millis timestamp so we can
39
+ * assert ordering and the watermark cursor.
40
+ */
41
+ async function insertUserMessageAt(
42
+ conversationId: string,
43
+ content: string,
44
+ createdAt: number,
45
+ ): Promise<string> {
46
+ const message = await addMessage(conversationId, "user", content);
47
+ // addMessage stamps createdAt to monotonic now(); rewrite for
48
+ // deterministic ordering in the test.
49
+ const db = getDb();
50
+ db.run(
51
+ `UPDATE messages SET created_at = ${createdAt} WHERE id = '${message.id}'`,
52
+ );
53
+ return message.id;
54
+ }
55
+
56
+ describe("queryUnreportedTurnEvents", () => {
57
+ test("attaches conversationId, conversationType, and turnIndex for a standard conversation", async () => {
58
+ const conv = createConversation({ conversationType: "standard" });
59
+ await insertUserMessageAt(conv.id, "hello", 1000);
60
+
61
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
62
+ expect(events.length).toBe(1);
63
+ expect(events[0].conversationId).toBe(conv.id);
64
+ expect(events[0].conversationType).toBe("standard");
65
+ // The single user message in this conversation is turn 1.
66
+ expect(events[0].turnIndex).toBe(1);
67
+ });
68
+
69
+ test("attaches conversationType for background and scheduled conversations", async () => {
70
+ const bg = createConversation({ conversationType: "background" });
71
+ const sched = createConversation({ conversationType: "scheduled" });
72
+ const std = createConversation({ conversationType: "standard" });
73
+
74
+ const bgMsg = await insertUserMessageAt(bg.id, "bg prompt", 1000);
75
+ const schedMsg = await insertUserMessageAt(sched.id, "sched prompt", 2000);
76
+ const stdMsg = await insertUserMessageAt(std.id, "user typed this", 3000);
77
+
78
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
79
+ const byId = Object.fromEntries(events.map((e) => [e.id, e]));
80
+
81
+ expect(byId[bgMsg].conversationType).toBe("background");
82
+ expect(byId[schedMsg].conversationType).toBe("scheduled");
83
+ expect(byId[stdMsg].conversationType).toBe("standard");
84
+ });
85
+
86
+ test("excludes tool_result and web_search_tool_result content patterns", async () => {
87
+ const conv = createConversation({ conversationType: "standard" });
88
+
89
+ // Real user turn
90
+ const realId = await insertUserMessageAt(conv.id, "real user text", 1000);
91
+
92
+ // Synthetic "user" rows that wrap tool results: these should be filtered
93
+ const db = getDb();
94
+ db.insert(messages)
95
+ .values({
96
+ id: "tool-result-id",
97
+ conversationId: conv.id,
98
+ role: "user",
99
+ content: JSON.stringify([
100
+ { type: "tool_result", tool_use_id: "x", content: "" },
101
+ ]),
102
+ createdAt: 2000,
103
+ })
104
+ .run();
105
+ db.insert(messages)
106
+ .values({
107
+ id: "web-search-tool-result-id",
108
+ conversationId: conv.id,
109
+ role: "user",
110
+ content: JSON.stringify([
111
+ { type: "web_search_tool_result", tool_use_id: "y", content: "" },
112
+ ]),
113
+ createdAt: 3000,
114
+ })
115
+ .run();
116
+
117
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
118
+ expect(events.length).toBe(1);
119
+ expect(events[0].id).toBe(realId);
120
+ expect(events[0].conversationType).toBe("standard");
121
+ // Tool-result rows must NOT increment the turn index: this is the
122
+ // only real user turn in the conversation, so its index is 1 even
123
+ // though two synthetic role="user" rows exist with later timestamps.
124
+ expect(events[0].turnIndex).toBe(1);
125
+ });
126
+
127
+ test("turnIndex counts real user turns in (createdAt, id) order within a conversation", async () => {
128
+ const conv = createConversation({ conversationType: "standard" });
129
+ const m1 = await insertUserMessageAt(conv.id, "first", 1000);
130
+ const m2 = await insertUserMessageAt(conv.id, "second", 2000);
131
+ const m3 = await insertUserMessageAt(conv.id, "third", 3000);
132
+
133
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
134
+ const byId = Object.fromEntries(events.map((e) => [e.id, e]));
135
+ expect(byId[m1].turnIndex).toBe(1);
136
+ expect(byId[m2].turnIndex).toBe(2);
137
+ expect(byId[m3].turnIndex).toBe(3);
138
+ });
139
+
140
+ test("turnIndex resets across conversations", async () => {
141
+ const a = createConversation({ conversationType: "standard" });
142
+ const b = createConversation({ conversationType: "standard" });
143
+ const a1 = await insertUserMessageAt(a.id, "a first", 1000);
144
+ const b1 = await insertUserMessageAt(b.id, "b first", 1500);
145
+ const a2 = await insertUserMessageAt(a.id, "a second", 2000);
146
+
147
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
148
+ const byId = Object.fromEntries(events.map((e) => [e.id, e]));
149
+ // Conversation A: 1, 2. Conversation B: 1 (independent of A).
150
+ expect(byId[a1].turnIndex).toBe(1);
151
+ expect(byId[a2].turnIndex).toBe(2);
152
+ expect(byId[b1].turnIndex).toBe(1);
153
+ // And the conversation_id labels them correctly.
154
+ expect(byId[a1].conversationId).toBe(a.id);
155
+ expect(byId[b1].conversationId).toBe(b.id);
156
+ });
157
+
158
+ test("turnIndex skips tool_result rows even when they're interleaved", async () => {
159
+ const conv = createConversation({ conversationType: "standard" });
160
+ const real1 = await insertUserMessageAt(conv.id, "first real", 1000);
161
+
162
+ // Inject a tool_result row between the two real turns. The
163
+ // correlated subquery must use the same content filter as the
164
+ // outer query, otherwise turn_index would jump by 2 instead of 1.
165
+ const db = getDb();
166
+ db.insert(messages)
167
+ .values({
168
+ id: "interleaved-tool-result",
169
+ conversationId: conv.id,
170
+ role: "user",
171
+ content: JSON.stringify([
172
+ { type: "tool_result", tool_use_id: "x", content: "" },
173
+ ]),
174
+ createdAt: 1500,
175
+ })
176
+ .run();
177
+
178
+ const real2 = await insertUserMessageAt(conv.id, "second real", 2000);
179
+
180
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
181
+ const byId = Object.fromEntries(events.map((e) => [e.id, e]));
182
+ expect(events.length).toBe(2);
183
+ expect(byId[real1].turnIndex).toBe(1);
184
+ expect(byId[real2].turnIndex).toBe(2);
185
+ });
186
+
187
+ test("respects the cursor and returns events in (createdAt, id) order", async () => {
188
+ const conv = createConversation({ conversationType: "standard" });
189
+ const m1 = await insertUserMessageAt(conv.id, "first", 1000);
190
+ const m2 = await insertUserMessageAt(conv.id, "second", 2000);
191
+ const m3 = await insertUserMessageAt(conv.id, "third", 3000);
192
+
193
+ // Cursor at (1500, undefined) should skip m1 and return m2, m3 in order.
194
+ const after = queryUnreportedTurnEvents(1500, undefined, 100);
195
+ expect(after.map((e) => e.id)).toEqual([m2, m3]);
196
+
197
+ // Sanity: pulling from the start returns all three with correct types.
198
+ const all = queryUnreportedTurnEvents(0, undefined, 100);
199
+ expect(all.map((e) => e.id)).toEqual([m1, m2, m3]);
200
+ for (const e of all) {
201
+ expect(e.conversationType).toBe("standard");
202
+ }
203
+ });
204
+
205
+ test("extracts interfaceId, channelId, and clientMetadata from messages.metadata", async () => {
206
+ // Three user messages with different metadata shapes to cover the
207
+ // realistic spectrum of attribution carried on messages.metadata:
208
+ // - Full interactive: macOS surface, vellum channel, with a client
209
+ // block stamped by the (forthcoming) HTTP header middleware.
210
+ // - Channel inbound: Slack surface, no client headers (channel
211
+ // inbound paths don't carry browser context).
212
+ // - Legacy: a message persisted before metadata threading existed.
213
+ const conv = createConversation({ conversationType: "standard" });
214
+
215
+ const macOsMsg = await addMessage(conv.id, "user", "hi from desktop", {
216
+ userMessageInterface: "macos",
217
+ userMessageChannel: "vellum",
218
+ client: {
219
+ os: "darwin",
220
+ interface_version: "0.8.2",
221
+ },
222
+ });
223
+ const slackMsg = await addMessage(conv.id, "user", "hi from slack", {
224
+ userMessageInterface: "slack",
225
+ userMessageChannel: "slack",
226
+ });
227
+ const legacyMsg = await addMessage(conv.id, "user", "hi from the past");
228
+
229
+ const events = queryUnreportedTurnEvents(0, undefined, 100);
230
+ const byId = Object.fromEntries(events.map((e) => [e.id, e]));
231
+
232
+ expect(byId[macOsMsg.id]).toBeDefined();
233
+ expect(byId[macOsMsg.id].interfaceId).toBe("macos");
234
+ expect(byId[macOsMsg.id].channelId).toBe("vellum");
235
+ // clientMetadata is returned as raw JSON text -- the reporter parses it.
236
+ // We verify it round-trips back to the input object.
237
+ expect(byId[macOsMsg.id].clientMetadata).not.toBeNull();
238
+ expect(
239
+ JSON.parse(byId[macOsMsg.id].clientMetadata as string),
240
+ ).toMatchObject({
241
+ os: "darwin",
242
+ interface_version: "0.8.2",
243
+ });
244
+
245
+ expect(byId[slackMsg.id].interfaceId).toBe("slack");
246
+ expect(byId[slackMsg.id].channelId).toBe("slack");
247
+ expect(byId[slackMsg.id].clientMetadata).toBeNull();
248
+
249
+ // Legacy rows (no metadata threading) return null for all three
250
+ // attribution fields -- downstream analytics treats these as
251
+ // "unknown" without breaking the batch.
252
+ expect(byId[legacyMsg.id].interfaceId).toBeNull();
253
+ expect(byId[legacyMsg.id].channelId).toBeNull();
254
+ expect(byId[legacyMsg.id].clientMetadata).toBeNull();
255
+ });
256
+ });
@@ -1392,6 +1392,10 @@ describe("twilio webhook routes", () => {
1392
1392
 
1393
1393
  expect(result.success).toBe(true);
1394
1394
  expect(result.hasCredentials).toBe(true);
1395
+ expect(mockRawConfigStore.twilio).toEqual({
1396
+ accountSid: "AC_new_credentials",
1397
+ setupStarted: true,
1398
+ });
1395
1399
  });
1396
1400
 
1397
1401
  test("clearing credentials succeeds", async () => {
@@ -81,7 +81,6 @@ registerPlugin({
81
81
  manifest: {
82
82
  name: "my-plugin",
83
83
  version: "0.0.1",
84
- requires: { pluginRuntime: "v1" },
85
84
  },
86
85
  });
87
86
  `,
@@ -111,7 +110,6 @@ registerPlugin({
111
110
  manifest: {
112
111
  name: "good-plugin",
113
112
  version: "0.0.1",
114
- requires: { pluginRuntime: "v1" },
115
113
  },
116
114
  });
117
115
  `,
@@ -151,7 +149,6 @@ registerPlugin({
151
149
  manifest: {
152
150
  name: "hanging-plugin",
153
151
  version: "0.0.1",
154
- requires: { pluginRuntime: "v1" },
155
152
  },
156
153
  });
157
154
  `,
@@ -163,7 +160,6 @@ registerPlugin({
163
160
  manifest: {
164
161
  name: "healthy-plugin",
165
162
  version: "0.0.1",
166
- requires: { pluginRuntime: "v1" },
167
163
  },
168
164
  });
169
165
  `,
@@ -198,7 +194,6 @@ registerPlugin({
198
194
  manifest: {
199
195
  name: "slow-late-plugin",
200
196
  version: "0.0.1",
201
- requires: { pluginRuntime: "v1" },
202
197
  },
203
198
  });
204
199
  `,
@@ -305,7 +300,6 @@ registerPlugin({
305
300
  manifest: {
306
301
  name: "healthy-legacy",
307
302
  version: "0.0.1",
308
- requires: { pluginRuntime: "v1" },
309
303
  },
310
304
  });
311
305
  `,
@@ -330,7 +324,6 @@ registerPlugin({
330
324
  manifest: {
331
325
  name: "old-style",
332
326
  version: "0.0.1",
333
- requires: { pluginRuntime: "v1" },
334
327
  },
335
328
  });
336
329
  `,