@vellumai/assistant 0.8.3 → 0.8.4

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 (342) hide show
  1. package/docker-entrypoint.sh +0 -1
  2. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  3. package/openapi.yaml +610 -16
  4. package/package.json +1 -1
  5. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  6. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  7. package/src/__tests__/agent-loop.test.ts +88 -3
  8. package/src/__tests__/anthropic-provider.test.ts +272 -0
  9. package/src/__tests__/approval-cascade.test.ts +1 -1
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  11. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  12. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  13. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  14. package/src/__tests__/compaction-events.test.ts +1 -1
  15. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  16. package/src/__tests__/config-watcher.test.ts +1 -1
  17. package/src/__tests__/context-token-estimator.test.ts +91 -1
  18. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  19. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
  20. package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
  21. package/src/__tests__/conversation-agent-loop.test.ts +25 -7
  22. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  23. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  24. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  25. package/src/__tests__/conversation-fork-crud.test.ts +161 -0
  26. package/src/__tests__/conversation-lifecycle.test.ts +1 -1
  27. package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
  28. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  29. package/src/__tests__/conversation-pairing.test.ts +2 -2
  30. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  31. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  32. package/src/__tests__/conversation-queue.test.ts +1 -1
  33. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  34. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  35. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  36. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  37. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  38. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  39. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  40. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  42. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  43. package/src/__tests__/credential-security-invariants.test.ts +6 -0
  44. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  45. package/src/__tests__/dm-backfill.test.ts +64 -0
  46. package/src/__tests__/dm-persistence.test.ts +33 -0
  47. package/src/__tests__/document-find-replace.test.ts +501 -0
  48. package/src/__tests__/first-greeting.test.ts +23 -2
  49. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  50. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  51. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  52. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  53. package/src/__tests__/host-file-proxy.test.ts +8 -1
  54. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  55. package/src/__tests__/identity-routes.test.ts +57 -0
  56. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  57. package/src/__tests__/injector-chain.test.ts +2 -0
  58. package/src/__tests__/injector-document-comments.test.ts +378 -0
  59. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  60. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  61. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  62. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  63. package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
  64. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  65. package/src/__tests__/llm-resolver.test.ts +85 -1
  66. package/src/__tests__/log-export-routes.test.ts +99 -2
  67. package/src/__tests__/message-queue-steer.test.ts +114 -0
  68. package/src/__tests__/openai-provider.test.ts +105 -0
  69. package/src/__tests__/openai-responses-provider.test.ts +4 -4
  70. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
  72. package/src/__tests__/platform.test.ts +0 -3
  73. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  74. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  75. package/src/__tests__/process-message-display-content.test.ts +21 -16
  76. package/src/__tests__/server-history-render.test.ts +83 -4
  77. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  78. package/src/__tests__/system-prompt.test.ts +51 -28
  79. package/src/__tests__/terminal-tools.test.ts +11 -1
  80. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  81. package/src/__tests__/thread-backfill.test.ts +370 -22
  82. package/src/__tests__/tool-executor.test.ts +90 -1
  83. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  84. package/src/__tests__/twilio-routes.test.ts +1 -1
  85. package/src/__tests__/web-fetch.test.ts +2 -2
  86. package/src/__tests__/workspace-git-service.test.ts +88 -5
  87. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  88. package/src/agent/attachments.ts +1 -0
  89. package/src/agent/loop.ts +57 -20
  90. package/src/background-wake/next-wake.test.ts +289 -0
  91. package/src/background-wake/next-wake.ts +172 -0
  92. package/src/browser/operations.ts +15 -0
  93. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  94. package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
  95. package/src/cli/commands/conversations.ts +128 -1
  96. package/src/cli/commands/inference-providers.ts +147 -1
  97. package/src/cli/commands/memory-v2.ts +308 -0
  98. package/src/cli/commands/notifications.ts +24 -2
  99. package/src/cli/utils/conversation-id.ts +17 -5
  100. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  101. package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
  102. package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
  103. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  104. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  105. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  106. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  107. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  108. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  109. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  110. package/src/config/bundled-tool-registry.ts +22 -12
  111. package/src/config/call-site-defaults.ts +19 -0
  112. package/src/config/feature-flag-registry.json +99 -3
  113. package/src/config/llm-resolver.ts +16 -2
  114. package/src/config/schemas/__tests__/memory-v2.test.ts +4 -0
  115. package/src/config/schemas/call-site-catalog.ts +21 -0
  116. package/src/config/schemas/llm.ts +3 -0
  117. package/src/config/schemas/memory-v2.ts +48 -1
  118. package/src/context/compactor.ts +8 -1
  119. package/src/context/token-estimator.ts +47 -4
  120. package/src/context/window-manager.ts +25 -0
  121. package/src/credential-health/credential-health-service.ts +34 -19
  122. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  123. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  124. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  125. package/src/daemon/conversation-agent-loop-handlers.ts +153 -23
  126. package/src/daemon/conversation-agent-loop.ts +223 -54
  127. package/src/daemon/conversation-lifecycle.ts +142 -116
  128. package/src/daemon/conversation-messaging.ts +3 -0
  129. package/src/daemon/conversation-process.ts +273 -0
  130. package/src/daemon/conversation-queue-manager.ts +14 -0
  131. package/src/daemon/conversation-runtime-assembly.ts +135 -75
  132. package/src/daemon/conversation-slash.ts +37 -5
  133. package/src/daemon/conversation-surfaces.ts +45 -2
  134. package/src/daemon/conversation-tool-setup.ts +7 -0
  135. package/src/daemon/conversation.ts +42 -5
  136. package/src/daemon/first-greeting.ts +10 -0
  137. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  138. package/src/daemon/handlers/config-a2a.ts +160 -0
  139. package/src/daemon/handlers/config-model.test.ts +1 -0
  140. package/src/daemon/handlers/conversations.ts +79 -0
  141. package/src/daemon/handlers/shared.ts +92 -29
  142. package/src/daemon/host-bash-proxy.ts +1 -1
  143. package/src/daemon/host-cu-proxy.ts +1 -1
  144. package/src/daemon/host-file-proxy.ts +1 -1
  145. package/src/daemon/host-transfer-proxy.ts +1 -1
  146. package/src/daemon/lifecycle.ts +18 -4
  147. package/src/daemon/message-protocol.ts +4 -0
  148. package/src/daemon/message-types/conversations.ts +8 -0
  149. package/src/daemon/message-types/document-comments.ts +50 -0
  150. package/src/daemon/message-types/messages.ts +68 -1
  151. package/src/daemon/message-types/surfaces.ts +3 -1
  152. package/src/daemon/message-types/web-activity.ts +57 -0
  153. package/src/daemon/plugin-source-watcher.ts +135 -3
  154. package/src/daemon/process-message.ts +69 -12
  155. package/src/daemon/query-complexity-router.ts +75 -0
  156. package/src/daemon/trust-context.ts +6 -0
  157. package/src/documents/document-comments-store.test.ts +338 -0
  158. package/src/documents/document-comments-store.ts +237 -0
  159. package/src/documents/document-store.ts +202 -0
  160. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  161. package/src/heartbeat/heartbeat-service.ts +1 -0
  162. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  163. package/src/home/feed-types.ts +6 -1
  164. package/src/home/home-content-refresh.ts +52 -0
  165. package/src/home/home-greeting-cache.ts +69 -0
  166. package/src/home/home-greeting.ts +94 -0
  167. package/src/home/suggested-prompts.ts +177 -9
  168. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  169. package/src/memory/__tests__/memory-retrospective-job.test.ts +320 -6
  170. package/src/memory/conversation-crud.ts +133 -43
  171. package/src/memory/db-init.ts +16 -0
  172. package/src/memory/delivery-crud.ts +41 -0
  173. package/src/memory/delivery-status.ts +141 -15
  174. package/src/memory/external-conversation-store.ts +32 -1
  175. package/src/memory/jobs-worker.ts +21 -1
  176. package/src/memory/memory-retrospective-constants.ts +28 -0
  177. package/src/memory/memory-retrospective-enqueue.ts +3 -2
  178. package/src/memory/memory-retrospective-job.ts +408 -18
  179. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  180. package/src/memory/memory-v2-activation-log-store.ts +26 -8
  181. package/src/memory/migrations/100-core-tables.ts +1 -0
  182. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  183. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  184. package/src/memory/migrations/253-document-comments.ts +47 -0
  185. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  186. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  187. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  188. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  189. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  190. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  191. package/src/memory/migrations/index.ts +17 -0
  192. package/src/memory/migrations/registry.ts +25 -0
  193. package/src/memory/onboarding-events-store.ts +7 -0
  194. package/src/memory/schema/calls.ts +1 -0
  195. package/src/memory/schema/conversations.ts +3 -0
  196. package/src/memory/schema/infrastructure.ts +1 -0
  197. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  198. package/src/memory/v2/__tests__/injection.test.ts +31 -14
  199. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  200. package/src/memory/v2/__tests__/router.test.ts +489 -1
  201. package/src/memory/v2/consolidation-job.ts +14 -0
  202. package/src/memory/v2/injection-events.ts +101 -0
  203. package/src/memory/v2/injection.ts +21 -10
  204. package/src/memory/v2/page-index.ts +209 -7
  205. package/src/memory/v2/page-store.ts +18 -0
  206. package/src/memory/v2/router.ts +209 -55
  207. package/src/messaging/providers/index.ts +7 -1
  208. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  209. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  210. package/src/messaging/providers/slack/adapter.ts +178 -25
  211. package/src/messaging/providers/slack/api.test.ts +54 -0
  212. package/src/messaging/providers/slack/api.ts +119 -3
  213. package/src/messaging/providers/slack/client.ts +12 -0
  214. package/src/messaging/providers/slack/deep-link.ts +20 -1
  215. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  216. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  217. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  218. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  219. package/src/messaging/providers/slack/send.test.ts +77 -0
  220. package/src/messaging/providers/slack/send.ts +8 -2
  221. package/src/messaging/providers/slack/types.ts +14 -0
  222. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  223. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  224. package/src/notifications/conversation-seed-composer.ts +14 -2
  225. package/src/notifications/deferred-emit.ts +135 -0
  226. package/src/notifications/emit-signal.ts +9 -1
  227. package/src/notifications/home-feed-side-effect.ts +60 -30
  228. package/src/oauth/connect-orchestrator.ts +3 -0
  229. package/src/oauth/credential-token-resolver.ts +2 -0
  230. package/src/oauth/manual-token-connection.ts +19 -0
  231. package/src/oauth/oauth-store.ts +12 -0
  232. package/src/oauth/seed-providers.ts +22 -0
  233. package/src/permissions/prompter.ts +5 -2
  234. package/src/permissions/secret-prompter.ts +4 -1
  235. package/src/plugins/defaults/injectors.ts +82 -9
  236. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  237. package/src/prompts/normalize-onboarding.ts +40 -0
  238. package/src/prompts/sections.ts +32 -14
  239. package/src/prompts/system-prompt.ts +105 -68
  240. package/src/prompts/template-detection.ts +37 -0
  241. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  242. package/src/prompts/templates/BOOTSTRAP.md +8 -0
  243. package/src/prompts/templates/VOICE.md +3 -0
  244. package/src/prompts/templates/system-sections.ts +53 -3
  245. package/src/providers/anthropic/client.ts +132 -5
  246. package/src/providers/fireworks/client.ts +20 -2
  247. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  248. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  249. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  250. package/src/providers/inference/adapter-factory.ts +15 -1
  251. package/src/providers/inference/auth.ts +3 -3
  252. package/src/providers/inference/codex-token-refresh.ts +128 -0
  253. package/src/providers/inference/resolve-auth.ts +49 -6
  254. package/src/providers/model-catalog.ts +48 -1
  255. package/src/providers/openai/chat-completions-provider.ts +57 -20
  256. package/src/providers/openai/responses-provider.ts +9 -3
  257. package/src/providers/openrouter/client.ts +5 -1
  258. package/src/providers/types.ts +25 -0
  259. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  260. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  261. package/src/runtime/agent-wake.ts +151 -56
  262. package/src/runtime/auth/route-policy.ts +7 -3
  263. package/src/runtime/background-job-runner.ts +26 -0
  264. package/src/runtime/channel-reply-delivery.ts +182 -47
  265. package/src/runtime/channel-retry-sweep.ts +141 -16
  266. package/src/runtime/http-types.ts +7 -4
  267. package/src/runtime/pending-interactions.ts +51 -8
  268. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  269. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +55 -1
  270. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  271. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
  272. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  273. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  274. package/src/runtime/routes/approval-routes.ts +4 -1
  275. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  276. package/src/runtime/routes/content-source-routes.ts +78 -0
  277. package/src/runtime/routes/conversation-cli-routes.ts +146 -1
  278. package/src/runtime/routes/conversation-query-routes.ts +60 -1
  279. package/src/runtime/routes/conversation-routes.ts +281 -76
  280. package/src/runtime/routes/document-comments-routes.ts +287 -0
  281. package/src/runtime/routes/documents-routes.ts +33 -0
  282. package/src/runtime/routes/home-feed-routes.ts +6 -3
  283. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  284. package/src/runtime/routes/host-browser-routes.ts +8 -1
  285. package/src/runtime/routes/identity-routes.ts +21 -0
  286. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  287. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  288. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  289. package/src/runtime/routes/index.ts +12 -4
  290. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  291. package/src/runtime/routes/integrations/a2a.ts +60 -1
  292. package/src/runtime/routes/log-export-routes.ts +39 -0
  293. package/src/runtime/routes/memory-v2-routes.ts +217 -0
  294. package/src/runtime/routes/notification-routes.ts +19 -2
  295. package/src/runtime/routes/question-routes.ts +4 -1
  296. package/src/runtime/routes/sanity-routes.ts +159 -0
  297. package/src/runtime/routes/slack-channel-routes.ts +187 -0
  298. package/src/runtime/services/conversation-serializer.ts +30 -4
  299. package/src/schedule/integration-status.ts +3 -1
  300. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  301. package/src/security/oauth2-device-code.ts +307 -0
  302. package/src/security/oauth2.ts +26 -9
  303. package/src/security/secure-keys.ts +5 -0
  304. package/src/skills/catalog-install.ts +6 -2
  305. package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
  306. package/src/tools/browser/browser-execution.ts +93 -0
  307. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  308. package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
  309. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
  310. package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
  311. package/src/tools/browser/cdp-client/factory.ts +87 -3
  312. package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
  313. package/src/tools/browser/cdp-client/types.ts +36 -0
  314. package/src/tools/browser/pinned-tabs.ts +90 -0
  315. package/src/tools/document/document-comment-tool.test.ts +379 -0
  316. package/src/tools/document/document-comment-tool.ts +156 -0
  317. package/src/tools/document/document-tool.ts +128 -2
  318. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  319. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  320. package/src/tools/network/domain-normalize.ts +17 -0
  321. package/src/tools/network/web-fetch.ts +213 -64
  322. package/src/tools/network/web-search.ts +191 -66
  323. package/src/tools/terminal/safe-env.ts +3 -2
  324. package/src/tools/tool-approval-handler.ts +19 -12
  325. package/src/tools/types.ts +4 -0
  326. package/src/tools/ui-surface/definitions.ts +3 -1
  327. package/src/types/onboarding-context.ts +4 -0
  328. package/src/util/__tests__/favicon.test.ts +84 -0
  329. package/src/util/favicon.ts +40 -0
  330. package/src/util/platform.ts +0 -5
  331. package/src/workspace/git-service.ts +75 -4
  332. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  333. package/src/workspace/migrations/registry.ts +2 -0
  334. package/src/config/bundled-skills/document/SKILL.md +0 -54
  335. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  336. package/src/daemon/seed-files.ts +0 -18
  337. package/src/runtime/routes/interface-routes.ts +0 -43
  338. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  339. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  340. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  341. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  342. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -202,6 +202,85 @@ export function deleteQueuedMessage(
202
202
  return { removed: false, reason: "message_not_found" };
203
203
  }
