@vellumai/assistant 0.4.17 → 0.4.19

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 (528) hide show
  1. package/docs/runbook-trusted-contacts.md +5 -3
  2. package/eslint.config.mjs +2 -2
  3. package/package.json +1 -1
  4. package/src/__tests__/access-request-decision.test.ts +128 -120
  5. package/src/__tests__/account-registry.test.ts +121 -110
  6. package/src/__tests__/active-skill-tools.test.ts +200 -172
  7. package/src/__tests__/actor-token-service.test.ts +341 -274
  8. package/src/__tests__/agent-loop-thinking.test.ts +28 -19
  9. package/src/__tests__/agent-loop.test.ts +798 -378
  10. package/src/__tests__/anthropic-provider.test.ts +405 -247
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +97 -97
  12. package/src/__tests__/app-bundler.test.ts +112 -79
  13. package/src/__tests__/app-executors.test.ts +205 -178
  14. package/src/__tests__/app-git-history.test.ts +90 -73
  15. package/src/__tests__/app-git-service.test.ts +67 -53
  16. package/src/__tests__/app-open-proxy.test.ts +29 -25
  17. package/src/__tests__/approval-conversation-turn.test.ts +100 -81
  18. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +45 -17
  19. package/src/__tests__/approval-message-composer.test.ts +119 -119
  20. package/src/__tests__/approval-primitive.test.ts +264 -233
  21. package/src/__tests__/approval-routes-http.test.ts +4 -3
  22. package/src/__tests__/asset-materialize-tool.test.ts +250 -178
  23. package/src/__tests__/asset-search-tool.test.ts +251 -191
  24. package/src/__tests__/assistant-attachment-directive.test.ts +187 -142
  25. package/src/__tests__/assistant-attachments.test.ts +254 -186
  26. package/src/__tests__/assistant-event-hub.test.ts +105 -63
  27. package/src/__tests__/assistant-event.test.ts +66 -58
  28. package/src/__tests__/assistant-events-sse-hardening.test.ts +113 -73
  29. package/src/__tests__/assistant-feature-flag-guard.test.ts +78 -52
  30. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +48 -45
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +118 -77
  32. package/src/__tests__/assistant-id-boundary-guard.test.ts +158 -104
  33. package/src/__tests__/attachments-store.test.ts +240 -183
  34. package/src/__tests__/attachments.test.ts +70 -62
  35. package/src/__tests__/audit-log-rotation.test.ts +50 -35
  36. package/src/__tests__/browser-fill-credential.test.ts +169 -101
  37. package/src/__tests__/browser-manager.test.ts +97 -75
  38. package/src/__tests__/browser-runtime-check.test.ts +16 -15
  39. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +12 -10
  40. package/src/__tests__/browser-skill-endstate.test.ts +97 -72
  41. package/src/__tests__/bundle-scanner.test.ts +47 -22
  42. package/src/__tests__/bundled-asset.test.ts +74 -47
  43. package/src/__tests__/call-constants.test.ts +19 -19
  44. package/src/__tests__/call-controller.test.ts +0 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +90 -65
  46. package/src/__tests__/call-domain.test.ts +149 -121
  47. package/src/__tests__/call-pointer-message-composer.test.ts +113 -83
  48. package/src/__tests__/call-pointer-messages.test.ts +213 -154
  49. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +9 -10
  50. package/src/__tests__/call-recovery.test.ts +232 -212
  51. package/src/__tests__/call-routes-http.test.ts +0 -1
  52. package/src/__tests__/call-start-guardian-guard.test.ts +32 -30
  53. package/src/__tests__/call-state-machine.test.ts +62 -51
  54. package/src/__tests__/call-state.test.ts +89 -75
  55. package/src/__tests__/call-store.test.ts +387 -316
  56. package/src/__tests__/callback-handoff-copy.test.ts +84 -82
  57. package/src/__tests__/canonical-guardian-store.test.ts +331 -280
  58. package/src/__tests__/channel-approval-routes.test.ts +1643 -1115
  59. package/src/__tests__/channel-approval.test.ts +139 -137
  60. package/src/__tests__/channel-approvals.test.ts +7 -2
  61. package/src/__tests__/channel-delivery-store.test.ts +232 -194
  62. package/src/__tests__/channel-guardian.test.ts +5 -3
  63. package/src/__tests__/channel-invite-transport.test.ts +107 -92
  64. package/src/__tests__/channel-policy.test.ts +42 -38
  65. package/src/__tests__/channel-readiness-service.test.ts +119 -102
  66. package/src/__tests__/channel-reply-delivery.test.ts +147 -118
  67. package/src/__tests__/channel-retry-sweep.test.ts +153 -110
  68. package/src/__tests__/checker.test.ts +3309 -1850
  69. package/src/__tests__/clarification-resolver.test.ts +91 -79
  70. package/src/__tests__/classifier.test.ts +64 -54
  71. package/src/__tests__/claude-code-skill-regression.test.ts +42 -37
  72. package/src/__tests__/claude-code-tool-profiles.test.ts +31 -29
  73. package/src/__tests__/clawhub.test.ts +92 -82
  74. package/src/__tests__/cli.test.ts +30 -30
  75. package/src/__tests__/clipboard.test.ts +53 -46
  76. package/src/__tests__/commit-guarantee.test.ts +59 -52
  77. package/src/__tests__/commit-message-enrichment-service.test.ts +203 -75
  78. package/src/__tests__/compaction.benchmark.test.ts +33 -31
  79. package/src/__tests__/computer-use-session-compaction.test.ts +60 -50
  80. package/src/__tests__/computer-use-session-lifecycle.test.ts +145 -117
  81. package/src/__tests__/computer-use-session-working-dir.test.ts +62 -48
  82. package/src/__tests__/computer-use-skill-baseline.test.ts +22 -19
  83. package/src/__tests__/computer-use-skill-endstate.test.ts +45 -31
  84. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +121 -88
  85. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +65 -42
  86. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +33 -18
  87. package/src/__tests__/computer-use-tools.test.ts +121 -98
  88. package/src/__tests__/config-schema.test.ts +443 -347
  89. package/src/__tests__/config-watcher.test.ts +96 -81
  90. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +148 -133
  91. package/src/__tests__/conflict-intent-tokenization.test.ts +96 -78
  92. package/src/__tests__/conflict-policy.test.ts +151 -80
  93. package/src/__tests__/conflict-store.test.ts +203 -157
  94. package/src/__tests__/connection-policy.test.ts +89 -59
  95. package/src/__tests__/contacts-tools.test.ts +247 -178
  96. package/src/__tests__/context-memory-e2e.test.ts +306 -214
  97. package/src/__tests__/context-token-estimator.test.ts +114 -74
  98. package/src/__tests__/context-window-manager.test.ts +269 -167
  99. package/src/__tests__/contradiction-checker.test.ts +161 -135
  100. package/src/__tests__/conversation-attention-store.test.ts +350 -290
  101. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  102. package/src/__tests__/conversation-pairing.test.ts +220 -113
  103. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  104. package/src/__tests__/conversation-store.test.ts +390 -235
  105. package/src/__tests__/credential-broker-browser-fill.test.ts +325 -250
  106. package/src/__tests__/credential-broker-server-use.test.ts +283 -243
  107. package/src/__tests__/credential-broker.test.ts +128 -74
  108. package/src/__tests__/credential-host-pattern-match.test.ts +64 -44
  109. package/src/__tests__/credential-metadata-store.test.ts +360 -311
  110. package/src/__tests__/credential-policy-validate.test.ts +81 -65
  111. package/src/__tests__/credential-resolve.test.ts +212 -145
  112. package/src/__tests__/credential-security-e2e.test.ts +144 -103
  113. package/src/__tests__/credential-security-invariants.test.ts +253 -208
  114. package/src/__tests__/credential-selection.test.ts +254 -146
  115. package/src/__tests__/credential-vault-unit.test.ts +531 -341
  116. package/src/__tests__/credential-vault.test.ts +761 -484
  117. package/src/__tests__/daemon-assistant-events.test.ts +91 -66
  118. package/src/__tests__/daemon-lifecycle.test.ts +258 -190
  119. package/src/__tests__/daemon-server-session-init.test.ts +2 -1
  120. package/src/__tests__/date-context.test.ts +314 -249
  121. package/src/__tests__/db-migration-rollback.test.ts +259 -130
  122. package/src/__tests__/db-schedule-syntax-migration.test.ts +78 -41
  123. package/src/__tests__/delete-managed-skill-tool.test.ts +77 -53
  124. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
  125. package/src/__tests__/dictation-mode-detection.test.ts +77 -55
  126. package/src/__tests__/dictation-profile-store.test.ts +70 -56
  127. package/src/__tests__/dictation-text-processing.test.ts +53 -35
  128. package/src/__tests__/diff.test.ts +102 -98
  129. package/src/__tests__/domain-normalize.test.ts +54 -54
  130. package/src/__tests__/domain-policy.test.ts +71 -55
  131. package/src/__tests__/dynamic-page-surface.test.ts +31 -33
  132. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +69 -69
  133. package/src/__tests__/edit-engine.test.ts +56 -56
  134. package/src/__tests__/elevenlabs-client.test.ts +117 -91
  135. package/src/__tests__/elevenlabs-config.test.ts +32 -31
  136. package/src/__tests__/email-classifier.test.ts +15 -12
  137. package/src/__tests__/email-cli.test.ts +121 -108
  138. package/src/__tests__/emit-signal-routing-intent.test.ts +76 -69
  139. package/src/__tests__/encrypted-store.test.ts +180 -154
  140. package/src/__tests__/entity-extractor.test.ts +108 -87
  141. package/src/__tests__/entity-search.test.ts +664 -258
  142. package/src/__tests__/ephemeral-permissions.test.ts +224 -188
  143. package/src/__tests__/event-bus.test.ts +81 -77
  144. package/src/__tests__/extract-email.test.ts +29 -20
  145. package/src/__tests__/file-edit-tool.test.ts +62 -44
  146. package/src/__tests__/file-ops-service.test.ts +131 -114
  147. package/src/__tests__/file-read-tool.test.ts +48 -31
  148. package/src/__tests__/file-write-tool.test.ts +43 -37
  149. package/src/__tests__/filesystem-tools.test.ts +238 -209
  150. package/src/__tests__/followup-tools.test.ts +237 -162
  151. package/src/__tests__/forbidden-legacy-symbols.test.ts +19 -20
  152. package/src/__tests__/frontmatter.test.ts +96 -81
  153. package/src/__tests__/fuzzy-match-property.test.ts +75 -81
  154. package/src/__tests__/fuzzy-match.test.ts +71 -65
  155. package/src/__tests__/gateway-client-managed-outbound.test.ts +76 -57
  156. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  157. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  158. package/src/__tests__/gemini-image-service.test.ts +113 -100
  159. package/src/__tests__/gemini-provider.test.ts +297 -220
  160. package/src/__tests__/get-weather.test.ts +188 -114
  161. package/src/__tests__/gmail-integration.test.ts +13 -5
  162. package/src/__tests__/guardian-action-conversation-turn.test.ts +226 -171
  163. package/src/__tests__/guardian-action-copy-generator.test.ts +111 -93
  164. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
  165. package/src/__tests__/guardian-action-followup-store.test.ts +199 -167
  166. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +297 -250
  167. package/src/__tests__/guardian-action-late-reply.test.ts +462 -316
  168. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +23 -18
  169. package/src/__tests__/guardian-action-store.test.ts +158 -109
  170. package/src/__tests__/guardian-action-sweep.test.ts +114 -100
  171. package/src/__tests__/guardian-actions-endpoint.test.ts +440 -256
  172. package/src/__tests__/guardian-control-plane-policy.test.ts +497 -331
  173. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +217 -215
  174. package/src/__tests__/guardian-dispatch.test.ts +316 -256
  175. package/src/__tests__/guardian-grant-minting.test.ts +247 -178
  176. package/src/__tests__/guardian-outbound-http.test.ts +5 -3
  177. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +99 -96
  178. package/src/__tests__/guardian-question-copy.test.ts +17 -17
  179. package/src/__tests__/guardian-question-mode.test.ts +134 -100
  180. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  181. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  182. package/src/__tests__/guardian-verification-intent-routing.test.ts +94 -88
  183. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  184. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +0 -1
  185. package/src/__tests__/handle-user-message-secret-resume.test.ts +7 -2
  186. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +92 -76
  187. package/src/__tests__/handlers-cu-observation-blob.test.ts +103 -70
  188. package/src/__tests__/handlers-ipc-blob-probe.test.ts +77 -51
  189. package/src/__tests__/handlers-slack-config.test.ts +63 -54
  190. package/src/__tests__/handlers-task-submit-slash.test.ts +18 -18
  191. package/src/__tests__/handlers-telegram-config.test.ts +662 -329
  192. package/src/__tests__/handlers-twitter-config.test.ts +525 -298
  193. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +5 -2
  194. package/src/__tests__/headless-browser-interactions.test.ts +444 -280
  195. package/src/__tests__/headless-browser-navigate.test.ts +116 -79
  196. package/src/__tests__/headless-browser-read-tools.test.ts +123 -86
  197. package/src/__tests__/headless-browser-snapshot.test.ts +71 -56
  198. package/src/__tests__/heartbeat-service.test.ts +76 -58
  199. package/src/__tests__/history-repair-observability.test.ts +14 -14
  200. package/src/__tests__/history-repair.test.ts +171 -167
  201. package/src/__tests__/home-base-bootstrap.test.ts +30 -27
  202. package/src/__tests__/hooks-blocking.test.ts +86 -37
  203. package/src/__tests__/hooks-cli.test.ts +104 -68
  204. package/src/__tests__/hooks-config.test.ts +81 -43
  205. package/src/__tests__/hooks-discovery.test.ts +106 -96
  206. package/src/__tests__/hooks-integration.test.ts +78 -72
  207. package/src/__tests__/hooks-manager.test.ts +99 -61
  208. package/src/__tests__/hooks-runner.test.ts +94 -71
  209. package/src/__tests__/hooks-settings.test.ts +69 -64
  210. package/src/__tests__/hooks-templates.test.ts +85 -54
  211. package/src/__tests__/hooks-ts-runner.test.ts +82 -45
  212. package/src/__tests__/hooks-watch.test.ts +32 -22
  213. package/src/__tests__/host-file-edit-tool.test.ts +190 -148
  214. package/src/__tests__/host-file-read-tool.test.ts +86 -63
  215. package/src/__tests__/host-file-write-tool.test.ts +98 -64
  216. package/src/__tests__/host-shell-tool.test.ts +342 -233
  217. package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
  218. package/src/__tests__/ingress-member-store.test.ts +163 -159
  219. package/src/__tests__/ingress-reconcile.test.ts +13 -6
  220. package/src/__tests__/ingress-routes-http.test.ts +441 -356
  221. package/src/__tests__/ingress-url-consistency.test.ts +125 -64
  222. package/src/__tests__/integration-status.test.ts +93 -73
  223. package/src/__tests__/intent-routing.test.ts +148 -118
  224. package/src/__tests__/invite-redemption-service.test.ts +163 -121
  225. package/src/__tests__/ipc-blob-store.test.ts +104 -91
  226. package/src/__tests__/ipc-contract-inventory.test.ts +27 -15
  227. package/src/__tests__/ipc-contract.test.ts +24 -23
  228. package/src/__tests__/ipc-protocol.test.ts +52 -46
  229. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +61 -50
  230. package/src/__tests__/ipc-snapshot.test.ts +1135 -1056
  231. package/src/__tests__/ipc-validate.test.ts +240 -179
  232. package/src/__tests__/key-migration.test.ts +123 -90
  233. package/src/__tests__/keychain.test.ts +150 -123
  234. package/src/__tests__/lifecycle-docs-guard.test.ts +65 -64
  235. package/src/__tests__/llm-usage-store.test.ts +112 -87
  236. package/src/__tests__/managed-skill-lifecycle.test.ts +147 -108
  237. package/src/__tests__/managed-store.test.ts +411 -360
  238. package/src/__tests__/mcp-cli.test.ts +190 -124
  239. package/src/__tests__/mcp-health-check.test.ts +26 -21
  240. package/src/__tests__/media-generate-image.test.ts +122 -99
  241. package/src/__tests__/media-reuse-story.e2e.test.ts +282 -214
  242. package/src/__tests__/media-visibility-policy.test.ts +86 -38
  243. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +146 -100
  244. package/src/__tests__/memory-lifecycle-e2e.test.ts +385 -297
  245. package/src/__tests__/memory-query-builder.test.ts +32 -33
  246. package/src/__tests__/memory-recall-quality.test.ts +761 -407
  247. package/src/__tests__/memory-regressions.experimental.test.ts +443 -380
  248. package/src/__tests__/memory-regressions.test.ts +3725 -2642
  249. package/src/__tests__/memory-retrieval-budget.test.ts +7 -8
  250. package/src/__tests__/memory-retrieval.benchmark.test.ts +144 -109
  251. package/src/__tests__/memory-upsert-concurrency.test.ts +292 -201
  252. package/src/__tests__/messaging-send-tool.test.ts +36 -29
  253. package/src/__tests__/migration-cli-flows.test.ts +69 -53
  254. package/src/__tests__/migration-ordering.test.ts +103 -86
  255. package/src/__tests__/mime-builder.test.ts +55 -32
  256. package/src/__tests__/mock-signup-server.test.ts +384 -246
  257. package/src/__tests__/model-intents.test.ts +61 -37
  258. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +9 -12
  259. package/src/__tests__/no-is-trusted-guard.test.ts +24 -21
  260. package/src/__tests__/non-member-access-request.test.ts +3 -2
  261. package/src/__tests__/notification-broadcaster.test.ts +99 -81
  262. package/src/__tests__/notification-decision-fallback.test.ts +223 -178
  263. package/src/__tests__/notification-decision-strategy.test.ts +375 -337
  264. package/src/__tests__/notification-deep-link.test.ts +67 -61
  265. package/src/__tests__/notification-guardian-path.test.ts +248 -206
  266. package/src/__tests__/notification-routing-intent.test.ts +166 -93
  267. package/src/__tests__/notification-thread-candidate-validation.test.ts +78 -75
  268. package/src/__tests__/notification-thread-candidates.test.ts +64 -61
  269. package/src/__tests__/oauth-callback-registry.test.ts +40 -30
  270. package/src/__tests__/oauth-connect-handler.test.ts +109 -89
  271. package/src/__tests__/oauth-scope-policy.test.ts +63 -55
  272. package/src/__tests__/oauth2-gateway-transport.test.ts +252 -174
  273. package/src/__tests__/onboarding-starter-tasks.test.ts +93 -89
  274. package/src/__tests__/onboarding-template-contract.test.ts +93 -94
  275. package/src/__tests__/openai-provider.test.ts +366 -274
  276. package/src/__tests__/pairing-concurrent.test.ts +18 -12
  277. package/src/__tests__/pairing-routes.test.ts +45 -41
  278. package/src/__tests__/parallel-tool.benchmark.test.ts +108 -58
  279. package/src/__tests__/parser.test.ts +316 -226
  280. package/src/__tests__/path-classifier.test.ts +24 -25
  281. package/src/__tests__/path-policy.test.ts +187 -147
  282. package/src/__tests__/phone.test.ts +36 -36
  283. package/src/__tests__/platform-move-helper.test.ts +48 -40
  284. package/src/__tests__/platform-socket-path.test.ts +23 -24
  285. package/src/__tests__/platform-workspace-migration.test.ts +464 -414
  286. package/src/__tests__/platform.test.ts +61 -53
  287. package/src/__tests__/playbook-execution.test.ts +397 -265
  288. package/src/__tests__/playbook-tools.test.ts +267 -196
  289. package/src/__tests__/prebuilt-home-base-seed.test.ts +30 -27
  290. package/src/__tests__/pricing.test.ts +316 -136
  291. package/src/__tests__/profile-compiler.test.ts +206 -188
  292. package/src/__tests__/provider-commit-message-generator.test.ts +114 -106
  293. package/src/__tests__/provider-error-scenarios.test.ts +212 -158
  294. package/src/__tests__/provider-fail-open-selection.test.ts +51 -44
  295. package/src/__tests__/provider-registry-ollama.test.ts +13 -9
  296. package/src/__tests__/provider-streaming.benchmark.test.ts +232 -183
  297. package/src/__tests__/proxy-approval-callback.test.ts +180 -119
  298. package/src/__tests__/public-ingress-urls.test.ts +112 -94
  299. package/src/__tests__/qdrant-manager.test.ts +147 -98
  300. package/src/__tests__/ratelimit.test.ts +152 -82
  301. package/src/__tests__/recording-handler.test.ts +273 -151
  302. package/src/__tests__/recording-intent-fallback.test.ts +94 -75
  303. package/src/__tests__/recording-intent-handler.test.ts +9 -2
  304. package/src/__tests__/recording-intent.test.ts +578 -379
  305. package/src/__tests__/recording-state-machine.test.ts +530 -316
  306. package/src/__tests__/recurrence-engine-rruleset.test.ts +150 -92
  307. package/src/__tests__/recurrence-engine.test.ts +81 -41
  308. package/src/__tests__/recurrence-types.test.ts +63 -44
  309. package/src/__tests__/relay-server.test.ts +2131 -1602
  310. package/src/__tests__/reminder-store.test.ts +158 -80
  311. package/src/__tests__/reminder.test.ts +113 -109
  312. package/src/__tests__/remote-skill-policy.test.ts +96 -72
  313. package/src/__tests__/request-file-tool.test.ts +74 -67
  314. package/src/__tests__/response-tier.test.ts +131 -74
  315. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  316. package/src/__tests__/runtime-events-sse-parity.test.ts +167 -145
  317. package/src/__tests__/runtime-events-sse.test.ts +0 -1
  318. package/src/__tests__/sandbox-diagnostics.test.ts +66 -56
  319. package/src/__tests__/sandbox-host-parity.test.ts +377 -301
  320. package/src/__tests__/scaffold-managed-skill-tool.test.ts +213 -161
  321. package/src/__tests__/schedule-store.test.ts +268 -205
  322. package/src/__tests__/schedule-tools.test.ts +702 -524
  323. package/src/__tests__/scheduler-recurrence.test.ts +240 -130
  324. package/src/__tests__/scoped-approval-grants.test.ts +258 -168
  325. package/src/__tests__/scoped-grant-security-matrix.test.ts +160 -146
  326. package/src/__tests__/script-proxy-certs.test.ts +38 -35
  327. package/src/__tests__/script-proxy-connect-tunnel.test.ts +71 -46
  328. package/src/__tests__/script-proxy-decision-trace.test.ts +161 -84
  329. package/src/__tests__/script-proxy-http-forwarder.test.ts +146 -129
  330. package/src/__tests__/script-proxy-injection-runtime.test.ts +139 -113
  331. package/src/__tests__/script-proxy-mitm-handler.test.ts +226 -142
  332. package/src/__tests__/script-proxy-policy-runtime.test.ts +126 -86
  333. package/src/__tests__/script-proxy-policy.test.ts +308 -153
  334. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +74 -62
  335. package/src/__tests__/script-proxy-router.test.ts +111 -77
  336. package/src/__tests__/script-proxy-session-manager.test.ts +156 -113
  337. package/src/__tests__/script-proxy-session-runtime.test.ts +28 -24
  338. package/src/__tests__/secret-allowlist.test.ts +105 -90
  339. package/src/__tests__/secret-ingress-handler.test.ts +41 -30
  340. package/src/__tests__/secret-onetime-send.test.ts +67 -50
  341. package/src/__tests__/secret-prompt-log-hygiene.test.ts +35 -31
  342. package/src/__tests__/secret-response-routing.test.ts +50 -41
  343. package/src/__tests__/secret-scanner-executor.test.ts +152 -111
  344. package/src/__tests__/secret-scanner.test.ts +495 -413
  345. package/src/__tests__/secure-keys.test.ts +132 -121
  346. package/src/__tests__/send-endpoint-busy.test.ts +8 -3
  347. package/src/__tests__/send-notification-tool.test.ts +43 -42
  348. package/src/__tests__/sensitive-output-placeholders.test.ts +72 -64
  349. package/src/__tests__/sequence-store.test.ts +335 -167
  350. package/src/__tests__/server-history-render.test.ts +341 -202
  351. package/src/__tests__/session-abort-tool-results.test.ts +133 -70
  352. package/src/__tests__/session-confirmation-signals.test.ts +252 -160
  353. package/src/__tests__/session-conflict-gate.test.ts +775 -585
  354. package/src/__tests__/session-error.test.ts +222 -191
  355. package/src/__tests__/session-evictor.test.ts +79 -62
  356. package/src/__tests__/session-init.benchmark.test.ts +170 -108
  357. package/src/__tests__/session-load-history-repair.test.ts +273 -139
  358. package/src/__tests__/session-messaging-secret-redirect.test.ts +130 -90
  359. package/src/__tests__/session-pre-run-repair.test.ts +106 -59
  360. package/src/__tests__/session-profile-injection.test.ts +198 -130
  361. package/src/__tests__/session-provider-retry-repair.test.ts +223 -141
  362. package/src/__tests__/session-queue.test.ts +624 -321
  363. package/src/__tests__/session-runtime-assembly.test.ts +425 -329
  364. package/src/__tests__/session-runtime-workspace.test.ts +69 -61
  365. package/src/__tests__/session-skill-tools.test.ts +973 -678
  366. package/src/__tests__/session-slash-known.test.ts +185 -133
  367. package/src/__tests__/session-slash-queue.test.ts +147 -81
  368. package/src/__tests__/session-slash-unknown.test.ts +135 -90
  369. package/src/__tests__/session-surfaces-task-progress.test.ts +122 -87
  370. package/src/__tests__/session-tool-setup-app-refresh.test.ts +338 -177
  371. package/src/__tests__/session-tool-setup-memory-scope.test.ts +63 -40
  372. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +60 -37
  373. package/src/__tests__/session-tool-setup-tools-disabled.test.ts +28 -26
  374. package/src/__tests__/session-undo.test.ts +43 -30
  375. package/src/__tests__/session-workspace-cache-state.test.ts +108 -67
  376. package/src/__tests__/session-workspace-injection.test.ts +245 -117
  377. package/src/__tests__/session-workspace-tool-tracking.test.ts +260 -93
  378. package/src/__tests__/shared-filesystem-errors.test.ts +47 -47
  379. package/src/__tests__/shell-credential-ref.test.ts +126 -90
  380. package/src/__tests__/shell-identity.test.ts +134 -111
  381. package/src/__tests__/shell-parser-fuzz.test.ts +263 -179
  382. package/src/__tests__/shell-parser-property.test.ts +435 -288
  383. package/src/__tests__/shell-tool-proxy-mode.test.ts +142 -70
  384. package/src/__tests__/size-guard.test.ts +42 -44
  385. package/src/__tests__/skill-feature-flags-integration.test.ts +79 -52
  386. package/src/__tests__/skill-feature-flags.test.ts +75 -47
  387. package/src/__tests__/skill-include-graph.test.ts +143 -148
  388. package/src/__tests__/skill-load-feature-flag.test.ts +94 -59
  389. package/src/__tests__/skill-load-tool.test.ts +371 -199
  390. package/src/__tests__/skill-projection-feature-flag.test.ts +131 -88
  391. package/src/__tests__/skill-projection.benchmark.test.ts +93 -65
  392. package/src/__tests__/skill-script-runner-host.test.ts +460 -250
  393. package/src/__tests__/skill-script-runner-sandbox.test.ts +168 -108
  394. package/src/__tests__/skill-script-runner.test.ts +115 -74
  395. package/src/__tests__/skill-tool-factory.test.ts +140 -96
  396. package/src/__tests__/skill-tool-manifest.test.ts +306 -210
  397. package/src/__tests__/skill-version-hash.test.ts +70 -56
  398. package/src/__tests__/skills.test.ts +0 -1
  399. package/src/__tests__/slack-channel-config.test.ts +127 -84
  400. package/src/__tests__/slack-skill.test.ts +60 -47
  401. package/src/__tests__/slash-commands-catalog.test.ts +37 -31
  402. package/src/__tests__/slash-commands-parser.test.ts +71 -64
  403. package/src/__tests__/slash-commands-resolver.test.ts +143 -107
  404. package/src/__tests__/slash-commands-rewrite.test.ts +22 -22
  405. package/src/__tests__/sms-messaging-provider.test.ts +4 -0
  406. package/src/__tests__/speaker-identification.test.ts +28 -25
  407. package/src/__tests__/starter-bundle.test.ts +27 -23
  408. package/src/__tests__/starter-task-flow.test.ts +67 -52
  409. package/src/__tests__/subagent-manager-notify.test.ts +154 -108
  410. package/src/__tests__/subagent-tools.test.ts +311 -270
  411. package/src/__tests__/subagent-types.test.ts +40 -40
  412. package/src/__tests__/surface-mutex-cleanup.test.ts +42 -30
  413. package/src/__tests__/swarm-dag-pathological.test.ts +122 -111
  414. package/src/__tests__/swarm-orchestrator.test.ts +135 -101
  415. package/src/__tests__/swarm-plan-validator.test.ts +125 -73
  416. package/src/__tests__/swarm-recursion.test.ts +58 -46
  417. package/src/__tests__/swarm-router-planner.test.ts +99 -74
  418. package/src/__tests__/swarm-session-integration.test.ts +148 -91
  419. package/src/__tests__/swarm-tool.test.ts +65 -45
  420. package/src/__tests__/swarm-worker-backend.test.ts +59 -45
  421. package/src/__tests__/swarm-worker-runner.test.ts +133 -118
  422. package/src/__tests__/system-prompt.test.ts +311 -256
  423. package/src/__tests__/task-compiler.test.ts +176 -120
  424. package/src/__tests__/task-management-tools.test.ts +561 -456
  425. package/src/__tests__/task-memory-cleanup.test.ts +627 -362
  426. package/src/__tests__/task-runner.test.ts +117 -94
  427. package/src/__tests__/task-scheduler.test.ts +113 -84
  428. package/src/__tests__/task-tools.test.ts +349 -264
  429. package/src/__tests__/terminal-sandbox.test.ts +138 -108
  430. package/src/__tests__/terminal-tools.test.ts +350 -305
  431. package/src/__tests__/thread-seed-composer.test.ts +307 -180
  432. package/src/__tests__/tool-approval-handler.test.ts +238 -137
  433. package/src/__tests__/tool-audit-listener.test.ts +69 -69
  434. package/src/__tests__/tool-domain-event-publisher.test.ts +142 -132
  435. package/src/__tests__/tool-execution-abort-cleanup.test.ts +155 -146
  436. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +136 -105
  437. package/src/__tests__/tool-executor-lifecycle-events.test.ts +355 -239
  438. package/src/__tests__/tool-executor-redaction.test.ts +112 -109
  439. package/src/__tests__/tool-executor-shell-integration.test.ts +130 -79
  440. package/src/__tests__/tool-executor.test.ts +1274 -674
  441. package/src/__tests__/tool-grant-request-escalation.test.ts +401 -283
  442. package/src/__tests__/tool-metrics-listener.test.ts +97 -85
  443. package/src/__tests__/tool-notification-listener.test.ts +42 -25
  444. package/src/__tests__/tool-permission-simulate-handler.test.ts +137 -113
  445. package/src/__tests__/tool-policy.test.ts +44 -25
  446. package/src/__tests__/tool-profiling-listener.test.ts +99 -93
  447. package/src/__tests__/tool-result-truncation.test.ts +5 -4
  448. package/src/__tests__/tool-trace-listener.test.ts +131 -111
  449. package/src/__tests__/top-level-renderer.test.ts +62 -58
  450. package/src/__tests__/top-level-scanner.test.ts +68 -64
  451. package/src/__tests__/trace-emitter.test.ts +56 -56
  452. package/src/__tests__/trust-context-guards.test.ts +65 -65
  453. package/src/__tests__/trust-store.test.ts +1239 -806
  454. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  455. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  456. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
  457. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
  458. package/src/__tests__/trusted-contact-verification.test.ts +251 -231
  459. package/src/__tests__/turn-commit.test.ts +259 -200
  460. package/src/__tests__/twilio-provider.test.ts +140 -126
  461. package/src/__tests__/twilio-rest.test.ts +22 -18
  462. package/src/__tests__/twilio-routes-elevenlabs.test.ts +0 -1
  463. package/src/__tests__/twilio-routes-twiml.test.ts +55 -55
  464. package/src/__tests__/twilio-routes.test.ts +0 -1
  465. package/src/__tests__/twitter-auth-handler.test.ts +184 -139
  466. package/src/__tests__/twitter-cli-error-shaping.test.ts +88 -73
  467. package/src/__tests__/twitter-cli-routing.test.ts +146 -99
  468. package/src/__tests__/twitter-oauth-client.test.ts +82 -65
  469. package/src/__tests__/update-bulletin-format.test.ts +69 -66
  470. package/src/__tests__/update-bulletin-state.test.ts +66 -60
  471. package/src/__tests__/update-bulletin.test.ts +150 -114
  472. package/src/__tests__/update-template-contract.test.ts +15 -10
  473. package/src/__tests__/url-safety.test.ts +288 -265
  474. package/src/__tests__/user-reference.test.ts +32 -32
  475. package/src/__tests__/view-image-tool.test.ts +118 -96
  476. package/src/__tests__/voice-invite-redemption.test.ts +111 -106
  477. package/src/__tests__/voice-quality.test.ts +117 -102
  478. package/src/__tests__/voice-scoped-grant-consumer.test.ts +204 -146
  479. package/src/__tests__/voice-session-bridge.test.ts +351 -216
  480. package/src/__tests__/weather-skill-regression.test.ts +170 -120
  481. package/src/__tests__/web-fetch.test.ts +664 -526
  482. package/src/__tests__/web-search.test.ts +379 -213
  483. package/src/__tests__/work-item-output.test.ts +90 -53
  484. package/src/__tests__/workspace-git-service.test.ts +437 -356
  485. package/src/__tests__/workspace-heartbeat-service.test.ts +125 -91
  486. package/src/__tests__/workspace-lifecycle.test.ts +98 -64
  487. package/src/__tests__/workspace-policy.test.ts +139 -71
  488. package/src/cli/mcp.ts +81 -28
  489. package/src/commands/__tests__/cc-command-registry.test.ts +142 -134
  490. package/src/config/__tests__/feature-flag-registry-guard.test.ts +48 -39
  491. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +25 -10
  492. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -1
  493. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +6 -11
  494. package/src/config/bundled-skills/messaging/SKILL.md +4 -3
  495. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +15 -5
  496. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -5
  497. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -2
  498. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +34 -32
  499. package/src/config/bundled-skills/sms-setup/SKILL.md +8 -16
  500. package/src/config/bundled-skills/telegram-setup/SKILL.md +3 -3
  501. package/src/config/bundled-skills/trusted-contacts/SKILL.md +13 -25
  502. package/src/config/bundled-skills/twilio-setup/SKILL.md +13 -23
  503. package/src/config/bundled-tool-registry.ts +2 -0
  504. package/src/config/env.ts +3 -4
  505. package/src/config/system-prompt.ts +32 -0
  506. package/src/mcp/client.ts +2 -7
  507. package/src/memory/db-connection.ts +16 -10
  508. package/src/messaging/providers/gmail/adapter.ts +10 -3
  509. package/src/messaging/providers/gmail/client.ts +280 -72
  510. package/src/runtime/auth/__tests__/context.test.ts +75 -65
  511. package/src/runtime/auth/__tests__/credential-service.test.ts +137 -114
  512. package/src/runtime/auth/__tests__/guard-tests.test.ts +84 -90
  513. package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +40 -40
  514. package/src/runtime/auth/__tests__/middleware.test.ts +80 -74
  515. package/src/runtime/auth/__tests__/policy.test.ts +9 -9
  516. package/src/runtime/auth/__tests__/route-policy.test.ts +76 -65
  517. package/src/runtime/auth/__tests__/scopes.test.ts +68 -60
  518. package/src/runtime/auth/__tests__/subject.test.ts +54 -54
  519. package/src/runtime/auth/__tests__/token-service.test.ts +115 -108
  520. package/src/runtime/auth/scopes.ts +3 -0
  521. package/src/runtime/auth/token-service.ts +4 -1
  522. package/src/runtime/auth/types.ts +2 -1
  523. package/src/runtime/http-server.ts +2 -1
  524. package/src/security/secure-keys.ts +120 -54
  525. package/src/tools/browser/__tests__/auth-cache.test.ts +69 -63
  526. package/src/tools/browser/__tests__/auth-detector.test.ts +218 -157
  527. package/src/tools/browser/__tests__/jit-auth.test.ts +83 -99
  528. package/src/tools/terminal/safe-env.ts +7 -0
