@vellumai/assistant 0.6.4 → 0.6.6

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 (1008) hide show
  1. package/.prettierignore +5 -0
  2. package/AGENTS.md +9 -1
  3. package/ARCHITECTURE.md +43 -49
  4. package/Dockerfile +17 -3
  5. package/README.md +3 -4
  6. package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
  7. package/bun.lock +8 -3
  8. package/docs/architecture/integrations.md +33 -59
  9. package/docs/architecture/memory.md +25 -30
  10. package/docs/architecture/security.md +19 -18
  11. package/docs/browser-use-architecture-phase2.md +63 -20
  12. package/docs/error-handling.md +111 -0
  13. package/docs/plugins.md +761 -0
  14. package/docs/skills.md +10 -10
  15. package/docs/stt-provider-onboarding.md +2 -1
  16. package/examples/plugins/echo/README.md +132 -0
  17. package/examples/plugins/echo/package.json +17 -0
  18. package/examples/plugins/echo/register.ts +187 -0
  19. package/knip.json +9 -2
  20. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  21. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  22. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  23. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  24. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  25. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  26. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  27. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  28. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  29. package/openapi.yaml +334 -78
  30. package/package.json +6 -3
  31. package/scripts/generate-openapi.ts +50 -11
  32. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  33. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  34. package/src/__tests__/agent-loop.test.ts +112 -1
  35. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  36. package/src/__tests__/anthropic-provider.test.ts +171 -2
  37. package/src/__tests__/app-compiler.test.ts +57 -0
  38. package/src/__tests__/approval-cascade.test.ts +36 -10
  39. package/src/__tests__/approval-routes-http.test.ts +134 -10
  40. package/src/__tests__/assistant-attachments.test.ts +44 -0
  41. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  42. package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
  43. package/src/__tests__/avatar-generator.test.ts +4 -2
  44. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  45. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  46. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  47. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  48. package/src/__tests__/btw-routes.test.ts +47 -1
  49. package/src/__tests__/bundled-asset.test.ts +6 -6
  50. package/src/__tests__/call-controller.test.ts +1 -2
  51. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  52. package/src/__tests__/catalog-cache.test.ts +96 -4
  53. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  54. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  55. package/src/__tests__/checker.test.ts +870 -655
  56. package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
  57. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  58. package/src/__tests__/compaction-events.test.ts +501 -0
  59. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  60. package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
  61. package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
  62. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  63. package/src/__tests__/config-analysis.test.ts +11 -28
  64. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  65. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  66. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  67. package/src/__tests__/config-model-image-provider.test.ts +110 -0
  68. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  69. package/src/__tests__/config-schema.test.ts +440 -114
  70. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
  71. package/src/__tests__/config-watcher.test.ts +2 -2
  72. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  73. package/src/__tests__/contacts-tools.test.ts +26 -0
  74. package/src/__tests__/contacts-write.test.ts +4 -4
  75. package/src/__tests__/context-overflow-policy.test.ts +7 -7
  76. package/src/__tests__/context-token-estimator.test.ts +191 -1
  77. package/src/__tests__/context-window-manager.test.ts +883 -4
  78. package/src/__tests__/conversation-abort-tool-results.test.ts +32 -15
  79. package/src/__tests__/conversation-agent-loop-overflow.test.ts +86 -46
  80. package/src/__tests__/conversation-agent-loop.test.ts +435 -216
  81. package/src/__tests__/conversation-attachments.test.ts +1 -1
  82. package/src/__tests__/conversation-confirmation-signals.test.ts +36 -10
  83. package/src/__tests__/conversation-error.test.ts +37 -6
  84. package/src/__tests__/conversation-history-web-search.test.ts +7 -0
  85. package/src/__tests__/conversation-init.benchmark.test.ts +34 -12
  86. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  87. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  88. package/src/__tests__/conversation-pairing.test.ts +174 -10
  89. package/src/__tests__/conversation-pre-run-repair.test.ts +32 -15
  90. package/src/__tests__/conversation-process-callsite.test.ts +309 -0
  91. package/src/__tests__/conversation-provider-retry-repair.test.ts +44 -21
  92. package/src/__tests__/conversation-queue.test.ts +68 -38
  93. package/src/__tests__/conversation-routes-disk-view.test.ts +36 -7
  94. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  95. package/src/__tests__/conversation-runtime-assembly.test.ts +2877 -152
  96. package/src/__tests__/conversation-runtime-workspace.test.ts +35 -50
  97. package/src/__tests__/conversation-seed-composer.test.ts +2 -2
  98. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  99. package/src/__tests__/conversation-slash-queue.test.ts +39 -19
  100. package/src/__tests__/conversation-slash-unknown.test.ts +53 -16
  101. package/src/__tests__/conversation-speed-override.test.ts +36 -12
  102. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  103. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  104. package/src/__tests__/conversation-title-service.test.ts +118 -2
  105. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
  106. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  107. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  108. package/src/__tests__/conversation-usage.test.ts +4 -2
  109. package/src/__tests__/conversation-workspace-cache-state.test.ts +33 -9
  110. package/src/__tests__/conversation-workspace-injection.test.ts +46 -15
  111. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -15
  112. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  113. package/src/__tests__/credential-health-service.test.ts +78 -9
  114. package/src/__tests__/credential-security-invariants.test.ts +5 -2
  115. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  116. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  117. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  118. package/src/__tests__/credentials-cli.test.ts +1 -9
  119. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  120. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  121. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  122. package/src/__tests__/delete-propagation.test.ts +437 -0
  123. package/src/__tests__/dm-backfill.test.ts +417 -0
  124. package/src/__tests__/dm-persistence.test.ts +227 -0
  125. package/src/__tests__/edit-propagation.test.ts +280 -0
  126. package/src/__tests__/empty-response-pipeline.test.ts +305 -0
  127. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  128. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  129. package/src/__tests__/estimator-calibration.test.ts +213 -0
  130. package/src/__tests__/extension-id-sync-guard.test.ts +29 -10
  131. package/src/__tests__/file-write-tool.test.ts +151 -1
  132. package/src/__tests__/filing-service.test.ts +255 -0
  133. package/src/__tests__/first-greeting.test.ts +247 -5
  134. package/src/__tests__/gemini-provider.test.ts +0 -3
  135. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  136. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  137. package/src/__tests__/headless-browser-mode.test.ts +57 -0
  138. package/src/__tests__/heartbeat-service.test.ts +96 -15
  139. package/src/__tests__/history-repair-pipeline.test.ts +399 -0
  140. package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
  141. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
  142. package/src/__tests__/host-proxy-interface.test.ts +36 -2
  143. package/src/__tests__/host-shell-tool.test.ts +124 -18
  144. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  145. package/src/__tests__/image-credentials.test.ts +137 -0
  146. package/src/__tests__/image-service-dispatcher.test.ts +186 -0
  147. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  148. package/src/__tests__/injector-chain.test.ts +526 -0
  149. package/src/__tests__/intent-routing.test.ts +1 -66
  150. package/src/__tests__/llm-call-pipeline.test.ts +285 -0
  151. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  152. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  153. package/src/__tests__/llm-resolver.test.ts +214 -0
  154. package/src/__tests__/llm-schema.test.ts +223 -0
  155. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  156. package/src/__tests__/media-generate-image.test.ts +119 -13
  157. package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
  158. package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
  159. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  160. package/src/__tests__/migration-import-from-url.test.ts +621 -0
  161. package/src/__tests__/model-intents.test.ts +11 -83
  162. package/src/__tests__/notification-broadcaster.test.ts +3 -3
  163. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  164. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  165. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  166. package/src/__tests__/notification-decision-strategy.test.ts +0 -11
  167. package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
  168. package/src/__tests__/oauth-apps-routes.test.ts +1 -1
  169. package/src/__tests__/oauth-cli.test.ts +14 -12
  170. package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
  171. package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
  172. package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
  173. package/src/__tests__/oauth-providers-routes.test.ts +3 -2
  174. package/src/__tests__/oauth-store.test.ts +46 -78
  175. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  176. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  177. package/src/__tests__/onboarding-template-contract.test.ts +16 -64
  178. package/src/__tests__/openai-image-service.test.ts +368 -0
  179. package/src/__tests__/openai-provider.test.ts +7 -0
  180. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  181. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  182. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  183. package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
  184. package/src/__tests__/permission-checker-host-gate.test.ts +1 -25
  185. package/src/__tests__/permission-mode.test.ts +16 -0
  186. package/src/__tests__/permission-types.test.ts +0 -1
  187. package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
  188. package/src/__tests__/persistence-pipeline.test.ts +377 -0
  189. package/src/__tests__/persona-resolver.test.ts +13 -13
  190. package/src/__tests__/pipeline-runner.test.ts +565 -0
  191. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  192. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  193. package/src/__tests__/platform.test.ts +5 -2
  194. package/src/__tests__/plugin-bootstrap.test.ts +483 -0
  195. package/src/__tests__/plugin-registry.test.ts +273 -0
  196. package/src/__tests__/plugin-route-contribution.test.ts +288 -0
  197. package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
  198. package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
  199. package/src/__tests__/plugin-types.test.ts +320 -0
  200. package/src/__tests__/pricing.test.ts +93 -14
  201. package/src/__tests__/profiler-routes.test.ts +1 -1
  202. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  203. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  204. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  205. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  206. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  207. package/src/__tests__/proxy-approval-callback.test.ts +69 -9
  208. package/src/__tests__/reaction-persistence.test.ts +561 -0
  209. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  210. package/src/__tests__/registry.test.ts +0 -2
  211. package/src/__tests__/relay-server.test.ts +1 -1
  212. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  213. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  214. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  215. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  216. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  217. package/src/__tests__/schedule-routes.test.ts +131 -1
  218. package/src/__tests__/scheduler-recurrence.test.ts +14 -70
  219. package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
  220. package/src/__tests__/secret-detection-handler.test.ts +0 -10
  221. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  222. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  223. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  224. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  225. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  226. package/src/__tests__/server-history-render.test.ts +31 -0
  227. package/src/__tests__/shell-identity.test.ts +0 -134
  228. package/src/__tests__/shell-parser-property.test.ts +13 -13
  229. package/src/__tests__/skill-cache-store.test.ts +182 -0
  230. package/src/__tests__/skills.test.ts +19 -33
  231. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  232. package/src/__tests__/slack-skill.test.ts +3 -8
  233. package/src/__tests__/starter-bundle.test.ts +35 -0
  234. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  235. package/src/__tests__/suggestion-routes.test.ts +259 -3
  236. package/src/__tests__/system-prompt.test.ts +22 -35
  237. package/src/__tests__/task-memory-cleanup.test.ts +1 -0
  238. package/src/__tests__/task-runner.test.ts +3 -1
  239. package/src/__tests__/task-scheduler.test.ts +3 -15
  240. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  241. package/src/__tests__/terminal-tools.test.ts +8 -0
  242. package/src/__tests__/test-preload.ts +11 -0
  243. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  244. package/src/__tests__/thread-backfill.test.ts +941 -0
  245. package/src/__tests__/title-generate-pipeline.test.ts +224 -0
  246. package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
  247. package/src/__tests__/tool-error-pipeline.test.ts +244 -0
  248. package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
  249. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -8
  250. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  251. package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
  252. package/src/__tests__/tool-executor.test.ts +201 -94
  253. package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
  254. package/src/__tests__/tool-result-truncation.test.ts +0 -110
  255. package/src/__tests__/trust-store.test.ts +442 -109
  256. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  257. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  258. package/src/__tests__/user-plugin-loader.test.ts +191 -0
  259. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  260. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  261. package/src/__tests__/volume-security-guard.test.ts +3 -2
  262. package/src/__tests__/web-search-history.test.ts +337 -0
  263. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  264. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  265. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  266. package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
  267. package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
  268. package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
  269. package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
  270. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  271. package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
  272. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  273. package/src/__tests__/workspace-policy.test.ts +22 -16
  274. package/src/acp/client-handler.ts +1 -2
  275. package/src/agent/loop.ts +545 -115
  276. package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
  277. package/src/approvals/guardian-request-resolvers.ts +80 -0
  278. package/src/avatar/resvg-lazy.test.ts +136 -0
  279. package/src/avatar/resvg-lazy.ts +82 -9
  280. package/src/avatar/traits-png-sync.ts +21 -1
  281. package/src/backup/__tests__/backup-worker.test.ts +2 -13
  282. package/src/backup/backup-worker.ts +3 -15
  283. package/src/browser/__tests__/operations.test.ts +163 -0
  284. package/src/browser/identifiers.ts +51 -0
  285. package/src/browser/operations.ts +660 -0
  286. package/src/browser/types.ts +81 -0
  287. package/src/bundler/app-compiler.ts +84 -1
  288. package/src/calls/call-state.ts +2 -2
  289. package/src/calls/guardian-question-copy.ts +2 -2
  290. package/src/calls/telephony-stt-routing.ts +1 -1
  291. package/src/calls/voice-session-bridge.ts +1 -0
  292. package/src/channels/__tests__/types.test.ts +3 -3
  293. package/src/channels/types.ts +6 -4
  294. package/src/cli/AGENTS.md +1 -1
  295. package/src/cli/__tests__/notifications.test.ts +87 -211
  296. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  297. package/src/cli/commands/__tests__/backup.test.ts +1 -1
  298. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  299. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  300. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  301. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  302. package/src/cli/commands/__tests__/image-generation.test.ts +886 -0
  303. package/src/cli/commands/__tests__/inference-send.test.ts +463 -0
  304. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  305. package/src/cli/commands/__tests__/task.test.ts +913 -0
  306. package/src/cli/commands/__tests__/tts-synthesize.test.ts +606 -0
  307. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  308. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  309. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  310. package/src/cli/commands/attachment.ts +182 -0
  311. package/src/cli/commands/backup.ts +2 -2
  312. package/src/cli/commands/browser.ts +350 -0
  313. package/src/cli/commands/cache.ts +341 -0
  314. package/src/cli/commands/clients.ts +138 -0
  315. package/src/cli/commands/completions.ts +2 -12
  316. package/src/cli/commands/config.ts +6 -6
  317. package/src/cli/commands/conversations-import.ts +347 -0
  318. package/src/cli/commands/conversations.ts +69 -8
  319. package/src/cli/commands/email.ts +234 -194
  320. package/src/cli/commands/image-generation.ts +299 -0
  321. package/src/cli/commands/inference.ts +200 -0
  322. package/src/cli/commands/memory.ts +127 -17
  323. package/src/cli/commands/notifications.ts +68 -103
  324. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
  325. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  326. package/src/cli/commands/oauth/connect.ts +2 -2
  327. package/src/cli/commands/oauth/providers.ts +176 -8
  328. package/src/cli/commands/oauth/status.ts +46 -36
  329. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  330. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  331. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  332. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  333. package/src/cli/commands/skills.ts +3 -4
  334. package/src/cli/commands/stt.ts +339 -0
  335. package/src/cli/commands/task.ts +795 -0
  336. package/src/cli/commands/trust.ts +50 -19
  337. package/src/cli/commands/tts.ts +273 -0
  338. package/src/cli/commands/ui.ts +670 -0
  339. package/src/cli/commands/watchers.ts +509 -0
  340. package/src/cli/lib/daemon-credential-client.ts +0 -19
  341. package/src/cli/program.ts +39 -24
  342. package/src/cli.ts +0 -37
  343. package/src/config/__tests__/backup-schema.test.ts +7 -2
  344. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  345. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
  346. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
  347. package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
  348. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
  349. package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
  350. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
  351. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
  352. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  353. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  354. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  355. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
  356. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +20 -1
  357. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  358. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  359. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +69 -12
  360. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  361. package/src/config/bundled-skills/schedule/SKILL.md +8 -3
  362. package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
  363. package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
  364. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  365. package/src/config/bundled-tool-registry.ts +0 -190
  366. package/src/config/env.ts +7 -2
  367. package/src/config/feature-flag-registry.json +42 -10
  368. package/src/config/llm-resolver.ts +128 -0
  369. package/src/config/loader.ts +194 -10
  370. package/src/config/raw-config-utils.ts +30 -2
  371. package/src/config/sanitize-for-transfer.ts +35 -0
  372. package/src/config/schema.ts +49 -41
  373. package/src/config/schemas/analysis.ts +3 -22
  374. package/src/config/schemas/backup.ts +1 -1
  375. package/src/config/schemas/calls.ts +0 -4
  376. package/src/config/schemas/conversations.ts +16 -0
  377. package/src/config/schemas/filing.ts +2 -7
  378. package/src/config/schemas/heartbeat.ts +0 -5
  379. package/src/config/schemas/inference.ts +3 -23
  380. package/src/config/schemas/llm.ts +317 -0
  381. package/src/config/schemas/memory-processing.ts +1 -9
  382. package/src/config/schemas/notifications.ts +4 -11
  383. package/src/config/schemas/platform.ts +3 -9
  384. package/src/config/schemas/security.ts +33 -0
  385. package/src/config/schemas/services.ts +9 -4
  386. package/src/config/schemas/stt.ts +1 -0
  387. package/src/config/schemas/tts.ts +64 -0
  388. package/src/config/schemas/updates.ts +1 -1
  389. package/src/config/schemas/workspace-git.ts +3 -40
  390. package/src/config/skill-state.ts +6 -2
  391. package/src/config/skills.ts +96 -7
  392. package/src/context/__tests__/compact-prompt.test.ts +63 -0
  393. package/src/context/__tests__/microcompact.test.ts +805 -0
  394. package/src/context/estimator-calibration.ts +136 -0
  395. package/src/context/microcompact.ts +443 -0
  396. package/src/context/prompts/compact.md +26 -0
  397. package/src/context/token-estimator.ts +61 -3
  398. package/src/context/tool-result-truncation.ts +3 -63
  399. package/src/context/window-manager.ts +417 -39
  400. package/src/credential-execution/approval-bridge.ts +0 -1
  401. package/src/credential-execution/executable-discovery.ts +19 -8
  402. package/src/credential-execution/process-manager.test.ts +109 -0
  403. package/src/credential-execution/process-manager.ts +65 -2
  404. package/src/credential-health/credential-health-service.ts +19 -6
  405. package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
  406. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
  407. package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
  408. package/src/daemon/approval-generators.ts +29 -4
  409. package/src/daemon/assistant-attachments.ts +24 -13
  410. package/src/daemon/classifier.ts +2 -2
  411. package/src/daemon/config-watcher.ts +0 -3
  412. package/src/daemon/context-overflow-policy.ts +4 -13
  413. package/src/daemon/context-overflow-reducer.ts +4 -1
  414. package/src/daemon/conversation-agent-loop-handlers.ts +162 -34
  415. package/src/daemon/conversation-agent-loop.ts +1282 -599
  416. package/src/daemon/conversation-attachments.ts +2 -6
  417. package/src/daemon/conversation-error.ts +36 -1
  418. package/src/daemon/conversation-history.ts +10 -19
  419. package/src/daemon/conversation-lifecycle.ts +59 -17
  420. package/src/daemon/conversation-messaging.ts +73 -4
  421. package/src/daemon/conversation-notifiers.ts +2 -110
  422. package/src/daemon/conversation-process.ts +24 -11
  423. package/src/daemon/conversation-queue-manager.ts +3 -0
  424. package/src/daemon/conversation-runtime-assembly.ts +1063 -211
  425. package/src/daemon/conversation-slash.ts +2 -2
  426. package/src/daemon/conversation-surfaces.ts +389 -1
  427. package/src/daemon/conversation-tool-setup.ts +51 -9
  428. package/src/daemon/conversation-usage.ts +1 -1
  429. package/src/daemon/conversation.ts +197 -64
  430. package/src/daemon/external-plugins-bootstrap.ts +478 -0
  431. package/src/daemon/external-skills-bootstrap.ts +41 -0
  432. package/src/daemon/first-greeting.ts +191 -14
  433. package/src/daemon/guardian-action-generators.ts +34 -14
  434. package/src/daemon/handlers/config-model.test.ts +86 -0
  435. package/src/daemon/handlers/config-model.ts +65 -12
  436. package/src/daemon/handlers/conversations.ts +9 -2
  437. package/src/daemon/handlers/shared.ts +39 -11
  438. package/src/daemon/handlers/skills.ts +7 -3
  439. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  440. package/src/daemon/lifecycle.ts +109 -82
  441. package/src/daemon/message-types/computer-use.ts +2 -34
  442. package/src/daemon/message-types/conversations.ts +63 -0
  443. package/src/daemon/message-types/messages.ts +21 -1
  444. package/src/daemon/message-types/trust.ts +0 -2
  445. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  446. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  447. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  448. package/src/daemon/pkb-context-tracker.ts +125 -0
  449. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  450. package/src/daemon/pkb-reminder-builder.ts +31 -0
  451. package/src/daemon/providers-setup.ts +6 -0
  452. package/src/daemon/server.ts +122 -12
  453. package/src/daemon/shutdown-handlers.ts +2 -12
  454. package/src/daemon/tool-side-effects.ts +14 -65
  455. package/src/daemon/web-search-history.ts +126 -0
  456. package/src/events/domain-events.ts +0 -1
  457. package/src/filing/filing-service.ts +9 -10
  458. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
  459. package/src/heartbeat/heartbeat-service.ts +99 -28
  460. package/src/home/__tests__/feed-population-integration.test.ts +312 -0
  461. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  462. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  463. package/src/home/assistant-feed-authoring.ts +4 -0
  464. package/src/home/emit-feed-event.ts +11 -0
  465. package/src/home/feed-scheduler.ts +20 -4
  466. package/src/home/feed-types.ts +97 -4
  467. package/src/home/relationship-state-writer.ts +2 -2
  468. package/src/home/rewrite-command-preview.ts +66 -0
  469. package/src/home/rollup-producer.ts +34 -5
  470. package/src/home/suggested-prompts.ts +101 -0
  471. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  472. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  473. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  474. package/src/ipc/__tests__/socket-path.test.ts +34 -0
  475. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  476. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  477. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  478. package/src/ipc/cli-client.ts +2 -1
  479. package/src/ipc/cli-server.ts +26 -8
  480. package/src/ipc/gateway-client.ts +6 -3
  481. package/src/ipc/routes/attachment.ts +114 -0
  482. package/src/ipc/routes/browser-context.ts +63 -0
  483. package/src/ipc/routes/browser.ts +97 -0
  484. package/src/ipc/routes/cache.ts +96 -0
  485. package/src/ipc/routes/get-contact.ts +16 -0
  486. package/src/ipc/routes/index.ts +31 -1
  487. package/src/ipc/routes/list-clients.ts +31 -0
  488. package/src/ipc/routes/merge-contacts.ts +17 -0
  489. package/src/ipc/routes/notification.ts +133 -0
  490. package/src/ipc/routes/rename-conversation.ts +59 -0
  491. package/src/ipc/routes/search-contacts.ts +19 -0
  492. package/src/ipc/routes/task-queue.ts +226 -0
  493. package/src/ipc/routes/task.ts +173 -0
  494. package/src/ipc/routes/ui-request.ts +50 -0
  495. package/src/ipc/routes/upsert-contact.ts +25 -0
  496. package/src/ipc/routes/watcher.ts +203 -0
  497. package/src/ipc/socket-path.ts +76 -0
  498. package/src/media/app-icon-generator.ts +23 -46
  499. package/src/media/avatar-router.ts +26 -41
  500. package/src/media/gemini-image-service.ts +8 -41
  501. package/src/media/image-credentials.ts +73 -0
  502. package/src/media/image-service.ts +85 -0
  503. package/src/media/openai-image-service.ts +131 -0
  504. package/src/media/types.ts +46 -0
  505. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  506. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  507. package/src/memory/admin.ts +18 -0
  508. package/src/memory/conversation-analyze-job.ts +14 -13
  509. package/src/memory/conversation-attention-store.ts +13 -6
  510. package/src/memory/conversation-crud.ts +133 -3
  511. package/src/memory/conversation-group-migration.ts +38 -6
  512. package/src/memory/conversation-queries.ts +57 -4
  513. package/src/memory/conversation-title-service.ts +32 -4
  514. package/src/memory/db-init.ts +10 -0
  515. package/src/memory/embedding-backend.ts +1 -1
  516. package/src/memory/embedding-gemini.test.ts +41 -2
  517. package/src/memory/embedding-gemini.ts +6 -1
  518. package/src/memory/graph/bootstrap.test.ts +282 -0
  519. package/src/memory/graph/bootstrap.ts +8 -5
  520. package/src/memory/graph/compaction.ts +299 -0
  521. package/src/memory/graph/consolidation.ts +4 -4
  522. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  523. package/src/memory/graph/extraction.test.ts +272 -2
  524. package/src/memory/graph/extraction.ts +183 -53
  525. package/src/memory/graph/graph-search.test.ts +93 -0
  526. package/src/memory/graph/graph-search.ts +4 -1
  527. package/src/memory/graph/inspect.ts +2 -2
  528. package/src/memory/graph/narrative.ts +2 -2
  529. package/src/memory/graph/pattern-scan.ts +2 -2
  530. package/src/memory/graph/retriever.test.ts +459 -0
  531. package/src/memory/graph/retriever.ts +237 -48
  532. package/src/memory/graph/store.ts +41 -0
  533. package/src/memory/graph/tool-handlers.ts +27 -0
  534. package/src/memory/graph/tools.ts +6 -1
  535. package/src/memory/indexer.ts +5 -5
  536. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  537. package/src/memory/job-handlers/summarization.ts +2 -2
  538. package/src/memory/job-utils.ts +7 -1
  539. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  540. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  541. package/src/memory/jobs-store.ts +44 -3
  542. package/src/memory/jobs-worker.ts +4 -0
  543. package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
  544. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  545. package/src/memory/migrations/149-oauth-tables.ts +1 -0
  546. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  547. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  548. package/src/memory/migrations/223-schedule-script-column.ts +11 -0
  549. package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
  550. package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
  551. package/src/memory/migrations/index.ts +5 -0
  552. package/src/memory/pkb/pkb-index.test.ts +369 -0
  553. package/src/memory/pkb/pkb-index.ts +255 -0
  554. package/src/memory/pkb/pkb-reconcile.test.ts +252 -0
  555. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  556. package/src/memory/pkb/pkb-search.test.ts +499 -0
  557. package/src/memory/pkb/pkb-search.ts +159 -0
  558. package/src/memory/pkb/types.ts +53 -0
  559. package/src/memory/qdrant-client.test.ts +60 -0
  560. package/src/memory/qdrant-client.ts +147 -1
  561. package/src/memory/schema/infrastructure.ts +1 -0
  562. package/src/memory/schema/oauth.ts +4 -1
  563. package/src/memory/slack-thread-store.ts +37 -0
  564. package/src/messaging/providers/gmail/adapter.ts +6 -16
  565. package/src/messaging/providers/gmail/client.ts +22 -0
  566. package/src/messaging/providers/gmail/types.ts +7 -0
  567. package/src/messaging/providers/slack/adapter.ts +14 -2
  568. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  569. package/src/messaging/providers/slack/backfill.ts +101 -0
  570. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  571. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  572. package/src/messaging/providers/slack/render-transcript.test.ts +1421 -0
  573. package/src/messaging/providers/slack/render-transcript.ts +501 -0
  574. package/src/messaging/style-analyzer.ts +5 -2
  575. package/src/notifications/README.md +9 -5
  576. package/src/notifications/conversation-pairing.ts +78 -19
  577. package/src/notifications/copy-composer.ts +0 -5
  578. package/src/notifications/decision-engine.ts +3 -9
  579. package/src/notifications/emit-signal.ts +1 -1
  580. package/src/notifications/preference-extractor.ts +2 -6
  581. package/src/notifications/signal.ts +1 -2
  582. package/src/oauth/AGENTS.md +1 -1
  583. package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
  584. package/src/oauth/connect-orchestrator.ts +8 -34
  585. package/src/oauth/connect-types.ts +6 -10
  586. package/src/oauth/manual-token-connection.ts +23 -0
  587. package/src/oauth/oauth-store.ts +31 -14
  588. package/src/oauth/platform-connection.test.ts +47 -0
  589. package/src/oauth/platform-connection.ts +15 -5
  590. package/src/oauth/provider-serializer.ts +6 -1
  591. package/src/oauth/seed-providers.ts +56 -106
  592. package/src/outbound-proxy/http-forwarder.ts +9 -0
  593. package/src/permissions/approval-policy.test.ts +1223 -0
  594. package/src/permissions/approval-policy.ts +309 -0
  595. package/src/permissions/arg-parser.test.ts +161 -0
  596. package/src/permissions/arg-parser.ts +141 -0
  597. package/src/permissions/bash-risk-classifier.test.ts +1620 -0
  598. package/src/permissions/bash-risk-classifier.ts +950 -0
  599. package/src/permissions/checker.ts +348 -711
  600. package/src/permissions/command-registry.test.ts +774 -0
  601. package/src/permissions/command-registry.ts +1005 -0
  602. package/src/permissions/defaults.ts +28 -79
  603. package/src/permissions/file-risk-classifier.test.ts +535 -0
  604. package/src/permissions/file-risk-classifier.ts +274 -0
  605. package/src/permissions/gateway-threshold-reader.ts +196 -0
  606. package/src/permissions/prompter.ts +4 -0
  607. package/src/permissions/risk-types.ts +262 -0
  608. package/src/permissions/schedule-risk-classifier.test.ts +129 -0
  609. package/src/permissions/schedule-risk-classifier.ts +85 -0
  610. package/src/permissions/secret-prompter.ts +53 -2
  611. package/src/permissions/shell-identity.ts +2 -42
  612. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  613. package/src/permissions/skill-risk-classifier.ts +214 -0
  614. package/src/permissions/trust-client.ts +52 -25
  615. package/src/permissions/trust-store-interface.ts +1 -6
  616. package/src/permissions/trust-store.ts +161 -62
  617. package/src/permissions/types.ts +25 -14
  618. package/src/permissions/web-risk-classifier.test.ts +170 -0
  619. package/src/permissions/web-risk-classifier.ts +89 -0
  620. package/src/permissions/workspace-policy.ts +9 -19
  621. package/src/platform/client.ts +19 -1
  622. package/src/plugins/defaults/circuit-breaker.ts +146 -0
  623. package/src/plugins/defaults/compaction.ts +145 -0
  624. package/src/plugins/defaults/empty-response.ts +126 -0
  625. package/src/plugins/defaults/history-repair.ts +85 -0
  626. package/src/plugins/defaults/index.ts +116 -0
  627. package/src/plugins/defaults/injectors.ts +491 -0
  628. package/src/plugins/defaults/llm-call.ts +82 -0
  629. package/src/plugins/defaults/memory-retrieval.ts +226 -0
  630. package/src/plugins/defaults/overflow-reduce.ts +181 -0
  631. package/src/plugins/defaults/persistence.ts +129 -0
  632. package/src/plugins/defaults/title-generate.ts +95 -0
  633. package/src/plugins/defaults/token-estimate.ts +104 -0
  634. package/src/plugins/defaults/tool-error.ts +126 -0
  635. package/src/plugins/defaults/tool-execute.ts +89 -0
  636. package/src/plugins/defaults/tool-result-truncate.ts +88 -0
  637. package/src/plugins/pipeline.ts +316 -0
  638. package/src/plugins/plugin-skill-contributions.ts +292 -0
  639. package/src/plugins/registry.ts +241 -0
  640. package/src/plugins/types.ts +1134 -0
  641. package/src/plugins/user-loader.ts +177 -0
  642. package/src/prompts/persona-resolver.ts +3 -3
  643. package/src/prompts/system-prompt.ts +19 -20
  644. package/src/prompts/templates/BOOTSTRAP.md +27 -77
  645. package/src/prompts/templates/SOUL.md +2 -2
  646. package/src/prompts/update-bulletin-job.ts +190 -0
  647. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  648. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  649. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  650. package/src/providers/anthropic/client.ts +183 -14
  651. package/src/providers/call-site-routing.ts +71 -0
  652. package/src/providers/gemini/client.ts +65 -2
  653. package/src/providers/managed-proxy/constants.ts +2 -1
  654. package/src/providers/model-catalog.ts +524 -33
  655. package/src/providers/model-intents.ts +4 -4
  656. package/src/providers/openai/chat-completions-provider.ts +57 -1
  657. package/src/providers/openai/responses-provider.ts +86 -9
  658. package/src/providers/openrouter/client.ts +80 -9
  659. package/src/providers/provider-env-vars.ts +56 -0
  660. package/src/providers/provider-send-message.ts +22 -5
  661. package/src/providers/ratelimit.ts +4 -0
  662. package/src/providers/registry.ts +19 -8
  663. package/src/providers/retry.ts +174 -39
  664. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  665. package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
  666. package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
  667. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  668. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  669. package/src/providers/speech-to-text/resolve.ts +7 -0
  670. package/src/providers/speech-to-text/xai-realtime.test.ts +646 -0
  671. package/src/providers/speech-to-text/xai-realtime.ts +821 -0
  672. package/src/providers/speech-to-text/xai.test.ts +155 -0
  673. package/src/providers/speech-to-text/xai.ts +97 -0
  674. package/src/providers/types.ts +93 -3
  675. package/src/runtime/AGENTS.md +27 -18
  676. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  677. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
  678. package/src/runtime/__tests__/client-registry.test.ts +293 -0
  679. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  680. package/src/runtime/agent-wake.ts +63 -22
  681. package/src/runtime/auth/route-policy.ts +4 -0
  682. package/src/runtime/btw-sidechain.ts +13 -3
  683. package/src/runtime/channel-reply-delivery.ts +106 -2
  684. package/src/runtime/client-registry.ts +261 -0
  685. package/src/runtime/decision-token.ts +116 -0
  686. package/src/runtime/gateway-client.ts +2 -2
  687. package/src/runtime/http-router.ts +32 -0
  688. package/src/runtime/http-server.ts +129 -9
  689. package/src/runtime/http-types.ts +23 -3
  690. package/src/runtime/interactive-ui.ts +362 -0
  691. package/src/runtime/invite-instruction-generator.ts +2 -2
  692. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  693. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  694. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  695. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  696. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  697. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  698. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  699. package/src/runtime/migrations/vbundle-builder.ts +1 -22
  700. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  701. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  702. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  703. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  704. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  705. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  706. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  707. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  708. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  709. package/src/runtime/routes/approval-prompt-ts-tracker.ts +78 -0
  710. package/src/runtime/routes/approval-routes.ts +29 -17
  711. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  712. package/src/runtime/routes/avatar-routes.ts +20 -4
  713. package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
  714. package/src/runtime/routes/btw-routes.ts +1 -4
  715. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  716. package/src/runtime/routes/conversation-routes.ts +351 -138
  717. package/src/runtime/routes/debug-routes.ts +1 -1
  718. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  719. package/src/runtime/routes/events-routes.ts +16 -0
  720. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  721. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  722. package/src/runtime/routes/home-feed-routes.ts +120 -2
  723. package/src/runtime/routes/inbound-message-handler.ts +987 -2
  724. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  725. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  726. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  727. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  728. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  729. package/src/runtime/routes/memory-item-routes.test.ts +1 -0
  730. package/src/runtime/routes/migration-routes.ts +720 -127
  731. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
  732. package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
  733. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
  734. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
  735. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
  736. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
  737. package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
  738. package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
  739. package/src/runtime/routes/playground/deps.ts +56 -0
  740. package/src/runtime/routes/playground/force-compact.ts +73 -0
  741. package/src/runtime/routes/playground/guard.ts +37 -0
  742. package/src/runtime/routes/playground/index.ts +28 -0
  743. package/src/runtime/routes/playground/inject-failures.ts +159 -0
  744. package/src/runtime/routes/playground/reset-circuit.ts +115 -0
  745. package/src/runtime/routes/playground/seed-conversation.ts +139 -0
  746. package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
  747. package/src/runtime/routes/playground/state.ts +78 -0
  748. package/src/runtime/routes/schedule-routes.ts +89 -8
  749. package/src/runtime/routes/settings-routes.ts +4 -2
  750. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  751. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  752. package/src/runtime/routes/work-items-routes.ts +3 -2
  753. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  754. package/src/runtime/services/analyze-conversation.ts +12 -16
  755. package/src/runtime/skill-route-registry.ts +97 -15
  756. package/src/schedule/run-script.ts +68 -0
  757. package/src/schedule/schedule-store.ts +7 -1
  758. package/src/schedule/scheduler.ts +56 -8
  759. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  760. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  761. package/src/security/oauth2.ts +98 -35
  762. package/src/security/secure-keys.ts +7 -8
  763. package/src/security/token-manager.ts +27 -13
  764. package/src/security/untrusted-content.ts +102 -0
  765. package/src/skills/catalog-cache.ts +35 -9
  766. package/src/skills/catalog-install.ts +31 -3
  767. package/src/skills/skill-cache-store.ts +97 -0
  768. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  769. package/src/stt/daemon-batch-transcriber.ts +33 -0
  770. package/src/stt/stt-stream-session.ts +8 -1
  771. package/src/stt/types.ts +5 -1
  772. package/src/subagent/manager.ts +41 -13
  773. package/src/tasks/ephemeral-permissions.ts +9 -4
  774. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  775. package/src/tools/browser/__tests__/browser-status.test.ts +234 -2
  776. package/src/tools/browser/browser-execution.ts +150 -54
  777. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
  778. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
  779. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  780. package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
  781. package/src/tools/browser/cdp-client/factory.ts +15 -4
  782. package/src/tools/credentials/tool-policy.ts +39 -5
  783. package/src/tools/credentials/vault.ts +9 -4
  784. package/src/tools/executor.ts +129 -73
  785. package/src/tools/filesystem/write.ts +52 -0
  786. package/src/tools/host-terminal/host-shell.ts +45 -5
  787. package/src/tools/memory/register.test.ts +185 -0
  788. package/src/tools/memory/register.ts +3 -1
  789. package/src/tools/network/script-proxy/session-manager.ts +37 -1
  790. package/src/tools/network/web-fetch.ts +20 -10
  791. package/src/tools/network/web-search.ts +19 -4
  792. package/src/tools/permission-checker.ts +116 -46
  793. package/src/tools/policy-context.ts +29 -8
  794. package/src/tools/registry.ts +195 -6
  795. package/src/tools/schedule/create.ts +23 -8
  796. package/src/tools/schedule/update.ts +3 -1
  797. package/src/tools/secret-detection-handler.ts +0 -51
  798. package/src/tools/side-effects.ts +0 -11
  799. package/src/tools/skills/execute.ts +2 -2
  800. package/src/tools/skills/sandbox-runner.ts +5 -2
  801. package/src/tools/system/avatar-generator.ts +6 -2
  802. package/src/tools/terminal/backends/native.ts +51 -2
  803. package/src/tools/terminal/safe-env.ts +3 -2
  804. package/src/tools/terminal/shell.ts +1 -0
  805. package/src/tools/tool-manifest.ts +6 -21
  806. package/src/tools/types.ts +40 -5
  807. package/src/tools/verification-control-plane-policy.ts +1 -1
  808. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  809. package/src/tts/provider-catalog.ts +18 -0
  810. package/src/tts/providers/index.ts +2 -0
  811. package/src/tts/providers/xai-provider.ts +224 -0
  812. package/src/tts/types.ts +46 -0
  813. package/src/types/tar-stream.d.ts +66 -0
  814. package/src/util/json.ts +17 -0
  815. package/src/util/platform.ts +9 -4
  816. package/src/util/pricing.ts +41 -8
  817. package/src/watcher/engine.ts +1 -1
  818. package/src/watcher/providers/google-calendar.ts +134 -8
  819. package/src/watcher/providers/outlook-calendar.ts +42 -2
  820. package/src/workspace/git-service.ts +23 -4
  821. package/src/workspace/migrations/006-services-config.ts +2 -4
  822. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
  823. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  824. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  825. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  826. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +56 -0
  827. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  828. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  829. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  830. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  831. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
  832. package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
  833. package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
  834. package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
  835. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
  836. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
  837. package/src/workspace/migrations/AGENTS.md +1 -1
  838. package/src/workspace/migrations/registry.ts +28 -0
  839. package/src/workspace/provider-commit-message-generator.ts +19 -38
  840. package/tsconfig.json +1 -1
  841. package/hook-templates/debug-prompt-logger/hook.json +0 -7
  842. package/hook-templates/debug-prompt-logger/run.sh +0 -66
  843. package/src/__tests__/context-overflow-approval.test.ts +0 -156
  844. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  845. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  846. package/src/__tests__/gmail-preferences.test.ts +0 -117
  847. package/src/__tests__/hooks-blocking.test.ts +0 -178
  848. package/src/__tests__/hooks-cli.test.ts +0 -182
  849. package/src/__tests__/hooks-config.test.ts +0 -108
  850. package/src/__tests__/hooks-discovery.test.ts +0 -211
  851. package/src/__tests__/hooks-integration.test.ts +0 -196
  852. package/src/__tests__/hooks-manager.test.ts +0 -226
  853. package/src/__tests__/hooks-runner.test.ts +0 -175
  854. package/src/__tests__/hooks-settings.test.ts +0 -160
  855. package/src/__tests__/hooks-templates.test.ts +0 -169
  856. package/src/__tests__/hooks-ts-runner.test.ts +0 -170
  857. package/src/__tests__/hooks-watch.test.ts +0 -112
  858. package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
  859. package/src/__tests__/oauth-scope-policy.test.ts +0 -180
  860. package/src/__tests__/outlook-attachments.test.ts +0 -301
  861. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  862. package/src/__tests__/outlook-categories.test.ts +0 -212
  863. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  864. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  865. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  866. package/src/__tests__/outlook-trash.test.ts +0 -77
  867. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  868. package/src/__tests__/send-notification-tool.test.ts +0 -83
  869. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  870. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  871. package/src/__tests__/update-bulletin.test.ts +0 -478
  872. package/src/__tests__/update-template-contract.test.ts +0 -29
  873. package/src/cli/commands/doctor.ts +0 -341
  874. package/src/cli/commands/shotgun.ts +0 -266
  875. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  876. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  877. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  878. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  879. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  880. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  881. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  882. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  883. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  884. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  885. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  886. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  887. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  888. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  889. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  890. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  891. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  892. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  893. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  894. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  895. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  896. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  897. package/src/config/bundled-skills/conversations/SKILL.md +0 -20
  898. package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
  899. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -66
  900. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  901. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  902. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  903. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  904. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  905. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  906. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  907. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  908. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  909. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  910. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  911. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  912. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  913. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  914. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  915. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  916. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  917. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  918. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  919. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  920. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  921. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  922. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  923. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  924. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  925. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  926. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  927. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  928. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  929. package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
  930. package/src/config/bundled-skills/notifications/SKILL.md +0 -40
  931. package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
  932. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
  933. package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
  934. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  935. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  936. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  937. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  938. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  939. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  940. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  941. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  942. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  943. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  944. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  945. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  946. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  947. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  948. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  949. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  950. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  951. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  952. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  953. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  954. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  955. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  956. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  957. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  958. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  959. package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
  960. package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
  961. package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
  962. package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
  963. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  964. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  965. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  966. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  967. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  968. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  969. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  970. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  971. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  972. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  973. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  974. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  975. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  976. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  977. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  978. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  979. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  980. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  981. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  982. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  983. package/src/daemon/context-overflow-approval.ts +0 -52
  984. package/src/daemon/watch-handler.ts +0 -399
  985. package/src/hooks/cli.ts +0 -253
  986. package/src/hooks/config.ts +0 -100
  987. package/src/hooks/discovery.ts +0 -135
  988. package/src/hooks/manager.ts +0 -179
  989. package/src/hooks/runner.ts +0 -117
  990. package/src/hooks/templates.ts +0 -77
  991. package/src/hooks/types.ts +0 -75
  992. package/src/oauth/scope-policy.ts +0 -89
  993. package/src/prompts/templates/UPDATES.md +0 -50
  994. package/src/prompts/update-bulletin-format.ts +0 -85
  995. package/src/prompts/update-bulletin-state.ts +0 -58
  996. package/src/prompts/update-bulletin-template-path.ts +0 -13
  997. package/src/prompts/update-bulletin.ts +0 -139
  998. package/src/runtime/gateway-internal-client.ts +0 -94
  999. package/src/runtime/routes/watch-routes.ts +0 -156
  1000. package/src/shared/provider-env-vars.ts +0 -19
  1001. package/src/signals/shotgun.ts +0 -203
  1002. package/src/tools/watch/screen-watch.ts +0 -144
  1003. package/src/tools/watch/watch-state.ts +0 -142
  1004. package/src/tools/watcher/create.ts +0 -86
  1005. package/src/tools/watcher/delete.ts +0 -36
  1006. package/src/tools/watcher/digest.ts +0 -54
  1007. package/src/tools/watcher/list.ts +0 -83
  1008. package/src/tools/watcher/update.ts +0 -71