204
204
 
205
+ /**
206
+ * Steer a conversation to a specific queued message.
207
+ * Promotes the message to the head of the queue, marks the conversation
208
+ * as needing tool-result repair, and aborts the current generation so the
209
+ * drain path picks up the promoted message.
210
+ *
211
+ * Returns `{ steered: true }` on success, or `{ steered: false, reason }` on failure.
212
+ */
213
+ export function steerToMessage(
214
+ conversationId: string,
215
+ requestId: string,
216
+ ):
217
+ | { steered: true }
218
+ | {
219
+ steered: false;
220
+ reason:
221
+ | "conversation_not_found"
222
+ | "message_not_found"
223
+ | "not_processing";
224
+ } {
225
+ const conversation = findConversation(conversationId);
226
+ if (!conversation) {
227
+ log.warn(
228
+ { conversationId, requestId },
229
+ "No conversation found for steer_to_message",
230
+ );
231
+ return { steered: false, reason: "conversation_not_found" };
232
+ }
233
+
234
+ if (!conversation.isProcessing()) {
235
+ log.warn(
236
+ { conversationId, requestId },
237
+ "Cannot steer: conversation is not processing",
238
+ );
239
+ return { steered: false, reason: "not_processing" };
240
+ }
241
+
242
+ const promoted = conversation.queue.promoteToHead(requestId);
243
+ if (!promoted) {
244
+ log.warn(
245
+ { conversationId, requestId },
246
+ "Queued message not found for steering",
247
+ );
248
+ return { steered: false, reason: "message_not_found" };
249
+ }
250
+
251
+ // Mark the conversation for tool-result repair so the drain path can
252
+ // inject synthetic tool results for any pending tool_use blocks that
253
+ // were abandoned by the aborted generation.
254
+ conversation.pendingSteerRepair = true;
255
+
256
+ // Broadcast the steer event so clients can update their UI.
257
+ broadcastMessage({
258
+ type: "message_steered",
259
+ conversationId,
260
+ requestId,
261
+ });
262
+
263
+ log.info(
264
+ { conversationId, requestId },
265
+ "Steering to queued message — aborting current generation",
266
+ );
267
+
268
+ // Abort the in-flight generation. The agent loop's finally block calls
269
+ // drainQueue, which will pick up the promoted message at the head.
270
+ // Unlike abortConversation, we do NOT clear the queue or dispose
271
+ // prompters — we want the queue to drain with the promoted message first.
272
+ const reason = createAbortReason(
273
+ "preempted_by_new_message",
274
+ "steerToMessage",
275
+ conversationId,
276
+ );
277
+ conversation.abortController?.abort(reason);
278
+ // Deny pending confirmations so the abort unblocks immediately.
279
+ conversation.denyAllPendingConfirmations();
280
+
281
+ return { steered: true };
282
+ }
283
+
205
284
  // ---------------------------------------------------------------------------
