@vellumai/assistant 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -0,0 +1,185 @@
1
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
2
+ import { getConfig } from "../config/loader.js";
3
+ import type { LLMCallSite } from "../config/schemas/llm.js";
4
+ import { safeStringSlice } from "../util/unicode.js";
5
+
6
+ const MAX_METADATA_VALUE_LENGTH = 128;
7
+
8
+ export type UsageAttributionProfileSource =
9
+ | "call_site"
10
+ | "conversation"
11
+ | "active"
12
+ | "default"
13
+ | "unknown";
14
+
15
+ export interface UsageAttributionInput {
16
+ callSite: LLMCallSite | null;
17
+ overrideProfile?: string | null;
18
+ }
19
+
20
+ export interface UsageAttributionSnapshot {
21
+ callSite: LLMCallSite | null;
22
+ activeProfile: string | null;
23
+ overrideProfile: string | null;
24
+ callSiteProfile: string | null;
25
+ appliedProfile: string | null;
26
+ profileSource: UsageAttributionProfileSource;
27
+ resolvedProvider: string;
28
+ resolvedModel: string;
29
+ }
30
+
31
+ /**
32
+ * Sanitizes values before they are copied into external metadata surfaces.
33
+ * Empty strings and control-character-bearing strings are dropped, and long
34
+ * values are capped so later forwarding cannot create unbounded headers.
35
+ */
36
+ export function sanitizeUsageMetadataValue(value: unknown): string | null {
37
+ if (typeof value !== "string") return null;
38
+
39
+ const trimmed = value.trim();
40
+ if (trimmed.length === 0) return null;
41
+ if (containsControlCharacter(trimmed)) return null;
42
+
43
+ return safeStringSlice(trimmed, 0, MAX_METADATA_VALUE_LENGTH);
44
+ }
45
+
46
+ export function resolveUsageAttribution(
47
+ input: UsageAttributionInput,
48
+ ): UsageAttributionSnapshot {
49
+ const llm = getConfig().llm;
50
+ const callSite = input.callSite;
51
+ const overrideProfile = normalizeProfileId(input.overrideProfile);
52
+
53
+ if (callSite == null) {
54
+ return {
55
+ callSite: null,
56
+ activeProfile: normalizeProfileId(llm.activeProfile),
57
+ overrideProfile,
58
+ callSiteProfile: null,
59
+ appliedProfile: null,
60
+ profileSource: "unknown",
61
+ resolvedProvider: llm.default.provider,
62
+ resolvedModel: llm.default.model,
63
+ };
64
+ }
65
+
66
+ const resolved = resolveCallSiteConfig(callSite, llm, {
67
+ ...(overrideProfile != null ? { overrideProfile } : {}),
68
+ });
69
+ const activeProfile = normalizeProfileId(llm.activeProfile);
70
+ const callSiteProfile = normalizeProfileId(
71
+ llm.callSites?.[callSite]?.profile,
72
+ );
73
+ const profile = resolveAppliedProfile({
74
+ callSite,
75
+ profiles: llm.profiles ?? {},
76
+ activeProfile,
77
+ overrideProfile,
78
+ callSiteProfile,
79
+ });
80
+
81
+ return {
82
+ callSite,
83
+ activeProfile,
84
+ overrideProfile,
85
+ callSiteProfile,
86
+ appliedProfile: profile.appliedProfile,
87
+ profileSource: profile.profileSource,
88
+ resolvedProvider: resolved.provider,
89
+ resolvedModel: resolved.model,
90
+ };
91
+ }
92
+
93
+ function resolveAppliedProfile(input: {
94
+ callSite: LLMCallSite;
95
+ profiles: Record<string, unknown>;
96
+ activeProfile: string | null;
97
+ overrideProfile: string | null;
98
+ callSiteProfile: string | null;
99
+ }): Pick<UsageAttributionSnapshot, "appliedProfile" | "profileSource"> {
100
+ if (input.callSite === "mainAgent") {
101
+ if (
102
+ input.overrideProfile != null &&
103
+ input.profiles[input.overrideProfile] != null
104
+ ) {
105
+ return {
106
+ appliedProfile: input.overrideProfile,
107
+ profileSource: "conversation",
108
+ };
109
+ }
110
+
111
+ if (
112
+ input.activeProfile != null &&
113
+ input.profiles[input.activeProfile] != null
114
+ ) {
115
+ return {
116
+ appliedProfile: input.activeProfile,
117
+ profileSource: "active",
118
+ };
119
+ }
120
+
121
+ if (
122
+ input.callSiteProfile != null &&
123
+ input.profiles[input.callSiteProfile] != null
124
+ ) {
125
+ return {
126
+ appliedProfile: input.callSiteProfile,
127
+ profileSource: "call_site",
128
+ };
129
+ }
130
+
131
+ return {
132
+ appliedProfile: null,
133
+ profileSource: "default",
134
+ };
135
+ }
136
+
137
+ if (
138
+ input.callSiteProfile != null &&
139
+ input.profiles[input.callSiteProfile] != null
140
+ ) {
141
+ return {
142
+ appliedProfile: input.callSiteProfile,
143
+ profileSource: "call_site",
144
+ };
145
+ }
146
+
147
+ if (
148
+ input.overrideProfile != null &&
149
+ input.profiles[input.overrideProfile] != null
150
+ ) {
151
+ return {
152
+ appliedProfile: input.overrideProfile,
153
+ profileSource: "conversation",
154
+ };
155
+ }
156
+
157
+ if (
158
+ input.activeProfile != null &&
159
+ input.profiles[input.activeProfile] != null
160
+ ) {
161
+ return {
162
+ appliedProfile: input.activeProfile,
163
+ profileSource: "active",
164
+ };
165
+ }
166
+
167
+ return {
168
+ appliedProfile: null,
169
+ profileSource: "default",
170
+ };
171
+ }
172
+
173
+ function normalizeProfileId(value: string | null | undefined): string | null {
174
+ return value ?? null;
175
+ }
176
+
177
+ function containsControlCharacter(value: string): boolean {
178
+ for (let i = 0; i < value.length; i++) {
179
+ const code = value.charCodeAt(i);
180
+ if (code < 0x20 || (code >= 0x7f && code <= 0x9f)) {
181
+ return true;
182
+ }
183
+ }
184
+ return false;
185
+ }
@@ -0,0 +1,166 @@
1
+ import { getConfig } from "../config/loader.js";
2
+ import type { ProviderResponse } from "../providers/types.js";
3
+ import { getLogger } from "../util/logger.js";
4
+ import {
5
+ resolvePricingForUsageWithOverrides,
6
+ usesAnthropicPricingRules,
7
+ } from "../util/pricing.js";
8
+ import type {
9
+ AnthropicCacheCreationTokenDetails,
10
+ PricingResult,
11
+ PricingUsage,
12
+ } from "./types.js";
13
+
14
+ const log = getLogger("usage-pricing");
15
+
16
+ export function normalizeTokenCount(value: number | null | undefined): number {
17
+ if (typeof value !== "number" || !Number.isFinite(value)) return 0;
18
+ return Math.max(value, 0);
19
+ }
20
+
21
+ function asRecord(value: unknown): Record<string, unknown> | null {
22
+ if (typeof value !== "object" || value == null) return null;
23
+ return value as Record<string, unknown>;
24
+ }
25
+
26
+ function extractAnthropicCacheCreationFromResponse(
27
+ response: unknown,
28
+ ): AnthropicCacheCreationTokenDetails | null {
29
+ const rawResponse = asRecord(response);
30
+ const usage = asRecord(rawResponse?.usage);
31
+ const cacheCreation = asRecord(usage?.cache_creation);
32
+ if (!cacheCreation) return null;
33
+
34
+ return {
35
+ ephemeral_5m_input_tokens: normalizeTokenCount(
36
+ cacheCreation.ephemeral_5m_input_tokens as number | null | undefined,
37
+ ),
38
+ ephemeral_1h_input_tokens: normalizeTokenCount(
39
+ cacheCreation.ephemeral_1h_input_tokens as number | null | undefined,
40
+ ),
41
+ };
42
+ }
43
+
44
+ function extractAnthropicCacheCreation(
45
+ rawResponse: unknown,
46
+ ): AnthropicCacheCreationTokenDetails | null {
47
+ const responses = Array.isArray(rawResponse) ? rawResponse : [rawResponse];
48
+ let foundDetails = false;
49
+ let ephemeral5mInputTokens = 0;
50
+ let ephemeral1hInputTokens = 0;
51
+
52
+ for (const response of responses) {
53
+ const details = extractAnthropicCacheCreationFromResponse(response);
54
+ if (!details) continue;
55
+ foundDetails = true;
56
+ ephemeral5mInputTokens += normalizeTokenCount(
57
+ details.ephemeral_5m_input_tokens,
58
+ );
59
+ ephemeral1hInputTokens += normalizeTokenCount(
60
+ details.ephemeral_1h_input_tokens,
61
+ );
62
+ }
63
+
64
+ if (!foundDetails) return null;
65
+
66
+ return {
67
+ ephemeral_5m_input_tokens: ephemeral5mInputTokens,
68
+ ephemeral_1h_input_tokens: ephemeral1hInputTokens,
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Extract the speed indicator from Anthropic fast mode API responses.
74
+ * The API returns `usage.speed: "fast" | "standard"` when using the
75
+ * fast-mode beta. For multi-response arrays, returns "fast" if any
76
+ * response used fast mode.
77
+ */
78
+ function extractAnthropicSpeed(
79
+ rawResponse: unknown,
80
+ ): "fast" | "standard" | null {
81
+ const responses = Array.isArray(rawResponse) ? rawResponse : [rawResponse];
82
+ let foundStandard = false;
83
+ for (const response of responses) {
84
+ const rec = asRecord(response);
85
+ const usage = asRecord(rec?.usage);
86
+ if (usage?.speed === "fast") return "fast";
87
+ if (usage?.speed === "standard") foundStandard = true;
88
+ }
89
+ return foundStandard ? "standard" : null;
90
+ }
91
+
92
+ export function buildPricingUsage(input: {
93
+ providerName: string;
94
+ model: string;
95
+ inputTokens: number;
96
+ outputTokens: number;
97
+ cacheCreationInputTokens?: number | null;
98
+ cacheReadInputTokens?: number | null;
99
+ rawResponse?: unknown;
100
+ }): PricingUsage & {
101
+ directInputTokens: number;
102
+ cacheCreationInputTokens: number;
103
+ cacheReadInputTokens: number;
104
+ } {
105
+ const normalizedCacheCreationInputTokens = normalizeTokenCount(
106
+ input.cacheCreationInputTokens,
107
+ );
108
+ const normalizedCacheReadInputTokens = normalizeTokenCount(
109
+ input.cacheReadInputTokens,
110
+ );
111
+ const directInputTokens = Math.max(
112
+ normalizeTokenCount(input.inputTokens) -
113
+ normalizedCacheCreationInputTokens -
114
+ normalizedCacheReadInputTokens,
115
+ 0,
116
+ );
117
+
118
+ const useAnthropicRules = usesAnthropicPricingRules(
119
+ input.providerName,
120
+ input.model,
121
+ );
122
+ return {
123
+ directInputTokens,
124
+ outputTokens: normalizeTokenCount(input.outputTokens),
125
+ cacheCreationInputTokens: normalizedCacheCreationInputTokens,
126
+ cacheReadInputTokens: normalizedCacheReadInputTokens,
127
+ anthropicCacheCreation: useAnthropicRules
128
+ ? extractAnthropicCacheCreation(input.rawResponse)
129
+ : null,
130
+ speed: useAnthropicRules ? extractAnthropicSpeed(input.rawResponse) : null,
131
+ };
132
+ }
133
+
134
+ export function buildPricingUsageFromResponse(
135
+ providerName: string,
136
+ response: ProviderResponse,
137
+ ): ReturnType<typeof buildPricingUsage> {
138
+ return buildPricingUsage({
139
+ providerName,
140
+ model: response.model,
141
+ inputTokens: response.usage.inputTokens,
142
+ outputTokens: response.usage.outputTokens,
143
+ cacheCreationInputTokens: response.usage.cacheCreationInputTokens,
144
+ cacheReadInputTokens: response.usage.cacheReadInputTokens,
145
+ rawResponse: response.rawResponse,
146
+ });
147
+ }
148
+
149
+ export function resolveStructuredPricing(
150
+ providerName: string,
151
+ model: string,
152
+ usage: PricingUsage,
153
+ ): PricingResult {
154
+ try {
155
+ const config = getConfig();
156
+ return resolvePricingForUsageWithOverrides(
157
+ providerName,
158
+ model,
159
+ usage,
160
+ config.llm.pricingOverrides,
161
+ );
162
+ } catch (err) {
163
+ log.warn({ err, model, providerName }, "Failed to resolve usage pricing");
164
+ return { estimatedCostUsd: null, pricingStatus: "unpriced" };
165
+ }
166
+ }
@@ -1,4 +1,12 @@
1
+ import type { LLMCallSite } from "../config/schemas/llm.js";
1
2
  import type { UsageActor } from "./actors.js";
3
+ import type { UsageAttributionProfileSource } from "./attribution.js";
4
+
5
+ export type {
6
+ UsageAttributionInput,
7
+ UsageAttributionProfileSource,
8
+ UsageAttributionSnapshot,
9
+ } from "./attribution.js";
2
10
 
3
11
  /**
4
12
  * Anthropic prompt caching exposes write-tier detail so callers can price
@@ -38,6 +46,9 @@ export interface UsageEventInput {
38
46
  conversationId: string | null;
39
47
  runId: string | null;
40
48
  requestId: string | null;
49
+ callSite?: LLMCallSite | null;
50
+ inferenceProfile?: string | null;
51
+ inferenceProfileSource?: UsageAttributionProfileSource | null;
41
52
  /** Number of actual LLM API calls represented by this event (defaults to 1). */
42
53
  llmCallCount?: number;
43
54
  }
@@ -57,6 +68,9 @@ export interface PricingResult {
57
68
  export interface UsageEvent extends UsageEventInput {
58
69
  id: string;
59
70
  createdAt: number;
71
+ callSite: LLMCallSite | null;
72
+ inferenceProfile: string | null;
73
+ inferenceProfileSource: UsageAttributionProfileSource | null;
60
74
  estimatedCostUsd: number | null;
61
75
  pricingStatus: "priced" | "unpriced";
62
76
  }
package/src/util/json.ts CHANGED
@@ -9,6 +9,19 @@ export function parseJsonSafe<T = unknown>(text: string): T | null {
9
9
  }
10
10
  }
11
11
 
12
+ /** Convert any object's Date-valued fields to ISO strings. */
13
+ export function datesToISO<T extends Record<string, unknown>>(
14
+ obj: T,
15
+ ): { [K in keyof T]: T[K] extends Date ? string : T[K] } {
16
+ const result = { ...obj } as Record<string, unknown>;
17
+ for (const [key, value] of Object.entries(result)) {
18
+ if (value instanceof Date) {
19
+ result[key] = value.toISOString();
20
+ }
21
+ }
22
+ return result as { [K in keyof T]: T[K] extends Date ? string : T[K] };
23
+ }
24
+
12
25
  /** Tolerant JSON parse that returns `{}` for invalid or non-object payloads. */
13
26
  export function safeParseRecord(raw: string): Record<string, unknown> {
14
27
  try {
@@ -142,9 +142,9 @@ function buildRotatingLogger(config: LogFileConfig): pino.Logger {
142
142
  // When stdout is not a TTY (e.g. desktop app redirects to a hatch log file),
143
143
  // write to the rotating file only — the hatch log already captured early
144
144
  // startup output and echoing pino output there is unnecessary duplication.
145
- // Exception: in containers, always write to stdout so `docker logs` can
146
- // capture daemon output for debugging.
147
- if (!process.stdout.isTTY && !getIsContainerized()) {
145
+ // DEBUG_STDOUT_LOGS opts in to stdout output for any non-TTY environment
146
+ // (containers, background daemons, etc.).
147
+ if (!process.stdout.isTTY && !getDebugStdoutLogs()) {
148
148
  return pino(
149
149
  { name: "assistant", level: "info", serializers: logSerializers },
150
150
  pino.multistream([
@@ -37,9 +37,48 @@ const PROVIDER_PRICING: Record<string, Record<string, ModelPricing>> = {
37
37
  "claude-haiku-4": { inputPer1M: 1, outputPer1M: 5 },
38
38
  },
39
39
  openai: {
40
- "gpt-5.5": { inputPer1M: 5, outputPer1M: 30 },
41
- "gpt-5.4": { inputPer1M: 2.5, outputPer1M: 15 },
42
- "gpt-5.4-mini": { inputPer1M: 0.5, outputPer1M: 3 },
40
+ "gpt-5.5": {
41
+ inputPer1M: 5,
42
+ outputPer1M: 30,
43
+ cacheReadPer1M: 0.5,
44
+ tiers: [
45
+ {
46
+ inputTokenThreshold: 272_000,
47
+ inputPer1M: 10,
48
+ outputPer1M: 45,
49
+ cacheReadPer1M: 1,
50
+ },
51
+ ],
52
+ },
53
+ "gpt-5.5-pro": {
54
+ inputPer1M: 30,
55
+ outputPer1M: 180,
56
+ tiers: [
57
+ {
58
+ inputTokenThreshold: 272_000,
59
+ inputPer1M: 60,
60
+ outputPer1M: 270,
61
+ },
62
+ ],
63
+ },
64
+ "gpt-5.4": {
65
+ inputPer1M: 2.5,
66
+ outputPer1M: 15,
67
+ cacheReadPer1M: 0.25,
68
+ tiers: [
69
+ {
70
+ inputTokenThreshold: 272_000,
71
+ inputPer1M: 5,
72
+ outputPer1M: 22.5,
73
+ cacheReadPer1M: 0.5,
74
+ },
75
+ ],
76
+ },
77
+ "gpt-5.4-mini": {
78
+ inputPer1M: 0.75,
79
+ outputPer1M: 4.5,
80
+ cacheReadPer1M: 0.075,
81
+ },
43
82
  "gpt-5.4-nano": { inputPer1M: 0.2, outputPer1M: 1.25 },
44
83
  "gpt-5.2": { inputPer1M: 1.75, outputPer1M: 14 },
45
84
  "gpt-4o": { inputPer1M: 2.5, outputPer1M: 10 },
@@ -103,6 +142,14 @@ const PROVIDER_PRICING: Record<string, Record<string, ModelPricing>> = {
103
142
  inputPer1M: 1.25,
104
143
  outputPer1M: 10,
105
144
  cacheReadPer1M: 0.3125,
145
+ tiers: [
146
+ {
147
+ inputTokenThreshold: 200_000,
148
+ inputPer1M: 2.5,
149
+ outputPer1M: 15,
150
+ cacheReadPer1M: 0.625,
151
+ },
152
+ ],
106
153
  },
107
154
  "gemini-2.0-flash": { inputPer1M: 0.1, outputPer1M: 0.4 },
108
155
  },
@@ -1,13 +1,13 @@
1
1
  /**
2
- * Module-level registry for running work items from tool context.
2
+ * Module-level runner for executing work items from tool context.
3
3
  *
4
- * The daemon server registers its `getOrCreateConversation` and `broadcast`
5
- * callbacks at startup. Tool implementations can then trigger async
6
- * work item execution without needing direct access to HandlerContext.
4
+ * Imports conversation-store and the assistant event hub directly — no
5
+ * daemon-server callback registration needed.
7
6
  */
8
7
 
9
- import type { Conversation } from "../daemon/conversation.js";
8
+ import { getOrCreateConversation } from "../daemon/conversation-store.js";
10
9
  import type { ServerMessage } from "../daemon/message-protocol.js";
10
+ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
11
11
  import { runTask } from "../tasks/task-runner.js";
12
12
  import { getTask } from "../tasks/task-store.js";
13
13
  import {
@@ -24,28 +24,12 @@ import {
24
24
 
25
25
  const log = getLogger("work-item-runner");
26
26
 
27
- // ── Daemon callback registry ─────────────────────────────────────────
28
-
29
- interface DaemonCallbacks {
30
- getOrCreateConversation: (conversationId: string) => Promise<Conversation>;
31
- broadcast: (msg: ServerMessage) => void;
32
- }
33
-
34
- let _callbacks: DaemonCallbacks | null = null;
35
-
36
- export function registerDaemonCallbacks(callbacks: DaemonCallbacks): void {
37
- _callbacks = callbacks;
38
- }
39
-
40
27
  // ── Public API ───────────────────────────────────────────────────────
41
28
 
42
- function broadcastWorkItemStatus(
43
- broadcast: (msg: ServerMessage) => void,
44
- id: string,
45
- ): void {
29
+ function broadcastWorkItemStatus(id: string): void {
46
30
  const item = getWorkItem(id);
47
31
  if (item) {
48
- broadcast({
32
+ broadcastMessage({
49
33
  type: "work_item_status_changed",
50
34
  item: {
51
35
  id: item.id,
@@ -75,14 +59,6 @@ export interface RunWorkItemResult {
75
59
  * auto-approved since the user explicitly requested execution.
76
60
  */
77
61
  export function runWorkItemInBackground(workItemId: string): RunWorkItemResult {
78
- if (!_callbacks) {
79
- return {
80
- success: false,
81
- error: "Daemon callbacks not registered",
82
- errorCode: "not_initialized",
83
- };
84
- }
85
-
86
62
  const workItem = getWorkItem(workItemId);
87
63
  if (!workItem) {
88
64
  return {
@@ -135,11 +111,8 @@ export function runWorkItemInBackground(workItemId: string): RunWorkItemResult {
135
111
  // Set status to running
136
112
  updateWorkItem(workItemId, { status: "running" });
137
113
 
138
- const { getOrCreateConversation, broadcast } = _callbacks;
139
-
140
- // Broadcast the running state
141
- broadcastWorkItemStatus(broadcast, workItemId);
142
- broadcast({ type: "tasks_changed" } as ServerMessage);
114
+ broadcastWorkItemStatus(workItemId);
115
+ broadcastMessage({ type: "tasks_changed" } as ServerMessage);
143
116
 
144
117
  // Execute asynchronously
145
118
  let conversation: Awaited<ReturnType<typeof getOrCreateConversation>> | null =
@@ -155,7 +128,7 @@ export function runWorkItemInBackground(workItemId: string): RunWorkItemResult {
155
128
  });
156
129
  conversation = await getOrCreateConversation(conversationId);
157
130
 
158
- broadcast({
131
+ broadcastMessage({
159
132
  type: "task_run_conversation_created",
160
133
  conversationId,
161
134
  workItemId,
@@ -165,7 +138,7 @@ export function runWorkItemInBackground(workItemId: string): RunWorkItemResult {
165
138
  conversation.headlessLock = true;
166
139
  }
167
140
  await conversation.processMessage(message, [], (event) => {
168
- broadcast(event);
141
+ broadcastMessage(event);
169
142
  });
170
143
  },
171
144
  );
@@ -188,8 +161,8 @@ export function runWorkItemInBackground(workItemId: string): RunWorkItemResult {
188
161
  });
189
162
  }
190
163
 
191
- broadcastWorkItemStatus(broadcast, workItemId);
192
- broadcast({ type: "tasks_changed" } as ServerMessage);
164
+ broadcastWorkItemStatus(workItemId);
165
+ broadcastMessage({ type: "tasks_changed" } as ServerMessage);
193
166
  } catch (err) {
194
167
  const errConversation = conversation as { headlessLock: boolean } | null;
195
168
  if (errConversation) {
@@ -200,8 +173,8 @@ export function runWorkItemInBackground(workItemId: string): RunWorkItemResult {
200
173
  status: "failed",
201
174
  lastRunStatus: "failed",
202
175
  });
203
- broadcastWorkItemStatus(broadcast, workItemId);
204
- broadcast({ type: "tasks_changed" } as ServerMessage);
176
+ broadcastWorkItemStatus(workItemId);
177
+ broadcastMessage({ type: "tasks_changed" } as ServerMessage);
205
178
  }
206
179
  })();
207
180
 
@@ -60,9 +60,10 @@ export const seedMainAgentOpusCallsiteMigration: WorkspaceMigration = {
60
60
 
61
61
  if (readObject(callSites.mainAgent) !== null) return;
62
62
 
63
- // maxTokens: 32000 matches Opus's maxOutputTokens (see
64
- // model-catalog.ts); without it the site would inherit the
65
- // default's 64000 and overshoot the model capability.
63
+ // Historical seed: at the time this migration shipped, Opus's standard
64
+ // output cap was 32k and this avoided inheriting a too-large default.
65
+ // The resolver now lets active/conversation profiles override this static
66
+ // mainAgent default.
66
67
  callSites.mainAgent = { model: "claude-opus-4-7", maxTokens: 32000 };
67
68
  llm.callSites = callSites;
68
69
  config.llm = llm;
@@ -28,9 +28,9 @@ import type { WorkspaceMigration } from "./types.js";
28
28
  * Existing values are never overwritten:
29
29
  * - A pre-existing profile by any of the three names is left intact.
30
30
  * - A pre-existing `activeProfile` is preserved on Anthropic workspaces.
31
- * - `llm.callSites` entries are not touched they continue to win at
32
- * resolver layer 5 over both `activeProfile` and per-site `profile`
33
- * references.
31
+ * - `llm.callSites` entries are not touched. Non-main-agent call sites
32
+ * continue to win over profiles; `mainAgent` profiles now win over static
33
+ * call-site defaults because they are the user's chat-model selection.
34
34
  *
35
35
  * **Skip when `VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH` is set.** Like
36
36
  * migration 040, a platform-provided default-config overlay (applied
@@ -3,17 +3,6 @@ import { join } from "node:path";
3
3
 
4
4
  import type { WorkspaceMigration } from "./types.js";
5
5
 
6
- /**
7
- * Initial contents of `memory/edges.json` — the bidirectional concept-page
8
- * edge index for the v2 memory subsystem. The version field lets future
9
- * migrations bump the schema if needed.
10
- */
11
- const EMPTY_EDGES_INDEX = `${JSON.stringify(
12
- { version: 1, edges: [] },
13
- null,
14
- 2,
15
- )}\n`;
16
-
17
6
  const PROSE_FILES = ["essentials.md", "threads.md", "recent.md", "buffer.md"];
18
7
 
19
8
  export const memoryV2InitMigration: WorkspaceMigration = {
@@ -26,13 +15,8 @@ export const memoryV2InitMigration: WorkspaceMigration = {
26
15
  mkdirSync(join(memoryDir, "archive"), { recursive: true });
27
16
  mkdirSync(join(memoryDir, ".v2-state"), { recursive: true });
28
17
 
29
- // Seed edges.json and the prose files only if missing — preserves any
30
- // user content from manual setup or a prior migration.
31
- const edgesPath = join(memoryDir, "edges.json");
32
- if (!existsSync(edgesPath)) {
33
- writeFileSync(edgesPath, EMPTY_EDGES_INDEX, "utf-8");
34
- }
35
-
18
+ // Seed the prose files only if missing — preserves any user content from
19
+ // manual setup or a prior migration.
36
20
  for (const filename of PROSE_FILES) {
37
21
  const filePath = join(memoryDir, filename);
38
22
  if (!existsSync(filePath)) {