@vellumai/assistant 0.10.0 → 0.10.1-staging.1

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 (824) hide show
  1. package/ARCHITECTURE.md +36 -37
  2. package/bun.lock +3 -0
  3. package/docs/workflows.md +12 -7
  4. package/eslint-rules/cli-no-daemon-internals.js +6 -0
  5. package/node_modules/@slack/types/LICENSE +23 -0
  6. package/node_modules/@slack/types/README.md +32 -0
  7. package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts +953 -0
  8. package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts.map +1 -0
  9. package/node_modules/@slack/types/dist/block-kit/block-elements.js +4 -0
  10. package/node_modules/@slack/types/dist/block-kit/block-elements.js.map +1 -0
  11. package/node_modules/@slack/types/dist/block-kit/blocks.d.ts +474 -0
  12. package/node_modules/@slack/types/dist/block-kit/blocks.d.ts.map +1 -0
  13. package/node_modules/@slack/types/dist/block-kit/blocks.js +3 -0
  14. package/node_modules/@slack/types/dist/block-kit/blocks.js.map +1 -0
  15. package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts +237 -0
  16. package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts.map +1 -0
  17. package/node_modules/@slack/types/dist/block-kit/composition-objects.js +4 -0
  18. package/node_modules/@slack/types/dist/block-kit/composition-objects.js.map +1 -0
  19. package/node_modules/@slack/types/dist/block-kit/extensions.d.ts +88 -0
  20. package/node_modules/@slack/types/dist/block-kit/extensions.d.ts.map +1 -0
  21. package/node_modules/@slack/types/dist/block-kit/extensions.js +3 -0
  22. package/node_modules/@slack/types/dist/block-kit/extensions.js.map +1 -0
  23. package/node_modules/@slack/types/dist/calls.d.ts +26 -0
  24. package/node_modules/@slack/types/dist/calls.d.ts.map +1 -0
  25. package/node_modules/@slack/types/dist/calls.js +6 -0
  26. package/node_modules/@slack/types/dist/calls.js.map +1 -0
  27. package/node_modules/@slack/types/dist/chunk.d.ts +52 -0
  28. package/node_modules/@slack/types/dist/chunk.d.ts.map +1 -0
  29. package/node_modules/@slack/types/dist/chunk.js +3 -0
  30. package/node_modules/@slack/types/dist/chunk.js.map +1 -0
  31. package/node_modules/@slack/types/dist/common/bot-profile.d.ts +12 -0
  32. package/node_modules/@slack/types/dist/common/bot-profile.d.ts.map +1 -0
  33. package/node_modules/@slack/types/dist/common/bot-profile.js +3 -0
  34. package/node_modules/@slack/types/dist/common/bot-profile.js.map +1 -0
  35. package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts +6 -0
  36. package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts.map +1 -0
  37. package/node_modules/@slack/types/dist/common/status-emoji-display-info.js +3 -0
  38. package/node_modules/@slack/types/dist/common/status-emoji-display-info.js.map +1 -0
  39. package/node_modules/@slack/types/dist/dialog.d.ts +36 -0
  40. package/node_modules/@slack/types/dist/dialog.d.ts.map +1 -0
  41. package/node_modules/@slack/types/dist/dialog.js +3 -0
  42. package/node_modules/@slack/types/dist/dialog.js.map +1 -0
  43. package/node_modules/@slack/types/dist/events/app.d.ts +204 -0
  44. package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -0
  45. package/node_modules/@slack/types/dist/events/app.js +3 -0
  46. package/node_modules/@slack/types/dist/events/app.js.map +1 -0
  47. package/node_modules/@slack/types/dist/events/assistant.d.ts +29 -0
  48. package/node_modules/@slack/types/dist/events/assistant.d.ts.map +1 -0
  49. package/node_modules/@slack/types/dist/events/assistant.js +3 -0
  50. package/node_modules/@slack/types/dist/events/assistant.js.map +1 -0
  51. package/node_modules/@slack/types/dist/events/call.d.ts +8 -0
  52. package/node_modules/@slack/types/dist/events/call.d.ts.map +1 -0
  53. package/node_modules/@slack/types/dist/events/call.js +3 -0
  54. package/node_modules/@slack/types/dist/events/call.js.map +1 -0
  55. package/node_modules/@slack/types/dist/events/channel.d.ts +85 -0
  56. package/node_modules/@slack/types/dist/events/channel.d.ts.map +1 -0
  57. package/node_modules/@slack/types/dist/events/channel.js +3 -0
  58. package/node_modules/@slack/types/dist/events/channel.js.map +1 -0
  59. package/node_modules/@slack/types/dist/events/dnd.d.ts +24 -0
  60. package/node_modules/@slack/types/dist/events/dnd.d.ts.map +1 -0
  61. package/node_modules/@slack/types/dist/events/dnd.js +3 -0
  62. package/node_modules/@slack/types/dist/events/dnd.js.map +1 -0
  63. package/node_modules/@slack/types/dist/events/email.d.ts +6 -0
  64. package/node_modules/@slack/types/dist/events/email.d.ts.map +1 -0
  65. package/node_modules/@slack/types/dist/events/email.js +3 -0
  66. package/node_modules/@slack/types/dist/events/email.js.map +1 -0
  67. package/node_modules/@slack/types/dist/events/emoji.d.ts +11 -0
  68. package/node_modules/@slack/types/dist/events/emoji.d.ts.map +1 -0
  69. package/node_modules/@slack/types/dist/events/emoji.js +3 -0
  70. package/node_modules/@slack/types/dist/events/emoji.js.map +1 -0
  71. package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts +21 -0
  72. package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts.map +1 -0
  73. package/node_modules/@slack/types/dist/events/entity-details-requested.js +3 -0
  74. package/node_modules/@slack/types/dist/events/entity-details-requested.js.map +1 -0
  75. package/node_modules/@slack/types/dist/events/file.d.ts +60 -0
  76. package/node_modules/@slack/types/dist/events/file.d.ts.map +1 -0
  77. package/node_modules/@slack/types/dist/events/file.js +4 -0
  78. package/node_modules/@slack/types/dist/events/file.js.map +1 -0
  79. package/node_modules/@slack/types/dist/events/function.d.ts +33 -0
  80. package/node_modules/@slack/types/dist/events/function.d.ts.map +1 -0
  81. package/node_modules/@slack/types/dist/events/function.js +3 -0
  82. package/node_modules/@slack/types/dist/events/function.js.map +1 -0
  83. package/node_modules/@slack/types/dist/events/grid-migration.d.ts +9 -0
  84. package/node_modules/@slack/types/dist/events/grid-migration.d.ts.map +1 -0
  85. package/node_modules/@slack/types/dist/events/grid-migration.js +3 -0
  86. package/node_modules/@slack/types/dist/events/grid-migration.js.map +1 -0
  87. package/node_modules/@slack/types/dist/events/group.d.ts +55 -0
  88. package/node_modules/@slack/types/dist/events/group.d.ts.map +1 -0
  89. package/node_modules/@slack/types/dist/events/group.js +3 -0
  90. package/node_modules/@slack/types/dist/events/group.js.map +1 -0
  91. package/node_modules/@slack/types/dist/events/im.d.ts +26 -0
  92. package/node_modules/@slack/types/dist/events/im.d.ts.map +1 -0
  93. package/node_modules/@slack/types/dist/events/im.js +3 -0
  94. package/node_modules/@slack/types/dist/events/im.js.map +1 -0
  95. package/node_modules/@slack/types/dist/events/index.d.ts +60 -0
  96. package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -0
  97. package/node_modules/@slack/types/dist/events/index.js +43 -0
  98. package/node_modules/@slack/types/dist/events/index.js.map +1 -0
  99. package/node_modules/@slack/types/dist/events/invite.d.ts +20 -0
  100. package/node_modules/@slack/types/dist/events/invite.d.ts.map +1 -0
  101. package/node_modules/@slack/types/dist/events/invite.js +3 -0
  102. package/node_modules/@slack/types/dist/events/invite.js.map +1 -0
  103. package/node_modules/@slack/types/dist/events/link-shared.d.ts +16 -0
  104. package/node_modules/@slack/types/dist/events/link-shared.d.ts.map +1 -0
  105. package/node_modules/@slack/types/dist/events/link-shared.js +3 -0
  106. package/node_modules/@slack/types/dist/events/link-shared.js.map +1 -0
  107. package/node_modules/@slack/types/dist/events/member.d.ts +19 -0
  108. package/node_modules/@slack/types/dist/events/member.d.ts.map +1 -0
  109. package/node_modules/@slack/types/dist/events/member.js +3 -0
  110. package/node_modules/@slack/types/dist/events/member.js.map +1 -0
  111. package/node_modules/@slack/types/dist/events/message-metadata.d.ts +38 -0
  112. package/node_modules/@slack/types/dist/events/message-metadata.d.ts.map +1 -0
  113. package/node_modules/@slack/types/dist/events/message-metadata.js +3 -0
  114. package/node_modules/@slack/types/dist/events/message-metadata.js.map +1 -0
  115. package/node_modules/@slack/types/dist/events/message.d.ts +306 -0
  116. package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -0
  117. package/node_modules/@slack/types/dist/events/message.js +3 -0
  118. package/node_modules/@slack/types/dist/events/message.js.map +1 -0
  119. package/node_modules/@slack/types/dist/events/pin.d.ts +60 -0
  120. package/node_modules/@slack/types/dist/events/pin.d.ts.map +1 -0
  121. package/node_modules/@slack/types/dist/events/pin.js +3 -0
  122. package/node_modules/@slack/types/dist/events/pin.js.map +1 -0
  123. package/node_modules/@slack/types/dist/events/reaction.d.ts +23 -0
  124. package/node_modules/@slack/types/dist/events/reaction.d.ts.map +1 -0
  125. package/node_modules/@slack/types/dist/events/reaction.js +3 -0
  126. package/node_modules/@slack/types/dist/events/reaction.js.map +1 -0
  127. package/node_modules/@slack/types/dist/events/shared-channel.d.ts +134 -0
  128. package/node_modules/@slack/types/dist/events/shared-channel.d.ts.map +1 -0
  129. package/node_modules/@slack/types/dist/events/shared-channel.js +3 -0
  130. package/node_modules/@slack/types/dist/events/shared-channel.js.map +1 -0
  131. package/node_modules/@slack/types/dist/events/star.d.ts +13 -0
  132. package/node_modules/@slack/types/dist/events/star.d.ts.map +1 -0
  133. package/node_modules/@slack/types/dist/events/star.js +3 -0
  134. package/node_modules/@slack/types/dist/events/star.js.map +1 -0
  135. package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts +82 -0
  136. package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts.map +1 -0
  137. package/node_modules/@slack/types/dist/events/steps-from-apps.js +3 -0
  138. package/node_modules/@slack/types/dist/events/steps-from-apps.js.map +1 -0
  139. package/node_modules/@slack/types/dist/events/subteam.d.ts +66 -0
  140. package/node_modules/@slack/types/dist/events/subteam.d.ts.map +1 -0
  141. package/node_modules/@slack/types/dist/events/subteam.js +3 -0
  142. package/node_modules/@slack/types/dist/events/subteam.js.map +1 -0
  143. package/node_modules/@slack/types/dist/events/team.d.ts +99 -0
  144. package/node_modules/@slack/types/dist/events/team.d.ts.map +1 -0
  145. package/node_modules/@slack/types/dist/events/team.js +3 -0
  146. package/node_modules/@slack/types/dist/events/team.js.map +1 -0
  147. package/node_modules/@slack/types/dist/events/token.d.ts +8 -0
  148. package/node_modules/@slack/types/dist/events/token.d.ts.map +1 -0
  149. package/node_modules/@slack/types/dist/events/token.js +3 -0
  150. package/node_modules/@slack/types/dist/events/token.js.map +1 -0
  151. package/node_modules/@slack/types/dist/events/user.d.ts +313 -0
  152. package/node_modules/@slack/types/dist/events/user.d.ts.map +1 -0
  153. package/node_modules/@slack/types/dist/events/user.js +3 -0
  154. package/node_modules/@slack/types/dist/events/user.js.map +1 -0
  155. package/node_modules/@slack/types/dist/index.d.ts +12 -0
  156. package/node_modules/@slack/types/dist/index.d.ts.map +1 -0
  157. package/node_modules/@slack/types/dist/index.js +28 -0
  158. package/node_modules/@slack/types/dist/index.js.map +1 -0
  159. package/node_modules/@slack/types/dist/message-attachments.d.ts +171 -0
  160. package/node_modules/@slack/types/dist/message-attachments.d.ts.map +1 -0
  161. package/node_modules/@slack/types/dist/message-attachments.js +3 -0
  162. package/node_modules/@slack/types/dist/message-attachments.js.map +1 -0
  163. package/node_modules/@slack/types/dist/message-metadata.d.ts +281 -0
  164. package/node_modules/@slack/types/dist/message-metadata.d.ts.map +1 -0
  165. package/node_modules/@slack/types/dist/message-metadata.js +27 -0
  166. package/node_modules/@slack/types/dist/message-metadata.js.map +1 -0
  167. package/node_modules/@slack/types/dist/views.d.ts +71 -0
  168. package/node_modules/@slack/types/dist/views.d.ts.map +1 -0
  169. package/node_modules/@slack/types/dist/views.js +3 -0
  170. package/node_modules/@slack/types/dist/views.js.map +1 -0
  171. package/node_modules/@slack/types/package.json +47 -0
  172. package/node_modules/@vellumai/gateway-client/bun.lock +3 -0
  173. package/node_modules/@vellumai/gateway-client/package.json +1 -0
  174. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +69 -0
  175. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +65 -0
  176. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
  177. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
  178. package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
  179. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +4 -2
  180. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +3 -2
  181. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +78 -0
  182. package/openapi.yaml +345 -18
  183. package/package.json +2 -1
  184. package/scripts/memory-inspect.ts +24 -14
  185. package/src/__tests__/access-request-seed-content-blocks.test.ts +83 -103
  186. package/src/__tests__/activation-early-marking.test.ts +1 -1
  187. package/src/__tests__/actor-token-service.test.ts +3 -3
  188. package/src/__tests__/agent-loop-callsite-precedence.test.ts +1 -40
  189. package/src/__tests__/agent-loop-compaction-events.test.ts +0 -1
  190. package/src/__tests__/agent-loop-compaction-strip.test.ts +0 -1
  191. package/src/__tests__/agent-loop-exit-reason.test.ts +0 -1
  192. package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
  193. package/src/__tests__/agent-loop-regrowth-guard.test.ts +0 -1
  194. package/src/__tests__/agent-loop.test.ts +3 -0
  195. package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
  196. package/src/__tests__/anthropic-provider.test.ts +143 -9
  197. package/src/__tests__/app-builder-skill-instructions.test.ts +47 -5
  198. package/src/__tests__/app-conversation-ids-backfill.test.ts +1 -1
  199. package/src/__tests__/app-source-watcher.test.ts +30 -10
  200. package/src/__tests__/approval-cascade.test.ts +6 -0
  201. package/src/__tests__/approval-interception-trust-gates.test.ts +151 -0
  202. package/src/__tests__/approval-primitive.test.ts +1 -1
  203. package/src/__tests__/approval-routes-http.test.ts +1 -1
  204. package/src/__tests__/assistant-attachments.test.ts +155 -0
  205. package/src/__tests__/assistant-event-hub-machine-name.test.ts +2 -4
  206. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  207. package/src/__tests__/assistant-events-sse-shed.test.ts +1 -1
  208. package/src/__tests__/attachment-upload-trusted-source.test.ts +13 -8
  209. package/src/__tests__/attachments-store.test.ts +1 -1
  210. package/src/__tests__/audit-log-rotation.test.ts +50 -54
  211. package/src/__tests__/auth-fallback-events-store.test.ts +1 -1
  212. package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -14
  213. package/src/__tests__/background-shell-bash.test.ts +4 -1
  214. package/src/__tests__/background-shell-host-bash.test.ts +17 -3
  215. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  216. package/src/__tests__/call-controller.test.ts +1 -1
  217. package/src/__tests__/call-conversation-messages.test.ts +1 -1
  218. package/src/__tests__/call-domain.test.ts +1 -1
  219. package/src/__tests__/call-pointer-messages.test.ts +3 -4
  220. package/src/__tests__/call-recovery.test.ts +1 -1
  221. package/src/__tests__/call-routes-http.test.ts +1 -1
  222. package/src/__tests__/call-store.test.ts +1 -1
  223. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  224. package/src/__tests__/canonical-guardian-store.test.ts +24 -1
  225. package/src/__tests__/channel-approval-routes.test.ts +73 -1119
  226. package/src/__tests__/channel-delivery-store.test.ts +1 -1
  227. package/src/__tests__/channel-guardian.test.ts +265 -641
  228. package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -2
  229. package/src/__tests__/channel-retry-sweep.test.ts +1 -1
  230. package/src/__tests__/compaction-events.test.ts +6 -0
  231. package/src/__tests__/compaction-trail-store.test.ts +6 -5
  232. package/src/__tests__/compaction.benchmark.test.ts +0 -1
  233. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  234. package/src/__tests__/config-loader-backfill.test.ts +183 -51
  235. package/src/__tests__/config-schema.test.ts +34 -0
  236. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -2
  237. package/src/__tests__/contact-store-user-file.test.ts +2 -2
  238. package/src/__tests__/contacts-relay-reads.test.ts +409 -0
  239. package/src/__tests__/contacts-tools.test.ts +4 -4
  240. package/src/__tests__/contacts-write.test.ts +1 -2
  241. package/src/__tests__/context-search-conversations-source.test.ts +1 -1
  242. package/src/__tests__/context-window-manager-compact-retry.test.ts +6 -2
  243. package/src/__tests__/context-window-manager-overflow-rung.test.ts +6 -2
  244. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  245. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
  246. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
  247. package/src/__tests__/conversation-agent-loop-overflow.test.ts +3 -0
  248. package/src/__tests__/conversation-agent-loop.test.ts +3 -0
  249. package/src/__tests__/conversation-attachments.test.ts +2 -5
  250. package/src/__tests__/conversation-attention-store.test.ts +1 -1
  251. package/src/__tests__/conversation-attention-telegram.test.ts +1 -2
  252. package/src/__tests__/conversation-clear-safety.test.ts +1 -1
  253. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
  254. package/src/__tests__/conversation-crud-inference-profile.test.ts +1 -1
  255. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +12 -19
  256. package/src/__tests__/conversation-disk-view-integration.test.ts +1 -1
  257. package/src/__tests__/conversation-disk-view.test.ts +1 -1
  258. package/src/__tests__/conversation-fork-crud.test.ts +10 -8
  259. package/src/__tests__/conversation-fork-retrospective.test.ts +250 -0
  260. package/src/__tests__/conversation-fork-route.test.ts +1 -1
  261. package/src/__tests__/conversation-inference-profile-list.test.ts +1 -1
  262. package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
  263. package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
  264. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  265. package/src/__tests__/conversation-lifecycle.test.ts +117 -0
  266. package/src/__tests__/conversation-list-source.test.ts +3 -3
  267. package/src/__tests__/conversation-process-callsite.test.ts +6 -14
  268. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  269. package/src/__tests__/conversation-queue.test.ts +6 -0
  270. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  271. package/src/__tests__/conversation-runtime-assembly.test.ts +115 -12
  272. package/src/__tests__/conversation-slash-queue.test.ts +6 -0
  273. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  274. package/src/__tests__/conversation-speed-override.test.ts +6 -0
  275. package/src/__tests__/conversation-starter-routes.test.ts +5 -5
  276. package/src/__tests__/conversation-store.test.ts +1 -1
  277. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -1
  278. package/src/__tests__/conversation-sync-tags.test.ts +1 -1
  279. package/src/__tests__/conversation-usage.test.ts +1 -1
  280. package/src/__tests__/conversation-wipe.test.ts +9 -8
  281. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
  282. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  283. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  284. package/src/__tests__/conversations-import-system-filter.test.ts +1 -1
  285. package/src/__tests__/copy-composer-tc-templates.test.ts +17 -0
  286. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  287. package/src/__tests__/db-acp-history.test.ts +2 -2
  288. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +5 -7
  289. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -7
  290. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +5 -10
  291. package/src/__tests__/db-migration-rollback.test.ts +129 -39
  292. package/src/__tests__/db-proxy-transaction.test.ts +1 -1
  293. package/src/__tests__/db-schedule-syntax-migration.test.ts +0 -11
  294. package/src/__tests__/db-test-helpers.ts +36 -19
  295. package/src/__tests__/delete-propagation.test.ts +1 -1
  296. package/src/__tests__/deterministic-verification-control-plane.test.ts +26 -8
  297. package/src/__tests__/disk-pressure-tools.test.ts +41 -1
  298. package/src/__tests__/dm-backfill.test.ts +1 -1
  299. package/src/__tests__/drop-capability-card-state-migration.test.ts +0 -8
  300. package/src/__tests__/edit-propagation.test.ts +1 -1
  301. package/src/__tests__/emit-signal-routing-intent.test.ts +83 -0
  302. package/src/__tests__/empty-response-hook.test.ts +42 -0
  303. package/src/__tests__/events-client-registration.test.ts +1 -1
  304. package/src/__tests__/followup-tools.test.ts +1 -1
  305. package/src/__tests__/gemini-count-tokens.test.ts +70 -0
  306. package/src/__tests__/guardian-action-sweep.test.ts +9 -2
  307. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  308. package/src/__tests__/guardian-card-withdrawal.test.ts +1 -1
  309. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -1
  310. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  311. package/src/__tests__/guardian-outbound-http.test.ts +7 -12
  312. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +1 -1
  313. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  314. package/src/__tests__/guardian-routing-state.test.ts +1 -2
  315. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  316. package/src/__tests__/headless-browser-mode.test.ts +2 -2
  317. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  318. package/src/__tests__/heartbeat-service.test.ts +6 -0
  319. package/src/__tests__/helpers/channel-test-adapter.ts +98 -0
  320. package/src/__tests__/http-conversation-lineage.test.ts +1 -1
  321. package/src/__tests__/image-recovery-hook.test.ts +1 -1
  322. package/src/__tests__/inbound-invite-redemption.test.ts +1 -2
  323. package/src/__tests__/inbound-trust-verdict.test.ts +254 -0
  324. package/src/__tests__/inference-profile-reaper.test.ts +1 -1
  325. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  326. package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
  327. package/src/__tests__/injector-chain.test.ts +1 -1
  328. package/src/__tests__/injector-disk-pressure.test.ts +11 -6
  329. package/src/__tests__/internal-telemetry-routes.test.ts +1 -1
  330. package/src/__tests__/invite-redemption-service.test.ts +244 -43
  331. package/src/__tests__/invite-routes-http.test.ts +35 -186
  332. package/src/__tests__/invite-service-ipc.test.ts +287 -0
  333. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +5 -5
  334. package/src/__tests__/jobs-store-upsert-debounced.test.ts +9 -12
  335. package/src/__tests__/list-messages-attachments.test.ts +42 -1
  336. package/src/__tests__/list-messages-client-message-id.test.ts +1 -1
  337. package/src/__tests__/list-messages-hidden-metadata.test.ts +1 -1
  338. package/src/__tests__/list-messages-page-latest.test.ts +1 -1
  339. package/src/__tests__/list-messages-tool-merge.test.ts +1 -1
  340. package/src/__tests__/llm-context-route-provider.test.ts +69 -4
  341. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +9 -5
  342. package/src/__tests__/llm-request-log-call-site.test.ts +6 -6
  343. package/src/__tests__/llm-request-log-turn-query.test.ts +27 -13
  344. package/src/__tests__/llm-usage-store.test.ts +40 -1
  345. package/src/__tests__/log-export-routes.test.ts +1 -1
  346. package/src/__tests__/log-export-workspace.test.ts +3 -3
  347. package/src/__tests__/memory-jobs-worker-lanes.test.ts +5 -5
  348. package/src/__tests__/memory-recall-log-store.test.ts +1 -1
  349. package/src/__tests__/memory-upsert-concurrency.test.ts +3 -4
  350. package/src/__tests__/messages-after-tiebreaker.test.ts +1 -1
  351. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  352. package/src/__tests__/mtime-cache.test.ts +375 -0
  353. package/src/__tests__/non-member-access-request.test.ts +1 -2
  354. package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
  355. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  356. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  357. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  358. package/src/__tests__/oauth-provider-visibility.test.ts +1 -1
  359. package/src/__tests__/oauth-store.test.ts +1 -1
  360. package/src/__tests__/persist-unsendable-image-downscale.test.ts +1 -1
  361. package/src/__tests__/persist-unsendable-image.test.ts +1 -1
  362. package/src/__tests__/persona-resolver.test.ts +39 -1
  363. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  364. package/src/__tests__/playbook-execution.test.ts +1 -1
  365. package/src/__tests__/playbook-tools.test.ts +1 -1
  366. package/src/__tests__/plugin-api-model-profiles.test.ts +74 -21
  367. package/src/__tests__/plugin-bootstrap.test.ts +78 -0
  368. package/src/__tests__/provider-platform-proxy-integration.test.ts +25 -5
  369. package/src/__tests__/provider-usage-tracking.test.ts +1 -1
  370. package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
  371. package/src/__tests__/reaction-persistence.test.ts +1 -1
  372. package/src/__tests__/relay-server.test.ts +357 -56
  373. package/src/__tests__/runtime-attachment-metadata.test.ts +10 -1
  374. package/src/__tests__/runtime-events-sse-bilingual.test.ts +7 -9
  375. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  376. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  377. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  378. package/src/__tests__/schedule-retry.test.ts +1 -1
  379. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -1
  380. package/src/__tests__/schedule-routes.test.ts +1 -1
  381. package/src/__tests__/schedule-store.test.ts +1 -1
  382. package/src/__tests__/schedule-tools.test.ts +1 -1
  383. package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
  384. package/src/__tests__/scheduler-recurrence.test.ts +1 -1
  385. package/src/__tests__/scheduler-reuse-conversation.test.ts +1 -1
  386. package/src/__tests__/scheduler-wake.test.ts +2 -1
  387. package/src/__tests__/scoped-approval-grants.test.ts +1 -1
  388. package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -5
  389. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +0 -8
  390. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -0
  391. package/src/__tests__/send-endpoint-busy.test.ts +1 -1
  392. package/src/__tests__/sequence-store.test.ts +1 -1
  393. package/src/__tests__/server-history-render.test.ts +40 -1
  394. package/src/__tests__/settings-routes.test.ts +11 -10
  395. package/src/__tests__/skill-load-tool.test.ts +72 -0
  396. package/src/__tests__/slack-inbound-verification.test.ts +1 -3
  397. package/src/__tests__/slack-messaging-token-resolution.test.ts +13 -2
  398. package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -1
  399. package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -73
  400. package/src/__tests__/subagent-tools.test.ts +1 -31
  401. package/src/__tests__/system-prompt.test.ts +1 -1
  402. package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
  403. package/src/__tests__/task-compiler.test.ts +1 -1
  404. package/src/__tests__/task-management-tools.test.ts +1 -1
  405. package/src/__tests__/task-memory-cleanup.test.ts +9 -6
  406. package/src/__tests__/task-scheduler.test.ts +1 -1
  407. package/src/__tests__/thread-backfill.test.ts +1 -1
  408. package/src/__tests__/tool-approval-handler.test.ts +1 -1
  409. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -0
  410. package/src/__tests__/tool-executor.test.ts +32 -1
  411. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -2
  412. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +73 -1
  413. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +34 -34
  414. package/src/__tests__/trusted-contact-multichannel.test.ts +1 -2
  415. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  416. package/src/__tests__/turn-boundary-resolution.test.ts +3 -3
  417. package/src/__tests__/turn-events-store.test.ts +1 -1
  418. package/src/__tests__/twilio-routes.test.ts +2 -3
  419. package/src/__tests__/usage-cache-backfill-migration.test.ts +20 -10
  420. package/src/__tests__/usage-routes.test.ts +1 -1
  421. package/src/__tests__/user-plugin-loader.test.ts +34 -29
  422. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  423. package/src/__tests__/voice-invite-redemption.test.ts +134 -36
  424. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
  425. package/src/__tests__/voice-session-bridge.test.ts +1 -1
  426. package/src/__tests__/workspace-git-service.test.ts +114 -1
  427. package/src/__tests__/workspace-heartbeat-service.test.ts +45 -0
  428. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +1 -1
  429. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
  430. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +88 -18
  431. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +6 -6
  432. package/src/__tests__/workspace-migration-109-swap-quality-profile-to-glm-5p2.test.ts +281 -0
  433. package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +167 -0
  434. package/src/__tests__/workspace-migrations-runner.test.ts +55 -0
  435. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +1 -1
  436. package/src/a2a/__tests__/task-store.test.ts +1 -1
  437. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -1
  438. package/src/acp/__tests__/session-manager-resume.test.ts +22 -11
  439. package/src/acp/__tests__/session-manager-startup.test.ts +1 -1
  440. package/src/acp/__tests__/session-manager.test.ts +72 -1
  441. package/src/acp/index.ts +10 -0
  442. package/src/acp/session-manager.ts +35 -0
  443. package/src/agent/loop.ts +45 -27
  444. package/src/api/index.ts +0 -6
  445. package/src/approvals/AGENTS.md +1 -2
  446. package/src/approvals/guardian-decision-primitive.ts +13 -210
  447. package/src/approvals/guardian-request-resolvers.ts +104 -58
  448. package/src/background-wake/wake-intent-hooks.test.ts +1 -1
  449. package/src/calls/__tests__/inbound-trust-reader.test.ts +110 -0
  450. package/src/calls/__tests__/relay-setup-router.test.ts +88 -62
  451. package/src/calls/inbound-trust-reader.ts +40 -0
  452. package/src/calls/relay-server.ts +65 -23
  453. package/src/calls/relay-setup-router.ts +20 -6
  454. package/src/calls/relay-verification.ts +7 -7
  455. package/src/cli/commands/contacts.ts +6 -24
  456. package/src/cli/commands/db/__tests__/repair.test.ts +15 -6
  457. package/src/cli/commands/db/__tests__/status.test.ts +7 -3
  458. package/src/cli/commands/db/status.ts +212 -33
  459. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +6 -1
  460. package/src/cli/commands/memory/index.ts +2 -0
  461. package/src/cli/commands/memory/memory-retrospective.ts +129 -0
  462. package/src/cli/commands/memory/memory-v3.ts +176 -4
  463. package/src/cli/commands/plugins.ts +268 -11
  464. package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
  465. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
  466. package/src/cli/lib/__tests__/toggle-plugin.test.ts +158 -0
  467. package/src/cli/lib/install-from-github.ts +47 -6
  468. package/src/cli/lib/plugin-marketplace.ts +11 -0
  469. package/src/cli/lib/plugin-pin-history.ts +257 -0
  470. package/src/cli/lib/toggle-plugin.ts +146 -0
  471. package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
  472. package/src/config/bundled-skills/app-builder/SKILL.md +15 -33
  473. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +3 -8
  474. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +64 -37
  475. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +1 -1
  476. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +14 -72
  477. package/src/config/bundled-skills/app-builder/references/examples/README.md +1 -2
  478. package/src/config/bundled-skills/contacts/SKILL.md +7 -12
  479. package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
  480. package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
  481. package/src/config/bundled-skills/workflows/SKILL.md +4 -3
  482. package/src/config/call-site-defaults.ts +11 -2
  483. package/src/config/feature-flag-registry.json +0 -8
  484. package/src/config/profile-dispatchability.ts +11 -0
  485. package/src/config/schemas/call-site-catalog.ts +7 -0
  486. package/src/config/schemas/llm.ts +2 -0
  487. package/src/config/schemas/memory-lifecycle.ts +5 -3
  488. package/src/config/schemas/timeouts.ts +24 -0
  489. package/src/config/seed-inference-profiles.ts +133 -45
  490. package/src/config/sync-gated-profiles.ts +13 -1
  491. package/src/contacts/contact-store.ts +21 -0
  492. package/src/contacts/member-status.ts +9 -0
  493. package/src/credential-health/credential-health-service.ts +1 -5
  494. package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
  495. package/src/daemon/app-source-watcher.ts +31 -18
  496. package/src/daemon/assistant-attachments.ts +94 -4
  497. package/src/daemon/conversation-agent-loop-handlers.ts +3 -0
  498. package/src/daemon/conversation-agent-loop.ts +9 -36
  499. package/src/daemon/conversation-runtime-assembly.ts +91 -66
  500. package/src/daemon/conversation-tool-setup.ts +20 -63
  501. package/src/daemon/conversation.ts +144 -52
  502. package/src/daemon/event-loop-watchdog.test.ts +85 -0
  503. package/src/daemon/event-loop-watchdog.ts +133 -0
  504. package/src/daemon/external-plugins-bootstrap.ts +26 -80
  505. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
  506. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +1 -1
  507. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +1 -1
  508. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +1 -1
  509. package/src/daemon/handlers/__tests__/config-a2a.test.ts +1 -1
  510. package/src/daemon/handlers/config-channels.ts +32 -18
  511. package/src/daemon/handlers/conversations.ts +7 -0
  512. package/src/daemon/handlers/shared.ts +7 -0
  513. package/src/daemon/lifecycle.ts +16 -3
  514. package/src/daemon/message-types/inbox.ts +0 -6
  515. package/src/daemon/message-types/messages.ts +0 -4
  516. package/src/daemon/message-types/surfaces.ts +18 -8
  517. package/src/daemon/server.ts +0 -4
  518. package/src/daemon/tool-setup-types.ts +0 -7
  519. package/src/daemon/trust-context.ts +6 -0
  520. package/src/daemon/wake-conversation-ops.ts +70 -0
  521. package/src/daemon/workspace-tools-watcher.ts +7 -3
  522. package/src/documents/document-comments-store.test.ts +1 -1
  523. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +1 -1
  524. package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -0
  525. package/src/heartbeat/heartbeat-service.ts +3 -4
  526. package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
  527. package/src/ipc/__tests__/browser-ipc.test.ts +73 -2
  528. package/src/ipc/__tests__/watcher-ipc.test.ts +59 -39
  529. package/src/ipc/assistant-server.ts +8 -0
  530. package/src/ipc/gateway-client.ts +2 -1
  531. package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +58 -0
  532. package/src/ipc/routes/invite-ipc-routes.ts +66 -0
  533. package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
  534. package/src/memory/__tests__/activation-session-store.test.ts +1 -1
  535. package/src/memory/__tests__/auto-analysis-guard.test.ts +1 -1
  536. package/src/memory/__tests__/conversation-group-migration.test.ts +1 -1
  537. package/src/memory/__tests__/conversation-queries.test.ts +1 -1
  538. package/src/memory/__tests__/db-async-query.test.ts +1 -1
  539. package/src/memory/__tests__/db-logs-attach.test.ts +110 -0
  540. package/src/memory/__tests__/db-maintenance.test.ts +28 -36
  541. package/src/memory/__tests__/db-memory-attach.test.ts +113 -0
  542. package/src/memory/__tests__/find-analysis-conversation.test.ts +1 -1
  543. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +1 -1
  544. package/src/memory/__tests__/fork-message-copy.test.ts +232 -0
  545. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +3 -0
  546. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +5 -5
  547. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +8 -6
  548. package/src/memory/__tests__/memory-retrospective-job.test.ts +30 -37
  549. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +69 -66
  550. package/src/memory/__tests__/memory-retrospective-state.test.ts +1 -1
  551. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  552. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +1 -1
  553. package/src/memory/__tests__/onboarding-events-store.test.ts +1 -1
  554. package/src/memory/__tests__/table-relocation.test.ts +129 -0
  555. package/src/memory/conversation-crud.ts +461 -152
  556. package/src/memory/db-async-query.ts +89 -5
  557. package/src/memory/db-connection.ts +101 -18
  558. package/src/memory/db-init.ts +409 -234
  559. package/src/memory/db-maintenance.ts +43 -38
  560. package/src/memory/db-singleton.ts +45 -19
  561. package/src/memory/fork-message-copy.ts +170 -0
  562. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +92 -0
  563. package/src/memory/graph/bootstrap.test.ts +6 -3
  564. package/src/memory/graph/retriever.test.ts +12 -12
  565. package/src/memory/graph/store.test.ts +15 -25
  566. package/src/memory/graph/store.ts +23 -14
  567. package/src/memory/graph/tool-handlers.ts +34 -5
  568. package/src/memory/graph/tools.ts +5 -2
  569. package/src/memory/indexer.ts +21 -9
  570. package/src/memory/job-handlers/cleanup.ts +10 -3
  571. package/src/memory/job-handlers/embedding.test.ts +4 -4
  572. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +4 -4
  573. package/src/memory/jobs/embed-pkb-file.test.ts +7 -7
  574. package/src/memory/jobs-store.ts +36 -24
  575. package/src/memory/llm-request-log-store.ts +51 -19
  576. package/src/memory/llm-usage-store.ts +31 -1
  577. package/src/memory/memory-retrospective-job.ts +27 -19
  578. package/src/memory/memory-retrospective-startup-cleanup.ts +10 -2
  579. package/src/memory/migrations/{100-core-tables.ts → 000-core-tables.ts} +6 -10
  580. package/src/memory/migrations/104-core-indexes.ts +1 -1
  581. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +189 -196
  582. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +98 -105
  583. package/src/memory/migrations/134-contacts-notes-column.ts +66 -69
  584. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +19 -22
  585. package/src/memory/migrations/136-drop-assistant-id-columns.ts +227 -230
  586. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +204 -209
  587. package/src/memory/migrations/141-rename-verification-table.ts +45 -48
  588. package/src/memory/migrations/142-rename-verification-session-id-column.ts +16 -23
  589. package/src/memory/migrations/143-rename-guardian-verification-values.ts +23 -30
  590. package/src/memory/migrations/144-rename-voice-to-phone.ts +133 -136
  591. package/src/memory/migrations/145-drop-accounts-table.ts +4 -7
  592. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +79 -82
  593. package/src/memory/migrations/148-drop-reminders-table.ts +3 -6
  594. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +71 -78
  595. package/src/memory/migrations/157-invite-contact-id.ts +73 -76
  596. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +44 -58
  597. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +36 -43
  598. package/src/memory/migrations/174-rename-thread-starters-table.ts +30 -37
  599. package/src/memory/migrations/176-drop-capability-card-state.ts +17 -22
  600. package/src/memory/migrations/177-create-trace-events-table.ts +23 -28
  601. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +36 -43
  602. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +14 -21
  603. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +17 -24
  604. package/src/memory/migrations/192-contacts-user-file-column.ts +6 -9
  605. package/src/memory/migrations/193-add-source-type-columns.ts +33 -36
  606. package/src/memory/migrations/194-memory-recall-logs.ts +34 -39
  607. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +59 -66
  608. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +41 -48
  609. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +11 -18
  610. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +76 -83
  611. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +50 -57
  612. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +6 -11
  613. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +4 -9
  614. package/src/memory/migrations/217-conversation-host-access.ts +13 -18
  615. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +86 -93
  616. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +41 -48
  617. package/src/memory/migrations/230-acp-session-history.ts +23 -28
  618. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +58 -62
  619. package/src/memory/migrations/232-activation-state.ts +11 -16
  620. package/src/memory/migrations/233-document-conversations.ts +20 -25
  621. package/src/memory/migrations/234-memory-v2-activation-logs.ts +26 -31
  622. package/src/memory/migrations/235-slack-compaction-watermark.ts +5 -10
  623. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +6 -11
  624. package/src/memory/migrations/237-heartbeat-runs.ts +22 -27
  625. package/src/memory/migrations/239-trace-events-created-at-index.ts +4 -9
  626. package/src/memory/migrations/242-message-bookmarks.ts +17 -22
  627. package/src/memory/migrations/245-memory-retrospective-state.ts +8 -13
  628. package/src/memory/migrations/249-normalize-slack-external-content.ts +37 -41
  629. package/src/memory/migrations/251-a2a-tasks.ts +27 -32
  630. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +12 -17
  631. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +10 -15
  632. package/src/memory/migrations/256-memory-v2-injection-events.ts +70 -74
  633. package/src/memory/migrations/259-conversation-cleaned-at.ts +4 -9
  634. package/src/memory/migrations/260-rename-cleaned-at.ts +11 -16
  635. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +3 -8
  636. package/src/memory/migrations/262-memory-v3-coactivation.ts +21 -26
  637. package/src/memory/migrations/263-memory-v3-auto-edges.ts +14 -19
  638. package/src/memory/migrations/270-schedule-description.ts +7 -12
  639. package/src/memory/migrations/272-acp-session-history-cwd.ts +8 -13
  640. package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +8 -13
  641. package/src/memory/migrations/297-move-llm-request-logs-to-logs-db.ts +111 -0
  642. package/src/memory/migrations/298-move-memory-jobs-to-memory-db.ts +128 -0
  643. package/src/memory/migrations/299-canonical-guardian-deliveries-conversation-index.ts +19 -0
  644. package/src/memory/migrations/__tests__/297-move-llm-request-logs.test.ts +180 -0
  645. package/src/memory/migrations/__tests__/run-migrations.test.ts +333 -7
  646. package/src/memory/migrations/helpers/relocation.ts +227 -0
  647. package/src/memory/migrations/registry.ts +63 -0
  648. package/src/memory/migrations/run-migrations.ts +187 -16
  649. package/src/memory/migrations/validate-migration-state.ts +50 -145
  650. package/src/memory/raw-query.ts +47 -2
  651. package/src/memory/skill-loaded-events-store.test.ts +1 -1
  652. package/src/memory/task-memory-cleanup.ts +62 -41
  653. package/src/memory/tool-executed-events-store.test.ts +1 -1
  654. package/src/memory/turn-trace-store.test.ts +1 -1
  655. package/src/memory/v2/__tests__/backfill-jobs.test.ts +16 -15
  656. package/src/memory/v2/__tests__/harness-compare.test.ts +1 -1
  657. package/src/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  658. package/src/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  659. package/src/memory/v2/__tests__/sweep-job.test.ts +2 -2
  660. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +38 -0
  661. package/src/memory/v3-eval/__tests__/eval-tally.test.ts +139 -0
  662. package/src/memory/v3-eval/eval-packets.ts +197 -12
  663. package/src/memory/v3-eval/eval-tally.ts +234 -0
  664. package/src/messaging/provider.ts +10 -0
  665. package/src/messaging/providers/gmail/adapter.ts +1 -0
  666. package/src/messaging/providers/gmail/client.ts +14 -0
  667. package/src/messaging/providers/index.ts +1 -1
  668. package/src/messaging/providers/slack/send.test.ts +87 -39
  669. package/src/messaging/providers/slack/send.ts +84 -105
  670. package/src/notifications/README.md +9 -5
  671. package/src/notifications/__tests__/deterministic-checks.test.ts +43 -1
  672. package/src/notifications/adapters/slack.ts +12 -10
  673. package/src/notifications/approval-card-builder.ts +81 -20
  674. package/src/notifications/approval-card-data.ts +8 -5
  675. package/src/notifications/canonical-delivery-recorder.ts +7 -5
  676. package/src/notifications/conversation-candidates.ts +24 -59
  677. package/src/notifications/copy-composer.ts +48 -68
  678. package/src/notifications/deterministic-checks.ts +19 -16
  679. package/src/notifications/emit-signal.ts +29 -1
  680. package/src/notifications/trusted-contact-payloads.ts +70 -0
  681. package/src/oauth/byo-connection.test.ts +9 -0
  682. package/src/oauth/connection-resolver.test.ts +146 -6
  683. package/src/oauth/connection-resolver.ts +132 -5
  684. package/src/oauth/oauth-store.ts +16 -3
  685. package/src/oauth/scope-utils.ts +21 -0
  686. package/src/plugin-api/index.ts +9 -4
  687. package/src/plugin-api/model-profiles.test.ts +123 -0
  688. package/src/plugin-api/model-profiles.ts +5 -1
  689. package/src/plugin-api/vision-support.test.ts +149 -0
  690. package/src/plugin-api/vision-support.ts +78 -0
  691. package/src/plugins/defaults/compaction/window-manager.ts +45 -64
  692. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +13 -4
  693. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +302 -0
  694. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +103 -0
  695. package/src/plugins/defaults/image-fallback/package.json +14 -0
  696. package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
  697. package/src/plugins/defaults/image-fallback/src/image-persist.ts +59 -0
  698. package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
  699. package/src/plugins/defaults/index.ts +23 -0
  700. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +14 -1
  701. package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
  702. package/src/plugins/external-plugin-loader.ts +47 -6
  703. package/src/plugins/mtime-cache.ts +772 -0
  704. package/src/plugins/pipeline.ts +7 -2
  705. package/src/plugins/registry.ts +16 -5
  706. package/src/plugins/user-loader.ts +22 -76
  707. package/src/prompts/persona-resolver.ts +29 -11
  708. package/src/prompts/system-prompt.ts +1 -1
  709. package/src/prompts/templates/system-sections.ts +4 -4
  710. package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
  711. package/src/providers/anthropic/client.ts +254 -185
  712. package/src/providers/call-site-routing.ts +10 -0
  713. package/src/providers/gemini/client.ts +43 -0
  714. package/src/providers/inference/adapter-factory.ts +6 -0
  715. package/src/providers/inference/connections.ts +6 -1
  716. package/src/providers/model-catalog.ts +37 -0
  717. package/src/providers/platform-proxy/constants.ts +5 -0
  718. package/src/providers/ratelimit.ts +9 -0
  719. package/src/providers/retry.ts +10 -0
  720. package/src/providers/together/client.ts +35 -0
  721. package/src/providers/types.ts +16 -0
  722. package/src/providers/usage-tracking.ts +7 -0
  723. package/src/runtime/AGENTS.md +9 -1
  724. package/src/runtime/__tests__/agent-wake.test.ts +259 -4
  725. package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
  726. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +417 -0
  727. package/src/runtime/actor-trust-resolver.ts +8 -16
  728. package/src/runtime/agent-wake.ts +183 -60
  729. package/src/runtime/channel-reply-delivery.ts +6 -3
  730. package/src/runtime/guardian-decision-types.ts +3 -22
  731. package/src/runtime/http-server.ts +1 -15
  732. package/src/runtime/invite-redemption-service.ts +155 -6
  733. package/src/runtime/invite-service.ts +113 -62
  734. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
  735. package/src/runtime/routes/__tests__/acp-routes.test.ts +1 -1
  736. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -1
  737. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +277 -0
  738. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +140 -0
  739. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +26 -7
  740. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +14 -10
  741. package/src/runtime/routes/__tests__/contact-routes-update-channel-relay.test.ts +164 -0
  742. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  743. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +1 -1
  744. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +8 -8
  745. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +1 -1
  746. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +1 -3
  747. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +240 -0
  748. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +4 -0
  749. package/src/runtime/routes/__tests__/plugins-routes.test.ts +143 -0
  750. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +1 -1
  751. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +1 -1
  752. package/src/runtime/routes/acp-routes-list.test.ts +4 -0
  753. package/src/runtime/routes/acp-routes.test.ts +5 -6
  754. package/src/runtime/routes/attachment-routes.ts +21 -17
  755. package/src/runtime/routes/browser-routes.ts +19 -1
  756. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -9
  757. package/src/runtime/routes/channel-verification-routes.ts +12 -1
  758. package/src/runtime/routes/contact-routes.ts +275 -164
  759. package/src/runtime/routes/conversation-query-routes.ts +15 -5
  760. package/src/runtime/routes/conversation-routes.ts +24 -3
  761. package/src/runtime/routes/conversation-starter-routes.ts +7 -8
  762. package/src/runtime/routes/guardian-approval-interception.ts +13 -274
  763. package/src/runtime/routes/inbound-message-handler.ts +20 -15
  764. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +285 -0
  765. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +45 -34
  766. package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
  767. package/src/runtime/routes/log-export-routes.ts +2 -2
  768. package/src/runtime/routes/memory-eval-routes.ts +92 -0
  769. package/src/runtime/routes/memory-item-routes.test.ts +12 -11
  770. package/src/runtime/routes/migration-routes.ts +51 -40
  771. package/src/runtime/routes/plugins-routes.ts +164 -8
  772. package/src/runtime/routes/schedule-routes.ts +1 -0
  773. package/src/runtime/routes/usage-routes.ts +3 -0
  774. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  775. package/src/runtime/slack-block-formatting.ts +46 -48
  776. package/src/runtime/trust-verdict-consumer.ts +172 -0
  777. package/src/schedule/scheduler.ts +6 -9
  778. package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
  779. package/src/tools/ask-question/ask-question-tool.test.ts +60 -52
  780. package/src/tools/ask-question/ask-question-tool.ts +14 -73
  781. package/src/tools/browser/__tests__/browser-status.test.ts +20 -0
  782. package/src/tools/browser/browser-execution.ts +16 -4
  783. package/src/tools/document/document-comment-tool.test.ts +1 -1
  784. package/src/tools/executor.ts +15 -3
  785. package/src/tools/host-terminal/host-shell.ts +28 -9
  786. package/src/tools/memory/register.test.ts +32 -0
  787. package/src/tools/skills/load.ts +43 -2
  788. package/src/tools/subagent/spawn.ts +4 -10
  789. package/src/tools/terminal/shell.ts +16 -5
  790. package/src/tools/types.ts +1 -0
  791. package/src/util/fs-watcher-error.ts +36 -0
  792. package/src/util/logs-db-path.ts +22 -0
  793. package/src/util/memory-db-path.ts +23 -0
  794. package/src/watcher/providers/gmail.ts +7 -2
  795. package/src/workflows/engine-integration.test.ts +1 -1
  796. package/src/workflows/engine.test.ts +1 -1
  797. package/src/workflows/engine.ts +22 -0
  798. package/src/workflows/fanout-load.test.ts +1 -1
  799. package/src/workflows/journal-store.test.ts +1 -1
  800. package/src/workflows/leaf-runner.test.ts +40 -1
  801. package/src/workflows/leaf-runner.ts +26 -1
  802. package/src/workspace/git-service.ts +144 -29
  803. package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +121 -0
  804. package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +82 -0
  805. package/src/workspace/migrations/registry.ts +4 -0
  806. package/src/workspace/migrations/runner.ts +32 -2
  807. package/src/__tests__/access-request-decision.test.ts +0 -375
  808. package/src/__tests__/guardian-grant-minting.test.ts +0 -607
  809. package/src/__tests__/plugin-source-watcher.test.ts +0 -302
  810. package/src/api/events/turn-profile-auto-routed.ts +0 -28
  811. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +0 -107
  812. package/src/daemon/plugin-source-watcher.ts +0 -278
  813. package/src/daemon/switch-inference-profile-tool.ts +0 -62
  814. package/src/memory/guardian-approvals.ts +0 -361
  815. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +0 -66
  816. package/src/memory/migrations/038-actor-token-records.ts +0 -45
  817. package/src/memory/migrations/039-actor-refresh-token-records.ts +0 -57
  818. package/src/memory/migrations/103-complex-migrations.ts +0 -23
  819. package/src/memory/migrations/113-late-migrations.ts +0 -30
  820. package/src/memory/migrations/index.ts +0 -301
  821. package/src/runtime/routes/access-request-decision.ts +0 -297
  822. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -963
  823. package/src/runtime/routes/channel-guardian-routes.ts +0 -19
  824. package/src/runtime/routes/guardian-expiry-sweep.ts +0 -132
