@vellumai/assistant 0.8.3 → 0.8.5

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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -1,5 +1,4 @@
1
1
  import { RiskLevel } from "../../permissions/types.js";
2
- import type { ToolDefinition } from "../../providers/types.js";
3
2
  import { registerTool } from "../registry.js";
4
3
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
5
4
 
@@ -57,13 +56,10 @@ class RequestSystemPermissionTool implements Tool {
57
56
  "Use when a tool fails with a permission/access error (e.g. 'Operation not permitted', 'EACCES', sandbox denial). " +
58
57
  "Do not explain how to open System Settings manually - this tool handles it with a clickable button.";
59
58
  category = "system";
59
+ executionTarget = "sandbox" as const;
60
60
  defaultRiskLevel = RiskLevel.High;
61
61
 
62
- getDefinition(): ToolDefinition {
63
- return {
64
- name: this.name,
65
- description: this.description,
66
- input_schema: {
62
+ input_schema = {
67
63
  type: "object",
68
64
  properties: {
69
65
  permission_type: {
@@ -78,9 +74,7 @@ class RequestSystemPermissionTool implements Tool {
78
74
  },
79
75
  },
80
76
  required: ["permission_type", "activity"],
81
- },
82
- };
83
- }
77
+ };
84
78
 
85
79
  async execute(
86
80
  input: Record<string, unknown>,
@@ -61,12 +61,13 @@ export const SAFE_ENV_VARS = [
61
61
  ] as const;
62
62
 
63
63
  export const KATA_SAFE_ENV_VARS = [
64
- "LD_LIBRARY_PATH",
65
64
  "VELLUM_APT_DATA_ROOT",
66
65
  "VELLUM_APT_DATA_SUITE",
67
66
  "VELLUM_APT_DATA_MIRROR",
68
67
  ] as const;
69
68
 
69
+ export const KATA_INJECTED_ENV_VARS = ["LD_LIBRARY_PATH"] as const;
70
+
70
71
  const KATA_APT_DATA_ROOT = "/data/system";
71
72
 
72
73
  function kataAptPaths(dataRoot: string): string[] {
@@ -132,7 +133,7 @@ export function buildSanitizedEnv(): Record<string, string> {
132
133
  env.VELLUM_APT_DATA_ROOT = kataAptDataRoot;
133
134
  env.PATH = appendUniquePathEntries(env.PATH, kataAptPaths(kataAptDataRoot));
134
135
  env.LD_LIBRARY_PATH = appendUniquePathEntries(
135
- env.LD_LIBRARY_PATH,
136
+ undefined,
136
137
  kataAptLibraryPaths(kataAptDataRoot),
137
138
  );
138
139
  }
@@ -4,7 +4,6 @@ import { spawn } from "node:child_process";
4
4
  import { getConfig } from "../../config/loader.js";
5
5
  import { isCesShellLockdownEnabled } from "../../credential-execution/feature-gates.js";
6
6
  import { RiskLevel } from "../../permissions/types.js";
7
- import type { ToolDefinition } from "../../providers/types.js";
8
7
  import { isUntrustedTrustClass } from "../../runtime/actor-trust-resolver.js";
9
8
  import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
10
9
  import { redactSecrets } from "../../security/secret-scanner.js";
@@ -49,13 +48,10 @@ class ShellTool implements Tool {
49
48
  name = "bash";
50
49
  description = "Execute a shell command on the local machine";
51
50
  category = "terminal";
51
+ executionTarget = "sandbox" as const;
52
52
  defaultRiskLevel = RiskLevel.Medium;
53
53
 
54
- getDefinition(): ToolDefinition {
55
- return {
56
- name: this.name,
57
- description: this.description,
58
- input_schema: {
54
+ input_schema = {
59
55
  type: "object",
60
56
  properties: {
61
57
  command: {
@@ -91,9 +87,7 @@ class ShellTool implements Tool {
91
87
  },
92
88
  },
93
89
  required: ["command", "activity"],
94
- },
95
- };
96
- }
90
+ };
97
91
 
98
92
  async execute(
99
93
  input: Record<string, unknown>,
@@ -334,9 +334,19 @@ export class ToolApprovalHandler {
334
334
  return { allowed: false, result: { content: msg, isError: true } };
335
335
  }
336
336
 
337
- // Gate tools not active for the current turn
338
- if (context.allowedToolNames && !context.allowedToolNames.has(name)) {
339
- const msg = `Tool "${name}" is not currently active. Load the skill that provides this tool first.`;
337
+ // Look up the tool before the allowedToolNames gate so a name no skill
338
+ // provides surfaces as "Unknown tool" (with the real list) instead of
339
+ // the misleading "load the skill" hint.
340
+ const tool = getTool(name);
341
+ if (!tool) {
342
+ const allowedToolNames = context.allowedToolNames;
343
+ const available = getAllTools()
344
+ .filter((t) => t.executionMode !== "proxy" || context.proxyToolResolver)
345
+ .map((t) => t.name)
346
+ .filter((n) => !allowedToolNames || allowedToolNames.has(n))
347
+ .sort()
348
+ .join(", ");
349
+ const msg = `Unknown tool: ${name}. Available tools: ${available}`;
340
350
  const durationMs = Date.now() - startTime;
341
351
  emitLifecycleEvent({
342
352
  type: "error",
@@ -356,15 +366,12 @@ export class ToolApprovalHandler {
356
366
  return { allowed: false, result: { content: msg, isError: true } };
357
367
  }
358
368
 
359
- // Resolve the tool from the registry
360
- const tool = getTool(name);
361
- if (!tool) {
362
- const available = getAllTools()
363
- .filter((t) => t.executionMode !== "proxy" || context.proxyToolResolver)
364
- .map((t) => t.name)
365
- .sort()
366
- .join(", ");
367
- const msg = `Unknown tool: ${name}. Available tools: ${available}`;
369
+ // Gate tools not active for the current turn
370
+ if (context.allowedToolNames && !context.allowedToolNames.has(name)) {
371
+ const loadHint = tool.ownerSkillId
372
+ ? `Load the "${tool.ownerSkillId}" skill that provides this tool first.`
373
+ : `Load the skill that provides this tool first.`;
374
+ const msg = `Tool "${name}" is not currently active. ${loadHint}`;
368
375
  const durationMs = Date.now() - startTime;
369
376
  emitLifecycleEvent({
370
377
  type: "error",
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Single source of truth for the defaults applied when a `ToolDefinition`
3
+ * omits one of the normally-required fields, plus the `finalizeTool`
4
+ * helper that lifts a `ToolDefinition` into a `LoadedTool`.
5
+ *
6
+ * Plugins, external loaders, and any other registration boundary that
7
+ * accepts loose `ToolDefinition` objects from authors must run them
8
+ * through `finalizeTool` before handing the result to a `registerXxxTools`
9
+ * call. The registry types make this a hard rule: every registered tool
10
+ * is a `LoadedTool` (`Required<ToolDefinition> & { name }`).
11
+ */
12
+
13
+ import type {
14
+ LoadedTool,
15
+ RiskLevel,
16
+ ToolDefinition,
17
+ ToolExecutionResult,
18
+ } from "./types.js";
19
+
20
+ /**
21
+ * Default values applied by `finalizeTool` when the author omits a field.
22
+ *
23
+ * - `description` defaults to empty — the model sees the tool name only
24
+ * for un-documented tools, which is the correct minimal-info signal.
25
+ * - `defaultRiskLevel` defaults to `medium` — the safe middle band that
26
+ * forces explicit approval for risky calls without spamming approval
27
+ * prompts on no-op tools.
28
+ * - `input_schema` defaults to an empty closed object — the model is
29
+ * allowed to call the tool with no arguments, and unknown arguments
30
+ * are rejected at the JSON-schema layer.
31
+ * - `executionTarget` defaults to `sandbox` — author-supplied tool code
32
+ * runs in the assistant container by default; opt in to `host` when
33
+ * the tool proxies work to the connected client.
34
+ *
35
+ * `execute` has no constant default because the default closure needs to
36
+ * close over the tool's name to produce a useful error message; see
37
+ * `finalizeTool` below.
38
+ */
39
+ export const TOOL_DEFAULTS = Object.freeze({
40
+ description: "",
41
+ defaultRiskLevel: "medium" as RiskLevel,
42
+ input_schema: Object.freeze({
43
+ type: "object",
44
+ properties: {},
45
+ additionalProperties: false,
46
+ }) as object,
47
+ executionTarget: "sandbox" as const,
48
+ });
49
+
50
+ /**
51
+ * Fill the four normally-required `ToolDefinition` fields with documented
52
+ * defaults when the author omitted them, attach the registration-time
53
+ * `name`, and return a `LoadedTool` that is safe to hand to a
54
+ * `registerXxxTools` call.
55
+ *
56
+ * The default `execute` returns an error result so the model sees a clear
57
+ * "this tool isn't wired up" signal at call time. The owning loader still
58
+ * registers the tool cleanly — a broken individual tool must never block
59
+ * the registration batch.
60
+ */
61
+ export function finalizeTool(
62
+ tool: ToolDefinition,
63
+ name: string,
64
+ ): LoadedTool {
65
+ const description =
66
+ typeof tool.description === "string"
67
+ ? tool.description
68
+ : TOOL_DEFAULTS.description;
69
+ const defaultRiskLevel =
70
+ typeof tool.defaultRiskLevel === "string"
71
+ ? tool.defaultRiskLevel
72
+ : TOOL_DEFAULTS.defaultRiskLevel;
73
+ const input_schema =
74
+ tool.input_schema !== null && typeof tool.input_schema === "object"
75
+ ? tool.input_schema
76
+ : TOOL_DEFAULTS.input_schema;
77
+ const execute =
78
+ typeof tool.execute === "function"
79
+ ? tool.execute
80
+ : async (): Promise<ToolExecutionResult> => ({
81
+ content: `tool ${name} has no execute implementation`,
82
+ isError: true,
83
+ });
84
+ const executionTarget = tool.executionTarget ?? TOOL_DEFAULTS.executionTarget;
85
+ return {
86
+ ...tool,
87
+ name,
88
+ description,
89
+ defaultRiskLevel,
90
+ input_schema,
91
+ executionTarget,
92
+ execute,
93
+ };
94
+ }
@@ -5,7 +5,6 @@ import type {
5
5
  ProxyApprovalCallback,
6
6
  RiskLevel,
7
7
  SensitiveOutputBinding,
8
- ToolDefinition,
9
8
  ToolExecutionErrorEvent,
10
9
  ToolExecutionStartEvent,
11
10
  ToolPermissionDeniedEvent,
@@ -14,6 +13,7 @@ import type {
14
13
 
15
14
  import type { InterfaceId } from "../channels/types.js";
16
15
  import type { CesClient } from "../credential-execution/client.js";
16
+ import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
17
17
  import type { SecretPromptResult } from "../permissions/secret-prompter.js";
18
18
  import type { ContentBlock } from "../providers/types.js";
19
19
  import type { TrustClass } from "../runtime/actor-trust-resolver.js";
@@ -63,7 +63,6 @@ export type {
63
63
  ProxyEnvVars,
64
64
  SensitiveOutputBinding,
65
65
  SensitiveOutputKind,
66
- ToolDefinition,
67
66
  ToolExecutionErrorEvent,
68
67
  ToolExecutionStartEvent,
69
68
  ToolPermissionDeniedEvent,
@@ -75,19 +74,7 @@ export { RiskLevel } from "@vellumai/skill-host-contracts";
75
74
  // Assistant-side concrete overlays
76
75
  // ---------------------------------------------------------------------------
77
76
 
78
- /**
79
- * Public, narrow subset of {@link ToolExecutionResult} that plugin-authored
80
- * tools are responsible for producing. Re-exported from
81
- * `@vellumai/plugin-api` as `ToolExecutionResult` — the type name plugin
82
- * authors actually import. The daemon-internal version below extends
83
- * this and adds runtime-only fields (risk metadata, approval
84
- * bookkeeping, sensitive-output bindings, etc.) that the executor
85
- * populates around the call — plugins MUST NOT set those.
86
- *
87
- * Adding fields here is a non-breaking change; renaming or removing
88
- * fields is breaking and gated on a major bump of `@vellumai/plugin-api`.
89
- */
90
- export interface PluginToolExecutionResult {
77
+ export interface ToolExecutionResult {
91
78
  /** Textual result shown to the model in the tool-result block. Empty string is valid. */
92
79
  content: string;
93
80
  /** When true, the agent loop treats `content` as an error and may surface it / retry. */
@@ -104,9 +91,6 @@ export interface PluginToolExecutionResult {
104
91
  * the LLM voluntarily end its turn.
105
92
  */
106
93
  yieldToUser?: boolean;
107
- }
108
-
109
- export interface ToolExecutionResult extends PluginToolExecutionResult {
110
94
  diff?: DiffInfo;
111
95
  /** Optional rich content blocks (e.g. images) to include alongside text in the tool result. */
112
96
  contentBlocks?: ContentBlock[];
@@ -163,6 +147,9 @@ export interface ToolExecutionResult extends PluginToolExecutionResult {
163
147
  * approval flow transparently.
164
148
  */
165
149
  cesApprovalRequired?: ApprovalRequired;
150
+ /** Structured activity metadata for client rendering (web search, web fetch, etc).
151
+ * Populated by daemon-internal tools; plugins must not set this. */
152
+ activityMetadata?: ToolActivityMetadata;
166
153
  }
167
154
 
168
155
  export type ProxyToolResolver = (
@@ -207,20 +194,7 @@ export type ToolLifecycleEventHandler = (
207
194
  event: ToolLifecycleEvent,
208
195
  ) => void | Promise<void>;
209
196
 
210
- /**
211
- * Public, narrow subset of {@link ToolContext} handed to plugin-authored
212
- * tools. Re-exported from `@vellumai/plugin-api` as `ToolContext` — the
213
- * type name plugin authors actually import. The daemon-internal version
214
- * below extends this and adds host-only fields (CES client, trust class,
215
- * lifecycle handlers, requester metadata, host-bash proxy, etc.). Plugin
216
- * tools see this shape only — the runtime still hands them the full
217
- * {@link ToolContext} value, but the structural extension here guarantees
218
- * the assignment without a manual cast.
219
- *
220
- * Adding fields here is a non-breaking change; renaming or removing
221
- * fields is breaking and gated on a major bump of `@vellumai/plugin-api`.
222
- */
223
- export interface PluginToolContext {
197
+ export interface ToolContext {
224
198
  /** Identifier of the conversation this tool invocation belongs to. */
225
199
  conversationId: string;
226
200
  /** Working directory the daemon was launched from. */
@@ -231,9 +205,6 @@ export interface PluginToolContext {
231
205
  signal?: AbortSignal;
232
206
  /** Optional incremental-output callback for streaming tools. Streaming tools should fall back to returning the full result in `content` when this is absent. */
233
207
  onOutput?: (chunk: string) => void;
234
- }
235
-
236
- export interface ToolContext extends PluginToolContext {
237
208
  /** Logical assistant scope for multi-assistant routing. */
238
209
  assistantId?: string;
239
210
  /** When set, the tool execution is part of a task run. Used to retrieve ephemeral permission rules. */
@@ -345,11 +316,32 @@ export interface ToolContext extends PluginToolContext {
345
316
  sourceActorPrincipalId?: string;
346
317
  }
347
318
 
348
- export interface Tool {
349
- name: string;
350
- description: string;
319
+ /**
320
+ * Author-facing tool spec — re-exported from `@vellumai/plugin-api`.
321
+ * Loaders fill documented defaults for omitted fields via `finalizeTool`
322
+ * in `tool-defaults.ts`.
323
+ */
324
+ export interface ToolDefinition {
325
+ /** Human-readable description shown to the model in the tool catalog. */
326
+ description?: string;
327
+ /** Author-asserted risk band — low / medium / high. Drives default permission gating. */
328
+ defaultRiskLevel?: RiskLevel;
329
+ /** JSON schema describing the tool's input arguments. */
330
+ input_schema?: object;
331
+ /** Where the tool runs — sandbox (assistant container) or host (guardian device via proxy). Resolved by `resolveExecutionTarget` if omitted. */
332
+ executionTarget?: ExecutionTarget;
333
+ /** Implementation invoked when the model calls the tool. */
334
+ execute?: (
335
+ input: Record<string, unknown>,
336
+ context: ToolContext,
337
+ ) => Promise<ToolExecutionResult>;
338
+ }
339
+
340
+ /** Tool after the loader has derived its name and filled defaults. */
341
+ export type LoadedTool = Required<ToolDefinition> & { name: string };
342
+
343
+ export interface Tool extends LoadedTool {
351
344
  category: string;
352
- defaultRiskLevel: RiskLevel;
353
345
  /** When set to 'proxy', the tool is forwarded to a connected client rather than executed locally. */
354
346
  executionMode?: "local" | "proxy";
355
347
  /** Whether this tool is a core built-in, provided by a skill, contributed by a plugin, or from an MCP server. */
@@ -364,63 +356,4 @@ export interface Tool {
364
356
  ownerSkillVersionHash?: string;
365
357
  /** Whether the owning skill is bundled with the daemon (trusted first-party). */
366
358
  ownerSkillBundled?: boolean;
367
- /** Declared execution target from the skill manifest. Used by resolveExecutionTarget
368
- * to accurately label lifecycle events for skill-provided tools. */
369
- executionTarget?: ExecutionTarget;
370
- getDefinition(): ToolDefinition;
371
- execute(
372
- input: Record<string, unknown>,
373
- context: ToolContext,
374
- ): Promise<ToolExecutionResult>;
375
359
  }
376
-
377
- /**
378
- * Plugin-facing tool shape. The narrow surface plugin authors implement;
379
- * differs from {@link Tool} in four ways:
380
- * - Plugins declare `input_schema` as a top-level field instead of
381
- * implementing `getDefinition()`. The registration boundary synthesizes
382
- * `getDefinition()` from `{name, description, input_schema}` before the
383
- * tool enters the internal registry.
384
- * - `name` is derived from the tool file's basename by the external plugin
385
- * loader.
386
- * - `category` is registry-owned and stamped to `"plugin"` when the tool is
387
- * registered.
388
- * - All ownership stamps (`origin`, `ownerPluginId`, etc.) are set
389
- * authoritatively by the bootstrap; plugin authors leave them blank.
390
- *
391
- * Every author-visible field is optional. The loader fills the four
392
- * normally-required slots (`description`, `defaultRiskLevel`,
393
- * `input_schema`, `execute`) with documented defaults when a plugin omits
394
- * them — see `applyPluginToolDefaults` in `external-plugin-loader.ts`.
395
- * A nameless, body-less `export default {}` is a valid (if useless) tool;
396
- * misconfigured tools surface at call time rather than blocking plugin
397
- * load.
398
- */
399
- export type PluginTool = Omit<
400
- Tool,
401
- "category" | "getDefinition" | "name" | "description" | "defaultRiskLevel"
402
- > & {
403
- description?: string;
404
- defaultRiskLevel?: RiskLevel;
405
- input_schema?: object;
406
- execute?: (
407
- input: Record<string, unknown>,
408
- context: ToolContext,
409
- ) => Promise<ToolExecutionResult>;
410
- };
411
-
412
- /**
413
- * Plugin tool after the external loader has derived its registry name and
414
- * filled defaults for any author-omitted fields. All four normally-required
415
- * slots are guaranteed present.
416
- */
417
- export type LoadedPluginTool = PluginTool & {
418
- name: string;
419
- description: string;
420
- defaultRiskLevel: RiskLevel;
421
- input_schema: object;
422
- execute: (
423
- input: Record<string, unknown>,
424
- context: ToolContext,
425
- ) => Promise<ToolExecutionResult>;
426
- };
@@ -8,7 +8,6 @@
8
8
  */
9
9
 
10
10
  import { RiskLevel } from "../../permissions/types.js";
11
- import type { ToolDefinition } from "../../providers/types.js";
12
11
  import type { Tool, ToolExecutionResult } from "../types.js";
13
12
 
14
13
  // ---------------------------------------------------------------------------
@@ -36,17 +35,15 @@ export const uiShowTool: Tool = {
36
35
  '- list: { items: [{ id, title, subtitle?, icon?, selected? }], selectionMode: "single"|"multiple"|"none" }\n' +
37
36
  "- confirmation: { message, detail?, confirmLabel?, confirmedLabel?, cancelLabel?, destructive? }\n" +
38
37
  "- dynamic_page: { html, width?, height?, preview?: { title, subtitle?, description?, icon?, metrics?: [{ label, value }] } }\n" +
39
- "- file_upload: { prompt, acceptedTypes?, maxFiles? }\n\n" +
38
+ "- file_upload: { prompt, acceptedTypes?, maxFiles? }\n" +
39
+ "- task_preferences: {} (no data needed — categories are rendered client-side)\n\n" +
40
40
  "Proactively show a task_progress card before multi-step or long-running work (web searches, file operations, research). Show it before your first tool call, then update steps as work progresses.",
41
41
  category: "ui-surface",
42
42
  defaultRiskLevel: RiskLevel.Low,
43
43
  executionMode: "proxy",
44
+ executionTarget: "host",
44
45
 
45
- getDefinition(): ToolDefinition {
46
- return {
47
- name: this.name,
48
- description: this.description,
49
- input_schema: {
46
+ input_schema: {
50
47
  type: "object",
51
48
  properties: {
52
49
  surface_type: {
@@ -59,6 +56,7 @@ export const uiShowTool: Tool = {
59
56
  "confirmation",
60
57
  "dynamic_page",
61
58
  "file_upload",
59
+ "task_preferences",
62
60
  ],
63
61
  description: "The type of surface to display",
64
62
  },
@@ -107,8 +105,6 @@ export const uiShowTool: Tool = {
107
105
  },
108
106
  required: ["surface_type", "data"],
109
107
  },
110
- };
111
- },
112
108
 
113
109
  execute: proxyExecute,
114
110
  };
@@ -125,12 +121,9 @@ const uiUpdateTool: Tool = {
125
121
  category: "ui-surface",
126
122
  defaultRiskLevel: RiskLevel.Low,
127
123
  executionMode: "proxy",
124
+ executionTarget: "host",
128
125
 
129
- getDefinition(): ToolDefinition {
130
- return {
131
- name: this.name,
132
- description: this.description,
133
- input_schema: {
126
+ input_schema: {
134
127
  type: "object",
135
128
  properties: {
136
129
  surface_id: {
@@ -144,8 +137,6 @@ const uiUpdateTool: Tool = {
144
137
  },
145
138
  required: ["surface_id", "data"],
146
139
  },
147
- };
148
- },
149
140
 
150
141
  execute: proxyExecute,
151
142
  };
@@ -160,12 +151,9 @@ const uiDismissTool: Tool = {
160
151
  category: "ui-surface",
161
152
  defaultRiskLevel: RiskLevel.Low,
162
153
  executionMode: "proxy",
154
+ executionTarget: "host",
163
155
 
164
- getDefinition(): ToolDefinition {
165
- return {
166
- name: this.name,
167
- description: this.description,
168
- input_schema: {
156
+ input_schema: {
169
157
  type: "object",
170
158
  properties: {
171
159
  surface_id: {
@@ -175,8 +163,6 @@ const uiDismissTool: Tool = {
175
163
  },
176
164
  required: ["surface_id"],
177
165
  },
178
- };
179
- },
180
166
 
181
167
  execute: proxyExecute,
182
168
  };
@@ -4,6 +4,10 @@ export interface OnboardingContext {
4
4
  tone: string;
5
5
  userName?: string;
6
6
  assistantName?: string;
7
+ priorAssistants?: string[];
7
8
  googleConnected?: boolean;
8
9
  googleScopes?: string[];
10
+ cohort?: string;
11
+ websiteUrl?: string;
12
+ contentSourceUrl?: string;
9
13
  }
@@ -20,9 +20,32 @@ function normalizeTokenCount(value: number | null | undefined): number {
20
20
 
21
21
  function asRecord(value: unknown): Record<string, unknown> | null {
22
22
  if (typeof value !== "object" || value == null) return null;
23
+ if (Array.isArray(value)) return null;
23
24
  return value as Record<string, unknown>;
24
25
  }
25
26
 
27
+ /**
28
+ * Extract the provider's untouched `usage` block from a `rawResponse`
29
+ * payload for opaque end-to-end forwarding (the `raw_usage` column /
30
+ * telemetry field).
31
+ *
32
+ * Returns `null` when there is no usage object to surface. For streaming
33
+ * providers that pass `rawResponse` as an accumulated array of chunks,
34
+ * the final element's `usage` is preferred — Anthropic and OpenAI both
35
+ * stamp the complete tally on the terminal chunk, so taking the last
36
+ * element captures the post-completion state without re-aggregating.
37
+ */
38
+ export function extractRawUsage(
39
+ rawResponse: unknown,
40
+ ): Record<string, unknown> | null {
41
+ if (rawResponse == null) return null;
42
+ const candidate = Array.isArray(rawResponse)
43
+ ? rawResponse[rawResponse.length - 1]
44
+ : rawResponse;
45
+ const record = asRecord(candidate);
46
+ return asRecord(record?.usage);
47
+ }
48
+
26
49
  function extractAnthropicCacheCreationFromResponse(
27
50
  response: unknown,
28
51
  ): AnthropicCacheCreationTokenDetails | null {
@@ -42,6 +42,18 @@ export interface UsageEventInput {
42
42
  outputTokens: number;
43
43
  cacheCreationInputTokens: number | null;
44
44
  cacheReadInputTokens: number | null;
45
+ /**
46
+ * The provider's untouched `usage` block (the literal object returned in
47
+ * the API response), preserved as JSON so downstream consumers can
48
+ * extract any provider-specific detail without requiring a schema
49
+ * change. Anthropic nests its TTL breakdown under
50
+ * `cache_creation.ephemeral_{5m,1h}_input_tokens`; OpenAI nests cached
51
+ * read counts under `prompt_tokens_details.cached_tokens`; both shapes
52
+ * are stored as-is. `null` when the provider did not return a usage
53
+ * block and for rows persisted before the
54
+ * `260-llm-usage-add-raw-usage` migration.
55
+ */
56
+ rawUsage: Record<string, unknown> | null;
45
57
  actor: UsageActor;
46
58
  conversationId: string | null;
47
59
  runId: string | null;
@@ -0,0 +1,84 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { faviconUrlForDomain } from "../favicon.js";
4
+
5
+ describe("faviconUrlForDomain", () => {
6
+ test("returns a properly encoded s2 URL for a valid host", () => {
7
+ expect(faviconUrlForDomain("example.com")).toBe(
8
+ "https://www.google.com/s2/favicons?domain=example.com&sz=64",
9
+ );
10
+ });
11
+
12
+ test("lowercases mixed-case hosts before encoding", () => {
13
+ expect(faviconUrlForDomain("Example.COM")).toBe(
14
+ "https://www.google.com/s2/favicons?domain=example.com&sz=64",
15
+ );
16
+ });
17
+
18
+ test("returns undefined for empty input", () => {
19
+ expect(faviconUrlForDomain("")).toBeUndefined();
20
+ });
21
+
22
+ test("returns undefined for whitespace-only input", () => {
23
+ expect(faviconUrlForDomain(" ")).toBeUndefined();
24
+ });
25
+
26
+ test("returns undefined for hosts containing a slash", () => {
27
+ expect(faviconUrlForDomain("example.com/path")).toBeUndefined();
28
+ });
29
+
30
+ test("returns undefined for hosts containing a space", () => {
31
+ expect(faviconUrlForDomain("example .com")).toBeUndefined();
32
+ });
33
+
34
+ test("URL-encodes unicode/IDN hosts", () => {
35
+ // Punycode-style raw unicode host should be percent-encoded by encodeURIComponent.
36
+ const result = faviconUrlForDomain("münchen.de");
37
+ expect(result).toBe(
38
+ `https://www.google.com/s2/favicons?domain=${encodeURIComponent("münchen.de")}&sz=64`,
39
+ );
40
+ // Sanity check: the encoded form contains percent-encoded bytes for "ü".
41
+ expect(result).toContain("m%C3%BCnchen.de");
42
+ });
43
+
44
+ test("returns undefined for localhost", () => {
45
+ expect(faviconUrlForDomain("localhost")).toBeUndefined();
46
+ });
47
+
48
+ test("returns undefined for private IPv4 hosts", () => {
49
+ expect(faviconUrlForDomain("127.0.0.1")).toBeUndefined();
50
+ expect(faviconUrlForDomain("10.0.0.5")).toBeUndefined();
51
+ expect(faviconUrlForDomain("192.168.1.1")).toBeUndefined();
52
+ });
53
+
54
+ test("returns undefined for any raw IPv4 literal — private or public", () => {
55
+ // We can't tell from the host alone whether an IP belongs to a routable
56
+ // public host or an internal one, so all IP literals are rejected to avoid
57
+ // leaking the address to Google when the client renders the icon.
58
+ expect(faviconUrlForDomain("172.16.0.1")).toBeUndefined();
59
+ expect(faviconUrlForDomain("8.8.8.8")).toBeUndefined();
60
+ expect(faviconUrlForDomain("1.1.1.1")).toBeUndefined();
61
+ });
62
+
63
+ test("returns undefined for raw IPv6 literals (bracketed or bare)", () => {
64
+ expect(faviconUrlForDomain("2001:db8::1")).toBeUndefined();
65
+ expect(faviconUrlForDomain("[2001:db8::1]")).toBeUndefined();
66
+ });
67
+
68
+ test("strips :port before the private-host check (host:port → undefined for private)", () => {
69
+ expect(faviconUrlForDomain("localhost:3000")).toBeUndefined();
70
+ expect(faviconUrlForDomain("127.0.0.1:8080")).toBeUndefined();
71
+ expect(faviconUrlForDomain("192.168.1.1:443")).toBeUndefined();
72
+ });
73
+
74
+ test("strips :port and encodes only the host (public host with port)", () => {
75
+ const result = faviconUrlForDomain("example.com:8080");
76
+ expect(result).toBe(
77
+ "https://www.google.com/s2/favicons?domain=example.com&sz=64",
78
+ );
79
+ });
80
+
81
+ test("handles bracketed IPv6 hosts with ports", () => {
82
+ expect(faviconUrlForDomain("[::1]:8080")).toBeUndefined();
83
+ });
84
+ });