@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea

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 (570) hide show
  1. package/Dockerfile +20 -4
  2. package/bun.lock +2 -2
  3. package/docker-entrypoint.sh +4 -2
  4. package/docker-init-apt-root.sh +3 -1
  5. package/docker-kata-apt-env.sh +3 -1
  6. package/docker-kata-runtime-family.sh +12 -0
  7. package/docs/architecture/memory.md +1 -1
  8. package/examples/plugins/echo/README.md +61 -66
  9. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  10. package/examples/plugins/echo/hooks/stop.ts +16 -0
  11. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  12. package/examples/plugins/echo/package.json +1 -2
  13. package/examples/plugins/echo/src/emit.ts +19 -0
  14. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
  15. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  16. package/openapi.yaml +3378 -335
  17. package/package.json +2 -2
  18. package/scripts/generate-openapi.ts +68 -41
  19. package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
  21. package/src/__tests__/agent-loop.test.ts +37 -87
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  23. package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
  24. package/src/__tests__/annotate-risk-options.test.ts +2 -3
  25. package/src/__tests__/anthropic-provider.test.ts +95 -2
  26. package/src/__tests__/app-control-flow.test.ts +1 -1
  27. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  28. package/src/__tests__/approval-routes-http.test.ts +4 -1
  29. package/src/__tests__/assistant-event-hub.test.ts +25 -0
  30. package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
  31. package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
  32. package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
  33. package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
  34. package/src/__tests__/btw-routes.test.ts +62 -3
  35. package/src/__tests__/build-persisted-content.test.ts +184 -0
  36. package/src/__tests__/catalog-files.test.ts +1 -1
  37. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  38. package/src/__tests__/channel-approvals.test.ts +1 -1
  39. package/src/__tests__/clawhub-files.test.ts +1 -1
  40. package/src/__tests__/compaction-circuit.test.ts +258 -0
  41. package/src/__tests__/compaction-direct.test.ts +132 -0
  42. package/src/__tests__/compaction.benchmark.test.ts +0 -30
  43. package/src/__tests__/config-watcher.test.ts +1 -1
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
  48. package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
  49. package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
  50. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  51. package/src/__tests__/conversation-history-web-search.test.ts +11 -1
  52. package/src/__tests__/conversation-pairing.test.ts +4 -31
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
  54. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
  55. package/src/__tests__/conversation-queue.test.ts +2 -0
  56. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
  57. package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
  58. package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
  59. package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
  60. package/src/__tests__/conversation-slash-commands.test.ts +8 -42
  61. package/src/__tests__/conversation-slash-queue.test.ts +6 -1
  62. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  63. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
  64. package/src/__tests__/conversation-sync-tags.test.ts +27 -15
  65. package/src/__tests__/conversation-title-service.test.ts +135 -2
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
  67. package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
  69. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  70. package/src/__tests__/cross-provider-web-search.test.ts +214 -1
  71. package/src/__tests__/db-acp-history.test.ts +101 -0
  72. package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
  73. package/src/__tests__/dm-persistence.test.ts +5 -1
  74. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  75. package/src/__tests__/empty-response-hook.test.ts +304 -0
  76. package/src/__tests__/feature-flag-test-helpers.ts +2 -2
  77. package/src/__tests__/file-write-tool.test.ts +63 -0
  78. package/src/__tests__/gateway-only-guard.test.ts +12 -2
  79. package/src/__tests__/gemini-image-service.test.ts +13 -0
  80. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  81. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  82. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  83. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  84. package/src/__tests__/heartbeat-service.test.ts +1 -0
  85. package/src/__tests__/helpers/mock-provider.ts +110 -0
  86. package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
  87. package/src/__tests__/history-repair-hook.test.ts +1 -0
  88. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  89. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  90. package/src/__tests__/identity-intro-cache.test.ts +12 -100
  91. package/src/__tests__/identity-routes.test.ts +248 -7
  92. package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
  93. package/src/__tests__/injector-background-turn.test.ts +3 -9
  94. package/src/__tests__/injector-chain.test.ts +139 -275
  95. package/src/__tests__/injector-disk-pressure.test.ts +75 -41
  96. package/src/__tests__/injector-document-comments.test.ts +3 -3
  97. package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
  98. package/src/__tests__/injector-v3-suppression.test.ts +31 -37
  99. package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
  100. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  101. package/src/__tests__/list-messages-page-latest.test.ts +60 -0
  102. package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
  103. package/src/__tests__/llm-usage-store.test.ts +223 -1
  104. package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
  105. package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
  106. package/src/__tests__/native-web-search.test.ts +191 -0
  107. package/src/__tests__/onboarding-template-contract.test.ts +2 -0
  108. package/src/__tests__/openai-image-service.test.ts +17 -0
  109. package/src/__tests__/openai-provider.test.ts +31 -1
  110. package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
  111. package/src/__tests__/persist-unsendable-image.test.ts +215 -0
  112. package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
  113. package/src/__tests__/pkb-autoinject.test.ts +2 -5
  114. package/src/__tests__/plugin-api-shim.test.ts +3 -6
  115. package/src/__tests__/plugin-bootstrap.test.ts +14 -40
  116. package/src/__tests__/plugin-registry.test.ts +3 -76
  117. package/src/__tests__/plugin-types.test.ts +0 -193
  118. package/src/__tests__/process-message-display-content.test.ts +6 -2
  119. package/src/__tests__/reaction-persistence.test.ts +1 -1
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
  121. package/src/__tests__/resolve-trust-class.test.ts +4 -4
  122. package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
  123. package/src/__tests__/schedule-routes.test.ts +603 -2
  124. package/src/__tests__/schedule-store.test.ts +41 -0
  125. package/src/__tests__/schedule-tools.test.ts +35 -0
  126. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  127. package/src/__tests__/server-history-render.test.ts +314 -1
  128. package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
  129. package/src/__tests__/skillssh-files.test.ts +1 -1
  130. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  131. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  132. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  133. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  134. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  135. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  136. package/src/__tests__/system-prompt.test.ts +20 -0
  137. package/src/__tests__/task-scheduler.test.ts +162 -1
  138. package/src/__tests__/terminal-tools.test.ts +6 -1
  139. package/src/__tests__/title-generate-hook.test.ts +319 -0
  140. package/src/__tests__/tool-error-hook.test.ts +278 -0
  141. package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
  142. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  143. package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
  144. package/src/__tests__/tool-result-truncation.test.ts +0 -2
  145. package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
  146. package/src/__tests__/ui-work-result-surface.test.ts +159 -0
  147. package/src/__tests__/usage-routes.test.ts +285 -1
  148. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  149. package/src/__tests__/voice-session-bridge.test.ts +6 -3
  150. package/src/__tests__/web-search-backend-failure.test.ts +166 -0
  151. package/src/acp/__tests__/agent-process.test.ts +161 -0
  152. package/src/acp/__tests__/client-handler.test.ts +40 -0
  153. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  154. package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
  155. package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
  156. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  157. package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
  158. package/src/acp/agent-process.ts +61 -1
  159. package/src/acp/auto-install.test.ts +196 -0
  160. package/src/acp/auto-install.ts +177 -0
  161. package/src/acp/client-handler.ts +31 -0
  162. package/src/acp/feature-gate.test.ts +48 -0
  163. package/src/acp/feature-gate.ts +34 -0
  164. package/src/acp/prepare-agent-env.ts +83 -29
  165. package/src/acp/resolve-agent.test.ts +320 -7
  166. package/src/acp/resolve-agent.ts +182 -18
  167. package/src/acp/resume-hint.ts +25 -0
  168. package/src/acp/session-manager.ts +495 -73
  169. package/src/acp/types.ts +8 -0
  170. package/src/agent/compaction-circuit.ts +60 -102
  171. package/src/agent/loop.ts +362 -485
  172. package/src/api/events/assistant-thinking-delta.ts +33 -0
  173. package/src/api/events/tool-output-chunk.ts +45 -0
  174. package/src/api/events/tool-use-preview-start.ts +32 -0
  175. package/src/api/events/trace-event.ts +69 -0
  176. package/src/api/index.ts +48 -13
  177. package/src/api/responses/conversation-message.ts +374 -0
  178. package/src/approvals/guardian-request-resolvers.ts +1 -1
  179. package/src/avatar/__tests__/avatar-store.test.ts +34 -29
  180. package/src/background-wake/next-wake.ts +1 -0
  181. package/src/cli/commands/__tests__/notifications.test.ts +58 -14
  182. package/src/cli/commands/notifications.ts +112 -60
  183. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  184. package/src/config/acp-defaults.test.ts +10 -0
  185. package/src/config/acp-defaults.ts +6 -0
  186. package/src/config/assistant-feature-flags.ts +22 -11
  187. package/src/config/bundled-skills/acp/SKILL.md +83 -31
  188. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  189. package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
  190. package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
  191. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  192. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  193. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  194. package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
  195. package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
  196. package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
  197. package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
  198. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  199. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  200. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  201. package/src/config/bundled-skills/messaging/SKILL.md +0 -7
  202. package/src/config/bundled-tool-registry.ts +2 -0
  203. package/src/config/feature-flag-cache.ts +3 -3
  204. package/src/config/feature-flag-registry.json +48 -7
  205. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  206. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
  207. package/src/config/schemas/heartbeat.ts +9 -0
  208. package/src/config/schemas/llm.ts +1 -0
  209. package/src/config/schemas/memory-v2.ts +8 -0
  210. package/src/config/schemas/memory-v3.ts +8 -0
  211. package/src/config/schemas/platform.ts +8 -0
  212. package/src/config/seed-inference-profiles.ts +2 -2
  213. package/src/config/skills.ts +13 -0
  214. package/src/context/compactor.ts +1 -1
  215. package/src/context/strip-injections.ts +128 -0
  216. package/src/context/token-estimator.ts +23 -0
  217. package/src/context/tool-result-truncation.ts +0 -23
  218. package/src/context/window-manager.ts +5 -7
  219. package/src/credential-execution/executable-discovery.ts +16 -0
  220. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
  221. package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
  222. package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
  223. package/src/daemon/assistant-attachments.ts +1 -1
  224. package/src/daemon/config-watcher.ts +2 -2
  225. package/src/daemon/context-overflow-reducer.ts +0 -1
  226. package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
  227. package/src/daemon/conversation-agent-loop.ts +301 -997
  228. package/src/daemon/conversation-history.ts +5 -4
  229. package/src/daemon/conversation-lifecycle.ts +3 -4
  230. package/src/daemon/conversation-messaging.ts +7 -6
  231. package/src/daemon/conversation-process.ts +11 -16
  232. package/src/daemon/conversation-registry.ts +159 -0
  233. package/src/daemon/conversation-runtime-assembly.ts +218 -398
  234. package/src/daemon/conversation-slash.ts +6 -25
  235. package/src/daemon/conversation-store.ts +9 -90
  236. package/src/daemon/conversation-surfaces.ts +222 -4
  237. package/src/daemon/conversation-tool-setup.ts +2 -29
  238. package/src/daemon/conversation-workspace.ts +17 -0
  239. package/src/daemon/conversation.ts +32 -20
  240. package/src/daemon/external-plugins-bootstrap.ts +17 -18
  241. package/src/daemon/handlers/config-a2a.ts +51 -36
  242. package/src/daemon/handlers/config-slack-channel.ts +20 -14
  243. package/src/daemon/handlers/config-telegram.ts +16 -2
  244. package/src/daemon/handlers/conversations.ts +3 -1
  245. package/src/daemon/handlers/shared.ts +156 -84
  246. package/src/daemon/handlers/skills.ts +42 -10
  247. package/src/daemon/lifecycle.ts +25 -0
  248. package/src/daemon/message-types/apps.ts +1 -29
  249. package/src/daemon/message-types/messages.ts +9 -57
  250. package/src/daemon/message-types/skills.ts +2 -0
  251. package/src/daemon/message-types/surfaces.ts +136 -3
  252. package/src/daemon/now-scratchpad.ts +21 -0
  253. package/src/daemon/orphan-reaper.test.ts +210 -0
  254. package/src/daemon/orphan-reaper.ts +240 -0
  255. package/src/daemon/overflow-reduction-loop.ts +230 -0
  256. package/src/daemon/persist-unsendable-image.ts +117 -0
  257. package/src/daemon/process-message.ts +1 -3
  258. package/src/daemon/server.ts +2 -0
  259. package/src/daemon/trace-emitter.ts +6 -4
  260. package/src/daemon/trust-context.ts +19 -0
  261. package/src/daemon/wake-target-adapter.ts +3 -1
  262. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  263. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  264. package/src/heartbeat/heartbeat-service.ts +26 -0
  265. package/src/home/home-greeting-cache.ts +24 -1
  266. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  267. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  268. package/src/ipc/gateway-client.test.ts +2 -2
  269. package/src/ipc/gateway-client.ts +3 -3
  270. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  271. package/src/ipc/skill-routes/memory.ts +4 -2
  272. package/src/media/gemini-image-service.ts +15 -0
  273. package/src/media/openai-image-service.ts +14 -0
  274. package/src/media/types.ts +34 -0
  275. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
  276. package/src/memory/auth-fallback-events-store.ts +94 -0
  277. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  278. package/src/memory/conversation-title-service.ts +65 -41
  279. package/src/memory/db-init.ts +6 -0
  280. package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
  281. package/src/memory/graph/conversation-graph-memory.ts +65 -0
  282. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  283. package/src/memory/jobs-store.ts +33 -0
  284. package/src/memory/jobs-worker.ts +32 -5
  285. package/src/memory/llm-usage-store.ts +224 -50
  286. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
  287. package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
  288. package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
  289. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  290. package/src/memory/migrations/index.ts +3 -0
  291. package/src/memory/pkb/autoinject.ts +61 -0
  292. package/src/memory/pkb/context.ts +50 -0
  293. package/src/memory/pkb/types.ts +14 -0
  294. package/src/memory/schedule-attribution-sql.ts +104 -0
  295. package/src/memory/schema/acp.ts +4 -0
  296. package/src/memory/schema/infrastructure.ts +16 -0
  297. package/src/memory/usage-grouped-buckets.ts +6 -1
  298. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
  299. package/src/memory/v2/consolidation-job.ts +14 -5
  300. package/src/notifications/conversation-pairing.ts +8 -15
  301. package/src/notifications/decision-engine.ts +6 -3
  302. package/src/notifications/home-feed-side-effect.ts +12 -1
  303. package/src/permissions/prompter.ts +4 -0
  304. package/src/plugin-api/constants.ts +4 -0
  305. package/src/plugin-api/index.ts +7 -5
  306. package/src/plugin-api/types.ts +151 -1
  307. package/src/plugins/defaults/compaction/compact.ts +59 -0
  308. package/src/plugins/defaults/compaction/package.json +1 -1
  309. package/src/plugins/defaults/compaction/register.ts +8 -19
  310. package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
  311. package/src/plugins/defaults/empty-response/register.ts +8 -13
  312. package/src/plugins/defaults/index.ts +2 -18
  313. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
  314. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
  315. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
  316. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
  317. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
  318. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
  319. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
  321. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
  322. package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
  323. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
  324. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
  325. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
  326. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
  328. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
  329. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
  330. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
  331. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
  332. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  333. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  334. package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
  335. package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
  336. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
  337. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
  338. package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
  339. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
  340. package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
  341. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
  342. package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
  343. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
  344. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
  345. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
  346. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
  347. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
  348. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
  349. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
  350. package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
  351. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
  352. package/src/plugins/defaults/title-generate/package.json +1 -1
  353. package/src/plugins/defaults/title-generate/register.ts +18 -18
  354. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
  355. package/src/plugins/defaults/tool-error/package.json +1 -1
  356. package/src/plugins/defaults/tool-error/register.ts +9 -21
  357. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
  358. package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
  359. package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
  360. package/src/plugins/external-api.ts +2 -2
  361. package/src/plugins/pipeline.ts +6 -305
  362. package/src/plugins/registry.ts +10 -55
  363. package/src/plugins/types.ts +62 -797
  364. package/src/plugins/user-loader.ts +30 -127
  365. package/src/proactive-artifact/aux-message-injector.ts +4 -4
  366. package/src/proactive-artifact/job.test.ts +8 -13
  367. package/src/prompts/__tests__/system-prompt.test.ts +42 -0
  368. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
  369. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  370. package/src/prompts/templates/system-sections.ts +15 -0
  371. package/src/providers/anthropic/client.ts +37 -29
  372. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
  373. package/src/providers/openai/chat-completions-provider.ts +44 -0
  374. package/src/providers/openrouter/client.ts +1 -0
  375. package/src/providers/placeholder-sentinels.ts +35 -0
  376. package/src/runtime/__tests__/agent-wake.test.ts +10 -6
  377. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  378. package/src/runtime/agent-wake.ts +2 -5
  379. package/src/runtime/assistant-event-hub.ts +37 -7
  380. package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
  381. package/src/runtime/channel-approvals.ts +1 -1
  382. package/src/runtime/http-router.ts +16 -21
  383. package/src/runtime/http-types.ts +16 -70
  384. package/src/runtime/interactive-ui.ts +1 -1
  385. package/src/runtime/pending-interactions.ts +1 -0
  386. package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
  387. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
  388. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  389. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
  390. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
  391. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  392. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  393. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  394. package/src/runtime/routes/acp-routes.test.ts +89 -25
  395. package/src/runtime/routes/acp-routes.ts +81 -29
  396. package/src/runtime/routes/app-management-routes.ts +6 -117
  397. package/src/runtime/routes/app-routes.ts +13 -15
  398. package/src/runtime/routes/approval-routes.ts +1 -1
  399. package/src/runtime/routes/attachment-routes.ts +26 -15
  400. package/src/runtime/routes/avatar-routes.ts +26 -0
  401. package/src/runtime/routes/browser-routes.ts +1 -1
  402. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  403. package/src/runtime/routes/btw-routes.ts +29 -23
  404. package/src/runtime/routes/consolidation-routes.ts +120 -20
  405. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  406. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  407. package/src/runtime/routes/conversation-query-routes.ts +3 -1
  408. package/src/runtime/routes/conversation-routes.ts +372 -185
  409. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  410. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  411. package/src/runtime/routes/documents-routes.ts +4 -0
  412. package/src/runtime/routes/domain-routes.ts +51 -37
  413. package/src/runtime/routes/epoch-millis-range.ts +34 -0
  414. package/src/runtime/routes/events-routes.ts +28 -34
  415. package/src/runtime/routes/gateway-log-routes.ts +26 -4
  416. package/src/runtime/routes/heartbeat-routes.ts +32 -12
  417. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  418. package/src/runtime/routes/host-cu-routes.ts +1 -1
  419. package/src/runtime/routes/identity-intro-cache.ts +11 -34
  420. package/src/runtime/routes/identity-routes.ts +224 -18
  421. package/src/runtime/routes/image-generation-routes.ts +40 -2
  422. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  423. package/src/runtime/routes/index.ts +2 -0
  424. package/src/runtime/routes/integrations/a2a.ts +12 -10
  425. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
  426. package/src/runtime/routes/integrations/slack/channel.ts +4 -0
  427. package/src/runtime/routes/integrations/slack/share.ts +27 -6
  428. package/src/runtime/routes/integrations/telegram.ts +6 -0
  429. package/src/runtime/routes/integrations/twilio.ts +42 -0
  430. package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
  431. package/src/runtime/routes/log-export-routes.ts +8 -0
  432. package/src/runtime/routes/memory-v2-routes.ts +15 -8
  433. package/src/runtime/routes/memory-v3-routes.ts +66 -34
  434. package/src/runtime/routes/oauth-apps.ts +66 -12
  435. package/src/runtime/routes/oauth-providers.ts +44 -5
  436. package/src/runtime/routes/platform-routes.ts +81 -5
  437. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
  438. package/src/runtime/routes/playground/force-compact.ts +1 -1
  439. package/src/runtime/routes/playground/helpers.ts +1 -1
  440. package/src/runtime/routes/rename-conversation-routes.ts +5 -0
  441. package/src/runtime/routes/schedule-routes.ts +152 -42
  442. package/src/runtime/routes/secret-routes.ts +14 -2
  443. package/src/runtime/routes/skills-routes.ts +43 -14
  444. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  445. package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
  446. package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
  447. package/src/runtime/routes/trust-rules-routes.ts +26 -2
  448. package/src/runtime/routes/tts-routes.ts +35 -0
  449. package/src/runtime/routes/types.ts +66 -8
  450. package/src/runtime/routes/usage-routes.ts +47 -39
  451. package/src/runtime/routes/webhook-routes.ts +41 -2
  452. package/src/runtime/routes/work-items-routes.ts +2 -4
  453. package/src/runtime/routes/workspace-routes.ts +4 -0
  454. package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
  455. package/src/runtime/services/analyze-conversation.ts +2 -2
  456. package/src/runtime/services/conversation-serializer.ts +1 -1
  457. package/src/schedule/schedule-store.ts +20 -1
  458. package/src/schedule/schedule-usage-store.ts +83 -0
  459. package/src/schedule/scheduler.ts +12 -5
  460. package/src/signals/cancel.ts +2 -4
  461. package/src/skills/catalog-files.ts +2 -2
  462. package/src/skills/catalog-install.ts +3 -0
  463. package/src/skills/categories-cache.ts +118 -0
  464. package/src/skills/clawhub-files.ts +1 -2
  465. package/src/skills/skillssh-files.ts +1 -2
  466. package/src/subagent/manager.ts +17 -5
  467. package/src/telemetry/types.ts +29 -1
  468. package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
  469. package/src/telemetry/usage-telemetry-reporter.ts +57 -2
  470. package/src/tools/acp/context.ts +20 -0
  471. package/src/tools/acp/list-agents.test.ts +7 -1
  472. package/src/tools/acp/spawn.test.ts +158 -55
  473. package/src/tools/acp/spawn.ts +47 -72
  474. package/src/tools/acp/steer.test.ts +105 -8
  475. package/src/tools/acp/steer.ts +48 -17
  476. package/src/tools/apps/executors.ts +13 -8
  477. package/src/tools/executor.ts +1 -53
  478. package/src/tools/filesystem/write.ts +34 -0
  479. package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
  480. package/src/tools/network/__tests__/web-search.test.ts +11 -3
  481. package/src/tools/network/web-search-error.test.ts +248 -0
  482. package/src/tools/network/web-search-error.ts +267 -0
  483. package/src/tools/network/web-search.ts +207 -48
  484. package/src/tools/schedule/create.ts +2 -0
  485. package/src/tools/subagent/spawn.ts +2 -4
  486. package/src/tools/terminal/safe-env.ts +10 -1
  487. package/src/tools/ui-surface/definitions.ts +34 -5
  488. package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
  489. package/src/tts/provider-catalog.ts +76 -1
  490. package/src/util/mutex.ts +47 -0
  491. package/src/workspace/git-service.ts +1 -42
  492. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  493. package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
  494. package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
  495. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
  496. package/src/workspace/migrations/registry.ts +6 -0
  497. package/docs/plugins.md +0 -836
  498. package/examples/plugins/echo/register.ts +0 -184
  499. package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
  500. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  501. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  502. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  503. package/src/__tests__/empty-response-pipeline.test.ts +0 -423
  504. package/src/__tests__/llm-call-pipeline.test.ts +0 -287
  505. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
  506. package/src/__tests__/persistence-pipeline.test.ts +0 -503
  507. package/src/__tests__/pipeline-runner.test.ts +0 -564
  508. package/src/__tests__/title-generate-pipeline.test.ts +0 -211
  509. package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
  510. package/src/__tests__/tool-error-pipeline.test.ts +0 -241
  511. package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
  512. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
  513. package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
  514. package/src/gallery/default-gallery.ts +0 -1359
  515. package/src/gallery/gallery-manifest.ts +0 -28
  516. package/src/home/feature-gate.ts +0 -22
  517. package/src/memory/v3/provider-blocks.ts +0 -16
  518. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  519. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  520. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  521. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  522. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  523. package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
  524. package/src/plugins/defaults/empty-response/terminal.ts +0 -106
  525. package/src/plugins/defaults/injectors/package.json +0 -15
  526. package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
  527. package/src/plugins/defaults/llm-call/register.ts +0 -45
  528. package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
  529. package/src/plugins/defaults/memory-retrieval/package.json +0 -15
  530. package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
  531. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  532. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  533. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  534. package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
  535. package/src/plugins/defaults/persistence/package.json +0 -15
  536. package/src/plugins/defaults/persistence/register.ts +0 -38
  537. package/src/plugins/defaults/persistence/terminal.ts +0 -83
  538. package/src/plugins/defaults/title-generate/terminal.ts +0 -31
  539. package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
  540. package/src/plugins/defaults/token-estimate/package.json +0 -15
  541. package/src/plugins/defaults/token-estimate/register.ts +0 -34
  542. package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
  543. package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
  544. package/src/plugins/defaults/tool-error/terminal.ts +0 -47
  545. package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
  546. package/src/plugins/defaults/tool-execute/package.json +0 -15
  547. package/src/plugins/defaults/tool-execute/register.ts +0 -49
  548. package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
  549. package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
  550. package/src/skills/category-inference.ts +0 -111
  551. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
  552. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
  553. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  554. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  555. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
  556. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
  557. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
  558. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
  559. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  560. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  561. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
  562. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  563. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  564. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  565. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  566. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  567. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  568. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
  569. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
  570. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
