@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
@@ -0,0 +1,83 @@
1
+ import { rawAll } from "../memory/raw-query.js";
2
+ import { buildScheduleAttributionSubquery } from "../memory/schedule-attribution-sql.js";
3
+
4
+ export interface ScheduleUsageSummary {
5
+ scheduleId: string;
6
+ runCount: number;
7
+ totalEstimatedCostUsd: number;
8
+ eventCount: number;
9
+ }
10
+
11
+ interface ScheduleUsageSummaryRow {
12
+ schedule_id: string;
13
+ run_count: number;
14
+ total_estimated_cost_usd: number | null;
15
+ event_count: number | null;
16
+ }
17
+
18
+ export function getScheduleUsageSummaries({
19
+ from,
20
+ to,
21
+ }: {
22
+ from: number;
23
+ to: number;
24
+ }): ScheduleUsageSummary[] {
25
+ const now = Date.now();
26
+ const scheduleAttribution = buildScheduleAttributionSubquery({
27
+ eventAlias: "e",
28
+ now,
29
+ selectExpression: "schedule_attr_runs.job_id",
30
+ });
31
+ const rows = rawAll<ScheduleUsageSummaryRow>(
32
+ /*sql*/ `
33
+ WITH run_counts AS (
34
+ SELECT
35
+ job_id AS schedule_id,
36
+ COUNT(*) AS run_count
37
+ FROM cron_runs
38
+ WHERE started_at >= ?
39
+ AND started_at <= ?
40
+ GROUP BY job_id
41
+ ),
42
+ attributed_usage AS (
43
+ SELECT
44
+ e.estimated_cost_usd,
45
+ COALESCE(e.llm_call_count, 1) AS event_count,
46
+ ${scheduleAttribution.sql} AS schedule_id
47
+ FROM llm_usage_events e
48
+ WHERE e.created_at >= ?
49
+ AND e.created_at <= ?
50
+ ),
51
+ usage_totals AS (
52
+ SELECT
53
+ schedule_id,
54
+ COALESCE(SUM(estimated_cost_usd), 0) AS total_estimated_cost_usd,
55
+ COALESCE(SUM(event_count), 0) AS event_count
56
+ FROM attributed_usage
57
+ WHERE schedule_id IS NOT NULL
58
+ GROUP BY schedule_id
59
+ )
60
+ SELECT
61
+ cron_jobs.id AS schedule_id,
62
+ COALESCE(run_counts.run_count, 0) AS run_count,
63
+ COALESCE(usage_totals.total_estimated_cost_usd, 0) AS total_estimated_cost_usd,
64
+ COALESCE(usage_totals.event_count, 0) AS event_count
65
+ FROM cron_jobs
66
+ LEFT JOIN run_counts ON run_counts.schedule_id = cron_jobs.id
67
+ LEFT JOIN usage_totals ON usage_totals.schedule_id = cron_jobs.id
68
+ ORDER BY cron_jobs.created_at ASC, cron_jobs.id ASC
69
+ `,
70
+ from,
71
+ to,
72
+ ...scheduleAttribution.params,
73
+ from,
74
+ to,
75
+ );
76
+
77
+ return rows.map((row) => ({
78
+ scheduleId: row.schedule_id,
79
+ runCount: row.run_count,
80
+ totalEstimatedCostUsd: row.total_estimated_cost_usd ?? 0,
81
+ eventCount: row.event_count ?? 0,
82
+ }));
83
+ }
@@ -28,6 +28,7 @@ import {
28
28
  type RoutingIntent,
29
29
  type ScheduleJob,
30
30
  scheduleRetry,
31
+ setScheduleRunConversationId,
31
32
  } from "./schedule-store.js";
32
33
 
33
34
  const log = getLogger("scheduler");
