@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
@@ -18,6 +18,7 @@ import type {
18
18
  Provider,
19
19
  ProviderResponse,
20
20
  SendMessageOptions,
21
+ ToolDefinition,
21
22
  } from "../types.js";
22
23
  import {
23
24
  ContextOverflowError,
@@ -823,181 +824,7 @@ export class AnthropicProvider implements Provider {
823
824
  // edge LB, NAT idle) — only the latter should be retried.
824
825
  let innerTimeoutSignal: AbortSignal | undefined;
825
826
  try {
826
- const formatted = messages
827
- .map((m) => {
828
- // Track whether an unknown block was dropped during filtering
829
- let droppedUnknownBlock = false;
830
-
831
- const content = m.content
832
- .map((block) => {
833
- const result = this.toAnthropicBlockSafe(block);
834
- if (result == null) {
835
- droppedUnknownBlock = true;
836
- }
837
- return result;
838
- })
839
- .filter(
840
- (block): block is Anthropic.ContentBlockParam => block != null,
841
- )
842
- .filter(
843
- (block) =>
844
- !(
845
- block.type === "text" &&
846
- !(block as { text?: string }).text?.trim()
847
- ),
848
- );
849
-
850
- // Preserve assistant turns that would otherwise become empty after filtering
851
- // unknown block types (e.g. ui_surface). Dropping these messages can violate
852
- // Anthropic's role alternation requirement.
853
- if (
854
- content.length === 0 &&
855
- m.role === "assistant" &&
856
- droppedUnknownBlock
857
- ) {
858
- return {
859
- role: m.role as "assistant",
860
- content: [
861
- { type: "text" as const, text: PLACEHOLDER_BLOCKS_OMITTED },
862
- ],
863
- };
864
- }
865
-
866
- return {
867
- role: m.role,
868
- content,
869
- } as Anthropic.MessageParam;
870
- })
871
- .reduce<Anthropic.MessageParam[]>((acc, m) => {
872
- if (m.content.length > 0) {
873
- acc.push(m);
874
- return acc;
875
- }
876
- // Dropping an empty assistant message between two user messages (or vice
877
- // versa) would create consecutive same-role messages, violating
878
- // Anthropic's role alternation requirement. Inject a placeholder instead.
879
- const prev = acc[acc.length - 1];
880
- if (m.role === "assistant" && prev && prev.role !== "assistant") {
881
- acc.push({
882
- role: "assistant" as const,
883
- content: [
884
- { type: "text" as const, text: PLACEHOLDER_EMPTY_TURN },
885
- ],
886
- });
887
- }
888
- return acc;
889
- }, []);
890
-
891
- // Post-processing: merge consecutive same-role messages that violate
892
- // Anthropic's strict user/assistant alternation requirement. These can
893
- // arise from:
894
- // - Dropping empty messages in the reduce above (placeholder-adjacent)
895
- // - History reconstruction artifacts that bypass repairHistory
896
- //
897
- // Walk backwards so splice indices stay valid. After a merge+splice
898
- // the element that was at i+1 shifts to i, potentially creating a
899
- // new adjacent pair — bump i back up to recheck that position.
900
- {
901
- let i = formatted.length - 1;
902
- while (i > 0 && i < formatted.length) {
903
- if (formatted[i].role !== formatted[i - 1].role) {
904
- i--;
905
- continue;
906
- }
907
-
908
- const iContent = (
909
- Array.isArray(formatted[i].content) ? formatted[i].content : []
910
- ) as Anthropic.ContentBlockParam[];
911
- const prevContent = (
912
- Array.isArray(formatted[i - 1].content)
913
- ? formatted[i - 1].content
914
- : []
915
- ) as Anthropic.ContentBlockParam[];
916
- const isPlaceholder = (c: Anthropic.ContentBlockParam[]): boolean => {
917
- if (
918
- c.length !== 1 ||
919
- typeof c[0] === "string" ||
920
- c[0].type !== "text"
921
- )
922
- return false;
923
- const text = (c[0] as { text?: string }).text;
924
- return typeof text === "string" && isPlaceholderSentinelText(text);
925
- };
926
-
927
- if (isPlaceholder(iContent)) {
928
- formatted.splice(i, 1);
929
- // Removed the later element. The new formatted[i] (formerly
930
- // i+1) may now be same-role as i-1, so decrement once to
931
- // recheck from the correct position.
932
- i--;
933
- } else if (isPlaceholder(prevContent)) {
934
- formatted.splice(i - 1, 1);
935
- // Removed the earlier element — everything shifted down by 1.
936
- // The element that was at i is now at i-1. Decrement so the
937
- // next iteration compares the new i-1 with i-2 (or exits if
938
- // i-1 is 0).
939
- i--;
940
- } else {
941
- // Neither is a placeholder — merge content blocks into the
942
- // earlier message and remove the later one. Skip the merge
943
- // when either message carries tool_use or tool_result blocks;
944
- // those require structural alternation for ensureToolPairing
945
- // to inject the correct synthetic results downstream.
946
- const hasToolBlock = (c: Anthropic.ContentBlockParam[]): boolean =>
947
- c.some(
948
- (b) =>
949
- typeof b !== "string" &&
950
- (b.type === "tool_use" || b.type === "tool_result"),
951
- );
952
- if (!hasToolBlock(prevContent) && !hasToolBlock(iContent)) {
953
- formatted[i - 1] = {
954
- ...formatted[i - 1],
955
- content: [...prevContent, ...iContent],
956
- };
957
- formatted.splice(i, 1);
958
- // Clamp i to the new last index — the splice may have put
959
- // us past the end. If there's a new element at i (formerly
960
- // i+1), it will be rechecked against the merged i-1.
961
- if (i >= formatted.length) {
962
- i = formatted.length - 1;
963
- }
964
- } else {
965
- // Can't merge (tool blocks present) — leave for
966
- // ensureToolPairing which handles tool_use/tool_result
967
- // alternation in its own forward walk.
968
- i--;
969
- }
970
- }
971
- }
972
- }
973
-
974
- // Strip thinking/redacted_thinking blocks from completed historical
975
- // assistant turns. Anthropic only requires these blocks for active
976
- // tool-use continuation (the tail span where assistant tool_use is
977
- // followed by user tool_result). Replaying stale thinking blocks from
978
- // earlier turns causes 400 errors when the signature is no longer
979
- // valid (e.g. after a provider/model/profile switch).
980
- const activeToolUseStart = findActiveToolUseContinuationStart(formatted);
981
- for (let i = 0; i < activeToolUseStart; i++) {
982
- const msg = formatted[i];
983
- if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
984
- const stripped = (msg.content as Anthropic.ContentBlockParam[]).filter(
985
- (b) =>
986
- typeof b === "string" ||
987
- (b.type !== "thinking" && b.type !== "redacted_thinking"),
988
- );
989
- if (stripped.length === 0) {
990
- stripped.push({
991
- type: "text" as const,
992
- text: PLACEHOLDER_BLOCKS_OMITTED,
993
- });
994
- }
995
- formatted[i] = { ...msg, content: stripped };
996
- }
997
-
998
- sentMessages = ensureToolPairing(
999
- repairOrphanedServerToolBlocks(formatted),
1000
- );
827
+ sentMessages = this.buildSentMessages(messages);
1001
828
  const {
1002
829
  effort,
1003
830
  speed,
@@ -1195,15 +1022,27 @@ export class AnthropicProvider implements Provider {
1195
1022
  }
1196
1023
 
1197
1024
  // Advancing tail: place a short-lived 5m cache breakpoint on the last
1198
- // block of the last message when it falls after the turn-starting user
1199
- // message (i.e. tool-use loop content). This caches the growing tail
1200
- // cheaply without conflicting with the 1h breakpoints above.
1201
- // Skip thinking/redacted_thinking blocks Anthropic doesn't allow
1025
+ // block of the last message. This caches the growing tail cheaply
1026
+ // without conflicting with the 1h breakpoints above. It fires during
1027
+ // tool-use loops (the tail falls after the turn-starting user message)
1028
+ // and also on a first-of-turn request whose volatile turn-start anchor
1029
+ // was skipped while a previous-turn anchor exists: there the latest
1030
+ // message would otherwise carry no breakpoint, so the next request's
1031
+ // anchor can land far ahead of the previous-turn anchor and Anthropic's
1032
+ // ~20-block cache lookback can't bridge the gap — forcing a full
1033
+ // re-creation of the prefix. The 5m breakpoint gives the next call an
1034
+ // exact, reachable boundary; cross-turn it expires harmlessly. The
1035
+ // first-of-turn bridge lands on the turn-start block, so it honors
1036
+ // `disableTurnStartCache` like the long-TTL anchor above. Skip
1037
+ // thinking/redacted_thinking blocks — Anthropic doesn't allow
1202
1038
  // cache_control on those types.
1203
1039
  if (
1204
1040
  !disableCache &&
1205
1041
  turnStartIdx >= 0 &&
1206
- turnStartIdx < sentMessages.length - 1
1042
+ (turnStartIdx < sentMessages.length - 1 ||
1043
+ (skipVolatileTurnStartAnchor &&
1044
+ turnStartIdx > 0 &&
1045
+ !disableTurnStartCache))
1207
1046
  ) {
1208
1047
  const lastMsg = sentMessages[sentMessages.length - 1];
1209
1048
  if (Array.isArray(lastMsg.content) && lastMsg.content.length > 0) {
@@ -1230,11 +1069,13 @@ export class AnthropicProvider implements Provider {
1230
1069
  }
1231
1070
 
1232
1071
  // Cache-breakpoint accounting: system(≤2) + tools(1, only when the
1233
- // system is a single block or absent) + turn-start(1) +
1234
- // (tail OR prev-turn-anchor)(1) ≤ 4 — Anthropic's per-request cap.
1235
- // Tail and prev-turn-anchor are mutually exclusive (the latter only
1236
- // fires when turn-start is the last message, which suppresses the
1237
- // tail), so the total can't drift past 4.
1072
+ // system is a single block or absent) + at most two message anchors
1073
+ // ≤ 4 — Anthropic's per-request cap. The two message anchors are
1074
+ // turn-start + prev-turn-anchor (first-of-turn), turn-start + tail
1075
+ // (tool-use loop), or prev-turn-anchor + tail (first-of-turn with the
1076
+ // volatile turn-start anchor skipped — the freed turn-start slot covers
1077
+ // the tail). At most two message-level breakpoints are placed, so the
1078
+ // total can't drift past 4.
1238
1079
 
1239
1080
  // Strip orphaned UTF-16 surrogates so the Anthropic JSON parser never
1240
1081
  // sees invalid strings produced by upstream surrogate-splitting `.slice()` calls.
@@ -1681,6 +1522,234 @@ export class AnthropicProvider implements Provider {
1681
1522
  }
1682
1523
  }
1683
1524
 
1525
+ /**
1526
+ * Exact prompt-token count via Anthropic's `/v1/messages/count_tokens`
1527
+ * endpoint — the real tokenizer, no inference. Serializes `messages` /
1528
+ * `systemPrompt` / `tools` the same way {@link sendMessage} does (so the
1529
+ * count tracks what the next call would actually send), minus the
1530
+ * `cache_control` breakpoints, which don't affect token counts.
1531
+ *
1532
+ * The serialization here is intentionally simpler than `sendMessage`'s
1533
+ * (no role-alternation merge / placeholder injection): on a pathological
1534
+ * history `count_tokens` may reject the request, which surfaces as a thrown
1535
+ * error the caller turns into a local-estimator fallback. The common path —
1536
+ * a well-formed history — counts exactly.
1537
+ */
1538
+ async countInputTokens(
1539
+ messages: Message[],
1540
+ systemPrompt: string,
1541
+ tools?: ToolDefinition[],
1542
+ ): Promise<number> {
1543
+ const sentMessages = this.buildSentMessages(messages);
1544
+
1545
+ const system = systemPrompt
1546
+ ? systemPrompt
1547
+ .split(SYSTEM_PROMPT_CACHE_BOUNDARY)
1548
+ .filter((text) => text.length > 0)
1549
+ .map((text) => ({ type: "text" as const, text }))
1550
+ : [];
1551
+ const toolsParam =
1552
+ tools && tools.length > 0
1553
+ ? tools.map((t) => ({
1554
+ name: t.name,
1555
+ description: t.description,
1556
+ input_schema: t.input_schema as Anthropic.Tool["input_schema"],
1557
+ }))
1558
+ : undefined;
1559
+
1560
+ const res = await this.client.messages.countTokens({
1561
+ model: this.model,
1562
+ messages: sentMessages,
1563
+ ...(system.length > 0 ? { system } : {}),
1564
+ ...(toolsParam ? { tools: toolsParam } : {}),
1565
+ });
1566
+ return res.input_tokens;
1567
+ }
1568
+
1569
+ /**
1570
+ * Serialize internal `Message[]` into the Anthropic `MessageParam[]` the
1571
+ * Messages API expects: drop unknown/empty blocks, preserve role
1572
+ * alternation (placeholder injection + same-role merge), strip stale
1573
+ * thinking blocks outside the active tool-use continuation, and repair
1574
+ * tool_use/tool_result pairing. Shared by {@link sendMessage} and
1575
+ * {@link countInputTokens} so both send the identical message payload —
1576
+ * `cache_control` breakpoints (which don't affect token counts) are the
1577
+ * only thing layered on top in `sendMessage`.
1578
+ */
1579
+ private buildSentMessages(messages: Message[]): Anthropic.MessageParam[] {
1580
+ const formatted = messages
1581
+ .map((m) => {
1582
+ // Track whether an unknown block was dropped during filtering
1583
+ let droppedUnknownBlock = false;
1584
+
1585
+ const content = m.content
1586
+ .map((block) => {
1587
+ const result = this.toAnthropicBlockSafe(block);
1588
+ if (result == null) {
1589
+ droppedUnknownBlock = true;
1590
+ }
1591
+ return result;
1592
+ })
1593
+ .filter(
1594
+ (block): block is Anthropic.ContentBlockParam => block != null,
1595
+ )
1596
+ .filter(
1597
+ (block) =>
1598
+ !(
1599
+ block.type === "text" &&
1600
+ !(block as { text?: string }).text?.trim()
1601
+ ),
1602
+ );
1603
+
1604
+ // Preserve assistant turns that would otherwise become empty after filtering
1605
+ // unknown block types (e.g. ui_surface). Dropping these messages can violate
1606
+ // Anthropic's role alternation requirement.
1607
+ if (
1608
+ content.length === 0 &&
1609
+ m.role === "assistant" &&
1610
+ droppedUnknownBlock
1611
+ ) {
1612
+ return {
1613
+ role: m.role as "assistant",
1614
+ content: [
1615
+ { type: "text" as const, text: PLACEHOLDER_BLOCKS_OMITTED },
1616
+ ],
1617
+ };
1618
+ }
1619
+
1620
+ return {
1621
+ role: m.role,
1622
+ content,
1623
+ } as Anthropic.MessageParam;
1624
+ })
1625
+ .reduce<Anthropic.MessageParam[]>((acc, m) => {
1626
+ if (m.content.length > 0) {
1627
+ acc.push(m);
1628
+ return acc;
1629
+ }
1630
+ // Dropping an empty assistant message between two user messages (or vice
1631
+ // versa) would create consecutive same-role messages, violating
1632
+ // Anthropic's role alternation requirement. Inject a placeholder instead.
1633
+ const prev = acc[acc.length - 1];
1634
+ if (m.role === "assistant" && prev && prev.role !== "assistant") {
1635
+ acc.push({
1636
+ role: "assistant" as const,
1637
+ content: [{ type: "text" as const, text: PLACEHOLDER_EMPTY_TURN }],
1638
+ });
1639
+ }
1640
+ return acc;
1641
+ }, []);
1642
+
1643
+ // Post-processing: merge consecutive same-role messages that violate
1644
+ // Anthropic's strict user/assistant alternation requirement. These can
1645
+ // arise from:
1646
+ // - Dropping empty messages in the reduce above (placeholder-adjacent)
1647
+ // - History reconstruction artifacts that bypass repairHistory
1648
+ //
1649
+ // Walk backwards so splice indices stay valid. After a merge+splice
1650
+ // the element that was at i+1 shifts to i, potentially creating a
1651
+ // new adjacent pair — bump i back up to recheck that position.
1652
+ {
1653
+ let i = formatted.length - 1;
1654
+ while (i > 0 && i < formatted.length) {
1655
+ if (formatted[i].role !== formatted[i - 1].role) {
1656
+ i--;
1657
+ continue;
1658
+ }
1659
+
1660
+ const iContent = (
1661
+ Array.isArray(formatted[i].content) ? formatted[i].content : []
1662
+ ) as Anthropic.ContentBlockParam[];
1663
+ const prevContent = (
1664
+ Array.isArray(formatted[i - 1].content)
1665
+ ? formatted[i - 1].content
1666
+ : []
1667
+ ) as Anthropic.ContentBlockParam[];
1668
+ const isPlaceholder = (c: Anthropic.ContentBlockParam[]): boolean => {
1669
+ if (
1670
+ c.length !== 1 ||
1671
+ typeof c[0] === "string" ||
1672
+ c[0].type !== "text"
1673
+ )
1674
+ return false;
1675
+ const text = (c[0] as { text?: string }).text;
1676
+ return typeof text === "string" && isPlaceholderSentinelText(text);
1677
+ };
1678
+
1679
+ if (isPlaceholder(iContent)) {
1680
+ formatted.splice(i, 1);
1681
+ // Removed the later element. The new formatted[i] (formerly
1682
+ // i+1) may now be same-role as i-1, so decrement once to
1683
+ // recheck from the correct position.
1684
+ i--;
1685
+ } else if (isPlaceholder(prevContent)) {
1686
+ formatted.splice(i - 1, 1);
1687
+ // Removed the earlier element — everything shifted down by 1.
1688
+ // The element that was at i is now at i-1. Decrement so the
1689
+ // next iteration compares the new i-1 with i-2 (or exits if
1690
+ // i-1 is 0).
1691
+ i--;
1692
+ } else {
1693
+ // Neither is a placeholder — merge content blocks into the
1694
+ // earlier message and remove the later one. Skip the merge
1695
+ // when either message carries tool_use or tool_result blocks;
1696
+ // those require structural alternation for ensureToolPairing
1697
+ // to inject the correct synthetic results downstream.
1698
+ const hasToolBlock = (c: Anthropic.ContentBlockParam[]): boolean =>
1699
+ c.some(
1700
+ (b) =>
1701
+ typeof b !== "string" &&
1702
+ (b.type === "tool_use" || b.type === "tool_result"),
1703
+ );
1704
+ if (!hasToolBlock(prevContent) && !hasToolBlock(iContent)) {
1705
+ formatted[i - 1] = {
1706
+ ...formatted[i - 1],
1707
+ content: [...prevContent, ...iContent],
1708
+ };
1709
+ formatted.splice(i, 1);
1710
+ // Clamp i to the new last index — the splice may have put
1711
+ // us past the end. If there's a new element at i (formerly
1712
+ // i+1), it will be rechecked against the merged i-1.
1713
+ if (i >= formatted.length) {
1714
+ i = formatted.length - 1;
1715
+ }
1716
+ } else {
1717
+ // Can't merge (tool blocks present) — leave for
1718
+ // ensureToolPairing which handles tool_use/tool_result
1719
+ // alternation in its own forward walk.
1720
+ i--;
1721
+ }
1722
+ }
1723
+ }
1724
+ }
1725
+
1726
+ // Strip thinking/redacted_thinking blocks from completed historical
1727
+ // assistant turns. Anthropic only requires these blocks for active
1728
+ // tool-use continuation (the tail span where assistant tool_use is
1729
+ // followed by user tool_result). Replaying stale thinking blocks from
1730
+ // earlier turns causes 400 errors when the signature is no longer
1731
+ // valid (e.g. after a provider/model/profile switch).
1732
+ const activeToolUseStart = findActiveToolUseContinuationStart(formatted);
1733
+ for (let i = 0; i < activeToolUseStart; i++) {
1734
+ const msg = formatted[i];
1735
+ if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
1736
+ const stripped = (msg.content as Anthropic.ContentBlockParam[]).filter(
1737
+ (b) =>
1738
+ typeof b === "string" ||
1739
+ (b.type !== "thinking" && b.type !== "redacted_thinking"),
1740
+ );
1741
+ if (stripped.length === 0) {
1742
+ stripped.push({
1743
+ type: "text" as const,
1744
+ text: PLACEHOLDER_BLOCKS_OMITTED,
1745
+ });
1746
+ }
1747
+ formatted[i] = { ...msg, content: stripped };
1748
+ }
1749
+
1750
+ return ensureToolPairing(repairOrphanedServerToolBlocks(formatted));
1751
+ }
1752
+
1684
1753
  /**
1685
1754
  * Convert a content block to Anthropic format, returning null for unknown
1686
1755
  * block types instead of throwing. Unknown types (e.g. ui_surface stored
@@ -60,6 +60,12 @@ export class CallSiteRoutingProvider implements Provider {
60
60
  return this._activeProviderContext.getStore() ?? this.defaultProvider.name;
61
61
  }
62
62
 
63
+ // Forward the optional token-counting endpoint from the default provider —
64
+ // the same one whose `tokenEstimationProvider` this wrapper surfaces, and
65
+ // the provider that handles the main agent turn that `/compact` sizes
66
+ // against. Per-call connection routing only affects `sendMessage`.
67
+ public readonly countInputTokens?: NonNullable<Provider["countInputTokens"]>;
68
+
63
69
  constructor(
64
70
  private readonly defaultProvider: Provider,
65
71
  /**
@@ -88,6 +94,10 @@ export class CallSiteRoutingProvider implements Provider {
88
94
  ) => Promise<Provider | null>,
89
95
  ) {
90
96
  this.tokenEstimationProvider = defaultProvider.tokenEstimationProvider;
97
+ if (defaultProvider.countInputTokens) {
98
+ this.countInputTokens =
99
+ defaultProvider.countInputTokens.bind(defaultProvider);
100
+ }
91
101
  }
92
102
 
93
103
  async sendMessage(
@@ -17,6 +17,7 @@ import type {
17
17
  Provider,
18
18
  ProviderResponse,
19
19
  SendMessageOptions,
20
+ ToolDefinition,
20
21
  } from "../types.js";
21
22
  import {
22
23
  ContextOverflowError,
@@ -518,6 +519,48 @@ export class GeminiProvider implements Provider {
518
519
  }
519
520
  }
520
521
 
522
+ /**
523
+ * Exact prompt-token count via Gemini's `models.countTokens` — the real
524
+ * tokenizer, no generation. Mirrors {@link sendMessage}'s composition
525
+ * (contents + `systemInstruction` + tool function declarations) so the count
526
+ * tracks what a real call would send. Throws when the endpoint returns no
527
+ * `totalTokens`, so the caller falls back to the local estimate.
528
+ */
529
+ async countInputTokens(
530
+ messages: Message[],
531
+ systemPrompt: string,
532
+ tools?: ToolDefinition[],
533
+ ): Promise<number> {
534
+ const contents = this.toGeminiContents(messages, this.model);
535
+ const config: genai.CountTokensConfig = {};
536
+ if (systemPrompt) {
537
+ config.systemInstruction = systemPrompt.replaceAll(
538
+ SYSTEM_PROMPT_CACHE_BOUNDARY,
539
+ "\n\n",
540
+ );
541
+ }
542
+ if (tools && tools.length > 0) {
543
+ config.tools = [
544
+ {
545
+ functionDeclarations: tools.map((t) => ({
546
+ name: t.name,
547
+ description: t.description,
548
+ parametersJsonSchema: t.input_schema,
549
+ })),
550
+ },
551
+ ];
552
+ }
553
+ const res = await this.client.models.countTokens({
554
+ model: this.model,
555
+ contents,
556
+ ...(Object.keys(config).length > 0 ? { config } : {}),
557
+ });
558
+ if (typeof res.totalTokens !== "number") {
559
+ throw new Error("Gemini countTokens returned no totalTokens");
560
+ }
561
+ return res.totalTokens;
562
+ }
563
+
521
564
  /** Convert neutral messages to Gemini Content[] format. */
522
565
  private toGeminiContents(
523
566
  messages: Message[],
@@ -29,6 +29,7 @@ import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provid
29
29
  import { OpenAIResponsesProvider } from "../openai/responses-provider.js";
30
30
  import { OpenRouterProvider } from "../openrouter/client.js";
31
31
  import { RetryProvider } from "../retry.js";
32
+ import { TogetherProvider } from "../together/client.js";
32
33
  import type { Provider } from "../types.js";
33
34
  import { UsageTrackingProvider } from "../usage-tracking.js";
34
35
  import type { ResolvedAuth } from "./auth.js";
@@ -117,6 +118,11 @@ const ADAPTER_FACTORIES: Record<string, AdapterFactory> = {
117
118
  new MinimaxProvider(apiKey, model, { streamTimeoutMs }),
118
119
  atlascloud: ({ apiKey, model, streamTimeoutMs }) =>
119
120
  new AtlasCloudProvider(apiKey, model, { streamTimeoutMs }),
121
+ together: ({ apiKey, model, streamTimeoutMs, baseURL }) =>
122
+ new TogetherProvider(apiKey, model, {
123
+ streamTimeoutMs,
124
+ ...(baseURL ? { baseURL } : {}),
125
+ }),
120
126
  };
121
127
 
122
128
  /**
@@ -346,6 +346,12 @@ const CANONICAL_CONNECTIONS: Array<{
346
346
  auth: { type: "platform" },
347
347
  label: "Fireworks",
348
348
  },
349
+ {
350
+ name: "together-managed",
351
+ provider: "together",
352
+ auth: { type: "platform" },
353
+ label: "Together AI",
354
+ },
349
355
  ];
350
356
 
351
357
  /**
@@ -415,4 +421,3 @@ export function seedCanonicalConnections(db: DrizzleDb): void {
415
421
  .run();
416
422
  }
417
423
  }
418
-
@@ -765,6 +765,43 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
765
765
  apiKeyUrl: "https://fireworks.ai/account/api-keys",
766
766
  apiKeyPlaceholder: "fw_...",
767
767
  },
768
+ {
769
+ id: "together",
770
+ displayName: "Together AI",
771
+ subtitle: "Open models served by Together AI. Requires a Together API key.",
772
+ setupMode: "api-key",
773
+ setupHint: "Enter your Together API key to enable Together models.",
774
+ envVar: "TOGETHER_API_KEY",
775
+ credentialsGuide: {
776
+ description: "Sign in to the Together dashboard and create an API key.",
777
+ url: "https://api.together.ai/settings/api-keys",
778
+ linkLabel: "Open Together Dashboard",
779
+ },
780
+ models: [
781
+ {
782
+ id: "MiniMaxAI/MiniMax-M3",
783
+ displayName: "MiniMax M3",
784
+ // Managed route for MiniMax M3. Together honors forced tool_choice
785
+ // and serializes object-typed tool args correctly. Window and pricing
786
+ // are from Together's published rate card.
787
+ contextWindowTokens: 524288,
788
+ maxOutputTokens: 512000,
789
+ supportsThinking: true,
790
+ supportsCaching: true,
791
+ supportsVision: true,
792
+ supportsToolUse: true,
793
+ maxEffort: "high",
794
+ pricing: {
795
+ inputPer1mTokens: 0.3,
796
+ outputPer1mTokens: 1.2,
797
+ cacheReadPer1mTokens: 0.06,
798
+ },
799
+ },
800
+ ],
801
+ defaultModel: "MiniMaxAI/MiniMax-M3",
802
+ apiKeyUrl: "https://api.together.ai/settings/api-keys",
803
+ apiKeyPlaceholder: "...",
804
+ },
768
805
  {
769
806
  id: "openrouter",
770
807
  displayName: "OpenRouter",
@@ -46,6 +46,11 @@ export const PLATFORM_PROVIDER_META: Record<string, ManagedProviderMeta> = {
46
46
  managed: true,
47
47
  proxyPath: "/v1/runtime-proxy/fireworks",
48
48
  },
49
+ together: {
50
+ name: "together",
51
+ managed: true,
52
+ proxyPath: "/v1/runtime-proxy/together",
53
+ },
49
54
  openrouter: {
50
55
  name: "openrouter",
51
56
  managed: false,
@@ -25,12 +25,21 @@ export class RateLimitProvider implements Provider {
25
25
 
26
26
  private requestTimestamps: number[];
27
27
 
28
+ // Forward the optional token-counting endpoint so the capability survives
29
+ // the wrapper chain. Bound straight to the inner provider — count_tokens is
30
+ // a cheap separate endpoint outside the message rate budget, and its caller
31
+ // falls back on error.
32
+ public readonly countInputTokens?: NonNullable<Provider["countInputTokens"]>;
33
+
28
34
  constructor(
29
35
  private readonly inner: Provider,
30
36
  private readonly config: RateLimitConfig,
31
37
  sharedRequestTimestamps?: number[],
32
38
  ) {
33
39
  this.requestTimestamps = sharedRequestTimestamps ?? [];
40
+ if (inner.countInputTokens) {
41
+ this.countInputTokens = inner.countInputTokens.bind(inner);
42
+ }
34
43
  }
35
44
 
36
45
  async sendMessage(