@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
@@ -1,9 +1,16 @@
1
1
  import { v4 as uuid } from "uuid";
2
2
 
3
+ import type {
4
+ ConversationContentBlock,
5
+ ConversationMessageAttachment,
6
+ ConversationMessageSurface,
7
+ ConversationMessageToolCall,
8
+ } from "../../api/responses/conversation-message.js";
9
+ import { ConfirmationDecisionSchema } from "../../api/responses/conversation-message.js";
3
10
  import { getConfig } from "../../config/loader.js";
4
11
  import type { LLMCallSite, Speed } from "../../config/schemas/llm.js";
5
12
  import type { SecretPromptResult } from "../../permissions/secret-prompter.js";
6
- import { isPlaceholderSentinelText } from "../../providers/anthropic/client.js";
13
+ import { isPlaceholderSentinelText } from "../../providers/placeholder-sentinels.js";
7
14
  import { broadcastMessage } from "../../runtime/assistant-event-hub.js";
8
15
  import type { AuthContext } from "../../runtime/auth/types.js";
9
16
  import { unwrapExternalContentForDisplay } from "../../security/untrusted-content.js";
@@ -30,74 +37,18 @@ const pendingStandaloneSecrets = new Map<
30
37
  }
31
38
  >();
32
39
 
33
- export interface HistoryToolCall {
34
- name: string;
35
- input: Record<string, unknown>;
36
- result?: string;
37
- isError?: boolean;
38
- /** Base64-encoded image data from tool contentBlocks (e.g. browser_screenshot). @deprecated Use imageDataList. */
39
- imageData?: string;
40
- /** Base64-encoded image data from tool contentBlocks (e.g. browser_screenshot, image generation). */
41
- imageDataList?: string[];
42
- /** Unix ms when the tool started executing. */
43
- startedAt?: number;
44
- /** Unix ms when the tool completed. */
45
- completedAt?: number;
46
- /** Confirmation decision for this tool call: "approved" | "denied" | "timed_out". */
47
- confirmationDecision?: string;
48
- /** Friendly label for the confirmation (e.g. "Edit File", "Run Command"). */
49
- confirmationLabel?: string;
50
- /** Risk level classification at invocation time ("low" | "medium" | "high" | "unknown"). */
51
- riskLevel?: string;
52
- /** Human-readable reason for the risk classification. */
53
- riskReason?: string;
54
- /** ID of the trust rule that matched this invocation (if any). */
55
- matchedTrustRuleId?: string;
56
- /**
57
- * @deprecated Use `approvalMode` and `approvalReason` instead.
58
- * Kept for backward compatibility during the migration window.
59
- */
60
- autoApproved?: boolean;
61
- /** How the approval decision was reached: prompted, auto, blocked, or unknown (legacy). */
62
- approvalMode?: string;
63
- /** Why the approval decision was reached (stable enum for client display). */
64
- approvalReason?: string;
65
- /** Snapshot of the auto-approve threshold at execution time. */
66
- riskThreshold?: string;
67
- /**
68
- * Display-only regex ladder for the rule editor (narrowest → broadest).
69
- * Persisted on tool_use blocks by `annotatePersistedAssistantMessage` so
70
- * historical chips render the same ladder as live tool_result events.
71
- */
72
- riskScopeOptions?: Array<{ pattern: string; label: string }>;
73
- /** Minimatch save patterns for the rule editor (narrowest → broadest). */
74
- riskAllowlistOptions?: Array<{
75
- label: string;
76
- description: string;
77
- pattern: string;
78
- }>;
79
- /** Directory scope ladder for the rule editor. */
80
- riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
81
- }
40
+ /**
41
+ * A single tool call rendered into a history row. Alias of the canonical
42
+ * wire-contract type so `renderHistoryContent` (the producer) cannot drift
43
+ * from what the messages endpoint serializes.
44
+ */
45
+ export type HistoryToolCall = ConversationMessageToolCall;
82
46
 