@@ -46,6 +46,14 @@ export interface TurnContext {
46
46
  turnNumber: number;
47
47
  currentMessage: string;
48
48
  recentContext: string;
49
+ /**
50
+ * Optional situational signal — the current date plus the live NOW.md
51
+ * scratchpad — so a leaf or page can be routed/selected on a date or
52
+ * live-state cue the message itself never names (e.g. a person whose
53
+ * anniversary is today). Omitted when unavailable; the router and selector
54
+ * render nothing for an undefined value.
55
+ */
56
+ situationalContext?: string;
49
57
  }
50
58
 
51
59
  export type SelectionSource = "l1+l2" | "core+l2" | "needle" | "carry-forward";
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Default `stop` hook: triggers the second-pass conversation-title
3
+ * regeneration once a conversation has accumulated enough context.
4
+ *
5
+ * The first title is generated from the opening prompt alone (see
6
+ * `./user-prompt-submit.ts`). After a few exchanges the conversation's real
7
+ * topic is usually clearer, so a single second pass re-titles using the most
8
+ * recent messages. This hook is the trigger — it fires the regeneration when
9
+ * the conversation reaches its third user turn — and delegates the title
10
+ * itself to the service (`memory/conversation-title-service.ts`), which
11
+ * re-checks that the title is still auto-generated, resolves the title
12
+ * provider, persists, and broadcasts the `conversation_title_updated` /
13
+ * `sync_changed` events.
14
+ *
15
+ * Turn count is read from history rather than an external counter: the number
16
+ * of genuine user prompts — user-role messages that aren't purely tool results
17
+ * — is the conversation's turn number. Deriving it from history keeps the hook
18
+ * stateless and means a mid-run array rewrite (compaction) can't invalidate it.
19
+ */
20
+
21
+ import type { PluginHookFn, StopContext } from "@vellumai/plugin-api";
22
+
23
+ import { getConfig } from "../../../../config/loader.js";
24
+ import { queueRegenerateConversationTitle } from "../../../../memory/conversation-title-service.js";
25
+ import type { Message } from "../../../../providers/types.js";
26
+
27
+ /**
28
+ * User turn at which the second title pass fires. Matches the
29
+ * `conversations.skipAutoRetitling` opt-out, documented as skipping the
30
+ * regeneration "that fires after the third user turn".
31
+ */
32
+ const SECOND_PASS_USER_TURN = 3;
33
+
34
+ /** A user-role message carrying only tool results, not a fresh prompt. */
35
+ function isToolResultMessage(message: Message): boolean {
36
+ return (
37
+ message.role === "user" &&
38
+ message.content.length > 0 &&
39
+ message.content.every((block) => block.type === "tool_result")
40
+ );
41
+ }
42
+
43
+ /** Count of genuine user prompts in history — the conversation's turn number. */
44
+ function countUserTurns(messages: ReadonlyArray<Message>): number {
45
+ let turns = 0;
46
+ for (const message of messages) {
47
+ if (message.role === "user" && !isToolResultMessage(message)) turns++;
48
+ }
49
+ return turns;
50
+ }
51
+
52
+ const stop: PluginHookFn<StopContext> = async (ctx) => {
53
+ // Only re-title at a genuine turn end. A `"continue"` decision means an
54
+ // earlier hook is re-querying the model (e.g. an empty-response nudge), so
55
+ // defer to the eventual terminal stop.
56
+ if (ctx.decision !== "stop") return;
57
+
58
+ if (getConfig().conversations.skipAutoRetitling) return;
59
+
60
+ if (countUserTurns(ctx.messages) !== SECOND_PASS_USER_TURN) return;
61
+
62
+ const { conversationId } = ctx;
63
+ // Deferred to a later macrotask so the just-completed turn lands first. The
64
+ // hook fires at the stop boundary, before the loop appends the turn's
65
+ // assistant reply to history and emits `message_complete` (which persists
66
+ // it). The service regenerates from the most recent stored messages, so it
67
+ // must run after the reply is persisted to reflect it. The service is itself
68
+ // fire-and-forget and re-checks replaceability, owning provider resolution,
69
+ // persistence, and the resulting broadcast.
70
+ setTimeout(() => {
71
+ queueRegenerateConversationTitle({ conversationId });
72
+ }, 0);
73
+ };
74
+
75
+ export default stop;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Default `user-prompt-submit` hook: kicks off conversation-title generation
3
+ * from the submitted prompt.
4
+ *
5
+ * Title generation is a self-contained side effect that only needs the user's
6
+ * prompt as context, so it belongs at the prompt-submit boundary rather than
7
+ * threaded through the agent loop. The hook is a pure trigger — it schedules
8
+ * the work and returns; persistence and the resulting
9
+ * `conversation_title_updated` / `sync_changed` broadcast are owned by the
10
+ * title service (see `memory/conversation-title-service.ts`).
11
+ */
12
+
13
+ import type {
14
+ PluginHookFn,
15
+ UserPromptSubmitContext,
16
+ } from "@vellumai/plugin-api";
17
+
18
+ import { queueGenerateConversationTitle } from "../../../../memory/conversation-title-service.js";
19
+
20
+ const userPromptSubmit: PluginHookFn<UserPromptSubmitContext> = async (ctx) => {
21
+ // Deferred to a later macrotask so the main agent-loop LLM request is
22
+ // issued first; on strict single-slot provider configs this keeps the
23
+ // background title call from claiming the rate-limit slot ahead of the
24
+ // user-visible response. The title service is itself fire-and-forget and
25
+ // re-checks title replaceability before making any LLM call, so an
26
+ // already-titled conversation incurs no generation.
27
+ setTimeout(() => {
28
+ queueGenerateConversationTitle({
29
+ conversationId: ctx.conversationId,
30
+ userMessage: ctx.prompt,
31
+ });
32
+ }, 0);
33
+ };
34
+
35
+ export default userPromptSubmit;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "default-title-generate",
3
3
  "version": "1.0.0",
