@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.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 (430) hide show
  1. package/bun.lock +0 -20
  2. package/docs/workspace-tools.md +33 -42
  3. package/eslint-rules/cli-no-daemon-internals.js +0 -6
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
  5. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
  6. package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
  7. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
  8. package/node_modules/@vellumai/service-contracts/package.json +0 -1
  9. package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  10. package/openapi.yaml +0 -155
  11. package/package.json +1 -4
  12. package/scripts/test.sh +15 -36
  13. package/src/__tests__/actor-token-service.test.ts +14 -36
  14. package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
  15. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
  16. package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
  17. package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
  18. package/src/__tests__/annotate-risk-options.test.ts +0 -2
  19. package/src/__tests__/approval-cascade.test.ts +0 -2
  20. package/src/__tests__/assistant-attachments.test.ts +0 -42
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  22. package/src/__tests__/btw-routes.test.ts +0 -2
  23. package/src/__tests__/build-persisted-content.test.ts +0 -2
  24. package/src/__tests__/call-controller.test.ts +0 -19
  25. package/src/__tests__/channel-guardian.test.ts +58 -94
  26. package/src/__tests__/channel-reply-delivery.test.ts +0 -2
  27. package/src/__tests__/compaction-events.test.ts +0 -2
  28. package/src/__tests__/compaction.benchmark.test.ts +0 -2
  29. package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
  30. package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
  31. package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
  32. package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
  33. package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
  34. package/src/__tests__/config-loader-backfill.test.ts +10 -123
  35. package/src/__tests__/config-schema.test.ts +0 -1
  36. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
  37. package/src/__tests__/contacts-relay-reads.test.ts +15 -13
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
  39. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  42. package/src/__tests__/conversation-agent-loop.test.ts +0 -134
  43. package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
  44. package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
  45. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
  46. package/src/__tests__/conversation-history-web-search.test.ts +0 -2
  47. package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
  48. package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
  49. package/src/__tests__/conversation-pairing.test.ts +0 -2
  50. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +0 -2
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
  53. package/src/__tests__/conversation-queue.test.ts +0 -91
  54. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
  56. package/src/__tests__/conversation-slash-queue.test.ts +0 -2
  57. package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
  58. package/src/__tests__/conversation-speed-override.test.ts +0 -2
  59. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
  60. package/src/__tests__/conversation-title-service.test.ts +0 -2
  61. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
  62. package/src/__tests__/conversation-usage.test.ts +0 -2
  63. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
  64. package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
  65. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
  66. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  67. package/src/__tests__/db-migration-rollback.test.ts +171 -205
  68. package/src/__tests__/db-test-helpers.ts +4 -5
  69. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
  70. package/src/__tests__/disk-pressure-guard.test.ts +0 -41
  71. package/src/__tests__/dm-persistence.test.ts +0 -2
  72. package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
  73. package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
  74. package/src/__tests__/exploration-drift-hook.test.ts +2 -3
  75. package/src/__tests__/filing-service.test.ts +0 -2
  76. package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
  77. package/src/__tests__/guardian-dispatch.test.ts +1 -95
  78. package/src/__tests__/guardian-outbound-http.test.ts +0 -13
  79. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
  80. package/src/__tests__/heartbeat-service.test.ts +0 -2
  81. package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
  82. package/src/__tests__/host-app-control-routes.test.ts +30 -24
  83. package/src/__tests__/host-bash-routes.test.ts +41 -31
  84. package/src/__tests__/host-browser-routes.test.ts +32 -26
  85. package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
  86. package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
  87. package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
  88. package/src/__tests__/http-user-message-parity.test.ts +8 -290
  89. package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
  90. package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
  91. package/src/__tests__/invite-redemption-service.test.ts +0 -198
  92. package/src/__tests__/llm-context-normalization.test.ts +0 -105
  93. package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
  94. package/src/__tests__/llm-usage-store.test.ts +0 -25
  95. package/src/__tests__/mcp-health-check.test.ts +1 -2
  96. package/src/__tests__/media-stream-server-integration.test.ts +0 -127
  97. package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
  98. package/src/__tests__/messaging-send-tool.test.ts +0 -2
  99. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  100. package/src/__tests__/mtime-cache.test.ts +5 -146
  101. package/src/__tests__/native-web-search.test.ts +0 -2
  102. package/src/__tests__/non-member-access-request.test.ts +17 -189
  103. package/src/__tests__/notification-broadcaster.test.ts +0 -4
  104. package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
  105. package/src/__tests__/notification-deep-link.test.ts +0 -6
  106. package/src/__tests__/notification-guardian-path.test.ts +0 -19
  107. package/src/__tests__/openai-provider.test.ts +12 -22
  108. package/src/__tests__/openai-responses-provider.test.ts +2 -12
  109. package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
  110. package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
  111. package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
  112. package/src/__tests__/plugin-bootstrap.test.ts +73 -3
  113. package/src/__tests__/plugin-route-contribution.test.ts +17 -4
  114. package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
  115. package/src/__tests__/plugin-types.test.ts +2 -0
  116. package/src/__tests__/process-message-background-slack.test.ts +0 -2
  117. package/src/__tests__/process-message-display-content.test.ts +0 -2
  118. package/src/__tests__/provider-error-scenarios.test.ts +4 -5
  119. package/src/__tests__/provider-usage-tracking.test.ts +0 -39
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
  121. package/src/__tests__/registry.test.ts +1 -4
  122. package/src/__tests__/relay-server.test.ts +25 -694
  123. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
  124. package/src/__tests__/secret-ingress-http.test.ts +0 -14
  125. package/src/__tests__/send-endpoint-busy.test.ts +8 -30
  126. package/src/__tests__/skills.test.ts +0 -44
  127. package/src/__tests__/slack-inbound-verification.test.ts +2 -47
  128. package/src/__tests__/stt-hints.test.ts +13 -44
  129. package/src/__tests__/subagent-detail.test.ts +0 -27
  130. package/src/__tests__/subagent-disposal.test.ts +0 -65
  131. package/src/__tests__/subagent-notify-parent.test.ts +0 -2
  132. package/src/__tests__/subagent-role-registry.test.ts +2 -7
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
  134. package/src/__tests__/subagent-tools.test.ts +0 -2
  135. package/src/__tests__/suggestion-routes.test.ts +0 -2
  136. package/src/__tests__/title-generate-hook.test.ts +0 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
  138. package/src/__tests__/tool-executor.test.ts +11 -16
  139. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
  140. package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
  141. package/src/__tests__/tool-start-timestamp.test.ts +0 -2
  142. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
  143. package/src/__tests__/twilio-routes.test.ts +0 -96
  144. package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
  145. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  146. package/src/__tests__/voice-invite-redemption.test.ts +0 -33
  147. package/src/__tests__/web-search-backend-failure.test.ts +0 -2
  148. package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
  149. package/src/__tests__/workspace-tool-loader.test.ts +2 -195
  150. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  151. package/src/agent/loop.ts +0 -56
  152. package/src/api/index.ts +1 -19
  153. package/src/api/responses/llm-request-log-entry.ts +0 -29
  154. package/src/api/responses/subagent-detail.ts +0 -17
  155. package/src/api/surfaces.ts +3 -39
  156. package/src/approvals/guardian-request-resolvers.ts +11 -1
  157. package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
  158. package/src/calls/call-domain.ts +3 -3
  159. package/src/calls/guardian-dispatch.ts +8 -10
  160. package/src/calls/inbound-trust-reader.ts +1 -17
  161. package/src/calls/media-stream-server.ts +0 -21
  162. package/src/calls/relay-server.ts +50 -167
  163. package/src/calls/relay-setup-router.ts +7 -37
  164. package/src/calls/relay-verification.ts +4 -4
  165. package/src/calls/stt-hints.ts +12 -9
  166. package/src/calls/twilio-routes.ts +4 -14
  167. package/src/channels/types.ts +20 -10
  168. package/src/cli/commands/__tests__/cache.test.ts +1 -8
  169. package/src/cli/commands/cache.ts +181 -194
  170. package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
  171. package/src/cli/commands/db/status.ts +1 -37
  172. package/src/cli/commands/mcp.ts +218 -252
  173. package/src/cli/commands/memory/index.ts +0 -2
  174. package/src/cli/commands/plugins.ts +3 -75
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
  177. package/src/cli/lib/list-installed-plugins.ts +1 -179
  178. package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
  179. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
  180. package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
  181. package/src/config/bundled-skills/subagent/SKILL.md +1 -1
  182. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  183. package/src/config/feature-flag-registry.json +13 -5
  184. package/src/config/loader.ts +5 -38
  185. package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
  186. package/src/config/schemas/memory-lifecycle.ts +0 -12
  187. package/src/config/schemas/memory-v3.ts +0 -7
  188. package/src/config/schemas/memory.ts +0 -4
  189. package/src/config/schemas/timeouts.ts +0 -8
  190. package/src/config/seed-inference-profiles.ts +11 -21
  191. package/src/config/skills.ts +5 -27
  192. package/src/config/sync-gated-profiles.ts +13 -12
  193. package/src/contacts/contacts-write.ts +0 -3
  194. package/src/daemon/assistant-attachments.ts +4 -27
  195. package/src/daemon/conversation-agent-loop.ts +0 -28
  196. package/src/daemon/conversation-process.ts +16 -35
  197. package/src/daemon/conversation-surfaces.ts +38 -111
  198. package/src/daemon/conversation-tool-setup.ts +16 -50
  199. package/src/daemon/conversation.ts +1 -13
  200. package/src/daemon/disk-pressure-guard.ts +2 -12
  201. package/src/daemon/event-loop-watchdog.ts +1 -28
  202. package/src/daemon/external-plugins-bootstrap.ts +34 -4
  203. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
  204. package/src/daemon/handlers/config-a2a.ts +14 -6
  205. package/src/daemon/handlers/config-channels.ts +22 -78
  206. package/src/daemon/handlers/conversations.ts +0 -77
  207. package/src/daemon/lifecycle.ts +0 -4
  208. package/src/daemon/mcp-reload-service.ts +0 -10
  209. package/src/daemon/memory-v2-startup.test.ts +0 -72
  210. package/src/daemon/memory-v2-startup.ts +19 -87
  211. package/src/daemon/message-types/conversations.ts +0 -2
  212. package/src/daemon/message-types/surfaces.ts +12 -12
  213. package/src/daemon/server.ts +4 -0
  214. package/src/daemon/shutdown-handlers.ts +0 -20
  215. package/src/daemon/tool-setup-types.ts +0 -9
  216. package/src/daemon/workspace-tools-watcher.ts +328 -0
  217. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  218. package/src/ipc/assistant-server.ts +2 -2
  219. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  220. package/src/mcp/client.ts +1 -15
  221. package/src/mcp/mcp-auth-orchestrator.ts +1 -6
  222. package/src/mcp/mcp-oauth-provider.ts +8 -19
  223. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
  224. package/src/memory/conversation-crud.ts +0 -38
  225. package/src/memory/db-connection.ts +3 -22
  226. package/src/memory/db-init.ts +502 -36
  227. package/src/memory/db-singleton.ts +4 -6
  228. package/src/memory/jobs-worker.ts +0 -58
  229. package/src/memory/llm-request-log-store.ts +1 -26
  230. package/src/memory/llm-usage-store.ts +20 -48
  231. package/src/memory/memory-retrospective-job.ts +8 -9
  232. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
  233. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  234. package/src/memory/migrations/registry.ts +573 -0
  235. package/src/memory/migrations/run-migrations.ts +6 -90
  236. package/src/memory/migrations/validate-migration-state.ts +66 -101
  237. package/src/memory/schema/conversations.ts +0 -9
  238. package/src/memory/schema/infrastructure.ts +0 -20
  239. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
  240. package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
  241. package/src/memory/v2/cli-command-store.ts +38 -75
  242. package/src/memory/v2/prompts/consolidation.ts +82 -13
  243. package/src/memory/v2/prompts/router.ts +93 -21
  244. package/src/memory/v2/skill-store.ts +31 -68
  245. package/src/notifications/__tests__/broadcaster.test.ts +8 -16
  246. package/src/notifications/__tests__/decision-engine.test.ts +9 -78
  247. package/src/notifications/broadcaster.ts +1 -8
  248. package/src/notifications/decision-engine.ts +7 -15
  249. package/src/notifications/destination-resolver.ts +24 -68
  250. package/src/notifications/emit-signal.ts +14 -39
  251. package/src/permissions/question-prompter.test.ts +1 -1
  252. package/src/permissions/question-prompter.ts +4 -7
  253. package/src/plugin-api/index.ts +6 -6
  254. package/src/plugin-api/types.ts +5 -3
  255. package/src/plugin-api/vision-support.test.ts +4 -28
  256. package/src/plugin-api/vision-support.ts +31 -66
  257. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
  258. package/src/plugins/defaults/advisor/consult.ts +6 -110
  259. package/src/plugins/defaults/advisor/steering.ts +2 -14
  260. package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
  261. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
  262. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
  263. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
  264. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
  265. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
  266. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
  267. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
  268. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
  269. package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
  270. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
  271. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
  272. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
  273. package/src/plugins/mtime-cache.ts +291 -76
  274. package/src/plugins/pipeline.ts +13 -111
  275. package/src/plugins/types.ts +2 -0
  276. package/src/providers/anthropic/client.ts +0 -5
  277. package/src/providers/call-site-routing.ts +0 -4
  278. package/src/providers/model-catalog.ts +0 -16
  279. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  280. package/src/providers/openai/chat-completions-provider.ts +83 -37
  281. package/src/providers/openai/responses-provider.ts +46 -50
  282. package/src/providers/openrouter/client.ts +0 -5
  283. package/src/providers/provider-send-message.ts +0 -4
  284. package/src/providers/ratelimit.ts +0 -4
  285. package/src/providers/retry.ts +0 -4
  286. package/src/providers/types.ts +0 -9
  287. package/src/providers/usage-tracking.ts +0 -4
  288. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
  289. package/src/runtime/access-request-helper.ts +39 -19
  290. package/src/runtime/actor-trust-resolver.ts +2 -2
  291. package/src/runtime/assistant-event-hub.ts +1 -1
  292. package/src/runtime/assistant-stream-state.ts +2 -9
  293. package/src/runtime/auth/require-bound-guardian.ts +11 -21
  294. package/src/runtime/channel-verification-service.ts +31 -56
  295. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  296. package/src/runtime/guardian-vellum-migration.ts +7 -66
  297. package/src/runtime/invite-redemption-service.ts +187 -198
  298. package/src/runtime/local-actor-identity.ts +11 -76
  299. package/src/runtime/pending-interactions.ts +1 -11
  300. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
  301. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  302. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
  303. package/src/runtime/routes/browser-routes.ts +1 -1
  304. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
  305. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  306. package/src/runtime/routes/contact-routes.ts +32 -8
  307. package/src/runtime/routes/conversation-cli-routes.ts +5 -4
  308. package/src/runtime/routes/conversation-list-routes.ts +7 -4
  309. package/src/runtime/routes/conversation-query-routes.ts +0 -72
  310. package/src/runtime/routes/conversation-routes.ts +85 -84
  311. package/src/runtime/routes/events-routes.ts +2 -2
  312. package/src/runtime/routes/global-search-routes.ts +1 -3
  313. package/src/runtime/routes/guardian-action-routes.ts +5 -4
  314. package/src/runtime/routes/host-app-control-routes.ts +4 -5
  315. package/src/runtime/routes/host-bash-routes.ts +4 -5
  316. package/src/runtime/routes/host-browser-routes.ts +11 -9
  317. package/src/runtime/routes/host-cu-routes.ts +4 -5
  318. package/src/runtime/routes/host-file-routes.ts +4 -5
  319. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  320. package/src/runtime/routes/http-adapter.ts +1 -1
  321. package/src/runtime/routes/identity-routes.ts +2 -3
  322. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  323. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
  324. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
  325. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
  326. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  327. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
  328. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
  329. package/src/runtime/routes/index.ts +0 -2
  330. package/src/runtime/routes/llm-context-normalization.ts +0 -83
  331. package/src/runtime/routes/mcp-auth-routes.ts +19 -171
  332. package/src/runtime/routes/migration-rollback-routes.ts +3 -4
  333. package/src/runtime/routes/migration-routes.ts +1 -4
  334. package/src/runtime/routes/subagents-routes.ts +0 -5
  335. package/src/runtime/routes/surface-action-routes.ts +56 -42
  336. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
  337. package/src/runtime/services/conversation-serializer.ts +9 -7
  338. package/src/runtime/tool-grant-request-helper.ts +3 -3
  339. package/src/runtime/trust-verdict-consumer.ts +9 -85
  340. package/src/runtime/verification-outbound-actions.ts +18 -18
  341. package/src/signals/user-message.ts +0 -16
  342. package/src/subagent/manager.ts +0 -9
  343. package/src/subagent/types.ts +3 -3
  344. package/src/telemetry/types.ts +1 -34
  345. package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
  346. package/src/telemetry/usage-telemetry-reporter.ts +3 -87
  347. package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
  348. package/src/tools/ask-question/ask-question-tool.ts +0 -13
  349. package/src/tools/executor.ts +4 -4
  350. package/src/tools/registry.ts +0 -18
  351. package/src/tools/shared/filesystem/path-policy.ts +5 -12
  352. package/src/tools/tool-approval-handler.ts +1 -1
  353. package/src/tools/tool-defaults.ts +2 -9
  354. package/src/tools/tool-manifest.ts +0 -3
  355. package/src/tools/types.ts +2 -17
  356. package/src/tools/workspace-tools/loader.ts +244 -348
  357. package/src/util/errors.ts +1 -26
  358. package/src/util/platform.ts +0 -5
  359. package/src/workflows/library.test.ts +0 -140
  360. package/src/workflows/library.ts +28 -82
  361. package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
  362. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
  363. package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
  364. package/src/workspace/migrations/registry.ts +0 -2
  365. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
  366. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
  367. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
  368. package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
  369. package/src/__tests__/code-search-tool.test.ts +0 -585
  370. package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
  371. package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
  372. package/src/__tests__/plugin-pipeline.test.ts +0 -96
  373. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
  374. package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
  375. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
  376. package/src/agent/loop-exclusive-tool.test.ts +0 -150
  377. package/src/api/constants/sse-replay.ts +0 -41
  378. package/src/api/events/conversation-notice.ts +0 -26
  379. package/src/approvals/guardian-channel-delivery.ts +0 -30
  380. package/src/approvals/guardian-expiry-notifier.ts +0 -148
  381. package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
  382. package/src/cli/commands/memory/worker.ts +0 -175
  383. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
  384. package/src/config/prune-seeded-callsite-defaults.ts +0 -110
  385. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
  386. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
  387. package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
  388. package/src/contacts/guardian-delivery-reader.ts +0 -223
  389. package/src/contacts/member-write-relay.ts +0 -189
  390. package/src/daemon/conversation-notices.ts +0 -60
  391. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
  392. package/src/hooks/hook-loader.ts +0 -341
  393. package/src/mcp/mcp-header-store.ts +0 -134
  394. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  395. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  396. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  397. package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
  398. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  399. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
  400. package/src/memory/prompt-override.ts +0 -129
  401. package/src/memory/steps.ts +0 -573
  402. package/src/memory/watchdog-events-store.ts +0 -87
  403. package/src/memory/worker-control.ts +0 -118
  404. package/src/memory/worker-process.ts +0 -72
  405. package/src/notifications/__tests__/connected-channels.test.ts +0 -114
  406. package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
  407. package/src/onboarding/checkin-event.test.ts +0 -222
  408. package/src/onboarding/checkin-event.ts +0 -321
  409. package/src/onboarding/schedule-checkin.ts +0 -190
  410. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
  411. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
  412. package/src/plugins/defaults/advisor/context-pack.ts +0 -288
  413. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  414. package/src/plugins/surface-import.ts +0 -121
  415. package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
  416. package/src/providers/openai/api-error-normalization.ts +0 -270
  417. package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
  418. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
  419. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
  420. package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
  421. package/src/runtime/anchored-guardian.test.ts +0 -156
  422. package/src/runtime/anchored-guardian.ts +0 -135
  423. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
  424. package/src/runtime/local-principal-trust.ts +0 -52
  425. package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
  426. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
  427. package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
  428. package/src/tools/filesystem/search.ts +0 -543
  429. package/src/util/telemetry-db-path.ts +0 -24
  430. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