@@ -7,18 +7,73 @@
7
7
  * supplies its domain-specific data (title, subtitle, metadata, etc.)
8
8
  * without duplicating the card structure or action wiring.
9
9
  *
10
- * The card data shape matches `CardSurfaceData` from
11
- * `daemon/message-types/surfaces.ts`: `{ title, subtitle, body, metadata }`.
12
- * Actions use the canonical `apr:<requestId>:<action>` callback format
13
- * consumed by `surface-action-routes.ts` `processGuardianDecision`.
10
+ * The `[ui_surface, text]` block pair is described by {@link ApprovalCardBlockSchema}
11
+ * so the builder returns a schema-derived type rather than `unknown[]`: the card
12
+ * `data` composes the canonical {@link CardSurfaceDataSchema} and actions reuse
13
+ * the canonical {@link SurfaceActionSchema}. Actions use the
14
+ * `apr:<requestId>:<action>` callback format consumed by
15
+ * `surface-action-routes.ts` → `processGuardianDecision`.
14
16
  */
15
17
 
18
+ import { z } from "zod";
19
+
20
+ import {
21
+ type SurfaceAction,
22
+ SurfaceActionSchema,
23
+ } from "../api/events/ui-surface-show.js";
24
+ import {
25
+ type CardSurfaceData,
26
+ CardSurfaceDataSchema,
27
+ } from "../daemon/message-types/surfaces.js";
28
+
29
+ // ── Seed content block schema ─────────────────────────────────────────────────
30
+
31
+ /**
32
+ * The interactive `ui_surface` card block clients render via
33
+ * `SurfaceRouter → CardSurface`. `data` is the canonical card surface data;
34
+ * `actions` reuse the canonical surface action schema.
35
+ */
36
+ export const ApprovalCardSurfaceBlockSchema = z.object({
37
+ type: z.literal("ui_surface"),
38
+ surfaceId: z.string(),
39
+ surfaceType: z.literal("card"),
40
+ title: z.string(),
41
+ data: CardSurfaceDataSchema,
42
+ actions: z.array(SurfaceActionSchema).optional(),
43
+ });
44
+
45
+ /**
46
+ * The plain-text fallback block, flagged so the display projector
47
+ * (`renderHistoryContent`) keeps it in flat `.text` but omits it from the
48
+ * rendered `contentBlocks` — without it a surface-capable client would render
49
+ * the card AND a duplicate text line.
50
+ */
51
+ export const ApprovalCardFallbackBlockSchema = z.object({
52
+ type: z.literal("text"),
53
+ text: z.string(),
54
+ _surfaceFallback: z.literal(true),
55
+ });
56
+
57
+ /** The `[ui_surface, text]` seed block pair produced for a guardian card. */
58
+ export const ApprovalCardBlockSchema = z.discriminatedUnion("type", [
59
+ ApprovalCardSurfaceBlockSchema,
60
+ ApprovalCardFallbackBlockSchema,
61
+ ]);
62
+
63
+ export type ApprovalCardSurfaceBlock = z.infer<
64
+ typeof ApprovalCardSurfaceBlockSchema
65
+ >;
66
+ export type ApprovalCardFallbackBlock = z.infer<
67
+ typeof ApprovalCardFallbackBlockSchema
68
+ >;
69
+ export type ApprovalCardBlock = z.infer<typeof ApprovalCardBlockSchema>;
70
+
16
71
  // ── Public types ────────────────────────────────────────────────────────────