4
- "description": "First-party default plugin wrapping the assistant's built-in title-generate pipeline with a passthrough implementation.",
4
+ "description": "First-party default plugin that triggers conversation-title generation from the user-prompt-submit hook.",
5
5
  "private": true,
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -1,11 +1,17 @@
1
1
  /**
2
- * Default `titleGenerate` pipeline plugin.
2
+ * Default `title-generate` plugin.
3
3
  *
4
- * Declares no middleware the terminal handler in `./terminal.ts` is wired in
5
- * as the pipeline's `terminal` argument by the `runPipeline` call site in
6
- * `daemon/conversation-agent-loop.ts`. This plugin exists purely to negotiate
7
- * the `titleGenerateApi` capability so bootstrap has a record that the
8
- * assistant runtime exposes this pipeline.
4
+ * Contributes two hooks, both pure triggers that delegate the title work to
5
+ * the service (`memory/conversation-title-service.ts`):
6
+ *
7
+ * - `user-prompt-submit` (`./hooks/user-prompt-submit.ts`) first-pass title
8
+ * generation from the submitted prompt.
9
+ * - `stop` (`./hooks/stop.ts`) — second-pass regeneration once the
10
+ * conversation reaches its third user turn, for a title that reflects the
11
+ * established topic.
12
+ *
13
+ * Persistence and the resulting `conversation_title_updated` / `sync_changed`
14
+ * broadcast are owned by the title service.
9
15
  *
10
16
  * Registered via a side-effect import from
11
17
  * `daemon/external-plugins-bootstrap.ts` so it is present in the registry
@@ -13,23 +19,17 @@
13
19
  */
