@vellumai/assistant 0.7.3 → 0.8.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 (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -3,10 +3,12 @@ import { describe, expect, test } from "bun:test";
3
3
  import type { ContextWindowConfig } from "../config/types.js";
4
4
  import { estimateTextTokens } from "../context/token-estimator.js";
5
5
  import {
6
+ appendTailAnchorToSummary,
6
7
  clampSummaryAtSectionBoundary,
7
8
  CONTEXT_SUMMARY_MARKER,
8
9
  ContextWindowManager,
9
10
  createContextSummaryMessage,
11
+ extractTailAssistantText,
10
12
  getSummaryFromContextMessage,
11
13
  stripCompactionOnlyInjections,
12
14
  } from "../context/window-manager.js";
@@ -72,7 +74,7 @@ describe("ContextWindowManager", () => {
72
74
  expect(result.reason).toBe("below compaction threshold");
73
75
  });
74
76
 
75
- test("explains forced compaction skip when conversation already fits target", async () => {
77
+ test("explains forced compaction skip when only one user turn exists", async () => {
76
78
  const provider = createProvider(() => {
77
79
  throw new Error("summarizer should not be called");
78
80
  });
@@ -84,6 +86,10 @@ describe("ContextWindowManager", () => {
84
86
  targetBudgetRatio: 0.5,
85
87
  }),
86
88
  });
89
+ // Only one user turn — there is nothing earlier to summarize, so
90
+ // forced compaction must still skip but report a clear reason
91
+ // instead of "conversation already fits within the compaction
92
+ // target". `force=true` is honored everywhere else.
87
93
  const history = [message("user", "hello"), message("assistant", "hi")];
88
94
 
89
95
  const result = await manager.maybeCompact(history, undefined, {
@@ -93,8 +99,151 @@ describe("ContextWindowManager", () => {
93
99
  expect(result.compacted).toBe(false);
94
100
  expect(result.messages).toEqual(history);
95
101
  expect(result.reason).toBe(
102
+ "only one user turn — nothing earlier to compact",
103
+ );
104
+ });
105
+
106
+ test("forced compaction summarizes when adjustForToolPairs would walk boundary to summary", async () => {
107
+ let summaryCalls = 0;
108
+ const provider = createProvider(() => {
109
+ summaryCalls += 1;
110
+ return {
111
+ content: [{ type: "text", text: "## Summary\n- rescue path ran" }],
112
+ model: "mock-model",
113
+ usage: { inputTokens: 100, outputTokens: 25 },
114
+ stopReason: "end_turn",
115
+ };
116
+ });
117
+ const manager = new ContextWindowManager({
118
+ provider,
119
+ systemPrompt: "system prompt",
120
+ config: makeConfig({
121
+ maxInputTokens: 10_000,
122
+ targetBudgetRatio: 0.5,
123
+ }),
124
+ });
125
+ // Conversation starts with consecutive `assistant(tool_use)` →
126
+ // `user(tool_result + text)` pairs. `collectUserTurnStartIndexes`
127
+ // includes the mixed user messages (not tool_result-only), so the
128
+ // earliest `userTurnStarts` entry is the message containing
129
+ // `tool_result(tool-1)`. Once the projection-optimism clamp
130
+ // decrements the keep boundary to that user turn,
131
+ // `adjustForToolPairs` walks the boundary back through the
132
+ // tool_use/tool_result chain to index 0 — under the old code that
133
+ // routed `/compact` through the "already fits" skip path. With the
134
+ // rescue, summarization runs and orphan `tool_result` blocks are
135
+ // stripped from the kept region.
136
+ const history: Message[] = [
137
+ {
138
+ role: "assistant",
139
+ content: [{ type: "tool_use", id: "tool-1", name: "x", input: {} }],
140
+ },
141
+ {
142
+ role: "user",
143
+ content: [
144
+ { type: "tool_result", tool_use_id: "tool-1", content: "result1" },
145
+ { type: "text", text: "u1" },
146
+ ],
147
+ },
148
+ {
149
+ role: "assistant",
150
+ content: [{ type: "tool_use", id: "tool-2", name: "x", input: {} }],
151
+ },
152
+ {
153
+ role: "user",
154
+ content: [
155
+ { type: "tool_result", tool_use_id: "tool-2", content: "result2" },
156
+ { type: "text", text: "u2" },
157
+ ],
158
+ },
159
+ message("assistant", "a3"),
160
+ message("user", "u3"),
161
+ message("assistant", "a4"),
162
+ ];
163
+
164
+ const result = await manager.maybeCompact(history, undefined, {
165
+ force: true,
166
+ precomputedEstimate: 50_000,
167
+ });
168
+
169
+ expect(result.compacted).toBe(true);
170
+ expect(summaryCalls).toBe(1);
171
+ expect(result.reason).not.toBe(
96
172
  "conversation already fits within the compaction target",
97
173
  );
174
+ expect(result.reason).not.toBe(
175
+ "truncated tool results without summarization",
176
+ );
177
+ expect(result.compactedMessages).toBeGreaterThan(0);
178
+
179
+ // The kept region must not contain orphan tool_result blocks whose
180
+ // tool_use lives in the compacted region — the LLM API would reject
181
+ // such messages on the next agent turn.
182
+ const keptToolUseIds = new Set<string>();
183
+ for (const msg of result.messages) {
184
+ if (msg.role !== "assistant") continue;
185
+ for (const block of msg.content) {
186
+ if (
187
+ (block.type === "tool_use" || block.type === "server_tool_use") &&
188
+ "id" in block
189
+ ) {
190
+ keptToolUseIds.add((block as { id: string }).id);
191
+ }
192
+ }
193
+ }
194
+ for (const msg of result.messages) {
195
+ if (msg.role !== "user") continue;
196
+ for (const block of msg.content) {
197
+ if (
198
+ (block.type === "tool_result" ||
199
+ block.type === "web_search_tool_result") &&
200
+ "tool_use_id" in block
201
+ ) {
202
+ expect(keptToolUseIds.has(block.tool_use_id as string)).toBe(true);
203
+ }
204
+ }
205
+ }
206
+ });
207
+
208
+ test("forced compaction summarizes when compactable count is below MIN guard", async () => {
209
+ let summaryCalls = 0;
210
+ const provider = createProvider(() => {
211
+ summaryCalls += 1;
212
+ return {
213
+ content: [{ type: "text", text: "## Summary\n- min-bypass ran" }],
214
+ model: "mock-model",
215
+ usage: { inputTokens: 100, outputTokens: 25 },
216
+ stopReason: "end_turn",
217
+ };
218
+ });
219
+ const manager = new ContextWindowManager({
220
+ provider,
221
+ systemPrompt: "system prompt",
222
+ config: makeConfig({
223
+ maxInputTokens: 10_000,
224
+ targetBudgetRatio: 0.5,
225
+ }),
226
+ });
227
+ // Two user turns separated by a single assistant message — the
228
+ // smallest realistic conversation where a forced compaction has
229
+ // anything to summarize. After the projection clamp + rescue, the
230
+ // compactable region is at most one user turn (the first one),
231
+ // which can fall below `MIN_COMPACTABLE_PERSISTED_MESSAGES`. The
232
+ // bypass must let summarization run instead of returning
233
+ // "insufficient compactable persisted messages".
234
+ const history: Message[] = [message("user", "u1"), message("user", "u2")];
235
+
236
+ const result = await manager.maybeCompact(history, undefined, {
237
+ force: true,
238
+ precomputedEstimate: 50_000,
239
+ });
240
+
241
+ expect(result.compacted).toBe(true);
242
+ expect(summaryCalls).toBe(1);
243
+ expect(result.reason).not.toBe(
244
+ "insufficient compactable persisted messages",
245
+ );
246
+ expect(result.compactedMessages).toBeGreaterThan(0);
98
247
  });
99
248
 
100
249
  test("forced compaction summarizes when projection fits but real usage exceeds target", async () => {
@@ -2091,3 +2240,242 @@ describe("clampSummaryAtSectionBoundary", () => {
2091
2240
  expect(clamped.length).toBeLessThanOrEqual(100);
2092
2241
  });
2093
2242
  });
2243
+
2244
+ describe("extractTailAssistantText", () => {
2245
+ test("returns the most recent assistant text block", () => {
2246
+ const messages: Message[] = [
2247
+ message("user", "u1"),
2248
+ message("assistant", "a1 first"),
2249
+ message("user", "u2"),
2250
+ message("assistant", "a2 last"),
2251
+ ];
2252
+ expect(extractTailAssistantText(messages)).toBe("a2 last");
2253
+ });
2254
+
2255
+ test("returns null when no assistant text is present", () => {
2256
+ const messages: Message[] = [message("user", "u1"), message("user", "u2")];
2257
+ expect(extractTailAssistantText(messages)).toBeNull();
2258
+ });
2259
+
2260
+ test("skips assistant messages with only tool_use blocks and finds the prior text", () => {
2261
+ const messages: Message[] = [
2262
+ message("assistant", "a1 narration before tool use"),
2263
+ message("user", "u1"),
2264
+ {
2265
+ role: "assistant",
2266
+ content: [
2267
+ {
2268
+ type: "tool_use",
2269
+ id: "tool-1",
2270
+ name: "bash",
2271
+ input: { command: "ls" },
2272
+ } as ContentBlock,
2273
+ ],
2274
+ },
2275
+ ];
2276
+ expect(extractTailAssistantText(messages)).toBe(
2277
+ "a1 narration before tool use",
2278
+ );
2279
+ });
2280
+
2281
+ test("clamps long text from the start so the END is preserved", () => {
2282
+ const longText = "early prefix " + "x".repeat(2000) + " FINAL NEXT STEP";
2283
+ const messages: Message[] = [message("assistant", longText)];
2284
+ const result = extractTailAssistantText(messages, 200);
2285
+ expect(result).not.toBeNull();
2286
+ expect(result!.startsWith("[...truncated]")).toBe(true);
2287
+ expect(result!.endsWith("FINAL NEXT STEP")).toBe(true);
2288
+ // Stripped block size ≈ maxChars; "[...truncated] " adds a fixed prefix.
2289
+ expect(result!.length).toBeLessThanOrEqual(200 + "[...truncated] ".length);
2290
+ });
2291
+
2292
+ test("ignores empty/whitespace-only assistant text", () => {
2293
+ const messages: Message[] = [
2294
+ message("assistant", "real content"),
2295
+ message("assistant", " \n "),
2296
+ ];
2297
+ expect(extractTailAssistantText(messages)).toBe("real content");
2298
+ });
2299
+
2300
+ test("returns null for an empty messages array", () => {
2301
+ expect(extractTailAssistantText([])).toBeNull();
2302
+ });
2303
+ });
2304
+
2305
+ describe("appendTailAnchorToSummary", () => {
2306
+ test("appends a tag-wrapped block after the summary", () => {
2307
+ const out = appendTailAnchorToSummary(
2308
+ "## Goals\n- item",
2309
+ "Next step: file the SSE followup.",
2310
+ );
2311
+ expect(out).toContain("## Goals\n- item");
2312
+ expect(out).toContain(
2313
+ "<verbatim_tail>\nNext step: file the SSE followup.\n</verbatim_tail>",
2314
+ );
2315
+ expect(out.endsWith("</verbatim_tail>")).toBe(true);
2316
+ });
2317
+
2318
+ test("is idempotent: re-applying with new text replaces the prior tail", () => {
2319
+ const first = appendTailAnchorToSummary("body", "tail-1");
2320
+ const second = appendTailAnchorToSummary(first, "tail-2");
2321
+ expect(second).toContain("body");
2322
+ expect(second).toContain("tail-2");
2323
+ expect(second).not.toContain("tail-1");
2324
+ // Exactly one open-tag occurrence — no stacking.
2325
+ expect(second.match(/<verbatim_tail>/g)?.length).toBe(1);
2326
+ });
2327
+ });
2328
+
2329
+ describe("compaction tail-anchor", () => {
2330
+ test("splices the last assistant text block verbatim into the summary message", async () => {
2331
+ const provider = createProvider(() => ({
2332
+ content: [{ type: "text", text: "## Goals\n- LLM summary" }],
2333
+ model: "mock-model",
2334
+ usage: { inputTokens: 100, outputTokens: 25 },
2335
+ stopReason: "end_turn",
2336
+ }));
2337
+ const manager = new ContextWindowManager({
2338
+ provider,
2339
+ systemPrompt: "system prompt",
2340
+ config: makeConfig({ maxInputTokens: 600 }),
2341
+ });
2342
+ const long = "x".repeat(240);
2343
+ const distinctiveTail =
2344
+ "Pushed 8fe70d63a0 — next step: file the SSE followup as promised.";
2345
+ // Place `distinctiveTail` as the assistant response for u1 so it lands
2346
+ // at the end of the compactable region. With the same 600-token budget
2347
+ // and 6-message shape as the existing 600-token compaction test above,
2348
+ // the binary search settles on keepTurns=2 (kept = [u2, a2, u3, a3];
2349
+ // compactable = [u1, distinctiveTail]) — exercising the real-world
2350
+ // drift scenario where the model's last narration in a long work span
2351
+ // gets summarized away.
2352
+ const history: Message[] = [
2353
+ message("user", `u1 ${long}`),
2354
+ message("assistant", distinctiveTail),
2355
+ message("user", `u2 ${long}`),
2356
+ message("assistant", `a2 ${long}`),
2357
+ message("user", `u3 ${long}`),
2358
+ message("assistant", `a3 ${long}`),
2359
+ ];
2360
+
2361
+ const result = await manager.maybeCompact(history);
2362
+
2363
+ expect(result.compacted).toBe(true);
2364
+ const summaryInner = getSummaryFromContextMessage(result.messages[0]);
2365
+ expect(summaryInner).not.toBeNull();
2366
+ // LLM summary still present.
2367
+ expect(summaryInner).toContain("LLM summary");
2368
+ // Verbatim tail spliced in: distinctive text from the LAST assistant
2369
+ // message in the compactable region (here, `distinctiveTail`).
2370
+ expect(summaryInner).toContain("<verbatim_tail>");
2371
+ expect(summaryInner).toContain(distinctiveTail);
2372
+ expect(summaryInner).toContain("</verbatim_tail>");
2373
+ // summaryText reflects what's persisted in messages[0] for consistency
2374
+ // with downstream consumers (DB, context_compacted event).
2375
+ expect(result.summaryText).toContain(distinctiveTail);
2376
+ });
2377
+
2378
+ test("omits the tail-anchor block when no assistant text exists in compactable region", async () => {
2379
+ // Construct a scenario where the compactable region has assistant
2380
+ // messages with ONLY tool_use blocks (no text) plus user turns. The
2381
+ // anchor should be omitted gracefully.
2382
+ const provider = createProvider(() => ({
2383
+ content: [{ type: "text", text: "## Goals\n- summary" }],
2384
+ model: "mock-model",
2385
+ usage: { inputTokens: 100, outputTokens: 25 },
2386
+ stopReason: "end_turn",
2387
+ }));
2388
+ const manager = new ContextWindowManager({
2389
+ provider,
2390
+ systemPrompt: "system prompt",
2391
+ config: makeConfig({ maxInputTokens: 600 }),
2392
+ });
2393
+ const long = "x".repeat(240);
2394
+ const history: Message[] = [
2395
+ message("user", `u1 ${long}`),
2396
+ {
2397
+ role: "assistant",
2398
+ content: [
2399
+ {
2400
+ type: "tool_use",
2401
+ id: "tool-1",
2402
+ name: "bash",
2403
+ input: { command: "ls" },
2404
+ } as ContentBlock,
2405
+ ],
2406
+ },
2407
+ {
2408
+ role: "user",
2409
+ content: [
2410
+ {
2411
+ type: "tool_result",
2412
+ tool_use_id: "tool-1",
2413
+ content: "ls output",
2414
+ } as ContentBlock,
2415
+ ],
2416
+ },
2417
+ message("user", `u2 ${long}`),
2418
+ message("assistant", `a2 ${long}`),
2419
+ message("user", `u3 ${long}`),
2420
+ message("assistant", `a3 ${long}`),
2421
+ ];
2422
+
2423
+ const result = await manager.maybeCompact(history);
2424
+
2425
+ expect(result.compacted).toBe(true);
2426
+ const summaryInner = getSummaryFromContextMessage(result.messages[0]);
2427
+ expect(summaryInner).not.toBeNull();
2428
+ // No tail anchor when the only compactable assistant message has no text.
2429
+ // (a2 / a3 are kept verbatim post-compaction since they're recent enough,
2430
+ // so the compactable-region's only assistant message is the tool_use one.)
2431
+ if (summaryInner!.includes("<verbatim_tail>")) {
2432
+ // If a2 ended up in the compactable region after binary search, the
2433
+ // anchor would surface a2's text — which is fine; the assertion that
2434
+ // matters is that the spliced content (when present) is verbatim
2435
+ // content from the compactable region, not noise. Validate the
2436
+ // ordering: anchor must follow LLM summary text.
2437
+ expect(summaryInner!.indexOf("summary")).toBeLessThan(
2438
+ summaryInner!.indexOf("<verbatim_tail>"),
2439
+ );
2440
+ }
2441
+ });
2442
+
2443
+ test("clamps tail-anchor when the last assistant text is longer than the cap", async () => {
2444
+ const provider = createProvider(() => ({
2445
+ content: [{ type: "text", text: "## Goals\n- summary" }],
2446
+ model: "mock-model",
2447
+ usage: { inputTokens: 100, outputTokens: 25 },
2448
+ stopReason: "end_turn",
2449
+ }));
2450
+ const manager = new ContextWindowManager({
2451
+ provider,
2452
+ systemPrompt: "system prompt",
2453
+ config: makeConfig({ maxInputTokens: 600 }),
2454
+ });
2455
+ const long = "x".repeat(240);
2456
+ const tailEnd = "FINAL DISTINCTIVE END MARKER";
2457
+ // Long enough to trip TAIL_ANCHOR_MAX_CHARS (=1500) clamping.
2458
+ const longTail = "early body " + "y".repeat(2000) + " " + tailEnd;
2459
+ const history: Message[] = [
2460
+ message("user", `u1 ${long}`),
2461
+ message("assistant", longTail),
2462
+ message("user", `u2 ${long}`),
2463
+ message("assistant", `a2 ${long}`),
2464
+ message("user", `u3 ${long}`),
2465
+ message("assistant", `a3 ${long}`),
2466
+ ];
2467
+
2468
+ const result = await manager.maybeCompact(history);
2469
+
2470
+ expect(result.compacted).toBe(true);
2471
+ const summaryInner = getSummaryFromContextMessage(result.messages[0]);
2472
+ expect(summaryInner).not.toBeNull();
2473
+ if (summaryInner!.includes("<verbatim_tail>")) {
2474
+ // When clamped, the END is preserved (most recent narration).
2475
+ expect(summaryInner).toContain(tailEnd);
2476
+ // And the early prefix is dropped.
2477
+ expect(summaryInner).toContain("[...truncated]");
2478
+ expect(summaryInner).not.toContain("early body");
2479
+ }
2480
+ });
2481
+ });
@@ -1,18 +1,12 @@
1
1
  import { describe, expect, mock, test } from "bun:test";
2
2
 
3
3
  import type { AgentEvent } from "../agent/loop.js";
4
- import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
5
4
  import type {
6
5
  ContentBlock,
7
6
  Message,
8
7
  ProviderResponse,
9
8
  } from "../providers/types.js";
10
9
 
11
- // This test exercises v1 conversation routing. The `memory-v2-enabled` flag
12
- // (registry default `true`) flips memory routing to v2 — disable it here so
13
- // the v1 paths under test stay active.
14
- _setOverridesForTesting({ "memory-v2-enabled": false });
15
-
16
10
  mock.module("../util/logger.js", () => ({
17
11
  getLogger: () =>
18
12
  new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
@@ -61,6 +55,7 @@ mock.module("../config/loader.js", () => ({
61
55
  pricingOverrides: [],
62
56
  },
63
57
  rateLimit: { maxRequestsPerMinute: 0 },
58
+ memory: { v2: { enabled: false } },
64
59
  daemon: {
65
60
  startupSocketWaitMs: 5000,
66
61
  stopTimeoutMs: 5000,
@@ -476,7 +476,7 @@ function makeCtx(
476
476
  }),
477
477
 
478
478
  graphMemory: {
479
- onCompacted: () => {},
479
+ onCompacted: async () => {},
480
480
  prepareMemory: async () => ({
481
481
  runMessages: [],
482
482
  injectedTokens: 0,
@@ -76,6 +76,7 @@ const defaultLlmConfig: LLMConfig = {
76
76
  profiles: {},
77
77
  profileOrder: [],
78
78
  callSites: {},
79
+ profileSession: { defaultTtlSeconds: 1800, maxTtlSeconds: 43200 },
79
80
  pricingOverrides: [],
80
81
  };
81
82
 
@@ -531,7 +532,7 @@ function makeCtx(
531
532
  }),
532
533
 
533
534
  graphMemory: {
534
- onCompacted: () => {},
535
+ onCompacted: async () => {},
535
536
  prepareMemory: async () => ({
536
537
  runMessages: [],
537
538
  injectedTokens: 0,
@@ -626,7 +626,7 @@ function makeCtx(
626
626
  }),
627
627
 
628
628
  graphMemory: {
629
- onCompacted: () => {},
629
+ onCompacted: async () => {},
630
630
  prepareMemory: async () => ({
631
631
  runMessages: [],
632
632
  injectedTokens: 0,
@@ -3652,11 +3652,11 @@ describe("session-agent-loop", () => {
3652
3652
  expect(rendered).not.toContain("original root");
3653
3653
  });
3654
3654
 
3655
- test("applyCompactionResult records Slack timestamp watermark when provided", () => {
3655
+ test("applyCompactionResult records Slack timestamp watermark when provided", async () => {
3656
3656
  const ctx = makeCtx();
3657
3657
  const events: ServerMessage[] = [];
3658
3658
 
3659
- applyCompactionResult(
3659
+ await applyCompactionResult(
3660
3660
  ctx,
3661
3661
  {
3662
3662
  messages: [
@@ -280,21 +280,13 @@ function seedPendingConfirmation(
280
280
  conversation: Conversation,
281
281
  requestId: string,
282
282
  ): void {
283
+ // Access private ownedIds so denyAllPending/dispose can find this request.
284
+ // promptResolve/promptReject callbacks are stored in pendingInteractions via
285
+ // registerPendingInteraction, which is called separately in each test.
283
286
  const prompter = conversation["prompter"] as unknown as {
284
- pending: Map<
285
- string,
286
- {
287
- resolve: (...args: unknown[]) => void;
288
- reject: (...args: unknown[]) => void;
289
- timer: ReturnType<typeof setTimeout>;
290
- }
291
- >;
287
+ ownedIds: Set<string>;
292
288
  };
293
- prompter.pending.set(requestId, {
294
- resolve: () => {},
295
- reject: () => {},
296
- timer: setTimeout(() => {}, 60_000),
297
- });
289
+ prompter.ownedIds.add(requestId);
298
290
  }
299
291
 
300
292
  // ---------------------------------------------------------------------------
@@ -9,7 +9,9 @@ mock.module("../util/logger.js", () => ({
9
9
  import {
10
10
  createConversation,
11
11
  getConversation,
12
+ getConversationOverrideProfileFromRow,
12
13
  setConversationInferenceProfile,
14
+ setConversationInferenceProfileSession,
13
15
  } from "../memory/conversation-crud.js";
14
16
  import { getDb } from "../memory/db-connection.js";
15
17
  import { initializeDb } from "../memory/db-init.js";
@@ -52,3 +54,101 @@ describe("setConversationInferenceProfile", () => {
52
54
  expect(updated).toHaveProperty("inferenceProfile", "cost-optimized");
53
55
  });
54
56
  });
57
+
58
+ describe("getConversationOverrideProfileFromRow — lazy expiry check", () => {
59
+ beforeEach(() => {
60
+ const db = getDb();
61
+ db.run(`DELETE FROM messages`);
62
+ db.run(`DELETE FROM conversations`);
63
+ });
64
+
65
+ test("returns undefined when inferenceProfileExpiresAt is in the past", () => {
66
+ const conv = createConversation("inference-profile-expired");
67
+ // Set a session-backed profile with an already-expired timestamp.
68
+ setConversationInferenceProfileSession(
69
+ conv.id,
70
+ "balanced",
71
+ "session-uuid-1",
72
+ Date.now() - 1,
73
+ );
74
+ const row = getConversation(conv.id);
75
+ expect(row).not.toBeNull();
76
+ expect(getConversationOverrideProfileFromRow(row)).toBeUndefined();
77
+ });
78
+
79
+ test("returns the profile when inferenceProfileExpiresAt is in the future", () => {
80
+ const conv = createConversation("inference-profile-active-session");
81
+ setConversationInferenceProfileSession(
82
+ conv.id,
83
+ "balanced",
84
+ "session-uuid-2",
85
+ Date.now() + 60_000,
86
+ );
87
+ const row = getConversation(conv.id);
88
+ expect(row).not.toBeNull();
89
+ expect(getConversationOverrideProfileFromRow(row)).toBe("balanced");
90
+ });
91
+
92
+ test("returns undefined at the exact-expiry boundary (expiresAt === now)", () => {
93
+ // Boundary consistency with the reaper SQL (`expires_at <= now`) and
94
+ // the active-session queries (`expiresAt > now`): the lazy check must
95
+ // treat `expiresAt === now` as expired, not active. Otherwise a
96
+ // just-expired session would be served for one extra turn while the
97
+ // reaper is racing to clear it.
98
+ const conv = createConversation("inference-profile-boundary");
99
+ const now = Date.now();
100
+ setConversationInferenceProfileSession(
101
+ conv.id,
102
+ "balanced",
103
+ "session-uuid-boundary",
104
+ now,
105
+ );
106
+ const row = getConversation(conv.id);
107
+ expect(row).not.toBeNull();
108
+ expect(row?.inferenceProfileExpiresAt).toBe(now);
109
+ // Freeze Date.now to the exact stored expiry so this is deterministic.
110
+ const realNow = Date.now;
111
+ Date.now = () => now;
112
+ try {
113
+ expect(getConversationOverrideProfileFromRow(row)).toBeUndefined();
114
+ } finally {
115
+ Date.now = realNow;
116
+ }
117
+ });
118
+
119
+ test("returns the profile when no expiry is set (non-session override)", () => {
120
+ const conv = createConversation("inference-profile-no-expiry");
121
+ setConversationInferenceProfileSession(
122
+ conv.id,
123
+ "quality-optimized",
124
+ null,
125
+ null,
126
+ );
127
+ const row = getConversation(conv.id);
128
+ expect(row).not.toBeNull();
129
+ expect(getConversationOverrideProfileFromRow(row)).toBe(
130
+ "quality-optimized",
131
+ );
132
+ });
133
+
134
+ test.each<"background" | "scheduled">(["background", "scheduled"])(
135
+ "returns undefined for %s conversations even when a profile is pinned",
136
+ (conversationType) => {
137
+ const conv = createConversation({
138
+ title: `inference-profile-${conversationType}`,
139
+ conversationType,
140
+ });
141
+ setConversationInferenceProfileSession(
142
+ conv.id,
143
+ "quality-optimized",
144
+ null,
145
+ null,
146
+ );
147
+ const row = getConversation(conv.id);
148
+ expect(row).not.toBeNull();
149
+ expect(row?.conversationType).toBe(conversationType);
150
+ expect(row?.inferenceProfile).toBe("quality-optimized");
151
+ expect(getConversationOverrideProfileFromRow(row)).toBeUndefined();
152
+ },
153
+ );
154
+ });
@@ -305,6 +305,44 @@ describe("classifyConversationError", () => {
305
305
  });
306
306
  });
307
307
 
308
+ describe("image-input dimension errors via ProviderError (400)", () => {
309
+ it("classifies Anthropic 400 with image-dimension overflow as image_dimensions_too_large (non-retryable)", () => {
310
+ const err = new ProviderError(
311
+ 'Anthropic API error (400): 400 {"type":"error","error":{"type":"invalid_request_error","message":"messages.8.content.3.image.source.base64.data: At least one of the image dimensions exceed max allowed size: 8000 pixels"},"request_id":"req_011CaoaGzPXNs2dxAWegSg9D"}',
312
+ "anthropic",
313
+ 400,
314
+ );
315
+ const result = classifyConversationError(err, baseCtx);
316
+ expect(result.code).toBe("IMAGE_TOO_LARGE");
317
+ expect(result.errorCategory).toBe("image_dimensions_too_large");
318
+ expect(result.retryable).toBe(false);
319
+ expect(result.userMessage).toContain("image");
320
+ expect(result.userMessage).toContain("8000");
321
+ });
322
+
323
+ it("matches the singular 'image dimension exceeds' phrasing as well", () => {
324
+ const err = new ProviderError(
325
+ "image dimension exceeds max allowed size: 8000 pixels",
326
+ "anthropic",
327
+ 400,
328
+ );
329
+ const result = classifyConversationError(err, baseCtx);
330
+ expect(result.errorCategory).toBe("image_dimensions_too_large");
331
+ expect(result.retryable).toBe(false);
332
+ });
333
+
334
+ it("does not steal generic 400s that happen to mention 'image'", () => {
335
+ const err = new ProviderError(
336
+ "invalid request: image source is missing",
337
+ "anthropic",
338
+ 400,
339
+ );
340
+ const result = classifyConversationError(err, baseCtx);
341
+ expect(result.errorCategory).toBe("provider_api_error");
342
+ expect(result.retryable).toBe(true);
343
+ });
344
+ });
345
+
308
346
  describe("ordering errors (tool_use/tool_result mismatches)", () => {
309
347
  const cases = [
310
348
  "tool_result block not immediately after tool_use block",