206
285
  // HTTP handler (delegates to shared logic)
207
286
  // ---------------------------------------------------------------------------
@@ -92,6 +92,19 @@ export interface HistorySurface {
92
92
  completionSummary?: string;
93
93
  }
94
94
 
95
+ /**
96
+ * Positional reference to a file attachment captured while walking the
97
+ * content array. The index of an entry in `RenderedHistoryContent.attachments`
98
+ * is what `contentOrder` references as `attachment:N`.
99
+ */
100
+ export interface HistoryAttachmentRef {
101
+ /** Stable DB attachment id when persisted on the file block (`_attachmentId`). */
102
+ attachmentId?: string;
103
+ filename: string;
104
+ mimeType: string;
105
+ sizeBytes: number;
106
+ }
107
+
95
108
  export interface RenderedHistoryContent {
96
109
  text: string;
97
110
  toolCalls: HistoryToolCall[];
@@ -99,12 +112,18 @@ export interface RenderedHistoryContent {
99
112
  toolCallsBeforeText: boolean;
100
113
  /** Text segments split by tool-call boundaries. */
101
114
  textSegments: string[];
102
- /** Content block ordering using "text:N", "tool:N", "surface:N" encoding. */
115
+ /** Content block ordering using "text:N", "tool:N", "surface:N", "attachment:N" encoding. */
103
116
  contentOrder: string[];
104
117
  /** UI surfaces (widgets) embedded in the message. */
105
118
  surfaces: HistorySurface[];
106
119
  /** Thinking segments extracted from thinking blocks. */
107
120
  thinkingSegments: string[];
121
+ /**
122
+ * File attachments captured in content order. Index `N` matches an
123
+ * `attachment:N` entry in `contentOrder`. Callers align their DB-sourced
124
+ * attachment metadata to this ordering for inline placement.
125
+ */
126
+ attachments: HistoryAttachmentRef[];
108
127
  }
109
128
 
110
129
  /**
@@ -115,6 +134,8 @@ export interface RenderedHistoryContent {
115
134
  export interface SlackInboundMessageMetadata {
116
135
  /** Slack channel id (conversation external id) — recorded as `channelId`. */
117
136
  channelId: string;
137
+ /** Human-readable Slack channel name, when the gateway supplied it. */
138
+ channelName?: string;
118
139
  /** Slack `ts` for this message — required so persistence can record `channelTs`. */
119
140
  channelTs: string;
120
141
  /** Parent `thread_ts` when the message lives inside a thread; absent for top-level. */
@@ -123,6 +144,18 @@ export interface SlackInboundMessageMetadata {
123
144
  displayName?: string;
124
145
  /** Canonical Slack external user id for the sender, when available. */
125
146
  actorExternalUserId?: string;
147
+ /** Raw Slack profile timezone for the sender, when supplied. */
148
+ actorTimezone?: string;
149
+ /** Compact Slack profile timezone label for the sender, when supplied. */
150
+ actorTimezoneLabel?: string;
151
+ /** Raw Slack profile timezone offset in seconds, when supplied. */
152
+ actorTimezoneOffsetSeconds?: number;
153
+ /** Timezone used to render this message's timestamp. */
154
+ timestampTimezone?: string;
155
+ /** Compact label for the rendered timestamp timezone. */
156
+ timestampTimezoneLabel?: string;
157
+ /** Compact timezone label appended to the rendered speaker name. */
158
+ speakerTimezoneLabel?: string;
126
159
  }
127
160
 
128
161
  /**
@@ -144,8 +177,6 @@ export interface ConversationCreateOptions {
144
177
  authContext?: AuthContext;
145
178
  /** Whether this turn can block on interactive approval prompts. */
146
179
  isInteractive?: boolean;
147
- /** Slack-only non-persisted notice injected into the active model turn. */
148
- slackRuntimeContextNotice?: string;
149
180
  /**
150
181
  * Persisted user-facing content. When present, storage/UI use this value
151
182
  * while the model-facing turn continues to use `content`.
@@ -192,22 +223,42 @@ function clampAttachmentText(text: string): string {
192
223
  return `${text.slice(0, HISTORY_ATTACHMENT_TEXT_LIMIT)}<truncated />`;
193
224
  }
194
225
 
195
- function renderFileBlockForHistory(block: Record<string, unknown>): string {
226
+ interface FileBlockMetadata {
227
+ mediaType: string;
228
+ filename: string;
229
+ sizeBytes: number;
230
+ }
231
+
232
+ function extractFileBlockMetadata(
233
+ block: Record<string, unknown>,
234
+ ): FileBlockMetadata {
196
235
  const source = isRecord(block.source) ? block.source : null;
197
- const mediaType =
198
- source && typeof source.media_type === "string"
199
- ? source.media_type
200
- : "application/octet-stream";
201
- const filename =
202
- source && typeof source.filename === "string"
203
- ? source.filename
204
- : "attachment";
205
- const sizeBytes =
206
- source && typeof source.data === "string"
207
- ? estimateBase64Bytes(source.data)
208
- : 0;
209
- const summaryParts = [`[File attachment] ${filename}`, `type=${mediaType}`];
210
- if (sizeBytes > 0) summaryParts.push(`size=${formatBytes(sizeBytes)}`);
236
+ return {
237
+ mediaType:
238
+ source && typeof source.media_type === "string"
239
+ ? source.media_type
240
+ : "application/octet-stream",
241
+ filename:
242
+ source && typeof source.filename === "string"
243
+ ? source.filename
244
+ : "attachment",
245
+ sizeBytes:
246
+ source && typeof source.data === "string"
247
+ ? estimateBase64Bytes(source.data)
248
+ : 0,
249
+ };
250
+ }
251
+
252
+ function renderFileBlockForHistory(
253
+ block: Record<string, unknown>,
254
+ meta: FileBlockMetadata,
255
+ ): string {
256
+ const summaryParts = [
257
+ `[File attachment] ${meta.filename}`,
258
+ `type=${meta.mediaType}`,
259
+ ];
260
+ if (meta.sizeBytes > 0)
261
+ summaryParts.push(`size=${formatBytes(meta.sizeBytes)}`);
211
262
 
212
263
  const extractedText =
213
264
  typeof block.extracted_text === "string" ? block.extracted_text.trim() : "";
@@ -237,11 +288,13 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
237
288
  contentOrder: text ? ["text:0"] : [],
238
289
  surfaces: [],
239
290
  thinkingSegments: [],
291
+ attachments: [],
240
292
  };
241
293
  }
242
294
 
243
295
  const textParts: string[] = [];
244
296
  const attachmentParts: string[] = [];
297
+ const attachments: HistoryAttachmentRef[] = [];
245
298
  const toolCalls: HistoryToolCall[] = [];
246
299
  const surfaces: HistorySurface[] = [];
247
300
  const thinkingSegments: string[] = [];
@@ -351,7 +404,19 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
351
404
  continue;
352
405
  }
353
406
  if (block.type === "file") {
354
- attachmentParts.push(renderFileBlockForHistory(block));
407
+ const meta = extractFileBlockMetadata(block);
408
+ attachmentParts.push(renderFileBlockForHistory(block, meta));
409
+ finalizeSegment();
410
+ const ref: HistoryAttachmentRef = {
411
+ filename: meta.filename,
412
+ mimeType: meta.mediaType,
413
+ sizeBytes: meta.sizeBytes,
414
+ };
415
+ if (typeof block._attachmentId === "string" && block._attachmentId) {
416
+ ref.attachmentId = block._attachmentId;
417
+ }
418
+ attachments.push(ref);
419
+ contentOrder.push(`attachment:${attachments.length - 1}`);
355
420
  continue;
356
421
  }
357
422
  if (block.type === "image") {
@@ -495,17 +560,14 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
495
560
  matched.imageData = imageDataList[0];
496
561
  matched.imageDataList = imageDataList;
497
562
  }
498
- } else {
499
- toolCalls.push({
500
- name: "unknown",
501
- input: {},
502
- result: resultContent,
503
- isError,
504
- ...(imageDataList.length > 0
505
- ? { imageData: imageDataList[0], imageDataList }
506
- : {}),
507
- });
508
563
  }
564
+ // Orphan tool_result with no matching tool_use — drop it. Synthesizing
565
+ // a "name: 'unknown'" phantom entry rendered in chat as "Used unknown"
566
+ // / "Completed 1 step" with no context, with a timestamp later than
567
+ // the assistant's final answer. Most commonly orphans appear when
568
+ // context-window compaction trims the parent tool_use block while
569
+ // leaving the paired tool_result. Losing the orphan's result content
570
+ // is correct: without the parent we can't tell the user what tool ran.
509
571
  continue;
510
572
  }
511
573
  }
@@ -541,6 +603,7 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
541
603
  contentOrder,
542
604
  surfaces,
543
605
  thinkingSegments,
606
+ attachments,
544
607
  };
545
608
  }
546
609
 
@@ -185,7 +185,7 @@ export class HostBashProxy extends HostProxyBase<
185
185
  timedOut: boolean;
186
186
  },
187
187
  ): void {
188
- pendingInteractions.resolve(requestId);
188
+ pendingInteractions.resolve(requestId, "answered");
189
189
  this.resolve(requestId, response);
190
190
  }
191
191
  }
@@ -280,7 +280,7 @@ export class HostCuProxy {
280
280
  observation: CuObservationResult,
281
281
  ): ToolExecutionResult | undefined {
282
282
  this._ownedRequests.delete(requestId);
283
- const interaction = pendingInteractions.resolve(requestId);
283
+ const interaction = pendingInteractions.resolve(requestId, "answered");
284
284
  if (!interaction?.rpcResolve) {
285
285
  log.warn({ requestId }, "No pending host CU request for response");
286
286
  return undefined;
@@ -227,7 +227,7 @@ export class HostFileProxy {
227
227
  requestId: string,
228
228
  response: { content: string; isError: boolean; imageData?: string },
229
229
  ): void {
230
- const interaction = pendingInteractions.resolve(requestId);
230
+ const interaction = pendingInteractions.resolve(requestId, "answered");
231
231
  if (!interaction?.rpcResolve) {
232
232
  log.warn({ requestId }, "No pending host file request for response");
233
233
  return;
@@ -508,7 +508,7 @@ export class HostTransferProxy {
508
508
  errorMessage?: string;
509
509
  },
510
510
  ): void {
511
- const interaction = pendingInteractions.resolve(requestId);
511
+ const interaction = pendingInteractions.resolve(requestId, "answered");
512
512
  if (!interaction?.rpcResolve) {
513
513
  log.warn({ requestId }, "No pending host transfer request for response");
514
514
  return;
@@ -32,6 +32,7 @@ import {
32
32
  } from "../credential-execution/startup-timeout.js";
33
33
  import { FilingService } from "../filing/filing-service.js";
34
34
  import { HeartbeatService } from "../heartbeat/heartbeat-service.js";
35
+ import { startHomeContentRefresh } from "../home/home-content-refresh.js";
35
36
  import { backfillRelationshipStateIfMissing } from "../home/relationship-state-writer.js";
36
37
  import { closeSentry, initSentry, setSentryDeviceId } from "../instrument.js";
37
38
  import { getMcpServerManager } from "../mcp/manager.js";
@@ -121,7 +122,6 @@ import {
121
122
  registerMessagingProviders,
122
123
  registerWatcherProviders,
123
124
  } from "./providers-setup.js";
124
- import { seedInterfaceFiles } from "./seed-files.js";
125
125
  import { DaemonServer } from "./server.js";
126
126
  import { installShutdownHandlers } from "./shutdown-handlers.js";
127
127
  import { refreshSkillCapabilityMemories } from "./skill-memory-refresh.js";
@@ -269,8 +269,13 @@ async function startCesProcess(
269
269
 
270
270
  // Entry point for the daemon process itself
271
271
  export async function runDaemon(): Promise<void> {
272
+ const startupStartedAt = Date.now();
273
+ // dotenv loads before the first log call so the lazy root logger
274
+ // initializes against the final VELLUM_WORKSPACE_DIR / log path, not
275
+ // whatever was in the live environment at process spawn.
272
276
  loadDotEnv();
273
277
  validateEnv();
278
+ log.info({ version: APP_VERSION }, "Daemon starting");
274
279
 
275
280
  try {
276
281
  // Initialize crash reporting eagerly so early startup failures are
@@ -353,8 +358,6 @@ export async function runDaemon(): Promise<void> {
353
358
  log.warn({ err }, "Background feature flag init failed"),
354
359
  );
355
360
 
356
- seedInterfaceFiles();
357
-
358
361
  log.info("Daemon startup: initializing DB");
359
362
  ensurePromptFiles();
360
363
 
@@ -470,6 +473,10 @@ export async function runDaemon(): Promise<void> {
470
473
  );
471
474
  });
472
475
 
476
+ // Pre-warm LLM-generated home page content (greeting + suggestion
477
+ // prompts) so the GET handler never triggers LLM calls.
478
+ startHomeContentRefresh();
479
+
473
480
  // Backfill injection templates on Slack bot token credentials so the
474
481
  // credential proxy can inject Authorization headers. Safe on every startup.
475
482
  try {
@@ -1228,7 +1235,6 @@ export async function runDaemon(): Promise<void> {
1228
1235
  }
1229
1236
 
1230
1237
  writePid(process.pid);
1231
- log.info({ pid: process.pid }, "Daemon started");
1232
1238
 
1233
1239
  // Install the `assistant` CLI symlink idempotently on every daemon start.
1234
1240
  // Non-blocking — failures are logged but don't affect startup.
@@ -1345,6 +1351,14 @@ export async function runDaemon(): Promise<void> {
1345
1351
  cleanupPidFile();
1346
1352
  },
1347
1353
  });
1354
+
1355
+ log.info(
1356
+ {
1357
+ durationMs: Date.now() - startupStartedAt,
1358
+ pid: process.pid,
1359
+ },
1360
+ "Daemon started",
1361
+ );
1348
1362
  } catch (err) {
1349
1363
  log.error({ err }, "Daemon startup failed — cleaning up");
1350
1364
  stopDiskPressureGuardForLifecycle();
@@ -22,6 +22,7 @@ export * from "./message-types/contacts.js";
22
22
  export * from "./message-types/conversations.js";
23
23
  export * from "./message-types/diagnostics.js";
24
24
  export * from "./message-types/disk-pressure.js";
25
+ export * from "./message-types/document-comments.js";
25
26
  export * from "./message-types/documents.js";
26
27
  export * from "./message-types/guardian-actions.js";
27
28
  export * from "./message-types/home.js";
@@ -45,6 +46,7 @@ export * from "./message-types/subagents.js";
45
46
  export * from "./message-types/surfaces.js";
46
47
  export * from "./message-types/sync.js";
47
48
  export * from "./message-types/upgrades.js";
49
+ export * from "./message-types/web-activity.js";
48
50
  export * from "./message-types/work-items.js";
49
51
  export * from "./message-types/workspace.js";
50
52
 
@@ -76,6 +78,7 @@ import type {
76
78
  _DiagnosticsServerMessages,
77
79
  } from "./message-types/diagnostics.js";
78
80
  import type { _DiskPressureServerMessages } from "./message-types/disk-pressure.js";
81
+ import type { _DocumentCommentsServerMessages } from "./message-types/document-comments.js";
79
82
  import type {
80
83
  _DocumentsClientMessages,
81
84
  _DocumentsServerMessages,
@@ -192,6 +195,7 @@ export type ServerMessage =
192
195
  | _BrowserServerMessages
193
196
  | _SubagentsServerMessages
194
197
  | _DocumentsServerMessages
198
+ | _DocumentCommentsServerMessages
195
199
  | _GuardianActionsServerMessages
196
200
  | _SyncInvalidationServerMessages
197
201
  | _HomeServerMessages
@@ -224,6 +224,7 @@ export interface ConversationTitleUpdated {
224
224
  interface ChannelBinding {
225
225
  sourceChannel: ChannelId;
226
226
  externalChatId: string;
227
+ externalChatName?: string | null;
227
228
  externalThreadId?: string | null;
228
229
  externalUserId?: string | null;
229
230
  displayName?: string | null;
@@ -236,6 +237,13 @@ interface ChannelBinding {
236
237
  webUrl?: string;
237
238
  };
238
239
  };
240
+ slackChannel?: {
241
+ channelId: string;
242
+ name?: string;
243
+ link?: {
244
+ webUrl?: string;
245
+ };
246
+ };
239
247
  }
240
248
 
241
249
  /** Attention state metadata for a conversation's latest assistant message. */
@@ -0,0 +1,50 @@
1
+ // Document comment event types (Server → Client).
2
+
3
+ export interface DocumentCommentCreated {
4
+ type: "document_comment_created";
5
+ conversationId: string;
6
+ surfaceId: string;
7
+ comment: {
8
+ id: string;
9
+ surfaceId: string;
10
+ author: string;
11
+ content: string;
12
+ anchorStart?: number;
13
+ anchorEnd?: number;
14
+ anchorText?: string;
15
+ parentCommentId?: string;
16
+ status: string;
17
+ createdAt: number;
18
+ updatedAt: number;
19
+ };
20
+ }
21
+
22
+ export interface DocumentCommentResolved {
23
+ type: "document_comment_resolved";
24
+ conversationId: string;
25
+ surfaceId: string;
26
+ commentId: string;
27
+ resolvedBy: string;
28
+ }
29
+
30
+ export interface DocumentCommentReopened {
31
+ type: "document_comment_reopened";
32
+ conversationId: string;
33
+ surfaceId: string;
34
+ commentId: string;
35
+ }
36
+
37
+ export interface DocumentCommentDeleted {
38
+ type: "document_comment_deleted";
39
+ conversationId: string;
40
+ surfaceId: string;
41
+ commentId: string;
42
+ }
43
+
44
+ // --- Domain-level union alias (consumed by the barrel file) ---
45
+
46
+ export type _DocumentCommentsServerMessages =
47
+ | DocumentCommentCreated
48
+ | DocumentCommentResolved
49
+ | DocumentCommentReopened
50
+ | DocumentCommentDeleted;
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { ChannelId, InterfaceId } from "../../channels/types.js";
4
4
  import type { CommandIntent, UserMessageAttachment } from "./shared.js";
5
+ import type { ToolActivityMetadata } from "./web-activity.js";
5
6
 
6
7
  // === Client → Server ===
7
8
 
@@ -175,6 +176,9 @@ export interface ToolResult {
175
176
  approvalReason?: string;
176
177
  /** Snapshot of the auto-approve threshold at execution time. */
177
178
  riskThreshold?: string;
179
+ /** Structured activity metadata for rich client rendering. Optional; old
180
+ * clients that key off `result` continue to work unchanged. */
181
+ activityMetadata?: ToolActivityMetadata;
178
182
  }
179
183
 
180
184
  export interface ConfirmationRequest {
@@ -363,6 +367,12 @@ export interface MessageQueuedDeleted {
363
367
  requestId: string;
364
368
  }
365
369
 
370
+ export interface MessageSteered {
371
+ type: "message_steered";
372
+ conversationId: string;
373
+ requestId: string;
374
+ }
375
+
366
376
  export interface SuggestionResponse {
367
377
  type: "suggestion_response";
368
378
  requestId: string;
@@ -390,6 +400,45 @@ export interface ConfirmationStateChanged {
390
400
  toolUseId?: string;
391
401
  }
392
402
 
403
+ /**
404
+ * Lifecycle states reported by `interaction_resolved`.
405
+ *
406
+ * - `"approved"` / `"rejected"` — user-supplied verdict on a confirmation.
407
+ * - `"answered"` — user/client provided a response (secret value, question
408
+ * answer, host-proxy result).
409
+ * - `"cancelled"` — the interaction was torn down without a user response
410
+ * (timeout, abort, dispose, prompter shutdown).
411
+ * - `"superseded"` — invalidated by a newer event (auto-deny on enqueue, a
412
+ * fresh user message arriving while a confirmation was outstanding).
413
+ */
414
+ export type InteractionResolutionState =
415
+ | "approved"
416
+ | "rejected"
417
+ | "answered"
418
+ | "cancelled"
419
+ | "superseded";
420
+
421
+ /**
422
+ * Broadcast when a pending interaction (confirmation, secret, question,
423
+ * host-proxy request) transitions to a resolved state. Clients use this to
424
+ * drop attention/processing indicators without polling.
425
+ */
426
+ export interface InteractionResolved {
427
+ type: "interaction_resolved";
428
+ requestId: string;
429
+ /**
430
+ * Conversation key for the interaction. The daemon's internal conversation
431
+ * id and the web client's conversation key coincide today (see
432
+ * `conversation-key-store.ts`); the field is named after the client-facing
433
+ * concept.
434
+ */
435
+ conversationKey: string;
436
+ state: InteractionResolutionState;
437
+ /** Kind of the resolved interaction (e.g. "confirmation", "secret", "host_bash"). */
438
+ kind: string;
439
+ conversationId?: string;
440
+ }
441
+
393
442
  /**
394
443
  * Server-side assistant activity lifecycle for thinking indicator placement.
395
444
  *
@@ -426,6 +475,21 @@ export interface AssistantActivityState {
426
475
  statusText?: string;
427
476
  }
428
477
 
478
+ /**
479
+ * Emitted when the query complexity auto-router selects a non-default
480
+ * profile for the current turn. Clients use this to show an inline
481
+ * notification (e.g. "Using Quality for this response"). Only fires when
482
+ * the router picks a profile — not when the user explicitly pinned one.
483
+ */
484
+ export interface TurnProfileAutoRouted {
485
+ type: "turn_profile_auto_routed";
486
+ conversationId: string;
487
+ /** Profile key (e.g. "quality-optimized"). */
488
+ profile: string;
489
+ /** Human-readable label (e.g. "Quality"). */
490
+ profileLabel: string;
491
+ }
492
+
429
493
  /**
430
494
  * Broadcast to clients when a conversation's inference-profile override
431
495
  * changes. `profile` is the profile name (a key in `llm.profiles`) or
@@ -497,8 +561,11 @@ export type _MessagesServerMessages =
497
561
  | MessageDequeued
498
562
  | MessageRequestComplete
499
563
  | MessageQueuedDeleted
564
+ | MessageSteered
500
565
  | SuggestionResponse
501
566
  | TraceEvent
502
567
  | ConfirmationStateChanged
503
568
  | AssistantActivityState
504
- | ConversationInferenceProfileUpdated;
569
+ | TurnProfileAutoRouted
570
+ | ConversationInferenceProfileUpdated
571
+ | InteractionResolved;
@@ -10,13 +10,15 @@ export type SurfaceType =
10
10
  | "confirmation"
11
11
  | "dynamic_page"
12
12
  | "file_upload"
13
- | "document_preview";
13
+ | "document_preview"
14
+ | "task_preferences";
14
15
 
15
16
  export const INTERACTIVE_SURFACE_TYPES: SurfaceType[] = [
16
17
  "form",
17
18
  "confirmation",
18
19
  "dynamic_page",
19
20
  "file_upload",
21
+ "task_preferences",
20
22
  ];
21
23
 
22
24
  export interface SurfaceAction {
@@ -0,0 +1,57 @@
1
+ // Shared structured result types for web-search and web-fetch tool activity.
2
+ //
3
+ // These types describe live (SSE-time) metadata that producers (search/fetch
4
+ // tool executors) emit and consumers (clients) render alongside the existing
5
+ // `result: string` payload. Persistence to conversation history is out of
6
+ // scope for this plan; the metadata is live-only.
7
+
8
+ export type WebSearchProviderId =
9
+ | "anthropic-native"
10
+ | "brave"
11
+ | "perplexity"
12
+ | "tavily";
13
+
14
+ export interface WebSearchResultItem {
15
+ rank: number; // 1-indexed
16
+ title: string;
17
+ url: string;
18
+ domain: string; // lowercased host
19
+ faviconUrl?: string;
20
+ snippet?: string; // not populated for anthropic-native (content encrypted)
21
+ age?: string; // Brave-only freshness hint
22
+ score?: number; // Tavily-only
23
+ }
24
+
25
+ export interface WebSearchMetadata {
26
+ query: string;
27
+ provider: WebSearchProviderId;
28
+ resultCount: number;
29
+ durationMs: number;
30
+ results: WebSearchResultItem[];
31
+ /** Present when search itself failed; results[] will be empty. */
32
+ errorMessage?: string;
33
+ }
34
+
35
+ export interface WebFetchMetadata {
36
+ url: string;
37
+ finalUrl: string;
38
+ status: number;
39
+ contentType?: string;
40
+ byteCount: number;
41
+ charCount: number;
42
+ truncated: boolean;
43
+ title?: string;
44
+ domain: string;
45
+ faviconUrl?: string;
46
+ redirectCount: number;
47
+ durationMs: number;
48
+ errorMessage?: string;
49
+ /** Set when extracted text is dramatically smaller than raw HTML — likely a JS-rendered SPA whose meaningful content the static fetcher missed. */
50
+ mayRequireJavaScript?: boolean;
51
+ }
52
+
53
+ /** Discriminated container so future tools can add their own metadata. */
54
+ export interface ToolActivityMetadata {
55
+ webSearch?: WebSearchMetadata;
56
+ webFetch?: WebFetchMetadata;
57
+ }