@@ -1,192 +0,0 @@
1
- /**
2
- * Tests for the shared prompt-override loader
3
- * (`assistant/src/memory/prompt-override.ts`) and the memory-v3
4
- * `resolveSelectorPrompt` built on it. Mirrors the v2 router/consolidation
5
- * prompt-path suites: a configured file replaces the bundled prompt, and any
6
- * missing / empty / oversized / non-regular / unreadable file degrades to the
7
- * bundled prompt with a diagnostic warning.
8
- */
9
- import { execFileSync } from "node:child_process";
10
- import { mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
11
- import { homedir, tmpdir } from "node:os";
12
- import { join } from "node:path";
13
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
14
-
15
- import { resolveSelectorPrompt } from "../../plugins/defaults/memory-v3-shadow/pool-select.js";
16
- import {
17
- loadPromptOverride,
18
- MAX_PROMPT_OVERRIDE_BYTES,
19
- resolveOverridePath,
20
- } from "../prompt-override.js";
21
-
22
- const warnCalls: Array<{ data: Record<string, unknown>; msg: string }> = [];
23
- const recordingLogger = {
24
- warn: (data: object, msg: string) => {
25
- warnCalls.push({ data: data as Record<string, unknown>, msg });
26
- },
27
- };
28
-
29
- let tmpDir: string;
30
-
31
- beforeEach(() => {
32
- warnCalls.length = 0;
33
- tmpDir = mkdtempSync(join(tmpdir(), "prompt-override-"));
34
- });
35
-
36
- afterEach(() => {
37
- rmSync(tmpDir, { recursive: true, force: true });
38
- });
39
-
40
- /** Load against the per-test temp dir with the recording logger. */
41
- const load = (
42
- overridePath: string | null | undefined,
43
- label = "test prompt",
44
- ): string | null =>
45
- loadPromptOverride({
46
- overridePath,
47
- workspaceDir: tmpDir,
48
- log: recordingLogger,
49
- label,
50
- });
51
-
52
- describe("resolveOverridePath", () => {
53
- test("expands a leading ~/ to the home directory", () => {
54
- expect(resolveOverridePath("~/sub/x.md", tmpDir)).toBe(
55
- join(homedir(), "sub/x.md"),
56
- );
57
- });
58
-
59
- test("uses an absolute path as-is", () => {
60
- expect(resolveOverridePath("/abs/x.md", tmpDir)).toBe("/abs/x.md");
61
- });
62
-
63
- test("resolves a relative path under the workspace dir", () => {
64
- expect(resolveOverridePath("rel/x.md", tmpDir)).toBe(
65
- join(tmpDir, "rel/x.md"),
66
- );
67
- });
68
- });
69
-
70
- describe("loadPromptOverride — usable override", () => {
71
- test("null overridePath returns null without touching the filesystem", () => {
72
- expect(load(null)).toBeNull();
73
- expect(warnCalls).toHaveLength(0);
74
- });
75
-
76
- test("undefined overridePath (unset config field) returns null without throwing", () => {
77
- expect(load(undefined)).toBeNull();
78
- expect(warnCalls).toHaveLength(0);
79
- });
80
-
81
- test("returns an absolute-path file's contents verbatim", () => {
82
- const p = join(tmpDir, "abs.md");
83
- writeFileSync(p, "absolute body\n");
84
- expect(load(p)).toBe("absolute body\n");
85
- expect(warnCalls).toHaveLength(0);
86
- });
87
-
88
- test("resolves a relative path under the workspace dir", () => {
89
- writeFileSync(join(tmpDir, "rel.md"), "relative body\n");
90
- expect(load("rel.md")).toBe("relative body\n");
91
- expect(warnCalls).toHaveLength(0);
92
- });
93
-
94
- test("expands a leading ~/ to the home directory", () => {
95
- const filename = `.vellum-prompt-override-test-${process.pid}.md`;
96
- const p = join(homedir(), filename);
97
- writeFileSync(p, "home body\n");
98
- try {
99
- expect(load(`~/${filename}`)).toBe("home body\n");
100
- expect(warnCalls).toHaveLength(0);
101
- } finally {
102
- rmSync(p, { force: true });
103
- }
104
- });
105
- });
106
-
107
- describe("loadPromptOverride — fallback to null with a diagnostic warning", () => {
108
- test("missing file logs ENOENT and returns null", () => {
109
- expect(load(join(tmpDir, "missing.md"))).toBeNull();
110
- expect(warnCalls).toHaveLength(1);
111
- expect(warnCalls[0].data.code).toBe("ENOENT");
112
- expect(warnCalls[0].data.fallback).toBe("bundled");
113
- });
114
-
115
- test("empty file is rejected", () => {
116
- const p = join(tmpDir, "empty.md");
117
- writeFileSync(p, "");
118
- expect(load(p)).toBeNull();
119
- expect(warnCalls[0].data.reason).toBe("empty_override");
120
- });
121
-
122
- test("whitespace-only file is rejected", () => {
123
- const p = join(tmpDir, "ws.md");
124
- writeFileSync(p, " \n\t\n");
125
- expect(load(p)).toBeNull();
126
- expect(warnCalls[0].data.reason).toBe("empty_override");
127
- });
128
-
129
- test("oversized file is rejected with its size", () => {
130
- const p = join(tmpDir, "huge.md");
131
- // 1 MiB + 1 byte — just over the cap so we don't waste test memory.
132
- writeFileSync(p, Buffer.alloc(MAX_PROMPT_OVERRIDE_BYTES + 1, 0x61));
133
- expect(load(p)).toBeNull();
134
- expect(warnCalls[0].data.reason).toBe("oversized_override");
135
- expect(warnCalls[0].data.size).toBe(MAX_PROMPT_OVERRIDE_BYTES + 1);
136
- });
137
-
138
- test("a directory is not a regular file", () => {
139
- expect(load(tmpDir)).toBeNull();
140
- expect(warnCalls[0].data.reason).toBe("not_regular_file");
141
- });
142
-
143
- test("a symlink is not a regular file (lstat does not follow it)", () => {
144
- const target = join(tmpDir, "target.md");
145
- writeFileSync(target, "real body\n");
146
- const link = join(tmpDir, "link.md");
147
- symlinkSync(target, link);
148
- expect(load(link)).toBeNull();
149
- expect(warnCalls[0].data.reason).toBe("not_regular_file");
150
- });
151
-
152
- test("a FIFO is not a regular file", () => {
153
- const fifoPath = join(tmpDir, "fifo");
154
- try {
155
- execFileSync("mkfifo", [fifoPath]);
156
- } catch {
157
- // mkfifo unavailable on this platform — skip without failing.
158
- return;
159
- }
160
- expect(load(fifoPath)).toBeNull();
161
- expect(warnCalls[0].data.reason).toBe("not_regular_file");
162
- });
163
-
164
- test("the label names the prompt in the warning message", () => {
165
- load(join(tmpDir, "missing.md"), "router prompt");
166
- expect(warnCalls[0].msg).toContain("router prompt override");
167
- });
168
- });
169
-
170
- describe("resolveSelectorPrompt", () => {
171
- // A stable phrase from the bundled selector prompt (`SYSTEM_PROMPT`).
172
- const BUNDLED_PHRASE =
173
- "Select EVERY candidate whose content the upcoming reply would draw on";
174
-
175
- test("null path returns the bundled selector prompt", () => {
176
- expect(resolveSelectorPrompt(null, tmpDir)).toContain(BUNDLED_PHRASE);
177
- });
178
-
179
- test("a configured file replaces the bundled prompt verbatim — no placeholder substitution", () => {
180
- const body = "Custom selector instructions {{NOT_A_PLACEHOLDER}}\n";
181
- writeFileSync(join(tmpDir, "selector.md"), body);
182
- const out = resolveSelectorPrompt("selector.md", tmpDir);
183
- expect(out).toBe(body);
184
- expect(out).not.toContain(BUNDLED_PHRASE);
185
- });
186
-
187
- test("a missing override falls back to the bundled prompt", () => {
188
- expect(resolveSelectorPrompt(join(tmpDir, "nope.md"), tmpDir)).toContain(
189
- BUNDLED_PHRASE,
190
- );
191
- });
192
- });
@@ -1,161 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- // Silence the logger.
4
- mock.module("../../util/logger.js", () => ({
5
- getLogger: () =>
6
- new Proxy({} as Record<string, unknown>, {
7
- get: () => () => {},
8
- }),
9
- }));
10
-
11
- let shareAnalytics = true;
12
-
13
- mock.module("../../platform/consent-cache.js", () => ({
14
- getCachedShareAnalytics: () => shareAnalytics,
15
- }));
16
-
17
- import { getTelemetryDb } from "../db-connection.js";
18
- import { initializeDb } from "../db-init.js";
19
- import { watchdogEvents } from "../schema.js";
20
- import {
21
- queryUnreportedWatchdogEvents,
22
- recordWatchdogEvent,
23
- } from "../watchdog-events-store.js";
24
-
25
- await initializeDb();
26
-
27
- function insertEvent(
28
- id: string,
29
- createdAt: number,
30
- checkName = "event_loop_blocked",
31
- ): void {
32
- const db = getTelemetryDb();
33
- if (!db) throw new Error("telemetry DB unavailable in test");
34
- db.insert(watchdogEvents).values({ id, createdAt, checkName }).run();
35
- }
36
-
37
- function clearEvents(): void {
38
- const db = getTelemetryDb();
39
- if (!db) throw new Error("telemetry DB unavailable in test");
40
- db.delete(watchdogEvents).run();
41
- }
42
-
43
- describe("watchdog-events-store", () => {
44
- beforeEach(() => {
45
- shareAnalytics = true;
46
- clearEvents();
47
- });
48
-
49
- test("honors the share_analytics opt-out (records nothing)", () => {
50
- shareAnalytics = false;
51
- recordWatchdogEvent({ checkName: "event_loop_blocked", value: 60000 });
52
- expect(queryUnreportedWatchdogEvents(0, undefined, 10)).toHaveLength(0);
53
- });
54
-
55
- test("record + query round-trips all fields", () => {
56
- recordWatchdogEvent({
57
- checkName: "event_loop_blocked",
58
- value: 12345,
59
- detail: { reason: "no_bytes_60s", threshold_ms: 5000 },
60
- });
61
-
62
- const rows = queryUnreportedWatchdogEvents(0, undefined, 10);
63
- expect(rows).toHaveLength(1);
64
- const row = rows[0]!;
65
- expect(row.id).toBeString();
66
- expect(row.createdAt).toBeGreaterThan(0);
67
- expect(row.checkName).toBe("event_loop_blocked");
68
- expect(row.value).toBe(12345);
69
- expect(row.detail).toBe(
70
- JSON.stringify({ reason: "no_bytes_60s", threshold_ms: 5000 }),
71
- );
72
- });
73
-
74
- test("optional fields persist as null", () => {
75
- recordWatchdogEvent({ checkName: "stream_idle" });
76
-
77
- const rows = queryUnreportedWatchdogEvents(0, undefined, 10);
78
- expect(rows).toHaveLength(1);
79
- expect(rows[0]).toMatchObject({
80
- checkName: "stream_idle",
81
- value: null,
82
- detail: null,
83
- });
84
- });
85
-
86
- test("explicit null value and detail persist as null", () => {
87
- recordWatchdogEvent({
88
- checkName: "restart",
89
- value: null,
90
- detail: null,
91
- });
92
-
93
- const rows = queryUnreportedWatchdogEvents(0, undefined, 10);
94
- expect(rows).toHaveLength(1);
95
- expect(rows[0]?.value).toBeNull();
96
- expect(rows[0]?.detail).toBeNull();
97
- });
98
-
99
- test("returns rows in (createdAt, id) order", () => {
100
- insertEvent("wd-b", 2000);
101
- insertEvent("wd-a", 1000);
102
-
103
- const rows = queryUnreportedWatchdogEvents(0, undefined, 100);
104
- expect(rows.map((r) => r.id)).toEqual(["wd-a", "wd-b"]);
105
- });
106
-
107
- test("query advances past the compound (createdAt, id) cursor", () => {
108
- // Two rows in the same millisecond: pagination must use the id
109
- // tiebreaker to make forward progress, not loop.
110
- insertEvent("wd-1", 5000);
111
- insertEvent("wd-2", 5000);
112
- insertEvent("wd-3", 6000);
113
-
114
- const first = queryUnreportedWatchdogEvents(0, undefined, 1);
115
- expect(first.map((r) => r.id)).toEqual(["wd-1"]);
116
-
117
- const second = queryUnreportedWatchdogEvents(
118
- first[0]!.createdAt,
119
- first[0]!.id,
120
- 100,
121
- );
122
- expect(second.map((r) => r.id)).toEqual(["wd-2", "wd-3"]);
123
-
124
- // Without an id cursor the timestamp-only branch is used.
125
- expect(
126
- queryUnreportedWatchdogEvents(5000, undefined, 100).map((r) => r.id),
127
- ).toEqual(["wd-3"]);
128
-
129
- // Cursor past the last row returns nothing.
130
- const last = second[second.length - 1]!;
131
- expect(
132
- queryUnreportedWatchdogEvents(last.createdAt, last.id, 100).length,
133
- ).toBe(0);
134
- });
135
-
136
- test("resumes from a persisted watermark without re-reporting", () => {
137
- insertEvent("wd-w1", 1000);
138
- insertEvent("wd-w2", 2000);
139
-
140
- const batch = queryUnreportedWatchdogEvents(0, undefined, 100);
141
- const watermark = batch[batch.length - 1]!;
142
-
143
- insertEvent("wd-w3", 3000);
144
-
145
- const resumed = queryUnreportedWatchdogEvents(
146
- watermark.createdAt,
147
- watermark.id,
148
- 100,
149
- );
150
- expect(resumed.map((r) => r.id)).toEqual(["wd-w3"]);
151
- });
152
-
153
- test("honors the limit", () => {
154
- insertEvent("wd-l1", 1000);
155
- insertEvent("wd-l2", 2000);
156
- insertEvent("wd-l3", 3000);
157
-
158
- const rows = queryUnreportedWatchdogEvents(0, undefined, 2);
159
- expect(rows.map((r) => r.id)).toEqual(["wd-l1", "wd-l2"]);
160
- });
161
- });
@@ -1,30 +0,0 @@
1
- import type { DrizzleDb } from "../db-connection.js";
2
- import { tableHasColumn } from "./schema-introspection.js";
3
-
4
- const COLUMN_NAME = "processing_started_at";
5
- const COLUMN_DEFINITION = "processing_started_at INTEGER";
6
-
7
- /**
8
- * Add `processing_started_at` column to the `conversations` table.
9
- *
10
- * The column is a nullable epoch-ms timestamp: non-NULL means the agent loop
11
- * is mid-turn for this conversation, NULL means idle. This is the
12
- * cross-process source of truth for processing state — the in-memory
13
- * `Conversation._processing` flag is the hot-path read for resident
14
- * conversations, but out-of-process callers (e.g. the retrospective CLI)
15
- * read this column directly via `isConversationProcessing()`.
16
- *
17
- * No backfill is needed — all existing rows default to NULL (not processing),
18
- * which is correct for any conversation that isn't actively mid-turn at
19
- * migration time.
20
- *
21
- * Idempotent: guarded with `tableHasColumn` so a crash between the `ALTER
22
- * TABLE` and the checkpoint write doesn't cause a duplicate-column error on
23
- * the next boot.
24
- */
25
- export function migrateAddProcessingStartedAt(database: DrizzleDb): void {
26
- if (tableHasColumn(database, "conversations", COLUMN_NAME)) {
27
- return;
28
- }
29
- database.run(`ALTER TABLE conversations ADD COLUMN ${COLUMN_DEFINITION}`);
30
- }
@@ -1,45 +0,0 @@
1
- import { Database } from "bun:sqlite";
2
-
3
- import { getTelemetryDbPath } from "../../util/telemetry-db-path.js";
4
- import {
5
- type DrizzleDb,
6
- getTelemetrySqlite,
7
- } from "../db-connection.js";
8
-
9
- /**
10
- * Create the `watchdog_events` table on the dedicated telemetry database
11
- * (`assistant-telemetry.db`), not the main DB. The migration runner passes the
12
- * main DrizzleDb, but this table lives on the telemetry connection, so we open
13
- * that connection and run DDL against it directly. The dedicated connection
14
- * itself performs no DDL on open, so this migration owns the schema.
15
- *
16
- * Idempotent (`IF NOT EXISTS`). Writes are gated on `share_analytics`
17
- * consent at the store level, so opted-out rows never exist and the
18
- * reporter's standard 0 watermark default is safe. The index backs the
19
- * telemetry reporter's compound `(created_at, id)` watermark cursor.
20
- *
21
- * The `mainDb` parameter is accepted to satisfy the migration-step signature but
22
- * is not used — this migration operates exclusively on the telemetry DB.
23
- */
24
- export function createWatchdogEventsTable(_mainDb: DrizzleDb): void {
25
- let raw: Database | null = getTelemetrySqlite();
26
- if (!raw) {
27
- // The dedicated connection failed to open (logged by openDedicatedDb).
28
- // Fall back to opening the file directly so the migration still runs —
29
- // the singleton will pick it up on a later access. This mirrors the
30
- // fail-soft pattern of the other dedicated-DB migrations.
31
- raw = new Database(getTelemetryDbPath());
32
- }
33
- raw.exec(/*sql*/ `
34
- CREATE TABLE IF NOT EXISTS watchdog_events (
35
- id TEXT PRIMARY KEY,
36
- created_at INTEGER NOT NULL,
37
- check_name TEXT NOT NULL,
38
- value REAL,
39
- detail TEXT
40
- )
41
- `);
42
- raw.exec(
43
- /*sql*/ `CREATE INDEX IF NOT EXISTS idx_watchdog_events_created_at_id ON watchdog_events (created_at, id)`,
44
- );
45
- }
@@ -1,224 +0,0 @@
1
- /**
2
- * Tests for migration 209 — stripping thinking / redacted_thinking blocks from
3
- * persisted assistant messages.
4
- *
5
- * The migration rewrites content entirely inside SQLite (JSON1), dispatched a
6
- * rowid window at a time through `runAsyncSqlite`. These tests drive the step
7
- * directly against a real DB and assert the at-rest content, idempotency,
8
- * scoping (assistant rows only), tolerance of malformed content, and that the
9
- * persisted rowid watermark is honored for resume.
10
- */
11
- import { describe, expect, test } from "bun:test";
12
-
13
- const { getDb, getSqlite } = await import("../../db-connection.js");
14
- const { initializeDb } = await import("../../db-init.js");
15
- const { migrateStripThinkingFromConsolidated } =
16
- await import("../209-strip-thinking-from-consolidated.js");
17
-
18
- await initializeDb();
19
-
20
- const CONV = "conv-209";
21
- getSqlite()
22
- .query(
23
- `INSERT OR IGNORE INTO conversations (id, created_at, updated_at) VALUES (?, ?, ?)`,
24
- )
25
- .run(CONV, Date.now(), Date.now());
26
-
27
- let seq = 0;
28
- function insert(role: string, content: string): { id: string; rowid: number } {
29
- const id = `m209-${seq++}`;
30
- getSqlite()
31
- .query(
32
- `INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)`,
33
- )
34
- .run(id, CONV, role, content, Date.now());
35
- const rowid = (
36
- getSqlite()
37
- .query(`SELECT rowid AS r FROM messages WHERE id = ?`)
38
- .get(id) as { r: number }
39
- ).r;
40
- return { id, rowid };
41
- }
42
-
43
- function content(id: string): string {
44
- return (
45
- getSqlite().query(`SELECT content FROM messages WHERE id = ?`).get(id) as {
46
- content: string;
47
- }
48
- ).content;
49
- }
50
-
51
- function blocks(id: string): Array<Record<string, unknown>> {
52
- return JSON.parse(content(id));
53
- }
54
-
55
- describe("migration 209 — strip thinking from consolidated assistant messages", () => {
56
- test("strips thinking blocks but keeps text and tool_use, preserving order", async () => {
57
- const { id } = insert(
58
- "assistant",
59
- JSON.stringify([
60
- { type: "thinking", thinking: "secret", signature: "sig" },
61
- { type: "text", text: "hello" },
62
- { type: "tool_use", id: "t1", name: "x", input: { a: 1 } },
63
- ]),
64
- );
65
-
66
- await migrateStripThinkingFromConsolidated(getDb());
67
-
68
- expect(blocks(id)).toEqual([
69
- { type: "text", text: "hello" },
70
- { type: "tool_use", id: "t1", name: "x", input: { a: 1 } },
71
- ]);
72
- });
73
-
74
- test("strips redacted_thinking blocks", async () => {
75
- const { id } = insert(
76
- "assistant",
77
- JSON.stringify([
78
- { type: "redacted_thinking", data: "blob" },
79
- { type: "text", text: "world" },
80
- ]),
81
- );
82
-
83
- await migrateStripThinkingFromConsolidated(getDb());
84
-
85
- expect(blocks(id)).toEqual([{ type: "text", text: "world" }]);
86
- });
87
-
88
- test("all-thinking message becomes the null-byte placeholder sentinel", async () => {
89
- const { id } = insert(
90
- "assistant",
91
- JSON.stringify([
92
- { type: "thinking", thinking: "a", signature: "s1" },
93
- { type: "redacted_thinking", data: "b" },
94
- ]),
95
- );
96
-
97
- await migrateStripThinkingFromConsolidated(getDb());
98
-
99
- const result = blocks(id);
100
- expect(result).toHaveLength(1);
101
- expect(result[0].type).toBe("text");
102
- expect(result[0].text).toBe("\x00__PLACEHOLDER__[internal blocks omitted]");
103
- // The leading byte must be a literal NUL, produced by SQLite's char(0).
104
- expect((result[0].text as string).charCodeAt(0)).toBe(0);
105
- });
106
-
107
- test("preserves blocks with a missing/null type", async () => {
108
- const { id } = insert(
109
- "assistant",
110
- JSON.stringify([
111
- { type: "thinking", thinking: "x", signature: "s" },
112
- { foo: "bar" },
113
- { type: "text", text: "kept" },
114
- ]),
115
- );
116
-
117
- await migrateStripThinkingFromConsolidated(getDb());
118
-
119
- expect(blocks(id)).toEqual([
120
- { foo: "bar" },
121
- { type: "text", text: "kept" },
122
- ]);
123
- });
124
-
125
- test("leaves thinking-free assistant messages untouched", async () => {
126
- const original = JSON.stringify([
127
- { type: "text", text: "I was thinking about lunch" },
128
- ]);
129
- const { id } = insert("assistant", original);
130
-
131
- await migrateStripThinkingFromConsolidated(getDb());
132
-
133
- // Substring 'thinking' appears in the text but no block is of thinking type.
134
- expect(content(id)).toBe(original);
135
- });
136
-
137
- test("does not touch non-assistant roles", async () => {
138
- const original = JSON.stringify([
139
- { type: "thinking", thinking: "x", signature: "s" },
140
- { type: "text", text: "u" },
141
- ]);
142
- const { id } = insert("user", original);
143
-
144
- await migrateStripThinkingFromConsolidated(getDb());
145
-
146
- expect(content(id)).toBe(original);
147
- });
148
-
149
- test("tolerates non-array and invalid JSON content", async () => {
150
- const obj = insert(
151
- "assistant",
152
- JSON.stringify({ type: "thinking", thinking: "x" }),
153
- );
154
- const invalid = insert("assistant", "{not json with thinking");
155
-
156
- await migrateStripThinkingFromConsolidated(getDb());
157
-
158
- expect(content(obj.id)).toBe(
159
- JSON.stringify({ type: "thinking", thinking: "x" }),
160
- );
161
- expect(content(invalid.id)).toBe("{not json with thinking");
162
- });
163
-
164
- test("is idempotent across repeated runs", async () => {
165
- const { id } = insert(
166
- "assistant",
167
- JSON.stringify([
168
- { type: "thinking", thinking: "x", signature: "s" },
169
- { type: "text", text: "stable" },
170
- ]),
171
- );
172
-
173
- await migrateStripThinkingFromConsolidated(getDb());
174
- const once = content(id);
175
- await migrateStripThinkingFromConsolidated(getDb());
176
- const twice = content(id);
177
-
178
- expect(twice).toBe(once);
179
- expect(blocks(id)).toEqual([{ type: "text", text: "stable" }]);
180
- });
181
-
182
- test("honors the persisted rowid watermark and resumes above it", async () => {
183
- const below = insert(
184
- "assistant",
185
- JSON.stringify([
186
- { type: "thinking", thinking: "x", signature: "s" },
187
- { type: "text", text: "below" },
188
- ]),
189
- );
190
- const above = insert(
191
- "assistant",
192
- JSON.stringify([
193
- { type: "thinking", thinking: "y", signature: "s" },
194
- { type: "text", text: "above" },
195
- ]),
196
- );
197
-
198
- // Pretend a prior run already swept through `below`'s rowid: the sweep must
199
- // resume strictly above it, leaving `below` untouched and cleaning `above`.
200
- getSqlite()
201
- .query(
202
- `INSERT OR REPLACE INTO memory_checkpoints (key, value, updated_at) VALUES (?, ?, ?)`,
203
- )
204
- .run(
205
- "migration_209_strip_thinking_watermark",
206
- String(below.rowid),
207
- Date.now(),
208
- );
209
-
210
- await migrateStripThinkingFromConsolidated(getDb());
211
-
212
- expect(blocks(below.id)).toEqual([
213
- { type: "thinking", thinking: "x", signature: "s" },
214
- { type: "text", text: "below" },
215
- ]);
216
- expect(blocks(above.id)).toEqual([{ type: "text", text: "above" }]);
217
-
218
- // The watermark is cleared once the sweep reaches the end of the table.
219
- const wm = getSqlite()
220
- .query(`SELECT value FROM memory_checkpoints WHERE key = ?`)
221
- .get("migration_209_strip_thinking_watermark");
222
- expect(wm).toBeNull();
223
- });
224
- });