@@ -442,6 +443,7 @@ export async function runScheduleDueWorkOnce(
442
443
  job.syntax === "rrule" &&
443
444
  job.expression != null &&
444
445
  hasSetConstructs(job.expression);
446
+ const runId = createScheduleRun(job.id, null);
445
447
  let failed = false;
446
448
  try {
447
449
  log.info(
@@ -472,14 +474,13 @@ export async function runScheduleDueWorkOnce(
472
474
  },
473
475
  );
474
476
 
477
+ setScheduleRunConversationId(runId, result.conversationId);
475
478
  onScheduleConversationCreated?.({
476
479
  conversationId: result.conversationId,
477
480
  scheduleJobId: job.id,
478
481
  title: result.status === "failed" ? `${job.name}: Error` : job.name,
479
482
  });
480
483
 
481
- // Track the schedule run using the task's conversation
482
- const runId = createScheduleRun(job.id, result.conversationId);
483
484
  if (result.status === "failed") {
484
485
  const errorMessage = result.error ?? "Task run failed";
485
486
  completeScheduleRun(runId, {
@@ -530,7 +531,7 @@ export async function runScheduleDueWorkOnce(
530
531
  scheduleJobId: job.id,
531
532
  title: `${job.name}: Error`,
532
533
  });
533
- const runId = createScheduleRun(job.id, fallbackConversation.id);
534
+ setScheduleRunConversationId(runId, fallbackConversation.id);
534
535
  completeScheduleRun(runId, { status: "error", error: message });
535
536
  emitTaskActivityFailed({
536
537
  taskId,
@@ -584,6 +585,8 @@ export async function runScheduleDueWorkOnce(
584
585
  let ok: boolean;
585
586
  let errorMsg: string | undefined;
586
587
  const conversationReused = reusedConversationId != null;
588
+ let runConversationId = reusedConversationId;
589
+ const runId = createScheduleRun(job.id, reusedConversationId);
587
590
 
588
591
  if (reusedConversationId) {
589
592
  // Reuse path: keep using the injected `processMessage` callback so the
@@ -625,6 +628,8 @@ export async function runScheduleDueWorkOnce(
625
628
  scheduleJobId: job.id,
626
629
  suppressFailureNotifications: job.quiet === true,
627
630
  onConversationCreated: (newConversationId) => {
631
+ runConversationId = newConversationId;
632
+ setScheduleRunConversationId(runId, newConversationId);
628
633
  onScheduleConversationCreated?.({
629
634
  conversationId: newConversationId,
630
635
  scheduleJobId: job.id,
@@ -641,12 +646,14 @@ export async function runScheduleDueWorkOnce(
641
646
  !result.ok && result.conversationId === ""
642
647
  ? `bootstrap-error:${job.id}`
643
648
  : result.conversationId;
649
+ if (runConversationId !== conversationId) {
650
+ runConversationId = conversationId;
651
+ setScheduleRunConversationId(runId, conversationId);
652
+ }
644
653
  ok = result.ok;
645
654
  errorMsg = result.error?.message;
646
655
  }
647
656
 
648
- const runId = createScheduleRun(job.id, conversationId);
649
-
650
657
  if (ok) {
651
658
  completeScheduleRun(runId, { status: "ok" });
652
659
  if (isOneShot) completeOneShot(job.id);
@@ -11,10 +11,8 @@ import { readFileSync } from "node:fs";
11
11
  import { join } from "node:path";
12
12
 
13
13
  import { getIsContainerized } from "../config/env-registry.js";
14
- import {
15
- findConversation,
16
- touchConversation,
17
- } from "../daemon/conversation-store.js";
14
+ import { findConversation } from "../daemon/conversation-registry.js";
15
+ import { touchConversation } from "../daemon/conversation-store.js";
18
16
  import { getSubagentManager } from "../subagent/index.js";
19
17
  import { createAbortReason } from "../util/abort-reasons.js";
20
18
  import { getLogger } from "../util/logger.js";
@@ -37,7 +37,6 @@ import {
37
37
  import { getLogger } from "../util/logger.js";
38
38
  import { getCachedCatalogSync, getCatalog } from "./catalog-cache.js";
39
39
  import { type CatalogSkill, getRepoSkillsDir } from "./catalog-install.js";
40
- import { inferCategory } from "./category-inference.js";
41
40
  import type { SkillFileProvider } from "./skill-file-provider.js";
42
41
 
43
42
  const log = getLogger("catalog-files");
@@ -503,11 +502,12 @@ export function catalogSkillToSlim(cs: CatalogSkill): SlimSkillResponse {
503
502
  id: cs.id,
504
503
  name,
505
504
  description: cs.description,
505
+ icon: cs.icon ?? cs.metadata?.icon,
506
506
  emoji: cs.emoji ?? cs.metadata?.emoji,
507
507
  kind: "catalog",
508
508
  origin: "vellum",
509
509
  status: "available",
510
- category: inferCategory(name, cs.description),
510
+ category: cs.metadata?.vellum?.category ?? "system",
511
511
  };
512
512
  }
513
513
 
@@ -29,17 +29,20 @@ export interface CatalogSkill {
29
29
  id: string;
30
30
  name: string;
31
31
  description: string;
32
+ icon?: string;
32
33
  emoji?: string;
33
34
  includes?: string[];
34
35
  version?: string;
35
36
  updatedAt?: string;
36
37
  metadata?: {
38
+ icon?: string;
37
39
  emoji?: string;
38
40
  vellum?: {
39
41
  "display-name"?: string;
40
42
  "activation-hints"?: string[];
41
43
  "avoid-when"?: string[];
42
44
  "feature-flag"?: string;
45
+ category?: string;
43
46
  };
44
47
  };
45
48
  }
@@ -0,0 +1,118 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { parse as parseYaml } from "yaml";
5
+
6
+ import { getPlatformBaseUrl } from "../config/env.js";
7
+ import { getLogger } from "../util/logger.js";
8
+ import { getRepoSkillsDir } from "./catalog-install.js";
9
+
10
+ const log = getLogger("categories-cache");
11
+ const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
12
+
13
+ export interface SkillCategoryDef {
14
+ slug: string;
15
+ label: string;
16
+ description: string;
17
+ icon: string;
18
+ }
19
+
20
+ let cachedCategories: SkillCategoryDef[] | null = null;
21
+ let cacheTimestamp = 0;
22
+
23
+ async function fetchCategories(): Promise<SkillCategoryDef[]> {
24
+ const platformUrl = getPlatformBaseUrl();
25
+ const url = `${platformUrl}/v1/skills/categories/`;
26
+ const response = await fetch(url, {
27
+ signal: AbortSignal.timeout(10000),
28
+ });
29
+
30
+ if (!response.ok) {
31
+ throw new Error(
32
+ `Platform API error ${response.status}: ${response.statusText}`,
33
+ );
34
+ }
35
+
36
+ const data = (await response.json()) as {
37
+ categories: SkillCategoryDef[];
38
+ };
39
+ if (!Array.isArray(data.categories)) {
40
+ throw new Error("Platform categories response has invalid categories array");
41
+ }
42
+ return data.categories.filter(
43
+ (c): c is SkillCategoryDef =>
44
+ !!c && typeof c.slug === "string" && typeof c.label === "string",
45
+ );
46
+ }
47
+
48
+ function readLocalCategories(repoSkillsDir: string): SkillCategoryDef[] {
49
+ try {
50
+ const raw = readFileSync(
51
+ join(repoSkillsDir, "skill-categories-catalog.yaml"),
52
+ "utf-8",
53
+ );
54
+ const parsed = parseYaml(raw) as { categories?: SkillCategoryDef[] };
55
+ if (!Array.isArray(parsed?.categories)) return [];
56
+ return parsed.categories.filter(
57
+ (c): c is SkillCategoryDef =>
58
+ !!c && typeof c.slug === "string" && typeof c.label === "string",
59
+ );
60
+ } catch {
61
+ return [];
62
+ }
63
+ }
64
+
65
+ export async function getCategories(): Promise<SkillCategoryDef[]> {
66
+ if (cachedCategories && Date.now() - cacheTimestamp < CACHE_TTL_MS) {
67
+ return cachedCategories;
68
+ }
69
+
70
+ const repoSkillsDir = getRepoSkillsDir();
71
+ const local = repoSkillsDir ? readLocalCategories(repoSkillsDir) : [];
72
+ let categories: SkillCategoryDef[];
73
+
74
+ try {
75
+ const remote = await fetchCategories();
76
+ if (local.length > 0) {
77
+ const localSlugs = new Set(local.map((c) => c.slug));
78
+ categories = [
79
+ ...local,
80
+ ...remote.filter((c) => !localSlugs.has(c.slug)),
81
+ ];
82
+ } else {
83
+ categories = remote;
84
+ }
85
+ } catch (err) {
86
+ if (cachedCategories) {
87
+ log.warn(
88
+ { err },
89
+ "Failed to fetch skill categories, keeping stale cache",
90
+ );
91
+ cacheTimestamp = Date.now();
92
+ return cachedCategories;
93
+ }
94
+ if (local.length > 0) {
95
+ log.warn(
96
+ { err },
97
+ "Failed to fetch skill categories, falling back to bundled local catalog",
98
+ );
99
+ categories = local;
100
+ } else {
101
+ log.warn({ err }, "Failed to fetch skill categories, returning empty");
102
+ return [];
103
+ }
104
+ }
105
+
106
+ cachedCategories = categories;
107
+ cacheTimestamp = Date.now();
108
+ return categories;
109
+ }
110
+
111
+ export function getCachedCategoriesSync(): SkillCategoryDef[] {
112
+ return cachedCategories ?? [];
113
+ }
114
+
115
+ export function invalidateCategoriesCache(): void {
116
+ cachedCategories = null;
117
+ cacheTimestamp = 0;
118
+ }
@@ -17,7 +17,6 @@ import type { SlimSkillResponse } from "../daemon/message-types/skills.js";
17
17
  import { isTextMimeType as isTextMime } from "../runtime/routes/workspace-utils.js";
18
18
  import { getLogger } from "../util/logger.js";
19
19
  import type { SkillFileEntry } from "./catalog-files.js";
20
- import { inferCategory } from "./category-inference.js";
21
20
  import {
22
21
  clawhubInspect,
23
22
  clawhubInspectFile,
@@ -199,7 +198,7 @@ export function createClawhubProvider(): SkillFileProvider {
199
198
  kind: "catalog",
200
199
  status: "available",
201
200
  origin: "clawhub",
202
- category: inferCategory(data.skill.displayName, data.skill.summary),
201
+ category: "integrations",
203
202
  slug: data.skill.slug,
204
203
  author: data.owner?.handle ?? "",
205
204
  stars: data.stats?.stars ?? 0,
@@ -24,7 +24,6 @@ import {
24
24
  sanitizeRelativePath,
25
25
  SKIP_DIRS,
26
26
  } from "./catalog-files.js";
27
- import { inferCategory } from "./category-inference.js";
28
27
  import type { SkillFileProvider } from "./skill-file-provider.js";
29
28
  import type { GitHubContentsEntry } from "./skillssh-registry.js";
30
29
  import {
@@ -384,7 +383,7 @@ export function createSkillsShProvider(): SkillFileProvider {
384
383
  kind: "catalog",
385
384
  status: "available",
386
385
  origin: "skillssh",
387
- category: inferCategory(source.skillSlug, ""),
386
+ category: "integrations",
388
387
  slug: skillId,
389
388
  sourceRepo: `${source.owner}/${source.repo}`,
390
389
  installs: 0,
@@ -13,7 +13,11 @@ import { v4 as uuid } from "uuid";
13
13
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
14
14
  import { getConfig } from "../config/loader.js";
15
15
  import { Conversation } from "../daemon/conversation.js";
16
- import { findConversation } from "../daemon/conversation-store.js";
16
+ import {
17
+ findConversation,
18
+ removeSubagentConversation,
19
+ setSubagentConversation,
20
+ } from "../daemon/conversation-registry.js";
17
21
  import type { ServerMessage } from "../daemon/message-protocol.js";
18
22
  import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
19
23
  import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
@@ -334,6 +338,10 @@ export class SubagentManager {
334
338
 
335
339
  managed.conversation = conversation;
336
340
  this.subagents.set(subagentId, managed);
341
+ // Index the live conversation so the per-conversation injectors (workspace
342
+ // context, disk-pressure warning) can resolve it by id; subagents are not
343
+ // in the eviction-managed conversation store.
344
+ setSubagentConversation(conversationRecord.id, conversation);
337
345
  const labelKey = `${config.parentConversationId}:${config.label.toLowerCase().trim()}`;
338
346
  if (this.labelIndex.has(labelKey)) {
339
347
  log.warn(
@@ -695,7 +703,9 @@ export class SubagentManager {
695
703
  */
696
704
  private releaseConversation(managed: ManagedSubagent): void {
697
705
  if (!managed.conversation) return;
698
- managed.conversation.dispose();
706
+ const conversation = managed.conversation;
707
+ removeSubagentConversation(conversation.conversationId, conversation);
708
+ conversation.dispose();
699
709
  managed.conversation = null;
700
710
  managed.retainedUntil = Date.now() + TERMINAL_RETENTION_MS;
701
711
  this.ensureSweepRunning();
@@ -716,16 +726,18 @@ export class SubagentManager {
716
726
  if (!managed) return;
717
727
 
718
728
  if (managed.conversation) {
729
+ const conversation = managed.conversation;
719
730
  if (!TERMINAL_STATUSES.has(managed.state.status)) {
720
- managed.conversation.abort(
731
+ conversation.abort(
721
732
  createAbortReason(
722
733
  "subagent_aborted",
723
734
  "SubagentManager.dispose",
724
- managed.conversation.conversationId,
735
+ conversation.conversationId,
725
736
  ),
726
737
  );
727
738
  }
728
- managed.conversation.dispose();
739
+ removeSubagentConversation(conversation.conversationId, conversation);
740
+ conversation.dispose();
729
741
  managed.conversation = null;
730
742
  }
731
743
  this.subagents.delete(subagentId);
@@ -185,9 +185,37 @@ export interface OnboardingTelemetryEvent extends TelemetryEventBase {
185
185
  ab_variant?: string;
186
186
  }
187
187
 
188
+ /**
189
+ * Auth-fallback event — aggregated count of requests served via the legacy
190
+ * loopback auth fallback. One event per (guard, path, failure_kind) per flush
191
+ * window. Lets the platform see which deployments still rely on the loopback
192
+ * exemption instead of sending a bearer token.
193
+ */
194
+ export interface AuthFallbackTelemetryEvent extends TelemetryEventBase {
195
+ type: "auth_fallback";
196
+ /** Which auth guard fell back: `"edge"` | `"edge-scoped"` | `"edge-guardian"`. */
197
+ guard: string;
198
+ /** Request pathname that fell back. */
199
+ path: string;
200
+ /**
201
+ * Why the bearer-token check did not succeed before the fallback:
202
+ * `"missing_authorization"` | `"malformed_authorization"` |
203
+ * `"token_validation_failed"` | `"insufficient_scope"` |
204
+ * `"non_actor_principal"` | `"guardian_mismatch"`.
205
+ */
206
+ failure_kind: string;
207
+ /** Number of requests that fell back for this key during the window. */
208
+ count: number;
209
+ /** Window start (epoch ms) the count was accumulated over. */
210
+ window_start: number;
211
+ /** Window end (epoch ms) the count was accumulated over. */
212
+ window_end: number;
213
+ }
214
+
188
215
  /** Discriminated union of all telemetry event types. */
189
216
  export type TelemetryEvent =
190
217
  | LlmUsageTelemetryEvent
191
218
  | TurnTelemetryEvent
192
219
  | LifecycleTelemetryEvent
193
- | OnboardingTelemetryEvent;
220
+ | OnboardingTelemetryEvent
221
+ | AuthFallbackTelemetryEvent;
@@ -94,7 +94,15 @@ mock.module("../version.js", () => ({
94
94
  let mockCollectUsageData = true;
95
95
 
96
96
  mock.module("../config/loader.js", () => ({
97
- getConfig: () => ({ collectUsageData: mockCollectUsageData }),
97
+ getConfig: () => ({
98
+ ui: {},
99
+ model: "test",
100
+ provider: "test",
101
+ memory: { enabled: false },
102
+ rateLimit: { maxRequestsPerMinute: 0 },
103
+ secretDetection: { enabled: false },
104
+ collectUsageData: mockCollectUsageData,
105
+ }),
98
106
  }));
99
107
 
100
108
  const mockQueryUnreportedLifecycleEvents = mock(
@@ -130,13 +138,24 @@ mock.module("../memory/onboarding-events-store.js", () => ({
130
138
  queryUnreportedOnboardingEvents: mockQueryUnreportedOnboardingEvents,
131
139
  }));
132
140
 
141
+ // The auth-fallback store is intentionally NOT mocked — it has its own
142
+ // DB-backed tests, and Bun's `mock.module` is process-global, so mocking it
143
+ // here would leak into those tests when files share an invocation. We seed the
144
+ // real DB instead so every auth-fallback test stays order-independent.
145
+
133
146
  // ---------------------------------------------------------------------------
134
147
  // Production import (after mocks)
135
148
  // ---------------------------------------------------------------------------
136
149
 
150
+ import { recordAuthFallbackCounts } from "../memory/auth-fallback-events-store.js";
151
+ import { getDb } from "../memory/db-connection.js";
152
+ import { initializeDb } from "../memory/db-init.js";
153
+ import { authFallbackEvents } from "../memory/schema.js";
137
154
  import type { UsageEvent } from "../usage/types.js";
138
155
  import { UsageTelemetryReporter } from "./usage-telemetry-reporter.js";
139
156
 
157
+ initializeDb();
158
+
140
159
  // ---------------------------------------------------------------------------
141
160
  // Helpers
142
161
  // ---------------------------------------------------------------------------
@@ -201,6 +220,7 @@ beforeEach(() => {
201
220
  mockQueryUnreportedLifecycleEvents.mockReturnValue([]);
202
221
  mockQueryUnreportedOnboardingEvents.mockReset();
203
222
  mockQueryUnreportedOnboardingEvents.mockReturnValue([]);
223
+ getDb().delete(authFallbackEvents).run();
204
224
  mockPlatformClient = null;
205
225
  mockGetPlatformBaseUrl.mockReset();
206
226
  mockGetDeviceId.mockReset();
@@ -909,9 +929,9 @@ describe("UsageTelemetryReporter", () => {
909
929
  // No HTTP call should have been made
910
930
  expect(mockFetch).not.toHaveBeenCalled();
911
931
 
912
- // All 4 timestamp watermarks should have been advanced (IDs left untouched
932
+ // All 5 timestamp watermarks should have been advanced (IDs left untouched
913
933
  // so the compound-cursor branch stays active)
914
- expect(mockSetMemoryCheckpoint).toHaveBeenCalledTimes(4);
934
+ expect(mockSetMemoryCheckpoint).toHaveBeenCalledTimes(5);
915
935
 
916
936
  const calls = mockSetMemoryCheckpoint.mock.calls;
917
937
  const keys = calls.map((c) => c[0]);
@@ -919,6 +939,7 @@ describe("UsageTelemetryReporter", () => {
919
939
  expect(keys).toContain("telemetry:turns:last_reported_at");
920
940
  expect(keys).toContain("telemetry:lifecycle:last_reported_at");
921
941
  expect(keys).toContain("telemetry:onboarding:last_reported_at");
942
+ expect(keys).toContain("telemetry:auth_fallback:last_reported_at");
922
943
  });
923
944
 
924
945
  test("events sent normally after re-enabling collectUsageData", async () => {
@@ -1075,4 +1096,92 @@ describe("UsageTelemetryReporter", () => {
1075
1096
  // Envelope still reflects the running binary, not either event.
1076
1097
  expect(body.assistant_version).toBe("1.2.3-test");
1077
1098
  });
1099
+
1100
+ // -------------------------------------------------------------------------
1101
+ // Auth-fallback events
1102
+ // -------------------------------------------------------------------------
1103
+
1104
+ test("auth_fallback events are included in the events array with type discriminator", async () => {
1105
+ mockQueryUnreportedUsageEvents.mockReturnValue([]);
1106
+ recordAuthFallbackCounts(1700000740000, 1700000800000, [
1107
+ {
1108
+ guard: "edge",
1109
+ path: "/v1/messages",
1110
+ failureKind: "missing_authorization",
1111
+ count: 42,
1112
+ },
1113
+ ]);
1114
+ mockFetch.mockImplementation(() =>
1115
+ Promise.resolve(new Response('{"accepted":1}', { status: 200 })),
1116
+ );
1117
+
1118
+ const reporter = new UsageTelemetryReporter();
1119
+ await reporter.flush();
1120
+
1121
+ expect(mockFetch).toHaveBeenCalledTimes(1);
1122
+ const body = JSON.parse(
1123
+ (mockFetch.mock.calls[0] as [string, RequestInit])[1].body as string,
1124
+ );
1125
+ expect(body.events.length).toBe(1);
1126
+ expect(body.events[0]).toMatchObject({
1127
+ type: "auth_fallback",
1128
+ guard: "edge",
1129
+ path: "/v1/messages",
1130
+ failure_kind: "missing_authorization",
1131
+ count: 42,
1132
+ window_start: 1700000740000,
1133
+ window_end: 1700000800000,
1134
+ assistant_version: "1.2.3-test",
1135
+ });
1136
+ // recorded_at is the row's createdAt (stamped at record time).
1137
+ expect(typeof body.events[0].recorded_at).toBe("number");
1138
+ expect(typeof body.events[0].daemon_event_id).toBe("string");
1139
+ });
1140
+
1141
+ test("auth_fallback watermark advances to the last reported row on success", async () => {
1142
+ mockQueryUnreportedUsageEvents.mockReturnValue([]);
1143
+ recordAuthFallbackCounts(1700000000000, 1700000001000, [
1144
+ {
1145
+ guard: "edge-scoped",
1146
+ path: "/v1/a",
1147
+ failureKind: "insufficient_scope",
1148
+ count: 1,
1149
+ },
1150
+ {
1151
+ guard: "edge-guardian",
1152
+ path: "/v1/b",
1153
+ failureKind: "guardian_mismatch",
1154
+ count: 3,
1155
+ },
1156
+ ]);
1157
+ mockFetch.mockImplementation(() =>
1158
+ Promise.resolve(new Response('{"accepted":2}', { status: 200 })),
1159
+ );
1160
+
1161
+ // The last row by the reporter's (createdAt, id) cursor order is the one
1162
+ // whose watermark should be persisted after a successful upload.
1163
+ const rows = getDb()
1164
+ .select()
1165
+ .from(authFallbackEvents)
1166
+ .orderBy(authFallbackEvents.createdAt, authFallbackEvents.id)
1167
+ .all();
1168
+ const lastRow = rows[rows.length - 1];
1169
+
1170
+ const reporter = new UsageTelemetryReporter();
1171
+ await reporter.flush();
1172
+
1173
+ const watermarkCalls = mockSetMemoryCheckpoint.mock.calls.filter(
1174
+ (c) => c[0] === "telemetry:auth_fallback:last_reported_at",
1175
+ );
1176
+ expect(watermarkCalls.length).toBeGreaterThanOrEqual(1);
1177
+ expect(watermarkCalls[watermarkCalls.length - 1][1]).toBe(
1178
+ String(lastRow.createdAt),
1179
+ );
1180
+
1181
+ const idCalls = mockSetMemoryCheckpoint.mock.calls.filter(
1182
+ (c) => c[0] === "telemetry:auth_fallback:last_reported_id",
1183
+ );
1184
+ expect(idCalls.length).toBeGreaterThanOrEqual(1);
1185
+ expect(idCalls[idCalls.length - 1][1]).toBe(lastRow.id);
1186
+ });
1078
1187
  });