@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-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 (439) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/docs/guardian-request-flow.md +0 -16
  5. package/openapi.yaml +49 -291
  6. package/package.json +1 -1
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  8. package/src/__tests__/app-compiler.test.ts +0 -6
  9. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  10. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  11. package/src/__tests__/app-source-watcher.test.ts +218 -0
  12. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  13. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  14. package/src/__tests__/computer-use-tools.test.ts +5 -17
  15. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  16. package/src/__tests__/config-schema.test.ts +29 -28
  17. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  18. package/src/__tests__/config-watcher.test.ts +8 -23
  19. package/src/__tests__/connection-model-compat.test.ts +2 -2
  20. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  21. package/src/__tests__/conversation-pairing.test.ts +0 -26
  22. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  23. package/src/__tests__/conversation-queue.test.ts +207 -48
  24. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  25. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  26. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  27. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  28. package/src/__tests__/conversation-title-service.test.ts +10 -14
  29. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  30. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  31. package/src/__tests__/credential-record-retire.test.ts +1 -171
  32. package/src/__tests__/credential-routes.test.ts +3 -212
  33. package/src/__tests__/credential-security-invariants.test.ts +2 -4
  34. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  35. package/src/__tests__/document-sync-tags.test.ts +0 -25
  36. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  37. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  38. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  39. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  40. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  42. package/src/__tests__/host-file-proxy.test.ts +23 -11
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  44. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  45. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  47. package/src/__tests__/mcp-health-check.test.ts +11 -8
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  49. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  51. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  52. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  53. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  54. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  55. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  56. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  57. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  58. package/src/__tests__/model-intents.test.ts +0 -3
  59. package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
  60. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  61. package/src/__tests__/platform-callback-registration.test.ts +16 -8
  62. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  63. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  64. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  66. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  67. package/src/__tests__/speaker-identification.test.ts +56 -0
  68. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  69. package/src/__tests__/subagent-tools.test.ts +2 -3
  70. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  71. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  72. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  73. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  74. package/src/__tests__/workspace-git-service.test.ts +0 -26
  75. package/src/acp/__tests__/agent-process.test.ts +4 -258
  76. package/src/acp/__tests__/auth-required.test.ts +0 -96
  77. package/src/acp/__tests__/client-handler.test.ts +2 -90
  78. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  79. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  80. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  81. package/src/acp/__tests__/session-manager.test.ts +4 -895
  82. package/src/acp/agent-process.test.ts +1 -4
  83. package/src/acp/agent-process.ts +9 -94
  84. package/src/acp/auth-required.ts +1 -50
  85. package/src/acp/auto-install.test.ts +7 -9
  86. package/src/acp/client-handler.ts +3 -16
  87. package/src/acp/resolve-agent.test.ts +6 -220
  88. package/src/acp/resolve-agent.ts +23 -88
  89. package/src/acp/session-manager.test.ts +3 -196
  90. package/src/acp/session-manager.ts +18 -441
  91. package/src/acp/types.ts +5 -50
  92. package/src/api/events/app-files-changed.ts +3 -4
  93. package/src/api/events/notification-intent.ts +0 -2
  94. package/src/api/index.ts +0 -6
  95. package/src/apps/app-store.ts +1 -1
  96. package/src/bundler/app-compiler.ts +0 -15
  97. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  98. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  99. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  100. package/src/calls/call-constants.ts +4 -24
  101. package/src/calls/call-controller.ts +199 -499
  102. package/src/calls/call-transport.ts +0 -16
  103. package/src/calls/media-stream-output.ts +0 -32
  104. package/src/calls/media-stream-server.ts +30 -82
  105. package/src/calls/media-stream-stt-session.ts +0 -15
  106. package/src/calls/resolve-call-tts-provider.ts +2 -33
  107. package/src/calls/speaker-identification.ts +233 -0
  108. package/src/calls/tts-call-strategy.ts +5 -9
  109. package/src/calls/types.ts +0 -2
  110. package/src/calls/voice-control-protocol.ts +21 -53
  111. package/src/calls/voice-session-bridge.ts +46 -59
  112. package/src/calls/voice-triage-escalate.ts +56 -175
  113. package/src/cli/commands/apps.help.ts +13 -67
  114. package/src/cli/commands/apps.ts +0 -183
  115. package/src/cli/commands/bash.help.ts +13 -8
  116. package/src/cli/commands/bash.ts +25 -7
  117. package/src/cli/commands/channels/index.help.ts +2 -70
  118. package/src/cli/commands/channels/index.ts +3 -16
  119. package/src/cli/commands/credentials.help.ts +2 -6
  120. package/src/cli/commands/credentials.ts +2 -2
  121. package/src/cli/commands/mcp.help.ts +8 -8
  122. package/src/cli/commands/mcp.ts +1 -1
  123. package/src/cli/commands/roadmap.help.ts +1 -5
  124. package/src/cli/commands/roadmap.ts +1 -1
  125. package/src/cli/lib/bundled-marketplace.json +90 -103
  126. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  127. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  128. package/src/config/__tests__/platform-rehydration.test.ts +9 -99
  129. package/src/config/acp-defaults.test.ts +3 -13
  130. package/src/config/acp-defaults.ts +6 -23
  131. package/src/config/acp-schema.ts +2 -30
  132. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  133. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  134. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  135. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  136. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  137. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  138. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  139. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  140. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  141. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  142. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  143. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  144. package/src/config/default-profile-catalog.ts +1 -1
  145. package/src/config/env.ts +2 -2
  146. package/src/config/feature-flag-registry.json +12 -24
  147. package/src/config/loader.ts +0 -1
  148. package/src/config/memory-v3-gate.test.ts +0 -31
  149. package/src/config/memory-v3-gate.ts +16 -20
  150. package/src/config/platform-rehydration.ts +27 -11
  151. package/src/config/schema.ts +2 -2
  152. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  153. package/src/config/schemas/calls.ts +28 -1
  154. package/src/config/schemas/live-voice.ts +173 -1
  155. package/src/config/schemas/mcp.ts +1 -1
  156. package/src/config/schemas/memory-retrospective.ts +0 -10
  157. package/src/config/schemas/services.ts +0 -8
  158. package/src/config/schemas/skills.ts +14 -0
  159. package/src/credential-execution/process-manager.test.ts +19 -18
  160. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  161. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  162. package/src/daemon/app-source-watcher.ts +218 -0
  163. package/src/daemon/config-watcher.ts +194 -13
  164. package/src/daemon/conversation-process.ts +64 -35
  165. package/src/daemon/conversation-skill-tools.ts +31 -13
  166. package/src/daemon/conversation-store.ts +1 -1
  167. package/src/daemon/conversation-surfaces.ts +8 -10
  168. package/src/daemon/conversation-tool-setup.ts +43 -37
  169. package/src/daemon/conversation.ts +3 -0
  170. package/src/daemon/host-bash-proxy.ts +12 -8
  171. package/src/daemon/host-browser-proxy.ts +1 -15
  172. package/src/daemon/host-file-proxy.ts +10 -8
  173. package/src/daemon/host-transfer-proxy.ts +18 -14
  174. package/src/daemon/lifecycle.ts +5 -0
  175. package/src/daemon/mcp-reload-service.ts +5 -5
  176. package/src/daemon/message-types/sync.ts +0 -1
  177. package/src/daemon/orphan-reaper.ts +1 -1
  178. package/src/daemon/providers-setup.ts +1 -1
  179. package/src/daemon/shutdown-handlers.ts +9 -1
  180. package/src/daemon/skill-memory-refresh.ts +0 -64
  181. package/src/daemon/tool-side-effects.ts +18 -7
  182. package/src/home/__tests__/feed-writer.test.ts +0 -22
  183. package/src/home/feed-writer.ts +2 -11
  184. package/src/hooks/types.ts +0 -33
  185. package/src/inbound/platform-callback-registration.ts +5 -4
  186. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  187. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  188. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  189. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  190. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  191. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  192. package/src/live-voice/live-voice-session.ts +693 -213
  193. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  194. package/src/live-voice/protocol.ts +2 -0
  195. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  196. package/src/mcp/effective-config.ts +3 -3
  197. package/src/mcp/mcp-header-store.ts +45 -29
  198. package/src/mcp/startup.ts +4 -8
  199. package/src/messaging/provider.ts +3 -10
  200. package/src/messaging/providers/callback-routing.ts +0 -18
  201. package/src/messaging/providers/channel-transport.ts +0 -56
  202. package/src/messaging/providers/discord/transport.ts +0 -17
  203. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  204. package/src/messaging/providers/slack/adapter.ts +44 -7
  205. package/src/messaging/providers/slack/transport.ts +0 -16
  206. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  207. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  208. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  209. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  210. package/src/messaging/providers/whatsapp/client.ts +29 -0
  211. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  212. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  213. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  214. package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
  215. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  216. package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
  217. package/src/notifications/adapters/macos.ts +0 -3
  218. package/src/notifications/assistant-reply-producer.ts +3 -8
  219. package/src/notifications/conversation-pairing.ts +16 -36
  220. package/src/notifications/delivered-post-record.ts +1 -11
  221. package/src/notifications/guardian-feed-projection.ts +5 -125
  222. package/src/notifications/home-feed-side-effect.ts +7 -55
  223. package/src/notifications/schedule-result-producer.ts +22 -66
  224. package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
  225. package/src/oauth/byo-connection.test.ts +0 -45
  226. package/src/oauth/byo-connection.ts +6 -36
  227. package/src/oauth/connection-resolver.test.ts +0 -73
  228. package/src/oauth/connection-resolver.ts +2 -95
  229. package/src/oauth/seed-providers.ts +0 -165
  230. package/src/outbound-proxy/certs.ts +5 -3
  231. package/src/permissions/checker.test.ts +6 -11
  232. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  233. package/src/persistence/conversation-crud.ts +63 -71
  234. package/src/persistence/conversation-lineage.ts +4 -12
  235. package/src/persistence/conversation-title-service.ts +26 -9
  236. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  237. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  238. package/src/persistence/message-reads.ts +0 -30
  239. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  240. package/src/persistence/schema/memory-core.ts +0 -5
  241. package/src/platform/client.test.ts +2 -4
  242. package/src/platform/client.ts +10 -2
  243. package/src/plugin-api/constants.ts +0 -2
  244. package/src/plugin-api/index.ts +0 -1
  245. package/src/plugin-api/types.ts +0 -2
  246. package/src/plugins/defaults/index.ts +0 -2
  247. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  248. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  249. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  250. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  251. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  252. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  253. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  254. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  255. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  256. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  257. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  258. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  259. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  260. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  261. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  262. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  263. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  264. package/src/plugins/defaults/memory/startup.ts +1 -6
  265. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  266. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  267. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  268. package/src/plugins/defaults/memory/worker.ts +0 -6
  269. package/src/plugins/mcp-servers.ts +75 -15
  270. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  271. package/src/providers/gemini/client.ts +23 -9
  272. package/src/providers/inference/auth.ts +3 -2
  273. package/src/providers/inference/connection-availability.ts +8 -27
  274. package/src/providers/inference/resolve-auth.ts +4 -22
  275. package/src/providers/model-catalog.ts +0 -34
  276. package/src/providers/model-intents.ts +5 -10
  277. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  278. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  279. package/src/providers/openai/chat-completions-provider.ts +78 -192
  280. package/src/providers/openai/codex-models.ts +4 -0
  281. package/src/runtime/AGENTS.md +0 -2
  282. package/src/runtime/auth/same-actor.ts +3 -38
  283. package/src/runtime/http-server.ts +151 -160
  284. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  286. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  287. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  288. package/src/runtime/routes/acp-routes.test.ts +0 -15
  289. package/src/runtime/routes/acp-routes.ts +9 -72
  290. package/src/runtime/routes/app-management-routes.ts +0 -73
  291. package/src/runtime/routes/app-routes.ts +1 -1
  292. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  293. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  294. package/src/runtime/routes/credential-routes.ts +10 -19
  295. package/src/runtime/routes/debug-bash-routes.ts +173 -0
  296. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  297. package/src/runtime/routes/index.ts +2 -4
  298. package/src/runtime/routes/log-export-routes.ts +0 -2
  299. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  300. package/src/runtime/routes/migration-routes.ts +20 -6
  301. package/src/runtime/routes/platform-routes.ts +15 -18
  302. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  303. package/src/runtime/services/conversation-serializer.ts +3 -16
  304. package/src/runtime/sync/resource-sync-events.ts +1 -2
  305. package/src/schedule/worker.ts +1 -1
  306. package/src/security/ces-rpc-record-backend.ts +0 -7
  307. package/src/subagent/consult-context.ts +25 -12
  308. package/src/tools/acp/list-agents.test.ts +1 -3
  309. package/src/tools/acp/spawn.test.ts +11 -146
  310. package/src/tools/acp/spawn.ts +3 -21
  311. package/src/tools/acp/status.ts +3 -40
  312. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  313. package/src/tools/capability-offer.test.ts +2 -22
  314. package/src/tools/capability-offer.ts +1 -16
  315. package/src/tools/computer-use/definitions.ts +2 -4
  316. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  317. package/src/tools/credentials/metadata-store.ts +0 -100
  318. package/src/tools/host-filesystem/edit.test.ts +1 -2
  319. package/src/tools/host-filesystem/edit.ts +2 -2
  320. package/src/tools/host-filesystem/read.test.ts +1 -2
  321. package/src/tools/host-filesystem/read.ts +2 -2
  322. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  323. package/src/tools/host-filesystem/transfer.ts +2 -2
  324. package/src/tools/host-filesystem/write.test.ts +1 -2
  325. package/src/tools/host-filesystem/write.ts +2 -2
  326. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  327. package/src/tools/host-terminal/host-shell.ts +20 -4
  328. package/src/tools/policy-context.ts +7 -6
  329. package/src/tools/subagent/spawn.ts +8 -5
  330. package/src/tools/watch/watch-retro-report.ts +8 -0
  331. package/src/util/__tests__/language-subtag.test.ts +1 -23
  332. package/src/util/fs-watcher-error.ts +36 -0
  333. package/src/util/language-subtag.ts +0 -16
  334. package/src/util/platform.ts +0 -8
  335. package/src/workspace/git-service.ts +54 -5
  336. package/src/workspace/migrations/registry.ts +0 -6
  337. package/scripts/smoke-desktop-window-theme.ts +0 -186
  338. package/src/__tests__/git-porcelain.test.ts +0 -47
  339. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  340. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  341. package/src/__tests__/resolve-app.test.ts +0 -135
  342. package/src/__tests__/service-account-token.test.ts +0 -247
  343. package/src/__tests__/source-fingerprint.test.ts +0 -184
  344. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  345. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  346. package/src/acp/model-config.test.ts +0 -166
  347. package/src/acp/model-config.ts +0 -138
  348. package/src/api/events/acp-session-model-update.test.ts +0 -88
  349. package/src/api/events/acp-session-model-update.ts +0 -46
  350. package/src/apps/resolve-app.ts +0 -81
  351. package/src/apps/source-fingerprint.ts +0 -266
  352. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  353. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  354. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  355. package/src/calls/barge-in-guard.ts +0 -118
  356. package/src/calls/voice-leg-coordinator.ts +0 -189
  357. package/src/calls/voice-progress-cadence.ts +0 -423
  358. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  359. package/src/cli/commands/__tests__/bash.test.ts +0 -53
  360. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  361. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  362. package/src/cli/commands/channels/send.ts +0 -128
  363. package/src/config/__tests__/platform-identity.test.ts +0 -255
  364. package/src/config/acp-agent-write.ts +0 -43
  365. package/src/config/acp-schema.test.ts +0 -81
  366. package/src/config/platform-identity.ts +0 -201
  367. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  368. package/src/config/schemas/voice.ts +0 -150
  369. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  370. package/src/daemon/app-change-notify.ts +0 -45
  371. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  372. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  373. package/src/desktop/desktop-chrome-policy.ts +0 -42
  374. package/src/desktop/desktop-dependencies.test.ts +0 -102
  375. package/src/desktop/desktop-dependencies.ts +0 -306
  376. package/src/desktop/desktop-feature.test.ts +0 -18
  377. package/src/desktop/desktop-feature.ts +0 -19
  378. package/src/desktop/desktop-panel-config.test.ts +0 -135
  379. package/src/desktop/desktop-panel-config.ts +0 -149
  380. package/src/desktop/desktop-session-manager.test.ts +0 -627
  381. package/src/desktop/desktop-session-manager.ts +0 -814
  382. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  383. package/src/desktop/desktop-stream-bridge.ts +0 -214
  384. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  385. package/src/desktop/desktop-wallpaper.ts +0 -113
  386. package/src/desktop/desktop-window-theme.ts +0 -170
  387. package/src/i18n/AGENTS.md +0 -22
  388. package/src/i18n/__tests__/i18n.test.ts +0 -108
  389. package/src/i18n/index.ts +0 -16
  390. package/src/i18n/locales.ts +0 -93
  391. package/src/i18n/messages.ts +0 -61
  392. package/src/i18n/title.ts +0 -25
  393. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  394. package/src/mcp/spec-schema.ts +0 -111
  395. package/src/mcp/workspace-mcp-config.ts +0 -188
  396. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  397. package/src/persistence/conversation-title-placeholders.ts +0 -23
  398. package/src/persistence/message-cursor.ts +0 -78
  399. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  400. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  401. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  402. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  403. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  404. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  405. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  406. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  407. package/src/providers/gemini-thought-signature.test.ts +0 -63
  408. package/src/providers/gemini-thought-signature.ts +0 -44
  409. package/src/providers/inference/service-account-token.ts +0 -248
  410. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  411. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  412. package/src/providers/openai/google-thought-signature.ts +0 -320
  413. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  414. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  415. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  416. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  417. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  418. package/src/runtime/channel-send.ts +0 -316
  419. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  420. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  421. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  422. package/src/runtime/routes/channel-send-routes.ts +0 -85
  423. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  424. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  425. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  426. package/src/security/ces-http-record-backend.ts +0 -120
  427. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  428. package/src/skills/workspace-skill-md-signature.ts +0 -50
  429. package/src/tools/acp/status.test.ts +0 -94
  430. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
  431. package/src/tools/terminal/sanitized-bash.ts +0 -105
  432. package/src/util/ca-bundle.ts +0 -13
  433. package/src/workspace/git-porcelain.ts +0 -66
  434. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  435. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  436. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  437. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  438. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  439. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -55,13 +55,6 @@ const SCHEDULE_ID = "sched-1";
