@vellumai/assistant 0.4.26 → 0.4.29

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 (1301) hide show
  1. package/.env.example +2 -2
  2. package/AGENTS.md +5 -0
  3. package/ARCHITECTURE.md +169 -69
  4. package/Dockerfile +1 -1
  5. package/README.md +111 -112
  6. package/bun.lock +0 -3
  7. package/docs/architecture/integrations.md +0 -1
  8. package/docs/architecture/memory.md +100 -63
  9. package/docs/error-handling.md +71 -0
  10. package/docs/runbook-trusted-contacts.md +10 -9
  11. package/docs/trusted-contact-access.md +48 -46
  12. package/package.json +3 -3
  13. package/scripts/compare-benchmarks.sh +12 -5
  14. package/scripts/ipc/check-swift-decoder-drift.ts +3 -0
  15. package/scripts/test.sh +89 -5
  16. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +46 -0
  17. package/src/__tests__/access-request-decision.test.ts +0 -1
  18. package/src/__tests__/account-registry.test.ts +1 -1
  19. package/src/__tests__/actor-token-service.test.ts +36 -23
  20. package/src/__tests__/agent-loop-thinking.test.ts +29 -13
  21. package/src/__tests__/agent-loop.test.ts +2 -1
  22. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -1
  23. package/src/__tests__/approval-routes-http.test.ts +2 -2
  24. package/src/__tests__/asset-materialize-tool.test.ts +7 -7
  25. package/src/__tests__/asset-search-tool.test.ts +7 -7
  26. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  27. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +217 -0
  28. package/src/__tests__/call-controller.test.ts +99 -69
  29. package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
  30. package/src/__tests__/channel-approval-routes.test.ts +113 -70
  31. package/src/__tests__/channel-guardian.test.ts +173 -282
  32. package/src/__tests__/channel-readiness-service.test.ts +6 -2
  33. package/src/__tests__/channel-reply-delivery.test.ts +2 -2
  34. package/src/__tests__/channel-retry-sweep.test.ts +14 -14
  35. package/src/__tests__/checker.test.ts +12 -31
  36. package/src/__tests__/claude-code-tool-profiles.test.ts +1 -1
  37. package/src/__tests__/commit-message-enrichment-service.test.ts +67 -59
  38. package/src/__tests__/compaction.benchmark.test.ts +6 -2
  39. package/src/__tests__/computer-use-tools.test.ts +1 -1
  40. package/src/__tests__/config-schema.test.ts +66 -7
  41. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -29
  42. package/src/__tests__/contacts-tools.test.ts +63 -2
  43. package/src/__tests__/context-overflow-approval.test.ts +141 -0
  44. package/src/__tests__/context-overflow-policy.test.ts +171 -0
  45. package/src/__tests__/context-overflow-reducer.test.ts +533 -0
  46. package/src/__tests__/context-window-manager.test.ts +97 -0
  47. package/src/__tests__/conversation-attention-telegram.test.ts +38 -46
  48. package/src/__tests__/conversation-pairing.test.ts +2 -2
  49. package/src/__tests__/conversation-routes-guardian-reply.test.ts +214 -10
  50. package/src/__tests__/conversation-routes.test.ts +4 -7
  51. package/src/__tests__/credential-broker-browser-fill.test.ts +13 -2
  52. package/src/__tests__/credential-security-e2e.test.ts +1 -1
  53. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  54. package/src/__tests__/credential-vault-unit.test.ts +1 -1
  55. package/src/__tests__/credential-vault.test.ts +11 -8
  56. package/src/__tests__/daemon-lifecycle.test.ts +2 -2
  57. package/src/__tests__/daemon-server-session-init.test.ts +6 -6
  58. package/src/__tests__/delete-managed-skill-tool.test.ts +1 -1
  59. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -2
  60. package/src/__tests__/emit-signal-routing-intent.test.ts +4 -0
  61. package/src/__tests__/encrypted-store.test.ts +10 -7
  62. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  63. package/src/__tests__/file-edit-tool.test.ts +1 -1
  64. package/src/__tests__/file-read-tool.test.ts +1 -1
  65. package/src/__tests__/file-write-tool.test.ts +1 -1
  66. package/src/__tests__/fixtures/credential-security-fixtures.ts +87 -64
  67. package/src/__tests__/fixtures/media-reuse-fixtures.ts +37 -31
  68. package/src/__tests__/fixtures/mock-signup-server.ts +171 -115
  69. package/src/__tests__/fixtures/proxy-fixtures.ts +39 -39
  70. package/src/__tests__/followup-tools.test.ts +1 -1
  71. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  72. package/src/__tests__/guardian-actions-endpoint.test.ts +543 -1
  73. package/src/__tests__/guardian-control-plane-policy.test.ts +15 -15
  74. package/src/__tests__/guardian-dispatch.test.ts +79 -1
  75. package/src/__tests__/guardian-grant-minting.test.ts +14 -14
  76. package/src/__tests__/guardian-outbound-http.test.ts +1 -2
  77. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -41
  78. package/src/__tests__/guardian-routing-invariants.test.ts +2 -5
  79. package/src/__tests__/guardian-routing-state.test.ts +36 -52
  80. package/src/__tests__/guardian-verification-intent-routing.test.ts +4 -6
  81. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +2 -2
  82. package/src/__tests__/handle-user-message-secret-resume.test.ts +39 -1
  83. package/src/__tests__/handlers-cu-observation-blob.test.ts +21 -10
  84. package/src/__tests__/handlers-telegram-config.test.ts +14 -14
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +23 -2
  86. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  87. package/src/__tests__/headless-browser-navigate.test.ts +1 -1
  88. package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
  89. package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
  90. package/src/__tests__/heartbeat-service.test.ts +45 -2
  91. package/src/__tests__/host-file-edit-tool.test.ts +1 -1
  92. package/src/__tests__/host-file-read-tool.test.ts +1 -1
  93. package/src/__tests__/host-file-write-tool.test.ts +1 -1
  94. package/src/__tests__/host-shell-tool.test.ts +1 -1
  95. package/src/__tests__/inbound-invite-redemption.test.ts +16 -18
  96. package/src/__tests__/ingress-reconcile.test.ts +2 -2
  97. package/src/__tests__/ingress-routes-http.test.ts +2 -1
  98. package/src/__tests__/integrations-cli.test.ts +256 -0
  99. package/src/__tests__/intent-routing.test.ts +4 -5
  100. package/src/__tests__/invite-redemption-service.test.ts +4 -3
  101. package/src/__tests__/ipc-snapshot.test.ts +28 -0
  102. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
  103. package/src/__tests__/mcp-cli.test.ts +136 -57
  104. package/src/__tests__/mcp-client-auth.test.ts +95 -0
  105. package/src/__tests__/media-generate-image.test.ts +2 -2
  106. package/src/__tests__/media-reuse-story.e2e.test.ts +8 -8
  107. package/src/__tests__/memory-regressions.test.ts +6 -6
  108. package/src/__tests__/messaging-send-tool.test.ts +1 -1
  109. package/src/__tests__/migration-cross-version-compatibility.test.ts +1855 -0
  110. package/src/__tests__/migration-export-http.test.ts +540 -0
  111. package/src/__tests__/migration-import-commit-http.test.ts +823 -0
  112. package/src/__tests__/migration-import-preflight-http.test.ts +755 -0
  113. package/src/__tests__/migration-parity-persistence.test.ts +1854 -0
  114. package/src/__tests__/migration-transport.test.ts +904 -0
  115. package/src/__tests__/migration-validate-http.test.ts +698 -0
  116. package/src/__tests__/migration-wizard.test.ts +1289 -0
  117. package/src/__tests__/non-member-access-request.test.ts +17 -17
  118. package/src/__tests__/notification-decision-strategy.test.ts +110 -2
  119. package/src/__tests__/notification-deep-link.test.ts +18 -0
  120. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  121. package/src/__tests__/oauth2-gateway-transport.test.ts +1 -1
  122. package/src/__tests__/playbook-execution.test.ts +1 -1
  123. package/src/__tests__/playbook-tools.test.ts +1 -1
  124. package/src/__tests__/provider-streaming.benchmark.test.ts +3 -1
  125. package/src/__tests__/proxy-approval-callback.test.ts +1 -1
  126. package/src/__tests__/qdrant-manager.test.ts +40 -11
  127. package/src/__tests__/rebind-secrets-screen.test.ts +839 -0
  128. package/src/__tests__/recording-handler.test.ts +2 -2
  129. package/src/__tests__/recording-intent-handler.test.ts +3 -3
  130. package/src/__tests__/recording-state-machine.test.ts +2 -2
  131. package/src/__tests__/relay-server.test.ts +506 -227
  132. package/src/__tests__/reminder-store.test.ts +8 -0
  133. package/src/__tests__/reminder.test.ts +8 -0
  134. package/src/__tests__/{resolve-guardian-trust-class.test.ts → resolve-trust-class.test.ts} +11 -17
  135. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
  136. package/src/__tests__/schedule-tools.test.ts +1 -1
  137. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  138. package/src/__tests__/script-proxy-connect-tunnel.test.ts +2 -3
  139. package/src/__tests__/script-proxy-decision-trace.test.ts +2 -2
  140. package/src/__tests__/script-proxy-http-forwarder.test.ts +1 -1
  141. package/src/__tests__/script-proxy-injection-runtime.test.ts +5 -5
  142. package/src/__tests__/script-proxy-mitm-handler.test.ts +4 -4
  143. package/src/__tests__/script-proxy-policy-runtime.test.ts +2 -2
  144. package/src/__tests__/script-proxy-policy.test.ts +2 -2
  145. package/src/__tests__/script-proxy-session-manager.test.ts +4 -7
  146. package/src/__tests__/script-proxy-session-runtime.test.ts +1 -6
  147. package/src/__tests__/secret-onetime-send.test.ts +4 -4
  148. package/src/__tests__/secret-scanner-executor.test.ts +2 -2
  149. package/src/__tests__/send-endpoint-busy.test.ts +11 -9
  150. package/src/__tests__/send-notification-tool.test.ts +2 -2
  151. package/src/__tests__/session-abort-tool-results.test.ts +17 -2
  152. package/src/__tests__/session-agent-loop.test.ts +456 -35
  153. package/src/__tests__/session-confirmation-signals.test.ts +3 -2
  154. package/src/__tests__/session-conflict-gate.test.ts +20 -3
  155. package/src/__tests__/session-init.benchmark.test.ts +2 -2
  156. package/src/__tests__/session-load-history-repair.test.ts +7 -7
  157. package/src/__tests__/session-pre-run-repair.test.ts +17 -2
  158. package/src/__tests__/session-profile-injection.test.ts +20 -3
  159. package/src/__tests__/session-provider-retry-repair.test.ts +86 -6
  160. package/src/__tests__/session-queue.test.ts +33 -18
  161. package/src/__tests__/session-runtime-assembly.test.ts +147 -1
  162. package/src/__tests__/session-runtime-workspace.test.ts +40 -0
  163. package/src/__tests__/session-slash-known.test.ts +21 -3
  164. package/src/__tests__/session-slash-queue.test.ts +17 -2
  165. package/src/__tests__/session-slash-unknown.test.ts +17 -2
  166. package/src/__tests__/session-surfaces-deselection.test.ts +208 -0
  167. package/src/__tests__/session-workspace-cache-state.test.ts +2 -2
  168. package/src/__tests__/session-workspace-injection.test.ts +17 -2
  169. package/src/__tests__/session-workspace-tool-tracking.test.ts +17 -2
  170. package/src/__tests__/shell-credential-ref.test.ts +1 -1
  171. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  172. package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
  173. package/src/__tests__/skill-load-tool.test.ts +1 -1
  174. package/src/__tests__/skill-script-runner-host.test.ts +1 -1
  175. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -1
  176. package/src/__tests__/skill-script-runner.test.ts +1 -1
  177. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  178. package/src/__tests__/slack-skill.test.ts +3 -2
  179. package/src/__tests__/subagent-tools.test.ts +3 -3
  180. package/src/__tests__/swarm-recursion.test.ts +1 -1
  181. package/src/__tests__/swarm-session-integration.test.ts +1 -1
  182. package/src/__tests__/swarm-tool.test.ts +1 -1
  183. package/src/__tests__/task-management-tools.test.ts +1 -1
  184. package/src/__tests__/task-tools.test.ts +1 -1
  185. package/src/__tests__/terminal-tools.test.ts +1 -1
  186. package/src/__tests__/test-support/browser-skill-harness.ts +39 -27
  187. package/src/__tests__/test-support/computer-use-skill-harness.ts +14 -14
  188. package/src/__tests__/tool-approval-handler.test.ts +15 -15
  189. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
  190. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  191. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  192. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  193. package/src/__tests__/tool-executor.test.ts +23 -182
  194. package/src/__tests__/tool-grant-request-escalation.test.ts +11 -11
  195. package/src/__tests__/tool-permission-simulate-handler.test.ts +4 -4
  196. package/src/__tests__/transfer-progress-screen.test.ts +1180 -0
  197. package/src/__tests__/trust-context-guards.test.ts +25 -29
  198. package/src/__tests__/trusted-contact-approval-notifier.test.ts +23 -21
  199. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +37 -40
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +29 -25
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +25 -24
  202. package/src/__tests__/trusted-contact-verification.test.ts +63 -77
  203. package/src/__tests__/turn-commit.test.ts +18 -18
  204. package/src/__tests__/twilio-provider.test.ts +7 -7
  205. package/src/__tests__/validation-results-screen.test.ts +1107 -0
  206. package/src/__tests__/view-image-tool.test.ts +1 -1
  207. package/src/__tests__/voice-invite-redemption.test.ts +3 -2
  208. package/src/__tests__/voice-scoped-grant-consumer.test.ts +12 -12
  209. package/src/__tests__/voice-session-bridge.test.ts +24 -24
  210. package/src/agent/attachments.ts +3 -1
  211. package/src/agent/loop.ts +13 -13
  212. package/src/agent/message-types.ts +13 -7
  213. package/src/amazon/cart.ts +59 -32
  214. package/src/amazon/checkout.ts +25 -14
  215. package/src/amazon/client.ts +68 -48
  216. package/src/amazon/product-details.ts +3 -3
  217. package/src/amazon/request-extractor.ts +46 -31
  218. package/src/amazon/search.ts +6 -4
  219. package/src/amazon/session.ts +33 -24
  220. package/src/approvals/AGENTS.md +26 -0
  221. package/src/approvals/approval-primitive.ts +87 -64
  222. package/src/approvals/guardian-decision-primitive.ts +172 -81
  223. package/src/approvals/guardian-request-resolvers.ts +262 -155
  224. package/src/autonomy/autonomy-resolver.ts +7 -5
  225. package/src/autonomy/autonomy-store.ts +34 -19
  226. package/src/autonomy/disposition-mapper.ts +5 -5
  227. package/src/autonomy/index.ts +6 -6
  228. package/src/autonomy/types.ts +7 -3
  229. package/src/browser-extension-relay/client.ts +50 -19
  230. package/src/browser-extension-relay/protocol.ts +11 -11
  231. package/src/browser-extension-relay/server.ts +45 -20
  232. package/src/bundler/app-bundler.ts +75 -50
  233. package/src/bundler/bundle-scanner.ts +145 -41
  234. package/src/bundler/bundle-signer.ts +16 -14
  235. package/src/bundler/signature-verifier.ts +36 -33
  236. package/src/calls/call-constants.ts +10 -3
  237. package/src/calls/call-controller.ts +473 -214
  238. package/src/calls/call-conversation-messages.ts +25 -15
  239. package/src/calls/call-domain.ts +401 -148
  240. package/src/calls/call-pointer-message-composer.ts +26 -21
  241. package/src/calls/call-pointer-messages.ts +52 -28
  242. package/src/calls/call-recovery.ts +53 -37
  243. package/src/calls/call-state-machine.ts +37 -7
  244. package/src/calls/call-state.ts +35 -13
  245. package/src/calls/call-store.ts +165 -77
  246. package/src/calls/elevenlabs-client.ts +39 -20
  247. package/src/calls/guardian-action-sweep.ts +42 -24
  248. package/src/calls/guardian-dispatch.ts +79 -56
  249. package/src/calls/guardian-question-copy.ts +28 -23
  250. package/src/calls/relay-server.ts +1121 -532
  251. package/src/calls/speaker-identification.ts +21 -15
  252. package/src/calls/twilio-config.ts +34 -17
  253. package/src/calls/twilio-provider.ts +108 -55
  254. package/src/calls/twilio-rest.ts +212 -100
  255. package/src/calls/twilio-routes.ts +165 -92
  256. package/src/calls/types.ts +55 -7
  257. package/src/calls/voice-quality.ts +6 -4
  258. package/src/calls/voice-session-bridge.ts +181 -133
  259. package/src/channels/config.ts +17 -13
  260. package/src/channels/types.ts +38 -10
  261. package/src/cli/amazon.ts +333 -227
  262. package/src/cli/config-commands.ts +236 -146
  263. package/src/cli/core-commands.ts +403 -329
  264. package/src/cli/email-guardrails.ts +38 -19
  265. package/src/cli/email.ts +207 -153
  266. package/src/cli/influencer.ts +58 -56
  267. package/src/cli/integrations.ts +362 -0
  268. package/src/cli/ipc-client.ts +24 -19
  269. package/src/cli/map.ts +176 -129
  270. package/src/cli/mcp.ts +260 -152
  271. package/src/cli/sequence.ts +165 -107
  272. package/src/cli/twitter.ts +302 -218
  273. package/src/cli.ts +418 -279
  274. package/src/commands/cc-command-registry.ts +52 -27
  275. package/src/config/agent-schema.ts +217 -134
  276. package/src/config/assistant-feature-flags.ts +23 -18
  277. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +19 -0
  278. package/src/config/bundled-skills/app-builder/tools/app-create.ts +7 -4
  279. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +6 -3
  280. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +7 -4
  281. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +6 -3
  282. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +6 -3
  283. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +7 -4
  284. package/src/config/bundled-skills/app-builder/tools/app-list.ts +6 -3
  285. package/src/config/bundled-skills/app-builder/tools/app-query.ts +6 -3
  286. package/src/config/bundled-skills/app-builder/tools/app-update.ts +6 -3
  287. package/src/config/bundled-skills/browser/tools/browser-click.ts +5 -2
  288. package/src/config/bundled-skills/browser/tools/browser-close.ts +5 -2
  289. package/src/config/bundled-skills/browser/tools/browser-extract.ts +5 -2
  290. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +5 -2
  291. package/src/config/bundled-skills/browser/tools/browser-hover.ts +5 -2
  292. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +5 -2
  293. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +5 -2
  294. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +5 -2
  295. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +5 -2
  296. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +5 -2
  297. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +5 -2
  298. package/src/config/bundled-skills/browser/tools/browser-type.ts +5 -2
  299. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +13 -6
  300. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +5 -2
  301. package/src/config/bundled-skills/claude-code/TOOLS.json +4 -0
  302. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +5 -2
  303. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  304. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +6 -3
  305. package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +6 -3
  306. package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +10 -3
  307. package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +6 -3
  308. package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +6 -3
  309. package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +6 -3
  310. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +10 -3
  311. package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +6 -3
  312. package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +10 -3
  313. package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +10 -3
  314. package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +6 -3
  315. package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +6 -3
  316. package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +6 -3
  317. package/src/config/bundled-skills/configure-settings/SKILL.md +28 -14
  318. package/src/config/bundled-skills/contacts/SKILL.md +446 -15
  319. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +99 -20
  320. package/src/config/bundled-skills/contacts/tools/contact-search.ts +74 -17
  321. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +89 -26
  322. package/src/config/bundled-skills/document/tools/document-create.ts +5 -2
  323. package/src/config/bundled-skills/document/tools/document-update.ts +5 -2
  324. package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -7
  325. package/src/config/bundled-skills/email-setup/SKILL.md +9 -9
  326. package/src/config/bundled-skills/followups/tools/followup-create.ts +5 -2
  327. package/src/config/bundled-skills/followups/tools/followup-list.ts +5 -2
  328. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +5 -2
  329. package/src/config/bundled-skills/google-calendar/calendar-client.ts +44 -32
  330. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +11 -5
  331. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +13 -7
  332. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +11 -5
  333. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +13 -7
  334. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +28 -12
  335. package/src/config/bundled-skills/google-calendar/tools/shared.ts +6 -4
  336. package/src/config/bundled-skills/google-calendar/types.ts +3 -3
  337. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +46 -24
  338. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +36 -19
  339. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +60 -35
  340. package/src/config/bundled-skills/mcp-setup/SKILL.md +75 -0
  341. package/src/config/bundled-skills/media-processing/SKILL.md +55 -15
  342. package/src/config/bundled-skills/media-processing/TOOLS.json +20 -2
  343. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +12 -10
  344. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +34 -19
  345. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +82 -66
  346. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +148 -0
  347. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +1 -1
  348. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +8 -3
  349. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +117 -53
  350. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +273 -0
  351. package/src/config/bundled-skills/media-processing/services/preprocess.ts +185 -97
  352. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +32 -27
  353. package/src/config/bundled-skills/media-processing/services/reduce.ts +101 -24
  354. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +121 -55
  355. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +58 -24
  356. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +177 -91
  357. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +98 -70
  358. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +59 -19
  359. package/src/config/bundled-skills/media-processing/tools/media-status.ts +26 -10
  360. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +29 -14
  361. package/src/config/bundled-skills/messaging/SKILL.md +7 -5
  362. package/src/config/bundled-skills/messaging/TOOLS.json +7 -7
  363. package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +31 -13
  364. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +16 -10
  365. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +18 -9
  366. package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +23 -16
  367. package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +28 -12
  368. package/src/config/bundled-skills/messaging/tools/gmail-filters.ts +41 -21
  369. package/src/config/bundled-skills/messaging/tools/gmail-follow-up.ts +44 -23
  370. package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +73 -33
  371. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +15 -9
  372. package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +22 -14
  373. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +99 -50
  374. package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +14 -8
  375. package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +63 -44
  376. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +90 -46
  377. package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +43 -22
  378. package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +15 -9
  379. package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +51 -22
  380. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +62 -26
  381. package/src/config/bundled-skills/messaging/tools/gmail-vacation.ts +34 -19
  382. package/src/config/bundled-skills/messaging/tools/google-contacts.ts +32 -16
  383. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +10 -4
  384. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +91 -47
  385. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +21 -9
  386. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +9 -3
  387. package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +30 -17
  388. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +10 -4
  389. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +14 -6
  390. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +16 -5
  391. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +63 -36
  392. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +10 -4
  393. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +30 -12
  394. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +48 -29
  395. package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +20 -6
  396. package/src/config/bundled-skills/messaging/tools/send-notification.ts +1 -1
  397. package/src/config/bundled-skills/messaging/tools/sequence-analytics.ts +59 -22
  398. package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +13 -7
  399. package/src/config/bundled-skills/messaging/tools/sequence-create.ts +27 -12
  400. package/src/config/bundled-skills/messaging/tools/sequence-delete.ts +14 -6
  401. package/src/config/bundled-skills/messaging/tools/sequence-enroll.ts +30 -11
  402. package/src/config/bundled-skills/messaging/tools/sequence-enrollment-list.ts +16 -8
  403. package/src/config/bundled-skills/messaging/tools/sequence-get.ts +31 -13
  404. package/src/config/bundled-skills/messaging/tools/sequence-import.ts +38 -22
  405. package/src/config/bundled-skills/messaging/tools/sequence-list.ts +16 -7
  406. package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +29 -10
  407. package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +16 -8
  408. package/src/config/bundled-skills/messaging/tools/sequence-update.ts +35 -16
  409. package/src/config/bundled-skills/messaging/tools/shared.ts +26 -12
  410. package/src/config/bundled-skills/notifications/tools/send-notification.ts +69 -34
  411. package/src/config/bundled-skills/notifications/tools/shared.ts +1 -1
  412. package/src/config/bundled-skills/phone-calls/SKILL.md +46 -48
  413. package/src/config/bundled-skills/phone-calls/tools/call-end.ts +1 -1
  414. package/src/config/bundled-skills/phone-calls/tools/call-start.ts +1 -1
  415. package/src/config/bundled-skills/phone-calls/tools/call-status.ts +1 -1
  416. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +91 -51
  417. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +30 -16
  418. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +66 -27
  419. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +89 -42
  420. package/src/config/bundled-skills/public-ingress/SKILL.md +26 -19
  421. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +5 -2
  422. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +5 -2
  423. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +5 -2
  424. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +5 -2
  425. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +5 -2
  426. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +5 -2
  427. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +5 -2
  428. package/src/config/bundled-skills/screen-recording/SKILL.md +11 -3
  429. package/src/config/bundled-skills/self-upgrade/SKILL.md +9 -8
  430. package/src/config/bundled-skills/slack/TOOLS.json +33 -15
  431. package/src/config/bundled-skills/slack/tools/shared.ts +7 -5
  432. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +11 -5
  433. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +11 -5
  434. package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +46 -16
  435. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +11 -5
  436. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +28 -0
  437. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +12 -6
  438. package/src/config/bundled-skills/sms-setup/SKILL.md +5 -8
  439. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +5 -2
  440. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +5 -2
  441. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +5 -2
  442. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +5 -2
  443. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +5 -2
  444. package/src/config/bundled-skills/tasks/tools/task-delete.ts +5 -2
  445. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +5 -2
  446. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +5 -2
  447. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +5 -2
  448. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +5 -2
  449. package/src/config/bundled-skills/tasks/tools/task-list.ts +5 -2
  450. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +5 -2
  451. package/src/config/bundled-skills/tasks/tools/task-run.ts +5 -2
  452. package/src/config/bundled-skills/tasks/tools/task-save.ts +5 -2
  453. package/src/config/bundled-skills/telegram-setup/SKILL.md +7 -8
  454. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +232 -127
  455. package/src/config/bundled-skills/twilio-setup/SKILL.md +7 -12
  456. package/src/config/bundled-skills/twitter/SKILL.md +19 -2
  457. package/src/config/bundled-skills/voice-setup/SKILL.md +5 -5
  458. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +5 -2
  459. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +5 -2
  460. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +5 -2
  461. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +5 -2
  462. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +5 -2
  463. package/src/config/bundled-skills/weather/tools/get-weather.ts +5 -2
  464. package/src/config/calls-schema.ts +108 -63
  465. package/src/config/computer-use-prompt.ts +7 -7
  466. package/src/config/core-schema.ts +239 -155
  467. package/src/config/defaults.ts +2 -2
  468. package/src/config/elevenlabs-schema.ts +15 -15
  469. package/src/config/env-registry.ts +33 -33
  470. package/src/config/feature-flag-registry.json +31 -7
  471. package/src/config/loader.ts +118 -58
  472. package/src/config/mcp-schema.ts +29 -15
  473. package/src/config/memory-schema.ts +434 -229
  474. package/src/config/notifications-schema.ts +4 -4
  475. package/src/config/sandbox-schema.ts +2 -2
  476. package/src/config/schema.ts +12 -2
  477. package/src/config/skill-state.ts +27 -15
  478. package/src/config/skills-schema.ts +72 -23
  479. package/src/config/skills.ts +303 -143
  480. package/src/config/system-prompt.ts +25 -6
  481. package/src/config/types.ts +1 -1
  482. package/src/config/update-bulletin-format.ts +3 -3
  483. package/src/config/update-bulletin-state.ts +15 -6
  484. package/src/config/update-bulletin-template-path.ts +8 -4
  485. package/src/config/update-bulletin.ts +33 -14
  486. package/src/config/user-reference.ts +8 -8
  487. package/src/contacts/contact-events.ts +21 -0
  488. package/src/contacts/contact-store.ts +622 -100
  489. package/src/contacts/contacts-write.ts +287 -0
  490. package/src/contacts/index.ts +13 -4
  491. package/src/contacts/startup-migration.ts +21 -0
  492. package/src/contacts/types.ts +47 -2
  493. package/src/context/token-estimator.ts +54 -31
  494. package/src/context/tool-result-truncation.ts +41 -7
  495. package/src/context/window-manager.ts +225 -120
  496. package/src/daemon/approval-generators.ts +83 -55
  497. package/src/daemon/approved-devices-store.ts +33 -20
  498. package/src/daemon/assistant-attachments.ts +134 -98
  499. package/src/daemon/auth-manager.ts +17 -15
  500. package/src/daemon/classifier.ts +117 -46
  501. package/src/daemon/computer-use-session.ts +316 -187
  502. package/src/daemon/config-watcher.ts +91 -44
  503. package/src/daemon/connection-policy.ts +18 -10
  504. package/src/daemon/context-overflow-approval.ts +48 -0
  505. package/src/daemon/context-overflow-policy.ts +50 -0
  506. package/src/daemon/context-overflow-reducer.ts +300 -0
  507. package/src/daemon/daemon-control.ts +79 -51
  508. package/src/daemon/date-context.ts +119 -69
  509. package/src/daemon/dictation-profile-store.ts +94 -48
  510. package/src/daemon/dictation-text-processing.ts +33 -12
  511. package/src/daemon/doordash-steps.ts +92 -49
  512. package/src/daemon/guardian-action-generators.ts +62 -46
  513. package/src/daemon/guardian-verification-intent.ts +31 -18
  514. package/src/daemon/handlers/apps.ts +257 -111
  515. package/src/daemon/handlers/avatar.ts +20 -15
  516. package/src/daemon/handlers/computer-use.ts +82 -39
  517. package/src/daemon/handlers/config-channels.ts +146 -69
  518. package/src/daemon/handlers/config-heartbeat.ts +114 -59
  519. package/src/daemon/handlers/config-inbox.ts +277 -106
  520. package/src/daemon/handlers/config-ingress.ts +127 -55
  521. package/src/daemon/handlers/config-integrations.ts +145 -88
  522. package/src/daemon/handlers/config-model.ts +58 -22
  523. package/src/daemon/handlers/config-platform.ts +40 -16
  524. package/src/daemon/handlers/config-scheduling.ts +109 -48
  525. package/src/daemon/handlers/config-slack-channel.ts +67 -35
  526. package/src/daemon/handlers/config-slack.ts +21 -20
  527. package/src/daemon/handlers/config-telegram.ts +100 -70
  528. package/src/daemon/handlers/config-tools.ts +103 -55
  529. package/src/daemon/handlers/config-trust.ts +50 -20
  530. package/src/daemon/handlers/config.ts +72 -24
  531. package/src/daemon/handlers/contacts.ts +163 -0
  532. package/src/daemon/handlers/diagnostics.ts +90 -48
  533. package/src/daemon/handlers/documents.ts +74 -46
  534. package/src/daemon/handlers/guardian-actions.ts +118 -71
  535. package/src/daemon/handlers/home-base.ts +19 -16
  536. package/src/daemon/handlers/identity.ts +65 -45
  537. package/src/daemon/handlers/index.ts +78 -54
  538. package/src/daemon/handlers/misc.ts +664 -234
  539. package/src/daemon/handlers/navigate-settings.ts +14 -11
  540. package/src/daemon/handlers/oauth-connect.ts +48 -35
  541. package/src/daemon/handlers/open-bundle-handler.ts +31 -24
  542. package/src/daemon/handlers/pairing.ts +51 -25
  543. package/src/daemon/handlers/publish.ts +55 -33
  544. package/src/daemon/handlers/recording.ts +378 -162
  545. package/src/daemon/handlers/sessions.ts +923 -423
  546. package/src/daemon/handlers/shared.ts +202 -117
  547. package/src/daemon/handlers/signing.ts +25 -6
  548. package/src/daemon/handlers/subagents.ts +117 -56
  549. package/src/daemon/handlers/twitter-auth.ts +70 -49
  550. package/src/daemon/handlers/work-items.ts +264 -112
  551. package/src/daemon/handlers/workspace-files.ts +27 -20
  552. package/src/daemon/handlers.ts +2 -2
  553. package/src/daemon/history-repair.ts +16 -15
  554. package/src/daemon/identity-helpers.ts +4 -4
  555. package/src/daemon/install-cli-launchers.ts +33 -22
  556. package/src/daemon/ipc-blob-store.ts +38 -24
  557. package/src/daemon/ipc-contract/apps.ts +61 -49
  558. package/src/daemon/ipc-contract/computer-use.ts +47 -37
  559. package/src/daemon/ipc-contract/contacts.ts +69 -0
  560. package/src/daemon/ipc-contract/diagnostics.ts +14 -14
  561. package/src/daemon/ipc-contract/documents.ts +8 -8
  562. package/src/daemon/ipc-contract/guardian-actions.ts +4 -4
  563. package/src/daemon/ipc-contract/inbox.ts +16 -16
  564. package/src/daemon/ipc-contract/integrations.ts +57 -44
  565. package/src/daemon/ipc-contract/memory.ts +3 -5
  566. package/src/daemon/ipc-contract/messages.ts +95 -69
  567. package/src/daemon/ipc-contract/notifications.ts +10 -6
  568. package/src/daemon/ipc-contract/pairing.ts +8 -8
  569. package/src/daemon/ipc-contract/schedules.ts +20 -20
  570. package/src/daemon/ipc-contract/sessions.ts +88 -57
  571. package/src/daemon/ipc-contract/settings.ts +12 -7
  572. package/src/daemon/ipc-contract/shared.ts +9 -7
  573. package/src/daemon/ipc-contract/skills.ts +46 -26
  574. package/src/daemon/ipc-contract/subagents.ts +9 -9
  575. package/src/daemon/ipc-contract/trust.ts +11 -11
  576. package/src/daemon/ipc-contract/work-items.ts +33 -28
  577. package/src/daemon/ipc-contract/workspace.ts +28 -21
  578. package/src/daemon/ipc-contract-inventory.json +8 -0
  579. package/src/daemon/ipc-contract-inventory.ts +29 -26
  580. package/src/daemon/ipc-contract.ts +111 -44
  581. package/src/daemon/ipc-handler.ts +27 -19
  582. package/src/daemon/ipc-protocol.ts +22 -12
  583. package/src/daemon/ipc-validate.ts +91 -46
  584. package/src/daemon/lifecycle.ts +25 -1
  585. package/src/daemon/main.ts +10 -8
  586. package/src/daemon/media-visibility-policy.ts +3 -1
  587. package/src/daemon/pairing-store.ts +72 -40
  588. package/src/daemon/providers-setup.ts +35 -25
  589. package/src/daemon/recording-executor.ts +37 -30
  590. package/src/daemon/recording-intent-fallback.ts +58 -28
  591. package/src/daemon/recording-intent.ts +71 -61
  592. package/src/daemon/ride-shotgun-handler.ts +201 -121
  593. package/src/daemon/seed-files.ts +28 -17
  594. package/src/daemon/server.ts +23 -14
  595. package/src/daemon/session-agent-loop-handlers.ts +261 -135
  596. package/src/daemon/session-agent-loop.ts +795 -253
  597. package/src/daemon/session-attachments.ts +104 -39
  598. package/src/daemon/session-conflict-gate.ts +72 -28
  599. package/src/daemon/session-dynamic-profile.ts +36 -22
  600. package/src/daemon/session-error.ts +50 -45
  601. package/src/daemon/session-evictor.ts +17 -10
  602. package/src/daemon/session-history.ts +201 -89
  603. package/src/daemon/session-lifecycle.ts +79 -42
  604. package/src/daemon/session-media-retry.ts +89 -41
  605. package/src/daemon/session-memory.ts +77 -55
  606. package/src/daemon/session-messaging.ts +261 -111
  607. package/src/daemon/session-notifiers.ts +57 -45
  608. package/src/daemon/session-process.ts +370 -154
  609. package/src/daemon/session-queue-manager.ts +30 -13
  610. package/src/daemon/session-runtime-assembly.ts +61 -15
  611. package/src/daemon/session-skill-tools.ts +84 -36
  612. package/src/daemon/session-slash.ts +178 -113
  613. package/src/daemon/session-surfaces.ts +498 -211
  614. package/src/daemon/session-tool-setup.ts +22 -17
  615. package/src/daemon/session-usage.ts +26 -13
  616. package/src/daemon/session-workspace.ts +7 -4
  617. package/src/daemon/session.ts +18 -19
  618. package/src/daemon/shutdown-handlers.ts +36 -33
  619. package/src/daemon/tls-certs.ts +90 -57
  620. package/src/daemon/tool-side-effects.ts +97 -65
  621. package/src/daemon/trace-emitter.ts +8 -7
  622. package/src/daemon/video-thumbnail.ts +55 -25
  623. package/src/daemon/watch-handler.ts +164 -86
  624. package/src/email/provider.ts +1 -1
  625. package/src/email/providers/agentmail.ts +87 -45
  626. package/src/email/providers/index.ts +19 -14
  627. package/src/email/service.ts +52 -24
  628. package/src/email/types.ts +2 -2
  629. package/src/errors.ts +1 -1
  630. package/src/events/bus.ts +30 -10
  631. package/src/events/domain-events.ts +19 -13
  632. package/src/events/index.ts +6 -6
  633. package/src/events/tool-audit-listener.ts +34 -20
  634. package/src/events/tool-domain-event-publisher.ts +22 -20
  635. package/src/events/tool-metrics-listener.ts +26 -21
  636. package/src/events/tool-notification-listener.ts +5 -5
  637. package/src/events/tool-profiling-listener.ts +33 -23
  638. package/src/events/tool-trace-listener.ts +70 -46
  639. package/src/export/formatter.ts +38 -32
  640. package/src/followups/followup-store.ts +43 -36
  641. package/src/followups/index.ts +2 -2
  642. package/src/followups/types.ts +1 -1
  643. package/src/gallery/default-gallery.ts +37 -34
  644. package/src/gallery/gallery-manifest.ts +9 -9
  645. package/src/heartbeat/heartbeat-service.ts +59 -37
  646. package/src/home-base/app-link-store.ts +14 -12
  647. package/src/home-base/bootstrap.ts +14 -8
  648. package/src/home-base/prebuilt/seed.ts +35 -26
  649. package/src/home-base/prebuilt-home-base-updater.ts +14 -8
  650. package/src/hooks/cli.ts +56 -43
  651. package/src/hooks/config.ts +27 -14
  652. package/src/hooks/discovery.ts +53 -33
  653. package/src/hooks/manager.ts +50 -26
  654. package/src/hooks/runner.ts +35 -29
  655. package/src/hooks/templates.ts +38 -15
  656. package/src/hooks/types.ts +13 -13
  657. package/src/inbound/platform-callback-registration.ts +21 -15
  658. package/src/inbound/public-ingress-urls.ts +9 -6
  659. package/src/index.ts +20 -19
  660. package/src/influencer/client.ts +269 -108
  661. package/src/instrument.ts +3 -1
  662. package/src/logfire.ts +64 -39
  663. package/src/mcp/client.ts +107 -55
  664. package/src/mcp/manager.ts +45 -18
  665. package/src/mcp/mcp-oauth-provider.ts +114 -62
  666. package/src/media/gemini-image-service.ts +28 -21
  667. package/src/memory/account-store.ts +16 -9
  668. package/src/memory/admin.ts +87 -57
  669. package/src/memory/app-git-service.ts +77 -47
  670. package/src/memory/app-store.ts +151 -77
  671. package/src/memory/attachments-store.ts +123 -53
  672. package/src/memory/canonical-guardian-store.ts +190 -48
  673. package/src/memory/channel-delivery-store.ts +5 -5
  674. package/src/memory/channel-guardian-store.ts +31 -16
  675. package/src/memory/checkpoints.ts +14 -7
  676. package/src/memory/clarification-resolver.ts +219 -104
  677. package/src/memory/conflict-intent.ts +74 -23
  678. package/src/memory/conflict-policy.ts +20 -7
  679. package/src/memory/conflict-store.ts +144 -94
  680. package/src/memory/contradiction-checker.ts +257 -132
  681. package/src/memory/conversation-attention-store.ts +72 -32
  682. package/src/memory/conversation-bootstrap.ts +28 -0
  683. package/src/memory/conversation-crud.ts +12 -5
  684. package/src/memory/conversation-display-order-migration.ts +7 -7
  685. package/src/memory/conversation-key-store.ts +18 -13
  686. package/src/memory/conversation-queries.ts +130 -52
  687. package/src/memory/conversation-store.ts +43 -26
  688. package/src/memory/conversation-title-service.ts +89 -66
  689. package/src/memory/db-init.ts +90 -2
  690. package/src/memory/db.ts +10 -3
  691. package/src/memory/delivery-channels.ts +12 -6
  692. package/src/memory/delivery-crud.ts +26 -12
  693. package/src/memory/delivery-status.ts +19 -16
  694. package/src/memory/embedding-backend.ts +205 -77
  695. package/src/memory/embedding-gemini.ts +23 -10
  696. package/src/memory/embedding-local.ts +89 -44
  697. package/src/memory/embedding-ollama.ts +25 -13
  698. package/src/memory/embedding-openai.ts +20 -11
  699. package/src/memory/embedding-runtime-manager.ts +163 -90
  700. package/src/memory/entity-extractor.ts +185 -123
  701. package/src/memory/external-conversation-store.ts +30 -12
  702. package/src/memory/fingerprint.ts +2 -2
  703. package/src/memory/fts-reconciler.ts +57 -28
  704. package/src/memory/guardian-action-store.ts +162 -100
  705. package/src/memory/guardian-approvals.ts +63 -129
  706. package/src/memory/guardian-rate-limits.ts +20 -9
  707. package/src/memory/guardian-verification.ts +82 -35
  708. package/src/memory/indexer.ts +96 -55
  709. package/src/memory/ingress-invite-store.ts +28 -169
  710. package/src/memory/items-extractor.ts +313 -157
  711. package/src/memory/job-handlers/backfill.ts +116 -63
  712. package/src/memory/job-handlers/cleanup.ts +64 -41
  713. package/src/memory/job-handlers/conflict.ts +90 -49
  714. package/src/memory/job-handlers/embedding.ts +32 -17
  715. package/src/memory/job-handlers/extraction.ts +58 -33
  716. package/src/memory/job-handlers/index-maintenance.ts +31 -17
  717. package/src/memory/job-handlers/media-processing.ts +65 -24
  718. package/src/memory/job-handlers/summarization.ts +186 -128
  719. package/src/memory/job-utils.ts +100 -57
  720. package/src/memory/jobs-store.ts +235 -142
  721. package/src/memory/jobs-worker.ts +167 -83
  722. package/src/memory/llm-request-log-store.ts +13 -11
  723. package/src/memory/llm-usage-store.ts +35 -26
  724. package/src/memory/media-store.ts +151 -44
  725. package/src/memory/message-content.ts +28 -18
  726. package/src/memory/migrations/001-job-deferrals.ts +11 -5
  727. package/src/memory/migrations/002-tool-invocations-fk.ts +14 -6
  728. package/src/memory/migrations/003-memory-fts-backfill.ts +11 -5
  729. package/src/memory/migrations/004-entity-relation-dedup.ts +17 -11
  730. package/src/memory/migrations/005-fingerprint-scope-unique.ts +36 -21
  731. package/src/memory/migrations/006-scope-salted-fingerprints.ts +35 -20
  732. package/src/memory/migrations/007-assistant-id-to-self.ts +40 -27
  733. package/src/memory/migrations/008-remove-assistant-id-columns.ts +58 -36
  734. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +36 -22
  735. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +21 -11
  736. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +30 -15
  737. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +4 -2
  738. package/src/memory/migrations/013-guardian-action-tables.ts +29 -11
  739. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +35 -21
  740. package/src/memory/migrations/015-drop-active-search-index.ts +17 -11
  741. package/src/memory/migrations/016-memory-segments-indexes.ts +7 -3
  742. package/src/memory/migrations/017-memory-items-indexes.ts +4 -2
  743. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -5
  744. package/src/memory/migrations/019-notification-tables-schema-migration.ts +34 -20
  745. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +87 -53
  746. package/src/memory/migrations/021-conversation-status-indexes.ts +7 -3
  747. package/src/memory/migrations/022-add-origin-interface.ts +4 -2
  748. package/src/memory/migrations/023-memory-item-sources-indexes.ts +4 -2
  749. package/src/memory/migrations/024-embedding-vector-blob.ts +34 -18
  750. package/src/memory/migrations/025-messages-fts-backfill.ts +11 -5
  751. package/src/memory/migrations/026-guardian-verification-sessions.ts +80 -14
  752. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +42 -26
  753. package/src/memory/migrations/027-notification-delivery-pairing-columns.ts +22 -8
  754. package/src/memory/migrations/027a-guardian-bootstrap-token.ts +11 -3
  755. package/src/memory/migrations/028-call-session-mode.ts +13 -3
  756. package/src/memory/migrations/028-notification-delivery-client-ack.ts +22 -8
  757. package/src/memory/migrations/029-channel-inbound-delivered-segments.ts +7 -3
  758. package/src/memory/migrations/030-guardian-action-followup.ts +46 -8
  759. package/src/memory/migrations/030-guardian-verification-purpose.ts +4 -2
  760. package/src/memory/migrations/031-conversations-thread-type-index.ts +4 -2
  761. package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +4 -2
  762. package/src/memory/migrations/032-notification-delivery-thread-decision.ts +22 -8
  763. package/src/memory/migrations/033-scoped-approval-grants.ts +1 -1
  764. package/src/memory/migrations/034-guardian-action-tool-metadata.ts +15 -3
  765. package/src/memory/migrations/035-guardian-action-supersession.ts +15 -3
  766. package/src/memory/migrations/036-normalize-phone-identities.ts +101 -87
  767. package/src/memory/migrations/037-voice-invite-columns.ts +22 -4
  768. package/src/memory/migrations/038-actor-token-records.ts +5 -9
  769. package/src/memory/migrations/039-actor-refresh-token-records.ts +7 -13
  770. package/src/memory/migrations/100-core-tables.ts +1 -1
  771. package/src/memory/migrations/101-watchers-and-logs.ts +1 -1
  772. package/src/memory/migrations/103-complex-migrations.ts +9 -9
  773. package/src/memory/migrations/104-core-indexes.ts +188 -64
  774. package/src/memory/migrations/105-contacts-and-triage.ts +28 -10
  775. package/src/memory/migrations/106-call-sessions.ts +58 -16
  776. package/src/memory/migrations/107-followups.ts +16 -6
  777. package/src/memory/migrations/108-tasks-and-work-items.ts +43 -11
  778. package/src/memory/migrations/109-external-conversation-bindings.ts +11 -5
  779. package/src/memory/migrations/110-channel-guardian.ts +48 -10
  780. package/src/memory/migrations/111-media-assets.ts +52 -18
  781. package/src/memory/migrations/112-assistant-inbox.ts +32 -12
  782. package/src/memory/migrations/113-late-migrations.ts +12 -12
  783. package/src/memory/migrations/114-notifications.ts +28 -12
  784. package/src/memory/migrations/115-sequences.ts +10 -4
  785. package/src/memory/migrations/116-messages-fts.ts +1 -1
  786. package/src/memory/migrations/117-conversation-attention.ts +16 -6
  787. package/src/memory/migrations/118-reminder-routing-intent.ts +7 -3
  788. package/src/memory/migrations/119-schema-indexes-and-columns.ts +35 -15
  789. package/src/memory/migrations/120-fk-cascade-rebuilds.ts +36 -17
  790. package/src/memory/migrations/121-canonical-guardian-requests.ts +25 -9
  791. package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +11 -3
  792. package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +4 -2
  793. package/src/memory/migrations/124-voice-invite-display-metadata.ts +15 -3
  794. package/src/memory/migrations/125-guardian-principal-id-columns.ts +22 -4
  795. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +174 -126
  796. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +58 -42
  797. package/src/memory/migrations/128-contacts-role-principal.ts +26 -0
  798. package/src/memory/migrations/129-contact-channels-access-fields.ts +105 -0
  799. package/src/memory/migrations/130-contact-channels-type-ext-chat-id-index.ts +15 -0
  800. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +134 -0
  801. package/src/memory/migrations/132-contacts-assistant-id.ts +21 -0
  802. package/src/memory/migrations/index.ts +82 -73
  803. package/src/memory/migrations/registry.ts +53 -37
  804. package/src/memory/migrations/validate-migration-state.ts +73 -46
  805. package/src/memory/profile-compiler.ts +58 -24
  806. package/src/memory/published-pages-store.ts +12 -16
  807. package/src/memory/qdrant-circuit-breaker.ts +28 -20
  808. package/src/memory/qdrant-client.ts +99 -63
  809. package/src/memory/qdrant-manager.ts +89 -57
  810. package/src/memory/query-builder.ts +9 -7
  811. package/src/memory/raw-query.ts +63 -14
  812. package/src/memory/recall-cache.ts +15 -8
  813. package/src/memory/retrieval-budget.ts +0 -1
  814. package/src/memory/retriever.ts +385 -192
  815. package/src/memory/schema-migration.ts +1 -1
  816. package/src/memory/schema.ts +44 -56
  817. package/src/memory/scoped-approval-grants.ts +99 -45
  818. package/src/memory/search/entity.ts +102 -40
  819. package/src/memory/search/formatting.ts +70 -52
  820. package/src/memory/search/lexical.ts +82 -43
  821. package/src/memory/search/ranking.ts +103 -39
  822. package/src/memory/search/semantic.ts +59 -35
  823. package/src/memory/search/types.ts +8 -8
  824. package/src/memory/segmenter.ts +20 -12
  825. package/src/memory/shared-app-links-store.ts +21 -16
  826. package/src/memory/task-memory-cleanup.ts +18 -8
  827. package/src/memory/tool-usage-store.ts +27 -19
  828. package/src/memory/validation.ts +4 -2
  829. package/src/messaging/activity-analyzer.ts +7 -7
  830. package/src/messaging/draft-store.ts +13 -10
  831. package/src/messaging/email-classifier.ts +73 -37
  832. package/src/messaging/index.ts +3 -3
  833. package/src/messaging/outreach-classifier.ts +76 -38
  834. package/src/messaging/provider-types.ts +2 -4
  835. package/src/messaging/provider.ts +37 -8
  836. package/src/messaging/providers/gmail/adapter.ts +183 -66
  837. package/src/messaging/providers/gmail/client.ts +3 -1
  838. package/src/messaging/providers/gmail/mime-builder.ts +21 -19
  839. package/src/messaging/providers/gmail/people-client.ts +22 -9
  840. package/src/messaging/providers/gmail/types.ts +6 -6
  841. package/src/messaging/providers/slack/adapter.ts +93 -43
  842. package/src/messaging/providers/slack/client.ts +100 -41
  843. package/src/messaging/providers/slack/types.ts +6 -0
  844. package/src/messaging/providers/sms/adapter.ts +76 -40
  845. package/src/messaging/providers/sms/client.ts +4 -4
  846. package/src/messaging/providers/telegram-bot/adapter.ts +52 -30
  847. package/src/messaging/providers/telegram-bot/client.ts +7 -7
  848. package/src/messaging/providers/whatsapp/adapter.ts +58 -31
  849. package/src/messaging/providers/whatsapp/client.ts +4 -4
  850. package/src/messaging/registry.ts +9 -5
  851. package/src/messaging/style-analyzer.ts +69 -39
  852. package/src/messaging/thread-summarizer.ts +101 -53
  853. package/src/messaging/triage-engine.ts +111 -82
  854. package/src/messaging/types.ts +10 -10
  855. package/src/migrations/config-merge.ts +18 -10
  856. package/src/migrations/data-layout.ts +35 -22
  857. package/src/migrations/data-merge.ts +17 -7
  858. package/src/migrations/hooks-merge.ts +43 -16
  859. package/src/migrations/index.ts +6 -6
  860. package/src/migrations/log.ts +9 -5
  861. package/src/migrations/skills-merge.ts +17 -7
  862. package/src/migrations/workspace-layout.ts +39 -25
  863. package/src/notifications/AGENTS.md +5 -0
  864. package/src/notifications/adapters/macos.ts +21 -14
  865. package/src/notifications/adapters/sms.ts +28 -15
  866. package/src/notifications/adapters/telegram.ts +24 -15
  867. package/src/notifications/broadcaster.ts +108 -52
  868. package/src/notifications/conversation-pairing.ts +64 -29
  869. package/src/notifications/copy-composer.ts +165 -95
  870. package/src/notifications/decision-engine.ts +353 -147
  871. package/src/notifications/decisions-store.ts +26 -10
  872. package/src/notifications/deliveries-store.ts +23 -13
  873. package/src/notifications/destination-resolver.ts +42 -24
  874. package/src/notifications/deterministic-checks.ts +78 -27
  875. package/src/notifications/emit-signal.ts +83 -45
  876. package/src/notifications/events-store.ts +13 -7
  877. package/src/notifications/guardian-question-mode.ts +125 -75
  878. package/src/notifications/preference-extractor.ts +85 -53
  879. package/src/notifications/preference-summary.ts +31 -18
  880. package/src/notifications/preferences-store.ts +29 -18
  881. package/src/notifications/runtime-dispatch.ts +22 -12
  882. package/src/notifications/signal.ts +4 -4
  883. package/src/notifications/thread-candidates.ts +59 -23
  884. package/src/notifications/thread-seed-composer.ts +45 -27
  885. package/src/notifications/types.ts +19 -10
  886. package/src/oauth/connect-orchestrator.ts +105 -54
  887. package/src/oauth/connect-types.ts +3 -3
  888. package/src/oauth/provider-profiles.ts +80 -59
  889. package/src/oauth/scope-policy.ts +5 -2
  890. package/src/oauth/token-persistence.ts +58 -24
  891. package/src/outbound-proxy/certs.ts +284 -0
  892. package/src/outbound-proxy/config.ts +94 -0
  893. package/src/outbound-proxy/connect-tunnel.ts +84 -0
  894. package/src/outbound-proxy/health.ts +62 -0
  895. package/src/outbound-proxy/host-pattern-match.ts +67 -0
  896. package/src/outbound-proxy/http-forwarder.ts +162 -0
  897. package/src/outbound-proxy/index.ts +80 -0
  898. package/src/outbound-proxy/logging.ts +193 -0
  899. package/src/outbound-proxy/mitm-handler.ts +292 -0
  900. package/src/outbound-proxy/policy.ts +172 -0
  901. package/src/outbound-proxy/router.ts +64 -0
  902. package/src/outbound-proxy/server.ts +145 -0
  903. package/src/outbound-proxy/types.ts +150 -0
  904. package/src/permissions/checker.ts +481 -189
  905. package/src/permissions/defaults.ts +135 -108
  906. package/src/permissions/prompter.ts +53 -27
  907. package/src/permissions/secret-prompter.ts +21 -15
  908. package/src/permissions/shell-identity.ts +47 -16
  909. package/src/permissions/trust-store.ts +185 -73
  910. package/src/permissions/types.ts +22 -12
  911. package/src/permissions/workspace-policy.ts +47 -38
  912. package/src/playbooks/index.ts +10 -2
  913. package/src/playbooks/playbook-compiler.ts +30 -24
  914. package/src/playbooks/types.ts +11 -8
  915. package/src/providers/anthropic/client.ts +325 -168
  916. package/src/providers/failover.ts +57 -22
  917. package/src/providers/fireworks/client.ts +9 -5
  918. package/src/providers/gemini/client.ts +61 -39
  919. package/src/providers/model-intents.ts +40 -33
  920. package/src/providers/ollama/client.ts +7 -7
  921. package/src/providers/openai/client.ts +106 -68
  922. package/src/providers/openrouter/client.ts +9 -5
  923. package/src/providers/provider-send-message.ts +59 -27
  924. package/src/providers/ratelimit.ts +25 -8
  925. package/src/providers/registry.ts +86 -38
  926. package/src/providers/retry.ts +84 -36
  927. package/src/providers/stream-timeout.ts +5 -3
  928. package/src/providers/types.ts +7 -6
  929. package/src/runtime/AGENTS.md +42 -0
  930. package/src/runtime/access-request-helper.ts +118 -68
  931. package/src/runtime/actor-refresh-token-store.ts +21 -16
  932. package/src/runtime/actor-token-store.ts +25 -18
  933. package/src/runtime/actor-trust-resolver.ts +183 -80
  934. package/src/runtime/approval-conversation-turn.ts +39 -26
  935. package/src/runtime/approval-message-composer.ts +116 -84
  936. package/src/runtime/assistant-event-hub.ts +25 -6
  937. package/src/runtime/assistant-event.ts +4 -4
  938. package/src/runtime/assistant-scope.ts +1 -1
  939. package/src/runtime/auth/__tests__/guard-tests.test.ts +36 -14
  940. package/src/runtime/auth/context.ts +8 -7
  941. package/src/runtime/auth/credential-service.ts +60 -38
  942. package/src/runtime/auth/external-assistant-id.ts +16 -8
  943. package/src/runtime/auth/index.ts +23 -16
  944. package/src/runtime/auth/route-policy.ts +170 -104
  945. package/src/runtime/auth/scopes.ts +22 -29
  946. package/src/runtime/auth/subject.ts +19 -13
  947. package/src/runtime/auth/token-service.ts +3 -3
  948. package/src/runtime/auth/types.ts +23 -23
  949. package/src/runtime/channel-approval-parser.ts +37 -14
  950. package/src/runtime/channel-approval-types.ts +12 -4
  951. package/src/runtime/channel-approvals.ts +41 -23
  952. package/src/runtime/channel-guardian-service.ts +144 -103
  953. package/src/runtime/channel-invite-transport.ts +4 -2
  954. package/src/runtime/channel-invite-transports/telegram.ts +16 -10
  955. package/src/runtime/channel-invite-transports/voice.ts +7 -7
  956. package/src/runtime/channel-readiness-service.ts +139 -90
  957. package/src/runtime/channel-readiness-types.ts +4 -2
  958. package/src/runtime/channel-reply-delivery.ts +21 -11
  959. package/src/runtime/channel-retry-sweep.ts +111 -62
  960. package/src/runtime/confirmation-request-guardian-bridge.ts +73 -54
  961. package/src/runtime/gateway-client.ts +86 -53
  962. package/src/runtime/guardian-action-conversation-turn.ts +34 -18
  963. package/src/runtime/guardian-action-followup-executor.ts +115 -45
  964. package/src/runtime/guardian-action-grant-minter.ts +40 -24
  965. package/src/runtime/guardian-action-message-composer.ts +105 -84
  966. package/src/runtime/guardian-decision-types.ts +28 -13
  967. package/src/runtime/guardian-outbound-actions.ts +9 -0
  968. package/src/runtime/guardian-reply-router.ts +274 -145
  969. package/src/runtime/guardian-vellum-migration.ts +38 -24
  970. package/src/runtime/guardian-verification-templates.ts +8 -11
  971. package/src/runtime/http-router.ts +175 -0
  972. package/src/runtime/http-server.ts +931 -669
  973. package/src/runtime/http-types.ts +2 -2
  974. package/src/runtime/ingress-service.ts +182 -89
  975. package/src/runtime/invite-redemption-service.ts +211 -134
  976. package/src/runtime/invite-redemption-templates.ts +18 -11
  977. package/src/runtime/local-actor-identity.ts +73 -55
  978. package/src/runtime/middleware/auth.ts +25 -14
  979. package/src/runtime/middleware/error-handler.ts +15 -11
  980. package/src/runtime/middleware/rate-limiter.ts +23 -17
  981. package/src/runtime/middleware/request-logger.ts +4 -4
  982. package/src/runtime/middleware/twilio-validation.ts +29 -20
  983. package/src/runtime/migrations/migration-transport.ts +575 -0
  984. package/src/runtime/migrations/migration-wizard.ts +715 -0
  985. package/src/runtime/migrations/rebind-secrets-screen.ts +351 -0
  986. package/src/runtime/migrations/transfer-progress-screen.ts +321 -0
  987. package/src/runtime/migrations/validation-results-screen.ts +467 -0
  988. package/src/runtime/migrations/vbundle-builder.ts +295 -0
  989. package/src/runtime/migrations/vbundle-import-analyzer.ts +212 -0
  990. package/src/runtime/migrations/vbundle-importer.ts +339 -0
  991. package/src/runtime/migrations/vbundle-validator.ts +356 -0
  992. package/src/runtime/pending-interactions.ts +16 -7
  993. package/src/runtime/routes/access-request-decision.ts +73 -52
  994. package/src/runtime/routes/app-routes.ts +56 -38
  995. package/src/runtime/routes/approval-routes.ts +165 -74
  996. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +930 -0
  997. package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +82 -0
  998. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +151 -0
  999. package/src/runtime/routes/attachment-routes.ts +59 -48
  1000. package/src/runtime/routes/brain-graph-routes.ts +85 -69
  1001. package/src/runtime/routes/call-routes.ts +79 -38
  1002. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +10 -10
  1003. package/src/runtime/routes/channel-delivery-routes.ts +19 -14
  1004. package/src/runtime/routes/channel-guardian-routes.ts +3 -3
  1005. package/src/runtime/routes/channel-inbound-routes.ts +2 -2
  1006. package/src/runtime/routes/channel-readiness-routes.ts +12 -6
  1007. package/src/runtime/routes/channel-route-shared.ts +33 -25
  1008. package/src/runtime/routes/channel-routes.ts +4 -6
  1009. package/src/runtime/routes/contact-routes.ts +205 -16
  1010. package/src/runtime/routes/conversation-attention-routes.ts +57 -28
  1011. package/src/runtime/routes/conversation-routes.ts +321 -174
  1012. package/src/runtime/routes/debug-routes.ts +14 -10
  1013. package/src/runtime/routes/events-routes.ts +90 -57
  1014. package/src/runtime/routes/global-search-routes.ts +266 -0
  1015. package/src/runtime/routes/guardian-action-routes.ts +147 -56
  1016. package/src/runtime/routes/guardian-approval-interception.ts +255 -880
  1017. package/src/runtime/routes/guardian-approval-prompt.ts +40 -24
  1018. package/src/runtime/routes/guardian-approval-reply-helpers.ts +135 -0
  1019. package/src/runtime/routes/guardian-bootstrap-routes.ts +55 -36
  1020. package/src/runtime/routes/guardian-expiry-sweep.ts +63 -37
  1021. package/src/runtime/routes/guardian-refresh-routes.ts +40 -19
  1022. package/src/runtime/routes/identity-routes.ts +71 -42
  1023. package/src/runtime/routes/inbound-conversation.ts +17 -11
  1024. package/src/runtime/routes/inbound-message-handler.ts +278 -1460
  1025. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +658 -0
  1026. package/src/runtime/routes/inbound-stages/background-dispatch.ts +492 -0
  1027. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +214 -0
  1028. package/src/runtime/routes/inbound-stages/edit-intercept.ts +116 -0
  1029. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +167 -0
  1030. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +185 -0
  1031. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +132 -0
  1032. package/src/runtime/routes/inbound-stages/verification-intercept.ts +340 -0
  1033. package/src/runtime/routes/ingress-routes.ts +34 -23
  1034. package/src/runtime/routes/integration-routes.ts +60 -21
  1035. package/src/runtime/routes/migration-routes.ts +434 -0
  1036. package/src/runtime/routes/pairing-routes.ts +157 -79
  1037. package/src/runtime/routes/secret-routes.ts +6 -2
  1038. package/src/runtime/routes/twilio-routes.ts +443 -249
  1039. package/src/runtime/tool-grant-request-helper.ts +36 -27
  1040. package/src/runtime/{guardian-context-resolver.ts → trust-context-resolver.ts} +29 -41
  1041. package/src/schedule/integration-status.ts +44 -9
  1042. package/src/schedule/recurrence-engine.ts +47 -24
  1043. package/src/schedule/recurrence-types.ts +12 -7
  1044. package/src/schedule/schedule-store.ts +166 -83
  1045. package/src/schedule/scheduler.ts +26 -22
  1046. package/src/security/encrypted-store.ts +68 -38
  1047. package/src/security/keychain.ts +183 -120
  1048. package/src/security/oauth-callback-registry.ts +3 -3
  1049. package/src/security/oauth2.ts +226 -138
  1050. package/src/security/redaction.ts +24 -24
  1051. package/src/security/secret-allowlist.ts +46 -21
  1052. package/src/security/secret-ingress.ts +15 -7
  1053. package/src/security/secret-scanner.ts +193 -104
  1054. package/src/security/secure-keys.ts +9 -3
  1055. package/src/security/token-manager.ts +99 -40
  1056. package/src/security/tool-approval-digest.ts +3 -3
  1057. package/src/sequence/analytics.ts +52 -27
  1058. package/src/sequence/engine.ts +135 -72
  1059. package/src/sequence/guardrails.ts +32 -20
  1060. package/src/sequence/importer.ts +75 -37
  1061. package/src/sequence/reply-matcher.ts +36 -18
  1062. package/src/sequence/store.ts +137 -75
  1063. package/src/sequence/types.ts +30 -16
  1064. package/src/services/published-app-updater.ts +26 -16
  1065. package/src/services/vercel-deploy.ts +19 -15
  1066. package/src/skills/active-skill-tools.ts +3 -3
  1067. package/src/skills/clawhub.ts +178 -90
  1068. package/src/skills/include-graph.ts +24 -17
  1069. package/src/skills/managed-store.ts +89 -42
  1070. package/src/skills/path-classifier.ts +10 -10
  1071. package/src/skills/remote-skill-policy.ts +31 -22
  1072. package/src/skills/slash-commands.ts +36 -30
  1073. package/src/skills/tool-manifest.ts +60 -31
  1074. package/src/skills/version-hash.ts +25 -15
  1075. package/src/slack/slack-webhook.ts +19 -15
  1076. package/src/subagent/index.ts +4 -8
  1077. package/src/subagent/manager.ts +119 -69
  1078. package/src/subagent/types.ts +9 -12
  1079. package/src/swarm/backend-claude-code.ts +124 -45
  1080. package/src/swarm/checkpoint.ts +36 -16
  1081. package/src/swarm/graph-utils.ts +1 -3
  1082. package/src/swarm/index.ts +38 -19
  1083. package/src/swarm/limits.ts +13 -4
  1084. package/src/swarm/orchestrator.ts +108 -57
  1085. package/src/swarm/plan-validator.ts +23 -17
  1086. package/src/swarm/router-planner.ts +51 -22
  1087. package/src/swarm/router-prompts.ts +4 -1
  1088. package/src/swarm/synthesizer.ts +26 -18
  1089. package/src/swarm/types.ts +14 -4
  1090. package/src/swarm/worker-backend.ts +36 -26
  1091. package/src/swarm/worker-prompts.ts +13 -9
  1092. package/src/swarm/worker-runner.ts +40 -34
  1093. package/src/tasks/candidate-store.ts +14 -6
  1094. package/src/tasks/ephemeral-permissions.ts +9 -5
  1095. package/src/tasks/task-compiler.ts +41 -38
  1096. package/src/tasks/task-runner.ts +54 -26
  1097. package/src/tasks/task-scheduler.ts +1 -1
  1098. package/src/tasks/task-store.ts +20 -7
  1099. package/src/tasks/tool-sanitizer.ts +3 -3
  1100. package/src/tools/apps/definitions.ts +23 -15
  1101. package/src/tools/apps/executors.ts +118 -37
  1102. package/src/tools/apps/open-proxy.ts +5 -5
  1103. package/src/tools/apps/registry.ts +2 -2
  1104. package/src/tools/assets/materialize.ts +59 -41
  1105. package/src/tools/assets/search.ts +86 -48
  1106. package/src/tools/browser/api-map.ts +52 -36
  1107. package/src/tools/browser/auth-cache.ts +21 -18
  1108. package/src/tools/browser/auth-detector.ts +43 -28
  1109. package/src/tools/browser/auto-navigate.ts +149 -68
  1110. package/src/tools/browser/browser-execution.ts +9 -3
  1111. package/src/tools/browser/headless-browser.ts +287 -150
  1112. package/src/tools/browser/jit-auth.ts +37 -21
  1113. package/src/tools/browser/network-recorder.ts +138 -56
  1114. package/src/tools/browser/recording-store.ts +22 -15
  1115. package/src/tools/browser/runtime-check.ts +8 -5
  1116. package/src/tools/browser/x-auto-navigate.ts +88 -47
  1117. package/src/tools/calls/call-end.ts +9 -6
  1118. package/src/tools/calls/call-start.ts +30 -20
  1119. package/src/tools/calls/call-status.ts +8 -5
  1120. package/src/tools/claude-code/claude-code.ts +301 -165
  1121. package/src/tools/computer-use/definitions.ts +159 -130
  1122. package/src/tools/computer-use/registry.ts +2 -2
  1123. package/src/tools/computer-use/request-computer-control.ts +21 -13
  1124. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  1125. package/src/tools/credentials/account-registry.ts +52 -35
  1126. package/src/tools/credentials/broker-types.ts +1 -1
  1127. package/src/tools/credentials/broker.ts +97 -55
  1128. package/src/tools/credentials/domain-policy.ts +5 -2
  1129. package/src/tools/credentials/host-pattern-match.ts +15 -8
  1130. package/src/tools/credentials/metadata-store.ts +93 -43
  1131. package/src/tools/credentials/policy-types.ts +5 -2
  1132. package/src/tools/credentials/policy-validate.ts +21 -14
  1133. package/src/tools/credentials/post-connect-hooks.ts +18 -7
  1134. package/src/tools/credentials/resolve.ts +11 -10
  1135. package/src/tools/credentials/selection.ts +30 -25
  1136. package/src/tools/credentials/tool-policy.ts +5 -2
  1137. package/src/tools/credentials/vault.ts +452 -183
  1138. package/src/tools/document/document-tool.ts +23 -17
  1139. package/src/tools/document/editor-template.ts +12 -7
  1140. package/src/tools/execution-target.ts +13 -10
  1141. package/src/tools/execution-timeout.ts +6 -5
  1142. package/src/tools/executor.ts +141 -74
  1143. package/src/tools/filesystem/edit.ts +82 -45
  1144. package/src/tools/filesystem/fuzzy-match.ts +70 -32
  1145. package/src/tools/filesystem/read.ts +46 -28
  1146. package/src/tools/filesystem/view-image.ts +86 -42
  1147. package/src/tools/filesystem/write.ts +53 -32
  1148. package/src/tools/followups/followup_create.ts +43 -17
  1149. package/src/tools/followups/followup_list.ts +28 -13
  1150. package/src/tools/followups/followup_resolve.ts +9 -6
  1151. package/src/tools/guardian-control-plane-policy.ts +15 -14
  1152. package/src/tools/host-filesystem/edit.ts +77 -42
  1153. package/src/tools/host-filesystem/read.ts +52 -33
  1154. package/src/tools/host-filesystem/write.ts +50 -29
  1155. package/src/tools/host-terminal/host-shell.ts +97 -61
  1156. package/src/tools/mcp/mcp-tool-factory.ts +21 -14
  1157. package/src/tools/memory/definitions.ts +60 -28
  1158. package/src/tools/memory/handlers.ts +149 -77
  1159. package/src/tools/memory/register.ts +39 -16
  1160. package/src/tools/network/__tests__/web-search.test.ts +236 -177
  1161. package/src/tools/network/domain-normalize.ts +13 -9
  1162. package/src/tools/network/script-proxy/__tests__/logging.test.ts +193 -123
  1163. package/src/tools/network/script-proxy/__tests__/policy.test.ts +225 -127
  1164. package/src/tools/network/script-proxy/index.ts +1 -17
  1165. package/src/tools/network/script-proxy/session-manager.ts +151 -84
  1166. package/src/tools/network/url-safety.ts +56 -34
  1167. package/src/tools/network/web-fetch.ts +273 -155
  1168. package/src/tools/network/web-search.ts +166 -81
  1169. package/src/tools/permission-checker.ts +6 -25
  1170. package/src/tools/policy-context.ts +8 -5
  1171. package/src/tools/registry.ts +73 -46
  1172. package/src/tools/reminder/reminder-store.ts +65 -44
  1173. package/src/tools/reminder/reminder.ts +76 -35
  1174. package/src/tools/schedule/create.ts +44 -21
  1175. package/src/tools/schedule/delete.ts +8 -5
  1176. package/src/tools/schedule/list.ts +39 -19
  1177. package/src/tools/schedule/update.ts +49 -26
  1178. package/src/tools/secret-detection-handler.ts +130 -49
  1179. package/src/tools/sensitive-output-placeholders.ts +15 -8
  1180. package/src/tools/shared/filesystem/edit-engine.ts +45 -14
  1181. package/src/tools/shared/filesystem/errors.ts +18 -18
  1182. package/src/tools/shared/filesystem/file-ops-service.ts +59 -32
  1183. package/src/tools/shared/filesystem/format-diff.ts +21 -11
  1184. package/src/tools/shared/filesystem/path-policy.ts +17 -13
  1185. package/src/tools/shared/filesystem/size-guard.ts +8 -4
  1186. package/src/tools/shared/filesystem/types.ts +2 -2
  1187. package/src/tools/shared/shell-output.ts +4 -3
  1188. package/src/tools/side-effects.ts +36 -28
  1189. package/src/tools/skills/delete-managed.ts +30 -17
  1190. package/src/tools/skills/load.ts +88 -46
  1191. package/src/tools/skills/sandbox-runner.ts +62 -46
  1192. package/src/tools/skills/scaffold-managed.ts +98 -48
  1193. package/src/tools/skills/script-contract.ts +5 -2
  1194. package/src/tools/skills/skill-script-runner.ts +29 -13
  1195. package/src/tools/skills/skill-tool-factory.ts +20 -10
  1196. package/src/tools/subagent/abort.ts +10 -4
  1197. package/src/tools/subagent/message.ts +14 -8
  1198. package/src/tools/subagent/read.ts +20 -11
  1199. package/src/tools/subagent/spawn.ts +14 -6
  1200. package/src/tools/subagent/status.ts +7 -4
  1201. package/src/tools/swarm/delegate.ts +75 -49
  1202. package/src/tools/system/avatar-generator.ts +46 -33
  1203. package/src/tools/system/navigate-settings.ts +29 -19
  1204. package/src/tools/system/open-system-settings.ts +30 -20
  1205. package/src/tools/system/request-permission.ts +59 -44
  1206. package/src/tools/system/version.ts +27 -16
  1207. package/src/tools/system/voice-config.ts +116 -53
  1208. package/src/tools/tasks/index.ts +8 -8
  1209. package/src/tools/tasks/task-delete.ts +61 -22
  1210. package/src/tools/tasks/task-list.ts +23 -11
  1211. package/src/tools/tasks/task-run.ts +41 -16
  1212. package/src/tools/tasks/task-save.ts +27 -10
  1213. package/src/tools/tasks/work-item-enqueue.ts +114 -48
  1214. package/src/tools/tasks/work-item-list.ts +20 -10
  1215. package/src/tools/tasks/work-item-remove.ts +49 -15
  1216. package/src/tools/tasks/work-item-run.ts +34 -13
  1217. package/src/tools/tasks/work-item-update.ts +84 -31
  1218. package/src/tools/terminal/backends/native.ts +64 -35
  1219. package/src/tools/terminal/backends/types.ts +6 -2
  1220. package/src/tools/terminal/parser.ts +200 -125
  1221. package/src/tools/terminal/safe-env.ts +27 -21
  1222. package/src/tools/terminal/sandbox-diagnostics.ts +31 -13
  1223. package/src/tools/terminal/sandbox.ts +10 -6
  1224. package/src/tools/terminal/shell.ts +124 -68
  1225. package/src/tools/tool-approval-handler.ts +193 -138
  1226. package/src/tools/types.ts +43 -23
  1227. package/src/tools/ui-surface/definitions.ts +124 -89
  1228. package/src/tools/ui-surface/registry.ts +2 -2
  1229. package/src/tools/watch/screen-watch.ts +50 -32
  1230. package/src/tools/watch/watch-state.ts +41 -15
  1231. package/src/tools/watcher/create.ts +37 -15
  1232. package/src/tools/watcher/delete.ts +9 -6
  1233. package/src/tools/watcher/digest.ts +10 -6
  1234. package/src/tools/watcher/list.ts +37 -14
  1235. package/src/tools/watcher/update.ts +33 -18
  1236. package/src/tools/weather/service.ts +331 -174
  1237. package/src/twitter/client.ts +261 -138
  1238. package/src/twitter/oauth-client.ts +17 -13
  1239. package/src/twitter/router.ts +51 -23
  1240. package/src/twitter/session.ts +27 -18
  1241. package/src/types/qrcode.d.ts +6 -3
  1242. package/src/usage/actors.ts +16 -16
  1243. package/src/usage/types.ts +3 -3
  1244. package/src/util/bundled-asset.ts +10 -6
  1245. package/src/util/canonicalize-identity.ts +11 -4
  1246. package/src/util/clipboard.ts +7 -7
  1247. package/src/util/content-id.ts +3 -3
  1248. package/src/util/debounce.ts +3 -2
  1249. package/src/util/diff.ts +55 -33
  1250. package/src/util/errors.ts +26 -26
  1251. package/src/util/fs.ts +8 -2
  1252. package/src/util/log-redact.ts +12 -12
  1253. package/src/util/logger.ts +112 -51
  1254. package/src/util/network-info.ts +13 -5
  1255. package/src/util/object.ts +4 -2
  1256. package/src/util/phone.ts +4 -4
  1257. package/src/util/platform.ts +80 -58
  1258. package/src/util/pricing.ts +49 -31
  1259. package/src/util/retry.ts +18 -7
  1260. package/src/util/row-mapper.ts +7 -4
  1261. package/src/util/silently.ts +7 -4
  1262. package/src/util/spawn.ts +48 -0
  1263. package/src/util/spinner.ts +9 -7
  1264. package/src/util/time.ts +16 -3
  1265. package/src/util/truncate.ts +1 -1
  1266. package/src/util/voice-code.ts +6 -4
  1267. package/src/util/xml.ts +5 -1
  1268. package/src/version.ts +12 -8
  1269. package/src/watcher/engine.ts +71 -44
  1270. package/src/watcher/provider-registry.ts +1 -1
  1271. package/src/watcher/providers/github.ts +40 -23
  1272. package/src/watcher/providers/gmail.ts +59 -38
  1273. package/src/watcher/providers/google-calendar.ts +62 -48
  1274. package/src/watcher/providers/linear.ts +219 -150
  1275. package/src/watcher/providers/slack.ts +93 -27
  1276. package/src/watcher/watcher-store.ts +75 -55
  1277. package/src/work-items/work-item-runner.ts +62 -29
  1278. package/src/work-items/work-item-store.ts +137 -47
  1279. package/src/workspace/commit-message-enrichment-service.ts +65 -25
  1280. package/src/workspace/commit-message-provider.ts +14 -12
  1281. package/src/workspace/git-service.ts +355 -239
  1282. package/src/workspace/heartbeat-service.ts +74 -37
  1283. package/src/workspace/provider-commit-message-generator.ts +95 -70
  1284. package/src/workspace/top-level-renderer.ts +10 -8
  1285. package/src/workspace/top-level-scanner.ts +9 -3
  1286. package/src/workspace/turn-commit.ts +63 -36
  1287. package/src/__tests__/ingress-member-store.test.ts +0 -294
  1288. package/src/__tests__/script-proxy-router.test.ts +0 -215
  1289. package/src/config/bundled-skills/trusted-contacts/SKILL.md +0 -372
  1290. package/src/memory/guardian-bindings.ts +0 -158
  1291. package/src/memory/ingress-member-store.ts +0 -352
  1292. package/src/tools/network/script-proxy/__tests__/router.test.ts +0 -77
  1293. package/src/tools/network/script-proxy/certs.ts +0 -7
  1294. package/src/tools/network/script-proxy/connect-tunnel.ts +0 -1
  1295. package/src/tools/network/script-proxy/http-forwarder.ts +0 -2
  1296. package/src/tools/network/script-proxy/logging.ts +0 -12
  1297. package/src/tools/network/script-proxy/mitm-handler.ts +0 -2
  1298. package/src/tools/network/script-proxy/policy.ts +0 -4
  1299. package/src/tools/network/script-proxy/router.ts +0 -2
  1300. package/src/tools/network/script-proxy/server.ts +0 -5
  1301. package/src/tools/network/script-proxy/types.ts +0 -19
