@vellumai/assistant 0.12.1-staging.1 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) 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/openapi.yaml +1 -291
  5. package/package.json +1 -1
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  7. package/src/__tests__/app-compiler.test.ts +0 -6
  8. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  9. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  10. package/src/__tests__/app-source-watcher.test.ts +218 -0
  11. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  12. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  13. package/src/__tests__/computer-use-tools.test.ts +5 -17
  14. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  15. package/src/__tests__/config-schema.test.ts +29 -28
  16. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  17. package/src/__tests__/config-watcher.test.ts +8 -23
  18. package/src/__tests__/connection-model-compat.test.ts +2 -2
  19. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  20. package/src/__tests__/conversation-pairing.test.ts +0 -26
  21. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  22. package/src/__tests__/conversation-queue.test.ts +207 -48
  23. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  24. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  25. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  26. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  27. package/src/__tests__/conversation-title-service.test.ts +10 -14
  28. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  29. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  30. package/src/__tests__/credential-record-retire.test.ts +1 -171
  31. package/src/__tests__/credential-routes.test.ts +3 -212
  32. package/src/__tests__/credential-security-invariants.test.ts +1 -2
  33. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  34. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  35. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  36. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  37. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  38. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  39. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  40. package/src/__tests__/host-file-proxy.test.ts +23 -11
  41. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  42. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  43. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  44. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  45. package/src/__tests__/mcp-health-check.test.ts +11 -8
  46. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  47. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  48. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  49. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  51. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  52. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  53. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  54. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  55. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  56. package/src/__tests__/model-intents.test.ts +0 -3
  57. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  58. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  59. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  60. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  61. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  62. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  63. package/src/__tests__/speaker-identification.test.ts +56 -0
  64. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  65. package/src/__tests__/subagent-tools.test.ts +2 -3
  66. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  67. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  68. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  69. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  70. package/src/__tests__/workspace-git-service.test.ts +0 -26
  71. package/src/acp/__tests__/agent-process.test.ts +4 -258
  72. package/src/acp/__tests__/auth-required.test.ts +0 -96
  73. package/src/acp/__tests__/client-handler.test.ts +2 -90
  74. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  75. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  76. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  77. package/src/acp/__tests__/session-manager.test.ts +4 -895
  78. package/src/acp/agent-process.test.ts +1 -4
  79. package/src/acp/agent-process.ts +9 -94
  80. package/src/acp/auth-required.ts +1 -50
  81. package/src/acp/auto-install.test.ts +7 -9
  82. package/src/acp/client-handler.ts +3 -16
  83. package/src/acp/resolve-agent.test.ts +6 -220
  84. package/src/acp/resolve-agent.ts +23 -88
  85. package/src/acp/session-manager.test.ts +3 -196
  86. package/src/acp/session-manager.ts +18 -441
  87. package/src/acp/types.ts +5 -50
  88. package/src/api/events/app-files-changed.ts +3 -4
  89. package/src/api/index.ts +0 -6
  90. package/src/apps/app-store.ts +1 -1
  91. package/src/bundler/app-compiler.ts +0 -15
  92. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  93. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  94. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  95. package/src/calls/call-constants.ts +4 -24
  96. package/src/calls/call-controller.ts +199 -499
  97. package/src/calls/call-transport.ts +0 -16
  98. package/src/calls/media-stream-output.ts +0 -32
  99. package/src/calls/media-stream-server.ts +30 -82
  100. package/src/calls/media-stream-stt-session.ts +0 -15
  101. package/src/calls/resolve-call-tts-provider.ts +2 -33
  102. package/src/calls/speaker-identification.ts +233 -0
  103. package/src/calls/tts-call-strategy.ts +5 -9
  104. package/src/calls/types.ts +0 -2
  105. package/src/calls/voice-control-protocol.ts +21 -53
  106. package/src/calls/voice-session-bridge.ts +46 -59
  107. package/src/calls/voice-triage-escalate.ts +56 -175
  108. package/src/cli/commands/apps.help.ts +13 -67
  109. package/src/cli/commands/apps.ts +0 -183
  110. package/src/cli/commands/channels/index.help.ts +2 -70
  111. package/src/cli/commands/channels/index.ts +3 -16
  112. package/src/cli/commands/credentials.help.ts +2 -6
  113. package/src/cli/commands/credentials.ts +2 -2
  114. package/src/cli/commands/mcp.help.ts +8 -8
  115. package/src/cli/commands/mcp.ts +1 -1
  116. package/src/cli/commands/roadmap.help.ts +1 -5
  117. package/src/cli/commands/roadmap.ts +1 -1
  118. package/src/cli/lib/bundled-marketplace.json +90 -103
  119. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  120. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  121. package/src/config/__tests__/platform-rehydration.test.ts +0 -93
  122. package/src/config/acp-defaults.test.ts +3 -13
  123. package/src/config/acp-defaults.ts +6 -23
  124. package/src/config/acp-schema.ts +2 -30
  125. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  126. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  127. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  128. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  129. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  130. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  131. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  132. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  133. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  134. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  135. package/src/config/default-profile-catalog.ts +1 -1
  136. package/src/config/env.ts +2 -2
  137. package/src/config/feature-flag-registry.json +12 -8
  138. package/src/config/memory-v3-gate.test.ts +0 -31
  139. package/src/config/memory-v3-gate.ts +16 -20
  140. package/src/config/platform-rehydration.ts +21 -75
  141. package/src/config/schema.ts +2 -2
  142. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  143. package/src/config/schemas/calls.ts +28 -1
  144. package/src/config/schemas/live-voice.ts +173 -1
  145. package/src/config/schemas/mcp.ts +1 -1
  146. package/src/config/schemas/memory-retrospective.ts +0 -10
  147. package/src/config/schemas/skills.ts +14 -0
  148. package/src/credential-execution/process-manager.test.ts +19 -18
  149. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  150. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  151. package/src/daemon/app-source-watcher.ts +218 -0
  152. package/src/daemon/config-watcher.ts +194 -13
  153. package/src/daemon/conversation-process.ts +64 -35
  154. package/src/daemon/conversation-skill-tools.ts +31 -13
  155. package/src/daemon/conversation-store.ts +1 -1
  156. package/src/daemon/conversation-surfaces.ts +8 -10
  157. package/src/daemon/conversation-tool-setup.ts +43 -37
  158. package/src/daemon/conversation.ts +3 -0
  159. package/src/daemon/host-bash-proxy.ts +12 -8
  160. package/src/daemon/host-browser-proxy.ts +1 -15
  161. package/src/daemon/host-file-proxy.ts +10 -8
  162. package/src/daemon/host-transfer-proxy.ts +18 -14
  163. package/src/daemon/lifecycle.ts +5 -0
  164. package/src/daemon/mcp-reload-service.ts +5 -5
  165. package/src/daemon/message-types/sync.ts +0 -1
  166. package/src/daemon/providers-setup.ts +1 -1
  167. package/src/daemon/shutdown-handlers.ts +9 -1
  168. package/src/daemon/skill-memory-refresh.ts +0 -64
  169. package/src/daemon/tool-side-effects.ts +18 -7
  170. package/src/hooks/types.ts +0 -33
  171. package/src/inbound/platform-callback-registration.ts +5 -4
  172. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  173. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  174. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  175. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  176. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  177. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  178. package/src/live-voice/live-voice-session.ts +693 -213
  179. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  180. package/src/live-voice/protocol.ts +2 -0
  181. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  182. package/src/mcp/effective-config.ts +3 -3
  183. package/src/mcp/mcp-header-store.ts +45 -29
  184. package/src/mcp/startup.ts +4 -8
  185. package/src/messaging/provider.ts +3 -10
  186. package/src/messaging/providers/callback-routing.ts +0 -18
  187. package/src/messaging/providers/channel-transport.ts +0 -56
  188. package/src/messaging/providers/discord/transport.ts +0 -17
  189. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  190. package/src/messaging/providers/slack/adapter.ts +44 -7
  191. package/src/messaging/providers/slack/transport.ts +0 -16
  192. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  193. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  194. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  195. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  196. package/src/messaging/providers/whatsapp/client.ts +29 -0
  197. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  198. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  199. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  200. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  201. package/src/notifications/assistant-reply-producer.ts +3 -8
  202. package/src/notifications/conversation-pairing.ts +16 -36
  203. package/src/notifications/delivered-post-record.ts +1 -11
  204. package/src/notifications/home-feed-side-effect.ts +7 -55
  205. package/src/outbound-proxy/certs.ts +5 -3
  206. package/src/permissions/checker.test.ts +6 -11
  207. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  208. package/src/persistence/conversation-crud.ts +63 -71
  209. package/src/persistence/conversation-lineage.ts +4 -12
  210. package/src/persistence/conversation-title-service.ts +26 -9
  211. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  212. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  213. package/src/persistence/message-reads.ts +0 -30
  214. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  215. package/src/persistence/schema/memory-core.ts +0 -5
  216. package/src/platform/client.test.ts +0 -2
  217. package/src/platform/client.ts +10 -2
  218. package/src/plugin-api/constants.ts +0 -2
  219. package/src/plugin-api/index.ts +0 -1
  220. package/src/plugin-api/types.ts +0 -2
  221. package/src/plugins/defaults/index.ts +0 -2
  222. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  223. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  224. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  225. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  226. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  227. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  228. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  229. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  230. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  231. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  232. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  233. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  234. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  235. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  236. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  237. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  238. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  239. package/src/plugins/defaults/memory/startup.ts +1 -6
  240. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  241. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  242. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  243. package/src/plugins/defaults/memory/worker.ts +0 -6
  244. package/src/plugins/mcp-servers.ts +75 -15
  245. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  246. package/src/providers/gemini/client.ts +23 -9
  247. package/src/providers/model-catalog.ts +0 -34
  248. package/src/providers/model-intents.ts +5 -10
  249. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  250. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  251. package/src/providers/openai/chat-completions-provider.ts +78 -192
  252. package/src/providers/openai/codex-models.ts +4 -0
  253. package/src/runtime/AGENTS.md +0 -2
  254. package/src/runtime/auth/same-actor.ts +3 -38
  255. package/src/runtime/http-server.ts +151 -160
  256. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  257. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  258. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  259. package/src/runtime/routes/acp-routes.test.ts +0 -15
  260. package/src/runtime/routes/acp-routes.ts +9 -72
  261. package/src/runtime/routes/app-management-routes.ts +0 -73
  262. package/src/runtime/routes/app-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  264. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  265. package/src/runtime/routes/credential-routes.ts +10 -19
  266. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  267. package/src/runtime/routes/index.ts +0 -4
  268. package/src/runtime/routes/log-export-routes.ts +0 -2
  269. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  270. package/src/runtime/routes/migration-routes.ts +21 -8
  271. package/src/runtime/routes/platform-routes.ts +15 -18
  272. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  273. package/src/runtime/services/conversation-serializer.ts +3 -16
  274. package/src/runtime/sync/resource-sync-events.ts +1 -2
  275. package/src/schedule/worker.ts +1 -1
  276. package/src/security/ces-rpc-record-backend.ts +0 -7
  277. package/src/subagent/consult-context.ts +25 -12
  278. package/src/tools/acp/list-agents.test.ts +1 -3
  279. package/src/tools/acp/spawn.test.ts +11 -146
  280. package/src/tools/acp/spawn.ts +3 -21
  281. package/src/tools/acp/status.ts +3 -40
  282. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  283. package/src/tools/capability-offer.test.ts +2 -22
  284. package/src/tools/capability-offer.ts +1 -16
  285. package/src/tools/computer-use/definitions.ts +2 -4
  286. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  287. package/src/tools/credentials/metadata-store.ts +0 -100
  288. package/src/tools/host-filesystem/edit.test.ts +1 -2
  289. package/src/tools/host-filesystem/edit.ts +2 -2
  290. package/src/tools/host-filesystem/read.test.ts +1 -2
  291. package/src/tools/host-filesystem/read.ts +2 -2
  292. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  293. package/src/tools/host-filesystem/transfer.ts +2 -2
  294. package/src/tools/host-filesystem/write.test.ts +1 -2
  295. package/src/tools/host-filesystem/write.ts +2 -2
  296. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  297. package/src/tools/host-terminal/host-shell.ts +20 -4
  298. package/src/tools/policy-context.ts +7 -6
  299. package/src/tools/subagent/spawn.ts +8 -5
  300. package/src/tools/watch/watch-retro-report.ts +8 -0
  301. package/src/util/__tests__/language-subtag.test.ts +1 -23
  302. package/src/util/fs-watcher-error.ts +36 -0
  303. package/src/util/language-subtag.ts +0 -16
  304. package/src/util/platform.ts +0 -8
  305. package/src/workspace/git-service.ts +54 -5
  306. package/src/workspace/migrations/registry.ts +0 -6
  307. package/scripts/smoke-desktop-window-theme.ts +0 -186
  308. package/src/__tests__/git-porcelain.test.ts +0 -47
  309. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  310. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  311. package/src/__tests__/resolve-app.test.ts +0 -135
  312. package/src/__tests__/source-fingerprint.test.ts +0 -184
  313. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  314. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  315. package/src/acp/model-config.test.ts +0 -166
  316. package/src/acp/model-config.ts +0 -138
  317. package/src/api/events/acp-session-model-update.test.ts +0 -88
  318. package/src/api/events/acp-session-model-update.ts +0 -46
  319. package/src/apps/resolve-app.ts +0 -81
  320. package/src/apps/source-fingerprint.ts +0 -266
  321. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  322. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  323. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  324. package/src/calls/barge-in-guard.ts +0 -118
  325. package/src/calls/voice-leg-coordinator.ts +0 -189
  326. package/src/calls/voice-progress-cadence.ts +0 -423
  327. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  328. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  329. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  330. package/src/cli/commands/channels/send.ts +0 -128
  331. package/src/config/__tests__/platform-identity.test.ts +0 -117
  332. package/src/config/acp-agent-write.ts +0 -43
  333. package/src/config/acp-schema.test.ts +0 -81
  334. package/src/config/platform-identity.ts +0 -144
  335. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  336. package/src/config/schemas/voice.ts +0 -150
  337. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  338. package/src/daemon/app-change-notify.ts +0 -45
  339. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  340. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  341. package/src/desktop/desktop-chrome-policy.ts +0 -42
  342. package/src/desktop/desktop-dependencies.test.ts +0 -102
  343. package/src/desktop/desktop-dependencies.ts +0 -306
  344. package/src/desktop/desktop-feature.test.ts +0 -18
  345. package/src/desktop/desktop-feature.ts +0 -19
  346. package/src/desktop/desktop-panel-config.test.ts +0 -135
  347. package/src/desktop/desktop-panel-config.ts +0 -149
  348. package/src/desktop/desktop-session-manager.test.ts +0 -627
  349. package/src/desktop/desktop-session-manager.ts +0 -814
  350. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  351. package/src/desktop/desktop-stream-bridge.ts +0 -214
  352. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  353. package/src/desktop/desktop-wallpaper.ts +0 -113
  354. package/src/desktop/desktop-window-theme.ts +0 -170
  355. package/src/i18n/AGENTS.md +0 -22
  356. package/src/i18n/__tests__/i18n.test.ts +0 -108
  357. package/src/i18n/index.ts +0 -16
  358. package/src/i18n/locales.ts +0 -93
  359. package/src/i18n/messages.ts +0 -61
  360. package/src/i18n/title.ts +0 -25
  361. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  362. package/src/mcp/spec-schema.ts +0 -111
  363. package/src/mcp/workspace-mcp-config.ts +0 -188
  364. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  365. package/src/persistence/conversation-title-placeholders.ts +0 -23
  366. package/src/persistence/message-cursor.ts +0 -78
  367. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  368. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  369. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  370. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  371. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  372. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  373. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  374. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  375. package/src/providers/gemini-thought-signature.test.ts +0 -63
  376. package/src/providers/gemini-thought-signature.ts +0 -44
  377. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  378. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  379. package/src/providers/openai/google-thought-signature.ts +0 -320
  380. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  381. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  382. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  383. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  384. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  385. package/src/runtime/channel-send.ts +0 -316
  386. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  387. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  388. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  389. package/src/runtime/routes/channel-send-routes.ts +0 -85
  390. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  391. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  392. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  393. package/src/security/ces-http-record-backend.ts +0 -120
  394. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  395. package/src/skills/workspace-skill-md-signature.ts +0 -50
  396. package/src/tools/acp/status.test.ts +0 -94
  397. package/src/util/ca-bundle.ts +0 -13
  398. package/src/workspace/git-porcelain.ts +0 -66
  399. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  400. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  401. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  402. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  403. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  404. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -1,5 +1,4 @@
