@vellumai/assistant 0.6.3 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1114) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +298 -39
  3. package/Dockerfile +14 -3
  4. package/README.md +3 -4
  5. package/bun.lock +13 -16
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/backup-troubleshooting.md +52 -0
  9. package/docs/browser-use-architecture-phase2.md +174 -0
  10. package/docs/error-handling.md +111 -0
  11. package/docs/skills.md +10 -10
  12. package/docs/stt-provider-onboarding.md +121 -0
  13. package/knip.json +20 -3
  14. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  15. package/node_modules/@vellumai/ces-contracts/package.json +5 -4
  16. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  17. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  18. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  19. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  20. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  21. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  22. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  23. package/openapi.yaml +1094 -72
  24. package/package.json +9 -8
  25. package/scripts/generate-openapi.ts +50 -12
  26. package/scripts/test.sh +73 -18
  27. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  28. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  29. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  30. package/src/__tests__/agent-loop.test.ts +235 -1
  31. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  32. package/src/__tests__/anthropic-provider.test.ts +434 -12
  33. package/src/__tests__/approval-cascade.test.ts +31 -10
  34. package/src/__tests__/approval-routes-http.test.ts +134 -10
  35. package/src/__tests__/assistant-attachments.test.ts +44 -0
  36. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  37. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  38. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  39. package/src/__tests__/browser-fill-credential.test.ts +12 -1
  40. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  41. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  42. package/src/__tests__/browser-skill-endstate.test.ts +52 -159
  43. package/src/__tests__/btw-routes.test.ts +54 -1
  44. package/src/__tests__/call-controller.test.ts +582 -22
  45. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  46. package/src/__tests__/catalog-cache.test.ts +27 -4
  47. package/src/__tests__/catalog-files.test.ts +138 -0
  48. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  49. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  50. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  51. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  52. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  53. package/src/__tests__/checker.test.ts +576 -502
  54. package/src/__tests__/clawhub-files.test.ts +347 -0
  55. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  56. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  57. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  58. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  59. package/src/__tests__/config-analysis.test.ts +83 -0
  60. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  61. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  62. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  63. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  64. package/src/__tests__/config-schema.test.ts +1458 -198
  65. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  66. package/src/__tests__/config-watcher.test.ts +45 -10
  67. package/src/__tests__/contact-store-user-file.test.ts +511 -0
  68. package/src/__tests__/contacts-write.test.ts +197 -0
  69. package/src/__tests__/context-token-estimator.test.ts +191 -1
  70. package/src/__tests__/context-window-manager.test.ts +618 -2
  71. package/src/__tests__/conversation-abort-tool-results.test.ts +32 -16
  72. package/src/__tests__/conversation-agent-loop-overflow.test.ts +62 -17
  73. package/src/__tests__/conversation-agent-loop.test.ts +510 -84
  74. package/src/__tests__/conversation-attachments.test.ts +1 -1
  75. package/src/__tests__/conversation-confirmation-signals.test.ts +165 -9
  76. package/src/__tests__/conversation-error.test.ts +102 -1
  77. package/src/__tests__/conversation-history-web-search.test.ts +17 -4
  78. package/src/__tests__/conversation-init.benchmark.test.ts +42 -1
  79. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  80. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  81. package/src/__tests__/conversation-list-source.test.ts +145 -0
  82. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  83. package/src/__tests__/conversation-pre-run-repair.test.ts +32 -16
  84. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  85. package/src/__tests__/conversation-provider-retry-repair.test.ts +32 -16
  86. package/src/__tests__/conversation-queue.test.ts +932 -76
  87. package/src/__tests__/conversation-routes-disk-view.test.ts +299 -1
  88. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  89. package/src/__tests__/conversation-runtime-assembly.test.ts +2790 -55
  90. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  91. package/src/__tests__/conversation-skill-tools.test.ts +12 -143
  92. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  93. package/src/__tests__/conversation-slash-queue.test.ts +120 -34
  94. package/src/__tests__/conversation-slash-unknown.test.ts +32 -16
  95. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  96. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  97. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  98. package/src/__tests__/conversation-title-service.test.ts +2 -2
  99. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  100. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  101. package/src/__tests__/conversation-usage.test.ts +3 -1
  102. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  103. package/src/__tests__/conversation-workspace-injection.test.ts +45 -15
  104. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -16
  105. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  106. package/src/__tests__/credential-health-service.test.ts +352 -0
  107. package/src/__tests__/credential-security-invariants.test.ts +8 -3
  108. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  109. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  110. package/src/__tests__/credential-vault-unit.test.ts +495 -3
  111. package/src/__tests__/credentials-cli.test.ts +32 -16
  112. package/src/__tests__/cross-provider-web-search.test.ts +230 -35
  113. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  114. package/src/__tests__/delete-propagation.test.ts +437 -0
  115. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  116. package/src/__tests__/device-id.test.ts +112 -0
  117. package/src/__tests__/dm-backfill.test.ts +417 -0
  118. package/src/__tests__/dm-persistence.test.ts +227 -0
  119. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  120. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  121. package/src/__tests__/edit-propagation.test.ts +280 -0
  122. package/src/__tests__/email-html-renderer.test.ts +71 -0
  123. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  124. package/src/__tests__/emit-event-signal.test.ts +71 -0
  125. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  126. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  127. package/src/__tests__/estimator-calibration.test.ts +213 -0
  128. package/src/__tests__/extension-id-sync-guard.test.ts +101 -15
  129. package/src/__tests__/file-write-tool.test.ts +151 -1
  130. package/src/__tests__/filing-service.test.ts +255 -0
  131. package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
  132. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  133. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  134. package/src/__tests__/gemini-provider.test.ts +64 -3
  135. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  136. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  137. package/src/__tests__/headless-browser-interactions.test.ts +44 -1
  138. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  139. package/src/__tests__/headless-browser-navigate.test.ts +142 -5
  140. package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
  141. package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
  142. package/src/__tests__/heartbeat-service.test.ts +166 -32
  143. package/src/__tests__/home-state-routes.test.ts +162 -0
  144. package/src/__tests__/host-bash-proxy.test.ts +0 -5
  145. package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
  146. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
  147. package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
  148. package/src/__tests__/host-cu-proxy.test.ts +0 -5
  149. package/src/__tests__/host-shell-tool.test.ts +124 -18
  150. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  151. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  152. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  153. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  154. package/src/__tests__/intent-routing.test.ts +1 -40
  155. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  156. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  157. package/src/__tests__/llm-context-normalization.test.ts +609 -0
  158. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  159. package/src/__tests__/llm-resolver.test.ts +214 -0
  160. package/src/__tests__/llm-schema.test.ts +223 -0
  161. package/src/__tests__/llm-usage-store.test.ts +363 -0
  162. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  163. package/src/__tests__/media-stream-output.test.ts +555 -0
  164. package/src/__tests__/media-stream-parser.test.ts +374 -0
  165. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  166. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  167. package/src/__tests__/media-turn-detector.test.ts +440 -0
  168. package/src/__tests__/message-queue.test.ts +125 -0
  169. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  170. package/src/__tests__/migration-export-http.test.ts +6 -6
  171. package/src/__tests__/migration-import-commit-http.test.ts +8 -6
  172. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  173. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  174. package/src/__tests__/migration-validate-http.test.ts +3 -3
  175. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  176. package/src/__tests__/model-intents.test.ts +10 -84
  177. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  178. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  179. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  180. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  181. package/src/__tests__/oauth-cli.test.ts +2 -0
  182. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  183. package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
  184. package/src/__tests__/oauth-providers-routes.test.ts +2 -0
  185. package/src/__tests__/oauth-store.test.ts +95 -7
  186. package/src/__tests__/oauth2-gateway-transport.test.ts +257 -9
  187. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  188. package/src/__tests__/onboarding-template-contract.test.ts +6 -13
  189. package/src/__tests__/openai-provider.test.ts +183 -0
  190. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  191. package/src/__tests__/openai-responses-provider.test.ts +1501 -0
  192. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  193. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  194. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  195. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  196. package/src/__tests__/permission-mode.test.ts +16 -0
  197. package/src/__tests__/permission-types.test.ts +0 -1
  198. package/src/__tests__/persona-resolver.test.ts +251 -0
  199. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  200. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -1
  201. package/src/__tests__/platform.test.ts +92 -1
  202. package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
  203. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  204. package/src/__tests__/pricing.test.ts +224 -3
  205. package/src/__tests__/profiler-routes.test.ts +1 -1
  206. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  207. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  208. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  209. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  210. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  211. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  212. package/src/__tests__/qdrant-manager.test.ts +29 -8
  213. package/src/__tests__/reaction-persistence.test.ts +560 -0
  214. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  215. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  216. package/src/__tests__/relay-server.test.ts +424 -6
  217. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  218. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  219. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  220. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  221. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  222. package/src/__tests__/search-skills-unified.test.ts +118 -0
  223. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  224. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  225. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  226. package/src/__tests__/secret-scanner-executor.test.ts +5 -1
  227. package/src/__tests__/secure-keys.test.ts +107 -0
  228. package/src/__tests__/send-endpoint-busy.test.ts +34 -2
  229. package/src/__tests__/sequence-store.test.ts +1 -1
  230. package/src/__tests__/server-history-render.test.ts +80 -0
  231. package/src/__tests__/settings-routes.test.ts +201 -0
  232. package/src/__tests__/shell-parser-property.test.ts +13 -13
  233. package/src/__tests__/skill-cache-store.test.ts +182 -0
  234. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  235. package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
  236. package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
  237. package/src/__tests__/skills.test.ts +19 -30
  238. package/src/__tests__/skillssh-files.test.ts +446 -0
  239. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  240. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  241. package/src/__tests__/slack-channel-config.test.ts +564 -1
  242. package/src/__tests__/slack-skill.test.ts +3 -8
  243. package/src/__tests__/starter-bundle.test.ts +35 -0
  244. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  245. package/src/__tests__/stt-stream-session.test.ts +535 -0
  246. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  247. package/src/__tests__/suggestion-routes.test.ts +160 -3
  248. package/src/__tests__/system-prompt.test.ts +126 -53
  249. package/src/__tests__/task-runner.test.ts +3 -1
  250. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  251. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  252. package/src/__tests__/terminal-tools.test.ts +26 -7
  253. package/src/__tests__/test-preload.ts +18 -0
  254. package/src/__tests__/test-support/browser-skill-harness.ts +2 -49
  255. package/src/__tests__/thread-backfill.test.ts +941 -0
  256. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  257. package/src/__tests__/tool-executor-lifecycle-events.test.ts +10 -6
  258. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  259. package/src/__tests__/tool-executor.test.ts +88 -113
  260. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  261. package/src/__tests__/trust-store.test.ts +442 -103
  262. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  263. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  264. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  265. package/src/__tests__/twilio-routes.test.ts +376 -0
  266. package/src/__tests__/unicode.test.ts +293 -0
  267. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  268. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  269. package/src/__tests__/usage-routes.test.ts +25 -4
  270. package/src/__tests__/user-reference.test.ts +46 -61
  271. package/src/__tests__/verification-control-plane-policy.test.ts +5 -22
  272. package/src/__tests__/voice-config-update.test.ts +403 -0
  273. package/src/__tests__/voice-quality.test.ts +434 -19
  274. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  275. package/src/__tests__/volume-security-guard.test.ts +3 -2
  276. package/src/__tests__/web-search-history.test.ts +337 -0
  277. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  278. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  279. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  280. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  281. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  282. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  283. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  284. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  285. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  286. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  287. package/src/__tests__/workspace-policy.test.ts +1 -11
  288. package/src/acp/client-handler.ts +1 -2
  289. package/src/agent/image-optimize.ts +24 -12
  290. package/src/agent/loop.ts +251 -19
  291. package/src/avatar/resvg-lazy.test.ts +136 -0
  292. package/src/avatar/resvg-lazy.ts +82 -9
  293. package/src/avatar/traits-png-sync.ts +21 -1
  294. package/src/backup/__tests__/backup-key.test.ts +152 -0
  295. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  296. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  297. package/src/backup/__tests__/local-writer.test.ts +218 -0
  298. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  299. package/src/backup/__tests__/paths.test.ts +300 -0
  300. package/src/backup/__tests__/restore.test.ts +498 -0
  301. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  302. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  303. package/src/backup/backup-key.ts +137 -0
  304. package/src/backup/backup-worker.ts +459 -0
  305. package/src/backup/list-snapshots.ts +147 -0
  306. package/src/backup/local-writer.ts +133 -0
  307. package/src/backup/offsite-writer.ts +222 -0
  308. package/src/backup/paths.ts +226 -0
  309. package/src/backup/restore.ts +322 -0
  310. package/src/backup/snapshot-lock.ts +431 -0
  311. package/src/backup/stream-crypt.ts +263 -0
  312. package/src/browser/__tests__/operations.test.ts +163 -0
  313. package/src/browser/identifiers.ts +51 -0
  314. package/src/browser/operations.ts +660 -0
  315. package/src/browser/types.ts +81 -0
  316. package/src/bundler/package-resolver.ts +4 -0
  317. package/src/calls/audio-store.ts +11 -5
  318. package/src/calls/call-controller.ts +226 -71
  319. package/src/calls/call-domain.ts +9 -0
  320. package/src/calls/call-speech-output.ts +190 -0
  321. package/src/calls/call-transport.ts +77 -0
  322. package/src/calls/guardian-question-copy.ts +2 -2
  323. package/src/calls/media-stream-audio-transcode.ts +173 -0
  324. package/src/calls/media-stream-output.ts +660 -0
  325. package/src/calls/media-stream-parser.ts +300 -0
  326. package/src/calls/media-stream-protocol.ts +166 -0
  327. package/src/calls/media-stream-server.ts +592 -0
  328. package/src/calls/media-stream-stt-session.ts +460 -0
  329. package/src/calls/media-turn-detector.ts +230 -0
  330. package/src/calls/relay-server.ts +90 -75
  331. package/src/calls/resolve-call-tts-provider.ts +136 -0
  332. package/src/calls/telephony-stt-routing.ts +145 -0
  333. package/src/calls/tts-call-strategy.ts +161 -0
  334. package/src/calls/tts-text-sanitizer.ts +32 -16
  335. package/src/calls/twilio-routes.ts +281 -17
  336. package/src/calls/voice-quality.ts +78 -35
  337. package/src/calls/voice-session-bridge.ts +9 -1
  338. package/src/channels/types.ts +16 -0
  339. package/src/cli/AGENTS.md +1 -1
  340. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  341. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  342. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  343. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  344. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  345. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  346. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  347. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  348. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  349. package/src/cli/commands/__tests__/email-list.test.ts +28 -4
  350. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  351. package/src/cli/commands/__tests__/email-send.test.ts +130 -5
  352. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  353. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  354. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  355. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  356. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  357. package/src/cli/commands/__tests__/task.test.ts +913 -0
  358. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  359. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  360. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  361. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  362. package/src/cli/commands/attachment.ts +182 -0
  363. package/src/cli/commands/backup.ts +993 -0
  364. package/src/cli/commands/browser.ts +350 -0
  365. package/src/cli/commands/cache.ts +341 -0
  366. package/src/cli/commands/completions.ts +0 -3
  367. package/src/cli/commands/config.ts +6 -6
  368. package/src/cli/commands/conversations-import.ts +347 -0
  369. package/src/cli/commands/conversations.ts +90 -0
  370. package/src/cli/commands/credentials.ts +0 -1
  371. package/src/cli/commands/domain.ts +210 -0
  372. package/src/cli/commands/email.ts +308 -16
  373. package/src/cli/commands/image-generation.ts +300 -0
  374. package/src/cli/commands/inference.ts +200 -0
  375. package/src/cli/commands/memory.ts +127 -17
  376. package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
  377. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
  378. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
  379. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
  380. package/src/cli/commands/oauth/mode.ts +12 -3
  381. package/src/cli/commands/oauth/providers.ts +15 -0
  382. package/src/cli/commands/oauth/shared.ts +2 -1
  383. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -10
  384. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -1
  385. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -2
  386. package/src/cli/commands/platform/__tests__/status.test.ts +6 -1
  387. package/src/cli/commands/stt.ts +339 -0
  388. package/src/cli/commands/task.ts +795 -0
  389. package/src/cli/commands/trust.ts +50 -19
  390. package/src/cli/commands/tts.ts +273 -0
  391. package/src/cli/commands/ui.ts +670 -0
  392. package/src/cli/commands/watchers.ts +509 -0
  393. package/src/cli/lib/daemon-credential-client.ts +0 -19
  394. package/src/cli/program.ts +53 -8
  395. package/src/cli.ts +0 -37
  396. package/src/config/__tests__/backup-schema.test.ts +134 -0
  397. package/src/config/assistant-feature-flags.ts +61 -62
  398. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
  399. package/src/config/bundled-skills/contacts/SKILL.md +2 -2
  400. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  401. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  402. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  403. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  404. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  405. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  406. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  407. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  408. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  409. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  410. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  411. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  412. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -2
  413. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  414. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  415. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  416. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  417. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +28 -18
  418. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  419. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  420. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  421. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  422. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  423. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  424. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  425. package/src/config/bundled-tool-registry.ts +0 -167
  426. package/src/config/env-registry.ts +24 -0
  427. package/src/config/env.ts +39 -10
  428. package/src/config/feature-flag-registry.json +63 -15
  429. package/src/config/llm-resolver.ts +128 -0
  430. package/src/config/loader.ts +220 -22
  431. package/src/config/raw-config-utils.ts +30 -2
  432. package/src/config/sanitize-for-transfer.ts +35 -0
  433. package/src/config/schema.ts +65 -51
  434. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  435. package/src/config/schemas/analysis.ts +32 -0
  436. package/src/config/schemas/backup.ts +72 -0
  437. package/src/config/schemas/calls.ts +1 -30
  438. package/src/config/schemas/elevenlabs.ts +0 -59
  439. package/src/config/schemas/filing.ts +49 -14
  440. package/src/config/schemas/heartbeat.ts +27 -10
  441. package/src/config/schemas/host-browser.ts +47 -1
  442. package/src/config/schemas/inference.ts +3 -23
  443. package/src/config/schemas/llm.ts +318 -0
  444. package/src/config/schemas/memory-lifecycle.ts +14 -2
  445. package/src/config/schemas/memory-processing.ts +1 -9
  446. package/src/config/schemas/notifications.ts +4 -11
  447. package/src/config/schemas/platform.ts +3 -9
  448. package/src/config/schemas/security.ts +33 -0
  449. package/src/config/schemas/services.ts +53 -4
  450. package/src/config/schemas/stt.ts +60 -0
  451. package/src/config/schemas/tts.ts +283 -0
  452. package/src/config/schemas/updates.ts +14 -0
  453. package/src/config/schemas/workspace-git.ts +3 -40
  454. package/src/config/skills.ts +6 -2
  455. package/src/config/types.ts +4 -0
  456. package/src/contacts/contact-store.ts +56 -11
  457. package/src/contacts/contacts-write.ts +38 -1
  458. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  459. package/src/context/__tests__/microcompact.test.ts +805 -0
  460. package/src/context/estimator-calibration.ts +136 -0
  461. package/src/context/microcompact.ts +443 -0
  462. package/src/context/post-turn-tool-result-truncation.ts +3 -2
  463. package/src/context/prompts/compact.md +12 -0
  464. package/src/context/token-estimator.ts +61 -3
  465. package/src/context/tool-result-truncation.ts +2 -1
  466. package/src/context/window-manager.ts +272 -35
  467. package/src/credential-execution/approval-bridge.ts +0 -1
  468. package/src/credential-execution/executable-discovery.ts +23 -2
  469. package/src/credential-execution/process-manager.test.ts +109 -0
  470. package/src/credential-execution/process-manager.ts +96 -2
  471. package/src/credential-health/credential-health-service.ts +366 -0
  472. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  473. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  474. package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
  475. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  476. package/src/daemon/approval-generators.ts +29 -4
  477. package/src/daemon/assistant-attachments.ts +24 -13
  478. package/src/daemon/classifier.ts +2 -2
  479. package/src/daemon/config-watcher.ts +99 -6
  480. package/src/daemon/context-overflow-reducer.ts +4 -1
  481. package/src/daemon/conversation-agent-loop-handlers.ts +85 -12
  482. package/src/daemon/conversation-agent-loop.ts +563 -104
  483. package/src/daemon/conversation-attachments.ts +2 -6
  484. package/src/daemon/conversation-error.ts +46 -0
  485. package/src/daemon/conversation-history.ts +40 -6
  486. package/src/daemon/conversation-launch.ts +220 -0
  487. package/src/daemon/conversation-lifecycle.ts +85 -11
  488. package/src/daemon/conversation-messaging.ts +110 -7
  489. package/src/daemon/conversation-notifiers.ts +5 -0
  490. package/src/daemon/conversation-process.ts +591 -23
  491. package/src/daemon/conversation-queue-manager.ts +27 -0
  492. package/src/daemon/conversation-runtime-assembly.ts +769 -28
  493. package/src/daemon/conversation-slash.ts +38 -2
  494. package/src/daemon/conversation-surfaces.ts +483 -5
  495. package/src/daemon/conversation-tool-setup.ts +35 -5
  496. package/src/daemon/conversation-usage.ts +8 -5
  497. package/src/daemon/conversation.ts +193 -47
  498. package/src/daemon/external-skills-bootstrap.ts +41 -0
  499. package/src/daemon/guardian-action-generators.ts +34 -14
  500. package/src/daemon/handlers/config-model.test.ts +86 -0
  501. package/src/daemon/handlers/config-model.ts +54 -12
  502. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  503. package/src/daemon/handlers/conversations.ts +13 -3
  504. package/src/daemon/handlers/shared.ts +51 -1
  505. package/src/daemon/handlers/skills.ts +323 -79
  506. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  507. package/src/daemon/host-browser-proxy.ts +2 -1
  508. package/src/daemon/lifecycle.ts +185 -26
  509. package/src/daemon/message-protocol.ts +6 -0
  510. package/src/daemon/message-types/conversations.ts +48 -1
  511. package/src/daemon/message-types/home.ts +40 -0
  512. package/src/daemon/message-types/meet.ts +143 -0
  513. package/src/daemon/message-types/messages.ts +23 -1
  514. package/src/daemon/message-types/schedules.ts +34 -2
  515. package/src/daemon/message-types/skills.ts +16 -0
  516. package/src/daemon/message-types/surfaces.ts +2 -0
  517. package/src/daemon/message-types/trust.ts +0 -2
  518. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  519. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  520. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  521. package/src/daemon/pkb-context-tracker.ts +125 -0
  522. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  523. package/src/daemon/pkb-reminder-builder.ts +31 -0
  524. package/src/daemon/providers-setup.ts +6 -0
  525. package/src/daemon/server.ts +463 -10
  526. package/src/daemon/shutdown-handlers.ts +32 -4
  527. package/src/daemon/shutdown-registry.ts +40 -0
  528. package/src/daemon/tool-side-effects.ts +9 -9
  529. package/src/daemon/watch-handler.ts +4 -4
  530. package/src/daemon/web-search-history.ts +126 -0
  531. package/src/email/html-renderer.ts +76 -0
  532. package/src/events/domain-events.ts +0 -1
  533. package/src/filing/filing-service.ts +9 -10
  534. package/src/heartbeat/heartbeat-service.ts +156 -22
  535. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  536. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  537. package/src/home/__tests__/feed-scheduler.test.ts +222 -0
  538. package/src/home/__tests__/feed-types.test.ts +275 -0
  539. package/src/home/__tests__/feed-writer.test.ts +688 -0
  540. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  541. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  542. package/src/home/__tests__/progress-formula.test.ts +213 -0
  543. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  544. package/src/home/__tests__/rollup-producer.test.ts +442 -0
  545. package/src/home/assistant-feed-authoring.ts +128 -0
  546. package/src/home/emit-feed-event.ts +162 -0
  547. package/src/home/feed-scheduler.ts +263 -0
  548. package/src/home/feed-types.ts +235 -0
  549. package/src/home/feed-writer.ts +469 -0
  550. package/src/home/platform-gmail-digest.ts +163 -0
  551. package/src/home/progress-formula.ts +86 -0
  552. package/src/home/relationship-state-writer.ts +824 -0
  553. package/src/home/relationship-state.ts +143 -0
  554. package/src/home/rollup-producer.ts +413 -0
  555. package/src/home/suggested-prompts.ts +101 -0
  556. package/src/hooks/runner.ts +7 -0
  557. package/src/inbound/platform-callback-registration.ts +12 -3
  558. package/src/inbound/public-ingress-urls.ts +12 -0
  559. package/src/instrument.ts +1 -1
  560. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  561. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  562. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  563. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  564. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  565. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  566. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  567. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  568. package/src/ipc/cli-client.ts +152 -0
  569. package/src/ipc/cli-server.ts +252 -0
  570. package/src/ipc/gateway-client.ts +180 -0
  571. package/src/ipc/routes/attachment.ts +114 -0
  572. package/src/ipc/routes/browser-context.ts +61 -0
  573. package/src/ipc/routes/browser.ts +96 -0
  574. package/src/ipc/routes/cache.ts +96 -0
  575. package/src/ipc/routes/index.ts +21 -0
  576. package/src/ipc/routes/task-queue.ts +226 -0
  577. package/src/ipc/routes/task.ts +173 -0
  578. package/src/ipc/routes/ui-request.ts +50 -0
  579. package/src/ipc/routes/wake-conversation.ts +19 -0
  580. package/src/ipc/routes/watcher.ts +203 -0
  581. package/src/ipc/socket-path.ts +100 -0
  582. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  583. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  584. package/src/memory/__tests__/conversation-analyze-job.test.ts +233 -0
  585. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  586. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  587. package/src/memory/admin.ts +18 -0
  588. package/src/memory/app-store.ts +1 -1
  589. package/src/memory/attachments-store.ts +70 -0
  590. package/src/memory/auto-analysis-enqueue.ts +127 -0
  591. package/src/memory/auto-analysis-guard.ts +27 -0
  592. package/src/memory/cleanup-schedule-state.ts +37 -0
  593. package/src/memory/conversation-analyze-job.ts +74 -0
  594. package/src/memory/conversation-attention-store.ts +13 -6
  595. package/src/memory/conversation-crud.ts +199 -0
  596. package/src/memory/conversation-disk-view.ts +7 -0
  597. package/src/memory/conversation-group-migration.ts +65 -1
  598. package/src/memory/conversation-queries.ts +6 -5
  599. package/src/memory/conversation-title-service.ts +7 -4
  600. package/src/memory/db-init.ts +8 -0
  601. package/src/memory/db-maintenance.ts +108 -0
  602. package/src/memory/db.ts +1 -0
  603. package/src/memory/embedding-backend.ts +1 -1
  604. package/src/memory/graph/compaction.ts +299 -0
  605. package/src/memory/graph/consolidation.ts +4 -4
  606. package/src/memory/graph/conversation-graph-memory.ts +104 -29
  607. package/src/memory/graph/extraction.test.ts +295 -2
  608. package/src/memory/graph/extraction.ts +181 -51
  609. package/src/memory/graph/graph-search.test.ts +92 -0
  610. package/src/memory/graph/graph-search.ts +4 -1
  611. package/src/memory/graph/narrative.ts +2 -2
  612. package/src/memory/graph/pattern-scan.ts +2 -2
  613. package/src/memory/graph/retriever.test.ts +459 -0
  614. package/src/memory/graph/retriever.ts +257 -66
  615. package/src/memory/graph/scoring.test.ts +186 -0
  616. package/src/memory/graph/scoring.ts +31 -1
  617. package/src/memory/graph/store.ts +41 -0
  618. package/src/memory/graph/tool-handlers.ts +27 -0
  619. package/src/memory/graph/tools.ts +6 -1
  620. package/src/memory/group-crud.ts +6 -1
  621. package/src/memory/indexer.ts +95 -16
  622. package/src/memory/job-handlers/cleanup.ts +11 -8
  623. package/src/memory/job-handlers/conversation-starters.ts +39 -30
  624. package/src/memory/job-handlers/summarization.ts +2 -2
  625. package/src/memory/job-utils.ts +7 -1
  626. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  627. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  628. package/src/memory/jobs-store.ts +106 -5
  629. package/src/memory/jobs-worker.ts +26 -9
  630. package/src/memory/llm-usage-store.ts +92 -56
  631. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  632. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  633. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  634. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  635. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  636. package/src/memory/migrations/index.ts +7 -0
  637. package/src/memory/migrations/registry.ts +8 -0
  638. package/src/memory/pkb/pkb-index.test.ts +368 -0
  639. package/src/memory/pkb/pkb-index.ts +255 -0
  640. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  641. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  642. package/src/memory/pkb/pkb-search.test.ts +438 -0
  643. package/src/memory/pkb/pkb-search.ts +137 -0
  644. package/src/memory/pkb/types.ts +53 -0
  645. package/src/memory/qdrant-client.ts +122 -1
  646. package/src/memory/qdrant-manager.ts +43 -16
  647. package/src/memory/schema/conversations.ts +2 -0
  648. package/src/memory/schema/oauth.ts +3 -0
  649. package/src/memory/slack-thread-store.ts +37 -0
  650. package/src/memory/usage-buckets.ts +396 -0
  651. package/src/messaging/providers/gmail/adapter.ts +6 -16
  652. package/src/messaging/providers/gmail/client.ts +79 -6
  653. package/src/messaging/providers/gmail/types.ts +7 -0
  654. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  655. package/src/messaging/providers/slack/adapter.ts +155 -38
  656. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  657. package/src/messaging/providers/slack/backfill.ts +101 -0
  658. package/src/messaging/providers/slack/client.ts +16 -0
  659. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  660. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  661. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  662. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  663. package/src/messaging/providers/slack/types.ts +4 -0
  664. package/src/messaging/style-analyzer.ts +5 -2
  665. package/src/notifications/README.md +9 -5
  666. package/src/notifications/decision-engine.ts +6 -12
  667. package/src/notifications/preference-extractor.ts +2 -6
  668. package/src/notifications/signal.ts +5 -0
  669. package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
  670. package/src/oauth/byo-connection.test.ts +18 -1
  671. package/src/oauth/byo-connection.ts +3 -1
  672. package/src/oauth/connect-orchestrator.ts +2 -0
  673. package/src/oauth/connection-resolver.ts +6 -2
  674. package/src/oauth/connection.ts +2 -0
  675. package/src/oauth/oauth-store.ts +10 -0
  676. package/src/oauth/platform-connection.test.ts +145 -0
  677. package/src/oauth/platform-connection.ts +62 -31
  678. package/src/oauth/seed-providers.ts +10 -1
  679. package/src/permissions/approval-policy.test.ts +948 -0
  680. package/src/permissions/approval-policy.ts +257 -0
  681. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  682. package/src/permissions/bash-risk-classifier.ts +707 -0
  683. package/src/permissions/checker.ts +218 -699
  684. package/src/permissions/command-registry.test.ts +535 -0
  685. package/src/permissions/command-registry.ts +825 -0
  686. package/src/permissions/defaults.ts +71 -75
  687. package/src/permissions/file-risk-classifier.test.ts +535 -0
  688. package/src/permissions/file-risk-classifier.ts +274 -0
  689. package/src/permissions/risk-types.ts +205 -0
  690. package/src/permissions/secret-prompter.ts +53 -2
  691. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  692. package/src/permissions/skill-risk-classifier.ts +214 -0
  693. package/src/permissions/trust-client.ts +52 -25
  694. package/src/permissions/trust-store-interface.ts +1 -6
  695. package/src/permissions/trust-store.ts +164 -65
  696. package/src/permissions/types.ts +23 -14
  697. package/src/permissions/web-risk-classifier.test.ts +170 -0
  698. package/src/permissions/web-risk-classifier.ts +89 -0
  699. package/src/permissions/workspace-policy.ts +1 -13
  700. package/src/platform/client.test.ts +10 -0
  701. package/src/platform/client.ts +19 -1
  702. package/src/platform/sync-identity.ts +129 -0
  703. package/src/prompts/persona-resolver.ts +127 -3
  704. package/src/prompts/system-prompt.ts +78 -38
  705. package/src/prompts/templates/BOOTSTRAP.md +5 -5
  706. package/src/prompts/templates/SOUL.md +5 -3
  707. package/src/prompts/templates/channels/slack.md +20 -0
  708. package/src/prompts/update-bulletin-job.ts +190 -0
  709. package/src/prompts/user-reference.ts +20 -17
  710. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  711. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  712. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  713. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  714. package/src/providers/anthropic/client.ts +335 -70
  715. package/src/providers/call-site-routing.ts +71 -0
  716. package/src/providers/fireworks/client.ts +2 -2
  717. package/src/providers/gemini/client.ts +74 -3
  718. package/src/providers/managed-proxy/constants.ts +2 -1
  719. package/src/providers/model-catalog.ts +502 -28
  720. package/src/providers/model-intents.ts +8 -8
  721. package/src/providers/ollama/client.ts +2 -2
  722. package/src/providers/openai/chat-completions-provider.ts +530 -0
  723. package/src/providers/openai/client.ts +25 -440
  724. package/src/providers/openai/responses-provider.ts +579 -0
  725. package/src/providers/openrouter/client.ts +168 -4
  726. package/src/providers/provider-env-vars.ts +56 -0
  727. package/src/providers/provider-secret-catalog.ts +139 -0
  728. package/src/providers/provider-send-message.ts +22 -5
  729. package/src/providers/ratelimit.ts +4 -0
  730. package/src/providers/registry.ts +21 -10
  731. package/src/providers/retry.ts +185 -39
  732. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  733. package/src/providers/speech-to-text/__tests__/resolve.test.ts +883 -0
  734. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  735. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  736. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  737. package/src/providers/speech-to-text/deepgram.ts +115 -0
  738. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  739. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  740. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  741. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  742. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  743. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  744. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  745. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  746. package/src/providers/speech-to-text/provider-catalog.ts +323 -0
  747. package/src/providers/speech-to-text/resolve.ts +393 -6
  748. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  749. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  750. package/src/providers/speech-to-text/xai.test.ts +155 -0
  751. package/src/providers/speech-to-text/xai.ts +97 -0
  752. package/src/providers/types.ts +102 -3
  753. package/src/runtime/AGENTS.md +45 -3
  754. package/src/runtime/__tests__/agent-wake.test.ts +872 -0
  755. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  756. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  757. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  758. package/src/runtime/agent-wake.ts +553 -0
  759. package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
  760. package/src/runtime/auth/route-policy.ts +34 -5
  761. package/src/runtime/auth/token-service.ts +56 -1
  762. package/src/runtime/btw-sidechain.ts +15 -3
  763. package/src/runtime/capability-tokens.ts +10 -10
  764. package/src/runtime/channel-invite-transport.ts +1 -1
  765. package/src/runtime/channel-invite-transports/email.ts +14 -6
  766. package/src/runtime/channel-readiness-service.ts +12 -22
  767. package/src/runtime/channel-reply-delivery.ts +106 -2
  768. package/src/runtime/chrome-extension-registry.ts +38 -2
  769. package/src/runtime/decision-token.ts +116 -0
  770. package/src/runtime/gateway-client.ts +2 -2
  771. package/src/runtime/http-router.ts +32 -0
  772. package/src/runtime/http-server.ts +447 -11
  773. package/src/runtime/http-types.ts +29 -3
  774. package/src/runtime/interactive-ui.ts +362 -0
  775. package/src/runtime/invite-instruction-generator.ts +2 -2
  776. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  777. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
  778. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  779. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  780. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  781. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  782. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  783. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  784. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  785. package/src/runtime/migrations/migration-transport.ts +1 -0
  786. package/src/runtime/migrations/migration-wizard.ts +1 -0
  787. package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
  788. package/src/runtime/migrations/vbundle-importer.ts +187 -8
  789. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  790. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  791. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  792. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  793. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  794. package/src/runtime/pending-interactions.ts +0 -11
  795. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  796. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +618 -0
  797. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +247 -0
  798. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  799. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  800. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  801. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  802. package/src/runtime/routes/app-management-routes.ts +12 -18
  803. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  804. package/src/runtime/routes/approval-routes.ts +12 -17
  805. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  806. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  807. package/src/runtime/routes/attachment-routes.ts +216 -17
  808. package/src/runtime/routes/avatar-routes.ts +20 -4
  809. package/src/runtime/routes/backup-routes.ts +519 -0
  810. package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
  811. package/src/runtime/routes/btw-routes.ts +9 -10
  812. package/src/runtime/routes/contact-routes.test.ts +298 -0
  813. package/src/runtime/routes/contact-routes.ts +132 -5
  814. package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
  815. package/src/runtime/routes/conversation-management-routes.ts +133 -0
  816. package/src/runtime/routes/conversation-routes.ts +487 -160
  817. package/src/runtime/routes/debug-routes.ts +1 -1
  818. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  819. package/src/runtime/routes/events-routes.ts +16 -0
  820. package/src/runtime/routes/filing-routes.ts +93 -0
  821. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  822. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  823. package/src/runtime/routes/home-feed-routes.ts +452 -0
  824. package/src/runtime/routes/home-state-routes.ts +138 -0
  825. package/src/runtime/routes/host-browser-routes.ts +3 -14
  826. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  827. package/src/runtime/routes/identity-routes.ts +3 -17
  828. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  829. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  830. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  831. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  832. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  833. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  834. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  835. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  836. package/src/runtime/routes/integrations/slack/channel.ts +36 -6
  837. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  838. package/src/runtime/routes/llm-context-normalization.ts +325 -0
  839. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  840. package/src/runtime/routes/migration-routes.ts +722 -91
  841. package/src/runtime/routes/settings-routes.ts +26 -7
  842. package/src/runtime/routes/skills-routes.ts +76 -7
  843. package/src/runtime/routes/stt-routes.ts +233 -0
  844. package/src/runtime/routes/surface-action-routes.ts +41 -2
  845. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  846. package/src/runtime/routes/tts-routes.ts +108 -24
  847. package/src/runtime/routes/usage-routes.ts +30 -2
  848. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  849. package/src/runtime/routes/user-routes.ts +13 -1
  850. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  851. package/src/runtime/routes/work-items-routes.ts +11 -3
  852. package/src/runtime/runtime-mode.ts +33 -0
  853. package/src/runtime/services/__tests__/analyze-conversation.test.ts +426 -0
  854. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  855. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  856. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  857. package/src/runtime/services/analyze-conversation.ts +340 -0
  858. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  859. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  860. package/src/runtime/skill-route-registry.ts +71 -0
  861. package/src/runtime/slack-block-formatting.ts +437 -10
  862. package/src/schedule/scheduler.ts +58 -0
  863. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  864. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  865. package/src/security/oauth2.ts +122 -37
  866. package/src/security/secure-keys.ts +32 -10
  867. package/src/security/token-manager.ts +35 -13
  868. package/src/security/untrusted-content.ts +102 -0
  869. package/src/sequence/engine.ts +23 -0
  870. package/src/sequence/types.ts +1 -1
  871. package/src/skills/catalog-cache.ts +26 -7
  872. package/src/skills/catalog-files.ts +64 -2
  873. package/src/skills/catalog-install.ts +31 -3
  874. package/src/skills/category-inference.ts +122 -0
  875. package/src/skills/clawhub-files.ts +213 -0
  876. package/src/skills/clawhub.ts +84 -23
  877. package/src/skills/skill-cache-store.ts +97 -0
  878. package/src/skills/skill-file-provider.ts +40 -0
  879. package/src/skills/skillssh-files.ts +395 -0
  880. package/src/skills/skillssh-registry.ts +4 -4
  881. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +468 -0
  882. package/src/stt/__tests__/types.test.ts +89 -0
  883. package/src/stt/daemon-batch-transcriber.ts +228 -0
  884. package/src/stt/stt-stream-session.ts +506 -0
  885. package/src/stt/types.ts +334 -0
  886. package/src/stt/wav-encoder.test.ts +373 -0
  887. package/src/stt/wav-encoder.ts +175 -0
  888. package/src/subagent/manager.ts +79 -27
  889. package/src/tasks/ephemeral-permissions.ts +9 -4
  890. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  891. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  892. package/src/tools/browser/__tests__/browser-status.test.ts +166 -0
  893. package/src/tools/browser/browser-execution.ts +1208 -41
  894. package/src/tools/browser/browser-manager.ts +45 -0
  895. package/src/tools/browser/browser-mode-constants.ts +12 -0
  896. package/src/tools/browser/browser-mode.ts +92 -0
  897. package/src/tools/browser/browser-status-constants.ts +33 -0
  898. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
  899. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
  900. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
  901. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
  902. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +205 -17
  903. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
  904. package/src/tools/browser/cdp-client/errors.ts +15 -0
  905. package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
  906. package/src/tools/browser/cdp-client/factory.ts +797 -87
  907. package/src/tools/browser/cdp-client/index.ts +16 -2
  908. package/src/tools/browser/cdp-client/types.ts +68 -0
  909. package/src/tools/credentials/tool-policy.ts +39 -5
  910. package/src/tools/credentials/vault.ts +41 -7
  911. package/src/tools/executor.ts +4 -0
  912. package/src/tools/filesystem/write.ts +52 -0
  913. package/src/tools/host-terminal/host-shell.ts +45 -5
  914. package/src/tools/memory/register.test.ts +185 -0
  915. package/src/tools/memory/register.ts +3 -1
  916. package/src/tools/network/web-fetch.ts +25 -12
  917. package/src/tools/network/web-search.ts +20 -2
  918. package/src/tools/permission-checker.ts +36 -15
  919. package/src/tools/policy-context.ts +25 -8
  920. package/src/tools/registry.ts +55 -3
  921. package/src/tools/shared/shell-output.ts +3 -1
  922. package/src/tools/side-effects.ts +0 -9
  923. package/src/tools/skills/execute.ts +2 -2
  924. package/src/tools/skills/sandbox-runner.ts +6 -2
  925. package/src/tools/terminal/backends/native.ts +51 -2
  926. package/src/tools/terminal/safe-env.ts +11 -2
  927. package/src/tools/terminal/shell.ts +16 -4
  928. package/src/tools/tool-manifest.ts +6 -0
  929. package/src/tools/types.ts +29 -3
  930. package/src/tools/ui-surface/definitions.ts +6 -1
  931. package/src/tools/verification-control-plane-policy.ts +1 -1
  932. package/src/tts/__tests__/provider-adapters.test.ts +1061 -0
  933. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  934. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  935. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  936. package/src/tts/provider-catalog.ts +219 -0
  937. package/src/tts/provider-registry.ts +73 -0
  938. package/src/tts/providers/deepgram-provider.ts +219 -0
  939. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  940. package/src/tts/providers/fish-audio-provider.ts +183 -0
  941. package/src/tts/providers/index.ts +44 -0
  942. package/src/tts/providers/register-builtins.ts +130 -0
  943. package/src/tts/providers/xai-provider.ts +224 -0
  944. package/src/tts/synthesize-text.ts +110 -0
  945. package/src/tts/tts-config-resolver.ts +78 -0
  946. package/src/tts/types.ts +199 -0
  947. package/src/types/onboarding-context.ts +7 -0
  948. package/src/types/tar-stream.d.ts +66 -0
  949. package/src/util/abort-reasons.ts +58 -0
  950. package/src/util/device-id.ts +32 -16
  951. package/src/util/errors.ts +9 -1
  952. package/src/util/json.ts +17 -0
  953. package/src/util/platform.ts +56 -12
  954. package/src/util/pricing.ts +78 -5
  955. package/src/util/spawn.ts +1 -1
  956. package/src/util/truncate.ts +4 -2
  957. package/src/util/unicode.ts +201 -0
  958. package/src/version.ts +19 -24
  959. package/src/watcher/engine.ts +24 -1
  960. package/src/watcher/providers/google-calendar.ts +134 -8
  961. package/src/watcher/providers/outlook-calendar.ts +42 -2
  962. package/src/watcher/watcher-store.ts +31 -0
  963. package/src/workspace/git-service.ts +23 -4
  964. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  965. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  966. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  967. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  968. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  969. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  970. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  971. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  972. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  973. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  974. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  975. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  976. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  977. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  978. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  979. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  980. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  981. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  982. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  983. package/src/workspace/migrations/AGENTS.md +1 -1
  984. package/src/workspace/migrations/registry.ts +32 -0
  985. package/src/workspace/provider-commit-message-generator.ts +19 -38
  986. package/src/workspace/top-level-renderer.ts +13 -1
  987. package/src/workspace/turn-commit.ts +31 -0
  988. package/src/__tests__/email-cli.test.ts +0 -297
  989. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  990. package/src/__tests__/outlook-attachments.test.ts +0 -301
  991. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  992. package/src/__tests__/outlook-categories.test.ts +0 -212
  993. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  994. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  995. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  996. package/src/__tests__/outlook-trash.test.ts +0 -77
  997. package/src/__tests__/outlook-unsubscribe.test.ts +0 -250
  998. package/src/__tests__/update-bulletin-format.test.ts +0 -122
  999. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  1000. package/src/__tests__/update-bulletin.test.ts +0 -277
  1001. package/src/__tests__/update-template-contract.test.ts +0 -29
  1002. package/src/cli/commands/browser-relay.ts +0 -466
  1003. package/src/cli/commands/doctor.ts +0 -341
  1004. package/src/config/bundled-skills/browser/SKILL.md +0 -63
  1005. package/src/config/bundled-skills/browser/TOOLS.json +0 -393
  1006. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  1007. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  1008. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  1009. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  1010. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  1011. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  1012. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  1013. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  1014. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  1015. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  1016. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  1017. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  1018. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -32
  1019. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  1020. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  1021. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  1022. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  1023. package/src/config/bundled-skills/gmail/SKILL.md +0 -175
  1024. package/src/config/bundled-skills/gmail/TOOLS.json +0 -558
  1025. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -149
  1026. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  1027. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  1028. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  1029. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  1030. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  1031. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  1032. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -220
  1033. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  1034. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -251
  1035. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  1036. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  1037. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  1038. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  1039. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  1040. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  1041. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  1042. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  1043. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  1044. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  1045. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  1046. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  1047. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  1048. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  1049. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  1050. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  1051. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  1052. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  1053. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  1054. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  1055. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  1056. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  1057. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  1058. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  1059. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  1060. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  1061. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  1062. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  1063. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  1064. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  1065. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  1066. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  1067. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  1068. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  1069. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  1070. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  1071. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  1072. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  1073. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  1074. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  1075. package/src/config/bundled-skills/slack/SKILL.md +0 -107
  1076. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  1077. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  1078. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  1079. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  1080. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  1081. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  1082. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  1083. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  1084. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  1085. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  1086. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  1087. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  1088. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  1089. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  1090. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  1091. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  1092. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  1093. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  1094. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  1095. package/src/email/guardrails.ts +0 -221
  1096. package/src/email/provider.ts +0 -117
  1097. package/src/email/providers/agentmail.ts +0 -361
  1098. package/src/email/providers/index.ts +0 -65
  1099. package/src/email/service.ts +0 -384
  1100. package/src/email/types.ts +0 -126
  1101. package/src/prompts/templates/UPDATES.md +0 -38
  1102. package/src/prompts/templates/USER.md +0 -13
  1103. package/src/prompts/update-bulletin-format.ts +0 -68
  1104. package/src/prompts/update-bulletin-state.ts +0 -58
  1105. package/src/prompts/update-bulletin-template-path.ts +0 -13
  1106. package/src/prompts/update-bulletin.ts +0 -128
  1107. package/src/providers/speech-to-text/types.ts +0 -17
  1108. package/src/runtime/routes/browser-cdp-routes.ts +0 -229
  1109. package/src/shared/provider-env-vars.ts +0 -19
  1110. package/src/tools/watcher/create.ts +0 -86
  1111. package/src/tools/watcher/delete.ts +0 -36
  1112. package/src/tools/watcher/digest.ts +0 -54
  1113. package/src/tools/watcher/list.ts +0 -83
  1114. package/src/tools/watcher/update.ts +0 -71
