@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
@@ -38,10 +38,13 @@ import type { HostAppControlProxy } from "./host-app-control-proxy.js";
38
38
  import type { HostCuProxy } from "./host-cu-proxy.js";
39
39
  import type {
40
40
  CardSurfaceData,
41
+ ChoiceSurfaceData,
41
42
  ConfirmationSurfaceData,
43
+ CopyBlockSurfaceData,
42
44
  DynamicPageSurfaceData,
43
45
  FormSurfaceData,
44
46
  ListSurfaceData,
47
+ OAuthConnectSurfaceData,
45
48
  ServerMessage,
46
49
  SurfaceData,
47
50
  SurfaceType,
@@ -395,6 +398,107 @@ function normalizeTaskProgressCardPatch(
395
398
  return normalizedPatch;
396
399
  }
397
400
 
401
+ function normalizeChoiceShowData(
402
+ rawData: Record<string, unknown>,
403
+ ): ChoiceSurfaceData {
404
+ const options = Array.isArray(rawData.options)
405
+ ? rawData.options
406
+ .filter((option): option is Record<string, unknown> =>
407
+ isPlainObject(option),
408
+ )
409
+ .map((option) => {
410
+ const id = typeof option.id === "string" ? option.id.trim() : "";
411
+ const title =
412
+ typeof option.title === "string"
413
+ ? option.title.trim()
414
+ : typeof option.label === "string"
415
+ ? option.label.trim()
416
+ : "";
417
+ if (!id || !title) return null;
418
+ return {
419
+ id,
420
+ title,
421
+ ...(typeof option.description === "string"
422
+ ? { description: option.description }
423
+ : {}),
424
+ ...(option.recommended === true ? { recommended: true } : {}),
425
+ ...(isPlainObject(option.data)
426
+ ? { data: option.data as Record<string, unknown> }
427
+ : {}),
428
+ };
429
+ })
430
+ .filter(
431
+ (option): option is NonNullable<typeof option> => option !== null,
432
+ )
433
+ : [];
434
+
435
+ return {
436
+ ...(typeof rawData.description === "string"
437
+ ? { description: rawData.description }
438
+ : {}),
439
+ options,
440
+ selectionMode: rawData.selectionMode === "multiple" ? "multiple" : "single",
441
+ ...(typeof rawData.submitLabel === "string"
442
+ ? { submitLabel: rawData.submitLabel }
443
+ : {}),
444
+ ...(typeof rawData.commitOnSelect === "boolean"
445
+ ? { commitOnSelect: rawData.commitOnSelect }
446
+ : {}),
447
+ };
448
+ }
449
+
450
+ function normalizeCopyBlockShowData(
451
+ rawData: Record<string, unknown>,
452
+ ): CopyBlockSurfaceData {
453
+ return {
454
+ text: typeof rawData.text === "string" ? rawData.text : "",
455
+ ...(typeof rawData.label === "string" ? { label: rawData.label } : {}),
456
+ ...(typeof rawData.language === "string"
457
+ ? { language: rawData.language }
458
+ : {}),
459
+ };
460
+ }
461
+
462
+ function normalizeOAuthConnectShowData(
463
+ rawData: Record<string, unknown>,
464
+ ): OAuthConnectSurfaceData {
465
+ return {
466
+ providerKey:
467
+ typeof rawData.providerKey === "string" ? rawData.providerKey.trim() : "",
468
+ ...(typeof rawData.displayName === "string"
469
+ ? { displayName: rawData.displayName }
470
+ : {}),
471
+ ...(typeof rawData.description === "string"
472
+ ? { description: rawData.description }
473
+ : {}),
474
+ ...(typeof rawData.logoUrl === "string" || rawData.logoUrl === null
475
+ ? { logoUrl: rawData.logoUrl }
476
+ : {}),
477
+ };
478
+ }
479
+
480
+ function buildChoiceActions(data: ChoiceSurfaceData): Array<{
481
+ id: string;
482
+ label: string;
483
+ style?: string;
484
+ data?: Record<string, unknown>;
485
+ }> {
486
+ return data.options.map((option) => ({
487
+ id: option.id,
488
+ label: option.title,
489
+ style: option.recommended ? "primary" : "secondary",
490
+ data: {
491
+ choiceId: option.id,
492
+ choiceTitle: option.title,
493
+ selectedIds: [option.id],
494
+ selectedTitles: [option.title],
495
+ ...(option.description ? { choiceDescription: option.description } : {}),
496
+ ...(option.recommended ? { recommended: true } : {}),
497
+ ...(option.data ?? {}),
498
+ },
499
+ }));
500
+ }
501
+
398
502
  function isTaskProgressCardData(data: SurfaceData | Record<string, unknown>) {
399
503
  return (data as Record<string, unknown>).template === "task_progress";
400
504
  }
@@ -1699,6 +1803,8 @@ export async function handleSurfaceAction(
1699
1803
  // been accepted. Deferred until after rejection check so the surface stays
1700
1804
  // active and retryable if the queue was full.
1701
1805
  const ONE_SHOT_SURFACE_TYPES = [
1806
+ "choice",
1807
+ "oauth_connect",
1702
1808
  "form",
1703
1809
  "confirmation",
1704
1810
  "file_upload",
@@ -1860,6 +1966,12 @@ export function buildCompletionSummary(
1860
1966
  data?: Record<string, unknown>,
1861
1967
  surfaceData?: Record<string, unknown>,
1862
1968
  ): string {
1969
+ const selectedTitles = Array.isArray(data?.selectedTitles)
1970
+ ? data.selectedTitles.filter(
1971
+ (title): title is string => typeof title === "string",
1972
+ )
1973
+ : [];
1974
+
1863
1975
  if (surfaceType === "confirmation") {
1864
1976
  if (actionId === "cancel") {
1865
1977
  const cancelLabel =
@@ -1892,6 +2004,43 @@ export function buildCompletionSummary(
1892
2004
  if (surfaceType === "form") {
1893
2005
  return "Submitted";
1894
2006
  }
2007
+ if (surfaceType === "choice" && data) {
2008
+ const choiceTitle =
2009
+ typeof data.choiceTitle === "string" ? data.choiceTitle : undefined;
2010
+ if (choiceTitle) return `User chose: "${choiceTitle}"`;
2011
+ if (selectedTitles.length === 1)
2012
+ return `User chose: "${selectedTitles[0]}"`;
2013
+ if (selectedTitles.length > 1) {
2014
+ return `User chose ${selectedTitles.length} options: ${selectedTitles
2015
+ .map((title) => `"${title}"`)
2016
+ .join(", ")}`;
2017
+ }
2018
+ return `User chose: ${actionId}`;
2019
+ }
2020
+ if (surfaceType === "oauth_connect") {
2021
+ const providerLabel =
2022
+ typeof data?.providerLabel === "string"
2023
+ ? data.providerLabel
2024
+ : typeof data?.displayName === "string"
2025
+ ? data.displayName
2026
+ : typeof data?.providerKey === "string"
2027
+ ? data.providerKey
2028
+ : "OAuth";
2029
+ const accountLabel =
2030
+ typeof data?.accountLabel === "string" ? data.accountLabel : undefined;
2031
+ if (actionId === "connect" || data?.status === "connected") {
2032
+ return accountLabel
2033
+ ? `Connected ${providerLabel}: ${accountLabel}`
2034
+ : `Connected ${providerLabel}`;
2035
+ }
2036
+ if (actionId === "cancel" || data?.status === "cancelled") {
2037
+ return `Cancelled ${providerLabel} connection`;
2038
+ }
2039
+ if (data?.status === "error") {
2040
+ return `${providerLabel} connection failed`;
2041
+ }
2042
+ return `${providerLabel} connection ${actionId}`;
2043
+ }
1895
2044
  if (surfaceType === "list" && data) {
1896
2045
  const selectedIds = data.selectedIds as string[] | undefined;
1897
2046
  const actionSuffix = actionId ? ` (action: ${actionId})` : "";
@@ -1922,6 +2071,11 @@ function buildUserFacingLabel(
1922
2071
  surfaceData?: Record<string, unknown>,
1923
2072
  ): string {
1924
2073
  const count = (data?.selectedIds as string[] | undefined)?.length;
2074
+ const selectedTitles = Array.isArray(data?.selectedTitles)
2075
+ ? data.selectedTitles.filter(
2076
+ (title): title is string => typeof title === "string",
2077
+ )
2078
+ : [];
1925
2079
 
1926
2080
  if (surfaceType === "confirmation") {
1927
2081
  if (actionId === "cancel") {
@@ -1948,6 +2102,39 @@ function buildUserFacingLabel(
1948
2102
  return `Selected: ${actionId}`;
1949
2103
  }
1950
2104
  if (surfaceType === "form") return "Submitted";
2105
+ if (surfaceType === "choice") {
2106
+ const choiceTitle =
2107
+ typeof data?.choiceTitle === "string" ? data.choiceTitle : undefined;
2108
+ if (choiceTitle) return choiceTitle;
2109
+ if (selectedTitles.length === 1) return selectedTitles[0];
2110
+ if (selectedTitles.length > 1)
2111
+ return `Selected ${selectedTitles.length} options`;
2112
+ return "Selected";
2113
+ }
2114
+ if (surfaceType === "oauth_connect") {
2115
+ const providerLabel =
2116
+ typeof data?.providerLabel === "string"
2117
+ ? data.providerLabel
2118
+ : typeof data?.displayName === "string"
2119
+ ? data.displayName
2120
+ : typeof data?.providerKey === "string"
2121
+ ? data.providerKey
2122
+ : "OAuth";
2123
+ const accountLabel =
2124
+ typeof data?.accountLabel === "string" ? data.accountLabel : undefined;
2125
+ if (actionId === "connect" || data?.status === "connected") {
2126
+ return accountLabel
2127
+ ? `Connected ${providerLabel}: ${accountLabel}`
2128
+ : `Connected ${providerLabel}`;
2129
+ }
2130
+ if (actionId === "cancel" || data?.status === "cancelled") {
2131
+ return "Cancelled";
2132
+ }
2133
+ if (data?.status === "error") {
2134
+ return `${providerLabel} connection failed`;
2135
+ }
2136
+ return `Selected: ${actionId}`;
2137
+ }
1951
2138
 
1952
2139
  // Table / list selection actions
1953
2140
  if (count) {
@@ -2213,11 +2400,17 @@ export async function surfaceProxyResolver(
2213
2400
  const data = (
2214
2401
  surfaceType === "card"
2215
2402
  ? normalizeCardShowData(input, rawData)
2216
- : surfaceType === "dynamic_page"
2217
- ? normalizeDynamicPageShowData(input, rawData)
2218
- : rawData
2403
+ : surfaceType === "choice"
2404
+ ? normalizeChoiceShowData(rawData)
2405
+ : surfaceType === "copy_block"
2406
+ ? normalizeCopyBlockShowData(rawData)
2407
+ : surfaceType === "oauth_connect"
2408
+ ? normalizeOAuthConnectShowData(rawData)
2409
+ : surfaceType === "dynamic_page"
2410
+ ? normalizeDynamicPageShowData(input, rawData)
2411
+ : rawData
2219
2412
  ) as SurfaceData;
2220
- const actions = input.actions as
2413
+ const inputActions = input.actions as
2221
2414
  | Array<{
2222
2415
  id: string;
2223
2416
  label: string;
@@ -2225,8 +2418,33 @@ export async function surfaceProxyResolver(
2225
2418
  data?: Record<string, unknown>;
2226
2419
  }>
2227
2420
  | undefined;
2421
+ const actions =
2422
+ surfaceType === "choice"
2423
+ ? buildChoiceActions(data as ChoiceSurfaceData)
2424
+ : inputActions;
2228
2425
  // Interactive surfaces default to awaiting user action.
2229
2426
  const hasActions = Array.isArray(actions) && actions.length > 0;
2427
+ if (surfaceType === "choice" && !hasActions) {
2428
+ return {
2429
+ content:
2430
+ "choice surfaces require at least one option with both id and title.",
2431
+ isError: true,
2432
+ };
2433
+ }
2434
+ const oauthProviderKey =
2435
+ surfaceType === "oauth_connect"
2436
+ ? (data as unknown as Record<string, unknown>).providerKey
2437
+ : undefined;
2438
+ if (
2439
+ surfaceType === "oauth_connect" &&
2440
+ (typeof oauthProviderKey !== "string" ||
2441
+ oauthProviderKey.trim().length === 0)
2442
+ ) {
2443
+ return {
2444
+ content: "oauth_connect surfaces require data.providerKey.",
2445
+ isError: true,
2446
+ };
2447
+ }
2230
2448
  const isInteractive =
2231
2449
  surfaceType === "card"
2232
2450
  ? hasActions
@@ -11,14 +11,12 @@ import {
11
11
  type InterfaceId,
12
12
  supportsHostProxy,
13
13
  } from "../channels/types.js";
14
- import { isHttpAuthDisabled } from "../config/env.js";
15
14
  import { getIsPlatform } from "../config/env-registry.js";
16
15
  import { getConfig } from "../config/loader.js";
17
16
  import { getBindingByConversation } from "../memory/external-conversation-store.js";
18
17
  import type { PermissionPrompter } from "../permissions/prompter.js";
19
18
  import type { SecretPrompter } from "../permissions/secret-prompter.js";
20
19
  import type { Message, ToolDefinition } from "../providers/types.js";
21
- import type { TrustClass } from "../runtime/actor-trust-resolver.js";
22
20
  import { assistantEventHub } from "../runtime/assistant-event-hub.js";
23
21
  import { registerConversationSender } from "../tools/browser/browser-screencast.js";
24
22
  import type { ToolExecutor } from "../tools/executor.js";
@@ -48,27 +46,10 @@ import {
48
46
  } from "./doordash-steps.js";
49
47
  import type { ServerMessage, UiSurfaceShow } from "./message-protocol.js";
50
48
  import { runPostExecutionSideEffects } from "./tool-side-effects.js";
51
- import type { TrustContext } from "./trust-context.js";
49
+ import { resolveTrustClass } from "./trust-context.js";
52
50
 
53
51
  const log = getLogger("conversation-tool-setup");
54
52
 
55
- /**
56
- * Resolve the effective trust class for tool execution.
57
- *
58
- * When HTTP auth is disabled (dev bypass), always returns `'guardian'`
59
- * so that control-plane gates don't block local development.
60
- *
61
- * When no trust context is available (e.g. desktop-only conversations that
62
- * don't go through channel trust resolution), defaults to `'unknown'`
63
- * to fail-closed.
64
- */
65
- export function resolveTrustClass(
66
- trustContext: TrustContext | undefined,
67
- ): TrustClass {
68
- if (isHttpAuthDisabled()) return "guardian";
69
- return trustContext?.trustClass ?? "unknown";
70
- }
71
-
72
53
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
73
54
  import { AUTO_PROFILE_KEY } from "../config/seed-inference-profiles.js";
74
55
  import {
@@ -97,7 +78,6 @@ export function createToolExecutor(
97
78
  input: Record<string, unknown>,
98
79
  onOutput?: (chunk: string) => void,
99
80
  toolUseId?: string,
100
- turnContext?: import("../plugins/types.js").TurnContext,
101
81
  ) => Promise<ToolExecutionResult> {
102
82
  // Register the conversation's sendToClient for browser screencast surface messages
103
83
  registerConversationSender(ctx.conversationId, (msg) =>
@@ -109,7 +89,6 @@ export function createToolExecutor(
109
89
  input: Record<string, unknown>,
110
90
  onOutput?: (chunk: string) => void,
111
91
  toolUseId?: string,
112
- turnContext?: import("../plugins/types.js").TurnContext,
113
92
  ) => {
114
93
  const { name: executionName, input: executionInput } =
115
94
  resolveToolInvocationAlias(name, input, ctx.allowedToolNames);
@@ -257,12 +236,7 @@ export function createToolExecutor(
257
236
  };
258
237
  }
259
238
 
260
- const result = await executor.execute(
261
- toolName,
262
- toolInput,
263
- toolContext,
264
- turnContext,
265
- );
239
+ const result = await executor.execute(toolName, toolInput, toolContext);
266
240
  if (toolContext.approvedViaPrompt) {
267
241
  ctx.approvedViaPromptThisTurn = true;
268
242
  }
@@ -276,7 +250,6 @@ export function createToolExecutor(
276
250
  executionName,
277
251
  executionInput,
278
252
  toolContext,
279
- turnContext,
280
253
  );
281
254
  if (toolContext.approvedViaPrompt) {
282
255
  ctx.approvedViaPromptThisTurn = true;
@@ -52,7 +52,6 @@ import { registerToolTraceListener } from "../events/tool-trace-listener.js";
52
52
  import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
53
53
  import {
54
54
  getConversation,
55
- getConversationOriginChannel,
56
55
  getConversationOverrideProfileFromRow,
57
56
  setConversationHistoryStrippedAt,
58
57
  } from "../memory/conversation-crud.js";
@@ -68,6 +67,7 @@ import type { TrustClass } from "../runtime/actor-trust-resolver.js";
68
67
  import { broadcastMessage } from "../runtime/assistant-event-hub.js";
69
68
  import type { AuthContext } from "../runtime/auth/types.js";
70
69
  import type { InteractiveUiResult } from "../runtime/interactive-ui.js";
70
+ import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
71
71
  import { ToolExecutor } from "../tools/executor.js";
72
72
  import { getAllToolDefinitions } from "../tools/registry.js";
73
73
  import type { ToolLifecycleEvent } from "../tools/types.js";
@@ -127,7 +127,6 @@ import type { ToolSetupContext } from "./conversation-tool-setup.js";
127
127
  import {
128
128
  createResolveToolsCallback,
129
129
  createToolExecutor,
130
- resolveTrustClass,
131
130
  } from "./conversation-tool-setup.js";
132
131
  import { refreshWorkspaceTopLevelContextIfNeeded as refreshWorkspaceImpl } from "./conversation-workspace.js";
133
132
  import { canonicalizeTimeZone } from "./date-context.js";
@@ -143,6 +142,7 @@ import type {
143
142
  import type { ConversationTransportMetadata } from "./message-types/conversations.js";
144
143
  import { isHostProxyTransport } from "./message-types/conversations.js";
145
144
  import type { ConfirmationStateChanged } from "./message-types/messages.js";
145
+ import { conversationMetadataSyncTag } from "./message-types/sync.js";
146
146
  import { TraceEmitter } from "./trace-emitter.js";
147
147
 
148
148
  const log = getLogger("conversation");
@@ -159,7 +159,7 @@ export type {
159
159
  QueueDrainReason,
160
160
  QueuePolicy,
161
161
  } from "./conversation-queue-manager.js";
162
- import type { TrustContext } from "./trust-context.js";
162
+ import { resolveTrustClass, type TrustContext } from "./trust-context.js";
163
163
 
164
164
  export interface ConversationConstructorOptions {
165
165
  maxTokens?: number;
@@ -174,7 +174,7 @@ export class Conversation {
174
174
  /** @internal */ provider: Provider;
175
175
  /** @internal */ messages: Message[] = [];
176
176
  /** @internal */ agentLoop: AgentLoop;
177
- /** @internal */ processing = false;
177
+ private _processing = false;
178
178
  private stale = false;
179
179
  /** @internal */ abortController: AbortController | null = null;
180
180
  /** @internal */ prompter: PermissionPrompter;
@@ -733,7 +733,30 @@ export class Conversation {
733
733
  }
734
734
 
735
735
  isProcessing(): boolean {
736
- return this.processing;
736
+ return this._processing;
737
+ }
738
+
739
+ /**
740
+ * Mutate the server-authoritative `processing` flag. Web/Capacitor/CLI
741
+ * caches treat this flag as the source of truth for the avatar streaming
742
+ * ring and thinking indicator, so the `true → false` clear must announce
743
+ * itself: the daemon flips it in the agent-loop `finally` (after an awaited
744
+ * turn-boundary commit), which is later than the user-visible terminal SSE
745
+ * events, and a racing metadata refetch can otherwise re-read the
746
+ * not-yet-cleared `true` and clobber the client's optimistic `false`.
747
+ *
748
+ * Emitting a metadata invalidation on the clear lets every client GET the
749
+ * authoritative `false`, per the multi-client-sync contract in AGENTS.md
750
+ * ("emit the invalidation after the canonical state write succeeds").
751
+ */
752
+ setProcessing(value: boolean): void {
753
+ const wasProcessing = this._processing;
754
+ this._processing = value;
755
+ if (wasProcessing && !value) {
756
+ void publishSyncInvalidation([
757
+ conversationMetadataSyncTag(this.conversationId),
758
+ ]);
759
+ }
737
760
  }
738
761
 
739
762
  markStale(): void {
@@ -795,6 +818,7 @@ export class Conversation {
795
818
  this.cesClient = undefined;
796
819
  this.activeContextNodeIds = this.graphMemory.tracker.getActiveNodeIds();
797
820
  this.graphMemory.persistState();
821
+ this.graphMemory.dispose();
798
822
  disposeConversation(this);
799
823
  }
800
824
 
@@ -836,7 +860,7 @@ export class Conversation {
836
860
  }
837
861
 
838
862
  canHandoffAtCheckpoint(): boolean {
839
- return this.processing && this.hasQueuedMessages();
863
+ return this._processing && this.hasQueuedMessages();
840
864
  }
841
865
 
842
866
  hasPendingConfirmation(requestId: string): boolean {
@@ -1020,9 +1044,7 @@ export class Conversation {
1020
1044
  }
1021
1045
  }
1022
1046
 
1023
- async forceCompact(options?: {
1024
- targetInputTokensOverride?: number;
1025
- }): Promise<ContextWindowResult> {
1047
+ async forceCompact(): Promise<ContextWindowResult> {
1026
1048
  const conversationRow = getConversation(this.conversationId);
1027
1049
  const overrideProfile =
1028
1050
  getConversationOverrideProfileFromRow(conversationRow) ?? null;
@@ -1066,11 +1088,7 @@ export class Conversation {
1066
1088
  this.abortController?.signal ?? undefined,
1067
1089
  {
1068
1090
  force: true,
1069
- lastCompactedAt: this.contextCompactedAt ?? undefined,
1070
- conversationOriginChannel:
1071
- getConversationOriginChannel(this.conversationId) ?? undefined,
1072
1091
  overrideProfile,
1073
- targetInputTokensOverride: options?.targetInputTokensOverride,
1074
1092
  actorTrustClass: this.trustContext?.trustClass,
1075
1093
  },
1076
1094
  );
@@ -1251,7 +1269,7 @@ export class Conversation {
1251
1269
  async persistUserMessage(
1252
1270
  options: PersistMessageOptions,
1253
1271
  ): Promise<{ id: string; deduplicated: boolean }> {
1254
- if (!this.processing) {
1272
+ if (!this._processing) {
1255
1273
  await this.ensureActorScopedHistory();
1256
1274
  }
1257
1275
  return persistUserMessageImpl(this, options);
@@ -16,9 +16,8 @@
16
16
  * the plugin is skipped wholesale — no `init()`, no tool/route/skill
17
17
  * contributions, no entry in the shutdown hook, and the plugin is also
18
18
  * dropped from the registry via {@link unregisterPlugin} so its middleware
19
- * and injectors stop participating in pipeline runs and system-prompt
20
- * assembly. This is the primary mechanism for shipping experimental
21
- * plugins behind a feature flag.
19
+ * stops participating in pipeline runs. This is the primary mechanism for
20
+ * shipping experimental plugins behind a feature flag.
22
21
  * 4. Resolves the plugin's `manifest.requiresCredential` entries via the
23
22
  * credential store helper ({@link getSecureKeyAsync}). In Docker mode
24
23
  * that helper goes through the CES HTTP API transparently; in local mode
@@ -190,8 +189,8 @@ function getDisabledPluginFlag(
190
189
  * 1. Install the `globalThis.__vellumPluginRuntime` bridge so plugins can touch
191
190
  * it from their module body (see `plugins/external-api.ts` — compiled-binary
192
191
  * module identity).
193
- * 2. Register the first-party defaults so their middleware and injectors
194
- * compose innermost, ahead of any user plugins.
192
+ * 2. Register the first-party defaults so their middleware composes innermost,
193
+ * ahead of any user plugins.
195
194
  * 3. Load user plugins from `<workspaceDir>/plugins/*`. A failing user plugin is
196
195
  * logged and skipped; `loadUserPlugins()` closes the registration window
197
196
  * when it returns, so the defaults must already be registered by then.
@@ -228,7 +227,7 @@ export async function initializePlugins(): Promise<void> {
228
227
  */
229
228
  export async function bootstrapPlugins(): Promise<void> {
230
229
  // Register first-party default plugins. Each default wraps one of the
231
- // assistant's canonical pipelines (`toolExecute`, `llmCall`, ...) with a
230
+ // assistant's canonical pipelines (`compaction`, `persistence`, ...) with a
232
231
  // passthrough so the pipeline shape is explicit at boot even when no
233
232
  // third-party plugins are loaded. Registration is idempotent via the
234
233
  // already-registered guard so repeated calls (e.g. during integration
@@ -237,8 +236,8 @@ export async function bootstrapPlugins(): Promise<void> {
237
236
 
238
237
  const plugins = getRegisteredPlugins();
239
238
  if (plugins.length === 0) {
240
- // No-op fast path. The default injectors normally populate the registry,
241
- // so this branch is primarily for tests that call
239
+ // No-op fast path. The default plugins normally populate the registry, so
240
+ // this branch is primarily for tests that call
242
241
  // `resetPluginRegistryForTests()` and stub the default registration.
243
242
  log.debug("bootstrapPlugins: registry empty — skipping");
244
243
  return;
@@ -263,8 +262,8 @@ export async function bootstrapPlugins(): Promise<void> {
263
262
  // two steps always move together on the bootstrap failure path: the former
264
263
  // clears tools/routes/skills (so they stop appearing to the model/HTTP
265
264
  // server), the latter drops the plugin's entry from the Map (so
266
- // `getMiddlewaresFor` / `getInjectors` don't re-enter an uninitialized
267
- // plugin on the next pipeline invocation).
265
+ // `getMiddlewaresFor` doesn't re-enter an uninitialized plugin on the next
266
+ // pipeline invocation).
268
267
  // Shutdown context is identical for every plugin in this boot — construct
269
268
  // once and reuse across the bootstrap-failure rollback and the normal
270
269
  // shutdown hook below. Only `assistantVersion` is exposed today; future
@@ -10,6 +10,8 @@
10
10
  * - acceptA2AInvite() — self-hosted broker: orchestrate complete + redeem across daemons
11
11
  */
12
12
 
13
+ import { z } from "zod";
14
+
13
15
  import {
14
16
  getConfig,
15
17
  invalidateConfigCache,
@@ -38,42 +40,55 @@ const log = getLogger("config-a2a");
38
40
 
39
41
  // ── Result types ────────────────────────────────────────────────────
40
42
 
41
- export interface A2AConfigResult {
42
- success: boolean;
43
- enabled: boolean;
44
- activeConnections: number;
45
- error?: string;
46
- }
47
-
48
- export interface CreateA2AInviteResult {
49
- success: boolean;
50
- inviteId?: string;
51
- token?: string;
52
- expiresAt?: number;
53
- senderGatewayUrl?: string;
54
- error?: string;
55
- }
56
-
57
- export interface CompleteA2AInviteResult {
58
- success: boolean;
59
- sender?: { assistantId: string; displayName: string; gatewayUrl: string };
60
- error?: string;
61
- }
62
-
63
- export interface RedeemA2AInviteResult {
64
- success: boolean;
65
- contactId?: string;
66
- alreadyConnected?: boolean;
67
- error?: string;
68
- }
69
-
70
- export interface AcceptA2AInviteResult {
71
- success: boolean;
72
- contactId?: string;
73
- alreadyConnected?: boolean;
74
- error?: string;
75
- errorCode?: string;
76
- }
43
+ export const A2AConfigResultSchema = z.object({
44
+ success: z.boolean(),
45
+ enabled: z.boolean(),
46
+ activeConnections: z.number(),
47
+ error: z.string().optional(),
48
+ });
49
+ export type A2AConfigResult = z.infer<typeof A2AConfigResultSchema>;
50
+
51
+ export const CreateA2AInviteResultSchema = z.object({
52
+ success: z.boolean(),
53
+ inviteId: z.string().optional(),
54
+ token: z.string().optional(),
55
+ expiresAt: z.number().optional(),
56
+ senderGatewayUrl: z.string().optional(),
57
+ error: z.string().optional(),
58
+ });
59
+ export type CreateA2AInviteResult = z.infer<typeof CreateA2AInviteResultSchema>;
60
+
61
+ export const CompleteA2AInviteResultSchema = z.object({
62
+ success: z.boolean(),
63
+ sender: z
64
+ .object({
65
+ assistantId: z.string(),
66
+ displayName: z.string(),
67
+ gatewayUrl: z.string(),
68
+ })
69
+ .optional(),
70
+ error: z.string().optional(),
71
+ });
72
+ export type CompleteA2AInviteResult = z.infer<
73
+ typeof CompleteA2AInviteResultSchema
74
+ >;
75
+
76
+ export const RedeemA2AInviteResultSchema = z.object({
77
+ success: z.boolean(),
78
+ contactId: z.string().optional(),
79
+ alreadyConnected: z.boolean().optional(),
80
+ error: z.string().optional(),
81
+ });
82
+ export type RedeemA2AInviteResult = z.infer<typeof RedeemA2AInviteResultSchema>;
83
+
84
+ export const AcceptA2AInviteResultSchema = z.object({
85
+ success: z.boolean(),
86
+ contactId: z.string().optional(),
87
+ alreadyConnected: z.boolean().optional(),
88
+ error: z.string().optional(),
89
+ errorCode: z.string().optional(),
90
+ });
91
+ export type AcceptA2AInviteResult = z.infer<typeof AcceptA2AInviteResultSchema>;
77
92
 
78
93
  // ── Config operations ───────────────────────────────────────────────
79
94