83
- export interface HistorySurface {
84
- surfaceId: string;
85
- surfaceType: string;
86
- title?: string;
87
- data: Record<string, unknown>;
88
- actions?: Array<{
89
- id: string;
90
- label: string;
91
- style?: string;
92
- data?: Record<string, unknown>;
93
- }>;
94
- display?: string;
95
- persistent?: boolean;
96
- completed?: boolean;
97
- completionSummary?: string;
98
- /** Id of the tool call that produced this surface (the `ui_show` proxy tool). Lets the client gate app previews on the tool result's arrival rather than whole-turn streaming state. */
99
- toolCallId?: string;
100
- }
47
+ /**
48
+ * A UI surface (widget) embedded in a history row. Alias of the canonical
49
+ * wire-contract type so the producer matches the serialized shape.
50
+ */
51
+ export type HistorySurface = ConversationMessageSurface;
101
52
 
102
53
  /**
103
54
  * Positional reference to a file attachment captured while walking the
@@ -131,6 +82,16 @@ export interface RenderedHistoryContent {
131
82
  * attachment metadata to this ordering for inline placement.
132
83
  */
133
84
  attachments: HistoryAttachmentRef[];
85
+ /**
86
+ * Unified ordered content blocks built directly from the model-native
87
+ * content during the single walk — the wire `contentBlocks` projection.
88
+ * `attachment` blocks are inlined for file blocks whose DB-hydrated metadata
89
+ * the caller supplies via the `attachmentBlocks` argument (matched by
90
+ * attachment-ref order); a file block with no supplied metadata produces no
91
+ * block. Every other block type is always complete, so the serializer ships
92
+ * this array as-is with no post-processing.
93
+ */
94
+ contentBlocks: ConversationContentBlock[];
134
95
  }
135
96
 