14
20
 
15
21
  import { type Plugin } from "../../types.js";
22
+ import stop from "./hooks/stop.js";
23
+ import userPromptSubmit from "./hooks/user-prompt-submit.js";
16
24
  import pkg from "./package.json" with { type: "json" };
17
25
 
18
- /**
19
- * Default titleGenerate plugin. Declares no middleware — it exists purely
20
- * to negotiate the `titleGenerateApi` capability so bootstrap has a record
21
- * that the assistant runtime exposes this pipeline.
22
- *
23
- * The terminal handler (`./terminal.ts`) is supplied at the call site in
24
- * `conversation-agent-loop.ts` rather than through `middleware.titleGenerate`,
25
- * because a default middleware would short-circuit user-registered middleware
26
- * by always running first in onion order. Keeping the terminal outside the
27
- * middleware chain lets user plugins observe/transform/short-circuit the
28
- * call without competing with an assistant-owned default middleware.
29
- */
30
26
  export const defaultTitleGeneratePlugin: Plugin = {
31
27
  manifest: {
32
28
  name: pkg.name,
33
29
  version: pkg.version,
34
30
  },
31
+ hooks: {
32
+ "user-prompt-submit": userPromptSubmit,
33
+ stop,
34
+ },
35
35
  };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Default `post-tool-use` hook: when a tool result carries `is_error`, set
