@vellumai/assistant 0.8.3 → 0.8.5

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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Text rendering for `assistant memory v3 validate` and `... tree`.
3
+ *
4
+ * Both functions are pure presentation: they take the daemon route's response
5
+ * shape and return a terminal-ready string. They live CLI-side (mirroring
6
+ * `memory-v2-compare-render.ts`) and import only the response *types* from the
7
+ * daemon route — `cli/no-daemon-internals` permits type-only imports but
8
+ * forbids pulling in daemon runtime modules.
9
+ */
10
+
11
+ import type {
12
+ DescentPass,
13
+ LlmCallRecord,
14
+ MemoryV3SimulateResult,
15
+ MemoryV3TreeResult,
16
+ MemoryV3ValidateResult,
17
+ } from "../../runtime/routes/memory-v3-routes.js";
18
+
19
+ /**
20
+ * Render a {@link MemoryV3ValidateResult} into a counts summary plus the
21
+ * offending ids for each non-empty category. Categories with zero entries
22
+ * print `none` so a clean tree reads at a glance.
23
+ */
24
+ export function renderValidationReport(report: MemoryV3ValidateResult): string {
25
+ const lines: string[] = [
26
+ "Memory v3 Tree Validation",
27
+ "=========================",
28
+ `Dangling child refs: ${report.danglingChildRefCount || "none"}`,
29
+ ];
30
+ for (const d of report.danglingChildRefs) {
31
+ lines.push(` - ${d.node} → ${d.kind}:${d.ref}`);
32
+ }
33
+
34
+ lines.push(`Orphan pages: ${report.orphanPageCount || "none"}`);
35
+ for (const slug of report.orphanPages) {
36
+ lines.push(` - ${slug}`);
37
+ }
38
+
39
+ lines.push(`Cycles: ${report.cycleCount || "none"}`);
40
+ for (const c of report.cycles) {
41
+ lines.push(` - ${c.from} → ${c.to}`);
42
+ }
43
+
44
+ lines.push(`Stale index: ${report.staleIndexCount || "none"}`);
45
+ for (const s of report.staleIndex) {
46
+ lines.push(` - ${s.node} (older than child ${s.child})`);
47
+ }
48
+
49
+ lines.push(
50
+ `Unknown edge targets: ${report.unknownEdgeTargetCount || "none"}`,
51
+ );
52
+ for (const e of report.unknownEdgeTargets) {
53
+ lines.push(` - ${e.from} → ${e.to}`);
54
+ }
55
+
56
+ return lines.join("\n");
57
+ }
58
+
59
+ /**
60
+ * Whether the validation report has any defect in any category. The CLI uses
61
+ * this to set a non-zero exit code so `validate` is scriptable as a check.
62
+ */
63
+ export function reportHasDefects(report: MemoryV3ValidateResult): boolean {
64
+ return (
65
+ report.danglingChildRefCount > 0 ||
66
+ report.orphanPageCount > 0 ||
67
+ report.cycleCount > 0 ||
68
+ report.staleIndexCount > 0 ||
69
+ report.unknownEdgeTargetCount > 0
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Render a {@link MemoryV3TreeResult} as an indented tree rooted at `view.root`,
75
+ * descending `node:` children depth-first. A node reached more than once
76
+ * (shared DAG sub-node) is printed once with a `(↑ …)` re-entry marker rather
77
+ * than re-expanded, which also bounds output when the structure contains a
78
+ * cycle. `page:` children are printed as leaves under their parent node.
79
+ */
80
+ export function renderTree(view: MemoryV3TreeResult): string {
81
+ const childrenById = new Map<string, MemoryV3TreeResult["nodes"][number]>();
82
+ for (const node of view.nodes) {
83
+ childrenById.set(node.id, node);
84
+ }
85
+
86
+ const lines: string[] = [];
87
+ const expanded = new Set<string>();
88
+
89
+ const walk = (nodeId: string, depth: number): void => {
90
+ const indent = " ".repeat(depth);
91
+ const node = childrenById.get(nodeId);
92
+
93
+ if (!node) {
94
+ lines.push(`${indent}node:${nodeId} (missing)`);
95
+ return;
96
+ }
97
+
98
+ if (expanded.has(nodeId)) {
99
+ // Shared DAG sub-node (or a cycle's back-edge): print the reference but
100
+ // do not re-expand, so output stays finite and the re-entry is visible.
101
+ lines.push(`${indent}node:${nodeId} (↑ already shown)`);
102
+ return;
103
+ }
104
+ expanded.add(nodeId);
105
+ lines.push(`${indent}node:${nodeId}`);
106
+
107
+ for (const child of node.children) {
108
+ if (child.kind === "page") {
109
+ lines.push(`${" ".repeat(depth + 1)}page:${child.ref}`);
110
+ } else {
111
+ walk(child.ref, depth + 1);
112
+ }
113
+ }
114
+ };
115
+
116
+ walk(view.root, 0);
117
+
118
+ if (lines.length === 0) {
119
+ lines.push("(empty tree)");
120
+ }
121
+
122
+ // Surface nodes that exist on disk but were never reached from the root —
123
+ // they would otherwise be invisible in a root-anchored print.
124
+ const unreached = view.nodes
125
+ .map((n) => n.id)
126
+ .filter((id) => !expanded.has(id))
127
+ .sort();
128
+ if (unreached.length > 0) {
129
+ lines.push("", `Unreachable nodes (${unreached.length}):`);
130
+ for (const id of unreached) {
131
+ lines.push(` - node:${id}`);
132
+ }
133
+ }
134
+
135
+ return lines.join("\n");
136
+ }
137
+
138
+ /** Canonical print order for the loop's provenance lanes. */
139
+ const SIMULATE_LANE_ORDER = ["hot", "sparse", "dense", "tree", "edge"] as const;
140
+
141
+ /** Render the effective lane toggles as a one-line `on` / restricted summary. */
142
+ function renderEffectiveLanes(
143
+ lanes: MemoryV3SimulateResult["effectiveConfig"]["lanes"],
144
+ ): string {
145
+ const on = Object.entries(lanes)
146
+ .filter(([, enabled]) => enabled)
147
+ .map(([name]) => name);
148
+ const off = Object.entries(lanes)
149
+ .filter(([, enabled]) => !enabled)
150
+ .map(([name]) => name);
151
+ if (off.length === 0) return on.join(", ");
152
+ return `${on.join(", ")} (off: ${off.join(", ")})`;
153
+ }
154
+
155
+ /** Render one pass's scout / tree / edge / gate breakdown into `lines`. */
156
+ function renderPass(pass: DescentPass, lines: string[]): void {
157
+ lines.push(`Pass ${pass.passNumber}`);
158
+
159
+ if (pass.scouts && pass.scouts.length > 0) {
160
+ const summary = pass.scouts
161
+ .map((s) => `${s.lane}=${s.slugs.length}`)
162
+ .join(" ");
163
+ lines.push(` scouts: ${summary}`);
164
+ }
165
+
166
+ if (pass.treeLevels && pass.treeLevels.length > 0) {
167
+ lines.push(` tree: ${pass.treeLevels.length} level(s)`);
168
+ for (const level of pass.treeLevels) {
169
+ const node = level.node === "" ? "[root]" : level.node;
170
+ lines.push(
171
+ ` ${node}: considered ${level.considered.length}, descended ${level.descended.length}, skipped ${level.skipped.length}`,
172
+ );
173
+ if (level.descended.length > 0) {
174
+ lines.push(` → ${level.descended.join(", ")}`);
175
+ }
176
+ if (level.reasoning.trim().length > 0) {
177
+ lines.push(` reason: ${level.reasoning.trim()}`);
178
+ }
179
+ }
180
+ }
181
+
182
+ if (pass.edgeExpansions && pass.edgeExpansions.length > 0) {
183
+ const pulled = pass.edgeExpansions.reduce((n, e) => n + e.pulled.length, 0);
184
+ lines.push(
185
+ ` edges: ${pass.edgeExpansions.length} seed(s) expanded, ${pulled} pulled`,
186
+ );
187
+ }
188
+
189
+ if (pass.gate) {
190
+ lines.push(` gate: ${pass.gate.decision}`);
191
+ for (const q of pass.gate.questions ?? []) {
192
+ lines.push(` ? ${q}`);
193
+ }
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Render a {@link MemoryV3SimulateResult} into a query echo, effective config,
199
+ * per-pass descent breakdown, and the final selection grouped by provenance
200
+ * lane (in fanout order). Mirrors the grouped layout of `memory v2 simulate`.
201
+ */
202
+ export function renderSimulation(result: MemoryV3SimulateResult): string {
203
+ const lines: string[] = [
204
+ "Memory v3 Retrieval Simulation",
205
+ "==============================",
206
+ `Query: ${JSON.stringify(result.query)}`,
207
+ "",
208
+ "Config (effective):",
209
+ ` passCap: ${result.effectiveConfig.passCap}`,
210
+ ` lanes: ${renderEffectiveLanes(result.effectiveConfig.lanes)}`,
211
+ "",
212
+ ];
213
+
214
+ const passes = result.trace.passes;
215
+ lines.push(`Passes: ${passes.length || "none"}`);
216
+ for (const pass of passes) {
217
+ lines.push("");
218
+ renderPass(pass, lines);
219
+ }
220
+ lines.push("");
221
+
222
+ lines.push(`Selected: ${result.selectedSlugs.length} page(s)`);
223
+ const grouped = new Map<string, string[]>();
224
+ for (const slug of result.selectedSlugs) {
225
+ const lane = result.sourceBySlug[slug] ?? "unknown";
226
+ const bucket = grouped.get(lane) ?? [];
227
+ bucket.push(slug);
228
+ grouped.set(lane, bucket);
229
+ }
230
+ const laneRank = (lane: string): number => {
231
+ const i = SIMULATE_LANE_ORDER.indexOf(
232
+ lane as (typeof SIMULATE_LANE_ORDER)[number],
233
+ );
234
+ return i === -1 ? SIMULATE_LANE_ORDER.length : i;
235
+ };
236
+ const lanes = [...grouped.keys()].sort((a, b) => laneRank(a) - laneRank(b));
237
+ for (const lane of lanes) {
238
+ const slugs = grouped.get(lane)!;
239
+ lines.push(` ${lane} (${slugs.length})`);
240
+ for (const slug of slugs) {
241
+ lines.push(` - ${slug}`);
242
+ }
243
+ }
244
+
245
+ if (result.cost.ms !== undefined) {
246
+ lines.push("", `Cost: ${result.cost.ms} ms`);
247
+ }
248
+ if (result.failureReason) {
249
+ lines.push(`Failure: ${result.failureReason}`);
250
+ }
251
+
252
+ return lines.join("\n");
253
+ }
254
+
255
+ // ── LLM-call capture ────────────────────────────────────────────────────────
256
+
257
+ type CapturedMessage = LlmCallRecord["request"]["messages"][number];
258
+ type CapturedBlock = LlmCallRecord["response"]["content"][number];
259
+
260
+ /** Concatenate the text blocks of a message (non-text blocks are ignored). */
261
+ function messageText(message: CapturedMessage): string {
262
+ return message.content
263
+ .filter(
264
+ (b): b is Extract<CapturedBlock, { type: "text" }> => b.type === "text",
265
+ )
266
+ .map((b) => b.text)
267
+ .join("\n");
268
+ }
269
+
270
+ /** The forced-tool block from a response, if the model returned one. */
271
+ function toolUseOf(
272
+ call: LlmCallRecord,
273
+ ): Extract<CapturedBlock, { type: "tool_use" }> | undefined {
274
+ return call.response.content.find(
275
+ (b): b is Extract<CapturedBlock, { type: "tool_use" }> =>
276
+ b.type === "tool_use",
277
+ );
278
+ }
279
+
280
+ function truncate(s: string, max: number): string {
281
+ const oneLine = s.replace(/\s+/g, " ").trim();
282
+ return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine;
283
+ }
284
+
285
+ function indent(s: string, by = " "): string {
286
+ return s
287
+ .split("\n")
288
+ .map((line) => by + line)
289
+ .join("\n");
290
+ }
291
+
292
+ /**
293
+ * Render the captured v3 LLM calls. Compact (default): one line per call —
294
+ * pass/lane/node, input size, round-trip ms, and the forced-tool summary. Full
295
+ * (`--show-llm`): the system prompt, every message, the tool names, and the
296
+ * tool_use input for each call. Grouped in call order (which is pass order).
297
+ */
298
+ export function renderLlmCalls(
299
+ calls: readonly LlmCallRecord[],
300
+ opts: { full: boolean },
301
+ ): string {
302
+ if (calls.length === 0) return "LLM calls: none";
303
+
304
+ const lines: string[] = [`LLM calls (${calls.length}):`];
305
+ for (const call of calls) {
306
+ const label =
307
+ `pass${call.pass} · ${call.lane}` +
308
+ (call.node ? ` · node=${call.node}` : "");
309
+ const inputChars =
310
+ call.request.systemPrompt.length +
311
+ call.request.messages.reduce((n, m) => n + messageText(m).length, 0);
312
+ const tool = toolUseOf(call);
313
+ const toolSummary = tool
314
+ ? `${tool.name}(${truncate(JSON.stringify(tool.input), 80)})`
315
+ : `no tool_use (stop=${call.response.stopReason})`;
316
+
317
+ if (!opts.full) {
318
+ lines.push(
319
+ ` ${label} · in ${inputChars}c · ${call.ms}ms · ${truncate(toolSummary, 100)}`,
320
+ );
321
+ continue;
322
+ }
323
+
324
+ lines.push("", `── ${label} (${call.callSite}, ${call.ms}ms) ──`);
325
+ lines.push("system:", indent(call.request.systemPrompt));
326
+ lines.push("messages:");
327
+ for (const message of call.request.messages) {
328
+ lines.push(
329
+ indent(`[${message.role}]`),
330
+ indent(messageText(message), " "),
331
+ );
332
+ }
333
+ lines.push(`tools: ${call.request.tools.map((t) => t.name).join(", ")}`);
334
+ lines.push("output:");
335
+ lines.push(
336
+ indent(
337
+ tool
338
+ ? `${tool.name} ${JSON.stringify(tool.input, null, 2)}`
339
+ : `(no tool_use, stop=${call.response.stopReason})`,
340
+ ),
341
+ );
342
+ }
343
+ return lines.join("\n");
344
+ }
@@ -0,0 +1,316 @@
1
+ /**
2
+ * `assistant memory v3` CLI subgroup.
3
+ *
4
+ * Operator-facing read-only inspection of the v3 memory tree — the DAG overlay
5
+ * the v2 → v3 data-migration hand-authors over the flat concept pages.
6
+ *
7
+ * Subcommands:
8
+ *
9
+ * - `validate` — print a structural health report (dangling refs, orphan
10
+ * pages, cycles, stale indexes, unknown edge targets). Exits non-zero when
11
+ * any defect is found so it is scriptable as a check.
12
+ * - `tree` — print the tree as an indented outline rooted at the tree root,
13
+ * marking shared-DAG re-entries.
14
+ * - `simulate` — dry-run the v3 retrieval loop against an ad-hoc query and
15
+ * print the per-pass descent trace plus the lane-grouped selection.
16
+ *
17
+ * All are read-only: they mutate nothing. `validate`/`tree` run no LLM;
18
+ * `simulate` invokes the loop (filter + gate LLM calls) but persists nothing.
19
+ * `--json` emits the raw daemon payload for any subcommand.
20
+ */
21
+
22
+ import { mkdirSync, writeFileSync } from "node:fs";
23
+ import { join } from "node:path";
24
+
25
+ import type { Command } from "commander";
26
+
27
+ import { cliIpcCall } from "../../ipc/cli-client.js";
28
+ import type {
29
+ MemoryV3SimulateResult,
30
+ MemoryV3TreeResult,
31
+ MemoryV3ValidateResult,
32
+ } from "../../runtime/routes/memory-v3-routes.js";
33
+ import { registerCommand } from "../lib/register-command.js";
34
+ import { log } from "../logger.js";
35
+ import {
36
+ renderLlmCalls,
37
+ renderSimulation,
38
+ renderTree,
39
+ renderValidationReport,
40
+ reportHasDefects,
41
+ } from "./memory-v3-render.js";
42
+
43
+ /** Valid lane names accepted by `--lanes` (matches memory.v3.lanes keys). */
44
+ const V3_LANE_NAMES = ["hot", "sparse", "dense", "tree", "edges"] as const;
45
+
46
+ export function registerMemoryV3Command(program: Command): void {
47
+ // Reuse an existing `memory` parent if a sibling registrar (e.g. v2)
48
+ // attached it first; otherwise create one. Keeps registration order between
49
+ // sibling memory registrars unconstrained.
50
+ const memory =
51
+ program.commands.find((c) => c.name() === "memory") ??
52
+ program
53
+ .command("memory")
54
+ .description("Manage the memory subsystem (concept-page model)");
55
+
56
+ registerCommand(memory, {
57
+ name: "v3",
58
+ transport: "ipc",
59
+ description: "Memory v3 subsystem operations (tree-DAG overlay)",
60
+ build: (v3) => {
61
+ v3.addHelpText(
62
+ "after",
63
+ `
64
+ The v3 memory subsystem layers a hand-authored DAG of tree nodes over the
65
+ flat v2 concept pages. Each node lives under /workspace/memory/tree/ and
66
+ its frontmatter 'children' list references sub-nodes (node:<id>) and leaf
67
+ concept pages (page:<slug>). The structure is authored by the v2 → v3
68
+ data-migration, so these subcommands are read-only inspection only — they
69
+ mutate nothing and run no LLM.
70
+
71
+ Examples:
72
+ $ assistant memory v3 validate
73
+ $ assistant memory v3 tree
74
+ $ assistant memory v3 tree --json | jq '.nodes | length'
75
+ $ assistant memory v3 simulate -q "what should we ship next"`,
76
+ );
77
+
78
+ // ── validate ──────────────────────────────────────────────────────────
79
+
80
+ v3.command("validate")
81
+ .description(
82
+ "Print a structural health report of the v3 tree (read-only)",
83
+ )
84
+ .option("--json", "Emit raw JSON instead of a formatted report")
85
+ .addHelpText(
86
+ "after",
87
+ `
88
+ Walks the hand-authored v3 tree DAG and reports:
89
+ - Dangling child refs (node:/page: targets that do not exist)
90
+ - Orphan pages (concept pages not reachable from the tree root)
91
+ - Cycles (back-edges in the node:/node: adjacency)
92
+ - Stale indexes (a node older than a child it composes)
93
+ - Unknown edge targets (page edges: pointing at a missing slug)
94
+
95
+ Read-only — mutates nothing. Exits non-zero if any defect is reported, so it
96
+ is usable as a pre-flight check while the v2 → v3 migration is in flight.
97
+
98
+ Examples:
99
+ $ assistant memory v3 validate
100
+ $ assistant memory v3 validate --json | jq '.orphanPageCount'`,
101
+ )
102
+ .action(async (opts: { json?: boolean }) => {
103
+ const result = await cliIpcCall<MemoryV3ValidateResult>(
104
+ "memory_v3_validate",
105
+ { body: {} },
106
+ );
107
+
108
+ if (!result.ok) {
109
+ log.error(result.error ?? "Failed to validate memory v3 tree");
110
+ process.exitCode = 1;
111
+ return;
112
+ }
113
+
114
+ const report = result.result!;
115
+
116
+ if (opts.json === true) {
117
+ log.info(JSON.stringify(report, null, 2));
118
+ } else {
119
+ log.info(renderValidationReport(report));
120
+ }
121
+
122
+ if (reportHasDefects(report)) {
123
+ process.exitCode = 1;
124
+ }
125
+ });
126
+
127
+ // ── tree ──────────────────────────────────────────────────────────────
128
+
129
+ v3.command("tree")
130
+ .description(
131
+ "Print the v3 tree as an indented outline from the root (read-only)",
132
+ )
133
+ .option("--json", "Emit raw JSON instead of a formatted tree")
134
+ .addHelpText(
135
+ "after",
136
+ `
137
+ Descends the v3 tree depth-first from its root node, printing one line per
138
+ node:/page: ref with indentation by depth. A node reached more than once
139
+ (shared DAG sub-node or a cycle back-edge) is printed once with a re-entry
140
+ marker rather than re-expanded, so output is finite. Nodes that exist on disk
141
+ but are unreachable from the root are listed separately.
142
+
143
+ Read-only — mutates nothing.
144
+
145
+ Examples:
146
+ $ assistant memory v3 tree
147
+ $ assistant memory v3 tree --json | jq '.root'`,
148
+ )
149
+ .action(async (opts: { json?: boolean }) => {
150
+ const result = await cliIpcCall<MemoryV3TreeResult>(
151
+ "memory_v3_tree",
152
+ {
153
+ body: {},
154
+ },
155
+ );
156
+
157
+ if (!result.ok) {
158
+ log.error(result.error ?? "Failed to read memory v3 tree");
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+
163
+ const view = result.result!;
164
+
165
+ if (opts.json === true) {
166
+ log.info(JSON.stringify(view, null, 2));
167
+ return;
168
+ }
169
+
170
+ log.info(renderTree(view));
171
+ });
172
+
173
+ // ── simulate ────────────────────────────────────────────────────────────
174
+
175
+ v3.command("simulate")
176
+ .description(
177
+ "Dry-run the v3 retrieval loop against an ad-hoc query (read-only)",
178
+ )
179
+ .requiredOption(
180
+ "-q, --query <text>",
181
+ "User query to run a single synthetic retrieval turn against",
182
+ )
183
+ .option(
184
+ "--pass-cap <n>",
185
+ "Override memory.v3.passCap for this run (positive integer)",
186
+ )
187
+ .option(
188
+ "--lanes <list>",
189
+ `Restrict to a comma-separated allowlist of lanes (others off): ${V3_LANE_NAMES.join(", ")}`,
190
+ )
191
+ .option("--json", "Emit raw JSON instead of a formatted report")
192
+ .option(
193
+ "--show-llm",
194
+ "Print the full input + output of every v3 LLM call (filter / descender / gate)",
195
+ )
196
+ .option(
197
+ "--dump-llm <dir>",
198
+ "Write one JSON file per v3 LLM call into <dir> (full request + raw response)",
199
+ )
200
+ .addHelpText(
201
+ "after",
202
+ `
203
+ Runs the v3 multi-lane bounded-descent loop read-only against the live page
204
+ index + tree DAG, building a single synthetic turn from the query plus the live
205
+ NOW context. Prints the per-pass descent trace (scouts / tree levels / edge
206
+ expansions / gate verdict) and the final selection grouped by provenance lane.
207
+
208
+ The loop is invoked directly — it does NOT require memory.v3.enabled or
209
+ memory.v3.shadow, so you can probe v3 retrieval before the flags flip. Writes
210
+ nothing (co-activation persistence is forced off), but each pass still spends
211
+ the loop's dense-filter + gate LLM calls, so pass-cap is the cost knob.
212
+
213
+ Examples:
214
+ $ assistant memory v3 simulate -q "what should we ship next"
215
+ $ assistant memory v3 simulate -q "..." --lanes tree,edges
216
+ $ assistant memory v3 simulate -q "..." --pass-cap 1 --json | jq '.selectedSlugs'
217
+ $ assistant memory v3 simulate -q "..." --show-llm
218
+ $ assistant memory v3 simulate -q "..." --dump-llm /tmp/v3-calls`,
219
+ )
220
+ .action(
221
+ async (opts: {
222
+ query: string;
223
+ passCap?: string;
224
+ lanes?: string;
225
+ json?: boolean;
226
+ showLlm?: boolean;
227
+ dumpLlm?: string;
228
+ }) => {
229
+ let passCap: number | undefined;
230
+ if (opts.passCap !== undefined) {
231
+ const parsed = Number(opts.passCap);
232
+ if (!Number.isInteger(parsed) || parsed < 1) {
233
+ log.error(
234
+ `--pass-cap must be a positive integer (got "${opts.passCap}")`,
235
+ );
236
+ process.exitCode = 1;
237
+ return;
238
+ }
239
+ passCap = parsed;
240
+ }
241
+
242
+ let lanes: string[] | undefined;
243
+ if (opts.lanes !== undefined) {
244
+ const requested = opts.lanes
245
+ .split(",")
246
+ .map((s) => s.trim())
247
+ .filter((s) => s.length > 0);
248
+ const invalid = requested.filter(
249
+ (l) =>
250
+ !V3_LANE_NAMES.includes(l as (typeof V3_LANE_NAMES)[number]),
251
+ );
252
+ if (invalid.length > 0) {
253
+ log.error(
254
+ `--lanes contains unknown lane(s): ${invalid.join(", ")}. Valid: ${V3_LANE_NAMES.join(", ")}`,
255
+ );
256
+ process.exitCode = 1;
257
+ return;
258
+ }
259
+ if (requested.length === 0) {
260
+ log.error("--lanes must list at least one lane");
261
+ process.exitCode = 1;
262
+ return;
263
+ }
264
+ lanes = requested;
265
+ }
266
+
267
+ const result = await cliIpcCall<MemoryV3SimulateResult>(
268
+ "memory_v3_simulate",
269
+ {
270
+ body: {
271
+ query: opts.query,
272
+ ...(passCap !== undefined ? { passCap } : {}),
273
+ ...(lanes !== undefined ? { lanes } : {}),
274
+ },
275
+ },
276
+ );
277
+
278
+ if (!result.ok) {
279
+ log.error(result.error ?? "Failed to simulate v3 retrieval");
280
+ process.exitCode = 1;
281
+ return;
282
+ }
283
+
284
+ const payload = result.result!;
285
+ if (opts.json === true) {
286
+ log.info(JSON.stringify(payload, null, 2));
287
+ return;
288
+ }
289
+ log.info(renderSimulation(payload));
290
+
291
+ log.info("");
292
+ log.info(
293
+ renderLlmCalls(payload.llmCalls, { full: opts.showLlm === true }),
294
+ );
295
+
296
+ if (opts.dumpLlm !== undefined) {
297
+ mkdirSync(opts.dumpLlm, { recursive: true });
298
+ for (const call of payload.llmCalls) {
299
+ const nodePart = call.node
300
+ ? `-${call.node.replace(/\//g, "_")}`
301
+ : "";
302
+ const file = join(
303
+ opts.dumpLlm,
304
+ `pass${call.pass}-${call.lane}${nodePart}.json`,
305
+ );
306
+ writeFileSync(file, JSON.stringify(call, null, 2));
307
+ }
308
+ log.info(
309
+ `\nWrote ${payload.llmCalls.length} LLM-call file(s) to ${opts.dumpLlm}`,
310
+ );
311
+ }
312
+ },
313
+ );
314
+ },
315
+ });
316
+ }