@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
@@ -26,10 +26,6 @@ import {
26
26
  test,
27
27
  } from "bun:test";
28
28
 
29
- import { ADMISSION_FLOOR } from "@vellumai/gateway-client";
30
-
31
- import { TRUST_CLASS_RANK } from "../runtime/actor-trust-resolver.js";
32
-
33
29
  // ── Platform + logger mocks (must come before any source imports) ────
34
30
 
35
31
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -42,6 +38,28 @@ mock.module("../util/logger.js", () => ({
42
38
  }),
43
39
  }));
44
40
 
41
+ // The voice redemption path now claims the gateway-canonical row over IPC
42
+ // before mutating. Stub it so tests don't attempt a real socket connect; the
43
+ // claim returns consumed (updated:true) so redemption proceeds.
44
+ //
45
+ // `inviteClaimCalls` counts gateway claims so concurrency tests can assert that
46
+ // a repeated code does NOT launch a second claim. `inviteClaimGate`, when set,
47
+ // holds the claim open mid-flight so a test can drive the race window where a
48
+ // second code arrives while the first redemption is still awaiting the gateway.
49
+ let inviteClaimCalls = 0;
50
+ let inviteClaimGate: Promise<void> | null = null;
51
+ mock.module("../ipc/gateway-client.js", () => ({
52
+ ipcCall: async () => undefined,
53
+ ipcCallPersistent: async (method: string) => {
54
+ if (method === "record_invite_redemption") {
55
+ inviteClaimCalls += 1;
56
+ if (inviteClaimGate) await inviteClaimGate;
57
+ return { ok: true, updated: true, mirrored: true };
58
+ }
59
+ return undefined;
60
+ },
61
+ }));
62
+
45
63
  // ── Identity helpers mock ─────────────────────────────────────────────
46
64
 
47
65
  let mockAssistantName: string | null = "Vellum";
@@ -145,40 +163,6 @@ mock.module("../calls/channel-admission-reader.js", () => ({
145
163
  },
146
164
  }));
147
165
 
148
- // Real floor semantics, mirroring relay-setup-router.test.ts. The
149
- // enforceAdmissionPolicy mock omits the exempt-channel short-circuit so the
150
- // deny path can be exercised end-to-end regardless of channel.
151
- // eslint-disable-next-line @typescript-eslint/no-require-imports
152
- const realAdmissionPolicyModule = require("../runtime/routes/inbound-stages/admission-policy.js");
153
- mock.module("../runtime/routes/inbound-stages/admission-policy.js", () => ({
154
- ...realAdmissionPolicyModule,
155
- enforceAdmissionPolicy: (input: {
156
- trustClass: string;
157
- memberStatus: string | undefined;
158
- policy: import("@vellumai/gateway-client").AdmissionPolicy;
159
- }) => {
160
- if (input.memberStatus === "blocked" || input.memberStatus === "revoked") {
161
- return {
162
- admitted: false,
163
- reason:
164
- input.memberStatus === "blocked" ? "member_blocked" : "member_revoked",
165
- shouldChallenge: false,
166
- effectivePolicy: input.policy,
167
- };
168
- }
169
- const rank =
170
- (TRUST_CLASS_RANK as Record<string, number>)[input.trustClass] ?? 0;
171
- const floor = ADMISSION_FLOOR[input.policy];
172
- if (rank >= floor) return { admitted: true };
173
- return {
174
- admitted: false,
175
- reason: `admission_policy_${input.policy}`,
176
- shouldChallenge: false,
177
- effectivePolicy: input.policy,
178
- };
179
- },
180
- }));
181
-
182
166
  // ── TTS provider mocks (for call-speech-output) ─────────────────────
183
167
 
184
168
  let mockTtsProviderId: string = "elevenlabs";
@@ -317,7 +301,7 @@ import { generateVoiceCode, hashVoiceCode } from "../util/voice-code.js";
317
301
  import { resetDbForTesting } from "./db-test-helpers.js";
318
302
  import { createGuardianBinding } from "./helpers/create-guardian-binding.js";