1
1
  import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
- import { tableExists } from "./schema-introspection.js";
3
2
 
4
3
  /**
5
4
  * Add a required contact_id column to assistant_ingress_invites.
@@ -11,16 +10,8 @@ import { tableExists } from "./schema-introspection.js";
11
10
  * 1. Add the column as nullable.
12
11
  * 2. Delete legacy rows that have no contact binding (NULL).
13
12
  * 3. Rebuild the table to enforce NOT NULL (SQLite cannot ALTER COLUMN).
14
- *
15
- * The rebuild copies whichever session-id column is live:
16
- * `source_conversation_id` (after migrateRenameCreatedBySessionIdColumns)
17
- * or `created_by_session_id`.
18
13
  */
19
14
  export function migrateInviteContactId(database: DrizzleDb): void {
20
- if (!tableExists(database, "assistant_ingress_invites")) {
21
- return;
22
- }
23
-
24
15
  const raw = getSqliteFrom(database);
25
16
 
26
17
  const cols = (
@@ -29,28 +20,25 @@ export function migrateInviteContactId(database: DrizzleDb): void {
29
20
  notnull: number;
30
21
  }>
31
22
  ).map((c) => ({ name: c.name, notnull: c.notnull }));
32
- const colNames = new Set(cols.map((c) => c.name));
33
23
 
34
24
  const col = cols.find((c) => c.name === "contact_id");
35
25
 
26
+ // Step 1: Add the column as nullable
36
27
  if (!col) {
37
28
  raw.exec(
38
29
  /*sql*/ `ALTER TABLE assistant_ingress_invites ADD COLUMN contact_id TEXT`,
39
30
  );
40
31
  }
41
32
 
33
+ // Step 2: Delete legacy rows with no contact binding
42
34
  raw.exec(
43
35
  /*sql*/ `DELETE FROM assistant_ingress_invites WHERE contact_id IS NULL OR contact_id = ''`,
44
36
  );
45
37
 
38
+ // Step 3: Rebuild the table with NOT NULL on contact_id
46
39
  if (col && col.notnull === 1) {
47
40
  return;
48
- }
49
-
50
- const sessionCol = colNames.has("source_conversation_id")
51
- ? "source_conversation_id"
52
- : "created_by_session_id";
53
- const sessionSelect = colNames.has(sessionCol) ? sessionCol : "NULL";
41
+ } // already NOT NULL
54
42
 
