@vellumai/assistant 0.8.1 → 0.8.3

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 (630) hide show
  1. package/ARCHITECTURE.md +13 -19
  2. package/Dockerfile +75 -1
  3. package/bun.lock +11 -1
  4. package/docker-entrypoint.sh +17 -0
  5. package/docker-init-apt-root.sh +167 -0
  6. package/docker-kata-apt-env.sh +39 -0
  7. package/docs/plugins.md +88 -47
  8. package/docs/skills.md +9 -7
  9. package/examples/plugins/echo/README.md +27 -27
  10. package/examples/plugins/echo/package.json +3 -0
  11. package/examples/plugins/echo/register.ts +31 -31
  12. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  13. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  14. package/openapi.yaml +642 -5
  15. package/package.json +3 -1
  16. package/scripts/generate-openapi.ts +83 -10
  17. package/scripts/sync-llm-catalog.ts +2 -2
  18. package/scripts/sync-web-search-catalog.ts +47 -25
  19. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  20. package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
  21. package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  23. package/src/__tests__/anthropic-provider.test.ts +45 -0
  24. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  25. package/src/__tests__/app-executors.test.ts +220 -4
  26. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  27. package/src/__tests__/bundled-asset.test.ts +6 -6
  28. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  29. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  30. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  31. package/src/__tests__/clawhub.test.ts +75 -16
  32. package/src/__tests__/compactor-tail-resolution.test.ts +147 -0
  33. package/src/__tests__/config-get-vision-flag.test.ts +136 -0
  34. package/src/__tests__/config-loader-backfill.test.ts +115 -18
  35. package/src/__tests__/config-schema.test.ts +21 -0
  36. package/src/__tests__/config-set-route.test.ts +80 -0
  37. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  38. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  39. package/src/__tests__/context-search-conversations-source.test.ts +117 -2
  40. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  41. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  42. package/src/__tests__/context-token-estimator.test.ts +31 -65
  43. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  44. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  45. package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
  46. package/src/__tests__/conversation-agent-loop.test.ts +59 -1
  47. package/src/__tests__/conversation-error.test.ts +42 -3
  48. package/src/__tests__/conversation-fork-crud.test.ts +82 -0
  49. package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
  50. package/src/__tests__/conversation-lifecycle.test.ts +173 -0
  51. package/src/__tests__/conversation-media-retry.test.ts +19 -8
  52. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  53. package/src/__tests__/conversation-pairing.test.ts +54 -0
  54. package/src/__tests__/conversation-process-callsite.test.ts +4 -1
  55. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  56. package/src/__tests__/conversation-queue.test.ts +4 -1
  57. package/src/__tests__/conversation-runtime-assembly.test.ts +102 -13
  58. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  59. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  60. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  61. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  62. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  63. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  64. package/src/__tests__/credential-security-invariants.test.ts +3 -2
  65. package/src/__tests__/date-context.test.ts +45 -0
  66. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  67. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  68. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  69. package/src/__tests__/dm-backfill.test.ts +121 -10
  70. package/src/__tests__/document-tool-security.test.ts +258 -0
  71. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  72. package/src/__tests__/edit-propagation.test.ts +33 -0
  73. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  74. package/src/__tests__/external-plugin-loader.test.ts +151 -55
  75. package/src/__tests__/filing-service.test.ts +140 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  77. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
  78. package/src/__tests__/guardian-dispatch.test.ts +1 -0
  79. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
  80. package/src/__tests__/heartbeat-service.test.ts +24 -164
  81. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  82. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  83. package/src/__tests__/helpers/wait-for.ts +21 -0
  84. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  85. package/src/__tests__/history-repair.test.ts +73 -0
  86. package/src/__tests__/host-app-control-proxy.test.ts +507 -10
  87. package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
  88. package/src/__tests__/image-credentials.test.ts +1 -1
  89. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  90. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
  91. package/src/__tests__/inference-profile-reaper.test.ts +4 -2
  92. package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
  93. package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
  94. package/src/__tests__/injector-background-turn.test.ts +153 -0
  95. package/src/__tests__/injector-chain.test.ts +15 -8
  96. package/src/__tests__/install-skill-routing.test.ts +155 -37
  97. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +99 -3
  98. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  99. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  100. package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
  101. package/src/__tests__/llm-catalog-parity.test.ts +58 -13
  102. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
  103. package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
  104. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +36 -0
  105. package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
  106. package/src/__tests__/llm-resolver.test.ts +255 -2
  107. package/src/__tests__/llm-usage-store.test.ts +114 -0
  108. package/src/__tests__/managed-profile-guard.test.ts +41 -29
  109. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  110. package/src/__tests__/managed-store.test.ts +84 -192
  111. package/src/__tests__/media-generate-image.test.ts +1 -1
  112. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  113. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  114. package/src/__tests__/notification-decision-fallback.test.ts +0 -91
  115. package/src/__tests__/notification-decision-strategy.test.ts +14 -31
  116. package/src/__tests__/notification-deep-link.test.ts +15 -0
  117. package/src/__tests__/notification-guardian-path.test.ts +1 -2
  118. package/src/__tests__/notification-platform-adapter.test.ts +5 -4
  119. package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
  120. package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
  121. package/src/__tests__/oauth-commands-routes.test.ts +168 -16
  122. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  123. package/src/__tests__/openai-provider.test.ts +242 -3
  124. package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
  125. package/src/__tests__/openrouter-provider-only.test.ts +51 -3
  126. package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
  127. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  128. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  129. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +7 -2
  130. package/src/__tests__/platform.test.ts +2 -0
  131. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  132. package/src/__tests__/plugin-bootstrap.test.ts +10 -36
  133. package/src/__tests__/plugin-external-api.test.ts +68 -0
  134. package/src/__tests__/plugin-registry.test.ts +0 -77
  135. package/src/__tests__/plugin-route-contribution.test.ts +0 -1
  136. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  137. package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
  138. package/src/__tests__/plugin-types.test.ts +3 -13
  139. package/src/__tests__/process-message-background-slack.test.ts +8 -1
  140. package/src/__tests__/process-message-display-content.test.ts +421 -0
  141. package/src/__tests__/provider-catalog-visibility.test.ts +158 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  143. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +33 -31
  144. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  145. package/src/__tests__/schedule-routes.test.ts +50 -3
  146. package/src/__tests__/schedule-store.test.ts +94 -0
  147. package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
  148. package/src/__tests__/schema-transforms.test.ts +20 -0
  149. package/src/__tests__/search-skills-unified.test.ts +0 -5
  150. package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +1 -1
  151. package/src/__tests__/server-history-render.test.ts +43 -0
  152. package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
  153. package/src/__tests__/skill-load-tool.test.ts +27 -89
  154. package/src/__tests__/skill-memory.test.ts +23 -3
  155. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  156. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  157. package/src/__tests__/skills-install-extract.test.ts +49 -38
  158. package/src/__tests__/skills-install-staging.test.ts +159 -0
  159. package/src/__tests__/skills-uninstall.test.ts +9 -41
  160. package/src/__tests__/skills.test.ts +51 -58
  161. package/src/__tests__/slack-channel-config.test.ts +9 -0
  162. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  163. package/src/__tests__/system-prompt.test.ts +670 -63
  164. package/src/__tests__/terminal-tools.test.ts +28 -1
  165. package/src/__tests__/thread-backfill.test.ts +557 -27
  166. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  167. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  168. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  169. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  170. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  171. package/src/__tests__/tool-executor.test.ts +16 -4
  172. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  173. package/src/__tests__/turn-events-store.test.ts +256 -0
  174. package/src/__tests__/twilio-routes.test.ts +4 -0
  175. package/src/__tests__/user-plugin-loader.test.ts +0 -7
  176. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  177. package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
  178. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
  179. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
  180. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  181. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  182. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  183. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
  184. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  185. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  186. package/src/a2a/__tests__/agent-card.test.ts +98 -0
  187. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
  188. package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
  189. package/src/a2a/__tests__/task-store.test.ts +246 -0
  190. package/src/a2a/agent-card.ts +58 -0
  191. package/src/a2a/feature-gate.ts +8 -0
  192. package/src/a2a/protocol-constants.ts +21 -0
  193. package/src/a2a/protocol-errors.ts +50 -0
  194. package/src/a2a/protocol-types.ts +162 -0
  195. package/src/a2a/task-store.ts +168 -0
  196. package/src/acp/resolve-agent.ts +1 -1
  197. package/src/agent/image-optimize.ts +13 -5
  198. package/src/agent/loop.ts +167 -18
  199. package/src/calls/voice-session-bridge.ts +61 -42
  200. package/src/channels/config.ts +9 -0
  201. package/src/channels/types.ts +122 -0
  202. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  203. package/src/cli/commands/__tests__/changelog.test.ts +304 -319
  204. package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
  205. package/src/cli/commands/__tests__/schedules.test.ts +960 -0
  206. package/src/cli/commands/changelog.ts +106 -42
  207. package/src/cli/commands/conversations.ts +102 -17
  208. package/src/cli/commands/default-action.ts +10 -53
  209. package/src/cli/commands/notifications.ts +388 -346
  210. package/src/cli/commands/plugins.ts +252 -0
  211. package/src/cli/commands/schedules.ts +683 -0
  212. package/src/cli/commands/telemetry.ts +40 -0
  213. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  214. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  215. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  216. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  217. package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
  218. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  219. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  220. package/src/cli/lib/cli-colors.ts +12 -0
  221. package/src/cli/lib/confirm-prompt.ts +79 -0
  222. package/src/cli/lib/install-from-github.ts +303 -0
  223. package/src/cli/lib/list-installed-plugins.ts +137 -0
  224. package/src/cli/lib/search-plugins.ts +163 -0
  225. package/src/cli/lib/uninstall-plugin.ts +82 -0
  226. package/src/cli/lib/unknown-command.ts +111 -0
  227. package/src/cli/program.ts +52 -2
  228. package/src/config/assistant-feature-flags.ts +24 -54
  229. package/src/config/bundled-skills/app-builder/SKILL.md +140 -22
  230. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  231. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  232. package/src/config/bundled-skills/document/SKILL.md +23 -3
  233. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  234. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  235. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  236. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  237. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  238. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  239. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  240. package/src/config/bundled-tool-registry.ts +6 -0
  241. package/src/config/call-site-defaults.ts +105 -0
  242. package/src/config/feature-flag-registry.json +41 -9
  243. package/src/config/llm-resolver.ts +52 -1
  244. package/src/config/loader.ts +64 -38
  245. package/src/config/schema.ts +9 -10
  246. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  247. package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
  248. package/src/config/schemas/channels.ts +17 -0
  249. package/src/config/schemas/compaction.ts +28 -0
  250. package/src/config/schemas/conversations.ts +10 -0
  251. package/src/config/schemas/heartbeat.ts +23 -0
  252. package/src/config/schemas/llm-request-logs.ts +31 -7
  253. package/src/config/schemas/llm.ts +1 -0
  254. package/src/config/schemas/memory-retrieval.ts +18 -0
  255. package/src/config/schemas/memory-retrospective.ts +1 -1
  256. package/src/config/schemas/memory-v2.ts +4 -4
  257. package/src/config/schemas/memory.ts +3 -1
  258. package/src/config/schemas/tools.ts +14 -0
  259. package/src/config/seed-inference-profiles.ts +99 -29
  260. package/src/config/skills.ts +3 -96
  261. package/src/context/compactor.ts +1107 -0
  262. package/src/context/token-estimator.ts +34 -36
  263. package/src/context/window-manager.ts +197 -1520
  264. package/src/credential-execution/managed-catalog.ts +37 -0
  265. package/src/credential-health/credential-health-service.ts +280 -19
  266. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +33 -18
  267. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  268. package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
  269. package/src/daemon/approval-generators.ts +8 -6
  270. package/src/daemon/config-watcher.ts +94 -31
  271. package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
  272. package/src/daemon/conversation-agent-loop.ts +198 -11
  273. package/src/daemon/conversation-error.ts +171 -37
  274. package/src/daemon/conversation-lifecycle.ts +53 -40
  275. package/src/daemon/conversation-messaging.ts +25 -6
  276. package/src/daemon/conversation-process.ts +49 -12
  277. package/src/daemon/conversation-runtime-assembly.ts +25 -1
  278. package/src/daemon/conversation-slash.ts +12 -5
  279. package/src/daemon/conversation-store.ts +11 -4
  280. package/src/daemon/conversation-tool-setup.ts +39 -7
  281. package/src/daemon/conversation.ts +33 -8
  282. package/src/daemon/date-context.ts +40 -0
  283. package/src/daemon/external-plugins-bootstrap.ts +217 -181
  284. package/src/daemon/first-greeting.ts +22 -2
  285. package/src/daemon/guardian-action-generators.ts +1 -125
  286. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
  287. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
  288. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
  289. package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
  290. package/src/daemon/handlers/config-a2a.ts +289 -0
  291. package/src/daemon/handlers/config-model.ts +6 -5
  292. package/src/daemon/handlers/config-slack-channel.ts +15 -3
  293. package/src/daemon/handlers/conversations.ts +1 -0
  294. package/src/daemon/handlers/shared.ts +14 -5
  295. package/src/daemon/handlers/skills.ts +111 -108
  296. package/src/daemon/history-repair.ts +28 -1
  297. package/src/daemon/host-app-control-proxy.ts +153 -27
  298. package/src/daemon/host-proxy-preactivation.ts +85 -18
  299. package/src/daemon/lifecycle.ts +89 -91
  300. package/src/daemon/meet-host-supervisor.ts +5 -4
  301. package/src/daemon/memory-v2-startup.ts +85 -0
  302. package/src/daemon/message-protocol.ts +1 -0
  303. package/src/daemon/message-types/conversations.ts +25 -0
  304. package/src/daemon/message-types/messages.ts +61 -0
  305. package/src/daemon/message-types/notifications.ts +21 -0
  306. package/src/daemon/message-types/subagents.ts +1 -0
  307. package/src/daemon/message-types/sync.ts +1 -0
  308. package/src/daemon/pkb-reminder-builder.test.ts +11 -54
  309. package/src/daemon/pkb-reminder-builder.ts +5 -20
  310. package/src/daemon/plugin-source-watcher.ts +146 -0
  311. package/src/daemon/process-message.ts +24 -3
  312. package/src/daemon/server.ts +11 -2
  313. package/src/daemon/skill-memory-refresh.ts +33 -0
  314. package/src/daemon/wake-target-adapter.ts +2 -0
  315. package/src/documents/document-store.ts +221 -3
  316. package/src/embedded/plugin-api.ts +40 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +121 -0
  318. package/src/export/transcript-formatter.ts +54 -20
  319. package/src/filing/filing-service.ts +39 -0
  320. package/src/heartbeat/__tests__/heartbeat-service.test.ts +135 -6
  321. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  322. package/src/heartbeat/heartbeat-service.ts +73 -189
  323. package/src/home/__tests__/feed-types.test.ts +80 -0
  324. package/src/home/feed-types.ts +36 -2
  325. package/src/home/post-connect-feed.ts +1 -0
  326. package/src/index.ts +18 -1
  327. package/src/ipc/cli-client.ts +147 -45
  328. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  329. package/src/mcp/client.ts +20 -4
  330. package/src/media/image-credentials.ts +3 -3
  331. package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
  332. package/src/memory/__tests__/conversation-queries.test.ts +483 -0
  333. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  334. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
  335. package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
  336. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
  337. package/src/memory/__tests__/message-content.test.ts +35 -0
  338. package/src/memory/bookmark-crud.ts +42 -10
  339. package/src/memory/context-search/sources/conversations.ts +62 -2
  340. package/src/memory/context-search/sources/workspace.ts +4 -0
  341. package/src/memory/conversation-crud.ts +63 -19
  342. package/src/memory/conversation-queries.ts +197 -11
  343. package/src/memory/conversation-title-service.ts +26 -4
  344. package/src/memory/db-init.ts +12 -0
  345. package/src/memory/delivery-crud.ts +152 -5
  346. package/src/memory/embedding-backend.ts +4 -4
  347. package/src/memory/external-conversation-store.ts +66 -5
  348. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +150 -12
  349. package/src/memory/graph/conversation-graph-memory.ts +49 -21
  350. package/src/memory/graph/tools.ts +9 -40
  351. package/src/memory/indexer.ts +34 -29
  352. package/src/memory/invite-store.ts +53 -0
  353. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
  354. package/src/memory/jobs/embed-concept-page.ts +20 -11
  355. package/src/memory/jobs-worker.ts +6 -1
  356. package/src/memory/llm-request-log-source-clickhouse.ts +24 -12
  357. package/src/memory/llm-request-log-source.ts +19 -52
  358. package/src/memory/llm-request-log-store.ts +92 -1
  359. package/src/memory/llm-usage-store.ts +125 -5
  360. package/src/memory/memory-retrospective-enqueue.ts +1 -20
  361. package/src/memory/memory-retrospective-job.ts +33 -6
  362. package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
  363. package/src/memory/message-content.ts +1 -1
  364. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  365. package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
  366. package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
  367. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  368. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  369. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  370. package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
  371. package/src/memory/migrations/251-a2a-tasks.ts +49 -0
  372. package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
  373. package/src/memory/migrations/index.ts +9 -0
  374. package/src/memory/migrations/registry.ts +16 -0
  375. package/src/memory/onboarding-events-store.ts +106 -0
  376. package/src/memory/schema/a2a.ts +15 -0
  377. package/src/memory/schema/bookmarks.ts +0 -2
  378. package/src/memory/schema/calls.ts +1 -0
  379. package/src/memory/schema/index.ts +1 -0
  380. package/src/memory/schema/inference.ts +3 -3
  381. package/src/memory/schema/infrastructure.ts +13 -0
  382. package/src/memory/turn-events-store.ts +127 -2
  383. package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
  384. package/src/memory/v2/__tests__/activation.test.ts +0 -8
  385. package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
  386. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
  387. package/src/memory/v2/__tests__/injection.test.ts +288 -11
  388. package/src/memory/v2/__tests__/migration.test.ts +87 -0
  389. package/src/memory/v2/__tests__/page-index.test.ts +83 -0
  390. package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
  391. package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
  392. package/src/memory/v2/__tests__/router.test.ts +15 -0
  393. package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
  394. package/src/memory/v2/__tests__/static-context.test.ts +12 -1
  395. package/src/memory/v2/activation-store.ts +14 -16
  396. package/src/memory/v2/cli-command-content.ts +19 -0
  397. package/src/memory/v2/cli-command-store.ts +304 -0
  398. package/src/memory/v2/frontmatter-sweep.ts +7 -1
  399. package/src/memory/v2/injection.ts +81 -26
  400. package/src/memory/v2/migration.ts +49 -19
  401. package/src/memory/v2/page-index.ts +63 -8
  402. package/src/memory/v2/prompts/router.ts +11 -8
  403. package/src/memory/v2/prompts/sweep.ts +2 -2
  404. package/src/memory/v2/qdrant.ts +135 -7
  405. package/src/memory/v2/router.ts +9 -8
  406. package/src/memory/v2/skill-store.ts +120 -35
  407. package/src/memory/v2/static-context.ts +4 -4
  408. package/src/memory/v2/types.ts +23 -0
  409. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
  410. package/src/messaging/providers/a2a/deliver.ts +156 -0
  411. package/src/messaging/providers/gmail/client.ts +9 -2
  412. package/src/messaging/providers/index.ts +11 -2
  413. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  414. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  415. package/src/messaging/providers/slack/adapter.ts +43 -5
  416. package/src/messaging/providers/slack/client.ts +27 -0
  417. package/src/messaging/providers/slack/deep-link.ts +65 -0
  418. package/src/messaging/providers/slack/download.ts +104 -0
  419. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  420. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  421. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  422. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  423. package/src/messaging/providers/slack/types.ts +20 -1
  424. package/src/notifications/__tests__/broadcaster.test.ts +203 -0
  425. package/src/notifications/__tests__/decision-engine.test.ts +283 -0
  426. package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
  427. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  428. package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
  429. package/src/notifications/adapters/macos.ts +12 -2
  430. package/src/notifications/broadcaster.ts +29 -4
  431. package/src/notifications/conversation-pairing.ts +2 -1
  432. package/src/notifications/copy-composer.ts +17 -64
  433. package/src/notifications/decision-engine.ts +113 -45
  434. package/src/notifications/deterministic-checks.ts +96 -0
  435. package/src/notifications/emit-signal.ts +21 -1
  436. package/src/notifications/home-feed-side-effect.ts +138 -5
  437. package/src/notifications/signal.ts +3 -5
  438. package/src/notifications/types.ts +8 -0
  439. package/src/oauth/connection-resolver.ts +8 -4
  440. package/src/oauth/platform-connection.test.ts +43 -3
  441. package/src/oauth/platform-connection.ts +19 -6
  442. package/src/oauth/seed-providers.ts +10 -1
  443. package/src/permissions/checker.ts +2 -0
  444. package/src/permissions/ipc-risk-types.ts +1 -0
  445. package/src/permissions/question-prompter.test.ts +416 -0
  446. package/src/permissions/question-prompter.ts +294 -0
  447. package/src/platform/client.test.ts +1 -1
  448. package/src/platform/client.ts +1 -1
  449. package/src/plugin-api/constants.ts +26 -0
  450. package/src/plugin-api/index.ts +34 -1
  451. package/src/plugin-api/types.ts +104 -22
  452. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  453. package/src/plugins/defaults/compaction.ts +0 -4
  454. package/src/plugins/defaults/empty-response.ts +0 -2
  455. package/src/plugins/defaults/history-repair.ts +0 -2
  456. package/src/plugins/defaults/injectors.ts +74 -22
  457. package/src/plugins/defaults/llm-call.ts +0 -2
  458. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  459. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  460. package/src/plugins/defaults/persistence.ts +0 -2
  461. package/src/plugins/defaults/title-generate.ts +0 -5
  462. package/src/plugins/defaults/token-estimate.ts +0 -2
  463. package/src/plugins/defaults/tool-error.ts +0 -7
  464. package/src/plugins/defaults/tool-execute.ts +0 -2
  465. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  466. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  467. package/src/plugins/external-api.ts +104 -0
  468. package/src/plugins/external-plugin-loader.ts +187 -42
  469. package/src/plugins/feature-gate.ts +22 -0
  470. package/src/plugins/pipeline.ts +37 -0
  471. package/src/plugins/registry.ts +48 -80
  472. package/src/plugins/types.ts +40 -26
  473. package/src/plugins/user-loader.ts +21 -2
  474. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  475. package/src/proactive-artifact/job.test.ts +37 -5
  476. package/src/prompts/__tests__/system-prompt.test.ts +10 -43
  477. package/src/prompts/__tests__/task-progress-hint-section.test.ts +95 -0
  478. package/src/prompts/normalize-onboarding.ts +27 -0
  479. package/src/prompts/sections.ts +302 -0
  480. package/src/prompts/system-prompt.ts +63 -174
  481. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  482. package/src/prompts/templates/system-sections.ts +164 -0
  483. package/src/providers/__tests__/inference.test.ts +24 -7
  484. package/src/providers/anthropic/client.ts +28 -28
  485. package/src/providers/call-site-routing.ts +24 -6
  486. package/src/providers/connection-resolution.ts +68 -11
  487. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
  488. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
  489. package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
  490. package/src/providers/inference/adapter-factory.ts +32 -6
  491. package/src/providers/inference/auth.ts +12 -0
  492. package/src/providers/inference/backfill.ts +14 -1
  493. package/src/providers/inference/connections.ts +159 -34
  494. package/src/providers/inference/resolve-auth.ts +14 -4
  495. package/src/providers/model-catalog.ts +249 -12
  496. package/src/providers/model-intents.ts +3 -3
  497. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
  498. package/src/providers/openai/chat-completions-provider.ts +169 -8
  499. package/src/providers/openrouter/client.ts +49 -4
  500. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -2
  501. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  502. package/src/providers/provider-availability.ts +17 -2
  503. package/src/providers/provider-catalog-visibility.ts +38 -0
  504. package/src/providers/provider-send-message.ts +27 -12
  505. package/src/providers/registry.ts +52 -15
  506. package/src/providers/retry.ts +47 -1
  507. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  508. package/src/runtime/agent-wake.ts +103 -15
  509. package/src/runtime/auth/route-policy.ts +21 -1
  510. package/src/runtime/btw-sidechain.ts +2 -0
  511. package/src/runtime/http-server.ts +7 -16
  512. package/src/runtime/http-types.ts +19 -47
  513. package/src/runtime/migrations/origin-mode.ts +1 -1
  514. package/src/runtime/pending-interactions.ts +1 -0
  515. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
  516. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
  517. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
  518. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +172 -23
  519. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
  520. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
  521. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  522. package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
  523. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  524. package/src/runtime/routes/acp-routes.ts +5 -3
  525. package/src/runtime/routes/auth-routes.ts +1 -1
  526. package/src/runtime/routes/bookmark-routes.ts +5 -3
  527. package/src/runtime/routes/btw-routes.ts +5 -1
  528. package/src/runtime/routes/channel-availability-routes.ts +126 -0
  529. package/src/runtime/routes/consolidation-routes.ts +100 -0
  530. package/src/runtime/routes/conversation-cli-routes.ts +44 -3
  531. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  532. package/src/runtime/routes/conversation-management-routes.ts +17 -42
  533. package/src/runtime/routes/conversation-query-routes.ts +99 -35
  534. package/src/runtime/routes/conversation-routes.ts +97 -11
  535. package/src/runtime/routes/documents-routes.ts +25 -86
  536. package/src/runtime/routes/group-routes.ts +5 -0
  537. package/src/runtime/routes/inbound-conversation.ts +28 -8
  538. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  539. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
  540. package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
  541. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  542. package/src/runtime/routes/index.ts +8 -0
  543. package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
  544. package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
  545. package/src/runtime/routes/inference-provider-connection-routes.ts +199 -22
  546. package/src/runtime/routes/integrations/a2a.ts +235 -0
  547. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  548. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  549. package/src/runtime/routes/integrations/twilio.ts +6 -13
  550. package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
  551. package/src/runtime/routes/notification-routes.ts +1 -1
  552. package/src/runtime/routes/oauth-commands-routes.ts +105 -15
  553. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  554. package/src/runtime/routes/question-routes.ts +259 -0
  555. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  556. package/src/runtime/routes/schedule-routes.ts +4 -7
  557. package/src/runtime/routes/subagents-routes.ts +98 -18
  558. package/src/runtime/routes/telemetry-routes.ts +27 -0
  559. package/src/runtime/routes/tts-routes.ts +27 -2
  560. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  561. package/src/runtime/routes/workspace-routes.ts +28 -0
  562. package/src/runtime/services/conversation-serializer.ts +39 -7
  563. package/src/runtime/sync/resource-sync-events.ts +93 -1
  564. package/src/schedule/schedule-store.ts +27 -2
  565. package/src/schedule/scheduler.ts +9 -1
  566. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  567. package/src/security/untrusted-content.ts +93 -8
  568. package/src/skills/catalog-files.ts +1 -1
  569. package/src/skills/catalog-install.ts +233 -116
  570. package/src/skills/clawhub.ts +70 -13
  571. package/src/skills/managed-store.ts +4 -119
  572. package/src/skills/skillssh-registry.ts +27 -48
  573. package/src/subagent/manager.ts +17 -7
  574. package/src/telemetry/types.ts +113 -1
  575. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  576. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  577. package/src/tools/apps/executors.ts +58 -7
  578. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  579. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  580. package/src/tools/browser/browser-execution.ts +15 -11
  581. package/src/tools/computer-use/definitions.ts +3 -3
  582. package/src/tools/credentials/vault.ts +1 -1
  583. package/src/tools/document/document-tool.ts +124 -1
  584. package/src/tools/filesystem/edit.ts +1 -1
  585. package/src/tools/filesystem/list.ts +1 -1
  586. package/src/tools/filesystem/read.ts +1 -1
  587. package/src/tools/filesystem/write.ts +5 -2
  588. package/src/tools/host-filesystem/transfer.ts +1 -1
  589. package/src/tools/host-terminal/host-shell.ts +1 -1
  590. package/src/tools/memory/register.ts +1 -9
  591. package/src/tools/permission-checker.ts +1 -1
  592. package/src/tools/registry.ts +17 -7
  593. package/src/tools/schedule/create.ts +2 -2
  594. package/src/tools/schema-transforms.ts +7 -2
  595. package/src/tools/side-effects.ts +1 -0
  596. package/src/tools/skills/delete-managed.ts +4 -4
  597. package/src/tools/skills/execute.ts +1 -1
  598. package/src/tools/skills/scaffold-managed.ts +3 -2
  599. package/src/tools/subagent/notify-parent.ts +1 -1
  600. package/src/tools/system/request-permission.ts +2 -2
  601. package/src/tools/terminal/safe-env.ts +60 -1
  602. package/src/tools/tool-manifest.ts +2 -0
  603. package/src/tools/types.ts +107 -21
  604. package/src/tools/ui-surface/definitions.ts +6 -5
  605. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  606. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  607. package/src/types/onboarding-context.ts +2 -0
  608. package/src/util/errors.ts +17 -0
  609. package/src/util/platform.ts +10 -0
  610. package/src/watcher/__tests__/engine.test.ts +22 -0
  611. package/src/watcher/engine.ts +6 -2
  612. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
  613. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
  614. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
  615. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  616. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  617. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  618. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  619. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
  620. package/src/workspace/migrations/registry.ts +10 -0
  621. package/src/workspace/migrations/runner.ts +39 -9
  622. package/src/workspace/migrations/types.ts +4 -0
  623. package/examples/plugins/echo/bun.lock +0 -25
  624. package/src/__tests__/context-window-manager.test.ts +0 -2481
  625. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
  626. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  627. package/src/context/prompts/compact.md +0 -26
  628. package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
  629. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  630. package/src/runtime/guardian-action-conversation-turn.ts +0 -99
