@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
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { describe, expect, test } from "bun:test";
5
5
 
6
+ import { MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT } from "../memory-retrospective-constants.js";
6
7
  import {
7
8
  buildForkInstruction,
8
9
  type ForkInstructionArgs,
@@ -47,7 +48,7 @@ Two dedup sources to skip:
47
48
  1. Anything semantically captured in <already_remembered> above (from prior retrospective passes).
48
49
  2. Anything you already called \`remember\` on inline within your review window — those appear as \`tool_use\` blocks with \`name: "remember"\` in your history.
49
50
 
50
- 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.
51
+ 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, reply with exactly "Nothing new to save." and stop.
51
52
  `);
52
53
  });
53
54
 
@@ -120,7 +121,7 @@ For everything else in your review window, use the \`remember\` tool on facts, p
120
121
  expect(out).not.toContain("PROCEDURE");
121
122
  expect(
122
123
  out.endsWith(
123
- 'If nothing new is worth saving, say "Nothing new to save." and stop.\n',
124
+ 'If nothing new is worth saving, reply with exactly "Nothing new to save." and stop.\n',
124
125
  ),
125
126
  ).toBe(true);
126
127
  });
@@ -175,7 +176,32 @@ describe("promptOverridePath", () => {
175
176
  writeFileSync(overridePath, "Just remember the good parts.\n");
176
177
  expect(
177
178
  buildForkInstruction(makeArgs({ promptOverridePath: overridePath })),
178
- ).toBe("Just remember the good parts.\n");
179
+ ).toBe(
180
+ "Just remember the good parts.\n\n\n" +
181
+ `If nothing new is worth saving, reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}" and stop.`,
182
+ );
183
+ });
184
+
185
+ test("an override that drops the no-findings mandate still carries the finalizer's exact-reply contract", () => {
186
+ // The finalizer advances a no-findings window only on a persisted reply
187
+ // that trims to exactly MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT. An
188
+ // override author who never read that code would otherwise stall every
189
+ // no-findings window forever, so the mandate must survive any override.
190
+ const overridePath = join(dir, "mandate-free.md");
191
+ writeFileSync(
192
+ overridePath,
193
+ "Review the window and save what matters. If nothing matters, do nothing.\n",
194
+ );
195
+ const out = buildForkInstruction(
196
+ makeArgs({ promptOverridePath: overridePath }),
197
+ );
198
+ expect(out).toContain(
199
+ `reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}"`,
200
+ );
201
+ // The mandate references the same constant the finalizer compares
202
+ // against, so the two cannot drift; guard the constant's exact value here
203
+ // to make an accidental rewording loud.
204
+ expect(MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT).toBe("Nothing new to save.");
179
205
  });
180
206
 
181
207
  test("missing override file falls back to the bundled rendering", () => {
@@ -200,3 +226,13 @@ describe("promptOverridePath", () => {
200
226
  expect(out).not.toContain("SENSITIVE FILE CONTENTS");
201
227
  });
202
228
  });