3
+ * `additionalContext` with a system-notice that coaches the model to either
4
+ * retry with corrected parameters (for recoverable errors) or report the
5
+ * failure to the user (for unrecoverable ones).
6
+ *
7
+ * The coaching is delivered via `additionalContext`, not by mutating the tool
8
+ * result's `content`. The loop appends it to the provider-bound history as a
9
+ * separate block after the tool_result event is emitted, so the model sees the
10
+ * guidance while the client-facing and persisted tool output stay the tool's
11
+ * actual result. This mirrors how Claude Code (`additionalContext`) and Codex
12
+ * (`additional_contexts`) surface PostToolUse feedback as separate context
13
+ * rather than rewriting the tool response.
14
+ *
15
+ * The coaching is bounded per tool: once a single tool has failed
16
+ * `MAX_CONSECUTIVE_ERROR_NUDGES` times in a row the notice is dropped — the
17
+ * error is likely not something the model can fix on its own, and continuing
18
+ * to coach a retry only burns tokens. The consecutive-failure count is derived
19
+ * from the conversation history (the trailing run of error results for this
20
+ * tool name, plus the current one) rather than a loop-held counter, so the
21
+ * guard survives mid-run compaction rewriting the history array. A successful
22
+ * result for the tool resets its streak.
23
+ */
24
+
25
+ import type { PluginHookFn, PostToolUseContext } from "@vellumai/plugin-api";
26
+
27
+ import type { Message } from "../../../../providers/types.js";
28
+
29
+ /**
30
+ * Canonical tool-error coaching text. Kept as a module-level constant so tests
31
+ * and plugins that wrap the default can match it without duplicating the
32
+ * string.
33
+ *
34
+ * This is shown to the model as provider-only context, not the user. Edits
35
+ * here affect retry behavior but not end-user UX directly.
36
+ */
37
+ export const TOOL_ERROR_NUDGE_TEXT =
38
+ "<system_notice>This tool call returned an error. If the error looks recoverable (e.g. missing or invalid parameters), fix the parameters and retry. If the error is clearly unrecoverable (e.g. a service is down, a resource does not exist, or a permission is permanently denied), report it to the user.</system_notice>";
39
+
40
+ /**
41
+ * Number of back-to-back failures of a single tool to coach before giving up.
42
+ * Coaching fires on the 1st through Nth consecutive failure and is dropped from
43
+ * the (N+1)th onward.
44
+ */
45
+ const MAX_CONSECUTIVE_ERROR_NUDGES = 3;
46
+
47
+ /** Map every `tool_use` block id in history to the tool name it invoked. */
48
+ function toolNamesById(messages: ReadonlyArray<Message>): Map<string, string> {
49
+ const names = new Map<string, string>();
50
+ for (const message of messages) {
51
+ if (message.role !== "assistant") continue;
52
+ for (const block of message.content) {
53
+ if (block.type === "tool_use") names.set(block.id, block.name);
54
+ }
55
+ }
56
+ return names;
57
+ }
58
+
59
+ /**
60
+ * Trailing run of consecutive error results for `toolName` already in history.
61
+ * Walks the tool's results in chronological order and counts back from the most
62
+ * recent until a successful result breaks the streak. The current result is not
63
+ * yet in history, so callers add it themselves.
64
+ */
65
+ function priorConsecutiveErrors(
66
+ messages: ReadonlyArray<Message>,
67
+ toolName: string,
68
+ namesById: ReadonlyMap<string, string>,
69
+ ): number {
70
+ const isErrorByOrder: boolean[] = [];
71
+ for (const message of messages) {
72
+ if (message.role !== "user") continue;
73
+ for (const block of message.content) {
74
+ if (block.type !== "tool_result") continue;
75
+ if (namesById.get(block.tool_use_id) !== toolName) continue;
76
+ isErrorByOrder.push(block.is_error === true);
77
+ }
78
+ }
79
+
80
+ let streak = 0;
81
+ for (let i = isErrorByOrder.length - 1; i >= 0; i--) {
82
+ if (!isErrorByOrder[i]) break;
83
+ streak++;
84
+ }
85
+ return streak;
86
+ }
87
+
88
+ const postToolUse: PluginHookFn<PostToolUseContext> = async (ctx) => {
89
+ if (ctx.toolResponse.is_error !== true) return;
90
+
91
+ const namesById = toolNamesById(ctx.messages);
92
+ const toolName = namesById.get(ctx.toolResponse.tool_use_id);
93
+
94
+ // Prior failures of this tool plus the current one. An unresolved name (the
95
+ // current turn's tool_use is always in history, so this is defensive) falls
96
+ // back to coaching this lone failure.
97
+ const consecutiveErrors =
98
+ (toolName === undefined
99
+ ? 0
100
+ : priorConsecutiveErrors(ctx.messages, toolName, namesById)) + 1;
101
+
102
+ if (consecutiveErrors > MAX_CONSECUTIVE_ERROR_NUDGES) {
103
+ ctx.logger.info(
104
+ {
105
+ plugin: "tool-error",
106
+ toolName,
107
+ toolUseId: ctx.toolResponse.tool_use_id,
108
+ consecutiveErrors,
109
+ },
110
+ "Skipping tool-error coaching after repeated consecutive failures",
111
+ );
112
+ return;
113
+ }
114
+
115
+ ctx.additionalContext = TOOL_ERROR_NUDGE_TEXT;
116
+ };
117
+
118
+ export default postToolUse;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "default-tool-error",
3
3
  "version": "1.0.0",
