@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
@@ -1,962 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import {
4
- conversationMessagesSyncTag,
5
- SYNC_TAGS,
6
- } from "../daemon/message-types/sync.js";
7
-
8
- // ── Mock state ──────────────────────────────────────────────────────────
9
-
10
- // Provider mock
11
- let decisionProviderAvailable = true;
12
- let buildProviderAvailable = true;
13
- let decisionResponse = "";
14
- let buildResponse = "";
15
- let copyResponse = "";
16
- let providerSendCalls: Array<{ callSite: string; messages: unknown[] }> = [];
17
-
18
- const mockProvider = (callSite: string) => ({
19
- name: "mock-provider",
20
- sendMessage: async (messages: unknown[]) => {
21
- providerSendCalls.push({ callSite, messages });
22
- if (callSite === "proactiveArtifactDecision") {
23
- return { content: [{ type: "text", text: decisionResponse }] };
24
- }
25
- if (callSite === "proactiveArtifactBuild") {
26
- // copyResponse is used when it's for message copy (second call)
27
- const isCopyCall = providerSendCalls.filter(
28
- (c) => c.callSite === "proactiveArtifactBuild",
29
- ).length;
30
- if (isCopyCall > 1) {
31
- return { content: [{ type: "text", text: copyResponse }] };
32
- }
33
- return { content: [{ type: "text", text: buildResponse }] };
34
- }
35
- return { content: [{ type: "text", text: "" }] };
36
- },
37
- });
38
-
39
- mock.module("../providers/provider-send-message.js", () => ({
40
- getConfiguredProvider: async (callSite: string) => {
41
- if (
42
- callSite === "proactiveArtifactDecision" &&
43
- !decisionProviderAvailable
44
- ) {
45
- return null;
46
- }
47
- if (callSite === "proactiveArtifactBuild" && !buildProviderAvailable) {
48
- return null;
49
- }
50
- return mockProvider(callSite);
51
- },
52
- extractText: (response: { content: Array<{ type: string; text: string }> }) =>
53
- response.content.find((b: { type: string }) => b.type === "text")?.text ??
54
- "",
55
- }));
56
-
57
- // rawAll mock
58
- let rawAllRows: Array<{ role: string; content: string }> = [];
59
- let rawAllLastSql = "";
60
- let rawAllLastArgs: unknown[] = [];
61
-
62
- mock.module("../memory/raw-query.js", () => ({
63
- rawAll: (sql: string, ...args: unknown[]) => {
64
- rawAllLastSql = sql;
65
- rawAllLastArgs = args;
66
- return rawAllRows;
67
- },
68
- rawRun: () => 0,
69
- }));
70
-
71
- // bootstrapConversation mock
72
- let bootstrapCalls: Array<Record<string, unknown>> = [];
73
-
74
- mock.module("../memory/conversation-bootstrap.js", () => ({
75
- bootstrapConversation: (opts: Record<string, unknown>) => {
76
- bootstrapCalls.push(opts);
77
- return { id: `bg-conv-${bootstrapCalls.length}` };
78
- },
79
- }));
80
-
81
- // processMessage mock
82
- let processMessageCalls: Array<{
83
- conversationId: string;
84
- prompt: string;
85
- options: unknown;
86
- }> = [];
87
- let processMessageShouldThrow = false;
88
-
89
- mock.module("../daemon/process-message.js", () => ({
90
- processMessage: async (
91
- conversationId: string,
92
- prompt: string,
93
- options: unknown,
94
- ) => {
95
- processMessageCalls.push({ conversationId, prompt, options });
96
- if (processMessageShouldThrow) {
97
- throw new Error("processMessage failed");
98
- }
99
- return { messageId: "pm-msg-1" };
100
- },
101
- }));
102
-
103
- // App store mock
104
- let mockApps: Array<{
105
- id: string;
106
- name: string;
107
- createdAt: number;
108
- updatedAt?: number;
109
- conversationIds?: string[];
110
- }> = [];
111
- let addAppConvCalls: Array<{ appId: string; conversationId: string }> = [];
112
-
113
- mock.module("../memory/app-store.js", () => ({
114
- listApps: () => mockApps,
115
- listAppsByConversation: (conversationId: string) =>
116
- mockApps.filter((app) => app.conversationIds?.includes(conversationId)),
117
- addAppConversationId: (appId: string, conversationId: string) => {
118
- addAppConvCalls.push({ appId, conversationId });
119
- return true;
120
- },
121
- }));
122
-
123
- // Document store mock
124
- let saveDocumentCalls: Array<Record<string, unknown>> = [];
125
- let saveDocumentResult: {
126
- success: boolean;
127
- surfaceId?: string;
128
- error?: string;
129
- } = {
130
- success: true,
131
- surfaceId: "doc-123",
132
- };
133
- let addDocConvCalls: Array<{ surfaceId: string; conversationId: string }> = [];
134
-
135
- mock.module("../documents/document-store.js", () => ({
136
- saveDocument: (params: Record<string, unknown>) => {
137
- saveDocumentCalls.push(params);
138
- return saveDocumentResult;
139
- },
140
- addDocumentConversation: (surfaceId: string, conversationId: string) => {
141
- addDocConvCalls.push({ surfaceId, conversationId });
142
- },
143
- }));
144
-
145
- // addMessage mock
146
- let addMessageCalls: Array<{
147
- conversationId: string;
148
- role: string;
149
- content: string;
150
- options: unknown;
151
- }> = [];
152
-
153
- mock.module("../memory/conversation-crud.js", () => ({
154
- addMessage: async (
155
- conversationId: string,
156
- role: string,
157
- content: string,
158
- options: unknown,
159
- ) => {
160
- addMessageCalls.push({ conversationId, role, content, options });
161
- return { id: `msg-${addMessageCalls.length}` };
162
- },
163
- reserveMessage: mock(async () => ({ id: "msg-reserve" })),
164
- }));
165
-
166
- // emitNotificationSignal mock
167
- let emitSignalCalls: Array<Record<string, unknown>> = [];
168
-
169
- mock.module("../notifications/emit-signal.js", () => ({
170
- emitNotificationSignal: async (params: Record<string, unknown>) => {
171
- emitSignalCalls.push(params);
172
- return {
173
- signalId: "signal-1",
174
- deduplicated: false,
175
- dispatched: true,
176
- reason: "ok",
177
- deliveryResults: [],
178
- };
179
- },
180
- }));
181
-
182
- // app sync invalidation mock
183
- let publishAppsChangedCalls: Array<string | undefined> = [];
184
-
185
- mock.module("../runtime/sync/resource-sync-events.js", () => ({
186
- publishAppsChanged: (originClientId?: string) => {
187
- publishAppsChangedCalls.push(originClientId);
188
- },
189
- }));
190
-
191
- // findConversation mock
192
- type MockConversation = {
193
- isProcessing(): boolean;
194
- messages: unknown[];
195
- getMessages: () => unknown[];
196
- };
197
- let mockConversations: Map<string, MockConversation> = new Map();
198
-
199
- mock.module("../daemon/conversation-store.js", () => ({
200
- findConversation: (id: string) => mockConversations.get(id),
201
- }));
202
-
203
- // createAssistantMessage mock
204
- mock.module("../agent/message-types.js", () => ({
205
- createAssistantMessage: (text: string) => ({
206
- role: "assistant",
207
- content: [{ type: "text", text }],
208
- }),
209
- }));
210
-
211
- // Trigger state mock
212
- let releaseClaimCalls = 0;
213
-
214
- mock.module("./trigger-state.js", () => ({
215
- releaseProactiveArtifactClaim: () => {
216
- releaseClaimCalls++;
217
- },
218
- }));
219
-
220
- // Trust context mock
221
- mock.module("../daemon/trust-context.js", () => ({
222
- INTERNAL_GUARDIAN_TRUST_CONTEXT: {
223
- sourceChannel: "vellum",
224
- trustClass: "guardian",
225
- },
226
- }));
227
-
228
- // Logger mock
229
- let logWarnCalls: Array<{ args: unknown[] }> = [];
230
-
231
- mock.module("../util/logger.js", () => ({
232
- getLogger: () => ({
233
- info: () => {},
234
- warn: (...args: unknown[]) => {
235
- logWarnCalls.push({ args });
236
- },
237
- error: () => {},
238
- debug: () => {},
239
- }),
240
- }));
241
-
242
- // uuid mock — deterministic IDs for testing
243
- let uuidCounter = 0;
244
- mock.module("uuid", () => ({
245
- v4: () => `test-uuid-${++uuidCounter}`,
246
- }));
247
-
248
- // ── Import SUT after mocks ─────────────────────────────────────────────
249
-
250
- const { runProactiveArtifactJob } = await import("./job.js");
251
- const { injectAuxAssistantMessage } = await import("./aux-message-injector.js");
252
- const {
253
- buildMessageCopyPrompt,
254
- ensureMessageMentionsLibraryLocation,
255
- parseMessageCopy,
256
- } = await import("./message-copy.js");
257
-
258
- // ── Test helpers ────────────────────────────────────────────────────────
259
-
260
- let broadcastCalls: Array<Record<string, unknown>> = [];
261
- const mockBroadcast: any = (msg: Record<string, unknown>) => {
262
- broadcastCalls.push(msg);
263
- };
264
-
265
- const defaultTranscript = [
266
- { role: "user", content: "Hello there" },
267
- { role: "assistant", content: "Hi! How can I help?" },
268
- { role: "user", content: "I need a budget tracker" },
269
- { role: "assistant", content: "I can help with that." },
270
- { role: "user", content: "I spend about $3000 per month" },
271
- { role: "assistant", content: "Got it, that is useful context." },
272
- { role: "user", content: "Yes, let us track groceries and rent" },
273
- {
274
- role: "assistant",
275
- content: "Great, I will remember those categories.",
276
- },
277
- ];
278
-
279
- const decisionYesApp = `SHOULD_BUILD: yes
280
- ARTIFACT_TYPE: app
281
- ARTIFACT_TITLE: Budget Tracker
282
- ARTIFACT_DESCRIPTION: A budget tracking app for monthly expenses around $3000, focusing on groceries and rent.`;
283
-
284
- const decisionYesDocument = `SHOULD_BUILD: yes
285
- ARTIFACT_TYPE: document
286
- ARTIFACT_TITLE: Monthly Budget Guide
287
- ARTIFACT_DESCRIPTION: A structured guide for tracking monthly expenses with categories for groceries and rent.`;
288
-
289
- const decisionNo = `SHOULD_BUILD: no
290
- SKIP_REASON: Not enough context to build something specific.`;
291
-
292
- function resetState() {
293
- decisionProviderAvailable = true;
294
- buildProviderAvailable = true;
295
- decisionResponse = "";
296
- buildResponse = "";
297
- copyResponse = "";
298
- providerSendCalls = [];
299
- rawAllRows = [];
300
- rawAllLastSql = "";
301
- rawAllLastArgs = [];
302
- bootstrapCalls = [];
303
- processMessageCalls = [];
304
- processMessageShouldThrow = false;
305
- mockApps = [];
306
- addAppConvCalls = [];
307
- saveDocumentCalls = [];
308
- saveDocumentResult = { success: true, surfaceId: "doc-123" };
309
- addDocConvCalls = [];
310
- releaseClaimCalls = 0;
311
- addMessageCalls = [];
312
- emitSignalCalls = [];
313
- publishAppsChangedCalls = [];
314
- broadcastCalls = [];
315
- mockConversations = new Map();
316
- logWarnCalls = [];
317
- uuidCounter = 0;
318
- }
319
-
320
- // ── Tests ───────────────────────────────────────────────────────────────
321
-
322
- beforeEach(() => {
323
- resetState();
324
- });
325
-
326
- afterEach(() => {
327
- resetState();
328
- });
329
-
330
- describe("runProactiveArtifactJob", () => {
331
- describe("Phase 1 — Decision", () => {
332
- test("shouldBuild:false → releases claim, no Phase 2", async () => {
333
- rawAllRows = defaultTranscript;
334
- decisionResponse = decisionNo;
335
-
336
- await runProactiveArtifactJob({
337
- conversationId: "conv-1",
338
- userMessageCutoff: 1000,
339
- assistantMessageId: "msg-4",
340
- broadcastMessage: mockBroadcast,
341
- });
342
-
343
- expect(releaseClaimCalls).toBe(1);
344
- expect(bootstrapCalls).toHaveLength(0);
345
- expect(processMessageCalls).toHaveLength(0);
346
- expect(addMessageCalls).toHaveLength(0);
347
- expect(emitSignalCalls).toHaveLength(0);
348
- expect(broadcastCalls).toHaveLength(0);
349
- });
350
-
351
- test("null (malformed) → releases claim, silent exit", async () => {
352
- rawAllRows = defaultTranscript;
353
- decisionResponse = "THIS IS GARBAGE OUTPUT";
354
-
355
- await runProactiveArtifactJob({
356
- conversationId: "conv-1",
357
- userMessageCutoff: 1000,
358
- assistantMessageId: "msg-4",
359
- broadcastMessage: mockBroadcast,
360
- });
361
-
362
- expect(releaseClaimCalls).toBe(1);
363
- expect(bootstrapCalls).toHaveLength(0);
364
- expect(processMessageCalls).toHaveLength(0);
365
- expect(addMessageCalls).toHaveLength(0);
366
- expect(emitSignalCalls).toHaveLength(0);
367
- });
368
-
369
- test("provider unavailable → releases claim, silent return", async () => {
370
- rawAllRows = defaultTranscript;
371
- decisionProviderAvailable = false;
372
-
373
- await runProactiveArtifactJob({
374
- conversationId: "conv-1",
375
- userMessageCutoff: 1000,
376
- assistantMessageId: "msg-4",
377
- broadcastMessage: mockBroadcast,
378
- });
379
-
380
- expect(releaseClaimCalls).toBe(1);
381
- expect(providerSendCalls).toHaveLength(0);
382
- expect(bootstrapCalls).toHaveLength(0);
383
- expect(addMessageCalls).toHaveLength(0);
384
- expect(emitSignalCalls).toHaveLength(0);
385
- });
386
- });
387
-
388
- describe("Phase 2 — Build", () => {
389
- test("Phase 2 failure → releases claim, no message, no notification", async () => {
390
- rawAllRows = defaultTranscript;
391
- decisionResponse = decisionYesApp;
392
- processMessageShouldThrow = true;
393
-
394
- await runProactiveArtifactJob({
395
- conversationId: "conv-1",
396
- userMessageCutoff: 1000,
397
- assistantMessageId: "msg-4",
398
- broadcastMessage: mockBroadcast,
399
- });
400
-
401
- // processMessage was called (the build attempt happened)
402
- expect(processMessageCalls).toHaveLength(1);
403
- // But no message injection or notification
404
- expect(addMessageCalls).toHaveLength(0);
405
- expect(emitSignalCalls).toHaveLength(0);
406
- expect(broadcastCalls).toHaveLength(0);
407
- // Claim released so next turn can retry
408
- expect(releaseClaimCalls).toBe(1);
409
- });
410
-
411
- test("successful app: Phase 1 → Phase 2 → app store query → message copy → inject → notify", async () => {
412
- rawAllRows = defaultTranscript;
413
- decisionResponse = decisionYesApp;
414
- copyResponse = "MESSAGE: I built a budget tracker for you!";
415
-
416
- const buildStartedAt = Date.now();
417
- mockApps = [
418
- {
419
- id: "app-123",
420
- name: "Budget Tracker",
421
- createdAt: buildStartedAt + 100,
422
- updatedAt: buildStartedAt + 100,
423
- },
424
- ];
425
-
426
- // Set up an idle conversation so injection works fully
427
- const convMessages: unknown[] = [];
428
- mockConversations.set("conv-1", {
429
- isProcessing: () => false,
430
- messages: convMessages,
431
- getMessages: () => convMessages,
432
- });
433
-
434
- await runProactiveArtifactJob({
435
- conversationId: "conv-1",
436
- userMessageCutoff: 1000,
437
- assistantMessageId: "msg-4",
438
- broadcastMessage: mockBroadcast,
439
- });
440
-
441
- // Phase 1: decision provider called
442
- expect(
443
- providerSendCalls.some(
444
- (c) => c.callSite === "proactiveArtifactDecision",
445
- ),
446
- ).toBe(true);
447
-
448
- // Phase 2: processMessage called with correct options
449
- expect(processMessageCalls).toHaveLength(1);
450
- expect(processMessageCalls[0].prompt).toContain("Budget Tracker");
451
- expect(processMessageCalls[0].prompt).toContain("auto_open: false");
452
- const pmOpts = processMessageCalls[0].options as Record<string, unknown>;
453
- expect(pmOpts.callSite).toBe("proactiveArtifactBuild");
454
- expect(pmOpts.trustContext).toEqual({
455
- sourceChannel: "vellum",
456
- trustClass: "guardian",
457
- });
458
-
459
- // Bootstrap conversation created for app build
460
- expect(bootstrapCalls).toHaveLength(1);
461
- expect(bootstrapCalls[0].conversationType).toBe("background");
462
- expect(bootstrapCalls[0].source).toBe("proactive_artifact");
463
-
464
- // App associated with user's conversation for existing artifact linkage
465
- expect(addAppConvCalls).toHaveLength(1);
466
- expect(addAppConvCalls[0].appId).toBe("app-123");
467
- expect(addAppConvCalls[0].conversationId).toBe("conv-1");
468
-
469
- expect(broadcastCalls).toContainEqual({
470
- type: "app_files_changed",
471
- appId: "app-123",
472
- });
473
- expect(publishAppsChangedCalls).toEqual([undefined]);
474
-
475
- // Message injection: addMessage called with skipIndexing
476
- expect(addMessageCalls).toHaveLength(1);
477
- expect(
478
- (addMessageCalls[0].options as Record<string, unknown>).skipIndexing,
479
- ).toBe(true);
480
- expect(addMessageCalls[0].conversationId).toBe("conv-1");
481
- const injectedAppContent = JSON.parse(addMessageCalls[0].content);
482
- expect(injectedAppContent[0].text).toContain("Library");
483
- expect(injectedAppContent[0].text).not.toContain("Assets");
484
-
485
- // Notification emitted
486
- expect(emitSignalCalls).toHaveLength(1);
487
- expect(emitSignalCalls[0].sourceEventName).toBe("activity.complete");
488
- expect(emitSignalCalls[0].sourceChannel).toBe("vellum");
489
- expect(emitSignalCalls[0].dedupeKey).toBe("proactive-artifact");
490
- const hints = emitSignalCalls[0].attentionHints as Record<
491
- string,
492
- unknown
493
- >;
494
- expect(hints.visibleInSourceNow).toBe(false);
495
- expect(hints.isAsyncBackground).toBe(true);
496
- expect(hints.requiresAction).toBe(false);
497
- // No conversationAffinityHint
498
- expect(emitSignalCalls[0].conversationAffinityHint).toBeUndefined();
499
-
500
- // Claim NOT released on success — guard stays permanent
501
- expect(releaseClaimCalls).toBe(0);
502
- });
503
-
504
- test("successful document: Phase 1 → content gen → saveDocument → message copy → inject → notify", async () => {
505
- rawAllRows = defaultTranscript;
506
- decisionResponse = decisionYesDocument;
507
- buildResponse =
508
- "# Monthly Budget Guide\n\nTrack groceries and rent expenses.";
509
- copyResponse =
510
- "MESSAGE: I created a monthly budget guide tailored to your needs.";
511
-
512
- mockConversations.set("conv-1", {
513
- isProcessing: () => false,
514
- messages: [],
515
- getMessages: () => [],
516
- });
517
-
518
- await runProactiveArtifactJob({
519
- conversationId: "conv-1",
520
- userMessageCutoff: 1000,
521
- assistantMessageId: "msg-4",
522
- broadcastMessage: mockBroadcast,
523
- });
524
-
525
- // Document saved via saveDocument (not raw file writes)
526
- expect(saveDocumentCalls).toHaveLength(1);
527
- expect(saveDocumentCalls[0].title).toBe("Monthly Budget Guide");
528
- expect(saveDocumentCalls[0].conversationId).toBe("conv-1");
529
- expect(saveDocumentCalls[0].content).toContain("Monthly Budget Guide");
530
- expect(
531
- (saveDocumentCalls[0].surfaceId as string).startsWith("doc-"),
532
- ).toBe(true);
533
- expect((saveDocumentCalls[0].wordCount as number) > 0).toBe(true);
534
-
535
- // No bootstrapConversation or processMessage for document path
536
- expect(bootstrapCalls).toHaveLength(0);
537
- expect(processMessageCalls).toHaveLength(0);
538
-
539
- // Message injection and notification
540
- expect(addMessageCalls).toHaveLength(1);
541
- const injectedDocumentContent = JSON.parse(addMessageCalls[0].content);
542
- expect(injectedDocumentContent[0].text).toContain("Library");
543
- expect(injectedDocumentContent[0].text).not.toContain("Assets");
544
- expect(emitSignalCalls).toHaveLength(1);
545
-
546
- // Claim NOT released on success
547
- expect(releaseClaimCalls).toBe(0);
548
- });
549
-
550
- test("app build - no matching app found → releases claim for retry", async () => {
551
- rawAllRows = defaultTranscript;
552
- decisionResponse = decisionYesApp;
553
- mockApps = []; // no apps in store
554
-
555
- await runProactiveArtifactJob({
556
- conversationId: "conv-1",
557
- userMessageCutoff: 1000,
558
- assistantMessageId: "msg-4",
559
- broadcastMessage: mockBroadcast,
560
- });
561
-
562
- expect(processMessageCalls).toHaveLength(1);
563
- expect(addMessageCalls).toHaveLength(0);
564
- expect(emitSignalCalls).toHaveLength(0);
565
- expect(releaseClaimCalls).toBe(1);
566
- });
567
-
568
- test("app decision with foreground app tool suppresses background build permanently", async () => {
569
- rawAllRows = defaultTranscript;
570
- decisionResponse = decisionYesApp;
571
-
572
- await runProactiveArtifactJob({
573
- conversationId: "conv-1",
574
- userMessageCutoff: 1000,
575
- assistantMessageId: "msg-4",
576
- suppressAppBuild: true,
577
- broadcastMessage: mockBroadcast,
578
- });
579
-
580
- expect(bootstrapCalls).toHaveLength(0);
581
- expect(processMessageCalls).toHaveLength(0);
582
- expect(addMessageCalls).toHaveLength(0);
583
- expect(emitSignalCalls).toHaveLength(0);
584
- expect(releaseClaimCalls).toBe(0);
585
- });
586
-
587
- test("app decision with recent app activity in source conversation suppresses background build permanently", async () => {
588
- rawAllRows = defaultTranscript;
589
- decisionResponse = decisionYesApp;
590
- mockApps = [
591
- {
592
- id: "app-main",
593
- name: "Budget Tracker",
594
- createdAt: 1200,
595
- updatedAt: 1300,
596
- conversationIds: ["conv-1"],
597
- },
598
- ];
599
-
600
- await runProactiveArtifactJob({
601
- conversationId: "conv-1",
602
- userMessageCutoff: 1000,
603
- assistantMessageId: "msg-4",
604
- broadcastMessage: mockBroadcast,
605
- });
606
-
607
- expect(bootstrapCalls).toHaveLength(0);
608
- expect(processMessageCalls).toHaveLength(0);
609
- expect(addMessageCalls).toHaveLength(0);
610
- expect(emitSignalCalls).toHaveLength(0);
611
- expect(releaseClaimCalls).toBe(0);
612
- });
613
-
614
- test("document build - build provider unavailable → releases claim for retry", async () => {
615
- rawAllRows = defaultTranscript;
616
- decisionResponse = decisionYesDocument;
617
- buildProviderAvailable = false;
618
-
619
- await runProactiveArtifactJob({
620
- conversationId: "conv-1",
621
- userMessageCutoff: 1000,
622
- assistantMessageId: "msg-4",
623
- broadcastMessage: mockBroadcast,
624
- });
625
-
626
- // No message, no notification
627
- expect(addMessageCalls).toHaveLength(0);
628
- expect(emitSignalCalls).toHaveLength(0);
629
- expect(releaseClaimCalls).toBe(1);
630
- });
631
- });
632
-
633
- describe("Message copy", () => {
634
- test("uses fallback message when copy provider unavailable", async () => {
635
- rawAllRows = defaultTranscript;
636
- decisionResponse = decisionYesApp;
637
- // Build provider is unavailable for copy step, but we need it for
638
- // the copy call. Since the same callSite is used, we'll test the
639
- // fallback by making the copy return unparseable output.
640
- buildProviderAvailable = true;
641
- copyResponse = "INVALID OUTPUT WITHOUT MESSAGE PREFIX";
642
-
643
- const buildTime = Date.now();
644
- mockApps = [
645
- { id: "app-456", name: "Budget Tracker", createdAt: buildTime + 50 },
646
- ];
647
-
648
- mockConversations.set("conv-1", {
649
- isProcessing: () => false,
650
- messages: [],
651
- getMessages: () => [],
652
- });
653
-
654
- await runProactiveArtifactJob({
655
- conversationId: "conv-1",
656
- userMessageCutoff: 1000,
657
- assistantMessageId: "msg-4",
658
- broadcastMessage: mockBroadcast,
659
- });
660
-
661
- // Verify fallback message was used
662
- expect(addMessageCalls).toHaveLength(1);
663
- const content = JSON.parse(addMessageCalls[0].content);
664
- expect(content[0].text).toContain("I made an app for you");
665
- expect(content[0].text).toContain("Budget Tracker");
666
- expect(content[0].text).toContain("Library");
667
- expect(content[0].text).not.toContain("Assets");
668
- });
669
- });
670
-
671
- describe("Transcript collection", () => {
672
- test("transcript query is scoped to the triggering conversation", async () => {
673
- rawAllRows = defaultTranscript;
674
- decisionResponse = decisionNo;
675
-
676
- await runProactiveArtifactJob({
677
- conversationId: "conv-1",
678
- userMessageCutoff: 5000,
679
- assistantMessageId: "asst-msg-99",
680
- broadcastMessage: mockBroadcast,
681
- });
682
-
683
- expect(rawAllLastSql).toContain("AND m.conversation_id = ?");
684
- expect(rawAllLastArgs).toEqual(["conv-1", 5000, "asst-msg-99"]);
685
- expect(
686
- providerSendCalls.some(
687
- (c) => c.callSite === "proactiveArtifactDecision",
688
- ),
689
- ).toBe(true);
690
- });
691
-
692
- test("empty transcript → early return", async () => {
693
- rawAllRows = [];
694
-
695
- await runProactiveArtifactJob({
696
- conversationId: "conv-1",
697
- userMessageCutoff: 1000,
698
- assistantMessageId: "msg-4",
699
- broadcastMessage: mockBroadcast,
700
- });
701
-
702
- expect(releaseClaimCalls).toBe(1);
703
- expect(providerSendCalls).toHaveLength(0);
704
- expect(addMessageCalls).toHaveLength(0);
705
- });
706
- });
707
- });
708
-
709
- describe("injectAuxAssistantMessage", () => {
710
- test("idle conversation: persists with skipIndexing, pushes to getMessages(), broadcasts delta + complete(aux) + list sync", async () => {
711
- const messages: unknown[] = [];
712
- mockConversations.set("conv-inject-1", {
713
- isProcessing: () => false,
714
- messages,
715
- getMessages: () => messages,
716
- });
717
-
718
- await injectAuxAssistantMessage({
719
- conversationId: "conv-inject-1",
720
- text: "Here is your artifact!",
721
- broadcastMessage: mockBroadcast,
722
- });
723
-
724
- // Persisted with skipIndexing
725
- expect(addMessageCalls).toHaveLength(1);
726
- expect(addMessageCalls[0].conversationId).toBe("conv-inject-1");
727
- expect(addMessageCalls[0].role).toBe("assistant");
728
- expect(
729
- (addMessageCalls[0].options as Record<string, unknown>).skipIndexing,
730
- ).toBe(true);
731
-
732
- // Pushed to in-memory messages
733
- expect(messages).toHaveLength(1);
734
-
735
- // Broadcasts: delta, complete(aux), list invalidation + sync tag
736
- const deltaMsg = broadcastCalls.find(
737
- (c) => c.type === "assistant_text_delta",
738
- );
739
- expect(deltaMsg).toBeDefined();
740
- expect(deltaMsg!.text).toBe("Here is your artifact!");
741
- expect(deltaMsg!.conversationId).toBe("conv-inject-1");
742
-
743
- const completeMsg = broadcastCalls.find(
744
- (c) => c.type === "message_complete",
745
- );
746
- expect(completeMsg).toBeDefined();
747
- expect(completeMsg!.source).toBe("aux");
748
- expect(completeMsg!.messageId).toBeDefined();
749
-
750
- const listMsg = broadcastCalls.find(
751
- (c) => c.type === "conversation_list_invalidated",
752
- );
753
- expect(listMsg).toBeDefined();
754
- expect(listMsg!.reason).toBe("reordered");
755
-
756
- const syncMsg = broadcastCalls.find((c) => c.type === "sync_changed");
757
- expect(syncMsg).toEqual({
758
- type: "sync_changed",
759
- tags: [
760
- SYNC_TAGS.conversationsList,
761
- conversationMessagesSyncTag("conv-inject-1"),
762
- ],
763
- });
764
- });
765
-
766
- test("processing → idle: waits for processing to become false before persisting", async () => {
767
- const messages: unknown[] = [];
768
- let processingFlag = true;
769
- const conv: MockConversation = {
770
- isProcessing: () => processingFlag,
771
- messages,
772
- getMessages: () => messages,
773
- };
774
- mockConversations.set("conv-inject-2", conv);
775
-
776
- // Simulate processing becoming idle after a short delay
777
- setTimeout(() => {
778
- processingFlag = false;
779
- }, 100);
780
-
781
- await injectAuxAssistantMessage({
782
- conversationId: "conv-inject-2",
783
- text: "Deferred message",
784
- broadcastMessage: mockBroadcast,
785
- });
786
-
787
- // Should have waited and then injected
788
- expect(addMessageCalls).toHaveLength(1);
789
- expect(messages).toHaveLength(1);
790
- expect(broadcastCalls.some((c) => c.type === "assistant_text_delta")).toBe(
791
- true,
792
- );
793
- });
794
-
795
- test("processing → timeout: injects anyway with warning after poll timeout", async () => {
796
- const messages: unknown[] = [];
797
- // Conversation stays processing permanently — never becomes idle
798
- const conv: MockConversation = {
799
- isProcessing: () => true,
800
- messages,
801
- getMessages: () => messages,
802
- };
803
- mockConversations.set("conv-inject-3", conv);
804
-
805
- // Mock Date.now() to simulate time past the 60s timeout.
806
- // First call sets `start`, second call must exceed IDLE_TIMEOUT_MS (60_000).
807
- const realDateNow = Date.now;
808
- let dateNowCallCount = 0;
809
- const baseTime = 1_000_000;
810
- Date.now = () => {
811
- dateNowCallCount++;
812
- // First call: start = baseTime
813
- // Second call onward: past the timeout
814
- if (dateNowCallCount <= 1) return baseTime;
815
- return baseTime + 60_001;
816
- };
817
-
818
- try {
819
- await injectAuxAssistantMessage({
820
- conversationId: "conv-inject-3",
821
- text: "Timeout message",
822
- broadcastMessage: mockBroadcast,
823
- });
824
- } finally {
825
- Date.now = realDateNow;
826
- }
827
-
828
- // Message was still persisted despite timeout
829
- expect(addMessageCalls).toHaveLength(1);
830
- expect(addMessageCalls[0].conversationId).toBe("conv-inject-3");
831
-
832
- // Warning log was emitted about the timeout
833
- expect(logWarnCalls.length).toBeGreaterThanOrEqual(1);
834
- const warnMsg = logWarnCalls.find((c) =>
835
- c.args.some(
836
- (arg) => typeof arg === "string" && arg.includes("Timed out"),
837
- ),
838
- );
839
- expect(warnMsg).toBeDefined();
840
-
841
- // Since conversation is still processing, no delta/complete broadcasts
842
- expect(
843
- broadcastCalls.filter((c) => c.type === "assistant_text_delta"),
844
- ).toHaveLength(0);
845
- expect(
846
- broadcastCalls.filter((c) => c.type === "message_complete"),
847
- ).toHaveLength(0);
848
-
849
- // But list invalidation + sync tag ARE sent regardless of processing state.
850
- expect(
851
- broadcastCalls.filter((c) => c.type === "conversation_list_invalidated"),
852
- ).toHaveLength(1);
853
- expect(broadcastCalls.filter((c) => c.type === "sync_changed")).toEqual([
854
- {
855
- type: "sync_changed",
856
- tags: [
857
- SYNC_TAGS.conversationsList,
858
- conversationMessagesSyncTag("conv-inject-3"),
859
- ],
860
- },
861
- ]);
862
- });
863
-
864
- test("inactive/unloaded conversation: persists + list sync only", async () => {
865
- // No conversation in the store
866
- await injectAuxAssistantMessage({
867
- conversationId: "conv-inject-4",
868
- text: "Offline message",
869
- broadcastMessage: mockBroadcast,
870
- });
871
-
872
- // Message persisted
873
- expect(addMessageCalls).toHaveLength(1);
874
- expect(addMessageCalls[0].conversationId).toBe("conv-inject-4");
875
-
876
- // No delta or complete (conversation not loaded)
877
- expect(
878
- broadcastCalls.filter((c) => c.type === "assistant_text_delta"),
879
- ).toHaveLength(0);
880
- expect(
881
- broadcastCalls.filter((c) => c.type === "message_complete"),
882
- ).toHaveLength(0);
883
-
884
- // But list invalidation + sync tag ARE sent
885
- expect(
886
- broadcastCalls.filter((c) => c.type === "conversation_list_invalidated"),
887
- ).toHaveLength(1);
888
- expect(broadcastCalls.filter((c) => c.type === "sync_changed")).toEqual([
889
- {
890
- type: "sync_changed",
891
- tags: [
892
- SYNC_TAGS.conversationsList,
893
- conversationMessagesSyncTag("conv-inject-4"),
894
- ],
895
- },
896
- ]);
897
- });
898
- });
899
-
900
- describe("message-copy", () => {
901
- test("buildMessageCopyPrompt includes all parameters", () => {
902
- const prompt = buildMessageCopyPrompt({
903
- artifactType: "app",
904
- artifactTitle: "Budget Tracker",
905
- artifactId: "app-123",
906
- transcript: "[User]: I need a budget tool",
907
- });
908
-
909
- expect(prompt).toContain("app");
910
- expect(prompt).toContain("Budget Tracker");
911
- expect(prompt).toContain("app-123");
912
- expect(prompt).toContain("I need a budget tool");
913
- expect(prompt).toContain("Library");
914
- expect(prompt).not.toContain("Assets pill");
915
- expect(prompt).toContain("MESSAGE:");
916
- });
917
-
918
- test("parseMessageCopy extracts MESSAGE value", () => {
919
- expect(parseMessageCopy("MESSAGE: Hello there!")).toBe("Hello there!");
920
- expect(
921
- parseMessageCopy("MESSAGE: I built something special for you."),
922
- ).toBe("I built something special for you.");
923
- });
924
-
925
- test("parseMessageCopy returns null for missing MESSAGE", () => {
926
- expect(parseMessageCopy("Some random text")).toBeNull();
927
- expect(parseMessageCopy("")).toBeNull();
928
- });
929
-
930
- test("parseMessageCopy returns null for empty MESSAGE", () => {
931
- expect(parseMessageCopy("MESSAGE: ")).toBeNull();
932
- });
933
-
934
- test("ensureMessageMentionsLibraryLocation appends missing location", () => {
935
- const message = ensureMessageMentionsLibraryLocation(
936
- "I built a budget tracker for your rent and groceries.",
937
- "app",
938
- );
939
- expect(message).toContain("Library");
940
- expect(message).not.toContain("Assets");
941
- });
942
-
943
- test("ensureMessageMentionsLibraryLocation normalizes terminal punctuation once", () => {
944
- const message = ensureMessageMentionsLibraryLocation(
945
- "I built a budget tracker for you!",
946
- "app",
947
- );
948
- expect(message).toBe(
949
- "I built a budget tracker for you. You can find the app in Library.",
950
- );
951
- });
952
-
953
- test("ensureMessageMentionsLibraryLocation replaces artifact panel wording", () => {
954
- const message = ensureMessageMentionsLibraryLocation(
955
- "You'll find it in the artifact panel.",
956
- "document",
957
- );
958
- expect(message).toContain("Library");
959
- expect(message).not.toContain("Assets");
960
- expect(message).not.toContain("artifact panel");
961
- });
962
- });