@vellumai/assistant 0.8.8 → 0.8.9-staging.1

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 (340) hide show
  1. package/bun.lock +2 -2
  2. package/examples/plugins/echo/README.md +61 -60
  3. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  4. package/examples/plugins/echo/hooks/stop.ts +16 -0
  5. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  6. package/examples/plugins/echo/package.json +1 -2
  7. package/examples/plugins/echo/src/emit.ts +19 -0
  8. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  9. package/openapi.yaml +236 -6
  10. package/package.json +2 -2
  11. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +185 -140
  13. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  14. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  15. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  16. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  17. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  18. package/src/__tests__/agent-loop.test.ts +441 -96
  19. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  20. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  21. package/src/__tests__/anthropic-provider.test.ts +1 -1
  22. package/src/__tests__/app-control-flow.test.ts +1 -1
  23. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  24. package/src/__tests__/approval-cascade.test.ts +5 -4
  25. package/src/__tests__/approval-routes-http.test.ts +4 -1
  26. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  27. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  28. package/src/__tests__/channel-approvals.test.ts +1 -1
  29. package/src/__tests__/compaction-circuit.test.ts +258 -0
  30. package/src/__tests__/compaction-direct.test.ts +132 -0
  31. package/src/__tests__/compaction-events.test.ts +5 -5
  32. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -4
  33. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  34. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +59 -103
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +94 -189
  36. package/src/__tests__/conversation-agent-loop.test.ts +249 -490
  37. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  38. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -4
  39. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  40. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -4
  41. package/src/__tests__/conversation-process-callsite.test.ts +14 -14
  42. package/src/__tests__/conversation-provider-retry-repair.test.ts +18 -16
  43. package/src/__tests__/conversation-queue.test.ts +9 -9
  44. package/src/__tests__/conversation-runtime-assembly.test.ts +923 -231
  45. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  46. package/src/__tests__/conversation-slash-queue.test.ts +6 -4
  47. package/src/__tests__/conversation-slash-unknown.test.ts +6 -4
  48. package/src/__tests__/conversation-speed-override.test.ts +10 -9
  49. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  50. package/src/__tests__/conversation-workspace-cache-state.test.ts +23 -20
  51. package/src/__tests__/conversation-workspace-injection.test.ts +68 -6
  52. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +14 -11
  53. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  54. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  55. package/src/__tests__/db-acp-history.test.ts +101 -0
  56. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  57. package/src/__tests__/empty-response-hook.test.ts +1 -1
  58. package/src/__tests__/file-write-tool.test.ts +63 -0
  59. package/src/__tests__/gateway-only-guard.test.ts +12 -2
  60. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  61. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  62. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  63. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  64. package/src/__tests__/heartbeat-service.test.ts +1 -0
  65. package/src/__tests__/history-repair-hook.test.ts +1 -1
  66. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  67. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  68. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  69. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  70. package/src/__tests__/injector-background-turn.test.ts +13 -23
  71. package/src/__tests__/injector-chain.test.ts +268 -44
  72. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  73. package/src/__tests__/injector-document-comments.test.ts +97 -114
  74. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  75. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  76. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  77. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  78. package/src/__tests__/memory-retrieval-hook.test.ts +73 -6
  79. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  80. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  81. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  82. package/src/__tests__/plugin-bootstrap.test.ts +12 -23
  83. package/src/__tests__/plugin-registry.test.ts +3 -49
  84. package/src/__tests__/plugin-types.test.ts +0 -70
  85. package/src/__tests__/reaction-persistence.test.ts +1 -1
  86. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  87. package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
  88. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  89. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  90. package/src/__tests__/subagent-detail.test.ts +25 -7
  91. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  92. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  93. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  94. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  95. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  96. package/src/__tests__/title-generate-hook.test.ts +1 -1
  97. package/src/__tests__/tool-error-hook.test.ts +1 -1
  98. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  99. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  100. package/src/acp/__tests__/agent-process.test.ts +161 -0
  101. package/src/acp/__tests__/client-handler.test.ts +40 -0
  102. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  103. package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
  104. package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
  105. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  106. package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
  107. package/src/acp/agent-process.ts +61 -1
  108. package/src/acp/auto-install.test.ts +196 -0
  109. package/src/acp/auto-install.ts +177 -0
  110. package/src/acp/client-handler.ts +31 -0
  111. package/src/acp/feature-gate.test.ts +48 -0
  112. package/src/acp/feature-gate.ts +34 -0
  113. package/src/acp/prepare-agent-env.ts +83 -29
  114. package/src/acp/resolve-agent.test.ts +320 -7
  115. package/src/acp/resolve-agent.ts +182 -18
  116. package/src/acp/resume-hint.ts +25 -0
  117. package/src/acp/session-manager.ts +495 -73
  118. package/src/acp/types.ts +8 -0
  119. package/src/agent/compaction-circuit.ts +60 -102
  120. package/src/agent/loop.ts +390 -240
  121. package/src/api/responses/conversation-message.ts +14 -1
  122. package/src/approvals/guardian-request-resolvers.ts +1 -1
  123. package/src/background-wake/next-wake.ts +1 -0
  124. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  125. package/src/cli/commands/plugins.ts +43 -37
  126. package/src/cli/lib/__tests__/install-from-github.test.ts +429 -111
  127. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  128. package/src/cli/lib/__tests__/plugin-details.test.ts +372 -0
  129. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +220 -0
  130. package/src/cli/lib/__tests__/search-plugins.test.ts +226 -32
  131. package/src/cli/lib/install-from-github.ts +464 -55
  132. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  133. package/src/cli/lib/plugin-details.ts +409 -0
  134. package/src/cli/lib/plugin-marketplace.ts +197 -0
  135. package/src/cli/lib/search-plugins.ts +195 -29
  136. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  137. package/src/config/acp-defaults.test.ts +10 -0
  138. package/src/config/acp-defaults.ts +6 -0
  139. package/src/config/bundled-skills/acp/SKILL.md +83 -31
  140. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  141. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  142. package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
  143. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  144. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  145. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  146. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  147. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  148. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  149. package/src/config/bundled-tool-registry.ts +2 -0
  150. package/src/config/feature-flag-registry.json +14 -5
  151. package/src/config/schemas/heartbeat.ts +9 -0
  152. package/src/context/strip-injections.ts +8 -2
  153. package/src/context/window-manager.ts +27 -13
  154. package/src/daemon/conversation-agent-loop-handlers.ts +10 -35
  155. package/src/daemon/conversation-agent-loop.ts +167 -1005
  156. package/src/daemon/conversation-lifecycle.ts +11 -255
  157. package/src/daemon/conversation-process.ts +8 -136
  158. package/src/daemon/conversation-registry.ts +159 -0
  159. package/src/daemon/conversation-runtime-assembly.ts +293 -392
  160. package/src/daemon/conversation-store.ts +9 -90
  161. package/src/daemon/conversation-surfaces.ts +24 -8
  162. package/src/daemon/conversation-workspace.ts +17 -0
  163. package/src/daemon/conversation.ts +383 -56
  164. package/src/daemon/external-plugins-bootstrap.ts +14 -19
  165. package/src/daemon/handlers/conversations.ts +3 -1
  166. package/src/daemon/handlers/skills.ts +4 -1
  167. package/src/daemon/host-proxy-preactivation.ts +1 -3
  168. package/src/daemon/lifecycle.ts +21 -0
  169. package/src/daemon/server.ts +2 -0
  170. package/src/daemon/wake-conversation-ops.ts +269 -0
  171. package/src/embedded/plugin-api.ts +2 -2
  172. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  173. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  174. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  175. package/src/heartbeat/heartbeat-service.ts +26 -0
  176. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  177. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  178. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  179. package/src/ipc/skill-routes/memory.ts +4 -2
  180. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  181. package/src/memory/conversation-crud.ts +29 -19
  182. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  183. package/src/memory/db-init.ts +2 -0
  184. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  185. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  186. package/src/memory/jobs-worker.ts +25 -1
  187. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  188. package/src/memory/migrations/index.ts +1 -0
  189. package/src/memory/schema/acp.ts +4 -0
  190. package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
  191. package/src/memory/v2/consolidation-job.ts +13 -4
  192. package/src/plugin-api/constants.ts +4 -0
  193. package/src/plugin-api/index.ts +6 -5
  194. package/src/plugin-api/types.ts +75 -0
  195. package/src/plugins/defaults/compaction/compact.ts +59 -0
  196. package/src/plugins/defaults/compaction/manager-store.ts +44 -0
  197. package/src/plugins/defaults/compaction/package.json +1 -2
  198. package/src/plugins/defaults/empty-response/package.json +0 -1
  199. package/src/plugins/defaults/history-repair/package.json +0 -1
  200. package/src/plugins/defaults/index.ts +135 -26
  201. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +103 -38
  202. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +167 -56
  203. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  204. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  205. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  206. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
  207. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +9 -6
  208. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
  209. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +8 -5
  210. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
  211. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
  212. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +10 -5
  213. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
  214. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +5 -5
  215. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +16 -17
  216. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -2
  217. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +9 -5
  218. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +5 -2
  219. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  220. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  221. package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
  222. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +15 -8
  223. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +2 -2
  224. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  225. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
  226. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/provider-blocks.ts +1 -1
  227. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +7 -3
  228. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
  229. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +5 -5
  230. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
  231. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +7 -7
  232. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +32 -94
  233. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
  234. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +1 -1
  235. package/src/plugins/defaults/title-generate/package.json +0 -1
  236. package/src/plugins/defaults/tool-error/package.json +0 -1
  237. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  238. package/src/plugins/pipeline.ts +6 -293
  239. package/src/plugins/registry.ts +9 -37
  240. package/src/plugins/types.ts +76 -381
  241. package/src/plugins/user-loader.ts +30 -127
  242. package/src/proactive-artifact/aux-message-injector.ts +1 -1
  243. package/src/proactive-artifact/job.test.ts +1 -1
  244. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  245. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +35 -3
  246. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  247. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  248. package/src/runtime/agent-wake.ts +108 -209
  249. package/src/runtime/assistant-event-hub.ts +1 -1
  250. package/src/runtime/channel-approvals.ts +1 -1
  251. package/src/runtime/interactive-ui.ts +1 -1
  252. package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
  253. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  254. package/src/runtime/routes/__tests__/plugins-routes.test.ts +398 -73
  255. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  256. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  257. package/src/runtime/routes/acp-routes.test.ts +89 -25
  258. package/src/runtime/routes/acp-routes.ts +81 -29
  259. package/src/runtime/routes/approval-routes.ts +1 -1
  260. package/src/runtime/routes/browser-routes.ts +1 -1
  261. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  262. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  264. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  265. package/src/runtime/routes/conversation-routes.ts +28 -2
  266. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  267. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  268. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  269. package/src/runtime/routes/host-cu-routes.ts +1 -1
  270. package/src/runtime/routes/identity-routes.ts +18 -3
  271. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  272. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  273. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  274. package/src/runtime/routes/memory-v3-routes.ts +16 -6
  275. package/src/runtime/routes/playground/helpers.ts +1 -1
  276. package/src/runtime/routes/plugins-routes.ts +336 -35
  277. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  278. package/src/runtime/routes/work-items-routes.ts +2 -4
  279. package/src/runtime/services/conversation-serializer.ts +1 -1
  280. package/src/signals/cancel.ts +2 -4
  281. package/src/subagent/manager.ts +21 -5
  282. package/src/tools/acp/context.ts +20 -0
  283. package/src/tools/acp/list-agents.test.ts +7 -1
  284. package/src/tools/acp/spawn.test.ts +158 -55
  285. package/src/tools/acp/spawn.ts +47 -72
  286. package/src/tools/acp/steer.test.ts +105 -8
  287. package/src/tools/acp/steer.ts +48 -17
  288. package/src/tools/apps/executors.ts +13 -8
  289. package/src/tools/filesystem/write.ts +34 -0
  290. package/src/tools/subagent/spawn.ts +2 -4
  291. package/src/tools/ui-surface/definitions.ts +25 -5
  292. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  293. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  294. package/docs/plugins.md +0 -832
  295. package/examples/plugins/echo/register.ts +0 -143
  296. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  297. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  298. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  299. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  300. package/src/__tests__/pipeline-runner.test.ts +0 -554
  301. package/src/__tests__/plugin-external-api.test.ts +0 -68
  302. package/src/daemon/wake-target-adapter.ts +0 -253
  303. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  304. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  305. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  306. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  307. package/src/plugins/defaults/compaction/register.ts +0 -35
  308. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  309. package/src/plugins/defaults/empty-response/register.ts +0 -23
  310. package/src/plugins/defaults/history-repair/register.ts +0 -24
  311. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  312. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  313. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  314. package/src/plugins/defaults/title-generate/register.ts +0 -35
  315. package/src/plugins/defaults/tool-error/register.ts +0 -23
  316. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  317. package/src/plugins/external-api.ts +0 -104
  318. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
  319. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
  320. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  321. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  322. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +0 -0
  323. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
  324. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/provider-blocks.test.ts +0 -0
  325. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
  326. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
  327. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  328. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  329. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
  330. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  331. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  332. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  333. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  334. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  335. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  336. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
  337. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
  338. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
  339. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
  340. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
