@vellumai/assistant 0.8.7 → 0.8.8

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 (387) hide show
  1. package/Dockerfile +20 -4
  2. package/docker-entrypoint.sh +4 -2
  3. package/docker-init-apt-root.sh +3 -1
  4. package/docker-kata-apt-env.sh +3 -1
  5. package/docker-kata-runtime-family.sh +12 -0
  6. package/docs/architecture/memory.md +1 -1
  7. package/docs/plugins.md +75 -79
  8. package/examples/plugins/echo/README.md +6 -12
  9. package/examples/plugins/echo/register.ts +0 -41
  10. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
  11. package/openapi.yaml +3381 -348
  12. package/package.json +1 -1
  13. package/scripts/generate-openapi.ts +68 -41
  14. package/src/__tests__/agent-loop-exit-reason.test.ts +34 -39
  15. package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
  16. package/src/__tests__/agent-loop.test.ts +37 -87
  17. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  18. package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
  19. package/src/__tests__/annotate-risk-options.test.ts +2 -3
  20. package/src/__tests__/anthropic-provider.test.ts +95 -2
  21. package/src/__tests__/assistant-event-hub.test.ts +25 -0
  22. package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
  23. package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
  24. package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
  25. package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
  26. package/src/__tests__/btw-routes.test.ts +62 -3
  27. package/src/__tests__/build-persisted-content.test.ts +184 -0
  28. package/src/__tests__/catalog-files.test.ts +1 -1
  29. package/src/__tests__/clawhub-files.test.ts +1 -1
  30. package/src/__tests__/compaction-pipeline.test.ts +1 -1
  31. package/src/__tests__/compaction.benchmark.test.ts +0 -30
  32. package/src/__tests__/config-watcher.test.ts +1 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -2
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +313 -1136
  37. package/src/__tests__/conversation-agent-loop.test.ts +596 -1616
  38. package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
  39. package/src/__tests__/conversation-history-web-search.test.ts +11 -1
  40. package/src/__tests__/conversation-pairing.test.ts +4 -31
  41. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
  42. package/src/__tests__/conversation-provider-retry-repair.test.ts +26 -5
  43. package/src/__tests__/conversation-queue.test.ts +2 -0
  44. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
  45. package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +170 -229
  47. package/src/__tests__/conversation-runtime-workspace.test.ts +3 -24
  48. package/src/__tests__/conversation-slash-commands.test.ts +8 -42
  49. package/src/__tests__/conversation-slash-queue.test.ts +6 -1
  50. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
  51. package/src/__tests__/conversation-sync-tags.test.ts +27 -15
  52. package/src/__tests__/conversation-title-service.test.ts +135 -2
  53. package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
  54. package/src/__tests__/cross-provider-web-search.test.ts +214 -1
  55. package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
  56. package/src/__tests__/dm-persistence.test.ts +5 -1
  57. package/src/__tests__/empty-response-hook.test.ts +304 -0
  58. package/src/__tests__/feature-flag-test-helpers.ts +2 -2
  59. package/src/__tests__/gemini-image-service.test.ts +13 -0
  60. package/src/__tests__/helpers/mock-provider.ts +110 -0
  61. package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
  62. package/src/__tests__/history-repair-hook.test.ts +1 -0
  63. package/src/__tests__/identity-intro-cache.test.ts +12 -100
  64. package/src/__tests__/identity-routes.test.ts +248 -7
  65. package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
  66. package/src/__tests__/injector-background-turn.test.ts +2 -8
  67. package/src/__tests__/injector-chain.test.ts +106 -270
  68. package/src/__tests__/injector-disk-pressure.test.ts +3 -12
  69. package/src/__tests__/injector-document-comments.test.ts +2 -2
  70. package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
  71. package/src/__tests__/injector-v3-suppression.test.ts +31 -37
  72. package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
  73. package/src/__tests__/list-messages-page-latest.test.ts +60 -0
  74. package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
  75. package/src/__tests__/llm-usage-store.test.ts +223 -1
  76. package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
  77. package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
  78. package/src/__tests__/native-web-search.test.ts +191 -0
  79. package/src/__tests__/onboarding-template-contract.test.ts +2 -0
  80. package/src/__tests__/openai-image-service.test.ts +17 -0
  81. package/src/__tests__/openai-provider.test.ts +31 -1
  82. package/src/__tests__/persist-unsendable-image.test.ts +215 -0
  83. package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
  84. package/src/__tests__/pipeline-runner.test.ts +29 -39
  85. package/src/__tests__/pkb-autoinject.test.ts +2 -5
  86. package/src/__tests__/plugin-bootstrap.test.ts +13 -28
  87. package/src/__tests__/plugin-registry.test.ts +0 -27
  88. package/src/__tests__/plugin-types.test.ts +2 -125
  89. package/src/__tests__/process-message-display-content.test.ts +6 -2
  90. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
  91. package/src/__tests__/resolve-trust-class.test.ts +4 -4
  92. package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
  93. package/src/__tests__/schedule-routes.test.ts +603 -2
  94. package/src/__tests__/schedule-store.test.ts +41 -0
  95. package/src/__tests__/schedule-tools.test.ts +35 -0
  96. package/src/__tests__/server-history-render.test.ts +314 -1
  97. package/src/__tests__/skillssh-files.test.ts +1 -1
  98. package/src/__tests__/system-prompt.test.ts +20 -0
  99. package/src/__tests__/task-scheduler.test.ts +162 -1
  100. package/src/__tests__/terminal-tools.test.ts +6 -1
  101. package/src/__tests__/title-generate-hook.test.ts +319 -0
  102. package/src/__tests__/tool-error-hook.test.ts +278 -0
  103. package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
  104. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  105. package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
  106. package/src/__tests__/tool-result-truncation.test.ts +0 -2
  107. package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
  108. package/src/__tests__/ui-work-result-surface.test.ts +159 -0
  109. package/src/__tests__/usage-routes.test.ts +285 -1
  110. package/src/__tests__/user-plugin-loader.test.ts +2 -2
  111. package/src/__tests__/voice-session-bridge.test.ts +6 -3
  112. package/src/__tests__/web-search-backend-failure.test.ts +166 -0
  113. package/src/agent/loop.ts +346 -442
  114. package/src/api/events/assistant-thinking-delta.ts +33 -0
  115. package/src/api/events/tool-output-chunk.ts +45 -0
  116. package/src/api/events/tool-use-preview-start.ts +32 -0
  117. package/src/api/events/trace-event.ts +69 -0
  118. package/src/api/index.ts +48 -13
  119. package/src/api/responses/conversation-message.ts +368 -0
  120. package/src/avatar/__tests__/avatar-store.test.ts +34 -29
  121. package/src/cli/commands/__tests__/notifications.test.ts +58 -14
  122. package/src/cli/commands/notifications.ts +112 -60
  123. package/src/config/assistant-feature-flags.ts +22 -11
  124. package/src/config/bundled-skills/app-builder/SKILL.md +3 -20
  125. package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
  126. package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
  127. package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
  128. package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
  129. package/src/config/bundled-skills/document-editor/SKILL.md +1 -1
  130. package/src/config/bundled-skills/messaging/SKILL.md +0 -7
  131. package/src/config/feature-flag-cache.ts +3 -3
  132. package/src/config/feature-flag-registry.json +35 -3
  133. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  134. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
  135. package/src/config/schemas/llm.ts +1 -0
  136. package/src/config/schemas/memory-v2.ts +8 -0
  137. package/src/config/schemas/memory-v3.ts +8 -0
  138. package/src/config/schemas/platform.ts +8 -0
  139. package/src/config/seed-inference-profiles.ts +2 -2
  140. package/src/config/skills.ts +13 -0
  141. package/src/context/compactor.ts +1 -1
  142. package/src/context/strip-injections.ts +122 -0
  143. package/src/context/token-estimator.ts +23 -0
  144. package/src/context/tool-result-truncation.ts +0 -23
  145. package/src/context/window-manager.ts +3 -6
  146. package/src/credential-execution/executable-discovery.ts +16 -0
  147. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
  148. package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
  149. package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
  150. package/src/daemon/assistant-attachments.ts +1 -1
  151. package/src/daemon/config-watcher.ts +2 -2
  152. package/src/daemon/context-overflow-reducer.ts +0 -1
  153. package/src/daemon/conversation-agent-loop-handlers.ts +605 -153
  154. package/src/daemon/conversation-agent-loop.ts +281 -760
  155. package/src/daemon/conversation-history.ts +5 -4
  156. package/src/daemon/conversation-lifecycle.ts +3 -4
  157. package/src/daemon/conversation-messaging.ts +7 -6
  158. package/src/daemon/conversation-process.ts +11 -16
  159. package/src/daemon/conversation-runtime-assembly.ts +130 -347
  160. package/src/daemon/conversation-slash.ts +6 -25
  161. package/src/daemon/conversation-surfaces.ts +222 -4
  162. package/src/daemon/conversation-tool-setup.ts +2 -29
  163. package/src/daemon/conversation.ts +32 -14
  164. package/src/daemon/external-plugins-bootstrap.ts +9 -10
  165. package/src/daemon/handlers/config-a2a.ts +51 -36
  166. package/src/daemon/handlers/config-slack-channel.ts +20 -14
  167. package/src/daemon/handlers/config-telegram.ts +16 -2
  168. package/src/daemon/handlers/shared.ts +156 -84
  169. package/src/daemon/handlers/skills.ts +39 -10
  170. package/src/daemon/lifecycle.ts +4 -0
  171. package/src/daemon/message-types/apps.ts +1 -29
  172. package/src/daemon/message-types/messages.ts +9 -57
  173. package/src/daemon/message-types/skills.ts +2 -0
  174. package/src/daemon/message-types/surfaces.ts +136 -3
  175. package/src/daemon/now-scratchpad.ts +21 -0
  176. package/src/daemon/orphan-reaper.test.ts +210 -0
  177. package/src/daemon/orphan-reaper.ts +240 -0
  178. package/src/daemon/persist-unsendable-image.ts +117 -0
  179. package/src/daemon/process-message.ts +1 -3
  180. package/src/daemon/trace-emitter.ts +6 -4
  181. package/src/daemon/trust-context.ts +19 -0
  182. package/src/daemon/wake-target-adapter.ts +3 -1
  183. package/src/home/home-greeting-cache.ts +24 -1
  184. package/src/ipc/gateway-client.test.ts +2 -2
  185. package/src/ipc/gateway-client.ts +3 -3
  186. package/src/media/gemini-image-service.ts +15 -0
  187. package/src/media/openai-image-service.ts +14 -0
  188. package/src/media/types.ts +34 -0
  189. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
  190. package/src/memory/auth-fallback-events-store.ts +94 -0
  191. package/src/memory/conversation-title-service.ts +65 -41
  192. package/src/memory/db-init.ts +4 -0
  193. package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
  194. package/src/memory/graph/conversation-graph-memory.ts +65 -0
  195. package/src/memory/jobs-store.ts +33 -0
  196. package/src/memory/jobs-worker.ts +31 -4
  197. package/src/memory/llm-usage-store.ts +224 -50
  198. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
  199. package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
  200. package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
  201. package/src/memory/migrations/index.ts +2 -0
  202. package/src/memory/pkb/autoinject.ts +61 -0
  203. package/src/memory/pkb/context.ts +50 -0
  204. package/src/memory/pkb/types.ts +14 -0
  205. package/src/memory/schedule-attribution-sql.ts +104 -0
  206. package/src/memory/schema/infrastructure.ts +16 -0
  207. package/src/memory/usage-grouped-buckets.ts +6 -1
  208. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -1
  209. package/src/memory/v2/consolidation-job.ts +1 -1
  210. package/src/memory/v3/__tests__/health.test.ts +16 -0
  211. package/src/memory/v3/__tests__/orchestrate.test.ts +45 -9
  212. package/src/memory/v3/__tests__/provider-blocks.test.ts +13 -0
  213. package/src/memory/v3/__tests__/router.test.ts +101 -29
  214. package/src/memory/v3/__tests__/selector.test.ts +93 -27
  215. package/src/memory/v3/__tests__/shadow-plugin.test.ts +23 -5
  216. package/src/memory/v3/health.ts +0 -0
  217. package/src/memory/v3/llm-retry.ts +32 -0
  218. package/src/memory/v3/orchestrate.ts +26 -14
  219. package/src/memory/v3/provider-blocks.ts +15 -5
  220. package/src/memory/v3/router.ts +48 -42
  221. package/src/memory/v3/selector.ts +57 -42
  222. package/src/memory/v3/shadow-plugin.ts +47 -15
  223. package/src/memory/v3/types.ts +8 -0
  224. package/src/notifications/conversation-pairing.ts +8 -15
  225. package/src/notifications/decision-engine.ts +6 -3
  226. package/src/notifications/home-feed-side-effect.ts +12 -1
  227. package/src/permissions/prompter.ts +4 -0
  228. package/src/plugin-api/constants.ts +4 -0
  229. package/src/plugin-api/index.ts +8 -1
  230. package/src/plugin-api/types.ts +151 -1
  231. package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
  232. package/src/plugins/defaults/empty-response/register.ts +8 -13
  233. package/src/plugins/defaults/index.ts +1 -15
  234. package/src/plugins/defaults/injectors/register.ts +243 -74
  235. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +91 -0
  236. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
  237. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
  238. package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
  239. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
  240. package/src/plugins/defaults/title-generate/package.json +1 -1
  241. package/src/plugins/defaults/title-generate/register.ts +18 -18
  242. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
  243. package/src/plugins/defaults/tool-error/package.json +1 -1
  244. package/src/plugins/defaults/tool-error/register.ts +9 -21
  245. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
  246. package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
  247. package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
  248. package/src/plugins/pipeline.ts +6 -18
  249. package/src/plugins/registry.ts +8 -25
  250. package/src/plugins/types.ts +43 -474
  251. package/src/proactive-artifact/aux-message-injector.ts +3 -3
  252. package/src/proactive-artifact/job.test.ts +7 -12
  253. package/src/prompts/__tests__/system-prompt.test.ts +36 -0
  254. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +62 -0
  255. package/src/prompts/templates/BOOTSTRAP.md +2 -2
  256. package/src/prompts/templates/system-sections.ts +15 -0
  257. package/src/providers/anthropic/client.ts +37 -29
  258. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
  259. package/src/providers/openai/chat-completions-provider.ts +44 -0
  260. package/src/providers/openrouter/client.ts +1 -0
  261. package/src/providers/placeholder-sentinels.ts +35 -0
  262. package/src/runtime/__tests__/agent-wake.test.ts +5 -1
  263. package/src/runtime/agent-wake.ts +2 -2
  264. package/src/runtime/assistant-event-hub.ts +36 -6
  265. package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
  266. package/src/runtime/http-router.ts +16 -21
  267. package/src/runtime/http-types.ts +16 -70
  268. package/src/runtime/pending-interactions.ts +1 -0
  269. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
  270. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
  271. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
  272. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  273. package/src/runtime/routes/app-management-routes.ts +6 -117
  274. package/src/runtime/routes/app-routes.ts +13 -15
  275. package/src/runtime/routes/attachment-routes.ts +26 -15
  276. package/src/runtime/routes/avatar-routes.ts +26 -0
  277. package/src/runtime/routes/btw-routes.ts +29 -23
  278. package/src/runtime/routes/consolidation-routes.ts +120 -20
  279. package/src/runtime/routes/conversation-query-routes.ts +2 -0
  280. package/src/runtime/routes/conversation-routes.ts +358 -184
  281. package/src/runtime/routes/documents-routes.ts +4 -0
  282. package/src/runtime/routes/domain-routes.ts +51 -37
  283. package/src/runtime/routes/epoch-millis-range.ts +34 -0
  284. package/src/runtime/routes/events-routes.ts +28 -34
  285. package/src/runtime/routes/gateway-log-routes.ts +26 -4
  286. package/src/runtime/routes/heartbeat-routes.ts +32 -12
  287. package/src/runtime/routes/identity-intro-cache.ts +11 -34
  288. package/src/runtime/routes/identity-routes.ts +208 -17
  289. package/src/runtime/routes/image-generation-routes.ts +40 -2
  290. package/src/runtime/routes/index.ts +2 -0
  291. package/src/runtime/routes/integrations/a2a.ts +12 -10
  292. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
  293. package/src/runtime/routes/integrations/slack/channel.ts +4 -0
  294. package/src/runtime/routes/integrations/slack/share.ts +27 -6
  295. package/src/runtime/routes/integrations/telegram.ts +6 -0
  296. package/src/runtime/routes/integrations/twilio.ts +42 -0
  297. package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
  298. package/src/runtime/routes/log-export-routes.ts +8 -0
  299. package/src/runtime/routes/memory-v2-routes.ts +15 -8
  300. package/src/runtime/routes/memory-v3-routes.ts +50 -28
  301. package/src/runtime/routes/oauth-apps.ts +66 -12
  302. package/src/runtime/routes/oauth-providers.ts +44 -5
  303. package/src/runtime/routes/platform-routes.ts +81 -5
  304. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
  305. package/src/runtime/routes/playground/force-compact.ts +1 -1
  306. package/src/runtime/routes/rename-conversation-routes.ts +5 -0
  307. package/src/runtime/routes/schedule-routes.ts +152 -42
  308. package/src/runtime/routes/secret-routes.ts +14 -2
  309. package/src/runtime/routes/skills-routes.ts +43 -14
  310. package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
  311. package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
  312. package/src/runtime/routes/trust-rules-routes.ts +26 -2
  313. package/src/runtime/routes/tts-routes.ts +35 -0
  314. package/src/runtime/routes/types.ts +66 -8
  315. package/src/runtime/routes/usage-routes.ts +47 -39
  316. package/src/runtime/routes/webhook-routes.ts +41 -2
  317. package/src/runtime/routes/workspace-routes.ts +4 -0
  318. package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
  319. package/src/runtime/services/analyze-conversation.ts +2 -2
  320. package/src/schedule/schedule-store.ts +20 -1
  321. package/src/schedule/schedule-usage-store.ts +83 -0
  322. package/src/schedule/scheduler.ts +12 -5
  323. package/src/skills/catalog-files.ts +2 -2
  324. package/src/skills/catalog-install.ts +3 -0
  325. package/src/skills/categories-cache.ts +118 -0
  326. package/src/skills/clawhub-files.ts +1 -2
  327. package/src/skills/skillssh-files.ts +1 -2
  328. package/src/telemetry/types.ts +29 -1
  329. package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
  330. package/src/telemetry/usage-telemetry-reporter.ts +57 -2
  331. package/src/tools/executor.ts +1 -53
  332. package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
  333. package/src/tools/network/__tests__/web-search.test.ts +11 -3
  334. package/src/tools/network/web-search-error.test.ts +248 -0
  335. package/src/tools/network/web-search-error.ts +267 -0
  336. package/src/tools/network/web-search.ts +207 -48
  337. package/src/tools/schedule/create.ts +2 -0
  338. package/src/tools/terminal/safe-env.ts +10 -1
  339. package/src/tools/ui-surface/definitions.ts +9 -1
  340. package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
  341. package/src/tts/provider-catalog.ts +76 -1
  342. package/src/util/mutex.ts +47 -0
  343. package/src/workspace/git-service.ts +1 -42
  344. package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
  345. package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
  346. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +93 -0
  347. package/src/workspace/migrations/registry.ts +6 -0
  348. package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
  349. package/src/__tests__/empty-response-pipeline.test.ts +0 -423
  350. package/src/__tests__/llm-call-pipeline.test.ts +0 -287
  351. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
  352. package/src/__tests__/persistence-pipeline.test.ts +0 -503
  353. package/src/__tests__/title-generate-pipeline.test.ts +0 -211
  354. package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
  355. package/src/__tests__/tool-error-pipeline.test.ts +0 -241
  356. package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
  357. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
  358. package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
  359. package/src/gallery/default-gallery.ts +0 -1359
  360. package/src/gallery/gallery-manifest.ts +0 -28
  361. package/src/home/feature-gate.ts +0 -22
  362. package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
  363. package/src/plugins/defaults/empty-response/terminal.ts +0 -106
  364. package/src/plugins/defaults/injectors/package.json +0 -15
  365. package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
  366. package/src/plugins/defaults/llm-call/package.json +0 -15
  367. package/src/plugins/defaults/llm-call/register.ts +0 -45
  368. package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
  369. package/src/plugins/defaults/memory-retrieval/package.json +0 -15
  370. package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
  371. package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
  372. package/src/plugins/defaults/persistence/package.json +0 -15
  373. package/src/plugins/defaults/persistence/register.ts +0 -38
  374. package/src/plugins/defaults/persistence/terminal.ts +0 -83
  375. package/src/plugins/defaults/title-generate/terminal.ts +0 -31
  376. package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
  377. package/src/plugins/defaults/token-estimate/package.json +0 -15
  378. package/src/plugins/defaults/token-estimate/register.ts +0 -34
  379. package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
  380. package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
  381. package/src/plugins/defaults/tool-error/terminal.ts +0 -47
  382. package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
  383. package/src/plugins/defaults/tool-execute/package.json +0 -15
  384. package/src/plugins/defaults/tool-execute/register.ts +0 -49
  385. package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
  386. package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
  387. package/src/skills/category-inference.ts +0 -111