@@ -7,6 +7,8 @@
7
7
  * runAgentLoop method here via the AgentLoopConversationContext interface.
8
8
  */
9
9
 
10
+ import { join } from "node:path";
11
+
10
12
  import { v4 as uuid } from "uuid";
11
13
 
12
14
  import type {
@@ -24,10 +26,18 @@ import type {
24
26
  } from "../channels/types.js";
25
27
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
26
28
  import { getConfig } from "../config/loader.js";
27
- import { derefToolResultReReads,postTurnTruncateToolResults } from "../context/post-turn-tool-result-truncation.js";
28
- import { estimatePromptTokens } from "../context/token-estimator.js";
29
+ import type { LLMCallSite } from "../config/schemas/llm.js";
30
+ import {
31
+ derefToolResultReReads,
32
+ postTurnTruncateToolResults,
33
+ } from "../context/post-turn-tool-result-truncation.js";
34
+ import {
35
+ estimatePromptTokens,
36
+ getCalibrationProviderKey,
37
+ } from "../context/token-estimator.js";
29
38
  import type { ContextWindowManager } from "../context/window-manager.js";
30
39
  import type { ToolProfiler } from "../events/tool-profiling-listener.js";
40
+ import { writeRelationshipState } from "../home/relationship-state-writer.js";
31
41
  import { getHookManager } from "../hooks/manager.js";
32
42
  import {
33
43
  clearSentryConversationContext,
@@ -35,12 +45,16 @@ import {
35
45
  } from "../instrument.js";
36
46
  import { commitAppTurnChanges } from "../memory/app-git-service.js";
37
47
  import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
48
+ import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
38
49
  import {
39
50
  addMessage,
51
+ clearPkbSystemReminderMetadataForConversation,
40
52
  deleteMessageById,
41
53
  getConversation,
42
54
  getConversationOriginChannel,
43
55
  getConversationOriginInterface,
56
+ getLastUserTimestampBefore,
57
+ getMessageById,
44
58
  provenanceFromTrustContext,
45
59
  updateConversationContextWindow,
46
60
  updateConversationTitle,
@@ -56,6 +70,7 @@ import {
56
70
  } from "../memory/conversation-title-service.js";
57
71
  import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
58
72
  import { recordMemoryRecallLog } from "../memory/memory-recall-log-store.js";
73
+ import { PKB_WORKSPACE_SCOPE } from "../memory/pkb/types.js";
59
74
  import type { PermissionPrompter } from "../permissions/prompter.js";
60
75
  import type { ContentBlock, Message } from "../providers/types.js";
61
76
  import type { Provider } from "../providers/types.js";
@@ -64,6 +79,8 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
64
79
  import { getSubagentManager } from "../subagent/index.js";
65
80
  import type { UsageActor } from "../usage/actors.js";
66
81
  import { getLogger } from "../util/logger.js";
82
+ import { getWorkspaceDir } from "../util/platform.js";
83
+ import { timeAgo } from "../util/time.js";
67
84
  import { truncate } from "../util/truncate.js";
68
85
  import { getWorkspaceGitService } from "../workspace/git-service.js";
69
86
  import { commitTurnChanges } from "../workspace/turn-commit.js";
@@ -107,8 +124,11 @@ import {
107
124
  buildSubagentStatusBlock,
108
125
  buildUnifiedTurnContextBlock,
109
126
  findLastInjectedNowContent,
127
+ getPkbAutoInjectList,
110
128
  inboundActorContextFromTrust,
111
129
  inboundActorContextFromTrustContext,
130
+ loadSlackActiveThreadFocusBlock,
131
+ loadSlackChronologicalMessages,
112
132
  readNowScratchpad,
113
133
  readPkbContext,
114
134
  stripInjectionsForCompaction,
@@ -127,44 +147,12 @@ import type {
127
147
  UsageStats,
128
148
  } from "./message-protocol.js";
129
149
  import type { MemoryRecalled } from "./message-types/memory.js";
150
+ import { parseActualTokensFromError } from "./parse-actual-tokens-from-error.js";
130
151
  import type { TraceEmitter } from "./trace-emitter.js";
152
+ import { stripHistoricalWebSearchResults } from "./web-search-history.js";
131
153
 
132
154
  const log = getLogger("conversation-agent-loop");
133
155
 
134
- /**
135
- * Parse the actual token count reported by the provider in a context-too-large
136
- * error message. Providers typically include the prompt size, e.g.:
137
- * "prompt is too long: 242201 tokens > 200000 maximum"
138
- * "too many input tokens: 242201 > 200000"
139
- *
140
- * Returns the actual token count or null if it cannot be parsed.
141
- */
142
- export function parseActualTokensFromError(
143
- errorMessage: string | null,
144
- ): number | null {
145
- if (!errorMessage) return null;
146
-
147
- // Match patterns like "242201 tokens > 200000" or "242201 > 200000 maximum"
148
- const match = errorMessage.match(
149
- /(\d[\d,]*)\s*tokens?\s*[>≥]|:\s*(\d[\d,]*)\s*[>≥]/i,
150
- );
151
- if (match) {
152
- const raw = (match[1] || match[2]).replace(/,/g, "");
153
- const parsed = parseInt(raw, 10);
154
- if (!isNaN(parsed) && parsed > 0) return parsed;
155
- }
156
-
157
- // Fallback: match "too many input tokens: N > M"
158
- const fallback = errorMessage.match(/(\d[\d,]*)\s*[>≥]\s*\d/);
159
- if (fallback) {
160
- const raw = fallback[1].replace(/,/g, "");
161
- const parsed = parseInt(raw, 10);
162
- if (!isNaN(parsed) && parsed > 0) return parsed;
163
- }
164
-
165
- return null;
166
- }
167
-
168
156
  /** Title-cased friendly labels for tool names, used in confirmation chips. */
169
157
  const TOOL_FRIENDLY_LABEL: Record<string, string> = {
170
158
  bash: "Run Command",
@@ -173,12 +161,6 @@ const TOOL_FRIENDLY_LABEL: Record<string, string> = {
173
161
  file_read: "Read File",
174
162
  file_write: "Write File",
175
163
  file_edit: "Edit File",
176
- browser_navigate: "Browser",
177
- browser_click: "Browser",
178
- browser_type: "Browser",
179
- browser_screenshot: "Browser",
180
- browser_scroll: "Browser",
181
- browser_wait: "Browser",
182
164
  app_create: "Create App",
183
165
  app_refresh: "Refresh App",
184
166
  skill_load: "Load Skill",
@@ -189,6 +171,79 @@ type GitServiceInitializer = {
189
171
  ensureInitialized(): Promise<void>;
190
172
  };
191
173
 
174
+ // ── Compaction circuit-breaker constants ────────────────────────────
175
+ //
176
+ // The circuit opens after `COMPACTION_CIRCUIT_FAILURE_THRESHOLD` consecutive
177
+ // summary-LLM failures and stays open for `COMPACTION_CIRCUIT_COOLDOWN_MS`
178
+ // before auto-compaction is allowed to retry. User-initiated compaction
179
+ // (`force: true`) bypasses the breaker regardless of its state.
180
+ const COMPACTION_CIRCUIT_FAILURE_THRESHOLD = 3;
181
+ const COMPACTION_CIRCUIT_COOLDOWN_MS = 60 * 60 * 1000; // 1 hour
182
+
183
+ /**
184
+ * Check whether the compaction circuit breaker is currently open for the
185
+ * given context. The breaker auto-closes once `compactionCircuitOpenUntil`
186
+ * has elapsed.
187
+ */
188
+ export function isCompactionCircuitOpen(ctx: {
189
+ compactionCircuitOpenUntil: number | null;
190
+ }): boolean {
191
+ return (
192
+ ctx.compactionCircuitOpenUntil !== null &&
193
+ Date.now() < ctx.compactionCircuitOpenUntil
194
+ );
195
+ }
196
+
197
+ /**
198
+ * Track the outcome of a `maybeCompact()` call against the circuit breaker.
199
+ *
200
+ * - When the summary LLM call failed (local fallback covered the result),
201
+ * increment the consecutive-failure counter. If the counter reaches the
202
+ * threshold, open the circuit for the cooldown window and emit
203
+ * `compaction_circuit_open` so clients can surface a notice.
204
+ * - When the call did not fail, reset the counter and clear any open circuit.
205
+ *
206
+ * This is called by every `maybeCompact()` site (including forced ones),
207
+ * because a run of three failures is a provider-health signal regardless of
208
+ * whether the caller bypassed the breaker.
209
+ */
210
+ export function trackCompactionOutcome(
211
+ ctx: {
212
+ consecutiveCompactionFailures: number;
213
+ compactionCircuitOpenUntil: number | null;
214
+ },
215
+ summaryFailed: boolean | undefined,
216
+ onEvent: (msg: ServerMessage) => void,
217
+ ): void {
218
+ if (summaryFailed) {
219
+ ctx.consecutiveCompactionFailures += 1;
220
+ // Treat a stale/expired open-until timestamp the same as null so a new
221
+ // 3-strike window can re-open the circuit after the prior cooldown
222
+ // elapses. Without this the second trip would no-op because
223
+ // `compactionCircuitOpenUntil` remains set to a past timestamp even
224
+ // though `isCompactionCircuitOpen()` correctly reports closed.
225
+ const circuitDormant =
226
+ ctx.compactionCircuitOpenUntil === null ||
227
+ Date.now() >= ctx.compactionCircuitOpenUntil;
228
+ if (
229
+ ctx.consecutiveCompactionFailures >=
230
+ COMPACTION_CIRCUIT_FAILURE_THRESHOLD &&
231
+ circuitDormant
232
+ ) {
233
+ const openUntil = Date.now() + COMPACTION_CIRCUIT_COOLDOWN_MS;
234
+ ctx.compactionCircuitOpenUntil = openUntil;
235
+ onEvent({
236
+ type: "compaction_circuit_open",
237
+ reason: "3_consecutive_failures",
238
+ openUntil,
239
+ });
240
+ }
241
+ } else {
242
+ ctx.consecutiveCompactionFailures = 0;
243
+ ctx.compactionCircuitOpenUntil = null;
244
+ }
245
+ }
246
+
192
247
  // ── Context Interface ────────────────────────────────────────────────
193
248
 
194
249
  export interface AgentLoopConversationContext {
@@ -205,6 +260,10 @@ export interface AgentLoopConversationContext {
205
260
  readonly contextWindowManager: ContextWindowManager;
206
261
  contextCompactedMessageCount: number;
207
262
  contextCompactedAt: number | null;
263
+ /** Tracks consecutive compaction failures (summary LLM call threw). */
264
+ consecutiveCompactionFailures: number;
265
+ /** Timestamp (ms since epoch) until which the circuit breaker is open. */
266
+ compactionCircuitOpenUntil: number | null;
208
267
 
209
268
  readonly memoryPolicy: { scopeId: string; includeDefaultFallback: boolean };
210
269
  readonly graphMemory: ConversationGraphMemory;
@@ -227,6 +286,7 @@ export interface AgentLoopConversationContext {
227
286
  >;
228
287
  pendingSurfaceActions: Map<string, { surfaceType: SurfaceType }>;
229
288
  surfaceActionRequestIds: Set<string>;
289
+ approvedViaPromptThisTurn?: boolean;
230
290
  currentTurnSurfaces: Array<{
231
291
  surfaceId: string;
232
292
  surfaceType: SurfaceType;
@@ -234,6 +294,7 @@ export interface AgentLoopConversationContext {
234
294
  data: SurfaceData;
235
295
  actions?: Array<{ id: string; label: string; style?: string }>;
236
296
  display?: string;
297
+ persistent?: boolean;
237
298
  }>;
238
299
 
239
300
  workingDir: string;
@@ -246,6 +307,8 @@ export interface AgentLoopConversationContext {
246
307
  currentTurnChannelCapabilities?: ChannelCapabilities;
247
308
  commandIntent?: { type: string; payload?: string; languageCode?: string };
248
309
  trustContext?: TrustContext;
310
+ /** Task-run scope for the current turn. Cleared at turn end so queued/drained turns don't inherit it. */
311
+ taskRunId?: string;
249
312
  assistantId?: string;
250
313
  voiceCallControlPrompt?: string;
251
314
  transportHints?: string[];
@@ -345,6 +408,13 @@ export async function runAgentLoopImpl(
345
408
  isInteractive?: boolean;
346
409
  isUserMessage?: boolean;
347
410
  titleText?: string;
411
+ /**
412
+ * LLM call-site identifier threaded into the per-call provider config.
413
+ * Adapter callers (heartbeat, filing, scheduler, etc.) pass their own
414
+ * call-site id so the resolver picks `llm.callSites.<id>`. When unset,
415
+ * the agent loop defaults to `'mainAgent'` for user-initiated turns.
416
+ */
417
+ callSite?: LLMCallSite;
348
418
  },
349
419
  ): Promise<void> {
350
420
  if (!ctx.abortController) {
@@ -368,6 +438,13 @@ export async function runAgentLoopImpl(
368
438
  });
369
439
  let yieldedForHandoff = false;
370
440
 
441
+ // Default user-initiated turns to the `mainAgent` call site. Other
442
+ // invocation contexts (heartbeat, filing, analyze, etc.) pass their own
443
+ // `callSite`. The provider layer resolves provider/model/maxTokens via
444
+ // `resolveCallSiteConfig`, picking up any user overrides under
445
+ // `llm.callSites.mainAgent` (falling back to `llm.default` when absent).
446
+ const turnCallSite: LLMCallSite = options?.callSite ?? "mainAgent";
447
+
371
448
  // Capture the turn channel context *before* any awaits so a second
372
449
  // message from a different channel can't overwrite it mid-flight.
373
450
  // When context is unavailable (e.g. regenerate after daemon restart),
@@ -513,7 +590,10 @@ export async function runAgentLoopImpl(
513
590
  let compactedThisTurn = false;
514
591
 
515
592
  const compactCheck = ctx.contextWindowManager.shouldCompact(ctx.messages);
516
- if (compactCheck.needed) {
593
+ // Skip auto-compaction while the circuit breaker is open. Force paths
594
+ // and user-initiated /compact bypass this check.
595
+ const autoCompactAllowed = !isCompactionCircuitOpen(ctx);
596
+ if (compactCheck.needed && autoCompactAllowed) {
517
597
  ctx.emitActivityState(
518
598
  "thinking",
519
599
  "context_compacting",
@@ -521,15 +601,27 @@ export async function runAgentLoopImpl(
521
601
  reqId,
522
602
  );
523
603
  }
524
- const compacted = await ctx.contextWindowManager.maybeCompact(
525
- ctx.messages,
526
- abortController.signal,
527
- {
528
- lastCompactedAt: ctx.contextCompactedAt ?? undefined,
529
- precomputedEstimate: compactCheck.estimatedTokens,
530
- },
531
- );
532
- if (compacted.compacted) {
604
+ const compacted = autoCompactAllowed
605
+ ? await ctx.contextWindowManager.maybeCompact(
606
+ ctx.messages,
607
+ abortController.signal,
608
+ {
609
+ lastCompactedAt: ctx.contextCompactedAt ?? undefined,
610
+ precomputedEstimate: compactCheck.estimatedTokens,
611
+ conversationOriginChannel:
612
+ getConversationOriginChannel(ctx.conversationId) ?? undefined,
613
+ },
614
+ )
615
+ : null;
616
+ // Only track circuit-breaker state when a summary LLM call actually ran.
617
+ // `summaryFailed` is `undefined` on early returns (compaction disabled,
618
+ // below threshold, cooldown active, no eligible messages, truncation-only
619
+ // path) — treating those as "successful" compactions would silently reset
620
+ // the 3-strike counter and break the invariant.
621
+ if (compacted && compacted.summaryFailed !== undefined) {
622
+ trackCompactionOutcome(ctx, compacted.summaryFailed, onEvent);
623
+ }
624
+ if (compacted?.compacted) {
533
625
  ctx.messages = compacted.messages;
534
626
  ctx.contextCompactedMessageCount += compacted.compactedPersistedMessages;
535
627
  ctx.contextCompactedAt = Date.now();
@@ -541,6 +633,13 @@ export async function runAgentLoopImpl(
541
633
  compacted.summaryText,
542
634
  ctx.contextCompactedMessageCount,
543
635
  );
636
+ // Fire auto-analysis on compaction so the reflective agent can
637
+ // crystallize anything worth remembering before the context window
638
+ // narrows further.
639
+ enqueueAutoAnalysisOnCompaction(
640
+ ctx.conversationId,
641
+ ctx.trustContext?.trustClass,
642
+ );
544
643
  onEvent({
545
644
  type: "context_compacted",
546
645
  previousEstimatedInputTokens: compacted.previousEstimatedInputTokens,
@@ -613,7 +712,12 @@ export async function runAgentLoopImpl(
613
712
  let runMessages = ctx.messages;
614
713
 
615
714
  // Memory graph retrieval — dispatches to context-load / per-turn based on
616
- // conversation state.
715
+ // conversation state. Keep the query vector around so the PKB reminder
716
+ // can reuse it for relevance-hint search (see `applyRuntimeInjections`).
717
+ let pkbQueryVector: number[] | undefined;
718
+ let pkbSparseVector:
719
+ | import("../memory/qdrant-client.js").QdrantSparseVector
720
+ | undefined;
617
721
  const isTrustedActor = resolveTrustClass(ctx.trustContext) === "guardian";
618
722
  if (isTrustedActor) {
619
723
  const graphResult = await ctx.graphMemory.prepareMemory(
@@ -623,6 +727,22 @@ export async function runAgentLoopImpl(
623
727
  onEvent,
624
728
  );
625
729
  runMessages = graphResult.runMessages;
730
+ // Select dense+sparse as a matched pair so RRF fusion combines two
731
+ // signals aligned to the same query text:
732
+ // 1. Context-load with a user query: user-query dense + user-query
733
+ // sparse — the cleanest pairing.
734
+ // 2. Otherwise (context-load without a user query, or per-turn):
735
+ // whatever `queryVector` / `sparseVector` the retriever produced,
736
+ // which are themselves co-aligned (both summary-derived in
737
+ // context-load, both user-last-message-derived in per-turn).
738
+ // Never pair a user-query dense with a summary-aligned sparse.
739
+ if (graphResult.userQueryVector) {
740
+ pkbQueryVector = graphResult.userQueryVector;
741
+ pkbSparseVector = graphResult.userQuerySparseVector;
742
+ } else {
743
+ pkbQueryVector = graphResult.queryVector;
744
+ pkbSparseVector = graphResult.sparseVector;
745
+ }
626
746
 
627
747
  // Persist the injected block text in message metadata so it survives
628
748
  // conversation reloads (eviction, restart, fork). loadFromDb re-injects
@@ -773,14 +893,35 @@ export async function runAgentLoopImpl(
773
893
  const isGuardian =
774
894
  resolvedInboundActorContext?.trustClass === "guardian" ||
775
895
  !resolvedInboundActorContext;
896
+
897
+ // Surface long gaps between user messages so the model can acknowledge
898
+ // the absence naturally. Gated at >12h to avoid noisy injection during
899
+ // normal back-and-forth turns.
900
+ const TWELVE_HOURS_MS = 12 * 60 * 60 * 1000;
901
+ let timeSinceLastMessage: string | null = null;
902
+ const currentUserMessage = getMessageById(userMessageId);
903
+ if (currentUserMessage) {
904
+ const prevUserTs = getLastUserTimestampBefore(
905
+ ctx.conversationId,
906
+ currentUserMessage.createdAt,
907
+ );
908
+ if (
909
+ prevUserTs > 0 &&
910
+ currentUserMessage.createdAt - prevUserTs > TWELVE_HOURS_MS
911
+ ) {
912
+ timeSinceLastMessage = timeAgo(prevUserTs);
913
+ }
914
+ }
915
+
776
916
  const unifiedTurnContextStr = buildUnifiedTurnContextBlock(
777
917
  isGuardian
778
- ? { timestamp, interfaceName, channelName }
918
+ ? { timestamp, interfaceName, channelName, timeSinceLastMessage }
779
919
  : {
780
920
  timestamp,
781
921
  interfaceName,
782
922
  channelName,
783
923
  actorContext: resolvedInboundActorContext,
924
+ timeSinceLastMessage,
784
925
  },
785
926
  );
786
927
 
@@ -800,6 +941,21 @@ export async function runAgentLoopImpl(
800
941
  const pkbContext = shouldInjectNowAndPkb ? currentPkbContent : null;
801
942
  const pkbActive = currentPkbContent !== null;
802
943
 
944
+ // PKB relevance-hint inputs. Resolved once per turn and reused across
945
+ // re-injections so post-compaction rebuilds pick up fresh hints against
946
+ // the updated conversation history.
947
+ const pkbRoot = pkbActive ? join(getWorkspaceDir(), "pkb") : undefined;
948
+ const pkbAutoInjectList = pkbRoot
949
+ ? getPkbAutoInjectList(pkbRoot)
950
+ : undefined;
951
+ // Pass `ctx` directly — `PkbContextConversation` is structural and
952
+ // `getInContextPkbPaths` re-reads `conversation.messages` on each call,
953
+ // so post-compaction re-injects see the updated history.
954
+ const pkbConversation = pkbActive ? ctx : undefined;
955
+ // PKB points live under a single workspace sentinel scope, not the
956
+ // conversation's memoryPolicy.scopeId. See `PKB_WORKSPACE_SCOPE` for why.
957
+ const pkbScopeId = pkbActive ? PKB_WORKSPACE_SCOPE : undefined;
958
+
803
959
  // Subagent status injection — gives the parent LLM visibility into active/completed children.
804
960
  // Skipped when this conversation IS a subagent (no nesting) or has no children.
805
961
  const subagentStatusBlock = ctx.isSubagent
@@ -808,6 +964,43 @@ export async function runAgentLoopImpl(
808
964
  getSubagentManager().getChildrenOf(ctx.conversationId),
809
965
  );
810
966
 
967
+ // For any Slack conversation (channels and DMs alike), build a
968
+ // chronological transcript from the persisted message rows so the
969
+ // model sees one channel-wide view instead of the gateway's per-turn
970
+ // hints. DMs render as a flat sequence (no thread tags), channels
971
+ // include sibling threads.
972
+ const isSlackConversation = ctx.channelCapabilities?.channel === "slack";
973
+ const slackChronologicalMessages = isSlackConversation
974
+ ? loadSlackChronologicalMessages(
975
+ ctx.conversationId,
976
+ ctx.channelCapabilities!,
977
+ { trustClass: ctx.trustContext?.trustClass },
978
+ )
979
+ : null;
980
+
981
+ // Active-thread focus block: when the inbound user message belongs to
982
+ // a Slack thread, append a non-persisted `<active_thread>` tail block
983
+ // to the final user turn listing the thread's parent + replies. Helps
984
+ // the model orient when the channel transcript is long and
985
+ // interleaved. Replays strip the block via RUNTIME_INJECTION_PREFIXES.
986
+ // DMs short-circuit to null inside `loadSlackActiveThreadFocusBlock`
987
+ // since DMs do not have threads.
988
+ const slackActiveThreadFocusBlock = isSlackConversation
989
+ ? loadSlackActiveThreadFocusBlock(
990
+ ctx.conversationId,
991
+ ctx.channelCapabilities!,
992
+ { trustClass: ctx.trustContext?.trustClass },
993
+ )
994
+ : null;
995
+
996
+ // Guards the chronological-transcript override on re-injection after
997
+ // the reducer compacts `ctx.messages`. The captured transcript is the
998
+ // full persisted history; blindly replaying it on every re-inject would
999
+ // overwrite the reducer's compacted messages and undo compaction. Flip
1000
+ // to `true` after any compaction so subsequent re-injections fall back
1001
+ // to the reduced `ctx.messages`.
1002
+ let reducerCompacted = compactedThisTurn;
1003
+
811
1004
  // Shared injection options — reused whenever we need to re-inject after reduction.
812
1005
  const injectionOpts = {
813
1006
  activeSurface,
@@ -819,27 +1012,66 @@ export async function runAgentLoopImpl(
819
1012
  unifiedTurnContext: unifiedTurnContextStr,
820
1013
  pkbContext,
821
1014
  pkbActive,
1015
+ pkbQueryVector,
1016
+ pkbSparseVector,
1017
+ pkbScopeId,
1018
+ pkbConversation,
1019
+ pkbAutoInjectList,
1020
+ pkbRoot,
1021
+ pkbWorkingDir: pkbActive ? ctx.workingDir : undefined,
822
1022
  nowScratchpad,
823
1023
  voiceCallControlPrompt: ctx.voiceCallControlPrompt ?? null,
824
1024
  transportHints: ctx.transportHints ?? null,
825
1025
  isNonInteractive: !isInteractiveResolved,
826
1026
  subagentStatusBlock,
1027
+ slackChronologicalMessages,
1028
+ slackActiveThreadFocusBlock,
827
1029
  } as const;
828
1030
 
829
1031
  let currentInjectionMode: InjectionMode = "full";
830
1032
 
831
- runMessages = applyRuntimeInjections(runMessages, {
1033
+ const injection = await applyRuntimeInjections(runMessages, {
832
1034
  ...injectionOpts,
1035
+ slackChronologicalMessages: reducerCompacted
1036
+ ? null
1037
+ : injectionOpts.slackChronologicalMessages,
833
1038
  mode: currentInjectionMode,
834
1039
  });
1040
+ runMessages = injection.messages;
1041
+
1042
+ // Persist injected blocks in message metadata so they survive conversation
1043
+ // reloads (eviction, restart, fork). loadFromDb re-injects from metadata.
1044
+ // Only the first call site persists — the overflow-recovery re-entry sites
1045
+ // send identical bytes and the tail row may not correspond to
1046
+ // `userMessageId`. Both blocks are written in a single call to avoid
1047
+ // doubling SQLite SELECT+UPDATE work on every turn.
1048
+ if (
1049
+ injection.blocks.unifiedTurnContext ||
1050
+ injection.blocks.pkbSystemReminder
1051
+ ) {
1052
+ try {
1053
+ const metadataUpdates: Record<string, unknown> = {};
1054
+ if (injection.blocks.unifiedTurnContext) {
1055
+ metadataUpdates.turnContextBlock =
1056
+ injection.blocks.unifiedTurnContext;
1057
+ }
1058
+ if (injection.blocks.pkbSystemReminder) {
1059
+ metadataUpdates.pkbSystemReminderBlock =
1060
+ injection.blocks.pkbSystemReminder;
1061
+ }
1062
+ updateMessageMetadata(userMessageId, metadataUpdates);
1063
+ } catch (err) {
1064
+ rlog.warn({ err }, "Failed to persist injection metadata (non-fatal)");
1065
+ }
1066
+ }
835
1067
 
836
1068
  // ── Preflight budget evaluation ──────────────────────────────
837
1069
  // After runtime injections are applied, estimate the prompt token count
838
1070
  // and proactively invoke the reducer if already above budget. This avoids
839
1071
  // a wasted provider round-trip that would just fail with context_too_large.
840
1072
  const config = getConfig();
841
- const overflowRecovery = config.contextWindow.overflowRecovery;
842
- const providerMaxTokens = config.contextWindow.maxInputTokens;
1073
+ const overflowRecovery = config.llm.default.contextWindow.overflowRecovery;
1074
+ const providerMaxTokens = config.llm.default.contextWindow.maxInputTokens;
843
1075
  // Widen safety margin for large conversations where estimation error
844
1076
  // compounds across many messages with tool results.
845
1077
  const baseSafetyMargin = overflowRecovery.safetyMarginRatio;
@@ -850,10 +1082,17 @@ export async function runAgentLoopImpl(
850
1082
  let reducerState: ReducerState | undefined;
851
1083
 
852
1084
  const toolTokenBudget = ctx.agentLoop.getToolTokenBudget(runMessages);
1085
+ // Canonical calibration key used at every `estimatePromptTokens` site in
1086
+ // this function. Matches the key recorded by `handleUsage` for wrapper
1087
+ // providers (OpenRouter routing to Anthropic → key is `"anthropic"`).
1088
+ const estimationProviderName = getCalibrationProviderKey(ctx.provider);
853
1089
  const preflightTokens = estimatePromptTokens(
854
1090
  runMessages,
855
1091
  ctx.systemPrompt,
856
- { providerName: ctx.provider.name, toolTokenBudget },
1092
+ {
1093
+ providerName: estimationProviderName,
1094
+ toolTokenBudget,
1095
+ },
857
1096
  );
858
1097
 
859
1098
  if (overflowRecovery.enabled && preflightTokens > preflightBudget) {
@@ -883,9 +1122,9 @@ export async function runAgentLoopImpl(
883
1122
  const step = await reduceContextOverflow(
884
1123
  ctx.messages,
885
1124
  {
886
- providerName: ctx.provider.name,
1125
+ providerName: estimationProviderName,
887
1126
  systemPrompt: ctx.systemPrompt,
888
- contextWindow: config.contextWindow,
1127
+ contextWindow: config.llm.default.contextWindow,
889
1128
  targetTokens: preflightBudget,
890
1129
  toolTokenBudget,
891
1130
  },
@@ -899,6 +1138,24 @@ export async function runAgentLoopImpl(
899
1138
  ctx.messages = step.messages;
900
1139
  currentInjectionMode = step.state.injectionMode;
901
1140
 
1141
+ // Track circuit-breaker state whenever the reducer invoked compaction.
1142
+ // The reducer's forced_compaction tier uses force:true, so it bypasses
1143
+ // the open-circuit check, but we still want failure tracking to detect
1144
+ // a run of broken summaries and clear the counter on success. Only
1145
+ // track when the summary LLM actually ran — `summaryFailed === undefined`
1146
+ // indicates an early return (no eligible messages, truncation-only
1147
+ // path, etc.) that shouldn't influence the breaker.
1148
+ if (
1149
+ step.compactionResult &&
1150
+ step.compactionResult.summaryFailed !== undefined
1151
+ ) {
1152
+ trackCompactionOutcome(
1153
+ ctx,
1154
+ step.compactionResult.summaryFailed,
1155
+ onEvent,
1156
+ );
1157
+ }
1158
+
902
1159
  if (step.compactionResult?.compacted) {
903
1160
  ctx.contextCompactedMessageCount +=
904
1161
  step.compactionResult.compactedPersistedMessages;
@@ -908,6 +1165,11 @@ export async function runAgentLoopImpl(
908
1165
  step.compactionResult.summaryText,
909
1166
  ctx.contextCompactedMessageCount,
910
1167
  );
1168
+ // Fire auto-analysis on compaction — see forceCompact() for rationale.
1169
+ enqueueAutoAnalysisOnCompaction(
1170
+ ctx.conversationId,
1171
+ ctx.trustContext?.trustClass,
1172
+ );
911
1173
  onEvent({
912
1174
  type: "context_compacted",
913
1175
  previousEstimatedInputTokens:
@@ -937,21 +1199,34 @@ export async function runAgentLoopImpl(
937
1199
  step.compactionResult.compactedPersistedMessages,
938
1200
  );
939
1201
  shouldInjectWorkspace = true;
1202
+ reducerCompacted = true;
940
1203
  }
941
1204
 
942
1205
  // Re-inject with potentially downgraded injection mode.
943
1206
  // When compaction ran it strips existing NOW.md / PKB blocks, so we
944
1207
  // must re-inject the current content. Otherwise rely on the deduplicated
945
1208
  // value from injectionOpts to avoid duplicate injection.
946
- runMessages = applyRuntimeInjections(ctx.messages, {
1209
+ const injection = await applyRuntimeInjections(ctx.messages, {
947
1210
  ...injectionOpts,
948
- ...(step.compactionResult?.compacted && { pkbContext: currentPkbContent }),
949
- ...(step.compactionResult?.compacted && { nowScratchpad: currentNowContent }),
1211
+ ...(step.compactionResult?.compacted && {
1212
+ pkbContext: currentPkbContent,
1213
+ }),
1214
+ ...(step.compactionResult?.compacted && {
1215
+ nowScratchpad: currentNowContent,
1216
+ }),
950
1217
  workspaceTopLevelContext: shouldInjectWorkspace
951
1218
  ? ctx.workspaceTopLevelContext
952
1219
  : null,
1220
+ // Once the reducer has compacted `ctx.messages`, the captured
1221
+ // `slackChronologicalMessages` snapshot (built from the full
1222
+ // persisted transcript) would overwrite the compacted history
1223
+ // and undo compaction. Suppress the override from here on.
1224
+ slackChronologicalMessages: reducerCompacted
1225
+ ? null
1226
+ : injectionOpts.slackChronologicalMessages,
953
1227
  mode: currentInjectionMode,
954
1228
  });
1229
+ runMessages = injection.messages;
955
1230
  if (isTrustedActor && currentInjectionMode !== "minimal") {
956
1231
  const memResult = ctx.graphMemory.reinjectCachedMemory(runMessages);
957
1232
  runMessages = memResult.runMessages;
@@ -963,7 +1238,10 @@ export async function runAgentLoopImpl(
963
1238
  const postInjectionTokens = estimatePromptTokens(
964
1239
  runMessages,
965
1240
  ctx.systemPrompt,
966
- { providerName: ctx.provider.name, toolTokenBudget },
1241
+ {
1242
+ providerName: estimationProviderName,
1243
+ toolTokenBudget,
1244
+ },
967
1245
  );
968
1246
 
969
1247
  if (postInjectionTokens <= preflightBudget) break;
@@ -986,6 +1264,20 @@ export async function runAgentLoopImpl(
986
1264
  runMessages = preRunRepair.messages;
987
1265
  }
988
1266
 
1267
+ // Replace historical web_search_tool_result blocks with text summaries.
1268
+ // The opaque `encrypted_content` tokens Anthropic attaches to each result
1269
+ // expire / are route-scoped; replaying a stale token is rejected with
1270
+ // `Invalid encrypted_content in search_result block`. Titles + URLs
1271
+ // preserve enough context for the model on follow-up turns.
1272
+ const webSearchStrip = stripHistoricalWebSearchResults(runMessages);
1273
+ if (webSearchStrip.stats.blocksStripped > 0) {
1274
+ rlog.info(
1275
+ { phase: "pre_run", ...webSearchStrip.stats },
1276
+ "Converted historical web_search_tool_result blocks to text summaries",
1277
+ );
1278
+ runMessages = webSearchStrip.messages;
1279
+ }
1280
+
989
1281
  let preRunHistoryLength = runMessages.length;
990
1282
 
991
1283
  const shouldGenerateTitle = isReplaceableTitle(
@@ -1008,17 +1300,11 @@ export async function runAgentLoopImpl(
1008
1300
  let yieldedForBudget = false;
1009
1301
 
1010
1302
  const onCheckpoint = (checkpoint: CheckpointInfo): CheckpointDecision => {
1011
- const turnTools = state.currentTurnToolNames;
1012
1303
  state.currentTurnToolNames = [];
1013
1304
 
1014
1305
  if (ctx.canHandoffAtCheckpoint()) {
1015
- const inBrowserFlow =
1016
- turnTools.length > 0 &&
1017
- turnTools.every((n) => n.startsWith("browser_"));
1018
- if (!inBrowserFlow) {
1019
- yieldedForHandoff = true;
1020
- return "yield";
1021
- }
1306
+ yieldedForHandoff = true;
1307
+ return "yield";
1022
1308
  }
1023
1309
 
1024
1310
  // Mid-loop token budget check: estimate current context size and
@@ -1029,7 +1315,10 @@ export async function runAgentLoopImpl(
1029
1315
  const estimated = estimatePromptTokens(
1030
1316
  checkpoint.history,
1031
1317
  ctx.systemPrompt,
1032
- { providerName: ctx.provider.name, toolTokenBudget },
1318
+ {
1319
+ providerName: estimationProviderName,
1320
+ toolTokenBudget,
1321
+ },
1033
1322
  );
1034
1323
  if (estimated > midLoopThreshold) {
1035
1324
  rlog.warn(
@@ -1048,12 +1337,20 @@ export async function runAgentLoopImpl(
1048
1337
 
1049
1338
  let denyCompressionMessage: Message | null = null;
1050
1339
 
1340
+ rlog.info({ callSite: turnCallSite }, "Starting agent loop run");
1341
+
1051
1342
  let updatedHistory = await ctx.agentLoop.run(
1052
1343
  runMessages,
1053
1344
  eventHandler,
1054
1345
  abortController.signal,
1055
1346
  reqId,
1056
1347
  onCheckpoint,
1348
+ turnCallSite,
1349
+ );
1350
+
1351
+ rlog.info(
1352
+ { resultMessageCount: updatedHistory.length },
1353
+ "Agent loop run completed",
1057
1354
  );
1058
1355
 
1059
1356
  // ── Proactive mid-loop compaction ───────────────────────────────
@@ -1081,6 +1378,14 @@ export async function runAgentLoopImpl(
1081
1378
  // so we compact the "raw" persistent messages.
1082
1379
  const rawHistory = stripInjectionsForCompaction(updatedHistory);
1083
1380
  ctx.messages = rawHistory;
1381
+ try {
1382
+ clearPkbSystemReminderMetadataForConversation(ctx.conversationId);
1383
+ } catch (err) {
1384
+ rlog.warn(
1385
+ { err },
1386
+ "Failed to clear pkbSystemReminderBlock metadata after compaction strip (non-fatal)",
1387
+ );
1388
+ }
1084
1389
 
1085
1390
  ctx.emitActivityState(
1086
1391
  "thinking",
@@ -1096,10 +1401,19 @@ export async function runAgentLoopImpl(
1096
1401
  lastCompactedAt: ctx.contextCompactedAt ?? undefined,
1097
1402
  force: true,
1098
1403
  targetInputTokensOverride: preflightBudget,
1404
+ conversationOriginChannel:
1405
+ getConversationOriginChannel(ctx.conversationId) ?? undefined,
1099
1406
  },
1100
1407
  );
1408
+ // `force: true` bypasses the cooldown/threshold gates but early returns
1409
+ // for "no eligible messages" / "insufficient messages" still leave
1410
+ // `summaryFailed` undefined. Only track when the summary LLM actually ran.
1411
+ if (midLoopCompact.summaryFailed !== undefined) {
1412
+ trackCompactionOutcome(ctx, midLoopCompact.summaryFailed, onEvent);
1413
+ }
1101
1414
  if (midLoopCompact.compacted) {
1102
1415
  ctx.messages = midLoopCompact.messages;
1416
+ reducerCompacted = true;
1103
1417
  ctx.contextCompactedMessageCount +=
1104
1418
  midLoopCompact.compactedPersistedMessages;
1105
1419
  ctx.contextCompactedAt = Date.now();
@@ -1108,6 +1422,11 @@ export async function runAgentLoopImpl(
1108
1422
  midLoopCompact.summaryText,
1109
1423
  ctx.contextCompactedMessageCount,
1110
1424
  );
1425
+ // Fire auto-analysis on compaction — see forceCompact() for rationale.
1426
+ enqueueAutoAnalysisOnCompaction(
1427
+ ctx.conversationId,
1428
+ ctx.trustContext?.trustClass,
1429
+ );
1111
1430
  onEvent({
1112
1431
  type: "context_compacted",
1113
1432
  previousEstimatedInputTokens:
@@ -1141,18 +1460,32 @@ export async function runAgentLoopImpl(
1141
1460
  // stripInjectionsForCompaction() unconditionally removed the existing
1142
1461
  // NOW.md block from ctx.messages above, so we must always re-inject
1143
1462
  // the current content regardless of whether compaction actually ran.
1144
- runMessages = applyRuntimeInjections(ctx.messages, {
1463
+ const injection = await applyRuntimeInjections(ctx.messages, {
1145
1464
  ...injectionOpts,
1146
1465
  pkbContext: currentPkbContent,
1147
1466
  nowScratchpad: currentNowContent,
1148
1467
  workspaceTopLevelContext: shouldInjectWorkspace
1149
1468
  ? ctx.workspaceTopLevelContext
1150
1469
  : null,
1470
+ // Suppress the chronological-transcript snapshot once the reducer
1471
+ // has collapsed `ctx.messages`; the captured snapshot reflects the
1472
+ // full persisted transcript and would overwrite compaction.
1473
+ slackChronologicalMessages: reducerCompacted
1474
+ ? null
1475
+ : injectionOpts.slackChronologicalMessages,
1151
1476
  mode: currentInjectionMode,
1152
1477
  });
1478
+ runMessages = injection.messages;
1153
1479
  if (isTrustedActor && currentInjectionMode !== "minimal") {
1154
- const memResult = ctx.graphMemory.reinjectCachedMemory(runMessages);
1155
- runMessages = memResult.runMessages;
1480
+ ctx.graphMemory.retrackCachedNodes();
1481
+ }
1482
+ const midLoopCompactStrip = stripHistoricalWebSearchResults(runMessages);
1483
+ if (midLoopCompactStrip.stats.blocksStripped > 0) {
1484
+ rlog.info(
1485
+ { phase: "mid-loop-compact", ...midLoopCompactStrip.stats },
1486
+ "Converted historical web_search_tool_result blocks to text summaries",
1487
+ );
1488
+ runMessages = midLoopCompactStrip.messages;
1156
1489
  }
1157
1490
  preRepairMessages = runMessages;
1158
1491
  preRunHistoryLength = runMessages.length;
@@ -1163,6 +1496,7 @@ export async function runAgentLoopImpl(
1163
1496
  abortController.signal,
1164
1497
  reqId,
1165
1498
  onCheckpoint,
1499
+ turnCallSite,
1166
1500
  );
1167
1501
  }
1168
1502
 
@@ -1194,7 +1528,9 @@ export async function runAgentLoopImpl(
1194
1528
  );
1195
1529
  const retryRepair = deepRepairHistory(runMessages);
1196
1530
  runMessages = retryRepair.messages;
1197
- preRepairMessages = retryRepair.messages;
1531
+ const retryStrip = stripHistoricalWebSearchResults(runMessages);
1532
+ runMessages = retryStrip.messages;
1533
+ preRepairMessages = runMessages;
1198
1534
  preRunHistoryLength = runMessages.length;
1199
1535
  state.orderingErrorDetected = false;
1200
1536
  state.deferredOrderingError = null;
@@ -1205,6 +1541,7 @@ export async function runAgentLoopImpl(
1205
1541
  abortController.signal,
1206
1542
  reqId,
1207
1543
  onCheckpoint,
1544
+ turnCallSite,
1208
1545
  );
1209
1546
 
1210
1547
  if (state.orderingErrorDetected) {
@@ -1234,6 +1571,14 @@ export async function runAgentLoopImpl(
1234
1571
 
1235
1572
  if (updatedHistory.length > preRunHistoryLength) {
1236
1573
  ctx.messages = stripInjectionsForCompaction(updatedHistory);
1574
+ try {
1575
+ clearPkbSystemReminderMetadataForConversation(ctx.conversationId);
1576
+ } catch (err) {
1577
+ rlog.warn(
1578
+ { err },
1579
+ "Failed to clear pkbSystemReminderBlock metadata after compaction strip (non-fatal)",
1580
+ );
1581
+ }
1237
1582
  convergenceStripped = true;
1238
1583
  preRepairMessages = updatedHistory;
1239
1584
  preRunHistoryLength = updatedHistory.length;
@@ -1246,14 +1591,19 @@ export async function runAgentLoopImpl(
1246
1591
  // message (e.g. "242201 tokens > 200000"), use it to correct the
1247
1592
  // compaction target. The estimator may significantly underestimate
1248
1593
  // (e.g. estimated 185k but actual was 242k), so using the
1249
- // uncorrected preflightBudget would still be too high.
1594
+ // uncorrected preflightBudget would still be too high. Passes the raw
1595
+ // error so ContextOverflowError.actualTokens can short-circuit the
1596
+ // string-regex path for proxy-rewrapped untyped errors.
1250
1597
  const actualTokens = parseActualTokensFromError(
1251
- state.contextTooLargeErrorMessage,
1598
+ state.contextTooLargeError,
1252
1599
  );
1253
1600
  const estimatedTokensAtOverflow = estimatePromptTokens(
1254
1601
  ctx.messages,
1255
1602
  ctx.systemPrompt,
1256
- { providerName: ctx.provider.name, toolTokenBudget },
1603
+ {
1604
+ providerName: estimationProviderName,
1605
+ toolTokenBudget,
1606
+ },
1257
1607
  );
1258
1608
  let correctedTarget = preflightBudget;
1259
1609
  if (actualTokens && estimatedTokensAtOverflow > 0) {
@@ -1301,9 +1651,9 @@ export async function runAgentLoopImpl(
1301
1651
  const step = await reduceContextOverflow(
1302
1652
  ctx.messages,
1303
1653
  {
1304
- providerName: ctx.provider.name,
1654
+ providerName: estimationProviderName,
1305
1655
  systemPrompt: ctx.systemPrompt,
1306
- contextWindow: config.contextWindow,
1656
+ contextWindow: config.llm.default.contextWindow,
1307
1657
  targetTokens: correctedTarget,
1308
1658
  toolTokenBudget,
1309
1659
  },
@@ -1317,6 +1667,21 @@ export async function runAgentLoopImpl(
1317
1667
  ctx.messages = step.messages;
1318
1668
  currentInjectionMode = step.state.injectionMode;
1319
1669
 
1670
+ // See the preflight reducer call above for rationale. Only track when
1671
+ // the summary LLM actually ran — `summaryFailed === undefined`
1672
+ // indicates the reducer's forced compaction took an early-return path
1673
+ // without calling the summary LLM.
1674
+ if (
1675
+ step.compactionResult &&
1676
+ step.compactionResult.summaryFailed !== undefined
1677
+ ) {
1678
+ trackCompactionOutcome(
1679
+ ctx,
1680
+ step.compactionResult.summaryFailed,
1681
+ onEvent,
1682
+ );
1683
+ }
1684
+
1320
1685
  if (step.compactionResult?.compacted) {
1321
1686
  ctx.contextCompactedMessageCount +=
1322
1687
  step.compactionResult.compactedPersistedMessages;
@@ -1326,6 +1691,11 @@ export async function runAgentLoopImpl(
1326
1691
  step.compactionResult.summaryText,
1327
1692
  ctx.contextCompactedMessageCount,
1328
1693
  );
1694
+ // Fire auto-analysis on compaction — see forceCompact() for rationale.
1695
+ enqueueAutoAnalysisOnCompaction(
1696
+ ctx.conversationId,
1697
+ ctx.trustContext?.trustClass,
1698
+ );
1329
1699
  onEvent({
1330
1700
  type: "context_compacted",
1331
1701
  previousEstimatedInputTokens:
@@ -1355,23 +1725,35 @@ export async function runAgentLoopImpl(
1355
1725
  step.compactionResult.compactedPersistedMessages,
1356
1726
  );
1357
1727
  shouldInjectWorkspace = true;
1728
+ reducerCompacted = true;
1358
1729
  }
1359
1730
 
1360
1731
  // Only re-inject NOW.md when ctx.messages was actually stripped;
1361
1732
  // otherwise the existing NOW.md block is still present and
1362
1733
  // re-injecting would duplicate it.
1363
- runMessages = applyRuntimeInjections(ctx.messages, {
1734
+ const injection = await applyRuntimeInjections(ctx.messages, {
1364
1735
  ...injectionOpts,
1365
1736
  pkbContext: currentPkbContent,
1366
1737
  nowScratchpad: convergenceStripped ? currentNowContent : null,
1367
1738
  workspaceTopLevelContext: shouldInjectWorkspace
1368
1739
  ? ctx.workspaceTopLevelContext
1369
1740
  : null,
1741
+ slackChronologicalMessages: reducerCompacted
1742
+ ? null
1743
+ : injectionOpts.slackChronologicalMessages,
1370
1744
  mode: currentInjectionMode,
1371
1745
  });
1746
+ runMessages = injection.messages;
1372
1747
  if (isTrustedActor && currentInjectionMode !== "minimal") {
1373
- const memResult = ctx.graphMemory.reinjectCachedMemory(runMessages);
1374
- runMessages = memResult.runMessages;
1748
+ ctx.graphMemory.retrackCachedNodes();
1749
+ }
1750
+ const convergenceStrip = stripHistoricalWebSearchResults(runMessages);
1751
+ if (convergenceStrip.stats.blocksStripped > 0) {
1752
+ rlog.info(
1753
+ { phase: "convergence", ...convergenceStrip.stats },
1754
+ "Converted historical web_search_tool_result blocks to text summaries",
1755
+ );
1756
+ runMessages = convergenceStrip.messages;
1375
1757
  }
1376
1758
  preRepairMessages = runMessages;
1377
1759
  preRunHistoryLength = runMessages.length;
@@ -1384,6 +1766,7 @@ export async function runAgentLoopImpl(
1384
1766
  abortController.signal,
1385
1767
  reqId,
1386
1768
  onCheckpoint,
1769
+ turnCallSite,
1387
1770
  );
1388
1771
 
1389
1772
  // If the rerun still yields at checkpoint, the turn is still
@@ -1405,6 +1788,14 @@ export async function runAgentLoopImpl(
1405
1788
  // pre-rerun messages.
1406
1789
  if (updatedHistory.length > preRunHistoryLength) {
1407
1790
  ctx.messages = stripInjectionsForCompaction(updatedHistory);
1791
+ try {
1792
+ clearPkbSystemReminderMetadataForConversation(ctx.conversationId);
1793
+ } catch (err) {
1794
+ rlog.warn(
1795
+ { err },
1796
+ "Failed to clear pkbSystemReminderBlock metadata after compaction strip (non-fatal)",
1797
+ );
1798
+ }
1408
1799
  convergenceStripped = true;
1409
1800
  preRepairMessages = updatedHistory;
1410
1801
  preRunHistoryLength = updatedHistory.length;
@@ -1440,8 +1831,18 @@ export async function runAgentLoopImpl(
1440
1831
  targetInputTokensOverride: correctedTarget,
1441
1832
  },
1442
1833
  );
1834
+ // Only track when the summary LLM actually ran; `force: true`
1835
+ // bypasses the cooldown but not the early-return paths.
1836
+ if (emergencyCompact.summaryFailed !== undefined) {
1837
+ trackCompactionOutcome(
1838
+ ctx,
1839
+ emergencyCompact.summaryFailed,
1840
+ onEvent,
1841
+ );
1842
+ }
1443
1843
  if (emergencyCompact.compacted) {
1444
1844
  ctx.messages = emergencyCompact.messages;
1845
+ reducerCompacted = true;
1445
1846
  ctx.contextCompactedMessageCount +=
1446
1847
  emergencyCompact.compactedPersistedMessages;
1447
1848
  ctx.contextCompactedAt = Date.now();
@@ -1450,6 +1851,11 @@ export async function runAgentLoopImpl(
1450
1851
  emergencyCompact.summaryText,
1451
1852
  ctx.contextCompactedMessageCount,
1452
1853
  );
1854
+ // Fire auto-analysis on compaction — see forceCompact() for rationale.
1855
+ enqueueAutoAnalysisOnCompaction(
1856
+ ctx.conversationId,
1857
+ ctx.trustContext?.trustClass,
1858
+ );
1453
1859
  onEvent({
1454
1860
  type: "context_compacted",
1455
1861
  previousEstimatedInputTokens:
@@ -1483,19 +1889,29 @@ export async function runAgentLoopImpl(
1483
1889
 
1484
1890
  // Only re-inject NOW.md when ctx.messages was actually stripped;
1485
1891
  // otherwise the existing block is still present.
1486
- runMessages = applyRuntimeInjections(ctx.messages, {
1892
+ const injection = await applyRuntimeInjections(ctx.messages, {
1487
1893
  ...injectionOpts,
1488
1894
  pkbContext: currentPkbContent,
1489
1895
  nowScratchpad: convergenceStripped ? currentNowContent : null,
1490
1896
  workspaceTopLevelContext: shouldInjectWorkspace
1491
1897
  ? ctx.workspaceTopLevelContext
1492
1898
  : null,
1899
+ slackChronologicalMessages: reducerCompacted
1900
+ ? null
1901
+ : injectionOpts.slackChronologicalMessages,
1493
1902
  mode: currentInjectionMode,
1494
1903
  });
1904
+ runMessages = injection.messages;
1495
1905
  if (isTrustedActor && currentInjectionMode !== "minimal") {
1496
- const memResult =
1497
- ctx.graphMemory.reinjectCachedMemory(runMessages);
1498
- runMessages = memResult.runMessages;
1906
+ ctx.graphMemory.retrackCachedNodes();
1907
+ }
1908
+ const emergencyStrip = stripHistoricalWebSearchResults(runMessages);
1909
+ if (emergencyStrip.stats.blocksStripped > 0) {
1910
+ rlog.info(
1911
+ { phase: "emergency_compact", ...emergencyStrip.stats },
1912
+ "Converted historical web_search_tool_result blocks to text summaries",
1913
+ );
1914
+ runMessages = emergencyStrip.messages;
1499
1915
  }
1500
1916
  preRepairMessages = runMessages;
1501
1917
  preRunHistoryLength = runMessages.length;
@@ -1507,6 +1923,7 @@ export async function runAgentLoopImpl(
1507
1923
  abortController.signal,
1508
1924
  reqId,
1509
1925
  onCheckpoint,
1926
+ turnCallSite,
1510
1927
  );
1511
1928
  } else {
1512
1929
  // User denied compression — emit a graceful assistant explanation
@@ -1560,8 +1977,18 @@ export async function runAgentLoopImpl(
1560
1977
  targetInputTokensOverride: correctedTarget,
1561
1978
  },
1562
1979
  );
1980
+ // Only track when the summary LLM actually ran; `force: true`
1981
+ // bypasses the cooldown but not the early-return paths.
1982
+ if (emergencyCompact.summaryFailed !== undefined) {
1983
+ trackCompactionOutcome(
1984
+ ctx,
1985
+ emergencyCompact.summaryFailed,
1986
+ onEvent,
1987
+ );
1988
+ }
1563
1989
  if (emergencyCompact.compacted) {
1564
1990
  ctx.messages = emergencyCompact.messages;
1991
+ reducerCompacted = true;
1565
1992
  ctx.contextCompactedMessageCount +=
1566
1993
  emergencyCompact.compactedPersistedMessages;
1567
1994
  ctx.contextCompactedAt = Date.now();
@@ -1570,6 +1997,11 @@ export async function runAgentLoopImpl(
1570
1997
  emergencyCompact.summaryText,
1571
1998
  ctx.contextCompactedMessageCount,
1572
1999
  );
2000
+ // Fire auto-analysis on compaction — see forceCompact() for rationale.
2001
+ enqueueAutoAnalysisOnCompaction(
2002
+ ctx.conversationId,
2003
+ ctx.trustContext?.trustClass,
2004
+ );
1573
2005
  onEvent({
1574
2006
  type: "context_compacted",
1575
2007
  previousEstimatedInputTokens:
@@ -1603,18 +2035,29 @@ export async function runAgentLoopImpl(
1603
2035
 
1604
2036
  // Only re-inject NOW.md when ctx.messages was actually stripped;
1605
2037
  // otherwise the existing block is still present.
1606
- runMessages = applyRuntimeInjections(ctx.messages, {
2038
+ const injection = await applyRuntimeInjections(ctx.messages, {
1607
2039
  ...injectionOpts,
1608
2040
  pkbContext: currentPkbContent,
1609
2041
  nowScratchpad: convergenceStripped ? currentNowContent : null,
1610
2042
  workspaceTopLevelContext: shouldInjectWorkspace
1611
2043
  ? ctx.workspaceTopLevelContext
1612
2044
  : null,
2045
+ slackChronologicalMessages: reducerCompacted
2046
+ ? null
2047
+ : injectionOpts.slackChronologicalMessages,
1613
2048
  mode: currentInjectionMode,
1614
2049
  });
2050
+ runMessages = injection.messages;
1615
2051
  if (isTrustedActor && currentInjectionMode !== "minimal") {
1616
- const memResult = ctx.graphMemory.reinjectCachedMemory(runMessages);
1617
- runMessages = memResult.runMessages;
2052
+ ctx.graphMemory.retrackCachedNodes();
2053
+ }
2054
+ const fallbackStrip = stripHistoricalWebSearchResults(runMessages);
2055
+ if (fallbackStrip.stats.blocksStripped > 0) {
2056
+ rlog.info(
2057
+ { phase: "fail_gracefully_compact", ...fallbackStrip.stats },
2058
+ "Converted historical web_search_tool_result blocks to text summaries",
2059
+ );
2060
+ runMessages = fallbackStrip.messages;
1618
2061
  }
1619
2062
  preRepairMessages = runMessages;
1620
2063
  preRunHistoryLength = runMessages.length;
@@ -1626,6 +2069,7 @@ export async function runAgentLoopImpl(
1626
2069
  abortController.signal,
1627
2070
  reqId,
1628
2071
  onCheckpoint,
2072
+ turnCallSite,
1629
2073
  );
1630
2074
  }
1631
2075
  // action === "fail_gracefully" falls through to the final error below
@@ -1753,9 +2197,16 @@ export async function runAgentLoopImpl(
1753
2197
  try {
1754
2198
  const conv = getConversation(ctx.conversationId);
1755
2199
  if (conv) {
1756
- const convDir = getResolvedConversationDirPath(ctx.conversationId, conv.createdAt);
1757
- const { messages: derefMessages, dereferencedCount } = derefToolResultReReads(restoredHistory);
1758
- const { messages: truncatedMessages, truncatedCount } = postTurnTruncateToolResults(derefMessages, { conversationDir: convDir });
2200
+ const convDir = getResolvedConversationDirPath(
2201
+ ctx.conversationId,
2202
+ conv.createdAt,
2203
+ );
2204
+ const { messages: derefMessages, dereferencedCount } =
2205
+ derefToolResultReReads(restoredHistory);
2206
+ const { messages: truncatedMessages, truncatedCount } =
2207
+ postTurnTruncateToolResults(derefMessages, {
2208
+ conversationDir: convDir,
2209
+ });
1759
2210
  if (truncatedCount > 0 || dereferencedCount > 0) {
1760
2211
  rlog.info(
1761
2212
  { truncatedCount, dereferencedCount },
@@ -1765,16 +2216,13 @@ export async function runAgentLoopImpl(
1765
2216
  restoredHistory = truncatedMessages;
1766
2217
  }
1767
2218
  } catch (err) {
1768
- rlog.warn({ err }, "Post-turn tool result truncation failed (non-fatal)");
2219
+ rlog.warn(
2220
+ { err },
2221
+ "Post-turn tool result truncation failed (non-fatal)",
2222
+ );
1769
2223
  }
1770
2224
  }
1771
2225
 
1772
- const postLoopContextEstimate = estimatePromptTokens(
1773
- restoredHistory,
1774
- ctx.systemPrompt,
1775
- { providerName: ctx.provider.name, toolTokenBudget },
1776
- );
1777
-
1778
2226
  // Persist injections in history: runtime-injected context stays on
1779
2227
  // historical user messages so the conversation prefix is stable for
1780
2228
  // Anthropic's prefix caching. Stripping only happens during
@@ -1795,8 +2243,8 @@ export async function runAgentLoopImpl(
1795
2243
  state.exchangeProviderName,
1796
2244
  state.exchangeLlmCallCount,
1797
2245
  {
1798
- tokens: postLoopContextEstimate,
1799
- maxTokens: config.contextWindow.maxInputTokens,
2246
+ tokens: state.lastCallInputTokens,
2247
+ maxTokens: config.llm.default.contextWindow.maxInputTokens,
1800
2248
  },
1801
2249
  );
1802
2250
 
@@ -2014,6 +2462,12 @@ export async function runAgentLoopImpl(
2014
2462
 
2015
2463
  // Commit app changes (fire-and-forget — apps repo is separate from workspace)
2016
2464
  void commitAppTurnChanges(ctx.conversationId, ctx.turnCount);
2465
+
2466
+ // Recompute relationship-state.json at turn boundary (fire-and-forget).
2467
+ // The writer swallows its own errors, but we still guard with catch()
2468
+ // here so a regression in the writer can never bubble out of the
2469
+ // agent loop and reject an otherwise-complete turn.
2470
+ void writeRelationshipState().catch(() => {});
2017
2471
  }
2018
2472
 
2019
2473
  ctx.profiler.emitSummary(ctx.traceEmitter, reqId);
@@ -2022,6 +2476,7 @@ export async function runAgentLoopImpl(
2022
2476
  ctx.processing = false;
2023
2477
  ctx.onConfirmationOutcome = undefined;
2024
2478
  ctx.surfaceActionRequestIds.delete(ctx.currentRequestId ?? "");
2479
+ ctx.approvedViaPromptThisTurn = false;
2025
2480
  ctx.currentRequestId = undefined;
2026
2481
  ctx.currentActiveSurfaceId = undefined;
2027
2482
  ctx.allowedToolNames = undefined;
@@ -2029,6 +2484,10 @@ export async function runAgentLoopImpl(
2029
2484
  // Channel command intents (e.g. Telegram /start) are single-turn metadata.
2030
2485
  // Clear at turn end so they never leak into subsequent unrelated messages.
2031
2486
  ctx.commandIntent = undefined;
2487
+ // taskRunId scopes ephemeral task-run permissions to a single turn. Clear
2488
+ // before drainQueue so queued/drained turns on a reused conversation can't
2489
+ // inherit stale in-task-run scope from the turn that just finished.
2490
+ ctx.taskRunId = undefined;
2032
2491
 
2033
2492
  // Consolidation deferred to compaction: keeping assistant + tool_result
2034
2493
  // messages unconsolidated preserves the exact message structure sent to