17
72
 
18
73
  export interface ApprovalCardParams {
19
74
  /** Prefix for `surfaceId` — combined with `requestId` to form e.g. "access-request-abc123". */
20
75
  surfaceIdPrefix: string;
21
- /** Top-level card title shown in the surface header (e.g. "Access Request", "Tool Approval"). */
76
+ /** Top-level card title shown in the surface header (e.g. "Access Request", "Tool approval"). */
22
77
  cardTitle: string;
23
78
  /** Primary line inside the card (typically the requester's display name). */
24
79
  requesterName: string;
@@ -40,10 +95,13 @@ export interface ApprovalCardParams {
40
95
  * Build a `[ui_surface, text]` block pair for a guardian approval notification.
41
96
  *
42
97
  * The `ui_surface` block renders as a card with Approve/Reject buttons in
43
- * clients that support Surface rendering. The `text` block provides a
44
- * plain-text fallback for older clients, search indexing, and CLI display.
98
+ * clients that support Surface rendering. The `text` block is the card's
99
+ * plain-text fallback it feeds the model, search indexing, CLI display, and
100
+ * channel replies, which read it as ordinary text.
45
101
  */
46
- export function buildApprovalCardBlocks(params: ApprovalCardParams): unknown[] {
102
+ export function buildApprovalCardBlocks(
103
+ params: ApprovalCardParams,
104
+ ): ApprovalCardBlock[] {
47
105
  const {
48
106
  surfaceIdPrefix,
49
107
  cardTitle,
@@ -55,7 +113,7 @@ export function buildApprovalCardBlocks(params: ApprovalCardParams): unknown[] {
55
113
  fallbackText,
56
114
  } = params;
57
115
 
58
- const actions = requestId
116
+ const actions: SurfaceAction[] | undefined = requestId
59
117
  ? [
60
118
  {
61
119
  id: `apr:${requestId}:approve_once`,
@@ -70,23 +128,26 @@ export function buildApprovalCardBlocks(params: ApprovalCardParams): unknown[] {
70
128
  ]
71
129
  : undefined;
72
130
 
73
- const surfaceBlock = {
74
- type: "ui_surface" as const,
131
+ const data: CardSurfaceData = {
132
+ title: requesterName,
133
+ subtitle,
134
+ body,
135
+ metadata,
136
+ };
137
+
138
+ const surfaceBlock: ApprovalCardSurfaceBlock = {
139
+ type: "ui_surface",
75
140
  surfaceId: `${surfaceIdPrefix}-${requestId ?? "unknown"}`,
76
- surfaceType: "card" as const,
141
+ surfaceType: "card",
77
142
  title: cardTitle,
78
- data: {
79
- title: requesterName,
80
- subtitle,
81
- body,
82
- metadata,
83
- },
143
+ data,
84
144
  ...(actions ? { actions } : {}),
85
145
  };
86
146
 
87
- const textBlock = {
88
- type: "text" as const,
147
+ const textBlock: ApprovalCardFallbackBlock = {
148
+ type: "text",
89
149
  text: fallbackText,
150
+ _surfaceFallback: true,
90
151
  };
91
152
 
92
153
  return [surfaceBlock, textBlock];
@@ -19,6 +19,7 @@ import {
19
19
  parseAccessRequestPayload,
20
20
  } from "./access-request-copy.js";
21
21
  import {
22
+ type ApprovalCardBlock,
22
23
  type ApprovalCardParams,
23
24
  buildApprovalCardBlocks,
24
25
  } from "./approval-card-builder.js";
@@ -285,7 +286,9 @@ export function resolveApprovalCardData(
285
286
  }
286
287
 
287
288
  /** Render resolved approval card data into Surface `[ui_surface, text]` blocks. */
288
- export function renderApprovalCardData(data: ApprovalCardData): unknown[] {
289
+ export function renderApprovalCardData(
290
+ data: ApprovalCardData,
291
+ ): ApprovalCardBlock[] {
289
292
  return buildApprovalCardBlocks(data.card);
290
293
  }
291
294
 
@@ -300,7 +303,7 @@ export function renderApprovalCardData(data: ApprovalCardData): unknown[] {
300
303
  */
301
304
  export function buildAccessRequestSeedContentBlocks(
302
305
  payload: Record<string, unknown>,
303
- ): unknown[] {
306
+ ): ApprovalCardBlock[] {
304
307
  return renderApprovalCardData({
305
308
  kind: "access_request",
306
309
  card: resolveAccessRequestCard(payload),
@@ -318,13 +321,13 @@ export function buildAccessRequestSeedContentBlocks(
318
321
  */
319
322
  export function buildToolApprovalSeedContentBlocks(
320
323
  payload: GuardianQuestionPayload,
321
- ): unknown[] | null;
324
+ ): ApprovalCardBlock[] | null;
322
325
  export function buildToolApprovalSeedContentBlocks(
323
326
  payload: Record<string, unknown>,
324
- ): unknown[] | null;
327
+ ): ApprovalCardBlock[] | null;
325
328
  export function buildToolApprovalSeedContentBlocks(
326
329
  payload: GuardianQuestionPayload | Record<string, unknown>,
327
- ): unknown[] | null {
330
+ ): ApprovalCardBlock[] | null {
328
331
  const data = resolveApprovalCardData(
329
332
  "guardian.question",
330
333
  payload as Record<string, unknown>,
@@ -91,11 +91,12 @@ export function recordApprovalCardDelivery(
91
91
  * that row's id as `vellumDeliveryId` and it is reused (only its status applied)
92
92
  * — otherwise the vellum row is created here from the result.
93
93
  *
94
- * The pipeline result carries the delivered address directly: a `vellum` result
95
- * carries a `conversationId`; channel results carry the chat (`destination`) and
96
- * channel-native id (`messageId`). A blank `destination` is recorded as unknown
97
- * rather than persisting the literal channel name as a chat id. Status is
98
- * diagnostic the read paths key off addressing, not status.
94
+ * Every result records the internal `conversationId` the card is shown in, so a
95
+ * conversation's pending cards can be found uniformly regardless of channel.
96
+ * Channel results additionally carry the chat (`destination`) and channel-native
97
+ * id (`messageId`) used to match inbound replies/reactions; a blank `destination`
98
+ * is recorded as unknown rather than persisting the literal channel name as a
99
+ * chat id. Status is diagnostic — the read paths key off addressing, not status.
99
100
  *
100
101
  * Returns the vellum delivery id (passed in, or created here) so a caller can
101
102
  * record its own "pipeline produced no vellum delivery" fallback.
@@ -123,6 +124,7 @@ export function recordGuardianRequestDeliveries(params: {
123
124
  deliveryId = recordApprovalCardDelivery({
124
125
  requestId,
125
126
  channel: result.channel,
127
+ conversationId: result.conversationId,
126
128
  chatId: result.destination.length > 0 ? result.destination : undefined,
127
129
  messageId: result.messageId,
128
130
  })?.id;
@@ -10,11 +10,11 @@
10
10
  * needs for a routing decision, not full conversation contents.
11
11
  */
12
12
 
13
- import { and, count, desc, eq, inArray, isNotNull } from "drizzle-orm";
13
+ import { and, desc, eq, isNotNull } from "drizzle-orm";
14
14
 
15
+ import { listPendingRequestsByConversationScope } from "../memory/canonical-guardian-store.js";
15
16
  import { getDb } from "../memory/db-connection.js";
16
17
  import {
17
- channelGuardianApprovalRequests,
18
18
  conversations,
19
19
  notificationDecisions,
20
20
  notificationDeliveries,
@@ -169,74 +169,39 @@ function buildCandidatesForChannel(
169
169
  if (candidates.length >= MAX_CANDIDATES_PER_CHANNEL) break;
170
170
  }
171
171
 
172
- // Batch-enrich all candidates with guardian context in a single query
173
- if (candidates.length > 0) {
174
- const pendingCounts = batchCountPendingByConversation(
175
- candidates.map((c) => c.conversationId),
176
- );
177
- for (const candidate of candidates) {
178
- const pendingCount = pendingCounts.get(candidate.conversationId) ?? 0;
172
+ // Enrich each candidate with its count of pending guardian requests. The
173
+ // canonical store owns the addressing convention and counts by conversation
174
+ // scope: the request's source conversation plus any conversation its card was
175
+ // delivered to (e.g. an access request whose synthetic source id differs from
176
+ // the in-app card's destination conversation).
177
+ //
178
+ // Best-effort per candidate: guardian context is supplementary, so a lookup
179
+ // failure degrades that candidate to "no context" (logged) rather than
180
+ // propagating to the per-channel catch in `buildConversationCandidates`,
181
+ // which would discard the channel's whole candidate set.
182
+ for (const candidate of candidates) {
183
+ try {
184
+ const pendingCount = listPendingRequestsByConversationScope(
185
+ candidate.conversationId,
186
+ candidate.channel,
187
+ ).length;
179
188
  if (pendingCount > 0) {
180
189
  candidate.guardianContext = {
181
190
  pendingUnresolvedRequestCount: pendingCount,
182
191
  };
183
192
  }
193
+ } catch (err) {
194
+ const errMsg = err instanceof Error ? err.message : String(err);
195
+ log.warn(
196
+ { err: errMsg, conversationId: candidate.conversationId },
197
+ "Failed to enrich candidate with guardian context",
198
+ );
184
199
  }
185
200
  }
186
201
 
187
202
  return candidates;
188
203
  }
189
204
 
190
- // -- Guardian context enrichment ----------------------------------------------
191
-
192
- /**
193
- * Batch-count pending guardian approval requests for multiple conversations
194
- * in a single query. Returns a map from conversationId to pending count
195
- * (only entries with count > 0 are included).
196
- */
197
- function batchCountPendingByConversation(
198
- conversationIds: string[],
199
- ): Map<string, number> {
200
- const result = new Map<string, number>();
201
- if (conversationIds.length === 0) return result;
202
-
203
- try {
204
- const db = getDb();
205
-
206
- const rows = db
207
- .select({
208
- conversationId: channelGuardianApprovalRequests.conversationId,
209
- count: count(),
210
- })
211
- .from(channelGuardianApprovalRequests)
212
- .where(
213
- and(
214
- inArray(
215
- channelGuardianApprovalRequests.conversationId,
216
- conversationIds,
217
- ),
218
- eq(channelGuardianApprovalRequests.status, "pending"),
219
- ),
220
- )
221
- .groupBy(channelGuardianApprovalRequests.conversationId)
222
- .all();
223
-
224
- for (const row of rows) {
225
- if (row.count > 0) {
226
- result.set(row.conversationId, row.count);
227
- }
228
- }
229
- } catch (err) {
230
- const errMsg = err instanceof Error ? err.message : String(err);
231
- log.warn(
232
- { err: errMsg },
233
- "Failed to batch-query guardian context for candidates",
234
- );
235
- }
236
-
237
- return result;
238
- }
239
-
240
205
  // -- Prompt serialization -----------------------------------------------------
241
206
 
242
207
  /**
@@ -29,6 +29,7 @@ import type {
29
29
  NotificationSignal,
30
30
  NotificationSourceEventName,
31
31
  } from "./signal.js";
32
+ import { parseTrustedContactDecisionPayload } from "./trusted-contact-payloads.js";
32
33
  import type { NotificationChannel, RenderedChannelCopy } from "./types.js";
33
34
 
34
35
  type CopyTemplate = (payload: Record<string, unknown>) => RenderedChannelCopy;
@@ -52,6 +53,35 @@ export function deriveTitle(body: string): string {
52
53
  : candidate.trim();
53
54
  }
54
55
 
56
+ /**
57
+ * Build a display label for a trusted-contact actor (requester or decider),
58
+ * preferring the display name, then a Slack `<@id>` mention for raw Slack user
59
+ * IDs, then the raw id, then a generic fallback. The result is sanitized for
60
+ * safe inclusion in notification copy.
61
+ */
62
+ function formatTrustedContactActor(
63
+ displayName: string | null | undefined,
64
+ externalUserId: string | null | undefined,
65
+ sourceChannel: string | null | undefined,
66
+ fallback: string,
67
+ ): string {
68
+ const name =
69
+ typeof displayName === "string" && displayName.length > 0
70
+ ? displayName
71
+ : undefined;
72
+ const slackMention =
73
+ sourceChannel === "slack" &&
74
+ typeof externalUserId === "string" &&
75
+ /^U[A-Z0-9]+$/i.test(externalUserId)
76
+ ? `<@${externalUserId}>`
77
+ : undefined;
78
+ const rawId =
79
+ typeof externalUserId === "string" && externalUserId.length > 0
80
+ ? externalUserId
81
+ : undefined;
82
+ return sanitizeIdentityField(name ?? slackMention ?? rawId ?? fallback);
83
+ }
84
+
55
85
  // Templates keyed by dot-separated sourceEventName strings matching producers.
56
86
  const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
57
87
  "schedule.notify": (payload) => ({
@@ -168,53 +198,20 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
168
198
  },
169
199
 
170
200
  "ingress.trusted_contact.guardian_decision": (payload) => {
171
- const decision = str(payload.decision, "decided on");
172
- const sourceChannel =
173
- typeof payload.sourceChannel === "string"
174
- ? payload.sourceChannel
175
- : undefined;
176
-
177
- const requesterDisplayName =
178
- typeof payload.requesterDisplayName === "string" &&
179
- payload.requesterDisplayName.length > 0
180
- ? payload.requesterDisplayName
181
- : undefined;
182
- const requesterExternalUserId =
183
- typeof payload.requesterExternalUserId === "string" &&
184
- payload.requesterExternalUserId.length > 0
185
- ? payload.requesterExternalUserId
186
- : undefined;
187
- const requesterLabel = sanitizeIdentityField(
188
- requesterDisplayName ??
189
- (sourceChannel === "slack" &&
190
- requesterExternalUserId &&
191
- /^U[A-Z0-9]+$/i.test(requesterExternalUserId)
192
- ? `<@${requesterExternalUserId}>`
193
- : requesterExternalUserId) ??
194
- "Someone",
201
+ const parsed = parseTrustedContactDecisionPayload(payload);
202
+ const requesterLabel = formatTrustedContactActor(
203
+ parsed?.requesterDisplayName,
204
+ parsed?.requesterExternalUserId,
205
+ parsed?.sourceChannel,
206
+ "Someone",
195
207
  );
196
-
197
- const decidedByDisplayName =
198
- typeof payload.decidedByDisplayName === "string" &&
199
- payload.decidedByDisplayName.length > 0
200
- ? payload.decidedByDisplayName
201
- : undefined;
202
- const decidedByExternalUserId =
203
- typeof payload.decidedByExternalUserId === "string" &&
204
- payload.decidedByExternalUserId.length > 0
205
- ? payload.decidedByExternalUserId
206
- : undefined;
207
- const decidedByLabel = sanitizeIdentityField(
208
- decidedByDisplayName ??
209
- (sourceChannel === "slack" &&
210
- decidedByExternalUserId &&
211
- /^U[A-Z0-9]+$/i.test(decidedByExternalUserId)
212
- ? `<@${decidedByExternalUserId}>`
213
- : decidedByExternalUserId) ??
214
- "a guardian",
208
+ const decidedByLabel = formatTrustedContactActor(
209
+ parsed?.decidedByDisplayName,
210
+ parsed?.decidedByExternalUserId,
211
+ parsed?.sourceChannel,
212
+ "a guardian",
215
213
  );
216
-
217
- const verb = decision === "approved" ? "approved" : "denied";
214
+ const verb = parsed?.decision === "approved" ? "approved" : "denied";
218
215
  return {
219
216
  title: "Trusted Contact Decision",
220
217
  body: `${requesterLabel}'s access request has been ${verb} by ${decidedByLabel}.`,
@@ -222,29 +219,12 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
222
219
  },
223
220
 
224
221
  "ingress.trusted_contact.denied": (payload) => {
225
- const sourceChannel =
226
- typeof payload.sourceChannel === "string"
227
- ? payload.sourceChannel
228
- : undefined;
229
-
230
- const requesterDisplayName =
231
- typeof payload.requesterDisplayName === "string" &&
232
- payload.requesterDisplayName.length > 0
233
- ? payload.requesterDisplayName
234
- : undefined;
235
- const requesterExternalUserId =
236
- typeof payload.requesterExternalUserId === "string" &&
237
- payload.requesterExternalUserId.length > 0
238
- ? payload.requesterExternalUserId
239
- : undefined;
240
- const requesterLabel = sanitizeIdentityField(
241
- requesterDisplayName ??
242
- (sourceChannel === "slack" &&
243
- requesterExternalUserId &&
244
- /^U[A-Z0-9]+$/i.test(requesterExternalUserId)
245
- ? `<@${requesterExternalUserId}>`
246
- : requesterExternalUserId) ??
247
- "Someone",
222
+ const parsed = parseTrustedContactDecisionPayload(payload);
223
+ const requesterLabel = formatTrustedContactActor(
224
+ parsed?.requesterDisplayName,
225
+ parsed?.requesterExternalUserId,
226
+ parsed?.sourceChannel,
227
+ "Someone",
248
228
  );
249
229
 
250
230
  return {
@@ -3,8 +3,13 @@
3
3
  *
4
4
  * These checks run after the decision engine produces a NotificationDecision
5
5
  * and before the broadcaster dispatches. They enforce hard invariants that
6
- * the LLM cannot override: channel availability, source-active suppression,
7
- * deduplication, and schema validity.
6
+ * the LLM cannot override: channel availability, deduplication, schema
7
+ * validity, and rendered-copy quality.
8
+ *
9
+ * Source-active suppression is also a hard invariant, but it depends only on
10
+ * the signal — not on the decision — so `emitNotificationSignal` runs it as a
11
+ * pre-decision gate, short-circuiting before the expensive LLM stage rather
12
+ * than discarding the decision after it. See `checkSourceActiveSuppression`.
8
13
  */
9
14
 
10
15
  import { and, eq } from "drizzle-orm";
@@ -52,17 +57,7 @@ export async function runDeterministicChecks(
52
57
  return schemaCheck;
53
58
  }
54
59
 
55
- // Check 2: Source-active suppression
56
- const sourceActiveCheck = checkSourceActiveSuppression(signal);
57
- if (!sourceActiveCheck.passed) {
58
- log.info(
59
- { signalId: signal.signalId, reason: sourceActiveCheck.reason },
60
- "Deterministic check failed: source active",
61
- );
62
- return sourceActiveCheck;
63
- }
64
-
65
- // Check 3: Channel availability
60
+ // Check 2: Channel availability
66
61
  const channelCheck = checkChannelAvailability(
67
62
  decision,
68
63
  context.connectedChannels,
@@ -75,7 +70,7 @@ export async function runDeterministicChecks(
75
70
  return channelCheck;
76
71
  }
77
72
 
78
- // Check 4: Dedupe
73
+ // Check 3: Dedupe
79
74
  const dedupeCheck = checkDedupe(
80
75
  signal,
81
76
  decision,
@@ -89,7 +84,7 @@ export async function runDeterministicChecks(
89
84
  return dedupeCheck;
90
85
  }
91
86
 
92
- // Check 5: Rendered copy quality (fail-closed)
87
+ // Check 4: Rendered copy quality (fail-closed)
93
88
  const copyCheck = checkRenderedCopyQuality(signal, decision);
94
89
  if (!copyCheck.passed) {
95
90
  log.info(
@@ -151,8 +146,16 @@ function checkDecisionSchema(decision: NotificationDecision): CheckResult {
151
146
  /**
152
147
  * If the user is already looking at the source context (visibleInSourceNow),
153
148
  * suppress the notification to avoid redundant alerts.
149
+ *
150
+ * This depends only on the signal, not on the decision, so the outcome is
151
+ * knowable before the decision engine runs. `emitNotificationSignal` calls it
152
+ * as a pre-decision gate to short-circuit statically-suppressed signals
153
+ * (e.g. trusted-contact `verification_sent`) before paying for an LLM
154
+ * inference whose result would be discarded. Exported for that caller.
154
155
  */
155
- function checkSourceActiveSuppression(signal: NotificationSignal): CheckResult {
156
+ export function checkSourceActiveSuppression(
157
+ signal: NotificationSignal,
158
+ ): CheckResult {
156
159
  if (signal.attentionHints.visibleInSourceNow) {
157
160
  return {
158
161
  passed: false,
@@ -27,6 +27,7 @@ import {
27
27
  import { enforceRoutingIntent, evaluateSignal } from "./decision-engine.js";
28
28
  import { updateDecision } from "./decisions-store.js";
29
29
  import {
30
+ checkSourceActiveSuppression,
30
31
  type DeterministicCheckContext,
31
32
  runDeterministicChecks,
32
33
  } from "./deterministic-checks.js";
@@ -209,7 +210,12 @@ export interface EmitSignalResult {
209
210
 
210
211
  /**
211
212
  * Emit a notification signal through the full pipeline:
212
- * createEvent -> evaluateSignal -> runDeterministicChecks -> dispatchDecision.
213
+ * createEvent -> (source-active pre-gate) -> evaluateSignal ->
214
+ * runDeterministicChecks -> dispatchDecision.
215
+ *
216
+ * Source-active suppression runs before the decision engine: it depends only
217
+ * on the signal, so a statically-suppressed signal short-circuits here without
218
+ * paying for an LLM inference whose result would be discarded downstream.
213
219
  *
214
220
  * Fire-and-forget safe by default: errors are caught and logged unless
215
221
  * `throwOnError` is enabled by the caller.
@@ -261,6 +267,28 @@ export async function emitNotificationSignal<TEventName extends string>(
261
267
  };
262
268
  }
263
269
 
270
+ // Step 1.5: Source-active pre-gate. visibleInSourceNow is a hard invariant
271
+ // the decision engine cannot override, and it depends only on the signal —
272
+ // so when it is set, the outcome is predetermined: suppress. Short-circuit
273
+ // before the (LLM-backed) decision stage so statically-suppressed signals
274
+ // (e.g. trusted-contact verification_sent) never incur an inference, a
275
+ // discarded decision row, or an LLM-dependent home-feed mirror. The event
276
+ // row persisted above preserves the lifecycle/audit trail.
277
+ const sourceActiveCheck = checkSourceActiveSuppression(signal);
278
+ if (!sourceActiveCheck.passed) {
279
+ log.info(
280
+ { signalId, reason: sourceActiveCheck.reason },
281
+ "Signal suppressed before decision stage (source-active)",
282
+ );
283
+ return {
284
+ signalId,
285
+ deduplicated: false,
286
+ dispatched: false,
287
+ reason: `Signal suppressed: ${sourceActiveCheck.reason}`,
288
+ deliveryResults: [],
289
+ };
290
+ }
291
+
264
292
  // Step 2: Evaluate the signal through the decision engine
265
293
  const connectedChannels = getConnectedChannels();
266
294
 
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Typed context payloads for the trusted-contact lifecycle notification signals.
3
+ *
4
+ * These `ingress.trusted_contact.*` signals are emitted from the canonical
5
+ * resolver (`approvals/guardian-request-resolvers.ts`), and the decision
6
+ * payload is read back by the notification copy-composer. A single zod schema
7
+ * is the source of truth for both sides, so the producer cannot drift from the
8
+ * consumer.
9
+ *
10
+ * Identity fields are nullable: producers populate them (using "" for an
11
+ * unknown id), but a payload read back off persisted JSON may legitimately
12
+ * carry a null/absent identity, and the copy-composer degrades per-field. Only
13
+ * `sourceChannel` and `decision` are strict — they gate routing and rendering.
14
+ *
15
+ * Shapes are zod schemas (single source of truth for runtime validation and
16
+ * TypeScript types), matching the `guardian.question` payload pattern.
17
+ * https://zod.dev/?id=basic-usage
18
+ */
19
+
20
+ import { z } from "zod";
21
+
22
+ import { NotificationSourceChannelSchema } from "./signal.js";
23
+
24
+ /** Identity fields shared by every trusted-contact lifecycle payload. */
25
+ const TrustedContactIdentitySchema = z.object({
26
+ sourceChannel: NotificationSourceChannelSchema,
27
+ requesterExternalUserId: z.string().nullable(),
28
+ requesterChatId: z.string().nullable(),
29
+ requesterDisplayName: z.string().nullable(),
30
+ decidedByDisplayName: z.string().nullable(),
31
+ });
32
+
33
+ /**
34
+ * Payload for `ingress.trusted_contact.guardian_decision` and
35
+ * `ingress.trusted_contact.denied` — the guardian's verdict on an access
36
+ * request. The deny path emits both events from one object; the approve path
37
+ * emits `guardian_decision` with `decision: "approved"` (identical shape).
38
+ */
39
+ export const TrustedContactDecisionPayloadSchema =
40
+ TrustedContactIdentitySchema.extend({
41
+ decidedByExternalUserId: z.string().nullable(),
42
+ decision: z.enum(["approved", "denied"]),
43
+ });
44
+ export type TrustedContactDecisionPayload = z.infer<
45
+ typeof TrustedContactDecisionPayloadSchema
46
+ >;
47
+
48
+ /**
49
+ * Payload for `ingress.trusted_contact.verification_sent` — the verification
50
+ * code was minted and delivered. Carries the session id; no `decision`.
51
+ */
52
+ export const TrustedContactVerificationSentPayloadSchema =
53
+ TrustedContactIdentitySchema.extend({
54
+ verificationSessionId: z.string(),
55
+ });
56
+ export type TrustedContactVerificationSentPayload = z.infer<
57
+ typeof TrustedContactVerificationSentPayloadSchema
58
+ >;
59
+
60
+ /**
61
+ * Parse an unknown context payload as a trusted-contact decision payload.
62
+ * Returns the typed payload on success, or `null` when the shape doesn't match
63
+ * — the copy-composer falls back to generic copy in that case.
64
+ */
65
+ export function parseTrustedContactDecisionPayload(
66
+ payload: Record<string, unknown>,
67
+ ): TrustedContactDecisionPayload | null {
68
+ const result = TrustedContactDecisionPayloadSchema.safeParse(payload);
69
+ return result.success ? result.data : null;
70
+ }
@@ -113,6 +113,15 @@ mock.module("./oauth-store.js", () => ({
113
113
  if (opts?.account && conn.accountInfo !== opts.account) return undefined;
114
114
  return conn;
115
115
  },
116
+ getActiveConnections: (
117
+ service: string,
118
+ opts?: { clientId?: string; account?: string },
119
+ ) => {
120
+ const conn = mockConnections.get(service);
121
+ if (!conn) return [];
122
+ if (opts?.account && conn.accountInfo !== opts.account) return [];
123
+ return [conn];
124
+ },
116
125
  getConnection: (id: string) => {
117
126
  for (const conn of mockConnections.values()) {
118
127
  if (conn.id === id) return conn;