@vellumai/assistant 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -2,7 +2,7 @@
2
2
  * Tests for slash command interception in the POST /v1/messages handler.
3
3
  *
4
4
  * Validates that:
5
- * - Built-in slash commands (/status, /models, /commands) are intercepted and
5
+ * - Built-in slash commands (/context, /models, /commands) are intercepted and
6
6
  * do NOT trigger the agent loop.
7
7
  * - Regular messages pass through to the agent loop unchanged.
8
8
  */
@@ -10,19 +10,13 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
10
10
 
11
11
  mock.module("../config/env.js", () => ({ isHttpAuthDisabled: () => true }));
12
12
 
13
- import type { SlashResolution } from "../daemon/conversation-slash.js";
14
-
15
- const resolveSlashMock = mock(
16
- (_content: string, _context?: unknown): SlashResolution => ({
17
- kind: "passthrough",
18
- content: _content,
19
- }),
13
+ const formatCompactResultMock = mock(
14
+ (result: { maxInputTokens: number }) =>
15
+ `Context Compacted\n\nContext: 10,000 / ${result.maxInputTokens.toLocaleString(
16
+ "en-US",
17
+ )} tokens`,
20
18
  );
21
19
 
22
- mock.module("../daemon/conversation-slash.js", () => ({
23
- resolveSlash: resolveSlashMock,
24
- }));
25
-
26
20
  mock.module("../config/loader.js", () => ({
27
21
  getConfig: () => ({
28
22
  ui: {},
@@ -56,7 +50,11 @@ mock.module("../config/loader.js", () => ({
56
50
  },
57
51
  },
58
52
  },
59
- profiles: {},
53
+ profiles: {
54
+ "short-context": {
55
+ contextWindow: { maxInputTokens: 150000 },
56
+ },
57
+ },
60
58
  callSites: {},
61
59
  pricingOverrides: [],
62
60
  },
@@ -133,6 +131,7 @@ mock.module("../memory/conversation-crud.js", () => ({
133
131
  content: string,
134
132
  metadata?: Record<string, unknown>,
135
133
  ) => addMessageMock(conversationId, role, content, metadata),
134
+ getConversationOverrideProfile: () => "short-context",
136
135
  getMessages: () => [],
137
136
  provenanceFromTrustContext: (ctx: unknown) =>
138
137
  ctx
@@ -152,6 +151,7 @@ mock.module("../daemon/conversation-process.js", () => ({
152
151
  isModelSlashCommand: (content: string) => {
153
152
  return content.trim() === "/models";
154
153
  },
154
+ formatCompactResult: formatCompactResultMock,
155
155
  }));
156
156
 
157
157
  mock.module("../runtime/local-actor-identity.js", () => ({
@@ -220,6 +220,21 @@ function makeConversation() {
220
220
  ) => undefined,
221
221
  );
222
222
  const setPreactivatedSkillIds = mock((_ids: string[] | undefined) => {});
223
+ const forceCompact = mock(async () => ({
224
+ messages: [],
225
+ compacted: true,
226
+ previousEstimatedInputTokens: 12000,
227
+ estimatedInputTokens: 10000,
228
+ maxInputTokens: 150000,
229
+ thresholdTokens: 120000,
230
+ compactedMessages: 2,
231
+ compactedPersistedMessages: 2,
232
+ summaryCalls: 1,
233
+ summaryInputTokens: 500,
234
+ summaryOutputTokens: 100,
235
+ summaryModel: "claude-opus-4-7",
236
+ summaryText: "Summary",
237
+ }));
223
238
  const events: unknown[] = [];
224
239
  const messages: unknown[] = [];
225
240
  const conversation = {
@@ -236,17 +251,14 @@ function makeConversation() {
236
251
  enqueueMessage: () => ({ queued: true, requestId: "queued-id" }),
237
252
  persistUserMessage,
238
253
  runAgentLoop,
254
+ forceCompact,
239
255
  setPreactivatedSkillIds,
240
256
  drainQueue: async () => {},
241
257
  getMessages: () => messages,
242
258
  assistantId: "self",
243
259
  trustContext: undefined,
244
260
  hasPendingConfirmation: () => false,
245
- setHostBashProxy: () => {},
246
261
  setHostBrowserProxy: () => {},
247
- setHostFileProxy: () => {},
248
- setHostTransferProxy: () => {},
249
- getHostTransferProxy: () => undefined,
250
262
  setHostCuProxy: () => {},
251
263
  addPreactivatedSkillId: () => {},
252
264
  usageStats: {
@@ -262,13 +274,18 @@ function makeConversation() {
262
274
  setPreactivatedSkillIds,
263
275
  events,
264
276
  messages,
277
+ forceCompact,
265
278
  };
266
279
  }
267
280
 
268
281
  function makeRequest(content: string, extras: Record<string, unknown> = {}) {
269
282
  return new Request("http://localhost/v1/messages", {
270
283
  method: "POST",
271
- headers: { "Content-Type": "application/json", "x-vellum-actor-principal-id": "test-user", "x-vellum-principal-type": "actor" },
284
+ headers: {
285
+ "Content-Type": "application/json",
286
+ "x-vellum-actor-principal-id": "test-user",
287
+ "x-vellum-principal-type": "actor",
288
+ },
272
289
  body: JSON.stringify({
273
290
  conversationKey: "slash-test-key",
274
291
  content,
@@ -293,22 +310,17 @@ function makeDeps(
293
310
 
294
311
  describe("handleSendMessage slash command interception", () => {
295
312
  beforeEach(() => {
296
- resolveSlashMock.mockClear();
313
+ formatCompactResultMock.mockClear();
297
314
  addMessageMock.mockClear();
298
315
  ipcCallMock.mockClear();
299
316
  });
300
317
 
301
318
  test("intercepts built-in slash commands (unknown kind) without calling agent loop", async () => {
302
- resolveSlashMock.mockReturnValue({
303
- kind: "unknown",
304
- message: "Conversation Status\n\nContext: 5%",
305
- });
306
-
307
319
  const { conversation, persistUserMessage, runAgentLoop } =
308
320
  makeConversation();
309
321
  const res = await callHandler(
310
322
  (args) => handleSendMessage(args, makeDeps(conversation)),
311
- makeRequest("/status"),
323
+ makeRequest("/context"),
312
324
  undefined,
313
325
  202,
314
326
  );
@@ -321,10 +333,6 @@ describe("handleSendMessage slash command interception", () => {
321
333
  expect(body.accepted).toBe(true);
322
334
  expect(body.messageId).toBe("persisted-user-id");
323
335
 
324
- // Slash command was resolved
325
- expect(resolveSlashMock).toHaveBeenCalledTimes(1);
326
- expect(resolveSlashMock.mock.calls[0][0]).toBe("/status");
327
-
328
336
  // User + assistant messages persisted, but agent loop NOT called
329
337
  expect(addMessageMock).toHaveBeenCalledTimes(2);
330
338
  const roles = addMessageMock.mock.calls.map((c) => c[1]);
@@ -333,12 +341,35 @@ describe("handleSendMessage slash command interception", () => {
333
341
  expect(runAgentLoop).not.toHaveBeenCalled();
334
342
  });
335
343
 
336
- test("passes regular messages through to agent loop unchanged", async () => {
337
- resolveSlashMock.mockReturnValue({
338
- kind: "passthrough",
339
- content: "hello there",
340
- });
344
+ test("handles /compact without calling agent loop and formats the compaction max", async () => {
345
+ const { conversation, persistUserMessage, runAgentLoop, forceCompact } =
346
+ makeConversation();
347
+ const res = await callHandler(
348
+ (args) => handleSendMessage(args, makeDeps(conversation)),
349
+ makeRequest("/compact"),
350
+ undefined,
351
+ 202,
352
+ );
341
353
 
354
+ expect(res.status).toBe(202);
355
+ const body = (await res.json()) as {
356
+ accepted: boolean;
357
+ messageId?: string;
358
+ };
359
+ expect(body.accepted).toBe(true);
360
+ expect(body.messageId).toBe("persisted-user-id");
361
+
362
+ await new Promise((resolve) => setTimeout(resolve, 0));
363
+
364
+ expect(forceCompact).toHaveBeenCalledTimes(1);
365
+ expect(formatCompactResultMock).toHaveBeenCalledWith(
366
+ expect.objectContaining({ maxInputTokens: 150000 }),
367
+ );
368
+ expect(persistUserMessage).not.toHaveBeenCalled();
369
+ expect(runAgentLoop).not.toHaveBeenCalled();
370
+ });
371
+
372
+ test("passes regular messages through to agent loop unchanged", async () => {
342
373
  const {
343
374
  conversation,
344
375
  persistUserMessage,
@@ -354,9 +385,6 @@ describe("handleSendMessage slash command interception", () => {
354
385
 
355
386
  expect(res.status).toBe(202);
356
387
 
357
- // Slash command was resolved but passed through
358
- expect(resolveSlashMock).toHaveBeenCalledTimes(1);
359
-
360
388
  // No skill preactivation
361
389
  expect(setPreactivatedSkillIds).not.toHaveBeenCalled();
362
390
 
@@ -367,41 +395,26 @@ describe("handleSendMessage slash command interception", () => {
367
395
  expect(loopContent).toBe("hello there");
368
396
  });
369
397
 
370
- test("passes SlashContext with session usage stats", async () => {
371
- resolveSlashMock.mockReturnValue({
372
- kind: "passthrough",
373
- content: "test",
374
- });
375
-
398
+ test("passes SlashContext with resolved profile context budget", async () => {
376
399
  const { conversation } = makeConversation();
377
400
  await callHandler(
378
401
  (args) => handleSendMessage(args, makeDeps(conversation)),
379
- makeRequest("test"),
402
+ makeRequest("/context"),
380
403
  undefined,
381
404
  202,
382
405
  );
383
406
 
384
- expect(resolveSlashMock).toHaveBeenCalledTimes(1);
385
- const context = resolveSlashMock.mock.calls[0][1] as Record<
386
- string,
387
- unknown
388
- >;
389
- expect(context).toMatchObject({
390
- inputTokens: 1000,
391
- outputTokens: 500,
392
- estimatedCost: 0.05,
393
- model: "claude-opus-4-7",
394
- provider: "anthropic",
395
- maxInputTokens: 200000,
396
- });
407
+ const assistantPersist = addMessageMock.mock.calls.find(
408
+ (call) => call[1] === "assistant",
409
+ );
410
+ expect(assistantPersist).toBeDefined();
411
+ expect(String(assistantPersist?.[2])).toContain("1,000 / 150,000 tokens");
412
+ expect(String(assistantPersist?.[2])).toContain(
413
+ "claude-opus-4-7 (anthropic)",
414
+ );
397
415
  });
398
416
 
399
417
  test("applies riskThreshold override when provided", async () => {
400
- resolveSlashMock.mockReturnValue({
401
- kind: "passthrough",
402
- content: "hello there",
403
- });
404
-
405
418
  const { conversation } = makeConversation();
406
419
  const res = await callHandler(
407
420
  (args) => handleSendMessage(args, makeDeps(conversation)),
@@ -418,10 +431,6 @@ describe("handleSendMessage slash command interception", () => {
418
431
  });
419
432
 
420
433
  test("returns 500 when riskThreshold IPC fails", async () => {
421
- resolveSlashMock.mockReturnValue({
422
- kind: "passthrough",
423
- content: "hello there",
424
- });
425
434
  ipcCallMock.mockImplementationOnce(async () => undefined);
426
435
 
427
436
  const { conversation } = makeConversation();
@@ -28,11 +28,13 @@ import {
28
28
  buildSubagentStatusBlock,
29
29
  buildUnifiedTurnContextBlock,
30
30
  findLastInjectedNowContent,
31
+ getSlackCompactionWatermarkForPrefix,
31
32
  injectChannelCapabilityContext,
32
33
  injectChannelCommandContext,
33
34
  isGroupChatType,
34
35
  isSlackChannelConversation,
35
36
  loadSlackActiveThreadFocusBlock,
37
+ loadSlackChronologicalContext,
36
38
  loadSlackChronologicalMessages,
37
39
  resolveChannelCapabilities,
38
40
  stripChannelCapabilityContext,
@@ -1159,9 +1161,7 @@ describe("buildUnifiedTurnContextBlock", () => {
1159
1161
  expect(text).toContain("member_policy: allow");
1160
1162
  // Behavioral guidance: conversational confirmation (one-time decision pattern)
1161
1163
  expect(text).toContain("trusted contact (non-guardian)");
1162
- expect(text).toContain(
1163
- "confirming the guardian's intent conversationally",
1164
- );
1164
+ expect(text).toContain("confirming the guardian's intent conversationally");
1165
1165
  expect(text).not.toContain(
1166
1166
  "tool execution layer will automatically deny it and escalate",
1167
1167
  );
@@ -2298,6 +2298,24 @@ describe("Slack channel chronological rendering — multi-thread", () => {
2298
2298
  });
2299
2299
  }
2300
2300
 
2301
+ test("normalized Slack mention labels stay in assembled model context", async () => {
2302
+ const rows: MessageRow[] = [
2303
+ userRow({
2304
+ id: "m-normalized-mention",
2305
+ createdAt: 1700000000_000,
2306
+ text: "@leo can you check this?",
2307
+ slackMeta: buildSlackMeta({ channelTs: T0, displayName: "alice" }),
2308
+ }),
2309
+ ];
2310
+
2311
+ const result = await runSlackChannelAssembly(rows);
2312
+ const renderedContext = texts(result).join("\n");
2313
+
2314
+ expect(renderedContext).toContain("@leo can you check this?");
2315
+ expect(renderedContext).not.toContain("<@U_LEO>");
2316
+ expect(renderedContext).not.toContain("U_LEO");
2317
+ });
2318
+
2301
2319
  // ── Scenario 1: reply in mid-thread ──────────────────────────────────
2302
2320
  // Alice posts to thread A, Bob replies in thread B (cross-thread). Then
2303
2321
  // Alice posts a follow-up reply in thread A. Cross-thread visibility:
@@ -2825,6 +2843,37 @@ describe("Slack channel chronological rendering — multi-thread", () => {
2825
2843
  expect(allText).not.toContain("dm context");
2826
2844
  });
2827
2845
 
2846
+ test("slack late-join notice is model-facing and non-persisted", async () => {
2847
+ const slackChannelCaps: ChannelCapabilities = {
2848
+ channel: "slack",
2849
+ dashboardCapable: false,
2850
+ supportsDynamicUi: false,
2851
+ supportsVoiceInput: false,
2852
+ chatType: "channel",
2853
+ };
2854
+ const notice =
2855
+ "Slack context note: this turn joined an existing thread. 3 earlier thread messages were backfilled before the current message.";
2856
+
2857
+ const { messages: result, blocks } = await applyRuntimeInjections(
2858
+ [{ role: "user", content: [{ type: "text", text: "current turn" }] }],
2859
+ {
2860
+ channelCapabilities: slackChannelCaps,
2861
+ slackRuntimeContextNotice: notice,
2862
+ transportHints: [notice],
2863
+ },
2864
+ );
2865
+
2866
+ const allText = result
2867
+ .flatMap((m) => m.content)
2868
+ .filter((b): b is { type: "text"; text: string } => b.type === "text")
2869
+ .map((b) => b.text)
2870
+ .join("\n");
2871
+ expect(allText).toContain("<slack_context_notice>");
2872
+ expect(allText).toContain(notice);
2873
+ expect(allText).not.toContain("<transport_hints>");
2874
+ expect(JSON.stringify(blocks)).not.toContain(notice);
2875
+ });
2876
+
2828
2877
  // ── transport_hints kept for non-slack channels ───────────────────────
2829
2878
  test("non-slack conversations still receive <transport_hints>", async () => {
2830
2879
  const { messages: result } = await applyRuntimeInjections(
@@ -2894,6 +2943,211 @@ describe("Slack channel chronological rendering — multi-thread", () => {
2894
2943
  expect(allText).toContain("from untrusted actor");
2895
2944
  });
2896
2945
 
2946
+ test("loadSlackChronologicalContext preserves summary and filters by Slack watermark", () => {
2947
+ const caps: ChannelCapabilities = {
2948
+ channel: "slack",
2949
+ dashboardCapable: false,
2950
+ supportsDynamicUi: false,
2951
+ supportsVoiceInput: false,
2952
+ chatType: "channel",
2953
+ };
2954
+ const rows: MessageRow[] = [
2955
+ userRow({
2956
+ id: "newer-inserted-first",
2957
+ createdAt: 1700000030_000,
2958
+ text: "after watermark",
2959
+ slackMeta: buildSlackMeta({
2960
+ channelTs: T2,
2961
+ displayName: "carol",
2962
+ }),
2963
+ }),
2964
+ userRow({
2965
+ id: "older-backfilled-later",
2966
+ createdAt: 1700000040_000,
2967
+ text: "before watermark even though inserted later",
2968
+ slackMeta: buildSlackMeta({
2969
+ channelTs: T0,
2970
+ displayName: "alice",
2971
+ }),
2972
+ }),
2973
+ userRow({
2974
+ id: "legacy-before-watermark",
2975
+ createdAt: 1700000008_000,
2976
+ text: "legacy row before watermark",
2977
+ }),
2978
+ userRow({
2979
+ id: "at-watermark",
2980
+ createdAt: 1700000045_000,
2981
+ text: "at watermark",
2982
+ slackMeta: buildSlackMeta({
2983
+ channelTs: T1,
2984
+ displayName: "bob",
2985
+ }),
2986
+ }),
2987
+ ];
2988
+
2989
+ const result = loadSlackChronologicalContext("conv-1", caps, {
2990
+ loader: () => rows,
2991
+ trustClass: "guardian",
2992
+ contextSummary: "## Summary\n- compacted Slack history",
2993
+ contextCompactedMessageCount: 99,
2994
+ slackContextCompactionWatermarkTs: T1,
2995
+ });
2996
+
2997
+ expect(result).not.toBeNull();
2998
+ const renderedText = result!.messages
2999
+ .flatMap((message) => message.content)
3000
+ .filter((block): block is { type: "text"; text: string } => {
3001
+ return block.type === "text";
3002
+ })
3003
+ .map((block) => block.text)
3004
+ .join("\n");
3005
+ expect(renderedText).toContain("<context_summary>");
3006
+ expect(renderedText).toContain("compacted Slack history");
3007
+ expect(renderedText).toContain("after watermark");
3008
+ expect(renderedText).not.toContain("before watermark");
3009
+ expect(renderedText).not.toContain("legacy row before watermark");
3010
+ expect(renderedText).not.toContain("at watermark");
3011
+ expect(result!.renderedMessages.map((entry) => entry.message)).toEqual(
3012
+ result!.messages,
3013
+ );
3014
+ expect(
3015
+ result!.renderedMessages.map((entry) => entry.sourceChannelTs),
3016
+ ).toEqual([null, T2]);
3017
+ expect(getSlackCompactionWatermarkForPrefix(result, 1)).toBe(T2);
3018
+ });
3019
+
3020
+ test("active-thread focus filters pre-watermark and legacy compacted rows", () => {
3021
+ const caps: ChannelCapabilities = {
3022
+ channel: "slack",
3023
+ dashboardCapable: false,
3024
+ supportsDynamicUi: false,
3025
+ supportsVoiceInput: false,
3026
+ chatType: "channel",
3027
+ };
3028
+ const rows: MessageRow[] = [
3029
+ userRow({
3030
+ id: "thread-root",
3031
+ createdAt: 1700000000_000,
3032
+ text: "compacted root",
3033
+ slackMeta: buildSlackMeta({
3034
+ channelTs: T0,
3035
+ threadTs: T0,
3036
+ displayName: "alice",
3037
+ }),
3038
+ }),
3039
+ userRow({
3040
+ id: "legacy-old",
3041
+ createdAt: 1700000005_000,
3042
+ text: "legacy compacted row",
3043
+ }),
3044
+ userRow({
3045
+ id: "reply-before",
3046
+ createdAt: 1700000008_000,
3047
+ text: "compacted reply",
3048
+ slackMeta: buildSlackMeta({
3049
+ channelTs: T0_REPLY1,
3050
+ threadTs: T0,
3051
+ displayName: "bob",
3052
+ }),
3053
+ }),
3054
+ userRow({
3055
+ id: "reply-after",
3056
+ createdAt: 1700000025_000,
3057
+ text: "live reply",
3058
+ slackMeta: buildSlackMeta({
3059
+ channelTs: T0_REPLY2,
3060
+ threadTs: T0,
3061
+ displayName: "carol",
3062
+ }),
3063
+ }),
3064
+ ];
3065
+
3066
+ const result = loadSlackActiveThreadFocusBlock("conv-1", caps, {
3067
+ loader: () => rows,
3068
+ trustClass: "guardian",
3069
+ contextCompactedMessageCount: 3,
3070
+ slackContextCompactionWatermarkTs: T1,
3071
+ });
3072
+
3073
+ expect(result).not.toBeNull();
3074
+ expect(result!).toContain("live reply");
3075
+ expect(result!).not.toContain("compacted root");
3076
+ expect(result!).not.toContain("compacted reply");
3077
+ expect(result!).not.toContain("legacy compacted row");
3078
+ });
3079
+
3080
+ test("long Slack thread stays compacted after a later reply", () => {
3081
+ const caps: ChannelCapabilities = {
3082
+ channel: "slack",
3083
+ dashboardCapable: false,
3084
+ supportsDynamicUi: false,
3085
+ supportsVoiceInput: false,
3086
+ chatType: "channel",
3087
+ };
3088
+ const ts = (n: number) => `1700000${String(n).padStart(3, "0")}.000000`;
3089
+ const watermark = ts(80);
3090
+ const rows: MessageRow[] = [
3091
+ ...Array.from({ length: 121 }, (_, index) =>
3092
+ userRow({
3093
+ id: `thread-${index}`,
3094
+ createdAt: 1700000000_000 + index,
3095
+ text: index === 0 ? "original root" : `pre-compaction ${index}`,
3096
+ slackMeta: buildSlackMeta({
3097
+ channelTs: ts(index),
3098
+ threadTs: index === 0 ? undefined : ts(0),
3099
+ displayName: index % 2 === 0 ? "alice" : "bob",
3100
+ }),
3101
+ }),
3102
+ ),
3103
+ userRow({
3104
+ id: "subsequent-reply",
3105
+ createdAt: 1700000000_500,
3106
+ text: "reply after compaction",
3107
+ slackMeta: buildSlackMeta({
3108
+ channelTs: ts(121),
3109
+ threadTs: ts(0),
3110
+ displayName: "carol",
3111
+ }),
3112
+ }),
3113
+ ];
3114
+
3115
+ const result = loadSlackChronologicalContext("conv-1", caps, {
3116
+ loader: () => rows,
3117
+ trustClass: "guardian",
3118
+ contextSummary: "## Summary\n- compacted long Slack thread",
3119
+ contextCompactedMessageCount: 81,
3120
+ slackContextCompactionWatermarkTs: watermark,
3121
+ });
3122
+
3123
+ expect(result).not.toBeNull();
3124
+ const renderedText = result!.messages
3125
+ .flatMap((message) => message.content)
3126
+ .filter((block): block is { type: "text"; text: string } => {
3127
+ return block.type === "text";
3128
+ })
3129
+ .map((block) => block.text)
3130
+ .join("\n");
3131
+
3132
+ expect(renderedText).toContain("compacted long Slack thread");
3133
+ expect(renderedText).toContain("reply after compaction");
3134
+ expect(renderedText).not.toContain("original root");
3135
+ expect(renderedText).not.toContain("pre-compaction 80");
3136
+ const sourceChannelTs = result!.renderedMessages.map(
3137
+ (entry) => entry.sourceChannelTs,
3138
+ );
3139
+ expect(sourceChannelTs[0]).toBeNull();
3140
+ expect(
3141
+ sourceChannelTs
3142
+ .slice(1)
3143
+ .every(
3144
+ (channelTs) =>
3145
+ channelTs !== null &&
3146
+ Number.parseFloat(channelTs) > Number.parseFloat(watermark),
3147
+ ),
3148
+ ).toBe(true);
3149
+ });
3150
+
2897
3151
  // ── loadSlackChronologicalMessages returns null for non-slack channels ─
2898
3152
  test("loadSlackChronologicalMessages returns null for non-slack channels", () => {
2899
3153
  const result = loadSlackChronologicalMessages(
@@ -36,6 +36,7 @@ describe("resolveSlash /commands interface-aware help", () => {
36
36
  expect(lines).toEqual([
37
37
  "/commands — List all available commands",
38
38
  "/compact — Force context compaction immediately",
39
+ "/context — Show conversation context usage",
39
40
  "/models — List all available models",
40
41
  "/status — Show conversation status and context usage",
41
42
  "/btw — Ask a side question while the assistant is working",
@@ -51,6 +52,7 @@ describe("resolveSlash /commands interface-aware help", () => {
51
52
  expect(lines).toEqual([
52
53
  "/commands — List all available commands",
53
54
  "/compact — Force context compaction immediately",
55
+ "/context — Show conversation context usage",
54
56
  "/models — List all available models",
55
57
  "/status — Show conversation status and context usage",
56
58
  "/btw — Ask a side question while the assistant is working",
@@ -65,17 +67,19 @@ describe("resolveSlash /commands interface-aware help", () => {
65
67
  expect(lines).toEqual([
66
68
  "/commands — List all available commands",
67
69
  "/compact — Force context compaction immediately",
70
+ "/context — Show conversation context usage",
68
71
  "/models — List all available models",
69
72
  "/status — Show conversation status and context usage",
70
73
  "/btw — Ask a side question while the assistant is working",
71
74
  ]);
72
75
  });
73
76
 
74
- test("keeps legacy fallback help when no interface is provided", async () => {
77
+ test("orders fallback help consistently when no interface is provided", async () => {
75
78
  const lines = await resolveCommandsLines(makeSlashContext());
76
79
  expect(lines).toEqual([
77
80
  "/commands — List all available commands",
78
81
  "/compact — Force context compaction immediately",
82
+ "/context — Show conversation context usage",
79
83
  "/models — List all available models",
80
84
  "/status — Show conversation status and context usage",
81
85
  ]);
@@ -92,9 +96,23 @@ describe("resolveSlash /commands interface-aware help", () => {
92
96
  });
93
97
 
94
98
  describe("resolveSlash command contract", () => {
99
+ test("/context reports the resolved context budget", async () => {
100
+ const result = await resolveSlash(
101
+ "/context",
102
+ makeSlashContext({ inputTokens: 75_000, maxInputTokens: 150_000 }),
103
+ );
104
+ expect(result.kind).toBe("unknown");
105
+ if (result.kind !== "unknown") {
106
+ throw new Error("Expected /context to resolve to kind=unknown");
107
+ }
108
+ expect(result.message).toContain("50%");
109
+ expect(result.message).toContain("75,000 / 150,000 tokens");
110
+ });
111
+
95
112
  test("keeps unsupported slash forms as passthrough", async () => {
96
113
  const slashForms = [
97
114
  "/commands foo",
115
+ "/context foo",
98
116
  "/models foo",
99
117
  "/status foo",
100
118
  "/pair foo",
@@ -110,17 +128,19 @@ describe("resolveSlash command contract", () => {
110
128
  expect(result).toEqual({ kind: "passthrough", content: input });
111
129
  }
112
130
  });
113
-
114
-
115
131
  });
116
132
 
117
133
  describe("classifySlash is a pure classifier matching resolveSlash kinds", () => {
118
134
  // Lookahead in `buildPassthroughBatch` must not run `resolveSlash`'s side
119
135
  // effects. The pure classifier is synchronous, takes no side-effecting
120
136
  // dependencies, and must agree with resolveSlash's `kind`.
121
- const cases: Array<{ input: string; kind: "passthrough" | "compact" | "unknown" }> = [
137
+ const cases: Array<{
138
+ input: string;
139
+ kind: "passthrough" | "compact" | "unknown";
140
+ }> = [
122
141
  { input: "/pair", kind: "passthrough" },
123
142
  { input: "/models", kind: "unknown" },
143
+ { input: "/context", kind: "unknown" },
124
144
  { input: "/status", kind: "unknown" },
125
145
  { input: "/commands", kind: "unknown" },
126
146
  { input: "/compact", kind: "compact" },
@@ -60,6 +60,8 @@ mock.module("../config/loader.js", () => ({
60
60
  pricingOverrides: [],
61
61
  },
62
62
  rateLimit: { maxRequestsPerMinute: 0 },
63
+ memory: { v2: { enabled: false } },
64
+ conversations: { skipAutoRetitling: false },
63
65
  daemon: {
64
66
  startupSocketWaitMs: 5000,
65
67
  stopTimeoutMs: 5000,
@@ -294,7 +294,6 @@ describe("per-conversation speed override", () => {
294
294
  4096,
295
295
  makeSendToClient(),
296
296
  "/tmp",
297
- undefined, // broadcastToAllClients
298
297
  undefined, // memoryPolicy
299
298
  undefined, // sharedCesClient
300
299
  "standard", // speedOverride
@@ -316,7 +315,6 @@ describe("per-conversation speed override", () => {
316
315
  4096,
317
316
  makeSendToClient(),
318
317
  "/tmp",
319
- undefined, // broadcastToAllClients
320
318
  undefined, // memoryPolicy
321
319
  undefined, // sharedCesClient
322
320
  // no speedOverride — should fall back to global config "fast"
@@ -337,7 +335,6 @@ describe("per-conversation speed override", () => {
337
335
  4096,
338
336
  makeSendToClient(),
339
337
  "/tmp",
340
- undefined, // broadcastToAllClients
341
338
  undefined, // memoryPolicy
342
339
  undefined, // sharedCesClient
343
340
  "fast", // speedOverride