@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62

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 (490) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -5,6 +5,7 @@ import { drizzle } from "drizzle-orm/bun-sqlite";
5
5
 
6
6
  import { getSqliteFrom } from "../memory/db-connection.js";
7
7
  import { migrate230AcpSessionHistory } from "../memory/migrations/230-acp-session-history.js";
8
+ import { migrateAcpSessionHistoryCwd } from "../memory/migrations/272-acp-session-history-cwd.js";
8
9
  import * as schema from "../memory/schema.js";
9
10
 
10
11
  function createTestDb() {
@@ -282,3 +283,103 @@ describe("acp_session_history migration", () => {
282
283
  expect(row?.id).toBe("history-rerun");
283
284
  });
284
285
  });
286
+
287
+ describe("acp_session_history cwd migration (272)", () => {
288
+ function readColumns(raw: Database): Map<string, ColumnRow> {
289
+ const columns = raw
290
+ .query(`PRAGMA table_info(acp_session_history)`)
291
+ .all() as ColumnRow[];
292
+ return new Map(columns.map((c) => [c.name, c]));
293
+ }
294
+
295
+ test("adds a nullable cwd TEXT column to an upgraded table", () => {
296
+ const db = createTestDb();
297
+ const raw = getSqliteFrom(db);
298
+ bootstrapCheckpointsTable(raw);
299
+
300
+ migrate230AcpSessionHistory(db);
301
+ expect(readColumns(raw).has("cwd")).toBe(false);
302
+
303
+ migrateAcpSessionHistoryCwd(db);
304
+
305
+ const cwd = readColumns(raw).get("cwd");
306
+ expect(cwd).toBeDefined();
307
+ expect(cwd?.type).toBe("TEXT");
308
+ expect(cwd?.notnull).toBe(0);
309
+ });
310
+
311
+ test("re-running is a no-op, including with a cleared checkpoint", () => {
312
+ const db = createTestDb();
313
+ const raw = getSqliteFrom(db);
314
+ bootstrapCheckpointsTable(raw);
315
+
316
+ migrate230AcpSessionHistory(db);
317
+ migrateAcpSessionHistoryCwd(db);
318
+
319
+ // Second run short-circuits on the completed checkpoint.
320
+ expect(() => migrateAcpSessionHistoryCwd(db)).not.toThrow();
321
+
322
+ // Even with the checkpoint cleared (simulating crash recovery), the
323
+ // column-existence guard makes the ALTER a no-op.
324
+ raw
325
+ .query(`DELETE FROM memory_checkpoints WHERE key = ?`)
326
+ .run("migration_acp_session_history_cwd_v1");
327
+ expect(() => migrateAcpSessionHistoryCwd(db)).not.toThrow();
328
+
329
+ const columns = raw
330
+ .query(`PRAGMA table_info(acp_session_history)`)
331
+ .all() as ColumnRow[];
332
+ expect(columns.filter((c) => c.name === "cwd")).toHaveLength(1);
333
+ });
334
+
335
+ test("legacy rows read back with cwd null; new rows round-trip cwd", () => {
336
+ const db = createTestDb();
337
+ const raw = getSqliteFrom(db);
338
+ bootstrapCheckpointsTable(raw);
339
+
340
+ migrate230AcpSessionHistory(db);
341
+
342
+ // Legacy row inserted before the cwd column existed.
343
+ raw
344
+ .query(
345
+ /*sql*/ `
346
+ INSERT INTO acp_session_history (
347
+ id, agent_id, acp_session_id, parent_conversation_id,
348
+ started_at, status
349
+ ) VALUES (?, ?, ?, ?, ?, ?)
350
+ `,
351
+ )
352
+ .run("legacy-1", "agent-old", "acp-old", "conv-old", 100, "completed");
353
+
354
+ migrateAcpSessionHistoryCwd(db);
355
+
356
+ const legacy = raw
357
+ .query(`SELECT cwd FROM acp_session_history WHERE id = 'legacy-1'`)
358
+ .get() as { cwd: string | null } | null;
359
+ expect(legacy?.cwd).toBeNull();
360
+
361
+ raw
362
+ .query(
363
+ /*sql*/ `
364
+ INSERT INTO acp_session_history (
365
+ id, agent_id, acp_session_id, parent_conversation_id,
366
+ started_at, status, cwd
367
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
368
+ `,
369
+ )
370
+ .run(
371
+ "new-1",
372
+ "agent-new",
373
+ "acp-new",
374
+ "conv-new",
375
+ 200,
376
+ "completed",
377
+ "/Users/me/project",
378
+ );
379
+
380
+ const fresh = raw
381
+ .query(`SELECT cwd FROM acp_session_history WHERE id = 'new-1'`)
382
+ .get() as { cwd: string | null } | null;
383
+ expect(fresh?.cwd).toBe("/Users/me/project");
384
+ });
385
+ });
@@ -94,6 +94,37 @@ describe("ui_show dynamic_page app substitute guard", () => {
94
94
  expect(proxied).toBe(false);
95
95
  });