4
- "description": "First-party default plugin wrapping the assistant's built-in tool-error pipeline with a passthrough implementation.",
4
+ "description": "First-party default plugin contributing a post-tool-use hook that coaches the model to retry or report a failed tool call.",
5
5
  "private": true,
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -1,35 +1,23 @@
1
1
  /**
2
- * Default `toolError` plugin.
2
+ * Default `tool-error` plugin.
3
3
  *
4
- * The plugin's middleware is a passthrough it calls `next(args)` and returns
5
- * the result unchanged. The actual nudge-decision logic lives in the terminal
6
- * handler in `./terminal.ts`, which is wired in as the pipeline's `terminal`
7
- * argument by the `runPipeline` call site in `agent/loop.ts`. This separation
8
- * matters: the default plugin is registered before any user plugin (defaults
9
- * load first via module-side-effect imports / `registerDefaultPlugins`), which
10
- * puts it at the OUTERMOST position of the onion chain. If the default
11
- * middleware invoked the decision logic directly without calling `next`, it
12
- * would shadow every later-registered plugin. Routing through `next(args)`
13
- * lets user middleware participate normally.
14
- *
15
- * Design doc: `.private/plans/agent-plugin-system.md` (PR 19).
4
+ * Contributes a `post-tool-use` hook that coaches the model to retry or report
5
+ * a failed tool call, bounded per tool so an unrecoverable error doesn't churn.
6
+ * The coaching is surfaced via `additionalContext` (a separate provider-only
7
+ * block), leaving the tool result's own content untouched. The decision logic
8
+ * lives in `./hooks/post-tool-use.ts`.
16
9
  */
