@vellumai/assistant 0.8.4 → 0.8.5

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 (438) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docs/browser-use-architecture-phase2.md +1 -1
  3. package/knip.json +2 -1
  4. package/openapi.yaml +809 -11
  5. package/package.json +1 -1
  6. package/src/__tests__/anthropic-provider.test.ts +34 -37
  7. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  8. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  9. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
  11. package/src/__tests__/btw-routes.test.ts +2 -3
  12. package/src/__tests__/call-controller.test.ts +0 -1
  13. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  14. package/src/__tests__/channel-guardian.test.ts +3 -3
  15. package/src/__tests__/checker.test.ts +6 -15
  16. package/src/__tests__/compaction-events.test.ts +1 -0
  17. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  18. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  19. package/src/__tests__/computer-use-tools.test.ts +2 -4
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  21. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  22. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
  24. package/src/__tests__/conversation-agent-loop.test.ts +163 -122
  25. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  26. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  27. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  29. package/src/__tests__/conversation-error.test.ts +31 -0
  30. package/src/__tests__/conversation-fork-crud.test.ts +178 -15
  31. package/src/__tests__/conversation-lifecycle.test.ts +52 -11
  32. package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
  33. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
  34. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  36. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  37. package/src/__tests__/conversation-store.test.ts +1 -1
  38. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  40. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  42. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  43. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  44. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  45. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  46. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  47. package/src/__tests__/email-html-renderer.test.ts +12 -0
  48. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  49. package/src/__tests__/gemini-provider.test.ts +78 -0
  50. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  51. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  52. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  53. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  54. package/src/__tests__/heartbeat-service.test.ts +4 -0
  55. package/src/__tests__/host-shell-tool.test.ts +1 -1
  56. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  57. package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
  58. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  59. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  60. package/src/__tests__/llm-resolver.test.ts +77 -9
  61. package/src/__tests__/llm-usage-store.test.ts +66 -0
  62. package/src/__tests__/logger.test.ts +89 -0
  63. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  64. package/src/__tests__/media-generate-image.test.ts +31 -0
  65. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  66. package/src/__tests__/model-intents.test.ts +2 -4
  67. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  68. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  69. package/src/__tests__/openai-provider.test.ts +46 -0
  70. package/src/__tests__/openai-responses-provider.test.ts +114 -12
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
  72. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  73. package/src/__tests__/platform.test.ts +2 -2
  74. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  75. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  76. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  77. package/src/__tests__/plugin-types.test.ts +3 -2
  78. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  79. package/src/__tests__/pricing.test.ts +12 -0
  80. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  81. package/src/__tests__/registry.test.ts +2 -8
  82. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  83. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  84. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  85. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  86. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  87. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  88. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  89. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  90. package/src/__tests__/suggestion-routes.test.ts +1 -0
  91. package/src/__tests__/sync-message-contract.test.ts +59 -0
  92. package/src/__tests__/system-prompt.test.ts +145 -131
  93. package/src/__tests__/terminal-tools.test.ts +1 -1
  94. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  95. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  96. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  97. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  98. package/src/__tests__/tool-executor.test.ts +9 -62
  99. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  100. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  101. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  102. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  103. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  104. package/src/__tests__/usage-routes.test.ts +3 -0
  105. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  106. package/src/__tests__/workspace-git-service.test.ts +6 -5
  107. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  108. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  109. package/src/acp/prepare-agent-env.ts +78 -0
  110. package/src/acp/session-manager.ts +1 -1
  111. package/src/agent/loop.ts +8 -0
  112. package/src/api/README.md +5 -0
  113. package/src/api/index.ts +4 -0
  114. package/src/api/package.json +10 -0
  115. package/src/background-wake/background-wake-routes.test.ts +233 -0
  116. package/src/background-wake/runtime-registry.ts +24 -0
  117. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  118. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  119. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  120. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  121. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  122. package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
  123. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  124. package/src/cli/commands/browser.ts +247 -0
  125. package/src/cli/commands/domain.ts +91 -41
  126. package/src/cli/commands/inference.ts +93 -40
  127. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  128. package/src/cli/commands/memory-v2.ts +176 -1
  129. package/src/cli/commands/memory-v3-render.ts +344 -0
  130. package/src/cli/commands/memory-v3.ts +316 -0
  131. package/src/cli/program.ts +2 -0
  132. package/src/config/assistant-feature-flags.ts +21 -9
  133. package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
  134. package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
  135. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  136. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  137. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  138. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  139. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  140. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  141. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  142. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  143. package/src/config/bundled-tool-registry.ts +2 -0
  144. package/src/config/call-site-defaults.ts +7 -6
  145. package/src/config/feature-flag-registry.json +16 -0
  146. package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
  147. package/src/config/schemas/call-site-catalog.ts +21 -7
  148. package/src/config/schemas/llm.ts +12 -1
  149. package/src/config/schemas/memory-v2.ts +246 -0
  150. package/src/config/schemas/memory.ts +2 -1
  151. package/src/context/compactor.ts +52 -0
  152. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  153. package/src/conversations/message-consolidation.ts +404 -0
  154. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  155. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  156. package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
  157. package/src/daemon/conversation-agent-loop.ts +126 -76
  158. package/src/daemon/conversation-error.ts +31 -1
  159. package/src/daemon/conversation-lifecycle.ts +27 -22
  160. package/src/daemon/conversation-runtime-assembly.ts +10 -9
  161. package/src/daemon/conversation-tool-setup.ts +63 -3
  162. package/src/daemon/conversation-usage.ts +2 -0
  163. package/src/daemon/conversation.ts +14 -29
  164. package/src/daemon/disk-pressure-guard.ts +14 -2
  165. package/src/daemon/handlers/config-model.test.ts +1 -0
  166. package/src/daemon/handlers/conversations.ts +11 -3
  167. package/src/daemon/host-browser-proxy.ts +5 -5
  168. package/src/daemon/host-cu-proxy.ts +4 -4
  169. package/src/daemon/host-file-proxy.ts +4 -4
  170. package/src/daemon/host-proxy-base.ts +4 -4
  171. package/src/daemon/host-transfer-proxy.ts +10 -10
  172. package/src/daemon/lifecycle.ts +23 -20
  173. package/src/daemon/meet-manifest-loader.ts +1 -7
  174. package/src/daemon/message-types/conversations.ts +6 -9
  175. package/src/daemon/message-types/home.ts +1 -13
  176. package/src/daemon/message-types/messages.ts +6 -14
  177. package/src/daemon/message-types/sync.ts +14 -0
  178. package/src/daemon/shutdown-handlers.ts +24 -5
  179. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  180. package/src/daemon/tool-setup-types.ts +13 -0
  181. package/src/events/relationship-state-updated.ts +25 -0
  182. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
  183. package/src/home/home-greeting.ts +0 -9
  184. package/src/home/suggested-prompts.ts +0 -9
  185. package/src/ipc/gateway-flag-listener.ts +123 -0
  186. package/src/ipc/skill-routes/registries.ts +8 -12
  187. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  188. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  189. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  190. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  191. package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
  192. package/src/memory/auto-analysis-enqueue.ts +5 -1
  193. package/src/memory/conversation-crud.ts +71 -70
  194. package/src/memory/conversation-starters-cadence.ts +3 -1
  195. package/src/memory/conversation-title-service.ts +19 -3
  196. package/src/memory/db-async-query.ts +214 -0
  197. package/src/memory/db-init.ts +10 -0
  198. package/src/memory/db-maintenance.ts +30 -21
  199. package/src/memory/graph/bootstrap.ts +8 -1
  200. package/src/memory/graph/capability-seed.ts +7 -3
  201. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  202. package/src/memory/graph/extraction.ts +1 -5
  203. package/src/memory/graph/graph-search.ts +7 -1
  204. package/src/memory/indexer.ts +28 -18
  205. package/src/memory/job-handlers/cleanup.ts +76 -18
  206. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  207. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  208. package/src/memory/jobs-store.ts +14 -0
  209. package/src/memory/jobs-worker.ts +55 -22
  210. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  211. package/src/memory/llm-request-log-source-local.ts +7 -0
  212. package/src/memory/llm-request-log-source.ts +9 -2
  213. package/src/memory/llm-request-log-store.ts +43 -1
  214. package/src/memory/llm-usage-store.ts +24 -0
  215. package/src/memory/memory-retrospective-enqueue.ts +8 -1
  216. package/src/memory/memory-retrospective-job.ts +5 -0
  217. package/src/memory/memory-v2-activation-log-store.ts +15 -6
  218. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  219. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  220. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  221. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  222. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  223. package/src/memory/migrations/index.ts +17 -0
  224. package/src/memory/migrations/registry.ts +33 -0
  225. package/src/memory/schema/conversations.ts +1 -1
  226. package/src/memory/schema/infrastructure.ts +21 -0
  227. package/src/memory/tool-usage-store.ts +36 -8
  228. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  229. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  230. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  231. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  232. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  233. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  234. package/src/memory/v2/__tests__/injection.test.ts +127 -98
  235. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  236. package/src/memory/v2/__tests__/router.test.ts +171 -3
  237. package/src/memory/v2/harness/compare.ts +57 -0
  238. package/src/memory/v2/harness/metrics.ts +124 -0
  239. package/src/memory/v2/harness/oracle.ts +145 -0
  240. package/src/memory/v2/harness/replay-input.ts +224 -0
  241. package/src/memory/v2/harness/retriever.ts +74 -0
  242. package/src/memory/v2/harness/router-retriever.ts +43 -0
  243. package/src/memory/v2/harness/runner.ts +106 -0
  244. package/src/memory/v2/harness/trace.ts +58 -0
  245. package/src/memory/v2/injection.ts +21 -15
  246. package/src/memory/v2/prompts/router.ts +26 -1
  247. package/src/memory/v2/qdrant.ts +14 -2
  248. package/src/memory/v2/router.ts +171 -18
  249. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  250. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  251. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  252. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  253. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  254. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  255. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  256. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  257. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  258. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  259. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  260. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  261. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  262. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  263. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  264. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  265. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  266. package/src/memory/v3/auto-edges.ts +223 -0
  267. package/src/memory/v3/coactivation-store.ts +124 -0
  268. package/src/memory/v3/consolidation-job.ts +323 -0
  269. package/src/memory/v3/edge-learning-job.ts +160 -0
  270. package/src/memory/v3/edges.ts +249 -0
  271. package/src/memory/v3/filter.ts +281 -0
  272. package/src/memory/v3/gate.ts +334 -0
  273. package/src/memory/v3/index-composition.ts +113 -0
  274. package/src/memory/v3/llm-capture.ts +46 -0
  275. package/src/memory/v3/loop.ts +382 -0
  276. package/src/memory/v3/maintenance.ts +144 -0
  277. package/src/memory/v3/prompt-context.ts +33 -0
  278. package/src/memory/v3/prompts/consolidation.ts +458 -0
  279. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  280. package/src/memory/v3/retriever.ts +33 -0
  281. package/src/memory/v3/scouts.ts +420 -0
  282. package/src/memory/v3/shadow-middleware.ts +305 -0
  283. package/src/memory/v3/traversal.ts +206 -0
  284. package/src/memory/v3/tree-index.ts +237 -0
  285. package/src/memory/v3/tree-store.ts +394 -0
  286. package/src/memory/v3/tree-walk.ts +351 -0
  287. package/src/memory/v3/types.ts +65 -0
  288. package/src/memory/v3/validate.ts +300 -0
  289. package/src/notifications/adapters/macos.ts +18 -1
  290. package/src/notifications/adapters/platform.ts +1 -1
  291. package/src/notifications/decision-engine.ts +1 -4
  292. package/src/notifications/emit-signal.ts +29 -49
  293. package/src/permissions/prompter.ts +3 -3
  294. package/src/permissions/question-prompter.ts +5 -2
  295. package/src/permissions/secret-prompter.ts +2 -2
  296. package/src/plugin-api/index.ts +4 -0
  297. package/src/plugin-api/types.ts +7 -33
  298. package/src/plugins/defaults/index.ts +6 -0
  299. package/src/plugins/defaults/injectors.ts +18 -11
  300. package/src/plugins/external-plugin-loader.ts +5 -68
  301. package/src/plugins/types.ts +11 -16
  302. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  303. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  304. package/src/prompts/persona-resolver.ts +36 -21
  305. package/src/prompts/sections.ts +39 -7
  306. package/src/prompts/system-prompt.ts +50 -185
  307. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  308. package/src/prompts/templates/system-sections.ts +230 -8
  309. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  310. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  311. package/src/providers/anthropic/client.ts +32 -66
  312. package/src/providers/call-site-routing.ts +14 -2
  313. package/src/providers/connection-model-compat.ts +38 -0
  314. package/src/providers/connection-resolution.ts +16 -2
  315. package/src/providers/gemini/client.ts +49 -6
  316. package/src/providers/inference/adapter-factory.ts +3 -0
  317. package/src/providers/minimax/client.ts +106 -0
  318. package/src/providers/model-catalog.ts +43 -0
  319. package/src/providers/model-intents.ts +1 -1
  320. package/src/providers/openai/chat-completions-provider.ts +6 -3
  321. package/src/providers/openai/codex-models.ts +18 -0
  322. package/src/providers/openai/responses-provider.ts +78 -21
  323. package/src/providers/provider-send-message.ts +7 -1
  324. package/src/providers/retry.ts +34 -3
  325. package/src/providers/thinking-config.ts +26 -1
  326. package/src/providers/usage-tracking.ts +2 -0
  327. package/src/runtime/AGENTS.md +2 -2
  328. package/src/runtime/agent-wake.ts +1 -0
  329. package/src/runtime/assistant-event-hub.ts +76 -6
  330. package/src/runtime/auth/route-policy.ts +36 -0
  331. package/src/runtime/btw-sidechain.ts +0 -6
  332. package/src/runtime/http-types.ts +0 -2
  333. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  334. package/src/runtime/pending-interactions.ts +0 -1
  335. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
  336. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
  337. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  338. package/src/runtime/routes/acp-routes.test.ts +255 -6
  339. package/src/runtime/routes/acp-routes.ts +8 -1
  340. package/src/runtime/routes/avatar-routes.ts +10 -10
  341. package/src/runtime/routes/background-wake-routes.ts +188 -0
  342. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  343. package/src/runtime/routes/btw-routes.ts +0 -6
  344. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  345. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  346. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  347. package/src/runtime/routes/conversation-query-routes.ts +142 -36
  348. package/src/runtime/routes/conversation-routes.ts +252 -410
  349. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  350. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  351. package/src/runtime/routes/domain-routes.ts +60 -10
  352. package/src/runtime/routes/email-routes.ts +5 -2
  353. package/src/runtime/routes/events-routes.ts +54 -10
  354. package/src/runtime/routes/group-routes.ts +24 -8
  355. package/src/runtime/routes/host-browser-routes.ts +10 -2
  356. package/src/runtime/routes/host-cu-routes.ts +2 -2
  357. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  358. package/src/runtime/routes/index.ts +8 -0
  359. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  360. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  361. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  362. package/src/runtime/routes/memory-item-routes.ts +8 -3
  363. package/src/runtime/routes/memory-v2-routes.ts +215 -5
  364. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  365. package/src/runtime/routes/migration-routes.ts +21 -24
  366. package/src/runtime/routes/plugins-routes.ts +337 -0
  367. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  368. package/src/runtime/routes/secret-routes.ts +25 -5
  369. package/src/runtime/routes/settings-routes.ts +12 -11
  370. package/src/runtime/routes/slack-channel-routes.ts +5 -4
  371. package/src/runtime/routes/workspace-routes.ts +25 -10
  372. package/src/runtime/sync/resource-sync-events.ts +106 -38
  373. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  374. package/src/runtime/sync/sync-publisher.ts +2 -1
  375. package/src/runtime/verification-outbound-actions.ts +73 -1
  376. package/src/telemetry/types.ts +12 -0
  377. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  378. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  379. package/src/tools/acp/spawn.test.ts +119 -0
  380. package/src/tools/acp/spawn.ts +15 -2
  381. package/src/tools/apps/definitions.ts +2 -8
  382. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  383. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  384. package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
  385. package/src/tools/browser/browser-execution.ts +16 -3
  386. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  387. package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
  388. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
  389. package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
  390. package/src/tools/browser/cdp-client/factory.ts +100 -17
  391. package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
  392. package/src/tools/browser/cdp-client/types.ts +65 -0
  393. package/src/tools/browser/pinned-tabs.ts +96 -40
  394. package/src/tools/computer-use/definitions.ts +22 -78
  395. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  396. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  397. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  398. package/src/tools/credentials/vault.ts +3 -9
  399. package/src/tools/document/document-tool.ts +59 -0
  400. package/src/tools/execution-target.ts +21 -23
  401. package/src/tools/executor.ts +6 -1
  402. package/src/tools/filesystem/edit.ts +3 -9
  403. package/src/tools/filesystem/list.ts +3 -9
  404. package/src/tools/filesystem/read.ts +3 -9
  405. package/src/tools/filesystem/write.ts +3 -9
  406. package/src/tools/host-filesystem/edit.ts +3 -9
  407. package/src/tools/host-filesystem/read.ts +3 -9
  408. package/src/tools/host-filesystem/transfer.ts +3 -9
  409. package/src/tools/host-filesystem/write.ts +3 -9
  410. package/src/tools/host-terminal/host-shell.ts +3 -9
  411. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  412. package/src/tools/memory/register.test.ts +1 -1
  413. package/src/tools/memory/register.ts +4 -9
  414. package/src/tools/network/web-fetch.ts +3 -9
  415. package/src/tools/network/web-search.ts +25 -32
  416. package/src/tools/registry.ts +7 -23
  417. package/src/tools/schema-transforms.ts +1 -1
  418. package/src/tools/skills/execute.ts +3 -9
  419. package/src/tools/skills/load.ts +3 -9
  420. package/src/tools/skills/skill-tool-factory.ts +1 -8
  421. package/src/tools/subagent/notify-parent.ts +3 -9
  422. package/src/tools/system/request-permission.ts +3 -9
  423. package/src/tools/terminal/shell.ts +3 -9
  424. package/src/tools/tool-defaults.ts +94 -0
  425. package/src/tools/types.ts +27 -98
  426. package/src/tools/ui-surface/definitions.ts +6 -22
  427. package/src/usage/pricing.ts +23 -0
  428. package/src/usage/types.ts +12 -0
  429. package/src/util/logger.ts +16 -7
  430. package/src/util/platform.ts +7 -2
  431. package/src/util/sqlite3-runtime.ts +65 -0
  432. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  433. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  434. package/src/workspace/migrations/registry.ts +2 -0
  435. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  436. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  437. package/src/daemon/query-complexity-router.ts +0 -75
  438. package/src/prompts/cache-boundary.ts +0 -8