136
97
  /**
@@ -256,6 +217,44 @@ function extractFileBlockMetadata(
256
217
  };
257
218
  }
258
219
 
220
+ /**
221
+ * Build the positional attachment reference for a `file` content block:
222
+ * filename/mime/size from the block's source plus the persisted
223
+ * `_attachmentId` when present (user-uploaded files).
224
+ */
225
+ function fileBlockToAttachmentRef(
226
+ block: Record<string, unknown>,
227
+ meta: FileBlockMetadata,
228
+ ): HistoryAttachmentRef {
229
+ const ref: HistoryAttachmentRef = {
230
+ filename: meta.filename,
231
+ mimeType: meta.mediaType,
232
+ sizeBytes: meta.sizeBytes,
233
+ };
234
+ if (typeof block._attachmentId === "string" && block._attachmentId) {
235
+ ref.attachmentId = block._attachmentId;
236
+ }
237
+ return ref;
238
+ }
239
+
240
+ /**
241
+ * Collect file-block attachment references in content-walk order without
242
+ * building the full history projection. The serializer aligns its DB-hydrated
243
+ * attachment rows against this ordering, then feeds the resolved metadata back
244
+ * into `renderHistoryContent` so it inlines `attachment` blocks during the walk.
245
+ */
246
+ export function collectAttachmentRefs(
247
+ content: unknown,
248
+ ): HistoryAttachmentRef[] {
249
+ if (!Array.isArray(content)) return [];
250
+ const refs: HistoryAttachmentRef[] = [];
251
+ for (const block of content) {
252
+ if (!isRecord(block) || block.type !== "file") continue;
253
+ refs.push(fileBlockToAttachmentRef(block, extractFileBlockMetadata(block)));
254
+ }
255
+ return refs;
256
+ }
257
+
259
258
  function renderFileBlockForHistory(
260
259
  block: Record<string, unknown>,
261
260
  meta: FileBlockMetadata,
@@ -277,7 +276,13 @@ function renderFileBlockForHistory(
277
276
  )}`;
278
277
  }
279
278
 
280
- export function renderHistoryContent(content: unknown): RenderedHistoryContent {
279
+ export function renderHistoryContent(
280
+ content: unknown,
281
+ attachmentBlocks?: ReadonlyArray<
282
+ ConversationMessageAttachment | null | undefined
283
+ >,
284
+ messageId?: string,
285
+ ): RenderedHistoryContent {
281
286
  if (!Array.isArray(content)) {
282
287
  let text: string;
283
288
  if (content == null) {
@@ -296,6 +301,7 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
296
301
  surfaces: [],
297
302
  thinkingSegments: [],
298
303
  attachments: [],
304
+ contentBlocks: text ? [{ type: "text", text }] : [],
299
305
  };
300
306
  }
301
307
 
@@ -316,6 +322,13 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
316
322
  let currentSegmentParts: string[] = [];
317
323
  let hasOpenSegment = false;
318
324
 
325
+ // Unified content blocks built in lockstep with the positional arrays as we
326
+ // walk the model-native content. `attachment` blocks are inlined here when
327
+ // the caller supplied DB-hydrated metadata in `attachmentBlocks`, matched by
328
+ // attachment-ref order; otherwise the file block contributes no block.
329
+ const contentBlocks: ConversationContentBlock[] = [];
330
+ let currentTextBlock: { type: "text"; text: string } | null = null;
331
+
319
332
  function joinWithSpacing(parts: string[]): string {
320
333
  let result = parts[0] ?? "";
321
334
  for (let i = 1; i < parts.length; i++) {
@@ -341,18 +354,42 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
341
354
 
342
355
  function finalizeSegment(): void {
343
356
  if (hasOpenSegment) {
344
- textSegments[textSegments.length - 1] =
345
- joinWithSpacing(currentSegmentParts);
357
+ const joined = joinWithSpacing(currentSegmentParts);
358
+ textSegments[textSegments.length - 1] = joined;
359
+ if (currentTextBlock) {
360
+ currentTextBlock.text = joined;
361
+ currentTextBlock = null;
362
+ }
346
363
  currentSegmentParts = [];
347
364
  hasOpenSegment = false;
348
365
  }
349
366
  }
350
367
 
351
- function ensureSegment(): void {
368
+ // Flush the open text segment into its tracked block and stop tracking it,
369
+ // without closing the segment. Used before folding the synthetic attachment
370
+ // description into the trailing segment: it stays in the legacy
371
+ // `textSegments`/`text` body but must not pollute the clean contentBlocks,
372
+ // since `attachment` blocks already carry that metadata.
373
+ function detachTextBlock(): void {
374
+ if (currentTextBlock) {
375
+ currentTextBlock.text = joinWithSpacing(currentSegmentParts);
376
+ currentTextBlock = null;
377
+ }
378
+ }
379
+
380
+ // `trackBlock` mirrors the segment into `contentBlocks`. The trailing
381
+ // attachment-description segment (legacy `message.text` for clients without
382
+ // attachment UI) sets it false so it isn't duplicated as a text block —
383
+ // attachments surface as `attachment` blocks instead.
384
+ function ensureSegment(trackBlock = true): void {
352
385
  if (!hasOpenSegment) {
353
386
  textSegments.push("");
354
387
  contentOrder.push(`text:${textSegments.length - 1}`);
355
388
  hasOpenSegment = true;
389
+ if (trackBlock) {
390
+ currentTextBlock = { type: "text", text: "" };
391
+ contentBlocks.push(currentTextBlock);
392
+ }
356
393
  }
357
394
  }
358
395
 
@@ -383,6 +420,7 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
383
420
  };
384
421
  surfaces.push(surface);
385
422
  contentOrder.push(`surface:${surfaces.length - 1}`);
423
+ contentBlocks.push({ type: "surface", surface });
386
424
  continue;
387
425
  }
388
426
 
@@ -390,6 +428,7 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
390
428
  finalizeSegment();
391
429
  thinkingSegments.push(block.thinking);
392
430
  contentOrder.push(`thinking:${thinkingSegments.length - 1}`);
431
+ contentBlocks.push({ type: "thinking", thinking: block.thinking });
393
432
  continue;
394
433
  }
395
434
 
@@ -416,16 +455,13 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
416
455
  const meta = extractFileBlockMetadata(block);
417
456
  attachmentParts.push(renderFileBlockForHistory(block, meta));
418
457
  finalizeSegment();
419
- const ref: HistoryAttachmentRef = {
420
- filename: meta.filename,
421
- mimeType: meta.mediaType,
422
- sizeBytes: meta.sizeBytes,
423
- };
424
- if (typeof block._attachmentId === "string" && block._attachmentId) {
425
- ref.attachmentId = block._attachmentId;
458
+ attachments.push(fileBlockToAttachmentRef(block, meta));
459
+ const refIndex = attachments.length - 1;
460
+ contentOrder.push(`attachment:${refIndex}`);
461
+ const hydrated = attachmentBlocks?.[refIndex];
462
+ if (hydrated) {
463
+ contentBlocks.push({ type: "attachment", attachment: hydrated });
426
464
  }
427
- attachments.push(ref);
428
- contentOrder.push(`attachment:${attachments.length - 1}`);
429
465
  continue;
430
466
  }
431
467
  if (block.type === "image") {
@@ -442,13 +478,18 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
442
478
  : {};
443
479
  const id = typeof block.id === "string" ? block.id : "";
444
480
  const entry: HistoryToolCall = { name, input };
481
+ if (id) entry.id = id;
445
482
  // Extract persisted timing/confirmation metadata
446
483
  if (typeof block._startedAt === "number")
447
484
  entry.startedAt = block._startedAt;
448
485
  if (typeof block._completedAt === "number")
449
486
  entry.completedAt = block._completedAt;
450
- if (typeof block._confirmationDecision === "string")
451
- entry.confirmationDecision = block._confirmationDecision;
487
+ const confirmationDecision = ConfirmationDecisionSchema.safeParse(
488
+ block._confirmationDecision,
489
+ );
490
+ if (confirmationDecision.success) {
491
+ entry.confirmationDecision = confirmationDecision.data;
492
+ }
452
493
  if (typeof block._confirmationLabel === "string")
453
494
  entry.confirmationLabel = block._confirmationLabel;
454
495
  if (typeof block._riskLevel === "string")
@@ -477,9 +518,18 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
477
518
  if (Array.isArray(block._riskDirectoryScopeOptions))
478
519
  entry.riskDirectoryScopeOptions =
479
520
  block._riskDirectoryScopeOptions as HistoryToolCall["riskDirectoryScopeOptions"];
521
+ // Read back tool activity (web_search / web_fetch) persisted by
522
+ // `annotatePersistedAssistantMessage` so the activity card survives a
523
+ // history reopen instead of degrading to the plain result text.
524
+ if (isRecord(block._activityMetadata))
525
+ entry.activityMetadata =
526
+ block._activityMetadata as HistoryToolCall["activityMetadata"];
480
527
  toolCalls.push(entry);
481
528
  if (id) pendingToolUses.set(id, entry);
482
529
  contentOrder.push(`tool:${toolCalls.length - 1}`);
530
+ // Same `entry` reference the block carries: a later tool_result pairs its
531
+ // output onto `entry`, so the content block reflects it automatically.
532
+ contentBlocks.push({ type: "tool_use", toolCall: entry });
483
533
  if (!seenToolUse) {
484
534
  seenToolUse = true;
485
535
  if (!seenText) toolCallsBeforeText = true;
@@ -494,9 +544,16 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
494
544
  : {};
495
545
  const id = typeof block.id === "string" ? block.id : "";
496
546
  const entry: HistoryToolCall = { name, input };
547
+ if (id) entry.id = id;
548
+ // Native server tools (Anthropic web_search) persist their activity on
549
+ // the server_tool_use block, so read it back here too.
550
+ if (isRecord(block._activityMetadata))
551
+ entry.activityMetadata =
552
+ block._activityMetadata as HistoryToolCall["activityMetadata"];
497
553
  toolCalls.push(entry);
498
554
  if (id) pendingToolUses.set(id, entry);
499
555
  contentOrder.push(`tool:${toolCalls.length - 1}`);
556
+ contentBlocks.push({ type: "tool_use", toolCall: entry });
500
557
  if (!seenToolUse) {
501
558
  seenToolUse = true;
502
559
  if (!seenText) toolCallsBeforeText = true;
@@ -586,14 +643,28 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
586
643
  // The macOS client handles this by selecting the *first* non-empty text
587
644
  // segment in interleaved content, so trailing attachment segments are safe.
588
645
  if (attachmentParts.length > 0) {
646
+ detachTextBlock();
589
647
  const attachmentText = attachmentParts.join("\n");
590
648
  const prefix = textParts.length > 0 ? "\n" : "";
591
- ensureSegment();
649
+ ensureSegment(false);
592
650
  currentSegmentParts.push(prefix + attachmentText);
593
651
  }
594
652
 
595
653
  finalizeSegment();
596
654
 
655
+ // Default any tool call the provider left without an `id` to the same
656
+ // positional id the web client historically synthesized, so every wire tool
657
+ // call is self-identifying and snapshot/stream ids line up. `idx` indexes the
658
+ // final `toolCalls` array (the client keys off the same positions); the
659
+ // shared `entry` references mean `contentBlocks` reflect this for free.
660
+ if (messageId !== undefined) {
661
+ toolCalls.forEach((toolCall, idx) => {
662
+ if (toolCall.id === undefined) {
663
+ toolCall.id = `tool-history-${messageId}-${idx}`;
664
+ }
665
+ });
666
+ }
667
+
597
668
  const text = joinWithSpacing(textParts);
598
669
  let rendered: string;
599
670
  if (attachmentParts.length === 0) {
@@ -613,6 +684,7 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
613
684
  surfaces,
614
685
  thinkingSegments,
615
686
  attachments,
687
+ contentBlocks,
616
688
  };
617
689
  }
618
690
 
@@ -31,7 +31,10 @@ import {
31
31
  isTextMimeType as isTextMime,
32
32
  MAX_INLINE_TEXT_SIZE,
33
33
  } from "../../runtime/routes/workspace-utils.js";
34
- import { getCatalog } from "../../skills/catalog-cache.js";
34
+ import {
35
+ getCachedCatalogSync,
36
+ getCatalog,
37
+ } from "../../skills/catalog-cache.js";
35
38
  import type { SkillFileEntry } from "../../skills/catalog-files.js";
36
39
  import {
37
40
  catalogSkillToSlim,
@@ -48,7 +51,6 @@ import {
48
51
  installSkillLocally,
49
52
  } from "../../skills/catalog-install.js";
50
53
  import { filterByQuery } from "../../skills/catalog-search.js";
51
- import { inferCategory } from "../../skills/category-inference.js";
52
54
  import type { ClawhubInspectResult } from "../../skills/clawhub.js";
53
55
  import {
54
56
  clawhubCheckUpdates,
@@ -285,6 +287,25 @@ function postInstallSkill(skillId: string): void {
285
287
  refreshSkillCapabilityMemories(getConfig());
286
288
  }
287
289
 
290
+ // ─── Catalog category lookup ────────────────────────────────────────────────
291
+
292
+ let _catalogCategoryMap: Map<string, string> | null = null;
293
+ let _catalogCategoryRef: readonly CatalogSkill[] | null = null;
294
+
295
+ function getCatalogCategoryMap(): Map<string, string> {
296
+ const catalog = getCachedCatalogSync();
297
+ if (_catalogCategoryMap && _catalogCategoryRef === catalog) {
298
+ return _catalogCategoryMap;
299
+ }
300
+ _catalogCategoryMap = new Map();
301
+ for (const s of catalog) {
302
+ const cat = s.metadata?.vellum?.category;
303
+ if (cat) _catalogCategoryMap.set(s.id, cat);
304
+ }
305
+ _catalogCategoryRef = catalog;
306
+ return _catalogCategoryMap;
307
+ }
308
+
288
309
  // ─── Kind / origin / status derivation ───────────────────────────────────────
289
310
 
290
311
  /** Map the old `source` field to the new `kind` axis. */
@@ -328,11 +349,12 @@ function toSlimSkillResponse(
328
349
  const origin = deriveOrigin(kind, summary.directoryPath, installMeta);
329
350
  const status: SlimSkillResponse["status"] = state;
330
351
 
331
- const category = inferCategory(summary.displayName, summary.description);
352
+ const category = getCatalogCategoryMap().get(summary.id) ?? "system";
332
353
  const base = {
333
354
  id: summary.id,
334
355
  name: summary.displayName,
335
356
  description: summary.description,
357
+ icon: summary.icon,
336
358
  emoji: summary.emoji,
337
359
  kind,
338
360
  status,
@@ -395,14 +417,20 @@ export function listSkills(): SlimSkillResponse[] {
395
417
  * Installed skills take precedence when deduplicating by ID.
396
418
  */
397
419
  async function listSkillsWithCatalog(): Promise<SlimSkillResponse[]> {
398
- const installed = listSkills();
399
- const installedIds = new Set(installed.map((s) => s.id));
400
-
420
+ // Warm the catalog cache before converting installed skills so
421
+ // getCatalogCategoryMap() in toSlimSkillResponse() sees real categories
422
+ // instead of falling back to "system" on a cold cache.
401
423
  let catalogSkills: CatalogSkill[];
402
424
  try {
403
425
  catalogSkills = await getCatalog();
404
426
  } catch {
405
- // If catalog fetch fails, return installed-only
427
+ catalogSkills = [];
428
+ }
429
+
430
+ const installed = listSkills();
431
+ const installedIds = new Set(installed.map((s) => s.id));
432
+
433
+ if (catalogSkills.length === 0) {
406
434
  return installed;
407
435
  }
408
436
 
@@ -605,6 +633,7 @@ export async function getSkill(
605
633
  id: slim.id,
606
634
  name: slim.name,
607
635
  description: slim.description,
636
+ icon: slim.icon,
608
637
  emoji: slim.emoji,
609
638
  kind: slim.kind,
610
639
  origin: slim.origin,
@@ -645,6 +674,7 @@ export async function getSkill(
645
674
  id: slim.id,
646
675
  name: slim.name,
647
676
  description: slim.description,
677
+ icon: slim.icon,
648
678
  emoji: slim.emoji,
649
679
  kind: slim.kind,
650
680
  origin: slim.origin,
@@ -676,6 +706,7 @@ export async function getSkill(
676
706
  id: slim.id,
677
707
  name: slim.name,
678
708
  description: slim.description,
709
+ icon: slim.icon,
679
710
  emoji: slim.emoji,
680
711
  kind: slim.kind,
681
712
  origin: slim.origin,
@@ -1365,11 +1396,12 @@ export async function searchSkills(
1365
1396
  id: s.id,
1366
1397
  name: s.displayName,
1367
1398
  description: s.description,
1399
+ icon: s.icon,
1368
1400
  emoji: s.emoji,
1369
1401
  kind: "catalog" as const,
1370
1402
  origin: "vellum" as const,
1371
1403
  status: "available" as const,
1372
- category: inferCategory(s.displayName, s.description),
1404
+ category: getCatalogCategoryMap().get(s.id) ?? "system",
1373
1405
  };
1374
1406
  });
1375
1407
 
@@ -1388,7 +1420,7 @@ export async function searchSkills(
1388
1420
  kind: "catalog" as const,
1389
1421
  origin: "clawhub" as const,
1390
1422
  status: "available" as const,
1391
- category: inferCategory(s.name, s.description),
1423
+ category: "integrations",
1392
1424
  slug: s.slug,
1393
1425
  author: s.author,
1394
1426
  stars: s.stars,
@@ -1415,7 +1447,7 @@ export async function searchSkills(
1415
1447
  kind: "catalog" as const,
1416
1448
  origin: "skillssh" as const,
1417
1449
  status: "available" as const,
1418
- category: inferCategory(r.name, ""),
1450
+ category: "integrations",
1419
1451
  slug: r.id,
1420
1452
  sourceRepo: r.source,
1421
1453
  installs: r.installs,
@@ -98,6 +98,7 @@ import {
98
98
  updateWorkItem,
99
99
  } from "../work-items/work-item-store.js";
100
100
  import { WorkspaceHeartbeatService } from "../workspace/heartbeat-service.js";
101
+ import { repairAdaptiveThinkingOnManagedProfiles } from "../workspace/migrations/097-enable-adaptive-thinking-managed-profiles.js";
101
102
  import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
102
103
  import { runWorkspaceMigrations } from "../workspace/migrations/runner.js";
103
104
  import {
@@ -117,6 +118,7 @@ import {
117
118
  maybeRebuildMemoryV2Concepts,
118
119
  rebuildBm25CorpusStatsAndReseedSkills,
119
120
  } from "./memory-v2-startup.js";
121
+ import { startOrphanReaper, stopOrphanReaper } from "./orphan-reaper.js";
120
122
  import { processMessage } from "./process-message.js";
121
123
  import { runProfilerSweep } from "./profiler-run-store.js";
122
124
  import {
@@ -588,6 +590,26 @@ export async function runDaemon(): Promise<void> {
588
590
  );
589
591
  }
590
592
 
593
+ // Re-run the adaptive thinking repair after overlay merge + profile seeding.
594
+ // Workspace migration 097 enables adaptive thinking on managed profiles, but
595
+ // it runs before mergeDefaultWorkspaceConfig() which can overwrite the fix
596
+ // with overlay profiles that have thinking disabled or absent. On-platform
597
+ // instances where the overlay supplies "balanced" / "quality-optimized"
598
+ // profiles without thinking enabled would be stuck permanently because the
599
+ // migration is already checkpointed as completed. This idempotent repair
600
+ // ensures thinking is enabled regardless of overlay ordering.
601
+ if (defaultConfigMerge.hadOverlay) {
602
+ try {
603
+ repairAdaptiveThinkingOnManagedProfiles(getWorkspaceDir());
604
+ log.info("Post-overlay adaptive thinking repair complete");
605
+ } catch (err) {
606
+ log.warn(
607
+ { err },
608
+ "Post-overlay adaptive thinking repair failed — continuing startup",
609
+ );
610
+ }
611
+ }
612
+
591
613
  log.info("Daemon startup: loading config");
592
614
  const config = loadConfig();
593
615
 
@@ -728,6 +750,7 @@ export async function runDaemon(): Promise<void> {
728
750
  await server.start();
729
751
  log.info("Daemon startup: DaemonServer started");
730
752
  startDiskPressureGuardForLifecycle();
753
+ startOrphanReaper();
731
754
 
732
755
  // Kick off the update bulletin background job AFTER `server.start()`
733
756
  // resolves. The conversation store must be initialized before wake
@@ -1324,6 +1347,7 @@ export async function runDaemon(): Promise<void> {
1324
1347
  cleanupPidFile: () => {
1325
1348
  stopGatewayFlagListener();
1326
1349
  stopDiskPressureGuardForLifecycle();
1350
+ stopOrphanReaper();
1327
1351
  cleanupPidFile();
1328
1352
  },
1329
1353
  });
@@ -1338,6 +1362,7 @@ export async function runDaemon(): Promise<void> {
1338
1362
  } catch (err) {
1339
1363
  log.error({ err }, "Daemon startup failed — cleaning up");
1340
1364
  stopDiskPressureGuardForLifecycle();
1365
+ stopOrphanReaper();
1341
1366
  cleanupPidFileIfOwner(process.pid);
1342
1367
  throw err;
1343
1368
  }
@@ -1,6 +1,4 @@
1
- // App management, gallery, publishing, and sharing types.
2
-
3
- import type { GalleryManifest } from "../../gallery/gallery-manifest.js";
1
+ // App management, publishing, and sharing types.
4
2
 
5
3
  // === Client → Server ===
6
4
 
@@ -81,15 +79,6 @@ export interface GetSigningIdentityResponse {
81
79
  error?: string;
82
80
  }
83
81
 
84
- export interface GalleryListRequest {
85
- type: "gallery_list";
86
- }
87
-
88
- export interface GalleryInstallRequest {
89
- type: "gallery_install";
90
- galleryAppId: string;
91
- }
92
-
93
82
  export interface AppHistoryRequest {
94
83
  type: "app_history_request";
95
84
  appId: string;
@@ -271,19 +260,6 @@ export interface ShareAppCloudResponse {
271
260
  error?: string;
272
261
  }
273
262
 
274
- export interface GalleryListResponse {
275
- type: "gallery_list_response";
276
- gallery: GalleryManifest;
277
- }
278
-
279
- export interface GalleryInstallResponse {
280
- type: "gallery_install_response";
281
- success: boolean;
282
- appId?: string;
283
- name?: string;
284
- error?: string;
285
- }
286
-
287
263
  export interface AppHistoryResponse {
288
264
  type: "app_history_response";
289
265
  appId: string;
@@ -347,8 +323,6 @@ export type _AppsClientMessages =
347
323
  | OpenBundleRequest
348
324
  | SignBundlePayloadResponse
349
325
  | GetSigningIdentityResponse
350
- | GalleryListRequest
351
- | GalleryInstallRequest
352
326
  | AppHistoryRequest
353
327
  | AppDiffRequest
354
328
  | AppFileAtVersionRequest
@@ -371,8 +345,6 @@ export type _AppsServerMessages =
371
345
  | SignBundlePayloadRequest
372
346
  | GetSigningIdentityRequest
373
347
  | ShareAppCloudResponse
374
- | GalleryListResponse
375
- | GalleryInstallResponse
376
348
  | AppHistoryResponse
377
349
  | AppDiffResponse
378
350
  | AppFileAtVersionResponse