@@ -74,6 +74,17 @@
74
74
  "change_summary": {
75
75
  "type": "string",
76
76
  "description": "Short summary of what changed, using git conventional commit format (e.g. 'feat: add coin flip app', 'fix: correct button alignment'). Used as the version history entry."
77
+ },
78
+ "icon": {
79
+ "type": "string",
80
+ "description": "Lenient alias. Prefer preview.icon. An emoji or image URL passed here is folded into preview.icon automatically."
81
+ },
82
+ "html": {
83
+ "type": "string",
84
+ "description": "Lenient alias. Prefer source_files. Raw HTML passed here is folded into source_files['src/index.html'] automatically."
85
+ },
86
+ "pages": {
87
+ "description": "Retired. Multi-page apps route inside the Preact app under src/components/. Passing this returns a guidance error."
77
88
  }
78
89
  },
79
90
  "required": ["name"]
@@ -150,6 +161,24 @@
150
161
  },
151
162
  "executor": "tools/app-generate-icon.ts",
152
163
  "execution_target": "host"
164
+ },
165
+ {
166
+ "name": "app_list",
167
+ "description": "List the persistent apps the user has built, returning each app's app_id, name, description, and timestamps (most recently updated first). Pass `query` to resolve an app the user mentions by name to its app_id before calling app_open. Use this whenever the user refers to an existing app and you don't already have its app_id in context.",
168
+ "category": "apps",
169
+ "risk": "low",
170
+ "input_schema": {
171
+ "type": "object",
172
+ "properties": {
173
+ "query": {
174
+ "type": "string",
175
+ "description": "Optional name (or partial name) the user mentioned. When provided, only matching apps are returned: an exact case-insensitive name match if one exists, otherwise substring matches in either direction (e.g. 'habit tracker' resolves 'Habit Tracker'). Omit to list all apps."
176
+ }
177
+ },
178
+ "required": []
179
+ },
180
+ "executor": "tools/app-list.ts",
181
+ "execution_target": "host"
153
182
  }