@@ -1,16 +1,22 @@
1
- import { describe, expect, test } from 'bun:test';
1
+ import { describe, expect, test } from "bun:test";
2
2
 
3
- import type { ContextWindowConfig } from '../config/types.js';
4
- import { estimateTextTokens } from '../context/token-estimator.js';
3
+ import type { ContextWindowConfig } from "../config/types.js";
4
+ import { estimateTextTokens } from "../context/token-estimator.js";
5
5
  import {
6
6
  CONTEXT_SUMMARY_MARKER,
7
7
  ContextWindowManager,
8
8
  createContextSummaryMessage,
9
9
  getSummaryFromContextMessage,
10
- } from '../context/window-manager.js';
11
- import type { Message, Provider, ProviderResponse } from '../providers/types.js';
12
-
13
- function makeConfig(overrides: Partial<ContextWindowConfig> = {}): ContextWindowConfig {
10
+ } from "../context/window-manager.js";
11
+ import type {
12
+ Message,
13
+ Provider,
14
+ ProviderResponse,
15
+ } from "../providers/types.js";
16
+
17
+ function makeConfig(
18
+ overrides: Partial<ContextWindowConfig> = {},
19
+ ): ContextWindowConfig {
14
20
  return {
15
21
  enabled: true,
16
22
  maxInputTokens: 450,
@@ -23,56 +29,65 @@ function makeConfig(overrides: Partial<ContextWindowConfig> = {}): ContextWindow
23
29
  };
24
30
  }