@@ -7,6 +7,8 @@ export const SYNC_TAGS = {
7
7
  assistantSounds: "assistant:self:sounds",
8
8
  assistantSchedules: "assistant:self:schedules",
9
9
  conversationsList: "conversations:list",
10
+ featureFlagsClient: "feature-flags:client",
11
+ featureFlagsAssistant: "feature-flags:assistant",
10
12
  } as const;
11
13
 
12
14
  export type KnownSyncInvalidationTag =
@@ -24,6 +26,14 @@ export type SyncInvalidationTag =
24
26
  export interface SyncChangedMessage {
25
27
  type: "sync_changed";
26
28
  tags: SyncInvalidationTag[];
29
+ /**
30
+ * Optional identifier of the client that originated the change. When set,
31
+ * the server fan-out and clients themselves can suppress self-echoes so
32
+ * the originating tab/process doesn't reinvalidate its own cache off its
33
+ * own mutation. Daemon-internal emits (agent loop, FS watcher, cron) leave
34
+ * this unset so the event fans out to every subscriber as before.
35
+ */
36
+ originClientId?: string;
27
37
  }
28
38
 
29
39
  export const SyncInvalidationTagSchema = z.string().min(1);
@@ -32,6 +42,7 @@ export const SyncChangedMessageSchema = z
32
42
  .object({
33
43
  type: z.literal("sync_changed"),
34
44
  tags: z.array(SyncInvalidationTagSchema).min(1),
45
+ originClientId: z.string().min(1).optional(),
35
46
  })