96
96
 
97
+ test("rejects dynamic_page with a clean title but substantial interactive html", async () => {
98
+ let proxied = false;
99
+
100
+ const result = await uiShowTool.execute(
101
+ {
102
+ surface_type: "dynamic_page",
103
+ title: "Labor Market Stats",
104
+ data: {
105
+ html:
106
+ "<div id='root'></div><script>" +
107
+ "const data=[/*...*/];".padEnd(2100, "/") +
108
+ "new Chart(document.getElementById('root'), {});</script>",
109
+ preview: { title: "Labor Market Stats" },
110
+ },
111
+ },
112
+ {
113
+ conversationId: "conversation-123",
114
+ workingDir: "/tmp",
115
+ trustClass: "guardian",
116
+ proxyToolResolver: async () => {
117
+ proxied = true;
118
+ return { content: "proxied", isError: false };
119
+ },
120
+ },
121
+ );
122
+
123
+ expect(result.isError).toBe(true);
124
+ expect(result.content).toContain('skill: "app-builder"');
125
+ expect(proxied).toBe(false);
126
+ });
127
+
97
128
  test("allows transient non-app dynamic_page surfaces", async () => {
98
129
  let proxied = false;
99
130
 
@@ -2,8 +2,7 @@
2
2
  * Tests for managed proxy Gemini embedding backend selection.
3
3
  *
4
4
  * Verifies that selectEmbeddingBackend correctly routes through the
5
- * managed proxy when the feature flag is enabled and managed proxy
6
- * prerequisites are satisfied.
5
+ * managed proxy when managed proxy prerequisites are satisfied.
7
6
  */
8
7
 
9
8
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
@@ -42,13 +41,9 @@ mock.module("../security/secure-keys.js", () => ({
42
41
  },
43
42
  }));
44
43
 
45
- // Feature flag mock
46
- const mockFeatureFlags: Record<string, boolean> = {};
47
-
44
+ // Feature flag mock — always returns true (flag is GA'ed)
48
45
  mock.module("../config/assistant-feature-flags.js", () => ({
49
- isAssistantFeatureFlagEnabled: (key: string, _config: unknown) => {
50
- return mockFeatureFlags[key] ?? false;
51
- },
46
+ isAssistantFeatureFlagEnabled: () => true,
52
47
  }));
53
48
 
54
49
  import type { AssistantConfig } from "../config/types.js";
@@ -75,14 +70,6 @@ function disableManagedProxy() {
75
70
  mockAssistantApiKey = null;
76
71
  }
77
72
 
78
- function enableFlag() {
79
- mockFeatureFlags["managed-gemini-embeddings-enabled"] = true;
80
- }
81
-
82
- function disableFlag() {
83
- mockFeatureFlags["managed-gemini-embeddings-enabled"] = false;
84
- }
85
-
86
73
  function makeConfig(
87
74
  overrides: {
88
75
  provider?: string;
@@ -116,7 +103,6 @@ function makeConfig(
116
103
 
117
104
  beforeEach(() => {
118
105
  disableManagedProxy();
119
- disableFlag();
120
106
  mockProviderKeys = {};
121
107
  clearEmbeddingBackendCache();
122
108
  });
@@ -126,9 +112,8 @@ afterEach(() => {
126
112
  });
127
113
 
128
114
  describe("managed proxy Gemini embedding selection", () => {
129
- test("selects managed proxy Gemini when flag enabled and proxy context available", async () => {
115
+ test("selects managed proxy Gemini when proxy context available", async () => {
130
116
  enableManagedProxy();
131
- enableFlag();
132
117
  const config = makeConfig();
133
118
 
134
119
  const { backend, reason } = await selectEmbeddingBackend(config);
@@ -141,7 +126,6 @@ describe("managed proxy Gemini embedding selection", () => {
141
126
 
142
127
  test("managed proxy backend uses default 3072 dimensions when geminiDimensions not set", async () => {
143
128
  enableManagedProxy();
144
- enableFlag();
145
129
  const config = makeConfig();
146
130
 
147
131
  const { backend } = await selectEmbeddingBackend(config);
@@ -155,7 +139,6 @@ describe("managed proxy Gemini embedding selection", () => {
155
139
 
156
140
  test("managed proxy backend uses explicit geminiDimensions when set", async () => {
157
141
  enableManagedProxy();
158
- enableFlag();
159
142
  const config = makeConfig({ geminiDimensions: 768 });
160
143
 
161
144
  const { backend } = await selectEmbeddingBackend(config);
@@ -168,7 +151,6 @@ describe("managed proxy Gemini embedding selection", () => {
168
151
 
169
152
  test("managed proxy backend uses managedBaseUrl (not direct Google API)", async () => {
170
153
  enableManagedProxy();
171
- enableFlag();
172
154
  const config = makeConfig();
173
155
 
174
156
  const { backend } = await selectEmbeddingBackend(config);
@@ -179,32 +161,19 @@ describe("managed proxy Gemini embedding selection", () => {
179
161
  expect(managedBaseUrl).toBe(`${PLATFORM_BASE}/v1/runtime-proxy/gemini`);
180
162
  });
181
163
 
182
- test("falls back to local when flag is disabled (no managed proxy)", async () => {
183
- enableManagedProxy();
184
- disableFlag();
185
- const config = makeConfig();
186
-
187
- const { backend } = await selectEmbeddingBackend(config);
188
-
189
- // With auto and no provider keys, falls through to local
190
- expect(backend).not.toBeNull();
191
- expect(backend!.provider).toBe("local");
192
- });
193
-
194
164
  test("falls back to local when managed proxy context unavailable", async () => {
195
165
  disableManagedProxy();
196
- enableFlag();
197
166
  const config = makeConfig();
198
167
 
199
168
  const { backend } = await selectEmbeddingBackend(config);
200
169
 
170
+ // With auto and no provider keys or proxy, falls through to local
201
171
  expect(backend).not.toBeNull();
202
172
  expect(backend!.provider).toBe("local");
203
173
  });
204
174
 
205
175
  test("selects managed proxy when provider is explicitly gemini", async () => {
206
176
  enableManagedProxy();
207
- enableFlag();
208
177
  const config = makeConfig({ provider: "gemini" });
209
178
 
210
179
  const { backend } = await selectEmbeddingBackend(config);
@@ -217,7 +186,6 @@ describe("managed proxy Gemini embedding selection", () => {
217
186
 
218
187
  test("does not use managed proxy when provider is explicitly local", async () => {
219
188
  enableManagedProxy();
220
- enableFlag();
221
189
  const config = makeConfig({ provider: "local" });
222
190
 
223
191
  const { backend } = await selectEmbeddingBackend(config);
@@ -228,7 +196,6 @@ describe("managed proxy Gemini embedding selection", () => {
228
196
 
229
197
  test("does not use managed proxy when provider is explicitly openai", async () => {
230
198
  enableManagedProxy();
231
- enableFlag();
232
199
  mockProviderKeys[credentialKey("openai", "api_key")] = "user-openai-key";
233
200
  const config = makeConfig({ provider: "openai" });
234
201
 
@@ -238,9 +205,8 @@ describe("managed proxy Gemini embedding selection", () => {
238
205
  expect(backend!.provider).toBe("openai");
239
206
  });
240
207
 
241
- test("direct Gemini key still works when flag is off", async () => {
208
+ test("direct Gemini key still works without managed proxy", async () => {
242
209
  disableManagedProxy();
243
- disableFlag();
244
210
  mockProviderKeys[credentialKey("gemini", "api_key")] = "user-gemini-key";
245
211
  const config = makeConfig({ provider: "gemini" });
246
212
 
@@ -31,7 +31,7 @@ import {
31
31
  REFUSAL_NUDGE_TEXT,
32
32
  } from "../plugins/defaults/empty-response/hooks/stop.js";
33
33
  import stop from "../plugins/defaults/empty-response/hooks/stop.js";
34
- import { defaultEmptyResponsePlugin } from "../plugins/defaults/empty-response/register.js";
34
+ import { defaultEmptyResponsePlugin } from "../plugins/defaults/index.js";
35
35
  import { runHook } from "../plugins/pipeline.js";
36
36
  import {
37
37
  registerPlugin,
@@ -260,3 +260,66 @@ describe("file_write tool PKB re-index hook", () => {
260
260
  expect(existsSync(join(workingDir, "pkb", "oops.md"))).toBe(true);
261
261
  });
262
262
  });
263
+
264
+ describe("file_write artifact-HTML guard", () => {
265
+ test("rejects a self-contained interactive HTML visualization", async () => {
266
+ const dir = makeTempDir();
267
+ const html =
268
+ "<!doctype html><html><head><title>Food Market</title></head>" +
269
+ "<body><canvas id='c'></canvas><script>" +
270
+ ("const data=[{x:1,y:2}];").padEnd(4000, "/") +
271
+ "new Chart(document.getElementById('c'), {data});</script></body></html>";
272
+
273
+ const result = await fileWriteTool.execute(
274
+ { path: "food-market-stats.html", content: html },
275
+ makeContext(dir),
276
+ );
277
+
278
+ expect(result.isError).toBe(true);
279
+ expect(result.content).toContain('skill: "app-builder"');
280
+ expect(existsSync(join(dir, "food-market-stats.html"))).toBe(false);
281
+ });
282
+
283
+ test("allows app-builder's thin shell index.html (external module script)", async () => {
284
+ const dir = makeTempDir();
285
+ const shell =
286
+ "<!doctype html><html><head>" +
287
+ "<link rel='stylesheet' href='/src/styles.css'>".padEnd(3200, " ") +
288
+ "</head><body><div id='app'></div>" +
289
+ "<script type='module' src='/src/main.tsx'></script></body></html>";
290
+
291
+ const result = await fileWriteTool.execute(
292
+ { path: "src/index.html", content: shell },
293
+ makeContext(dir),
294
+ );
295
+
296
+ expect(result.isError).toBe(false);
297
+ expect(existsSync(join(dir, "src", "index.html"))).toBe(true);
298
+ });
299
+
300
+ test("allows a small/static HTML snippet", async () => {
301
+ const dir = makeTempDir();
302
+ const result = await fileWriteTool.execute(
303
+ { path: "note.html", content: "<html><body><h1>Hi</h1></body></html>" },
304
+ makeContext(dir),
305
+ );
306
+
307
+ expect(result.isError).toBe(false);
308
+ expect(existsSync(join(dir, "note.html"))).toBe(true);
309
+ });
310
+
311
+ test("allows a non-HTML file even with inline script-like content", async () => {
312
+ const dir = makeTempDir();
313
+ const result = await fileWriteTool.execute(
314
+ {
315
+ path: "notes.md",
316
+ content:
317
+ "<script>" + "x".padEnd(2000, "x") + "</script>" + "\n# notes\n",
318
+ },
319
+ makeContext(dir),
320
+ );
321
+
322
+ expect(result.isError).toBe(false);
323
+ expect(existsSync(join(dir, "notes.md"))).toBe(true);
324
+ });
325
+ });
@@ -27,6 +27,7 @@ const ALLOWLIST = new Set([
27
27
  "clients/shared/App/Auth/PlatformOAuthService.swift", // comment explaining runtimeUrl vs platformUrl
28
28
  "clients/macos/vellum-assistant/App/AppDelegate.swift",
29
29
  "clients/macos/vellum-assistant/Features/Settings/SettingsConnectTab.swift",
30
+ "apps/macos/src/main/bundle-flow.ts", // Electron main calls the local gateway (gatewayPort) with a Guardian token to scan bundles
30
31
  ".claude/skills/update/SKILL.md", // daemon health check script
31
32
 
32
33
  // --- Test fixtures that poll the daemon directly (gateway may require auth) ---
@@ -84,12 +85,26 @@ function isGatewayInternal(filePath: string): boolean {
84
85
  return filePath.startsWith("gateway/");
85
86
  }
86
87
 
88
+ /** Additional files allowed for the interpolated-port check only (use gateway port, not runtime). */
89
+ const INTERPOLATED_PORT_ALLOWLIST = new Set([
90
+ "apps/macos/src/main/bundle-flow.ts",
91
+ // Electron main bridges the host proxy to a local assistant's gateway
92
+ // (gatewayPort) over loopback with a Guardian-minted gateway token — same
93
+ // class as bundle-flow.ts. Added with #34049 (host proxy for cloud/managed
94
+ // assistants); the allowlist entry was missed there.
95
+ "apps/macos/src/main/host-proxy-router.ts",
96
+ ]);
97
+
87
98
  /** Shared violation filter: exempt test files, gateway internals, and allowlisted paths. */
88
- function filterViolations(files: string[]): string[] {
99
+ function filterViolations(
100
+ files: string[],
101
+ extraAllowlist?: Set<string>,
102
+ ): string[] {
89
103
  return files.filter((f) => {
90
104
  if (isTestFile(f)) return false;
91
105
  if (isGatewayInternal(f)) return false;
92
106
  if (ALLOWLIST.has(f)) return false;
107
+ if (extraAllowlist?.has(f)) return false;
93
108
  return true;
94
109
  });
95
110
  }
@@ -181,7 +196,7 @@ describe("gateway-only API consumption guard", () => {
181
196
  }
182
197
 
183
198
  const files = grepOutput.split("\n").filter((f) => f.length > 0);
184
- const violations = filterViolations(files);
199
+ const violations = filterViolations(files, INTERPOLATED_PORT_ALLOWLIST);
185
200
 
186
201
  if (violations.length > 0) {
187
202
  const message = [
@@ -20,7 +20,7 @@ mock.module("../util/logger.js", () => ({
20
20
  }));
21
21
 
22
22
  const _conversationMocks = new Map<string, unknown>();
23
- mock.module("../daemon/conversation-store.js", () => ({
23
+ mock.module("../daemon/conversation-registry.js", () => ({
24
24
  findConversation: (id: string) => _conversationMocks.get(id),
25
25
  }));
26
26
 
@@ -21,7 +21,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
21
21
  mock.module("../config/env.js", () => ({ isHttpAuthDisabled: () => true }));
22
22
 
23
23
  const _conversationMocks = new Map<string, unknown>();
24
- mock.module("../daemon/conversation-store.js", () => ({
24
+ mock.module("../daemon/conversation-registry.js", () => ({
25
25
  findConversation: (id: string) => _conversationMocks.get(id),
26
26
  }));
27
27
 
@@ -51,9 +51,7 @@ import {
51
51
  routeGuardianReply,
52
52
  } from "../runtime/guardian-reply-router.js";
53
53
  import * as pendingInteractions from "../runtime/pending-interactions.js";
54
- import {
55
- listGuardianDecisionPrompts,
56
- } from "../runtime/routes/guardian-action-routes.js";
54
+ import { listGuardianDecisionPrompts } from "../runtime/routes/guardian-action-routes.js";
57
55
 
58
56
  initializeDb();
59
57
 
@@ -1334,6 +1332,97 @@ describe("routing invariant: callback buttons route through canonical primitive"
1334
1332
  });
1335
1333
  });
1336
1334
 
1335
+ // ===========================================================================
1336
+ // SECTION 8b: route-owned (directResolve) confirmations resolve via the
1337
+ // channel/guardian-action path too.
1338
+ //
1339
+ // The ACP spawn/steer approval gate (acp-routes.ts, ATL-822) registers
1340
+ // pending confirmations with a `directResolve` callback rather than a
1341
+ // Conversation.prompter. The tool_approval resolver must fire that callback
1342
+ // directly; otherwise a guardian approval submitted over a channel never
1343
+ // reaches the waiting route and the spawn/resume hangs until timeout.
1344
+ // ===========================================================================
1345
+
1346
+ describe("routing invariant: directResolve interactions resolve via guardian decisions", () => {
1347
+ beforeEach(() => resetTables());
1348
+
1349
+ function registerDirectResolveInteraction(
1350
+ requestId: string,
1351
+ conversationId: string,
1352
+ ): string[] {
1353
+ const decisions: string[] = [];
1354
+ pendingInteractions.register(requestId, {
1355
+ conversationId,
1356
+ kind: "confirmation",
1357
+ confirmationDetails: {
1358
+ toolName: "acp_spawn",
1359
+ input: { agent: "claude", task: "t", cwd: "/work" },
1360
+ riskLevel: "high",
1361
+ executionTarget: "host",
1362
+ allowlistOptions: [],
1363
+ scopeOptions: [],
1364
+ persistentDecisionsAllowed: false,
1365
+ },
1366
+ directResolve: (d) => decisions.push(d),
1367
+ });
1368
+ return decisions;
1369
+ }
1370
+
1371
+ test("channel approval fires directResolve('allow') with no live Conversation", async () => {
1372
+ const req = createCanonicalGuardianRequest({
1373
+ kind: "tool_approval",
1374
+ sourceType: "channel",
1375
+ conversationId: "conv-acp",
1376
+ guardianExternalUserId: "guardian-1",
1377
+ guardianPrincipalId: TEST_PRINCIPAL_ID,
1378
+ toolName: "acp_spawn",
1379
+ expiresAt: Date.now() + 60_000,
1380
+ });
1381
+ // Deliberately no _conversationMocks entry: the prompter path would have
1382
+ // failed with conversation_not_found, proving directResolve is what runs.
1383
+ const decisions = registerDirectResolveInteraction(req.id, "conv-acp");
1384
+
1385
+ const result = await routeGuardianReply(
1386
+ replyCtx({
1387
+ messageText: "",
1388
+ callbackData: `apr:${req.id}:approve_once`,
1389
+ conversationId: "conv-acp",
1390
+ }),
1391
+ );
1392
+
1393
+ expect(result.decisionApplied).toBe(true);
1394
+ expect(decisions).toEqual(["allow"]);
1395
+ expect(pendingInteractions.get(req.id)).toBeUndefined();
1396
+ expect(getCanonicalGuardianRequest(req.id)!.status).toBe("approved");
1397
+ });
1398
+
1399
+ test("channel rejection fires directResolve('deny')", async () => {
1400
+ const req = createCanonicalGuardianRequest({
1401
+ kind: "tool_approval",
1402
+ sourceType: "channel",
1403
+ conversationId: "conv-acp",
1404
+ guardianExternalUserId: "guardian-1",
1405
+ guardianPrincipalId: TEST_PRINCIPAL_ID,
1406
+ toolName: "acp_spawn",
1407
+ expiresAt: Date.now() + 60_000,
1408
+ });
1409
+ const decisions = registerDirectResolveInteraction(req.id, "conv-acp");
1410
+
1411
+ const result = await routeGuardianReply(
1412
+ replyCtx({
1413
+ messageText: "",
1414
+ callbackData: `apr:${req.id}:reject`,
1415
+ conversationId: "conv-acp",
1416
+ }),
1417
+ );
1418
+
1419
+ expect(result.decisionApplied).toBe(true);
1420
+ expect(decisions).toEqual(["deny"]);
1421
+ expect(pendingInteractions.get(req.id)).toBeUndefined();
1422
+ expect(getCanonicalGuardianRequest(req.id)!.status).toBe("denied");
1423
+ });
1424
+ });
1425
+
1337
1426
  // ===========================================================================
1338
1427
  // SECTION 9: Destination hints do not bypass principal binding for tool_approval
1339
1428
  // ===========================================================================
@@ -143,7 +143,7 @@ mock.module("../util/logger.js", () => ({
143
143
  import {
144
144
  clearConversations,
145
145
  setConversation,
146
- } from "../daemon/conversation-store.js";
146
+ } from "../daemon/conversation-registry.js";
147
147
  import { handleConfirmationResponse } from "../daemon/handlers/conversations.js";
148
148
 
149
149
  describe("handleConfirmationResponse canonical status sync", () => {
@@ -56,6 +56,7 @@ mock.module("../heartbeat/heartbeat-run-store.js", () => ({
56
56
  markStaleRunsAsMissed: mockMarkStaleRunsAsMissed,
57
57
  markStaleRunningAsError: mockMarkStaleRunningAsError,
58
58
  countCompletedHeartbeatRuns: mock(() => 10),
59
+ countCompletedRunsToday: mock(() => 0),
59
60
  countRecentConsecutiveRuns: mock(() => 0),
60
61
  }));
61
62
 
@@ -32,6 +32,7 @@ mock.module("../heartbeat/heartbeat-run-store.js", () => ({
32
32
  markStaleRunningAsError: mockMarkStaleRunningAsError,
33
33
  listHeartbeatRuns: mockListHeartbeatRuns,
34
34
  countCompletedHeartbeatRuns: mockCountCompletedHeartbeatRuns,
35
+ countCompletedRunsToday: mock(() => 0),
35
36
  countRecentConsecutiveRuns: mock(() => 0),
36
37
  }));
37
38
 
@@ -21,8 +21,8 @@ import type {
21
21
  UserPromptSubmitContext,
22
22
  } from "../plugin-api/types.js";
23
23
  import userPromptSubmit from "../plugins/defaults/history-repair/hooks/user-prompt-submit.js";
24
- import { defaultHistoryRepairPlugin } from "../plugins/defaults/history-repair/register.js";
25
24
  import { repairHistory } from "../plugins/defaults/history-repair/terminal.js";
25
+ import { defaultHistoryRepairPlugin } from "../plugins/defaults/index.js";
26
26
  import { runHook } from "../plugins/pipeline.js";
27
27
  import {
28
28
  registerPlugin,
@@ -40,6 +40,10 @@ const noopLogger: PluginLogger = {
40
40
  function makeCtx(messages: Message[]): UserPromptSubmitContext {
41
41
  return {
42
42
  conversationId: "conv-test",
43
+ userMessageId: "msg-test",
44
+ requestId: "req-test",
45
+ modelProfileKey: null,
46
+ isNonInteractive: false,
43
47
  prompt: "",
44
48
  originalMessages: messages,
45
49
  latestMessages: messages,
@@ -372,6 +372,49 @@ describe("HostAppControlProxy", () => {
372
372
  proxy.dispose();
373
373
  });
374
374
 
375
+ test("non-start tool with mismatched target client is rejected", async () => {
376
+ mockActorMap.set("client-A", "user-1");
377
+ mockActorMap.set("client-B", "user-1");
378
+ const proxy = new HostAppControlProxy("conv-1");
379
+ const startCtrl = new AbortController();
380
+
381
+ const pStart = proxy.request(
382
+ "app_control_start",
383
+ { tool: "start", app: "com.example.editor" },
384
+ "conv-1",
385
+ startCtrl.signal,
386
+ "user-1",
387
+ "client-A",
388
+ );
389
+ proxy.resolve(
390
+ (sentMessages[0] as Record<string, unknown>).requestId as string,
391
+ payload({ pngBase64: PNG_A }),
392
+ );
393
+ await pStart;
394
+ sentMessages.length = 0;
395
+
396
+ const result = await proxy.request(
397
+ "app_control_type",
398
+ {
399
+ tool: "type",
400
+ app: "com.example.editor",
401
+ text: "hello",
402
+ },
403
+ "conv-1",
404
+ new AbortController().signal,
405
+ "user-1",
406
+ "client-B",
407
+ );
408
+
409
+ expect(result.isError).toBe(true);
410
+ expect(result.content).toContain("client-A");
411
+ expect(result.content).toContain("client-B");
412
+ expect(result.content).toContain("app_control_start");
413
+ expect(sentMessages).toHaveLength(0);
414
+
415
+ proxy.dispose();
416
+ });
417
+
375
418
  test("non-start tool with case-different but otherwise matching app is allowed", async () => {
376
419
  const proxy = new HostAppControlProxy("conv-1");
377
420
  const startCtrl = new AbortController();
@@ -1297,6 +1340,7 @@ describe("HostAppControlProxy", () => {
1297
1340
  _setActiveAppControlSession({
1298
1341
  conversationId: "conv-1",
1299
1342
  app: "com.example.app",
1343
+ targetClientId: "client-A",
1300
1344
  });
1301
1345
 
1302
1346
  const resultPromise = proxy.request(
@@ -1332,6 +1376,7 @@ describe("HostAppControlProxy", () => {
1332
1376
  _setActiveAppControlSession({
1333
1377
  conversationId: "conv-1",
1334
1378
  app: "com.example.app",
1379
+ targetClientId: "client-A",
1335
1380
  });
1336
1381
 
1337
1382
  const resultPromise = proxy.request(
@@ -47,7 +47,7 @@ interface FakeConversation {
47
47
 
48
48
  const conversations = new Map<string, FakeConversation>();
49
49
 
50
- mock.module("../daemon/conversation-store.js", () => ({
50
+ mock.module("../daemon/conversation-registry.js", () => ({
51
51
  findConversation: (id: string) => conversations.get(id),
52
52
  }));
53
53