@mycadet/assistant 0.12.9 → 0.12.11

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 (658) hide show
  1. package/Dockerfile +0 -8
  2. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +1 -1
  3. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
  4. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
  5. package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
  6. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
  7. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
  8. package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
  9. package/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
  10. package/openapi.yaml +62 -910
  11. package/package.json +3 -7
  12. package/scripts/build-test-fixtures.ts +1 -1
  13. package/scripts/generate-openapi.ts +22 -6
  14. package/scripts/postinstall.ts +4 -10
  15. package/scripts/run-tests.ts +0 -21
  16. package/src/__tests__/adaptive-thinking-repair.test.ts +19 -57
  17. package/src/__tests__/agent-loop.test.ts +0 -76
  18. package/src/__tests__/anthropic-provider.test.ts +6 -6
  19. package/src/__tests__/assert-not-live-db.ts +1 -1
  20. package/src/__tests__/assistant-id-boundary-guard.test.ts +3 -3
  21. package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
  22. package/src/__tests__/attachments-store.test.ts +1 -1
  23. package/src/__tests__/audit-log-rotation.test.ts +1 -1
  24. package/src/__tests__/btw-routes.test.ts +1 -1
  25. package/src/__tests__/byok-default-profile-ensure.test.ts +21 -27
  26. package/src/__tests__/call-conversation-messages.test.ts +0 -5
  27. package/src/__tests__/call-recovery.test.ts +2 -7
  28. package/src/__tests__/call-routes-http.test.ts +0 -12
  29. package/src/__tests__/call-store.test.ts +2 -7
  30. package/src/__tests__/catalog-files.test.ts +7 -5
  31. package/src/__tests__/checker.test.ts +1 -1
  32. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +4 -4
  33. package/src/__tests__/cloud-client-verify-credential.test.ts +0 -4
  34. package/src/__tests__/cloud-credential-catalog-cli.test.ts +14 -14
  35. package/src/__tests__/cloud-profile-guard.test.ts +87 -404
  36. package/src/__tests__/compaction-events.test.ts +2 -2
  37. package/src/__tests__/config-loader-backfill.test.ts +74 -163
  38. package/src/__tests__/config-loader-cloud-defaults.test.ts +11 -11
  39. package/src/__tests__/config-loader-corrupt.test.ts +10 -10
  40. package/src/__tests__/config-loader-quarantine-notice.test.ts +7 -7
  41. package/src/__tests__/config-loader-validation-reset-notice.test.ts +11 -11
  42. package/src/__tests__/config-schema.test.ts +26 -27
  43. package/src/__tests__/config-set-route.test.ts +2 -6
  44. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +28 -300
  45. package/src/__tests__/conversation-agent-loop-overflow.test.ts +39 -246
  46. package/src/__tests__/conversation-agent-loop.test.ts +2 -58
  47. package/src/__tests__/conversation-clear-safety.test.ts +0 -30
  48. package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
  49. package/src/__tests__/conversation-queue.test.ts +1 -1
  50. package/src/__tests__/conversation-runtime-assembly.test.ts +1 -1
  51. package/src/__tests__/conversation-skill-tools.test.ts +4 -444
  52. package/src/__tests__/conversation-slash-commands.test.ts +1 -1
  53. package/src/__tests__/conversation-store.test.ts +1 -84
  54. package/src/__tests__/conversation-surface-state.test.ts +0 -16
  55. package/src/__tests__/credential-health-service.test.ts +14 -1
  56. package/src/__tests__/credential-record-retire.test.ts +1 -1
  57. package/src/__tests__/credential-record-write-through.test.ts +1 -1
  58. package/src/__tests__/credential-security-invariants.test.ts +0 -145
  59. package/src/__tests__/custom-profile-ensure.test.ts +1 -1
  60. package/src/__tests__/default-profile-catalog-fallback.test.ts +5 -15
  61. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -2
  62. package/src/__tests__/dictation-profile-store.test.ts +6 -6
  63. package/src/__tests__/disk-usage.test.ts +28 -164
  64. package/src/__tests__/docker-signing-key-bootstrap.test.ts +1 -1
  65. package/src/__tests__/embedding-cloud-proxy-selection.test.ts +1 -1
  66. package/src/__tests__/emit-event-signal.test.ts +1 -1
  67. package/src/__tests__/gateway-client-cloud-outbound.test.ts +3 -3
  68. package/src/__tests__/gateway-only-enforcement.test.ts +1 -1
  69. package/src/__tests__/guardian-dispatch.test.ts +0 -13
  70. package/src/__tests__/helpers/seed-app.ts +1 -1
  71. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -1
  72. package/src/__tests__/host-shell-tool.test.ts +1 -1
  73. package/src/__tests__/identity-routes.test.ts +1 -1
  74. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  75. package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
  76. package/src/__tests__/injector-chain.test.ts +1 -1
  77. package/src/__tests__/injector-config-quarantine-notice.test.ts +1 -1
  78. package/src/__tests__/injector-config-validation-reset-notice.test.ts +1 -1
  79. package/src/__tests__/injector-pkb-v2-silenced.test.ts +1 -1
  80. package/src/__tests__/{platform.test.ts → layout.test.ts} +1 -1
  81. package/src/__tests__/list-all-apps.test.ts +1 -1
  82. package/src/__tests__/live-workspace-guard.test.ts +2 -2
  83. package/src/__tests__/llm-resolver-override-or-default.test.ts +5 -6
  84. package/src/__tests__/llm-resolver.test.ts +7 -7
  85. package/src/__tests__/llm-schema-fallback-profile.test.ts +9 -10
  86. package/src/__tests__/llm-usage-store.test.ts +0 -495
  87. package/src/__tests__/log-export-routes.test.ts +1 -1
  88. package/src/__tests__/mcp-config-secret-boundary.test.ts +12 -53
  89. package/src/__tests__/mcp-list-plugin-servers.test.ts +1 -1
  90. package/src/__tests__/memory-config-file-parity.test.ts +1 -1
  91. package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
  92. package/src/__tests__/messages-read-boundary-guard.test.ts +0 -2
  93. package/src/__tests__/notification-guardian-path.test.ts +0 -7
  94. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  95. package/src/__tests__/openai-provider.test.ts +8 -8
  96. package/src/__tests__/path-policy.test.ts +1 -1
  97. package/src/__tests__/persona-resolver.test.ts +1 -1
  98. package/src/__tests__/plugin-app-serve-routes.test.ts +1 -1
  99. package/src/__tests__/plugin-effective-enabled-set.test.ts +1 -1
  100. package/src/__tests__/plugin-import-boundary-guard.test.ts +4 -6
  101. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -3
  102. package/src/__tests__/provider-cloud-proxy-integration.test.ts +1 -5
  103. package/src/__tests__/provider-connections-backfill.test.ts +10 -10
  104. package/src/__tests__/prune-old-conversations-job.test.ts +6 -31
  105. package/src/__tests__/resolve-app.test.ts +1 -1
  106. package/src/__tests__/run-due-schedules.test.ts +1 -1
  107. package/src/__tests__/scaffold-managed-skill-tool.test.ts +0 -53
  108. package/src/__tests__/schedule-routes.test.ts +1 -1
  109. package/src/__tests__/schedule-store.test.ts +1 -1
  110. package/src/__tests__/secret-routes-cloud-proxy.test.ts +1 -1
  111. package/src/__tests__/skill-load-plugin-scope.test.ts +1 -1
  112. package/src/__tests__/surface-completion-compaction-boundary.test.ts +1 -1
  113. package/src/__tests__/tool-approval-handler.test.ts +1 -1
  114. package/src/__tests__/tool-audit.test.ts +5 -235
  115. package/src/__tests__/tool-executor-lifecycle-events.test.ts +54 -114
  116. package/src/__tests__/tools-get-route.test.ts +1 -1
  117. package/src/__tests__/turn-outcome-read.test.ts +1 -1
  118. package/src/__tests__/twilio-routes.test.ts +0 -1
  119. package/src/__tests__/usage-attribution.test.ts +0 -31
  120. package/src/__tests__/verification-control-plane-policy.test.ts +3 -10
  121. package/src/__tests__/visible-app-context.test.ts +1 -1
  122. package/src/__tests__/voice-ingress-preflight.test.ts +1 -1
  123. package/src/__tests__/workspace-git-service.test.ts +1 -1
  124. package/src/__tests__/workspace-greetings.test.ts +1 -1
  125. package/src/acp/__tests__/helpers/acp-config-stub.ts +1 -1
  126. package/src/activation/progress-store.ts +1 -1
  127. package/src/activation/turn-hooks.ts +1 -1
  128. package/src/agent/loop.ts +0 -51
  129. package/src/apps/app-store.ts +1 -1
  130. package/src/avatar/__tests__/avatar-store.test.ts +2 -172
  131. package/src/avatar/accent-backfill.ts +1 -1
  132. package/src/avatar/avatar-manifest.ts +1 -1
  133. package/src/avatar/avatar-store.ts +10 -69
  134. package/src/avatar/ensure-raster.ts +1 -1
  135. package/src/avatar/identity-avatar.ts +1 -1
  136. package/src/avatar/sync-avatar.ts +1 -1
  137. package/src/avatar/traits-png-sync.ts +1 -1
  138. package/src/bundler/compiler-tools.ts +1 -1
  139. package/src/bundler/package-resolver.ts +1 -1
  140. package/src/calls/__tests__/call-controller.test.ts +25 -27
  141. package/src/calls/active-call-lease.ts +1 -1
  142. package/src/calls/call-controller.ts +3 -3
  143. package/src/calls/call-domain.ts +4 -8
  144. package/src/calls/call-store.ts +2 -76
  145. package/src/calls/resolve-call-tts-provider.ts +3 -3
  146. package/src/calls/twilio-config.ts +3 -3
  147. package/src/calls/twilio-rest.ts +2 -2
  148. package/src/calls/voice-ingress-preflight.ts +2 -2
  149. package/src/cli/bundled-modules.ts +0 -2
  150. package/src/cli/commands/__tests__/apps.test.ts +1 -1
  151. package/src/cli/commands/__tests__/plugins.test.ts +9 -66
  152. package/src/cli/commands/__tests__/ps.test.ts +67 -0
  153. package/src/cli/commands/auth.help.ts +2 -2
  154. package/src/cli/commands/avatar.ts +1 -1
  155. package/src/cli/commands/changelog.ts +1 -1
  156. package/src/cli/commands/cloud/__tests__/subscription.test.ts +2 -2
  157. package/src/cli/commands/cloud/index.help.ts +1 -1
  158. package/src/cli/commands/cloud/index.ts +2 -2
  159. package/src/cli/commands/db/refresh.ts +1 -1
  160. package/src/cli/commands/db/repair-step-conversation-backfill.ts +1 -1
  161. package/src/cli/commands/db/repair.ts +1 -1
  162. package/src/cli/commands/db/status.ts +1 -1
  163. package/src/cli/commands/inference-profiles.ts +1 -12
  164. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +1 -116
  165. package/src/cli/commands/memory/index.help.ts +1 -43
  166. package/src/cli/commands/memory/memory-v3.ts +0 -64
  167. package/src/cli/commands/plugins.ts +54 -205
  168. package/src/cli/commands/ps.ts +5 -2
  169. package/src/cli/commands/status.ts +1 -1
  170. package/src/cli/index.help.ts +0 -2
  171. package/src/cli/lib/__tests__/inspect-plugin.test.ts +36 -66
  172. package/src/cli/lib/__tests__/install-from-cloud.test.ts +1 -1
  173. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -117
  174. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +2 -185
  175. package/src/cli/lib/__tests__/plugin-catalog-resolve.test.ts +36 -66
  176. package/src/cli/lib/__tests__/plugin-catalog-visibility.test.ts +4 -6
  177. package/src/cli/lib/__tests__/plugin-details.test.ts +113 -96
  178. package/src/cli/lib/__tests__/search-plugins.test.ts +9 -16
  179. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +1 -1
  180. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +38 -15
  181. package/src/cli/lib/diff-plugin.ts +1 -1
  182. package/src/cli/lib/inspect-plugin.ts +13 -97
  183. package/src/cli/lib/install-from-cloud.ts +1 -1
  184. package/src/cli/lib/install-from-github.ts +75 -154
  185. package/src/cli/lib/install-plugin-dependencies.ts +1 -1
  186. package/src/cli/lib/list-installed-plugins.ts +1 -1
  187. package/src/cli/lib/open-browser.ts +1 -1
  188. package/src/cli/lib/plugin-catalog-cache.ts +8 -51
  189. package/src/cli/lib/plugin-catalog-resolve.ts +3 -22
  190. package/src/cli/lib/plugin-details.ts +5 -27
  191. package/src/cli/lib/plugin-marketplace.ts +18 -266
  192. package/src/cli/lib/search-plugins.ts +23 -43
  193. package/src/cli/lib/toggle-plugin.ts +1 -1
  194. package/src/cli/lib/uninstall-plugin.ts +1 -1
  195. package/src/cli/lib/upgrade-plugin.ts +3 -49
  196. package/src/cli/program.ts +1 -3
  197. package/src/cli.ts +1 -1
  198. package/src/cloud/client.ts +0 -6
  199. package/src/cloud/consent-cache.test.ts +22 -201
  200. package/src/cloud/consent-cache.ts +16 -111
  201. package/src/cloud/sync-identity.ts +1 -1
  202. package/src/config/__tests__/chat-settings.test.ts +1 -1
  203. package/src/config/__tests__/cloud-identity.test.ts +15 -2
  204. package/src/config/__tests__/default-plugin-skill-discovery.test.ts +1 -1
  205. package/src/config/__tests__/default-profile-catalog.test.ts +12 -51
  206. package/src/config/__tests__/deployment-context-defaults.test.ts +13 -13
  207. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +4 -4
  208. package/src/config/__tests__/loader-last-known-good.test.ts +9 -9
  209. package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +7 -7
  210. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +1 -1
  211. package/src/config/__tests__/profile-materialization.test.ts +2 -4
  212. package/src/config/__tests__/sync-gated-profiles.test.ts +1 -106
  213. package/src/config/acp-agent-write.ts +1 -1
  214. package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +1 -1
  215. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  216. package/src/config/call-site-defaults.ts +0 -6
  217. package/src/config/cloud-identity.ts +12 -5
  218. package/src/config/composer-preferences.ts +1 -1
  219. package/src/config/default-profile-catalog.ts +8 -75
  220. package/src/config/default-profile-names.ts +2 -25
  221. package/src/config/env-registry.ts +1 -14
  222. package/src/config/env.ts +8 -6
  223. package/src/config/llm-resolver.ts +1 -2
  224. package/src/config/loader.ts +13 -17
  225. package/src/config/profile-materialization.ts +1 -1
  226. package/src/config/schema.ts +1 -7
  227. package/src/config/schemas/call-site-catalog.ts +0 -7
  228. package/src/config/schemas/llm.ts +25 -32
  229. package/src/config/seed-inference-profiles.ts +16 -17
  230. package/src/config/skills.ts +2 -2
  231. package/src/config/sync-gated-profiles.ts +6 -24
  232. package/src/credential-health/credential-health-service.ts +10 -3
  233. package/src/daemon/approval-generators.ts +3 -3
  234. package/src/daemon/config-watcher.ts +2 -2
  235. package/src/daemon/conversation-agent-loop-handlers.ts +0 -18
  236. package/src/daemon/conversation-agent-loop.ts +6 -97
  237. package/src/daemon/conversation-process.ts +1 -1
  238. package/src/daemon/conversation-skill-tools.ts +4 -72
  239. package/src/daemon/conversation-store.ts +1 -1
  240. package/src/daemon/conversation-surface-state.ts +0 -33
  241. package/src/daemon/conversation-surfaces.ts +1 -86
  242. package/src/daemon/conversation-tool-setup.test.ts +1 -1
  243. package/src/daemon/conversation-tool-setup.ts +0 -23
  244. package/src/daemon/conversation.ts +3 -5
  245. package/src/daemon/daemon-control.ts +3 -3
  246. package/src/daemon/dictation-profile-store.ts +3 -3
  247. package/src/daemon/event-loop-watchdog.test.ts +2 -198
  248. package/src/daemon/event-loop-watchdog.ts +0 -185
  249. package/src/daemon/external-plugins-bootstrap.ts +1 -1
  250. package/src/daemon/first-greeting.ts +1 -1
  251. package/src/daemon/handlers/skills.ts +1 -1
  252. package/src/daemon/host-app-control-proxy.ts +1 -1
  253. package/src/daemon/host-cu-proxy.ts +2 -2
  254. package/src/daemon/identity-helpers.ts +1 -1
  255. package/src/daemon/lifecycle.ts +11 -15
  256. package/src/daemon/main.ts +1 -1
  257. package/src/daemon/now-scratchpad.ts +1 -1
  258. package/src/daemon/process-message.ts +4 -4
  259. package/src/daemon/profiler-run-store.ts +2 -2
  260. package/src/daemon/providers-setup.ts +2 -2
  261. package/src/daemon/shutdown-handlers.ts +0 -10
  262. package/src/daemon/sqlite-corruption-watchdog.test.ts +2 -142
  263. package/src/daemon/sqlite-corruption-watchdog.ts +17 -81
  264. package/src/daemon/tool-side-effects.ts +1 -1
  265. package/src/desktop/desktop-session-manager.ts +1 -1
  266. package/src/desktop/desktop-wallpaper-renderer.ts +1 -1
  267. package/src/heartbeat/heartbeat-service.ts +1 -1
  268. package/src/home/feed-writer.ts +1 -1
  269. package/src/home/home-greeting-cache.ts +1 -1
  270. package/src/home/relationship-state-writer.ts +2 -2
  271. package/src/hooks/__tests__/hook-live-reload.test.ts +1 -1
  272. package/src/hooks/hook-loader.ts +2 -2
  273. package/src/inbound/__tests__/oauth-callback-url.test.ts +2 -2
  274. package/src/inbound/oauth-callback-url.ts +3 -3
  275. package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
  276. package/src/ipc/socket-path.ts +1 -1
  277. package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
  278. package/src/live-voice/__tests__/live-voice-vad.test.ts +1 -1
  279. package/src/live-voice/live-voice-session.ts +3 -66
  280. package/src/mcp/__tests__/effective-config.test.ts +1 -1
  281. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +2 -2
  282. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +2 -3
  283. package/src/mcp/__tests__/reload-signal-emission.test.ts +1 -1
  284. package/src/mcp/__tests__/reload-signal.test.ts +1 -1
  285. package/src/mcp/__tests__/workspace-mcp-config.test.ts +19 -21
  286. package/src/mcp/reload-signal.ts +1 -1
  287. package/src/mcp/workspace-mcp-config.ts +1 -23
  288. package/src/messaging/draft-store.ts +1 -1
  289. package/src/monitoring/__tests__/active-conversations.test.ts +1 -1
  290. package/src/monitoring/__tests__/page-cache.test.ts +1 -1
  291. package/src/monitoring/__tests__/stall-capture.test.ts +1 -1
  292. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +1 -1
  293. package/src/monitoring/active-conversations.ts +1 -1
  294. package/src/monitoring/control.ts +1 -1
  295. package/src/monitoring/daemon-boot-time.ts +1 -1
  296. package/src/monitoring/daemon-heartbeat.ts +1 -1
  297. package/src/monitoring/page-cache.ts +1 -1
  298. package/src/monitoring/plugin-auto-update.ts +1 -7
  299. package/src/monitoring/plugin-source-watch.ts +1 -1
  300. package/src/monitoring/recovery/db.ts +1 -1
  301. package/src/monitoring/recovery/inflight-content.ts +1 -1
  302. package/src/monitoring/resource-sampler.ts +3 -14
  303. package/src/monitoring/stall-capture.ts +1 -1
  304. package/src/monitoring/worker.ts +9 -76
  305. package/src/monitoring/workspace-git-heartbeat.ts +1 -1
  306. package/src/oauth/connect-orchestrator.ts +4 -4
  307. package/src/permissions/checker.ts +1 -1
  308. package/src/permissions/workspace-policy.ts +1 -1
  309. package/src/persistence/__tests__/main-db-readonly-probe.ts +27 -52
  310. package/src/persistence/__tests__/message-content-file.test.ts +1 -1
  311. package/src/persistence/__tests__/slow-sync-log.test.ts +0 -2
  312. package/src/persistence/attachments-store.ts +1 -1
  313. package/src/persistence/conversation-crud.ts +1 -38
  314. package/src/persistence/conversation-directories.ts +1 -1
  315. package/src/persistence/conversation-types.ts +0 -8
  316. package/src/persistence/db-async-query.ts +1 -1
  317. package/src/persistence/db-connection.ts +11 -1
  318. package/src/persistence/db-init.ts +1 -1
  319. package/src/persistence/db-maintenance.ts +1 -1
  320. package/src/persistence/embeddings/__tests__/embedding-local-lifecycle.test.ts +1 -1
  321. package/src/persistence/embeddings/embedding-local.ts +4 -4
  322. package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -1
  323. package/src/persistence/embeddings/qdrant-client.ts +1 -1
  324. package/src/persistence/embeddings/qdrant-manager.ts +1 -1
  325. package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +1 -1
  326. package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +1 -1
  327. package/src/persistence/job-handlers/cleanup.ts +8 -17
  328. package/src/persistence/llm-usage-store.ts +2 -229
  329. package/src/persistence/message-content-file.ts +1 -1
  330. package/src/persistence/migrations/209-strip-thinking-from-consolidated.ts +1 -1
  331. package/src/persistence/migrations/222-strip-placeholder-sentinels-from-messages.ts +1 -1
  332. package/src/persistence/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +1 -1
  333. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +1 -1
  334. package/src/persistence/migrations/329-move-onboarding-events-to-telemetry-db.test.ts +13 -0
  335. package/src/persistence/migrations/330-move-auth-fallback-events-to-telemetry-db.test.ts +13 -0
  336. package/src/persistence/migrations/331-move-lifecycle-events-to-telemetry-db.test.ts +13 -0
  337. package/src/persistence/migrations/332-move-skill-loaded-events-to-telemetry-db.test.ts +13 -0
  338. package/src/persistence/migrations/333-create-telemetry-events-table.test.ts +7 -4
  339. package/src/persistence/migrations/334-backfill-telemetry-events-outbox.test.ts +13 -0
  340. package/src/persistence/migrations/387-drop-telemetry-tables.ts +51 -0
  341. package/src/persistence/migrations/__tests__/327-create-flush-checkpoints.test.ts +9 -1
  342. package/src/persistence/migrations/__tests__/387-drop-telemetry-tables.test.ts +79 -0
  343. package/src/persistence/migrations/helpers/relocation.ts +1 -1
  344. package/src/persistence/migrations/run-migrations.ts +1 -1
  345. package/src/persistence/migrations/validate-migration-state.ts +1 -1
  346. package/src/persistence/raw-query.ts +1 -29
  347. package/src/persistence/slow-sync-log.ts +0 -23
  348. package/src/persistence/steps.ts +2 -0
  349. package/src/{telemetry → persistence}/tool-audit.ts +6 -121
  350. package/src/plugin-api/index.ts +1 -1
  351. package/src/plugin-api/plugin-name-env.ts +1 -1
  352. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +1 -1
  353. package/src/plugins/collect-source-versions.ts +1 -1
  354. package/src/plugins/defaults/channel/package.json +1 -1
  355. package/src/plugins/defaults/cloud-hosted/package.json +1 -1
  356. package/src/plugins/defaults/compaction/package.json +1 -1
  357. package/src/plugins/defaults/documents/package.json +1 -1
  358. package/src/plugins/defaults/empty-response/package.json +1 -1
  359. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  360. package/src/plugins/defaults/image-fallback/package.json +1 -1
  361. package/src/plugins/defaults/image-recovery/package.json +1 -1
  362. package/src/plugins/defaults/max-tokens-continue/package.json +1 -1
  363. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +1 -1
  364. package/src/plugins/defaults/memory/__tests__/db-maintenance.test.ts +1 -1
  365. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +0 -82
  366. package/src/plugins/defaults/memory/__tests__/memory-retrospective-skill-card.test.ts +0 -41
  367. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -2
  368. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -52
  369. package/src/plugins/defaults/memory/memory-retrospective-skill-card.ts +0 -18
  370. package/src/plugins/defaults/memory/package.json +1 -1
  371. package/src/plugins/defaults/memory/paths.ts +4 -4
  372. package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +1 -1
  373. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +5 -5
  374. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +0 -207
  375. package/src/plugins/defaults/memory/src/memory-worker-routes.ts +1 -1
  376. package/src/plugins/defaults/memory/startup.ts +1 -22
  377. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +2 -253
  378. package/src/plugins/defaults/memory/v3/orchestrate.ts +5 -129
  379. package/src/plugins/defaults/memory/worker-control.ts +1 -1
  380. package/src/plugins/defaults/memory/worker.ts +2 -2
  381. package/src/plugins/defaults/session/package.json +1 -1
  382. package/src/plugins/defaults/surface-completion-nudge/package.json +1 -1
  383. package/src/plugins/defaults/task-progress/package.json +1 -1
  384. package/src/plugins/defaults/task-progress-nudge/package.json +1 -1
  385. package/src/plugins/defaults/title-generate/package.json +1 -1
  386. package/src/plugins/defaults/tool-error/package.json +1 -1
  387. package/src/plugins/defaults/tool-result-truncate/package.json +1 -1
  388. package/src/plugins/defaults/turn-context/package.json +1 -1
  389. package/src/plugins/defaults/workspace/injectors.ts +1 -1
  390. package/src/plugins/defaults/workspace/package.json +1 -1
  391. package/src/plugins/disabled-state.ts +1 -1
  392. package/src/plugins/ensure-plugin-api-shim.ts +1 -1
  393. package/src/plugins/ensure-shared-dep-links.ts +1 -1
  394. package/src/plugins/installed-plugin-dirs.ts +1 -1
  395. package/src/plugins/mcp-servers.ts +7 -9
  396. package/src/plugins/mtime-cache.ts +2 -2
  397. package/src/plugins/source-versions.ts +1 -1
  398. package/src/prompts/bootstrap-cleanup.ts +1 -1
  399. package/src/prompts/persona-resolver.ts +1 -1
  400. package/src/prompts/sections.ts +2 -2
  401. package/src/prompts/system-prompt.ts +10 -42
  402. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +0 -37
  403. package/src/providers/__tests__/cadet-connection-routing.test.ts +2 -2
  404. package/src/providers/cadet/client.ts +1 -1
  405. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -1
  406. package/src/providers/inference/adapter-factory.ts +1 -1
  407. package/src/providers/inference/backfill.ts +3 -10
  408. package/src/providers/inference/profile-probe.ts +1 -1
  409. package/src/providers/retry.ts +0 -2
  410. package/src/providers/types.ts +0 -7
  411. package/src/providers/usage-tracking.ts +1 -1
  412. package/src/routes/__tests__/route-host.test.ts +1 -1
  413. package/src/routes/control.ts +1 -1
  414. package/src/routes/route-host-client.ts +1 -1
  415. package/src/routes/worker.ts +2 -2
  416. package/src/runtime/agent-wake.ts +1 -1
  417. package/src/runtime/assistant-stream-state.ts +1 -1
  418. package/src/runtime/auth/token-service.ts +1 -1
  419. package/src/runtime/background-job-runner.ts +1 -1
  420. package/src/runtime/middleware/twilio-validation.ts +2 -2
  421. package/src/runtime/routes/__tests__/app-pin-routes.test.ts +1 -1
  422. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +1 -1
  423. package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +3 -33
  424. package/src/runtime/routes/__tests__/cloud-credits-routes.test.ts +5 -4
  425. package/src/runtime/routes/__tests__/cloud-invoice-routes.test.ts +4 -3
  426. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +72 -298
  427. package/src/runtime/routes/__tests__/default-plugin-routes.test.ts +1 -1
  428. package/src/runtime/routes/__tests__/deprecated-route-context.test.ts +15 -62
  429. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +105 -12
  430. package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +1 -1
  431. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -1
  432. package/src/runtime/routes/__tests__/plugins-routes.test.ts +47 -211
  433. package/src/runtime/routes/__tests__/route-host-worker-routes.test.ts +1 -1
  434. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +1 -1
  435. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +1 -1
  436. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +1 -1
  437. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +1 -1
  438. package/src/runtime/routes/__tests__/user-routes-cli.test.ts +1 -1
  439. package/src/runtime/routes/__tests__/user-routes-notices.test.ts +1 -1
  440. package/src/runtime/routes/__tests__/user-routes-request.test.ts +1 -1
  441. package/src/runtime/routes/app-management-routes.ts +1 -1
  442. package/src/runtime/routes/attachment-routes.ts +1 -1
  443. package/src/runtime/routes/audit-routes.ts +1 -1
  444. package/src/runtime/routes/avatar-routes.ts +3 -10
  445. package/src/runtime/routes/cloud-routes.ts +3 -3
  446. package/src/runtime/routes/content-source-routes.ts +1 -1
  447. package/src/runtime/routes/conversation-query-routes.ts +49 -706
  448. package/src/runtime/routes/conversation-routes.ts +1 -38
  449. package/src/runtime/routes/debug-routes.ts +1 -1
  450. package/src/runtime/routes/deprecated-route-context.ts +5 -61
  451. package/src/runtime/routes/heartbeat-routes.ts +1 -1
  452. package/src/runtime/routes/identity-routes.ts +1 -1
  453. package/src/runtime/routes/index.ts +0 -6
  454. package/src/runtime/routes/inference-profile-session-handler.ts +3 -3
  455. package/src/runtime/routes/inference-profiles-routes.ts +48 -21
  456. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -1
  457. package/src/runtime/routes/llm-call-sites-routes.ts +3 -3
  458. package/src/runtime/routes/log-export/__tests__/installed-inventory.test.ts +1 -1
  459. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +1 -1
  460. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +1 -1
  461. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  462. package/src/runtime/routes/log-export-routes.ts +17 -15
  463. package/src/runtime/routes/migration-rollback-routes.ts +1 -1
  464. package/src/runtime/routes/migration-routes.ts +2 -3
  465. package/src/runtime/routes/monitoring-routes.ts +2 -2
  466. package/src/runtime/routes/oauth-providers.ts +5 -5
  467. package/src/runtime/routes/plugins-routes.ts +38 -163
  468. package/src/runtime/routes/profiler-routes.ts +1 -1
  469. package/src/runtime/routes/route-host-worker-routes.ts +1 -1
  470. package/src/runtime/routes/sanity-routes.ts +1 -1
  471. package/src/runtime/routes/schedule-routes.ts +1 -1
  472. package/src/runtime/routes/schedule-worker-routes.ts +1 -1
  473. package/src/runtime/routes/settings-routes.ts +1 -1
  474. package/src/runtime/routes/sounds-config-routes.ts +1 -1
  475. package/src/runtime/routes/surface-conversation-resolver.ts +1 -7
  476. package/src/runtime/routes/user-route-dispatcher.ts +1 -3
  477. package/src/runtime/routes/user-route-import.ts +1 -1
  478. package/src/runtime/routes/user-route-resolution.ts +1 -1
  479. package/src/runtime/routes/user-routes-cli.ts +1 -1
  480. package/src/runtime/routes/workspace-commit-routes.ts +1 -1
  481. package/src/runtime/routes/workspace-greetings.ts +1 -1
  482. package/src/runtime/routes/workspace-routes.ts +1 -1
  483. package/src/runtime/routes/workspace-utils.ts +1 -1
  484. package/src/runtime/sync/resource-sync-events.ts +1 -1
  485. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +1 -1
  486. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -1
  487. package/src/schedule/plugin-schedule-availability.ts +1 -1
  488. package/src/schedule/plugin-schedule-declarations.ts +1 -1
  489. package/src/schedule/run-script.ts +1 -1
  490. package/src/schedule/scheduler.ts +1 -11
  491. package/src/schedule/worker-control.ts +1 -1
  492. package/src/schedule/worker.ts +3 -3
  493. package/src/security/oauth2.ts +2 -2
  494. package/src/security/secret-allowlist.ts +1 -1
  495. package/src/signals/cancel.ts +1 -1
  496. package/src/signals/conversation-undo.ts +1 -1
  497. package/src/signals/emit-event.ts +1 -1
  498. package/src/signals/event-stream.ts +1 -1
  499. package/src/signals/user-message.ts +1 -1
  500. package/src/skills/catalog-install.ts +2 -1
  501. package/src/skills/clawhub.ts +1 -1
  502. package/src/skills/cloud-store.ts +1 -1
  503. package/src/skills/path-classifier.ts +1 -1
  504. package/src/skills/skill-history.ts +1 -1
  505. package/src/skills/skillssh-registry.ts +1 -1
  506. package/src/skills/uninstall.ts +1 -1
  507. package/src/skills/workspace-skill-md-signature.ts +1 -1
  508. package/src/subagent/manager.ts +1 -1
  509. package/src/theme/workspace-theme.ts +1 -1
  510. package/src/tools/browser/auth-cache.ts +1 -1
  511. package/src/tools/browser/browser-manager.ts +1 -1
  512. package/src/tools/browser/runtime-check.ts +1 -1
  513. package/src/tools/executor.ts +4 -4
  514. package/src/tools/filesystem/write.ts +1 -1
  515. package/src/tools/permission-checker.ts +2 -51
  516. package/src/tools/run-standalone.ts +1 -1
  517. package/src/tools/skills/format-input-schema.ts +1 -1
  518. package/src/tools/skills/load.ts +1 -1
  519. package/src/tools/skills/scaffold-cloud.ts +0 -32
  520. package/src/tools/terminal/safe-env.ts +1 -2
  521. package/src/tools/terminal/sanitized-bash.ts +1 -1
  522. package/src/tools/terminal/shell.ts +1 -1
  523. package/src/tools/tool-approval-handler.ts +4 -1
  524. package/src/tools/workflows/manage-workflows.ts +2 -2
  525. package/src/tools/workflows/run-workflow.test.ts +1 -1
  526. package/src/tools/workspace-tools/loader.ts +1 -1
  527. package/src/tts/synthesis-stream.ts +2 -2
  528. package/src/usage/attribution.ts +1 -11
  529. package/src/util/browser.ts +1 -1
  530. package/src/util/bun-runtime.ts +2 -1
  531. package/src/util/device-id.ts +1 -1
  532. package/src/util/disk-usage.ts +4 -139
  533. package/src/util/layout.ts +3 -3
  534. package/src/util/logger.ts +1 -1
  535. package/src/util/logs-db-path.ts +1 -1
  536. package/src/util/memory-db-path.ts +1 -1
  537. package/src/util/{platform.ts → os.ts} +5 -30
  538. package/src/util/process-tree.ts +19 -0
  539. package/src/util/sqlite3-runtime.ts +1 -1
  540. package/src/util/telemetry-db-path.ts +1 -1
  541. package/src/watcher/__tests__/engine.test.ts +0 -23
  542. package/src/watcher/engine.ts +0 -7
  543. package/src/windows-compiled-cli.ts +0 -4
  544. package/src/windows-compiled-worker-entry.ts +0 -6
  545. package/src/workflows/leaf-runner.test.ts +1 -1
  546. package/src/workflows/leaf-runner.ts +1 -1
  547. package/src/workflows/library.ts +1 -1
  548. package/src/workspace/adaptive-thinking-repair.ts +5 -24
  549. package/src/workspace/byok-default-profile-ensure.ts +24 -26
  550. package/src/workspace/custom-profile-ensure.ts +2 -2
  551. package/src/workspace/git-service.ts +1 -1
  552. package/src/workspace/hatched-date.ts +1 -1
  553. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +2 -2
  554. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +1 -1
  555. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +1 -1
  556. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +1 -1
  557. package/src/workspace/migrations/registry.ts +0 -4
  558. package/src/workspace/turn-commit.ts +1 -1
  559. package/docs/activation-funnel-telemetry.md +0 -324
  560. package/scripts/bundled-plugin-packages.ts +0 -154
  561. package/scripts/generate-bundled-plugin-packages.ts +0 -29
  562. package/src/__tests__/activation-early-marking.test.ts +0 -114
  563. package/src/__tests__/auth-fallback-events-store.test.ts +0 -99
  564. package/src/__tests__/config-get-vision-flag.test.ts +0 -139
  565. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +0 -400
  566. package/src/__tests__/internal-telemetry-routes.test.ts +0 -213
  567. package/src/__tests__/telemetry-routes.test.ts +0 -182
  568. package/src/__tests__/turn-events-store.test.ts +0 -376
  569. package/src/__tests__/ui-channel-variants.test.ts +0 -53
  570. package/src/avatar/__tests__/avatar-changed-telemetry.test.ts +0 -217
  571. package/src/avatar/avatar-changed-telemetry.ts +0 -128
  572. package/src/calls/__tests__/call-funnel-telemetry.test.ts +0 -204
  573. package/src/cli/commands/telemetry.help.ts +0 -27
  574. package/src/cli/commands/telemetry.ts +0 -83
  575. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +0 -251
  576. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +0 -113
  577. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +0 -384
  578. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +0 -164
  579. package/src/cli/lib/__tests__/plugins-install-offline.test.ts +0 -228
  580. package/src/cli/lib/bundled-marketplace.json +0 -1575
  581. package/src/cli/lib/bundled-plugin-packages.json +0 -827
  582. package/src/cli/lib/bundled-plugin-packages.ts +0 -87
  583. package/src/cli/lib/plugin-catalog-local.ts +0 -94
  584. package/src/cli/lib/plugin-pin-history.ts +0 -276
  585. package/src/cloud/feature-gate.ts +0 -8
  586. package/src/config/__tests__/cloud-rehydration.test.ts +0 -180
  587. package/src/config/cloud-rehydration.ts +0 -35
  588. package/src/daemon/__tests__/auto-profile-router.test.ts +0 -380
  589. package/src/daemon/auto-profile-router.ts +0 -428
  590. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +0 -391
  591. package/src/monitoring/__tests__/db-integrity-sample.test.ts +0 -113
  592. package/src/monitoring/__tests__/oom-kill-reporter.test.ts +0 -374
  593. package/src/monitoring/db-integrity-check.ts +0 -163
  594. package/src/monitoring/db-integrity-sample.ts +0 -176
  595. package/src/monitoring/oom-kill-reporter.ts +0 -469
  596. package/src/onboarding/__tests__/onboarding-events-store.test.ts +0 -158
  597. package/src/onboarding/onboarding-events-store.ts +0 -296
  598. package/src/persistence/__tests__/raw-query-telemetry.test.ts +0 -76
  599. package/src/persistence/lifecycle-events-store.test.ts +0 -134
  600. package/src/persistence/lifecycle-events-store.ts +0 -110
  601. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +0 -76
  602. package/src/plugins/defaults/memory/activation-session-store.ts +0 -50
  603. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +0 -281
  604. package/src/runtime/routes/auto-profile-routes.ts +0 -83
  605. package/src/runtime/routes/internal-telemetry-routes.ts +0 -142
  606. package/src/runtime/routes/telemetry-routes.ts +0 -274
  607. package/src/security/auth-fallback-events-store.ts +0 -57
  608. package/src/telemetry/__tests__/activation-funnel.test.ts +0 -95
  609. package/src/telemetry/__tests__/config-setting-events-store.test.ts +0 -63
  610. package/src/telemetry/__tests__/config-setting-snapshot.test.ts +0 -143
  611. package/src/telemetry/__tests__/flush-checkpoints.test.ts +0 -56
  612. package/src/telemetry/__tests__/live-voice-funnel.test.ts +0 -174
  613. package/src/telemetry/__tests__/outbox-test-harness.ts +0 -85
  614. package/src/telemetry/__tests__/phone-call-funnel.test.ts +0 -72
  615. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +0 -282
  616. package/src/telemetry/__tests__/watchdog-events-store.test.ts +0 -71
  617. package/src/telemetry/activation-funnel.ts +0 -172
  618. package/src/telemetry/config-setting-events-store.ts +0 -40
  619. package/src/telemetry/config-setting-snapshot.ts +0 -170
  620. package/src/telemetry/flush-checkpoints.ts +0 -70
  621. package/src/telemetry/live-voice-funnel.ts +0 -185
  622. package/src/telemetry/memory-corpus-size.test.ts +0 -120
  623. package/src/telemetry/memory-corpus-size.ts +0 -184
  624. package/src/telemetry/memory-tier-reporter.test.ts +0 -195
  625. package/src/telemetry/memory-tier-reporter.ts +0 -130
  626. package/src/telemetry/phone-call-funnel.ts +0 -144
  627. package/src/telemetry/skill-loaded-events-store.test.ts +0 -93
  628. package/src/telemetry/skill-loaded-events-store.ts +0 -39
  629. package/src/telemetry/telemetry-event-sources.test.ts +0 -223
  630. package/src/telemetry/telemetry-event-sources.ts +0 -597
  631. package/src/telemetry/telemetry-events-outbox.test.ts +0 -375
  632. package/src/telemetry/telemetry-events-outbox.ts +0 -237
  633. package/src/telemetry/telemetry-main-db.ts +0 -48
  634. package/src/telemetry/telemetry-wire-source.json +0 -4
  635. package/src/telemetry/telemetry-wire-validation.test.ts +0 -157
  636. package/src/telemetry/telemetry-wire-validation.ts +0 -162
  637. package/src/telemetry/telemetry-wire.generated.ts +0 -483
  638. package/src/telemetry/tool-executed-events-store.test.ts +0 -210
  639. package/src/telemetry/tool-executed-events-store.ts +0 -102
  640. package/src/telemetry/trace-collection-policy.test.ts +0 -28
  641. package/src/telemetry/trace-collection-policy.ts +0 -30
  642. package/src/telemetry/turn-events-store.ts +0 -216
  643. package/src/telemetry/turn-trace-store.test.ts +0 -884
  644. package/src/telemetry/turn-trace-store.ts +0 -399
  645. package/src/telemetry/types.test.ts +0 -38
  646. package/src/telemetry/types.ts +0 -780
  647. package/src/telemetry/usage-telemetry-reporter.test.ts +0 -3445
  648. package/src/telemetry/usage-telemetry-reporter.ts +0 -566
  649. package/src/telemetry/watchdog-direct-emit.test.ts +0 -112
  650. package/src/telemetry/watchdog-direct-emit.ts +0 -104
  651. package/src/telemetry/watchdog-events-store.ts +0 -31
  652. package/src/tools/ui-surface/channel-variants.ts +0 -52
  653. package/src/watcher/__tests__/telemetry.test.ts +0 -178
  654. package/src/watcher/telemetry.ts +0 -93
  655. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +0 -165
  656. package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +0 -151
  657. /package/src/{telemetry → persistence}/tool-usage-store.ts +0 -0
  658. /package/src/{telemetry → persistence}/turn-outcome.ts +0 -0