36
47
  .strict();
37
48
 
@@ -49,11 +60,14 @@ export function conversationMetadataSyncTag(
49
60
 
50
61
  export function buildSyncChangedMessage(
51
62
  tags: SyncInvalidationTag[],
63
+ originClientId?: string,
52
64
  ): SyncChangedMessage {
53
65
  const dedupedTags = Array.from(new Set(tags));
66
+ const trimmedOrigin = originClientId?.trim();
54
67
  const parsed = SyncChangedMessageSchema.parse({
55
68
  type: "sync_changed",
56
69
  tags: dedupedTags,
70
+ ...(trimmedOrigin ? { originClientId: trimmedOrigin } : {}),
57
71
  });
58
72
  return parsed as SyncChangedMessage;
59
73
  }
@@ -34,10 +34,9 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
34
34
  let shuttingDown = false;
35
35
  let exitCode = 0;
36
36
 
37
- const shutdown = async () => {
37
+ const shutdown = async (_signal?: NodeJS.Signals) => {
38
38
  if (shuttingDown) return;
39
39
  shuttingDown = true;
40
- log.info("Shutting down daemon...");
41
40
 
42
41
  // Force exit if graceful shutdown takes too long.
43
42
  // Set this BEFORE awaiting heartbeat stop so it covers all
@@ -156,9 +155,29 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
156
155
  process.exit(exitCode);
157
156
  };
158
157
 
159
- process.on("SIGTERM", shutdown);
160
- process.on("SIGINT", shutdown);
161
- process.on("SIGHUP", shutdown);
158
+ process.on("SIGTERM", () => {
159
+ log.warn(
160
+ { signal: "SIGTERM", pid: process.pid, uptime: process.uptime() },
161
+ "Received SIGTERM — process termination requested",
162
+ );
163
+ void shutdown("SIGTERM");
164
+ });
165
+
166
+ process.on("SIGINT", () => {
167
+ log.warn(
168
+ { signal: "SIGINT", pid: process.pid, uptime: process.uptime() },
169
+ "Received SIGINT — user interrupt",
170
+ );
171
+ void shutdown("SIGINT");
172
+ });
173
+
174
+ process.on("SIGHUP", () => {
175
+ log.warn(
176
+ { signal: "SIGHUP", pid: process.pid, uptime: process.uptime() },
177
+ "Received SIGHUP — terminal hangup",
178
+ );
179
+ void shutdown("SIGHUP");
180
+ });
162
181
 
163
182
  process.on("unhandledRejection", (reason) => {
164
183
  log.error(
@@ -0,0 +1,52 @@
1
+ import type { ProfileEntry } from "../config/schemas/llm.js";
2
+ import type { ToolDefinition } from "../providers/types.js";
3
+
4
+ export const SWITCH_INFERENCE_PROFILE_TOOL_NAME = "switch_inference_profile";
5
+
6
+ const PROFILE_DESCRIPTION_FALLBACKS: Record<string, string> = {
7
+ "quality-optimized":
8
+ "Most capable model for complex reasoning, multi-step analysis, math, and coding",
9
+ balanced: "Good balance of quality, cost, and speed for most tasks",
10
+ "cost-optimized":
11
+ "Fast responses for simple factual questions, short lookups, and casual chat",
12
+ };
13
+
14
+ export function buildSwitchInferenceProfileToolDef(
15
+ profiles: Record<string, ProfileEntry>,
16
+ currentProfile?: string,
17
+ ): ToolDefinition | null {
18
+ const entries = Object.entries(profiles).filter(
19
+ ([, entry]) => entry.status !== "disabled",
20
+ );
21
+ if (entries.length < 2) return null;
22
+
23
+ const profileDescriptions = entries
24
+ .map(([key, entry]) => {
25
+ const label = entry.label ?? key;
26
+ const desc =
27
+ entry.description || PROFILE_DESCRIPTION_FALLBACKS[key] || "";
28
+ const descSuffix = desc ? `: ${desc}` : "";
29
+ const current = key === currentProfile ? " (current)" : "";
30
+ return `- ${key} — ${label}${descSuffix}${current}`;
31
+ })
32
+ .join("\n");
33
+
34
+ const currentEntry = currentProfile ? profiles[currentProfile] : undefined;
35
+ const currentLabel = currentEntry?.label ?? currentProfile ?? "current";
36
+
37
+ return {
38
+ name: SWITCH_INFERENCE_PROFILE_TOOL_NAME,
39
+ description: `Switch to a different inference profile BEFORE answering. You MUST call this tool when the user's query requires capabilities beyond what your current profile ("${currentLabel}") provides. Examples of when to switch to a more capable profile: multi-step reasoning or analysis, math proofs or derivations, complex coding tasks, detailed creative writing, or any task requiring deep thought. Examples of when to switch to a faster profile: simple greetings, one-word answers, factual lookups. When in doubt about whether you can handle the query well, switch to a more capable profile.\n\nAvailable profiles:\n${profileDescriptions}`,
40
+ input_schema: {
41
+ type: "object" as const,
42
+ properties: {
43
+ profile: {
44
+ type: "string",
45
+ enum: entries.map(([key]) => key),
46
+ description: "The profile key to switch to.",
47
+ },
48
+ },
49
+ required: ["profile"],
50
+ },
51
+ };
52
+ }
@@ -57,4 +57,17 @@ export interface ToolSetupContext extends SurfaceConversationContext {
57
57
  * return `undefined` for the in-flight (background) subagent.
58
58
  */
59
59
  currentTurnOverrideProfile?: string;
60
+ /**
61
+ * Set by the `switch_inference_profile` tool when the model self-selects a
62
+ * different profile mid-turn. Read by `readCurrentOverrideProfile` in the
63
+ * agent loop so the next LLM call uses the switched profile. Reset at
64
+ * turn start.
65
+ */
66
+ toolRoutedProfile?: string;
67
+ /**
68
+ * True when the user has explicitly selected an inference profile for this
69
+ * conversation (via the composer profile picker). When set, tool-based
70
+ * auto-routing is suppressed — the user's explicit choice takes precedence.
71
+ */
72
+ hasExplicitProfileOverride?: boolean;
60
73
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `relationship_state_updated` SSE event.
3
+ *
4
+ * Broadcast by the daemon after a successful write of
5
+ * `relationship-state.json` to disk. Subscribers refetch
6
+ * `GET /v1/home/state` to read the new state — payload here just
7
+ * carries the new `updatedAt` for cache-tag comparison.
8
+ *
9
+ * Canonical wire-contract source. Daemon code imports the type
10
+ * directly from this file; external consumers import via
11
+ * `@vellumai/assistant-api`.
12
+ */
13
+
14
+ import { z } from "zod";
15
+
16
+ export const RelationshipStateUpdatedSchema = z
17
+ .object({
18
+ type: z.literal("relationship_state_updated"),
19
+ updatedAt: z.string(),
20
+ })
21
+ .strict();
22
+
23
+ export type RelationshipStateUpdated = z.infer<
24
+ typeof RelationshipStateUpdatedSchema
25
+ >;
@@ -14,6 +14,7 @@ mock.module("../../runtime/assistant-event-hub.js", () => ({
14
14
  publish: publishSpy,
15
15
  subscribe: () => () => {},
16
16
  },
17
+ broadcastMessage: () => {},
17
18
  }));
18
19
 
19
20
  // Stub workspace prompt reads so the heartbeat service doesn't try to
@@ -99,7 +100,6 @@ mock.module("../../prompts/persona-resolver.js", () => ({
99
100
  }));
100
101
  mock.module("../../prompts/system-prompt.js", () => ({
101
102
  isTemplateContent: () => false,
102
- SYSTEM_PROMPT_CACHE_BOUNDARY: "<<CACHE_BOUNDARY>>",
103
103
  buildCoreIdentityContext: () => "",
104
104
  buildSystemPrompt: () => "",
105
105
  ensurePromptFiles: () => {},
@@ -13,7 +13,6 @@
13
13
 
14
14
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
15
15
  import { getConfig } from "../config/loader.js";
16
- import { resolvePersonaContext } from "../prompts/persona-resolver.js";
17
16
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
18
17
  import { getConfiguredProvider } from "../providers/provider-send-message.js";
19
18
  import { runBtwSidechain } from "../runtime/btw-sidechain.js";
@@ -56,17 +55,9 @@ export async function refreshPersonalizedGreeting(): Promise<void> {
56
55
  return;
57
56
  }
58
57
 
59
- const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
60
- undefined,
61
- undefined,
62
- );
63
-
64
58
  const systemPrompt = buildSystemPrompt({
65
59
  excludeBootstrap: true,
66
60
  excludeCustomPrefix: true,
67
- userPersona,
68
- channelPersona,
69
- userSlug,
70
61
  });
71
62
 
72
63
  const result = await runBtwSidechain({
@@ -16,7 +16,6 @@
16
16
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
17
17
  import { getConfig } from "../config/loader.js";
18
18
  import { listProviders } from "../oauth/oauth-store.js";
19
- import { resolvePersonaContext } from "../prompts/persona-resolver.js";
20
19
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
21
20
  import { getConfiguredProvider } from "../providers/provider-send-message.js";
22
21
  import { buildAssistantEvent } from "../runtime/assistant-event.js";
@@ -234,17 +233,9 @@ async function generateAssistantPrompts(
234
233
  return [];
235
234
  }
236
235
 
237
- const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
238
- undefined,
239
- undefined,
240
- );
241
-
242
236
  const systemPrompt = buildSystemPrompt({
243
237
  excludeBootstrap: true,
244
238
  excludeCustomPrefix: true,
245
- userPersona,
246
- channelPersona,
247
- userSlug,
248
239
  });
249
240
 
250
241
  const existingLabels = deterministicPrompts.map((p) => p.label).join(", ");
@@ -0,0 +1,123 @@
1
+ import { connect, type Socket } from "node:net";
2
+
3
+ import { refreshOverridesFromGateway } from "../config/assistant-feature-flags.js";
4
+ import { SYNC_TAGS } from "../daemon/message-types/sync.js";
5
+ import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
6
+ import { getLogger } from "../util/logger.js";
7
+ import { resolveIpcSocketPath } from "./socket-path.js";
8
+
9
+ const log = getLogger("gateway-flag-listener");
10
+
11
+ const MAX_BACKOFF_MS = 30_000;
12
+ const INITIAL_BACKOFF_MS = 1_000;
13
+
14
+ let socket: Socket | null = null;
15
+ let stopped = false;
16
+ let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
17
+ let currentBackoffMs = INITIAL_BACKOFF_MS;
18
+
19
+ function getSocketPath(): string {
20
+ return resolveIpcSocketPath("gateway").path;
21
+ }
22
+
23
+ function handleData(chunk: Buffer): void {
24
+ const lines = chunk.toString().split("\n");
25
+ for (const line of lines) {
26
+ const trimmed = line.trim();
27
+ if (!trimmed) continue;
28
+ try {
29
+ const msg = JSON.parse(trimmed) as { event?: string };
30
+ if (msg.event === "feature_flags_changed") {
31
+ log.info("Received feature_flags_changed event — refreshing overrides");
32
+ refreshOverridesFromGateway().catch((err) => {
33
+ log.warn({ err }, "Failed to refresh feature flag overrides");
34
+ });
35
+ // Fan out to every connected web client so React Query caches
36
+ // for `/v1/feature-flags/client-flag-values/` and
37
+ // `/v1/assistants/:id/feature-flags` invalidate immediately
38
+ // instead of waiting on a 5s polling tick.
39
+ publishSyncInvalidation([
40
+ SYNC_TAGS.featureFlagsClient,
41
+ SYNC_TAGS.featureFlagsAssistant,
42
+ ]).catch((err) => {
43
+ log.warn({ err }, "Failed to broadcast feature-flags sync_changed");
44
+ });
45
+ }
46
+ } catch {
47
+ // Ignore non-JSON lines (e.g. IPC responses on a shared socket)
48
+ }
49
+ }
50
+ }
51
+
52
+ function scheduleReconnect(): void {
53
+ if (stopped) return;
54
+ reconnectTimer = setTimeout(() => {
55
+ reconnectTimer = null;
56
+ connectToGateway();
57
+ }, currentBackoffMs);
58
+ currentBackoffMs = Math.min(currentBackoffMs * 2, MAX_BACKOFF_MS);
59
+ }
60
+
61
+ function connectToGateway(): void {
62
+ if (stopped) return;
63
+
64
+ const socketPath = getSocketPath();
65
+ const conn = connect(socketPath);
66
+
67
+ conn.on("connect", () => {
68
+ if (stopped) {
69
+ conn.destroy();
70
+ return;
71
+ }
72
+ log.info("Connected to gateway IPC for flag events");
73
+ currentBackoffMs = INITIAL_BACKOFF_MS;
74
+ socket = conn;
75
+ refreshOverridesFromGateway().catch((err) => {
76
+ log.warn({ err }, "Failed to refresh feature flag overrides on reconnect");
77
+ });
78
+ });
79
+
80
+ let buffer = "";
81
+ conn.on("data", (chunk) => {
82
+ buffer += chunk.toString();
83
+ let newlineIdx: number;
84
+ while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
85
+ const line = buffer.slice(0, newlineIdx);
86
+ buffer = buffer.slice(newlineIdx + 1);
87
+ if (line.trim()) {
88
+ handleData(Buffer.from(line));
89
+ }
90
+ }
91
+ });
92
+
93
+ conn.on("close", () => {
94
+ socket = null;
95
+ if (!stopped) {
96
+ log.debug("Gateway IPC connection closed — reconnecting");
97
+ scheduleReconnect();
98
+ }
99
+ });
100
+
101
+ conn.on("error", (err) => {
102
+ log.debug({ err }, "Gateway IPC connection error");
103
+ conn.destroy();
104
+ });
105
+ }
106
+
107
+ export function startGatewayFlagListener(): void {
108
+ stopped = false;
109
+ currentBackoffMs = INITIAL_BACKOFF_MS;
110
+ connectToGateway();
111
+ }
112
+
113
+ export function stopGatewayFlagListener(): void {
114
+ stopped = true;
115
+ if (reconnectTimer) {
116
+ clearTimeout(reconnectTimer);
117
+ reconnectTimer = null;
118
+ }
119
+ if (socket) {
120
+ socket.destroy();
121
+ socket = null;
122
+ }
123
+ }
@@ -22,12 +22,9 @@ import { z } from "zod";
22
22
  import type { MeetHostSupervisor } from "../../daemon/meet-host-supervisor.js";
23
23
  import { registerShutdownHook } from "../../daemon/shutdown-registry.js";
24
24
  import { registerSkillRoute } from "../../runtime/skill-route-registry.js";
25
+ import { resolveExecutionTarget } from "../../tools/execution-target.js";
25
26
  import { registerSkillTools } from "../../tools/registry.js";
26
- import type {
27
- ExecutionTarget,
28
- Tool,
29
- ToolDefinition,
30
- } from "../../tools/types.js";
27
+ import type { ExecutionTarget, Tool } from "../../tools/types.js";
31
28
  import { RiskLevel } from "../../tools/types.js";
32
29
  import { getLogger } from "../../util/logger.js";
33
30
  import type { SkillIpcRoute } from "../skill-ipc-types.js";
@@ -182,25 +179,24 @@ export function __getActiveSessionCountForTesting(): number {
182
179
  * exercised end-to-end.
183
180
  */
184
181
  function buildProxyTool(manifest: ToolManifest): Tool {
185
- const definition: ToolDefinition = {
186
- name: manifest.name,
187
- description: manifest.description,
188
- input_schema: manifest.input_schema as object,
189
- };
190
182
  // RiskLevel is a string enum whose values are "low" | "medium" | "high",
191
183
  // matching the schema above exactly — the cast is a no-op at runtime.
192
184
  return {
193
185
  name: manifest.name,
194
186
  description: manifest.description,
187
+ input_schema: manifest.input_schema as object,
195
188
  category: manifest.category,
196
189
  defaultRiskLevel: manifest.defaultRiskLevel as RiskLevel,
197
190
  executionMode: manifest.executionMode ?? "proxy",
198
- executionTarget: manifest.executionTarget as ExecutionTarget | undefined,
191
+ executionTarget: resolveExecutionTarget({
192
+ name: manifest.name,
193
+ executionTarget: manifest.executionTarget as ExecutionTarget | undefined,
194
+ executionMode: manifest.executionMode ?? "proxy",
195
+ }),
199
196
  origin: "skill",
200
197
  ownerSkillId: manifest.ownerSkillId,
201
198
  ownerSkillBundled: manifest.ownerSkillBundled,
202
199
  ownerSkillVersionHash: manifest.ownerSkillVersionHash,
203
- getDefinition: () => definition,
204
200
  execute: async () => {
205
201
  // Only reached when no supervisor is attached (tests/boot race);
206
202
  // the supervisor short-circuit above replaces this with the
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Tests for `db-async-query.ts` — the runAsyncSqlite abstraction.
3
+ *
4
+ * The contract this PR locks in:
5
+ * 1. **The main event loop keeps ticking while a long SQLite
6
+ * statement is in flight via the sqlite3 CLI backend.** This is
7
+ * the structural anti-block assertion — a recursive `setImmediate`
8
+ * probe counts event-loop iterations during the operation; if
9
+ * anyone moves the slow path back onto the main thread,
10
+ * `bun:sqlite` is synchronous and tick counting collapses to ~0;
11
+ * this test fails loudly.
12
+ * 2. The CLI backend reports `backend: "sqlite3-cli"` and `ok: true`
13
+ * on success.
14
+ * 3. The in-process fallback backend executes the statement
15
+ * synchronously and reports `backend: "in-process-blocking"`.
16
+ * 4. Errors from sqlite3 surface as `ok: false` with the stderr
17
+ * preserved in `error`.
18
+ */
19
+ import { beforeEach, describe, expect, test } from "bun:test";
20
+
21
+ const { getSqlite } = await import("../db-connection.js");
22
+ const { initializeDb } = await import("../db-init.js");
23
+ const { runAsyncSqlite, _resetFallbackWarning } =
24
+ await import("../db-async-query.js");
25
+ const { findSqlite3 } = await import("../../util/sqlite3-runtime.js");
26
+
27
+ initializeDb();
28
+
29
+ const sqlite3Available = findSqlite3() !== undefined;
30
+
31
+ beforeEach(() => {
32
+ _resetFallbackWarning();
33
+ });
34
+
35
+ function inflateAndDelete(byteTarget: number): void {
36
+ const sqlite = getSqlite();
37
+ sqlite.exec(
38
+ "CREATE TABLE IF NOT EXISTS async_bloat (id INTEGER PRIMARY KEY, payload BLOB)",
39
+ );
40
+ const pageSize = (
41
+ sqlite.query("PRAGMA page_size").get() as { page_size: number }
42
+ ).page_size;
43
+ const rowsTarget = Math.max(1, Math.ceil(byteTarget / pageSize));
44
+ const payload = new Uint8Array(Math.max(1, pageSize - 64));
45
+ const insert = sqlite.prepare("INSERT INTO async_bloat (payload) VALUES (?)");
46
+ sqlite.exec("BEGIN");
47
+ for (let i = 0; i < rowsTarget; i++) {
48
+ insert.run(payload);
49
+ }
50
+ sqlite.exec("COMMIT");
51
+ sqlite.exec("DELETE FROM async_bloat");
52
+ sqlite.exec("DROP TABLE async_bloat");
53
+ sqlite.exec("PRAGMA wal_checkpoint(TRUNCATE)");
54
+ }
55
+
56
+ describe("runAsyncSqlite", () => {
57
+ test("returns ok=true for a trivial statement", async () => {
58
+ const result = await runAsyncSqlite("SELECT 1");
59
+ expect(result.ok).toBe(true);
60
+ expect(result.error).toBeNull();
61
+ });
62
+
63
+ test("in-process fallback reports the right backend", async () => {
64
+ const result = await runAsyncSqlite("SELECT 1", {
65
+ forceBackend: "in-process-blocking",
66
+ });
67
+ expect(result.ok).toBe(true);
68
+ expect(result.backend).toBe("in-process-blocking");
69
+ });
70
+
71
+ test("in-process fallback emits changes() count on stdout after a DELETE", async () => {
72
+ // Regression for Codex P1 on #31894: callers (e.g. prune jobs) rely
73
+ // on reading the row count off `result.stdout`. The CLI backend
74
+ // populates this naturally when the SQL ends with `SELECT changes();`,
75
+ // but `bun:sqlite`'s `exec()` discards SELECT results — so the
76
+ // in-process backend has to synthesize the same line, or the
77
+ // re-enqueue gate in pruneOld*Job silently never fires on hosts
78
+ // without the sqlite3 CLI.
79
+ const sqlite = getSqlite();
80
+ sqlite.exec(
81
+ "CREATE TABLE IF NOT EXISTS async_changes_probe (id INTEGER PRIMARY KEY)",
82
+ );
83
+ sqlite.exec("DELETE FROM async_changes_probe");
84
+ sqlite.exec(
85
+ "INSERT INTO async_changes_probe (id) VALUES (1),(2),(3),(4),(5)",
86
+ );
87
+
88
+ const result = await runAsyncSqlite(
89
+ "DELETE FROM async_changes_probe WHERE id <= 3; SELECT changes();",
90
+ { forceBackend: "in-process-blocking" },
91
+ );
92
+
93
+ expect(result.ok).toBe(true);
94
+ expect(result.backend).toBe("in-process-blocking");
95
+ // The synthesized stdout matches what the CLI backend would emit:
96
+ // a bare integer on its own line. The exact format keeps the
97
+ // parser in cleanup.ts backend-agnostic.
98
+ expect(result.stdout).toBe("3\n");
99
+
100
+ sqlite.exec("DROP TABLE async_changes_probe");
101
+ });
102
+
103
+ test.if(sqlite3Available)(
104
+ "sqlite3 CLI backend reports the right backend on success",
105
+ async () => {
106
+ const result = await runAsyncSqlite("SELECT 1");
107
+ expect(result.ok).toBe(true);
108
+ expect(result.backend).toBe("sqlite3-cli");
109
+ },
110
+ );
111
+
112
+ test.if(sqlite3Available)(
113
+ "surfaces sqlite3 errors as ok=false with the message preserved",
114
+ async () => {
115
+ // Intentional SQL syntax error.
116
+ const result = await runAsyncSqlite("THIS IS NOT VALID SQL");
117
+ expect(result.ok).toBe(false);
118
+ expect(result.backend).toBe("sqlite3-cli");
119
+ expect(result.error).toBeTruthy();
120
+ },
121
+ );
122
+
123
+ test.if(sqlite3Available)(
124
+ "VACUUM via sqlite3 CLI keeps the event loop ticking (anti-block)",
125
+ async () => {
126
+ // Inflate the DB so VACUUM has measurable work to do. Without
127
+ // this the subprocess finishes in single-digit ms and the
128
+ // probe has no opportunity to record meaningful ticks.
129
+ inflateAndDelete(8 * 1024 * 1024);
130
+
131
+ // Probe the event loop with recursive setImmediate. This fires
132
+ // on every event-loop iteration with no minimum delay, so on a
133
+ // healthy unblocked loop it produces tens of thousands of ticks
134
+ // per second (vs. setInterval(1) which is capped by the host's
135
+ // timer resolution — observed at ~32 ms on GitHub Actions
136
+ // runners). If anyone moves VACUUM back onto the main thread,
137
+ // `bun:sqlite` is sync and tick count collapses to ~0; the
138
+ // assertion below fails loudly. The signal is intentionally
139
+ // binary: "many" vs "none".
140
+ let tickCount = 0;
141
+ let probing = true;
142
+ const tick = (): void => {
143
+ if (!probing) return;
144
+ tickCount += 1;
145
+ setImmediate(tick);
146
+ };
147
+ setImmediate(tick);
148
+
149
+ let result;
150
+ try {
151
+ result = await runAsyncSqlite("VACUUM");
152
+ } finally {
153
+ probing = false;
154
+ }
155
+
156
+ expect(result.ok).toBe(true);
157
+ expect(result.backend).toBe("sqlite3-cli");
158
+
159
+ // Any positive tick count proves the event loop wasn't blocked.
160
+ // A sync in-process VACUUM would collapse this to 0.
161
+ expect(tickCount).toBeGreaterThanOrEqual(1);
162
+ },
163
+ 60_000,
164
+ );
165
+ });