@vellumai/assistant 0.4.26 → 0.4.30

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 (1360) hide show
  1. package/.env.example +2 -2
  2. package/AGENTS.md +5 -0
  3. package/ARCHITECTURE.md +207 -105
  4. package/Dockerfile +1 -1
  5. package/README.md +111 -113
  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 +89 -52
  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 +5 -3
  15. package/scripts/test.sh +89 -5
  16. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +50 -37
  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 +40 -26
  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__/app-executors.test.ts +7 -17
  24. package/src/__tests__/approval-routes-http.test.ts +2 -2
  25. package/src/__tests__/asset-materialize-tool.test.ts +7 -7
  26. package/src/__tests__/asset-search-tool.test.ts +7 -7
  27. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -10
  28. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  29. package/src/__tests__/browser-skill-endstate.test.ts +10 -1
  30. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +218 -0
  31. package/src/__tests__/call-controller.test.ts +99 -69
  32. package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
  33. package/src/__tests__/channel-approval-routes.test.ts +157 -114
  34. package/src/__tests__/channel-approval.test.ts +8 -0
  35. package/src/__tests__/channel-approvals.test.ts +39 -1
  36. package/src/__tests__/channel-guardian.test.ts +176 -275
  37. package/src/__tests__/channel-readiness-service.test.ts +6 -2
  38. package/src/__tests__/channel-reply-delivery.test.ts +33 -2
  39. package/src/__tests__/channel-retry-sweep.test.ts +14 -14
  40. package/src/__tests__/checker.test.ts +12 -31
  41. package/src/__tests__/claude-code-tool-profiles.test.ts +1 -1
  42. package/src/__tests__/commit-message-enrichment-service.test.ts +71 -59
  43. package/src/__tests__/compaction.benchmark.test.ts +6 -2
  44. package/src/__tests__/computer-use-tools.test.ts +1 -1
  45. package/src/__tests__/config-schema.test.ts +66 -7
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -29
  47. package/src/__tests__/contacts-tools.test.ts +63 -2
  48. package/src/__tests__/context-overflow-approval.test.ts +141 -0
  49. package/src/__tests__/context-overflow-policy.test.ts +171 -0
  50. package/src/__tests__/context-overflow-reducer.test.ts +533 -0
  51. package/src/__tests__/context-window-manager.test.ts +97 -0
  52. package/src/__tests__/conversation-attention-telegram.test.ts +38 -46
  53. package/src/__tests__/conversation-pairing.test.ts +2 -2
  54. package/src/__tests__/conversation-routes-guardian-reply.test.ts +214 -10
  55. package/src/__tests__/conversation-routes.test.ts +4 -7
  56. package/src/__tests__/credential-broker-browser-fill.test.ts +13 -2
  57. package/src/__tests__/credential-security-e2e.test.ts +1 -1
  58. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  59. package/src/__tests__/credential-vault-unit.test.ts +1 -1
  60. package/src/__tests__/credential-vault.test.ts +11 -8
  61. package/src/__tests__/daemon-lifecycle.test.ts +2 -2
  62. package/src/__tests__/daemon-server-session-init.test.ts +6 -6
  63. package/src/__tests__/delete-managed-skill-tool.test.ts +1 -1
  64. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -2
  65. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +9 -0
  66. package/src/__tests__/emit-signal-routing-intent.test.ts +4 -0
  67. package/src/__tests__/encrypted-store.test.ts +10 -7
  68. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  69. package/src/__tests__/file-edit-tool.test.ts +1 -1
  70. package/src/__tests__/file-read-tool.test.ts +1 -1
  71. package/src/__tests__/file-write-tool.test.ts +1 -1
  72. package/src/__tests__/fixtures/credential-security-fixtures.ts +87 -64
  73. package/src/__tests__/fixtures/media-reuse-fixtures.ts +37 -31
  74. package/src/__tests__/fixtures/mock-signup-server.ts +171 -115
  75. package/src/__tests__/fixtures/proxy-fixtures.ts +39 -39
  76. package/src/__tests__/followup-tools.test.ts +1 -1
  77. package/src/__tests__/gateway-only-guard.test.ts +4 -0
  78. package/src/__tests__/gemini-image-service.test.ts +2 -2
  79. package/src/__tests__/guardian-actions-endpoint.test.ts +543 -1
  80. package/src/__tests__/guardian-control-plane-policy.test.ts +15 -15
  81. package/src/__tests__/guardian-dispatch.test.ts +79 -1
  82. package/src/__tests__/guardian-grant-minting.test.ts +20 -20
  83. package/src/__tests__/guardian-outbound-http.test.ts +1 -2
  84. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -41
  85. package/src/__tests__/guardian-routing-invariants.test.ts +36 -16
  86. package/src/__tests__/guardian-routing-state.test.ts +36 -52
  87. package/src/__tests__/guardian-verification-intent-routing.test.ts +4 -6
  88. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +6 -8
  89. package/src/__tests__/handle-user-message-secret-resume.test.ts +39 -1
  90. package/src/__tests__/handlers-cu-observation-blob.test.ts +21 -10
  91. package/src/__tests__/handlers-telegram-config.test.ts +14 -14
  92. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +23 -2
  93. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  94. package/src/__tests__/headless-browser-navigate.test.ts +1 -1
  95. package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
  96. package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
  97. package/src/__tests__/heartbeat-service.test.ts +45 -2
  98. package/src/__tests__/host-file-edit-tool.test.ts +1 -1
  99. package/src/__tests__/host-file-read-tool.test.ts +1 -1
  100. package/src/__tests__/host-file-write-tool.test.ts +1 -1
  101. package/src/__tests__/host-shell-tool.test.ts +1 -1
  102. package/src/__tests__/inbound-invite-redemption.test.ts +17 -19
  103. package/src/__tests__/ingress-reconcile.test.ts +2 -2
  104. package/src/__tests__/integrations-cli.test.ts +232 -0
  105. package/src/__tests__/intent-routing.test.ts +7 -5
  106. package/src/__tests__/invite-redemption-service.test.ts +5 -4
  107. package/src/__tests__/{ingress-routes-http.test.ts → invite-routes-http.test.ts} +42 -321
  108. package/src/__tests__/ipc-snapshot.test.ts +32 -31
  109. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
  110. package/src/__tests__/mcp-cli.test.ts +136 -57
  111. package/src/__tests__/mcp-client-auth.test.ts +95 -0
  112. package/src/__tests__/media-generate-image.test.ts +2 -2
  113. package/src/__tests__/media-reuse-story.e2e.test.ts +8 -8
  114. package/src/__tests__/memory-regressions.test.ts +6 -6
  115. package/src/__tests__/messaging-send-tool.test.ts +1 -1
  116. package/src/__tests__/migration-cross-version-compatibility.test.ts +1855 -0
  117. package/src/__tests__/migration-export-http.test.ts +540 -0
  118. package/src/__tests__/migration-import-commit-http.test.ts +823 -0
  119. package/src/__tests__/migration-import-preflight-http.test.ts +755 -0
  120. package/src/__tests__/migration-parity-persistence.test.ts +1854 -0
  121. package/src/__tests__/migration-transport.test.ts +904 -0
  122. package/src/__tests__/migration-validate-http.test.ts +698 -0
  123. package/src/__tests__/migration-wizard.test.ts +1289 -0
  124. package/src/__tests__/nl-approval-parser.test.ts +305 -0
  125. package/src/__tests__/non-member-access-request.test.ts +17 -17
  126. package/src/__tests__/notification-decision-strategy.test.ts +110 -2
  127. package/src/__tests__/notification-deep-link.test.ts +18 -0
  128. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  129. package/src/__tests__/oauth-provider-profiles.test.ts +34 -0
  130. package/src/__tests__/oauth2-gateway-transport.test.ts +1 -1
  131. package/src/__tests__/playbook-execution.test.ts +1 -1
  132. package/src/__tests__/playbook-tools.test.ts +1 -1
  133. package/src/__tests__/provider-error-scenarios.test.ts +68 -0
  134. package/src/__tests__/provider-streaming.benchmark.test.ts +3 -1
  135. package/src/__tests__/proxy-approval-callback.test.ts +1 -1
  136. package/src/__tests__/qdrant-manager.test.ts +40 -11
  137. package/src/__tests__/rebind-secrets-screen.test.ts +839 -0
  138. package/src/__tests__/recording-handler.test.ts +2 -2
  139. package/src/__tests__/recording-intent-handler.test.ts +3 -3
  140. package/src/__tests__/recording-state-machine.test.ts +2 -2
  141. package/src/__tests__/relay-server.test.ts +507 -228
  142. package/src/__tests__/reminder-store.test.ts +8 -0
  143. package/src/__tests__/reminder.test.ts +8 -0
  144. package/src/__tests__/{resolve-guardian-trust-class.test.ts → resolve-trust-class.test.ts} +11 -17
  145. package/src/__tests__/retry-after-extraction.test.ts +111 -0
  146. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
  147. package/src/__tests__/schedule-tools.test.ts +1 -1
  148. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  149. package/src/__tests__/script-proxy-connect-tunnel.test.ts +2 -3
  150. package/src/__tests__/script-proxy-decision-trace.test.ts +2 -2
  151. package/src/__tests__/script-proxy-http-forwarder.test.ts +1 -1
  152. package/src/__tests__/script-proxy-injection-runtime.test.ts +5 -5
  153. package/src/__tests__/script-proxy-mitm-handler.test.ts +4 -4
  154. package/src/__tests__/script-proxy-policy-runtime.test.ts +2 -2
  155. package/src/__tests__/script-proxy-policy.test.ts +2 -2
  156. package/src/__tests__/script-proxy-profile-template-fallback.test.ts +127 -0
  157. package/src/__tests__/script-proxy-session-manager.test.ts +4 -7
  158. package/src/__tests__/script-proxy-session-runtime.test.ts +1 -6
  159. package/src/__tests__/secret-onetime-send.test.ts +4 -4
  160. package/src/__tests__/secret-scanner-executor.test.ts +2 -2
  161. package/src/__tests__/send-endpoint-busy.test.ts +11 -9
  162. package/src/__tests__/send-notification-tool.test.ts +2 -2
  163. package/src/__tests__/session-abort-tool-results.test.ts +17 -2
  164. package/src/__tests__/session-agent-loop.test.ts +456 -35
  165. package/src/__tests__/session-confirmation-signals.test.ts +3 -2
  166. package/src/__tests__/session-conflict-gate.test.ts +20 -3
  167. package/src/__tests__/session-init.benchmark.test.ts +2 -2
  168. package/src/__tests__/session-load-history-repair.test.ts +7 -7
  169. package/src/__tests__/session-media-retry.test.ts +147 -0
  170. package/src/__tests__/session-pre-run-repair.test.ts +17 -2
  171. package/src/__tests__/session-profile-injection.test.ts +20 -3
  172. package/src/__tests__/session-provider-retry-repair.test.ts +86 -6
  173. package/src/__tests__/session-queue.test.ts +33 -18
  174. package/src/__tests__/session-runtime-assembly.test.ts +147 -1
  175. package/src/__tests__/session-runtime-workspace.test.ts +40 -0
  176. package/src/__tests__/session-slash-known.test.ts +21 -3
  177. package/src/__tests__/session-slash-queue.test.ts +17 -2
  178. package/src/__tests__/session-slash-unknown.test.ts +17 -2
  179. package/src/__tests__/session-surfaces-deselection.test.ts +208 -0
  180. package/src/__tests__/session-workspace-cache-state.test.ts +2 -2
  181. package/src/__tests__/session-workspace-injection.test.ts +17 -2
  182. package/src/__tests__/session-workspace-tool-tracking.test.ts +17 -2
  183. package/src/__tests__/shell-credential-ref.test.ts +1 -1
  184. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  185. package/src/__tests__/skill-feature-flags-integration.test.ts +9 -5
  186. package/src/__tests__/skill-feature-flags.test.ts +18 -12
  187. package/src/__tests__/skill-load-feature-flag.test.ts +5 -4
  188. package/src/__tests__/skill-load-tool.test.ts +1 -1
  189. package/src/__tests__/skill-script-runner-host.test.ts +1 -1
  190. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -1
  191. package/src/__tests__/skill-script-runner.test.ts +1 -1
  192. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  193. package/src/__tests__/slack-block-formatting.test.ts +100 -0
  194. package/src/__tests__/slack-inbound-verification.test.ts +346 -0
  195. package/src/__tests__/slack-reaction-approvals.test.ts +77 -0
  196. package/src/__tests__/slack-skill.test.ts +4 -2
  197. package/src/__tests__/starter-task-flow.test.ts +0 -1
  198. package/src/__tests__/subagent-tools.test.ts +3 -3
  199. package/src/__tests__/swarm-recursion.test.ts +1 -1
  200. package/src/__tests__/swarm-session-integration.test.ts +1 -1
  201. package/src/__tests__/swarm-tool.test.ts +1 -1
  202. package/src/__tests__/task-management-tools.test.ts +1 -1
  203. package/src/__tests__/task-tools.test.ts +1 -1
  204. package/src/__tests__/terminal-tools.test.ts +1 -1
  205. package/src/__tests__/test-support/browser-skill-harness.ts +39 -27
  206. package/src/__tests__/test-support/computer-use-skill-harness.ts +14 -14
  207. package/src/__tests__/tool-approval-handler.test.ts +15 -15
  208. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
  209. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  210. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  211. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  212. package/src/__tests__/tool-executor.test.ts +23 -182
  213. package/src/__tests__/tool-grant-request-escalation.test.ts +11 -11
  214. package/src/__tests__/tool-permission-simulate-handler.test.ts +4 -4
  215. package/src/__tests__/transfer-progress-screen.test.ts +1180 -0
  216. package/src/__tests__/trust-context-guards.test.ts +25 -29
  217. package/src/__tests__/trusted-contact-approval-notifier.test.ts +23 -21
  218. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +37 -40
  219. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +29 -25
  220. package/src/__tests__/trusted-contact-multichannel.test.ts +25 -24
  221. package/src/__tests__/trusted-contact-verification.test.ts +64 -76
  222. package/src/__tests__/turn-commit.test.ts +18 -18
  223. package/src/__tests__/twilio-provider.test.ts +7 -7
  224. package/src/__tests__/validation-results-screen.test.ts +1107 -0
  225. package/src/__tests__/view-image-tool.test.ts +1 -1
  226. package/src/__tests__/voice-invite-redemption.test.ts +4 -3
  227. package/src/__tests__/voice-scoped-grant-consumer.test.ts +12 -12
  228. package/src/__tests__/voice-session-bridge.test.ts +24 -24
  229. package/src/agent/attachments.ts +3 -1
  230. package/src/agent/loop.ts +13 -13
  231. package/src/agent/message-types.ts +13 -7
  232. package/src/amazon/cart.ts +59 -32
  233. package/src/amazon/checkout.ts +25 -14
  234. package/src/amazon/client.ts +61 -58
  235. package/src/amazon/product-details.ts +3 -3
  236. package/src/amazon/request-extractor.ts +46 -31
  237. package/src/amazon/search.ts +6 -4
  238. package/src/amazon/session.ts +33 -24
  239. package/src/approvals/AGENTS.md +26 -0
  240. package/src/approvals/approval-primitive.ts +87 -64
  241. package/src/approvals/guardian-decision-primitive.ts +172 -81
  242. package/src/approvals/guardian-request-resolvers.ts +262 -155
  243. package/src/autonomy/autonomy-resolver.ts +7 -5
  244. package/src/autonomy/autonomy-store.ts +34 -19
  245. package/src/autonomy/disposition-mapper.ts +5 -5
  246. package/src/autonomy/index.ts +6 -6
  247. package/src/autonomy/types.ts +7 -3
  248. package/src/browser-extension-relay/client.ts +50 -19
  249. package/src/browser-extension-relay/protocol.ts +11 -11
  250. package/src/browser-extension-relay/server.ts +45 -20
  251. package/src/bundler/app-bundler.ts +75 -50
  252. package/src/bundler/bundle-scanner.ts +145 -41
  253. package/src/bundler/bundle-signer.ts +16 -14
  254. package/src/bundler/signature-verifier.ts +36 -33
  255. package/src/calls/call-constants.ts +10 -3
  256. package/src/calls/call-controller.ts +473 -214
  257. package/src/calls/call-conversation-messages.ts +25 -15
  258. package/src/calls/call-domain.ts +401 -148
  259. package/src/calls/call-pointer-message-composer.ts +26 -21
  260. package/src/calls/call-pointer-messages.ts +52 -28
  261. package/src/calls/call-recovery.ts +53 -37
  262. package/src/calls/call-state-machine.ts +37 -7
  263. package/src/calls/call-state.ts +35 -13
  264. package/src/calls/call-store.ts +165 -77
  265. package/src/calls/elevenlabs-client.ts +39 -20
  266. package/src/calls/guardian-action-sweep.ts +42 -24
  267. package/src/calls/guardian-dispatch.ts +79 -56
  268. package/src/calls/guardian-question-copy.ts +28 -23
  269. package/src/calls/relay-server.ts +1149 -532
  270. package/src/calls/speaker-identification.ts +21 -15
  271. package/src/calls/twilio-config.ts +34 -17
  272. package/src/calls/twilio-provider.ts +108 -55
  273. package/src/calls/twilio-rest.ts +212 -100
  274. package/src/calls/twilio-routes.ts +165 -92
  275. package/src/calls/types.ts +55 -7
  276. package/src/calls/voice-quality.ts +6 -4
  277. package/src/calls/voice-session-bridge.ts +181 -133
  278. package/src/channels/config.ts +18 -14
  279. package/src/channels/types.ts +38 -10
  280. package/src/cli/amazon.ts +333 -227
  281. package/src/cli/config-commands.ts +236 -146
  282. package/src/cli/core-commands.ts +403 -329
  283. package/src/cli/email-guardrails.ts +38 -19
  284. package/src/cli/email.ts +207 -153
  285. package/src/cli/influencer.ts +58 -56
  286. package/src/cli/integrations.ts +306 -0
  287. package/src/cli/ipc-client.ts +24 -19
  288. package/src/cli/map.ts +176 -129
  289. package/src/cli/mcp.ts +260 -152
  290. package/src/cli/sequence.ts +165 -107
  291. package/src/cli/twitter.ts +302 -218
  292. package/src/cli.ts +418 -279
  293. package/src/commands/cc-command-registry.ts +52 -27
  294. package/src/config/agent-schema.ts +217 -134
  295. package/src/config/assistant-feature-flags.ts +23 -18
  296. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +19 -0
  297. package/src/config/bundled-skills/app-builder/SKILL.md +193 -1500
  298. package/src/config/bundled-skills/app-builder/TOOLS.json +70 -18
  299. package/src/config/bundled-skills/app-builder/tools/app-create.ts +7 -4
  300. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +6 -3
  301. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +7 -4
  302. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +6 -3
  303. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +6 -3
  304. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +7 -4
  305. package/src/config/bundled-skills/app-builder/tools/app-list.ts +6 -3
  306. package/src/config/bundled-skills/app-builder/tools/app-query.ts +6 -3
  307. package/src/config/bundled-skills/app-builder/tools/app-update.ts +6 -3
  308. package/src/config/bundled-skills/browser/TOOLS.json +59 -2
  309. package/src/config/bundled-skills/browser/tools/browser-click.ts +5 -2
  310. package/src/config/bundled-skills/browser/tools/browser-close.ts +5 -2
  311. package/src/config/bundled-skills/browser/tools/browser-extract.ts +5 -2
  312. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +5 -2
  313. package/src/config/bundled-skills/browser/tools/browser-hover.ts +5 -2
  314. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +5 -2
  315. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +5 -2
  316. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +5 -2
  317. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +5 -2
  318. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +5 -2
  319. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +5 -2
  320. package/src/config/bundled-skills/browser/tools/browser-type.ts +5 -2
  321. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +13 -6
  322. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +5 -2
  323. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +4 -0
  324. package/src/config/bundled-skills/claude-code/TOOLS.json +4 -0
  325. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +5 -2
  326. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  327. package/src/config/bundled-skills/computer-use/TOOLS.json +50 -2
  328. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +6 -3
  329. package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +6 -3
  330. package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +10 -3
  331. package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +6 -3
  332. package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +6 -3
  333. package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +6 -3
  334. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +10 -3
  335. package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +6 -3
  336. package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +10 -3
  337. package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +10 -3
  338. package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +6 -3
  339. package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +6 -3
  340. package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +6 -3
  341. package/src/config/bundled-skills/configure-settings/SKILL.md +28 -14
  342. package/src/config/bundled-skills/contacts/SKILL.md +453 -15
  343. package/src/config/bundled-skills/contacts/TOOLS.json +22 -2
  344. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +79 -20
  345. package/src/config/bundled-skills/contacts/tools/contact-search.ts +55 -18
  346. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +64 -19
  347. package/src/config/bundled-skills/document/TOOLS.json +8 -0
  348. package/src/config/bundled-skills/document/tools/document-create.ts +5 -2
  349. package/src/config/bundled-skills/document/tools/document-update.ts +5 -2
  350. package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -7
  351. package/src/config/bundled-skills/email-setup/SKILL.md +12 -9
  352. package/src/config/bundled-skills/followups/TOOLS.json +12 -0
  353. package/src/config/bundled-skills/followups/tools/followup-create.ts +5 -2
  354. package/src/config/bundled-skills/followups/tools/followup-list.ts +5 -2
  355. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +5 -2
  356. package/src/config/bundled-skills/google-calendar/TOOLS.json +124 -26
  357. package/src/config/bundled-skills/google-calendar/calendar-client.ts +44 -32
  358. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +11 -5
  359. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +13 -7
  360. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +11 -5
  361. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +13 -7
  362. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +28 -12
  363. package/src/config/bundled-skills/google-calendar/tools/shared.ts +6 -4
  364. package/src/config/bundled-skills/google-calendar/types.ts +3 -3
  365. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +88 -33
  366. package/src/config/bundled-skills/image-studio/TOOLS.json +12 -2
  367. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +48 -25
  368. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +13 -3
  369. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +60 -35
  370. package/src/config/bundled-skills/mcp-setup/SKILL.md +75 -0
  371. package/src/config/bundled-skills/media-processing/SKILL.md +55 -15
  372. package/src/config/bundled-skills/media-processing/TOOLS.json +48 -2
  373. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +12 -10
  374. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +34 -19
  375. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +82 -66
  376. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +148 -0
  377. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +1 -1
  378. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +8 -3
  379. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +117 -53
  380. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +273 -0
  381. package/src/config/bundled-skills/media-processing/services/preprocess.ts +185 -97
  382. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +32 -27
  383. package/src/config/bundled-skills/media-processing/services/reduce.ts +101 -24
  384. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +121 -55
  385. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +58 -24
  386. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +198 -92
  387. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +98 -70
  388. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +59 -19
  389. package/src/config/bundled-skills/media-processing/tools/media-status.ts +26 -10
  390. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +29 -14
  391. package/src/config/bundled-skills/messaging/SKILL.md +7 -5
  392. package/src/config/bundled-skills/messaging/TOOLS.json +232 -186
  393. package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +31 -13
  394. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +16 -10
  395. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +18 -9
  396. package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +23 -16
  397. package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +28 -12
  398. package/src/config/bundled-skills/messaging/tools/gmail-filters.ts +41 -21
  399. package/src/config/bundled-skills/messaging/tools/gmail-follow-up.ts +44 -23
  400. package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +73 -33
  401. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +15 -9
  402. package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +22 -14
  403. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +99 -50
  404. package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +14 -8
  405. package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +63 -44
  406. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +90 -46
  407. package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +43 -22
  408. package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +15 -9
  409. package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +51 -22
  410. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +62 -26
  411. package/src/config/bundled-skills/messaging/tools/gmail-vacation.ts +34 -19
  412. package/src/config/bundled-skills/messaging/tools/google-contacts.ts +32 -16
  413. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +10 -4
  414. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +91 -47
  415. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +21 -9
  416. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +9 -3
  417. package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +30 -17
  418. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +10 -4
  419. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +14 -6
  420. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +16 -5
  421. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +63 -36
  422. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +10 -4
  423. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +30 -12
  424. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +48 -29
  425. package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +20 -6
  426. package/src/config/bundled-skills/messaging/tools/send-notification.ts +1 -1
  427. package/src/config/bundled-skills/messaging/tools/sequence-analytics.ts +59 -22
  428. package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +13 -7
  429. package/src/config/bundled-skills/messaging/tools/sequence-create.ts +27 -12
  430. package/src/config/bundled-skills/messaging/tools/sequence-delete.ts +14 -6
  431. package/src/config/bundled-skills/messaging/tools/sequence-enroll.ts +30 -11
  432. package/src/config/bundled-skills/messaging/tools/sequence-enrollment-list.ts +16 -8
  433. package/src/config/bundled-skills/messaging/tools/sequence-get.ts +31 -13
  434. package/src/config/bundled-skills/messaging/tools/sequence-import.ts +38 -22
  435. package/src/config/bundled-skills/messaging/tools/sequence-list.ts +16 -7
  436. package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +29 -10
  437. package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +16 -8
  438. package/src/config/bundled-skills/messaging/tools/sequence-update.ts +35 -16
  439. package/src/config/bundled-skills/messaging/tools/shared.ts +26 -12
  440. package/src/config/bundled-skills/notifications/SKILL.md +3 -2
  441. package/src/config/bundled-skills/notifications/TOOLS.json +7 -13
  442. package/src/config/bundled-skills/notifications/tools/send-notification.ts +69 -34
  443. package/src/config/bundled-skills/notifications/tools/shared.ts +1 -1
  444. package/src/config/bundled-skills/phone-calls/SKILL.md +46 -48
  445. package/src/config/bundled-skills/phone-calls/TOOLS.json +13 -1
  446. package/src/config/bundled-skills/phone-calls/tools/call-end.ts +1 -1
  447. package/src/config/bundled-skills/phone-calls/tools/call-start.ts +1 -1
  448. package/src/config/bundled-skills/phone-calls/tools/call-status.ts +1 -1
  449. package/src/config/bundled-skills/playbooks/TOOLS.json +16 -0
  450. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +91 -51
  451. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +30 -16
  452. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +66 -27
  453. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +89 -42
  454. package/src/config/bundled-skills/public-ingress/SKILL.md +26 -19
  455. package/src/config/bundled-skills/reminder/TOOLS.json +15 -2
  456. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +5 -2
  457. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +5 -2
  458. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +5 -2
  459. package/src/config/bundled-skills/schedule/SKILL.md +33 -15
  460. package/src/config/bundled-skills/schedule/TOOLS.json +17 -1
  461. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +5 -2
  462. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +5 -2
  463. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +5 -2
  464. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +5 -2
  465. package/src/config/bundled-skills/screen-recording/SKILL.md +11 -3
  466. package/src/config/bundled-skills/self-upgrade/SKILL.md +9 -8
  467. package/src/config/bundled-skills/slack/SKILL.md +30 -1
  468. package/src/config/bundled-skills/slack/TOOLS.json +122 -17
  469. package/src/config/bundled-skills/slack/tools/shared.ts +7 -5
  470. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +11 -5
  471. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +11 -5
  472. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +146 -0
  473. package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +46 -16
  474. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +11 -5
  475. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +28 -0
  476. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +12 -6
  477. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +120 -0
  478. package/src/config/bundled-skills/slack-app-setup/SKILL.md +200 -0
  479. package/src/config/bundled-skills/sms-setup/SKILL.md +5 -8
  480. package/src/config/bundled-skills/subagent/TOOLS.json +22 -2
  481. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +5 -2
  482. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +5 -2
  483. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +5 -2
  484. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +5 -2
  485. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +5 -2
  486. package/src/config/bundled-skills/tasks/TOOLS.json +86 -14
  487. package/src/config/bundled-skills/tasks/tools/task-delete.ts +5 -2
  488. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +5 -2
  489. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +5 -2
  490. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +5 -2
  491. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +5 -2
  492. package/src/config/bundled-skills/tasks/tools/task-list.ts +5 -2
  493. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +5 -2
  494. package/src/config/bundled-skills/tasks/tools/task-run.ts +5 -2
  495. package/src/config/bundled-skills/tasks/tools/task-save.ts +5 -2
  496. package/src/config/bundled-skills/telegram-setup/SKILL.md +7 -8
  497. package/src/config/bundled-skills/transcribe/TOOLS.json +4 -0
  498. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +232 -127
  499. package/src/config/bundled-skills/twilio-setup/SKILL.md +7 -12
  500. package/src/config/bundled-skills/twitter/SKILL.md +19 -2
  501. package/src/config/bundled-skills/voice-setup/SKILL.md +5 -5
  502. package/src/config/bundled-skills/watcher/TOOLS.json +20 -0
  503. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +5 -2
  504. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +5 -2
  505. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +5 -2
  506. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +5 -2
  507. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +5 -2
  508. package/src/config/bundled-skills/weather/TOOLS.json +4 -0
  509. package/src/config/bundled-skills/weather/tools/get-weather.ts +5 -2
  510. package/src/config/bundled-tool-registry.ts +2 -0
  511. package/src/config/calls-schema.ts +108 -63
  512. package/src/config/channel-permission-profiles.ts +155 -0
  513. package/src/config/computer-use-prompt.ts +7 -7
  514. package/src/config/core-schema.ts +239 -155
  515. package/src/config/defaults.ts +2 -2
  516. package/src/config/elevenlabs-schema.ts +15 -15
  517. package/src/config/env-registry.ts +33 -33
  518. package/src/config/env.ts +4 -1
  519. package/src/config/feature-flag-registry.json +31 -7
  520. package/src/config/loader.ts +118 -58
  521. package/src/config/mcp-schema.ts +29 -15
  522. package/src/config/memory-schema.ts +434 -229
  523. package/src/config/notifications-schema.ts +4 -4
  524. package/src/config/sandbox-schema.ts +2 -2
  525. package/src/config/schema.ts +12 -2
  526. package/src/config/skill-state.ts +27 -15
  527. package/src/config/skills-schema.ts +72 -23
  528. package/src/config/skills.ts +303 -143
  529. package/src/config/system-prompt.ts +25 -6
  530. package/src/config/types.ts +1 -1
  531. package/src/config/update-bulletin-format.ts +3 -3
  532. package/src/config/update-bulletin-state.ts +15 -6
  533. package/src/config/update-bulletin-template-path.ts +8 -4
  534. package/src/config/update-bulletin.ts +33 -14
  535. package/src/config/user-reference.ts +8 -8
  536. package/src/contacts/contact-events.ts +21 -0
  537. package/src/contacts/contact-store.ts +813 -100
  538. package/src/contacts/contacts-write.ts +287 -0
  539. package/src/contacts/index.ts +13 -4
  540. package/src/contacts/startup-migration.ts +21 -0
  541. package/src/contacts/types.ts +73 -2
  542. package/src/context/token-estimator.ts +54 -31
  543. package/src/context/tool-result-truncation.ts +41 -7
  544. package/src/context/window-manager.ts +225 -120
  545. package/src/daemon/approval-generators.ts +83 -55
  546. package/src/daemon/approved-devices-store.ts +33 -20
  547. package/src/daemon/assistant-attachments.ts +157 -101
  548. package/src/daemon/auth-manager.ts +17 -15
  549. package/src/daemon/classifier.ts +117 -46
  550. package/src/daemon/computer-use-session.ts +316 -187
  551. package/src/daemon/config-watcher.ts +91 -44
  552. package/src/daemon/connection-policy.ts +18 -10
  553. package/src/daemon/context-overflow-approval.ts +48 -0
  554. package/src/daemon/context-overflow-policy.ts +50 -0
  555. package/src/daemon/context-overflow-reducer.ts +300 -0
  556. package/src/daemon/daemon-control.ts +79 -51
  557. package/src/daemon/date-context.ts +119 -69
  558. package/src/daemon/dictation-profile-store.ts +94 -48
  559. package/src/daemon/dictation-text-processing.ts +33 -12
  560. package/src/daemon/doordash-steps.ts +92 -49
  561. package/src/daemon/guardian-action-generators.ts +62 -46
  562. package/src/daemon/guardian-verification-intent.ts +35 -19
  563. package/src/daemon/handlers/apps.ts +258 -113
  564. package/src/daemon/handlers/avatar.ts +20 -15
  565. package/src/daemon/handlers/computer-use.ts +82 -39
  566. package/src/daemon/handlers/config-channels.ts +146 -69
  567. package/src/daemon/handlers/config-heartbeat.ts +114 -59
  568. package/src/daemon/handlers/config-inbox.ts +213 -160
  569. package/src/daemon/handlers/config-ingress.ts +127 -55
  570. package/src/daemon/handlers/config-integrations.ts +145 -88
  571. package/src/daemon/handlers/config-model.ts +58 -22
  572. package/src/daemon/handlers/config-platform.ts +40 -16
  573. package/src/daemon/handlers/config-scheduling.ts +109 -48
  574. package/src/daemon/handlers/config-slack-channel.ts +67 -35
  575. package/src/daemon/handlers/config-slack.ts +21 -20
  576. package/src/daemon/handlers/config-telegram.ts +100 -70
  577. package/src/daemon/handlers/config-tools.ts +103 -55
  578. package/src/daemon/handlers/config-trust.ts +50 -20
  579. package/src/daemon/handlers/config.ts +72 -24
  580. package/src/daemon/handlers/contacts.ts +163 -0
  581. package/src/daemon/handlers/diagnostics.ts +90 -48
  582. package/src/daemon/handlers/documents.ts +74 -46
  583. package/src/daemon/handlers/guardian-actions.ts +57 -77
  584. package/src/daemon/handlers/home-base.ts +19 -16
  585. package/src/daemon/handlers/identity.ts +65 -45
  586. package/src/daemon/handlers/index.ts +78 -54
  587. package/src/daemon/handlers/misc.ts +664 -234
  588. package/src/daemon/handlers/navigate-settings.ts +14 -11
  589. package/src/daemon/handlers/oauth-connect.ts +48 -35
  590. package/src/daemon/handlers/open-bundle-handler.ts +31 -24
  591. package/src/daemon/handlers/pairing.ts +51 -25
  592. package/src/daemon/handlers/publish.ts +55 -33
  593. package/src/daemon/handlers/recording.ts +378 -162
  594. package/src/daemon/handlers/sessions.ts +922 -423
  595. package/src/daemon/handlers/shared.ts +202 -117
  596. package/src/daemon/handlers/signing.ts +25 -6
  597. package/src/daemon/handlers/subagents.ts +117 -56
  598. package/src/daemon/handlers/twitter-auth.ts +70 -49
  599. package/src/daemon/handlers/work-items.ts +264 -112
  600. package/src/daemon/handlers/workspace-files.ts +27 -20
  601. package/src/daemon/handlers.ts +2 -2
  602. package/src/daemon/history-repair.ts +16 -15
  603. package/src/daemon/identity-helpers.ts +4 -4
  604. package/src/daemon/install-cli-launchers.ts +33 -22
  605. package/src/daemon/ipc-blob-store.ts +38 -24
  606. package/src/daemon/ipc-contract/apps.ts +61 -50
  607. package/src/daemon/ipc-contract/computer-use.ts +47 -37
  608. package/src/daemon/ipc-contract/contacts.ts +69 -0
  609. package/src/daemon/ipc-contract/diagnostics.ts +14 -14
  610. package/src/daemon/ipc-contract/documents.ts +8 -8
  611. package/src/daemon/ipc-contract/guardian-actions.ts +4 -4
  612. package/src/daemon/ipc-contract/inbox.ts +12 -71
  613. package/src/daemon/ipc-contract/integrations.ts +57 -44
  614. package/src/daemon/ipc-contract/memory.ts +3 -5
  615. package/src/daemon/ipc-contract/messages.ts +95 -69
  616. package/src/daemon/ipc-contract/notifications.ts +10 -6
  617. package/src/daemon/ipc-contract/pairing.ts +8 -8
  618. package/src/daemon/ipc-contract/schedules.ts +20 -20
  619. package/src/daemon/ipc-contract/sessions.ts +89 -57
  620. package/src/daemon/ipc-contract/settings.ts +12 -7
  621. package/src/daemon/ipc-contract/shared.ts +9 -7
  622. package/src/daemon/ipc-contract/skills.ts +46 -26
  623. package/src/daemon/ipc-contract/subagents.ts +9 -9
  624. package/src/daemon/ipc-contract/surfaces.ts +0 -1
  625. package/src/daemon/ipc-contract/trust.ts +11 -11
  626. package/src/daemon/ipc-contract/work-items.ts +33 -28
  627. package/src/daemon/ipc-contract/workspace.ts +28 -21
  628. package/src/daemon/ipc-contract-inventory.json +10 -4
  629. package/src/daemon/ipc-contract-inventory.ts +29 -26
  630. package/src/daemon/ipc-contract.ts +111 -44
  631. package/src/daemon/ipc-handler.ts +27 -19
  632. package/src/daemon/ipc-protocol.ts +22 -12
  633. package/src/daemon/ipc-validate.ts +91 -46
  634. package/src/daemon/lifecycle.ts +39 -3
  635. package/src/daemon/main.ts +10 -8
  636. package/src/daemon/media-visibility-policy.ts +3 -1
  637. package/src/daemon/pairing-store.ts +72 -40
  638. package/src/daemon/providers-setup.ts +35 -25
  639. package/src/daemon/recording-executor.ts +37 -30
  640. package/src/daemon/recording-intent-fallback.ts +58 -28
  641. package/src/daemon/recording-intent.ts +71 -61
  642. package/src/daemon/ride-shotgun-handler.ts +201 -121
  643. package/src/daemon/seed-files.ts +28 -17
  644. package/src/daemon/server.ts +23 -14
  645. package/src/daemon/session-agent-loop-handlers.ts +270 -135
  646. package/src/daemon/session-agent-loop.ts +796 -253
  647. package/src/daemon/session-attachments.ts +109 -40
  648. package/src/daemon/session-conflict-gate.ts +72 -28
  649. package/src/daemon/session-dynamic-profile.ts +36 -22
  650. package/src/daemon/session-error.ts +68 -45
  651. package/src/daemon/session-evictor.ts +17 -10
  652. package/src/daemon/session-history.ts +201 -89
  653. package/src/daemon/session-lifecycle.ts +80 -44
  654. package/src/daemon/session-media-retry.ts +104 -42
  655. package/src/daemon/session-memory.ts +77 -55
  656. package/src/daemon/session-messaging.ts +261 -111
  657. package/src/daemon/session-notifiers.ts +57 -45
  658. package/src/daemon/session-process.ts +370 -154
  659. package/src/daemon/session-queue-manager.ts +30 -13
  660. package/src/daemon/session-runtime-assembly.ts +61 -15
  661. package/src/daemon/session-skill-tools.ts +84 -36
  662. package/src/daemon/session-slash.ts +178 -113
  663. package/src/daemon/session-surfaces.ts +498 -212
  664. package/src/daemon/session-tool-setup.ts +24 -16
  665. package/src/daemon/session-usage.ts +26 -13
  666. package/src/daemon/session-workspace.ts +7 -4
  667. package/src/daemon/session.ts +18 -19
  668. package/src/daemon/shutdown-handlers.ts +36 -33
  669. package/src/daemon/tls-certs.ts +90 -57
  670. package/src/daemon/tool-side-effects.ts +97 -65
  671. package/src/daemon/trace-emitter.ts +8 -7
  672. package/src/daemon/video-thumbnail.ts +55 -25
  673. package/src/daemon/watch-handler.ts +164 -86
  674. package/src/email/provider.ts +1 -1
  675. package/src/email/providers/agentmail.ts +87 -45
  676. package/src/email/providers/index.ts +19 -14
  677. package/src/email/service.ts +52 -24
  678. package/src/email/types.ts +2 -2
  679. package/src/errors.ts +1 -1
  680. package/src/events/bus.ts +30 -10
  681. package/src/events/domain-events.ts +20 -13
  682. package/src/events/index.ts +6 -6
  683. package/src/events/tool-audit-listener.ts +34 -20
  684. package/src/events/tool-domain-event-publisher.ts +22 -20
  685. package/src/events/tool-metrics-listener.ts +26 -21
  686. package/src/events/tool-notification-listener.ts +5 -5
  687. package/src/events/tool-profiling-listener.ts +33 -23
  688. package/src/events/tool-trace-listener.ts +70 -46
  689. package/src/export/formatter.ts +38 -32
  690. package/src/followups/followup-store.ts +43 -36
  691. package/src/followups/index.ts +2 -2
  692. package/src/followups/types.ts +1 -1
  693. package/src/gallery/default-gallery.ts +37 -34
  694. package/src/gallery/gallery-manifest.ts +9 -9
  695. package/src/heartbeat/heartbeat-service.ts +59 -37
  696. package/src/home-base/app-link-store.ts +14 -12
  697. package/src/home-base/bootstrap.ts +14 -8
  698. package/src/home-base/prebuilt/seed.ts +34 -26
  699. package/src/home-base/prebuilt-home-base-updater.ts +14 -8
  700. package/src/hooks/cli.ts +56 -43
  701. package/src/hooks/config.ts +27 -14
  702. package/src/hooks/discovery.ts +53 -33
  703. package/src/hooks/manager.ts +50 -26
  704. package/src/hooks/runner.ts +35 -29
  705. package/src/hooks/templates.ts +38 -15
  706. package/src/hooks/types.ts +13 -13
  707. package/src/inbound/platform-callback-registration.ts +21 -15
  708. package/src/inbound/public-ingress-urls.ts +9 -6
  709. package/src/index.ts +20 -19
  710. package/src/influencer/client.ts +261 -117
  711. package/src/instrument.ts +3 -1
  712. package/src/logfire.ts +64 -39
  713. package/src/mcp/client.ts +107 -55
  714. package/src/mcp/manager.ts +45 -18
  715. package/src/mcp/mcp-oauth-provider.ts +114 -62
  716. package/src/media/gemini-image-service.ts +75 -23
  717. package/src/memory/account-store.ts +16 -9
  718. package/src/memory/admin.ts +87 -57
  719. package/src/memory/app-git-service.ts +77 -47
  720. package/src/memory/app-store.ts +148 -78
  721. package/src/memory/attachments-store.ts +123 -53
  722. package/src/memory/canonical-guardian-store.ts +190 -48
  723. package/src/memory/channel-delivery-store.ts +5 -5
  724. package/src/memory/channel-guardian-store.ts +31 -16
  725. package/src/memory/checkpoints.ts +14 -7
  726. package/src/memory/clarification-resolver.ts +219 -104
  727. package/src/memory/conflict-intent.ts +74 -23
  728. package/src/memory/conflict-policy.ts +20 -7
  729. package/src/memory/conflict-store.ts +144 -94
  730. package/src/memory/contradiction-checker.ts +257 -132
  731. package/src/memory/conversation-attention-store.ts +74 -32
  732. package/src/memory/conversation-bootstrap.ts +28 -0
  733. package/src/memory/conversation-crud.ts +12 -5
  734. package/src/memory/conversation-display-order-migration.ts +7 -7
  735. package/src/memory/conversation-key-store.ts +18 -13
  736. package/src/memory/conversation-queries.ts +130 -52
  737. package/src/memory/conversation-store.ts +43 -26
  738. package/src/memory/conversation-title-service.ts +89 -66
  739. package/src/memory/db-init.ts +94 -2
  740. package/src/memory/db.ts +10 -3
  741. package/src/memory/delivery-channels.ts +12 -6
  742. package/src/memory/delivery-crud.ts +26 -12
  743. package/src/memory/delivery-status.ts +19 -16
  744. package/src/memory/embedding-backend.ts +205 -77
  745. package/src/memory/embedding-gemini.ts +23 -10
  746. package/src/memory/embedding-local.ts +89 -44
  747. package/src/memory/embedding-ollama.ts +25 -13
  748. package/src/memory/embedding-openai.ts +20 -11
  749. package/src/memory/embedding-runtime-manager.ts +163 -90
  750. package/src/memory/entity-extractor.ts +185 -123
  751. package/src/memory/external-conversation-store.ts +30 -12
  752. package/src/memory/fingerprint.ts +2 -2
  753. package/src/memory/fts-reconciler.ts +57 -28
  754. package/src/memory/guardian-action-store.ts +162 -100
  755. package/src/memory/guardian-approvals.ts +63 -129
  756. package/src/memory/guardian-rate-limits.ts +20 -9
  757. package/src/memory/guardian-verification.ts +82 -35
  758. package/src/memory/indexer.ts +96 -55
  759. package/src/memory/{ingress-invite-store.ts → invite-store.ts} +28 -169
  760. package/src/memory/items-extractor.ts +313 -157
  761. package/src/memory/job-handlers/backfill.ts +116 -63
  762. package/src/memory/job-handlers/cleanup.ts +64 -41
  763. package/src/memory/job-handlers/conflict.ts +90 -49
  764. package/src/memory/job-handlers/embedding.ts +32 -17
  765. package/src/memory/job-handlers/extraction.ts +58 -33
  766. package/src/memory/job-handlers/index-maintenance.ts +31 -17
  767. package/src/memory/job-handlers/media-processing.ts +65 -24
  768. package/src/memory/job-handlers/summarization.ts +186 -128
  769. package/src/memory/job-utils.ts +100 -57
  770. package/src/memory/jobs-store.ts +235 -142
  771. package/src/memory/jobs-worker.ts +167 -83
  772. package/src/memory/llm-request-log-store.ts +13 -11
  773. package/src/memory/llm-usage-store.ts +35 -26
  774. package/src/memory/media-store.ts +151 -44
  775. package/src/memory/message-content.ts +28 -18
  776. package/src/memory/migrations/001-job-deferrals.ts +11 -5
  777. package/src/memory/migrations/002-tool-invocations-fk.ts +14 -6
  778. package/src/memory/migrations/003-memory-fts-backfill.ts +11 -5
  779. package/src/memory/migrations/004-entity-relation-dedup.ts +17 -11
  780. package/src/memory/migrations/005-fingerprint-scope-unique.ts +36 -21
  781. package/src/memory/migrations/006-scope-salted-fingerprints.ts +35 -20
  782. package/src/memory/migrations/007-assistant-id-to-self.ts +40 -27
  783. package/src/memory/migrations/008-remove-assistant-id-columns.ts +58 -36
  784. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +36 -22
  785. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +21 -11
  786. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +30 -15
  787. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +4 -2
  788. package/src/memory/migrations/013-guardian-action-tables.ts +29 -11
  789. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +35 -21
  790. package/src/memory/migrations/015-drop-active-search-index.ts +17 -11
  791. package/src/memory/migrations/016-memory-segments-indexes.ts +7 -3
  792. package/src/memory/migrations/017-memory-items-indexes.ts +4 -2
  793. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -5
  794. package/src/memory/migrations/019-notification-tables-schema-migration.ts +34 -20
  795. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +87 -53
  796. package/src/memory/migrations/021-conversation-status-indexes.ts +7 -3
  797. package/src/memory/migrations/022-add-origin-interface.ts +4 -2
  798. package/src/memory/migrations/023-memory-item-sources-indexes.ts +4 -2
  799. package/src/memory/migrations/024-embedding-vector-blob.ts +34 -18
  800. package/src/memory/migrations/025-messages-fts-backfill.ts +11 -5
  801. package/src/memory/migrations/026-guardian-verification-sessions.ts +80 -14
  802. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +42 -26
  803. package/src/memory/migrations/027-notification-delivery-pairing-columns.ts +22 -8
  804. package/src/memory/migrations/027a-guardian-bootstrap-token.ts +11 -3
  805. package/src/memory/migrations/028-call-session-mode.ts +13 -3
  806. package/src/memory/migrations/028-notification-delivery-client-ack.ts +22 -8
  807. package/src/memory/migrations/029-channel-inbound-delivered-segments.ts +7 -3
  808. package/src/memory/migrations/030-guardian-action-followup.ts +46 -8
  809. package/src/memory/migrations/030-guardian-verification-purpose.ts +4 -2
  810. package/src/memory/migrations/031-conversations-thread-type-index.ts +4 -2
  811. package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +4 -2
  812. package/src/memory/migrations/032-notification-delivery-thread-decision.ts +22 -8
  813. package/src/memory/migrations/033-scoped-approval-grants.ts +1 -1
  814. package/src/memory/migrations/034-guardian-action-tool-metadata.ts +15 -3
  815. package/src/memory/migrations/035-guardian-action-supersession.ts +15 -3
  816. package/src/memory/migrations/036-normalize-phone-identities.ts +101 -87
  817. package/src/memory/migrations/037-voice-invite-columns.ts +22 -4
  818. package/src/memory/migrations/038-actor-token-records.ts +5 -9
  819. package/src/memory/migrations/039-actor-refresh-token-records.ts +7 -13
  820. package/src/memory/migrations/100-core-tables.ts +1 -1
  821. package/src/memory/migrations/101-watchers-and-logs.ts +1 -1
  822. package/src/memory/migrations/103-complex-migrations.ts +9 -9
  823. package/src/memory/migrations/104-core-indexes.ts +188 -64
  824. package/src/memory/migrations/105-contacts-and-triage.ts +28 -10
  825. package/src/memory/migrations/106-call-sessions.ts +58 -16
  826. package/src/memory/migrations/107-followups.ts +16 -6
  827. package/src/memory/migrations/108-tasks-and-work-items.ts +43 -11
  828. package/src/memory/migrations/109-external-conversation-bindings.ts +11 -5
  829. package/src/memory/migrations/110-channel-guardian.ts +48 -10
  830. package/src/memory/migrations/111-media-assets.ts +52 -18
  831. package/src/memory/migrations/112-assistant-inbox.ts +32 -12
  832. package/src/memory/migrations/113-late-migrations.ts +12 -12
  833. package/src/memory/migrations/114-notifications.ts +28 -12
  834. package/src/memory/migrations/115-sequences.ts +10 -4
  835. package/src/memory/migrations/116-messages-fts.ts +1 -1
  836. package/src/memory/migrations/117-conversation-attention.ts +16 -6
  837. package/src/memory/migrations/118-reminder-routing-intent.ts +7 -3
  838. package/src/memory/migrations/119-schema-indexes-and-columns.ts +35 -15
  839. package/src/memory/migrations/120-fk-cascade-rebuilds.ts +36 -17
  840. package/src/memory/migrations/121-canonical-guardian-requests.ts +25 -9
  841. package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +11 -3
  842. package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +4 -2
  843. package/src/memory/migrations/124-voice-invite-display-metadata.ts +15 -3
  844. package/src/memory/migrations/125-guardian-principal-id-columns.ts +22 -4
  845. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +174 -126
  846. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +58 -42
  847. package/src/memory/migrations/128-contacts-role-principal.ts +26 -0
  848. package/src/memory/migrations/129-contact-channels-access-fields.ts +105 -0
  849. package/src/memory/migrations/130-contact-channels-type-ext-chat-id-index.ts +15 -0
  850. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +134 -0
  851. package/src/memory/migrations/132-contacts-assistant-id.ts +21 -0
  852. package/src/memory/migrations/133-assistant-contact-metadata.ts +21 -0
  853. package/src/memory/migrations/index.ts +83 -73
  854. package/src/memory/migrations/registry.ts +53 -37
  855. package/src/memory/migrations/validate-migration-state.ts +73 -46
  856. package/src/memory/profile-compiler.ts +58 -24
  857. package/src/memory/published-pages-store.ts +12 -16
  858. package/src/memory/qdrant-circuit-breaker.ts +28 -20
  859. package/src/memory/qdrant-client.ts +99 -63
  860. package/src/memory/qdrant-manager.ts +89 -57
  861. package/src/memory/query-builder.ts +9 -7
  862. package/src/memory/raw-query.ts +63 -14
  863. package/src/memory/recall-cache.ts +15 -8
  864. package/src/memory/retrieval-budget.ts +0 -1
  865. package/src/memory/retriever.ts +385 -192
  866. package/src/memory/schema-migration.ts +1 -1
  867. package/src/memory/schema.ts +56 -56
  868. package/src/memory/scoped-approval-grants.ts +99 -45
  869. package/src/memory/search/entity.ts +102 -40
  870. package/src/memory/search/formatting.ts +70 -52
  871. package/src/memory/search/lexical.ts +82 -43
  872. package/src/memory/search/ranking.ts +103 -39
  873. package/src/memory/search/semantic.ts +59 -35
  874. package/src/memory/search/types.ts +8 -8
  875. package/src/memory/segmenter.ts +20 -12
  876. package/src/memory/shared-app-links-store.ts +21 -16
  877. package/src/memory/slack-thread-store.ts +187 -0
  878. package/src/memory/task-memory-cleanup.ts +18 -8
  879. package/src/memory/tool-usage-store.ts +27 -19
  880. package/src/memory/validation.ts +4 -2
  881. package/src/messaging/activity-analyzer.ts +7 -7
  882. package/src/messaging/draft-store.ts +13 -10
  883. package/src/messaging/email-classifier.ts +73 -37
  884. package/src/messaging/index.ts +3 -3
  885. package/src/messaging/outreach-classifier.ts +76 -38
  886. package/src/messaging/provider-types.ts +2 -4
  887. package/src/messaging/provider.ts +37 -8
  888. package/src/messaging/providers/gmail/adapter.ts +183 -66
  889. package/src/messaging/providers/gmail/client.ts +3 -1
  890. package/src/messaging/providers/gmail/mime-builder.ts +21 -19
  891. package/src/messaging/providers/gmail/people-client.ts +22 -9
  892. package/src/messaging/providers/gmail/types.ts +6 -6
  893. package/src/messaging/providers/slack/adapter.ts +93 -43
  894. package/src/messaging/providers/slack/client.ts +165 -48
  895. package/src/messaging/providers/slack/types.ts +10 -0
  896. package/src/messaging/providers/sms/adapter.ts +76 -40
  897. package/src/messaging/providers/sms/client.ts +4 -4
  898. package/src/messaging/providers/telegram-bot/adapter.ts +52 -30
  899. package/src/messaging/providers/telegram-bot/client.ts +7 -7
  900. package/src/messaging/providers/whatsapp/adapter.ts +58 -31
  901. package/src/messaging/providers/whatsapp/client.ts +4 -4
  902. package/src/messaging/registry.ts +9 -5
  903. package/src/messaging/style-analyzer.ts +69 -39
  904. package/src/messaging/thread-summarizer.ts +101 -53
  905. package/src/messaging/triage-engine.ts +111 -82
  906. package/src/messaging/types.ts +10 -10
  907. package/src/migrations/config-merge.ts +18 -10
  908. package/src/migrations/data-layout.ts +35 -22
  909. package/src/migrations/data-merge.ts +17 -7
  910. package/src/migrations/hooks-merge.ts +43 -16
  911. package/src/migrations/index.ts +6 -6
  912. package/src/migrations/log.ts +9 -5
  913. package/src/migrations/skills-merge.ts +17 -7
  914. package/src/migrations/workspace-layout.ts +39 -25
  915. package/src/notifications/AGENTS.md +5 -0
  916. package/src/notifications/adapters/macos.ts +21 -14
  917. package/src/notifications/adapters/slack.ts +90 -0
  918. package/src/notifications/adapters/sms.ts +28 -15
  919. package/src/notifications/adapters/telegram.ts +24 -15
  920. package/src/notifications/broadcaster.ts +108 -52
  921. package/src/notifications/conversation-pairing.ts +64 -29
  922. package/src/notifications/copy-composer.ts +165 -95
  923. package/src/notifications/decision-engine.ts +353 -147
  924. package/src/notifications/decisions-store.ts +26 -10
  925. package/src/notifications/deliveries-store.ts +23 -13
  926. package/src/notifications/destination-resolver.ts +83 -24
  927. package/src/notifications/deterministic-checks.ts +78 -27
  928. package/src/notifications/emit-signal.ts +95 -41
  929. package/src/notifications/events-store.ts +13 -7
  930. package/src/notifications/guardian-question-mode.ts +125 -75
  931. package/src/notifications/preference-extractor.ts +85 -53
  932. package/src/notifications/preference-summary.ts +31 -18
  933. package/src/notifications/preferences-store.ts +29 -18
  934. package/src/notifications/runtime-dispatch.ts +22 -12
  935. package/src/notifications/signal.ts +4 -4
  936. package/src/notifications/thread-candidates.ts +59 -23
  937. package/src/notifications/thread-seed-composer.ts +45 -27
  938. package/src/notifications/types.ts +19 -10
  939. package/src/oauth/connect-orchestrator.ts +105 -54
  940. package/src/oauth/connect-types.ts +3 -3
  941. package/src/oauth/provider-profiles.ts +102 -59
  942. package/src/oauth/scope-policy.ts +5 -2
  943. package/src/oauth/token-persistence.ts +58 -24
  944. package/src/outbound-proxy/certs.ts +284 -0
  945. package/src/outbound-proxy/config.ts +94 -0
  946. package/src/outbound-proxy/connect-tunnel.ts +84 -0
  947. package/src/outbound-proxy/health.ts +62 -0
  948. package/src/outbound-proxy/host-pattern-match.ts +67 -0
  949. package/src/outbound-proxy/http-forwarder.ts +162 -0
  950. package/src/outbound-proxy/index.ts +80 -0
  951. package/src/outbound-proxy/logging.ts +193 -0
  952. package/src/outbound-proxy/mitm-handler.ts +292 -0
  953. package/src/outbound-proxy/policy.ts +172 -0
  954. package/src/outbound-proxy/router.ts +64 -0
  955. package/src/outbound-proxy/server.ts +145 -0
  956. package/src/outbound-proxy/types.ts +150 -0
  957. package/src/permissions/checker.ts +481 -189
  958. package/src/permissions/defaults.ts +135 -108
  959. package/src/permissions/prompter.ts +53 -27
  960. package/src/permissions/secret-prompter.ts +21 -15
  961. package/src/permissions/shell-identity.ts +47 -16
  962. package/src/permissions/trust-store.ts +185 -73
  963. package/src/permissions/types.ts +22 -12
  964. package/src/permissions/workspace-policy.ts +47 -38
  965. package/src/playbooks/index.ts +10 -2
  966. package/src/playbooks/playbook-compiler.ts +30 -24
  967. package/src/playbooks/types.ts +11 -8
  968. package/src/providers/anthropic/client.ts +328 -168
  969. package/src/providers/failover.ts +57 -22
  970. package/src/providers/fireworks/client.ts +9 -5
  971. package/src/providers/gemini/client.ts +61 -39
  972. package/src/providers/model-intents.ts +40 -33
  973. package/src/providers/ollama/client.ts +7 -7
  974. package/src/providers/openai/client.ts +109 -68
  975. package/src/providers/openrouter/client.ts +9 -5
  976. package/src/providers/provider-send-message.ts +59 -27
  977. package/src/providers/ratelimit.ts +25 -8
  978. package/src/providers/registry.ts +86 -38
  979. package/src/providers/retry.ts +93 -37
  980. package/src/providers/stream-timeout.ts +5 -3
  981. package/src/providers/types.ts +7 -6
  982. package/src/runtime/AGENTS.md +42 -0
  983. package/src/runtime/access-request-helper.ts +118 -68
  984. package/src/runtime/actor-refresh-token-store.ts +21 -16
  985. package/src/runtime/actor-token-store.ts +25 -18
  986. package/src/runtime/actor-trust-resolver.ts +191 -80
  987. package/src/runtime/approval-conversation-turn.ts +39 -26
  988. package/src/runtime/approval-message-composer.ts +116 -84
  989. package/src/runtime/assistant-event-hub.ts +25 -6
  990. package/src/runtime/assistant-event.ts +4 -4
  991. package/src/runtime/assistant-scope.ts +1 -1
  992. package/src/runtime/auth/__tests__/guard-tests.test.ts +36 -14
  993. package/src/runtime/auth/context.ts +8 -7
  994. package/src/runtime/auth/credential-service.ts +60 -38
  995. package/src/runtime/auth/external-assistant-id.ts +16 -8
  996. package/src/runtime/auth/index.ts +23 -16
  997. package/src/runtime/auth/require-bound-guardian.ts +44 -0
  998. package/src/runtime/auth/route-policy.ts +166 -104
  999. package/src/runtime/auth/scopes.ts +22 -29
  1000. package/src/runtime/auth/subject.ts +19 -13
  1001. package/src/runtime/auth/token-service.ts +3 -3
  1002. package/src/runtime/auth/types.ts +23 -23
  1003. package/src/runtime/channel-approval-parser.ts +37 -14
  1004. package/src/runtime/channel-approval-types.ts +30 -4
  1005. package/src/runtime/channel-approvals.ts +49 -23
  1006. package/src/runtime/channel-guardian-service.ts +144 -103
  1007. package/src/runtime/channel-invite-transport.ts +5 -3
  1008. package/src/runtime/channel-invite-transports/telegram.ts +16 -10
  1009. package/src/runtime/channel-invite-transports/voice.ts +7 -7
  1010. package/src/runtime/channel-readiness-service.ts +139 -90
  1011. package/src/runtime/channel-readiness-types.ts +4 -2
  1012. package/src/runtime/channel-reply-delivery.ts +83 -14
  1013. package/src/runtime/channel-retry-sweep.ts +111 -62
  1014. package/src/runtime/confirmation-request-guardian-bridge.ts +73 -54
  1015. package/src/runtime/gateway-client.ts +122 -55
  1016. package/src/runtime/gateway-internal-client.ts +86 -0
  1017. package/src/runtime/guardian-action-conversation-turn.ts +34 -18
  1018. package/src/runtime/guardian-action-followup-executor.ts +115 -45
  1019. package/src/runtime/guardian-action-grant-minter.ts +40 -24
  1020. package/src/runtime/guardian-action-message-composer.ts +105 -84
  1021. package/src/runtime/guardian-action-service.ts +127 -0
  1022. package/src/runtime/guardian-decision-types.ts +28 -13
  1023. package/src/runtime/guardian-outbound-actions.ts +9 -0
  1024. package/src/runtime/guardian-reply-router.ts +274 -145
  1025. package/src/runtime/guardian-vellum-migration.ts +38 -24
  1026. package/src/runtime/guardian-verification-templates.ts +24 -12
  1027. package/src/runtime/http-router.ts +175 -0
  1028. package/src/runtime/http-server.ts +913 -680
  1029. package/src/runtime/http-types.ts +2 -2
  1030. package/src/runtime/invite-redemption-service.ts +211 -134
  1031. package/src/runtime/invite-redemption-templates.ts +18 -11
  1032. package/src/runtime/{ingress-service.ts → invite-service.ts} +92 -151
  1033. package/src/runtime/local-actor-identity.ts +73 -55
  1034. package/src/runtime/middleware/auth.ts +25 -14
  1035. package/src/runtime/middleware/error-handler.ts +15 -11
  1036. package/src/runtime/middleware/rate-limiter.ts +23 -17
  1037. package/src/runtime/middleware/request-logger.ts +4 -4
  1038. package/src/runtime/middleware/twilio-validation.ts +29 -20
  1039. package/src/runtime/migrations/migration-transport.ts +575 -0
  1040. package/src/runtime/migrations/migration-wizard.ts +715 -0
  1041. package/src/runtime/migrations/rebind-secrets-screen.ts +351 -0
  1042. package/src/runtime/migrations/transfer-progress-screen.ts +321 -0
  1043. package/src/runtime/migrations/validation-results-screen.ts +467 -0
  1044. package/src/runtime/migrations/vbundle-builder.ts +295 -0
  1045. package/src/runtime/migrations/vbundle-import-analyzer.ts +212 -0
  1046. package/src/runtime/migrations/vbundle-importer.ts +339 -0
  1047. package/src/runtime/migrations/vbundle-validator.ts +356 -0
  1048. package/src/runtime/nl-approval-parser.ts +138 -0
  1049. package/src/runtime/pending-interactions.ts +16 -7
  1050. package/src/runtime/routes/access-request-decision.ts +73 -52
  1051. package/src/runtime/routes/app-routes.ts +56 -38
  1052. package/src/runtime/routes/approval-routes.ts +144 -92
  1053. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +930 -0
  1054. package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +82 -0
  1055. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +151 -0
  1056. package/src/runtime/routes/attachment-routes.ts +59 -48
  1057. package/src/runtime/routes/brain-graph-routes.ts +85 -69
  1058. package/src/runtime/routes/call-routes.ts +79 -38
  1059. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +10 -10
  1060. package/src/runtime/routes/channel-delivery-routes.ts +19 -14
  1061. package/src/runtime/routes/channel-guardian-routes.ts +3 -3
  1062. package/src/runtime/routes/channel-inbound-routes.ts +2 -2
  1063. package/src/runtime/routes/channel-readiness-routes.ts +12 -6
  1064. package/src/runtime/routes/channel-route-shared.ts +67 -25
  1065. package/src/runtime/routes/channel-routes.ts +4 -6
  1066. package/src/runtime/routes/contact-routes.ts +374 -17
  1067. package/src/runtime/routes/conversation-attention-routes.ts +57 -28
  1068. package/src/runtime/routes/conversation-routes.ts +321 -174
  1069. package/src/runtime/routes/debug-routes.ts +14 -10
  1070. package/src/runtime/routes/events-routes.ts +90 -57
  1071. package/src/runtime/routes/global-search-routes.ts +266 -0
  1072. package/src/runtime/routes/guardian-action-routes.ts +112 -113
  1073. package/src/runtime/routes/guardian-approval-interception.ts +325 -874
  1074. package/src/runtime/routes/guardian-approval-prompt.ts +40 -24
  1075. package/src/runtime/routes/guardian-approval-reply-helpers.ts +135 -0
  1076. package/src/runtime/routes/guardian-bootstrap-routes.ts +55 -36
  1077. package/src/runtime/routes/guardian-expiry-sweep.ts +63 -37
  1078. package/src/runtime/routes/guardian-refresh-routes.ts +40 -19
  1079. package/src/runtime/routes/identity-routes.ts +71 -42
  1080. package/src/runtime/routes/inbound-conversation.ts +17 -11
  1081. package/src/runtime/routes/inbound-message-handler.ts +305 -1459
  1082. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +880 -0
  1083. package/src/runtime/routes/inbound-stages/background-dispatch.ts +600 -0
  1084. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +214 -0
  1085. package/src/runtime/routes/inbound-stages/edit-intercept.ts +116 -0
  1086. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +167 -0
  1087. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +185 -0
  1088. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +132 -0
  1089. package/src/runtime/routes/inbound-stages/verification-intercept.ts +340 -0
  1090. package/src/runtime/routes/integration-routes.ts +60 -21
  1091. package/src/runtime/routes/invite-routes.ts +140 -0
  1092. package/src/runtime/routes/migration-routes.ts +434 -0
  1093. package/src/runtime/routes/pairing-routes.ts +157 -79
  1094. package/src/runtime/routes/secret-routes.ts +6 -2
  1095. package/src/runtime/routes/twilio-routes.ts +443 -249
  1096. package/src/runtime/slack-block-formatting.ts +176 -0
  1097. package/src/runtime/tool-grant-request-helper.ts +36 -27
  1098. package/src/runtime/{guardian-context-resolver.ts → trust-context-resolver.ts} +29 -41
  1099. package/src/schedule/integration-status.ts +44 -9
  1100. package/src/schedule/recurrence-engine.ts +47 -24
  1101. package/src/schedule/recurrence-types.ts +12 -7
  1102. package/src/schedule/schedule-store.ts +166 -83
  1103. package/src/schedule/scheduler.ts +37 -24
  1104. package/src/security/encrypted-store.ts +68 -38
  1105. package/src/security/keychain.ts +183 -120
  1106. package/src/security/oauth-callback-registry.ts +3 -3
  1107. package/src/security/oauth2.ts +226 -138
  1108. package/src/security/redaction.ts +24 -24
  1109. package/src/security/secret-allowlist.ts +46 -21
  1110. package/src/security/secret-ingress.ts +15 -7
  1111. package/src/security/secret-scanner.ts +193 -104
  1112. package/src/security/secure-keys.ts +9 -3
  1113. package/src/security/token-manager.ts +99 -40
  1114. package/src/security/tool-approval-digest.ts +3 -3
  1115. package/src/sequence/analytics.ts +52 -27
  1116. package/src/sequence/engine.ts +135 -72
  1117. package/src/sequence/guardrails.ts +32 -20
  1118. package/src/sequence/importer.ts +75 -37
  1119. package/src/sequence/reply-matcher.ts +36 -18
  1120. package/src/sequence/store.ts +137 -75
  1121. package/src/sequence/types.ts +30 -16
  1122. package/src/services/published-app-updater.ts +26 -16
  1123. package/src/services/vercel-deploy.ts +19 -15
  1124. package/src/skills/active-skill-tools.ts +3 -3
  1125. package/src/skills/clawhub.ts +178 -90
  1126. package/src/skills/include-graph.ts +24 -17
  1127. package/src/skills/managed-store.ts +89 -42
  1128. package/src/skills/path-classifier.ts +10 -10
  1129. package/src/skills/remote-skill-policy.ts +31 -22
  1130. package/src/skills/slash-commands.ts +36 -30
  1131. package/src/skills/tool-manifest.ts +60 -31
  1132. package/src/skills/version-hash.ts +25 -15
  1133. package/src/slack/slack-webhook.ts +19 -15
  1134. package/src/subagent/index.ts +4 -8
  1135. package/src/subagent/manager.ts +119 -69
  1136. package/src/subagent/types.ts +9 -12
  1137. package/src/swarm/backend-claude-code.ts +124 -45
  1138. package/src/swarm/checkpoint.ts +36 -16
  1139. package/src/swarm/graph-utils.ts +1 -3
  1140. package/src/swarm/index.ts +38 -19
  1141. package/src/swarm/limits.ts +13 -4
  1142. package/src/swarm/orchestrator.ts +108 -57
  1143. package/src/swarm/plan-validator.ts +23 -17
  1144. package/src/swarm/router-planner.ts +51 -22
  1145. package/src/swarm/router-prompts.ts +4 -1
  1146. package/src/swarm/synthesizer.ts +26 -18
  1147. package/src/swarm/types.ts +14 -4
  1148. package/src/swarm/worker-backend.ts +36 -26
  1149. package/src/swarm/worker-prompts.ts +13 -9
  1150. package/src/swarm/worker-runner.ts +40 -34
  1151. package/src/tasks/candidate-store.ts +14 -6
  1152. package/src/tasks/ephemeral-permissions.ts +9 -5
  1153. package/src/tasks/task-compiler.ts +41 -38
  1154. package/src/tasks/task-runner.ts +54 -26
  1155. package/src/tasks/task-scheduler.ts +1 -1
  1156. package/src/tasks/task-store.ts +20 -7
  1157. package/src/tasks/tool-sanitizer.ts +3 -3
  1158. package/src/tools/apps/definitions.ts +23 -15
  1159. package/src/tools/apps/executors.ts +122 -40
  1160. package/src/tools/apps/open-proxy.ts +5 -5
  1161. package/src/tools/apps/registry.ts +2 -2
  1162. package/src/tools/assets/materialize.ts +59 -41
  1163. package/src/tools/assets/search.ts +86 -48
  1164. package/src/tools/browser/api-map.ts +52 -36
  1165. package/src/tools/browser/auth-cache.ts +21 -18
  1166. package/src/tools/browser/auth-detector.ts +43 -28
  1167. package/src/tools/browser/auto-navigate.ts +149 -68
  1168. package/src/tools/browser/browser-execution.ts +9 -3
  1169. package/src/tools/browser/headless-browser.ts +287 -150
  1170. package/src/tools/browser/jit-auth.ts +37 -21
  1171. package/src/tools/browser/network-recorder.ts +138 -56
  1172. package/src/tools/browser/recording-store.ts +22 -15
  1173. package/src/tools/browser/runtime-check.ts +8 -5
  1174. package/src/tools/browser/x-auto-navigate.ts +88 -47
  1175. package/src/tools/calls/call-end.ts +10 -7
  1176. package/src/tools/calls/call-start.ts +30 -20
  1177. package/src/tools/calls/call-status.ts +8 -5
  1178. package/src/tools/claude-code/claude-code.ts +301 -165
  1179. package/src/tools/computer-use/definitions.ts +175 -130
  1180. package/src/tools/computer-use/registry.ts +2 -2
  1181. package/src/tools/computer-use/request-computer-control.ts +21 -13
  1182. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  1183. package/src/tools/credentials/account-registry.ts +52 -35
  1184. package/src/tools/credentials/broker-types.ts +1 -1
  1185. package/src/tools/credentials/broker.ts +97 -55
  1186. package/src/tools/credentials/domain-policy.ts +5 -2
  1187. package/src/tools/credentials/host-pattern-match.ts +15 -8
  1188. package/src/tools/credentials/metadata-store.ts +93 -43
  1189. package/src/tools/credentials/policy-types.ts +5 -2
  1190. package/src/tools/credentials/policy-validate.ts +21 -14
  1191. package/src/tools/credentials/post-connect-hooks.ts +18 -7
  1192. package/src/tools/credentials/resolve.ts +11 -10
  1193. package/src/tools/credentials/selection.ts +30 -25
  1194. package/src/tools/credentials/tool-policy.ts +5 -2
  1195. package/src/tools/credentials/vault.ts +538 -185
  1196. package/src/tools/document/document-tool.ts +23 -17
  1197. package/src/tools/document/editor-template.ts +12 -7
  1198. package/src/tools/execution-target.ts +13 -10
  1199. package/src/tools/execution-timeout.ts +6 -5
  1200. package/src/tools/executor.ts +141 -74
  1201. package/src/tools/filesystem/edit.ts +82 -45
  1202. package/src/tools/filesystem/fuzzy-match.ts +70 -32
  1203. package/src/tools/filesystem/read.ts +46 -28
  1204. package/src/tools/filesystem/view-image.ts +86 -42
  1205. package/src/tools/filesystem/write.ts +53 -32
  1206. package/src/tools/followups/followup_create.ts +43 -17
  1207. package/src/tools/followups/followup_list.ts +28 -13
  1208. package/src/tools/followups/followup_resolve.ts +9 -6
  1209. package/src/tools/guardian-control-plane-policy.ts +15 -14
  1210. package/src/tools/host-filesystem/edit.ts +77 -42
  1211. package/src/tools/host-filesystem/read.ts +52 -33
  1212. package/src/tools/host-filesystem/write.ts +50 -29
  1213. package/src/tools/host-terminal/host-shell.ts +97 -61
  1214. package/src/tools/mcp/mcp-tool-factory.ts +21 -14
  1215. package/src/tools/memory/definitions.ts +60 -28
  1216. package/src/tools/memory/handlers.ts +149 -77
  1217. package/src/tools/memory/register.ts +39 -16
  1218. package/src/tools/network/__tests__/web-search.test.ts +236 -177
  1219. package/src/tools/network/domain-normalize.ts +13 -9
  1220. package/src/tools/network/script-proxy/__tests__/logging.test.ts +193 -123
  1221. package/src/tools/network/script-proxy/__tests__/policy.test.ts +225 -127
  1222. package/src/tools/network/script-proxy/index.ts +1 -17
  1223. package/src/tools/network/script-proxy/session-manager.ts +178 -86
  1224. package/src/tools/network/url-safety.ts +56 -34
  1225. package/src/tools/network/web-fetch.ts +273 -155
  1226. package/src/tools/network/web-search.ts +166 -81
  1227. package/src/tools/permission-checker.ts +24 -25
  1228. package/src/tools/policy-context.ts +8 -5
  1229. package/src/tools/registry.ts +73 -46
  1230. package/src/tools/reminder/reminder-store.ts +65 -44
  1231. package/src/tools/reminder/reminder.ts +76 -35
  1232. package/src/tools/schedule/create.ts +44 -21
  1233. package/src/tools/schedule/delete.ts +8 -5
  1234. package/src/tools/schedule/list.ts +39 -19
  1235. package/src/tools/schedule/update.ts +49 -26
  1236. package/src/tools/secret-detection-handler.ts +130 -49
  1237. package/src/tools/sensitive-output-placeholders.ts +15 -8
  1238. package/src/tools/shared/filesystem/edit-engine.ts +45 -14
  1239. package/src/tools/shared/filesystem/errors.ts +18 -18
  1240. package/src/tools/shared/filesystem/file-ops-service.ts +59 -32
  1241. package/src/tools/shared/filesystem/format-diff.ts +21 -11
  1242. package/src/tools/shared/filesystem/path-policy.ts +17 -13
  1243. package/src/tools/shared/filesystem/size-guard.ts +8 -4
  1244. package/src/tools/shared/filesystem/types.ts +2 -2
  1245. package/src/tools/shared/shell-output.ts +4 -3
  1246. package/src/tools/side-effects.ts +36 -28
  1247. package/src/tools/skills/delete-managed.ts +30 -17
  1248. package/src/tools/skills/load.ts +88 -46
  1249. package/src/tools/skills/sandbox-runner.ts +62 -46
  1250. package/src/tools/skills/scaffold-managed.ts +98 -48
  1251. package/src/tools/skills/script-contract.ts +5 -2
  1252. package/src/tools/skills/skill-script-runner.ts +29 -13
  1253. package/src/tools/skills/skill-tool-factory.ts +20 -10
  1254. package/src/tools/subagent/abort.ts +10 -4
  1255. package/src/tools/subagent/message.ts +14 -8
  1256. package/src/tools/subagent/read.ts +20 -11
  1257. package/src/tools/subagent/spawn.ts +14 -6
  1258. package/src/tools/subagent/status.ts +7 -4
  1259. package/src/tools/swarm/delegate.ts +75 -49
  1260. package/src/tools/system/avatar-generator.ts +46 -33
  1261. package/src/tools/system/navigate-settings.ts +29 -19
  1262. package/src/tools/system/open-system-settings.ts +30 -20
  1263. package/src/tools/system/request-permission.ts +59 -44
  1264. package/src/tools/system/version.ts +27 -16
  1265. package/src/tools/system/voice-config.ts +116 -53
  1266. package/src/tools/tasks/index.ts +8 -8
  1267. package/src/tools/tasks/task-delete.ts +61 -22
  1268. package/src/tools/tasks/task-list.ts +23 -11
  1269. package/src/tools/tasks/task-run.ts +41 -16
  1270. package/src/tools/tasks/task-save.ts +27 -10
  1271. package/src/tools/tasks/work-item-enqueue.ts +114 -48
  1272. package/src/tools/tasks/work-item-list.ts +20 -10
  1273. package/src/tools/tasks/work-item-remove.ts +49 -15
  1274. package/src/tools/tasks/work-item-run.ts +34 -13
  1275. package/src/tools/tasks/work-item-update.ts +84 -31
  1276. package/src/tools/terminal/backends/native.ts +64 -35
  1277. package/src/tools/terminal/backends/types.ts +6 -2
  1278. package/src/tools/terminal/parser.ts +200 -125
  1279. package/src/tools/terminal/safe-env.ts +27 -21
  1280. package/src/tools/terminal/sandbox-diagnostics.ts +31 -13
  1281. package/src/tools/terminal/sandbox.ts +10 -6
  1282. package/src/tools/terminal/shell.ts +134 -68
  1283. package/src/tools/tool-approval-handler.ts +239 -140
  1284. package/src/tools/types.ts +79 -22
  1285. package/src/tools/ui-surface/definitions.ts +124 -89
  1286. package/src/tools/ui-surface/registry.ts +2 -2
  1287. package/src/tools/watch/screen-watch.ts +50 -32
  1288. package/src/tools/watch/watch-state.ts +41 -15
  1289. package/src/tools/watcher/create.ts +37 -15
  1290. package/src/tools/watcher/delete.ts +9 -6
  1291. package/src/tools/watcher/digest.ts +10 -6
  1292. package/src/tools/watcher/list.ts +37 -14
  1293. package/src/tools/watcher/update.ts +33 -18
  1294. package/src/tools/weather/service.ts +331 -174
  1295. package/src/twitter/client.ts +261 -138
  1296. package/src/twitter/oauth-client.ts +17 -13
  1297. package/src/twitter/router.ts +51 -23
  1298. package/src/twitter/session.ts +27 -18
  1299. package/src/types/qrcode.d.ts +6 -3
  1300. package/src/usage/actors.ts +16 -16
  1301. package/src/usage/types.ts +3 -3
  1302. package/src/util/bundled-asset.ts +10 -6
  1303. package/src/util/canonicalize-identity.ts +11 -4
  1304. package/src/util/clipboard.ts +7 -7
  1305. package/src/util/content-id.ts +3 -3
  1306. package/src/util/debounce.ts +3 -2
  1307. package/src/util/diff.ts +55 -33
  1308. package/src/util/errors.ts +31 -27
  1309. package/src/util/fs.ts +8 -2
  1310. package/src/util/log-redact.ts +12 -12
  1311. package/src/util/logger.ts +112 -51
  1312. package/src/util/network-info.ts +13 -5
  1313. package/src/util/object.ts +4 -2
  1314. package/src/util/phone.ts +4 -4
  1315. package/src/util/platform.ts +80 -58
  1316. package/src/util/pricing.ts +49 -31
  1317. package/src/util/retry.ts +39 -7
  1318. package/src/util/row-mapper.ts +7 -4
  1319. package/src/util/silently.ts +7 -4
  1320. package/src/util/spawn.ts +48 -0
  1321. package/src/util/spinner.ts +9 -7
  1322. package/src/util/time.ts +16 -3
  1323. package/src/util/truncate.ts +1 -1
  1324. package/src/util/voice-code.ts +6 -4
  1325. package/src/util/xml.ts +5 -1
  1326. package/src/version.ts +12 -8
  1327. package/src/watcher/engine.ts +71 -44
  1328. package/src/watcher/provider-registry.ts +1 -1
  1329. package/src/watcher/providers/github.ts +40 -23
  1330. package/src/watcher/providers/gmail.ts +59 -38
  1331. package/src/watcher/providers/google-calendar.ts +62 -48
  1332. package/src/watcher/providers/linear.ts +219 -150
  1333. package/src/watcher/providers/slack.ts +125 -29
  1334. package/src/watcher/watcher-store.ts +75 -55
  1335. package/src/work-items/work-item-runner.ts +62 -29
  1336. package/src/work-items/work-item-store.ts +137 -47
  1337. package/src/workspace/commit-message-enrichment-service.ts +65 -25
  1338. package/src/workspace/commit-message-provider.ts +14 -12
  1339. package/src/workspace/git-service.ts +355 -239
  1340. package/src/workspace/heartbeat-service.ts +74 -37
  1341. package/src/workspace/provider-commit-message-generator.ts +95 -70
  1342. package/src/workspace/top-level-renderer.ts +10 -8
  1343. package/src/workspace/top-level-scanner.ts +9 -3
  1344. package/src/workspace/turn-commit.ts +63 -36
  1345. package/src/__tests__/ingress-member-store.test.ts +0 -294
  1346. package/src/__tests__/script-proxy-router.test.ts +0 -215
  1347. package/src/config/bundled-skills/trusted-contacts/SKILL.md +0 -372
  1348. package/src/memory/guardian-bindings.ts +0 -158
  1349. package/src/memory/ingress-member-store.ts +0 -352
  1350. package/src/runtime/routes/ingress-routes.ts +0 -229
  1351. package/src/tools/network/script-proxy/__tests__/router.test.ts +0 -77
  1352. package/src/tools/network/script-proxy/certs.ts +0 -7
  1353. package/src/tools/network/script-proxy/connect-tunnel.ts +0 -1
  1354. package/src/tools/network/script-proxy/http-forwarder.ts +0 -2
  1355. package/src/tools/network/script-proxy/logging.ts +0 -12
  1356. package/src/tools/network/script-proxy/mitm-handler.ts +0 -2
  1357. package/src/tools/network/script-proxy/policy.ts +0 -4
  1358. package/src/tools/network/script-proxy/router.ts +0 -2
  1359. package/src/tools/network/script-proxy/server.ts +0 -5
  1360. package/src/tools/network/script-proxy/types.ts +0 -19