@@ -1,34 +1,56 @@
1
- import * as net from 'node:net';
1
+ import * as net from "node:net";
2
2
 
3
- import { v4 as uuid } from 'uuid';
3
+ import { v4 as uuid } from "uuid";
4
4
 
5
- import { createAssistantMessage, createUserMessage } from '../../agent/message-types.js';
6
- import { type InterfaceId,isChannelId, parseChannelId, parseInterfaceId } from '../../channels/types.js';
7
- import { getConfig } from '../../config/loader.js';
8
- import { getAttachmentsForMessage, getFilePathForAttachment, setAttachmentThumbnail } from '../../memory/attachments-store.js';
5
+ import {
6
+ createAssistantMessage,
7
+ createUserMessage,
8
+ } from "../../agent/message-types.js";
9
+ import {
10
+ type InterfaceId,
11
+ isChannelId,
12
+ parseChannelId,
13
+ parseInterfaceId,
14
+ } from "../../channels/types.js";
15
+ import { getConfig } from "../../config/loader.js";
16
+ import {
17
+ getAttachmentsForMessage,
18
+ getFilePathForAttachment,
19
+ setAttachmentThumbnail,
20
+ } from "../../memory/attachments-store.js";
9
21
  import {
10
22
  createCanonicalGuardianRequest,
11
23
  generateCanonicalRequestCode,
12
24
  listCanonicalGuardianRequests,
13
25
  listPendingCanonicalGuardianRequestsByDestinationConversation,
14
26
  resolveCanonicalGuardianRequest,
15
- } from '../../memory/canonical-guardian-store.js';
16
- import { getAttentionStateByConversationIds } from '../../memory/conversation-attention-store.js';
17
- import * as conversationStore from '../../memory/conversation-store.js';
18
- import { GENERATING_TITLE, queueGenerateConversationTitle, UNTITLED_FALLBACK } from '../../memory/conversation-title-service.js';
19
- import * as externalConversationStore from '../../memory/external-conversation-store.js';
20
- import { DAEMON_INTERNAL_ASSISTANT_ID } from '../../runtime/assistant-scope.js';
21
- import { routeGuardianReply } from '../../runtime/guardian-reply-router.js';
22
- import { resolveLocalIpcAuthContext, resolveLocalIpcGuardianContext } from '../../runtime/local-actor-identity.js';
23
- import * as pendingInteractions from '../../runtime/pending-interactions.js';
24
- import { checkIngressForSecrets } from '../../security/secret-ingress.js';
25
- import { compileCustomPatterns, redactSecrets } from '../../security/secret-scanner.js';
26
- import { getSubagentManager } from '../../subagent/index.js';
27
- import { silentlyWithLog } from '../../util/silently.js';
28
- import { truncate } from '../../util/truncate.js';
29
- import { createApprovalConversationGenerator } from '../approval-generators.js';
30
- import { getAssistantName } from '../identity-helpers.js';
31
- import type { UserMessageAttachment } from '../ipc-contract.js';
27
+ } from "../../memory/canonical-guardian-store.js";
28
+ import { getAttentionStateByConversationIds } from "../../memory/conversation-attention-store.js";
29
+ import * as conversationStore from "../../memory/conversation-store.js";
30
+ import {
31
+ GENERATING_TITLE,
32
+ queueGenerateConversationTitle,
33
+ UNTITLED_FALLBACK,
34
+ } from "../../memory/conversation-title-service.js";
35
+ import * as externalConversationStore from "../../memory/external-conversation-store.js";
36
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../runtime/assistant-scope.js";
37
+ import { routeGuardianReply } from "../../runtime/guardian-reply-router.js";
38
+ import {
39
+ resolveLocalIpcAuthContext,
40
+ resolveLocalIpcTrustContext,
41
+ } from "../../runtime/local-actor-identity.js";
42
+ import * as pendingInteractions from "../../runtime/pending-interactions.js";
43
+ import { checkIngressForSecrets } from "../../security/secret-ingress.js";
44
+ import {
45
+ compileCustomPatterns,
46
+ redactSecrets,
47
+ } from "../../security/secret-scanner.js";
48
+ import { getSubagentManager } from "../../subagent/index.js";
49
+ import { silentlyWithLog } from "../../util/silently.js";
50
+ import { truncate } from "../../util/truncate.js";
51
+ import { createApprovalConversationGenerator } from "../approval-generators.js";
52
+ import { getAssistantName } from "../identity-helpers.js";
53
+ import type { UserMessageAttachment } from "../ipc-contract.js";
32
54
  import type {
33
55
  CancelRequest,
34
56
  ConfirmationResponse,
@@ -47,16 +69,28 @@ import type {
47
69
  UndoRequest,
48
70
  UsageRequest,
49
71
  UserMessage,
50
- } from '../ipc-protocol.js';
51
- import { normalizeThreadType } from '../ipc-protocol.js';
52
- import { executeRecordingIntent } from '../recording-executor.js';
53
- import { resolveRecordingIntent } from '../recording-intent.js';
54
- import { classifyRecordingIntentFallback, containsRecordingKeywords } from '../recording-intent-fallback.js';
55
- import type { Session } from '../session.js';
56
- import { buildSessionErrorMessage,classifySessionError } from '../session-error.js';
57
- import { resolveChannelCapabilities } from '../session-runtime-assembly.js';
58
- import { generateVideoThumbnail } from '../video-thumbnail.js';
59
- import { handleRecordingPause, handleRecordingRestart, handleRecordingResume, handleRecordingStart, handleRecordingStop } from './recording.js';
72
+ } from "../ipc-protocol.js";
73
+ import { normalizeThreadType } from "../ipc-protocol.js";
74
+ import { executeRecordingIntent } from "../recording-executor.js";
75
+ import { resolveRecordingIntent } from "../recording-intent.js";
76
+ import {
77
+ classifyRecordingIntentFallback,
78
+ containsRecordingKeywords,
79
+ } from "../recording-intent-fallback.js";
80
+ import type { Session } from "../session.js";
81
+ import {
82
+ buildSessionErrorMessage,
83
+ classifySessionError,
84
+ } from "../session-error.js";
85
+ import { resolveChannelCapabilities } from "../session-runtime-assembly.js";
86
+ import { generateVideoThumbnail } from "../video-thumbnail.js";
87
+ import {
88
+ handleRecordingPause,
89
+ handleRecordingRestart,
90
+ handleRecordingResume,
91
+ handleRecordingStart,
92
+ handleRecordingStop,
93
+ } from "./recording.js";
60
94
  import {
61
95
  defineHandlers,
62
96
  type HandlerContext,
@@ -68,24 +102,28 @@ import {
68
102
  pendingStandaloneSecrets,
69
103
  renderHistoryContent,
70
104
  wireEscalationHandler,
71
- } from './shared.js';
105
+ } from "./shared.js";
72
106
 
