@vellumai/assistant 0.11.2 → 0.11.3-staging.2

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 (720) hide show
  1. package/ARCHITECTURE.md +58 -3
  2. package/docs/trusted-contact-access.md +9 -5
  3. package/docs/vellum-doctor.md +195 -0
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  7. package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
  8. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
  9. package/node_modules/@vellumai/environments/package.json +2 -1
  10. package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
  11. package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
  12. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
  13. package/node_modules/@vellumai/environments/src/index.ts +17 -6
  14. package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
  15. package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
  16. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  19. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
  20. package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
  21. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
  22. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
  23. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
  24. package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
  25. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
  26. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
  27. package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  28. package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  29. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  30. package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
  31. package/openapi.yaml +589 -30
  32. package/package.json +1 -1
  33. package/src/__tests__/agent-image-optimize.test.ts +4 -4
  34. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
  35. package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
  36. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
  37. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  38. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  39. package/src/__tests__/answered-question-persistence.test.ts +240 -0
  40. package/src/__tests__/anthropic-provider.test.ts +165 -30
  41. package/src/__tests__/app-control-flow.test.ts +9 -8
  42. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  43. package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
  44. package/src/__tests__/attachments-store.test.ts +130 -68
  45. package/src/__tests__/attachments.test.ts +36 -36
  46. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  47. package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
  48. package/src/__tests__/canned-reply-release.test.ts +86 -0
  49. package/src/__tests__/channel-guardian.test.ts +59 -29
  50. package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
  51. package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
  52. package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
  53. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  54. package/src/__tests__/consult-deadline.test.ts +65 -0
  55. package/src/__tests__/conversation-agent-loop.test.ts +438 -2
  56. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
  57. package/src/__tests__/conversation-disk-view.test.ts +4 -4
  58. package/src/__tests__/conversation-error.test.ts +22 -3
  59. package/src/__tests__/conversation-fork-crud.test.ts +5 -1
  60. package/src/__tests__/conversation-fork-referential.test.ts +352 -0
  61. package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
  62. package/src/__tests__/conversation-group-tools.test.ts +32 -2
  63. package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
  64. package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
  65. package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
  66. package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
  67. package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
  68. package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
  69. package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
  70. package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
  71. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
  72. package/src/__tests__/conversation-queue.test.ts +433 -1
  73. package/src/__tests__/conversation-retry-route.test.ts +3 -1
  74. package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
  75. package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
  76. package/src/__tests__/conversation-store.test.ts +26 -10
  77. package/src/__tests__/conversation-summarize-route.test.ts +1 -1
  78. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
  79. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
  81. package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
  82. package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
  83. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
  84. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  85. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
  90. package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
  91. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
  92. package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
  93. package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
  94. package/src/__tests__/credential-prompt-route.test.ts +57 -7
  95. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  96. package/src/__tests__/cu-unified-flow.test.ts +89 -28
  97. package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
  98. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
  99. package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
  100. package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
  101. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  102. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  103. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  104. package/src/__tests__/disk-usage.test.ts +35 -20
  105. package/src/__tests__/document-sync-tags.test.ts +379 -0
  106. package/src/__tests__/document-update-default-surface.test.ts +28 -0
  107. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  108. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
  109. package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
  110. package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
  111. package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
  112. package/src/__tests__/file-list-tool.test.ts +12 -10
  113. package/src/__tests__/file-ops-service.test.ts +151 -44
  114. package/src/__tests__/file-read-container-boundary.test.ts +137 -0
  115. package/src/__tests__/file-read-tool.test.ts +21 -9
  116. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  117. package/src/__tests__/filesystem-tools.test.ts +82 -66
  118. package/src/__tests__/guardian-outbound-http.test.ts +8 -8
  119. package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
  120. package/src/__tests__/helpers/hub-clients.ts +42 -0
  121. package/src/__tests__/helpers/mock-conversation.ts +46 -0
  122. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
  123. package/src/__tests__/history-repair.test.ts +112 -12
  124. package/src/__tests__/host-bash-proxy.test.ts +10 -5
  125. package/src/__tests__/host-bash-routes.test.ts +67 -0
  126. package/src/__tests__/host-browser-proxy.test.ts +2 -2
  127. package/src/__tests__/host-cu-proxy.test.ts +3 -7
  128. package/src/__tests__/host-file-proxy.test.ts +3 -7
  129. package/src/__tests__/host-file-read-tool.test.ts +5 -1
  130. package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
  131. package/src/__tests__/http-conversation-lineage.test.ts +2 -5
  132. package/src/__tests__/http-user-message-parity.test.ts +44 -0
  133. package/src/__tests__/identity-routes.test.ts +13 -13
  134. package/src/__tests__/image-conversion.test.ts +29 -26
  135. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  136. package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
  137. package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
  138. package/src/__tests__/introduction-card-resolver.test.ts +6 -1
  139. package/src/__tests__/list-messages-attachments.test.ts +56 -32
  140. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  141. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  142. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  143. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  144. package/src/__tests__/list-messages-provider-error.test.ts +6 -6
  145. package/src/__tests__/list-messages-queued.test.ts +49 -6
  146. package/src/__tests__/list-messages-system-card.test.ts +4 -4
  147. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  148. package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
  149. package/src/__tests__/llm-usage-store.test.ts +55 -0
  150. package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
  151. package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
  152. package/src/__tests__/media-stream-server-integration.test.ts +36 -0
  153. package/src/__tests__/migration-export-http.test.ts +1 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  155. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  156. package/src/__tests__/migration-validate-http.test.ts +1 -1
  157. package/src/__tests__/mtime-cache.test.ts +65 -3
  158. package/src/__tests__/notification-platform-adapter.test.ts +104 -0
  159. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  160. package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
  161. package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
  162. package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
  163. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  164. package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
  165. package/src/__tests__/path-policy.test.ts +164 -1
  166. package/src/__tests__/persist-media-references.test.ts +2 -2
  167. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  168. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  169. package/src/__tests__/persona-resolver.test.ts +154 -0
  170. package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
  171. package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
  172. package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
  173. package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
  174. package/src/__tests__/profiler-routes.test.ts +13 -13
  175. package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
  176. package/src/__tests__/proxy-approval-callback.test.ts +3 -3
  177. package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
  178. package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
  179. package/src/__tests__/resolve-trust-class.test.ts +20 -0
  180. package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
  181. package/src/__tests__/run-due-schedules.test.ts +174 -0
  182. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  183. package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
  184. package/src/__tests__/schedule-routes.test.ts +730 -8
  185. package/src/__tests__/schedule-store.test.ts +540 -0
  186. package/src/__tests__/schedule-tools.test.ts +103 -0
  187. package/src/__tests__/scheduler-wake.test.ts +5 -0
  188. package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
  189. package/src/__tests__/secure-keys.test.ts +91 -0
  190. package/src/__tests__/server-history-render.test.ts +97 -7
  191. package/src/__tests__/size-guard.test.ts +8 -8
  192. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  193. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  194. package/src/__tests__/skills-install-staging.test.ts +15 -6
  195. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  196. package/src/__tests__/slack-inbound-verification.test.ts +4 -1
  197. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  198. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  199. package/src/__tests__/starter-task-flow.test.ts +5 -4
  200. package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
  201. package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
  202. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  203. package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
  204. package/src/__tests__/subagent-disposal.test.ts +10 -0
  205. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  206. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  207. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  208. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  209. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  210. package/src/__tests__/subagent-persistence.test.ts +141 -0
  211. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  212. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  213. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  214. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  215. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  216. package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
  217. package/src/__tests__/subagent-tools.test.ts +1901 -108
  218. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  219. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  220. package/src/__tests__/system-prompt.test.ts +82 -7
  221. package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
  222. package/src/__tests__/tool-result-spool.test.ts +74 -18
  223. package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
  224. package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
  225. package/src/__tests__/tools-audio-read.test.ts +10 -10
  226. package/src/__tests__/tools-get-route.test.ts +85 -12
  227. package/src/__tests__/tools-list-cli.test.ts +171 -0
  228. package/src/__tests__/top-level-renderer.test.ts +54 -1
  229. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
  230. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
  231. package/src/__tests__/turn-tail-chain.test.ts +135 -0
  232. package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
  233. package/src/__tests__/ui-visual-surface.test.ts +5 -4
  234. package/src/__tests__/ui-work-result-surface.test.ts +5 -4
  235. package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
  236. package/src/__tests__/usage-routes.test.ts +62 -0
  237. package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
  238. package/src/__tests__/visible-app-context.test.ts +20 -4
  239. package/src/__tests__/web-search-history.test.ts +96 -0
  240. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
  241. package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
  242. package/src/acp/failure-error.ts +3 -5
  243. package/src/agent/attachments.ts +26 -24
  244. package/src/agent/history-repair/history-repair.ts +27 -26
  245. package/src/agent/image-optimize.ts +6 -6
  246. package/src/agent/loop.ts +40 -22
  247. package/src/agent/message-types.ts +3 -3
  248. package/src/api/constants/document-tools.ts +55 -0
  249. package/src/api/events/question-answered.ts +53 -0
  250. package/src/api/events/tool-result.ts +7 -0
  251. package/src/api/index.ts +13 -0
  252. package/src/api/responses/conversation-message.ts +11 -0
  253. package/src/api/surfaces-oauth-connect.test.ts +96 -0
  254. package/src/api/surfaces.ts +36 -8
  255. package/src/approvals/guardian-channel-delivery.ts +83 -0
  256. package/src/approvals/guardian-expiry-notifier.ts +13 -11
  257. package/src/approvals/guardian-request-resolvers.ts +222 -135
  258. package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
  259. package/src/calls/media-stream-server.ts +9 -1
  260. package/src/calls/voice-session-bridge.ts +38 -0
  261. package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
  262. package/src/channels/config.ts +7 -2
  263. package/src/channels/gateway-verification-sessions.ts +7 -2
  264. package/src/channels/types.ts +7 -1
  265. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  266. package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
  267. package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
  268. package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
  269. package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
  270. package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
  271. package/src/cli/commands/__tests__/plugins.test.ts +692 -0
  272. package/src/cli/commands/__tests__/schedules.test.ts +136 -37
  273. package/src/cli/commands/conversations.ts +7 -3
  274. package/src/cli/commands/credentials.help.ts +7 -0
  275. package/src/cli/commands/inference-profiles.ts +9 -3
  276. package/src/cli/commands/inference.help.ts +16 -2
  277. package/src/cli/commands/mcp.help.ts +4 -2
  278. package/src/cli/commands/memory/memory-retrospective.ts +18 -0
  279. package/src/cli/commands/notifications.ts +3 -6
  280. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
  281. package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
  282. package/src/cli/commands/oauth/connect.test.ts +26 -1
  283. package/src/cli/commands/oauth/connect.ts +4 -1
  284. package/src/cli/commands/oauth/index.help.ts +3 -1
  285. package/src/cli/commands/oauth/providers.ts +3 -0
  286. package/src/cli/commands/plugins.help.ts +25 -2
  287. package/src/cli/commands/plugins.ts +289 -10
  288. package/src/cli/commands/schedules.help.ts +14 -12
  289. package/src/cli/commands/schedules.ts +19 -5
  290. package/src/cli/commands/tools.help.ts +4 -2
  291. package/src/cli/commands/tools.ts +38 -0
  292. package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
  293. package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
  294. package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
  295. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
  296. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
  297. package/src/cli/lib/install-from-github.ts +61 -0
  298. package/src/cli/lib/install-from-platform.ts +13 -2
  299. package/src/cli/lib/plugin-surfaces.ts +124 -4
  300. package/src/cli/lib/upgrade-plugin.ts +18 -0
  301. package/src/cli.ts +1 -1
  302. package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
  303. package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
  304. package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
  305. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  306. package/src/config/bundled-skills/AGENTS.md +1 -1
  307. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  308. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
  309. package/src/config/bundled-skills/schedule/SKILL.md +5 -1
  310. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  311. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  312. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
  313. package/src/config/bundled-skills/subagent/SKILL.md +53 -22
  314. package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
  315. package/src/config/bundled-skills/visualize/SKILL.md +1 -1
  316. package/src/config/default-profile-catalog.ts +6 -2
  317. package/src/config/feature-flag-registry.json +25 -17
  318. package/src/config/llm-resolver.ts +45 -15
  319. package/src/config/loader.ts +70 -1
  320. package/src/config/profile-tool-support.ts +110 -0
  321. package/src/config/sanitize-for-transfer.ts +11 -0
  322. package/src/config/schema.ts +4 -0
  323. package/src/config/schemas/__tests__/stt.test.ts +20 -5
  324. package/src/config/schemas/channels.ts +13 -0
  325. package/src/config/schemas/memory-retrospective.ts +25 -0
  326. package/src/config/schemas/plugin-updates.ts +55 -0
  327. package/src/config/schemas/services.ts +8 -4
  328. package/src/config/schemas/stt.ts +17 -5
  329. package/src/config/schemas/timeouts.ts +1 -1
  330. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
  331. package/src/contacts/guardian-delivery-reader.ts +29 -2
  332. package/src/context/compactor.ts +4 -4
  333. package/src/context/post-turn-tool-result-truncation.ts +32 -16
  334. package/src/context/strip-injections.ts +42 -0
  335. package/src/context/tool-result-spool.ts +32 -18
  336. package/src/credential-execution/ces-runtime.ts +3 -0
  337. package/src/credential-execution/client.ts +22 -1
  338. package/src/credential-execution/process-manager.test.ts +99 -0
  339. package/src/credential-execution/process-manager.ts +62 -16
  340. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  341. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
  342. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  343. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
  344. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
  345. package/src/daemon/channel-ui-capability.ts +4 -4
  346. package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
  347. package/src/daemon/conversation-agent-loop.ts +318 -148
  348. package/src/daemon/conversation-attachments.ts +1 -1
  349. package/src/daemon/conversation-error.ts +8 -1
  350. package/src/daemon/conversation-initial-prompt.ts +16 -38
  351. package/src/daemon/conversation-lifecycle.ts +154 -32
  352. package/src/daemon/conversation-messaging.ts +106 -43
  353. package/src/daemon/conversation-process.ts +131 -33
  354. package/src/daemon/conversation-queue-manager.ts +10 -0
  355. package/src/daemon/conversation-runtime-assembly.ts +9 -4
  356. package/src/daemon/conversation-store.ts +52 -3
  357. package/src/daemon/conversation-surface-state.ts +9 -0
  358. package/src/daemon/conversation-surfaces.ts +403 -210
  359. package/src/daemon/conversation-tool-setup.ts +56 -7
  360. package/src/daemon/conversation-turn-finalize.ts +134 -89
  361. package/src/daemon/conversation.ts +111 -27
  362. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  363. package/src/daemon/disk-pressure-guard.ts +3 -3
  364. package/src/daemon/doordash-steps.ts +5 -5
  365. package/src/daemon/external-plugins-bootstrap.ts +7 -1
  366. package/src/daemon/handlers/config-channels.ts +48 -5
  367. package/src/daemon/handlers/conversation-history.ts +1 -1
  368. package/src/daemon/handlers/conversations.ts +62 -17
  369. package/src/daemon/handlers/shared.ts +12 -0
  370. package/src/daemon/handlers/skills.ts +11 -1
  371. package/src/daemon/identity-helpers.ts +38 -10
  372. package/src/daemon/install-assistant-command.ts +322 -0
  373. package/src/daemon/lifecycle.ts +14 -3
  374. package/src/daemon/message-types/conversations.ts +6 -7
  375. package/src/daemon/message-types/sync.ts +1 -0
  376. package/src/daemon/persist-media-references.ts +23 -14
  377. package/src/daemon/process-message.ts +6 -6
  378. package/src/daemon/tool-setup-types.ts +19 -122
  379. package/src/daemon/tool-side-effects.ts +17 -94
  380. package/src/daemon/trust-context-types.ts +39 -0
  381. package/src/daemon/trust-context.ts +14 -6
  382. package/src/daemon/turn-tail-chain.ts +73 -0
  383. package/src/daemon/web-search-history.ts +47 -33
  384. package/src/heartbeat/heartbeat-service.ts +6 -6
  385. package/src/ipc/__tests__/socket-path.test.ts +21 -0
  386. package/src/ipc/assistant-server.ts +17 -10
  387. package/src/ipc/cli-client.ts +10 -1
  388. package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
  389. package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
  390. package/src/ipc/socket-cleanup.ts +9 -7
  391. package/src/ipc/socket-path.ts +4 -96
  392. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  393. package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
  394. package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
  395. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  396. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
  397. package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
  398. package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
  399. package/src/live-voice/__tests__/protocol.test.ts +52 -0
  400. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
  401. package/src/live-voice/live-voice-archive.ts +13 -13
  402. package/src/live-voice/live-voice-connection.ts +7 -1
  403. package/src/live-voice/live-voice-photo.ts +169 -0
  404. package/src/live-voice/live-voice-session.ts +108 -4
  405. package/src/live-voice/protocol.ts +89 -1
  406. package/src/mcp/client.ts +10 -0
  407. package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
  408. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
  409. package/src/messaging/providers/callback-routing.ts +1 -0
  410. package/src/messaging/providers/discord/api.ts +312 -0
  411. package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
  412. package/src/messaging/providers/discord/render.test.ts +204 -0
  413. package/src/messaging/providers/discord/render.ts +195 -0
  414. package/src/messaging/providers/discord/send.test.ts +179 -0
  415. package/src/messaging/providers/discord/send.ts +212 -0
  416. package/src/messaging/providers/discord/transport.ts +81 -0
  417. package/src/messaging/providers/index.ts +3 -1
  418. package/src/messaging/providers/retry-policy.test.ts +247 -0
  419. package/src/messaging/providers/retry-policy.ts +206 -0
  420. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  421. package/src/messaging/providers/slack/mention-source.ts +287 -0
  422. package/src/messaging/providers/telegram-bot/api.ts +47 -130
  423. package/src/messaging/providers/whatsapp/api.ts +47 -136
  424. package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
  425. package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
  426. package/src/monitoring/db-integrity-sample.ts +6 -1
  427. package/src/monitoring/plugin-auto-update.ts +359 -0
  428. package/src/monitoring/resource-sampler.ts +21 -5
  429. package/src/monitoring/worker.ts +13 -0
  430. package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
  431. package/src/notifications/__tests__/broadcaster.test.ts +37 -1
  432. package/src/notifications/__tests__/copy-composer.test.ts +165 -0
  433. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
  434. package/src/notifications/__tests__/notification-utils.test.ts +249 -0
  435. package/src/notifications/adapters/platform.ts +31 -2
  436. package/src/notifications/assistant-reply-producer.ts +79 -32
  437. package/src/notifications/broadcaster.ts +30 -10
  438. package/src/notifications/copy-composer.ts +69 -0
  439. package/src/notifications/emit-signal.ts +82 -15
  440. package/src/notifications/events-store.ts +10 -2
  441. package/src/notifications/home-feed-side-effect.ts +6 -3
  442. package/src/notifications/notification-utils.ts +173 -5
  443. package/src/notifications/signal.ts +12 -0
  444. package/src/oauth/AGENTS.md +4 -2
  445. package/src/oauth/byo-connection.ts +6 -1
  446. package/src/oauth/credential-token-resolver.ts +3 -10
  447. package/src/oauth/manual-token-connection.ts +29 -64
  448. package/src/oauth/manual-token-providers.ts +62 -0
  449. package/src/oauth/provider-serializer.ts +13 -0
  450. package/src/oauth/seed-providers.ts +62 -11
  451. package/src/onboarding/onboarding-events-store.ts +91 -1
  452. package/src/permissions/question-prompter.test.ts +4 -0
  453. package/src/permissions/question-prompter.ts +21 -4
  454. package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
  455. package/src/persistence/attachments-store.ts +15 -15
  456. package/src/persistence/conversation-attention-store.ts +30 -10
  457. package/src/persistence/conversation-bootstrap.ts +17 -0
  458. package/src/persistence/conversation-crud.ts +363 -97
  459. package/src/persistence/conversation-group-migration.ts +1 -1
  460. package/src/persistence/conversation-key-store.ts +38 -10
  461. package/src/persistence/conversation-lineage.ts +226 -0
  462. package/src/persistence/conversation-plugin-facade.ts +28 -3
  463. package/src/persistence/conversation-queries.ts +207 -33
  464. package/src/persistence/conversation-types.ts +107 -1
  465. package/src/persistence/jobs-store.ts +32 -8
  466. package/src/persistence/llm-usage-store.ts +22 -0
  467. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  468. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  469. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  470. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  471. package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
  472. package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
  473. package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
  474. package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
  475. package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
  476. package/src/persistence/schema/conversations.ts +32 -0
  477. package/src/persistence/schema/infrastructure.ts +3 -0
  478. package/src/persistence/steps.ts +30 -0
  479. package/src/persistence/subagent-store.ts +148 -6
  480. package/src/platform/managed-speech.test.ts +20 -0
  481. package/src/platform/managed-speech.ts +9 -0
  482. package/src/plugin-api/index.ts +8 -0
  483. package/src/plugin-api/webhook-url.ts +151 -0
  484. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
  485. package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
  486. package/src/plugins/collect-source-versions.ts +4 -27
  487. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  488. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  489. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  490. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  491. package/src/plugins/defaults/index.ts +1 -1
  492. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
  493. package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
  494. package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
  495. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
  496. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
  497. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
  498. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
  499. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
  500. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
  501. package/src/plugins/defaults/memory/job-handlers.ts +87 -5
  502. package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
  503. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  504. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
  505. package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
  506. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
  507. package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
  508. package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
  509. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  510. package/src/plugins/defaults/memory/v2/router.ts +8 -0
  511. package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
  512. package/src/plugins/external-plugin-loader.ts +17 -8
  513. package/src/plugins/installed-plugin-dirs.ts +101 -0
  514. package/src/plugins/mtime-cache.ts +34 -22
  515. package/src/plugins/types.ts +69 -8
  516. package/src/prompts/persona-resolver.ts +6 -2
  517. package/src/prompts/system-prompt.ts +72 -17
  518. package/src/providers/__tests__/inference.test.ts +40 -0
  519. package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
  520. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  521. package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
  522. package/src/providers/anthropic/client.ts +112 -95
  523. package/src/providers/connection-resolution.ts +35 -1
  524. package/src/providers/gemini/client.ts +5 -5
  525. package/src/providers/inference/adapter-factory.ts +16 -10
  526. package/src/providers/inference/auth.ts +16 -0
  527. package/src/providers/inference/connection-availability.ts +164 -12
  528. package/src/providers/inference/connections.ts +25 -1
  529. package/src/providers/media-resolve.ts +21 -11
  530. package/src/providers/model-catalog.ts +15 -0
  531. package/src/providers/openai/chat-completions-provider.ts +4 -4
  532. package/src/providers/openai/responses-provider.ts +12 -25
  533. package/src/providers/registry.ts +9 -4
  534. package/src/providers/retry.ts +25 -0
  535. package/src/providers/server-tool-pairing.ts +134 -0
  536. package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
  537. package/src/providers/speech-to-text/deepgram.ts +1 -0
  538. package/src/providers/speech-to-text/resolve.ts +80 -10
  539. package/src/providers/speech-to-text/vellum-managed.ts +7 -1
  540. package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
  541. package/src/providers/types.ts +26 -6
  542. package/src/providers/vellum-model-routing.ts +6 -7
  543. package/src/runtime/AGENTS.md +2 -0
  544. package/src/runtime/__tests__/agent-wake.test.ts +16 -16
  545. package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
  546. package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
  547. package/src/runtime/agent-wake.ts +63 -24
  548. package/src/runtime/assistant-event-hub.ts +87 -12
  549. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
  550. package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
  551. package/src/runtime/auth/same-actor.ts +56 -8
  552. package/src/runtime/auth/scopes.ts +12 -0
  553. package/src/runtime/auth/types.ts +2 -0
  554. package/src/runtime/background-job-runner.ts +5 -27
  555. package/src/runtime/channel-readiness-service.ts +59 -3
  556. package/src/runtime/channel-readiness-types.ts +18 -0
  557. package/src/runtime/desktop-presence.ts +69 -0
  558. package/src/runtime/http-server.ts +12 -0
  559. package/src/runtime/local-actor-identity.ts +11 -9
  560. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  561. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  562. package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
  563. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
  564. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
  565. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
  566. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
  567. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  568. package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
  569. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  570. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
  571. package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
  572. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
  573. package/src/runtime/routes/archive-utils.ts +16 -12
  574. package/src/runtime/routes/attachment-routes.ts +13 -6
  575. package/src/runtime/routes/canned-reply-release.ts +54 -0
  576. package/src/runtime/routes/channel-verification-routes.ts +2 -27
  577. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
  578. package/src/runtime/routes/client-routes.ts +114 -2
  579. package/src/runtime/routes/conversation-cli-routes.ts +10 -12
  580. package/src/runtime/routes/conversation-list-routes.ts +59 -10
  581. package/src/runtime/routes/conversation-management-routes.ts +47 -18
  582. package/src/runtime/routes/conversation-query-routes.ts +32 -53
  583. package/src/runtime/routes/conversation-routes.ts +360 -293
  584. package/src/runtime/routes/credential-prompt-routes.ts +23 -2
  585. package/src/runtime/routes/debug-routes.ts +4 -1
  586. package/src/runtime/routes/default-provider-routes.ts +7 -11
  587. package/src/runtime/routes/documents-routes.ts +44 -1
  588. package/src/runtime/routes/events-routes.ts +28 -1
  589. package/src/runtime/routes/host-app-control-routes.ts +2 -0
  590. package/src/runtime/routes/host-bash-routes.ts +2 -0
  591. package/src/runtime/routes/host-browser-routes.ts +2 -0
  592. package/src/runtime/routes/host-cu-routes.ts +2 -0
  593. package/src/runtime/routes/host-file-routes.ts +2 -0
  594. package/src/runtime/routes/host-transfer-routes.ts +4 -0
  595. package/src/runtime/routes/identity-routes.ts +6 -6
  596. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  597. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
  598. package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
  599. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
  600. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
  601. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
  602. package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
  603. package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
  604. package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
  605. package/src/runtime/routes/inference-profiles-routes.ts +152 -73
  606. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
  607. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  608. package/src/runtime/routes/log-export-routes.ts +1 -1
  609. package/src/runtime/routes/notification-routes.ts +0 -14
  610. package/src/runtime/routes/oauth-providers.ts +1 -0
  611. package/src/runtime/routes/plugins-routes.ts +106 -1
  612. package/src/runtime/routes/profiler-routes.ts +4 -2
  613. package/src/runtime/routes/question-routes.ts +28 -10
  614. package/src/runtime/routes/retrospective-routes.ts +9 -3
  615. package/src/runtime/routes/schedule-routes.ts +210 -12
  616. package/src/runtime/routes/secret-routes.ts +40 -23
  617. package/src/runtime/routes/settings-routes.ts +41 -13
  618. package/src/runtime/routes/skills-routes.ts +79 -0
  619. package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
  620. package/src/runtime/routes/wake-conversation-routes.ts +23 -0
  621. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  622. package/src/runtime/services/conversation-serializer.ts +24 -9
  623. package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
  624. package/src/runtime/sync/resource-sync-events.ts +79 -1
  625. package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
  626. package/src/runtime/sync/worker-daemon-notify.ts +44 -6
  627. package/src/runtime/verification-outbound-actions.ts +250 -222
  628. package/src/runtime/verification-templates.ts +41 -30
  629. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
  630. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
  631. package/src/schedule/inference-profile.ts +64 -3
  632. package/src/schedule/plugin-schedule-declarations.ts +518 -0
  633. package/src/schedule/plugin-schedule-reconciler.ts +605 -0
  634. package/src/schedule/plugin-schedules-gate.ts +23 -0
  635. package/src/schedule/schedule-store.ts +520 -26
  636. package/src/schedule/scheduler.ts +38 -0
  637. package/src/security/credential-backend.ts +51 -4
  638. package/src/security/encrypted-store.ts +64 -42
  639. package/src/security/secure-keys.ts +55 -7
  640. package/src/skills/catalog-install.ts +20 -7
  641. package/src/skills/inline-command-runner.ts +2 -7
  642. package/src/skills/skill-history.test.ts +269 -0
  643. package/src/skills/skill-history.ts +250 -0
  644. package/src/skills/skillssh-registry.ts +1 -1
  645. package/src/stt/daemon-batch-transcriber.ts +8 -6
  646. package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
  647. package/src/subagent/consult-prompt.ts +3 -1
  648. package/src/subagent/consult-transcript.ts +1 -1
  649. package/src/subagent/manager.ts +304 -44
  650. package/src/subagent/progress-events.ts +35 -0
  651. package/src/subagent/role-resolution.ts +88 -0
  652. package/src/subagent/types.ts +302 -67
  653. package/src/subagent/validate-allowlists.ts +3 -4
  654. package/src/telegram/__tests__/webhook-health.test.ts +73 -1
  655. package/src/telegram/webhook-health.ts +101 -3
  656. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  657. package/src/telemetry/activation-funnel.ts +6 -1
  658. package/src/telemetry/live-voice-funnel.ts +75 -0
  659. package/src/telemetry/telemetry-event-sources.ts +6 -0
  660. package/src/telemetry/telemetry-wire-source.json +1 -1
  661. package/src/telemetry/telemetry-wire.generated.ts +2 -0
  662. package/src/telemetry/types.ts +23 -4
  663. package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
  664. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  665. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  666. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  667. package/src/tools/browser/browser-execution.ts +1 -1
  668. package/src/tools/calls/call-start.ts +8 -5
  669. package/src/tools/conversation-groups/move_to_group.ts +10 -12
  670. package/src/tools/document/document-tool.ts +11 -4
  671. package/src/tools/execution-timeout.ts +9 -2
  672. package/src/tools/executor.ts +7 -6
  673. package/src/tools/filesystem/edit.ts +1 -1
  674. package/src/tools/filesystem/list.ts +1 -1
  675. package/src/tools/filesystem/read.ts +7 -13
  676. package/src/tools/filesystem/search.ts +23 -21
  677. package/src/tools/filesystem/write.ts +4 -1
  678. package/src/tools/host-filesystem/edit.ts +7 -2
  679. package/src/tools/host-filesystem/read.ts +21 -8
  680. package/src/tools/host-filesystem/write.ts +10 -2
  681. package/src/tools/host-terminal/host-shell.ts +2 -2
  682. package/src/tools/mcp/mcp-tool-factory.ts +25 -1
  683. package/src/tools/permission-checker.ts +8 -3
  684. package/src/tools/schedule/delete.ts +13 -1
  685. package/src/tools/schedule/list.ts +14 -3
  686. package/src/tools/schedule/update.ts +56 -33
  687. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  688. package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
  689. package/src/tools/shared/filesystem/image-read.ts +12 -12
  690. package/src/tools/shared/filesystem/path-policy.ts +70 -5
  691. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  692. package/src/tools/shared/input-misuse.ts +72 -0
  693. package/src/tools/skills/scaffold-managed.ts +82 -0
  694. package/src/tools/skills/skill-tool-factory.ts +14 -1
  695. package/src/tools/subagent/consult-deadline.ts +12 -7
  696. package/src/tools/subagent/message.ts +3 -1
  697. package/src/tools/subagent/read.ts +66 -4
  698. package/src/tools/subagent/spawn.ts +500 -78
  699. package/src/tools/tool-approval-handler.ts +45 -4
  700. package/src/tools/types.ts +22 -3
  701. package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
  702. package/src/tools/ui-surface/visual-validation.ts +2 -0
  703. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  704. package/src/usage/subagent-attribution.ts +108 -0
  705. package/src/util/__tests__/sqlite-retry.test.ts +112 -0
  706. package/src/util/abort-reasons.ts +16 -0
  707. package/src/util/ansi.ts +44 -0
  708. package/src/util/disk-usage.ts +17 -13
  709. package/src/util/image-conversion.ts +20 -13
  710. package/src/util/schedule-source-key.ts +23 -0
  711. package/src/util/worker-process.ts +7 -1
  712. package/src/workspace/git-service.ts +33 -9
  713. package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
  714. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
  715. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
  716. package/src/workspace/migrations/registry.ts +4 -0
  717. package/src/workspace/top-level-renderer.ts +15 -2
  718. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
  719. package/src/daemon/install-symlink.ts +0 -207
  720. package/src/notifications/deferred-emit.ts +0 -147