@@ -1,884 +0,0 @@
1
- /**
2
- * Tests for the turn-trace assembler.
3
- *
4
- * Verifies that a turn's transcript (user message, assistant responses, and
5
- * tool_result rows) plus its tool invocations are gathered into a faithful,
6
- * window-bounded trace, that the window stops at the next REAL user turn (and
7
- * never at the turn's own tool-result rows), that tool inputs/results are
8
- * captured verbatim (no field-level redaction), that coalesced-batch turns
9
- * trace their natural windows (head user-only, shared response on the final
10
- * batched turn — no batch inference), and that the size cap omits oversized
11
- * traces fail-closed.
12
- */
13
-
14
- import { beforeEach, describe, expect, mock, test } from "bun:test";
15
-
16
- // Control the live-conversation lookup so `isTurnSettled` can be exercised
17
- // without a running agent loop. Returns `undefined` (no live conversation) by
18
- // default; tests set a fake with a chosen `isProcessing()`.
19
- let mockLiveConversation:
20
- | {
21
- isProcessing: () => boolean;
22
- getCurrentSystemPrompt?: () => string;
23
- getRegisteredToolDefinitions?: () => Array<{
24
- name: string;
25
- description: string;
26
- input_schema: object;
27
- }>;
28
- }
29
- | undefined;
30
- mock.module("../daemon/conversation-registry.js", () => ({
31
- findConversation: () => mockLiveConversation,
32
- }));
33
-
34
- import { createConversation } from "../persistence/conversation-crud.js";
35
- import { getDb } from "../persistence/db-connection.js";
36
- import { initializeDb } from "../persistence/db-init.js";
37
- import { messages, toolInvocations } from "../persistence/schema/index.js";
38
- import {
39
- assembleBoundedTurnTrace,
40
- assembleTurnTrace,
41
- isTurnSettled,
42
- MAX_TRACE_SERIALIZED_BYTES,
43
- type TurnTraceBoundary,
44
- } from "./turn-trace-store.js";
45
-
46
- await initializeDb();
47
-
48
- function purge(): void {
49
- const db = getDb();
50
- db.run("DELETE FROM tool_invocations");
51
- db.run("DELETE FROM messages");
52
- db.run("DELETE FROM conversations");
53
- }
54
-
55
- beforeEach(() => {
56
- purge();
57
- mockLiveConversation = undefined;
58
- });
59
-
60
- interface MessageSeed {
61
- id: string;
62
- role: "user" | "assistant" | "system";
63
- content: unknown;
64
- createdAt: number;
65
- /** Persisted `messages.metadata` bag; assistant rows carry `{ model }`. */
66
- metadata?: Record<string, unknown>;
67
- }
68
-
69
- function insertMessage(conversationId: string, seed: MessageSeed): void {
70
- getDb()
71
- .insert(messages)
72
- .values({
73
- id: seed.id,
74
- conversationId,
75
- role: seed.role,
76
- content:
77
- typeof seed.content === "string"
78
- ? seed.content
79
- : JSON.stringify(seed.content),
80
- createdAt: seed.createdAt,
81
- metadata: seed.metadata ? JSON.stringify(seed.metadata) : null,
82
- })
83
- .run();
84
- }
85
-
86
- interface ToolSeed {
87
- id: string;
88
- toolName: string;
89
- input: string;
90
- result: string;
91
- decision?: string;
92
- durationMs?: number;
93
- createdAt: number;
94
- }
95
-
96
- function insertTool(conversationId: string, seed: ToolSeed): void {
97
- getDb()
98
- .insert(toolInvocations)
99
- .values({
100
- id: seed.id,
101
- conversationId,
102
- toolName: seed.toolName,
103
- input: seed.input,
104
- result: seed.result,
105
- decision: seed.decision ?? "allow",
106
- riskLevel: "low",
107
- durationMs: seed.durationMs ?? 5,
108
- createdAt: seed.createdAt,
109
- })
110
- .run();
111
- }
112
-
113
- function boundary(
114
- conversationId: string,
115
- userMessageId: string,
116
- createdAt: number,
117
- ): TurnTraceBoundary {
118
- return { conversationId, userMessageId, userMessageCreatedAt: createdAt };
119
- }
120
-
121
- describe("assembleTurnTrace", () => {
122
- test("gathers user message, assistant responses, tool-result rows, and tool calls for a multi-message turn", () => {
123
- const conv = createConversation({ conversationType: "standard" });
124
-
125
- // Turn 1: user asks, assistant calls a tool, tool result lands as a
126
- // role="user" row, assistant replies.
127
- insertMessage(conv.id, {
128
- id: "m-user-1",
129
- role: "user",
130
- content: [{ type: "text", text: "what's on my calendar?" }],
131
- createdAt: 1000,
132
- });
133
- insertMessage(conv.id, {
134
- id: "m-asst-1a",
135
- role: "assistant",
136
- content: [
137
- {
138
- type: "tool_use",
139
- id: "tu-1",
140
- name: "calendar_list_events",
141
- input: { range: "today" },
142
- },
143
- ],
144
- createdAt: 1100,
145
- metadata: { model: "claude-fable-5" },
146
- });
147
- insertMessage(conv.id, {
148
- id: "m-toolresult-1",
149
- role: "user",
150
- content: [
151
- { type: "tool_result", tool_use_id: "tu-1", content: "2 events" },
152
- ],
153
- createdAt: 1200,
154
- });
155
- insertMessage(conv.id, {
156
- id: "m-asst-1b",
157
- role: "assistant",
158
- content: [{ type: "text", text: "You have 2 events today." }],
159
- createdAt: 1300,
160
- metadata: { model: "claude-fable-5" },
161
- });
162
- insertTool(conv.id, {
163
- id: "ti-1",
164
- toolName: "calendar_list_events",
165
- input: JSON.stringify({ range: "today" }),
166
- result: JSON.stringify({ events: 2 }),
167
- createdAt: 1150,
168
- });
169
-
170
- // Turn 2: next real user turn — must NOT be in turn 1's trace.
171
- insertMessage(conv.id, {
172
- id: "m-user-2",
173
- role: "user",
174
- content: [{ type: "text", text: "thanks" }],
175
- createdAt: 2000,
176
- });
177
- insertTool(conv.id, {
178
- id: "ti-2",
179
- toolName: "noop",
180
- input: "{}",
181
- result: "{}",
182
- createdAt: 2100,
183
- });
184
-
185
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
186
-
187
- expect(trace.schema_version).toBe(3);
188
- // Window stops before turn 2: only turn-1 message rows, oldest-first.
189
- expect(trace.messages.map((m) => m.id)).toEqual([
190
- "m-user-1",
191
- "m-asst-1a",
192
- "m-toolresult-1",
193
- "m-asst-1b",
194
- ]);
195
- // Model attribution is per message, from `metadata.model` (the served
196
- // `response.model` persisted with the finalized content): assistant rows
197
- // carry it, user and tool-result rows carry null.
198
- expect(trace.messages.map((m) => [m.id, m.model])).toEqual([
199
- ["m-user-1", null],
200
- ["m-asst-1a", "claude-fable-5"],
201
- ["m-toolresult-1", null],
202
- ["m-asst-1b", "claude-fable-5"],
203
- ]);
204
- // The tool-result row keeps role="user" (faithful to what the model saw).
205
- const toolResultMsg = trace.messages.find((m) => m.id === "m-toolresult-1");
206
- expect(toolResultMsg?.role).toBe("user");
207
- // Content is parsed JSON (ContentBlock[]), not a string.
208
- expect(Array.isArray(toolResultMsg?.content)).toBe(true);
209
-
210
- // Only turn-1's tool invocation is in scope.
211
- expect(trace.tool_calls.map((t) => t.id)).toEqual(["ti-1"]);
212
- expect(trace.tool_calls[0]).toMatchObject({
213
- tool_name: "calendar_list_events",
214
- decision: "allow",
215
- duration_ms: 5,
216
- created_at: 1150,
217
- });
218
- // Result is forwarded verbatim.
219
- expect(trace.tool_calls[0].result).toBe(JSON.stringify({ events: 2 }));
220
- });
221
-
222
- test("attributes each assistant row to the model that served it when a hook reroutes mid-turn", () => {
223
- // A pre-model-call hook reroutes the SECOND call in the turn, so the two
224
- // assistant rows carry different served models — attribution stays faithful
225
- // per message.
226
- const conv = createConversation({ conversationType: "standard" });
227
- insertMessage(conv.id, {
228
- id: "m-user-1",
229
- role: "user",
230
- content: [{ type: "text", text: "hello" }],
231
- createdAt: 1000,
232
- });
233
- insertMessage(conv.id, {
234
- id: "m-asst-1a",
235
- role: "assistant",
236
- content: [{ type: "tool_use", id: "tu-1", name: "noop", input: {} }],
237
- createdAt: 1100,
238
- metadata: { model: "claude-fable-5" },
239
- });
240
- insertMessage(conv.id, {
241
- id: "m-toolresult-1",
242
- role: "user",
243
- content: [{ type: "tool_result", tool_use_id: "tu-1", content: "ok" }],
244
- createdAt: 1200,
245
- });
246
- insertMessage(conv.id, {
247
- id: "m-asst-1b",
248
- role: "assistant",
249
- content: [{ type: "text", text: "done" }],
250
- createdAt: 1300,
251
- metadata: { model: "claude-opus-4-8" },
252
- });
253
-
254
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
255
-
256
- expect(trace.messages.map((m) => [m.id, m.model])).toEqual([
257
- ["m-user-1", null],
258
- ["m-asst-1a", "claude-fable-5"],
259
- ["m-toolresult-1", null],
260
- ["m-asst-1b", "claude-opus-4-8"],
261
- ]);
262
- });
263
-
264
- test("per-message model is null for rows with no stamped model (historical / missing metadata)", () => {
265
- const conv = createConversation({ conversationType: "standard" });
266
- insertMessage(conv.id, {
267
- id: "m-user-1",
268
- role: "user",
269
- content: [{ type: "text", text: "hello" }],
270
- createdAt: 1000,
271
- });
272
- // Assistant row with no metadata at all (historical row before stamping).
273
- insertMessage(conv.id, {
274
- id: "m-asst-1",
275
- role: "assistant",
276
- content: [{ type: "text", text: "hi" }],
277
- createdAt: 1100,
278
- });
279
- // Assistant row whose metadata bag omits `model`.
280
- insertMessage(conv.id, {
281
- id: "m-asst-2",
282
- role: "assistant",
283
- content: [{ type: "text", text: "again" }],
284
- createdAt: 1200,
285
- metadata: { provenanceTrustClass: "unknown" },
286
- });
287
-
288
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
289
-
290
- expect(trace.messages.map((m) => m.model)).toEqual([null, null, null]);
291
- });
292
-
293
- test("includes system_prompt and tool_definitions from the live conversation", () => {
294
- const conv = createConversation({ conversationType: "standard" });
295
- insertMessage(conv.id, {
296
- id: "m-user-1",
297
- role: "user",
298
- content: [{ type: "text", text: "hello" }],
299
- createdAt: 1000,
300
- });
301
- insertMessage(conv.id, {
302
- id: "m-asst-1",
303
- role: "assistant",
304
- content: [{ type: "text", text: "hi" }],
305
- createdAt: 1100,
306
- });
307
-
308
- // The conversation resolves + sorts its registered tools; trace assembly
309
- // just maps them into the trace, so feed it already-resolved definitions.
310
- mockLiveConversation = {
311
- isProcessing: () => false,
312
- getCurrentSystemPrompt: () => "You are a helpful assistant.",
313
- getRegisteredToolDefinitions: () => [
314
- { name: "file_read", description: "Read a file", input_schema: {} },
315
- { name: "notify_parent", description: "", input_schema: {} },
316
- { name: "web_search", description: "Search the web", input_schema: {} },
317
- ],
318
- };
319
-
320
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
321
-
322
- expect(trace.system_prompt).toBe("You are a helpful assistant.");
323
- expect(trace.tool_definitions).toEqual([
324
- { name: "file_read", description: "Read a file", input_schema: {} },
325
- { name: "notify_parent", description: "", input_schema: {} },
326
- { name: "web_search", description: "Search the web", input_schema: {} },
327
- ]);
328
- });
329
-
330
- test("system_prompt is null and tool_definitions is empty when conversation is evicted", () => {
331
- const conv = createConversation({ conversationType: "standard" });
332
- insertMessage(conv.id, {
333
- id: "m-user-1",
334
- role: "user",
335
- content: [{ type: "text", text: "hello" }],
336
- createdAt: 1000,
337
- });
338
- insertMessage(conv.id, {
339
- id: "m-asst-1",
340
- role: "assistant",
341
- content: [{ type: "text", text: "hi" }],
342
- createdAt: 1100,
343
- });
344
-
345
- // No mockLiveConversation set — simulates evicted conversation.
346
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
347
-
348
- expect(trace.system_prompt).toBeNull();
349
- expect(trace.tool_definitions).toEqual([]);
350
- });
351
-
352
- test("the final turn's window runs to the end of the conversation", () => {
353
- const conv = createConversation({ conversationType: "standard" });
354
- insertMessage(conv.id, {
355
- id: "m-user-1",
356
- role: "user",
357
- content: [{ type: "text", text: "first" }],
358
- createdAt: 1000,
359
- });
360
- insertMessage(conv.id, {
361
- id: "m-user-2",
362
- role: "user",
363
- content: [{ type: "text", text: "second (latest)" }],
364
- createdAt: 2000,
365
- });
366
- insertMessage(conv.id, {
367
- id: "m-asst-2",
368
- role: "assistant",
369
- content: [{ type: "text", text: "reply to second" }],
370
- createdAt: 2100,
371
- });
372
- insertTool(conv.id, {
373
- id: "ti-late",
374
- toolName: "noop",
375
- input: "{}",
376
- result: "ok",
377
- createdAt: 2200,
378
- });
379
-
380
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-2", 2000));
381
- expect(trace.messages.map((m) => m.id)).toEqual(["m-user-2", "m-asst-2"]);
382
- expect(trace.tool_calls.map((t) => t.id)).toEqual(["ti-late"]);
383
- });
384
-
385
- test("two real user turns sharing created_at: the first turn's trace is not truncated and excludes the second turn", () => {
386
- // Forked conversations preserve the source `created_at` with fresh ids, so
387
- // two real user messages can share a millisecond. A timestamp-only upper
388
- // bound would equal the current turn's own `created_at` and empty the
389
- // window — the compound `(created_at, id)` bound must keep this turn's rows
390
- // (which sort by id at the shared millisecond) while excluding the next.
391
- const conv = createConversation({ conversationType: "standard" });
392
-
393
- // Turn 1 (id "m-user-1") and turn 2 (id "m-user-2") share created_at=1000.
394
- // Turn 1's assistant reply, tool-result row, and tool call also land at
395
- // 1000 — the worst case for a timestamp-only bound.
396
- insertMessage(conv.id, {
397
- id: "m-user-1",
398
- role: "user",
399
- content: [{ type: "text", text: "first (same ms)" }],
400
- createdAt: 1000,
401
- });
402
- insertMessage(conv.id, {
403
- id: "m-user-1-asst",
404
- role: "assistant",
405
- content: [{ type: "text", text: "reply to first" }],
406
- createdAt: 1000,
407
- });
408
- insertMessage(conv.id, {
409
- id: "m-user-1-toolresult",
410
- role: "user",
411
- content: [{ type: "tool_result", tool_use_id: "tu-1", content: "ok" }],
412
- createdAt: 1000,
413
- });
414
- insertTool(conv.id, {
415
- id: "ti-turn1",
416
- toolName: "noop",
417
- input: "{}",
418
- result: "r1",
419
- createdAt: 1000,
420
- });
421
-
422
- // Turn 2 user message + its content, same created_at=1000 (higher id).
423
- insertMessage(conv.id, {
424
- id: "m-user-2",
425
- role: "user",
426
- content: [{ type: "text", text: "second (same ms)" }],
427
- createdAt: 1000,
428
- });
429
- insertMessage(conv.id, {
430
- id: "m-user-2-asst",
431
- role: "assistant",
432
- content: [{ type: "text", text: "reply to second" }],
433
- createdAt: 1000,
434
- });
435
-
436
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
437
-
438
- // Turn 1's rows (ids < "m-user-2" at ms 1000) are present; the trace is
439
- // NOT truncated/emptied. The second user turn and its reply are excluded.
440
- expect(trace.messages.map((m) => m.id)).toEqual([
441
- "m-user-1",
442
- "m-user-1-asst",
443
- "m-user-1-toolresult",
444
- ]);
445
- // Turn 1's same-millisecond tool call is retained (degenerate `<=` window).
446
- expect(trace.tool_calls.map((t) => t.id)).toEqual(["ti-turn1"]);
447
- });
448
-
449
- test("the SECOND of two same-created_at turns captures its own trace to end of conversation", () => {
450
- // Complement of the previous test: assembling the trace for the later of
451
- // two same-millisecond user turns must include only that turn's rows.
452
- const conv = createConversation({ conversationType: "standard" });
453
- insertMessage(conv.id, {
454
- id: "m-user-1",
455
- role: "user",
456
- content: [{ type: "text", text: "first (same ms)" }],
457
- createdAt: 1000,
458
- });
459
- insertMessage(conv.id, {
460
- id: "m-user-1-asst",
461
- role: "assistant",
462
- content: [{ type: "text", text: "reply to first" }],
463
- createdAt: 1000,
464
- });
465
- insertMessage(conv.id, {
466
- id: "m-user-2",
467
- role: "user",
468
- content: [{ type: "text", text: "second (same ms, latest)" }],
469
- createdAt: 1000,
470
- });
471
- insertMessage(conv.id, {
472
- id: "m-user-2-asst",
473
- role: "assistant",
474
- content: [{ type: "text", text: "reply to second" }],
475
- createdAt: 1100,
476
- });
477
-
478
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-2", 1000));
479
- expect(trace.messages.map((m) => m.id)).toEqual([
480
- "m-user-2",
481
- "m-user-2-asst",
482
- ]);
483
- });
484
-
485
- test("a tool-result role=user row does NOT truncate the turn it belongs to", () => {
486
- const conv = createConversation({ conversationType: "standard" });
487
- insertMessage(conv.id, {
488
- id: "m-user-1",
489
- role: "user",
490
- content: [{ type: "text", text: "do a thing" }],
491
- createdAt: 1000,
492
- });
493
- // Tool-result row persisted as role="user" — must be treated as part of
494
- // the turn, not as the next user turn.
495
- insertMessage(conv.id, {
496
- id: "m-toolresult",
497
- role: "user",
498
- content: [{ type: "tool_result", tool_use_id: "tu-x", content: "done" }],
499
- createdAt: 1100,
500
- });
501
- insertMessage(conv.id, {
502
- id: "m-asst-after-result",
503
- role: "assistant",
504
- content: [{ type: "text", text: "all done" }],
505
- createdAt: 1200,
506
- });
507
-
508
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
509
- // All three rows belong to the single turn — the tool-result row did not
510
- // close the window early.
511
- expect(trace.messages.map((m) => m.id)).toEqual([
512
- "m-user-1",
513
- "m-toolresult",
514
- "m-asst-after-result",
515
- ]);
516
- });
517
-
518
- test("captures tool inputs verbatim — no field-level redaction, even for credential-shaped keys", () => {
519
- // The consented trace is full-fidelity. Keys that look sensitive
520
- // (access_token, api_key) are NOT redacted — the protections are the
521
- // consent gate, the PII-segregated table, and its TTL, not redaction.
522
- const conv = createConversation({ conversationType: "standard" });
523
- insertMessage(conv.id, {
524
- id: "m-user-1",
525
- role: "user",
526
- content: [{ type: "text", text: "use my token" }],
527
- createdAt: 1000,
528
- });
529
- const rawInput = {
530
- url: "https://api.example.com",
531
- access_token: "super-secret-value",
532
- nested: { api_key: "also-secret" },
533
- };
534
- insertTool(conv.id, {
535
- id: "ti-secret",
536
- toolName: "http_request",
537
- input: JSON.stringify(rawInput),
538
- result: JSON.stringify({ status: 200 }),
539
- createdAt: 1100,
540
- });
541
-
542
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
543
- const call = trace.tool_calls[0];
544
- // Parsed input matches the raw stored input exactly — including the
545
- // credential-shaped values, which are present verbatim (not redacted).
546
- expect(call.input).toEqual(rawInput);
547
- const input = call.input as Record<string, unknown>;
548
- expect(input.access_token).toBe("super-secret-value");
549
- expect((input.nested as Record<string, unknown>).api_key).toBe(
550
- "also-secret",
551
- );
552
- expect(JSON.stringify(call.input)).not.toContain("<redacted />");
553
- // Result is also forwarded verbatim.
554
- expect(call.result).toBe(JSON.stringify({ status: 200 }));
555
- });
556
-
557
- test("non-JSON tool input is forwarded as a raw string", () => {
558
- const conv = createConversation({ conversationType: "standard" });
559
- insertMessage(conv.id, {
560
- id: "m-user-1",
561
- role: "user",
562
- content: [{ type: "text", text: "hi" }],
563
- createdAt: 1000,
564
- });
565
- insertTool(conv.id, {
566
- id: "ti-raw",
567
- toolName: "bash",
568
- input: "ls -la /tmp",
569
- result: "ok",
570
- createdAt: 1100,
571
- });
572
-
573
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
574
- expect(trace.tool_calls[0].input).toBe("ls -la /tmp");
575
- });
576
-
577
- test("legacy plain-string message content is forwarded as a string", () => {
578
- const conv = createConversation({ conversationType: "standard" });
579
- // A legacy row stored the content as a bare (JSON) string, not a block
580
- // array. JSON.parse of a quoted string yields a string; an unquoted
581
- // legacy value falls back to the raw string.
582
- insertMessage(conv.id, {
583
- id: "m-user-1",
584
- role: "user",
585
- content: "plain legacy text",
586
- createdAt: 1000,
587
- });
588
- const trace = assembleTurnTrace(boundary(conv.id, "m-user-1", 1000));
589
- expect(trace.messages[0].content).toBe("plain legacy text");
590
- });
591
-
592
- test("scopes the trace to a single conversation", () => {
593
- const a = createConversation({ conversationType: "standard" });
594
- const b = createConversation({ conversationType: "standard" });
595
- insertMessage(a.id, {
596
- id: "m-a-user",
597
- role: "user",
598
- content: [{ type: "text", text: "in A" }],
599
- createdAt: 1000,
600
- });
601
- insertMessage(b.id, {
602
- id: "m-b-user",
603
- role: "user",
604
- content: [{ type: "text", text: "in B" }],
605
- createdAt: 1050,
606
- });
607
- insertTool(b.id, {
608
- id: "ti-b",
609
- toolName: "noop",
610
- input: "{}",
611
- result: "ok",
612
- createdAt: 1060,
613
- });
614
-
615
- const trace = assembleTurnTrace(boundary(a.id, "m-a-user", 1000));
616
- expect(trace.messages.map((m) => m.id)).toEqual(["m-a-user"]);
617
- // Tool calls from conversation B never leak into A's trace.
618
- expect(trace.tool_calls).toEqual([]);
619
- });
620
- });
621
-
622
- describe("assembleTurnTrace — coalesced-batch natural windows", () => {
623
- // The daemon coalesces queued user messages: drainBatch persists every
624
- // batched user row, then runs ONE shared response attributed to the LAST
625
- // batched user row. On disk: [u1][u2][u3][assistant + tools][u4][assistant2].
626
- // No batch inference is attempted (there is no durable batch signal in the
627
- // stored messages, and a batch head is indistinguishable from a turn that
628
- // failed/cancelled before responding). Each turn just traces its natural
629
- // window, which is faithful.
630
- function seedThreeMessageBatch(convId: string): void {
631
- insertMessage(convId, {
632
- id: "u1",
633
- role: "user",
634
- content: [{ type: "text", text: "first batched" }],
635
- createdAt: 1000,
636
- });
637
- insertMessage(convId, {
638
- id: "u2",
639
- role: "user",
640
- content: [{ type: "text", text: "second batched" }],
641
- createdAt: 1010,
642
- });
643
- insertMessage(convId, {
644
- id: "u3",
645
- role: "user",
646
- content: [{ type: "text", text: "third batched (final)" }],
647
- createdAt: 1020,
648
- });
649
- // Shared response written AFTER the last batched user row, with a tool call.
650
- insertMessage(convId, {
651
- id: "a-shared",
652
- role: "assistant",
653
- content: [
654
- { type: "tool_use", id: "tu-1", name: "calendar", input: {} },
655
- { type: "text", text: "shared reply to all three" },
656
- ],
657
- createdAt: 1030,
658
- });
659
- insertMessage(convId, {
660
- id: "a-shared-toolresult",
661
- role: "user",
662
- content: [{ type: "tool_result", tool_use_id: "tu-1", content: "ok" }],
663
- createdAt: 1040,
664
- });
665
- insertTool(convId, {
666
- id: "ti-shared",
667
- toolName: "calendar",
668
- input: "{}",
669
- result: "ok",
670
- createdAt: 1035,
671
- });
672
- }
673
-
674
- test("a batched HEAD turn's trace contains only its own user row (faithful, no batch field)", () => {
675
- const conv = createConversation({ conversationType: "standard" });
676
- seedThreeMessageBatch(conv.id);
677
-
678
- const trace = assembleTurnTrace(boundary(conv.id, "u1", 1000));
679
- // Natural window: just the head's own user row. Its window genuinely has no
680
- // assistant response (the shared response is on the final batched turn).
681
- expect(trace.messages.map((m) => m.id)).toEqual(["u1"]);
682
- expect(trace.tool_calls).toEqual([]);
683
- // No batch inference: the response is not duplicated onto the head, and the
684
- // trace carries no `batch` field.
685
- expect(JSON.stringify(trace)).not.toContain("shared reply to all three");
686
- expect("batch" in trace).toBe(false);
687
- });
688
-
689
- test("a batched MIDDLE turn's trace also contains only its own user row", () => {
690
- const conv = createConversation({ conversationType: "standard" });
691
- seedThreeMessageBatch(conv.id);
692
-
693
- const trace = assembleTurnTrace(boundary(conv.id, "u2", 1010));
694
- expect(trace.messages.map((m) => m.id)).toEqual(["u2"]);
695
- expect(trace.tool_calls).toEqual([]);
696
- expect("batch" in trace).toBe(false);
697
- });
698
-
699
- test("the FINAL batched turn's trace contains the shared assistant response + tools", () => {
700
- const conv = createConversation({ conversationType: "standard" });
701
- seedThreeMessageBatch(conv.id);
702
-
703
- // The shared response is attributed by the daemon to the last batched user
704
- // row (lastUserMessageId == u3); u3's natural window includes it.
705
- const trace = assembleTurnTrace(boundary(conv.id, "u3", 1020));
706
- expect(trace.messages.map((m) => m.id)).toEqual([
707
- "u3",
708
- "a-shared",
709
- "a-shared-toolresult",
710
- ]);
711
- expect(trace.tool_calls.map((t) => t.id)).toEqual(["ti-shared"]);
712
- expect("batch" in trace).toBe(false);
713
- });
714
- });
715
-
716
- describe("assembleBoundedTurnTrace", () => {
717
- test("returns the trace when under the size cap", () => {
718
- const conv = createConversation({ conversationType: "standard" });
719
- insertMessage(conv.id, {
720
- id: "m-user-1",
721
- role: "user",
722
- content: [{ type: "text", text: "small" }],
723
- createdAt: 1000,
724
- });
725
- const trace = assembleBoundedTurnTrace(boundary(conv.id, "m-user-1", 1000));
726
- expect(trace).not.toBeNull();
727
- expect(trace?.messages.map((m) => m.id)).toEqual(["m-user-1"]);
728
- });
729
-
730
- test("omits (returns null) when the serialized trace exceeds the cap", () => {
731
- const conv = createConversation({ conversationType: "standard" });
732
- insertMessage(conv.id, {
733
- id: "m-user-1",
734
- role: "user",
735
- content: [{ type: "text", text: "huge" }],
736
- createdAt: 1000,
737
- });
738
- // A single oversized tool result pushes the trace past the cap.
739
- insertTool(conv.id, {
740
- id: "ti-huge",
741
- toolName: "dump",
742
- input: "{}",
743
- result: "x".repeat(MAX_TRACE_SERIALIZED_BYTES + 1024),
744
- createdAt: 1100,
745
- });
746
-
747
- const trace = assembleBoundedTurnTrace(boundary(conv.id, "m-user-1", 1000));
748
- expect(trace).toBeNull();
749
- });
750
- });
751
-
752
- describe("isTurnSettled", () => {
753
- test("batched head with a later real user row is NOT settled while the conversation is processing", () => {
754
- // Batched-message path: drainBatch persists the head user row AND the tail
755
- // user row(s) up front, then runs ONE shared response. So the head has a
756
- // later real user turn while the shared response is still in flight — it
757
- // must NOT be treated as settled (the old "successor exists" shortcut would
758
- // have shipped a partial trace for the head).
759
- const conv = createConversation({ conversationType: "standard" });
760
- insertMessage(conv.id, {
761
- id: "m-user-1",
762
- role: "user",
763
- content: [{ type: "text", text: "head of batch" }],
764
- createdAt: 1000,
765
- });
766
- insertMessage(conv.id, {
767
- id: "m-user-2",
768
- role: "user",
769
- content: [{ type: "text", text: "tail of batch" }],
770
- createdAt: 2000,
771
- });
772
- // Shared response still generating.
773
- mockLiveConversation = { isProcessing: () => true };
774
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(false);
775
- // The tail (latest turn) is likewise deferred while processing.
776
- expect(isTurnSettled(boundary(conv.id, "m-user-2", 2000))).toBe(false);
777
- });
778
-
779
- test("the batched head settles once the shared response completes (conversation idle)", () => {
780
- const conv = createConversation({ conversationType: "standard" });
781
- insertMessage(conv.id, {
782
- id: "m-user-1",
783
- role: "user",
784
- content: [{ type: "text", text: "head of batch" }],
785
- createdAt: 1000,
786
- });
787
- insertMessage(conv.id, {
788
- id: "m-user-2",
789
- role: "user",
790
- content: [{ type: "text", text: "tail of batch" }],
791
- createdAt: 2000,
792
- });
793
- // Shared response finished -> conversation idle -> both turns settle.
794
- mockLiveConversation = { isProcessing: () => false };
795
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(true);
796
- expect(isTurnSettled(boundary(conv.id, "m-user-2", 2000))).toBe(true);
797
- });
798
-
799
- test("a completed earlier turn defers while a later turn's response is in flight, then settles when idle", () => {
800
- // Serialized (non-batch) path: T1 finished, T2 now generating. Gating on
801
- // isProcessing() defers T1 until the conversation goes idle. This is a
802
- // latency cost, not data loss — T1 traces completely once T2 finishes.
803
- const conv = createConversation({ conversationType: "standard" });
804
- insertMessage(conv.id, {
805
- id: "m-user-1",
806
- role: "user",
807
- content: [{ type: "text", text: "first (done)" }],
808
- createdAt: 1000,
809
- });
810
- insertMessage(conv.id, {
811
- id: "m-user-2",
812
- role: "user",
813
- content: [{ type: "text", text: "second (generating)" }],
814
- createdAt: 2000,
815
- });
816
- mockLiveConversation = { isProcessing: () => true };
817
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(false);
818
-
819
- // Conversation goes idle -> the earlier turn settles promptly.
820
- mockLiveConversation = { isProcessing: () => false };
821
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(true);
822
- });
823
-
824
- test("settledness follows the conversation's processing state regardless of intervening tool-result rows", () => {
825
- const conv = createConversation({ conversationType: "standard" });
826
- insertMessage(conv.id, {
827
- id: "m-user-1",
828
- role: "user",
829
- content: [{ type: "text", text: "do a thing" }],
830
- createdAt: 1000,
831
- });
832
- // Tool-result row persisted as role="user" — part of this turn's response.
833
- insertMessage(conv.id, {
834
- id: "m-toolresult",
835
- role: "user",
836
- content: [{ type: "tool_result", tool_use_id: "tu-x", content: "done" }],
837
- createdAt: 1100,
838
- });
839
- // Still generating -> not settled.
840
- mockLiveConversation = { isProcessing: () => true };
841
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(false);
842
- // Response finished -> settled.
843
- mockLiveConversation = { isProcessing: () => false };
844
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(true);
845
- });
846
-
847
- test("NOT settled when this is the latest real user turn and the conversation is processing", () => {
848
- const conv = createConversation({ conversationType: "standard" });
849
- insertMessage(conv.id, {
850
- id: "m-user-1",
851
- role: "user",
852
- content: [{ type: "text", text: "still generating" }],
853
- createdAt: 1000,
854
- });
855
- // Latest real turn + live conversation actively processing -> in-flight.
856
- mockLiveConversation = { isProcessing: () => true };
857
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(false);
858
- });
859
-
860
- test("settled when this is the latest real user turn but the conversation is idle (final turn)", () => {
861
- const conv = createConversation({ conversationType: "standard" });
862
- insertMessage(conv.id, {
863
- id: "m-user-1",
864
- role: "user",
865
- content: [{ type: "text", text: "final turn" }],
866
- createdAt: 1000,
867
- });
868
- mockLiveConversation = { isProcessing: () => false };
869
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(true);
870
- });
871
-
872
- test("settled when the conversation is not in the live registry (evicted / not loaded)", () => {
873
- const conv = createConversation({ conversationType: "standard" });
874
- insertMessage(conv.id, {
875
- id: "m-user-1",
876
- role: "user",
877
- content: [{ type: "text", text: "from an evicted conversation" }],
878
- createdAt: 1000,
879
- });
880
- // No live conversation -> no in-flight turn -> settled.
881
- mockLiveConversation = undefined;
882
- expect(isTurnSettled(boundary(conv.id, "m-user-1", 1000))).toBe(true);
883
- });
884
- });