55
55
  const RUN_ID = "run-1";
56
56
  const RUN_STARTED_AT = 1700000000000;
57
57
 
58
- /**
59
- * The synthetic user rows carrying each tool call's result. A delivery counts
60
- * only when its call reported success, so a case that wants suppression has to
61
- * supply the matching successful result.
62
- */
63
- let toolResultRows: MessageRow[] = [];
64
-
65
58
  const realCrud = await import("../../persistence/conversation-crud.js");
66
59
  mock.module("../../persistence/conversation-crud.js", () => ({
67
60
  ...realCrud,
@@ -73,7 +66,6 @@ mock.module("../../persistence/conversation-crud.js", () => ({
73
66
  messageId === ASSISTANT_MESSAGE_ID
74
67
  ? [...turnRows.map((row) => row.id), ASSISTANT_MESSAGE_ID]
75
68
  : [messageId],
76
- getMessagesAfter: () => toolResultRows,
77
69
  }));
78
70
 
79
71
  const realAttentionStore =
@@ -122,25 +114,6 @@ function makeToolCallRow(
122
114
  );
123
115
  }
124
116
 
125
- /** The executor's verdict on the call `makeToolCallRow(name, ...)` made. */
126
- function makeToolResultRow(name: string, isError = false): MessageRow {
127
- return makeAssistantRow(
128
- [
129
- {
130
- type: "tool_result",
131
- tool_use_id: `tu-${name}`,
132
- content: isError ? "failed" : "ok",
133
- ...(isError ? { is_error: true } : {}),
134
- },
135
- ] as ContentBlock[],
136
- {
137
- id: `res-${name}`,
138
- role: "user",
139
- createdAt: RUN_STARTED_AT + 150,
140
- },
141
- );
142
- }
143
-
144
117
  function makeAttentionState(
145
118
  overrides: Partial<AttentionState> = {},
146
119
  ): AttentionState {
@@ -216,7 +189,6 @@ beforeEach(() => {
216
189
  notifiedProbeArgs.length = 0;
217
190
  alreadyNotified = false;
218
191
  turnRows = [];
219
- toolResultRows = [];
220
192
  attentionState = makeAttentionState();
221
193
  assistantRow = makeAssistantRow([
222
194
  { type: "text", text: "**3 new emails** and one calendar change." },
@@ -273,8 +245,7 @@ describe("emitScheduleResultNotification", () => {
273
245
 
274
246
  test("stays silent when the run delivered by email through messaging_send", async () => {
275
247
  // The schedule skill's prescribed route for rich content. It writes no
276
- // notification event, so the successful tool call is what shows the user
277
- // has the result.
248
+ // notification event, so only the tool call shows the user has the result.
278
249
  turnRows = [
279
250
  makeToolCallRow("messaging_send", {
280
251
  platform: "gmail",
@@ -282,7 +253,6 @@ describe("emitScheduleResultNotification", () => {
282
253
  message: "Inbox digest…",
283
254
  }),
284
255
  ];
285
- toolResultRows = [makeToolResultRow("messaging_send")];
286
256
  assistantRow = makeAssistantRow([
287
257
  { type: "text", text: "Sent the digest to your inbox." },
288
258
  ] as ContentBlock[]);
@@ -292,86 +262,20 @@ describe("emitScheduleResultNotification", () => {
292
262
  expect(emitCalls).toHaveLength(0);
293
263
  });
294
264
 
295
- test("stays silent when the run posted to a channel through messaging_send", async () => {
296
- turnRows = [
297
- makeToolCallRow("messaging_send", {
298
- platform: "slack",
299
- conversation_id: "C0123456789",
300
- text: "the digest",
301
- }),
302
- ];
303
- toolResultRows = [makeToolResultRow("messaging_send")];
304
- assistantRow = makeAssistantRow([
305
- { type: "text", text: "Posted the digest to #general." },
306
- ] as ContentBlock[]);
307
-
308
- await run();
309
-
310
- expect(emitCalls).toHaveLength(0);
311
- });
312
-
313
- test("notifies when the channel send failed, so the run is not silent", async () => {
314
- // The failure this guard exists for: the post never landed, the run said
315
- // so in a conversation nobody has open, and suppressing on the attempt
316
- // would cost the user the digest and the explanation both.
317
- turnRows = [
318
- makeToolCallRow("messaging_send", {
319
- platform: "slack",
320
- conversation_id: "C0123456789",
321
- text: "the digest",
322
- }),
323
- ];
324
- toolResultRows = [makeToolResultRow("messaging_send", true)];
325
- assistantRow = makeAssistantRow([
326
- { type: "text", text: "I could not post the digest to #general." },
327
- ] as ContentBlock[]);
328
-
329
- await run();
330
-
331
- expect(emitCalls).toHaveLength(1);
332
- expect(emitCalls[0].contextPayload.requestedMessage).toBe(
333
- "I could not post the digest to #general.",
334
- );
335
- });
336
-
337
- test("notifies when a delivery call left no result at all", async () => {
338
- // An interrupted turn persists the call without its verdict. Unproven is
339
- // not delivered.
340
- turnRows = [
341
- makeToolCallRow("messaging_send", {
342
- platform: "slack",
343
- conversation_id: "C0123456789",
344
- text: "the digest",
345
- }),
346
- ];
347
- toolResultRows = [];
348
- assistantRow = makeAssistantRow([
349
- { type: "text", text: "Here is the digest." },
350
- ] as ContentBlock[]);
351
-
352
- await run();
353
-
354
- expect(emitCalls).toHaveLength(1);
355
- });
356
-
357
- test("notifies after a Web API post, whose success cannot prove Slack accepted it", async () => {
358
- // Slack refuses a call with HTTP 200 and `ok: false`, so a successful bash
359
- // result is no evidence the post landed. This is the best case the route
360
- // can produce, and it still gets the fallback.
265
+ test("stays silent when the run posted to Slack through chat.postMessage", async () => {
361
266
  turnRows = [
362
267
  makeToolCallRow("bash", {
363
268
  command:
364
269
  'assistant oauth request --provider slack_channel /chat.postMessage --json \'{"channel":"C1","text":"digest"}\'',
365
270
  }),
366
271
  ];
367
- toolResultRows = [makeToolResultRow("bash")];
368
272
  assistantRow = makeAssistantRow([
369
273
  { type: "text", text: "Posted the digest to #general." },
370
274
  ] as ContentBlock[]);
371
275
 
372
276
  await run();
373
277
 
374
- expect(emitCalls).toHaveLength(1);
278
+ expect(emitCalls).toHaveLength(0);
375
279
  });
376
280
 
377
281
  test("still notifies when the run's tool calls were not deliveries", async () => {
@@ -20,7 +20,6 @@
20
20
 
21
21
  import type { AssistantEvent } from "../../api/index.js";
22
22
  import type { InterfaceId } from "../../channels/types.js";
23
- import { getAssistantName } from "../../daemon/identity-helpers.js";
24
23
  import { updateMessageContent } from "../../persistence/conversation-crud.js";
25
24
  import { publishConversationMessagesChanged } from "../../runtime/sync/resource-sync-events.js";
26
25
  import { getLogger } from "../../util/logger.js";
@@ -102,14 +101,12 @@ export class VellumAdapter implements ChannelAdapter {
102
101
 
103
102
  const silent =
104
103
  payload.urgency !== "high" && payload.urgency !== "critical";
105
- const assistantName = getAssistantName()?.trim() || undefined;
106
104
 
107
105
  this.broadcast({
108
106
  type: "notification_intent",
109
107
  deliveryId: payload.deliveryId,
110
108
  correlationId: payload.correlationId,
111
109
  sourceEventName: payload.sourceEventName,
112
- ...(assistantName ? { assistantName } : {}),
113
110
  title: payload.copy.title,
114
111
  body: payload.copy.body,
115
112
  deepLinkMetadata: payload.deepLinkTarget,
@@ -22,7 +22,6 @@ import {
22
22
  getMessageById,
23
23
  parseMessageMetadata,
24
24
  } from "../persistence/conversation-crud.js";
25
- import { isReplaceableTitle } from "../persistence/conversation-title-placeholders.js";
26
25
  import {
27
26
  isDesktopOriginatedUserMessage,
28
27
  isReplyPushIneligibleUserMessage,
@@ -248,13 +247,9 @@ export async function emitAssistantReplyNotification(params: {
248
247
  // lock screen. Absent `requestedTitle` lets the decision branch derive a
249
248
  // title from the body, which reads better than an empty or placeholder
250
249
  // conversation title.
251
- //
252
- // Placeholder titles are plausible non-empty strings and survive
253
- // sanitizing. They count as absent so the body supplies the title instead.
254
- const storedTitle = conversation.title?.trim() ?? "";
255
- const requestedTitle = isReplaceableTitle(storedTitle)
256
- ? ""
257
- : sanitizeNotificationTitle(flattenTitleWhitespace(storedTitle));
250
+ const requestedTitle = sanitizeNotificationTitle(
251
+ flattenTitleWhitespace(conversation.title ?? ""),
252
+ );
258
253
 
259
254
  // Read as close to the emit as possible: nothing short-circuits on it.
260
255
  // Presence only speaks for a turn the desktop itself opened, on that row's
@@ -130,7 +130,6 @@ export interface PairingOptions {
130
130
  * transactional request or a system alert.
131
131
  */
132
132
  const ASSISTANT_SHARE_EVENT = "assistant.share";
133
- const ASSISTANT_REPLY_EVENT = "chat.assistant_reply";
134
133
 
135
134
  /**
136
135
  * Promote a background share into an assistant-initiated thread, under the
@@ -264,25 +263,7 @@ export async function pairDeliveryWithConversation(
264
263
  // notification can appear. The home feed aims its "Go to Conversation"
265
264
  // button at the same row whenever it mirrors the signal.
266
265
  //
267
- // `chat.assistant_reply` already has its complete reply in that transcript.
268
- // Its notification body is a lock-screen preview, so appending it would
269
- // create a second, truncated assistant row. Keep the conversation target
270
- // for deep links without writing the preview into the transcript.
271
- if (
272
- strategy === "start_new_conversation" &&
273
- !signal.requiresConversation &&
274
- signal.sourceEventName === ASSISTANT_REPLY_EVENT
275
- ) {
276
- return {
277
- conversationId: resolveSourceConversationId(signal),
278
- messageId: null,
279
- strategy,
280
- createdNewConversation: false,
281
- conversationFallbackUsed: false,
282
- };
283
- }
284
-
285
- // This is deliberately not gated on home-feed eligibility: a signal the
266
+ // So this is deliberately not gated on home-feed eligibility: a signal the
286
267
  // feed declines to mirror still reaches the user through the banner, and
287
268
  // this row is what makes that landing honest.
288
269
  if (strategy === "start_new_conversation" && !signal.requiresConversation) {
@@ -767,45 +748,44 @@ async function resolveChannelDeliveryHome(params: {
767
748
  * Indexing is skipped for parity with the other notification write paths:
768
749
  * notification copy is delivery audit, not conversational memory.
769
750
  */
770
- function resolveSourceConversationId(signal: NotificationSignal): string | null {
771
- if (!signal.sourceContextId) {
751
+ async function appendBodyToSourceConversation(
752
+ signal: NotificationSignal,
753
+ channel: NotificationChannel,
754
+ messageContent: string,
755
+ ): Promise<{ conversationId: string; messageId: string } | null> {
756
+ const sourceContextId = signal.sourceContextId;
757
+ if (!sourceContextId) {
772
758
  return null;
773
759
  }
760
+
761
+ let existing: ReturnType<typeof getConversation>;
774
762
  try {
775
- return getConversation(signal.sourceContextId)?.id ?? null;
763
+ existing = getConversation(sourceContextId);
776
764
  } catch {
777
765
  return null;
778
766
  }
779
- }
780
-
781
- async function appendBodyToSourceConversation(
782
- signal: NotificationSignal,
783
- channel: NotificationChannel,
784
- messageContent: string,
785
- ): Promise<{ conversationId: string; messageId: string } | null> {
786
- const conversationId = resolveSourceConversationId(signal);
787
- if (!conversationId) {
767
+ if (!existing) {
788
768
  return null;
789
769
  }
790
770
 
791
- const message = await addMessage(conversationId, "assistant", messageContent, {
771
+ const message = await addMessage(existing.id, "assistant", messageContent, {
792
772
  skipIndexing: true,
793
773
  });
794
774
  // `addMessage` projects attention metadata alone, so a client with this
795
775
  // conversation open needs the messages tag to refetch the transcript. A
796
776
  // notification the user taps through to has every chance of landing on an
797
777
  // already-open conversation.
798
- publishConversationMessagesChanged(conversationId);
778
+ publishConversationMessagesChanged(existing.id);
799
779
 
800
780
  log.info(
801
781
  {
802
782
  signalId: signal.signalId,
803
783
  channel,
804
- conversationId,
784
+ conversationId: existing.id,
805
785
  messageId: message.id,
806
786
  },
807
787
  "Appended notification body to producing conversation",
808
788
  );
809
789
 
810
- return { conversationId, messageId: message.id };
790
+ return { conversationId: existing.id, messageId: message.id };
811
791
  }
@@ -39,12 +39,6 @@ export interface DeliveredChannelPost {
39
39
  text: string;
40
40
  /** The message id the channel assigned when it acknowledged the post. */
41
41
  providerMessageId: string;
42
- /**
43
- * The ids of the further posts the same text became when the channel
44
- * split it, in send order. Each is reconciled onto the row like the first,
45
- * so a reaction, edit, or delete naming any chunk resolves to this row.
46
- */
47
- additionalProviderMessageIds?: readonly string[];
48
42
  /**
49
43
  * The conversation whose turn made the post, when a different one from
50
44
  * the home it is recorded in (the messaging tool sending from a scheduled
@@ -81,11 +75,7 @@ export async function recordDeliveredChannelPost(
81
75
  : {}),
82
76
  },
83
77
  });
84
- const reconcile = makeSentMessageIdReconciler(row.id);
85
- await reconcile(post.providerMessageId);
86
- for (const id of post.additionalProviderMessageIds ?? []) {
87
- await reconcile(id);
88
- }
78
+ await makeSentMessageIdReconciler(row.id)(post.providerMessageId);
89
79
  // A resident conversation reloads its history on the next turn so the
90
80
  // post is in context; the client refetches the transcript.
91
81
  findConversation(post.conversationId)?.markHistoryStale();
@@ -31,10 +31,6 @@ import {
31
31
  patchFeedItemContent,
32
32
  readHomeFeed,
33
33
  } from "../home/feed-writer.js";
34
- import {
35
- getMemoryCheckpoint,
36
- setMemoryCheckpoint,
37
- } from "../persistence/checkpoints.js";
38
34
  import { getLogger } from "../util/logger.js";
39
35
  import {
40
36
  buildToolApprovalSourceView,
@@ -170,17 +166,11 @@ export interface GuardianFeedReceiptParams {
170
166
  *
171
167
  * The item keeps its title and summary; `guardianRequest` flips to the
172
168
  * terminal status (which is what removes the client's action buttons),
173
- * urgency drops to `medium` so the item leaves the protected "Needs
174
- * attention" treatment and becomes an ordinary clearable notification,
175
- * and an item still marked `new` is marked `seen`: a request settled on
176
- * any surface is no longer something the user has to review, and leaving
177
- * it unread is a false attention signal. That clear happens only on the
178
- * edge into terminal, so a status the user set later (including marking
179
- * the receipt unread again) survives a caller that receipts twice.
180
- *
181
- * Returns false only when the write itself failed, so the withdrawal
182
- * fan-out can hold its per-request receipt back and retry (same
183
- * contract as the other surfaces it settles). A request with no
169
+ * and urgency drops to `medium` so the item leaves the protected
170
+ * "Needs attention" treatment and becomes an ordinary clearable
171
+ * notification. Returns false only when the write itself failed, so the
172
+ * withdrawal fan-out can hold its per-request receipt back and retry
173
+ * (same contract as the other surfaces it settles). A request with no
184
174
  * projection item resolves true: the pending writer converges the
185
175
  * write-vs-resolve race by re-checking canonical status after its
186
176
  * append, so there is nothing here for a retry to fix.
@@ -207,15 +197,6 @@ export async function writeGuardianFeedReceipt(
207
197
  }
208
198
  const updated = await patchFeedItemContent(itemId, {
209
199
  urgency: "medium",
210
- // Only on the pending-to-terminal edge. A later receipt for the
211
- // same request (the fan-out retries per surface, reconciliation
212
- // heals drift) must not undo a user who marked the receipt unread
213
- // again; from `new` specifically, because a pending item the user
214
- // dismissed outright stays dismissed.
215
- status: (existing) =>
216
- existing.status === "new" && isPendingGuardianFeedItem(existing)
217
- ? "seen"
218
- : existing.status,
219
200
  guardianRequest: (existing) => ({
220
201
  ...existing,
221
202
  status: params.status,
@@ -287,103 +268,6 @@ export async function receiptGuardianFeedItemIfRequestTerminal(
287
268
  */
288
269
  const RECONCILE_BACKFILL_LIMIT = 50;
289
270
 
290
- /** Ceiling on rows healed per round, mirroring the backfill bound. */
291
- const LEGACY_UNREAD_HEAL_LIMIT = 50;
292
-
293
- /**
294
- * Completion sentinel for the one-time heal below, in the daemon's
295
- * checkpoint ledger (the same shape as the lexical backfill's
296
- * `lexical:messages:backfill_complete`). It is the only thing that
297
- * separates the two kinds of terminal receipt stored at `status: "new"`:
298
- * one that never passed the pending-to-terminal edge, and one the user
299
- * marked unread after it did. The rows are byte-identical (terminal
300
- * projection, urgency `medium`), so the boundary is recorded rather
301
- * than inferred.
302
- */
303
- const LEGACY_UNREAD_HEAL_COMPLETE_KEY =
304
- "guardian_feed:receipt_unread_heal_complete";
305
-
306
- /**
307
- * Clear unread on terminal guardian receipts that never passed the
308
- * pending-to-terminal edge in `writeGuardianFeedReceipt`.
309
- *
310
- * Nothing else reaches those rows: the edge runs only while a
311
- * projection still reads pending, reconciliation skips items whose
312
- * projection is already terminal, and guardian items carry no
313
- * `expiresAt`. Without this pass they read unread indefinitely.
314
- *
315
- * Runs once per assistant, not once per boot. A recurring pass would
316
- * take back a deliberate "mark unread" every minute, and a per-boot pass
317
- * would take it back on the next restart; the sentinel is what makes a
318
- * later `new` unambiguously the user's, so it is never touched.
319
- *
320
- * Same user-choice semantics as the edge, enforced the same way: the
321
- * transition is re-evaluated inside the writer's coalescing queue, moves
322
- * only `new`, and leaves `seen`, `acted_on` and `dismissed` alone.
323
- * Bounded per round, and the sentinel is written only once a round drains
324
- * with nothing left and nothing failed, so an interrupted pass resumes.
325
- */
326
- export async function healLegacyGuardianReceiptUnread(): Promise<void> {
327
- try {
328
- if (getMemoryCheckpoint(LEGACY_UNREAD_HEAL_COMPLETE_KEY) === "1") {
329
- return;
330
- }
331
- } catch (err) {
332
- // A DB that cannot answer skips the round rather than risk re-healing
333
- // a row the user has since marked unread.
334
- log.warn({ err }, "Guardian receipt unread heal: checkpoint unreadable");
335
- return;
336
- }
337
-
338
- const stale = readHomeFeed().items.filter(
339
- (item) =>
340
- item.guardianRequest !== undefined &&
341
- !isPendingGuardianFeedItem(item) &&
342
- item.status === "new",
343
- );
344
-
345
- const batch = stale.slice(0, LEGACY_UNREAD_HEAL_LIMIT);
346
- let failed = 0;
347
- for (const item of batch) {
348
- // Re-tested at write time rather than trusted from the read above,
349
- // so a row the edge transition or the user changed in between keeps
350
- // whatever it was given.
351
- const updated = await patchFeedItemContent(item.id, {
352
- status: (existing) =>
353
- existing.status === "new" && !isPendingGuardianFeedItem(existing)
354
- ? "seen"
355
- : existing.status,
356
- });
357
- if (!updated) {
358
- failed++;
359
- }
360
- }
361
-
362
- if (batch.length > 0) {
363
- log.info(
364
- {
365
- healed: batch.length - failed,
366
- failed,
367
- remaining: stale.length - batch.length,
368
- },
369
- "Cleared unread on terminal guardian receipts that never passed the edge",
370
- );
371
- }
372
-
373
- if (failed > 0 || stale.length > batch.length) {
374
- // Not finished: leave the sentinel unset so the next round resumes.
375
- return;
376
- }
377
-
378
- try {
379
- setMemoryCheckpoint(LEGACY_UNREAD_HEAL_COMPLETE_KEY, "1");
380
- } catch (err) {
381
- // The heal itself landed; only the sentinel is missing, so the next
382
- // round repeats a pass that now has nothing to do.
383
- log.warn({ err }, "Guardian receipt unread heal: checkpoint not persisted");
384
- }
385
- }
386
-
387
271
  /**
388
272
  * Converge the feed against canonical guardian state. Run from the
389
273
  * guardian expiry sweep, so drift heals on the same cadence expiry does:
@@ -401,10 +285,6 @@ export async function healLegacyGuardianReceiptUnread(): Promise<void> {
401
285
  * not be mistaken for "everything resolved".
402
286
  */
403
287
  export async function reconcileGuardianFeedProjections(): Promise<void> {
404
- // Ahead of the gateway read: the heal heads off stored rows alone and
405
- // must not be held up by an unreachable gateway.
406
- await healLegacyGuardianReceiptUnread();
407
-
408
288
  let pending: GuardianRequestWire[];
409
289
  try {
410
290
  pending = await listGuardianRequests({ status: "pending" });
@@ -23,10 +23,7 @@ import {
23
23
  getMessageById,
24
24
  updateMessageContent,
25
25
  } from "../persistence/conversation-crud.js";
26
- import {
27
- ASSISTANT_INITIATED_SOURCE,
28
- isBackgroundConversationType,
29
- } from "../persistence/conversation-types.js";
26
+ import { isBackgroundConversationType } from "../persistence/conversation-types.js";
30
27
  import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
31
28
  import { getLogger } from "../util/logger.js";
32
29
  import { normalizeTitle, stripMarkdown } from "../util/short-title.js";
@@ -275,11 +272,6 @@ async function resolveOwnedConversationMessageId(
275
272
  sourceConversationId: string | undefined,
276
273
  summary: string,
277
274
  ): Promise<string | undefined> {
278
- // The completed reply is already the source conversation's canonical row.
279
- // This signal's body is a compact push preview, not conversation content.
280
- if (signal.sourceEventName === "chat.assistant_reply") {
281
- return undefined;
282
- }
283
275
  if (vellumDelivery?.conversationId) {
284
276
  return vellumDelivery.conversationId === sourceConversationId
285
277
  ? vellumDelivery.messageId
@@ -503,18 +495,6 @@ function deriveDetailPanelKind(
503
495
  * `isAsyncBackground` hint. `chat.assistant_reply` also mirrors: it is the
504
496
  * durable in-app record for the push sent after a user leaves a chat, while
505
497
  * retaining the normal interactive conversation as its navigation target.
506
- *
507
- * A delivery that materialized an assistant-initiated thread never mirrors.
508
- * Under the `assistant-initiated-threads` flag, `conversation-pairing.ts`
509
- * promotes a background `assistant.share` into a standard conversation
510
- * stamped {@link ASSISTANT_INITIATED_SOURCE}, and that thread's row in the
511
- * sidebar's assistant section is the share's one surface. Mirroring it here
512
- * as well put the same share in the bell a second time, labeled by its
513
- * source channel ("Heartbeat"). The check reads the paired conversation's
514
- * `source` rather than re-deriving the promotion rule, so it holds however
515
- * that rule narrows or widens. Guardian requests are checked first on
516
- * purpose: the bell is their canonical home whatever conversation they pair
517
- * with.
518
498
  */
519
499
  function resolveHomeFeedMirror(
520
500
  signal: NotificationSignal,
@@ -545,15 +525,6 @@ function resolveHomeFeedMirror(
545
525
  : fallbackConversationId;
546
526
  const sourceScheduleJobId = sourceRow?.scheduleJobId ?? undefined;
547
527
 
548
- // Guardian requests always project into the feed: the "Needs
549
- // attention" item is the request's canonical home, and the request
550
- // blocks on the guardian whatever kind of conversation raised it.
551
- if (isGuardianRequestSignalEvent(signal.sourceEventName)) {
552
- return { mirror: true, sourceConversationId, sourceScheduleJobId };
553
- }
554
- if (isAssistantInitiatedThreadDelivery(fallbackConversationId)) {
555
- return { mirror: false };
556
- }
557
528
  if (
558
529
  signal.sourceChannel === "assistant_tool" ||
559
530
  signal.sourceEventName === "chat.assistant_reply"
@@ -563,37 +534,18 @@ function resolveHomeFeedMirror(
563
534
  if (signal.attentionHints.isAsyncBackground) {
564
535
  return { mirror: true, sourceConversationId, sourceScheduleJobId };
565
536
  }
537
+ // Guardian requests always project into the feed: the "Needs
538
+ // attention" item is the request's canonical home, and the request
539
+ // blocks on the guardian whatever kind of conversation raised it.
540
+ if (isGuardianRequestSignalEvent(signal.sourceEventName)) {
541
+ return { mirror: true, sourceConversationId, sourceScheduleJobId };
542
+ }
566
543
  if (isBackgroundConversationType(sourceRow?.conversationType)) {
567
544
  return { mirror: true, sourceConversationId, sourceScheduleJobId };
568
545
  }
569
546
  return { mirror: false };
570
547
  }
571
548
 
572
- /**
573
- * Whether the vellum delivery this signal produced landed in a thread the
574
- * sidebar's assistant section already shows.
575
- *
576
- * Best-effort like the source lookup above: a missing id, a missing row, or
577
- * a lookup failure all read as "not an assistant thread", so a storage
578
- * hiccup degrades to the pre-existing behavior (a bell row) rather than
579
- * dropping the notification everywhere.
580
- */
581
- function isAssistantInitiatedThreadDelivery(
582
- deliveryConversationId: string | undefined,
583
- ): boolean {
584
- if (!deliveryConversationId) {
585
- return false;
586
- }
587
- try {
588
- return (
589
- getConversation(deliveryConversationId)?.source ===
590
- ASSISTANT_INITIATED_SOURCE
591
- );
592
- } catch {
593
- return false;
594
- }
595
- }
596
-
597
549
  /**
598
550
  * Routing-intent enforcement can prune `selectedChannels` without also
599
551
  * pruning `renderedCopy`, so iterating `renderedCopy` directly risks