package/src/agent/loop.ts CHANGED
@@ -1,8 +1,28 @@
1
1
  import * as Sentry from "@sentry/node";
2
2
 
3
- import { estimateToolsTokens } from "../context/token-estimator.js";
4
- import { truncateOversizedToolResults } from "../context/tool-result-truncation.js";
5
- import { getHookManager } from "../hooks/manager.js";
3
+ import type { LLMCallSite } from "../config/schemas/llm.js";
4
+ import {
5
+ estimatePromptTokensRaw,
6
+ estimateToolsTokens,
7
+ getCalibrationProviderKey,
8
+ } from "../context/token-estimator.js";
9
+ import { calculateMaxToolResultChars } from "../context/tool-result-truncation.js";
10
+ import { defaultEmptyResponseTerminal } from "../plugins/defaults/empty-response.js";
11
+ import { defaultToolErrorTerminal } from "../plugins/defaults/tool-error.js";
12
+ import { defaultToolResultTruncateTerminal } from "../plugins/defaults/tool-result-truncate.js";
13
+ import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
14
+ import { getMiddlewaresFor } from "../plugins/registry.js";
15
+ import type {
16
+ EmptyResponseArgs,
17
+ EmptyResponseDecision,
18
+ LLMCallArgs,
19
+ LLMCallResult,
20
+ ToolErrorArgs,
21
+ ToolErrorDecision,
22
+ ToolResultTruncateArgs,
23
+ ToolResultTruncateResult,
24
+ TurnContext,
25
+ } from "../plugins/types.js";
6
26
  import type {
7
27
  ContentBlock,
8
28
  Message,
@@ -15,7 +35,9 @@ import {
15
35
  applyStreamingSubstitution,
16
36
  applySubstitutions,
17
37
  } from "../tools/sensitive-output-placeholders.js";
38
+ import { AssistantError, ErrorCode, ProviderError } from "../util/errors.js";
18
39
  import { getLogger } from "../util/logger.js";
40
+ import { isRetryableNetworkError } from "../util/retry.js";
19
41
 
20
42
  const log = getLogger("agent-loop");
21
43
 
@@ -23,7 +45,7 @@ export interface AgentLoopConfig {
23
45
  maxTokens: number;
24
46
  maxInputTokens?: number; // context window size for tool result truncation
25
47
  thinking?: { enabled: boolean };
26
- effort: "low" | "medium" | "high" | "max";
48
+ effort: "low" | "medium" | "high" | "xhigh" | "max";
27
49
  speed?: "standard" | "fast";
28
50
  toolChoice?:
29
51
  | { type: "auto" }
@@ -68,6 +90,10 @@ export type AgentEvent =
68
90
  };
69
91
  status?: string;
70
92
  contentBlocks?: ContentBlock[];
93
+ riskLevel?: string;
94
+ riskReason?: string;
95
+ isContainerized?: boolean;
96
+ riskScopeOptions?: Array<{ pattern: string; label: string }>;
71
97
  }