@@ -46,6 +46,7 @@ import {
46
46
  type ConversationRow,
47
47
  deleteConversation,
48
48
  getConversation,
49
+ getConversationProcessingStartedAt,
49
50
  isConversationProcessing,
50
51
  } from "@vellumai/plugin-api";
51
52
 
@@ -56,7 +57,7 @@ import {
56
57
  } from "../../../channels/types.js";
57
58
  import { isV3TierActive } from "../../../config/memory-v3-gate.js";
58
59
  import type { AssistantConfig } from "../../../config/types.js";
59
- import { getGuardianDelivery } from "../../../contacts/guardian-delivery-reader.js";
60
+ import { warmGuardianBindings } from "../../../contacts/guardian-delivery-reader.js";
60
61
  import { extractTurnContextTimestamp } from "../../../context/compactor.js";
61
62
  import {
62
63
  formatLocalTimestamp,
@@ -72,7 +73,6 @@ import {
72
73
  enqueueMemoryJob,
73
74
  type MemoryJob,
74
75
  type MemoryJobType,
75
- upsertMemoryRetrospectiveJob,
76
76
  } from "../../../persistence/jobs-store.js";
77
77
  import { resolveUserSlug } from "../../../prompts/persona-resolver.js";
78
78
  import type { SystemPromptPersonaOverride } from "../../../prompts/system-prompt.js";
@@ -88,6 +88,7 @@ import {
88
88
  MEMORY_RETROSPECTIVE_FORK_SOURCE,
89
89
  MEMORY_RETROSPECTIVE_GROUP_ID,
90
90
  MEMORY_RETROSPECTIVE_INSTRUCTION_KIND,
91
+ MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT,
91
92
  MEMORY_RETROSPECTIVE_ORIGIN,
92
93
  MEMORY_RETROSPECTIVE_SOURCE,
93
94
  SKILL_MANAGEMENT_SKILL_ID,
@@ -112,15 +113,17 @@ const log = getLogger("memory-retrospective-job");
112
113
  const FOLLOW_UP_JOB_TYPES: readonly MemoryJobType[] = [] as const;
113
114
 
114
115
  /**
115
- * Fallback delay for re-upserting a run that was skipped because the source
116
- * conversation was mid-turn. The PRIMARY requeue is event-driven: the
117
- * mid-turn skip leaves `lastRunAt` unbumped, so the message-indexing pass on
118
- * the turn's final assistant message re-enqueues immediately. This timed row
119
- * only covers a turn that aborts without ever persisting another message.
120
- * Each retried attempt re-checks the processing flag and re-upserts at the
121
- * same cadence, so the loop self-resolves when the turn ends.
116
+ * Age past which a source conversation's persisted `processing_started_at`
117
+ * stamp is treated as stranded rather than live, and the retrospective
118
+ * proceeds despite it. A turn-end flag clear can fail and be swallowed under
119
+ * DB-lock contention while the daemon stays up, and the monitor-process
120
+ * reaper only clears flags older than the daemon's boot time, so an
121
+ * in-process stranded flag otherwise blocks a conversation's retrospectives
122
+ * indefinitely. Proceeding risks only forking a half-finished display turn
123
+ * (a review-quality concern; the fork copies complete persisted turns), which
124
+ * is strictly better than never forming memories for the conversation again.
122
125
  */
123
- export const SOURCE_PROCESSING_REQUEUE_DELAY_MS = 60_000;
126
+ export const STALE_SOURCE_PROCESSING_OVERRIDE_MS = 6 * 60 * 60 * 1000;
124
127
 
125
128
  /** Watchdog check_name for the per-run retrospective outcome counter. */
126
129
  const MEMORY_RETROSPECTIVE_RUN_CHECK_NAME = "memory_retrospective_run";
@@ -132,6 +135,7 @@ export type MemoryRetrospectiveOutcome =
132
135
  | { kind: "source_dormant" }
133
136
  | { kind: "source_processing" }
134
137
  | { kind: "wake_failed"; reason?: string; conversationId?: string }
138
+ | { kind: "no_usable_output"; reason?: string; conversationId?: string }
135
139
  | {
136
140
  kind: "invoked";
137
141
  backgroundConversationId: string;
@@ -150,6 +154,20 @@ export async function memoryRetrospectiveJob(
150
154
  return { kind: "no_new_messages" };
151
155
  }
152
156
 
157
+ // Execution-time twin of the enqueue funnel's `memory.retrospective.enabled`
158
+ // gate: rows queued before the flag was turned off drain as no-ops instead
159
+ // of forking. The CLI's manual `memory retrospective run` calls
160
+ // `runForkBasedRetrospective` directly and so is unaffected: an operator's
161
+ // explicit request overrides the flag, matching the lookback and
162
+ // user-activity gates.
163
+ if (!config.memory.retrospective.enabled) {
164
+ log.info(
165
+ { jobId: job.id, sourceConversationId },
166
+ "Skipping job: memory.retrospective.enabled is false",
167
+ );
168
+ return { kind: "disabled" };
169
+ }
170
+
153
171
  // Central health counter (admin analytics groups on the watchdog
154
172
  // check_name): one event per run with its outcome kind. A run that
155
173
  // throws records outcome "error" before the exception continues to the
@@ -186,7 +204,9 @@ export async function memoryRetrospectiveJob(
186
204
  }
187
205
  emitRunOutcome(
188
206
  outcome.kind,
189
- outcome.kind === "wake_failed" ? outcome.reason : undefined,
207
+ outcome.kind === "wake_failed" || outcome.kind === "no_usable_output"
208
+ ? outcome.reason
209
+ : undefined,
190
210
  );
191
211
  return outcome;
192
212
  }
@@ -271,34 +291,36 @@ export async function runForkBasedRetrospective(
271
291
  // persisted message — including the turn's final assistant message — so an
272
292
  // unbumped `lastRunAt` lets that turn-end pass re-enqueue with no cooldown
273
293
  // suppression. That is the primary, event-driven requeue: the retrospective
274
- // runs right after the colliding turn completes. Mid-turn attempts are
275
- // cheap no-ops (existence + processing check) that recur at most once per
276
- // persisted message and coalesce into a single pending row via the upsert.
277
- // The timed re-upsert below is a fallback for a turn that aborts without
278
- // ever indexing another message (the lifecycle/disposal enqueue remains
279
- // the last-resort net). Both state pointers stay untouched, so nothing is
280
- // lost. Returning (not throwing) keeps the jobs-worker from
281
- // retry-with-backoff.
294
+ // runs right after the colliding turn completes. The `source_processing`
295
+ // outcome maps to a bounded deferral of the SAME job row at the worker
296
+ // (see `resolveRetrospectiveOutcome` in `job-handlers.ts`); turn-end
297
+ // trigger upserts coalesce onto that pending row, so the event-driven
298
+ // retry keeps its immediacy while a stranded flag can no longer mint an
299
+ // unbounded stream of fresh rows. Both state pointers stay untouched, so
300
+ // nothing is lost.
301
+ //
302
+ // Stranded-flag override: a swallowed turn-end flag clear leaves the
303
+ // persisted stamp set while the daemon stays up, where the monitor
304
+ // process's boot-time-fenced reaper never touches it. A stamp older than
305
+ // `STALE_SOURCE_PROCESSING_OVERRIDE_MS` is treated as stranded and the run
306
+ // proceeds; a set-but-stampless flag reads as live (deferral bounds it).
282
307
  if (await isConversationProcessing(sourceConversationId)) {
283
- try {
284
- upsertMemoryRetrospectiveJob(
285
- { conversationId: sourceConversationId },
286
- Date.now() + SOURCE_PROCESSING_REQUEUE_DELAY_MS,
287
- );
308
+ const processingStartedAt =
309
+ await getConversationProcessingStartedAt(sourceConversationId);
310
+ const stale =
311
+ processingStartedAt != null &&
312
+ startedAtMs - processingStartedAt > STALE_SOURCE_PROCESSING_OVERRIDE_MS;
313
+ if (!stale) {
288
314
  log.info(
289
- {
290
- sourceConversationId,
291
- requeueDelayMs: SOURCE_PROCESSING_REQUEUE_DELAY_MS,
292
- },
293
- "memory-retrospective (fork): source conversation is mid-turn; requeued",
294
- );
295
- } catch (err) {
296
- log.warn(
297
- { err, sourceConversationId },
298
- "memory-retrospective (fork): mid-turn fallback requeue failed; relying on the turn-end trigger check",
315
+ { sourceConversationId, processingStartedAt },
316
+ "memory-retrospective (fork): source conversation is mid-turn; deferring",
299
317
  );
318
+ return { kind: "source_processing" };
300
319
  }
301
- return { kind: "source_processing" };
320
+ log.warn(
321
+ { sourceConversationId, processingStartedAt },
322
+ "memory-retrospective (fork): processing flag is stale beyond the override window; proceeding despite it",
323
+ );
302
324
  }
303
325
 
304
326
  const state = getRetrospectiveState(sourceConversationId);
@@ -457,10 +479,11 @@ export async function runForkBasedRetrospective(
457
479
  // parity — the fork always runs execution gate mode below, so the source's
458
480
  // full tool surface stays on the wire while the allowlist holds at
459
481
  // execution time.
460
- // Warm the vellum guardian-delivery cache so the sync slug resolution inside
461
- // resolveSourceParityPins (resolveUserSlug(undefined)) hits a fresh key
462
- // instead of falling back to "default" on a cold/TTL-expired cache.
463
- await getGuardianDelivery({ channelTypes: ["vellum"] });
482
+ // Warm both guardian-delivery cache keys (vellum + unfiltered) so the sync
483
+ // slug resolution inside resolveSourceParityPins (resolveUserSlug(undefined)),
484
+ // including its any-channel fallback, hits fresh keys instead of falling
485
+ // back to "default" on a cold/TTL-expired cache.
486
+ await warmGuardianBindings();
464
487
  const { personaOverride, toolContextPin } = resolveSourceParityPins(
465
488
  sourceConversation,
466
489
  newMessages,
@@ -549,25 +572,65 @@ export async function runForkBasedRetrospective(
549
572
  }
550
573
 
551
574
  if (wakeSucceeded) {
552
- return await finalizeSuccessfulRetrospective({
553
- config,
554
- sourceConversationId,
555
- retrospectiveConversationId: forkId,
556
- cutoffMessageId,
557
- newMessageCount: newMessages.length,
558
- prior,
559
- priorRemembers,
560
- logFields: {
561
- kind: "fork",
562
- windowStartTimestamp,
563
- durationMs: Date.now() - startedAtMs,
564
- },
565
- });
575
+ // Fail-closed finalization: `invoked: true` proves only that the wake
576
+ // went live, not that the run produced anything. The agent loop swallows
577
+ // provider rejections into a normal no-output return, an exhausted output
578
+ // budget can stop a run before any visible text or tool call, and a
579
+ // model may reply with analysis (or nothing) without saving. Advancement
580
+ // past the window therefore requires POSITIVE evidence from THIS run,
581
+ // one of:
582
+ // - a memory-writing tool call on the fork's post-boundary tail whose
583
+ // execution verifiably succeeded (matching non-error tool_result), or
584
+ // - the explicit no-findings reply the instruction mandates (an
585
+ // assistant text block that is exactly the sentinel phrase), with no
586
+ // memory-writing tool attempts at all; a run that attempted a save
587
+ // and failed cannot advance by also claiming no findings.
588
+ // The evidence read is run-specific by construction
589
+ // (`loadRetrospectiveRunMessages` scopes to rows after the fork
590
+ // boundary), so a prior run's persisted saves can never satisfy it, and
591
+ // it reads the DB rather than the returned history, so a checkpoint that
592
+ // went live and persisted saves counts even when a later in-loop repair
593
+ // rebased the returned tail. A run with neither evidence kind follows
594
+ // the wake-failure path: cursor, remembered log, and the prior
595
+ // retrospective (the dedup baseline) stay untouched and the window
596
+ // remains retryable.
597
+ const runEvidence = await collectRetrospectiveRunEvidence(forkId);
598
+ const reviewedNoFindings =
599
+ runEvidence.explicitNoFindings &&
600
+ runEvidence.durableToolAttemptCount === 0;
601
+ if (runEvidence.durableToolCallCount === 0 && !reviewedNoFindings) {
602
+ log.warn(
603
+ {
604
+ sourceConversationId,
605
+ forkId,
606
+ newMessageCount: newMessages.length,
607
+ durableToolAttempts: runEvidence.durableToolAttemptCount,
608
+ },
609
+ "memory-retrospective (fork): run produced neither a verified durable write nor an explicit no-findings reply; leaving window retryable",
610
+ );
611
+ } else {
612
+ return await finalizeSuccessfulRetrospective({
613
+ config,
614
+ sourceConversationId,
615
+ retrospectiveConversationId: forkId,
616
+ cutoffMessageId,
617
+ newMessageCount: newMessages.length,
618
+ prior,
619
+ priorRemembers,
620
+ runRemembers: runEvidence.remembers,
621
+ logFields: {
622
+ kind: "fork",
623
+ windowStartTimestamp,
624
+ durationMs: Date.now() - startedAtMs,
625
+ noFindings: reviewedNoFindings,
626
+ },
627
+ });
628
+ }
566
629
  }
567
630
 
568
- // Wake failed. Bump `lastRunAt` only so the cooldown gate applies, leave
569
- // `lastProcessedMessageId` alone so the next attempt re-processes the
570
- // same messages. Then clean up the orphan fork.
631
+ // Wake failed or produced no usable output. Bump `lastRunAt` only so the
632
+ // cooldown gate applies, leave `lastProcessedMessageId` alone so the next
633
+ // attempt re-processes the same messages. Then clean up the orphan fork.
571
634
  await bumpRetrospectiveLastRunAt(sourceConversationId, Date.now());
572
635
  await safeDeleteRetrospectiveConversation(
573
636
  forkId,
@@ -578,6 +641,13 @@ export async function runForkBasedRetrospective(
578
641
  throw threw;
579
642
  }
580
643
 
644
+ if (wakeSucceeded) {
645
+ return {
646
+ kind: "no_usable_output",
647
+ reason: failureReason ?? "run persisted no memory-writing tool call",
648
+ conversationId: forkId,
649
+ };
650
+ }
581
651
  return {
582
652
  kind: "wake_failed",
583
653
  reason: failureReason,
@@ -786,6 +856,12 @@ async function finalizeSuccessfulRetrospective(args: {
786
856
  newMessageCount: number;
787
857
  prior: PriorRetrospective | null;
788
858
  priorRemembers: string[];
859
+ /**
860
+ * The `remember` contents extracted from this run's persisted tail by the
861
+ * caller's usable-output check; passed through so the evidence that gated
862
+ * advancement is exactly the evidence folded into the log.
863
+ */
864
+ runRemembers: string[];
789
865
  /** Per-kind extras for the success log line (e.g. `kind`, fork anchor). */
790
866
  logFields: Record<string, unknown>;
791
867
  }): Promise<MemoryRetrospectiveOutcome> {
@@ -797,12 +873,10 @@ async function finalizeSuccessfulRetrospective(args: {
797
873
  newMessageCount,
798
874
  prior,
799
875
  priorRemembers,
876
+ runRemembers,
800
877
  logFields,
801
878
  } = args;
802
879
 
803
- const runRemembers = await extractRetrospectiveRunRemembers(
804
- retrospectiveConversationId,
805
- );
806
880
  await upsertRetrospectiveState({
807
881
  conversationId: sourceConversationId,
808
882
  lastProcessedMessageId: cutoffMessageId,
@@ -1003,9 +1077,204 @@ async function extractRetrospectiveRunRemembers(
1003
1077
  if (runMessages == null) {
1004
1078
  return [];
1005
1079
  }
1080
+ // Deliberately unfiltered by execution success: this reads a PRIOR run for
1081
+ // the <already_remembered> dedup baseline, where over-inclusion is the
1082
+ // safe direction (worst case a fact is not re-saved) and old runs predate
1083
+ // result-verified evidence. The CURRENT run's log append goes through
1084
+ // `collectRetrospectiveRunEvidence`, which does verify execution.
1006
1085
  return extractRememberContents(runMessages);
1007
1086
  }
1008
1087
 
1088
+ /**
1089
+ * Tool names whose persisted `tool_use` blocks count as durable memory work
1090
+ * for the fail-closed advancement gate: `remember` writes the memory buffer,
1091
+ * `scaffold_managed_skill` writes a managed skill. Read-only tools on the
1092
+ * retrospective allowlist (`skill_load`, `find_similar_skills`) deliberately
1093
+ * do not qualify: a run that only browsed produced nothing durable.
1094
+ */
1095
+ const DURABLE_RETROSPECTIVE_TOOLS: ReadonlySet<string> = new Set([
1096
+ "remember",
1097
+ "scaffold_managed_skill",
1098
+ ]);
1099
+
1100
+ /**
1101
+ * Read the durable evidence a retrospective run persisted: its `remember`
1102
+ * contents plus a count of every memory-writing tool call on the run's
1103
+ * post-boundary tail whose EXECUTION succeeded. A `tool_use` block alone
1104
+ * proves only that the model asked; the durable write happens inside the
1105
+ * executor, so a call counts (and its facts feed the remembered log) only
1106
+ * when a matching non-error `tool_result` is persisted on the same tail. A
1107
+ * failed or missing execution therefore leaves the window retryable, and a
1108
+ * failed `remember`'s facts never enter the `<already_remembered>` baseline
1109
+ * where they would suppress the retry's re-save. A load failure
1110
+ * (`runMessages == null`) reports zero durable calls, which the advancement
1111
+ * gate treats as "not proven usable" (fail-closed).
1112
+ */
1113
+ async function collectRetrospectiveRunEvidence(
1114
+ conversationId: string,
1115
+ ): Promise<{
1116
+ remembers: string[];
1117
+ /** Memory-writing tool calls whose execution verifiably succeeded. */
1118
+ durableToolCallCount: number;
1119
+ /** Memory-writing tool calls the run attempted, regardless of outcome. */
1120
+ durableToolAttemptCount: number;
1121
+ /**
1122
+ * The run replied with exactly the mandated no-findings sentinel text
1123
+ * ({@link MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}) in a persisted assistant
1124
+ * text block. Strict whole-block equality: prose that merely mentions the
1125
+ * phrase does not qualify, so an analysis-only reply stays unusable.
1126
+ */
1127
+ explicitNoFindings: boolean;
1128
+ }> {
1129
+ const conv = await getConversation(conversationId);
1130
+ const runMessages = await loadRetrospectiveRunMessages(
1131
+ conversationId,
1132
+ conv?.source ?? null,
1133
+ );
1134
+ if (runMessages == null) {
1135
+ return {
1136
+ remembers: [],
1137
+ durableToolCallCount: 0,
1138
+ durableToolAttemptCount: 0,
1139
+ explicitNoFindings: false,
1140
+ };
1141
+ }
1142
+ const succeededIds = collectSuccessfulToolResultIds(runMessages);
1143
+ return {
1144
+ remembers: extractRememberContents(runMessages, succeededIds),
1145
+ durableToolCallCount: countDurableToolUses(runMessages, succeededIds),
1146
+ durableToolAttemptCount: countDurableToolUses(runMessages, null),
1147
+ explicitNoFindings: hasExplicitNoFindingsReply(runMessages),
1148
+ };
1149
+ }
1150
+
1151
+ /**
1152
+ * Whether any persisted assistant row on the run's tail carries a text block
1153
+ * that is exactly the no-findings sentinel (after trimming). The instruction
1154
+ * template mandates this exact reply for a reviewed-and-nothing-to-save
1155
+ * pass, making it the positive persisted artifact that distinguishes a
1156
+ * legitimate no-findings review from an empty or unusable response.
1157
+ */
1158
+ function hasExplicitNoFindingsReply(messages: MessageLike[]): boolean {
1159
+ for (const msg of messages) {
1160
+ if (msg.role !== "assistant") {
1161
+ continue;
1162
+ }
1163
+ let blocks: unknown = msg.content;
1164
+ if (typeof blocks === "string") {
1165
+ try {
1166
+ blocks = JSON.parse(blocks);
1167
+ } catch {
1168
+ continue;
1169
+ }
1170
+ }
1171
+ if (!Array.isArray(blocks)) {
1172
+ continue;
1173
+ }
1174
+ for (const block of blocks) {
1175
+ if (!block || typeof block !== "object") {
1176
+ continue;
1177
+ }
1178
+ const b = block as Record<string, unknown>;
1179
+ if (
1180
+ b.type === "text" &&
1181
+ typeof b.text === "string" &&
1182
+ b.text.trim() === MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT
1183
+ ) {
1184
+ return true;
1185
+ }
1186
+ }
1187
+ }
1188
+ return false;
1189
+ }
1190
+
1191
+ /**
1192
+ * Ids of `tool_result` blocks on the run's user rows whose execution did not
1193
+ * report an error. Robust to malformed content JSON the same way
1194
+ * `extractRememberContents` is.
1195
+ */
1196
+ function collectSuccessfulToolResultIds(messages: MessageLike[]): Set<string> {
1197
+ const ids = new Set<string>();
1198
+ for (const msg of messages) {
1199
+ if (msg.role !== "user") {
1200
+ continue;
1201
+ }
1202
+ let blocks: unknown = msg.content;
1203
+ if (typeof blocks === "string") {
1204
+ try {
1205
+ blocks = JSON.parse(blocks);
1206
+ } catch {
1207
+ continue;
1208
+ }
1209
+ }
1210
+ if (!Array.isArray(blocks)) {
1211
+ continue;
1212
+ }
1213
+ for (const block of blocks) {
1214
+ if (!block || typeof block !== "object") {
1215
+ continue;
1216
+ }
1217
+ const b = block as Record<string, unknown>;
1218
+ // guard:allow-tool-result-only: success evidence for locally-executed
1219
+ // durable memory tools; server-side web_search_tool_result never
1220
+ // corresponds to a durable write and carries no is_error flag.
1221
+ if (
1222
+ b.type === "tool_result" &&
1223
+ typeof b.tool_use_id === "string" &&
1224
+ b.is_error !== true
1225
+ ) {
1226
+ ids.add(b.tool_use_id);
1227
+ }
1228
+ }
1229
+ }
1230
+ return ids;
1231
+ }
1232
+
1233
+ /**
1234
+ * Count persisted `tool_use` blocks whose `name` is in
1235
+ * {@link DURABLE_RETROSPECTIVE_TOOLS} across the run's assistant rows.
1236
+ * With a `succeededIds` set, only calls whose id has a matching successful
1237
+ * `tool_result` count (verified executions); with `null`, every attempt
1238
+ * counts regardless of outcome.
1239
+ */
1240
+ function countDurableToolUses(
1241
+ messages: MessageLike[],
1242
+ succeededIds: ReadonlySet<string> | null,
1243
+ ): number {
1244
+ let count = 0;
1245
+ for (const msg of messages) {
1246
+ if (msg.role !== "assistant") {
1247
+ continue;
1248
+ }
1249
+ let blocks: unknown = msg.content;
1250
+ if (typeof blocks === "string") {
1251
+ try {
1252
+ blocks = JSON.parse(blocks);
1253
+ } catch {
1254
+ continue;
1255
+ }
1256
+ }
1257
+ if (!Array.isArray(blocks)) {
1258
+ continue;
1259
+ }
1260
+ for (const block of blocks) {
1261
+ if (!block || typeof block !== "object") {
1262
+ continue;
1263
+ }
1264
+ const b = block as Record<string, unknown>;
1265
+ if (
1266
+ b.type === "tool_use" &&
1267
+ DURABLE_RETROSPECTIVE_TOOLS.has(String(b.name)) &&
1268
+ (succeededIds === null ||
1269
+ (typeof b.id === "string" && succeededIds.has(b.id)))
1270
+ ) {
1271
+ count += 1;
1272
+ }
1273
+ }
1274
+ }
1275
+ return count;
1276
+ }
1277
+
1009
1278
  interface MessageLike {
1010
1279
  role: string;
1011
1280
  content: string | ContentBlock[];
@@ -1016,7 +1285,10 @@ interface MessageLike {
1016
1285
  * `"remember"` and return the `input.content` strings in order. Robust to
1017
1286
  * malformed content JSON — unparseable rows are skipped, not propagated.
1018
1287
  */
1019
- function extractRememberContents(messages: MessageLike[]): string[] {
1288
+ function extractRememberContents(
1289
+ messages: MessageLike[],
1290
+ succeededIds?: ReadonlySet<string>,
1291
+ ): string[] {
1020
1292
  const contents: string[] = [];
1021
1293
  for (const msg of messages) {
1022
1294
  if (msg.role !== "assistant") {
@@ -1044,6 +1316,16 @@ function extractRememberContents(messages: MessageLike[]): string[] {
1044
1316
  if (b.name !== "remember") {
1045
1317
  continue;
1046
1318
  }
1319
+ // When a success set is provided, only executions that reported a
1320
+ // non-error tool_result contribute facts: a failed remember never
1321
+ // wrote the buffer, and logging its facts would suppress the retry's
1322
+ // re-save via <already_remembered>.
1323
+ if (
1324
+ succeededIds !== undefined &&
1325
+ (typeof b.id !== "string" || !succeededIds.has(b.id))
1326
+ ) {
1327
+ continue;
1328
+ }
1047
1329
  const input = b.input;
1048
1330
  if (!input || typeof input !== "object") {
1049
1331
  continue;
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  import { getLogger } from "./logging.js";
30
+ import { MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT } from "./memory-retrospective-constants.js";
30
31
  import { getWorkspaceDir } from "./paths.js";
31
32
  import { loadPromptOverride } from "./prompt-override.js";
32
33
 
@@ -43,6 +44,13 @@ function neutralizeSentinels(s: string): string {
43
44
  );
44
45
  }
45
46
 
47
+ /**
48
+ * The sentence mandating the exact no-findings reply. Built from
49
+ * {@link MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT} so the instruction and the
50
+ * finalizer's acceptance check can never drift apart.
51
+ */
52
+ const NO_FINDINGS_MANDATE = `If nothing new is worth saving, reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}" and stop.`;
53
+
46
54
  /**
47
55
  * Bundled fork-instruction template. Exported so tests (and any future
48
56
  * "Load default" affordance) can reference the canonical body verbatim.
@@ -63,7 +71,7 @@ Two dedup sources to skip:
63
71
  1. Anything semantically captured in <already_remembered> above (from prior retrospective passes).
64
72
  2. Anything you already called \`remember\` on inline within your review window — those appear as \`tool_use\` blocks with \`name: "remember"\` in your history.
65
73
 
66
- For everything else in your review window, use the \`remember\` tool on facts, plans, decisions, preferences, names, dates, felt moments, corrections, commitments, or anything else concrete and worth carrying forward. When several facts are worth saving, pass them all as an array to a single \`remember\` call rather than calling it once per fact. If nothing new is worth saving, say "Nothing new to save." and stop.
74
+ For everything else in your review window, use the \`remember\` tool on facts, plans, decisions, preferences, names, dates, felt moments, corrections, commitments, or anything else concrete and worth carrying forward. When several facts are worth saving, pass them all as an array to a single \`remember\` call rather than calling it once per fact. ${NO_FINDINGS_MANDATE}
67
75
  {{SKILL_AUTHORING_SECTION}}`;
68
76
 
69
77
  /** Placeholder names recognized in the bundled template and overrides. */
@@ -140,7 +148,9 @@ export interface ForkInstructionArgs {
140
148
  * override resolves to a usable file (bounded to a regular file under 1 MiB by
141
149
  * the shared {@link loadPromptOverride}), else the bundled
142
150
  * {@link RETROSPECTIVE_INSTRUCTION_TEMPLATE}; both get the same placeholder
143
- * substitution.
151
+ * substitution. An override additionally gets the no-findings mandate
152
+ * appended after its body: the exact-reply sentinel is the finalizer's
153
+ * advancement contract, so it holds regardless of what the override says.
144
154
  */
145
155
  export function buildForkInstruction({
146
156
  windowStartTimestamp,
@@ -175,7 +185,7 @@ export function buildForkInstruction({
175
185
  label: "retrospective prompt",
176
186
  });
177
187
 
178
- return substituteInstructionParts(
188
+ const rendered = substituteInstructionParts(
179
189
  override ?? RETROSPECTIVE_INSTRUCTION_TEMPLATE,
180
190
  {
181
191
  AVAILABLE_TOOLS_LINE: availableToolsLine,
@@ -186,6 +196,16 @@ export function buildForkInstruction({
186
196
  : "",
187
197
  },
188
198
  );
199
+ if (override == null) {
200
+ return rendered;
201
+ }
202
+ // The finalizer recognizes a no-findings review only by the exact
203
+ // MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT reply, so the mandate is part of
204
+ // the advancement contract, not prompt styling: an override body that
205
+ // drops it would leave every no-findings window permanently retryable.
206
+ // Appended outside the override so a custom prompt cannot break the
207
+ // contract.
208
+ return `${rendered}\n\n${NO_FINDINGS_MANDATE}`;
189
209
  }
190
210
 
191
211
  /**
@@ -31,11 +31,16 @@ const log = getLogger("memory-v2-consolidate");
31
31
 
32
32
  /**
33
33
  * Hard timeout for the consolidation run. Consolidation reads the buffer,
34
- * rewrites several files, and re-encodes essentials/threads: generous
35
- * upper bound so a slow run isn't killed mid-edit, but bounded so a stuck
36
- * provider can't pin the worker indefinitely.
34
+ * rewrites several files, and re-encodes essentials/threads: on a mature
35
+ * corpus a full pass legitimately runs ~20 minutes under cross-process write
36
+ * contention, so the bound leaves headroom above that while still keeping a
37
+ * stuck run from pinning the worker indefinitely. Matches the default
38
+ * `timeouts.backgroundTurnTimeoutSec` budget for heartbeat/background turns.
39
+ * Overrunning it marks the run failed and skips its follow-up jobs (reembeds,
40
+ * v3 maintenance) even though the agent's file edits land, so the bound must
41
+ * comfortably exceed a healthy run's duration.
37
42
  */
38
- export const CONSOLIDATION_TIMEOUT_MS = 15 * 60 * 1000;
43
+ export const CONSOLIDATION_TIMEOUT_MS = 30 * 60 * 1000;
39
44
 
40
45
  /**
41
46
  * Age past which a lock held by an apparently-live PID is taken over anyway.
@@ -36,6 +36,7 @@ import { z } from "zod";
36
36
 
37
37
  import { usesConceptPageMemory } from "../../../../config/memory-v3-gate.js";
38
38
  import type { AssistantConfig } from "../../../../config/types.js";
39
+ import { warmGuardianBindings } from "../../../../contacts/guardian-delivery-reader.js";
39
40
  import { emitNotificationSignal } from "../../../../notifications/emit-signal.js";
40
41
  import { getDb } from "../../../../persistence/db-connection.js";
41
42
  import type { MemoryJob } from "../../../../persistence/jobs-store.js";
@@ -155,6 +156,12 @@ export async function memoryV2SweepJob(
155
156
  return 0;
156
157
  }
157
158
 
159
+ // Warm both guardian-delivery cache keys (vellum + unfiltered) so
160
+ // resolveUserName's sync guardian-file resolution, including its
161
+ // any-channel fallback, hits fresh keys instead of falling back to
162
+ // users/default.md on this worker process's cold cache.
163
+ await warmGuardianBindings();
164
+
158
165
  const systemPrompt = renderSweepPrompt({
159
166
  assistantName: getAssistantName(),
160
167
  userName: resolveUserName(workspaceDir),
@@ -349,7 +349,7 @@ export async function resolveInjectionImages(
349
349
  continue;
350
350
  }
351
351
 
352
- const optimized = optimizeImageForTransport(
352
+ const optimized = await optimizeImageForTransport(
353
353
  data.data.toString("base64"),
354
354
  data.mimeType,
355
355
  );
@@ -41,6 +41,7 @@ import {
41
41
  import { z } from "zod";
42
42
 
43
43
  import type { AssistantConfig } from "../../../../config/types.js";
44
+ import { warmGuardianBindings } from "../../../../contacts/guardian-delivery-reader.js";
44
45
  import {
45
46
  cachedTextBlock,
46
47
  extractToolUse,
@@ -393,6 +394,13 @@ async function runRouterBatch(
393
394
  provider,
394
395
  } = params;
395
396
 
397
+ // Warm both guardian-delivery cache keys (vellum + unfiltered) so
398
+ // resolveUserName's sync guardian-file resolution, including its
399
+ // any-channel fallback, hits fresh keys instead of falling back to
400
+ // users/default.md on a cold/TTL-expired cache. Two local-socket IPC
401
+ // reads per batch, dwarfed by the batch's provider call.
402
+ await warmGuardianBindings();
403
+
396
404
  const systemPrompt = resolveRouterPrompt(
397
405
  config.memory?.v2?.router?.router_prompt_path ?? null,
398
406
  workspaceDir,