@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
@@ -7,10 +7,15 @@ import { availableParallelism, cpus, totalmem } from "node:os";
7
7
 
8
8
  import { z } from "zod";
9
9
 
10
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
10
11
  import { getCpuLimit, getIsPlatform } from "../../config/env-registry.js";
12
+ import { resolveCallSiteConfig } from "../../config/llm-resolver.js";
13
+ import { getConfig } from "../../config/loader.js";
11
14
  import { parseIdentityFields } from "../../daemon/handlers/identity.js";
12
15
  import { getProfilerRuntimeStatus } from "../../daemon/profiler-run-store.js";
13
16
  import { getMaxMigrationVersion } from "../../memory/migrations/registry.js";
17
+ import { buildSystemPrompt } from "../../prompts/system-prompt.js";
18
+ import { getConfiguredProvider } from "../../providers/provider-send-message.js";
14
19
  import { getCesClient } from "../../security/secure-keys.js";
15
20
  import {
16
21
  getDiskUsageInfo,
@@ -23,10 +28,12 @@ import { resolveHatchedAtReadOnly } from "../../workspace/hatched-date.js";
23
28
  import { WORKSPACE_MIGRATIONS } from "../../workspace/migrations/registry.js";
24
29
  import { getLastWorkspaceMigrationId } from "../../workspace/migrations/runner.js";
25
30
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
31
+ import { runBtwSidechain } from "../btw-sidechain.js";
26
32
  import { NotFoundError } from "./errors.js";
27
33
  import {
28
34
  getCachedIntro,
29
35
  readWorkspaceGreetings,
36
+ setCachedIntro,
30
37
  } from "./identity-intro-cache.js";
31
38
  import type { RouteDefinition } from "./types.js";
32
39
 
@@ -402,31 +409,190 @@ const FALLBACK_GREETINGS = [
402
409
  "Ready when you are.",
403
410
  ];
404
411
 
405
- function getIdentityIntro() {
412
+ const GENERATED_GREETING_LIMIT = 4;
413
+ const GREETING_GENERATION_TIMEOUT_MS = 10_000;
414
+ const GREETING_GENERATION_FAILURE_COOLDOWN_MS = 60_000;
415
+ const EMPTY_STATE_GREETING_CALLSITE = "emptyStateGreeting" as const;
416
+ const EMPTY_STATE_DYNAMIC_GREETINGS_FLAG =
417
+ "empty-state-dynamic-greetings" as const;
418
+
419
+ type IdentityIntroSource = "workspace" | "cache" | "fallback";
420
+
421
+ interface IdentityIntroResponse {
422
+ greetings: string[];
423
+ text: string;
424
+ source: IdentityIntroSource;
425
+ refreshing: boolean;
426
+ }
427
+
428
+ let greetingGenerationInFlight: Promise<void> | null = null;
429
+ let lastGreetingGenerationFailureAt = 0;
430
+
431
+ function identityIntroResponse(
432
+ greetings: string[],
433
+ source: IdentityIntroSource,
434
+ refreshing = false,
435
+ ): IdentityIntroResponse {
436
+ return {
437
+ greetings,
438
+ text: greetings[0] ?? "",
439
+ source,
440
+ refreshing,
441
+ };
442
+ }
443
+
444
+ function getIdentityIntro(): IdentityIntroResponse {
406
445
  // 1. User-defined greetings from SOUL.md `## Greetings`
407
446
  const workspaceGreetings = readWorkspaceGreetings();
408
447
  if (workspaceGreetings) {
409
- return { greetings: workspaceGreetings, text: workspaceGreetings[0] };
448
+ return identityIntroResponse(workspaceGreetings, "workspace");
449
+ }
450
+
451
+ const config = getConfig();
452
+ if (
453
+ !isAssistantFeatureFlagEnabled(EMPTY_STATE_DYNAMIC_GREETINGS_FLAG, config)
454
+ ) {
455
+ return identityIntroResponse(FALLBACK_GREETINGS, "fallback");
410
456
  }
411
457
 
412
458
  // 2. Cached LLM-generated greetings
413
459
  const cached = getCachedIntro();
414
460
  if (cached) {
415
- return { greetings: cached.greetings, text: cached.greetings[0] };
461
+ return identityIntroResponse(cached.greetings, "cache");
416
462
  }
417
463
 
418
- // 3. Fallback: name-based greeting + static defaults
419
- const identityPath = getWorkspacePromptPath("IDENTITY.md");
420
- if (existsSync(identityPath)) {
421
- const content = readFileSync(identityPath, "utf-8");
422
- const fields = parseIdentityFields(content);
423
- if (fields.name) {
424
- const greetings = [`Hi, I'm ${fields.name}!`, ...FALLBACK_GREETINGS];
425
- return { greetings, text: greetings[0] };
464
+ // 3. Trigger fresh generation without blocking the empty-state UI.
465
+ const refreshing = triggerEmptyStateGreetingGeneration();
466
+
467
+ // 4. Generic fallback only when generation is unavailable.
468
+ return identityIntroResponse(FALLBACK_GREETINGS, "fallback", refreshing);
469
+ }
470
+
471
+ function triggerEmptyStateGreetingGeneration(): boolean {
472
+ if (greetingGenerationInFlight) {
473
+ return true;
474
+ }
475
+
476
+ if (
477
+ lastGreetingGenerationFailureAt > 0 &&
478
+ Date.now() - lastGreetingGenerationFailureAt <
479
+ GREETING_GENERATION_FAILURE_COOLDOWN_MS
480
+ ) {
481
+ return false;
482
+ }
483
+
484
+ greetingGenerationInFlight = new Promise<void>((resolve) => {
485
+ queueMicrotask(() => {
486
+ void generateEmptyStateGreetings()
487
+ .then((greetings) => {
488
+ lastGreetingGenerationFailureAt = greetings === null ? Date.now() : 0;
489
+ })
490
+ .finally(() => {
491
+ greetingGenerationInFlight = null;
492
+ resolve();
493
+ });
494
+ });
495
+ });
496
+
497
+ return true;
498
+ }
499
+
500
+ async function generateEmptyStateGreetings(): Promise<string[] | null> {
501
+ try {
502
+ const provider = await getConfiguredProvider(EMPTY_STATE_GREETING_CALLSITE);
503
+ if (!provider) {
504
+ return null;
505
+ }
506
+
507
+ const resolved = resolveCallSiteConfig(
508
+ EMPTY_STATE_GREETING_CALLSITE,
509
+ getConfig().llm,
510
+ );
511
+ const systemPrompt = buildSystemPrompt({
512
+ excludeBootstrap: true,
513
+ excludeCustomPrefix: true,
514
+ });
515
+ const result = await runBtwSidechain({
516
+ content:
517
+ `Generate ${GENERATED_GREETING_LIMIT} short first-person greeting options for the empty new-chat screen. ` +
518
+ "Use the assistant identity, voice, and relationship guidance from IDENTITY.md and SOUL.md. " +
519
+ "Each greeting should feel personal and inviting, not like a generic assistant introduction. " +
520
+ "Return only a JSON array of strings. No markdown, keys, or explanation.",
521
+ provider,
522
+ systemPrompt,
523
+ messages: [],
524
+ tools: [],
525
+ callSite: EMPTY_STATE_GREETING_CALLSITE,
526
+ maxTokens: resolved.maxTokens,
527
+ timeoutMs: GREETING_GENERATION_TIMEOUT_MS,
528
+ });
529
+
530
+ const greetings = parseGeneratedGreetings(result.text);
531
+ if (greetings.length === 0) {
532
+ return null;
533
+ }
534
+
535
+ setCachedIntro(greetings);
536
+ return greetings;
537
+ } catch (err) {
538
+ getLogger("identity").warn(
539
+ { err },
540
+ "Failed to generate empty-state greetings",
541
+ );
542
+ return null;
543
+ }
544
+ }
545
+
546
+ function parseGeneratedGreetings(text: string): string[] {
547
+ const cleaned = text
548
+ .trim()
549
+ .replace(/^```(?:json)?\s*/i, "")
550
+ .replace(/\s*```$/i, "")
551
+ .trim();
552
+
553
+ try {
554
+ const parsed = JSON.parse(cleaned) as unknown;
555
+ if (Array.isArray(parsed)) {
556
+ return normalizeGeneratedGreetings(parsed);
426
557
  }
558
+ if (
559
+ parsed &&
560
+ typeof parsed === "object" &&
561
+ Array.isArray((parsed as { greetings?: unknown }).greetings)
562
+ ) {
563
+ return normalizeGeneratedGreetings(
564
+ (parsed as { greetings: unknown[] }).greetings,
565
+ );
566
+ }
567
+ } catch {
568
+ // Fall through to line parsing for non-JSON model output.
569
+ }
570
+
571
+ return normalizeGeneratedGreetings(cleaned.split("\n"));
572
+ }
573
+
574
+ function normalizeGeneratedGreetings(values: unknown[]): string[] {
575
+ const greetings: string[] = [];
576
+ const seen = new Set<string>();
577
+
578
+ for (const value of values) {
579
+ if (typeof value !== "string") continue;
580
+ const greeting = value
581
+ .trim()
582
+ .replace(/^(?:[-*+]\s+|\d+[.)]\s+)/, "")
583
+ .replace(/^["'`]+|["'`]+$/g, "")
584
+ .trim();
585
+ if (!greeting) continue;
586
+
587
+ const key = greeting.toLowerCase();
588
+ if (seen.has(key)) continue;
589
+ seen.add(key);
590
+ greetings.push(greeting);
591
+
592
+ if (greetings.length >= GENERATED_GREETING_LIMIT) break;
427
593
  }
428
594
 
429
- return { greetings: FALLBACK_GREETINGS, text: FALLBACK_GREETINGS[0] };
595
+ return greetings;
430
596
  }
431
597
 
432
598
  // ---------------------------------------------------------------------------
@@ -464,14 +630,37 @@ const cesHealthSchema = z.object({
464
630
  connected: z.boolean(),
465
631
  });
466
632
 
633
+ const healthDiskSchema = z.object({
634
+ path: z.string(),
635
+ totalMb: z.number(),
636
+ usedMb: z.number(),
637
+ freeMb: z.number(),
638
+ });
639
+
640
+ const healthMemorySchema = z.object({
641
+ currentMb: z.number(),
642
+ maxMb: z.number(),
643
+ });
644
+
645
+ const healthCpuSchema = z.object({
646
+ currentPercent: z.number(),
647
+ maxCores: z.number(),
648
+ });
649
+
650
+ const healthMigrationsSchema = z.object({
651
+ dbVersion: z.number(),
652
+ lastWorkspaceMigrationId: z.string().nullable(),
653
+ });
654
+
467
655
  const detailedHealthSchema = z.object({
468
656
  status: z.string(),
469
657
  timestamp: z.string(),
470
658
  version: z.string(),
471
- disk: z.object({}).passthrough(),
472
- memory: z.object({}).passthrough(),
473
- cpu: z.object({}).passthrough(),
474
- migrations: z.object({}).passthrough(),
659
+ // `getDiskUsageInfo()` returns null when usage can't be measured.
660
+ disk: healthDiskSchema.nullable(),
661
+ memory: healthMemorySchema,
662
+ cpu: healthCpuSchema,
663
+ migrations: healthMigrationsSchema,
475
664
  ces: cesHealthSchema,
476
665
  profiler: profilerStatusSchema.optional(),
477
666
  });
@@ -544,11 +733,13 @@ export const ROUTES: RouteDefinition[] = [
544
733
  handler: getIdentityIntro,
545
734
  summary: "Get identity greetings",
546
735
  description:
547
- "Returns an array of greetings sourced from SOUL.md, LLM cache, or static fallbacks.",
736
+ "Returns greetings sourced from SOUL.md, the generated cache, or generic fallbacks while background generation refreshes the cache.",
548
737
  tags: ["identity"],
549
738
  responseBody: z.object({
550
739
  greetings: z.array(z.string()),
551
740
  text: z.string(),
741
+ source: z.enum(["workspace", "cache", "fallback"]),
742
+ refreshing: z.boolean(),
552
743
  }),
553
744
  },
554
745
  ];
@@ -1,3 +1,5 @@
1
+ import { z } from "zod";
2
+
1
3
  import { getConfig } from "../../config/loader.js";
2
4
  import { resolveImageGenCredentials } from "../../media/image-credentials.js";
3
5
  import {
@@ -6,16 +8,50 @@ import {
6
8
  providerForModel,
7
9
  } from "../../media/image-service.js";
8
10
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
9
- import { BadRequestError, InternalError, UnprocessableEntityError } from "./errors.js";
11
+ import {
12
+ BadRequestError,
13
+ InternalError,
14
+ UnprocessableEntityError,
15
+ } from "./errors.js";
10
16
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
11
17
 
18
+ // ---------------------------------------------------------------------------
19
+ // Schemas
20
+ // ---------------------------------------------------------------------------
21
+
22
+ const SourceImageSchema = z.object({
23
+ mimeType: z.string(),
24
+ dataBase64: z.string(),
25
+ });
26
+
27
+ const ImageGenerationRequestSchema = z.object({
28
+ prompt: z.string(),
29
+ mode: z.enum(["generate", "edit"]).optional(),
30
+ sourceImages: z.array(SourceImageSchema).optional(),
31
+ model: z.string().optional(),
32
+ variants: z.number().optional(),
33
+ });
34
+
35
+ const GeneratedImageSchema = z.object({
36
+ mimeType: z.string(),
37
+ dataBase64: z.string(),
38
+ title: z.string().optional(),
39
+ });
40
+
41
+ const ImageGenerationResponseSchema = z.object({
42
+ images: z.array(GeneratedImageSchema),
43
+ text: z.string().optional(),
44
+ resolvedModel: z.string(),
45
+ });
46
+ type ImageGenerationResponse = z.infer<typeof ImageGenerationResponseSchema>;
47
+
12
48
  // ---------------------------------------------------------------------------
13
49
  // Handler
14
50
  // ---------------------------------------------------------------------------
15
51
 
16
52
  async function handleImageGenerationGenerate(
17
53
  args: RouteHandlerArgs,
18
- ): Promise<unknown> {
54
+ ): Promise<ImageGenerationResponse> {
19
55
  const { prompt, mode, sourceImages, model, variants } = args.body ?? {};
20
56
 
21
57
  // Validate prompt
@@ -99,6 +135,8 @@ export const ROUTES: RouteDefinition[] = [
99
135
  description:
100
136
  "Calls the configured image-generation provider (Gemini or OpenAI) to produce one or more images.",
101
137
  tags: ["image-generation"],
138
+ requestBody: ImageGenerationRequestSchema,
139
+ responseBody: ImageGenerationResponseSchema,
102
140
  handler: handleImageGenerationGenerate,
103
141
  },
104
142
  ];
@@ -85,6 +85,7 @@ import { ROUTES as TELEGRAM_ROUTES } from "./integrations/telegram.js";
85
85
  import { ROUTES as TWILIO_ROUTES } from "./integrations/twilio.js";
86
86
  import { ROUTES as VERCEL_ROUTES } from "./integrations/vercel.js";
87
87
  import { ROUTES as INTERNAL_OAUTH_ROUTES } from "./internal-oauth-routes.js";
88
+ import { ROUTES as INTERNAL_TELEMETRY_ROUTES } from "./internal-telemetry-routes.js";
88
89
  import { ROUTES as INTERNAL_TWILIO_ROUTES } from "./internal-twilio-routes.js";
89
90
  import { ROUTES as LLM_CALL_SITES_ROUTES } from "./llm-call-sites-routes.js";
90
91
  import { ROUTES as LOG_EXPORT_ROUTES } from "./log-export-routes.js";
@@ -212,6 +213,7 @@ export const ROUTES: RouteDefinition[] = [
212
213
  ...INFERENCE_PROVIDER_CONNECTION_ROUTES,
213
214
  ...INFERENCE_SEND_ROUTES,
214
215
  ...INTERNAL_OAUTH_ROUTES,
216
+ ...INTERNAL_TELEMETRY_ROUTES,
215
217
  ...MCP_AUTH_ROUTES,
216
218
  ...OAUTH_CONNECT_ROUTES,
217
219
  ...INTERNAL_TWILIO_ROUTES,
@@ -10,17 +10,20 @@
10
10
  * POST /v1/integrations/a2a/invite/accept — self-hosted broker: orchestrate complete + redeem
11
11
  */
12
12
 
13
- import { z } from "zod";
14
-
15
13
  import { isA2AEnabled } from "../../../a2a/feature-gate.js";
16
14
  import { getConfig } from "../../../config/loader.js";
17
15
  import {
16
+ A2AConfigResultSchema,
18
17
  acceptA2AInvite,
18
+ AcceptA2AInviteResultSchema,
19
19
  clearA2AConfig,
20
20
  completeA2AInvite,
21
+ CompleteA2AInviteResultSchema,
21
22
  createA2AInvite,
23
+ CreateA2AInviteResultSchema,
22
24
  getA2AConfig,
23
25
  redeemA2AInvite,
26
+ RedeemA2AInviteResultSchema,
24
27
  setA2AConfig,
25
28
  } from "../../../daemon/handlers/config-a2a.js";
26
29
  import {
@@ -232,6 +235,7 @@ export const ROUTES: RouteDefinition[] = [
232
235
  description: "Check current A2A channel configuration status.",
233
236
  tags: ["integrations"],
234
237
  handler: () => handleGetA2AConfig(),
238
+ responseBody: A2AConfigResultSchema,
235
239
  },
236
240
  {
237
241
  operationId: "integrations_a2a_config_post",
@@ -242,6 +246,7 @@ export const ROUTES: RouteDefinition[] = [
242
246
  description: "Enable the A2A channel for inter-assistant communication.",
243
247
  tags: ["integrations"],
244
248
  handler: () => handleSetA2AConfig(),
249
+ responseBody: A2AConfigResultSchema,
245
250
  },
246
251
  {
247
252
  operationId: "integrations_a2a_config_delete",
@@ -252,6 +257,7 @@ export const ROUTES: RouteDefinition[] = [
252
257
  description: "Disable the A2A channel.",
253
258
  tags: ["integrations"],
254
259
  handler: () => handleClearA2AConfig(),
260
+ responseBody: A2AConfigResultSchema,
255
261
  },
256
262
  {
257
263
  operationId: "integrations_a2a_invite_post",
@@ -266,14 +272,7 @@ export const ROUTES: RouteDefinition[] = [
266
272
  "Create a shareable A2A invite token for link-based contact creation.",
267
273
  tags: ["integrations"],
268
274
  handler: handleCreateA2AInvite,
269
- responseBody: z.object({
270
- success: z.boolean(),
271
- inviteId: z.string().optional(),
272
- token: z.string().optional(),
273
- expiresAt: z.number().optional(),
274
- senderGatewayUrl: z.string().optional(),
275
- error: z.string().optional(),
276
- }),
275
+ responseBody: CreateA2AInviteResultSchema,
277
276
  },
278
277
  {
279
278
  operationId: "integrations_a2a_invite_complete_post",
@@ -288,6 +287,7 @@ export const ROUTES: RouteDefinition[] = [
288
287
  "Called by the platform to finalize the sender side of a link-based A2A connection.",
289
288
  tags: ["integrations"],
290
289
  handler: handleCompleteA2AInvite,
290
+ responseBody: CompleteA2AInviteResultSchema,
291
291
  },
292
292
  {
293
293
  operationId: "integrations_a2a_invite_redeem_post",
@@ -302,6 +302,7 @@ export const ROUTES: RouteDefinition[] = [
302
302
  "Called by the platform to create a trusted contact on the receiver side of a link-based A2A connection.",
303
303
  tags: ["integrations"],
304
304
  handler: handleRedeemA2AInvite,
305
+ responseBody: RedeemA2AInviteResultSchema,
305
306
  },
306
307
  {
307
308
  operationId: "integrations_a2a_invite_accept_post",
@@ -313,5 +314,6 @@ export const ROUTES: RouteDefinition[] = [
313
314
  "Orchestrate cross-daemon invite acceptance for self-hosted deployments. Calls the sender's invite/complete, then creates a local contact via invite/redeem.",
314
315
  tags: ["integrations"],
315
316
  handler: handleAcceptA2AInvite,
317
+ responseBody: AcceptA2AInviteResultSchema,
316
318
  },
317
319
  ];
@@ -7,6 +7,8 @@
7
7
 
8
8
  import { afterEach, describe, expect, mock, test } from "bun:test";
9
9
 
10
+ import { z } from "zod";
11
+
10
12
  import type { SlackChannelConfigResult } from "../../../../../daemon/handlers/config-slack-channel.js";
11
13
 
12
14
  // ---------------------------------------------------------------------------
@@ -29,6 +31,20 @@ let mockSetConfigResult: SlackChannelConfigResult = {
29
31
  };
30
32
 
31
33
  mock.module("../../../../../daemon/handlers/config-slack-channel.js", () => ({
34
+ SlackChannelConfigResultSchema: z.object({
35
+ success: z.boolean(),
36
+ hasBotToken: z.boolean(),
37
+ hasAppToken: z.boolean(),
38
+ hasUserToken: z.boolean(),
39
+ connected: z.boolean(),
40
+ teamId: z.string().optional(),
41
+ teamName: z.string().optional(),
42
+ teamUrl: z.string().optional(),
43
+ botUserId: z.string().optional(),
44
+ botUsername: z.string().optional(),
45
+ error: z.string().optional(),
46
+ warning: z.string().optional(),
47
+ }),
32
48
  setSlackChannelConfig: async (
33
49
  botToken?: string,
34
50
  appToken?: string,
@@ -12,6 +12,7 @@ import {
12
12
  clearSlackChannelConfig,
13
13
  getSlackChannelConfig,
14
14
  setSlackChannelConfig,
15
+ SlackChannelConfigResultSchema,
15
16
  } from "../../../../daemon/handlers/config-slack-channel.js";
16
17
  import { ACTOR_PRINCIPALS } from "../../../auth/route-policy.js";
17
18
  import { BadRequestError } from "../../errors.js";
@@ -62,6 +63,7 @@ export const ROUTES: RouteDefinition[] = [
62
63
  summary: "Get Slack channel config",
63
64
  description: "Check current Slack channel configuration status.",
64
65
  tags: ["integrations"],
66
+ responseBody: SlackChannelConfigResultSchema,
65
67
  handler: () => handleGetSlackChannelConfig(),
66
68
  },
67
69
  {
@@ -80,6 +82,7 @@ export const ROUTES: RouteDefinition[] = [
80
82
  botToken: z.string().describe("Slack bot token"),
81
83
  appToken: z.string().describe("Slack app-level token"),
82
84
  }),
85
+ responseBody: SlackChannelConfigResultSchema,
83
86
  },
84
87
  {
85
88
  operationId: "integrations_slack_channel_config_delete",
@@ -92,6 +95,7 @@ export const ROUTES: RouteDefinition[] = [
92
95
  summary: "Clear Slack channel config",
93
96
  description: "Clear stored Slack channel credentials.",
94
97
  tags: ["integrations"],
98
+ responseBody: SlackChannelConfigResultSchema,
95
99
  handler: () => handleClearSlackChannelConfig(),
96
100
  },
97
101
  ];
@@ -5,6 +5,8 @@
5
5
  * without going through the legacy Slack share flow.
6
6
  */
7
7
 
8
+ import { z } from "zod";
9
+
8
10
  import { getApp } from "../../../../memory/app-store.js";
9
11
  import {
10
12
  listConversations,
@@ -29,12 +31,24 @@ const log = getLogger("slack-share");
29
31
  // GET /v1/slack/channels
30
32
  // ---------------------------------------------------------------------------
31
33
 
32
- interface NormalizedChannel {
33
- id: string;
34
- name: string;
35
- type: "channel" | "group" | "dm";
36
- isPrivate: boolean;
37
- }
34
+ const NormalizedChannelSchema = z.object({
35
+ id: z.string(),
36
+ name: z.string(),
37
+ type: z.enum(["channel", "group", "dm"]),
38
+ isPrivate: z.boolean(),
39
+ });
40
+
41
+ type NormalizedChannel = z.infer<typeof NormalizedChannelSchema>;
42
+
43
+ const SlackChannelsListResultSchema = z.object({
44
+ channels: z.array(NormalizedChannelSchema),
45
+ });
46
+
47
+ const SlackShareResultSchema = z.object({
48
+ ok: z.boolean(),
49
+ ts: z.string(),
50
+ channel: z.string(),
51
+ });
38
52
 
39
53
  function classifyConversation(
40
54
  conv: SlackConversation,
@@ -205,6 +219,7 @@ export const ROUTES: RouteDefinition[] = [
205
219
  summary: "List Slack channels",
206
220
  description: "List Slack channels, groups, and DMs for the channel picker.",
207
221
  tags: ["integrations"],
222
+ responseBody: SlackChannelsListResultSchema,
208
223
  handler: () => handleListSlackChannels(),
209
224
  },
210
225
  {
@@ -218,6 +233,12 @@ export const ROUTES: RouteDefinition[] = [
218
233
  summary: "Share to Slack channel",
219
234
  description: "Post an app link directly to a Slack channel.",
220
235
  tags: ["integrations"],
236
+ requestBody: z.object({
237
+ appId: z.string().describe("App to share"),
238
+ channelId: z.string().describe("Target Slack channel ID"),
239
+ message: z.string().optional().describe("Optional accompanying message"),
240
+ }),
241
+ responseBody: SlackShareResultSchema,
221
242
  handler: handleShareToSlackChannel,
222
243
  },
223
244
  ];
@@ -16,6 +16,7 @@ import {
16
16
  setTelegramCommands,
17
17
  setTelegramConfig,
18
18
  setupTelegram,
19
+ TelegramConfigResultSchema,
19
20
  } from "../../../daemon/handlers/config-telegram.js";
20
21
  import { ACTOR_PRINCIPALS } from "../../auth/route-policy.js";
21
22
  import { BadRequestError } from "../errors.js";
@@ -87,6 +88,7 @@ export const ROUTES: RouteDefinition[] = [
87
88
  summary: "Get Telegram config",
88
89
  description: "Check current Telegram bot configuration status.",
89
90
  tags: ["integrations"],
91
+ responseBody: TelegramConfigResultSchema,
90
92
  handler: () => handleGetTelegramConfig(),
91
93
  },
92
94
  {
@@ -104,6 +106,7 @@ export const ROUTES: RouteDefinition[] = [
104
106
  requestBody: z.object({
105
107
  botToken: z.string().describe("Telegram bot token"),
106
108
  }),
109
+ responseBody: TelegramConfigResultSchema,
107
110
  },
108
111
  {
109
112
  operationId: "integrations_telegram_config_delete",
@@ -116,6 +119,7 @@ export const ROUTES: RouteDefinition[] = [
116
119
  summary: "Clear Telegram config",
117
120
  description: "Clear credentials and deregister webhook.",
118
121
  tags: ["integrations"],
122
+ responseBody: TelegramConfigResultSchema,
119
123
  handler: () => handleClearTelegramConfig(),
120
124
  },
121
125
  {
@@ -129,6 +133,7 @@ export const ROUTES: RouteDefinition[] = [
129
133
  summary: "Register Telegram commands",
130
134
  description: "Register bot commands with the Telegram API.",
131
135
  tags: ["integrations"],
136
+ responseBody: TelegramConfigResultSchema,
132
137
  handler: handleSetTelegramCommands,
133
138
  },
134
139
  {
@@ -142,6 +147,7 @@ export const ROUTES: RouteDefinition[] = [
142
147
  summary: "Setup Telegram",
143
148
  description: "Composite: set config + register commands.",
144
149
  tags: ["integrations"],
150
+ responseBody: TelegramConfigResultSchema,
145
151
  handler: handleSetupTelegram,
146
152
  },
147
153
  ];