154
183
  ]
155
184
  }
@@ -0,0 +1,48 @@
1
+ # Design System
2
+
3
+ A design system CSS is auto-injected inside a `@layer`, so your styles always take priority. It provides element defaults and automatic light/dark mode switching via `prefers-color-scheme`.
4
+
5
+ **Use `--v-*` variables and `.v-*` classes** — they handle light/dark mode automatically. No manual dark mode CSS needed.
6
+
7
+ ---
8
+
9
+ ## Design tokens
10
+
11
+ | Category | Tokens |
12
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | **Backgrounds** | `--v-bg`, `--v-surface`, `--v-surface-border` |
14
+ | **Text** | `--v-text`, `--v-text-secondary`, `--v-text-muted` |
15
+ | **Accent** | `--v-accent`, `--v-accent-hover` |
16
+ | **Status** | `--v-success`, `--v-danger`, `--v-warning` |
17
+ | **Spacing** | `--v-spacing-xxs` (2px) / `-xs` (4px) / `-sm` (8px) / `-md` (12px) / `-lg` (16px) / `-xl` (24px) / `-xxl` (32px) / `-xxxl` (48px) |
18
+ | **Radius** | `--v-radius-xs` (2px) / `-sm` (4px) / `-md` (8px) / `-lg` (12px) / `-xl` (16px) / `-pill` (999px) |
19
+ | **Shadows** | `--v-shadow-sm`, `--v-shadow-md`, `--v-shadow-lg` |
20
+ | **Typography** | `--v-font-family`, `--v-font-mono`, `--v-font-size-xs` (10px) / `-sm` (11px) / `-base` (14px) / `-lg` (17px) / `-xl` (22px) / `-2xl` (26px), `--v-line-height` |
21
+ | **Animation** | `--v-duration-fast` (0.15s) / `-standard` (0.25s) / `-slow` (0.4s) |
22
+ | **Palettes** | `--v-slate-{950..50}`, `--v-emerald-*`, `--v-violet-*`, `--v-indigo-*`, `--v-rose-*`, `--v-amber-*` |
23
+ | **Constant** | `--v-aux-white` (always `#FFFFFF` in both modes — use for text on filled/accent backgrounds) |
24
+
25
+ ---
26
+
27
+ ## Utility classes
28
+
29
+ `.v-button` (`.secondary` / `.danger` / `.ghost`), `.v-card`, `.v-list` / `.v-list-item`, `.v-badge` (`.success` / `.warning` / `.danger`), `.v-input-row`, `.v-empty-state`, `.v-toggle`.
30
+
31
+ ⚠️ **Never hardcode `color: white` or `color: #fff`.** Use `var(--v-aux-white)` for text on filled/accent backgrounds, or `var(--v-text)` / `var(--v-text-secondary)` for text on surface backgrounds. Hardcoded white causes invisible text on light surfaces.
32
+
33
+ ---
34
+
35
+ ## Custom themes
36
+
37
+ When the user wants a specific branded look, write complete CSS with hardcoded colors and `@media (prefers-color-scheme: dark)` for dark variants. Don't mix `--v-*` auto-switching variables with hardcoded colors in the same element.
38
+
39
+ ---
40
+
41
+ ## Theme detection in JavaScript
42
+
43
+ ```javascript
44
+ console.log(window.vellum.theme.mode); // 'light' or 'dark'
45
+ window.addEventListener("vellum-theme-change", (e) => {
46
+ console.log("Theme:", e.detail.mode);
47
+ });
48
+ ```
@@ -0,0 +1,57 @@
1
+ # Responsive Baseline & Mobile-First Mode
2
+
3
+ Every app must work across phone (~360px) to desktop (~1400px+).
4
+
5
+ ## Mode selection
6
+
7
+ The conversation context's `<turn_context>` block carries an `interface:` field.
8
+
9
+ **If `interface: ios`** (or any future mobile-web / android identifier):
10
+ → Mobile-first build. Design the narrow viewport first, enhance upward.
11
+
12
+ **If `interface: macos` or `web`**:
13
+ → Desktop-first build. Design larger composition first; narrow fallback still meets the universal baseline below.
14
+
15
+ **If field is absent or ambiguous**:
16
+ → Default to desktop-first unless the request implies phone use ("for my iPhone", "a tap-tracker I'll use on the go").
17
+
18
+ ---
19
+
20
+ ## Universal baseline (every build, regardless of interface)
21
+
22
+ ### Viewport & safe areas
23
+
24
+ - Set viewport meta: `<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">`. Never set `user-scalable=no` — it blocks accessibility zoom.
25
+ - Pad the root container with `env(safe-area-inset-*)` so content clears the notch: `padding-top: max(var(--v-spacing-lg), env(safe-area-inset-top))`, mirrored for `-bottom` / `-left` / `-right`.
26
+ - Use `100dvh` (dynamic viewport height), not `100vh`, for full-height containers.
27
+
28
+ ### Form controls
29
+
30
+ - `<input>`, `<textarea>`, `<select>` must be `font-size: 16px` or larger, or iOS Safari will zoom on focus and break the layout. This applies to every build.
31
+ - Add `inputmode` to text fields with structured input: `numeric` for integers, `decimal` for amounts, `email`, `tel`, `url`.
32
+
33
+ ### Touch & hover
34
+
35
+ - Interactive elements must be ≥44×44pt. `.v-button` already meets this; for custom controls, set `min-height: 44px` explicitly.
36
+ - Gate hover affordances behind `@media (hover: hover)` so they don't stick on touch devices.
37
+ - Disable text selection on app chrome with `user-select: none; -webkit-user-select: none`.
38
+
39
+ ### Layout fluidity
40
+
41
+ - Use fluid widths only. No fixed-pixel layouts. Prefer `%`, `fr`, `minmax`, `clamp()` over `px` on container widths.
42
+ - At narrow widths, collapse tables into stacked cards with labels and values arranged vertically.
43
+ - Size `vellum.widgets.*` chart containers in `vw` / `%`, not fixed `px`.
44
+
45
+ ---
46
+
47
+ ## Mobile-first priorities (`interface: ios`)
48
+
49
+ - Default body text to `--v-font-size-lg` (17px), not `--v-font-size-base` (14px).
50
+ - Bump default vertical rhythm one step (e.g. `--v-spacing-md` → `--v-spacing-lg`).
51
+ - One column as the default, not a fallback. Opt into multi-column only above `@media (min-width: 720px)`.
52
+ - Bottom-anchor the primary action: `position: sticky; bottom: env(safe-area-inset-bottom)`.
53
+ - Replace side modals and popovers with bottom sheets.
54
+
55
+ ## Desktop-first priorities (`interface: macos` / `web`)
56
+
57
+ Multi-column composition, hover-rich affordances, denser information, side modals, inline primary actions. The universal baseline above is still the floor — narrow view must still work.
@@ -0,0 +1,38 @@
1
+ # Presentation Slide Design
2
+
3
+ Slides are a different domain from apps. Skip app-specific patterns (contextual headers, search/filter, toast notifications, form validation, custom routes). Slides are static content — build navigation and layouts with custom HTML/CSS.
4
+
5
+ ## Key principles
6
+
7
+ - One idea per slide — understood in 3 seconds
8
+ - Layout variety — 3+ different types per deck, never consecutive same-type
9
+ - 8 layout types: Title, Stats, Bullets, Quote, Comparison, Timeline, Visual/Immersive, Closing/CTA
10
+ - Bold backgrounds — dark, gradient, or strongly tinted
11
+ - Max 6 bullets per slide, max 3 sentences body text
12
+ - Never go below 15px for any visible text
13
+
14
+ ## Navigation
15
+
16
+ Build slide navigation as your own component. Common patterns:
17
+ - Keyboard: `ArrowLeft` / `ArrowRight` / `Space` / `Escape`
18
+ - Click affordances at left/right edges
19
+ - Slide counter pill in a corner (e.g. `3 / 12`)
20
+ - Optional progress bar at the top
21
+
22
+ ## Layout templates
23
+
24
+ - **Title** — Centered headline, optional subtitle, no body. Full-bleed background or gradient.
25
+ - **Stats** — One huge number, label below, supporting paragraph optional.
26
+ - **Bullets** — Heading + 3–6 short bullets. Avoid wall-of-text.
27
+ - **Quote** — Pull quote in large italic type, attribution below, contrasting background.
28
+ - **Comparison** — Two columns (before/after, us/them, problem/solution). Visual symmetry matters.
29
+ - **Timeline** — Horizontal or vertical sequence with dates and milestones.
30
+ - **Visual/Immersive** — Full-bleed image, gradient, or generated graphic with minimal text overlay.
31
+ - **Closing/CTA** — Headline + single call to action. Mirror the title slide aesthetic.
32
+
33
+ ## What to avoid
34
+
35
+ - Generic Keynote / PowerPoint aesthetic (default white background, sans-serif body, bullet lists everywhere)
36
+ - Tiny text below 15px — slides are read across rooms
37
+ - Same layout type used 3+ times in a row — vary the rhythm
38
+ - Body paragraphs longer than 3 sentences — split into multiple slides
@@ -0,0 +1,62 @@
1
+ import * as appStore from "../../../../memory/app-store.js";
2
+ import type {
3
+ ToolContext,
4
+ ToolExecutionResult,
5
+ } from "../../../../tools/types.js";
6
+
7
+ interface AppListEntry {
8
+ app_id: string;
9
+ name: string;
10
+ description?: string;
11
+ updated_at: number;
12
+ created_at: number;
13
+ }
14
+
15
+ function toEntry(app: appStore.AppDefinition): AppListEntry {
16
+ return {
17
+ app_id: app.id,
18
+ name: app.name,
19
+ ...(app.description ? { description: app.description } : {}),
20
+ updated_at: app.updatedAt,
21
+ created_at: app.createdAt,
22
+ };
23
+ }
24
+
25
+ export async function run(
26
+ input: Record<string, unknown>,
27
+ _context: ToolContext,
28
+ ): Promise<ToolExecutionResult> {
29
+ const apps = appStore.listApps();
30
+ const entries = apps.map(toEntry);
31
+
32
+ const query =
33
+ typeof input.query === "string" ? input.query.trim().toLowerCase() : "";
34
+
35
+ if (!query) {
36
+ return {
37
+ content: JSON.stringify({ count: entries.length, apps: entries }),
38
+ isError: false,
39
+ };
40
+ }
41
+
42
+ // Resolve the app the user mentioned by name. Prefer an exact (case-insensitive)
43
+ // name match, then fall back to substring matches in either direction so
44
+ // "habit tracker" resolves "Habit Tracker" and "my budget" resolves "Budget".
45
+ const exact = entries.filter((e) => e.name.toLowerCase() === query);
46
+ const matches =
47
+ exact.length > 0
48
+ ? exact
49
+ : entries.filter((e) => {
50
+ const name = e.name.toLowerCase();
51
+ return name.includes(query) || query.includes(name);
52
+ });
53
+
54
+ return {
55
+ content: JSON.stringify({
56
+ query: input.query,
57
+ match_count: matches.length,
58
+ matches,
59
+ }),
60
+ isError: false,
61
+ };
62
+ }
@@ -1,44 +1,37 @@
1
1
  ---