@@ -72,6 +72,40 @@ const RETRYABLE_STREAM_PATTERNS = [
72
72
  */
73
73
  const RETRYABLE_PROVIDER_MESSAGE_PATTERNS = [/overloaded/i];
74
74
 
75
+ /**
76
+ * Patterns that indicate the Anthropic provider SDK reported a transport-level
77
+ * abort (TCP close mid-stream, edge LB idle cutoff, Bun fetch deadline) rather
78
+ * than a caller-initiated cancellation or inner-timeout deadline. The SDK
79
+ * surfaces all three cases as ``Request was aborted`` with ``error.status ===
80
+ * undefined``; the catch-site in ``providers/anthropic/client.ts`` separates
81
+ * them by:
82
+ * - tagging caller cancellations with ``abortReason`` (short-circuits in
83
+ * {@link isRetryableError} before reaching this predicate)
84
+ * - rewriting the inner-timeout message to ``"Anthropic stream timed out
85
+ * after Xs (inner streamTimeoutMs)"`` (doesn't start with ``Anthropic API
86
+ * error:`` so it falls through to network-error classification)
87
+ * - leaving the transport-abort message verbatim as
88
+ * ``"Anthropic API error: Request was aborted."``
89
+ *
90
+ * Pattern is intentionally anchored to the Anthropic-specific message prefix.
91
+ * The OpenAI / Gemini / OpenRouter catch-sites format their errors as
92
+ * ``"<Provider> API error (undefined): Request was aborted."`` (note the
93
+ * ``(undefined)`` parenthetical) and — crucially — do **not** rewrite
94
+ * inner-timeout failures, so a provider-agnostic ``/request was aborted/i``
95
+ * predicate would erroneously retry their 30-minute deadline failures three
96
+ * additional times. Once those catch-sites grow the same
97
+ * ``innerTimeoutFired`` distinction the Anthropic one has, the pattern set
98
+ * here can be expanded to cover them too.
99
+ *
100
+ * This is the daemon-side counterpart to the vembda graceful-close behavior
101
+ * for upstream disconnects (LUM-1536) — together they collapse the 45 s
102
+ * silent-stall window the web client used to observe whenever Anthropic's
103
+ * stream was cut mid-token.
104
+ */
105
+ const RETRYABLE_TRANSPORT_ABORT_PATTERNS = [
106
+ /^anthropic api error:\s*request was aborted/i,
107
+ ];
108
+
75
109
  function isRetryableStreamError(error: unknown): boolean {
76
110
  if (!(error instanceof ProviderError)) return false;
77
111
  if (error.statusCode !== undefined) return false; // has a real HTTP status — not a stream error
@@ -84,6 +118,15 @@ function isRetryableProviderMessage(error: unknown): boolean {
84
118
  return RETRYABLE_PROVIDER_MESSAGE_PATTERNS.some((p) => p.test(error.message));
85
119
  }
86
120
 
121
+ function isRetryableTransportAbort(error: unknown): boolean {
122
+ if (!(error instanceof ProviderError)) return false;
123
+ // Transport aborts surface with ``status === undefined`` (the SDK never
124
+ // saw an HTTP response). A real HTTP status here means a server error,
125
+ // which is handled by the status check.
126
+ if (error.statusCode !== undefined) return false;
127
+ return RETRYABLE_TRANSPORT_ABORT_PATTERNS.some((p) => p.test(error.message));
128
+ }
129
+
87
130
  function isRetryableError(error: unknown): boolean {
88
131
  // Context overflow is deterministic — retrying the same oversized prompt
89
132
  // will never succeed. Short-circuit before the generic 429/5xx check so
@@ -103,6 +146,7 @@ function isRetryableError(error: unknown): boolean {
103
146
  }
104
147
  if (isRetryableProviderMessage(error)) return true;
105
148
  if (isRetryableStreamError(error)) return true;
149
+ if (isRetryableTransportAbort(error)) return true;
106
150
  return isRetryableNetworkError(error);
107
151
  }
108
152
 
@@ -482,7 +526,9 @@ export class RetryProvider implements Provider {
482
526
  ? "provider_overloaded"
483
527
  : isRetryableStreamError(error)
484
528
  ? "stream_corruption"
485
- : "network_error";
529
+ : isRetryableTransportAbort(error)
530
+ ? "transport_abort"
531
+ : "network_error";
486
532
  log.warn(
487
533
  {
488
534
  attempt: attempt + 1,
@@ -68,6 +68,33 @@ mock.module("../../daemon/disk-pressure-guard.js", () => ({
68
68
  getDiskPressureStatus: () => mockDiskPressureStatus,
69
69
  }));
70
70
 
71
+ const recordRequestLogCalls: Array<{
72
+ conversationId: string;
73
+ requestPayload: string;
74
+ responsePayload: string;
75
+ messageId?: string;
76
+ provider?: string;
77
+ }> = [];
78
+ mock.module("../../memory/llm-request-log-store.js", () => ({
79
+ recordRequestLog: (
80
+ conversationId: string,
81
+ requestPayload: string,
82
+ responsePayload: string,
83
+ messageId?: string,
84
+ provider?: string,
85
+ ) => {
86
+ recordRequestLogCalls.push({
87
+ conversationId,
88
+ requestPayload,
89
+ responsePayload,
90
+ messageId,
91
+ provider,
92
+ });
93
+ return "log-id-test";
94
+ },
95
+ backfillMessageIdOnLogs: () => {},
96
+ }));
97
+
71
98
  import type { AgentEvent } from "../../agent/loop.js";
72
99
  import type { Message } from "../../providers/types.js";
73
100
  import {
@@ -220,6 +247,7 @@ function makeTarget(options: {
220
247
 
221
248
  beforeEach(() => {
222
249
  __resetWakeChainForTests();
250
+ recordRequestLogCalls.length = 0;
223
251
  mockDiskPressureStatus = {
224
252
  enabled: false,
225
253
  state: "disabled",
@@ -1435,4 +1463,128 @@ describe("wakeAgentForOpportunity", () => {
1435
1463
  expect(uiBlock!.surfaceId).toBe(wakeProducedOutputCalls[0]);
1436
1464
  },
1437
1465
  );
1466
+
1467
+ test(
1468
+ "silent no-op wake drops LLM request logs so a future backfillMessageIdOnLogs " +
1469
+ "sweep cannot misattach them to an unrelated assistant reply",
1470
+ async () => {
1471
+ const usageEvent: AgentEvent = {
1472
+ type: "usage",
1473
+ inputTokens: 100,
1474
+ outputTokens: 5,
1475
+ model: "test-model",
1476
+ actualProvider: "test-provider",
1477
+ providerDurationMs: 10,
1478
+ rawRequest: { request: "no-op wake" },
1479
+ rawResponse: { response: "no output" },
1480
+ };
1481
+ const target = makeTarget({
1482
+ baseline: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
1483
+ scriptedEvents: [usageEvent],
1484
+ // Empty assistant text → silent no-op.
1485
+ scriptedAssistant: {
1486
+ role: "assistant",
1487
+ content: [{ type: "text", text: "" }],
1488
+ },
1489
+ });
1490
+
1491
+ const result = await wakeAgentForOpportunity(
1492
+ {
1493
+ conversationId: target.conversationId,
1494
+ hint: "consider doing nothing",
1495
+ source: "unit-test",
1496
+ },
1497
+ { resolveTarget: async () => target },
1498
+ );
1499
+
1500
+ expect(result).toEqual({ invoked: true, producedToolCalls: false });
1501
+ // Nothing emitted, nothing persisted to the conversation.
1502
+ expect(target.emittedEvents).toHaveLength(0);
1503
+ expect(target.persistedTailCalls).toHaveLength(0);
1504
+ // Critical: the LLM request log must NOT be inserted with messageId=NULL,
1505
+ // otherwise the next user turn's backfillMessageIdOnLogs sweep would
1506
+ // misattach this row to an unrelated future assistant reply.
1507
+ expect(recordRequestLogCalls).toHaveLength(0);
1508
+ },
1509
+ );
1510
+
1511
+ test("wake that produces output persists buffered LLM request logs", async () => {
1512
+ const usageEvent: AgentEvent = {
1513
+ type: "usage",
1514
+ inputTokens: 100,
1515
+ outputTokens: 5,
1516
+ model: "test-model",
1517
+ actualProvider: "test-provider",
1518
+ providerDurationMs: 10,
1519
+ rawRequest: { request: "produced wake" },
1520
+ rawResponse: { response: "real reply" },
1521
+ };
1522
+ const target = makeTarget({
1523
+ baseline: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
1524
+ scriptedEvents: [usageEvent],
1525
+ scriptedAssistant: {
1526
+ role: "assistant",
1527
+ content: [{ type: "text", text: "real reply" }],
1528
+ },
1529
+ });
1530
+
1531
+ const result = await wakeAgentForOpportunity(
1532
+ {
1533
+ conversationId: target.conversationId,
1534
+ hint: "do reply",
1535
+ source: "unit-test",
1536
+ },
1537
+ { resolveTarget: async () => target },
1538
+ );
1539
+
1540
+ expect(result).toEqual({ invoked: true, producedToolCalls: false });
1541
+ expect(recordRequestLogCalls).toHaveLength(1);
1542
+ expect(recordRequestLogCalls[0]).toMatchObject({
1543
+ conversationId: target.conversationId,
1544
+ provider: "test-provider",
1545
+ messageId: undefined,
1546
+ });
1547
+ });
1548
+
1549
+ test("non-serializable usage payload does not abort the wake", async () => {
1550
+ // Circular reference in rawRequest — JSON.stringify throws on this.
1551
+ // Serialization must happen inside persistLog's try/catch so the
1552
+ // failure is swallowed as a non-fatal log warning rather than
1553
+ // escaping and aborting the wake.
1554
+ const circular: Record<string, unknown> = { request: "produced wake" };
1555
+ circular.self = circular;
1556
+ const usageEvent: AgentEvent = {
1557
+ type: "usage",
1558
+ inputTokens: 100,
1559
+ outputTokens: 5,
1560
+ model: "test-model",
1561
+ actualProvider: "test-provider",
1562
+ providerDurationMs: 10,
1563
+ rawRequest: circular,
1564
+ rawResponse: { response: "real reply" },
1565
+ };
1566
+ const target = makeTarget({
1567
+ baseline: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
1568
+ scriptedEvents: [usageEvent],
1569
+ scriptedAssistant: {
1570
+ role: "assistant",
1571
+ content: [{ type: "text", text: "real reply" }],
1572
+ },
1573
+ });
1574
+
1575
+ const result = await wakeAgentForOpportunity(
1576
+ {
1577
+ conversationId: target.conversationId,
1578
+ hint: "do reply",
1579
+ source: "unit-test",
1580
+ },
1581
+ { resolveTarget: async () => target },
1582
+ );
1583
+
1584
+ expect(result).toEqual({ invoked: true, producedToolCalls: false });
1585
+ // Wake still produced output even though logging failed.
1586
+ expect(target.persistedTailCalls).toHaveLength(1);
1587
+ // No log row was inserted because JSON.stringify threw.
1588
+ expect(recordRequestLogCalls).toHaveLength(0);
1589
+ });
1438
1590
  });
@@ -57,7 +57,11 @@ import {
57
57
  } from "../daemon/disk-pressure-policy.js";
58
58
  import type { TrustContext } from "../daemon/trust-context.js";
59
59
  import { getConversationOverrideProfile } from "../memory/conversation-crud.js";
60
- import { recordRequestLog } from "../memory/llm-request-log-store.js";
60
+ import {
61
+ buildProviderErrorResponsePayload,
62
+ recordRequestLog,
63
+ setAgentLoopExitReasonOnLatestLog,
64
+ } from "../memory/llm-request-log-store.js";
61
65
  import type { TurnContext } from "../plugins/types.js";
62
66
  import type { Message } from "../providers/types.js";
63
67
  import { getLogger } from "../util/logger.js";
@@ -330,7 +334,7 @@ function classifyWakeDiskPressurePolicy(opts: WakeOptions): {
330
334
  const status = getDiskPressureStatus();
331
335
  const decision = classifyDiskPressureTurnPolicy(status, {
332
336
  conversationSource: opts.source,
333
- callSite: "mainAgent",
337
+ callSite: opts.callSite ?? "mainAgent",
334
338
  isDirectWake: true,
335
339
  sourceChannel: opts.sourceChannel ?? opts.trustContext?.sourceChannel,
336
340
  sourceInterface: opts.sourceInterface,
@@ -537,6 +541,49 @@ export async function wakeAgentForOpportunity(
537
541
  // only after `agentLoop.run()` returns.
538
542
  let mode: "buffering" | "live" = "buffering";
539
543
  const buffered: AgentEvent[] = [];
544
+ // LLM request logs accumulated while buffering. Persisted only if the
545
+ // wake transitions to live (i.e. produced output). A silent no-op wake
546
+ // drops them — otherwise the next user-turn's `backfillMessageIdOnLogs`
547
+ // sweep would misattach these NULL-messageId rows to an unrelated
548
+ // future assistant message, contaminating inspector context.
549
+ type PendingLog = {
550
+ rawRequest: unknown;
551
+ rawResponse: unknown;
552
+ provider?: string;
553
+ };
554
+ const pendingLogs: PendingLog[] = [];
555
+ // Exit reason deferred alongside pendingLogs. Same drop-on-silent-
556
+ // wake guarantee: if the wake never goes live, this stays null and
557
+ // no DB row is touched. Applied after pendingLogs flush in goLive
558
+ // so the latest-row lookup in `setAgentLoopExitReasonOnLatestLog`
559
+ // can see the freshly-persisted final usage row.
560
+ let pendingExitReason: string | null = null;
561
+ const persistLog = (record: PendingLog): void => {
562
+ try {
563
+ recordRequestLog(
564
+ conversationId,
565
+ JSON.stringify(record.rawRequest),
566
+ JSON.stringify(record.rawResponse),
567
+ undefined,
568
+ record.provider,
569
+ );
570
+ } catch (err) {
571
+ log.warn(
572
+ { err, conversationId, source },
573
+ "agent-wake: failed to persist LLM request log (non-fatal)",
574
+ );
575
+ }
576
+ };
577
+ const persistExitReason = (reason: string): void => {
578
+ try {
579
+ setAgentLoopExitReasonOnLatestLog(conversationId, reason);
580
+ } catch (err) {
581
+ log.warn(
582
+ { err, conversationId, source, reason },
583
+ "agent-wake: failed to persist agent_loop_exit_reason (non-fatal)",
584
+ );
585
+ }
586
+ };
540
587
  const safeEmit = (event: AgentEvent): void => {
541
588
  try {
542
589
  target.emitAgentEvent(event);
@@ -550,20 +597,49 @@ export async function wakeAgentForOpportunity(
550
597
  const onEvent = (event: AgentEvent): void => {
551
598
  // Replicates the recordRequestLog side-effect in `handleUsage` because
552
599
  // wakes own their own onEvent and never reach `dispatchAgentEvent`.
600
+ // Defer persistence while buffering — see `pendingLogs` above.
553
601
  if (event.type === "usage" && event.rawRequest && event.rawResponse) {
554
- try {
555
- recordRequestLog(
556
- conversationId,
557
- JSON.stringify(event.rawRequest),
558
- JSON.stringify(event.rawResponse),
559
- undefined,
560
- event.actualProvider,
561
- );
562
- } catch (err) {
563
- log.warn(
564
- { err, conversationId, source },
565
- "agent-wake: failed to persist LLM request log (non-fatal)",
566
- );
602
+ const record = {
603
+ rawRequest: event.rawRequest,
604
+ rawResponse: event.rawResponse,
605
+ provider: event.actualProvider,
606
+ };
607
+ if (mode === "buffering") {
608
+ pendingLogs.push(record);
609
+ } else {
610
+ persistLog(record);
611
+ }
612
+ }
613
+ // Mirror the same recording side-effect for provider-rejected calls.
614
+ // `handleProviderError` in the daemon dispatcher persists these on the
615
+ // normal turn path; the wake path owns its own onEvent and bypasses
616
+ // that dispatcher entirely, so we replicate here. Buffering rules
617
+ // match the success path: if the wake never goes live (silent no-op),
618
+ // the rows are dropped so a stale `messageId IS NULL` row doesn't get
619
+ // mis-backfilled onto an unrelated future assistant message.
620
+ if (event.type === "provider_error") {
621
+ const record: PendingLog = {
622
+ rawRequest: event.rawRequest,
623
+ rawResponse: buildProviderErrorResponsePayload(event.error),
624
+ provider: event.actualProvider,
625
+ };
626
+ if (mode === "buffering") {
627
+ pendingLogs.push(record);
628
+ } else {
629
+ persistLog(record);
630
+ }
631
+ }
632
+ // Replicates the setAgentLoopExitReasonOnLatestLog side-effect that
633
+ // `dispatchAgentEvent` does for the normal path. In live mode the
634
+ // final usage event of the run has already landed its row, so the
635
+ // latest-row lookup hits the right target. In buffering mode the
636
+ // reason is stashed and applied in `goLive` after pendingLogs are
637
+ // persisted, preserving the same ordering guarantee.
638
+ if (event.type === "agent_loop_exit") {
639
+ if (mode === "buffering") {
640
+ pendingExitReason = event.reason;
641
+ } else {
642
+ persistExitReason(event.reason);
567
643
  }
568
644
  }
569
645
  if (mode === "buffering") {
@@ -620,6 +696,18 @@ export async function wakeAgentForOpportunity(
620
696
  safeEmit(event);
621
697
  }
622
698
  buffered.length = 0;
699
+ for (const record of pendingLogs) {
700
+ persistLog(record);
701
+ }
702
+ pendingLogs.length = 0;
703
+ // Apply the deferred exit reason after pendingLogs are persisted —
704
+ // the latest-row lookup in `setAgentLoopExitReasonOnLatestLog`
705
+ // needs the final usage row to already exist. Cleared after use so
706
+ // an extremely unlikely double-goLive can't double-stamp.
707
+ if (pendingExitReason !== null) {
708
+ persistExitReason(pendingExitReason);
709
+ pendingExitReason = null;
710
+ }
623
711
  mode = "live";
624
712
  };
625
713
 
@@ -164,6 +164,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
164
164
  { endpoint: "confirm", scopes: ["approval.write"] },
165
165
  { endpoint: "secret", scopes: ["approval.write"] },
166
166
  { endpoint: "trust-rules", scopes: ["approval.write"] },
167
+ { endpoint: "question-response", scopes: ["approval.write"] },
167
168
  { endpoint: "host-app-control-result", scopes: ["approval.write"] },
168
169
  { endpoint: "host-bash-result", scopes: ["approval.write"] },
169
170
  { endpoint: "host-browser-result", scopes: ["approval.write"] },
@@ -242,6 +243,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
242
243
  endpoint: "integrations/slack/channel/config:DELETE",
243
244
  scopes: ["settings.write"],
244
245
  },
246
+ { endpoint: "integrations/a2a/invite", scopes: ["settings.write"] },
245
247
  { endpoint: "channel-verification-sessions", scopes: ["settings.write"] },
246
248
  {
247
249
  endpoint: "channel-verification-sessions:DELETE",
@@ -285,7 +287,8 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
285
287
  { endpoint: "slack/channels", scopes: ["settings.read"] },
286
288
  { endpoint: "slack/share", scopes: ["settings.write"] },
287
289
 
288
- // Channel readiness
290
+ // Channel availability + readiness
291
+ { endpoint: "channels/available", scopes: ["settings.read"] },
289
292
  { endpoint: "channels/readiness", scopes: ["settings.read"] },
290
293
  { endpoint: "channels/readiness/refresh", scopes: ["settings.write"] },
291
294
 
@@ -342,6 +345,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
342
345
 
343
346
  // Lifecycle telemetry
344
347
  { endpoint: "telemetry/lifecycle", scopes: ["settings.write"] },
348
+ { endpoint: "telemetry/flush", scopes: ["settings.write"] },
345
349
 
346
350
  // Debug / introspection
347
351
  { endpoint: "clients", scopes: ["settings.read"] },
@@ -683,6 +687,18 @@ for (const endpoint of INTERNAL_ENDPOINTS) {
683
687
  });
684
688
  }
685
689
 
690
+ // A2A invite completion: gateway-only (platform-orchestrated)
691
+ registerPolicy("integrations/a2a/invite/complete", {
692
+ requiredScopes: ["internal.write"],
693
+ allowedPrincipalTypes: ["svc_gateway"],
694
+ });
695
+
696
+ // A2A invite redemption: gateway-only (platform-orchestrated)
697
+ registerPolicy("integrations/a2a/invite/redeem", {
698
+ requiredScopes: ["internal.write"],
699
+ allowedPrincipalTypes: ["svc_gateway"],
700
+ });
701
+
686
702
  // Admin control-plane endpoints: gateway-only
687
703
  registerPolicy("admin/upgrade-broadcast", {
688
704
  requiredScopes: ["internal.write"],
@@ -1079,6 +1095,10 @@ registerPolicy("oauth/mode.set", {
1079
1095
  requiredScopes: ["settings.write"],
1080
1096
  allowedPrincipalTypes: ["local"],
1081
1097
  });
1098
+ registerPolicy("oauth/connection-changed", {
1099
+ requiredScopes: ["settings.write"],
1100
+ allowedPrincipalTypes: ["local"],
1101
+ });
1082
1102
  registerPolicy("oauth/status", {
1083
1103
  requiredScopes: ["settings.read"],
1084
1104
  allowedPrincipalTypes: ["local"],
@@ -70,6 +70,8 @@ export async function runBtwSidechain(
70
70
  const tools = params.tools;
71
71
  const history = params.messages ?? params.conversation?.getMessages() ?? [];
72
72
  const messages = [...history, userMessage(trimmedContent)];
73
+ // Side-chains force `tool_choice: { type: "none" }` below, so tool usage
74
+ // guidance must stay in tool descriptions rather than this system prompt.
73
75
  const systemPrompt =
74
76
  params.systemPrompt ??
75
77
  (params.conversation?.hasSystemPromptOverride
@@ -28,6 +28,8 @@ import {
28
28
  import { isHttpAuthDisabled } from "../config/env.js";
29
29
  import { getIsPlatform } from "../config/env-registry.js";
30
30
  import { getConfig } from "../config/loader.js";
31
+ import { createApprovalCopyGenerator } from "../daemon/approval-generators.js";
32
+ import { createGuardianActionCopyGenerator } from "../daemon/guardian-action-generators.js";
31
33
  import { processMessage } from "../daemon/process-message.js";
32
34
  import { createLiveVoiceSession } from "../live-voice/live-voice-session.js";
33
35
  import { LiveVoiceSessionManager } from "../live-voice/live-voice-session-manager.js";
@@ -96,10 +98,8 @@ import { matchSkillRoute } from "./skill-route-registry.js";
96
98
  export { isPrivateAddress } from "./middleware/auth.js";
97
99
 
98
100
  import type {
99
- ApprovalConversationGenerator,
100
101
  ApprovalCopyGenerator,
101
102
  GuardianActionCopyGenerator,
102
- GuardianFollowUpConversationGenerator,
103
103
  RuntimeHttpServerOptions,
104
104
  } from "./http-types.js";
105
105
 
@@ -161,10 +161,8 @@ export class RuntimeHttpServer {
161
161
  private port: number;
162
162
  private hostname: string;
163
163
 
164
- private approvalCopyGenerator?: ApprovalCopyGenerator;
165
- private approvalConversationGenerator?: ApprovalConversationGenerator;
166
- private guardianActionCopyGenerator?: GuardianActionCopyGenerator;
167
- private guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator;
164
+ private readonly approvalCopyGenerator: ApprovalCopyGenerator;
165
+ private readonly guardianActionCopyGenerator: GuardianActionCopyGenerator;
168
166
  private retrySweepTimer: ReturnType<typeof setInterval> | null = null;
169
167
  private sweepInProgress = false;
170
168
 
@@ -175,11 +173,8 @@ export class RuntimeHttpServer {
175
173
  this.port = options.port ?? DEFAULT_PORT;
176
174
  this.hostname = options.hostname ?? DEFAULT_HOSTNAME;
177
175
 
178
- this.approvalCopyGenerator = options.approvalCopyGenerator;
179
- this.approvalConversationGenerator = options.approvalConversationGenerator;
180
- this.guardianActionCopyGenerator = options.guardianActionCopyGenerator;
181
- this.guardianFollowUpConversationGenerator =
182
- options.guardianFollowUpConversationGenerator;
176
+ this.approvalCopyGenerator = createApprovalCopyGenerator();
177
+ this.guardianActionCopyGenerator = createGuardianActionCopyGenerator();
183
178
  this.liveVoiceSessionManager = new LiveVoiceSessionManager({
184
179
  createSession: (context) => createLiveVoiceSession(context),
185
180
  });
@@ -560,11 +555,7 @@ export class RuntimeHttpServer {
560
555
  const endpoint = url.pathname.slice("/v1/".length).replace(/\/$/, "");
561
556
  meta = this.router.findLoggingMetadata(req.method, endpoint) ?? undefined;
562
557
  }
563
- return withRequestLogging(
564
- req,
565
- () => this.routeRequest(req, server),
566
- meta,
567
- );
558
+ return withRequestLogging(req, () => this.routeRequest(req, server), meta);
568
559
  }
569
560
 
570
561
  private async routeRequest(
@@ -14,10 +14,6 @@ import type {
14
14
  export type { SlackInboundMessageMetadata };
15
15
  import type { ServerMessage } from "../daemon/message-protocol.js";
16
16
  import type { AssistantEventHub } from "./assistant-event-hub.js";
17
- import type {
18
- ApprovalCopyGenerator,
19
- GuardianActionCopyGenerator,
20
- } from "./message-composer-types.js";
21
17
 
22
18
  export type {
23
19
  ApprovalCopyGenerator,
@@ -61,41 +57,6 @@ export type ApprovalConversationGenerator = (
61
57
  context: ApprovalConversationContext,
62
58
  ) => Promise<ApprovalConversationResult>;
63
59
 
64
- // ---------------------------------------------------------------------------
65
- // Guardian follow-up conversation flow types
66
- // ---------------------------------------------------------------------------
67
-
68
- /** The disposition returned by the guardian follow-up conversation engine. */
69
- export type GuardianFollowUpDisposition =
70
- | "call_back"
71
- | "decline"
72
- | "keep_pending";
73
-
74
- /** Structured result from a single turn of the guardian follow-up conversation. */
75
- export interface GuardianFollowUpTurnResult {
76
- disposition: GuardianFollowUpDisposition;
77
- replyText: string;
78
- }
79
-
80
- /** Input context for the guardian follow-up conversation engine. */
81
- export interface GuardianFollowUpConversationContext {
82
- /** The original question that was asked during the voice call. */
83
- questionText: string;
84
- /** The guardian's late answer text that initiated the follow-up. */
85
- lateAnswerText: string;
86
- /** The guardian's latest reply in the follow-up conversation. */
87
- guardianReply: string;
88
- }
89
-
90
- /**
91
- * Daemon-injected function that processes one turn of a guardian follow-up
92
- * conversation. Classifies the guardian's intent into a structured disposition
93
- * and produces a natural reply.
94
- */
95
- export type GuardianFollowUpConversationGenerator = (
96
- context: GuardianFollowUpConversationContext,
97
- ) => Promise<GuardianFollowUpTurnResult>;
98
-
99
60
  export interface RuntimeMessageConversationOptions {
100
61
  transport?: {
101
62
  channelId: ChannelId;
@@ -115,6 +76,11 @@ export interface RuntimeMessageConversationOptions {
115
76
  commandIntent?: { type: string; payload?: string; languageCode?: string };
116
77
  /** Slack-only non-persisted notice injected into the active model turn. */
117
78
  slackRuntimeContextNotice?: string;
79
+ /**
80
+ * Persisted user-facing content. When present, storage/UI use this value
81
+ * while the model-facing turn continues to use `content`.
82
+ */
83
+ displayContent?: string;
118
84
  /** Optional callback to receive real-time agent loop events (text deltas, tool starts, etc.). */
119
85
  onEvent?: (msg: ServerMessage) => void;
120
86
  /**
@@ -168,14 +134,6 @@ export interface RuntimeHttpServerOptions {
168
134
  port?: number;
169
135
  /** Hostname / IP to bind to. Defaults to '127.0.0.1' (loopback-only). */
170
136
  hostname?: string;
171
- /** Daemon-injected generator for approval copy (provider-backed). */
172
- approvalCopyGenerator?: ApprovalCopyGenerator;
173
- /** Daemon-injected generator for conversational approval flow (provider-backed). */
174
- approvalConversationGenerator?: ApprovalConversationGenerator;
175
- /** Daemon-injected generator for guardian action copy (provider-backed). */
176
- guardianActionCopyGenerator?: GuardianActionCopyGenerator;
177
- /** Daemon-injected generator for guardian follow-up conversation (provider-backed). */
178
- guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator;
179
137
  }
180
138
 
181
139
  export interface RuntimeAttachmentMetadata {
@@ -227,5 +185,19 @@ export interface RuntimeMessagePayload {
227
185
  status: string;
228
186
  error?: string;
229
187
  conversationId?: string;
188
+ objective?: string;
189
+ };
190
+ slackMessage?: {
191
+ channelId: string;
192
+ channelTs: string;
193
+ threadTs?: string;
194
+ messageLink?: {
195
+ appUrl?: string;
196
+ webUrl?: string;
197
+ };
198
+ threadLink?: {
199
+ appUrl?: string;
200
+ webUrl?: string;
201
+ };
230
202
  };
231
203
  }
@@ -14,7 +14,7 @@
14
14
  * combination logic.
15
15
  */
16
16
 
17
- import { hasManagedProxyPrereqs } from "../../providers/managed-proxy/context.js";
17
+ import { hasManagedProxyPrereqs } from "../../providers/platform-proxy/context.js";
18
18
  import { getDaemonRuntimeMode } from "../runtime-mode.js";
19
19
 
20
20
  export type VBundleOriginMode =
@@ -47,6 +47,7 @@ export interface PendingInteraction {
47
47
  kind:
48
48
  | "confirmation"
49
49
  | "secret"
50
+ | "question"
50
51
  | "host_bash"
51
52
  | "host_file"
52
53
  | "host_cu"
@@ -241,6 +241,23 @@ describe("bookmark routes", () => {
241
241
  ).toBe("msg-6");
242
242
  });
243
243
 
244
+ test("duplicate POSTs only broadcast one bookmark.created event", async () => {
245
+ seedConversationAndMessage({
246
+ conversationId: "conv-dup",
247
+ messageId: "msg-dup",
248
+ });
249
+
250
+ await call(createHandler, {
251
+ body: { messageId: "msg-dup", conversationId: "conv-dup" },
252
+ });
253
+ await call(createHandler, {
254
+ body: { messageId: "msg-dup", conversationId: "conv-dup" },
255
+ });
256
+ await new Promise((r) => setTimeout(r, 0));
257
+
258
+ expect(publishedTypes()).toEqual(["bookmark.created"]);
259
+ });
260
+
244
261
  test("DELETE on a non-existent messageId does not publish", async () => {
245
262
  await call(deleteByMessageHandler, {
246
263
  pathParams: { messageId: "does-not-exist" },