229
+
230
+ // The finalizer's explicit-no-findings gate matches persisted assistant text
231
+ // against MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT by strict equality, and the
232
+ // bundled instruction is what teaches the model to emit it. This guard fails
233
+ // if either side drifts.
234
+ test("bundled template mandates the exact no-findings sentinel the finalizer matches", () => {
235
+ expect(RETROSPECTIVE_INSTRUCTION_TEMPLATE).toContain(
236
+ `reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}" and stop.`,
237
+ );
238
+ });
@@ -0,0 +1,493 @@
1
+ /**
2
+ * LUM-3013 regression: the retrospective's fail-closed advancement gate must
3
+ * hold through the REAL producer chain, not just against a mocked wake.
4
+ *
5
+ * These tests run the real `memoryRetrospectiveJob` handler → the real
6
+ * `wakeAgentForOpportunity` (runtime/agent-wake.ts, NOT mocked) → a
7
+ * conversation double whose `agentLoop` is a real `AgentLoop` driven by a
8
+ * scripted fake `Provider`. Only the provider and the daemon/persistence
9
+ * boundaries are test doubles, so the chain exercises the actual mechanism
10
+ * behind the bug:
11
+ *
12
+ * - `AgentLoop.run` SWALLOWS provider rejections: the outer catch
13
+ * (agent/loop.ts, `onEvent({ type: "error" })` + `stopTurn("error")`)
14
+ * returns normally with the history unchanged.
15
+ * - The wake then finds no tail output and takes its silent no-op branch
16
+ * (agent-wake.ts), returning `{ invoked: true, producedToolCalls: false }`.
17
+ * - `invoked: true` alone must therefore NOT advance
18
+ * `memory_retrospective_state`: the handler re-reads the fork's persisted
19
+ * rows (`collectRetrospectiveRunEvidence` → `loadRetrospectiveRunMessages`
20
+ * → `getMessages`) and only advances when a durable memory-writing
21
+ * `tool_use` (`remember` / `scaffold_managed_skill`) was persisted by THIS
22
+ * run.
23
+ */
24
+
25
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Mock state. Reset between tests.
29
+ // ---------------------------------------------------------------------------
30
+
31
+ const SOURCE_ID = "src-conv-1";
32
+ const FORK_ID = "fork-conv-1";
33
+
34
+ let stateUpserts: Array<{
35
+ conversationId: string;
36
+ lastProcessedMessageId: string;
37
+ lastRunAt: number;
38
+ rememberedLog?: string[];
39
+ }> = [];
40
+ let lastRunAtBumps: Array<{ conversationId: string; lastRunAt: number }> = [];
41
+
42
+ let newMessages: Array<{
43
+ id: string;
44
+ createdAt: number;
45
+ role?: string;
46
+ content?: string | Array<Record<string, unknown>>;
47
+ metadata?: string | null;
48
+ }> = [];
49
+
50
+ /**
51
+ * Persisted message rows, keyed by conversation id. `addMessage` appends here
52
+ * and `getMessages` reads it back. The same store serves the handler's
53
+ * instruction staging, the wake's tail persistence, and the finalizer's
54
+ * durable-evidence read, so the evidence gate sees exactly what the real
55
+ * producer chain persisted.
56
+ */
57
+ type PersistedRow = {
58
+ role: string;
59
+ content: string;
60
+ createdAt: number;
61
+ metadata: string | null;
62
+ };
63
+ let messageStores: Record<string, PersistedRow[]> = {};
64
+ let persistedMessageCounter = 0;
65
+
66
+ let deletedConversationIds: string[] = [];
67
+ let forkCalls: Array<{ conversationId: string; throughMessageId?: string }> =
68
+ [];
69
+
70
+ // ---------------------------------------------------------------------------
71
+ // Retrospective-side mocks (mirroring memory-retrospective-job.test.ts, but
72
+ // WITHOUT mocking ../../../../runtime/agent-wake.js: the wake runs real).
73
+ // ---------------------------------------------------------------------------
74
+
75
+ mock.module("../memory-retrospective-state.js", () => ({
76
+ getRetrospectiveState: (_id: string) => null,
77
+ upsertRetrospectiveState: (args: {
78
+ conversationId: string;
79
+ lastProcessedMessageId: string;
80
+ lastRunAt: number;
81
+ rememberedLog?: string[];
82
+ }) => {
83
+ stateUpserts.push(args);
84
+ },
85
+ bumpRetrospectiveLastRunAt: (conversationId: string, lastRunAt: number) => {
86
+ lastRunAtBumps.push({ conversationId, lastRunAt });
87
+ },
88
+ appendToRememberedLog: (existing: string[], newEntries: string[]) => [
89
+ ...existing,
90
+ ...newEntries,
91
+ ],
92
+ }));
93
+
94
+ mock.module("../find-most-recent-retrospective-for.js", () => ({
95
+ findMostRecentRetrospectiveFor: (_id: string) => null,
96
+ }));
97
+
98
+ mock.module("../../../../persistence/conversation-crud.js", () => ({
99
+ getMessagesAfter: (_id: string, _afterId: string | null) => newMessages,
100
+ getMessages: (id: string) => messageStores[id] ?? [],
101
+ // `defaultResolveTarget` in the REAL wake reads the FORK id's row for the
102
+ // archived check, so both rows carry archivedAt/createdAt. The fork's
103
+ // "user" source makes `loadRetrospectiveRunMessages` treat every persisted
104
+ // row as the run's own (legacy-kind), the simplest faithful setup here.
105
+ getConversation: (id: string) => {
106
+ if (id === FORK_ID) {
107
+ return {
108
+ source: "user",
109
+ forkParentMessageId: null,
110
+ title: "Fork",
111
+ archivedAt: null,
112
+ createdAt: "2026-01-01T00:00:00.000Z",
113
+ };
114
+ }
115
+ return {
116
+ source: "user",
117
+ forkParentMessageId: null,
118
+ title: "Source conversation",
119
+ archivedAt: null,
120
+ createdAt: "2026-01-01T00:00:00.000Z",
121
+ };
122
+ },
123
+ isConversationProcessing: (_id: string) => false,
124
+ getConversationProcessingStartedAt: (_id: string) => null,
125
+ forkConversationForRetrospective: async (params: {
126
+ conversationId: string;
127
+ throughMessageId?: string;
128
+ }) => {
129
+ forkCalls.push(params);
130
+ return { id: FORK_ID };
131
+ },
132
+ addMessage: async (
133
+ conversationId: string,
134
+ role: string,
135
+ content: string,
136
+ _options: unknown,
137
+ ) => {
138
+ const store = (messageStores[conversationId] ??= []);
139
+ store.push({ role, content, createdAt: Date.now(), metadata: null });
140
+ persistedMessageCounter += 1;
141
+ return { id: `msg-${persistedMessageCounter}` };
142
+ },
143
+ deleteConversation: (id: string) => {
144
+ deletedConversationIds.push(id);
145
+ },
146
+ deleteConversationGently: async (id: string) => {
147
+ deletedConversationIds.push(id);
148
+ return { segmentIds: [], deletedSummaryIds: [] };
149
+ },
150
+ resolveOverrideProfile: () => undefined,
151
+ getConversationOverrideProfile: () => undefined,
152
+ provenanceFromTrustContext: () => ({}),
153
+ reserveMessage: async () => ({ id: "msg-reserve" }),
154
+ }));
155
+
156
+ mock.module("../../../../daemon/trust-context.js", () => ({
157
+ INTERNAL_GUARDIAN_TRUST_CONTEXT: {
158
+ sourceChannel: "vellum",
159
+ trustClass: "guardian",
160
+ },
161
+ }));
162
+
163
+ mock.module("../../../../prompts/persona-resolver.js", () => ({
164
+ resolveUserSlug: (_trustContext: unknown) => "alice",
165
+ }));
166
+
167
+ mock.module("../../../../persistence/jobs-store.js", () => ({
168
+ enqueueMemoryJob: () => "follow-up-job-id",
169
+ upsertMemoryRetrospectiveJob: () => {},
170
+ }));
171
+
172
+ mock.module("../../../../telemetry/watchdog-events-store.js", () => ({
173
+ recordWatchdogEvent: () => {},
174
+ }));
175
+
176
+ mock.module("../../../../config/memory-v3-gate.js", () => ({
177
+ isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
178
+ config?.memory?.enabled !== false,
179
+ isV3TierActive: () => false,
180
+ isMemoryV3Live: () => false,
181
+ usesConceptPageMemory: () => false,
182
+ }));
183
+
184
+ mock.module("../../../../daemon/conversation-registry.js", () => ({
185
+ findConversation: (_id: string | undefined) => undefined,
186
+ }));
187
+
188
+ // ---------------------------------------------------------------------------
189
+ // Wake-side boundary mocks (mirroring runtime/__tests__/agent-wake.test.ts,
190
+ // with relative paths adjusted for this directory).
191
+ // ---------------------------------------------------------------------------
192
+
193
+ mock.module("../../../../persistence/conversation-disk-view.js", () => ({
194
+ syncMessageToDisk: () => {},
195
+ }));
196
+
197
+ mock.module("../../../../runtime/assistant-event-hub.js", () => ({
198
+ broadcastMessage: () => {},
199
+ }));
200
+
201
+ mock.module("../../../../runtime/sync/resource-sync-events.js", () => ({
202
+ publishConversationMessagesChanged: () => {},
203
+ }));
204
+
205
+ mock.module("../../../../daemon/conversation-store.js", () => ({
206
+ // The real wake's `defaultResolveTarget` lands here after the archived
207
+ // check; it must yield the live fork conversation the run executes on.
208
+ getOrCreateConversation: async (
209
+ _conversationId: string,
210
+ _options?: unknown,
211
+ ) => makeForkConversationDouble(),
212
+ }));
213
+
214
+ mock.module("../../../../config/llm-context-resolution.js", () => ({
215
+ resolveEffectiveContextWindow: () => ({ maxInputTokens: 200_000 }),
216
+ }));
217
+
218
+ mock.module("../../../../daemon/disk-pressure-guard.js", () => ({
219
+ getDiskPressureStatus: () => ({
220
+ enabled: false,
221
+ state: "disabled",
222
+ locked: false,
223
+ acknowledged: false,
224
+ overrideActive: false,
225
+ effectivelyLocked: false,
226
+ lockId: null,
227
+ usagePercent: null,
228
+ thresholdPercent: 95,
229
+ path: null,
230
+ lastCheckedAt: null,
231
+ blockedCapabilities: [],
232
+ error: null,
233
+ }),
234
+ }));
235
+
236
+ mock.module("../../../../daemon/conversation-usage.js", () => ({
237
+ recordUsage: () => {},
238
+ }));
239
+
240
+ mock.module("../../../../persistence/llm-request-log-store.js", () => ({
241
+ recordRequestLog: () => "log-id",
242
+ backfillMessageIdOnLogs: () => {},
243
+ setAgentLoopExitReasonOnLatestLog: () => {},
244
+ buildProviderErrorResponsePayload: (error: unknown) => ({
245
+ error: String(error),
246
+ }),
247
+ }));
248
+
249
+ import { AgentLoop } from "../../../../agent/loop.js";
250
+ import type { Conversation } from "../../../../daemon/conversation.js";
251
+ import type { MemoryJob } from "../../../../persistence/jobs-store.js";
252
+ import type {
253
+ Message,
254
+ Provider,
255
+ ProviderResponse,
256
+ SendMessageOptions,
257
+ } from "../../../../providers/types.js";
258
+ import { ProviderError } from "../../../../util/errors.js";
259
+ import { memoryRetrospectiveJob } from "../memory-retrospective-job.js";
260
+
261
+ // ---------------------------------------------------------------------------
262
+ // Fake provider: the ONLY seam scripted per scenario. Everything between the
263
+ // job handler and this `sendMessage` is real production code.
264
+ // ---------------------------------------------------------------------------
265
+
266
+ let providerCalls: Array<{ messages: Message[] }> = [];
267
+ let providerImpl: (
268
+ messages: Message[],
269
+ options?: SendMessageOptions,
270
+ ) => Promise<ProviderResponse> = async () => textOnlyResponse("unused");
271
+
272
+ const fakeProvider: Provider = {
273
+ name: "fake-provider",
274
+ async sendMessage(
275
+ messages: Message[],
276
+ options?: SendMessageOptions,
277
+ ): Promise<ProviderResponse> {
278
+ providerCalls.push({ messages: [...messages] });
279
+ return providerImpl(messages, options);
280
+ },
281
+ };
282
+
283
+ function textOnlyResponse(text: string): ProviderResponse {
284
+ return {
285
+ content: [{ type: "text", text }],
286
+ model: "test-model",
287
+ usage: { inputTokens: 10, outputTokens: 5 },
288
+ stopReason: "end_turn",
289
+ };
290
+ }
291
+
292
+ function rememberToolUseResponse(): ProviderResponse {
293
+ return {
294
+ content: [
295
+ { type: "text", text: "Saving one fact." },
296
+ {
297
+ type: "tool_use",
298
+ id: "tu-1",
299
+ name: "remember",
300
+ input: { content: "provider-path fact" },
301
+ },
302
+ ],
303
+ model: "test-model",
304
+ usage: { inputTokens: 10, outputTokens: 5 },
305
+ stopReason: "tool_use",
306
+ };
307
+ }
308
+
309
+ // ---------------------------------------------------------------------------
310
+ // Conversation double: minimal structural stand-in for the fork the wake
311
+ // resolves. Its `agentLoop` is a REAL AgentLoop over the fake provider; its
312
+ // message history hydrates from the persisted store (so the instruction row
313
+ // the handler staged is the run's baseline, exactly like a DB rehydration).
314
+ // ---------------------------------------------------------------------------
315
+
316
+ function makeForkConversationDouble(): Conversation {
317
+ const messages: Message[] = (messageStores[FORK_ID] ?? []).map((row) => ({
318
+ role: row.role as Message["role"],
319
+ content: JSON.parse(row.content) as Message["content"],
320
+ }));
321
+ const realLoop = new AgentLoop({
322
+ provider: fakeProvider,
323
+ systemPrompt: "test",
324
+ conversationId: FORK_ID,
325
+ // Real executor round-trip: the finalizer's durable-evidence gate
326
+ // requires a matching successful tool_result, so the loop must execute
327
+ // the remember call and persist its result exactly as production does.
328
+ toolExecutor: async (name: string) => {
329
+ if (name === "remember") {
330
+ return { content: "Saved.", isError: false };
331
+ }
332
+ return { content: `unknown tool ${name}`, isError: true };
333
+ },
334
+ });
335
+ const conversation = {
336
+ conversationId: FORK_ID,
337
+ messages,
338
+ getMessages: () => messages,
339
+ isProcessing: () => false,
340
+ setProcessing: (_on: boolean) => {},
341
+ waitForIdle: async (_opts: { timeoutMs: number }) => true,
342
+ drainQueue: async () => {},
343
+ maybeCompact: async () => null,
344
+ subagentAllowedTools: undefined,
345
+ setSubagentAllowedTools: (_tools: Set<string> | undefined) => {},
346
+ preactivatedSkillIds: undefined,
347
+ setPreactivatedSkillIds: (_ids: readonly string[] | undefined) => {},
348
+ trustContext: undefined,
349
+ setTrustContext: (_ctx: unknown) => {},
350
+ currentTurnTrustContext: undefined,
351
+ wakePersonaOverride: undefined,
352
+ contextWindowManager: { estimateInputTokens: () => 0 },
353
+ getTurnChannelContext: () => null,
354
+ getTurnInterfaceContext: () => null,
355
+ buildCurrentSystemPrompt: () => "test-system-prompt",
356
+ provider: { name: "fake-provider" },
357
+ usageStats: {},
358
+ modelOverride: undefined,
359
+ agentLoop: {
360
+ run: (options: Parameters<AgentLoop["run"]>[0]) => realLoop.run(options),
361
+ },
362
+ };
363
+ return conversation as unknown as Conversation;
364
+ }
365
+
366
+ // ---------------------------------------------------------------------------
367
+ // Job/config helpers (shape copied from memory-retrospective-job.test.ts).
368
+ // ---------------------------------------------------------------------------
369
+
370
+ function makeConfig(): Parameters<typeof memoryRetrospectiveJob>[1] {
371
+ return {
372
+ memory: {
373
+ v2: { enabled: true },
374
+ retrospective: {
375
+ enabled: true,
376
+ keepSupersededRuns: false,
377
+ matchConversationProfile: false,
378
+ promptPath: null,
379
+ requireUserActivity: false,
380
+ sweepIntervalMs: 8 * 60 * 60 * 1000,
381
+ sweepLookbackMs: 7 * 24 * 60 * 60 * 1000,
382
+ },
383
+ },
384
+ ui: {
385
+ userTimezone: undefined,
386
+ detectedTimezone: undefined,
387
+ },
388
+ } as unknown as Parameters<typeof memoryRetrospectiveJob>[1];
389
+ }
390
+
391
+ const stubConfig = makeConfig();
392
+
393
+ function makeJob(conversationId = SOURCE_ID): MemoryJob<{
394
+ conversationId?: string;
395
+ }> {
396
+ return {
397
+ id: "job-1",
398
+ type: "memory_retrospective",
399
+ payload: { conversationId },
400
+ status: "pending",
401
+ attempts: 0,
402
+ deferrals: 0,
403
+ runAfter: 0,
404
+ lastError: null,
405
+ startedAt: null,
406
+ createdAt: 0,
407
+ updatedAt: 0,
408
+ };
409
+ }
410
+
411
+ describe("memoryRetrospectiveJob through the real wake + real agent loop", () => {
412
+ beforeEach(() => {
413
+ stateUpserts = [];
414
+ lastRunAtBumps = [];
415
+ deletedConversationIds = [];
416
+ forkCalls = [];
417
+ messageStores = {};
418
+ persistedMessageCounter = 0;
419
+ providerCalls = [];
420
+ providerImpl = async () => textOnlyResponse("unused");
421
+ newMessages = [
422
+ { id: "m1", createdAt: Date.parse("2026-05-11T10:00:00Z") },
423
+ { id: "m2", createdAt: Date.parse("2026-05-11T10:05:00Z") },
424
+ { id: "m3", createdAt: Date.parse("2026-05-11T10:10:00Z") },
425
+ ];
426
+ });
427
+
428
+ test("real provider rejection is classified at the wake layer and leaves the window retryable", async () => {
429
+ // The wake's exit-reason classifier fails a swallowed rejection before
430
+ // finalization (invoked: false, reason run_error), so the handler
431
+ // reports wake_failed. Full rejection-chain coverage (state
432
+ // preservation, prior-fork survival, retry consuming the window) lives
433
+ // in memory-retrospective-wake-chain.test.ts; this case pins only the
434
+ // layered outcome and that the finalizer was never reached.
435
+ providerImpl = async () => {
436
+ throw new ProviderError(
437
+ "This model (test-model) doesn't support image input. Remove the image or switch to a vision-capable model.",
438
+ "openai",
439
+ 400,
440
+ );
441
+ };
442
+
443
+ const outcome = await memoryRetrospectiveJob(makeJob(), stubConfig);
444
+
445
+ expect(outcome.kind).toBe("wake_failed");
446
+ if (outcome.kind === "wake_failed") {
447
+ expect(outcome.reason).toBe("run_error");
448
+ }
449
+ expect(providerCalls.length).toBeGreaterThanOrEqual(1);
450
+ expect(stateUpserts).toHaveLength(0);
451
+ expect(lastRunAtBumps).toHaveLength(1);
452
+ expect(deletedConversationIds).toEqual([FORK_ID]);
453
+ });
454
+
455
+ test("durable remember persisted through the real loop advances the cursor", async () => {
456
+ // Scenario B: first call emits a `remember` tool_use; the loop (built
457
+ // without a tool executor) stops after persisting the tool-bearing
458
+ // assistant message, and the wake's tail persistence writes it through
459
+ // `addMessage`. Subsequent calls (defensive) return plain text.
460
+ let call = 0;
461
+ providerImpl = async () => {
462
+ call += 1;
463
+ return call === 1 ? rememberToolUseResponse() : textOnlyResponse("Done.");
464
+ };
465
+
466
+ const outcome = await memoryRetrospectiveJob(makeJob(), stubConfig);
467
+
468
+ expect(outcome.kind).toBe("invoked");
469
+ expect(providerCalls.length).toBeGreaterThanOrEqual(1);
470
+ expect(stateUpserts).toHaveLength(1);
471
+ expect(stateUpserts[0]!.lastProcessedMessageId).toBe("m3");
472
+ expect(stateUpserts[0]!.rememberedLog).toContain("provider-path fact");
473
+ // The durable evidence really flowed through persistence: the fork store
474
+ // holds the instruction row plus the wake-persisted tool_use tail.
475
+ const persistedRoles = messageStores[FORK_ID]!.map((row) => row.role);
476
+ expect(persistedRoles[0]).toBe("user");
477
+ expect(persistedRoles).toContain("assistant");
478
+ expect(lastRunAtBumps).toHaveLength(0);
479
+ });
480
+
481
+ test("clean empty reply through the real loop does not advance", async () => {
482
+ // Scenario C: the model answers with analysis text and no tool calls.
483
+ // The wake persists the text tail (visible output), but with zero
484
+ // durable memory-writing tool calls the gate must refuse to advance.
485
+ providerImpl = async () => textOnlyResponse("Nothing worth saving.");
486
+
487
+ const outcome = await memoryRetrospectiveJob(makeJob(), stubConfig);
488
+
489
+ expect(outcome.kind).toBe("no_usable_output");
490
+ expect(providerCalls.length).toBeGreaterThanOrEqual(1);
491
+ expect(stateUpserts).toHaveLength(0);
492
+ });
493
+ });
@@ -409,9 +409,10 @@ describe("memory retrospective wake state chain (real AgentLoop)", () => {
409
409
  expect(listRetroForksOf(fixture.sourceId)).toEqual([fixture.priorRetroId]);
410
410
 
411
411
  // (2) The window stays retryable: the same slice succeeds on retry.
412
- providerScript = [
413
- { response: textResponse("Reviewed. Nothing new worth saving.") },
414
- ];
412
+ // The finalizer's usable-output gate accepts free text only when it is
413
+ // exactly the mandated no-findings sentinel; a verified remember write
414
+ // is the other accepted evidence. Use the sentinel for the control.
415
+ providerScript = [{ response: textResponse("Nothing new to save.") }];
415
416
  providerCallCount = 0;
416
417
  const retry = await runForkBasedRetrospective(
417
418
  fixture.sourceId,
@@ -459,7 +460,7 @@ describe("memory retrospective wake state chain (real AgentLoop)", () => {
459
460
  expect(listRetroForksOf(fixture.sourceId)).toEqual([fixture.priorRetroId]);
460
461
 
461
462
  // The window stays retryable and a usable reply consumes it.
462
- providerScript = [{ response: textResponse("Reviewed; nothing new.") }];
463
+ providerScript = [{ response: textResponse("Nothing new to save.") }];
463
464
  providerCallCount = 0;
464
465
  const retry = await runForkBasedRetrospective(
465
466
  fixture.sourceId,
@@ -196,7 +196,7 @@ interface TierKeyExemption {
196
196
  * shape.
197
197
  * - `telemetry/config-setting-snapshot.ts` (both) — reports both tier keys
198
198
  * as-is.
199
- * - the six named migrations append-only history that rewrites or reads the
199
+ * - the named migrations: append-only history that rewrites or reads the
200
200
  * historical tier keys it was written for. Listed per file, not per
201
201
  * directory: a future migration reading a tier key is a new decision and
202
202
  * gets challenged like any other.
@@ -257,6 +257,10 @@ const TIER_KEY_READ_ALLOWLIST: readonly TierKeyExemption[] = [
257
257
  path: "src/workspace/migrations/135-copy-substrate-tunables.ts",
258
258
  keys: ["substrate", "v2"],
259
259
  },
260
+ {
261
+ path: "src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts",
262
+ keys: ["v3"],
263
+ },
260
264
  ];
261
265
 
262
266
  /** Tier directory a plugin-root-relative path lives in, or `"spine"`. */