2
2
  name: document-editor
3
- description: Rich text document editor with collaborative editing tools create, read, update, and annotate documents
3
+ description: Use whenever the user wants to write or draft an article, blog post, essay, report, or any long-form content. Creates the content in a rich text editor instead of dumping it in chat, so it can be streamed, reviewed, edited, and exported.
4
4
  compatibility: "Designed for Vellum personal assistants"
5
5
  metadata:
6
- emoji: "📄"
6
+ emoji: "✍️"
7
7
  vellum:
8
- display-name: "Document Editor"
8
+ display-name: "Document Writer"
9
9
  activation-hints:
10
- - "User asks to write, draft, or collaborate on long-form content — use the document editor for a better editing experience"
11
- - "When content will be iterated on, reviewed, or exported, prefer the document editor over inline markdown"
12
- - "When a file attachment contains a draft or document the user wants to iterate on, open it in the editor"
10
+ - "User asks to write, draft, or compose an article, blog post, essay, report, story, or any long-form content — always create it in the document editor, not as a chat reply"
11
+ - "User wants written content they will iterate on, review, or export use the editor instead of inline markdown"
12
+ - "A file attachment contains a draft or document the user wants to revise open it in the editor"
13
+ avoid-when:
14
+ - "The user wants an interactive app, dashboard, calculator, game, or anything with state or data — use app-builder instead"
15
+ - "A one or two sentence answer is enough — just reply in chat"
13
16
  ---
