@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,95 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- // The addressing capability resolves a named chat into exactly what each
3
- // transport's own operations read: the callback URL `channelForCallback`
4
- // resolves and the params `deliver` consumes. Resolution is local, so these
5
- // assertions make no platform call; the tests import the transports'
6
- // modules, which pull in their provider-API senders, so the senders'
7
- // credential lookups are stubbed to keep the import inert.
8
- import { mock } from "bun:test";
9
-
10
- const actualSecureKeys = await import("../../../security/secure-keys.js");
11
- mock.module("../../../security/secure-keys.js", () => ({
12
- ...actualSecureKeys,
13
- getSecureKeyAsync: async () => null,
14
- getSecureKeyResultAsync: async () => ({ value: null }),
15
- }));
16
-
17
- const { channelForCallback } = await import("../callback-routing.js");
18
- const { discordTransport } = await import("../discord/transport.js");
19
- const { slackTransport } = await import("../slack/transport.js");
20
- const { telegramTransport } = await import("../telegram-bot/transport.js");
21
- const { whatsappTransport } = await import("../whatsapp/transport.js");
22
-
23
- describe("addressFor resolves to the channel's own routing state", () => {
24
- test("slack: a chat, optionally under a thread", () => {
25
- const room = slackTransport.addressFor!({ kind: "chat", chatId: "C123" });
26
- expect(room).toEqual({
27
- ctx: { callbackUrl: "/deliver/slack", params: {} },
28
- chatId: "C123",
29
- });
30
- const thread = slackTransport.addressFor!({
31
- kind: "chat",
32
- chatId: "C123",
33
- threadId: "1690000000.000001",
34
- });
35
- expect(thread).toEqual({
36
- ctx: {
37
- callbackUrl: "/deliver/slack?threadTs=1690000000.000001",
38
- params: { threadTs: "1690000000.000001" },
39
- },
40
- chatId: "C123",
41
- threadId: "1690000000.000001",
42
- });
43
- expect(channelForCallback(thread!.ctx.callbackUrl)).toBe("slack");
44
- });
45
-
46
- test("telegram: a chat with a topic; binds on send", () => {
47
- expect(
48
- telegramTransport.addressFor!({
49
- kind: "chat",
50
- chatId: "123",
51
- threadId: "42",
52
- }),
53
- ).toEqual({
54
- ctx: {
55
- callbackUrl: "/deliver/telegram?threadId=42",
56
- params: { threadId: "42" },
57
- },
58
- chatId: "123",
59
- threadId: "42",
60
- });
61
- expect(telegramTransport.bindsChatOnProactiveSend).toBe(true);
62
- });
63
-
64
- test("discord: a chat with a thread, which is its own channel", () => {
65
- const thread = discordTransport.addressFor!({
66
- kind: "chat",
67
- chatId: "C1",
68
- threadId: "T1",
69
- });
70
- expect(thread).toEqual({
71
- ctx: {
72
- callbackUrl: "/deliver/discord?threadId=T1",
73
- params: { threadId: "T1" },
74
- },
75
- chatId: "C1",
76
- threadId: "T1",
77
- });
78
- expect(channelForCallback(thread!.ctx.callbackUrl)).toBe("discord");
79
- expect(discordTransport.bindsChatOnProactiveSend).toBeUndefined();
80
- });
81
-
82
- test("whatsapp: the number is the chat; no threads; binds on send", () => {
83
- expect(
84
- whatsappTransport.addressFor!({
85
- kind: "chat",
86
- chatId: "12125550100",
87
- threadId: "ignored",
88
- }),
89
- ).toEqual({
90
- ctx: { callbackUrl: "/deliver/whatsapp", params: {} },
91
- chatId: "12125550100",
92
- });
93
- expect(whatsappTransport.bindsChatOnProactiveSend).toBe(true);
94
- });
95
- });
@@ -1,23 +0,0 @@
1
- import { isMessageKey } from "../i18n/index.js";
2
-
3
- const REPLACEABLE_PATTERNS = [
4
- /^Runtime:\s/,
5
- /^New Conversation$/,
6
- /^Untitled$/,
7
- /^Untitled Conversation$/,
8
- /^Generating title\.\.\.$/,
9
- ];
10
-
11
- /**
12
- * Check whether a title is a system-generated placeholder that can be
13
- * replaced or omitted without discarding user-provided copy.
14
- */
15
- export function isReplaceableTitle(title: string | null): boolean {
16
- if (title == null || title.trim() === "") {
17
- return true;
18
- }
19
- if (isMessageKey(title.trim())) {
20
- return true;
21
- }
22
- return REPLACEABLE_PATTERNS.some((pattern) => pattern.test(title));
23
- }
@@ -1,78 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Message cursors: the "(createdAt, id) after which" reference behind the
3
- // messages-after reads, resilient to the referenced row being deleted.
4
- // ---------------------------------------------------------------------------
5
- //
6
- // A bare message id bounds a read only while its row exists. A regenerated
7
- // reply (the conversation retry route discards the latest assistant turn) or a
8
- // retried turn deletes the row, and a caller holding just the id can no longer
9
- // say where it sat. A `MessageCursor` carries the row's `createdAt` alongside
10
- // its id, so the `(createdAt, id)` bound is reconstructible from the cursor
11
- // alone. The live row stays authoritative whenever it exists.
12
-
13
- import { eq } from "drizzle-orm";
14
-
15
- import type { LineageBound } from "./conversation-lineage.js";
16
- import { getDb } from "./db-connection.js";
17
- import { messages } from "./schema/index.js";
18
-
19
- export { messagesAfterBoundFilter } from "./conversation-lineage.js";
20
-
21
- /**
22
- * A `(createdAt, id)` message reference. `createdAt` is null when the holder
23
- * never recorded it; such a cursor bounds a read only while its row exists.
24
- */
25
- export interface MessageCursor {
26
- readonly id: string;
27
- readonly createdAt: number | null;
28
- }
29
-
30
- /**
31
- * Accepted "after" references: a message id, a {@link MessageCursor}, or
32
- * null. `null`, `""`, and a cursor whose id is `""` all mean "no lower bound".
33
- */
34
- export type MessagesAfterRef = string | MessageCursor | null;
35
-
36
- /** Where a messages-after read starts. */
37
- export type MessagesAfterBound =
38
- /** No lower bound: every row the conversation owns. */
39
- | { kind: "all" }
40
- /** Rows strictly after `bound` in `(createdAt, id)` order. */
41
- | { kind: "after"; bound: LineageBound }
42
- /**
43
- * The referenced row is gone and the reference carried no timestamp, so
44
- * the read has no defensible starting point. Readers return nothing.
45
- */
46
- | { kind: "vanished" };
47
-
48
- /** The `(createdAt, id)` bound of a single message, or null when it is gone. */
49
- export function loadMessageBound(messageId: string): LineageBound | null {
50
- const row = getDb()
51
- .select({ createdAt: messages.createdAt, id: messages.id })
52
- .from(messages)
53
- .where(eq(messages.id, messageId))
54
- .get();
55
- return row ?? null;
56
- }
57
-
58
- /**
59
- * Resolve an "after" reference to the bound a read filters on. A live row
60
- * wins; a cursor whose row is gone falls back to the `createdAt` it carries,
61
- * paired with its id so same-millisecond neighbours keep their order.
62
- */
63
- export function resolveMessagesAfterBound(
64
- after: MessagesAfterRef,
65
- ): MessagesAfterBound {
66
- const id = typeof after === "string" ? after : (after?.id ?? "");
67
- if (id === "") {
68
- return { kind: "all" };
69
- }
70
- const live = loadMessageBound(id);
71
- if (live) {
72
- return { kind: "after", bound: live };
73
- }
74
- if (typeof after === "object" && after !== null && after.createdAt !== null) {
75
- return { kind: "after", bound: { createdAt: after.createdAt, id } };
76
- }
77
- return { kind: "vanished" };
78
- }
@@ -1,149 +0,0 @@
1
- import { Database } from "bun:sqlite";
2
- import { describe, expect, test } from "bun:test";
3
-
4
- import { drizzle } from "drizzle-orm/bun-sqlite";
5
-
6
- import { getSqliteFrom } from "../../db-connection.js";
7
- import * as schema from "../../schema.js";
8
- import { migrateInviteContactId } from "../157-invite-contact-id.js";
9
- import { tableExists, tableHasColumn } from "../schema-introspection.js";
10
-
11
- function createTestDb() {
12
- const sqlite = new Database(":memory:");
13
- sqlite.exec("PRAGMA journal_mode=WAL");
14
- return drizzle(sqlite, { schema });
15
- }
16
-
17
- function columnNotNull(raw: Database, name: string): boolean {
18
- const cols = raw.query(`PRAGMA table_info(assistant_ingress_invites)`).all() as Array<{
19
- name: string;
20
- notnull: number;
21
- }>;
22
- return cols.some((c) => c.name === name && c.notnull === 1);
23
- }
24
-
25
- describe("migrateInviteContactId", () => {
26
- test("rebuilds a legacy created_by_session_id table with NOT NULL contact_id", () => {
27
- const db = createTestDb();
28
- const raw = getSqliteFrom(db);
29
- raw.exec(/*sql*/ `
30
- CREATE TABLE assistant_ingress_invites (
31
- id TEXT PRIMARY KEY,
32
- source_channel TEXT NOT NULL,
33
- token_hash TEXT NOT NULL,
34
- created_by_session_id TEXT,
35
- note TEXT,
36
- max_uses INTEGER NOT NULL DEFAULT 1,
37
- use_count INTEGER NOT NULL DEFAULT 0,
38
- expires_at INTEGER NOT NULL,
39
- status TEXT NOT NULL DEFAULT 'active',
40
- redeemed_by_external_user_id TEXT,
41
- redeemed_by_external_chat_id TEXT,
42
- redeemed_at INTEGER,
43
- expected_external_user_id TEXT,
44
- voice_code_hash TEXT,
45
- voice_code_digits INTEGER,
46
- invite_code_hash TEXT,
47
- friend_name TEXT,
48
- guardian_name TEXT,
49
- created_at INTEGER NOT NULL,
50
- updated_at INTEGER NOT NULL
51
- )
52
- `);
53
- raw.run(
54
- `INSERT INTO assistant_ingress_invites
55
- (id, source_channel, token_hash, created_by_session_id, max_uses, use_count,
56
- expires_at, status, created_at, updated_at)
57
- VALUES ('inv-keep', 'slack', 'hash-keep', 'conv-1', 1, 0, 9, 'active', 1, 1)`,
58
- );
59
- raw.exec(
60
- `ALTER TABLE assistant_ingress_invites ADD COLUMN contact_id TEXT`,
61
- );
62
- raw.run(
63
- `UPDATE assistant_ingress_invites SET contact_id = 'contact-keep' WHERE id = 'inv-keep'`,
64
- );
65
- raw.run(
66
- `INSERT INTO assistant_ingress_invites
67
- (id, source_channel, token_hash, max_uses, use_count, expires_at, status,
68
- created_at, updated_at)
69
- VALUES ('inv-drop', 'slack', 'hash-drop', 1, 0, 9, 'active', 1, 1)`,
70
- );
71
-
72
- migrateInviteContactId(db);
73
-
74
- expect(tableHasColumn(db, "assistant_ingress_invites", "contact_id")).toBe(
75
- true,
76
- );
77
- expect(columnNotNull(raw, "contact_id")).toBe(true);
78
- expect(
79
- tableHasColumn(db, "assistant_ingress_invites", "created_by_session_id"),
80
- ).toBe(true);
81
- const rows = raw
82
- .query(`SELECT id, contact_id FROM assistant_ingress_invites ORDER BY id`)
83
- .all() as Array<{ id: string; contact_id: string }>;
84
- expect(rows).toEqual([{ id: "inv-keep", contact_id: "contact-keep" }]);
85
- });
86
-
87
- test("rebuilds after created_by_session_id was renamed to source_conversation_id", () => {
88
- const db = createTestDb();
89
- const raw = getSqliteFrom(db);
90
- raw.exec(/*sql*/ `
91
- CREATE TABLE assistant_ingress_invites (
92
- id TEXT PRIMARY KEY,
93
- source_channel TEXT NOT NULL,
94
- token_hash TEXT NOT NULL,
95
- source_conversation_id TEXT,
96
- note TEXT,
97
- max_uses INTEGER NOT NULL DEFAULT 1,
98
- use_count INTEGER NOT NULL DEFAULT 0,
99
- expires_at INTEGER NOT NULL,
100
- status TEXT NOT NULL DEFAULT 'active',
101
- redeemed_by_external_user_id TEXT,
102
- redeemed_by_external_chat_id TEXT,
103
- redeemed_at INTEGER,
104
- expected_external_user_id TEXT,
105
- voice_code_hash TEXT,
106
- voice_code_digits INTEGER,
107
- invite_code_hash TEXT,
108
- friend_name TEXT,
109
- guardian_name TEXT,
110
- created_at INTEGER NOT NULL,
111
- updated_at INTEGER NOT NULL
112
- )
113
- `);
114
- raw.exec(
115
- `ALTER TABLE assistant_ingress_invites ADD COLUMN contact_id TEXT`,
116
- );
117
- raw.run(
118
- `INSERT INTO assistant_ingress_invites
119
- (id, source_channel, token_hash, source_conversation_id, contact_id,
120
- max_uses, use_count, expires_at, status, created_at, updated_at)
121
- VALUES ('inv-1', 'slack', 'hash-1', 'conv-9', 'contact-1', 1, 0, 9, 'active', 1, 1)`,
122
- );
123
-
124
- migrateInviteContactId(db);
125
-
126
- expect(columnNotNull(raw, "contact_id")).toBe(true);
127
- expect(
128
- tableHasColumn(db, "assistant_ingress_invites", "source_conversation_id"),
129
- ).toBe(true);
130
- expect(
131
- tableHasColumn(db, "assistant_ingress_invites", "created_by_session_id"),
132
- ).toBe(false);
133
- const row = raw
134
- .query(
135
- `SELECT source_conversation_id, contact_id FROM assistant_ingress_invites WHERE id = 'inv-1'`,
136
- )
137
- .get() as { source_conversation_id: string; contact_id: string };
138
- expect(row).toEqual({
139
- source_conversation_id: "conv-9",
140
- contact_id: "contact-1",
141
- });
142
- });
143
-
144
- test("is a no-op when the table does not exist", () => {
145
- const db = createTestDb();
146
- migrateInviteContactId(db);
147
- expect(tableExists(db, "assistant_ingress_invites")).toBe(false);
148
- });
149
- });
@@ -1,118 +0,0 @@
1
- import { beforeEach, describe, expect, test } from "bun:test";
2
-
3
- import { setConfig } from "../../../../__tests__/helpers/set-config.js";
4
-
5
- // Disable memory so persistence writes don't index into the real memory
6
- // pipeline (both flags default true under the real loader).
7
- setConfig("memory", { enabled: false, v2: { enabled: false } });
8
-
9
- import { createConversation } from "../../../../persistence/conversation-crud.js";
10
- import {
11
- getDb,
12
- getMemorySqlite,
13
- } from "../../../../persistence/db-connection.js";
14
- import { initializeDb } from "../../../../persistence/db-init.js";
15
- import { messages } from "../../../../persistence/schema/index.js";
16
- import { backfillRetrospectiveCursorTimestamps } from "../memory-retrospective-cursor-backfill.js";
17
- import {
18
- ensureRetrospectiveCursorColumn,
19
- getRetrospectiveState,
20
- } from "../memory-retrospective-state.js";
21
-
22
- await initializeDb();
23
-
24
- function resetTables(): void {
25
- const db = getDb();
26
- db.run(`DELETE FROM messages`);
27
- db.run(`DELETE FROM conversations`);
28
- getMemorySqlite()!.exec(`DELETE FROM memory_retrospective_state`);
29
- }
30
-
31
- /** A state row as written before the timestamp column existed. */
32
- function insertLegacyState(conversationId: string, messageId: string): void {
33
- ensureRetrospectiveCursorColumn("test");
34
- getMemorySqlite()!
35
- .query(
36
- `INSERT INTO memory_retrospective_state
37
- (conversation_id, last_processed_message_id, last_run_at, remembered_log, last_processed_created_at)
38
- VALUES (?, ?, 1, NULL, NULL)`,
39
- )
40
- .run(conversationId, messageId);
41
- }
42
-
43
- function insertMessage(
44
- conversationId: string,
45
- id: string,
46
- createdAt: number,
47
- ): void {
48
- getDb()
49
- .insert(messages)
50
- .values({
51
- id,
52
- conversationId,
53
- role: "user",
54
- content: "[]",
55
- createdAt,
56
- metadata: null,
57
- })
58
- .run();
59
- }
60
-
61
- describe("backfillRetrospectiveCursorTimestamps", () => {
62
- beforeEach(() => {
63
- resetTables();
64
- });
65
-
66
- test("fills the timestamp from the cursor's message, leaves vanished cursors NULL, and is idempotent", async () => {
67
- createConversation({ id: "conv-a" });
68
- createConversation({ id: "conv-b" });
69
- createConversation({ id: "conv-c" });
70
- insertMessage("conv-a", "a-m1", 1_000);
71
- insertLegacyState("conv-a", "a-m1");
72
- // Cursor row already deleted: nothing left to recover.
73
- insertLegacyState("conv-b", "gone");
74
- // The failure-only sentinel is never a cursor, so it is never scanned.
75
- insertLegacyState("conv-c", "");
76
-
77
- const first = await backfillRetrospectiveCursorTimestamps();
78
-
79
- expect(first).toEqual({ scanned: 2, backfilled: 1, unrecoverable: 1 });
80
- expect(getRetrospectiveState("conv-a")?.lastProcessedCreatedAt).toBe(1_000);
81
- expect(getRetrospectiveState("conv-b")?.lastProcessedCreatedAt).toBeNull();
82
- expect(getRetrospectiveState("conv-c")?.lastProcessedCreatedAt).toBeNull();
83
-
84
- const second = await backfillRetrospectiveCursorTimestamps();
85
-
86
- expect(second).toEqual({ scanned: 1, backfilled: 0, unrecoverable: 1 });
87
- });
88
-
89
- test("pages through the backlog by conversation id, advancing past unrecoverable rows", async () => {
90
- for (const id of ["conv-1", "conv-2", "conv-3", "conv-4", "conv-5"]) {
91
- createConversation({ id });
92
- }
93
- insertMessage("conv-1", "m-1", 1_000);
94
- insertLegacyState("conv-1", "m-1");
95
- insertLegacyState("conv-2", "gone-2");
96
- insertMessage("conv-3", "m-3", 3_000);
97
- insertLegacyState("conv-3", "m-3");
98
- insertLegacyState("conv-4", "gone-4");
99
- insertMessage("conv-5", "m-5", 5_000);
100
- insertLegacyState("conv-5", "m-5");
101
-
102
- const result = await backfillRetrospectiveCursorTimestamps({ pageSize: 2 });
103
-
104
- expect(result).toEqual({ scanned: 5, backfilled: 3, unrecoverable: 2 });
105
- expect(getRetrospectiveState("conv-1")?.lastProcessedCreatedAt).toBe(1_000);
106
- expect(getRetrospectiveState("conv-3")?.lastProcessedCreatedAt).toBe(3_000);
107
- expect(getRetrospectiveState("conv-5")?.lastProcessedCreatedAt).toBe(5_000);
108
- expect(getRetrospectiveState("conv-4")?.lastProcessedCreatedAt).toBeNull();
109
- });
110
-
111
- test("a table with nothing to fill is a clean no-op", async () => {
112
- expect(await backfillRetrospectiveCursorTimestamps()).toEqual({
113
- scanned: 0,
114
- backfilled: 0,
115
- unrecoverable: 0,
116
- });
117
- });
118
- });
@@ -1,83 +0,0 @@
1
- import { beforeEach, describe, expect, test } from "bun:test";
2
-
3
- import { setConfig } from "../../../../__tests__/helpers/set-config.js";
4
-
5
- // Disable memory so persistence writes don't index into the real memory
6
- // pipeline (both flags default true under the real loader).
7
- setConfig("memory", { enabled: false, v2: { enabled: false } });
8
-
9
- import { getMemorySqlite } from "../../../../persistence/db-connection.js";
10
- import { initializeDb } from "../../../../persistence/db-init.js";
11
- import { preserveRetrospectiveCursorTimestamps } from "../memory-retrospective-cursor-preserve.js";
12
- import {
13
- ensureRetrospectiveCursorColumn,
14
- getRetrospectiveState,
15
- upsertRetrospectiveState,
16
- } from "../memory-retrospective-state.js";
17
-
18
- await initializeDb();
19
-
20
- /** A state row as written before the timestamp column existed. */
21
- function insertLegacyState(conversationId: string, messageId: string): void {
22
- ensureRetrospectiveCursorColumn("test");
23
- getMemorySqlite()!
24
- .query(
25
- `INSERT INTO memory_retrospective_state
26
- (conversation_id, last_processed_message_id, last_run_at, remembered_log, last_processed_created_at)
27
- VALUES (?, ?, 1, NULL, NULL)`,
28
- )
29
- .run(conversationId, messageId);
30
- }
31
-
32
- describe("preserveRetrospectiveCursorTimestamps", () => {
33
- beforeEach(() => {
34
- getMemorySqlite()!.exec(`DELETE FROM memory_retrospective_state`);
35
- });
36
-
37
- test("records the timestamp of a legacy cursor whose row is about to be deleted", async () => {
38
- insertLegacyState("conv-a", "reply-1");
39
-
40
- await preserveRetrospectiveCursorTimestamps("conv-a", [
41
- { id: "tool-1", createdAt: 1_500 },
42
- { id: "reply-1", createdAt: 2_000 },
43
- ]);
44
-
45
- expect(getRetrospectiveState("conv-a")?.lastProcessedCreatedAt).toBe(2_000);
46
- });
47
-
48
- test("leaves a cursor that already has a timestamp, points elsewhere, or does not exist untouched", async () => {
49
- await upsertRetrospectiveState({
50
- conversationId: "conv-stamped",
51
- lastProcessedMessageId: "reply-1",
52
- lastProcessedCreatedAt: 1_000,
53
- lastRunAt: 1,
54
- });
55
- insertLegacyState("conv-elsewhere", "older-reply");
56
-
57
- await preserveRetrospectiveCursorTimestamps("conv-stamped", [
58
- { id: "reply-1", createdAt: 9_999 },
59
- ]);
60
- await preserveRetrospectiveCursorTimestamps("conv-elsewhere", [
61
- { id: "reply-1", createdAt: 9_999 },
62
- ]);
63
- await preserveRetrospectiveCursorTimestamps("conv-missing", [
64
- { id: "reply-1", createdAt: 9_999 },
65
- ]);
66
-
67
- expect(getRetrospectiveState("conv-stamped")?.lastProcessedCreatedAt).toBe(
68
- 1_000,
69
- );
70
- expect(
71
- getRetrospectiveState("conv-elsewhere")?.lastProcessedCreatedAt,
72
- ).toBeNull();
73
- expect(getRetrospectiveState("conv-missing")).toBeNull();
74
- });
75
-
76
- test("an empty row list is a no-op", async () => {
77
- insertLegacyState("conv-a", "reply-1");
78
-
79
- await preserveRetrospectiveCursorTimestamps("conv-a", []);
80
-
81
- expect(getRetrospectiveState("conv-a")?.lastProcessedCreatedAt).toBeNull();
82
- });
83
- });
@@ -1,21 +0,0 @@
1
- /**
2
- * Default `memory` message-deleted hook.
3
- *
4
- * Stamps the conversation's retrospective cursor with the deleted row's
5
- * `createdAt` when the cursor points at that row and was written without a
6
- * timestamp (by a build before the column existed). The cursor usually sits
7
- * on the latest assistant reply, which is exactly the row a regenerate
8
- * deletes, and once the row is gone only the timestamp can place it.
9
- */
10
-
11
- import type { HookFunction, MessageDeletedContext } from "@vellumai/plugin-api";
12
-
13
- import { preserveRetrospectiveCursorTimestamps } from "../memory-retrospective-cursor-preserve.js";
14
-
15
- const messageDeleted: HookFunction<MessageDeletedContext> = async (ctx) => {
16
- await preserveRetrospectiveCursorTimestamps(ctx.conversationId, [
17
- { id: ctx.messageId, createdAt: ctx.createdAt },
18
- ]);
19
- };
20
-
21
- export default messageDeleted;