73
- const desktopApprovalConversationGenerator = createApprovalConversationGenerator();
107
+ const desktopApprovalConversationGenerator =
108
+ createApprovalConversationGenerator();
74
109
 
75
110
  function syncCanonicalStatusFromIpcConfirmationDecision(
76
111
  requestId: string,
77
- decision: ConfirmationResponse['decision'],
112
+ decision: ConfirmationResponse["decision"],
78
113
  ): void {
79
- const targetStatus = decision === 'deny' || decision === 'always_deny'
80
- ? 'denied' as const
81
- : 'approved' as const;
114
+ const targetStatus =
115
+ decision === "deny" || decision === "always_deny"
116
+ ? ("denied" as const)
117
+ : ("approved" as const);
82
118
 
83
119
  try {
84
- resolveCanonicalGuardianRequest(requestId, 'pending', { status: targetStatus });
120
+ resolveCanonicalGuardianRequest(requestId, "pending", {
121
+ status: targetStatus,
122
+ });
85
123
  } catch (err) {
86
124
  log.debug(
87
125
  { err, requestId, targetStatus },
88
- 'Failed to resolve canonical request from IPC confirmation response',
126
+ "Failed to resolve canonical request from IPC confirmation response",
89
127
  );
90
128
  }
91
129
  }