55
43
  raw.exec("PRAGMA foreign_keys = OFF");
56
44
  try {
@@ -61,7 +49,7 @@ export function migrateInviteContactId(database: DrizzleDb): void {
61
49
  id TEXT PRIMARY KEY,
62
50
  source_channel TEXT NOT NULL,
63
51
  token_hash TEXT NOT NULL,
64
- ${sessionCol} TEXT,
52
+ created_by_session_id TEXT,
65
53
  note TEXT,
66
54
  max_uses INTEGER NOT NULL DEFAULT 1 CHECK (max_uses > 0),
67
55
  use_count INTEGER NOT NULL DEFAULT 0 CHECK (use_count >= 0),
@@ -82,7 +70,7 @@ export function migrateInviteContactId(database: DrizzleDb): void {
82
70
  );
83
71
 
84
72
  INSERT INTO assistant_ingress_invites_new
85
- SELECT id, source_channel, token_hash, ${sessionSelect}, note,
73
+ SELECT id, source_channel, token_hash, created_by_session_id, note,
86
74
  max_uses, use_count, expires_at, status,
87
75
  redeemed_by_external_user_id, redeemed_by_external_chat_id,
88
76
  redeemed_at, expected_external_user_id, voice_code_hash,
@@ -104,11 +104,6 @@ export const memoryRetrospectiveState = sqliteTable(
104
104
  conversationId: text("conversation_id").primaryKey(),
105
105
  lastProcessedMessageId: text("last_processed_message_id").notNull(),
106
106
  lastRunAt: integer("last_run_at").notNull(),
107
- // `createdAt` of the `last_processed_message_id` row when the pointer was
108
- // written, so the cursor still bounds reads after that row is deleted.
109
- // NULL when unknown. Added lazily by `ensureRetrospectiveCursorColumn`
110
- // (memory-retrospective-state.ts), not by the migration chain.
111
- lastProcessedCreatedAt: integer("last_processed_created_at"),
112
107
  // JSON array of strings — cumulative `remember` contents from prior
113
108
  // retrospective passes (capped; see memory-retrospective-state.ts).
114
109
  // NULL for rows that predate migration 281 or have no saves yet.
@@ -24,9 +24,7 @@ mock.module("../providers/platform-proxy/context.js", () => ({
24
24
  resolveManagedProxyContext: () => mockResolveManagedProxyContext(),
25
25
  }));
26
26
 
27
- const actualEnv = await import("../config/env.js");
28
27
  mock.module("../config/env.js", () => ({
29
- ...actualEnv,
30
28
  getPlatformAssistantId: () => mockAssistantId,
31
29
  }));
32
30
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  import type { PlatformCredentialVerificationStatus } from "@vellumai/service-contracts/platform-credential";
9
9
 
10
- import { resolvePlatformAssistantId } from "../config/platform-identity.js";
10
+ import { getPlatformAssistantId } from "../config/env.js";
11
11
  import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js";
12
12
  import { credentialKey } from "../security/credential-key.js";
13
13
  import { getSecureKeyAsync } from "../security/secure-keys.js";
@@ -63,7 +63,7 @@ async function resolvePlatformClientConfig(): Promise<PlatformClientConfig | nul
63
63
 
64
64
  let baseUrl = ctx.enabled ? ctx.platformBaseUrl : "";
65
65
  let apiKey = ctx.enabled ? ctx.assistantApiKey : "";
66
- const assistantId = await resolvePlatformAssistantId();
66
+ let assistantId = getPlatformAssistantId();
67
67
 
68
68
  // Fall back to credential store for values not yet rehydrated (standalone CLI).
69
69
  if (!baseUrl) {
@@ -76,6 +76,14 @@ async function resolvePlatformClientConfig(): Promise<PlatformClientConfig | nul
76
76
  (await getSecureKeyAsync(credentialKey("vellum", "assistant_api_key"))) ??
77
77
  "";
78
78
  }
79
+ if (!assistantId) {
80
+ assistantId =
81
+ (
82
+ await getSecureKeyAsync(
83
+ credentialKey("vellum", "platform_assistant_id"),
84
+ )
85
+ )?.trim() ?? "";
86
+ }
79
87
 
80
88
  if (!baseUrl || !apiKey) {
81
89
  const level = _missingPrereqsWarned ? "debug" : "warn";
@@ -34,8 +34,6 @@ export const HOOKS = {
34
34
  CONVERSATION_DELETED: "conversation-deleted",
35
35
  /** Fires once when every conversation is wiped at once (the clear-all reset), after the main tables are cleared. Carries no `conversationId`; cleanup hooks wipe their own per-conversation state wholesale. */
36
36
  CONVERSATIONS_CLEARED: "conversations-cleared",
37
- /** Fires once per deleted message row, after the row is removed, carrying the row's `(createdAt, id)` so a hook can settle state that pointed at it. Fire-and-forget cleanup signal, like `conversation-deleted`; whole-conversation deletes dispatch that hook instead. */
38
- MESSAGE_DELETED: "message-deleted",
39
37
  } as const;
40
38
 
41
39
  /** Union of every hook name declared in {@link HOOKS}. */
@@ -110,7 +110,6 @@ export type {
110
110
  HookBroadcast,
111
111
  HookFunction,
112
112
  InitContext,
113
- MessageDeletedContext,
114
113
  ModelProfileInfo,
115
114
  PluginLogger,
116
115
  PostCompactContext,
@@ -16,7 +16,6 @@ export type {
16
16
  ConversationDeletedContext,
17
17
  ConversationsClearedContext,
18
18
  HookBroadcast,
19
- MessageDeletedContext,
20
19
  PluginLogger,
21
20
  PostCompactContext,
22
21
  PostModelCallContext,
@@ -61,7 +60,6 @@ export type {
61
60
  * - `post-model-call` — {@link PostModelCallContext}
62
61
  * - `conversation-deleted` — {@link ConversationDeletedContext}
63
62
  * - `conversations-cleared` — {@link ConversationsClearedContext}
64
- * - `message-deleted`: {@link MessageDeletedContext}
65
63
  */
66
64
  export type HookFunction<TCtx = unknown> = (
67
65
  ctx: TCtx,
@@ -65,7 +65,6 @@ import maxTokensContinuePkg from "./max-tokens-continue/package.json" with { typ
65
65
  import memoryConversationDeleted from "./memory/hooks/conversation-deleted.js";
66
66
  import memoryConversationsCleared from "./memory/hooks/conversations-cleared.js";
67
67
  import memoryInit from "./memory/hooks/init.js";
68
- import memoryMessageDeleted from "./memory/hooks/message-deleted.js";
69
68
  import memoryPostCompact from "./memory/hooks/post-compact.js";
70
69
  import memoryShutdown from "./memory/hooks/shutdown.js";
71
70
  import memoryUserPromptSubmit from "./memory/hooks/user-prompt-submit.js";
@@ -200,7 +199,6 @@ export const defaultMemoryPlugin: Plugin = {
200
199
  "post-compact": memoryPostCompact,
201
200
  "conversation-deleted": memoryConversationDeleted,
202
201
  "conversations-cleared": memoryConversationsCleared,
203
- "message-deleted": memoryMessageDeleted,
204
202
  },
205
203
  injectors: memoryInjectors,
206
204
  };
@@ -434,49 +434,3 @@ describe("ambient camera frames are not retrospective work", () => {
434
434
  expect(hasQualifyingUserMessageAfter(CONV, null)).toBe(true);
435
435
  });
436
436
  });
437
-
438
- describe("retrospective accounting: a cursor survives its row's deletion", () => {
439
- beforeEach(() => {
440
- const db = getDb();
441
- db.run(`DELETE FROM messages`);
442
- db.run(`DELETE FROM conversations`);
443
- createConversation({ id: CONV });
444
- });
445
-
446
- test("a deleted cursor row with a stored timestamp still bounds the count, the slice, and the user-activity probe", () => {
447
- insertRaw({ role: "user", content: TEXT, createdAt: 1_000 });
448
- const reply = insertRaw({
449
- role: "assistant",
450
- content: TEXT,
451
- createdAt: 2_000,
452
- });
453
- // Regenerate: the reply the cursor sits on is discarded and replaced.
454
- getDb().delete(messages).where(eq(messages.id, reply)).run();
455
- const regenerated = insertRaw({
456
- role: "assistant",
457
- content: TEXT,
458
- createdAt: 3_000,
459
- });
460
- const followUp = insertRaw({
461
- role: "user",
462
- content: TEXT,
463
- createdAt: 4_000,
464
- });
465
-
466
- const cursor = { id: reply, createdAt: 2_000 };
467
- expect(countRetrospectiveMessagesAfter(CONV, cursor)).toBe(2);
468
- expect(
469
- getRetrospectiveMessagesAfter(CONV, cursor).map((r) => r.id),
470
- ).toEqual([regenerated, followUp]);
471
- expect(hasQualifyingUserMessageAfter(CONV, cursor)).toBe(true);
472
- });
473
-
474
- test("a deleted cursor row without a timestamp still reads as no new work", () => {
475
- insertRaw({ role: "user", content: TEXT, createdAt: 1_000 });
476
-
477
- const cursor = { id: "gone", createdAt: null };
478
- expect(countRetrospectiveMessagesAfter(CONV, cursor)).toBe(0);
479
- expect(getRetrospectiveMessagesAfter(CONV, cursor)).toEqual([]);
480
- expect(hasQualifyingUserMessageAfter(CONV, cursor)).toBe(false);
481
- });
482
- });
@@ -1,7 +1,5 @@
1
1
  import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
- import type { MessagesAfterRef } from "../../../../persistence/message-cursor.js";
4
-
5
3
  // ---------------------------------------------------------------------------
6
4
  // Mock state — reset between tests.
7
5
  // ---------------------------------------------------------------------------
@@ -19,7 +17,6 @@ let cfgThrows = false;
19
17
  let mockStateRow: {
20
18
  conversationId: string;
21
19
  lastProcessedMessageId: string;
22
- lastProcessedCreatedAt: number | null;
23
20
  lastRunAt: number;
24
21
  rememberedLog: string[];
25
22
  } | null = null;
@@ -27,7 +24,7 @@ let tailQualifies = true;
27
24
  let gateProbeThrows = false;
28
25
  let gateProbeCalls: Array<{
29
26
  conversationId: string;
30
- after: MessagesAfterRef;
27
+ afterMessageId: string | null;
31
28
  }> = [];
32
29
 
33
30
  mock.module("../../../../persistence/conversation-crud.js", () => ({
@@ -71,9 +68,9 @@ mock.module("../memory-retrospective-state.js", () => ({
71
68
  mock.module("../memory-retrospective-accounting.js", () => ({
72
69
  hasQualifyingUserMessageAfter: (
73
70
  conversationId: string,
74
- after: MessagesAfterRef,
71
+ afterMessageId: string | null,
75
72
  ) => {
76
- gateProbeCalls.push({ conversationId, after });
73
+ gateProbeCalls.push({ conversationId, afterMessageId });
77
74
  if (gateProbeThrows) {
78
75
  throw new Error("messages table unavailable");
79
76
  }
@@ -173,11 +170,10 @@ describe("enqueueMemoryRetrospectiveIfEnabled", () => {
173
170
  expect(gateProbeCalls).toHaveLength(0);
174
171
  });
175
172
 
176
- test("gate probes the tail from the state row's cursor, timestamp included", () => {
173
+ test("gate probes the tail from the state row's cursor", () => {
177
174
  mockStateRow = {
178
175
  conversationId: "c1",
179
176
  lastProcessedMessageId: "m9",
180
- lastProcessedCreatedAt: 9_000,
181
177
  lastRunAt: 1,
182
178
  rememberedLog: [],
183
179
  };
@@ -187,7 +183,7 @@ describe("enqueueMemoryRetrospectiveIfEnabled", () => {
187
183
  });
188
184
 
189
185
  expect(gateProbeCalls).toEqual([
190
- { conversationId: "c1", after: { id: "m9", createdAt: 9_000 } },
186
+ { conversationId: "c1", afterMessageId: "m9" },
191
187
  ]);
192
188
  });
193
189
 
@@ -20,7 +20,6 @@ let mockState: StateRow = null;
20
20
  let stateUpserts: Array<{
21
21
  conversationId: string;
22
22
  lastProcessedMessageId: string;
23
- lastProcessedCreatedAt?: number | null;
24
23
  lastRunAt: number;
25
24
  rememberedLog?: string[];
26
25
  }> = [];
@@ -150,7 +149,6 @@ mock.module("../memory-retrospective-state.js", () => ({
150
149
  upsertRetrospectiveState: (args: {
151
150
  conversationId: string;
152
151
  lastProcessedMessageId: string;
153
- lastProcessedCreatedAt?: number | null;
154
152
  lastRunAt: number;
155
153
  rememberedLog?: string[];
156
154
  }) => {
@@ -334,16 +332,15 @@ mock.module("../../../../persistence/jobs-store.js", () => ({
334
332
  },
335
333
  }));
336
334
 
337
- // Retrospective skill improvement is distinct from the v3 tier. Keep v3 live
338
- // while flipping the authoring gate so these tests prove the job reads the
339
- // dedicated predicate rather than using the broader tier predicate.
340
- let mockV3TierActive = true;
341
- let mockSkillImprovementActive = false;
335
+ // The v3-tier gate. Drives both `buildForkInstruction`'s skill-authoring
336
+ // section (proc-to-skills) and the wake's origin pin behavior. Default inactive
337
+ // (remember-only), matching a stock install; tests flip it on to assert the
338
+ // authoring section.
339
+ let mockV3TierActive = false;
342
340
  mock.module("../../../../config/memory-v3-gate.js", () => ({
343
341
  isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
344
342
  config?.memory?.enabled !== false,
345
343
  isV3TierActive: () => mockV3TierActive,
346
- isSkillImprovementActive: () => mockSkillImprovementActive,
347
344
  isMemoryV3Live: () => mockV3TierActive,
348
345
  usesConceptPageMemory: (memory?: {
349
346
  enabled?: boolean;
@@ -507,8 +504,7 @@ describe("memoryRetrospectiveJob", () => {
507
504
  processingStartedAtById = {};
508
505
  mockResolvedUserSlug = "alice";
509
506
  resolveUserSlugCalls = [];
510
- mockV3TierActive = true;
511
- mockSkillImprovementActive = false;
507
+ mockV3TierActive = false;
512
508
  });
513
509
 
514
510
  test("first-run happy path: no state row, no prior retrospective, both pointer fields set on success", async () => {
@@ -522,11 +518,6 @@ describe("memoryRetrospectiveJob", () => {
522
518
  }
523
519
  expect(stateUpserts).toHaveLength(1);
524
520
  expect(stateUpserts[0]!.lastProcessedMessageId).toBe("m3");
525
- // The cutoff's `createdAt` rides along so the cursor keeps bounding reads
526
- // after a regenerate deletes m3.
527
- expect(stateUpserts[0]!.lastProcessedCreatedAt).toBe(
528
- Date.parse("2026-05-11T10:10:00Z"),
529
- );
530
521
  expect(lastRunAtBumps).toHaveLength(0);
531
522
  expect(wakeCalls).toHaveLength(1);
532
523
  // Forks off the source so future runs can find it via
@@ -1317,7 +1308,7 @@ describe("memoryRetrospectiveJob", () => {
1317
1308
  });
1318
1309
 
1319
1310
  test("wake allows memory saves + skill authoring and suppresses the internal wake surface", async () => {
1320
- mockSkillImprovementActive = true;
1311
+ mockV3TierActive = true;
1321
1312
  await memoryRetrospectiveJob(makeJob(), stubConfig);
1322
1313
 
1323
1314
  expect(forkCalls).toHaveLength(1);
@@ -1340,9 +1331,8 @@ describe("memoryRetrospectiveJob", () => {
1340
1331
  expect(opts.hintRole).toBe("user");
1341
1332
  });
1342
1333
 
1343
- test("wake is remember-only when skill improvement is disabled on a live v3 tier", async () => {
1344
- mockV3TierActive = true;
1345
- mockSkillImprovementActive = false;
1334
+ test("wake is remember-only when proc-to-skills is inactive", async () => {
1335
+ mockV3TierActive = false;
1346
1336
  await memoryRetrospectiveJob(makeJob(), stubConfig);
1347
1337
 
1348
1338
  expect(wakeCalls).toHaveLength(1);
@@ -2548,7 +2538,7 @@ describe("memoryRetrospectiveJob", () => {
2548
2538
  });
2549
2539
 
2550
2540
  test("proc-to-skills active: instruction carries the pre-check + dedup + companion-file directives", async () => {
2551
- mockSkillImprovementActive = true;
2541
+ mockV3TierActive = true;
2552
2542
 
2553
2543
  await memoryRetrospectiveJob(makeJob(), stubConfig);
2554
2544
 
@@ -6,22 +6,16 @@ import { setConfig } from "../../../../__tests__/helpers/set-config.js";
6
6
  // pipeline (both flags default true under the real loader).
7
7
  setConfig("memory", { enabled: false, v2: { enabled: false } });
8
8
 
9
- import { createConversation } from "../../../../persistence/conversation-crud.js";
10
9
  import {
11
10
  getDb,
12
11
  getMemorySqlite,
13
- resetDb,
14
12
  } from "../../../../persistence/db-connection.js";
15
13
  import { initializeDb } from "../../../../persistence/db-init.js";
16
- import { messages } from "../../../../persistence/schema/index.js";
17
14
  import {
18
- _resetRetrospectiveCursorColumnForTests,
19
15
  appendToRememberedLog,
20
16
  bumpRetrospectiveLastRunAt,
21
- ensureRetrospectiveCursorColumn,
22
17
  forkRetrospectiveState,
23
18
  getRetrospectiveState,
24
- listRetrospectiveStates,
25
19
  REMEMBERED_LOG_MAX_BYTES,
26
20
  REMEMBERED_LOG_MAX_ENTRIES,
27
21
  upsertRetrospectiveState,
@@ -182,219 +176,6 @@ describe("memory-retrospective-state remembered log persistence", () => {
182
176
  });
183
177
  });
184
178
 
185
- describe("memory-retrospective-state cursor timestamp", () => {
186
- beforeEach(() => {
187
- resetTables();
188
- });
189
-
190
- test("upsert persists lastProcessedCreatedAt and both reads return it", async () => {
191
- await upsertRetrospectiveState({
192
- conversationId: "conv-ts",
193
- lastProcessedMessageId: "m1",
194
- lastProcessedCreatedAt: 1_234,
195
- lastRunAt: 1000,
196
- });
197
-
198
- expect(getRetrospectiveState("conv-ts")?.lastProcessedCreatedAt).toBe(
199
- 1_234,
200
- );
201
- expect(
202
- listRetrospectiveStates(10).find((s) => s.conversationId === "conv-ts")
203
- ?.lastProcessedCreatedAt,
204
- ).toBe(1_234);
205
- });
206
-
207
- test("an upsert that omits the timestamp records unknown for the new pointer", async () => {
208
- await upsertRetrospectiveState({
209
- conversationId: "conv-ts",
210
- lastProcessedMessageId: "m1",
211
- lastProcessedCreatedAt: 1_234,
212
- lastRunAt: 1000,
213
- });
214
- await upsertRetrospectiveState({
215
- conversationId: "conv-ts",
216
- lastProcessedMessageId: "m2",
217
- lastRunAt: 2000,
218
- });
219
-
220
- const state = getRetrospectiveState("conv-ts");
221
- expect(state?.lastProcessedMessageId).toBe("m2");
222
- expect(state?.lastProcessedCreatedAt).toBeNull();
223
- });
224
-
225
- test("bumpRetrospectiveLastRunAt leaves the timestamp untouched", async () => {
226
- await upsertRetrospectiveState({
227
- conversationId: "conv-ts",
228
- lastProcessedMessageId: "m1",
229
- lastProcessedCreatedAt: 1_234,
230
- lastRunAt: 1000,
231
- });
232
- await bumpRetrospectiveLastRunAt("conv-ts", 5000);
233
-
234
- const state = getRetrospectiveState("conv-ts");
235
- expect(state?.lastRunAt).toBe(5000);
236
- expect(state?.lastProcessedCreatedAt).toBe(1_234);
237
- });
238
-
239
- test("forking carries the forked pointer's createdAt, read through the main handle", async () => {
240
- const db = getDb();
241
- createConversation({ id: "conv-fork-ts-src" });
242
- createConversation({ id: "conv-fork-ts-dst" });
243
- for (const [id, conversationId] of [
244
- ["src-m1", "conv-fork-ts-src"],
245
- ["dst-m1", "conv-fork-ts-dst"],
246
- ] as const) {
247
- db.insert(messages)
248
- .values({
249
- id,
250
- conversationId,
251
- role: "user",
252
- content: "[]",
253
- createdAt: 4_000,
254
- metadata: null,
255
- })
256
- .run();
257
- }
258
- await upsertRetrospectiveState({
259
- conversationId: "conv-fork-ts-src",
260
- lastProcessedMessageId: "src-m1",
261
- lastProcessedCreatedAt: 4_000,
262
- lastRunAt: 1,
263
- });
264
-
265
- forkRetrospectiveState({
266
- database: db,
267
- sourceConversationId: "conv-fork-ts-src",
268
- forkedConversationId: "conv-fork-ts-dst",
269
- forkedMessageIds: new Map([["src-m1", "dst-m1"]]),
270
- lastCopiedSourceMessageId: "src-m1",
271
- });
272
-
273
- const child = getRetrospectiveState("conv-fork-ts-dst");
274
- expect(child?.lastProcessedMessageId).toBe("dst-m1");
275
- expect(child?.lastProcessedCreatedAt).toBe(4_000);
276
-
277
- db.run(`DELETE FROM messages`);
278
- db.run(`DELETE FROM conversations`);
279
- });
280
-
281
- test("a source cursor whose row was regenerated away is placed by its stored bound, not clamped past the copies", async () => {
282
- const db = getDb();
283
- createConversation({ id: "conv-fork-bound-src" });
284
- createConversation({ id: "conv-fork-bound-dst" });
285
- // src-m2 (createdAt 2_000) was the cursor; a regenerate deleted it and
286
- // src-m3 replaced it. The fork copies src-m1 and src-m3.
287
- for (const [id, conversationId, createdAt] of [
288
- ["src-m1", "conv-fork-bound-src", 1_000],
289
- ["src-m3", "conv-fork-bound-src", 3_000],
290
- ["dst-m1", "conv-fork-bound-dst", 1_000],
291
- ["dst-m3", "conv-fork-bound-dst", 3_000],
292
- ] as const) {
293
- db.insert(messages)
294
- .values({
295
- id,
296
- conversationId,
297
- role: "user",
298
- content: "[]",
299
- createdAt,
300
- metadata: null,
301
- })
302
- .run();
303
- }
304
- await upsertRetrospectiveState({
305
- conversationId: "conv-fork-bound-src",
306
- lastProcessedMessageId: "src-m2",
307
- lastProcessedCreatedAt: 2_000,
308
- lastRunAt: 1,
309
- });
310
-
311
- forkRetrospectiveState({
312
- database: db,
313
- sourceConversationId: "conv-fork-bound-src",
314
- forkedConversationId: "conv-fork-bound-dst",
315
- forkedMessageIds: new Map([
316
- ["src-m1", "dst-m1"],
317
- ["src-m3", "dst-m3"],
318
- ]),
319
- lastCopiedSourceMessageId: "src-m3",
320
- });
321
-
322
- const child = getRetrospectiveState("conv-fork-bound-dst");
323
- expect(child?.lastProcessedMessageId).toBe("dst-m1");
324
- expect(child?.lastProcessedCreatedAt).toBe(1_000);
325
-
326
- // A bound before every copied row leaves the child with nothing processed.
327
- await upsertRetrospectiveState({
328
- conversationId: "conv-fork-bound-src",
329
- lastProcessedMessageId: "src-m0",
330
- lastProcessedCreatedAt: 500,
331
- lastRunAt: 1,
332
- });
333
- forkRetrospectiveState({
334
- database: db,
335
- sourceConversationId: "conv-fork-bound-src",
336
- forkedConversationId: "conv-fork-bound-dst",
337
- forkedMessageIds: new Map([
338
- ["src-m1", "dst-m1"],
339
- ["src-m3", "dst-m3"],
340
- ]),
341
- lastCopiedSourceMessageId: "src-m3",
342
- });
343
- expect(
344
- getRetrospectiveState("conv-fork-bound-dst")?.lastProcessedMessageId,
345
- ).toBe("");
346
-
347
- db.run(`DELETE FROM messages`);
348
- db.run(`DELETE FROM conversations`);
349
- });
350
-
351
- test("ensureRetrospectiveCursorColumn adds the column to a legacy table once and is a no-op after", () => {
352
- const raw = getMemorySqlite()!;
353
- raw.exec("DROP TABLE memory_retrospective_state");
354
- raw.exec(`
355
- CREATE TABLE memory_retrospective_state (
356
- conversation_id TEXT PRIMARY KEY,
357
- last_processed_message_id TEXT NOT NULL,
358
- last_run_at INTEGER NOT NULL,
359
- remembered_log TEXT
360
- )
361
- `);
362
- _resetRetrospectiveCursorColumnForTests();
363
-
364
- expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
365
- expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
366
-
367
- const columns = raw
368
- .query("PRAGMA table_info(memory_retrospective_state)")
369
- .all() as Array<{ name: string }>;
370
- expect(
371
- columns.filter((c) => c.name === "last_processed_created_at"),
372
- ).toHaveLength(1);
373
- });
374
-
375
- test("a replaced memory connection is probed again, so a restored database without the column gets it", () => {
376
- expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
377
-
378
- // What a restore or import does: the stored connections are dropped and
379
- // reopened. Strip the column on the reopened file to stand in for an
380
- // older database.
381
- resetDb();
382
- const reopened = getMemorySqlite()!;
383
- reopened.exec(
384
- "ALTER TABLE memory_retrospective_state DROP COLUMN last_processed_created_at",
385
- );
386
-
387
- expect(getRetrospectiveState("conv-none")).toBeNull();
388
- expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
389
- const columns = reopened
390
- .query("PRAGMA table_info(memory_retrospective_state)")
391
- .all() as Array<{ name: string }>;
392
- expect(columns.some((c) => c.name === "last_processed_created_at")).toBe(
393
- true,
394
- );
395
- });
396
- });
397
-
398
179
  describe("fail-soft when the underlying statement fails", () => {
399
180
  // The memory connection is present, but the relocated table is gone (a
400
181
  // corrupt/dropped table, SQLITE_FULL, I/O error, or SQLITE_BUSY after
@@ -412,34 +412,3 @@ describe("listSweepCandidateConversationIds", () => {
412
412
  ]);
413
413
  });
414
414
  });
415
-
416
- describe("runRetrospectiveSweep: cursor survives a regenerated reply", () => {
417
- beforeEach(() => {
418
- resetTables();
419
- enqueueCalls = [];
420
- enqueueDeclines = new Set();
421
- });
422
-
423
- test("a stale conversation whose cursor row was regenerated away is still swept", async () => {
424
- const conv = createConversation({ id: "conv-a" });
425
- insertMessage(conv.id, { createdAt: 1_000 });
426
- const reply = insertMessage(conv.id, {
427
- role: "assistant",
428
- createdAt: 2_000,
429
- });
430
- await upsertRetrospectiveState({
431
- conversationId: conv.id,
432
- lastProcessedMessageId: reply,
433
- lastProcessedCreatedAt: 2_000,
434
- lastRunAt: Date.now() - SWEEP_INTERVAL_MS - 60_000,
435
- });
436
- getDb().delete(messages).where(eq(messages.id, reply)).run();
437
- insertMessage(conv.id, { role: "assistant", createdAt: 3_000 });
438
-
439
- await runRetrospectiveSweep(makeConfig());
440
-
441
- expect(enqueueCalls).toEqual([
442
- { conversationId: conv.id, trigger: "sweep" },
443
- ]);
444
- });
445
- });