14
17
 
15
- Create and edit long-form documents using the built-in rich text editor. Documents open in workspace mode with chat docked to the side.
18
+ Write and edit long-form documents using the built-in rich text editor. Documents open in workspace mode with chat docked to the side. When a request is about writing prose (an article, blog post, report, essay, story, or similar), create it here rather than writing it into the chat response.
16
19
 
17
20
  ## Tools
18
21
 
19
- - **document_open** - Opens an existing document in the editor panel by `surface_id`. Use this when a document exists but isn't visible in the editor — for example after the user switches devices, refreshes the page, or when the editor panel was closed. Fetches the document from storage and sends it to the client.
20
- - **document_create** - Opens a new document editor with an optional title and initial Markdown content. Returns a `surface_id` for subsequent updates.
22
+ - **document_create** - Opens a new document editor with an optional title and initial Markdown content. Returns a `surface_id` for subsequent updates. This is the entry point for any new piece of writing.
21
23
  - **document_update** - Updates content in an open document editor by `surface_id`. Supports `replace` (overwrite) and `append` (add to end) modes.
22
24
  - **document_read** - Reads the current content of a document by `surface_id` when it belongs to the current conversation, or when the current actor is the guardian/local user. Use to verify content before editing.
23
- - **document_list** - Lists documents. Without `query`, lists the current conversation's documents. With `query`, searches by title; guardian/local users can search across conversations, while other actors are scoped to the current conversation.
24
25
  - **document_find** - Searches a document for text or regex patterns. Returns matching lines with line numbers, match positions, and matched text.
25
26
  - **document_replace_text** - Targeted find-and-replace within a document. Supports literal and regex patterns (with backreferences). Optionally limit the number of replacements.
27
+ - **document_list** - Lists documents. Without `query`, lists the current conversation's documents. With `query`, searches by title; guardian/local users can search across conversations, while other actors are scoped to the current conversation.
28
+ - **document_open** - Opens an existing document in the editor panel by `surface_id`. Use this when a document exists but isn't visible in the editor — for example after the user switches devices, refreshes the page, or when the editor panel was closed. Fetches the document from storage and sends it to the client.
26
29
  - **document_delete** - Deletes a document by `surface_id`. Use to clean up unwanted documents.
27
30
 
28
- ## Retrieving existing documents
29
-
30
- When the user asks to see, open, or pull up a document:
31
-
32
- 1. Check the `<active_documents>` block in your context — it lists all documents in this conversation with their `surface_id` and title.
33
- 2. If the document is NOT in `<active_documents>`, call `document_list` with a `query` matching the document title. For guardian/local users, this searches across previous conversations and sessions.
34
- 3. Once you have the `surface_id`, call `document_open` to open the editor panel. This surfaces the editor on the client and returns document metadata (`surface_id`, `title`, `word_count`) — not the full content. If you need the actual document text, follow up with `document_read`.
35
-
36
- **Never** search the filesystem, conversation history, or archives to find a document. Always use `document_list` with a `query`.
37
-
38
- **If the user says they can't see a document you know exists** (e.g. after switching from macOS to web, or after a page refresh), call `document_open` with the `surface_id` to re-surface the editor panel on their current client.
39
-
40
31
  ## Creating a new document