@@ -97,20 +135,14 @@ function makeIpcEventSender(params: {
97
135
  conversationId: string;
98
136
  sourceChannel: string;
99
137
  }): (event: ServerMessage) => void {
100
- const {
101
- ctx,
102
- socket,
103
- session,
104
- conversationId,
105
- sourceChannel,
106
- } = params;
138
+ const { ctx, socket, session, conversationId, sourceChannel } = params;
107
139
 
108
140
  return (event: ServerMessage) => {
109
- if (event.type === 'confirmation_request') {
141
+ if (event.type === "confirmation_request") {
110
142
  pendingInteractions.register(event.requestId, {
111
143
  session,
112
144
  conversationId,
113
- kind: 'confirmation',
145
+ kind: "confirmation",
114
146
  confirmationDetails: {
115
147
  toolName: event.toolName,
116
148
  input: event.input,
@@ -124,30 +156,30 @@ function makeIpcEventSender(params: {
124
156
  });
125
157
 
126
158
  try {
127
- const guardianContext = session.guardianContext;
159
+ const trustContext = session.trustContext;
128
160
  createCanonicalGuardianRequest({
129
161
  id: event.requestId,
130
- kind: 'tool_approval',
131
- sourceType: 'desktop',
162
+ kind: "tool_approval",
163
+ sourceType: "desktop",
132
164
  sourceChannel,
133
165
  conversationId,
134
- guardianPrincipalId: guardianContext?.guardianPrincipalId ?? undefined,
166
+ guardianPrincipalId: trustContext?.guardianPrincipalId ?? undefined,
135
167
  toolName: event.toolName,
136
- status: 'pending',
168
+ status: "pending",
137
169
  requestCode: generateCanonicalRequestCode(),
138
170
  expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
139
171
  });
140
172
  } catch (err) {
141
173
  log.debug(
142
174
  { err, requestId: event.requestId, conversationId },
143
- 'Failed to create canonical request from IPC confirmation event',
175
+ "Failed to create canonical request from IPC confirmation event",
144
176
  );
145
177
  }
146
- } else if (event.type === 'secret_request') {
178
+ } else if (event.type === "secret_request") {
147
179
  pendingInteractions.register(event.requestId, {
148
180
  session,
149
181
  conversationId,
150
- kind: 'secret',
182
+ kind: "secret",
151
183
  });
152
184
  }
153
185
 
@@ -172,7 +204,7 @@ export async function handleUserMessage(
172
204
  wireEscalationHandler(session, socket, ctx);
173
205
  }
174
206
 
175
- const ipcChannel = parseChannelId(msg.channel) ?? 'vellum';
207
+ const ipcChannel = parseChannelId(msg.channel) ?? "vellum";
176
208
  const sendEvent = makeIpcEventSender({
177
209
  ctx,
178
210
  socket,
@@ -187,8 +219,9 @@ export async function handleUserMessage(
187
219
  const ipcInterface = parseInterfaceId(msg.interface);
188
220
  if (!ipcInterface) {
189
221
  ctx.send(socket, {
190
- type: 'error',
191
- message: 'Invalid user_message: interface is required and must be valid',
222
+ type: "error",
223
+ message:
224
+ "Invalid user_message: interface is required and must be valid",
192
225
  });
193
226
  return;
194
227
  }
@@ -201,30 +234,34 @@ export async function handleUserMessage(
201
234
 
202
235
  // Update channel capabilities eagerly so both immediate and queued paths
203
236
  // reflect the latest PTT / microphone state from the client.
204
- session.setChannelCapabilities(resolveChannelCapabilities(ipcChannel, ipcInterface, {
205
- pttActivationKey: msg.pttActivationKey,
206
- microphonePermissionGranted: msg.microphonePermissionGranted,
207
- }));
237
+ session.setChannelCapabilities(
238
+ resolveChannelCapabilities(ipcChannel, ipcInterface, {
239
+ pttActivationKey: msg.pttActivationKey,
240
+ microphonePermissionGranted: msg.microphonePermissionGranted,
241
+ }),
242
+ );
208
243
 
209
244
  const dispatchUserMessage = (
210
245
  content: string,
211
246
  attachments: UserMessageAttachment[],
212
247
  dispatchRequestId: string,
213
- source: 'user_message' | 'secure_redirect_resume',
248
+ source: "user_message" | "secure_redirect_resume",
214
249
  activeSurfaceId?: string,
215
250
  currentPage?: string,
216
251
  displayContent?: string,
217
252
  ): void => {
218
- const receivedDescription = source === 'user_message'
219
- ? 'User message received'
220
- : 'Resuming message after secure credential save';
221
- const queuedDescription = source === 'user_message'
222
- ? 'Message queued (session busy)'
223
- : 'Resumed message queued (session busy)';
224
-
225
- session.traceEmitter.emit('request_received', receivedDescription, {
253
+ const receivedDescription =
254
+ source === "user_message"
255
+ ? "User message received"
256
+ : "Resuming message after secure credential save";
257
+ const queuedDescription =
258
+ source === "user_message"
259
+ ? "Message queued (session busy)"
260
+ : "Resumed message queued (session busy)";
261
+
262
+ session.traceEmitter.emit("request_received", receivedDescription, {
226
263
  requestId: dispatchRequestId,
227
- status: 'info',
264
+ status: "info",
228
265
  attributes: { source },
229
266
  });
230
267
 
@@ -240,30 +277,46 @@ export async function handleUserMessage(
240
277
  displayContent,
241
278
  );
242
279
  if (result.rejected) {
243
- rlog.warn({ source }, 'Message rejected — queue is full');
244
- session.traceEmitter.emit('request_error', 'Message rejected — queue is full', {
245
- requestId: dispatchRequestId,
246
- status: 'error',
247
- attributes: { reason: 'queue_full', queueDepth: session.getQueueDepth(), source },
248
- });
249
- ctx.send(socket, buildSessionErrorMessage(msg.sessionId, {
250
- code: 'QUEUE_FULL',
251
- userMessage: 'Message queue is full (max depth: 10). Please wait for current messages to be processed.',
252
- retryable: true,
253
- debugDetails: 'Message rejected — session queue is full',
254
- }));
280
+ rlog.warn({ source }, "Message rejected — queue is full");
281
+ session.traceEmitter.emit(
282
+ "request_error",
283
+ "Message rejected — queue is full",
284
+ {
285
+ requestId: dispatchRequestId,
286
+ status: "error",
287
+ attributes: {
288
+ reason: "queue_full",
289
+ queueDepth: session.getQueueDepth(),
290
+ source,
291
+ },
292
+ },
293
+ );
294
+ ctx.send(
295
+ socket,
296
+ buildSessionErrorMessage(msg.sessionId, {
297
+ code: "QUEUE_FULL",
298
+ userMessage:
299
+ "Message queue is full (max depth: 10). Please wait for current messages to be processed.",
300
+ retryable: true,
301
+ debugDetails: "Message rejected — session queue is full",
302
+ }),
303
+ );
255
304
  return;
256
305
  }
257
306
  if (result.queued) {
258
307
  const position = session.getQueueDepth();
259
308
  rlog.info({ source, position }, queuedDescription);
260
- session.traceEmitter.emit('request_queued', `Message queued at position ${position}`, {
261
- requestId: dispatchRequestId,
262
- status: 'info',
263
- attributes: { position, source },
264
- });
309
+ session.traceEmitter.emit(
310
+ "request_queued",
311
+ `Message queued at position ${position}`,
312
+ {
313
+ requestId: dispatchRequestId,
314
+ status: "info",
315
+ attributes: { position, source },
316
+ },
317
+ );
265
318
  ctx.send(socket, {
266
- type: 'message_queued',
319
+ type: "message_queued",
267
320
  sessionId: msg.sessionId,
268
321
  requestId: dispatchRequestId,
269
322
  position,
@@ -271,8 +324,13 @@ export async function handleUserMessage(
271
324
  return;
272
325
  }
273
326
 
274
- rlog.info({ source }, 'Processing user message');
275
- session.emitActivityState('thinking', 'message_dequeued', 'assistant_turn', dispatchRequestId);
327
+ rlog.info({ source }, "Processing user message");
328
+ session.emitActivityState(
329
+ "thinking",
330
+ "message_dequeued",
331
+ "assistant_turn",
332
+ dispatchRequestId,
333
+ );
276
334
  session.setTurnChannelContext({
277
335
  userMessageChannel: ipcChannel,
278
336
  assistantMessageChannel: ipcChannel,
@@ -284,45 +342,69 @@ export async function handleUserMessage(
284
342
  session.setAssistantId(DAEMON_INTERNAL_ASSISTANT_ID);
285
343
  // Resolve local IPC actor identity through the same trust pipeline
286
344
  // used by HTTP channel ingress. The vellum guardian binding provides
287
- // the guardianPrincipalId, and resolveGuardianContext classifies the
345
+ // the guardianPrincipalId, and resolveTrustContext classifies the
288
346
  // local user as 'guardian' via binding match.
289
- session.setGuardianContext(resolveLocalIpcGuardianContext(ipcChannel));
347
+ session.setTrustContext(resolveLocalIpcTrustContext(ipcChannel));
290
348
  // Align IPC sessions with the same AuthContext shape as HTTP sessions.
291
349
  session.setAuthContext(resolveLocalIpcAuthContext(msg.sessionId));
292
350
  session.setCommandIntent(null);
293
351
  // Fire-and-forget: don't block the IPC handler so the connection can
294
352
  // continue receiving messages (e.g. cancel, confirmations, or
295
353
  // additional user_message that will be queued by the session).
296
- session.processMessage(content, attachments, sendEvent, dispatchRequestId, activeSurfaceId, currentPage, undefined, displayContent).catch((err) => {
297
- const message = err instanceof Error ? err.message : String(err);
298
- rlog.error({ err, source }, 'Error processing user message (session or provider failure)');
299
- ctx.send(socket, { type: 'error', message: `Failed to process message: ${message}` });
300
- const classified = classifySessionError(err, { phase: 'agent_loop' });
301
- ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
302
- });
354
+ session
355
+ .processMessage(
356
+ content,
357
+ attachments,
358
+ sendEvent,
359
+ dispatchRequestId,
360
+ activeSurfaceId,
361
+ currentPage,
362
+ undefined,
363
+ displayContent,
364
+ )
365
+ .catch((err) => {
366
+ const message = err instanceof Error ? err.message : String(err);
367
+ rlog.error(
368
+ { err, source },
369
+ "Error processing user message (session or provider failure)",
370
+ );
371
+ ctx.send(socket, {
372
+ type: "error",
373
+ message: `Failed to process message: ${message}`,
374
+ });
375
+ const classified = classifySessionError(err, { phase: "agent_loop" });
376
+ ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
377
+ });
303
378
  };
304
379
 
305
380
  const config = getConfig();
306
- let messageText = msg.content ?? '';
381
+ let messageText = msg.content ?? "";
307
382
 
308
383
  // Block inbound messages that contain secrets and redirect to secure prompt
309
384
  if (!msg.bypassSecretCheck) {
310
385
  const ingressCheck = checkIngressForSecrets(messageText);
311
386
  if (ingressCheck.blocked) {
312
- rlog.warn({ detectedTypes: ingressCheck.detectedTypes }, 'Blocked user message containing secrets');
387
+ rlog.warn(
388
+ { detectedTypes: ingressCheck.detectedTypes },
389
+ "Blocked user message containing secrets",
390
+ );
313
391
  ctx.send(socket, {
314
- type: 'error',
392
+ type: "error",
315
393
  message: ingressCheck.userNotice!,
316
- category: 'secret_blocked',
394
+ category: "secret_blocked",
317
395
  });
318
396
 
319
397
  const compiledCustom = config.secretDetection.customPatterns?.length
320
398
  ? compileCustomPatterns(config.secretDetection.customPatterns)
321
399
  : undefined;
322
- const redactedMessageText = redactSecrets(messageText, {
323
- enabled: true,
324
- base64Threshold: config.secretDetection.entropyThreshold,
325
- }, compiledCustom).trim();
400
+ const redactedMessageText = redactSecrets(
401
+ messageText,
402
+ {
403
+ enabled: true,
404
+ base64Threshold: config.secretDetection.entropyThreshold,
405
+ },
406
+ compiledCustom,
407
+ ).trim();
326
408
 
327
409
  // Redirect: trigger a secure prompt so the user can enter the secret safely.
328
410
  // After save, continue the same request with redacted text so the model keeps
@@ -330,25 +412,29 @@ export async function handleUserMessage(
330
412
  session.redirectToSecurePrompt(ingressCheck.detectedTypes, {
331
413
  onStored: (record) => {
332
414
  ctx.send(socket, {
333
- type: 'assistant_text_delta',
415
+ type: "assistant_text_delta",
416
+ sessionId: msg.sessionId,
417
+ text: "Saved your secret securely. Continuing with your request.",
418
+ });
419
+ ctx.send(socket, {
420
+ type: "message_complete",
334
421
  sessionId: msg.sessionId,
335
- text: 'Saved your secret securely. Continuing with your request.',
336
422
  });
337
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
338
423
 
339
424
  const continuationParts: string[] = [];
340
- if (redactedMessageText.length > 0) continuationParts.push(redactedMessageText);
425
+ if (redactedMessageText.length > 0)
426
+ continuationParts.push(redactedMessageText);
341
427
  continuationParts.push(
342
428
  `I entered the redacted secret via the Secure Credential UI and saved it as credential ${record.service}/${record.field}. ` +
343
- 'Continue with my request using that stored credential and do not ask me to paste the secret again.',
429
+ "Continue with my request using that stored credential and do not ask me to paste the secret again.",
344
430
  );
345
- const continuationMessage = continuationParts.join('\n\n');
431
+ const continuationMessage = continuationParts.join("\n\n");
346
432
  const continuationRequestId = uuid();
347
433
  dispatchUserMessage(
348
434
  continuationMessage,
349
435
  msg.attachments ?? [],
350
436
  continuationRequestId,
351
- 'secure_redirect_resume',
437
+ "secure_redirect_resume",
352
438
  msg.activeSurfaceId,
353
439
  msg.currentPage,
354
440
  );
@@ -359,94 +445,205 @@ export async function handleUserMessage(
359
445
  }
360
446
 
361
447
  // ── Structured command intent (bypasses text parsing) ──────────────────
362
- if (config.daemon.standaloneRecording && msg.commandIntent?.domain === 'screen_recording') {
448
+ if (
449
+ config.daemon.standaloneRecording &&
450
+ msg.commandIntent?.domain === "screen_recording"
451
+ ) {
363
452
  const action = msg.commandIntent.action;
364
- rlog.info({ action, source: 'commandIntent' }, 'Recording command intent received in user_message');
365
- if (action === 'start') {
366
- const recordingId = handleRecordingStart(msg.sessionId, { promptForSource: true }, socket, ctx);
367
- const responseText = recordingId ? 'Starting screen recording.' : 'A recording is already active.';
453
+ rlog.info(
454
+ { action, source: "commandIntent" },
455
+ "Recording command intent received in user_message",
456
+ );
457
+ if (action === "start") {
458
+ const recordingId = handleRecordingStart(
459
+ msg.sessionId,
460
+ { promptForSource: true },
461
+ socket,
462
+ ctx,
463
+ );
464
+ const responseText = recordingId
465
+ ? "Starting screen recording."
466
+ : "A recording is already active.";
368
467
  ctx.send(socket, {
369
- type: 'assistant_text_delta',
468
+ type: "assistant_text_delta",
370
469
  text: responseText,
371
470
  sessionId: msg.sessionId,
372
471
  });
373
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
374
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
375
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
472
+ ctx.send(socket, {
473
+ type: "message_complete",
474
+ sessionId: msg.sessionId,
475
+ });
476
+ await conversationStore.addMessage(
477
+ msg.sessionId,
478
+ "user",
479
+ JSON.stringify([{ type: "text", text: messageText }]),
480
+ );
481
+ await conversationStore.addMessage(
482
+ msg.sessionId,
483
+ "assistant",
484
+ JSON.stringify([{ type: "text", text: responseText }]),
485
+ );
376
486
  // Keep in-memory session history aligned with DB so regenerate() and
377
487
  // other history operations that rely on session.messages stay consistent.
378
488
  // Only push when agent loop is NOT active to avoid corrupting role alternation.
379
489
  if (!session.isProcessing()) {
380
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
381
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
490
+ session.messages.push({
491
+ role: "user",
492
+ content: [{ type: "text", text: messageText }],
493
+ });
494
+ session.messages.push({
495
+ role: "assistant",
496
+ content: [{ type: "text", text: responseText }],
497
+ });
382
498
  }
383
499
  return;
384
- } else if (action === 'stop') {
500
+ } else if (action === "stop") {
385
501
  const stopped = handleRecordingStop(msg.sessionId, ctx) !== undefined;
386
- const responseText = stopped ? 'Stopping the recording.' : 'No active recording to stop.';
502
+ const responseText = stopped
503
+ ? "Stopping the recording."
504
+ : "No active recording to stop.";
387
505
  ctx.send(socket, {
388
- type: 'assistant_text_delta',
506
+ type: "assistant_text_delta",
389
507
  text: responseText,
390
508
  sessionId: msg.sessionId,
391
509
  });
392
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
393
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
394
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
510
+ ctx.send(socket, {
511
+ type: "message_complete",
512
+ sessionId: msg.sessionId,
513
+ });
514
+ await conversationStore.addMessage(
515
+ msg.sessionId,
516
+ "user",
517
+ JSON.stringify([{ type: "text", text: messageText }]),
518
+ );
519
+ await conversationStore.addMessage(
520
+ msg.sessionId,
521
+ "assistant",
522
+ JSON.stringify([{ type: "text", text: responseText }]),
523
+ );
395
524
  if (!session.isProcessing()) {
396
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
397
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
525
+ session.messages.push({
526
+ role: "user",
527
+ content: [{ type: "text", text: messageText }],
528
+ });
529
+ session.messages.push({
530
+ role: "assistant",
531
+ content: [{ type: "text", text: responseText }],
532
+ });
398
533
  }
399
534
  return;
400
- } else if (action === 'restart') {
401
- const restartResult = handleRecordingRestart(msg.sessionId, socket, ctx);
535
+ } else if (action === "restart") {
536
+ const restartResult = handleRecordingRestart(
537
+ msg.sessionId,
538
+ socket,
539
+ ctx,
540
+ );
402
541
  ctx.send(socket, {
403
- type: 'assistant_text_delta',
542
+ type: "assistant_text_delta",
404
543
  text: restartResult.responseText,
405
544
  sessionId: msg.sessionId,
406
545
  });
407
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
408
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
409
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: restartResult.responseText }]));
546
+ ctx.send(socket, {
547
+ type: "message_complete",
548
+ sessionId: msg.sessionId,
549
+ });
550
+ await conversationStore.addMessage(
551
+ msg.sessionId,
552
+ "user",
553
+ JSON.stringify([{ type: "text", text: messageText }]),
554
+ );
555
+ await conversationStore.addMessage(
556
+ msg.sessionId,
557
+ "assistant",
558
+ JSON.stringify([{ type: "text", text: restartResult.responseText }]),
559
+ );
410
560
  if (!session.isProcessing()) {
411
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
412
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: restartResult.responseText }] });
561
+ session.messages.push({
562
+ role: "user",
563
+ content: [{ type: "text", text: messageText }],
564
+ });
565
+ session.messages.push({
566
+ role: "assistant",
567
+ content: [{ type: "text", text: restartResult.responseText }],
568
+ });
413
569
  }
414
570
  return;
415
- } else if (action === 'pause') {
571
+ } else if (action === "pause") {
416
572
  const paused = handleRecordingPause(msg.sessionId, ctx) !== undefined;
417
- const responseText = paused ? 'Pausing the recording.' : 'No active recording to pause.';
573
+ const responseText = paused
574
+ ? "Pausing the recording."
575
+ : "No active recording to pause.";
418
576
  ctx.send(socket, {
419
- type: 'assistant_text_delta',
577
+ type: "assistant_text_delta",
420
578
  text: responseText,
421
579
  sessionId: msg.sessionId,
422
580
  });
423
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
424
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
425
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
581
+ ctx.send(socket, {
582
+ type: "message_complete",
583
+ sessionId: msg.sessionId,
584
+ });
585
+ await conversationStore.addMessage(
586
+ msg.sessionId,
587
+ "user",
588
+ JSON.stringify([{ type: "text", text: messageText }]),
589
+ );
590
+ await conversationStore.addMessage(
591
+ msg.sessionId,
592
+ "assistant",
593
+ JSON.stringify([{ type: "text", text: responseText }]),
594
+ );
426
595
  if (!session.isProcessing()) {
427
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
428
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
596
+ session.messages.push({
597
+ role: "user",
598
+ content: [{ type: "text", text: messageText }],
599
+ });
600
+ session.messages.push({
601
+ role: "assistant",
602
+ content: [{ type: "text", text: responseText }],
603
+ });
429
604
  }
430
605
  return;
431
- } else if (action === 'resume') {
606
+ } else if (action === "resume") {
432
607
  const resumed = handleRecordingResume(msg.sessionId, ctx) !== undefined;
433
- const responseText = resumed ? 'Resuming the recording.' : 'No active recording to resume.';
608
+ const responseText = resumed
609
+ ? "Resuming the recording."
610
+ : "No active recording to resume.";
434
611
  ctx.send(socket, {
435
- type: 'assistant_text_delta',
612
+ type: "assistant_text_delta",
436
613
  text: responseText,
437
614
  sessionId: msg.sessionId,
438
615
  });
439
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
440
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
441
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
616
+ ctx.send(socket, {
617
+ type: "message_complete",
618
+ sessionId: msg.sessionId,
619
+ });
620
+ await conversationStore.addMessage(
621
+ msg.sessionId,
622
+ "user",
623
+ JSON.stringify([{ type: "text", text: messageText }]),
624
+ );
625
+ await conversationStore.addMessage(
626
+ msg.sessionId,
627
+ "assistant",
628
+ JSON.stringify([{ type: "text", text: responseText }]),
629
+ );
442
630
  if (!session.isProcessing()) {
443
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
444
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
631
+ session.messages.push({
632
+ role: "user",
633
+ content: [{ type: "text", text: messageText }],
634
+ });
635
+ session.messages.push({
636
+ role: "assistant",
637
+ content: [{ type: "text", text: responseText }],
638
+ });
445
639
  }
446
640
  return;
447
641
  } else {
448
642
  // Unrecognized action — fall through to normal text handling
449
- rlog.warn({ action, source: 'commandIntent' }, 'Unrecognized screen_recording action, falling through to text handling');
643
+ rlog.warn(
644
+ { action, source: "commandIntent" },
645
+ "Unrecognized screen_recording action, falling through to text handling",
646
+ );
450
647
  }
451
648
  }
452
649
 
@@ -457,10 +654,14 @@ export async function handleUserMessage(
457
654
  const dynamicNames = [name].filter(Boolean) as string[];
458
655
  const intentResult = resolveRecordingIntent(messageText, dynamicNames);
459
656
 
460
- if (intentResult.kind === 'start_only' || intentResult.kind === 'stop_only' ||
461
- intentResult.kind === 'start_and_stop_only' ||
462
- intentResult.kind === 'restart_only' || intentResult.kind === 'pause_only' ||
463
- intentResult.kind === 'resume_only') {
657
+ if (
658
+ intentResult.kind === "start_only" ||
659
+ intentResult.kind === "stop_only" ||
660
+ intentResult.kind === "start_and_stop_only" ||
661
+ intentResult.kind === "restart_only" ||
662
+ intentResult.kind === "pause_only" ||
663
+ intentResult.kind === "resume_only"
664
+ ) {
464
665
  const execResult = executeRecordingIntent(intentResult, {
465
666
  conversationId: msg.sessionId,
466
667
  socket,
@@ -468,25 +669,49 @@ export async function handleUserMessage(
468
669
  });
469
670
 
470
671
  if (execResult.handled) {
471
- rlog.info({ kind: intentResult.kind }, 'Recording intent intercepted in user_message');
672
+ rlog.info(
673
+ { kind: intentResult.kind },
674
+ "Recording intent intercepted in user_message",
675
+ );
472
676
  ctx.send(socket, {
473
- type: 'assistant_text_delta',
677
+ type: "assistant_text_delta",
474
678
  text: execResult.responseText!,
475
679
  sessionId: msg.sessionId,
476
680
  });
477
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
478
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
479
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
681
+ ctx.send(socket, {
682
+ type: "message_complete",
683
+ sessionId: msg.sessionId,
684
+ });
685
+ await conversationStore.addMessage(
686
+ msg.sessionId,
687
+ "user",
688
+ JSON.stringify([{ type: "text", text: messageText }]),
689
+ );
690
+ await conversationStore.addMessage(
691
+ msg.sessionId,
692
+ "assistant",
693
+ JSON.stringify([{ type: "text", text: execResult.responseText! }]),
694
+ );
480
695
  if (!session.isProcessing()) {
481
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
482
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
696
+ session.messages.push({
697
+ role: "user",
698
+ content: [{ type: "text", text: messageText }],
699
+ });
700
+ session.messages.push({
701
+ role: "assistant",
702
+ content: [{ type: "text", text: execResult.responseText! }],
703
+ });
483
704
  }
484
705
  return;
485
706
  }
486
707
  }
487
708
 
488
- if (intentResult.kind === 'start_with_remainder' || intentResult.kind === 'stop_with_remainder' ||
489
- intentResult.kind === 'start_and_stop_with_remainder' || intentResult.kind === 'restart_with_remainder') {
709
+ if (
710
+ intentResult.kind === "start_with_remainder" ||
711
+ intentResult.kind === "stop_with_remainder" ||
712
+ intentResult.kind === "start_and_stop_with_remainder" ||
713
+ intentResult.kind === "restart_with_remainder"
714
+ ) {
490
715
  const execResult = executeRecordingIntent(intentResult, {
491
716
  conversationId: msg.sessionId,
492
717
  socket,
@@ -501,40 +726,75 @@ export async function handleUserMessage(
501
726
  messageText = msg.content;
502
727
 
503
728
  // Execute the recording side effects that executeRecordingIntent deferred
504
- if (intentResult.kind === 'stop_with_remainder') {
729
+ if (intentResult.kind === "stop_with_remainder") {
505
730
  handleRecordingStop(msg.sessionId, ctx);
506
731
  }
507
- if (intentResult.kind === 'start_with_remainder') {
508
- handleRecordingStart(msg.sessionId, { promptForSource: true }, socket, ctx);
732
+ if (intentResult.kind === "start_with_remainder") {
733
+ handleRecordingStart(
734
+ msg.sessionId,
735
+ { promptForSource: true },
736
+ socket,
737
+ ctx,
738
+ );
509
739
  }
510
740
  // start_and_stop_with_remainder / restart_with_remainder — route through
511
741
  // handleRecordingRestart which properly cleans up maps between stop and start.
512
- if (intentResult.kind === 'restart_with_remainder' || intentResult.kind === 'start_and_stop_with_remainder') {
513
- const restartResult = handleRecordingRestart(msg.sessionId, socket, ctx);
742
+ if (
743
+ intentResult.kind === "restart_with_remainder" ||
744
+ intentResult.kind === "start_and_stop_with_remainder"
745
+ ) {
746
+ const restartResult = handleRecordingRestart(
747
+ msg.sessionId,
748
+ socket,
749
+ ctx,
750
+ );
514
751
  // Only fall back to plain start for start_and_stop_with_remainder.
515
752
  // restart_with_remainder should NOT silently start a new recording when idle.
516
- if (!restartResult.initiated && restartResult.reason === 'no_active_recording'
517
- && intentResult.kind === 'start_and_stop_with_remainder') {
518
- handleRecordingStart(msg.sessionId, { promptForSource: true }, socket, ctx);
753
+ if (
754
+ !restartResult.initiated &&
755
+ restartResult.reason === "no_active_recording" &&
756
+ intentResult.kind === "start_and_stop_with_remainder"
757
+ ) {
758
+ handleRecordingStart(
759
+ msg.sessionId,
760
+ { promptForSource: true },
761
+ socket,
762
+ ctx,
763
+ );
519
764
  }
520
765
  }
521
766
 
522
- rlog.info({ remaining: msg.content, kind: intentResult.kind }, 'Recording intent with remainder — continuing with remaining text');
767
+ rlog.info(
768
+ { remaining: msg.content, kind: intentResult.kind },
769
+ "Recording intent with remainder — continuing with remaining text",
770
+ );
523
771
  }
524
772
 
525
773
  // 'none' — deterministic resolver found nothing; try LLM fallback
526
774
  // if the text contains recording-related keywords.
527
- if (intentResult.kind === 'none' && containsRecordingKeywords(messageText)) {
775
+ if (
776
+ intentResult.kind === "none" &&
777
+ containsRecordingKeywords(messageText)
778
+ ) {
528
779
  const fallback = await classifyRecordingIntentFallback(messageText);
529
- rlog.info({ fallbackAction: fallback.action, fallbackConfidence: fallback.confidence }, 'Recording intent LLM fallback result');
530
-
531
- if (fallback.action !== 'none' && fallback.confidence === 'high') {
532
- const kindMap: Record<string, import('../recording-intent.js').RecordingIntentResult> = {
533
- start: { kind: 'start_only' },
534
- stop: { kind: 'stop_only' },
535
- restart: { kind: 'restart_only' },
536
- pause: { kind: 'pause_only' },
537
- resume: { kind: 'resume_only' },
780
+ rlog.info(
781
+ {
782
+ fallbackAction: fallback.action,
783
+ fallbackConfidence: fallback.confidence,
784
+ },
785
+ "Recording intent LLM fallback result",
786
+ );
787
+
788
+ if (fallback.action !== "none" && fallback.confidence === "high") {
789
+ const kindMap: Record<
790
+ string,
791
+ import("../recording-intent.js").RecordingIntentResult
792
+ > = {
793
+ start: { kind: "start_only" },
794
+ stop: { kind: "stop_only" },
795
+ restart: { kind: "restart_only" },
796
+ pause: { kind: "pause_only" },
797
+ resume: { kind: "resume_only" },
538
798
  };
539
799
  const mapped = kindMap[fallback.action];
540
800
  if (mapped) {
@@ -545,18 +805,40 @@ export async function handleUserMessage(
545
805
  });
546
806
 
547
807
  if (execResult.handled) {
548
- rlog.info({ kind: mapped.kind, source: 'llm_fallback' }, 'Recording intent intercepted via LLM fallback');
808
+ rlog.info(
809
+ { kind: mapped.kind, source: "llm_fallback" },
810
+ "Recording intent intercepted via LLM fallback",
811
+ );
549
812
  ctx.send(socket, {
550
- type: 'assistant_text_delta',
813
+ type: "assistant_text_delta",
551
814
  text: execResult.responseText!,
552
815
  sessionId: msg.sessionId,
553
816
  });
554
- ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
555
- await conversationStore.addMessage(msg.sessionId, 'user', JSON.stringify([{ type: 'text', text: messageText }]));
556
- await conversationStore.addMessage(msg.sessionId, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
817
+ ctx.send(socket, {
818
+ type: "message_complete",
819
+ sessionId: msg.sessionId,
820
+ });
821
+ await conversationStore.addMessage(
822
+ msg.sessionId,
823
+ "user",
824
+ JSON.stringify([{ type: "text", text: messageText }]),
825
+ );
826
+ await conversationStore.addMessage(
827
+ msg.sessionId,
828
+ "assistant",
829
+ JSON.stringify([
830
+ { type: "text", text: execResult.responseText! },
831
+ ]),
832
+ );
557
833
  if (!session.isProcessing()) {
558
- session.messages.push({ role: 'user', content: [{ type: 'text', text: messageText }] });
559
- session.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
834
+ session.messages.push({
835
+ role: "user",
836
+ content: [{ type: "text", text: messageText }],
837
+ });
838
+ session.messages.push({
839
+ role: "assistant",
840
+ content: [{ type: "text", text: execResult.responseText! }],
841
+ });
560
842
  }
561
843
  return;
562
844
  }
@@ -570,41 +852,45 @@ export async function handleUserMessage(
570
852
  // gate on queue depth: users often retry "approve"/"yes" while the queue
571
853
  // is draining after a prior denial, and requiring an empty queue causes a
572
854
  // deny/retry cascade where natural-language approvals never land.
573
- if (
574
- session.hasAnyPendingConfirmation()
575
- && messageText.trim().length > 0
576
- ) {
855
+ if (session.hasAnyPendingConfirmation() && messageText.trim().length > 0) {
577
856
  try {
578
857
  const pendingInteractionRequestIdsForConversation = pendingInteractions
579
858
  .getByConversation(msg.sessionId)
580
859
  .filter(
581
860
  (interaction) =>
582
- interaction.kind === 'confirmation'
583
- && interaction.session === session
584
- && session.hasPendingConfirmation(interaction.requestId),
861
+ interaction.kind === "confirmation" &&
862
+ interaction.session === session &&
863
+ session.hasPendingConfirmation(interaction.requestId),
585
864
  )
586
865
  .map((interaction) => interaction.requestId);
587
866
 
588
867
  const pendingCanonicalRequestIdsForConversation = [
589
- ...listPendingCanonicalGuardianRequestsByDestinationConversation(msg.sessionId, ipcChannel)
590
- .filter((request) => request.kind === 'tool_approval')
868
+ ...listPendingCanonicalGuardianRequestsByDestinationConversation(
869
+ msg.sessionId,
870
+ ipcChannel,
871
+ )
872
+ .filter((request) => request.kind === "tool_approval")
591
873
  .map((request) => request.id),
592
874
  ...listCanonicalGuardianRequests({
593
- status: 'pending',
875
+ status: "pending",
594
876
  conversationId: msg.sessionId,
595
- kind: 'tool_approval',
877
+ kind: "tool_approval",
596
878
  }).map((request) => request.id),
597
- ].filter((pendingRequestId) => session.hasPendingConfirmation(pendingRequestId));
879
+ ].filter((pendingRequestId) =>
880
+ session.hasPendingConfirmation(pendingRequestId),
881
+ );
598
882
 
599
- const pendingRequestIdsForConversation = Array.from(new Set([
600
- ...pendingInteractionRequestIdsForConversation,
601
- ...pendingCanonicalRequestIdsForConversation,
602
- ]));
883
+ const pendingRequestIdsForConversation = Array.from(
884
+ new Set([
885
+ ...pendingInteractionRequestIdsForConversation,
886
+ ...pendingCanonicalRequestIdsForConversation,
887
+ ]),
888
+ );
603
889
 
604
890
  if (pendingRequestIdsForConversation.length > 0) {
605
891
  // Resolve the local IPC actor's principal via the vellum guardian binding
606
892
  // for principal-based authorization in the canonical decision primitive.
607
- const localCtx = resolveLocalIpcGuardianContext(ipcChannel);
893
+ const localCtx = resolveLocalIpcTrustContext(ipcChannel);
608
894
  const routerResult = await routeGuardianReply({
609
895
  messageText: messageText.trim(),
610
896
  channel: ipcChannel,
@@ -617,13 +903,16 @@ export async function handleUserMessage(
617
903
  pendingRequestIds: pendingRequestIdsForConversation,
618
904
  approvalConversationGenerator: desktopApprovalConversationGenerator,
619
905
  emissionContext: {
620
- source: 'inline_nl',
906
+ source: "inline_nl",
621
907
  causedByRequestId: requestId,
622
908
  decisionText: messageText.trim(),
623
909
  },
624
910
  });
625
911
 
626
- if (routerResult.consumed && routerResult.type !== 'nl_keep_pending') {
912
+ if (
913
+ routerResult.consumed &&
914
+ routerResult.type !== "nl_keep_pending"
915
+ ) {
627
916
  // Success-path emissions (approved/denied) are handled centrally
628
917
  // by handleConfirmationResponse (called via the resolver chain).
629
918
  // However, stale/failed paths never reach handleConfirmationResponse,
@@ -632,8 +921,8 @@ export async function handleUserMessage(
632
921
  session.emitConfirmationStateChanged({
633
922
  sessionId: msg.sessionId,
634
923
  requestId: routerResult.requestId,
635
- state: 'resolved_stale',
636
- source: 'inline_nl',
924
+ state: "resolved_stale",
925
+ source: "inline_nl",
637
926
  causedByRequestId: requestId,
638
927
  decisionText: messageText.trim(),
639
928
  });
@@ -644,23 +933,29 @@ export async function handleUserMessage(
644
933
  assistantMessageChannel: ipcChannel,
645
934
  userMessageInterface: ipcInterface,
646
935
  assistantMessageInterface: ipcInterface,
647
- provenanceTrustClass: 'guardian' as const,
936
+ provenanceTrustClass: "guardian" as const,
648
937
  };
649
938
 
650
- const consumedUserMessage = createUserMessage(messageText, msg.attachments ?? []);
939
+ const consumedUserMessage = createUserMessage(
940
+ messageText,
941
+ msg.attachments ?? [],
942
+ );
651
943
  await conversationStore.addMessage(
652
944
  msg.sessionId,
653
- 'user',
945
+ "user",
654
946
  JSON.stringify(consumedUserMessage.content),
655
947
  consumedChannelMeta,
656
948
  );
657
949
 
658
- const replyText = (routerResult.replyText?.trim())
659
- || (routerResult.decisionApplied ? 'Decision applied.' : 'Request already resolved.');
950
+ const replyText =
951
+ routerResult.replyText?.trim() ||
952
+ (routerResult.decisionApplied
953
+ ? "Decision applied."
954
+ : "Request already resolved.");
660
955
  const consumedAssistantMessage = createAssistantMessage(replyText);
661
956
  await conversationStore.addMessage(
662
957
  msg.sessionId,
663
- 'assistant',
958
+ "assistant",
664
959
  JSON.stringify(consumedAssistantMessage.content),
665
960
  consumedChannelMeta,
666
961
  );
@@ -669,19 +964,22 @@ export async function handleUserMessage(
669
964
  if (!session.isProcessing()) {
670
965
  // Keep in-memory history aligned with persisted transcript so
671
966
  // session-history operations (undo/regenerate) target the same turn.
672
- session.messages.push(consumedUserMessage, consumedAssistantMessage);
967
+ session.messages.push(
968
+ consumedUserMessage,
969
+ consumedAssistantMessage,
970
+ );
673
971
  }
674
972
 
675
973
  // Mirror the normal queued/dequeued lifecycle so desktop clients can
676
974
  // reconcile queued bubble state for this just-sent user message.
677
975
  ctx.send(socket, {
678
- type: 'message_queued',
976
+ type: "message_queued",
679
977
  sessionId: msg.sessionId,
680
978
  requestId,
681
979
  position: 0,
682
980
  });
683
981
  ctx.send(socket, {
684
- type: 'message_dequeued',
982
+ type: "message_dequeued",
685
983
  sessionId: msg.sessionId,
686
984
  requestId,
687
985
  });
@@ -693,27 +991,34 @@ export async function handleUserMessage(
693
991
  // client will see it on the next transcript reload / session switch.
694
992
  if (!session.isProcessing()) {
695
993
  ctx.send(socket, {
696
- type: 'assistant_text_delta',
994
+ type: "assistant_text_delta",
697
995
  text: replyText,
698
996
  sessionId: msg.sessionId,
699
997
  });
700
998
  }
701
999
  ctx.send(socket, {
702
- type: 'message_request_complete',
1000
+ type: "message_request_complete",
703
1001
  sessionId: msg.sessionId,
704
1002
  requestId,
705
1003
  runStillActive: session.isProcessing(),
706
1004
  });
707
1005
 
708
1006
  rlog.info(
709
- { routerType: routerResult.type, decisionApplied: routerResult.decisionApplied, routerRequestId: routerResult.requestId },
710
- 'Consumed pending-confirmation reply before auto-deny',
1007
+ {
1008
+ routerType: routerResult.type,
1009
+ decisionApplied: routerResult.decisionApplied,
1010
+ routerRequestId: routerResult.requestId,
1011
+ },
1012
+ "Consumed pending-confirmation reply before auto-deny",
711
1013
  );
712
1014
  return;
713
1015
  }
714
1016
  }
715
1017
  } catch (err) {
716
- rlog.warn({ err }, 'Failed to process pending-confirmation reply; falling back to auto-deny behavior');
1018
+ rlog.warn(
1019
+ { err },
1020
+ "Failed to process pending-confirmation reply; falling back to auto-deny behavior",
1021
+ );
717
1022
  }
718
1023
  }
719
1024
 
@@ -721,16 +1026,21 @@ export async function handleUserMessage(
721
1026
  // agent can process the user's follow-up message instead. The agent
722
1027
  // will see the denial and can re-request the tool if still needed.
723
1028
  if (session.hasAnyPendingConfirmation()) {
724
- rlog.info('Auto-denying pending confirmation(s) due to new user message');
1029
+ rlog.info("Auto-denying pending confirmation(s) due to new user message");
725
1030
  // Emit authoritative confirmation state for each auto-denied request
726
1031
  // before the prompter clears them.
727
- for (const interaction of pendingInteractions.getByConversation(msg.sessionId)) {
728
- if (interaction.session === session && interaction.kind === 'confirmation') {
1032
+ for (const interaction of pendingInteractions.getByConversation(
1033
+ msg.sessionId,
1034
+ )) {
1035
+ if (
1036
+ interaction.session === session &&
1037
+ interaction.kind === "confirmation"
1038
+ ) {
729
1039
  session.emitConfirmationStateChanged({
730
1040
  sessionId: msg.sessionId,
731
1041
  requestId: interaction.requestId,
732
- state: 'denied',
733
- source: 'auto_deny',
1042
+ state: "denied",
1043
+ source: "auto_deny",
734
1044
  causedByRequestId: requestId,
735
1045
  });
736
1046
  }
@@ -738,9 +1048,17 @@ export async function handleUserMessage(
738
1048
  session.denyAllPendingConfirmations();
739
1049
  // Keep the pending-interaction tracker aligned with the prompter so
740
1050
  // stale request IDs are not reused as routing candidates.
741
- for (const interaction of pendingInteractions.getByConversation(msg.sessionId)) {
742
- if (interaction.session === session && interaction.kind === 'confirmation') {
743
- syncCanonicalStatusFromIpcConfirmationDecision(interaction.requestId, 'deny');
1051
+ for (const interaction of pendingInteractions.getByConversation(
1052
+ msg.sessionId,
1053
+ )) {
1054
+ if (
1055
+ interaction.session === session &&
1056
+ interaction.kind === "confirmation"
1057
+ ) {
1058
+ syncCanonicalStatusFromIpcConfirmationDecision(
1059
+ interaction.requestId,
1060
+ "deny",
1061
+ );
744
1062
  pendingInteractions.resolve(interaction.requestId);
745
1063
  }
746
1064
  }
@@ -750,16 +1068,19 @@ export async function handleUserMessage(
750
1068
  messageText,
751
1069
  msg.attachments ?? [],
752
1070
  requestId,
753
- 'user_message',
1071
+ "user_message",
754
1072
  msg.activeSurfaceId,
755
1073
  msg.currentPage,
756
1074
  originalContentBeforeStrip,
757
1075
  );
758
1076
  } catch (err) {
759
1077
  const message = err instanceof Error ? err.message : String(err);
760
- rlog.error({ err }, 'Error setting up user message processing');
761
- ctx.send(socket, { type: 'error', message: `Failed to process message: ${message}` });
762
- const classified = classifySessionError(err, { phase: 'handler' });
1078
+ rlog.error({ err }, "Error setting up user message processing");
1079
+ ctx.send(socket, {
1080
+ type: "error",
1081
+ message: `Failed to process message: ${message}`,
1082
+ });
1083
+ const classified = classifySessionError(err, { phase: "handler" });
763
1084
  ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
764
1085
  }
765
1086
  }
@@ -781,9 +1102,12 @@ export function handleConfirmationResponse(
781
1102
  msg.selectedPattern,
782
1103
  msg.selectedScope,
783
1104
  undefined,
784
- { source: 'button' },
1105
+ { source: "button" },
1106
+ );
1107
+ syncCanonicalStatusFromIpcConfirmationDecision(
1108
+ msg.requestId,
1109
+ msg.decision,
785
1110
  );
786
- syncCanonicalStatusFromIpcConfirmationDecision(msg.requestId, msg.decision);
787
1111
  pendingInteractions.resolve(msg.requestId);
788
1112
  return;
789
1113
  }
@@ -798,13 +1122,19 @@ export function handleConfirmationResponse(
798
1122
  msg.selectedPattern,
799
1123
  msg.selectedScope,
800
1124
  );
801
- syncCanonicalStatusFromIpcConfirmationDecision(msg.requestId, msg.decision);
1125
+ syncCanonicalStatusFromIpcConfirmationDecision(
1126
+ msg.requestId,
1127
+ msg.decision,
1128
+ );
802
1129
  pendingInteractions.resolve(msg.requestId);
803
1130
  return;
804
1131
  }
805
1132
  }
806
1133
 
807
- log.warn({ requestId: msg.requestId }, 'No session found with pending confirmation for requestId');
1134
+ log.warn(
1135
+ { requestId: msg.requestId },
1136
+ "No session found with pending confirmation for requestId",
1137
+ );
808
1138
  }
809
1139
 
810
1140
  export function handleSecretResponse(
@@ -818,7 +1148,10 @@ export function handleSecretResponse(
818
1148
  if (standalone) {
819
1149
  clearTimeout(standalone.timer);
820
1150
  pendingStandaloneSecrets.delete(msg.requestId);
821
- standalone.resolve({ value: msg.value ?? null, delivery: msg.delivery ?? 'store' });
1151
+ standalone.resolve({
1152
+ value: msg.value ?? null,
1153
+ delivery: msg.delivery ?? "store",
1154
+ });
822
1155
  pendingInteractions.resolve(msg.requestId);
823
1156
  return;
824
1157
  }
@@ -834,52 +1167,86 @@ export function handleSecretResponse(
834
1167
  return;
835
1168
  }
836
1169
  }
837
- log.warn({ requestId: msg.requestId }, 'No session found with pending secret prompt for requestId');
1170
+ log.warn(
1171
+ { requestId: msg.requestId },
1172
+ "No session found with pending secret prompt for requestId",
1173
+ );
838
1174
  }
839
1175
 
840
- export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offset = 0, limit = 50): void {
841
- const conversations = conversationStore.listConversations(limit, false, offset);
1176
+ export function handleSessionList(
1177
+ socket: net.Socket,
1178
+ ctx: HandlerContext,
1179
+ offset = 0,
1180
+ limit = 50,
1181
+ ): void {
1182
+ const conversations = conversationStore.listConversations(
1183
+ limit,
1184
+ false,
1185
+ offset,
1186
+ );
842
1187
  const totalCount = conversationStore.countConversations();
843
1188
  const conversationIds = conversations.map((c) => c.id);
844
- const bindings = externalConversationStore.getBindingsForConversations(conversationIds);
1189
+ const bindings =
1190
+ externalConversationStore.getBindingsForConversations(conversationIds);
845
1191
  const attentionStates = getAttentionStateByConversationIds(conversationIds);
846
- const displayMetas = conversationStore.getDisplayMetaForConversations(conversationIds);
1192
+ const displayMetas =
1193
+ conversationStore.getDisplayMetaForConversations(conversationIds);
847
1194
  ctx.send(socket, {
848
- type: 'session_list_response',
1195
+ type: "session_list_response",
849
1196
  sessions: conversations.map((c) => {
850
1197
  const binding = bindings.get(c.id);
851
1198
  const originChannel = parseChannelId(c.originChannel);
852
1199
  const originInterface = parseInterfaceId(c.originInterface);
853
1200
  const attn = attentionStates.get(c.id);
854
1201
  const displayMeta = displayMetas.get(c.id);
855
- const assistantAttention = attn ? {
856
- hasUnseenLatestAssistantMessage: attn.latestAssistantMessageAt != null &&
857
- (attn.lastSeenAssistantMessageAt == null || attn.lastSeenAssistantMessageAt < attn.latestAssistantMessageAt),
858
- ...(attn.latestAssistantMessageAt != null ? { latestAssistantMessageAt: attn.latestAssistantMessageAt } : {}),
859
- ...(attn.lastSeenAssistantMessageAt != null ? { lastSeenAssistantMessageAt: attn.lastSeenAssistantMessageAt } : {}),
860
- ...(attn.lastSeenConfidence != null ? { lastSeenConfidence: attn.lastSeenConfidence } : {}),
861
- ...(attn.lastSeenSignalType != null ? { lastSeenSignalType: attn.lastSeenSignalType } : {}),
862
- } : undefined;
1202
+ const assistantAttention = attn
1203
+ ? {
1204
+ hasUnseenLatestAssistantMessage:
1205
+ attn.latestAssistantMessageAt != null &&
1206
+ (attn.lastSeenAssistantMessageAt == null ||
1207
+ attn.lastSeenAssistantMessageAt <
1208
+ attn.latestAssistantMessageAt),
1209
+ ...(attn.latestAssistantMessageAt != null
1210
+ ? { latestAssistantMessageAt: attn.latestAssistantMessageAt }
1211
+ : {}),
1212
+ ...(attn.lastSeenAssistantMessageAt != null
1213
+ ? { lastSeenAssistantMessageAt: attn.lastSeenAssistantMessageAt }
1214
+ : {}),
1215
+ ...(attn.lastSeenConfidence != null
1216
+ ? { lastSeenConfidence: attn.lastSeenConfidence }
1217
+ : {}),
1218
+ ...(attn.lastSeenSignalType != null
1219
+ ? { lastSeenSignalType: attn.lastSeenSignalType }
1220
+ : {}),
1221
+ }
1222
+ : undefined;
863
1223
  return {
864
1224
  id: c.id,
865
- title: c.title ?? 'Untitled',
1225
+ title: c.title ?? "Untitled",
866
1226
  createdAt: c.createdAt,
867
1227
  updatedAt: c.updatedAt,
868
1228
  threadType: normalizeThreadType(c.threadType),
869
- source: c.source ?? 'user',
870
- ...(binding && isChannelId(binding.sourceChannel) ? {
871
- channelBinding: {
872
- sourceChannel: binding.sourceChannel,
873
- externalChatId: binding.externalChatId,
874
- externalUserId: binding.externalUserId,
875
- displayName: binding.displayName,
876
- username: binding.username,
877
- },
878
- } : {}),
1229
+ source: c.source ?? "user",
1230
+ ...(binding && isChannelId(binding.sourceChannel)
1231
+ ? {
1232
+ channelBinding: {
1233
+ sourceChannel: binding.sourceChannel,
1234
+ externalChatId: binding.externalChatId,
1235
+ externalUserId: binding.externalUserId,
1236
+ displayName: binding.displayName,
1237
+ username: binding.username,
1238
+ },
1239
+ }
1240
+ : {}),
1241
+ ...(c.scheduleJobId ? { scheduleJobId: c.scheduleJobId } : {}),
879
1242
  ...(originChannel ? { conversationOriginChannel: originChannel } : {}),
880
- ...(originInterface ? { conversationOriginInterface: originInterface } : {}),
1243
+ ...(originInterface
1244
+ ? { conversationOriginInterface: originInterface }
1245
+ : {}),
881
1246
  ...(assistantAttention ? { assistantAttention } : {}),
882
- ...(displayMeta?.displayOrder != null ? { displayOrder: displayMeta.displayOrder } : {}),
1247
+ ...(displayMeta?.displayOrder != null
1248
+ ? { displayOrder: displayMeta.displayOrder }
1249
+ : {}),
883
1250
  ...(displayMeta?.isPinned ? { isPinned: displayMeta.isPinned } : {}),
884
1251
  };
885
1252
  }),
@@ -887,14 +1254,17 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
887
1254
  });
888
1255
  }
889
1256
 
890
- export function handleSessionsClear(socket: net.Socket, ctx: HandlerContext): void {
1257
+ export function handleSessionsClear(
1258
+ socket: net.Socket,
1259
+ ctx: HandlerContext,
1260
+ ): void {
891
1261
  const cleared = ctx.clearAllSessions();
892
1262
  // Also clear DB conversations. When a new IPC connection triggers
893
1263
  // sendInitialSession, it auto-creates a conversation if none exist.
894
1264
  // Without this DB clear, that auto-created row survives, contradicting
895
1265
  // the "clear all conversations" intent.
896
1266
  conversationStore.clearAll();
897
- ctx.send(socket, { type: 'sessions_clear_response', cleared });
1267
+ ctx.send(socket, { type: "sessions_clear_response", cleared });
898
1268
  }
899
1269
 
900
1270
  export async function handleSessionCreate(
@@ -903,7 +1273,8 @@ export async function handleSessionCreate(
903
1273
  ctx: HandlerContext,
904
1274
  ): Promise<void> {
905
1275
  const threadType = normalizeThreadType(msg.threadType);
906
- const title = msg.title ?? (msg.initialMessage ? GENERATING_TITLE : 'New Conversation');
1276
+ const title =
1277
+ msg.title ?? (msg.initialMessage ? GENERATING_TITLE : "New Conversation");
907
1278
  const conversation = conversationStore.createConversation({
908
1279
  title,
909
1280
  threadType,
@@ -922,9 +1293,9 @@ export async function handleSessionCreate(
922
1293
  }
923
1294
 
924
1295
  ctx.send(socket, {
925
- type: 'session_info',
1296
+ type: "session_info",
926
1297
  sessionId: conversation.id,
927
- title: conversation.title ?? 'New Conversation',
1298
+ title: conversation.title ?? "New Conversation",
928
1299
  ...(msg.correlationId ? { correlationId: msg.correlationId } : {}),
929
1300
  threadType: normalizeThreadType(conversation.threadType),
930
1301
  });
@@ -939,11 +1310,11 @@ export async function handleSessionCreate(
939
1310
  if (title === GENERATING_TITLE) {
940
1311
  queueGenerateConversationTitle({
941
1312
  conversationId: conversation.id,
942
- context: { origin: 'ipc' },
1313
+ context: { origin: "ipc" },
943
1314
  userMessage: msg.initialMessage,
944
1315
  onTitleUpdated: (newTitle) => {
945
1316
  ctx.send(socket, {
946
- type: 'session_title_updated',
1317
+ type: "session_title_updated",
947
1318
  sessionId: conversation.id,
948
1319
  title: newTitle,
949
1320
  });
@@ -953,7 +1324,8 @@ export async function handleSessionCreate(
953
1324
 
954
1325
  ctx.socketToSession.set(socket, conversation.id);
955
1326
  const requestId = uuid();
956
- const transportChannel = parseChannelId(msg.transport?.channelId) ?? 'vellum';
1327
+ const transportChannel =
1328
+ parseChannelId(msg.transport?.channelId) ?? "vellum";
957
1329
  const sendEvent = makeIpcEventSender({
958
1330
  ctx,
959
1331
  socket,
@@ -966,33 +1338,45 @@ export async function handleSessionCreate(
966
1338
  userMessageChannel: transportChannel,
967
1339
  assistantMessageChannel: transportChannel,
968
1340
  });
969
- const transportInterface: InterfaceId = parseInterfaceId(msg.transport?.interfaceId) ?? 'vellum';
1341
+ const transportInterface: InterfaceId =
1342
+ parseInterfaceId(msg.transport?.interfaceId) ?? "vellum";
970
1343
  session.setTurnInterfaceContext({
971
1344
  userMessageInterface: transportInterface,
972
1345
  assistantMessageInterface: transportInterface,
973
1346
  });
974
- session.processMessage(msg.initialMessage, [], sendEvent, requestId).catch((err) => {
975
- const message = err instanceof Error ? err.message : String(err);
976
- log.error({ err, sessionId: conversation.id }, 'Error processing initial message');
977
- ctx.send(socket, { type: 'error', message: `Failed to process initial message: ${message}` });
1347
+ session
1348
+ .processMessage(msg.initialMessage, [], sendEvent, requestId)
1349
+ .catch((err) => {
1350
+ const message = err instanceof Error ? err.message : String(err);
1351
+ log.error(
1352
+ { err, sessionId: conversation.id },
1353
+ "Error processing initial message",
1354
+ );
1355
+ ctx.send(socket, {
1356
+ type: "error",
1357
+ message: `Failed to process initial message: ${message}`,
1358
+ });
978
1359
 
979
- // Replace stuck loading placeholder with a stable fallback title
980
- // if title generation hasn't already completed or been renamed.
981
- try {
982
- const current = conversationStore.getConversation(conversation.id);
983
- if (current && current.title === GENERATING_TITLE) {
984
- const fallback = UNTITLED_FALLBACK;
985
- conversationStore.updateConversationTitle(conversation.id, fallback);
986
- ctx.send(socket, {
987
- type: 'session_title_updated',
988
- sessionId: conversation.id,
989
- title: fallback,
990
- });
1360
+ // Replace stuck loading placeholder with a stable fallback title
1361
+ // if title generation hasn't already completed or been renamed.
1362
+ try {
1363
+ const current = conversationStore.getConversation(conversation.id);
1364
+ if (current && current.title === GENERATING_TITLE) {
1365
+ const fallback = UNTITLED_FALLBACK;
1366
+ conversationStore.updateConversationTitle(
1367
+ conversation.id,
1368
+ fallback,
1369
+ );
1370
+ ctx.send(socket, {
1371
+ type: "session_title_updated",
1372
+ sessionId: conversation.id,
1373
+ title: fallback,
1374
+ });
1375
+ }
1376
+ } catch {
1377
+ // Best-effort fallback
991
1378
  }
992
- } catch {
993
- // Best-effort fallback
994
- }
995
- });
1379
+ });
996
1380
  }
997
1381
  }
998
1382
 
@@ -1003,7 +1387,10 @@ export async function handleSessionSwitch(
1003
1387
  ): Promise<void> {
1004
1388
  const conversation = conversationStore.getConversation(msg.sessionId);
1005
1389
  if (!conversation) {
1006
- ctx.send(socket, { type: 'error', message: `Session ${msg.sessionId} not found` });
1390
+ ctx.send(socket, {
1391
+ type: "error",
1392
+ message: `Session ${msg.sessionId} not found`,
1393
+ });
1007
1394
  return;
1008
1395
  }
1009
1396
 
@@ -1028,9 +1415,9 @@ export async function handleSessionSwitch(
1028
1415
  }
1029
1416
 
1030
1417
  ctx.send(socket, {
1031
- type: 'session_info',
1418
+ type: "session_info",
1032
1419
  sessionId: conversation.id,
1033
- title: conversation.title ?? 'Untitled',
1420
+ title: conversation.title ?? "Untitled",
1034
1421
  threadType: normalizeThreadType(conversation.threadType),
1035
1422
  });
1036
1423
  }
@@ -1042,18 +1429,25 @@ export function handleSessionRename(
1042
1429
  ): void {
1043
1430
  const conversation = conversationStore.getConversation(msg.sessionId);
1044
1431
  if (!conversation) {
1045
- ctx.send(socket, { type: 'error', message: `Session ${msg.sessionId} not found` });
1432
+ ctx.send(socket, {
1433
+ type: "error",
1434
+ message: `Session ${msg.sessionId} not found`,
1435
+ });
1046
1436
  return;
1047
1437
  }
1048
1438
  conversationStore.updateConversationTitle(msg.sessionId, msg.title, 0);
1049
1439
  ctx.send(socket, {
1050
- type: 'session_title_updated',
1440
+ type: "session_title_updated",
1051
1441
  sessionId: msg.sessionId,
1052
1442
  title: msg.title,
1053
1443
  });
1054
1444
  }
1055
1445
 
1056
- export function handleCancel(msg: CancelRequest, socket: net.Socket, ctx: HandlerContext): void {
1446
+ export function handleCancel(
1447
+ msg: CancelRequest,
1448
+ socket: net.Socket,
1449
+ ctx: HandlerContext,
1450
+ ): void {
1057
1451
  const sessionId = msg.sessionId || ctx.socketToSession.get(socket);
1058
1452
  if (sessionId) {
1059
1453
  const session = ctx.sessions.get(sessionId);
@@ -1080,20 +1474,21 @@ export function handleHistoryRequest(
1080
1474
 
1081
1475
  // Resolve include flags: explicit flags override mode, mode provides defaults.
1082
1476
  // Default mode is 'light' when no mode and no include flags are specified.
1083
- const isFullMode = msg.mode === 'full';
1477
+ const isFullMode = msg.mode === "full";
1084
1478
  const includeAttachments = msg.includeAttachments ?? isFullMode;
1085
1479
  const includeToolImages = msg.includeToolImages ?? isFullMode;
1086
1480
  const includeSurfaceData = msg.includeSurfaceData ?? isFullMode;
1087
1481
 
1088
- const { messages: dbMessages, hasMore } = conversationStore.getMessagesPaginated(
1089
- msg.sessionId,
1090
- limit,
1091
- msg.beforeTimestamp,
1092
- msg.beforeMessageId,
1093
- );
1482
+ const { messages: dbMessages, hasMore } =
1483
+ conversationStore.getMessagesPaginated(
1484
+ msg.sessionId,
1485
+ limit,
1486
+ msg.beforeTimestamp,
1487
+ msg.beforeMessageId,
1488
+ );
1094
1489
 
1095
1490
  const parsed: ParsedHistoryMessage[] = dbMessages.map((m) => {
1096
- let text = '';
1491
+ let text = "";
1097
1492
  let toolCalls: HistoryToolCall[] = [];
1098
1493
  let toolCallsBeforeText = false;
1099
1494
  let textSegments: string[] = [];
@@ -1108,25 +1503,53 @@ export function handleHistoryRequest(
1108
1503
  textSegments = rendered.textSegments;
1109
1504
  contentOrder = rendered.contentOrder;
1110
1505
  surfaces = rendered.surfaces;
1111
- if (m.role === 'assistant' && toolCalls.length > 0) {
1112
- log.info({ messageId: m.id, toolCallCount: toolCalls.length, text: truncate(text, 100, '') }, 'History message with tool calls');
1506
+ if (m.role === "assistant" && toolCalls.length > 0) {
1507
+ log.info(
1508
+ {
1509
+ messageId: m.id,
1510
+ toolCallCount: toolCalls.length,
1511
+ text: truncate(text, 100, ""),
1512
+ },
1513
+ "History message with tool calls",
1514
+ );
1113
1515
  }
1114
1516
  } catch (err) {
1115
- log.debug({ err, messageId: m.id }, 'Failed to parse message content as JSON, using raw text');
1517
+ log.debug(
1518
+ { err, messageId: m.id },
1519
+ "Failed to parse message content as JSON, using raw text",
1520
+ );
1116
1521
  text = m.content;
1117
1522
  textSegments = text ? [text] : [];
1118
- contentOrder = text ? ['text:0'] : [];
1523
+ contentOrder = text ? ["text:0"] : [];
1119
1524
  surfaces = [];
1120
1525
  }
1121
- let subagentNotification: ParsedHistoryMessage['subagentNotification'];
1526
+ let subagentNotification: ParsedHistoryMessage["subagentNotification"];
1122
1527
  if (m.metadata) {
1123
1528
  try {
1124
- subagentNotification = (JSON.parse(m.metadata) as { subagentNotification?: ParsedHistoryMessage['subagentNotification'] }).subagentNotification;
1529
+ subagentNotification = (
1530
+ JSON.parse(m.metadata) as {
1531
+ subagentNotification?: ParsedHistoryMessage["subagentNotification"];
1532
+ }
1533
+ ).subagentNotification;
1125
1534
  } catch (err) {
1126
- log.debug({ err, messageId: m.id }, 'Failed to parse message metadata as JSON, ignoring');
1535
+ log.debug(
1536
+ { err, messageId: m.id },
1537
+ "Failed to parse message metadata as JSON, ignoring",
1538
+ );
1127
1539
  }
1128
1540
  }
1129
- return { id: m.id, role: m.role, text, timestamp: m.createdAt, toolCalls, toolCallsBeforeText, textSegments, contentOrder, surfaces, ...(subagentNotification ? { subagentNotification } : {}) };
1541
+ return {
1542
+ id: m.id,
1543
+ role: m.role,
1544
+ text,
1545
+ timestamp: m.createdAt,
1546
+ toolCalls,
1547
+ toolCallsBeforeText,
1548
+ textSegments,
1549
+ contentOrder,
1550
+ surfaces,
1551
+ ...(subagentNotification ? { subagentNotification } : {}),
1552
+ };
1130
1553
  });
1131
1554
 
1132
1555
  // Merge tool_result data from user messages into the preceding assistant
@@ -1136,7 +1559,7 @@ export function handleHistoryRequest(
1136
1559
 
1137
1560
  const historyMessages = merged.map((m) => {
1138
1561
  let attachments: UserMessageAttachment[] | undefined;
1139
- if (m.role === 'assistant' && m.id) {
1562
+ if (m.role === "assistant" && m.id) {
1140
1563
  const linked = getAttachmentsForMessage(m.id);
1141
1564
  if (linked.length > 0) {
1142
1565
  if (includeAttachments) {
@@ -1144,16 +1567,23 @@ export function handleHistoryRequest(
1144
1567
  const MAX_INLINE_B64_SIZE = 512 * 1024;
1145
1568
  attachments = linked.map((a) => {
1146
1569
  const isFileBacked = !a.dataBase64;
1147
- const omit = isFileBacked || (a.mimeType.startsWith('video/') && a.dataBase64.length > MAX_INLINE_B64_SIZE);
1148
-
1149
- if (a.mimeType.startsWith('video/') && !a.thumbnailBase64 && a.dataBase64) {
1570
+ const omit =
1571
+ isFileBacked ||
1572
+ (a.mimeType.startsWith("video/") &&
1573
+ a.dataBase64.length > MAX_INLINE_B64_SIZE);
1574
+
1575
+ if (
1576
+ a.mimeType.startsWith("video/") &&
1577
+ !a.thumbnailBase64 &&
1578
+ a.dataBase64
1579
+ ) {
1150
1580
  const attachmentId = a.id;
1151
1581
  const base64 = a.dataBase64;
1152
1582
  silentlyWithLog(
1153
1583
  generateVideoThumbnail(base64).then((thumb) => {
1154
1584
  if (thumb) setAttachmentThumbnail(attachmentId, thumb);
1155
1585
  }),
1156
- 'video thumbnail generation',
1586
+ "video thumbnail generation",
1157
1587
  );
1158
1588
  }
1159
1589
 
@@ -1162,9 +1592,11 @@ export function handleHistoryRequest(
1162
1592
  id: a.id,
1163
1593
  filename: a.originalFilename,
1164
1594
  mimeType: a.mimeType,
1165
- data: omit ? '' : a.dataBase64,
1595
+ data: omit ? "" : a.dataBase64,
1166
1596
  ...(omit ? { sizeBytes: a.sizeBytes } : {}),
1167
- ...(a.thumbnailBase64 ? { thumbnailData: a.thumbnailBase64 } : {}),
1597
+ ...(a.thumbnailBase64
1598
+ ? { thumbnailData: a.thumbnailBase64 }
1599
+ : {}),
1168
1600
  ...(fp ? { filePath: fp } : {}),
1169
1601
  };
1170
1602
  });
@@ -1176,9 +1608,11 @@ export function handleHistoryRequest(
1176
1608
  id: a.id,
1177
1609
  filename: a.originalFilename,
1178
1610
  mimeType: a.mimeType,
1179
- data: '',
1611
+ data: "",
1180
1612
  sizeBytes: a.sizeBytes,
1181
- ...(a.thumbnailBase64 ? { thumbnailData: a.thumbnailBase64 } : {}),
1613
+ ...(a.thumbnailBase64
1614
+ ? { thumbnailData: a.thumbnailBase64 }
1615
+ : {}),
1182
1616
  ...(fp ? { filePath: fp } : {}),
1183
1617
  };
1184
1618
  });
@@ -1187,83 +1621,107 @@ export function handleHistoryRequest(
1187
1621
  }
1188
1622
 
1189
1623
  // In light mode, strip imageData from tool calls
1190
- const filteredToolCalls = m.toolCalls.length > 0
1191
- ? (includeToolImages
1192
- ? m.toolCalls
1193
- : m.toolCalls.map((tc) => {
1194
- if (tc.imageData) {
1195
- const { imageData: _, ...rest } = tc;
1196
- return rest;
1197
- }
1198
- return tc;
1199
- }))
1200
- : m.toolCalls;
1624
+ const filteredToolCalls =
1625
+ m.toolCalls.length > 0
1626
+ ? includeToolImages
1627
+ ? m.toolCalls
1628
+ : m.toolCalls.map((tc) => {
1629
+ if (tc.imageData) {
1630
+ const { imageData: _, ...rest } = tc;
1631
+ return rest;
1632
+ }
1633
+ return tc;
1634
+ })
1635
+ : m.toolCalls;
1201
1636
 
1202
1637
  // In light mode, strip full data from surfaces (keep metadata)
1203
- const filteredSurfaces = m.surfaces.length > 0
1204
- ? (includeSurfaceData
1205
- ? m.surfaces
1206
- : m.surfaces.map((s) => ({
1207
- surfaceId: s.surfaceId,
1208
- surfaceType: s.surfaceType,
1209
- title: s.title,
1210
- data: {
1211
- ...(s.surfaceType === 'dynamic_page'
1212
- ? {
1213
- ...(s.data.preview ? { preview: s.data.preview } : {}),
1214
- ...(s.data.appId ? { appId: s.data.appId } : {}),
1215
- ...(s.data.appType ? { appType: s.data.appType } : {}),
1216
- }
1217
- : {}),
1218
- } as Record<string, unknown>,
1219
- ...(s.actions ? { actions: s.actions } : {}),
1220
- ...(s.display ? { display: s.display } : {}),
1221
- })))
1222
- : m.surfaces;
1638
+ const filteredSurfaces =
1639
+ m.surfaces.length > 0
1640
+ ? includeSurfaceData
1641
+ ? m.surfaces
1642
+ : m.surfaces.map((s) => ({
1643
+ surfaceId: s.surfaceId,
1644
+ surfaceType: s.surfaceType,
1645
+ title: s.title,
1646
+ data: {
1647
+ ...(s.surfaceType === "dynamic_page"
1648
+ ? {
1649
+ ...(s.data.preview ? { preview: s.data.preview } : {}),
1650
+ ...(s.data.appId ? { appId: s.data.appId } : {}),
1651
+ ...(s.data.appType ? { appType: s.data.appType } : {}),
1652
+ }
1653
+ : {}),
1654
+ } as Record<string, unknown>,
1655
+ ...(s.actions ? { actions: s.actions } : {}),
1656
+ ...(s.display ? { display: s.display } : {}),
1657
+ }))
1658
+ : m.surfaces;
1223
1659
 
1224
1660
  // Apply text truncation when maxTextChars is set
1225
1661
  let wasTruncated = false;
1226
1662
  let textWasTruncated = false;
1227
1663
  let text = m.text;
1228
1664
  if (msg.maxTextChars !== undefined && text.length > msg.maxTextChars) {
1229
- text = text.slice(0, msg.maxTextChars) + ' \u2026 [truncated]';
1665
+ text = text.slice(0, msg.maxTextChars) + " \u2026 [truncated]";
1230
1666
  wasTruncated = true;
1231
1667
  textWasTruncated = true;
1232
1668
  }
1233
1669
 
1234
1670
  // Apply tool result truncation when maxToolResultChars is set
1235
- const truncatedToolCalls = msg.maxToolResultChars !== undefined && filteredToolCalls.length > 0
1236
- ? filteredToolCalls.map((tc) => {
1237
- if (tc.result !== undefined && tc.result.length > msg.maxToolResultChars!) {
1238
- wasTruncated = true;
1239
- return { ...tc, result: tc.result.slice(0, msg.maxToolResultChars!) + ' \u2026 [truncated]' };
1240
- }
1241
- return tc;
1242
- })
1243
- : filteredToolCalls;
1671
+ const truncatedToolCalls =
1672
+ msg.maxToolResultChars !== undefined && filteredToolCalls.length > 0
1673
+ ? filteredToolCalls.map((tc) => {
1674
+ if (
1675
+ tc.result !== undefined &&
1676
+ tc.result.length > msg.maxToolResultChars!
1677
+ ) {
1678
+ wasTruncated = true;
1679
+ return {
1680
+ ...tc,
1681
+ result:
1682
+ tc.result.slice(0, msg.maxToolResultChars!) +
1683
+ " \u2026 [truncated]",
1684
+ };
1685
+ }
1686
+ return tc;
1687
+ })
1688
+ : filteredToolCalls;
1244
1689
 
1245
1690
  return {
1246
1691
  ...(m.id ? { id: m.id } : {}),
1247
1692
  role: m.role,
1248
1693
  text,
1249
1694
  timestamp: m.timestamp,
1250
- ...(truncatedToolCalls.length > 0 ? { toolCalls: truncatedToolCalls, toolCallsBeforeText: m.toolCallsBeforeText } : {}),
1695
+ ...(truncatedToolCalls.length > 0
1696
+ ? {
1697
+ toolCalls: truncatedToolCalls,
1698
+ toolCallsBeforeText: m.toolCallsBeforeText,
1699
+ }
1700
+ : {}),
1251
1701
  ...(attachments ? { attachments } : {}),
1252
- ...(!textWasTruncated && m.textSegments.length > 0 ? { textSegments: m.textSegments } : {}),
1253
- ...(!textWasTruncated && m.contentOrder.length > 0 ? { contentOrder: m.contentOrder } : {}),
1702
+ ...(!textWasTruncated && m.textSegments.length > 0
1703
+ ? { textSegments: m.textSegments }
1704
+ : {}),
1705
+ ...(!textWasTruncated && m.contentOrder.length > 0
1706
+ ? { contentOrder: m.contentOrder }
1707
+ : {}),
1254
1708
  ...(filteredSurfaces.length > 0 ? { surfaces: filteredSurfaces } : {}),
1255
- ...(m.subagentNotification ? { subagentNotification: m.subagentNotification } : {}),
1709
+ ...(m.subagentNotification
1710
+ ? { subagentNotification: m.subagentNotification }
1711
+ : {}),
1256
1712
  ...(wasTruncated ? { wasTruncated: true } : {}),
1257
1713
  };
1258
1714
  });
1259
1715
 
1260
- const oldestTimestamp = historyMessages.length > 0 ? historyMessages[0].timestamp : undefined;
1716
+ const oldestTimestamp =
1717
+ historyMessages.length > 0 ? historyMessages[0].timestamp : undefined;
1261
1718
  // Provide the oldest message ID as a tie-breaker cursor so clients can
1262
1719
  // paginate without skipping same-millisecond messages at page boundaries.
1263
- const oldestMessageId = historyMessages.length > 0 ? historyMessages[0].id : undefined;
1720
+ const oldestMessageId =
1721
+ historyMessages.length > 0 ? historyMessages[0].id : undefined;
1264
1722
 
1265
1723
  ctx.send(socket, {
1266
- type: 'history_response',
1724
+ type: "history_response",
1267
1725
  sessionId: msg.sessionId,
1268
1726
  messages: historyMessages,
1269
1727
  hasMore,
@@ -1282,12 +1740,16 @@ export function handleUndo(
1282
1740
  ): void {
1283
1741
  const session = ctx.sessions.get(msg.sessionId);
1284
1742
  if (!session) {
1285
- ctx.send(socket, { type: 'error', message: 'No active session' });
1743
+ ctx.send(socket, { type: "error", message: "No active session" });
1286
1744
  return;
1287
1745
  }
1288
1746
  ctx.touchSession(msg.sessionId);
1289
1747
  const removedCount = session.undo();
1290
- ctx.send(socket, { type: 'undo_complete', removedCount, sessionId: msg.sessionId });
1748
+ ctx.send(socket, {
1749
+ type: "undo_complete",
1750
+ removedCount,
1751
+ sessionId: msg.sessionId,
1752
+ });
1291
1753
  }
1292
1754
 
1293
1755
  export async function handleRegenerate(
@@ -1297,14 +1759,14 @@ export async function handleRegenerate(
1297
1759
  ): Promise<void> {
1298
1760
  const session = ctx.sessions.get(msg.sessionId);
1299
1761
  if (!session) {
1300
- ctx.send(socket, { type: 'error', message: 'No active session' });
1762
+ ctx.send(socket, { type: "error", message: "No active session" });
1301
1763
  return;
1302
1764
  }
1303
1765
  ctx.touchSession(msg.sessionId);
1304
1766
 
1305
- const regenerateChannel = parseChannelId(
1306
- session.getTurnChannelContext()?.assistantMessageChannel,
1307
- ) ?? 'vellum';
1767
+ const regenerateChannel =
1768
+ parseChannelId(session.getTurnChannelContext()?.assistantMessageChannel) ??
1769
+ "vellum";
1308
1770
  const sendEvent = makeIpcEventSender({
1309
1771
  ctx,
1310
1772
  socket,
@@ -1314,23 +1776,29 @@ export async function handleRegenerate(
1314
1776
  });
1315
1777
  session.updateClient(sendEvent, false);
1316
1778
  const requestId = uuid();
1317
- session.traceEmitter.emit('request_received', 'Regenerate requested', {
1779
+ session.traceEmitter.emit("request_received", "Regenerate requested", {
1318
1780
  requestId,
1319
- status: 'info',
1320
- attributes: { source: 'regenerate' },
1781
+ status: "info",
1782
+ attributes: { source: "regenerate" },
1321
1783
  });
1322
1784
  try {
1323
1785
  await session.regenerate(sendEvent, requestId);
1324
1786
  } catch (err) {
1325
1787
  const message = err instanceof Error ? err.message : String(err);
1326
- log.error({ err, sessionId: msg.sessionId }, 'Error regenerating message');
1327
- session.traceEmitter.emit('request_error', truncate(message, 200, ''), {
1788
+ log.error({ err, sessionId: msg.sessionId }, "Error regenerating message");
1789
+ session.traceEmitter.emit("request_error", truncate(message, 200, ""), {
1328
1790
  requestId,
1329
- status: 'error',
1330
- attributes: { errorClass: err instanceof Error ? err.constructor.name : 'Error', message: truncate(message, 500, '') },
1791
+ status: "error",
1792
+ attributes: {
1793
+ errorClass: err instanceof Error ? err.constructor.name : "Error",
1794
+ message: truncate(message, 500, ""),
1795
+ },
1331
1796
  });
1332
- ctx.send(socket, { type: 'error', message: `Failed to regenerate: ${message}` });
1333
- const classified = classifySessionError(err, { phase: 'regenerate' });
1797
+ ctx.send(socket, {
1798
+ type: "error",
1799
+ message: `Failed to regenerate: ${message}`,
1800
+ });
1801
+ const classified = classifySessionError(err, { phase: "regenerate" });
1334
1802
  ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
1335
1803
  }
1336
1804
  }
@@ -1342,12 +1810,12 @@ export function handleUsageRequest(
1342
1810
  ): void {
1343
1811
  const conversation = conversationStore.getConversation(msg.sessionId);
1344
1812
  if (!conversation) {
1345
- ctx.send(socket, { type: 'error', message: 'No active session' });
1813
+ ctx.send(socket, { type: "error", message: "No active session" });
1346
1814
  return;
1347
1815
  }
1348
1816
  const config = getConfig();
1349
1817
  ctx.send(socket, {
1350
- type: 'usage_response',
1818
+ type: "usage_response",
1351
1819
  totalInputTokens: conversation.totalInputTokens,
1352
1820
  totalOutputTokens: conversation.totalOutputTokens,
1353
1821
  estimatedCost: conversation.totalEstimatedCost,
@@ -1362,7 +1830,7 @@ export function handleSandboxSet(
1362
1830
  ): void {
1363
1831
  log.warn(
1364
1832
  { enabled: msg.enabled },
1365
- 'Received deprecated sandbox_set message. Runtime sandbox overrides are ignored.',
1833
+ "Received deprecated sandbox_set message. Runtime sandbox overrides are ignored.",
1366
1834
  );
1367
1835
  }
1368
1836
 
@@ -1373,18 +1841,24 @@ export function handleDeleteQueuedMessage(
1373
1841
  ): void {
1374
1842
  const session = ctx.sessions.get(msg.sessionId);
1375
1843
  if (!session) {
1376
- log.warn({ sessionId: msg.sessionId, requestId: msg.requestId }, 'No session found for delete_queued_message');
1844
+ log.warn(
1845
+ { sessionId: msg.sessionId, requestId: msg.requestId },
1846
+ "No session found for delete_queued_message",
1847
+ );
1377
1848
  return;
1378
1849
  }
1379
1850
  const removed = session.removeQueuedMessage(msg.requestId);
1380
1851
  if (removed) {
1381
1852
  ctx.send(socket, {
1382
- type: 'message_queued_deleted',
1853
+ type: "message_queued_deleted",
1383
1854
  sessionId: msg.sessionId,
1384
1855
  requestId: msg.requestId,
1385
1856
  });
1386
1857
  } else {
1387
- log.warn({ sessionId: msg.sessionId, requestId: msg.requestId }, 'Queued message not found for deletion');
1858
+ log.warn(
1859
+ { sessionId: msg.sessionId, requestId: msg.requestId },
1860
+ "Queued message not found for deletion",
1861
+ );
1388
1862
  }
1389
1863
  }
1390
1864
 
@@ -1398,7 +1872,7 @@ export function handleConversationSearch(
1398
1872
  maxMessagesPerConversation: msg.maxMessagesPerConversation,
1399
1873
  });
1400
1874
  ctx.send(socket, {
1401
- type: 'conversation_search_response',
1875
+ type: "conversation_search_response",
1402
1876
  query: msg.query,
1403
1877
  results,
1404
1878
  });
@@ -1409,14 +1883,22 @@ export function handleMessageContentRequest(
1409
1883
  socket: net.Socket,
1410
1884
  ctx: HandlerContext,
1411
1885
  ): void {
1412
- const dbMessage = conversationStore.getMessageById(msg.messageId, msg.sessionId);
1886
+ const dbMessage = conversationStore.getMessageById(
1887
+ msg.messageId,
1888
+ msg.sessionId,
1889
+ );
1413
1890
  if (!dbMessage) {
1414
- ctx.send(socket, { type: 'error', message: `Message ${msg.messageId} not found in session ${msg.sessionId}` });
1891
+ ctx.send(socket, {
1892
+ type: "error",
1893
+ message: `Message ${msg.messageId} not found in session ${msg.sessionId}`,
1894
+ });
1415
1895
  return;
1416
1896
  }
1417
1897
 
1418
1898
  let text: string | undefined;
1419
- let toolCalls: Array<{ name: string; result?: string; input?: Record<string, unknown> }> | undefined;
1899
+ let toolCalls:
1900
+ | Array<{ name: string; result?: string; input?: Record<string, unknown> }>
1901
+ | undefined;
1420
1902
 
1421
1903
  try {
1422
1904
  const content = JSON.parse(dbMessage.content);
@@ -1427,19 +1909,32 @@ export function handleMessageContentRequest(
1427
1909
  // Handle legacy conversations where tool_result blocks are stored in the
1428
1910
  // following user message rather than inline with the assistant message.
1429
1911
  // This mirrors the mergeToolResults logic used by handleHistoryRequest.
1430
- if (dbMessage.role === 'assistant' && mergedToolCalls.some((tc) => tc.result === undefined)) {
1431
- const nextMsg = conversationStore.getNextMessage(msg.sessionId, dbMessage.createdAt, dbMessage.id);
1432
- if (nextMsg && nextMsg.role === 'user') {
1912
+ if (
1913
+ dbMessage.role === "assistant" &&
1914
+ mergedToolCalls.some((tc) => tc.result === undefined)
1915
+ ) {
1916
+ const nextMsg = conversationStore.getNextMessage(
1917
+ msg.sessionId,
1918
+ dbMessage.createdAt,
1919
+ dbMessage.id,
1920
+ );
1921
+ if (nextMsg && nextMsg.role === "user") {
1433
1922
  try {
1434
1923
  const nextContent = JSON.parse(nextMsg.content);
1435
1924
  const nextRendered = renderHistoryContent(nextContent);
1436
- if (nextRendered.text.trim() === '' && nextRendered.toolCalls.length > 0) {
1925
+ if (
1926
+ nextRendered.text.trim() === "" &&
1927
+ nextRendered.toolCalls.length > 0
1928
+ ) {
1437
1929
  for (const resultEntry of nextRendered.toolCalls) {
1438
- const unresolved = mergedToolCalls.find((tc) => tc.result === undefined);
1930
+ const unresolved = mergedToolCalls.find(
1931
+ (tc) => tc.result === undefined,
1932
+ );
1439
1933
  if (unresolved) {
1440
1934
  unresolved.result = resultEntry.result;
1441
1935
  unresolved.isError = resultEntry.isError;
1442
- if (resultEntry.imageData) unresolved.imageData = resultEntry.imageData;
1936
+ if (resultEntry.imageData)
1937
+ unresolved.imageData = resultEntry.imageData;
1443
1938
  }
1444
1939
  }
1445
1940
  }
@@ -1462,7 +1957,7 @@ export function handleMessageContentRequest(
1462
1957
  }
1463
1958
 
1464
1959
  ctx.send(socket, {
1465
- type: 'message_content_response',
1960
+ type: "message_content_response",
1466
1961
  sessionId: msg.sessionId,
1467
1962
  messageId: msg.messageId,
1468
1963
  ...(text !== undefined ? { text } : {}),
@@ -1479,7 +1974,11 @@ export function handleReorderThreads(
1479
1974
  return;
1480
1975
  }
1481
1976
  conversationStore.batchSetDisplayOrders(
1482
- msg.updates.map((u) => ({ id: u.sessionId, displayOrder: u.displayOrder ?? null, isPinned: u.isPinned ?? false })),
1977
+ msg.updates.map((u) => ({
1978
+ id: u.sessionId,
1979
+ displayOrder: u.displayOrder ?? null,
1980
+ isPinned: u.isPinned ?? false,
1981
+ })),
1483
1982
  );
1484
1983
  }
1485
1984
 
@@ -1487,7 +1986,8 @@ export const sessionHandlers = defineHandlers({
1487
1986
  user_message: handleUserMessage,
1488
1987
  confirmation_response: handleConfirmationResponse,
1489
1988
  secret_response: handleSecretResponse,
1490
- session_list: (msg, socket, ctx) => handleSessionList(socket, ctx, msg.offset ?? 0, msg.limit ?? 50),
1989
+ session_list: (msg, socket, ctx) =>
1990
+ handleSessionList(socket, ctx, msg.offset ?? 0, msg.limit ?? 50),
1491
1991
  session_create: handleSessionCreate,
1492
1992
  sessions_clear: (_msg, socket, ctx) => handleSessionsClear(socket, ctx),
1493
1993
  session_switch: handleSessionSwitch,