72
98
  | { type: "tool_use_preview_start"; toolUseId: string; toolName: string }
73
99
  | {
@@ -100,6 +126,13 @@ export type AgentEvent =
100
126
  providerDurationMs: number;
101
127
  rawRequest?: unknown;
102
128
  rawResponse?: unknown;
129
+ /**
130
+ * Pre-send token estimate for the same call. Used by the estimator
131
+ * calibrator to learn how off the heuristic is versus provider
132
+ * ground truth. Omitted only when estimation genuinely was not run
133
+ * for this call (e.g. legacy/stubbed code paths).
134
+ */
135
+ estimatedInputTokens?: number;
103
136
  };
104
137
 
105
138
  const DEFAULT_CONFIG: AgentLoopConfig = {
@@ -111,12 +144,139 @@ const DEFAULT_CONFIG: AgentLoopConfig = {
111
144
  const MAX_CONSECUTIVE_ERROR_NUDGES = 3;
112
145
  const MAX_EMPTY_RESPONSE_RETRIES = 1;
113
146
 
147
+ /**
148
+ * Build a minimal {@link TurnContext} for pipeline invocations inside the
149
+ * agent loop. Real production call sites thread a full `TurnContext` into
150
+ * `AgentLoop.run()` (see the `turnContext` parameter on
151
+ * {@link AgentLoop.run}); this helper is the fallback used only by unit
152
+ * tests that construct `AgentLoop` directly without an orchestrator.
153
+ *
154
+ * When the orchestrator-supplied context is present, {@link resolveLoopTurnContext}
155
+ * is used instead of this helper so the pipeline sees the real
156
+ * `conversationId`, trust, and `contextWindowManager`. In the fallback path
157
+ * the returned context is still useful for pipeline logging: `requestId`
158
+ * surfaces in every structured record, and `turnIndex` reflects the
159
+ * current tool-use iteration.
160
+ */
161
+ function buildLoopTurnContext(
162
+ requestId: string | undefined,
163
+ turnIndex: number,
164
+ ): TurnContext {
165
+ return {
166
+ requestId: requestId ?? "agent-loop",
167
+ // Loop-scoped pipelines do not currently carry a conversation ID; the
168
+ // outer orchestrator owns that dimension. Use a fixed sentinel so log
169
+ // consumers can filter loop-origin records out of conversation queries.
170
+ conversationId: "agent-loop",
171
+ turnIndex,
172
+ trust: {
173
+ sourceChannel: "vellum",
174
+ trustClass: "unknown",
175
+ },
176
+ };
177
+ }
178
+
179
+ /**
180
+ * Produce a `TurnContext` for a pipeline call inside {@link AgentLoop.run}.
181
+ *
182
+ * When the orchestrator supplied a `turnContext`, clone it and overwrite
183
+ * `requestId` + `turnIndex` with the loop-scoped values so plugin log
184
+ * records correctly attribute the call to the current tool-use iteration
185
+ * while preserving the real `conversationId`, trust context, and
186
+ * `contextWindowManager` the orchestrator assembled for the turn. Without
187
+ * an orchestrator context (unit tests that instantiate `AgentLoop` with no
188
+ * `turnContext`), fall back to {@link buildLoopTurnContext}'s synthesized
189
+ * placeholder.
190
+ */
191
+ function resolveLoopTurnContext(
192
+ base: TurnContext | undefined,
193
+ requestId: string | undefined,
194
+ turnIndex: number,
195
+ ): TurnContext {
196
+ if (base) {
197
+ return { ...base, requestId: requestId ?? base.requestId, turnIndex };
198
+ }
199
+ return buildLoopTurnContext(requestId, turnIndex);
200
+ }
201
+
202
+ /**
203
+ * User-config HTTP status codes that should never page the on-call: billing
204
+ * exhaustion (402), invalid credentials (401), and forbidden/plan-gated (403).
205
+ * The user-facing error path already surfaces an actionable message (e.g.
206
+ * credits_exhausted); a Sentry issue adds noise without engineering signal.
207
+ */
208
+ const USER_CONFIG_STATUS_CODES = new Set([401, 402, 403]);
209
+
210
+ /**
211
+ * Whether an agent-loop error should be reported to Sentry. Suppresses:
212
+ *
213
+ * - `ProviderError` carrying a user-config status code (401/402/403) — these
214
+ * are bad API keys, exhausted billing, or plan gates, not engineering bugs.
215
+ * - Retry-exhausted transient network errors (`retriesExhausted === true` +
216
+ * still categorized as retryable network) — the retry loop already tried
217
+ * its best; the user's network was flaky, not our code.
218
+ *
219
+ * Everything else (5xx with no retry-exhaustion tag, surprise errors, tool
220
+ * failures, etc.) still pages.
221
+ */
222
+ export function shouldCaptureAgentLoopError(err: Error): boolean {
223
+ if (
224
+ err instanceof ProviderError &&
225
+ err.statusCode !== undefined &&
226
+ USER_CONFIG_STATUS_CODES.has(err.statusCode)
227
+ ) {
228
+ return false;
229
+ }
230
+ const exhausted = (err as Error & { retriesExhausted?: boolean })
231
+ .retriesExhausted;
232
+ if (exhausted === true && isRetryableNetworkError(err)) {
233
+ return false;
234
+ }
235
+ return true;
236
+ }
237
+
114
238
  export interface ResolvedSystemPrompt {
115
239
  systemPrompt: string;
116
240
  maxTokens?: number;
117
241
  model?: string;
118
242
  }
119
243
 
244
+ /**
245
+ * Callback shape the loop uses to execute a tool invocation.
246
+ *
247
+ * The trailing `turnContext` is optional so in-process tests that wire the
248
+ * callback without an orchestrator keep working. Production sites (the
249
+ * `Conversation`'s `createToolExecutor`) forward the supplied context into
250
+ * `ToolExecutor.execute` so the `toolExecute` pipeline sees the orchestrator's
251
+ * real conversation identity/trust/contextWindowManager instead of the
252
+ * synthesized placeholder `ToolExecutor` would otherwise build from the
253
+ * `ToolContext` alone.
254
+ */
255
+ export type LoopToolExecutor = (
256
+ name: string,
257
+ input: Record<string, unknown>,
258
+ onOutput?: (chunk: string) => void,
259
+ toolUseId?: string,
260
+ turnContext?: TurnContext,
261
+ ) => Promise<{
262
+ content: string;
263
+ isError: boolean;
264
+ diff?: {
265
+ filePath: string;
266
+ oldContent: string;
267
+ newContent: string;
268
+ isNewFile: boolean;
269
+ };
270
+ status?: string;
271
+ contentBlocks?: ContentBlock[];
272
+ sensitiveBindings?: SensitiveOutputBinding[];
273
+ yieldToUser?: boolean;
274
+ riskLevel?: string;
275
+ riskReason?: string;
276
+ isContainerized?: boolean;
277
+ riskScopeOptions?: Array<{ pattern: string; label: string }>;
278
+ }>;
279
+
120
280
  export class AgentLoop {
121
281
  private provider: Provider;
122
282
  private systemPrompt: string;
@@ -126,52 +286,14 @@ export class AgentLoop {
126
286
  private resolveSystemPrompt:
127
287
  | ((history: Message[]) => ResolvedSystemPrompt)
128
288
  | null;
129
- private toolExecutor:
130
- | ((
131
- name: string,
132
- input: Record<string, unknown>,
133
- onOutput?: (chunk: string) => void,
134
- toolUseId?: string,
135
- ) => Promise<{
136
- content: string;
137
- isError: boolean;
138
- diff?: {
139
- filePath: string;
140
- oldContent: string;
141
- newContent: string;
142
- isNewFile: boolean;
143
- };
144
- status?: string;
145
- contentBlocks?: ContentBlock[];
146
- sensitiveBindings?: SensitiveOutputBinding[];
147
- yieldToUser?: boolean;
148
- }>)
149
- | null;
289
+ private toolExecutor: LoopToolExecutor | null;
150
290
 
151
291
  constructor(
152
292
  provider: Provider,
153
293
  systemPrompt: string,
154
294
  config?: Partial<AgentLoopConfig>,
155
295
  tools?: ToolDefinition[],
156
- toolExecutor?: (
157
- name: string,
158
- input: Record<string, unknown>,
159
- onOutput?: (chunk: string) => void,
160
- toolUseId?: string,
161
- ) => Promise<{
162
- content: string;
163
- isError: boolean;
164
- diff?: {
165
- filePath: string;
166
- oldContent: string;
167
- newContent: string;
168
- isNewFile: boolean;
169
- };
170
- status?: string;
171
- contentBlocks?: ContentBlock[];
172
- sensitiveBindings?: SensitiveOutputBinding[];
173
- yieldToUser?: boolean;
174
- }>,
296
+ toolExecutor?: LoopToolExecutor,
175
297
  resolveTools?: (history: Message[]) => ToolDefinition[],
176
298
  resolveSystemPrompt?: (history: Message[]) => ResolvedSystemPrompt,
177
299
  ) {
@@ -184,6 +306,21 @@ export class AgentLoop {
184
306
  this.toolExecutor = toolExecutor ?? null;
185
307
  }
186
308
 
309
+ /**
310
+ * Resolve the tool definitions sent to the provider for the given turn.
311
+ *
312
+ * Mirrors the logic of {@link getToolTokenBudget} but returns the tool
313
+ * array itself — callers that need to thread the tool set into a plugin
314
+ * pipeline (e.g. `tokenEstimate`, where the pipeline's args include
315
+ * `tools`) use this rather than re-implementing the dynamic-vs-static
316
+ * resolver fork.
317
+ */
318
+ getResolvedTools(history?: Message[]): ToolDefinition[] {
319
+ return history && this.resolveTools
320
+ ? this.resolveTools(history)
321
+ : this.tools;
322
+ }
323
+
187
324
  /**
188
325
  * Estimate token cost of the tool definitions sent to the provider.
189
326
  *
@@ -193,9 +330,7 @@ export class AgentLoop {
193
330
  * without a resolver), falls back to the static `this.tools`.
194
331
  */
195
332
  getToolTokenBudget(history?: Message[]): number {
196
- const tools =
197
- history && this.resolveTools ? this.resolveTools(history) : this.tools;
198
- return estimateToolsTokens(tools);
333
+ return estimateToolsTokens(this.getResolvedTools(history));
199
334
  }
200
335
 
201
336
  async run(
@@ -203,9 +338,22 @@ export class AgentLoop {
203
338
  onEvent: (event: AgentEvent) => void | Promise<void>,
204
339
  signal?: AbortSignal,
205
340
  requestId?: string,
206
- onCheckpoint?: (checkpoint: CheckpointInfo) => CheckpointDecision,
341
+ onCheckpoint?: (
342
+ checkpoint: CheckpointInfo,
343
+ ) => CheckpointDecision | Promise<CheckpointDecision>,
344
+ callSite?: LLMCallSite,
345
+ /**
346
+ * Optional per-turn context supplied by the orchestrator. Every pipeline
347
+ * invocation inside the loop clones from this value (overwriting only
348
+ * `turnIndex`/`requestId`) so middleware sees the real conversation
349
+ * identity, trust class, and `contextWindowManager` rather than the
350
+ * `"agent-loop"` sentinel used when the loop is instantiated standalone
351
+ * in unit tests.
352
+ */
353
+ turnContext?: TurnContext,
207
354
  ): Promise<Message[]> {
208
355
  const history = [...messages];
356
+ const initialHistoryLength = messages.length;
209
357
  let toolUseTurns = 0;
210
358
  let consecutiveErrorTurns = 0;
211
359
  let emptyResponseRetries = 0;
@@ -221,6 +369,11 @@ export class AgentLoop {
221
369
  while (true) {
222
370
  if (signal?.aborted) break;
223
371
 
372
+ rlog.info(
373
+ { turn: toolUseTurns, messageCount: history.length },
374
+ "Agent loop iteration start",
375
+ );
376
+
224
377
  let toolUseBlocks: Extract<ContentBlock, { type: "tool_use" }>[] = [];
225
378
 
226
379
  try {
@@ -235,25 +388,47 @@ export class AgentLoop {
235
388
  ? this.resolveSystemPrompt(history)
236
389
  : null;
237
390
  const turnSystemPrompt = resolved?.systemPrompt ?? this.systemPrompt;
238
- const turnMaxTokens = resolved?.maxTokens ?? this.config.maxTokens;
239
391
  const turnModel = resolved?.model;
240
392
 
241
- const providerConfig: Record<string, unknown> = {
242
- max_tokens: turnMaxTokens,
243
- };
244
- if (turnModel) {
245
- providerConfig.model = turnModel;
246
- }
247
- if (this.config.thinking?.enabled) {
248
- providerConfig.thinking = { type: "adaptive" };
393
+ // Field precedence (highest wins):
394
+ // 1. Per-turn explicit (`resolved.maxTokens` / `resolved.model`)
395
+ // 2. Call-site resolved values (filled by
396
+ // `RetryProvider.normalizeSendMessageOptions` from
397
+ // `resolveCallSiteConfig(callSite, llm)`)
398
+ // 3. Conversation defaults (`this.config.*`, sourced from
399
+ // `llm.default`)
400
+ //
401
+ // When `callSite` is present we deliberately leave
402
+ // `max_tokens`/`thinking`/`effort`/`speed` *unset* in `providerConfig`
403
+ // so the normalizer can fill them from the call-site resolution. The
404
+ // normalizer only writes these fields when they're undefined; if we
405
+ // pre-set them from `this.config` here, every per-call-site override
406
+ // for these knobs is silently ignored.
407
+ //
408
+ // `toolChoice` and `cacheTtl` are not part of the call-site schema, so
409
+ // they always come from `this.config` regardless of `callSite`.
410
+ const providerConfig: Record<string, unknown> = {};
411
+
412
+ if (resolved?.maxTokens !== undefined) {
413
+ providerConfig.max_tokens = resolved.maxTokens;
414
+ } else if (!callSite) {
415
+ providerConfig.max_tokens = this.config.maxTokens;
249
416
  }
250
417
 
251
- if (this.config.effort) {
252
- providerConfig.effort = this.config.effort;
418
+ if (turnModel) {
419
+ providerConfig.model = turnModel;
253
420
  }
254
421
 
255
- if (this.config.speed && this.config.speed !== "standard") {
256
- providerConfig.speed = this.config.speed;
422
+ if (!callSite) {
423
+ if (this.config.thinking?.enabled) {
424
+ providerConfig.thinking = { type: "adaptive" };
425
+ }
426
+ if (this.config.effort) {
427
+ providerConfig.effort = this.config.effort;
428
+ }
429
+ if (this.config.speed && this.config.speed !== "standard") {
430
+ providerConfig.speed = this.config.speed;
431
+ }
257
432
  }
258
433
 
259
434
  if (this.config.toolChoice) {
@@ -264,20 +439,15 @@ export class AgentLoop {
264
439
  providerConfig.cacheTtl = this.config.cacheTtl;
265
440
  }
266
441
 
267
- const preLlmResult = await getHookManager().trigger("pre-llm-call", {
268
- systemPrompt: turnSystemPrompt,
269
- messages: history,
270
- toolCount: currentTools.length,
271
- });
272
-
273
- if (preLlmResult.blocked) {
274
- onEvent({
275
- type: "error",
276
- error: new Error(
277
- `LLM call blocked by hook "${preLlmResult.blockedBy}"`,
278
- ),
279
- });
280
- break;
442
+ // Per-call LLM call-site identifier. Surfaces on the per-call
443
+ // `config.callSite` so `RetryProvider.normalizeSendMessageOptions`
444
+ // can route through `resolveCallSiteConfig` against
445
+ // `llm.callSites.<id>` (falling back to `llm.default` when absent).
446
+ // User-initiated conversation turns default to `mainAgent` in the
447
+ // agent loop's caller; other invocation contexts (heartbeat, filing,
448
+ // analyze, etc.) pass their own `callSite`.
449
+ if (callSite) {
450
+ providerConfig.callSite = callSite;
281
451
  }
282
452
 
283
453
  // Rate-limit consecutive LLM calls to prevent spin when tools return instantly
@@ -292,6 +462,25 @@ export class AgentLoop {
292
462
  const providerStart = Date.now();
293
463
  lastLlmCallTime = providerStart;
294
464
 
465
+ // Compute the pre-send estimate against the full in-memory
466
+ // history — matching what upstream callers of
467
+ // `estimatePromptTokens` (preflight, mid-loop checkpoints, the
468
+ // window manager) see. We use the RAW estimate (before applying
469
+ // the existing correction) so the calibrator learns the true
470
+ // bias against provider ground truth instead of ratcheting a
471
+ // feedback loop against its own corrected output.
472
+ const toolTokenBudget =
473
+ currentTools.length > 0 ? estimateToolsTokens(currentTools) : 0;
474
+ const preSendEstimatedTokens = estimatePromptTokensRaw(
475
+ history,
476
+ turnSystemPrompt,
477
+ {
478
+ providerName: getCalibrationProviderKey(this.provider),
479
+ toolTokenBudget,
480
+ },
481
+ );
482
+ rlog.info({ turn: toolUseTurns }, "LLM call start");
483
+
295
484
  // Strip image contentBlocks from older tool results to prevent
296
485
  // screenshots from accumulating in the context window. The LLM
297
486
  // already saw each image on the turn it was captured; keeping
@@ -302,11 +491,26 @@ export class AgentLoop {
302
491
  stripOldImageBlocks(history),
303
492
  );
304
493
 
305
- const response = await this.provider.sendMessage(
306
- providerHistory,
307
- currentTools.length > 0 ? currentTools : undefined,
308
- turnSystemPrompt,
309
- {
494
+ // Wrap the provider call in the `llmCall` pipeline so middleware
495
+ // contributed by plugins may observe, rewrite, short-circuit, or
496
+ // post-process every LLM request. The terminal below is the real
497
+ // `provider.sendMessage(...)` call; middleware that call `next(args)`
498
+ // eventually reach it. The default `defaultLlmCallPlugin` contributes
499
+ // only a passthrough middleware that forwards to `next(args)` —
500
+ // registered at module load, it sits at the outermost layer in the
501
+ // onion, so short-circuiting there would silently disable every
502
+ // user-registered `llmCall` middleware. Timeout is `null`
503
+ // (`DEFAULT_TIMEOUTS.llmCall`) — the provider layer already enforces
504
+ // its own HTTP-level budgets.
505
+ //
506
+ // The `onEvent` wrapping is kept inside `args.options` so substitution
507
+ // and streaming behavior exactly match the pre-pipeline call site.
508
+ const llmCallArgs: LLMCallArgs = {
509
+ provider: this.provider,
510
+ messages: providerHistory,
511
+ tools: currentTools.length > 0 ? currentTools : undefined,
512
+ systemPrompt: turnSystemPrompt,
513
+ options: {
310
514
  config: providerConfig,
311
515
  onEvent: (event) => {
312
516
  if (event.type === "text_delta") {
@@ -357,6 +561,36 @@ export class AgentLoop {
357
561
  },
358
562
  signal,
359
563
  },
564
+ };
565
+
566
+ // Per-turn pipeline context. When the orchestrator threaded a full
567
+ // `turnContext` into `run()`, use it (overwriting `turnIndex` with
568
+ // the loop-scoped tool-use iteration) so middleware sees the real
569
+ // conversation identity, trust, and `contextWindowManager`. The
570
+ // synthesized fallback is only reached by standalone unit-test
571
+ // instantiations that never plumb a context through.
572
+ const turnCtx = resolveLoopTurnContext(
573
+ turnContext,
574
+ requestId,
575
+ toolUseTurns,
576
+ );
577
+
578
+ const response: LLMCallResult = await runPipeline<
579
+ LLMCallArgs,
580
+ LLMCallResult
581
+ >(
582
+ "llmCall",
583
+ getMiddlewaresFor("llmCall"),
584
+ (args) =>
585
+ args.provider.sendMessage(
586
+ args.messages,
587
+ args.tools,
588
+ args.systemPrompt,
589
+ args.options,
590
+ ),
591
+ llmCallArgs,
592
+ turnCtx,
593
+ DEFAULT_TIMEOUTS.llmCall,
360
594
  );
361
595
 
362
596
  const providerDurationMs = Date.now() - providerStart;
@@ -372,14 +606,7 @@ export class AgentLoop {
372
606
  providerDurationMs,
373
607
  rawRequest: response.rawRequest,
374
608
  rawResponse: response.rawResponse,
375
- });
376
-
377
- void getHookManager().trigger("post-llm-call", {
378
- model: response.model,
379
- inputTokens: response.usage.inputTokens,
380
- outputTokens: response.usage.outputTokens,
381
- contentBlockCount: response.content.length,
382
- durationMs: providerDurationMs,
609
+ estimatedInputTokens: preSendEstimatedTokens,
383
610
  });
384
611
 
385
612
  // Flush any buffered streaming text from the substitution pipeline
@@ -407,19 +634,97 @@ export class AgentLoop {
407
634
  block.type === "tool_use",
408
635
  );
409
636
 
637
+ rlog.info(
638
+ {
639
+ turn: toolUseTurns,
640
+ stopReason: response.stopReason,
641
+ contentBlocks: response.content.length,
642
+ toolUseCount: toolUseBlocks.length,
643
+ durationMs: providerDurationMs,
644
+ },
645
+ "LLM call complete",
646
+ );
647
+
410
648
  // Detect empty responses: no user-visible text and no tool calls.
411
649
  // This can happen when the model fails to produce output after
412
650
  // receiving a large tool result. Retry once with a nudge before
413
651
  // the message is persisted.
652
+ //
653
+ // Only nudge when the model hasn't already delivered text to the user
654
+ // earlier in this tool-use chain. If a prior assistant turn in history
655
+ // contained visible text (e.g. the model said its piece before calling
656
+ // a side-effect tool like `remember`), an empty follow-up is the model
657
+ // correctly ending its turn — nudging would mislead it into thinking
658
+ // its earlier text didn't land and cause a verbatim re-send.
659
+ //
660
+ // Note: we check ANY prior assistant turn from this run()
661
+ // invocation, not just the most recent one. In multi-step tool-use
662
+ // chains (say-something → call-tool → call-another-tool → end),
663
+ // the "say-something" text lives on an earlier assistant turn while
664
+ // the most recent assistant turn is a pure tool_use with no text.
665
+ // Restricting the check to the most recent assistant turn would
666
+ // falsely nudge in that case and trigger a duplicate re-send of
667
+ // text the user already saw.
668
+ //
669
+ // Scope the scan to messages appended during this run() call only.
670
+ // Assistant text from prior conversation turns (earlier run()
671
+ // invocations passed in via `messages`) must NOT suppress the
672
+ // nudge — those turns completed long ago and have no bearing on
673
+ // whether the current tool-use chain has delivered text yet.
674
+ //
675
+ // The actual decision (nudge vs. accept vs. error) is delegated to
676
+ // the `emptyResponse` plugin pipeline. The pipeline returns a
677
+ // decision; the loop carries out the side-effect (pushing the nudge
678
+ // or surfacing the error). See `plugins/defaults/empty-response.ts`
679
+ // for the default decision logic.
414
680
  const hasVisibleText = response.content.some(
415
681
  (block) => block.type === "text" && block.text.trim().length > 0,
416
682
  );
417
- if (
418
- !hasVisibleText &&
419
- toolUseBlocks.length === 0 &&
420
- toolUseTurns > 0 &&
421
- emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES
422
- ) {
683
+ const priorAssistantHadVisibleText = (() => {
684
+ for (let i = history.length - 1; i >= initialHistoryLength; i--) {
685
+ const msg = history[i];
686
+ if (msg.role !== "assistant") continue;
687
+ const hasText = msg.content.some(
688
+ (block) =>
689
+ block.type === "text" &&
690
+ typeof (block as { text?: unknown }).text === "string" &&
691
+ (block as { text: string }).text.trim().length > 0,
692
+ );
693
+ if (hasText) return true;
694
+ }
695
+ return false;
696
+ })();
697
+
698
+ const emptyResponseArgs: EmptyResponseArgs = {
699
+ responseContent: response.content,
700
+ toolUseBlocksLength: toolUseBlocks.length,
701
+ toolUseTurns,
702
+ emptyResponseRetries,
703
+ maxEmptyResponseRetries: MAX_EMPTY_RESPONSE_RETRIES,
704
+ priorAssistantHadVisibleText,
705
+ };
706
+ const emptyResponseCtx = resolveLoopTurnContext(
707
+ turnContext,
708
+ requestId,
709
+ toolUseTurns,
710
+ );
711
+ const emptyResponseDecision: EmptyResponseDecision = await runPipeline(
712
+ "emptyResponse",
713
+ getMiddlewaresFor("emptyResponse"),
714
+ async (args) => defaultEmptyResponseTerminal(args),
715
+ emptyResponseArgs,
716
+ emptyResponseCtx,
717
+ DEFAULT_TIMEOUTS.emptyResponse,
718
+ );
719
+
720
+ if (emptyResponseDecision.action === "nudge") {
721
+ // Fall back to the canonical nudge text if the plugin returned
722
+ // `action: "nudge"` but forgot `nudgeText`. Keeps a misbehaving
723
+ // plugin from silently breaking the loop invariant that the
724
+ // model sees a coherent prompt.
725
+ const nudgeText =
726
+ emptyResponseDecision.nudgeText ??
727
+ "<system_notice>Your previous response was empty. You must respond to the user with a summary of what you found or did. Do not use any tools — just respond with text.</system_notice>";
423
728
  emptyResponseRetries++;
424
729
  rlog.warn(
425
730
  { turn: toolUseTurns, retry: emptyResponseRetries },
@@ -427,17 +732,31 @@ export class AgentLoop {
427
732
  );
428
733
  history.push({
429
734
  role: "user",
430
- content: [
431
- {
432
- type: "text",
433
- text: "<system_notice>Your previous response was empty. You must respond to the user with a summary of what you found or did. Do not use any tools — just respond with text.</system_notice>",
434
- },
435
- ],
735
+ content: [{ type: "text", text: nudgeText }],
436
736
  });
437
737
  continue;
438
738
  }
439
739
 
440
- if (!hasVisibleText && toolUseBlocks.length === 0 && toolUseTurns > 0) {
740
+ if (emptyResponseDecision.action === "error") {
741
+ rlog.error(
742
+ { turn: toolUseTurns, retries: emptyResponseRetries },
743
+ "emptyResponse pipeline requested error surface",
744
+ );
745
+ throw new AssistantError(
746
+ "Model returned empty response after tool results",
747
+ ErrorCode.INTERNAL_ERROR,
748
+ );
749
+ }
750
+
751
+ // action === "accept" — fall through. Emit a dedicated log line for
752
+ // the specific "empty turn after tool results, retries exhausted"
753
+ // case so ops dashboards that grep on this line keep working.
754
+ if (
755
+ !hasVisibleText &&
756
+ toolUseBlocks.length === 0 &&
757
+ toolUseTurns > 0 &&
758
+ !priorAssistantHadVisibleText
759
+ ) {
441
760
  rlog.error(
442
761
  { turn: toolUseTurns, retries: emptyResponseRetries },
443
762
  "Model returned empty response after tool results — retries exhausted",
@@ -479,6 +798,15 @@ export class AgentLoop {
479
798
  // Execute all tools concurrently for reduced latency.
480
799
  // Race against the abort signal so cancellation isn't blocked by
481
800
  // stuck tools (e.g. a hung browser navigation).
801
+ const toolExecStart = Date.now();
802
+ rlog.info(
803
+ {
804
+ turn: toolUseTurns,
805
+ toolNames: toolUseBlocks.map((t) => t.name),
806
+ },
807
+ "Tool execution start",
808
+ );
809
+
482
810
  const toolExecutionPromise = Promise.all(
483
811
  toolUseBlocks.map(async (toolUse) => {
484
812
  const result = await this.toolExecutor!(
@@ -492,6 +820,14 @@ export class AgentLoop {
492
820
  });
493
821
  },
494
822
  toolUse.id,
823
+ // Forward the loop's resolved `TurnContext` through the
824
+ // executor callback so `ToolExecutor.execute` can thread the
825
+ // real orchestrator context into the `toolExecute` pipeline.
826
+ // Standalone tests that don't wire a `turnContext` into
827
+ // `AgentLoop.run()` pass `undefined` here and the executor
828
+ // falls back to the synthesized placeholder — preserving the
829
+ // existing unit-test behavior.
830
+ turnCtx,
495
831
  );
496
832
 
497
833
  return { toolUse, result };
@@ -522,6 +858,15 @@ export class AgentLoop {
522
858
  toolResults = await toolExecutionPromise;
523
859
  }
524
860
 
861
+ rlog.info(
862
+ {
863
+ turn: toolUseTurns,
864
+ toolCount: toolResults.length,
865
+ durationMs: Date.now() - toolExecStart,
866
+ },
867
+ "Tool execution complete",
868
+ );
869
+
525
870
  // Merge sensitive output bindings from tool results into the
526
871
  // per-run substitution map. Bindings carry placeholder->value pairs
527
872
  // that are resolved in streamed text deltas and final message text.
@@ -546,12 +891,52 @@ export class AgentLoop {
546
891
  }),
547
892
  );
548
893
 
549
- // Pre-emptively truncate oversized tool results to prevent context overflow
550
- const { blocks: resultBlocks, truncatedCount } =
551
- truncateOversizedToolResults(
552
- rawResultBlocks,
553
- this.config.maxInputTokens ?? 180_000,
894
+ // Pre-emptively truncate oversized tool results to prevent context
895
+ // overflow. The work is delegated to the `toolResultTruncate`
896
+ // plugin pipeline so downstream plugins can swap in a smarter
897
+ // truncation strategy (e.g. a summariser) while the default
898
+ // middleware preserves the historical tail-drop behaviour.
899
+ const contextWindowTokens = this.config.maxInputTokens ?? 180_000;
900
+ const maxChars = calculateMaxToolResultChars(contextWindowTokens);
901
+ const truncateMiddlewares = getMiddlewaresFor("toolResultTruncate");
902
+
903
+ let truncatedCount = 0;
904
+ const truncatedBlocks: ContentBlock[] = [];
905
+ for (const block of rawResultBlocks) {
906
+ if (block.type !== "tool_result") {
907
+ truncatedBlocks.push(block);
908
+ continue;
909
+ }
910
+ const toolBlock = block as ToolResultContent;
911
+ if (
912
+ typeof toolBlock.content !== "string" ||
913
+ toolBlock.content.length <= maxChars
914
+ ) {
915
+ truncatedBlocks.push(block);
916
+ continue;
917
+ }
918
+ const pipelineResult = await runPipeline<
919
+ ToolResultTruncateArgs,
920
+ ToolResultTruncateResult
921
+ >(
922
+ "toolResultTruncate",
923
+ truncateMiddlewares,
924
+ async (args) => defaultToolResultTruncateTerminal(args),
925
+ { content: toolBlock.content, maxChars },
926
+ turnCtx,
927
+ DEFAULT_TIMEOUTS.toolResultTruncate,
554
928
  );
929
+ if (pipelineResult.truncated) {
930
+ truncatedCount++;
931
+ truncatedBlocks.push({
932
+ ...toolBlock,
933
+ content: pipelineResult.content,
934
+ });
935
+ } else {
936
+ truncatedBlocks.push(block);
937
+ }
938
+ }
939
+ const resultBlocks = truncatedBlocks;
555
940
  if (truncatedCount > 0) {
556
941
  log.warn(
557
942
  `Truncated ${truncatedCount} oversized tool result(s) to prevent context overflow`,
@@ -577,6 +962,10 @@ export class AgentLoop {
577
962
  diff: result.diff,
578
963
  status: result.status,
579
964
  contentBlocks: result.contentBlocks,
965
+ riskLevel: result.riskLevel,
966
+ riskReason: result.riskReason,
967
+ isContainerized: result.isContainerized,
968
+ riskScopeOptions: result.riskScopeOptions,
580
969
  });
581
970
  }
582
971
 
@@ -598,29 +987,59 @@ export class AgentLoop {
598
987
  // When any tool returned an error, nudge the LLM to retry with
599
988
  // corrected parameters instead of ending its turn. Skip the nudge
600
989
  // after MAX_CONSECUTIVE_ERROR_NUDGES consecutive error turns
601
- // (the error is likely unrecoverable at that point).
990
+ // (the error is likely unrecoverable at that point). The nudge
991
+ // decision is delegated to the `toolError` plugin pipeline so user
992
+ // plugins can change the text, observe the event, or suppress it.
602
993
  const hasToolError = toolResults.some(({ result }) => result.isError);
603
994
  if (hasToolError) {
604
995
  consecutiveErrorTurns++;
605
996
  } else {
606
997
  consecutiveErrorTurns = 0;
607
998
  }
608
- if (
609
- hasToolError &&
610
- consecutiveErrorTurns <= MAX_CONSECUTIVE_ERROR_NUDGES
611
- ) {
999
+ const toolErrorArgs: ToolErrorArgs = {
1000
+ hasToolError,
1001
+ consecutiveErrorTurns,
1002
+ maxConsecutiveErrorNudges: MAX_CONSECUTIVE_ERROR_NUDGES,
1003
+ };
1004
+ const toolErrorCtx: TurnContext = resolveLoopTurnContext(
1005
+ turnContext,
1006
+ requestId,
1007
+ toolUseTurns - 1,
1008
+ );
1009
+ const toolErrorDecision = await runPipeline<
1010
+ ToolErrorArgs,
1011
+ ToolErrorDecision
1012
+ >(
1013
+ "toolError",
1014
+ getMiddlewaresFor("toolError"),
1015
+ // Terminal: the canonical nudge decision. The default plugin's
1016
+ // middleware is a passthrough (so later-registered user plugins
1017
+ // aren't shadowed), so this terminal is what actually produces
1018
+ // the decision when no user plugin overrides it. Wiring the
1019
+ // decision here — rather than inside the default plugin's
1020
+ // middleware — also preserves the legacy nudge for direct
1021
+ // AgentLoop callers (tests, benchmarks) that skip
1022
+ // `bootstrapPlugins()` and therefore never register the default.
1023
+ async (args) => defaultToolErrorTerminal(args),
1024
+ toolErrorArgs,
1025
+ toolErrorCtx,
1026
+ DEFAULT_TIMEOUTS.toolError,
1027
+ );
1028
+ if (toolErrorDecision.action === "nudge") {
612
1029
  resultBlocks.push({
613
1030
  type: "text",
614
- text: "<system_notice>One or more tool calls returned an error. If the error looks recoverable (e.g. missing or invalid parameters), fix the parameters and retry. If the error is clearly unrecoverable (e.g. a service is down, a resource does not exist, or a permission is permanently denied), report it to the user.</system_notice>",
1031
+ text: toolErrorDecision.nudgeText,
615
1032
  });
616
1033
  }
617
1034
 
618
1035
  // Add tool results as a user message and continue the loop
619
1036
  history.push({ role: "user", content: resultBlocks });
620
1037
 
621
- // Invoke checkpoint callback after tool results are in history
1038
+ // Invoke checkpoint callback after tool results are in history.
1039
+ // The callback may be async — the mid-loop budget check delegates
1040
+ // to the `tokenEstimate` plugin pipeline, which is asynchronous.
622
1041
  if (onCheckpoint) {
623
- const decision = onCheckpoint({
1042
+ const decision = await onCheckpoint({
624
1043
  turnIndex: toolUseTurns - 1, // 0-based (toolUseTurns was already incremented)
625
1044
  toolCount: toolUseBlocks.length,
626
1045
  hasToolUse: true,
@@ -653,12 +1072,23 @@ export class AgentLoop {
653
1072
  { err, turn: toolUseTurns, messageCount: history.length },
654
1073
  "Agent loop error during turn processing",
655
1074
  );
656
- Sentry.captureException(err);
1075
+ if (shouldCaptureAgentLoopError(err)) {
1076
+ Sentry.captureException(err);
1077
+ }
657
1078
  onEvent({ type: "error", error: err });
658
1079
  break;
659
1080
  }
660
1081
  }
661
1082
 
1083
+ rlog.info(
1084
+ {
1085
+ turns: toolUseTurns,
1086
+ finalMessageCount: history.length,
1087
+ aborted: signal?.aborted ?? false,
1088
+ },
1089
+ "Agent loop exited",
1090
+ );
1091
+
662
1092
  return history;
663
1093
  }
664
1094
  }