41
32
 
33
+ This is the default path when the user asks you to write something.
34
+
42
35
  1. **Create the document**: Call `document_create` with a title (inferred from the request). Call the tool immediately, not after conversational preamble. Capture the `surface_id` from the response — every subsequent `document_update` call must reference it.
43
36
  2. **Write content in Markdown**: Use proper structure (`#` for titles, `##` for sections), **bold**, _italic_, code blocks, tables, lists, blockquotes as appropriate.
44
37
  3. **CRITICAL - Stream content in chunks**: Call `document_update` MULTIPLE times, not just once. Break content into logical chunks (paragraphs, sections, or every 200-300 words). Call `document_update` with `mode: "append"` for EACH chunk separately. The user experiences real-time content appearing as you write.
@@ -59,6 +52,18 @@ When the user requests changes to a document:
59
52
  - `document_find` + `document_replace_text` — **for everything else**. Fixing typos, renaming terms, swapping sections, reordering content, adjusting formatting, or any edit that touches only part of the document. This is the default choice for edits. It avoids rewriting the entire document and eliminates the risk of accidentally dropping content.
60
53
  4. **Do NOT use `document_update` with `mode: "replace"` for targeted edits.** Rewriting the entire document to change a few words or rearrange sections is wasteful and error-prone.
61
54
 
55
+ ## Retrieving existing documents
56
+
57
+ When the user asks to see, open, or pull up a document:
58
+
59
+ 1. Check the `<active_documents>` block in your context — it lists all documents in this conversation with their `surface_id` and title.
60
+ 2. If the document is NOT in `<active_documents>`, call `document_list` with a `query` matching the document title. For guardian/local users, this searches across previous conversations and sessions.
61
+ 3. Once you have the `surface_id`, call `document_open` to open the editor panel. This surfaces the editor on the client and returns document metadata (`surface_id`, `title`, `word_count`) — not the full content. If you need the actual document text, follow up with `document_read`.
62
+
63
+ **Never** search the filesystem, conversation history, or archives to find a document. Always use `document_list` with a `query`.
64
+
65
+ **If the user says they can't see a document you know exists** (e.g. after switching from macOS to web, or after a page refresh), call `document_open` with the `surface_id` to re-surface the editor panel on their current client.
66
+
62
67
  ## Find & Replace
63
68
 
64
69
  Use `document_find` and `document_replace_text` for surgical edits that target specific text patterns without rewriting the entire document.