@@ -1,52 +1,47 @@
1
1
  /**
2
2
  * Approval interception: checks for pending approvals and handles inbound
3
3
  * messages as decisions, reminders, or conversational follow-ups.
4
+ *
5
+ * This module is the top-level dispatcher. It delegates to strategy modules:
6
+ * - guardian-callback-strategy.ts — guardian callback button and text decisions
7
+ * - guardian-text-engine-strategy.ts — conversational engine for plain-text messages
8
+ * - guardian-legacy-fallback-strategy.ts — deterministic parser fallback
4
9
  */
5
- import { applyGuardianDecision } from '../../approvals/guardian-decision-primitive.js';
6
- import type { ChannelId } from '../../channels/types.js';
10
+ import { applyGuardianDecision } from "../../approvals/guardian-decision-primitive.js";
11
+ import type { ChannelId } from "../../channels/types.js";
12
+ import type { TrustContext } from "../../daemon/session-runtime-assembly.js";
7
13
  import {
8
- getAllPendingApprovalsByGuardianChat,
9
- getPendingApprovalByRequestAndGuardianChat,
10
14
  getPendingApprovalForRequest,
11
15
  getUnresolvedApprovalForRequest,
12
- type GuardianApprovalRequest,
13
16
  updateApprovalDecision,
14
- } from '../../memory/channel-guardian-store.js';
15
- import { emitNotificationSignal } from '../../notifications/emit-signal.js';
16
- import { getLogger } from '../../util/logger.js';
17
- import { runApprovalConversationTurn } from '../approval-conversation-turn.js';
18
- import { composeApprovalMessageGenerative } from '../approval-message-composer.js';
19
- import { parseApprovalDecision } from '../channel-approval-parser.js';
20
- import type {
21
- ApprovalAction,
22
- ApprovalDecisionResult,
23
- } from '../channel-approval-types.js';
17
+ } from "../../memory/channel-guardian-store.js";
18
+ import { getLogger } from "../../util/logger.js";
19
+ import { runApprovalConversationTurn } from "../approval-conversation-turn.js";
20
+ import { composeApprovalMessageGenerative } from "../approval-message-composer.js";
21
+ import type { ApprovalDecisionResult } from "../channel-approval-types.js";
24
22
  import {
25
23
  getApprovalInfoByConversation,
26
24
  getChannelApprovalPrompt,
27
25
  handleChannelDecision,
28
- } from '../channel-approvals.js';
29
- import { deliverChannelReply } from '../gateway-client.js';
26
+ } from "../channel-approvals.js";
27
+ import { deliverChannelReply } from "../gateway-client.js";
30
28
  import type {
31
29
  ApprovalConversationContext,
32
30
  ApprovalConversationGenerator,
33
31
  ApprovalCopyGenerator,
34
- } from '../http-types.js';
35
- import {
36
- deliverVerificationCodeToGuardian,
37
- type DeliveryResult,
38
- handleAccessRequestDecision,
39
- notifyRequesterOfApproval,
40
- notifyRequesterOfDeliveryFailure,
41
- notifyRequesterOfDenial,
42
- } from './access-request-decision.js';
32
+ } from "../http-types.js";
33
+ import { parseApprovalIntent } from "../nl-approval-parser.js";
34
+ import { handleGuardianCallbackDecision } from "./approval-strategies/guardian-callback-strategy.js";
35
+ import { handleGuardianLegacyFallback } from "./approval-strategies/guardian-legacy-fallback-strategy.js";
36
+ import { handleGuardianTextEngineDecision } from "./approval-strategies/guardian-text-engine-strategy.js";
43
37
  import {
44
38
  buildGuardianDenyContext,
45
- type GuardianContext,
46
39
  parseCallbackData,
47
- } from './channel-route-shared.js';
40
+ parseReactionCallbackData,
41
+ } from "./channel-route-shared.js";
42
+ import { deliverStaleApprovalReply } from "./guardian-approval-reply-helpers.js";
48
43
 