@@ -12,40 +12,19 @@ import { describe, expect, test } from "bun:test";
12
12
 
13
13
  import type { TrustContext } from "../daemon/trust-context.js";
14
14
  import { RiskLevel } from "../permissions/types.js";
15
- import type {
16
- ToolResultTruncateArgs,
17
- ToolResultTruncateResult,
18
- } from "../plugins/defaults/tool-result-truncate/types.js";
19
15
  import {
20
16
  type CircuitBreakerArgs,
21
17
  type CircuitBreakerResult,
22
18
  type CompactionArgs,
23
19
  type CompactionResult,
24
- type EmptyResponseArgs,
25
- type EmptyResponseResult,
26
- type EstimateArgs,
27
- type EstimateResult,
28
- type Injector,
29
- type LLMCallArgs,
30
- type LLMCallResult,
31
- type MemoryArgs,
32
- type MemoryResult,
33
20
  type Middleware,
34
21
  type OverflowReduceArgs,
35
22
  type OverflowReduceResult,
36
- type PersistArgs,
37
- type PersistResult,
38
23
  type Plugin,
39
24
  PluginExecutionError,
40
25
  type PluginInitContext,
41
26
  type PluginManifest,
42
27
  PluginTimeoutError,
43
- type TitleArgs,
44
- type TitleResult,
45
- type ToolErrorArgs,
46
- type ToolErrorDecision,
47
- type ToolExecuteArgs,
48
- type ToolExecuteResult,
49
28
  type TurnContext,
50
29
  } from "../plugins/types.js";