@@ -117,7 +122,7 @@ Users can leave inline comments on documents. Open comments are surfaced in a `<
117
122
  ## Anti-Patterns
118
123
 
119
124
  - **Don't use `app_create` for blog posts, articles, or written content.** Use `document_create` — apps are for interactive content with state/data.
120
- - **Don't output the full content in chat.** The content goes in the document editor, not in the chat response. Acknowledge what you're doing and stream to the editor.
125
+ - **Don't write the article into the chat response.** Long-form prose goes in the document editor via `document_create`, not in chat and not into a `.md` file in the workspace. Acknowledge what you're doing and stream to the editor.
121
126
  - **Don't wait to generate everything before sending.** Stream content in chunks via `document_update` with `mode: "append"` so users see progress in real time.
122
127
 
123
128
  ## Usage Notes
@@ -42,7 +42,7 @@
42
42
  },
43
43
  {
44
44
  "name": "document_update",
45
- "description": "Update content in an open document editor. Use this to stream generated content or apply edits.",
45
+ "description": "Append to or fully replace a document's content. Takes the full Markdown in `content` plus a `mode`: \"append\" adds it to the end (use this to stream generated content in chunks), \"replace\" overwrites the entire document. This tool does NOT do targeted edits — for changing specific words, phrases, or sections, use document_replace_text instead. There is no old/new or find/replace parameter here.",
46
46
  "category": "document-editor",
47
47
  "risk": "low",
48
48
  "input_schema": {
@@ -23,6 +23,7 @@ import * as acpSteer from "./bundled-skills/acp/tools/acp-steer.js";
23
23
  import * as appCreate from "./bundled-skills/app-builder/tools/app-create.js";
24
24
  import * as appDelete from "./bundled-skills/app-builder/tools/app-delete.js";
25
25
  import * as appGenerateIcon from "./bundled-skills/app-builder/tools/app-generate-icon.js";
26
+ import * as appList from "./bundled-skills/app-builder/tools/app-list.js";
26
27
  import * as appRefresh from "./bundled-skills/app-builder/tools/app-refresh.js";
27
28
  // ── app-control ────────────────────────────────────────────────────────────────
28
29
  import * as appControlClick from "./bundled-skills/app-control/tools/app-control-click.js";
@@ -142,6 +143,7 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
142
143
  ["app-builder:tools/app-delete.ts", appDelete],
143
144
  ["app-builder:tools/app-refresh.ts", appRefresh],
144
145
  ["app-builder:tools/app-generate-icon.ts", appGenerateIcon],
146
+ ["app-builder:tools/app-list.ts", appList],
145
147
 
146
148
  // app-control
147
149
  ["app-control:tools/app-control-start.ts", appControlStart],
@@ -26,12 +26,13 @@
26
26
  "defaultEnabled": false
27
27
  },
28
28
  {
29
- "id": "prechat-onboarding-condensed-flow",
29
+ "id": "pre-chat-onboarding-experiment-2026-06-06",
30
30
  "scope": "client",
31
- "key": "prechat-onboarding-condensed-flow",
32
- "label": "Condensed Pre-chat Onboarding",
33
- "description": "Enable the condensed pre-chat onboarding flow for a standard LaunchDarkly percentage rollout.",
34
- "defaultEnabled": false
31
+ "key": "pre-chat-onboarding-experiment-2026-06-06",
32
+ "label": "Pre-chat Onboarding Experiment 2026-06-06",
33
+ "description": "Pre-chat onboarding experiment with control and variant-a arms. Control shows the full funnel; variant-a shows the condensed pared-down flow.",
34
+ "defaultEnabled": "control",
35
+ "values": ["control", "variant-a"]
35
36
  },
36
37
  {
37
38
  "id": "experiment-activation-flow-2026-06-03",
@@ -488,6 +489,14 @@
488
489
  "label": "Provider-First Profile Creation",
489
490
  "description": "New profile creation flow: pick (or inline-create) a provider first, then a model, with pre-filled provider and profile name/key, plus a quick-add \"+\" in the chat composer's Model Profile menu. When off, profile creation uses the previous field order and there is no composer quick-add.",
490
491
  "defaultEnabled": false
492
+ },
493
+ {
494
+ "id": "acp",
495
+ "scope": "assistant",
496
+ "key": "acp",
497
+ "label": "ACP Coding Agents",
498
+ "description": "Enable spawning and steering external coding agents (Claude Code, Codex, Gemini) via the Agent Client Protocol. Alternative gate to the acp.enabled workspace config field; either enables the subsystem.",
499
+ "defaultEnabled": false
491
500
  }
492
501
  ]
493
502
  }
@@ -56,6 +56,15 @@ export const HeartbeatConfigSchema = z
56
56
  .describe(
57
57
  "Maximum heartbeats that can run consecutively without a guardian message. Counter resets when the guardian sends a message. Set to null for unlimited.",
58
58
  ),
59
+ maxDailyRuns: z
60
+ .number({ error: "heartbeat.maxDailyRuns must be a number" })
61
+ .int("heartbeat.maxDailyRuns must be an integer")
62
+ .positive("heartbeat.maxDailyRuns must be a positive integer")
63
+ .nullable()
64
+ .default(2)
65
+ .describe(
66
+ "Maximum heartbeats that can run per calendar day. Resets at midnight local time. Set to null for unlimited.",
67
+ ),
59
68
  disposition: z
60
69
  .string({ error: "heartbeat.disposition must be a string" })
61
70
  .default(
@@ -87,8 +87,14 @@ const RUNTIME_INJECTION_PREFIXES: InjectionMatcher[] = [
87
87
  { prefix: "<info>\n", suffix: "\n</info>" },
88
88
  "<voice_call_control>",
89
89
  "<workspace_top_level>", // backward-compat: strip legacy workspace blocks
90
- // NOTE: <workspace> is intentionally NOT stripped workspace context
91
- // persists in history so the assistant retains workspace grounding.
90
+ // The `<workspace>` top-level block is stripped so each compaction re-injects
91
+ // a fresh directory snapshot rather than carrying a stale listing into the
92
+ // summary — matching the `<knowledge_base>`/`<NOW.md>` cadence and keeping the
93
+ // `workspace-context` injector's presence detection in lockstep (the block is
94
+ // present exactly when compaction would strip it). The full `{ prefix, suffix }`
95
+ // wrapper shape ensures user-authored text merely starting with `<workspace>\n`
96
+ // is never mistaken for an injected block.
97
+ { prefix: "<workspace>\n", suffix: "\n</workspace>" },
92
98
  "<temporal_context>\nToday:", // backward-compat: strip legacy temporal blocks
93
99
  "<active_subagents>",
94
100
  "<active_workspace>",
@@ -40,7 +40,8 @@ const INTERNAL_CONTEXT_SUMMARY_MESSAGES = new WeakSet<Message>();
40
40
 
41
41
  // ---------------------------------------------------------------------------
42
42
  // Public types — preserved for downstream consumers (agent loop, conversation,
43
- // plugin pipeline, applyCompactionResult, routes/playground/force-compact).
43
+ // default compaction plugin, applyCompactionResult,
44
+ // routes/playground/force-compact).
44
45
  // ---------------------------------------------------------------------------
45
46
 
46
47
  export interface ContextWindowResult {
@@ -198,8 +199,7 @@ export class ContextWindowManager {
198
199
  * `compactedMessages` so `compactedPersistedMessages` only reflects DB
199
200
  * rows. Decremented after a successful compaction.
200
201
  */
201
- nonPersistedPrefixCount = 0;
202
- summaryIsInjected = false;
202
+ private _nonPersistedPrefixCount = 0;
203
203
  private _resolvedSystemPrompt: string | undefined;
204
204
 
205
205
  constructor(options: ContextWindowManagerOptions) {
@@ -215,6 +215,21 @@ export class ContextWindowManager {
215
215
  this.config = config;
216
216
  }
217
217
 
218
+ /** Leading non-persisted inherited-context messages the compactor preserves. */
219
+ get nonPersistedPrefixCount(): number {
220
+ return this._nonPersistedPrefixCount;
221
+ }
222
+
223
+ /**
224
+ * Seed the non-persisted inherited-context prefix when a forked/sub
225
+ * conversation inherits its parent's in-memory context. The compactor folds
226
+ * this prefix into the summary and {@link consumeCompactionState} decrements
227
+ * it as the leading messages are compacted away.
228
+ */
229
+ seedNonPersistedPrefix(count: number): void {
230
+ this._nonPersistedPrefixCount = count;
231
+ }
232
+
218
233
  private get estimationProviderName(): string {
219
234
  return this.provider.tokenEstimationProvider ?? this.provider.name;
220
235
  }
@@ -352,7 +367,7 @@ export class ContextWindowManager {
352
367
  signal,
353
368
  overrideProfile: options?.overrideProfile ?? null,
354
369
  actorTrustClass: options?.actorTrustClass,
355
- nonPersistedPrefixCount: this.nonPersistedPrefixCount,
370
+ nonPersistedPrefixCount: this._nonPersistedPrefixCount,
356
371
  };
357
372
 
358
373
  // Retry budget for the compactor itself. Lives here (not in the
@@ -390,7 +405,7 @@ export class ContextWindowManager {
390
405
  ...baseArgs,
391
406
  messages: result.messages,
392
407
  previousEstimatedInputTokens: previousEstimate,
393
- nonPersistedPrefixCount: this.nonPersistedPrefixCount,
408
+ nonPersistedPrefixCount: this._nonPersistedPrefixCount,
394
409
  });
395
410
  if (!nextResult.compacted) break;
396
411
  const nextEstimate = this.recomputePostCompactionEstimate(
@@ -434,21 +449,20 @@ export class ContextWindowManager {
434
449
  }
435
450
 
436
451
  /**
437
- * Decrement the non-persisted prefix bookkeeping and clear the
438
- * injected-summary flag after a productive compaction. Called once per
439
- * successful internal attempt so multi-attempt runs keep the count
440
- * honest as the leading injected messages get folded into the summary.
452
+ * Decrement the non-persisted prefix bookkeeping after a productive
453
+ * compaction. Called once per successful internal attempt so multi-attempt
454
+ * runs keep the count honest as the leading injected messages get folded
455
+ * into the summary.
441
456
  */
442
457
  private consumeCompactionState(compactedMessages: number): void {
443
458
  const compactedAway = Math.min(
444
- this.nonPersistedPrefixCount,
459
+ this._nonPersistedPrefixCount,
445
460
  compactedMessages,
446
461
  );
447
- this.nonPersistedPrefixCount = Math.max(
462
+ this._nonPersistedPrefixCount = Math.max(
448
463
  0,
449
- this.nonPersistedPrefixCount - compactedAway,
464
+ this._nonPersistedPrefixCount - compactedAway,
450
465
  );
451
- this.summaryIsInjected = false;
452
466
  }
453
467
  }
454
468
 
@@ -76,10 +76,8 @@ import {
76
76
  cleanAssistantContent,
77
77
  drainDirectiveDisplayBuffer,
78
78
  } from "./assistant-attachments.js";
79
- import type {
80
- AgentLoopConversationContext,
81
- AssistantSurface,
82
- } from "./conversation-agent-loop.js";
79
+ import type { Conversation } from "./conversation.js";
80
+ import type { AssistantSurface } from "./conversation-agent-loop.js";
83
81
  import {
84
82
  buildConversationErrorMessage,
85
83
  classifyConversationError,
@@ -295,29 +293,11 @@ export interface EventHandlerState {
295
293
  * never claims content a flush has not yet written.
296
294
  */
297
295
  lastPersistedContentSeq: number | undefined;
298
- /**
299
- * Whether the workspace top-level block should be (re)injected on this
300
- * turn. Compaction's prepare phase strips the workspace / NOW.md / PKB
301
- * blocks off the tail, so it is set after any successful compaction to
302
- * force the workspace overview back in. On an ordinary turn the block is
303
- * already present in history, so it defaults `false` to avoid burning
304
- * tokens re-injecting it redundantly.
305
- */
306
- shouldInjectWorkspace: boolean;
307
- /**
308
- * Whether the reducer has compacted `ctx.messages`, gating the Slack
309
- * chronological-transcript override on re-injection. The captured
310
- * transcript is the full persisted history; blindly replaying it after
311
- * compaction would overwrite the reduced messages and undo compaction, so
312
- * once this is `true` the override falls back to the reduced
313
- * `ctx.messages`.
314
- */
315
- reducerCompacted: boolean;
316
296
  }
317
297
 
318
298
  /** Immutable context shared across event handlers within a single agent loop run. */
319
299
  export interface EventHandlerDeps {
320
- readonly ctx: AgentLoopConversationContext;
300
+ readonly ctx: Conversation;
321
301
  readonly onEvent: (msg: ServerMessage) => void;
322
302
  readonly reqId: string;
323
303
  readonly isFirstMessage: boolean;
@@ -392,8 +372,6 @@ export function createEventHandlerState(): EventHandlerState {
392
372
  pendingPartialFlushPromise: undefined,
393
373
  currentMessageContent: [],
394
374
  lastPersistedContentSeq: undefined,
395
- shouldInjectWorkspace: false,
396
- reducerCompacted: false,
397
375
  };
398
376
  }
399
377
 
@@ -655,9 +633,7 @@ function computeToolUseStatusText(
655
633
  return `Running ${friendlyToolName(name)}`;
656
634
  }
657
635
 
658
- function resolveAssistantReplyTimestampTimezone(
659
- ctx: AgentLoopConversationContext,
660
- ): string {
636
+ function resolveAssistantReplyTimestampTimezone(ctx: Conversation): string {
661
637
  const config = getConfig();
662
638
  return resolveTurnTimezoneContext({
663
639
  configuredUserTimeZone: config.ui?.userTimezone ?? null,
@@ -1659,6 +1635,8 @@ export async function handleMessageComplete(
1659
1635
  deps.ctx.conversationId,
1660
1636
  state.pendingNotifiedInferenceProfile,
1661
1637
  );
1638
+ deps.ctx.lastNotifiedInferenceProfile =
1639
+ state.pendingNotifiedInferenceProfile;
1662
1640
  state.pendingNotifiedInferenceProfile = null;
1663
1641
  }
1664
1642
 
@@ -2302,17 +2280,14 @@ export async function dispatchAgentEvent(
2302
2280
  // so re-injection re-applies onto the stripped history even when the
2303
2281
  // pipeline ran but did not compact. When it did compact, commit the
2304
2282
  // durable result (DB-record fields, Slack provenance, SSE) — which
2305
- // overwrites `ctx.messages` with the compacted history and flip the
2306
- // per-turn re-injection guards the orchestrator reads. This runs
2283
+ // overwrites `ctx.messages` with the compacted history. This runs
2307
2284
  // before the loop's `reinject` hook (the loop awaits this dispatch),
2308
- // so the guards are set in time. A failed durable commit re-throws
2309
- // below to abort the turn rather than re-injecting against
2310
- // half-applied state.
2285
+ // so the committed history is in place in time. A failed durable
2286
+ // commit re-throws below to abort the turn rather than re-injecting
2287
+ // against half-applied state.
2311
2288
  deps.ctx.messages = event.basis;
2312
2289
  if (event.result.compacted) {
2313
2290
  await deps.applyCompaction(event.result, event.basis);
2314
- state.reducerCompacted = true;
2315
- state.shouldInjectWorkspace = true;
2316
2291
  }
2317
2292
  break;
2318
2293
  case "history_stripped":