@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
@@ -11,6 +11,7 @@ import { getOrCreateConversation } from "../../daemon/conversation-store.js";
11
11
  import { INTERNAL_GUARDIAN_TRUST_CONTEXT } from "../../daemon/trust-context.js";
12
12
  import { bootstrapConversation } from "../../memory/conversation-bootstrap.js";
13
13
  import { getConversation } from "../../memory/conversation-crud.js";
14
+ import { getUsageCostForConversationWindow } from "../../memory/llm-usage-store.js";
14
15
  import { normalizeScheduleSyntax } from "../../schedule/recurrence-types.js";
15
16
  import {
16
17
  runScript,
@@ -27,10 +28,13 @@ import {
27
28
  getSchedule,
28
29
  getScheduleRuns,
29
30
  listSchedules,
31
+ setScheduleRunConversationId,
30
32
  updateSchedule,
31
33
  } from "../../schedule/schedule-store.js";
34
+ import { getScheduleUsageSummaries } from "../../schedule/schedule-usage-store.js";
32
35
  import { getLogger } from "../../util/logger.js";
33
36
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
37
+ import { parseEpochMillisRange } from "./epoch-millis-range.js";
34
38
  import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
35
39
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
36
40
 
@@ -57,6 +61,9 @@ const scheduleSchema = z.object({
57
61
  maxRetries: z.number(),
58
62
  retryBackoffMs: z.number(),
59
63
  timeoutMs: z.number().nullable(),
64
+ createdFromConversationId: z.string().nullable(),
65
+ createdFromConversationExists: z.boolean(),
66
+ createdFromConversationArchivedAt: z.number().nullable(),
60
67
  description: z.string().nullable(),
61
68
  mode: z.enum(["notify", "execute", "script", "wake"]),
62
69
  status: z.enum(["active", "firing", "fired", "cancelled"]),
@@ -76,48 +83,96 @@ const scheduleRunSchema = z.object({
76
83
  output: z.string().nullable(),
77
84
  error: z.string().nullable(),
78
85
  conversationId: z.string().nullable(),
86
+ conversationExists: z.boolean(),
87
+ conversationArchivedAt: z.number().nullable(),
88
+ estimatedCostUsd: z.number(),
79
89
  createdAt: z.number(),
80
90
  });
81
91
 
92
+ const scheduleUsageSummarySchema = z.object({
93
+ scheduleId: z.string(),
94
+ runCount: z.number(),
95
+ totalEstimatedCostUsd: z.number(),
96
+ eventCount: z.number(),
97
+ });
98
+
82
99
  // ---------------------------------------------------------------------------
83
100
  // Handlers (transport-agnostic)
84
101
  // ---------------------------------------------------------------------------
85
102
 
103
+ interface CreatedFromConversationState {
104
+ exists: boolean;
105
+ archivedAt: number | null;
106
+ }
107
+
108
+ function getCreatedFromConversationState(
109
+ conversationId: string | null,
110
+ cache: Map<string, CreatedFromConversationState>,
111
+ ): CreatedFromConversationState {
112
+ if (!conversationId) {
113
+ return { exists: false, archivedAt: null };
114
+ }
115
+
116
+ const cached = cache.get(conversationId);
117
+ if (cached) return cached;
118
+
119
+ const conversation = getConversation(conversationId);
120
+ const state = {
121
+ exists: conversation !== null,
122
+ archivedAt: conversation?.archivedAt ?? null,
123
+ };
124
+ cache.set(conversationId, state);
125
+ return state;
126
+ }
127
+
86
128
  function handleListSchedules(queryParams: Record<string, string>) {
87
129
  const includeAll = queryParams.include_all === "true";
88
130
  const jobs = listSchedules();
89
131
  const filtered = includeAll
90
132
  ? jobs
91
133
  : jobs.filter((j) => j.createdBy !== "defer");
134
+ const sourceConversationCache = new Map<
135
+ string,
136
+ CreatedFromConversationState
137
+ >();
92
138
  return {
93
- schedules: filtered.map((j) => ({
94
- id: j.id,
95
- name: j.name,
96
- enabled: j.enabled,
97
- syntax: j.syntax,
98
- expression: j.expression,
99
- cronExpression: j.cronExpression,
100
- timezone: j.timezone,
101
- message: j.message,
102
- script: j.script,
103
- nextRunAt: j.nextRunAt,
104
- lastRunAt: j.lastRunAt,
105
- lastStatus: j.lastStatus,
106
- retryCount: j.retryCount,
107
- maxRetries: j.maxRetries,
108
- retryBackoffMs: j.retryBackoffMs,
109
- timeoutMs: j.timeoutMs,
110
- description:
111
- j.syntax === "cron"
112
- ? describeCronExpression(j.cronExpression)
113
- : j.expression,
114
- mode: j.mode,
115
- status: j.status,
116
- routingIntent: j.routingIntent,
117
- reuseConversation: j.reuseConversation,
118
- wakeConversationId: j.wakeConversationId,
119
- isOneShot: j.cronExpression == null,
120
- })),
139
+ schedules: filtered.map((j) => {
140
+ const sourceConversation = getCreatedFromConversationState(
141
+ j.createdFromConversationId,
142
+ sourceConversationCache,
143
+ );
144
+ return {
145
+ id: j.id,
146
+ name: j.name,
147
+ enabled: j.enabled,
148
+ syntax: j.syntax,
149
+ expression: j.expression,
150
+ cronExpression: j.cronExpression,
151
+ timezone: j.timezone,
152
+ message: j.message,
153
+ script: j.script,
154
+ nextRunAt: j.nextRunAt,
155
+ lastRunAt: j.lastRunAt,
156
+ lastStatus: j.lastStatus,
157
+ retryCount: j.retryCount,
158
+ maxRetries: j.maxRetries,
159
+ retryBackoffMs: j.retryBackoffMs,
160
+ timeoutMs: j.timeoutMs,
161
+ createdFromConversationId: j.createdFromConversationId,
162
+ createdFromConversationExists: sourceConversation.exists,
163
+ createdFromConversationArchivedAt: sourceConversation.archivedAt,
164
+ description:
165
+ j.syntax === "cron"
166
+ ? describeCronExpression(j.cronExpression)
167
+ : j.expression,
168
+ mode: j.mode,
169
+ status: j.status,
170
+ routingIntent: j.routingIntent,
171
+ reuseConversation: j.reuseConversation,
172
+ wakeConversationId: j.wakeConversationId,
173
+ isOneShot: j.cronExpression == null,
174
+ };
175
+ }),
121
176
  };
122
177
  }
123
178
 
@@ -291,22 +346,42 @@ function handleListScheduleRuns(
291
346
  ? Math.min(Math.max(Math.floor(rawLimit), 1), 100)
292
347
  : 10;
293
348
  const runs = getScheduleRuns(id, limit);
349
+ const now = Date.now();
294
350
  return {
295
- runs: runs.map((r) => ({
296
- id: r.id,
297
- jobId: r.jobId,
298
- status: r.status,
299
- startedAt: r.startedAt,
300
- finishedAt: r.finishedAt,
301
- durationMs: r.durationMs,
302
- output: r.output,
303
- error: r.error,
304
- conversationId: r.conversationId,
305
- createdAt: r.createdAt,
306
- })),
351
+ runs: runs.map((r) => {
352
+ const conversation = r.conversationId
353
+ ? getConversation(r.conversationId)
354
+ : null;
355
+ return {
356
+ id: r.id,
357
+ jobId: r.jobId,
358
+ status: r.status,
359
+ startedAt: r.startedAt,
360
+ finishedAt: r.finishedAt,
361
+ durationMs: r.durationMs,
362
+ output: r.output,
363
+ error: r.error,
364
+ conversationId: r.conversationId,
365
+ conversationExists: conversation != null,
366
+ conversationArchivedAt: conversation?.archivedAt ?? null,
367
+ estimatedCostUsd: r.conversationId
368
+ ? getUsageCostForConversationWindow({
369
+ conversationId: r.conversationId,
370
+ from: r.startedAt,
371
+ to: r.finishedAt ?? now,
372
+ })
373
+ : 0,
374
+ createdAt: r.createdAt,
375
+ };
376
+ }),
307
377
  };
308
378
  }
309
379
 
380
+ function handleScheduleUsageSummary(queryParams: Record<string, string>) {
381
+ const range = parseEpochMillisRange(queryParams);
382
+ return { summaries: getScheduleUsageSummaries(range) };
383
+ }
384
+
310
385
  // ---------------------------------------------------------------------------
311
386
  // Shared route definitions (HTTP + IPC)
312
387
  // ---------------------------------------------------------------------------
@@ -337,6 +412,40 @@ export const ROUTES: RouteDefinition[] = [
337
412
  handler: ({ queryParams }: RouteHandlerArgs) =>
338
413
  handleListSchedules(queryParams ?? {}),
339
414
  },
415
+ {
416
+ operationId: "getScheduleUsageSummary",
417
+ endpoint: "schedules/usage-summary",
418
+ method: "GET",
419
+ policy: {
420
+ requiredScopes: ["settings.read"],
421
+ allowedPrincipalTypes: ACTOR_PRINCIPALS,
422
+ },
423
+ summary: "Get schedule usage summaries",
424
+ description:
425
+ "Return per-schedule run counts and usage totals for a time range.",
426
+ tags: ["schedules"],
427
+ queryParams: [
428
+ {
429
+ name: "from",
430
+ type: "integer",
431
+ required: true,
432
+ description: "Start epoch millis (required)",
433
+ },
434
+ {
435
+ name: "to",
436
+ type: "integer",
437
+ required: true,
438
+ description: "End epoch millis (required)",
439
+ },
440
+ ],
441
+ responseBody: z.object({
442
+ summaries: z
443
+ .array(scheduleUsageSummarySchema)
444
+ .describe("Schedule usage summary rows"),
445
+ }),
446
+ handler: ({ queryParams }: RouteHandlerArgs) =>
447
+ handleScheduleUsageSummary(queryParams ?? {}),
448
+ },
340
449
  {
341
450
  operationId: "createSchedule",
342
451
  endpoint: "schedules",
@@ -551,6 +660,7 @@ async function handleRunScheduleNow(id: string) {
551
660
  const taskMatch = schedule.message.match(/^run_task:(\S+)$/);
552
661
  if (taskMatch) {
553
662
  const taskId = taskMatch[1];
663
+ const runId = createScheduleRun(schedule.id, null);
554
664
  try {
555
665
  log.info(
556
666
  { jobId: schedule.id, name: schedule.name, taskId },
@@ -577,7 +687,7 @@ async function handleRunScheduleNow(id: string) {
577
687
  },
578
688
  );
579
689
 
580
- const runId = createScheduleRun(schedule.id, result.conversationId);
690
+ setScheduleRunConversationId(runId, result.conversationId);
581
691
  if (result.status === "failed") {
582
692
  completeScheduleRun(runId, {
583
693
  status: "error",
@@ -598,7 +708,7 @@ async function handleRunScheduleNow(id: string) {
598
708
  origin: "schedule",
599
709
  systemHint: `Schedule (manual): ${schedule.name}`,
600
710
  });
601
- const runId = createScheduleRun(schedule.id, fallbackConversation.id);
711
+ setScheduleRunConversationId(runId, fallbackConversation.id);
602
712
  completeScheduleRun(runId, { status: "error", error: message });
603
713
  }
604
714
  return handleListSchedules({});
@@ -684,9 +684,21 @@ export const ROUTES: RouteDefinition[] = [
684
684
  tags: ["secrets"],
685
685
  responseBody: z.object({
686
686
  secrets: z
687
- .array(z.unknown())
687
+ .array(
688
+ z.object({
689
+ type: z.enum(["api_key", "credential"]),
690
+ name: z.string(),
691
+ }),
692
+ )
688
693
  .describe("List of secret metadata entries, each with type and name"),
689
- accounts: z.array(z.unknown()).describe("Alias for secrets (same data)"),
694
+ accounts: z
695
+ .array(
696
+ z.object({
697
+ type: z.enum(["api_key", "credential"]),
698
+ name: z.string(),
699
+ }),
700
+ )
701
+ .describe("Alias for secrets (same data)"),
690
702
  }),
691
703
  handler: handleListSecrets,
692
704
  },
@@ -26,6 +26,7 @@ import {
26
26
  uninstallSkill,
27
27
  updateSkill,
28
28
  } from "../../daemon/handlers/skills.js";
29
+ import { getCategories } from "../../skills/categories-cache.js";
29
30
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
30
31
  import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
31
32
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
@@ -41,19 +42,11 @@ const slimSkillBase = {
41
42
  id: z.string(),
42
43
  name: z.string(),
43
44
  description: z.string(),
45
+ icon: z.string().optional(),
44
46
  emoji: z.string().optional(),
45
47
  kind: z.enum(["bundled", "installed", "catalog"]),
46
48
  status: z.enum(["enabled", "disabled", "available"]),
47
- category: z.enum([
48
- "communication",
49
- "productivity",
50
- "development",
51
- "media",
52
- "automation",
53
- "webSocial",
54
- "knowledge",
55
- "integration",
56
- ]),
49
+ category: z.string(),
57
50
  };
58
51
 
59
52
  const slimSkillSchema = z.discriminatedUnion("origin", [
@@ -220,6 +213,33 @@ export const ROUTES: RouteDefinition[] = [
220
213
  return { skills };
221
214
  },
222
215
  },
216
+ {
217
+ operationId: "listSkillCategories",
218
+ endpoint: "skills/categories",
219
+ method: "GET",
220
+ policy: {
221
+ requiredScopes: ["settings.read"],
222
+ allowedPrincipalTypes: ACTOR_PRINCIPALS,
223
+ },
224
+ summary: "List skill categories",
225
+ description:
226
+ "Return all skill category definitions with labels, icons, and descriptions.",
227
+ tags: ["skills"],
228
+ responseBody: z.object({
229
+ categories: z.array(
230
+ z.object({
231
+ slug: z.string(),
232
+ label: z.string(),
233
+ description: z.string(),
234
+ icon: z.string(),
235
+ }),
236
+ ),
237
+ }),
238
+ handler: async () => {
239
+ const categories = await getCategories();
240
+ return { categories };
241
+ },
242
+ },
223
243
  {
224
244
  operationId: "getSkillFileContent",
225
245
  endpoint: "skills/:id/files/content",
@@ -546,10 +566,19 @@ export const ROUTES: RouteDefinition[] = [
546
566
  description: "Install a skill by slug, URL, or spec.",
547
567
  tags: ["skills"],
548
568
  requestBody: z.object({
549
- slug: z.string().describe("Skill slug"),
550
- url: z.string().describe("Skill URL"),
551
- spec: z.string().describe("Skill spec"),
552
- version: z.string(),
569
+ slug: z
570
+ .string()
571
+ .optional()
572
+ .describe("Skill slug. One of slug, url, or spec is required."),
573
+ url: z
574
+ .string()
575
+ .optional()
576
+ .describe("Skill URL. One of slug, url, or spec is required."),
577
+ spec: z
578
+ .string()
579
+ .optional()
580
+ .describe("Skill spec. One of slug, url, or spec is required."),
581
+ version: z.string().optional().describe("Specific version to install"),
553
582
  origin: z
554
583
  .enum(["clawhub", "skillssh"])
555
584
  .optional()
@@ -18,8 +18,8 @@ import type { Conversation } from "../../daemon/conversation.js";
18
18
  import {
19
19
  findConversation,
20
20
  findConversationBySurfaceId,
21
- getOrCreateConversation,
22
- } from "../../daemon/conversation-store.js";
21
+ } from "../../daemon/conversation-registry.js";
22
+ import { getOrCreateConversation } from "../../daemon/conversation-store.js";
23
23
  import { rawGet } from "../../memory/raw-query.js";
24
24
 
25
25
  /**
@@ -60,6 +60,7 @@ export async function resolveSurfaceConversation(
60
60
  `%"surfaceId":"${escaped}"%`,
61
61
  );
62
62
  if (!row) return undefined;
63
- if (conversationId && conversationId !== row.conversation_id) return undefined;
63
+ if (conversationId && conversationId !== row.conversation_id)
64
+ return undefined;
64
65
  return await getOrCreateConversation(row.conversation_id);
65
66
  }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Tests for render-time enrichment of history tool calls with confirmation
3
+ * context: derived scope ladders for scope-aware tools and outstanding prompts
4
+ * read from the pending-interactions registry.
5
+ */
6
+ import { afterEach, describe, expect, test } from "bun:test";
7
+
8
+ import type { ConversationMessageToolCall } from "../../api/responses/conversation-message.js";
9
+ import { clear, register } from "../pending-interactions.js";
10
+ import {
11
+ collectPendingConfirmations,
12
+ enrichToolCallsWithConfirmation,
13
+ } from "./tool-call-confirmation-enrichment.js";
14
+
15
+ const WORKSPACE = "/home/user/project";
16
+
17
+ function toolCall(
18
+ overrides: Partial<ConversationMessageToolCall>,
19
+ ): ConversationMessageToolCall {
20
+ return {
21
+ name: "file_read",
22
+ input: {},
23
+ ...overrides,
24
+ };
25
+ }
26
+
27
+ afterEach(() => {
28
+ clear();
29
+ });
30
+
31
+ describe("collectPendingConfirmations", () => {
32
+ test("keys confirmation interactions by toolUseId", () => {
33
+ // GIVEN a confirmation interaction registered for a conversation with a
34
+ // tool-use id and confirmation details
35
+ register("req-1", {
36
+ conversationId: "conv-1",
37
+ kind: "confirmation",
38
+ toolUseId: "tool-abc",
39
+ confirmationDetails: {
40
+ toolName: "file_read",
41
+ input: { path: "/home/user/project/a.txt" },
42
+ riskLevel: "low",
43
+ allowlistOptions: [],
44
+ scopeOptions: [],
45
+ },
46
+ });
47
+
48
+ // WHEN we collect the conversation's pending confirmations
49
+ const byToolUseId = collectPendingConfirmations("conv-1");
50
+
51
+ // THEN the interaction is keyed by its tool-use id
52
+ expect(byToolUseId.size).toBe(1);
53
+ expect(byToolUseId.get("tool-abc")?.requestId).toBe("req-1");
54
+ });
55
+
56
+ test("ignores interactions lacking a toolUseId or confirmation details", () => {
57
+ // GIVEN a confirmation without a toolUseId AND a non-confirmation
58
+ // interaction in the same conversation
59
+ register("req-no-tool", {
60
+ conversationId: "conv-2",
61
+ kind: "confirmation",
62
+ confirmationDetails: {
63
+ toolName: "file_read",
64
+ input: {},
65
+ riskLevel: "low",
66
+ allowlistOptions: [],
67
+ scopeOptions: [],
68
+ },
69
+ });
70
+ register("req-secret", {
71
+ conversationId: "conv-2",
72
+ kind: "secret",
73
+ toolUseId: "tool-xyz",
74
+ });
75
+
76
+ // WHEN we collect the conversation's pending confirmations
77
+ const byToolUseId = collectPendingConfirmations("conv-2");
78
+
79
+ // THEN neither is included — one has no toolUseId, the other is not a
80
+ // confirmation
81
+ expect(byToolUseId.size).toBe(0);
82
+ });
83
+ });
84
+
85
+ describe("enrichToolCallsWithConfirmation", () => {
86
+ test("derives the scope ladder for scope-aware tools", () => {
87
+ // GIVEN a completed scope-aware tool call with no registry entry
88
+ const calls = [toolCall({ id: "tool-1", name: "file_read" })];
89
+
90
+ // WHEN we enrich it
91
+ const [enriched] = enrichToolCallsWithConfirmation(calls, {
92
+ workspaceDir: WORKSPACE,
93
+ pendingConfirmations: new Map(),
94
+ });
95
+
96
+ // THEN the scope ladder is derived from the workspace and tool name
97
+ expect(enriched?.scopeOptions?.[0]).toEqual({
98
+ label: WORKSPACE,
99
+ scope: WORKSPACE,
100
+ });
101
+ // AND no pending confirmation is stamped
102
+ expect(enriched?.pendingConfirmation).toBeUndefined();
103
+ });
104
+
105
+ test("leaves non-scope-aware tool calls untouched", () => {
106
+ // GIVEN a tool call for a tool that has no scope ladder
107
+ const original = toolCall({ id: "tool-2", name: "web_search" });
108
+
109
+ // WHEN we enrich it with no matching registry entry
110
+ const [enriched] = enrichToolCallsWithConfirmation([original], {
111
+ workspaceDir: WORKSPACE,
112
+ pendingConfirmations: new Map(),
113
+ });
114
+
115
+ // THEN the tool call is returned unchanged (same reference)
116
+ expect(enriched).toBe(original);
117
+ });
118
+
119
+ test("stamps the pending confirmation when the registry has a match", () => {
120
+ // GIVEN a registry entry matching the tool call by id
121
+ const pendingConfirmations = collectPendingConfirmationsFixture();
122
+ const calls = [toolCall({ id: "tool-abc", name: "file_read" })];
123
+
124
+ // WHEN we enrich it
125
+ const [enriched] = enrichToolCallsWithConfirmation(calls, {
126
+ workspaceDir: WORKSPACE,
127
+ pendingConfirmations,
128
+ });
129
+
130
+ // THEN the outstanding prompt is projected onto the tool call
131
+ expect(enriched?.pendingConfirmation?.requestId).toBe("req-1");
132
+ expect(enriched?.pendingConfirmation?.toolName).toBe("file_read");
133
+ expect(enriched?.pendingConfirmation?.riskLevel).toBe("high");
134
+ // AND the directory scope ladder carries through from the registry so a
135
+ // restored prompt offers the same scope the live event did
136
+ expect(enriched?.pendingConfirmation?.directoryScopeOptions).toEqual([
137
+ { label: "Anywhere in project/", scope: "/home/user/project" },
138
+ ]);
139
+ // AND the derived scope ladder is still present
140
+ expect(enriched?.scopeOptions?.length).toBeGreaterThan(0);
141
+ });
142
+ });
143
+
144
+ function collectPendingConfirmationsFixture() {
145
+ register("req-1", {
146
+ conversationId: "conv-fixture",
147
+ kind: "confirmation",
148
+ toolUseId: "tool-abc",
149
+ confirmationDetails: {
150
+ toolName: "file_read",
151
+ input: { path: "/home/user/project/a.txt" },
152
+ riskLevel: "high",
153
+ allowlistOptions: [],
154
+ scopeOptions: [],
155
+ directoryScopeOptions: [
156
+ { label: "Anywhere in project/", scope: "/home/user/project" },
157
+ ],
158
+ },
159
+ });
160
+ return collectPendingConfirmations("conv-fixture");
161
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Render-time enrichment of history tool calls with confirmation context.
3
+ *
4
+ * Two pieces of state the persisted content does not itself carry are layered
5
+ * onto each rendered tool call here so the web/API clients can render the same
6
+ * confirmation UI on a cold reconnect (or a history reopen after the live
7
+ * event buffer has aged out) that the live `confirmation_request` SSE stream
8
+ * would have produced:
9
+ *
10
+ * 1. `scopeOptions` — the confirmation scope ladder for scope-aware tools
11
+ * (file/bash). It is a pure function of the workspace directory and the
12
+ * tool name, so it is *derived* at render rather than persisted. Completed
13
+ * tool calls regain the ladder the rule editor's trust-rule suggestion
14
+ * fallback consumes.
15
+ *
16
+ * 2. `pendingConfirmation` — the in-flight prompt for a tool call still
17
+ * awaiting a user decision. It is read from the in-memory
18
+ * `pending-interactions` registry (the authoritative store of unresolved
19
+ * prompts), so it appears only while the prompt is genuinely outstanding.
20
+ */
21
+
22
+ import type { ConversationMessageToolCall } from "../../api/responses/conversation-message.js";
23
+ import { generateScopeOptions } from "../../permissions/checker.js";
24
+ import {
25
+ type ConfirmationDetails,
26
+ getByConversation,
27
+ } from "../pending-interactions.js";
28
+
29
+ /** A pending confirmation matched to the tool call it prompts for, keyed by `toolUseId`. */
30
+ interface PendingConfirmationMatch {
31
+ requestId: string;
32
+ details: ConfirmationDetails;
33
+ }
34
+
35
+ /**
36
+ * Build the `toolUseId → pending confirmation` lookup for a conversation from
37
+ * the registry. Only confirmation interactions that carry both a `toolUseId`
38
+ * and `confirmationDetails` can be stamped onto a wire tool call.
39
+ */
40
+ export function collectPendingConfirmations(
41
+ conversationId: string,
42
+ ): Map<string, PendingConfirmationMatch> {
43
+ const byToolUseId = new Map<string, PendingConfirmationMatch>();
44
+ for (const interaction of getByConversation(conversationId)) {
45
+ if (
46
+ interaction.kind === "confirmation" &&
47
+ interaction.confirmationDetails &&
48
+ interaction.toolUseId
49
+ ) {
50
+ byToolUseId.set(interaction.toolUseId, {
51
+ requestId: interaction.requestId,
52
+ details: interaction.confirmationDetails,
53
+ });
54
+ }
55
+ }
56
+ return byToolUseId;
57
+ }
58
+
59
+ /** Project a registry `ConfirmationDetails` into the wire `pendingConfirmation` shape. */
60
+ function toPendingConfirmation(
61
+ requestId: string,
62
+ details: ConfirmationDetails,
63
+ ): NonNullable<ConversationMessageToolCall["pendingConfirmation"]> {
64
+ return {
65
+ requestId,
66
+ toolName: details.toolName,
67
+ riskLevel: details.riskLevel,
68
+ input: details.input,
69
+ allowlistOptions: details.allowlistOptions,
70
+ scopeOptions: details.scopeOptions,
71
+ directoryScopeOptions: details.directoryScopeOptions,
72
+ persistentDecisionsAllowed: details.persistentDecisionsAllowed,
73
+ };
74
+ }
75
+
76
+ /**
77
+ * Layer derived `scopeOptions` and any outstanding `pendingConfirmation` onto a
78
+ * message's rendered tool calls. Returns a new array; tool calls without
79
+ * enrichment are returned unchanged.
80
+ */
81
+ export function enrichToolCallsWithConfirmation(
82
+ toolCalls: ConversationMessageToolCall[],
83
+ opts: {
84
+ workspaceDir: string;
85
+ pendingConfirmations: ReadonlyMap<string, PendingConfirmationMatch>;
86
+ },
87
+ ): ConversationMessageToolCall[] {
88
+ return toolCalls.map((tc) => {
89
+ const scopeOptions = generateScopeOptions(opts.workspaceDir, tc.name);
90
+ const match = tc.id ? opts.pendingConfirmations.get(tc.id) : undefined;
91
+ if (scopeOptions.length === 0 && !match) {
92
+ return tc;
93
+ }
94
+ return {
95
+ ...tc,
96
+ ...(scopeOptions.length > 0 ? { scopeOptions } : {}),
97
+ ...(match
98
+ ? {
99
+ pendingConfirmation: toPendingConfirmation(
100
+ match.requestId,
101
+ match.details,
102
+ ),
103
+ }
104
+ : {}),
105
+ };
106
+ });
107
+ }