@vellumai/assistant 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -159,8 +159,8 @@ mock.module("../daemon/disk-pressure-policy.js", () => ({
159
159
  const updateMessageMetadataMock = mock(
160
160
  (_id: string, _updates: Record<string, unknown>) => {},
161
161
  );
162
- const clearStrippedInjectionMetadataForConversationMock = mock(
163
- (_conversationId: string) => {},
162
+ const setConversationHistoryStrippedAtMock = mock(
163
+ (_conversationId: string, _historyStrippedAt: number | null) => {},
164
164
  );
165
165
  const updateConversationSlackContextWatermarkMock = mock(
166
166
  (_conversationId: string, _watermarkTs: string, _compactedAt?: number) => {},
@@ -180,8 +180,7 @@ mock.module("../memory/conversation-crud.js", () => ({
180
180
  setConversationOriginChannelIfUnset: () => {},
181
181
  updateConversationUsage: () => {},
182
182
  updateMessageMetadata: updateMessageMetadataMock,
183
- clearStrippedInjectionMetadataForConversation:
184
- clearStrippedInjectionMetadataForConversationMock,
183
+ setConversationHistoryStrippedAt: setConversationHistoryStrippedAtMock,
185
184
  getMessages: () => [],
186
185
  getConversation: () => mockConversationRow,
187
186
  provenanceFromTrustContext: () => ({
@@ -283,6 +282,7 @@ let mockSlackChronologicalContext: {
283
282
  renderedMessages: Array<{
284
283
  message: Message;
285
284
  sourceChannelTs: string | null;
285
+ tagLineProvenance: "none" | "slack-reaction" | "slack-timezone-message";
286
286
  }>;
287
287
  messages: Message[];
288
288
  compactableStartIndex: number;
@@ -387,6 +387,7 @@ mock.module("../daemon/history-repair.js", () => ({
387
387
  const recordUsageMock = mock(() => {});
388
388
  const recordRequestLogMock = mock(() => {});
389
389
  const backfillMessageIdOnLogsMock = mock(() => {});
390
+ const setAgentLoopExitReasonOnLatestLogMock = mock(() => {});
390
391
  mock.module("../daemon/conversation-usage.js", () => ({
391
392
  recordUsage: recordUsageMock,
392
393
  }));
@@ -484,6 +485,7 @@ mock.module("../memory/archive-store.js", () => ({
484
485
  mock.module("../memory/llm-request-log-store.js", () => ({
485
486
  recordRequestLog: recordRequestLogMock,
486
487
  backfillMessageIdOnLogs: backfillMessageIdOnLogsMock,
488
+ setAgentLoopExitReasonOnLatestLog: setAgentLoopExitReasonOnLatestLogMock,
487
489
  }));
488
490
 
489
491
  let mockHasProactiveArtifactCompleted = true;
@@ -660,6 +662,7 @@ beforeEach(() => {
660
662
  recordUsageMock.mockClear();
661
663
  recordRequestLogMock.mockClear();
662
664
  backfillMessageIdOnLogsMock.mockClear();
665
+ setAgentLoopExitReasonOnLatestLogMock.mockClear();
663
666
  syncMessageToDiskMock.mockClear();
664
667
  rebuildConversationDiskViewFromDbStateMock.mockClear();
665
668
  updateMessageMetadataMock.mockClear();
@@ -680,10 +683,8 @@ beforeEach(() => {
680
683
  mockHasProactiveArtifactCompleted = true;
681
684
  mockTryClaimProactiveArtifactTrigger = false;
682
685
  runProactiveArtifactJobMock.mockClear();
683
- clearStrippedInjectionMetadataForConversationMock.mockClear();
684
- clearStrippedInjectionMetadataForConversationMock.mockImplementation(
685
- () => {},
686
- );
686
+ setConversationHistoryStrippedAtMock.mockClear();
687
+ setConversationHistoryStrippedAtMock.mockImplementation(() => {});
687
688
  applyRuntimeInjectionsMock.mockClear();
688
689
  buildUnifiedTurnContextBlockMock.mockClear();
689
690
  resolveTurnTimezoneContextMock.mockClear();
@@ -1214,20 +1215,8 @@ describe("session-agent-loop", () => {
1214
1215
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
1215
1216
 
1216
1217
  expect(recordRequestLogMock).toHaveBeenCalledTimes(1);
1217
- const call = recordRequestLogMock.mock.calls[0] as unknown as [
1218
- string,
1219
- string,
1220
- string,
1221
- undefined,
1222
- string,
1223
- ];
1224
- expect(call).toEqual([
1225
- "test-conv",
1226
- JSON.stringify(rawRequest),
1227
- JSON.stringify(rawResponse),
1228
- undefined,
1229
- "fireworks",
1230
- ]);
1218
+ const call = recordRequestLogMock.mock.calls[0] as unknown as unknown[];
1219
+ expect(call[4]).toBe("fireworks");
1231
1220
  });
1232
1221
 
1233
1222
  test("record request log falls back to the runtime provider when no actual provider is supplied", async () => {
@@ -1373,20 +1362,9 @@ describe("session-agent-loop", () => {
1373
1362
  await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
1374
1363
 
1375
1364
  expect(recordRequestLogMock).toHaveBeenCalledTimes(1);
1376
- const call = recordRequestLogMock.mock.calls[0] as unknown as [
1377
- string,
1378
- string,
1379
- string,
1380
- undefined,
1381
- string,
1382
- ];
1383
- expect(call).toEqual([
1384
- "test-conv",
1385
- JSON.stringify(rawRequest),
1386
- JSON.stringify(rawResponse),
1387
- undefined,
1388
- "openai",
1389
- ]);
1365
+ const call = recordRequestLogMock.mock.calls[0] as unknown as unknown[];
1366
+ expect(call[1]).toBe(JSON.stringify(rawRequest));
1367
+ expect(call[2]).toBe(JSON.stringify(rawResponse));
1390
1368
  });
1391
1369
  });
1392
1370
 
@@ -2038,6 +2016,154 @@ describe("session-agent-loop", () => {
2038
2016
  expect(complete).toBeDefined();
2039
2017
  });
2040
2018
 
2019
+ test("emits budget_yield_unrecovered when auto_compress rerun yields at mid-loop budget", async () => {
2020
+ // Regression test for the silent-stall failure mode:
2021
+ // when every recovery layer has been applied (tier reducer
2022
+ // exhausted + auto_compress_latest_turn emergency compaction)
2023
+ // and the final `agentLoop.run` STILL yields at the mid-loop
2024
+ // budget checkpoint, the orchestrator used to fall through to
2025
+ // post-turn cleanup with NO `agent_loop_exit_reason` emitted —
2026
+ // the turn just stopped mid-action and `llm_request_logs` showed
2027
+ // a NULL exit reason on the final row. We now emit
2028
+ // `budget_yield_unrecovered` so the inspector and dashboards can
2029
+ // attribute the silent stall.
2030
+ const events: ServerMessage[] = [];
2031
+ let callCount = 0;
2032
+
2033
+ // Reducer exhausts all 4 tiers on first call so the convergence
2034
+ // loop runs exactly one iteration before falling through to
2035
+ // the auto_compress_latest_turn branch.
2036
+ mockReducerStepFn = (msgs: Message[]) => ({
2037
+ messages: msgs,
2038
+ tier: "injection_downgrade",
2039
+ state: {
2040
+ appliedTiers: [
2041
+ "forced_compaction",
2042
+ "tool_result_truncation",
2043
+ "media_stubbing",
2044
+ "injection_downgrade",
2045
+ ],
2046
+ injectionMode: "minimal",
2047
+ exhausted: true,
2048
+ },
2049
+ estimatedTokens: 120_000,
2050
+ });
2051
+
2052
+ mockOverflowAction = "auto_compress_latest_turn";
2053
+
2054
+ // Sits between the preflight budget (preflightBudget =
2055
+ // 100k * 0.95 = 95k — anything above triggers preflight reducer
2056
+ // *before* we get to the convergence/auto_compress path under
2057
+ // test) and the mid-loop threshold (preflightBudget * 0.85 =
2058
+ // ≈80.75k — anything above flips yieldedForBudget on a checkpoint
2059
+ // call). 90k satisfies both so the path reaches call 3.
2060
+ mockEstimateTokens = 90_000;
2061
+
2062
+ const agentLoopRun: AgentLoopRun = async (
2063
+ messages,
2064
+ onEvent,
2065
+ _signal,
2066
+ _reqId,
2067
+ onCheckpoint,
2068
+ ) => {
2069
+ callCount++;
2070
+ if (callCount <= 2) {
2071
+ // Calls 1 (initial) and 2 (convergence rerun): error so
2072
+ // `state.contextTooLargeDetected` stays true through
2073
+ // convergence exit and we enter the auto_compress branch.
2074
+ onEvent({
2075
+ type: "error",
2076
+ error: new Error("context_length_exceeded"),
2077
+ });
2078
+ onEvent({
2079
+ type: "usage",
2080
+ inputTokens: 100,
2081
+ outputTokens: 0,
2082
+ model: "test-model",
2083
+ providerDurationMs: 50,
2084
+ });
2085
+ return messages;
2086
+ }
2087
+ // Call 3: the auto_compress_latest_turn rerun. Invoke
2088
+ // onCheckpoint so the orchestrator's mid-loop budget check
2089
+ // flips `yieldedForBudget` to true, then return without
2090
+ // finishing — mirroring what AgentLoop.run does when its
2091
+ // checkpoint returns "yield".
2092
+ if (onCheckpoint) {
2093
+ await onCheckpoint({
2094
+ turnIndex: 0,
2095
+ toolCount: 1,
2096
+ hasToolUse: true,
2097
+ history: messages,
2098
+ });
2099
+ }
2100
+ return messages;
2101
+ };
2102
+
2103
+ const ctx = makeCtx({
2104
+ agentLoopRun,
2105
+ hasNoClient: true,
2106
+ contextWindowManager: {
2107
+ shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
2108
+ maybeCompact: async () => ({
2109
+ compacted: true,
2110
+ messages: [
2111
+ { role: "user", content: [{ type: "text", text: "Hello" }] },
2112
+ ] as Message[],
2113
+ compactedPersistedMessages: 3,
2114
+ summaryText: "Compressed summary",
2115
+ previousEstimatedInputTokens: 120000,
2116
+ estimatedInputTokens: 30000,
2117
+ maxInputTokens: 100000,
2118
+ thresholdTokens: 80000,
2119
+ compactedMessages: 5,
2120
+ summaryCalls: 1,
2121
+ summaryInputTokens: 300,
2122
+ summaryOutputTokens: 100,
2123
+ summaryModel: "mock-model",
2124
+ }),
2125
+ } as unknown as AgentLoopConversationContext["contextWindowManager"],
2126
+ });
2127
+
2128
+ await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
2129
+
2130
+ // Observability emit: exit reason was stamped onto the latest
2131
+ // llm_request_logs row.
2132
+ expect(setAgentLoopExitReasonOnLatestLogMock).toHaveBeenCalledWith(
2133
+ "test-conv",
2134
+ "budget_yield_unrecovered",
2135
+ );
2136
+
2137
+ // We did NOT also emit context_too_large — the auto_compress
2138
+ // branch resets `contextTooLargeDetected` before its rerun and
2139
+ // the rerun's yield-for-budget keeps it false, so the error
2140
+ // branch above stays skipped.
2141
+ expect(setAgentLoopExitReasonOnLatestLogMock).not.toHaveBeenCalledWith(
2142
+ "test-conv",
2143
+ "context_too_large",
2144
+ );
2145
+
2146
+ // User-facing emit: the classified BUDGET_YIELD_UNRECOVERED
2147
+ // error is sent to the client so the UI can render a notice
2148
+ // instead of leaving the turn looking like a silent ghost. The
2149
+ // assistant-side notice persistence is exercised in the overflow
2150
+ // suite (`conversation-agent-loop-overflow.test.ts`); this test
2151
+ // owns the observability + emit contract.
2152
+ const conversationError = events.find(
2153
+ (e) => e.type === "conversation_error",
2154
+ );
2155
+ expect(conversationError).toBeDefined();
2156
+ if (conversationError && "code" in conversationError) {
2157
+ expect(conversationError.code).toBe("BUDGET_YIELD_UNRECOVERED");
2158
+ expect(conversationError.retryable).toBe(true);
2159
+ expect(conversationError.errorCategory).toBe(
2160
+ "budget_yield_unrecovered",
2161
+ );
2162
+ } else {
2163
+ throw new Error("conversation_error missing `code` field");
2164
+ }
2165
+ });
2166
+
2041
2167
  test("recovery loop is bounded by maxAttempts", async () => {
2042
2168
  const events: ServerMessage[] = [];
2043
2169
  let reducerCalls = 0;
@@ -2300,6 +2426,10 @@ describe("session-agent-loop", () => {
2300
2426
 
2301
2427
  const handoff = events.find((e) => e.type === "generation_handoff");
2302
2428
  expect(handoff).toBeDefined();
2429
+ expect(setAgentLoopExitReasonOnLatestLogMock).toHaveBeenCalledWith(
2430
+ "test-conv",
2431
+ "checkpoint_handoff",
2432
+ );
2303
2433
  });
2304
2434
 
2305
2435
  test("continues when canHandoffAtCheckpoint returns false", async () => {
@@ -2359,6 +2489,10 @@ describe("session-agent-loop", () => {
2359
2489
 
2360
2490
  const handoff = events.find((e) => e.type === "generation_handoff");
2361
2491
  expect(handoff).toBeUndefined();
2492
+ expect(setAgentLoopExitReasonOnLatestLogMock).not.toHaveBeenCalledWith(
2493
+ "test-conv",
2494
+ "checkpoint_handoff",
2495
+ );
2362
2496
  const complete = events.find((e) => e.type === "message_complete");
2363
2497
  expect(complete).toBeDefined();
2364
2498
  });
@@ -2903,11 +3037,8 @@ describe("session-agent-loop", () => {
2903
3037
  // (from the mocked `addMessage` -> `{ id: "mock-msg-id" }`) into the
2904
3038
  // backfill primitive, scoped to this conversation.
2905
3039
  expect(backfillMessageIdOnLogsMock).toHaveBeenCalledTimes(1);
2906
- const backfillCall =
2907
- backfillMessageIdOnLogsMock.mock.calls[0] as unknown as [
2908
- string,
2909
- string,
2910
- ];
3040
+ const backfillCall = backfillMessageIdOnLogsMock.mock
3041
+ .calls[0] as unknown as [string, string];
2911
3042
  expect(backfillCall[0]).toBe("test-conv");
2912
3043
  expect(backfillCall[1]).toBe("mock-msg-id");
2913
3044
  });
@@ -3023,6 +3154,7 @@ describe("session-agent-loop", () => {
3023
3154
  "1700000020.000000",
3024
3155
  "1700000030.000000",
3025
3156
  ][index]!,
3157
+ tagLineProvenance: "none",
3026
3158
  })),
3027
3159
  compactableStartIndex: 0,
3028
3160
  };
@@ -3122,6 +3254,7 @@ describe("session-agent-loop", () => {
3122
3254
  "1700000020.000000",
3123
3255
  "1700000030.000000",
3124
3256
  ][index]!,
3257
+ tagLineProvenance: "none",
3125
3258
  })),
3126
3259
  compactableStartIndex: 0,
3127
3260
  };
@@ -3238,6 +3371,7 @@ describe("session-agent-loop", () => {
3238
3371
  "1700000030.000000",
3239
3372
  "1700000040.000000",
3240
3373
  ][index]!,
3374
+ tagLineProvenance: "none",
3241
3375
  })),
3242
3376
  compactableStartIndex: 0,
3243
3377
  };
@@ -3343,9 +3477,10 @@ describe("session-agent-loop", () => {
3343
3477
  {
3344
3478
  message: firstSummaryMessage,
3345
3479
  sourceChannelTs: null,
3480
+ tagLineProvenance: "none",
3346
3481
  },
3347
- mockSlackChronologicalContext.renderedMessages[2],
3348
- mockSlackChronologicalContext.renderedMessages[3],
3482
+ mockSlackChronologicalContext!.renderedMessages[2],
3483
+ mockSlackChronologicalContext!.renderedMessages[3],
3349
3484
  ],
3350
3485
  messages: firstCompactedMessages,
3351
3486
  compactableStartIndex: 1,
@@ -3384,6 +3519,7 @@ describe("session-agent-loop", () => {
3384
3519
  "1700000020.000000",
3385
3520
  "1700000030.000000",
3386
3521
  ][index]!,
3522
+ tagLineProvenance: "none",
3387
3523
  })),
3388
3524
  compactableStartIndex: 0,
3389
3525
  };
@@ -3541,6 +3677,7 @@ describe("session-agent-loop", () => {
3541
3677
  ],
3542
3678
  },
3543
3679
  sourceChannelTs: null,
3680
+ tagLineProvenance: "none",
3544
3681
  },
3545
3682
  {
3546
3683
  message: {
@@ -3548,6 +3685,7 @@ describe("session-agent-loop", () => {
3548
3685
  content: [{ type: "text", text: "after watermark reply" }],
3549
3686
  },
3550
3687
  sourceChannelTs: "1700000020.000000",
3688
+ tagLineProvenance: "none",
3551
3689
  },
3552
3690
  ],
3553
3691
  compactableStartIndex: 1,
@@ -3642,6 +3780,7 @@ describe("session-agent-loop", () => {
3642
3780
  ],
3643
3781
  },
3644
3782
  sourceChannelTs: null,
3783
+ tagLineProvenance: "none",
3645
3784
  },
3646
3785
  {
3647
3786
  message: {
@@ -3654,6 +3793,7 @@ describe("session-agent-loop", () => {
3654
3793
  ],
3655
3794
  },
3656
3795
  sourceChannelTs: "1700000121.000000",
3796
+ tagLineProvenance: "none",
3657
3797
  },
3658
3798
  ],
3659
3799
  compactableStartIndex: 1,
@@ -3751,8 +3891,8 @@ describe("session-agent-loop", () => {
3751
3891
  });
3752
3892
  });
3753
3893
 
3754
- describe("compaction-strip metadata consistency", () => {
3755
- test("clears pkbSystemReminderBlock metadata when convergence strip runs", async () => {
3894
+ describe("compaction-strip marker persistence", () => {
3895
+ test("records historyStrippedAt when convergence strip runs", async () => {
3756
3896
  // Reducer: succeed on first call, returning reduced messages.
3757
3897
  mockReducerStepFn = (msgs: Message[]) => ({
3758
3898
  messages: msgs,
@@ -3823,91 +3963,10 @@ describe("session-agent-loop", () => {
3823
3963
 
3824
3964
  await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
3825
3965
 
3826
- // The bulk-clear helper must have been called with the conversation id
3827
- // at least once (one of the three strip sites fired).
3828
- const clearCalls =
3829
- clearStrippedInjectionMetadataForConversationMock.mock.calls.filter(
3830
- (call) => call[0] === "test-conv",
3831
- );
3832
- expect(clearCalls.length).toBeGreaterThanOrEqual(1);
3833
- });
3834
-
3835
- test("strip-site clear is non-fatal when the helper throws", async () => {
3836
- clearStrippedInjectionMetadataForConversationMock.mockImplementation(
3837
- () => {
3838
- throw new Error("db write failed");
3839
- },
3966
+ const stripCalls = setConversationHistoryStrippedAtMock.mock.calls.filter(
3967
+ (call) => call[0] === "test-conv",
3840
3968
  );
3841
-
3842
- mockReducerStepFn = (msgs: Message[]) => ({
3843
- messages: msgs,
3844
- tier: "forced_compaction",
3845
- state: {
3846
- appliedTiers: ["forced_compaction"],
3847
- injectionMode: "full",
3848
- exhausted: false,
3849
- },
3850
- estimatedTokens: 5000,
3851
- });
3852
-
3853
- let callCount = 0;
3854
- const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
3855
- callCount++;
3856
- if (callCount === 1) {
3857
- onEvent({
3858
- type: "error",
3859
- error: new Error("context_length_exceeded"),
3860
- });
3861
- onEvent({
3862
- type: "usage",
3863
- inputTokens: 100,
3864
- outputTokens: 0,
3865
- model: "test-model",
3866
- providerDurationMs: 50,
3867
- });
3868
- return [
3869
- ...messages,
3870
- {
3871
- role: "assistant" as const,
3872
- content: [{ type: "text", text: "partial" }] as ContentBlock[],
3873
- },
3874
- ];
3875
- }
3876
- onEvent({
3877
- type: "message_complete",
3878
- message: {
3879
- role: "assistant",
3880
- content: [{ type: "text", text: "recovered" }],
3881
- },
3882
- });
3883
- onEvent({
3884
- type: "usage",
3885
- inputTokens: 50,
3886
- outputTokens: 25,
3887
- model: "test-model",
3888
- providerDurationMs: 100,
3889
- });
3890
- return [
3891
- ...messages,
3892
- {
3893
- role: "assistant" as const,
3894
- content: [{ type: "text", text: "recovered" }] as ContentBlock[],
3895
- },
3896
- ];
3897
- };
3898
-
3899
- const ctx = makeCtx({
3900
- agentLoopRun,
3901
- contextWindowManager: {
3902
- shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
3903
- maybeCompact: async () => ({ compacted: false }),
3904
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
3905
- });
3906
-
3907
- // Must not throw — the strip-site clear is wrapped in try/catch.
3908
- await expect(
3909
- runAgentLoopImpl(ctx, "hello", "msg-1", () => {}),
3910
- ).resolves.toBeUndefined();
3969
+ expect(stripCalls.length).toBeGreaterThanOrEqual(1);
3911
3970
  });
3912
3971
  });
3913
3972
  });
@@ -110,15 +110,12 @@ mock.module("../tools/skills/skill-tool-factory.js", () => ({
110
110
  description: entry.description,
111
111
  category: entry.category,
112
112
  defaultRiskLevel: RiskLevel.Medium,
113
+ executionTarget: "sandbox" as const,
113
114
  origin: "skill" as const,
114
115
  ownerSkillId: skillId,
115
116
  ownerSkillVersionHash: versionHash,
116
117
  ownerSkillBundled: bundled ?? undefined,
117
- getDefinition: () => ({
118
- name: entry.name,
119
- description: entry.description,
120
- input_schema: entry.input_schema as object,
121
- }),
118
+ input_schema: entry.input_schema as object,
122
119
  execute: async () => ({ content: "", isError: false }),
123
120
  })),
124
121
  }));
@@ -22,7 +22,7 @@ mock.module("../util/logger.js", () => ({
22
22
 
23
23
  mock.module("../providers/registry.js", () => ({
24
24
  getProvider: () => ({ name: "mock-provider" }),
25
- initializeProviders: () => {},
25
+ initializeProviders: async () => {},
26
26
  }));
27
27
 
28
28
  mock.module("../config/loader.js", () => ({
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Tests for the `/clean` slash command primitives.
3
+ *
4
+ * `/clean` is wired up so that:
5
+ * 1. Runtime injection prefixes are stripped from user-message text blocks
6
+ * (same allowlist `/compact` uses).
7
+ * 2. Assistant turns, tool_use blocks, and tool_result blocks are preserved
8
+ * verbatim — `/clean` never alters history shape.
9
+ * 3. The user-facing result message reports tokens reclaimed and the
10
+ * number of messages preserved.
11
+ *
12
+ * The slash-routing layer is covered by `conversation-slash-commands.test.ts`;
13
+ * the graph-memory eviction hook is covered by the v2 routing tests. This
14
+ * file focuses on the formatter and the strip behavior that defines the
15
+ * "no history loss" contract.
16
+ */
17
+ import { describe, expect, test } from "bun:test";
18
+
19
+ import { formatCleanResult } from "../daemon/conversation-process.js";
20
+ import { stripInjectionsForCompaction } from "../daemon/conversation-runtime-assembly.js";
21
+ import type { Message } from "../providers/types.js";
22
+
23
+ describe("formatCleanResult", () => {
24
+ test("formats token reclamation and preserved-message count", () => {
25
+ const out = formatCleanResult({
26
+ previousEstimatedInputTokens: 100_000,
27
+ estimatedInputTokens: 95_000,
28
+ maxInputTokens: 200_000,
29
+ preservedMessages: 250,
30
+ });
31
+ expect(out).toContain("Context Cleaned");
32
+ expect(out).toContain("100,000 → 95,000 (5,000 reclaimed)");
33
+ expect(out).toContain("95,000 / 200,000 tokens");
34
+ expect(out).toContain("250 preserved");
35
+ });
36
+
37
+ test("renders zero reclaimed when nothing was stripped", () => {
38
+ const out = formatCleanResult({
39
+ previousEstimatedInputTokens: 12_345,
40
+ estimatedInputTokens: 12_345,
41
+ maxInputTokens: 200_000,
42
+ preservedMessages: 10,
43
+ });
44
+ expect(out).toContain("12,345 → 12,345 (0 reclaimed)");
45
+ expect(out).toContain("10 preserved");
46
+ });
47
+ });
48
+
49
+ describe("stripInjectionsForCompaction preserves history shape", () => {
50
+ test("strips known injection prefixes from user text blocks", () => {
51
+ const messages: Message[] = [
52
+ {
53
+ role: "user",
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: "<NOW.md Always keep this up to date>\nfoo\n</NOW.md>",
58
+ },
59
+ { type: "text", text: "Hello, please help with X." },
60
+ ],
61
+ },
62
+ ];
63
+ const out = stripInjectionsForCompaction(messages);
64
+ expect(out).toHaveLength(1);
65
+ expect(out[0].content).toHaveLength(1);
66
+ expect(out[0].content[0]).toEqual({
67
+ type: "text",
68
+ text: "Hello, please help with X.",
69
+ });
70
+ });
71
+
72
+ test("preserves assistant turns and tool_use/tool_result blocks verbatim", () => {
73
+ const messages: Message[] = [
74
+ {
75
+ role: "user",
76
+ content: [
77
+ {
78
+ type: "text",
79
+ text: "<knowledge_base>\nstale kb\n</knowledge_base>",
80
+ },
81
+ { type: "text", text: "Run the calculator." },
82
+ ],
83
+ },
84
+ {
85
+ role: "assistant",
86
+ content: [
87
+ { type: "text", text: "Using the calculator." },
88
+ {
89
+ type: "tool_use",
90
+ id: "tool-1",
91
+ name: "calculator",
92
+ input: { expr: "1 + 2" },
93
+ },
94
+ ],
95
+ },
96
+ {
97
+ role: "user",
98
+ content: [
99
+ {
100
+ type: "tool_result",
101
+ tool_use_id: "tool-1",
102
+ content: "3",
103
+ },
104
+ ],
105
+ },
106
+ {
107
+ role: "assistant",
108
+ content: [{ type: "text", text: "The answer is 3." }],
109
+ },
110
+ ];
111
+
112
+ const out = stripInjectionsForCompaction(messages);
113
+
114
+ expect(out).toHaveLength(4);
115
+ expect(out[0].content).toEqual([
116
+ { type: "text", text: "Run the calculator." },
117
+ ]);
118
+ expect(out[1]).toEqual(messages[1]);
119
+ expect(out[2]).toEqual(messages[2]);
120
+ expect(out[3]).toEqual(messages[3]);
121
+ });
122
+
123
+ test("leaves <turn_context>, <workspace>, and <memory __injected> alone", () => {
124
+ const messages: Message[] = [
125
+ {
126
+ role: "user",
127
+ content: [
128
+ { type: "text", text: "<turn_context>\nnow\n</turn_context>" },
129
+ { type: "text", text: "<workspace>\nfiles\n</workspace>" },
130
+ { type: "text", text: "<memory __injected>\nrecent\n</memory>" },
131
+ ],
132
+ },
133
+ ];
134
+ const out = stripInjectionsForCompaction(messages);
135
+ expect(out[0].content).toEqual(messages[0].content);
136
+ });
137
+ });