25
31
 
26
- function createProvider(fn: (messages: Message[]) => ProviderResponse | Promise<ProviderResponse>): Provider {
32
+ function createProvider(
33
+ fn: (messages: Message[]) => ProviderResponse | Promise<ProviderResponse>,
34
+ ): Provider {
27
35
  return {
28
- name: 'mock',
36
+ name: "mock",
29
37
  async sendMessage(messages: Message[]): Promise<ProviderResponse> {
30
38
  return fn(messages);
31
39
  },
32
40
  };
33
41
  }
34
42
 
35
- function message(role: 'user' | 'assistant', text: string): Message {
36
- return { role, content: [{ type: 'text', text }] };
43
+ function message(role: "user" | "assistant", text: string): Message {
44
+ return { role, content: [{ type: "text", text }] };
37
45
  }
38
46
 
39
- describe('ContextWindowManager', () => {
40
- test('skips compaction when estimated tokens are below threshold', async () => {
47
+ describe("ContextWindowManager", () => {
48
+ test("skips compaction when estimated tokens are below threshold", async () => {
41
49
  const provider = createProvider(() => {
42
- throw new Error('should not be called');
50
+ throw new Error("should not be called");
43
51
  });
44
- const manager = new ContextWindowManager(provider, 'system prompt', makeConfig());
45
- const history = [
46
- message('user', 'hello'),
47
- message('assistant', 'hi'),
48
- ];
52
+ const manager = new ContextWindowManager(
53
+ provider,
54
+ "system prompt",
55
+ makeConfig(),
56
+ );
57
+ const history = [message("user", "hello"), message("assistant", "hi")];
49
58
 
50
59
  const result = await manager.maybeCompact(history);
51
60
  expect(result.compacted).toBe(false);
52
61
  expect(result.messages).toEqual(history);
53
- expect(result.reason).toBe('below compaction threshold');
62
+ expect(result.reason).toBe("below compaction threshold");
54
63
  });
55
64
 
56
- test('compacts old turns and keeps recent user turns', async () => {
65
+ test("compacts old turns and keeps recent user turns", async () => {
57
66
  let summaryCalls = 0;
58
67
  const provider = createProvider(() => {
59
68
  summaryCalls += 1;
60
69
  return {
61
- content: [{ type: 'text', text: `## Goals\n- summary call ${summaryCalls}` }],
62
- model: 'mock-model',
70
+ content: [
71
+ { type: "text", text: `## Goals\n- summary call ${summaryCalls}` },
72
+ ],
73
+ model: "mock-model",
63
74
  usage: { inputTokens: 100, outputTokens: 25 },
64
- stopReason: 'end_turn',
75
+ stopReason: "end_turn",
65
76
  };
66
77
  });
67
- const manager = new ContextWindowManager(provider, 'system prompt', makeConfig());
68
- const long = 'x'.repeat(240);
78
+ const manager = new ContextWindowManager(
79
+ provider,
80
+ "system prompt",
81
+ makeConfig(),
82
+ );
83
+ const long = "x".repeat(240);
69
84
  const history: Message[] = [
70
- message('user', `u1 ${long}`),
71
- message('assistant', `a1 ${long}`),
72
- message('user', `u2 ${long}`),
73
- message('assistant', `a2 ${long}`),
74
- message('user', `u3 ${long}`),
75
- message('assistant', `a3 ${long}`),
85
+ message("user", `u1 ${long}`),
86
+ message("assistant", `a1 ${long}`),
87
+ message("user", `u2 ${long}`),
88
+ message("assistant", `a2 ${long}`),
89
+ message("user", `u3 ${long}`),
90
+ message("assistant", `a3 ${long}`),
76
91
  ];
77
92
 
78
93
  const result = await manager.maybeCompact(history);
@@ -82,68 +97,80 @@ describe('ContextWindowManager', () => {
82
97
  expect(result.summaryCalls).toBe(summaryCalls);
83
98
  expect(result.summaryInputTokens).toBeGreaterThan(0);
84
99
  expect(result.summaryOutputTokens).toBeGreaterThan(0);
85
- expect(result.messages[0].role).toBe('user');
86
- expect(getSummaryFromContextMessage(result.messages[0])?.length).toBeGreaterThan(0);
100
+ expect(result.messages[0].role).toBe("user");
101
+ expect(
102
+ getSummaryFromContextMessage(result.messages[0])?.length,
103
+ ).toBeGreaterThan(0);
87
104
 
88
105
  const userTexts = result.messages
89
- .filter((m) => m.role === 'user')
90
- .map((m) => (m.content[0].type === 'text' ? m.content[0].text : ''));
91
- expect(userTexts.some((text) => text.startsWith('u1 '))).toBe(false);
92
- expect(userTexts.some((text) => text.startsWith('u2 '))).toBe(true);
93
- expect(userTexts.some((text) => text.startsWith('u3 '))).toBe(true);
106
+ .filter((m) => m.role === "user")
107
+ .map((m) => (m.content[0].type === "text" ? m.content[0].text : ""));
108
+ expect(userTexts.some((text) => text.startsWith("u1 "))).toBe(false);
109
+ expect(userTexts.some((text) => text.startsWith("u2 "))).toBe(true);
110
+ expect(userTexts.some((text) => text.startsWith("u3 "))).toBe(true);
94
111
  });
95
112
 
96
- test('updates an existing summary message instead of nesting summaries', async () => {
113
+ test("updates an existing summary message instead of nesting summaries", async () => {
97
114
  const provider = createProvider(() => ({
98
- content: [{ type: 'text', text: '## Goals\n- updated summary' }],
99
- model: 'mock-model',
115
+ content: [{ type: "text", text: "## Goals\n- updated summary" }],
116
+ model: "mock-model",
100
117
  usage: { inputTokens: 50, outputTokens: 10 },
101
- stopReason: 'end_turn',
118
+ stopReason: "end_turn",
102
119
  }));
103
120
  const manager = new ContextWindowManager(
104
121
  provider,
105
- 'system prompt',
106
- makeConfig({ maxInputTokens: 300, targetInputTokens: 160, preserveRecentUserTurns: 1 }),
122
+ "system prompt",
123
+ makeConfig({
124
+ maxInputTokens: 300,
125
+ targetInputTokens: 160,
126
+ preserveRecentUserTurns: 1,
127
+ }),
107
128
  );
108
- const long = 'y'.repeat(220);
129
+ const long = "y".repeat(220);
109
130
  const history: Message[] = [
110
- createContextSummaryMessage('## Goals\n- old summary'),
111
- message('user', `older ${long}`),
112
- message('assistant', `reply ${long}`),
113
- message('user', `latest ${long}`),
131
+ createContextSummaryMessage("## Goals\n- old summary"),
132
+ message("user", `older ${long}`),
133
+ message("assistant", `reply ${long}`),
134
+ message("user", `latest ${long}`),
114
135
  ];
115
136
 
116
137
  const result = await manager.maybeCompact(history);
117
138
  expect(result.compacted).toBe(true);
118
139
  expect(result.messages.length).toBeLessThan(history.length + 1);
119
- expect(getSummaryFromContextMessage(result.messages[0])).toContain('updated summary');
140
+ expect(getSummaryFromContextMessage(result.messages[0])).toContain(
141
+ "updated summary",
142
+ );
120
143
  expect(
121
144
  result.messages.filter(
122
145
  (m) =>
123
- m.role === 'user'
124
- && m.content.some(
146
+ m.role === "user" &&
147
+ m.content.some(
125
148
  (block) =>
126
- block.type === 'text'
127
- && block.text.startsWith(CONTEXT_SUMMARY_MARKER),
149
+ block.type === "text" &&
150
+ block.text.startsWith(CONTEXT_SUMMARY_MARKER),
128
151
  ),
129
152
  ),
130
153
  ).toHaveLength(1);
131
154
  });
132
155
 
133
- test('falls back to local summary when provider summarization fails', async () => {
156
+ test("falls back to local summary when provider summarization fails", async () => {
134
157
  const provider = createProvider(async () => {
135
- throw new Error('provider unavailable');
158
+ throw new Error("provider unavailable");
136
159
  });
137
160
  const manager = new ContextWindowManager(
138
161
  provider,
139
- 'system prompt',
140
- makeConfig({ maxInputTokens: 260, targetInputTokens: 140, preserveRecentUserTurns: 1 }),
162
+ "system prompt",
163
+ makeConfig({
164
+ maxInputTokens: 260,
165
+ targetInputTokens: 140,
166
+ preserveRecentUserTurns: 1,
167
+ }),
141
168
  );
142
- const long = 'z'.repeat(220);
169
+ const long = "z".repeat(220);
143
170
  const history = [
144
- message('user', `task ${long}`),
145
- message('assistant', `result ${long}`),
146
- message('user', `followup ${long}`),
171
+ message("user", `task ${long}`),
172
+ message("assistant", `result ${long}`),
173
+ message("user", `followup ${long}`),
147
174
  ];
148
175
 
149
176
  const result = await manager.maybeCompact(history);
@@ -151,79 +178,104 @@ describe('ContextWindowManager', () => {
151
178
  expect(result.summaryCalls).toBeGreaterThan(0);
152
179
  expect(result.summaryInputTokens).toBe(0);
153
180
  expect(result.summaryOutputTokens).toBe(0);
154
- expect(result.summaryModel).toBe('');
155
- expect(result.summaryText).toContain('## Recent Progress');
181
+ expect(result.summaryModel).toBe("");
182
+ expect(result.summaryText).toContain("## Recent Progress");
156
183
  });
157
184
 
158
- test('serializes file blocks for summary chunks', async () => {
185
+ test("serializes file blocks for summary chunks", async () => {
159
186
  const prompts: string[] = [];
160
187
  const provider = createProvider((messages) => {
161
188
  const textBlock = messages[0]?.content[0];
162
- if (textBlock?.type === 'text') {
189
+ if (textBlock?.type === "text") {
163
190
  prompts.push(textBlock.text);
164
191
  }
165
192
  return {
166
- content: [{ type: 'text', text: '## Goals\n- file summarized' }],
167
- model: 'mock-model',
193
+ content: [{ type: "text", text: "## Goals\n- file summarized" }],
194
+ model: "mock-model",
168
195
  usage: { inputTokens: 60, outputTokens: 12 },
169
- stopReason: 'end_turn',
196
+ stopReason: "end_turn",
170
197
  };
171
198
  });
172
199
  const manager = new ContextWindowManager(
173
200
  provider,
174
- 'system prompt',
175
- makeConfig({ maxInputTokens: 280, targetInputTokens: 150, preserveRecentUserTurns: 1 }),
201
+ "system prompt",
202
+ makeConfig({
203
+ maxInputTokens: 280,
204
+ targetInputTokens: 150,
205
+ preserveRecentUserTurns: 1,
206
+ }),
176
207
  );
177
- const long = 'f'.repeat(220);
208
+ const long = "f".repeat(220);
178
209
  const history: Message[] = [
179
210
  {
180
- role: 'user',
211
+ role: "user",
181
212
  content: [
182
213
  {
183
- type: 'file',
214
+ type: "file",
184
215
  source: {
185
- type: 'base64',
186
- media_type: 'application/pdf',
187
- filename: 'spec.pdf',
188
- data: 'a'.repeat(4096),
216
+ type: "base64",
217
+ media_type: "application/pdf",
218
+ filename: "spec.pdf",
219
+ data: "a".repeat(4096),
189
220
  },
190
- extracted_text: 'Critical requirement from attached spec.',
221
+ extracted_text: "Critical requirement from attached spec.",
191
222
  },
192
223
  ],
193
224
  },
194
- message('assistant', `ack ${long}`),
195
- message('user', `followup ${long}`),
225
+ message("assistant", `ack ${long}`),
226
+ message("user", `followup ${long}`),
196
227
  ];
197
228
 
198
229
  const result = await manager.maybeCompact(history);
199
230
  expect(result.compacted).toBe(true);
200
231
 
201
- const combinedPrompts = prompts.join('\n');
202
- expect(combinedPrompts).toContain('file: spec.pdf');
203
- expect(combinedPrompts).toContain('application/pdf');
204
- expect(combinedPrompts).toContain('Critical requirement from attached spec.');
205
- expect(combinedPrompts).not.toContain('unknown_block');
232
+ const combinedPrompts = prompts.join("\n");
233
+ expect(combinedPrompts).toContain("file: spec.pdf");
234
+ expect(combinedPrompts).toContain("application/pdf");
235
+ expect(combinedPrompts).toContain(
236
+ "Critical requirement from attached spec.",
237
+ );
238
+ expect(combinedPrompts).not.toContain("unknown_block");
206
239
  });
207
240
 
208
- test('counts compacted persisted messages including tool-result user turns', async () => {
241
+ test("counts compacted persisted messages including tool-result user turns", async () => {
209
242
  const provider = createProvider(() => ({
210
- content: [{ type: 'text', text: '## Goals\n- compacted summary' }],
211
- model: 'mock-model',
243
+ content: [{ type: "text", text: "## Goals\n- compacted summary" }],
244
+ model: "mock-model",
212
245
  usage: { inputTokens: 75, outputTokens: 20 },
213
- stopReason: 'end_turn',
246
+ stopReason: "end_turn",
214
247
  }));
215
248
  const manager = new ContextWindowManager(
216
249
  provider,
217
- 'system prompt',
218
- makeConfig({ maxInputTokens: 320, targetInputTokens: 170, preserveRecentUserTurns: 1 }),
250
+ "system prompt",
251
+ makeConfig({
252
+ maxInputTokens: 320,
253
+ targetInputTokens: 170,
254
+ preserveRecentUserTurns: 1,
255
+ }),
219
256
  );
220
- const long = 'k'.repeat(220);
257
+ const long = "k".repeat(220);
221
258
  const history: Message[] = [
222
- message('user', `u1 ${long}`),
223
- { role: 'assistant', content: [{ type: 'tool_use', id: 't1', name: 'read_file', input: { path: '/tmp/a' } }] },
224
- { role: 'user', content: [{ type: 'tool_result', tool_use_id: 't1', content: 'contents' }] },
225
- message('assistant', `a1 ${long}`),
226
- message('user', `u2 ${long}`),
259
+ message("user", `u1 ${long}`),
260
+ {
261
+ role: "assistant",
262
+ content: [
263
+ {
264
+ type: "tool_use",
265
+ id: "t1",
266
+ name: "read_file",
267
+ input: { path: "/tmp/a" },
268
+ },
269
+ ],
270
+ },
271
+ {
272
+ role: "user",
273
+ content: [
274
+ { type: "tool_result", tool_use_id: "t1", content: "contents" },
275
+ ],
276
+ },
277
+ message("assistant", `a1 ${long}`),
278
+ message("user", `u2 ${long}`),
227
279
  ];
228
280
 
229
281
  const result = await manager.maybeCompact(history);
@@ -234,36 +286,47 @@ describe('ContextWindowManager', () => {
234
286
  expect(result.compactedPersistedMessages).toBe(4);
235
287
  });
236
288
 
237
- test('counts mixed tool_result+text user messages as persisted', async () => {
289
+ test("counts mixed tool_result+text user messages as persisted", async () => {
238
290
  const provider = createProvider(() => ({
239
- content: [{ type: 'text', text: '## Goals\n- mixed summary' }],
240
- model: 'mock-model',
291
+ content: [{ type: "text", text: "## Goals\n- mixed summary" }],
292
+ model: "mock-model",
241
293
  usage: { inputTokens: 75, outputTokens: 20 },
242
- stopReason: 'end_turn',
294
+ stopReason: "end_turn",
243
295
  }));
244
296
  const manager = new ContextWindowManager(
245
297
  provider,
246
- 'system prompt',
247
- makeConfig({ maxInputTokens: 320, targetInputTokens: 170, preserveRecentUserTurns: 1 }),
298
+ "system prompt",
299
+ makeConfig({
300
+ maxInputTokens: 320,
301
+ targetInputTokens: 170,
302
+ preserveRecentUserTurns: 1,
303
+ }),
248
304
  );
249
- const long = 'k'.repeat(220);
305
+ const long = "k".repeat(220);
250
306
  // Simulates a merged user message (repairHistory merges consecutive same-role
251
307
  // messages), resulting in a user turn with both tool_result and text blocks.
252
308
  const history: Message[] = [
253
- message('user', `u1 ${long}`),
309
+ message("user", `u1 ${long}`),
254
310
  {
255
- role: 'assistant',
256
- content: [{ type: 'tool_use', id: 't1', name: 'read_file', input: { path: '/tmp/a' } }],
311
+ role: "assistant",
312
+ content: [
313
+ {
314
+ type: "tool_use",
315
+ id: "t1",
316
+ name: "read_file",
317
+ input: { path: "/tmp/a" },
318
+ },
319
+ ],
257
320
  },
258
321
  {
259
- role: 'user',
322
+ role: "user",
260
323
  content: [
261
- { type: 'tool_result', tool_use_id: 't1', content: 'contents' },
262
- { type: 'text', text: `follow-up question ${long}` },
324
+ { type: "tool_result", tool_use_id: "t1", content: "contents" },
325
+ { type: "text", text: `follow-up question ${long}` },
263
326
  ],
264
327
  },
265
- message('assistant', `a1 ${long}`),
266
- message('user', `u2 ${long}`),
328
+ message("assistant", `a1 ${long}`),
329
+ message("user", `u2 ${long}`),
267
330
  ];
268
331
 
269
332
  const result = await manager.maybeCompact(history);
@@ -272,64 +335,81 @@ describe('ContextWindowManager', () => {
272
335
  expect(result.compactedPersistedMessages).toBe(4);
273
336
  });
274
337
 
275
- test('parses legacy assistant-role context summary messages', () => {
338
+ test("parses legacy assistant-role context summary messages", () => {
276
339
  const legacySummary: Message = {
277
- role: 'assistant',
278
- content: [{ type: 'text', text: `${CONTEXT_SUMMARY_MARKER}\n## Goals\n- legacy` }],
340
+ role: "assistant",
341
+ content: [
342
+ { type: "text", text: `${CONTEXT_SUMMARY_MARKER}\n## Goals\n- legacy` },
343
+ ],
279
344
  };
280
- expect(getSummaryFromContextMessage(legacySummary)).toContain('legacy');
345
+ expect(getSummaryFromContextMessage(legacySummary)).toContain("legacy");
281
346
  });
282
347
 
283
- test('does not parse user-authored summary marker text as internal summary', () => {
348
+ test("does not parse user-authored summary marker text as internal summary", () => {
284
349
  const userMessage: Message = {
285
- role: 'user',
286
- content: [{ type: 'text', text: `${CONTEXT_SUMMARY_MARKER}\nI typed this prefix myself` }],
350
+ role: "user",
351
+ content: [
352
+ {
353
+ type: "text",
354
+ text: `${CONTEXT_SUMMARY_MARKER}\nI typed this prefix myself`,
355
+ },
356
+ ],
287
357
  };
288
358
  expect(getSummaryFromContextMessage(userMessage)).toBeNull();
289
359
  });
290
360
 
291
- test('skips compaction during cooldown', async () => {
361
+ test("skips compaction during cooldown", async () => {
292
362
  const provider = createProvider(() => {
293
- throw new Error('summarizer should not be called while cooldown skip is active');
363
+ throw new Error(
364
+ "summarizer should not be called while cooldown skip is active",
365
+ );
294
366
  });
295
367
  const manager = new ContextWindowManager(
296
368
  provider,
297
- 'system prompt',
298
- makeConfig({ maxInputTokens: 260, targetInputTokens: 180, preserveRecentUserTurns: 1 }),
369
+ "system prompt",
370
+ makeConfig({
371
+ maxInputTokens: 260,
372
+ targetInputTokens: 180,
373
+ preserveRecentUserTurns: 1,
374
+ }),
299
375
  );
300
- const long = 'c'.repeat(220);
376
+ const long = "c".repeat(220);
301
377
  const history: Message[] = [
302
- message('user', `u1 ${long}`),
303
- message('assistant', `a1 ${long}`),
304
- message('user', `u2 ${long}`),
378
+ message("user", `u1 ${long}`),
379
+ message("assistant", `a1 ${long}`),
380
+ message("user", `u2 ${long}`),
305
381
  ];
306
382
 
307
383
  const result = await manager.maybeCompact(history, undefined, {
308
384
  lastCompactedAt: Date.now() - 30_000,
309
385
  });
310
386
  expect(result.compacted).toBe(false);
311
- expect(result.reason).toBe('compaction cooldown active');
387
+ expect(result.reason).toBe("compaction cooldown active");
312
388
  });
313
389
 
314
- test('ignores cooldown and compacts under severe token pressure', async () => {
390
+ test("ignores cooldown and compacts under severe token pressure", async () => {
315
391
  const provider = createProvider(() => ({
316
- content: [{ type: 'text', text: '## Goals\n- compacted under pressure' }],
317
- model: 'mock-model',
392
+ content: [{ type: "text", text: "## Goals\n- compacted under pressure" }],
393
+ model: "mock-model",
318
394
  usage: { inputTokens: 60, outputTokens: 12 },
319
- stopReason: 'end_turn',
395
+ stopReason: "end_turn",
320
396
  }));
321
397
  const manager = new ContextWindowManager(
322
398
  provider,
323
- 'system prompt',
324
- makeConfig({ maxInputTokens: 320, targetInputTokens: 180, preserveRecentUserTurns: 1 }),
399
+ "system prompt",
400
+ makeConfig({
401
+ maxInputTokens: 320,
402
+ targetInputTokens: 180,
403
+ preserveRecentUserTurns: 1,
404
+ }),
325
405
  );
326
- const long = 'p'.repeat(340);
406
+ const long = "p".repeat(340);
327
407
  const history: Message[] = [
328
- message('user', `u1 ${long}`),
329
- message('assistant', `a1 ${long}`),
330
- message('user', `u2 ${long}`),
331
- message('assistant', `a2 ${long}`),
332
- message('user', `u3 ${long}`),
408
+ message("user", `u1 ${long}`),
409
+ message("assistant", `a1 ${long}`),
410
+ message("user", `u2 ${long}`),
411
+ message("assistant", `a2 ${long}`),
412
+ message("user", `u3 ${long}`),
333
413
  ];
334
414
 
335
415
  const result = await manager.maybeCompact(history, undefined, {
@@ -339,23 +419,27 @@ describe('ContextWindowManager', () => {
339
419
  expect(result.reason).toBeUndefined();
340
420
  });
341
421
 
342
- test('force=true bypasses cooldown for context-too-large recovery', async () => {
422
+ test("force=true bypasses cooldown for context-too-large recovery", async () => {
343
423
  const provider = createProvider(() => ({
344
- content: [{ type: 'text', text: '## Goals\n- forced compaction' }],
345
- model: 'mock-model',
424
+ content: [{ type: "text", text: "## Goals\n- forced compaction" }],
425
+ model: "mock-model",
346
426
  usage: { inputTokens: 60, outputTokens: 12 },
347
- stopReason: 'end_turn',
427
+ stopReason: "end_turn",
348
428
  }));
349
429
  const manager = new ContextWindowManager(
350
430
  provider,
351
- 'system prompt',
352
- makeConfig({ maxInputTokens: 260, targetInputTokens: 180, preserveRecentUserTurns: 1 }),
431
+ "system prompt",
432
+ makeConfig({
433
+ maxInputTokens: 260,
434
+ targetInputTokens: 180,
435
+ preserveRecentUserTurns: 1,
436
+ }),
353
437
  );
354
- const long = 'c'.repeat(220);
438
+ const long = "c".repeat(220);
355
439
  const history: Message[] = [
356
- message('user', `u1 ${long}`),
357
- message('assistant', `a1 ${long}`),
358
- message('user', `u2 ${long}`),
440
+ message("user", `u1 ${long}`),
441
+ message("assistant", `a1 ${long}`),
442
+ message("user", `u2 ${long}`),
359
443
  ];
360
444
 
361
445
  // Same setup as the cooldown test, but with force=true — should compact.
@@ -367,39 +451,57 @@ describe('ContextWindowManager', () => {
367
451
  expect(result.reason).toBeUndefined();
368
452
  });
369
453
 
370
- test('image-heavy payload is no longer underestimated as below-threshold', async () => {
454
+ test("image-heavy payload is no longer underestimated as below-threshold", async () => {
371
455
  const provider = createProvider(() => ({
372
- content: [{ type: 'text', text: '## Goals\n- compacted image-heavy history' }],
373
- model: 'mock-model',
456
+ content: [
457
+ { type: "text", text: "## Goals\n- compacted image-heavy history" },
458
+ ],
459
+ model: "mock-model",
374
460
  usage: { inputTokens: 75, outputTokens: 20 },
375
- stopReason: 'end_turn',
461
+ stopReason: "end_turn",
376
462
  }));
377
463
  const manager = new ContextWindowManager(
378
464
  provider,
379
- 'system prompt',
380
- makeConfig({ maxInputTokens: 7000, targetInputTokens: 5000, compactThreshold: 0.8, preserveRecentUserTurns: 1 }),
465
+ "system prompt",
466
+ makeConfig({
467
+ maxInputTokens: 7000,
468
+ targetInputTokens: 5000,
469
+ compactThreshold: 0.8,
470
+ preserveRecentUserTurns: 1,
471
+ }),
381
472
  );
382
473
 
383
474
  const images = Array.from({ length: 5 }, (_, i) => ({
384
- type: 'image' as const,
475
+ type: "image" as const,
385
476
  source: {
386
- type: 'base64' as const,
387
- media_type: 'image/png',
388
- data: `${String(i)}${'A'.repeat(40_000)}`,
477
+ type: "base64" as const,
478
+ media_type: "image/png",
479
+ data: `${String(i)}${"A".repeat(40_000)}`,
389
480
  },
390
481
  }));
391
482
 
392
483
  const history: Message[] = [
393
- { role: 'user', content: [{ type: 'text', text: 'Please analyze these screenshots.' }, ...images] },
394
- message('assistant', 'Sure, uploading now.'),
484
+ {
485
+ role: "user",
486
+ content: [
487
+ { type: "text", text: "Please analyze these screenshots." },
488
+ ...images,
489
+ ],
490
+ },
491
+ message("assistant", "Sure, uploading now."),
395
492
  ];
396
493
 
397
494
  const result = await manager.maybeCompact(history);
398
- expect(result.reason).not.toBe('below compaction threshold');
495
+ expect(result.reason).not.toBe("below compaction threshold");
399
496
 
400
497
  // Sanity check for this repro: counting raw base64 as text would exceed threshold.
401
- const rawBase64Chars = images.reduce((sum, img) => sum + img.source.data.length, 0);
402
- const rawBase64TokenEquivalent = estimateTextTokens('A'.repeat(rawBase64Chars));
498
+ const rawBase64Chars = images.reduce(
499
+ (sum, img) => sum + img.source.data.length,
500
+ 0,
501
+ );
502
+ const rawBase64TokenEquivalent = estimateTextTokens(
503
+ "A".repeat(rawBase64Chars),
504
+ );
403
505
  expect(rawBase64TokenEquivalent).toBeGreaterThan(result.thresholdTokens);
404
506
  });
405
507
  });