51
30
  import type { Tool } from "../tools/types.js";
@@ -73,70 +52,6 @@ describe("plugin core types", () => {
73
52
  config: { parse: (input: unknown) => input },
74
53
  };
75
54
 
76
- // Generic passthrough — typed per slot below because per-pipeline
77
- // arg/result types have diverged from the early `{input: unknown}` /
78
- // `{output: unknown}` placeholders as individual pipeline wrap-up PRs
79
- // land.
80
- const passthrough: Middleware<
81
- { input: unknown },
82
- { output: unknown }
83
- > = async (args, next, _ctx) => next(args);
84
- // `llmCall` has concrete arg/result types (upgraded in PR 15).
85
- const llmCallPassthrough: Middleware<LLMCallArgs, LLMCallResult> = async (
86
- args,
87
- next,
88
- _ctx,
89
- ) => next(args);
90
-
91
- // `toolExecute` has concrete arg/result types (refined in PR 16).
92
- const toolExecutePassthrough: Middleware<
93
- ToolExecuteArgs,
94
- ToolExecuteResult
95
- > = async (args, next, _ctx) => next(args);
96
-
97
- // `toolResultTruncate` has a concrete args/result shape (PR 17) so we
98
- // need a dedicated passthrough for that slot.
99
- const truncatePassthrough: Middleware<
100
- ToolResultTruncateArgs,
101
- ToolResultTruncateResult
102
- > = async (args, _next, _ctx) => ({
103
- content: args.content,
104
- truncated: false,
105
- });
106
-
107
- // The `emptyResponse` slot has concrete args/result types; use a
108
- // dedicated passthrough so the `satisfies Plugin` check stays honest.
109
- const emptyResponsePassthrough: Middleware<
110
- EmptyResponseArgs,
111
- EmptyResponseResult
112
- > = async (args, next, _ctx) => next(args);
113
-
114
- // The `toolError` slot has concrete args/result types (PR 19); use a
115
- // dedicated passthrough so the shape-only test keeps compiling as types
116
- // get tightened.
117
- const toolErrorPassthrough: Middleware<
118
- ToolErrorArgs,
119
- ToolErrorDecision
120
- > = async (args, next, _ctx) => next(args);
121
-
122
- // `memoryRetrieval` has a concrete typed signature (MemoryArgs →
123
- // MemoryResult) introduced in PR 20, so it can't use the generic
124
- // `{ input }` passthrough above.
125
- const memoryPassthrough: Middleware<MemoryArgs, MemoryResult> = async (
126
- args,
127
- next,
128
- _ctx,
129
- ) => next(args);
130
-
131
- // `tokenEstimate` has a concrete arg/result shape (refined in the
132
- // tokenEstimate-pipeline PR), so its middleware can't share the generic
133
- // `{ input, output }` passthrough. A slot-specific passthrough keeps the
134
- // shape-only assertion honest across type-refinement PRs.
135
- const tokenEstimatePassthrough: Middleware<
136
- EstimateArgs,
137
- EstimateResult
138
- > = async (args, next, _ctx) => next(args);
139
-
140
55
  // `overflowReduce` has a concrete arg/result shape (PR 23). Uses a
141
56
  // dedicated passthrough that returns a structurally-correct result so
142
57
  // `satisfies Plugin` keeps verifying the signature.
@@ -174,33 +89,6 @@ describe("plugin core types", () => {
174
89
  CircuitBreakerResult
175
90
  > = async (args, next, _ctx) => next(args);
176
91
 
177
- // `persistence` has concrete discriminated-union arg/result types
178
- // (upgraded from the initial `{ input }/{ output }` placeholder in PR 27)
179
- // so it gets its own passthrough rather than sharing the generic one
180
- // above.
181
- const persistPassthrough: Middleware<PersistArgs, PersistResult> = async (
182
- args,
183
- next,
184
- _ctx,
185
- ) => next(args);
186
-
187
- // The `titleGenerate` slot now has concrete arg/result types (PR 28)
188
- // rather than the placeholder `{ input/output: unknown }` shape, so it
189
- // needs its own passthrough implementation.
190
- const titlePassthrough: Middleware<TitleArgs, TitleResult> = async (
191
- args,
192
- next,
193
- _ctx,
194
- ) => next(args);
195
-
196
- const injector: Injector = {
197
- name: "sample-injector",
198
- order: 10,
199
- async produce(_ctx) {
200
- return { id: "sample-block", text: "hello", meta: { kind: "demo" } };
201
- },
202
- };
203
-
204
92
  const sampleTool: Tool = {
205
93
  name: "sample-tool",
206
94
  description: "Sample plugin tool",
@@ -244,27 +132,16 @@ describe("plugin core types", () => {
244
132
  body: "## Sample\n\nPlugin-provided skill body.",
245
133
  },
246
134
  ],
247
- injectors: [injector],
248
135
  middleware: {
249
- turn: passthrough,
250
- llmCall: llmCallPassthrough,
251
- toolExecute: toolExecutePassthrough,
252
- memoryRetrieval: memoryPassthrough,
253
- tokenEstimate: tokenEstimatePassthrough,
254
136
  compaction: compactionPassthrough,
255
137
  overflowReduce: overflowReducePassthrough,
256
- persistence: persistPassthrough,
257
- titleGenerate: titlePassthrough,
258
- toolResultTruncate: truncatePassthrough,
259
- emptyResponse: emptyResponsePassthrough,
260
- toolError: toolErrorPassthrough,
261
138
  circuitBreaker: circuitPassthrough,
262
139
  },
263
140
  } satisfies Plugin;
264
141
 
265
142
  // Minimal runtime check so the test body is non-empty.
266
143
  expect(plugin.manifest.name).toBe("sample-plugin");
267
- expect(plugin.middleware.turn).toBe(passthrough);
144
+ expect(plugin.middleware.compaction).toBe(compactionPassthrough);
268
145
  });
269
146
 
270
147
  test("PluginTimeoutError carries pipeline, plugin, and elapsed fields", () => {
@@ -280,7 +157,7 @@ describe("plugin core types", () => {
280
157
  });
281
158
 
282
159
  test("PluginTimeoutError omits plugin suffix when unknown", () => {
283
- const err = new PluginTimeoutError("llmCall", undefined, 1234);
160
+ const err = new PluginTimeoutError("circuitBreaker", undefined, 1234);
284
161
  expect(err.pluginName).toBeUndefined();
285
162
  expect(err.message).not.toContain("offending plugin");
286
163
  });
@@ -12,7 +12,7 @@ let activeConversation: unknown;
12
12
  type TestSlashResolution =
13
13
  | { kind: "passthrough"; content: string }
14
14
  | { kind: "unknown"; message: string }
15
- | { kind: "compact"; targetInputTokensOverride?: number };
15
+ | { kind: "compact" };
16
16
 
17
17
  let resolveSlashForTest: (
18
18
  content: string,
@@ -129,10 +129,14 @@ function makeTestConversation() {
129
129
  drain: () => [],
130
130
  size: () => 0,
131
131
  } as unknown as MessageQueue;
132
+ let processing = false;
132
133
  const messagingCtx: MessagingConversationContext = {
133
134
  conversationId: "conv-display-content",
134
135
  messages,
135
- processing: false,
136
+ isProcessing: () => processing,
137
+ setProcessing: (value: boolean) => {
138
+ processing = value;
139
+ },
136
140
  abortController: null,
137
141
  queue: queueStub,
138
142
  getTurnChannelContext: () => turnChannelContext,
@@ -104,6 +104,7 @@ function buildContext(
104
104
  ];
105
105
 
106
106
  const traceEvents = overrides.traceEvents ?? [];
107
+ let processing = false;
107
108
 
108
109
  const runAgentLoop: HistoryConversationContext["runAgentLoop"] =
109
110
  overrides.runAgentLoop ??
@@ -120,7 +121,10 @@ function buildContext(
120
121
  } as unknown as HistoryConversationContext["traceEmitter"],
121
122
  sendToClient: () => {},
122
123
  messages,
123
- processing: false,
124
+ isProcessing: () => processing,
125
+ setProcessing: (value: boolean) => {
126
+ processing = value;
127
+ },
124
128
  abortController: null,
125
129
  runAgentLoop,
126
130
  };
@@ -1,7 +1,5 @@
1
1
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
-
4
-
5
3
  // ── Module mocks ─────────────────────────────────────────────────────
6
4
 
7
5
  let fakeHttpAuthDisabled = false;
@@ -13,8 +11,10 @@ mock.module("../config/env.js", () => ({
13
11
 
14
12
  // ── Real imports (after mocks) ───────────────────────────────────────
15
13
 
16
- import { resolveTrustClass } from "../daemon/conversation-tool-setup.js";
17
- import type { TrustContext } from "../daemon/trust-context.js";
14
+ import {
15
+ resolveTrustClass,
16
+ type TrustContext,
17
+ } from "../daemon/trust-context.js";
18
18
 
19
19
  afterAll(() => {
20
20
  mock.restore();
@@ -35,9 +35,9 @@ import { getDb } from "../memory/db-connection.js";
35
35
  import { initializeDb } from "../memory/db-init.js";
36
36
  import { buildAssistantEvent } from "../runtime/assistant-event.js";
37
37
  import {
38
- _resetConversationStreamsForTesting,
38
+ _resetStreamStateForTesting,
39
39
  stampAndBuffer,
40
- } from "../runtime/conversation-stream-state.js";
40
+ } from "../runtime/assistant-stream-state.js";
41
41
 
42
42
  initializeDb();
43
43
 
@@ -56,11 +56,11 @@ describe("SSE reconnect replay (B7.2)", () => {
56
56
  const db = getDb();
57
57
  db.run("DELETE FROM conversation_keys");
58
58
  db.run("DELETE FROM conversations");
59
- _resetConversationStreamsForTesting();
59
+ _resetStreamStateForTesting();
60
60
  });
61
61
 
62
62
  afterEach(() => {
63
- _resetConversationStreamsForTesting();
63
+ _resetStreamStateForTesting();
64
64
  });
65
65
 
66
66
  test("replays buffered events with seq > lastSeenSeq before the first heartbeat", async () => {
@@ -94,11 +94,9 @@ describe("SSE reconnect replay (B7.2)", () => {
94
94
  const frame1 = await readFrame(reader);
95
95
  expect(frame1).toContain("event: assistant_event");
96
96
  expect(frame1).toContain('"seq":2');
97
- expect(frame1).toContain('"clientSeq":1');
98
97
 
99
98
  const frame2 = await readFrame(reader);
100
99
  expect(frame2).toContain('"seq":3');
101
- expect(frame2).toContain('"clientSeq":2');
102
100
 
103
101
  // Then the heartbeat.
104
102
  const heartbeat = await readFrame(reader);
@@ -107,6 +105,50 @@ describe("SSE reconnect replay (B7.2)", () => {
107
105
  ac.abort();
108
106
  });
109
107
 
108
+ test("unfiltered connection replays events across conversations from one global cursor", async () => {
109
+ // The web app rides a single unfiltered (assistant-wide) SSE
110
+ // connection that multiplexes every conversation. Because `seq` is
111
+ // one global counter, a single `lastSeenSeq` resumes the whole
112
+ // stream -- replay must return the missed events from BOTH
113
+ // conversations, interleaved in global seq order.
114
+ const { conversationId: convA } = getOrCreateConversation("multi-conv-a");
115
+ const { conversationId: convB } = getOrCreateConversation("multi-conv-b");
116
+
117
+ stampAndBuffer(buildAssistantEvent({ type: "pong" }, convA)); // seq 1
118
+ stampAndBuffer(buildAssistantEvent({ type: "pong" }, convB)); // seq 2
119
+ stampAndBuffer(buildAssistantEvent({ type: "pong" }, convA)); // seq 3
120
+ stampAndBuffer(buildAssistantEvent({ type: "pong" }, convB)); // seq 4
121
+
122
+ const ac = new AbortController();
123
+ const { handleSubscribeAssistantEvents } =
124
+ await import("../runtime/routes/events-routes.js");
125
+ // No conversation scope -> unfiltered connection.
126
+ const stream = handleSubscribeAssistantEvents({
127
+ queryParams: { lastSeenSeq: "1" },
128
+ abortSignal: ac.signal,
129
+ });
130
+
131
+ const reader = stream.getReader();
132
+
133
+ // seqs 2, 3, 4 replay in global order regardless of conversation.
134
+ const f2 = await readFrame(reader);
135
+ expect(f2).toContain('"seq":2');
136
+ expect(f2).toContain(convB);
137
+
138
+ const f3 = await readFrame(reader);
139
+ expect(f3).toContain('"seq":3');
140
+ expect(f3).toContain(convA);
141
+
142
+ const f4 = await readFrame(reader);
143
+ expect(f4).toContain('"seq":4');
144
+ expect(f4).toContain(convB);
145
+
146
+ const heartbeat = await readFrame(reader);
147
+ expect(heartbeat).toBe(": heartbeat\n\n");
148
+
149
+ ac.abort();
150
+ });
151
+
110
152
  test("connects live without replay when lastSeenSeq is older than the ring's oldest entry", async () => {
111
153
  // When the client's cursor is older than the ring can serve, the
112
154
  // route deliberately does NOT signal anything special over the
@@ -124,10 +166,10 @@ describe("SSE reconnect replay (B7.2)", () => {
124
166
  stampAndBuffer(buildAssistantEvent({ type: "pong" }, conversationId));
125
167
  }
126
168
  const { _peekStreamForTesting } =
127
- await import("../runtime/conversation-stream-state.js");
128
- const peek = _peekStreamForTesting(conversationId);
129
- expect(peek?.oldestSeq).toBe(3);
130
- expect(peek?.newestSeq).toBe(202);
169
+ await import("../runtime/assistant-stream-state.js");
170
+ const peek = _peekStreamForTesting();
171
+ expect(peek.oldestSeq).toBe(3);
172
+ expect(peek.newestSeq).toBe(202);
131
173
 
132
174
  const ac = new AbortController();
133
175
  const { handleSubscribeAssistantEvents } =
@@ -226,14 +268,13 @@ describe("SSE reconnect replay (B7.2)", () => {
226
268
  ac.abort();
227
269
  });
228
270
 
229
- test("clientSeq is gap-free when targeted events create seq gaps", async () => {
271
+ test("replay excludes events the subscriber is not targeted to receive", async () => {
230
272
  // Stamp three events: two untargeted (seq 1, 3) + one with a
231
273
  // capability target (seq 2, host_bash). A process subscriber
232
274
  // does NOT match capability targeting (matchesSubscriber requires
233
275
  // type=client + matching capability), so the replay filters out
234
- // seq 2. The subscriber receives seq 1 and 3 — a gap in raw seq
235
- // but clientSeq is 1, 2 — gap-free.
236
- const { conversationId } = getOrCreateConversation("clientseq-gap");
276
+ // seq 2. The subscriber receives seq 1 and 3.
277
+ const { conversationId } = getOrCreateConversation("replay-targeting");
237
278
 
238
279
  stampAndBuffer(buildAssistantEvent({ type: "pong" }, conversationId));
239
280
  stampAndBuffer(buildAssistantEvent({ type: "pong" }, conversationId), {
@@ -246,7 +287,7 @@ describe("SSE reconnect replay (B7.2)", () => {
246
287
  await import("../runtime/routes/events-routes.js");
247
288
  const stream = handleSubscribeAssistantEvents({
248
289
  queryParams: {
249
- conversationKey: "clientseq-gap",
290
+ conversationKey: "replay-targeting",
250
291
  lastSeenSeq: "0",
251
292
  },
252
293
  abortSignal: ac.signal,
@@ -255,14 +296,12 @@ describe("SSE reconnect replay (B7.2)", () => {
255
296
  const reader = stream.getReader();
256
297
 
257
298
  // seq 2 (host_bash-targeted) is filtered out by replay.
258
- // Only seq 1 and 3 are delivered, with gap-free clientSeq.
299
+ // Only seq 1 and 3 are delivered.
259
300
  const f1 = await readFrame(reader);
260
301
  expect(f1).toContain('"seq":1');
261
- expect(f1).toContain('"clientSeq":1');
262
302
 
263
303
  const f2 = await readFrame(reader);
264
304
  expect(f2).toContain('"seq":3');
265
- expect(f2).toContain('"clientSeq":2');
266
305
 
267
306
  const heartbeat = await readFrame(reader);
268
307
  expect(heartbeat).toBe(": heartbeat\n\n");
@@ -270,8 +309,8 @@ describe("SSE reconnect replay (B7.2)", () => {
270
309
  ac.abort();
271
310
  });
272
311
 
273
- test("live callback includes clientSeq on conversation-scoped events", async () => {
274
- const { conversationId } = getOrCreateConversation("clientseq-live");
312
+ test("live callback stamps seq on conversation-scoped events", async () => {
313
+ const { conversationId } = getOrCreateConversation("live-seq");
275
314
 
276
315
  const ac = new AbortController();
277
316
  const { AssistantEventHub } =
@@ -281,7 +320,7 @@ describe("SSE reconnect replay (B7.2)", () => {
281
320
  await import("../runtime/routes/events-routes.js");
282
321
  const stream = handleSubscribeAssistantEvents(
283
322
  {
284
- queryParams: { conversationKey: "clientseq-live" },
323
+ queryParams: { conversationKey: "live-seq" },
285
324
  abortSignal: ac.signal,
286
325
  },
287
326
  { hub: testHub },
@@ -303,11 +342,9 @@ describe("SSE reconnect replay (B7.2)", () => {
303
342
 
304
343
  const f1 = await readFrame(reader);
305
344
  expect(f1).toContain('"seq":1');
306
- expect(f1).toContain('"clientSeq":1');
307
345
 
308
346
  const f2 = await readFrame(reader);
309
347
  expect(f2).toContain('"seq":2');
310
- expect(f2).toContain('"clientSeq":2');
311
348
 
312
349
  ac.abort();
313
350
  });