17
10
 
18
11
  import { type Plugin } from "../../types.js";
19
- import defaultToolErrorMiddleware from "./middlewares/toolError.js";
12
+ import postToolUse from "./hooks/post-tool-use.js";
20
13
  import pkg from "./package.json" with { type: "json" };
21
14
 
22
- /**
23
- * Plugin registration for the default `toolError` behavior. Registered by
24
- * `daemon/external-plugins-bootstrap.ts` via a side-effect import so the
25
- * middleware is available to the pipeline runner from daemon startup.
26
- */
27
15
  export const defaultToolErrorPlugin: Plugin = {
28
16
  manifest: {
29
17
  name: pkg.name,
30
18
  version: pkg.version,
31
19
  },
32
- middleware: {
33
- toolError: defaultToolErrorMiddleware,
20
+ hooks: {
21
+ "post-tool-use": postToolUse,
34
22
  },
35
23
  };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Default `post-tool-use` hook: tail-drops an oversized tool result down to a
3
+ * character budget derived from the model's context window, keeping a single
4
+ * result from blowing the provider's context.
5
+ *
6
+ * Defaults register before any user plugin, so this hook runs at the front of
7
+ * the `post-tool-use` chain — every later hook sees an already-bounded result.
8
+ * The hook mutates `toolResponse.content` in place.
9
+ */
10
+
11
+ import type { PluginHookFn, PostToolUseContext } from "@vellumai/plugin-api";
12
+
13
+ import { truncateToolResult } from "../terminal.js";
14
+
15
+ const postToolUse: PluginHookFn<PostToolUseContext> = async (ctx) => {
16
+ const { content, truncated } = truncateToolResult(
17
+ ctx.toolResponse.content,
18
+ ctx.maxInputTokens,
19
+ );
20
+ if (truncated) {
21
+ ctx.toolResponse.content = content;
22
+ ctx.logger.warn(
23
+ {
24
+ plugin: "tool-result-truncate",
25
+ toolUseId: ctx.toolResponse.tool_use_id,
26
+ },
27
+ "Truncated oversized tool result to prevent context overflow",
28
+ );
29
+ }
30
+ };
31
+
32
+ export default postToolUse;
@@ -1,35 +1,24 @@
1
1
  /**
2
- * Default `toolResultTruncate` plugin.
2
+ * Default `tool-result-truncate` plugin.
3
3
  *
4
- * The plugin's middleware is a passthrough it calls `next(args)` and returns
5
- * the result unchanged. The actual truncation lives in the terminal handler in
6
- * `./terminal.ts`, which is wired in as the pipeline's `terminal` argument by
7
- * the `runPipeline` call site in `agent/loop.ts`. This separation matters: the
8
- * default plugin is registered before any user plugin (defaults load first in
9
- * `bootstrapPlugins()`), which puts it at the OUTERMOST position of the onion
10
- * chain. If the default
11
- * middleware were to invoke the terminal directly without calling `next`, it
12
- * would shadow every later-registered plugin (including hot-reloaded ones).
13
- * Routing through `next(args)` lets user middleware participate normally.
14
- *
15
- * Design doc: `.private/plans/agent-plugin-system.md` (PR 17).
4
+ * Contributes a `post-tool-use` hook that tail-drops an oversized tool result
5
+ * down to a character budget derived from the model's context window before
6
+ * the result is sent to the provider. The truncation implementation lives in
7
+ * `./terminal.ts`; the hook in `./hooks/post-tool-use.ts` wires it into the
8
+ * lifecycle. Defaults register before user plugins, so this runs at the front
9
+ * of the hook chain.
16
10
  */
17
11
 
18
12
  import { type Plugin } from "../../types.js";
19
- import toolResultTruncate from "./middlewares/toolResultTruncate.js";
13
+ import postToolUse from "./hooks/post-tool-use.js";
20
14
  import pkg from "./package.json" with { type: "json" };
21
15
 
22
- /**
23
- * Plugin descriptor for the default tool-result truncation middleware.
24
- * Registered by `plugins/defaults/index.ts` so the registry always has at
25
- * least one middleware for the `toolResultTruncate` pipeline.
26
- */
27
16
  export const defaultToolResultTruncatePlugin: Plugin = {
28
17
  manifest: {
29
18
  name: pkg.name,
30
19
  version: pkg.version,
31
20
  },
32
- middleware: {
33
- toolResultTruncate,
21
+ hooks: {
22
+ "post-tool-use": postToolUse,
34
23
  },
35
24
  };
@@ -1,15 +1,11 @@
1
1
  /**
2
- * Default `toolResultTruncate` behavior: tail-drops oversized tool-result text
3
- * down to a character budget, plus the truncation primitive it wraps.
2
+ * Tool-result truncation: tail-drops oversized tool-result text down to a
3
+ * character budget derived from the model's context window, plus the
4
+ * primitives it wraps.
4
5
  *
5
6
  * This module is side-effect free: importing it does not register any plugin.
6
7
  */
7
8
 
8
- import type {
9
- ToolResultTruncateArgs,
10
- ToolResultTruncateResult,
11
- } from "./types.js";
12
-
13
9
  const HIGH_SURROGATE_START = 0xd800;
14
10
  const HIGH_SURROGATE_END = 0xdbff;
15
11
  const LOW_SURROGATE_START = 0xdc00;
@@ -98,16 +94,39 @@ export function truncateToolResultText(text: string, maxChars: number): string {
98
94
  }
99
95
 
100
96
  /**
101
- * Truncate a single tool-result block's content to `args.maxChars`. Exported
102
- * so the agent loop can call it directly and tests can verify the default
103
- * behavior.
97
+ * Maximum share of the context window that a single tool result may occupy.
98
+ */
99
+ const MAX_TOOL_RESULT_CONTEXT_SHARE = 0.3;
100
+
101
+ /**
102
+ * Absolute cap on tool-result characters (~100K tokens).
103
+ */
104
+ export const HARD_MAX_TOOL_RESULT_CHARS = 400_000;
105
+
106
+ /**
107
+ * Calculate the maximum allowed characters for a tool result based on the
108
+ * context window size. Uses ~4 chars per token as a rough heuristic.
109
+ */
110
+ export function calculateMaxToolResultChars(
111
+ contextWindowTokens: number,
112
+ ): number {
113
+ return Math.min(
114
+ HARD_MAX_TOOL_RESULT_CHARS,
115
+ Math.floor(contextWindowTokens * MAX_TOOL_RESULT_CONTEXT_SHARE * 4),
116
+ );
117
+ }
118
+
119
+ /**
120
+ * Truncate a tool result's content to fit the model's context window. Derives
121
+ * the character budget from `maxInputTokens` and tail-drops anything beyond it.
122
+ * Returns the (possibly truncated) content alongside a `truncated` flag the
123
+ * caller can use for telemetry.
104
124
  */
105
- export function defaultToolResultTruncateTerminal(
106
- args: ToolResultTruncateArgs,
107
- ): ToolResultTruncateResult {
108
- const truncated = truncateToolResultText(args.content, args.maxChars);
109
- return {
110
- content: truncated,
111
- truncated: truncated !== args.content,
112
- };
125
+ export function truncateToolResult(
126
+ content: string,
127
+ maxInputTokens: number,
128
+ ): { content: string; truncated: boolean } {
129
+ const maxChars = calculateMaxToolResultChars(maxInputTokens);
130
+ const next = truncateToolResultText(content, maxChars);
131
+ return { content: next, truncated: next !== content };
113
132
  }
@@ -31,8 +31,8 @@
31
31
  * absolute paths or workspace-local copies — the TypeScript compiler erases
32
32
  * them and they have no module-identity effect at runtime.
33
33
  *
34
- * See `assistant/docs/plugins.md` for the full authoring contract and
35
- * `assistant/examples/plugins/echo/register.ts` for a worked example.
34
+ * See `experimental/plugins/README.md` for the full authoring contract and
35
+ * `assistant/examples/plugins/echo/` for a worked example.
36
36
  */
37
37
 
38
38
  import { assistantEventHub } from "../runtime/assistant-event-hub.js";