49
- const log = getLogger('runtime-http');
44
+ const log = getLogger("runtime-http");
50
45
 
51
46
  export interface ApprovalInterceptionParams {
52
47
  conversationId: string;
@@ -57,7 +52,7 @@ export interface ApprovalInterceptionParams {
57
52
  actorExternalId?: string;
58
53
  replyCallbackUrl: string;
59
54
  bearerToken?: string;
60
- guardianCtx: GuardianContext;
55
+ trustCtx: TrustContext;
61
56
  assistantId: string;
62
57
  approvalCopyGenerator?: ApprovalCopyGenerator;
63
58
  approvalConversationGenerator?: ApprovalConversationGenerator;
@@ -65,7 +60,11 @@ export interface ApprovalInterceptionParams {
65
60
 
66
61
  export interface ApprovalInterceptionResult {
67
62
  handled: boolean;
68
- type?: 'decision_applied' | 'assistant_turn' | 'guardian_decision_applied' | 'stale_ignored';
63
+ type?:
64
+ | "decision_applied"
65
+ | "assistant_turn"
66
+ | "guardian_decision_applied"
67
+ | "stale_ignored";
69
68
  }
70
69
 
71
70
  /**
@@ -90,7 +89,7 @@ export async function handleApprovalInterception(
90
89
  actorExternalId,
91
90
  replyCallbackUrl,
92
91
  bearerToken,
93
- guardianCtx,
92
+ trustCtx,
94
93
  assistantId,
95
94
  approvalCopyGenerator,
96
95
  approvalConversationGenerator,
@@ -99,450 +98,50 @@ export async function handleApprovalInterception(
99
98
  // ── Guardian approval decision path ──
100
99
  // When the sender is the guardian and there's a pending guardian approval
101
100
  // request targeting this chat, the message might be a decision on behalf
102
- // of a non-guardian requester.
103
- if (
104
- guardianCtx.trustClass === 'guardian' &&
105
- actorExternalId
106
- ) {
107
- // Callback/button path: deterministic and takes priority.
108
- let callbackDecision: ApprovalDecisionResult | null = null;
109
- if (callbackData) {
110
- callbackDecision = parseCallbackData(callbackData, sourceChannel);
101
+ // of a non-guardian requester. Delegated to the guardian callback strategy.
102
+ if (trustCtx.trustClass === "guardian" && actorExternalId) {
103
+ const guardianResult = await handleGuardianCallbackDecision({
104
+ content,
105
+ callbackData,
106
+ conversationExternalId,
107
+ sourceChannel,
108
+ actorExternalId,
109
+ replyCallbackUrl,
110
+ bearerToken,
111
+ assistantId,
112
+ approvalCopyGenerator,
113
+ approvalConversationGenerator,
114
+ });
115
+ if (guardianResult) {
116
+ return guardianResult;
111
117
  }
118
+ }
112
119
 
113
- // When a callback button provides a request ID, use the scoped lookup so
114
- // the decision resolves to exactly the right approval even when
115
- // multiple approvals target the same guardian chat.
116
- let guardianApproval = callbackDecision?.requestId
117
- ? getPendingApprovalByRequestAndGuardianChat(callbackDecision.requestId, sourceChannel, conversationExternalId, assistantId)
118
- : null;
119
-
120
- // When the scoped lookup didn't resolve an approval (either because
121
- // there was no callback or the requestId pointed to a stale/expired request),
122
- // fall back to checking all pending approvals for this guardian chat.
123
- if (!guardianApproval && callbackDecision) {
124
- const allPending = getAllPendingApprovalsByGuardianChat(sourceChannel, conversationExternalId, assistantId);
125
- if (allPending.length === 1) {
126
- guardianApproval = allPending[0];
127
- } else if (allPending.length > 1) {
128
- // The callback targeted a stale/expired request but the guardian has other
129
- // pending approvals. Inform them the clicked approval is no longer valid.
130
- try {
131
- const staleText = await composeApprovalMessageGenerative({
132
- scenario: 'guardian_disambiguation',
133
- pendingCount: allPending.length,
134
- channel: sourceChannel,
135
- }, {}, approvalCopyGenerator);
136
- await deliverChannelReply(replyCallbackUrl, {
137
- chatId: conversationExternalId,
138
- text: staleText,
139
- assistantId,
140
- }, bearerToken);
141
- } catch (err) {
142
- log.error({ err, conversationExternalId }, 'Failed to deliver stale callback disambiguation notice');
143
- }
144
- return { handled: true, type: 'stale_ignored' };
145
- }
120
+ // ── Slack reaction path ──
121
+ // Reactions produce `callbackData` of the form `reaction:<emoji_name>`.
122
+ // Handled before the pendingPrompt guard because guardian reactions arrive
123
+ // on the guardian's chat (guardianChatId), not the requester's conversation,
124
+ // so getChannelApprovalPrompt(conversationId) would return null.
125
+ // Only guardians can approve via reaction — non-guardian reactions are
126
+ // silently ignored to prevent self-approval.
127
+ if (callbackData?.startsWith("reaction:")) {
128
+ if (trustCtx.trustClass !== "guardian") {
129
+ return { handled: true, type: "stale_ignored" };
146
130
  }
147
-
148
- // For plain-text messages (no callback), check if there are any pending
149
- // approvals for this guardian chat to route through the conversation engine.
150
- if (!guardianApproval && !callbackDecision) {
151
- const allPending = getAllPendingApprovalsByGuardianChat(sourceChannel, conversationExternalId, assistantId);
152
- if (allPending.length === 1) {
153
- guardianApproval = allPending[0];
154
- } else if (allPending.length > 1) {
155
- // Multiple pending — pick the first approval matching this sender as
156
- // primary context. The conversation engine sees all matching approvals
157
- // via pendingApprovals and can disambiguate.
158
- guardianApproval = allPending.find(a => a.guardianExternalUserId === actorExternalId) ?? allPending[0];
159
- }
131
+ const reactionDecision = parseReactionCallbackData(callbackData);
132
+ if (!reactionDecision) {
133
+ // Unknown emoji ignore silently
134
+ return { handled: true, type: "stale_ignored" };
160
135
  }
161
-
162
- if (guardianApproval) {
163
- // Validate that the sender is the specific guardian who was assigned
164
- // this approval request. This is a defense-in-depth check — the
165
- // trustClass check above already verifies the sender is a guardian,
166
- // but this catches edge cases like binding rotation between request
167
- // creation and decision.
168
- if (actorExternalId !== guardianApproval.guardianExternalUserId) {
169
- log.warn(
170
- { conversationExternalId, actorExternalId, expectedGuardian: guardianApproval.guardianExternalUserId },
171
- 'Non-guardian sender attempted to act on guardian approval request',
172
- );
173
- try {
174
- const mismatchText = await composeApprovalMessageGenerative({
175
- scenario: 'guardian_identity_mismatch',
176
- channel: sourceChannel,
177
- }, {}, approvalCopyGenerator);
178
- await deliverChannelReply(replyCallbackUrl, {
179
- chatId: conversationExternalId,
180
- text: mismatchText,
181
- assistantId,
182
- }, bearerToken);
183
- } catch (err) {
184
- log.error({ err, conversationExternalId }, 'Failed to deliver guardian identity rejection notice');
185
- }
186
- return { handled: true, type: 'guardian_decision_applied' };
187
- }
188
-
189
- if (callbackDecision) {
190
- // Access request approvals don't have a pending interaction in the
191
- // session tracker, so they need a separate decision path that creates
192
- // a verification session instead of resuming an agent loop.
193
- if (guardianApproval.toolName === 'ingress_access_request') {
194
- const accessResult = await handleAccessRequestApproval(
195
- guardianApproval,
196
- callbackDecision.action === 'reject' ? 'deny' : 'approve',
197
- actorExternalId,
198
- replyCallbackUrl,
199
- assistantId,
200
- bearerToken,
201
- );
202
- return accessResult;
203
- }
204
-
205
- // Apply the decision through the unified guardian decision primitive.
206
- // The primitive handles approve_always downgrade, approval info capture,
207
- // record update, and scoped grant minting.
208
- const result = applyGuardianDecision({
209
- approval: guardianApproval,
210
- decision: callbackDecision,
211
- actorExternalUserId: actorExternalId,
212
- actorChannel: sourceChannel,
213
- });
214
-
215
- if (result.applied) {
216
- // Notify the requester's chat about the outcome with the tool name
217
- const effectiveAction = callbackDecision.action === 'approve_always' ? 'approve_once' : callbackDecision.action;
218
- const outcomeText = await composeApprovalMessageGenerative({
219
- scenario: 'guardian_decision_outcome',
220
- decision: effectiveAction === 'reject' ? 'denied' : 'approved',
221
- toolName: guardianApproval.toolName,
222
- channel: sourceChannel,
223
- }, {}, approvalCopyGenerator);
224
- try {
225
- await deliverChannelReply(replyCallbackUrl, {
226
- chatId: guardianApproval.requesterChatId,
227
- text: outcomeText,
228
- assistantId,
229
- }, bearerToken);
230
- } catch (err) {
231
- log.error({ err, conversationId: guardianApproval.conversationId }, 'Failed to notify requester of guardian decision');
232
- }
233
-
234
- // Post-decision delivery is handled by the onEvent callback
235
- // in the session that registered the pending interaction.
236
- return { handled: true, type: 'guardian_decision_applied' };
237
- }
238
-
239
- // Race condition: callback arrived after request was already resolved.
240
- return { handled: true, type: 'stale_ignored' };
241
- }
242
-
243
- // ── Conversational engine for guardian plain-text messages ──
244
- // Gather all pending guardian approvals for this chat so the engine
245
- // can handle disambiguation when multiple are pending.
246
- const allGuardianPending = getAllPendingApprovalsByGuardianChat(sourceChannel, conversationExternalId, assistantId);
247
- // Only present approvals that belong to this sender so the engine
248
- // does not offer disambiguation for requests assigned to a rotated
249
- // guardian the sender cannot act on.
250
- const senderPending = allGuardianPending.filter(a => a.guardianExternalUserId === actorExternalId);
251
- const effectivePending = senderPending.length > 0 ? senderPending : allGuardianPending;
252
- if (effectivePending.length > 0 && approvalConversationGenerator && content) {
253
- const guardianAllowedActions = ['approve_once', 'reject'];
254
- const engineContext: ApprovalConversationContext = {
255
- toolName: guardianApproval.toolName,
256
- allowedActions: guardianAllowedActions,
257
- role: 'guardian',
258
- pendingApprovals: effectivePending.map((a) => ({ requestId: a.requestId ?? a.runId, toolName: a.toolName })),
259
- userMessage: content,
260
- };
261
-
262
- const engineResult = await runApprovalConversationTurn(engineContext, approvalConversationGenerator);
263
-
264
- if (engineResult.disposition === 'keep_pending') {
265
- // Non-decision follow-up (clarification, disambiguation, etc.)
266
- try {
267
- await deliverChannelReply(replyCallbackUrl, {
268
- chatId: conversationExternalId,
269
- text: engineResult.replyText,
270
- assistantId,
271
- }, bearerToken);
272
- } catch (err) {
273
- log.error({ err, conversationId: guardianApproval.conversationId }, 'Failed to deliver guardian conversation reply');
274
- }
275
- return { handled: true, type: 'assistant_turn' };
276
- }
277
-
278
- // Decision-bearing disposition from the engine
279
- let decisionAction = engineResult.disposition as ApprovalAction;
280
-
281
- // Belt-and-suspenders: guardians cannot use broad allow modes even if
282
- // the engine returns them (the engine's allowedActions validation should
283
- // already prevent this, but enforce it here too).
284
- if (decisionAction === 'approve_always' || decisionAction === 'approve_10m' || decisionAction === 'approve_thread') {
285
- decisionAction = 'approve_once';
286
- }
287
-
288
- // Resolve the target approval: use targetRequestId from the engine if
289
- // provided, otherwise use the single guardian approval.
290
- const targetApproval = engineResult.targetRequestId
291
- ? allGuardianPending.find((a) => (a.requestId ?? a.runId) === engineResult.targetRequestId) ?? guardianApproval
292
- : guardianApproval;
293
-
294
- // Re-validate guardian identity against the resolved target. The
295
- // engine may select a different pending approval (via targetRequestId)
296
- // that was assigned to a different guardian. Without this check a
297
- // currently bound guardian could act on a request assigned to a
298
- // previous guardian after a binding rotation.
299
- if (actorExternalId !== targetApproval.guardianExternalUserId) {
300
- log.warn(
301
- { conversationExternalId, actorExternalId, expectedGuardian: targetApproval.guardianExternalUserId, targetRequestId: engineResult.targetRequestId },
302
- 'Guardian identity mismatch on engine-selected target approval',
303
- );
304
- try {
305
- const mismatchText = await composeApprovalMessageGenerative({
306
- scenario: 'guardian_identity_mismatch',
307
- channel: sourceChannel,
308
- }, {}, approvalCopyGenerator);
309
- await deliverChannelReply(replyCallbackUrl, {
310
- chatId: conversationExternalId,
311
- text: mismatchText,
312
- assistantId,
313
- }, bearerToken);
314
- } catch (err) {
315
- log.error({ err, conversationExternalId }, 'Failed to deliver guardian identity mismatch notice for engine target');
316
- }
317
- return { handled: true, type: 'guardian_decision_applied' };
318
- }
319
-
320
- // Access request approvals need a separate decision path.
321
- if (targetApproval.toolName === 'ingress_access_request') {
322
- const accessResult = await handleAccessRequestApproval(
323
- targetApproval,
324
- decisionAction === 'reject' ? 'deny' : 'approve',
325
- actorExternalId,
326
- replyCallbackUrl,
327
- assistantId,
328
- bearerToken,
329
- );
330
- return accessResult;
331
- }
332
-
333
- const engineDecision: ApprovalDecisionResult = {
334
- action: decisionAction,
335
- source: 'plain_text',
336
- ...(engineResult.targetRequestId ? { requestId: engineResult.targetRequestId } : {}),
337
- };
338
-
339
- // Apply the decision through the unified guardian decision primitive.
340
- const result = applyGuardianDecision({
341
- approval: targetApproval,
342
- decision: engineDecision,
343
- actorExternalUserId: actorExternalId,
344
- actorChannel: sourceChannel,
345
- });
346
-
347
- if (result.applied) {
348
- // Notify the requester's chat about the outcome
349
- const outcomeText = await composeApprovalMessageGenerative({
350
- scenario: 'guardian_decision_outcome',
351
- decision: decisionAction === 'reject' ? 'denied' : 'approved',
352
- toolName: targetApproval.toolName,
353
- channel: sourceChannel,
354
- }, {}, approvalCopyGenerator);
355
- try {
356
- await deliverChannelReply(replyCallbackUrl, {
357
- chatId: targetApproval.requesterChatId,
358
- text: outcomeText,
359
- assistantId,
360
- }, bearerToken);
361
- } catch (err) {
362
- log.error({ err, conversationId: targetApproval.conversationId }, 'Failed to notify requester of guardian decision');
363
- }
364
-
365
- // Deliver the engine's reply to the guardian
366
- try {
367
- await deliverChannelReply(replyCallbackUrl, {
368
- chatId: conversationExternalId,
369
- text: engineResult.replyText,
370
- assistantId,
371
- }, bearerToken);
372
- } catch (err) {
373
- log.error({ err, conversationId: targetApproval.conversationId }, 'Failed to deliver guardian decision reply');
374
- }
375
-
376
- return { handled: true, type: 'guardian_decision_applied' };
377
- }
378
-
379
- // Race condition: request was already resolved. Deliver a stale notice
380
- // instead of the engine's optimistic reply.
381
- try {
382
- const staleText = await composeApprovalMessageGenerative({
383
- scenario: 'approval_already_resolved',
384
- channel: sourceChannel,
385
- }, {}, approvalCopyGenerator);
386
- await deliverChannelReply(replyCallbackUrl, {
387
- chatId: conversationExternalId,
388
- text: staleText,
389
- assistantId,
390
- }, bearerToken);
391
- } catch (err) {
392
- log.error({ err, conversationId: targetApproval.conversationId }, 'Failed to deliver stale guardian approval notice');
393
- }
394
-
395
- return { handled: true, type: 'stale_ignored' };
396
- }
397
-
398
- // ── Legacy fallback when no conversational engine is available ──
399
- // Use the deterministic parser to handle guardian plain-text so that
400
- // simple yes/no replies still work when the engine is not injected.
401
- if (content && !approvalConversationGenerator) {
402
- const legacyGuardianDecision = parseApprovalDecision(content);
403
- if (legacyGuardianDecision) {
404
- // Guardians cannot approve_always — downgrade to approve_once.
405
- if (legacyGuardianDecision.action === 'approve_always') {
406
- legacyGuardianDecision.action = 'approve_once';
407
- }
408
-
409
- // Resolve the target approval: when a [ref:<requestId>] tag is
410
- // present, look up the specific pending approval by that requestId
411
- // so the decision applies to the correct conversation even when
412
- // multiple guardian approvals are pending.
413
- let targetLegacyApproval = guardianApproval;
414
- if (legacyGuardianDecision.requestId) {
415
- const resolvedByRequest = getPendingApprovalByRequestAndGuardianChat(
416
- legacyGuardianDecision.requestId,
417
- sourceChannel,
418
- conversationExternalId,
419
- assistantId,
420
- );
421
- if (!resolvedByRequest) {
422
- // The referenced request doesn't match any pending guardian
423
- // approval — it may have expired or already been resolved.
424
- try {
425
- const staleText = await composeApprovalMessageGenerative({
426
- scenario: 'guardian_disambiguation',
427
- channel: sourceChannel,
428
- }, {}, approvalCopyGenerator);
429
- await deliverChannelReply(replyCallbackUrl, {
430
- chatId: conversationExternalId,
431
- text: staleText,
432
- assistantId,
433
- }, bearerToken);
434
- } catch (err) {
435
- log.error({ err, conversationExternalId }, 'Failed to deliver stale approval notice (legacy path)');
436
- }
437
- return { handled: true, type: 'stale_ignored' };
438
- }
439
- targetLegacyApproval = resolvedByRequest;
440
- }
441
-
442
- // Re-validate guardian identity against the resolved target.
443
- // The default guardianApproval was already checked, but a
444
- // requestId-resolved approval may belong to a different guardian.
445
- if (actorExternalId !== targetLegacyApproval.guardianExternalUserId) {
446
- log.warn(
447
- { conversationExternalId, actorExternalId, expectedGuardian: targetLegacyApproval.guardianExternalUserId, requestId: legacyGuardianDecision.requestId },
448
- 'Guardian identity mismatch on legacy ref-resolved target approval',
449
- );
450
- try {
451
- const mismatchText = await composeApprovalMessageGenerative({
452
- scenario: 'guardian_identity_mismatch',
453
- channel: sourceChannel,
454
- }, {}, approvalCopyGenerator);
455
- await deliverChannelReply(replyCallbackUrl, {
456
- chatId: conversationExternalId,
457
- text: mismatchText,
458
- assistantId,
459
- }, bearerToken);
460
- } catch (err) {
461
- log.error({ err, conversationExternalId }, 'Failed to deliver guardian identity mismatch notice (legacy path)');
462
- }
463
- return { handled: true, type: 'guardian_decision_applied' };
464
- }
465
-
466
- // Access request approvals need a separate decision path.
467
- if (targetLegacyApproval.toolName === 'ingress_access_request') {
468
- const accessResult = await handleAccessRequestApproval(
469
- targetLegacyApproval,
470
- legacyGuardianDecision.action === 'reject' ? 'deny' : 'approve',
471
- actorExternalId,
472
- replyCallbackUrl,
473
- assistantId,
474
- bearerToken,
475
- );
476
- return accessResult;
477
- }
478
-
479
- // Apply the decision through the unified guardian decision primitive.
480
- const result = applyGuardianDecision({
481
- approval: targetLegacyApproval,
482
- decision: legacyGuardianDecision,
483
- actorExternalUserId: actorExternalId,
484
- actorChannel: sourceChannel,
485
- });
486
-
487
- if (result.applied) {
488
- // Notify the requester's chat about the outcome
489
- const outcomeText = await composeApprovalMessageGenerative({
490
- scenario: 'guardian_decision_outcome',
491
- decision: legacyGuardianDecision.action === 'reject' ? 'denied' : 'approved',
492
- toolName: targetLegacyApproval.toolName,
493
- channel: sourceChannel,
494
- }, {}, approvalCopyGenerator);
495
- try {
496
- await deliverChannelReply(replyCallbackUrl, {
497
- chatId: targetLegacyApproval.requesterChatId,
498
- text: outcomeText,
499
- assistantId,
500
- }, bearerToken);
501
- } catch (err) {
502
- log.error({ err, conversationId: targetLegacyApproval.conversationId }, 'Failed to notify requester of guardian decision (legacy path)');
503
- }
504
-
505
- return { handled: true, type: 'guardian_decision_applied' };
506
- }
507
-
508
- // Race condition: request was already resolved. Deliver stale notice.
509
- try {
510
- const staleText = await composeApprovalMessageGenerative({
511
- scenario: 'approval_already_resolved',
512
- channel: sourceChannel,
513
- }, {}, approvalCopyGenerator);
514
- await deliverChannelReply(replyCallbackUrl, {
515
- chatId: conversationExternalId,
516
- text: staleText,
517
- assistantId,
518
- }, bearerToken);
519
- } catch (err) {
520
- log.error({ err, conversationId: targetLegacyApproval.conversationId }, 'Failed to deliver stale guardian legacy fallback notice');
521
- }
522
- return { handled: true, type: 'stale_ignored' };
523
- }
524
-
525
- // No decision could be parsed — send a generic reminder to the guardian
526
- try {
527
- const reminderText = await composeApprovalMessageGenerative({
528
- scenario: 'reminder_prompt',
529
- toolName: guardianApproval.toolName,
530
- channel: sourceChannel,
531
- }, {}, approvalCopyGenerator);
532
- await deliverChannelReply(replyCallbackUrl, {
533
- chatId: conversationExternalId,
534
- text: reminderText,
535
- assistantId,
536
- }, bearerToken);
537
- } catch (err) {
538
- log.error({ err, conversationId: guardianApproval.conversationId }, 'Failed to deliver guardian reminder (legacy path)');
539
- }
540
- return { handled: true, type: 'assistant_turn' };
541
- }
542
-
543
- // No content and no engine — nothing to do, fall through to standard
544
- // approval interception below.
136
+ const pending = getApprovalInfoByConversation(conversationId);
137
+ if (pending.length === 0) {
138
+ return { handled: true, type: "stale_ignored" };
139
+ }
140
+ const result = handleChannelDecision(conversationId, reactionDecision);
141
+ if (result.applied) {
142
+ return { handled: true, type: "decision_applied" };
545
143
  }
144
+ return { handled: true, type: "stale_ignored" };
546
145
  }
547
146
 
548
147
  // ── Standard approval interception (existing flow) ──
@@ -553,7 +152,8 @@ export async function handleApprovalInterception(
553
152
  // unknown trust + explicit denial reason (`no_identity` / `no_binding`).
554
153
  // Unknown without a denial reason means identity-known, non-member sender
555
154
  // in a shared channel; that case must not force-reject someone else's request.
556
- const isLegacyUnverifiedSender = guardianCtx.trustClass === 'unknown' && !!guardianCtx.denialReason;
155
+ const isLegacyUnverifiedSender =
156
+ trustCtx.trustClass === "unknown" && !!trustCtx.denialReason;
557
157
 
558
158
  // When the sender is from a legacy-unverified channel actor, auto-deny any
559
159
  // pending confirmation and block self-approval.
@@ -562,14 +162,14 @@ export async function handleApprovalInterception(
562
162
  if (pending.length > 0) {
563
163
  handleChannelDecision(
564
164
  conversationId,
565
- { action: 'reject', source: 'plain_text' },
165
+ { action: "reject", source: "plain_text" },
566
166
  buildGuardianDenyContext(
567
167
  pending[0].toolName,
568
- guardianCtx.denialReason ?? 'no_binding',
168
+ trustCtx.denialReason ?? "no_binding",
569
169
  sourceChannel,
570
170
  ),
571
171
  );
572
- return { handled: true, type: 'decision_applied' };
172
+ return { handled: true, type: "decision_applied" };
573
173
  }
574
174
  }
575
175
 
@@ -579,12 +179,15 @@ export async function handleApprovalInterception(
579
179
  //
580
180
  // Include identity-known, non-member senders (`unknown` without denialReason)
581
181
  // so shared-channel participants can't approve/deny someone else's pending request.
582
- const isIdentityKnownNonGuardian = guardianCtx.trustClass === 'trusted_contact'
583
- || (guardianCtx.trustClass === 'unknown' && !guardianCtx.denialReason);
182
+ const isIdentityKnownNonGuardian =
183
+ trustCtx.trustClass === "trusted_contact" ||
184
+ (trustCtx.trustClass === "unknown" && !trustCtx.denialReason);
584
185
  if (isIdentityKnownNonGuardian) {
585
186
  const pending = getApprovalInfoByConversation(conversationId);
586
187
  if (pending.length > 0) {
587
- const guardianApprovalForRequest = getPendingApprovalForRequest(pending[0].requestId);
188
+ const guardianApprovalForRequest = getPendingApprovalForRequest(
189
+ pending[0].requestId,
190
+ );
588
191
  if (guardianApprovalForRequest) {
589
192
  // Allow the requester to cancel their own pending guardian request.
590
193
  // Only reject/cancel is permitted — self-approval is still blocked.
@@ -599,24 +202,30 @@ export async function handleApprovalInterception(
599
202
  if (approvalConversationGenerator) {
600
203
  const cancelContext: ApprovalConversationContext = {
601
204
  toolName: pending[0].toolName,
602
- allowedActions: ['reject'],
603
- role: 'requester',
604
- pendingApprovals: pending.map(p => ({ requestId: p.requestId, toolName: p.toolName })),
205
+ allowedActions: ["reject"],
206
+ role: "requester",
207
+ pendingApprovals: pending.map((p) => ({
208
+ requestId: p.requestId,
209
+ toolName: p.toolName,
210
+ })),
605
211
  userMessage: content,
606
212
  };
607
- const cancelResult = await runApprovalConversationTurn(cancelContext, approvalConversationGenerator);
608
- if (cancelResult.disposition === 'reject') {
213
+ const cancelResult = await runApprovalConversationTurn(
214
+ cancelContext,
215
+ approvalConversationGenerator,
216
+ );
217
+ if (cancelResult.disposition === "reject") {
609
218
  requesterCancelIntent = true;
610
219
  cancelReplyText = cancelResult.replyText;
611
- } else if (cancelResult.disposition === 'keep_pending') {
220
+ } else if (cancelResult.disposition === "keep_pending") {
612
221
  requesterFollowupReplyText = cancelResult.replyText;
613
222
  }
614
223
  }
615
224
 
616
225
  if (requesterCancelIntent) {
617
226
  const rejectDecision: ApprovalDecisionResult = {
618
- action: 'reject',
619
- source: 'plain_text',
227
+ action: "reject",
228
+ source: "plain_text",
620
229
  };
621
230
  // Apply the cancel decision through the unified primitive.
622
231
  // The primitive handles record update and (no-op) grant logic.
@@ -628,119 +237,152 @@ export async function handleApprovalInterception(
628
237
  });
629
238
  if (cancelApplyResult.applied) {
630
239
  // Notify requester
631
- const replyText = cancelReplyText ?? await composeApprovalMessageGenerative({
632
- scenario: 'requester_cancel',
633
- toolName: pending[0].toolName,
634
- channel: sourceChannel,
635
- }, {}, approvalCopyGenerator);
240
+ const replyText =
241
+ cancelReplyText ??
242
+ (await composeApprovalMessageGenerative(
243
+ {
244
+ scenario: "requester_cancel",
245
+ toolName: pending[0].toolName,
246
+ channel: sourceChannel,
247
+ },
248
+ {},
249
+ approvalCopyGenerator,
250
+ ));
636
251
  try {
637
- await deliverChannelReply(replyCallbackUrl, {
638
- chatId: conversationExternalId,
639
- text: replyText,
640
- assistantId,
641
- }, bearerToken);
252
+ await deliverChannelReply(
253
+ replyCallbackUrl,
254
+ {
255
+ chatId: conversationExternalId,
256
+ text: replyText,
257
+ assistantId,
258
+ },
259
+ bearerToken,
260
+ );
642
261
  } catch (err) {
643
- log.error({ err, conversationId }, 'Failed to deliver requester cancel notice');
262
+ log.error(
263
+ { err, conversationId },
264
+ "Failed to deliver requester cancel notice",
265
+ );
644
266
  }
645
267
 
646
268
  // Notify guardian that the request was cancelled
647
269
  try {
648
- const guardianNotice = await composeApprovalMessageGenerative({
649
- scenario: 'guardian_decision_outcome',
650
- decision: 'denied',
651
- toolName: pending[0].toolName,
652
- channel: sourceChannel,
653
- }, {}, approvalCopyGenerator);
654
- await deliverChannelReply(replyCallbackUrl, {
655
- chatId: guardianApprovalForRequest.guardianChatId,
656
- text: guardianNotice,
657
- assistantId,
658
- }, bearerToken);
270
+ const guardianNotice = await composeApprovalMessageGenerative(
271
+ {
272
+ scenario: "guardian_decision_outcome",
273
+ decision: "denied",
274
+ toolName: pending[0].toolName,
275
+ channel: sourceChannel,
276
+ },
277
+ {},
278
+ approvalCopyGenerator,
279
+ );
280
+ await deliverChannelReply(
281
+ replyCallbackUrl,
282
+ {
283
+ chatId: guardianApprovalForRequest.guardianChatId,
284
+ text: guardianNotice,
285
+ assistantId,
286
+ },
287
+ bearerToken,
288
+ );
659
289
  } catch (err) {
660
- log.error({ err, conversationId }, 'Failed to notify guardian of requester cancellation');
290
+ log.error(
291
+ { err, conversationId },
292
+ "Failed to notify guardian of requester cancellation",
293
+ );
661
294
  }
662
295
 
663
- return { handled: true, type: 'decision_applied' };
296
+ return { handled: true, type: "decision_applied" };
664
297
  }
665
298
 
666
299
  // Race condition: approval was already resolved elsewhere.
667
- try {
668
- const staleText = await composeApprovalMessageGenerative({
669
- scenario: 'approval_already_resolved',
670
- channel: sourceChannel,
671
- }, {}, approvalCopyGenerator);
672
- await deliverChannelReply(replyCallbackUrl, {
673
- chatId: conversationExternalId,
674
- text: staleText,
675
- assistantId,
676
- }, bearerToken);
677
- } catch (err) {
678
- log.error({ err, conversationId }, 'Failed to deliver stale requester-cancel notice');
679
- }
680
- return { handled: true, type: 'stale_ignored' };
300
+ await deliverStaleApprovalReply({
301
+ scenario: "approval_already_resolved",
302
+ sourceChannel,
303
+ replyCallbackUrl,
304
+ chatId: conversationExternalId,
305
+ assistantId,
306
+ bearerToken,
307
+ approvalCopyGenerator,
308
+ logger: log,
309
+ errorLogMessage:
310
+ "Failed to deliver stale requester-cancel notice",
311
+ errorLogContext: { conversationId },
312
+ });
313
+ return { handled: true, type: "stale_ignored" };
681
314
  }
682
315
 
683
316
  if (requesterFollowupReplyText) {
684
317
  try {
685
- await deliverChannelReply(replyCallbackUrl, {
686
- chatId: conversationExternalId,
687
- text: requesterFollowupReplyText,
688
- assistantId,
689
- }, bearerToken);
318
+ await deliverChannelReply(
319
+ replyCallbackUrl,
320
+ {
321
+ chatId: conversationExternalId,
322
+ text: requesterFollowupReplyText,
323
+ assistantId,
324
+ },
325
+ bearerToken,
326
+ );
690
327
  } catch (err) {
691
- log.error({ err, conversationId }, 'Failed to deliver requester follow-up reply while awaiting guardian');
328
+ log.error(
329
+ { err, conversationId },
330
+ "Failed to deliver requester follow-up reply while awaiting guardian",
331
+ );
692
332
  }
693
- return { handled: true, type: 'assistant_turn' };
333
+ return { handled: true, type: "assistant_turn" };
694
334
  }
695
335
  }
696
336
 
697
337
  // Not a cancel intent — tell the requester their request is pending
698
- try {
699
- const pendingText = await composeApprovalMessageGenerative({
700
- scenario: 'request_pending_guardian',
701
- channel: sourceChannel,
702
- }, {}, approvalCopyGenerator);
703
- await deliverChannelReply(replyCallbackUrl, {
704
- chatId: conversationExternalId,
705
- text: pendingText,
706
- assistantId,
707
- }, bearerToken);
708
- } catch (err) {
709
- log.error({ err, conversationId }, 'Failed to deliver guardian-pending notice to requester');
710
- }
711
- return { handled: true, type: 'assistant_turn' };
338
+ await deliverStaleApprovalReply({
339
+ scenario: "request_pending_guardian",
340
+ sourceChannel,
341
+ replyCallbackUrl,
342
+ chatId: conversationExternalId,
343
+ assistantId,
344
+ bearerToken,
345
+ approvalCopyGenerator,
346
+ logger: log,
347
+ errorLogMessage:
348
+ "Failed to deliver guardian-pending notice to requester",
349
+ errorLogContext: { conversationId },
350
+ });
351
+ return { handled: true, type: "assistant_turn" };
712
352
  }
713
353
 
714
354
  // Check for an expired-but-unresolved guardian approval. If the approval
715
355
  // expired without a guardian decision, auto-deny and transition
716
356
  // the approval to 'expired'. Without this, the requester could bypass
717
357
  // guardian-only controls by simply waiting for the TTL to elapse.
718
- const unresolvedApproval = getUnresolvedApprovalForRequest(pending[0].requestId);
358
+ const unresolvedApproval = getUnresolvedApprovalForRequest(
359
+ pending[0].requestId,
360
+ );
719
361
  if (unresolvedApproval) {
720
- updateApprovalDecision(unresolvedApproval.id, { status: 'expired' });
362
+ updateApprovalDecision(unresolvedApproval.id, { status: "expired" });
721
363
 
722
364
  // Auto-deny the underlying request so it does not remain actionable
723
365
  const expiredDecision: ApprovalDecisionResult = {
724
- action: 'reject',
725
- source: 'plain_text',
366
+ action: "reject",
367
+ source: "plain_text",
726
368
  };
727
369
  handleChannelDecision(conversationId, expiredDecision);
728
370
 
729
- try {
730
- const expiredText = await composeApprovalMessageGenerative({
731
- scenario: 'guardian_expired_requester',
732
- toolName: pending[0].toolName,
733
- channel: sourceChannel,
734
- }, {}, approvalCopyGenerator);
735
- await deliverChannelReply(replyCallbackUrl, {
736
- chatId: conversationExternalId,
737
- text: expiredText,
738
- assistantId,
739
- }, bearerToken);
740
- } catch (err) {
741
- log.error({ err, conversationId }, 'Failed to deliver guardian-expiry notice to requester');
742
- }
743
- return { handled: true, type: 'decision_applied' };
371
+ await deliverStaleApprovalReply({
372
+ scenario: "guardian_expired_requester",
373
+ sourceChannel,
374
+ replyCallbackUrl,
375
+ chatId: conversationExternalId,
376
+ assistantId,
377
+ bearerToken,
378
+ approvalCopyGenerator,
379
+ logger: log,
380
+ errorLogMessage:
381
+ "Failed to deliver guardian-expiry notice to requester",
382
+ extraContext: { toolName: pending[0].toolName },
383
+ errorLogContext: { conversationId },
384
+ });
385
+ return { handled: true, type: "decision_applied" };
744
386
  }
745
387
 
746
388
  // Guard: non-guardian actors with a guardian binding must not self-approve
@@ -751,29 +393,60 @@ export async function handleApprovalInterception(
751
393
  // persisted, any non-guardian actor could otherwise fall through to the
752
394
  // standard conversational engine / legacy parser and resolve their own
753
395
  // pending request via handleChannelDecision.
754
- if (guardianCtx.trustClass !== 'guardian' && guardianCtx.guardianExternalUserId) {
396
+ if (
397
+ trustCtx.trustClass !== "guardian" &&
398
+ trustCtx.guardianExternalUserId
399
+ ) {
755
400
  log.info(
756
- { conversationId, conversationExternalId, guardianExternalUserId: guardianCtx.guardianExternalUserId },
757
- 'Blocking non-guardian self-approval: pending confirmation exists but guardian approval row not yet created',
401
+ {
402
+ conversationId,
403
+ conversationExternalId,
404
+ guardianExternalUserId: trustCtx.guardianExternalUserId,
405
+ },
406
+ "Blocking non-guardian self-approval: pending confirmation exists but guardian approval row not yet created",
758
407
  );
759
- try {
760
- const pendingText = await composeApprovalMessageGenerative({
761
- scenario: 'request_pending_guardian',
762
- channel: sourceChannel,
763
- }, {}, approvalCopyGenerator);
764
- await deliverChannelReply(replyCallbackUrl, {
765
- chatId: conversationExternalId,
766
- text: pendingText,
767
- assistantId,
768
- }, bearerToken);
769
- } catch (err) {
770
- log.error({ err, conversationId }, 'Failed to deliver guardian-pending notice to non-guardian actor (pre-row guard)');
771
- }
772
- return { handled: true, type: 'assistant_turn' };
408
+ await deliverStaleApprovalReply({
409
+ scenario: "request_pending_guardian",
410
+ sourceChannel,
411
+ replyCallbackUrl,
412
+ chatId: conversationExternalId,
413
+ assistantId,
414
+ bearerToken,
415
+ approvalCopyGenerator,
416
+ logger: log,
417
+ errorLogMessage:
418
+ "Failed to deliver guardian-pending notice to non-guardian actor (pre-row guard)",
419
+ errorLogContext: { conversationId },
420
+ });
421
+ return { handled: true, type: "assistant_turn" };
773
422
  }
774
423
  }
775
424
  }
776
425
 
426
+ // ── Slack reaction path ──
427
+ // Reactions produce `callbackData` of the form `reaction:<emoji_name>`.
428
+ // Only guardians can approve via reaction — non-guardian reactions are
429
+ // silently ignored to prevent self-approval.
430
+ if (callbackData?.startsWith("reaction:")) {
431
+ if (trustCtx.trustClass !== "guardian") {
432
+ return { handled: true, type: "stale_ignored" };
433
+ }
434
+ const reactionDecision = parseReactionCallbackData(callbackData);
435
+ if (!reactionDecision) {
436
+ // Unknown emoji — ignore silently
437
+ return { handled: true, type: "stale_ignored" };
438
+ }
439
+ const pending = getApprovalInfoByConversation(conversationId);
440
+ if (pending.length === 0) {
441
+ return { handled: true, type: "stale_ignored" };
442
+ }
443
+ const result = handleChannelDecision(conversationId, reactionDecision);
444
+ if (result.applied) {
445
+ return { handled: true, type: "decision_applied" };
446
+ }
447
+ return { handled: true, type: "stale_ignored" };
448
+ }
449
+
777
450
  // Try to extract a decision from callback data (button press) first.
778
451
  // Callback/button path remains deterministic and takes priority.
779
452
  if (callbackData) {
@@ -784,12 +457,15 @@ export async function handleApprovalInterception(
784
457
  // previous approval prompt) must not apply to a different pending interaction.
785
458
  if (cbDecision.requestId) {
786
459
  const pending = getApprovalInfoByConversation(conversationId);
787
- if (pending.length === 0 || !pending.some(p => p.requestId === cbDecision.requestId)) {
460
+ if (
461
+ pending.length === 0 ||
462
+ !pending.some((p) => p.requestId === cbDecision.requestId)
463
+ ) {
788
464
  log.warn(
789
465
  { conversationId, callbackRequestId: cbDecision.requestId },
790
- 'Callback request ID does not match any pending interaction, ignoring stale button press',
466
+ "Callback request ID does not match any pending interaction, ignoring stale button press",
791
467
  );
792
- return { handled: true, type: 'stale_ignored' };
468
+ return { handled: true, type: "stale_ignored" };
793
469
  }
794
470
  }
795
471
 
@@ -798,321 +474,96 @@ export async function handleApprovalInterception(
798
474
  if (result.applied) {
799
475
  // Post-decision delivery is handled by the onEvent callback
800
476
  // in the session that registered the pending interaction.
801
- return { handled: true, type: 'decision_applied' };
477
+ return { handled: true, type: "decision_applied" };
802
478
  }
803
479
 
804
480
  // Race condition: request was already resolved between the stale check
805
481
  // above and the decision attempt.
806
- return { handled: true, type: 'stale_ignored' };
482
+ return { handled: true, type: "stale_ignored" };
807
483
  }
808
484
  }
809
485
 
810
486
  // ── Conversational approval engine for plain-text messages ──
811
- // Instead of deterministic keyword matching and reminder prompts, delegate
812
- // to the conversational approval engine which can classify natural language
813
- // and respond conversationally.
487
+ // Delegates to the text engine strategy which classifies natural language
488
+ // and responds conversationally.
814
489
  const pending = getApprovalInfoByConversation(conversationId);
815
490
  if (pending.length > 0 && approvalConversationGenerator && content) {
816
491
  const allowedActions = pendingPrompt.actions.map((a) => a.id);
817
- const engineContext: ApprovalConversationContext = {
818
- toolName: pending[0].toolName,
819
- allowedActions,
820
- role: 'requester',
821
- pendingApprovals: pending.map((p) => ({ requestId: p.requestId, toolName: p.toolName })),
822
- userMessage: content,
823
- };
824
-
825
- const engineResult = await runApprovalConversationTurn(engineContext, approvalConversationGenerator);
826
-
827
- if (engineResult.disposition === 'keep_pending') {
828
- // Non-decision follow-up — deliver the engine's reply and keep the request pending
829
- try {
830
- await deliverChannelReply(replyCallbackUrl, {
831
- chatId: conversationExternalId,
832
- text: engineResult.replyText,
833
- assistantId,
834
- }, bearerToken);
835
- } catch (err) {
836
- log.error({ err, conversationId }, 'Failed to deliver approval conversation reply');
837
- }
838
- return { handled: true, type: 'assistant_turn' };
839
- }
840
-
841
- // Decision-bearing disposition — map to ApprovalDecisionResult and apply
842
- const decisionAction = engineResult.disposition as ApprovalAction;
843
- const engineDecision: ApprovalDecisionResult = {
844
- action: decisionAction,
845
- source: 'plain_text',
846
- ...(engineResult.targetRequestId ? { requestId: engineResult.targetRequestId } : {}),
847
- };
848
-
849
- const result = handleChannelDecision(conversationId, engineDecision);
850
-
851
- if (result.applied) {
852
- // Deliver the engine's reply text to the user
853
- try {
854
- await deliverChannelReply(replyCallbackUrl, {
855
- chatId: conversationExternalId,
856
- text: engineResult.replyText,
857
- assistantId,
858
- }, bearerToken);
859
- } catch (err) {
860
- log.error({ err, conversationId }, 'Failed to deliver approval decision reply');
861
- }
862
-
863
- return { handled: true, type: 'decision_applied' };
864
- }
865
-
866
- // Race condition: request was already resolved by expiry sweep or
867
- // concurrent callback. Deliver a stale notice instead of the
868
- // engine's optimistic reply.
869
- try {
870
- const staleText = await composeApprovalMessageGenerative({
871
- scenario: 'approval_already_resolved',
872
- channel: sourceChannel,
873
- }, {}, approvalCopyGenerator);
874
- await deliverChannelReply(replyCallbackUrl, {
875
- chatId: conversationExternalId,
876
- text: staleText,
877
- assistantId,
878
- }, bearerToken);
879
- } catch (err) {
880
- log.error({ err, conversationId }, 'Failed to deliver stale approval notice');
881
- }
882
-
883
- return { handled: true, type: 'stale_ignored' };
884
- }
885
-
886
- // Fallback: no conversational generator available or no content — use
887
- // the legacy deterministic path as a safety net. This preserves backward
888
- // compatibility when the generator is not injected.
889
- if (content) {
890
- const legacyDecision = parseApprovalDecision(content);
891
- if (legacyDecision) {
892
- if (legacyDecision.requestId) {
893
- if (pending.length === 0 || !pending.some(p => p.requestId === legacyDecision.requestId)) {
894
- return { handled: true, type: 'stale_ignored' };
895
- }
896
- }
897
- const result = handleChannelDecision(conversationId, legacyDecision);
898
- if (result.applied) {
899
- return { handled: true, type: 'decision_applied' };
900
- }
901
-
902
- // Race condition: request was already resolved.
903
- try {
904
- const staleText = await composeApprovalMessageGenerative({
905
- scenario: 'approval_already_resolved',
906
- channel: sourceChannel,
907
- }, {}, approvalCopyGenerator);
908
- await deliverChannelReply(replyCallbackUrl, {
909
- chatId: conversationExternalId,
910
- text: staleText,
911
- assistantId,
912
- }, bearerToken);
913
- } catch (err) {
914
- log.error({ err, conversationId }, 'Failed to deliver stale approval notice (legacy path)');
915
- }
916
- return { handled: true, type: 'stale_ignored' };
917
- }
918
- }
919
-
920
- // No decision could be extracted and no conversational engine is available —
921
- // deliver a simple status reply rather than a reminder prompt.
922
- try {
923
- const statusText = await composeApprovalMessageGenerative({
924
- scenario: 'reminder_prompt',
925
- channel: sourceChannel,
926
- toolName: pending.length > 0 ? pending[0].toolName : undefined,
927
- }, {}, approvalCopyGenerator);
928
- await deliverChannelReply(replyCallbackUrl, {
929
- chatId: conversationExternalId,
930
- text: statusText,
931
- assistantId,
932
- }, bearerToken);
933
- } catch (err) {
934
- log.error({ err, conversationId }, 'Failed to deliver approval status reply');
935
- }
936
-
937
- return { handled: true, type: 'assistant_turn' };
938
- }
939
-
940
- // ---------------------------------------------------------------------------
941
- // Access request decision helper
942
- // ---------------------------------------------------------------------------
943
-
944
- /**
945
- * Handle a guardian's decision on an `ingress_access_request` approval.
946
- * Delegates to the access-request-decision module and orchestrates
947
- * notification delivery.
948
- *
949
- * On approve: creates a verification session, delivers the code to the
950
- * guardian, and notifies the requester to expect a code.
951
- *
952
- * On deny: marks the request as denied and notifies the requester.
953
- */
954
- async function handleAccessRequestApproval(
955
- approval: GuardianApprovalRequest,
956
- action: 'approve' | 'deny',
957
- decidedByExternalUserId: string,
958
- replyCallbackUrl: string,
959
- assistantId: string,
960
- bearerToken?: string,
961
- ): Promise<ApprovalInterceptionResult> {
962
- const decisionResult = handleAccessRequestDecision(
963
- approval,
964
- action,
965
- decidedByExternalUserId,
966
- );
967
-
968
- if (decisionResult.type === 'stale' || decisionResult.type === 'idempotent') {
969
- return { handled: true, type: 'stale_ignored' };
970
- }
971
-
972
- if (decisionResult.type === 'denied') {
973
- await notifyRequesterOfDenial({
492
+ return handleGuardianTextEngineDecision({
493
+ conversationId,
494
+ conversationExternalId,
495
+ sourceChannel,
974
496
  replyCallbackUrl,
975
- requesterChatId: approval.requesterChatId,
497
+ content,
976
498
  assistantId,
977
499
  bearerToken,
500
+ approvalCopyGenerator,
501
+ approvalConversationGenerator,
502
+ pending,
503
+ allowedActions,
978
504
  });
979
-
980
- // Emit both guardian_decision and denied signals so all lifecycle
981
- // observers are notified of the denial.
982
- const deniedPayload = {
983
- sourceChannel: approval.channel,
984
- requesterExternalUserId: approval.requesterExternalUserId,
985
- requesterChatId: approval.requesterChatId,
986
- decidedByExternalUserId,
987
- decision: 'denied' as const,
988
- };
989
-
990
- void emitNotificationSignal({
991
- sourceEventName: 'ingress.trusted_contact.guardian_decision',
992
- sourceChannel: approval.channel,
993
- sourceSessionId: approval.conversationId,
994
- assistantId,
995
- attentionHints: {
996
- requiresAction: false,
997
- urgency: 'medium',
998
- isAsyncBackground: false,
999
- visibleInSourceNow: false,
1000
- },
1001
- contextPayload: deniedPayload,
1002
- dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
1003
- });
1004
-
1005
- void emitNotificationSignal({
1006
- sourceEventName: 'ingress.trusted_contact.denied',
1007
- sourceChannel: approval.channel,
1008
- sourceSessionId: approval.conversationId,
1009
- assistantId,
1010
- attentionHints: {
1011
- requiresAction: false,
1012
- urgency: 'low',
1013
- isAsyncBackground: false,
1014
- visibleInSourceNow: false,
1015
- },
1016
- contextPayload: deniedPayload,
1017
- dedupeKey: `trusted-contact:denied:${approval.id}`,
1018
- });
1019
-
1020
- return { handled: true, type: 'guardian_decision_applied' };
1021
505
  }
1022
506
 
1023
- // Approved: deliver the verification code to the guardian and notify the requester.
1024
- const requesterIdentifier = approval.requesterExternalUserId;
1025
-
1026
- let codeDelivered = true;
1027
- if (decisionResult.verificationCode) {
1028
- const deliveryResult: DeliveryResult = await deliverVerificationCodeToGuardian({
1029
- replyCallbackUrl,
1030
- guardianChatId: approval.guardianChatId,
1031
- requesterIdentifier,
1032
- verificationCode: decisionResult.verificationCode,
1033
- assistantId,
1034
- bearerToken,
1035
- });
1036
- if (!deliveryResult.ok) {
1037
- log.error(
1038
- { reason: deliveryResult.reason, approvalId: approval.id },
1039
- 'Skipping requester notification verification code was not delivered to guardian',
1040
- );
1041
- codeDelivered = false;
507
+ // ── Natural language approval intent parser ──
508
+ // Covers a broad set of colloquial approval/rejection phrases, emoji, and
509
+ // timed-approval variants. Runs before the legacy parser to provide wider
510
+ // coverage for channels (like Slack) that rely on plain-text responses.
511
+ if (pending.length > 0 && content) {
512
+ const nlIntent = parseApprovalIntent(content);
513
+ if (nlIntent && nlIntent.confidence >= 0.9) {
514
+ const nlDecision: ApprovalDecisionResult = {
515
+ action:
516
+ nlIntent.decision === "approve"
517
+ ? "approve_once"
518
+ : nlIntent.decision === "approve_10m"
519
+ ? "approve_10m"
520
+ : "reject",
521
+ source: "plain_text",
522
+ };
523
+ const nlResult = handleChannelDecision(conversationId, nlDecision);
524
+ if (nlResult.applied) {
525
+ return { handled: true, type: "decision_applied" };
526
+ }
1042
527
  }
1043
528
  }
1044
529
 
1045
- if (codeDelivered) {
1046
- await notifyRequesterOfApproval({
1047
- replyCallbackUrl,
1048
- requesterChatId: approval.requesterChatId,
1049
- assistantId,
1050
- bearerToken,
1051
- });
1052
- } else {
1053
- // Let the requester know something went wrong without revealing details
1054
- await notifyRequesterOfDeliveryFailure({
530
+ // ── Legacy deterministic fallback ──
531
+ // When no conversational engine is available, use the deterministic parser
532
+ // as a safety net for backward compatibility.
533
+ if (content) {
534
+ const legacyResult = await handleGuardianLegacyFallback({
535
+ conversationId,
536
+ conversationExternalId,
537
+ sourceChannel,
1055
538
  replyCallbackUrl,
1056
- requesterChatId: approval.requesterChatId,
539
+ content,
1057
540
  assistantId,
1058
541
  bearerToken,
542
+ approvalCopyGenerator,
543
+ pending,
1059
544
  });
545
+ if (legacyResult) {
546
+ return legacyResult;
547
+ }
1060
548
  }
1061
549
 
1062
- // Don't emit guardian_decision for approvals that still require code
1063
- // verification the guardian already received the code, and emitting
1064
- // this signal prematurely causes the notification pipeline to deliver
1065
- // a confusing "approved" message before the requester has verified.
1066
- // The guardian_decision signal should only fire once access is fully granted
1067
- // (i.e. after code consumption), which is handled in the verification path.
1068
- if (!decisionResult.verificationSessionId) {
1069
- void emitNotificationSignal({
1070
- sourceEventName: 'ingress.trusted_contact.guardian_decision',
1071
- sourceChannel: approval.channel,
1072
- sourceSessionId: approval.conversationId,
1073
- assistantId,
1074
- attentionHints: {
1075
- requiresAction: false,
1076
- urgency: 'medium',
1077
- isAsyncBackground: false,
1078
- visibleInSourceNow: false,
1079
- },
1080
- contextPayload: {
1081
- sourceChannel: approval.channel,
1082
- requesterExternalUserId: approval.requesterExternalUserId,
1083
- requesterChatId: approval.requesterChatId,
1084
- decidedByExternalUserId,
1085
- decision: 'approved',
1086
- },
1087
- dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
1088
- });
1089
- }
1090
-
1091
- // Emit verification_sent with visibleInSourceNow=true so the notification
1092
- // pipeline suppresses delivery — the guardian already received the
1093
- // verification code directly. Without this flag, the pipeline generates
1094
- // a redundant LLM message like "Good news! Your request has been approved."
1095
- if (decisionResult.verificationSessionId && codeDelivered) {
1096
- void emitNotificationSignal({
1097
- sourceEventName: 'ingress.trusted_contact.verification_sent',
1098
- sourceChannel: approval.channel,
1099
- sourceSessionId: approval.conversationId,
1100
- assistantId,
1101
- attentionHints: {
1102
- requiresAction: false,
1103
- urgency: 'low',
1104
- isAsyncBackground: true,
1105
- visibleInSourceNow: true,
1106
- },
1107
- contextPayload: {
1108
- sourceChannel: approval.channel,
1109
- requesterExternalUserId: approval.requesterExternalUserId,
1110
- requesterChatId: approval.requesterChatId,
1111
- verificationSessionId: decisionResult.verificationSessionId,
1112
- },
1113
- dedupeKey: `trusted-contact:verification-sent:${decisionResult.verificationSessionId}`,
1114
- });
1115
- }
550
+ // No decision could be extracted and no conversational engine is available —
551
+ // deliver a simple status reply rather than a reminder prompt.
552
+ await deliverStaleApprovalReply({
553
+ scenario: "reminder_prompt",
554
+ sourceChannel,
555
+ replyCallbackUrl,
556
+ chatId: conversationExternalId,
557
+ assistantId,
558
+ bearerToken,
559
+ approvalCopyGenerator,
560
+ logger: log,
561
+ errorLogMessage: "Failed to deliver approval status reply",
562
+ extraContext: {
563
+ toolName: pending.length > 0 ? pending[0].toolName : undefined,
564
+ },
565
+ errorLogContext: { conversationId },
566
+ });
1116
567
 
1117
- return { handled: true, type: 'guardian_decision_applied' };
568
+ return { handled: true, type: "assistant_turn" };
1118
569
  }