319
303
 
320
- initializeDb();
304
+ await initializeDb();
321
305
 
322
306
  // Activate the channel-admission-reader stub only while this file's tests run,
323
307
  // so the registered (process-global) mock delegates to the real module for
@@ -489,6 +473,8 @@ describe("relay-server", () => {
489
473
  verifiedVia: "bootstrap",
490
474
  });
491
475
  activeRelayConnections.clear();
476
+ inviteClaimCalls = 0;
477
+ inviteClaimGate = null;
492
478
  mockUserReference = "my human";
493
479
  mockAssistantName = "Vellum";
494
480
  mockAdmissionPolicy = null;
@@ -2311,8 +2297,9 @@ describe("relay-server", () => {
2311
2297
 
2312
2298
  // ── Inbound voice invite redemption ──────────────────────────────────
2313
2299
 
2314
- test("inbound voice invite redemption: personalized welcome prompt with friend/guardian names", async () => {
2300
+ test("inbound voice invite redemption: personalized welcome prompt uses contact displayName", async () => {
2315
2301
  ensureConversation("conv-invite-welcome");
2302
+ mockUserReference = "Bob";
2316
2303
  const session = createCallSession({
2317
2304
  conversationId: "conv-invite-welcome",
2318
2305
  provider: "twilio",
@@ -2320,18 +2307,16 @@ describe("relay-server", () => {
2320
2307
  toNumber: "+15551111111",
2321
2308
  });
2322
2309
 
2323
- // Create a voice invite with friend/guardian names
2310
+ // The invitee's name is read from the bound contact's displayName.
2324
2311
  const code = generateVoiceCode(6);
2325
2312
  const codeHash = hashVoiceCode(code);
2326
2313
  createInvite({
2327
2314
  sourceChannel: "phone",
2328
- contactId: createTargetContact(),
2315
+ contactId: createTargetContact("Alice"),
2329
2316
  maxUses: 1,
2330
2317
  expectedExternalUserId: "+15558887777",
2331
2318
  voiceCodeHash: codeHash,
2332
2319
  voiceCodeDigits: 6,
2333
- friendName: "Alice",
2334
- guardianName: "Bob",
2335
2320
  });
2336
2321
 
2337
2322
  mockSendMessage.mockImplementation(
@@ -2352,7 +2337,8 @@ describe("relay-server", () => {
2352
2337
  // Should be in verification-pending state for invite redemption
2353
2338
  expect(relay.getConnectionState()).toBe("verification_pending");
2354
2339
 
2355
- // Check that the welcome prompt includes friend/guardian names
2340
+ // Welcome prompt should use the contact's first-name and the resolved
2341
+ // guardian label (not stale name flags from the invite row).
2356
2342
  const textMessages = ws.sentMessages
2357
2343
  .map((raw) => JSON.parse(raw) as { type: string; token?: string })
2358
2344
  .filter((m) => m.type === "text");
@@ -2387,6 +2373,7 @@ describe("relay-server", () => {
2387
2373
 
2388
2374
  test("inbound voice invite redemption: invalid code gets exact failure copy with guardian name and call ends", async () => {
2389
2375
  ensureConversation("conv-invite-fail");
2376
+ mockUserReference = "Dave";
2390
2377
  const session = createCallSession({
2391
2378
  conversationId: "conv-invite-fail",
2392
2379
  provider: "twilio",
@@ -2394,18 +2381,16 @@ describe("relay-server", () => {
2394
2381
  toNumber: "+15551111111",
2395
2382
  });
2396
2383
 
2397
- // Create a voice invite with friend/guardian names
2384
+ // Bound contact's displayName is used; guardian label is resolved at runtime.
2398
2385
  const code = generateVoiceCode(6);
2399
2386
  const codeHash = hashVoiceCode(code);
2400
2387
  createInvite({
2401
2388
  sourceChannel: "phone",
2402
- contactId: createTargetContact(),
2389
+ contactId: createTargetContact("Carol"),
2403
2390
  maxUses: 1,
2404
2391
  expectedExternalUserId: "+15558886666",
2405
2392
  voiceCodeHash: codeHash,
2406
2393
  voiceCodeDigits: 6,
2407
- friendName: "Carol",
2408
- guardianName: "Dave",
2409
2394
  });
2410
2395
 
2411
2396
  const { ws, relay } = createMockWs(session.id);
@@ -2426,7 +2411,11 @@ describe("relay-server", () => {
2426
2411
  await relay.handleMessage(JSON.stringify({ type: "dtmf", digit }));
2427
2412
  }
2428
2413
 
2429
- // Call should be marked as failed immediately
2414
+ // Redemption is dispatched async (it now consults the gateway lifecycle
2415
+ // pre-check over IPC), so flush the microtask/timer queue before asserting.
2416
+ await new Promise((resolve) => setTimeout(resolve, 10));
2417
+
2418
+ // Call should be marked as failed
2430
2419
  const updated = getCallSession(session.id);
2431
2420
  expect(updated).not.toBeNull();
2432
2421
  expect(updated!.status).toBe("failed");
@@ -2466,6 +2455,184 @@ describe("relay-server", () => {
2466
2455
  relay.destroy();
2467
2456
  });
2468
2457
 
2458
+ test("inbound voice invite redemption: repeated code during in-flight claim is deduped (no second redemption, no spurious failure)", async () => {
2459
+ ensureConversation("conv-invite-dedup");
2460
+ const session = createCallSession({
2461
+ conversationId: "conv-invite-dedup",
2462
+ provider: "twilio",
2463
+ fromNumber: "+15558885555",
2464
+ toNumber: "+15551111111",
2465
+ });
2466
+
2467
+ const code = generateVoiceCode(6);
2468
+ const codeHash = hashVoiceCode(code);
2469
+ createInvite({
2470
+ sourceChannel: "phone",
2471
+ contactId: createTargetContact("Eve"),
2472
+ maxUses: 1,
2473
+ expectedExternalUserId: "+15558885555",
2474
+ voiceCodeHash: codeHash,
2475
+ voiceCodeDigits: 6,
2476
+ });
2477
+
2478
+ mockSendMessage.mockImplementation(
2479
+ createMockProviderResponse(["Hello, how can I help?"]),
2480
+ );
2481
+
2482
+ const { ws, relay } = createMockWs(session.id);
2483
+
2484
+ await relay.handleMessage(
2485
+ JSON.stringify({
2486
+ type: "setup",
2487
+ callSid: "CA_invite_dedup",
2488
+ from: "+15558885555",
2489
+ to: "+15551111111",
2490
+ }),
2491
+ );
2492
+
2493
+ expect(relay.getConnectionState()).toBe("verification_pending");
2494
+
2495
+ // Hold the gateway claim open so the first redemption stays in flight while
2496
+ // the caller re-speaks the SAME code (the race this guard prevents).
2497
+ let releaseClaim: () => void = () => {};
2498
+ inviteClaimGate = new Promise<void>((resolve) => {
2499
+ releaseClaim = resolve;
2500
+ });
2501
+
2502
+ // First attempt: enter the full code via DTMF — dispatched fire-and-forget.
2503
+ for (const digit of code) {
2504
+ await relay.handleMessage(JSON.stringify({ type: "dtmf", digit }));
2505
+ }
2506
+ // Let the async handler reach the awaited gateway claim.
2507
+ await new Promise((resolve) => setTimeout(resolve, 0));
2508
+ expect(inviteClaimCalls).toBe(1);
2509
+
2510
+ // Second attempt with the SAME code arrives while the first is in flight.
2511
+ // It must be ignored — no second claim, no failure branch.
2512
+ for (const digit of code) {
2513
+ await relay.handleMessage(JSON.stringify({ type: "dtmf", digit }));
2514
+ }
2515
+ await new Promise((resolve) => setTimeout(resolve, 0));
2516
+ expect(inviteClaimCalls).toBe(1);
2517
+
2518
+ // Now let the first redemption resolve.
2519
+ releaseClaim();
2520
+ await new Promise((resolve) => setTimeout(resolve, 10));
2521
+
2522
+ // Exactly one gateway claim ran across both attempts.
2523
+ expect(inviteClaimCalls).toBe(1);
2524
+
2525
+ // Activation succeeded — call continued, never marked failed.
2526
+ expect(relay.getConnectionState()).toBe("connected");
2527
+ const updated = getCallSession(session.id);
2528
+ expect(updated).not.toBeNull();
2529
+ expect(updated!.status).not.toBe("failed");
2530
+
2531
+ const events = getCallEvents(session.id);
2532
+ expect(
2533
+ events.some((e) => e.eventType === "invite_redemption_succeeded"),
2534
+ ).toBe(true);
2535
+ expect(events.some((e) => e.eventType === "invite_redemption_failed")).toBe(
2536
+ false,
2537
+ );
2538
+
2539
+ // No failure copy was sent for the deduped second attempt.
2540
+ const failureCopy = ws.sentMessages
2541
+ .map((raw) => JSON.parse(raw) as { type: string; token?: string })
2542
+ .filter(
2543
+ (m) =>
2544
+ m.type === "text" &&
2545
+ (m.token ?? "").includes("incorrect or has since expired"),
2546
+ );
2547
+ expect(failureCopy.length).toBe(0);
2548
+
2549
+ relay.destroy();
2550
+ });
2551
+
2552
+ test("inbound voice invite redemption: a fresh redemption after a prior attempt fully resolves still proceeds (guard cleared, no deadlock)", async () => {
2553
+ // Prior attempt: a fully-resolved redemption on its own call.
2554
+ ensureConversation("conv-invite-prior");
2555
+ const priorSession = createCallSession({
2556
+ conversationId: "conv-invite-prior",
2557
+ provider: "twilio",
2558
+ fromNumber: "+15558883333",
2559
+ toNumber: "+15551111111",
2560
+ });
2561
+ const priorCode = generateVoiceCode(6);
2562
+ createInvite({
2563
+ sourceChannel: "phone",
2564
+ contactId: createTargetContact("Ivan"),
2565
+ maxUses: 1,
2566
+ expectedExternalUserId: "+15558883333",
2567
+ voiceCodeHash: hashVoiceCode(priorCode),
2568
+ voiceCodeDigits: 6,
2569
+ });
2570
+
2571
+ mockSendMessage.mockImplementation(
2572
+ createMockProviderResponse(["Hello, how can I help?"]),
2573
+ );
2574
+
2575
+ const prior = createMockWs(priorSession.id);
2576
+ await prior.relay.handleMessage(
2577
+ JSON.stringify({
2578
+ type: "setup",
2579
+ callSid: "CA_invite_prior",
2580
+ from: "+15558883333",
2581
+ to: "+15551111111",
2582
+ }),
2583
+ );
2584
+ for (const digit of priorCode) {
2585
+ await prior.relay.handleMessage(
2586
+ JSON.stringify({ type: "dtmf", digit }),
2587
+ );
2588
+ }
2589
+ await new Promise((resolve) => setTimeout(resolve, 10));
2590
+ expect(prior.relay.getConnectionState()).toBe("connected");
2591
+ expect(inviteClaimCalls).toBe(1);
2592
+ prior.relay.destroy();
2593
+
2594
+ // Fresh attempt: a brand-new redemption proceeds (the in-flight guard from
2595
+ // the resolved attempt does not block it — it was cleared in finally).
2596
+ ensureConversation("conv-invite-fresh");
2597
+ const freshSession = createCallSession({
2598
+ conversationId: "conv-invite-fresh",
2599
+ provider: "twilio",
2600
+ fromNumber: "+15558882222",
2601
+ toNumber: "+15551111111",
2602
+ });
2603
+ const freshCode = generateVoiceCode(6);
2604
+ createInvite({
2605
+ sourceChannel: "phone",
2606
+ contactId: createTargetContact("Kim"),
2607
+ maxUses: 1,
2608
+ expectedExternalUserId: "+15558882222",
2609
+ voiceCodeHash: hashVoiceCode(freshCode),
2610
+ voiceCodeDigits: 6,
2611
+ });
2612
+
2613
+ const fresh = createMockWs(freshSession.id);
2614
+ await fresh.relay.handleMessage(
2615
+ JSON.stringify({
2616
+ type: "setup",
2617
+ callSid: "CA_invite_fresh",
2618
+ from: "+15558882222",
2619
+ to: "+15551111111",
2620
+ }),
2621
+ );
2622
+ for (const digit of freshCode) {
2623
+ await fresh.relay.handleMessage(
2624
+ JSON.stringify({ type: "dtmf", digit }),
2625
+ );
2626
+ }
2627
+ await new Promise((resolve) => setTimeout(resolve, 10));
2628
+
2629
+ // A second claim ran for the fresh attempt — guard did not deadlock it.
2630
+ expect(inviteClaimCalls).toBe(2);
2631
+ expect(fresh.relay.getConnectionState()).toBe("connected");
2632
+
2633
+ fresh.relay.destroy();
2634
+ });
2635
+
2469
2636
  test("inbound voice: unknown caller with no active invite enters name capture flow", async () => {
2470
2637
  ensureConversation("conv-invite-no-invite");
2471
2638
  const session = createCallSession({
@@ -4519,7 +4686,7 @@ describe("relay-server", () => {
4519
4686
  relay.destroy();
4520
4687
  });
4521
4688
 
4522
- test("invite redemption success: continues call with handoff copy instead of ending", async () => {
4689
+ test("invite redemption success: greeting uses bound contact's displayName first-token, not friendName", async () => {
4523
4690
  ensureConversation("conv-invite-continue");
4524
4691
  const session = createCallSession({
4525
4692
  conversationId: "conv-invite-continue",
@@ -4530,15 +4697,19 @@ describe("relay-server", () => {
4530
4697
 
4531
4698
  const code = generateVoiceCode(6);
4532
4699
  const codeHash = hashVoiceCode(code);
4700
+ // Bound contact's displayName is the source of truth — its first token
4701
+ // (here "Carolina") is what the post-redemption greeting should use.
4702
+ // The legacy friendName column carries an out-of-date free-text label
4703
+ // ("Stale Name") to prove the greeting reads from the contact, not the
4704
+ // legacy column.
4533
4705
  createInvite({
4534
4706
  sourceChannel: "phone",
4535
- contactId: createTargetContact(),
4707
+ contactId: createTargetContact("Carolina Flaherty"),
4536
4708
  maxUses: 1,
4537
4709
  expectedExternalUserId: "+15557776666",
4538
4710
  voiceCodeHash: codeHash,
4539
4711
  voiceCodeDigits: 6,
4540
- friendName: "Eve",
4541
- guardianName: "Frank",
4712
+ friendName: "Stale Name",
4542
4713
  });
4543
4714
 
4544
4715
  mockSendMessage.mockImplementation(
@@ -4569,15 +4740,18 @@ describe("relay-server", () => {
4569
4740
  // Call should remain connected
4570
4741
  expect(relay.getConnectionState()).toBe("connected");
4571
4742
 
4572
- // Handoff copy should have been sent
4743
+ // Handoff copy should use the contact's first-name, not the stale friendName
4573
4744
  const textMessages = ws.sentMessages
4574
4745
  .map((raw) => JSON.parse(raw) as { type: string; token?: string })
4575
4746
  .filter((m) => m.type === "text");
4576
4747
  expect(
4577
4748
  textMessages.some((m) =>
4578
- (m.token ?? "").includes("verified that you are Eve"),
4749
+ (m.token ?? "").includes("verified that you are Carolina"),
4579
4750
  ),
4580
4751
  ).toBe(true);
4752
+ expect(
4753
+ textMessages.every((m) => !(m.token ?? "").includes("Stale Name")),
4754
+ ).toBe(true);
4581
4755
 
4582
4756
  // No end message — call stays alive
4583
4757
  const endMessages = ws.sentMessages
@@ -4602,6 +4776,7 @@ describe("relay-server", () => {
4602
4776
  test("outbound invite prompt uses assistant introduction", async () => {
4603
4777
  ensureConversation("conv-outbound-invite-origin");
4604
4778
  ensureConversation("conv-outbound-invite");
4779
+ mockUserReference = "Hank";
4605
4780
  const session = createCallSession({
4606
4781
  conversationId: "conv-outbound-invite",
4607
4782
  provider: "twilio",
@@ -4644,6 +4819,132 @@ describe("relay-server", () => {
4644
4819
  relay.destroy();
4645
4820
  });
4646
4821
 
4822
+ test("invite redemption success: empty contact displayName triggers neutral 'Hi there' greeting", async () => {
4823
+ ensureConversation("conv-invite-blank-name");
4824
+ mockUserReference = "my human";
4825
+ mockAssistantName = "";
4826
+ const session = createCallSession({
4827
+ conversationId: "conv-invite-blank-name",
4828
+ provider: "twilio",
4829
+ fromNumber: "+15557775555",
4830
+ toNumber: "+15551111111",
4831
+ });
4832
+
4833
+ const code = generateVoiceCode(6);
4834
+ const codeHash = hashVoiceCode(code);
4835
+ // displayName is whitespace-only — greeting falls back to "Hi there"
4836
+ // rather than substituting the channel address.
4837
+ createInvite({
4838
+ sourceChannel: "phone",
4839
+ contactId: createTargetContact(" "),
4840
+ maxUses: 1,
4841
+ expectedExternalUserId: "+15557775555",
4842
+ voiceCodeHash: codeHash,
4843
+ voiceCodeDigits: 6,
4844
+ });
4845
+
4846
+ mockSendMessage.mockImplementation(
4847
+ createMockProviderResponse(["I'd be happy to help."]),
4848
+ );
4849
+
4850
+ const { ws, relay } = createMockWs(session.id);
4851
+
4852
+ await relay.handleMessage(
4853
+ JSON.stringify({
4854
+ type: "setup",
4855
+ callSid: "CA_invite_blank_name",
4856
+ from: "+15557775555",
4857
+ to: "+15551111111",
4858
+ }),
4859
+ );
4860
+
4861
+ for (const digit of code) {
4862
+ await relay.handleMessage(JSON.stringify({ type: "dtmf", digit }));
4863
+ }
4864
+ await new Promise((resolve) => setTimeout(resolve, 10));
4865
+
4866
+ expect(relay.getConnectionState()).toBe("connected");
4867
+
4868
+ const textMessages = ws.sentMessages
4869
+ .map((raw) => JSON.parse(raw) as { type: string; token?: string })
4870
+ .filter((m) => m.type === "text");
4871
+ expect(
4872
+ textMessages.some((m) => (m.token ?? "").startsWith("Hi there!")),
4873
+ ).toBe(true);
4874
+ expect(
4875
+ textMessages.every(
4876
+ (m) => !(m.token ?? "").includes("+15557775555"),
4877
+ ),
4878
+ ).toBe(true);
4879
+
4880
+ relay.destroy();
4881
+ });
4882
+
4883
+ test("invite redemption success: empty contact displayName with stale friendName column still greets 'Hi there'", async () => {
4884
+ // Guards the Codex P2 on #35581 (discussion_r3453033493): when a bound
4885
+ // contact's displayName is blank and the invite row carries a stale
4886
+ // free-text friend_name, the greeting must NOT fall back to that stale
4887
+ // label. contact_id is NOT NULL, so every invite is bound — empty
4888
+ // displayName falls through to the neutral "Hi there" copy.
4889
+ ensureConversation("conv-invite-stale-friend");
4890
+ mockUserReference = "my human";
4891
+ mockAssistantName = "";
4892
+ const session = createCallSession({
4893
+ conversationId: "conv-invite-stale-friend",
4894
+ provider: "twilio",
4895
+ fromNumber: "+15557774444",
4896
+ toNumber: "+15551111111",
4897
+ });
4898
+
4899
+ const code = generateVoiceCode(6);
4900
+ const codeHash = hashVoiceCode(code);
4901
+ createInvite({
4902
+ sourceChannel: "phone",
4903
+ contactId: createTargetContact(" "),
4904
+ maxUses: 1,
4905
+ expectedExternalUserId: "+15557774444",
4906
+ voiceCodeHash: codeHash,
4907
+ voiceCodeDigits: 6,
4908
+ friendName: "Stale Legacy Name",
4909
+ });
4910
+
4911
+ mockSendMessage.mockImplementation(
4912
+ createMockProviderResponse(["I'd be happy to help."]),
4913
+ );
4914
+
4915
+ const { ws, relay } = createMockWs(session.id);
4916
+
4917
+ await relay.handleMessage(
4918
+ JSON.stringify({
4919
+ type: "setup",
4920
+ callSid: "CA_invite_stale_friend",
4921
+ from: "+15557774444",
4922
+ to: "+15551111111",
4923
+ }),
4924
+ );
4925
+
4926
+ for (const digit of code) {
4927
+ await relay.handleMessage(JSON.stringify({ type: "dtmf", digit }));
4928
+ }
4929
+ await new Promise((resolve) => setTimeout(resolve, 10));
4930
+
4931
+ expect(relay.getConnectionState()).toBe("connected");
4932
+
4933
+ const textMessages = ws.sentMessages
4934
+ .map((raw) => JSON.parse(raw) as { type: string; token?: string })
4935
+ .filter((m) => m.type === "text");
4936
+ expect(
4937
+ textMessages.some((m) => (m.token ?? "").startsWith("Hi there!")),
4938
+ ).toBe(true);
4939
+ expect(
4940
+ textMessages.every(
4941
+ (m) => !(m.token ?? "").includes("Stale Legacy Name"),
4942
+ ),
4943
+ ).toBe(true);
4944
+
4945
+ relay.destroy();
4946
+ });
4947
+
4647
4948
  // ── resolveGuardianLabel resolution priority ─────────────────────────
4648
4949
 
4649
4950
  test("guardian label: guardian persona name takes precedence over Contact.displayName", async () => {
@@ -58,8 +58,9 @@ import { resetTestTables } from "../memory/raw-query.js";
58
58
  import { RuntimeHttpServer } from "../runtime/http-server.js";
59
59
  import * as pendingInteractions from "../runtime/pending-interactions.js";
60
60
  import { resetDbForTesting } from "./db-test-helpers.js";
61
+ import { resolveLocalTrustVerdict } from "./helpers/channel-test-adapter.js";
61
62
 
62
- initializeDb();
63
+ await initializeDb();
63
64
 
64
65
  afterAll(() => {
65
66
  resetDbForTesting();
@@ -266,6 +267,13 @@ describe("WhatsApp channel ingress attachment resolution", () => {
266
267
  function makeInboundBody(
267
268
  overrides: Record<string, unknown> = {},
268
269
  ): Record<string, unknown> {
270
+ // Mirror the gateway: stamp a trust verdict from the local contact store so
271
+ // the daemon's fail-closed ACL stage admits the request to attachment logic.
272
+ const trustVerdict = resolveLocalTrustVerdict({
273
+ channelType: "whatsapp",
274
+ actorExternalId: WHATSAPP_USER_ID,
275
+ externalChatId: "whatsapp-chat-1",
276
+ });
269
277
  return {
270
278
  sourceChannel: "whatsapp",
271
279
  interface: "whatsapp",
@@ -274,6 +282,7 @@ describe("WhatsApp channel ingress attachment resolution", () => {
274
282
  externalMessageId: `wa-msg-${Date.now()}-${Math.random()}`,
275
283
  content: "Check these attachments",
276
284
  replyCallbackUrl: "https://gateway.test/deliver",
285
+ sourceMetadata: { trustVerdict },
277
286
  ...overrides,
278
287
  };
279
288
  }
@@ -38,13 +38,10 @@ import { getDb } from "../memory/db-connection.js";
38
38
  import { initializeDb } from "../memory/db-init.js";
39
39
  import { buildAssistantEvent } from "../runtime/assistant-event.js";
40
40
  import { AssistantEventHub } from "../runtime/assistant-event-hub.js";
41
- import {
42
- BadRequestError,
43
- NotFoundError,
44
- } from "../runtime/routes/errors.js";
41
+ import { BadRequestError, NotFoundError } from "../runtime/routes/errors.js";
45
42
  import { handleSubscribeAssistantEvents } from "../runtime/routes/events-routes.js";
46
43
 
47
- initializeDb();
44
+ await initializeDb();
48
45
 
49
46
  describe("GET /v1/events — bilingual scope query params", () => {
50
47
  beforeEach(() => {
@@ -75,7 +72,9 @@ describe("GET /v1/events — bilingual scope query params", () => {
75
72
  expect(new TextDecoder().decode(heartbeat.value)).toBe(": heartbeat\n\n");
76
73
 
77
74
  // Publish an event scoped to that conversation — should be delivered.
78
- await testHub.publish(buildAssistantEvent({ type: "pong" }, conversationId));
75
+ await testHub.publish(
76
+ buildAssistantEvent({ type: "pong" }, conversationId),
77
+ );
79
78
 
80
79
  const { value, done } = await reader.read();
81
80
  ac.abort();
@@ -99,9 +98,8 @@ describe("GET /v1/events — bilingual scope query params", () => {
99
98
  // Materialise two distinct conversations: one we'll subscribe to by id,
100
99
  // one we'll publish to via the ignored key.
101
100
  const { conversationId: idConv } = getOrCreateConversation("sse-id-wins");
102
- const { conversationId: keyConv } = getOrCreateConversation(
103
- "sse-key-ignored",
104
- );
101
+ const { conversationId: keyConv } =
102
+ getOrCreateConversation("sse-key-ignored");
105
103
  expect(idConv).not.toBe(keyConv);
106
104
 
107
105
  const ac = new AbortController();
@@ -44,7 +44,7 @@ import type { AssistantEvent } from "../runtime/assistant-event.js";
44
44
  import { buildAssistantEvent } from "../runtime/assistant-event.js";
45
45
  import { assistantEventHub } from "../runtime/assistant-event-hub.js";
46
46
 
47
- initializeDb();
47
+ await initializeDb();
48
48
 
49
49
  // ---------------------------------------------------------------------------
50
50
  // Helpers
@@ -39,7 +39,7 @@ import {
39
39
  stampAndBuffer,
40
40
  } from "../runtime/assistant-stream-state.js";
41
41
 
42
- initializeDb();
42
+ await initializeDb();
43
43
 
44
44
  const decoder = new TextDecoder();
45
45
 
@@ -36,7 +36,7 @@ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
36
36
  import { mintToken } from "../runtime/auth/token-service.js";
37
37
  import { RuntimeHttpServer } from "../runtime/http-server.js";
38
38
 
39
- initializeDb();
39
+ await initializeDb();
40
40
 
41
41
  const TEST_JWT = mintToken({
42
42
  aud: "vellum-daemon",
@@ -82,7 +82,7 @@ function startScheduler(
82
82
  return startSchedulerReal(processMessage, notifyScheduleOneShot, options);
83
83
  }
84
84
 
85
- initializeDb();
85
+ await initializeDb();
86
86
 
87
87
  /** Access the underlying bun:sqlite Database for raw parameterized queries. */
88
88
  function getRawDb(): import("bun:sqlite").Database {
@@ -51,7 +51,7 @@ import {
51
51
  listSchedules,
52
52
  } from "../schedule/schedule-store.js";
53
53
 
54
- initializeDb();
54
+ await initializeDb();
55
55
 
56
56
  function clearTables(): void {
57
57
  const db = getDb();