@vellumai/assistant 0.8.10 → 0.8.11-staging.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 (400) hide show
  1. package/bun.lock +62 -1
  2. package/docs/workspace-tools.md +196 -0
  3. package/examples/plugins/echo/README.md +3 -3
  4. package/knip.json +1 -0
  5. package/openapi.yaml +460 -128
  6. package/package.json +2 -1
  7. package/scripts/build-plugin-api.ts +299 -0
  8. package/src/__tests__/agent-loop-callsite-precedence.test.ts +7 -0
  9. package/src/__tests__/agent-loop-compaction-events.test.ts +197 -0
  10. package/src/__tests__/agent-loop-exit-reason.test.ts +93 -96
  11. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +2 -0
  12. package/src/__tests__/agent-loop-output-hooks.test.ts +274 -1
  13. package/src/__tests__/agent-loop-override-profile.test.ts +3 -0
  14. package/src/__tests__/agent-loop-provider-error-recording.test.ts +4 -0
  15. package/src/__tests__/agent-loop-thinking.test.ts +4 -0
  16. package/src/__tests__/agent-loop.test.ts +578 -5
  17. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -1
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  20. package/src/__tests__/btw-routes.test.ts +0 -1
  21. package/src/__tests__/build-persisted-content.test.ts +75 -1
  22. package/src/__tests__/catalog-install-normalize.test.ts +141 -0
  23. package/src/__tests__/ces-startup-timeout.test.ts +60 -0
  24. package/src/__tests__/compaction-events.test.ts +1 -0
  25. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  26. package/src/__tests__/context-overflow-reducer.test.ts +264 -124
  27. package/src/__tests__/context-window-manager-overflow-rung.test.ts +351 -0
  28. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  29. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -5
  30. package/src/__tests__/conversation-agent-loop-overflow.test.ts +284 -455
  31. package/src/__tests__/conversation-agent-loop.test.ts +131 -551
  32. package/src/__tests__/conversation-app-control-instantiation.test.ts +13 -0
  33. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  34. package/src/__tests__/conversation-fork-crud.test.ts +259 -0
  35. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  36. package/src/__tests__/conversation-lifecycle.test.ts +257 -1
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +38 -377
  39. package/src/__tests__/conversation-queue.test.ts +1 -39
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +119 -8
  41. package/src/__tests__/conversation-skill-tools.test.ts +491 -5
  42. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  43. package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
  44. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  45. package/src/__tests__/conversation-store.test.ts +74 -0
  46. package/src/__tests__/conversation-surfaces-app-control.test.ts +4 -1
  47. package/src/__tests__/conversation-tool-setup-attribution.test.ts +323 -0
  48. package/src/__tests__/conversation-tool-setup-tools-disabled.test.ts +34 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -0
  52. package/src/__tests__/corrected-target.test.ts +93 -0
  53. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -5
  54. package/src/__tests__/credential-execution-tools.test.ts +23 -11
  55. package/src/__tests__/credential-security-invariants.test.ts +6 -1
  56. package/src/__tests__/db-schedule-syntax-migration.test.ts +80 -0
  57. package/src/__tests__/device-id.test.ts +70 -1
  58. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  59. package/src/__tests__/empty-response-hook.test.ts +242 -66
  60. package/src/__tests__/external-plugin-loader.test.ts +0 -31
  61. package/src/__tests__/get-skill-detail-audit.test.ts +43 -1
  62. package/src/__tests__/guardian-routing-invariants.test.ts +91 -0
  63. package/src/__tests__/history-repair-hook.test.ts +228 -3
  64. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +254 -9
  66. package/src/__tests__/identity-routes.test.ts +1 -0
  67. package/src/__tests__/image-recovery-hook.test.ts +387 -0
  68. package/src/__tests__/injector-chain.test.ts +5 -4
  69. package/src/__tests__/injector-v3-suppression.test.ts +373 -47
  70. package/src/__tests__/intent-routing.test.ts +7 -0
  71. package/src/__tests__/memory-retrieval-hook.test.ts +117 -15
  72. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  73. package/src/__tests__/oauth-store.test.ts +0 -85
  74. package/src/__tests__/{context-overflow-policy.test.ts → overflow-policy.test.ts} +1 -1
  75. package/src/__tests__/parallel-tool.benchmark.test.ts +4 -0
  76. package/src/__tests__/persist-unsendable-image-downscale.test.ts +29 -9
  77. package/src/__tests__/persist-unsendable-image.test.ts +4 -4
  78. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  79. package/src/__tests__/plugin-bootstrap.test.ts +82 -73
  80. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  81. package/src/__tests__/plugin-types.test.ts +0 -8
  82. package/src/__tests__/provider-catalog-visibility.test.ts +1 -9
  83. package/src/__tests__/prune-old-conversations-job.test.ts +99 -0
  84. package/src/__tests__/registry.test.ts +240 -1
  85. package/src/__tests__/require-fresh-approval.test.ts +3 -0
  86. package/src/__tests__/schedule-routes.test.ts +116 -1
  87. package/src/__tests__/schedule-store.test.ts +28 -0
  88. package/src/__tests__/schedule-tools.test.ts +94 -1
  89. package/src/__tests__/server-history-render.test.ts +39 -0
  90. package/src/__tests__/skill-projection-feature-flag.test.ts +13 -0
  91. package/src/__tests__/skill-projection.benchmark.test.ts +25 -7
  92. package/src/__tests__/skills.test.ts +202 -0
  93. package/src/__tests__/slim-skill-category.test.ts +195 -0
  94. package/src/__tests__/strip-memory-injections.test.ts +33 -39
  95. package/src/__tests__/test-support/tool-invocation-seed.ts +79 -0
  96. package/src/__tests__/title-generate-hook.test.ts +9 -7
  97. package/src/__tests__/tool-audit-listener.test.ts +264 -1
  98. package/src/__tests__/tool-error-hook.test.ts +4 -3
  99. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
  100. package/src/__tests__/tool-executor-lifecycle-events.test.ts +273 -0
  101. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
  102. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  103. package/src/__tests__/tools-get-route.test.ts +202 -0
  104. package/src/__tests__/workspace-tool-loader.test.ts +319 -0
  105. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  106. package/src/agent/loop.ts +569 -319
  107. package/src/api/events/tool-result.ts +9 -0
  108. package/src/api/events/tool-use-start.ts +7 -0
  109. package/src/api/index.ts +10 -0
  110. package/src/api/responses/conversation-message.ts +135 -27
  111. package/src/api/responses/memory-v3-selection-log.ts +4 -4
  112. package/src/approvals/guardian-request-resolvers.ts +26 -0
  113. package/src/browser-session/backends/host-bridge.ts +29 -0
  114. package/src/browser-session/index.ts +1 -0
  115. package/src/browser-session/types.ts +5 -1
  116. package/src/cli/commands/__tests__/schedules.test.ts +62 -4
  117. package/src/cli/commands/__tests__/skills.test.ts +53 -0
  118. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  119. package/src/cli/commands/inference-providers.ts +0 -8
  120. package/src/cli/commands/plugins.ts +2 -2
  121. package/src/cli/commands/schedules.ts +27 -4
  122. package/src/cli/commands/skills.ts +187 -146
  123. package/src/cli/commands/tools.ts +106 -0
  124. package/src/cli/lib/__tests__/install-from-github.test.ts +256 -328
  125. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +6 -2
  126. package/src/cli/lib/__tests__/plugin-details.test.ts +10 -16
  127. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +2 -2
  128. package/src/cli/lib/__tests__/search-plugins.test.ts +145 -240
  129. package/src/cli/lib/install-from-github.ts +187 -117
  130. package/src/cli/lib/plugin-catalog-cache.ts +9 -9
  131. package/src/cli/lib/plugin-details.ts +38 -68
  132. package/src/cli/lib/plugin-marketplace.ts +42 -14
  133. package/src/cli/lib/search-plugins.ts +29 -129
  134. package/src/cli/program.ts +2 -0
  135. package/src/config/bundled-skills/acp/SKILL.md +1 -0
  136. package/src/config/bundled-skills/app-builder/SKILL.md +1 -0
  137. package/src/config/bundled-skills/app-control/SKILL.md +1 -0
  138. package/src/config/bundled-skills/computer-use/SKILL.md +1 -0
  139. package/src/config/bundled-skills/contacts/SKILL.md +1 -0
  140. package/src/config/bundled-skills/document-editor/SKILL.md +1 -0
  141. package/src/config/bundled-skills/followups/SKILL.md +1 -0
  142. package/src/config/bundled-skills/image-studio/SKILL.md +1 -0
  143. package/src/config/bundled-skills/media-processing/SKILL.md +1 -0
  144. package/src/config/bundled-skills/messaging/SKILL.md +1 -0
  145. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -0
  146. package/src/config/bundled-skills/playbooks/SKILL.md +1 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +1 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +11 -3
  149. package/src/config/bundled-skills/sequences/SKILL.md +1 -0
  150. package/src/config/bundled-skills/settings/SKILL.md +1 -0
  151. package/src/config/bundled-skills/skill-management/SKILL.md +101 -1
  152. package/src/config/bundled-skills/subagent/SKILL.md +1 -0
  153. package/src/config/bundled-skills/transcribe/SKILL.md +1 -0
  154. package/src/config/env-registry.ts +23 -0
  155. package/src/config/feature-flag-registry.json +17 -81
  156. package/src/config/loader.ts +5 -22
  157. package/src/config/schema.ts +2 -0
  158. package/src/config/schemas/__tests__/compaction-logs.test.ts +56 -0
  159. package/src/config/schemas/__tests__/memory-v2.test.ts +0 -1
  160. package/src/config/schemas/__tests__/memory-v3.test.ts +61 -1
  161. package/src/config/schemas/compaction-logs.ts +79 -0
  162. package/src/config/schemas/memory-v2.ts +0 -8
  163. package/src/config/schemas/memory-v3.ts +104 -33
  164. package/src/config/seed-inference-profiles.ts +1 -1
  165. package/src/config/skills.ts +117 -47
  166. package/src/context/compactor.ts +11 -0
  167. package/src/context/strip-injections.ts +38 -4
  168. package/src/credential-execution/feature-gates.ts +0 -21
  169. package/src/credential-execution/startup-timeout.ts +32 -4
  170. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +18 -0
  171. package/src/daemon/conversation-agent-loop-handlers.ts +140 -91
  172. package/src/daemon/conversation-agent-loop.ts +123 -658
  173. package/src/daemon/conversation-error.ts +6 -33
  174. package/src/daemon/conversation-lifecycle.ts +1 -1
  175. package/src/daemon/conversation-runtime-assembly.ts +183 -22
  176. package/src/daemon/conversation-skill-tools.ts +137 -8
  177. package/src/daemon/conversation-slash.ts +0 -14
  178. package/src/daemon/conversation-store.ts +2 -19
  179. package/src/daemon/conversation-tool-setup.ts +87 -1
  180. package/src/daemon/conversation.ts +119 -50
  181. package/src/daemon/external-plugins-bootstrap.ts +36 -95
  182. package/src/daemon/handlers/config-channels.ts +11 -2
  183. package/src/daemon/handlers/shared.ts +9 -1
  184. package/src/daemon/handlers/skills.ts +10 -4
  185. package/src/daemon/host-app-control-proxy.ts +72 -57
  186. package/src/daemon/host-browser-proxy.ts +117 -22
  187. package/src/daemon/lifecycle.ts +34 -5
  188. package/src/daemon/message-protocol.ts +0 -7
  189. package/src/daemon/message-types/schedules.ts +1 -0
  190. package/src/daemon/message-types/skills.ts +17 -0
  191. package/src/daemon/providers-setup.ts +3 -0
  192. package/src/daemon/server.ts +3 -3
  193. package/src/daemon/tool-setup-types.ts +9 -3
  194. package/src/daemon/trust-context.ts +23 -0
  195. package/src/daemon/workspace-tools-watcher.ts +324 -0
  196. package/src/events/tool-audit-listener.ts +78 -16
  197. package/src/events/tool-metrics-listener.ts +2 -5
  198. package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +227 -0
  199. package/src/memory/__tests__/conversation-queries.test.ts +176 -0
  200. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +20 -32
  201. package/src/memory/compaction-log-writer-clickhouse.ts +418 -0
  202. package/src/memory/conversation-crud.ts +134 -3
  203. package/src/memory/conversation-queries.ts +64 -7
  204. package/src/memory/db-init.ts +14 -0
  205. package/src/memory/embedding-backend.test.ts +130 -1
  206. package/src/memory/embedding-backend.ts +79 -106
  207. package/src/memory/embedding-gemini.ts +5 -0
  208. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +12 -0
  209. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +19 -0
  210. package/src/memory/graph/conversation-graph-memory.ts +36 -25
  211. package/src/memory/graph/tool-handlers.ts +3 -0
  212. package/src/memory/job-handlers/cleanup.ts +3 -1
  213. package/src/memory/jobs-store.ts +0 -28
  214. package/src/memory/jobs-worker.ts +10 -22
  215. package/src/memory/memory-marker.ts +29 -0
  216. package/src/memory/memory-retrospective-startup-cleanup.ts +1 -1
  217. package/src/memory/migrations/268-add-memory-v3-selections.ts +6 -0
  218. package/src/memory/migrations/270-schedule-description.ts +36 -0
  219. package/src/memory/migrations/275-tool-invocations-add-skill-id.test.ts +81 -0
  220. package/src/memory/migrations/275-tool-invocations-add-skill-id.ts +20 -0
  221. package/src/memory/migrations/276-tool-invocations-created-at-id-index.test.ts +68 -0
  222. package/src/memory/migrations/276-tool-invocations-created-at-id-index.ts +20 -0
  223. package/src/memory/migrations/277-add-memory-v3-ever-injected.ts +29 -0
  224. package/src/memory/migrations/278-tool-invocations-telemetry-columns.test.ts +96 -0
  225. package/src/memory/migrations/278-tool-invocations-telemetry-columns.ts +39 -0
  226. package/src/memory/migrations/279-create-skill-loaded-events.test.ts +84 -0
  227. package/src/memory/migrations/279-create-skill-loaded-events.ts +26 -0
  228. package/src/memory/migrations/280-conversations-surfaced-at.test.ts +88 -0
  229. package/src/memory/migrations/280-conversations-surfaced-at.ts +24 -0
  230. package/src/memory/migrations/index.ts +10 -0
  231. package/src/memory/migrations/registry.ts +8 -0
  232. package/src/memory/schema/conversations.ts +16 -0
  233. package/src/memory/schema/infrastructure.ts +26 -0
  234. package/src/memory/skill-loaded-events-store.test.ts +160 -0
  235. package/src/memory/skill-loaded-events-store.ts +95 -0
  236. package/src/memory/tool-executed-events-store.test.ts +219 -0
  237. package/src/memory/tool-executed-events-store.ts +102 -0
  238. package/src/memory/tool-usage-store.ts +15 -3
  239. package/src/memory/v2/__tests__/consolidation-job.test.ts +117 -12
  240. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +189 -0
  241. package/src/memory/v2/__tests__/injected-block-slugs.test.ts +90 -0
  242. package/src/memory/v2/__tests__/page-store.test.ts +33 -0
  243. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +88 -15
  244. package/src/memory/v2/activation-store.ts +50 -1
  245. package/src/memory/v2/consolidation-job.ts +113 -29
  246. package/src/memory/v2/injected-block-slugs.ts +79 -0
  247. package/src/memory/v2/injection.ts +6 -1
  248. package/src/memory/v2/prompts/consolidation.ts +414 -13
  249. package/src/memory/v2/router.ts +2 -28
  250. package/src/memory/v2/static-context.ts +1 -1
  251. package/src/memory/v2/types.ts +16 -0
  252. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  253. package/src/notifications/access-request-copy.ts +298 -0
  254. package/src/notifications/adapters/slack.ts +3 -3
  255. package/src/notifications/adapters/telegram.ts +2 -1
  256. package/src/notifications/copy-composer.ts +49 -267
  257. package/src/notifications/decision-engine.ts +16 -35
  258. package/src/notifications/home-feed-side-effect.ts +1 -6
  259. package/src/oauth/oauth-store.ts +0 -9
  260. package/src/permissions/checker.test.ts +83 -1
  261. package/src/permissions/checker.ts +25 -2
  262. package/src/permissions/gateway-threshold-reader.test.ts +182 -0
  263. package/src/permissions/gateway-threshold-reader.ts +80 -0
  264. package/src/platform/client.ts +1 -3
  265. package/src/platform/feature-gate.ts +3 -12
  266. package/src/plugin-api/constants.ts +4 -2
  267. package/src/plugin-api/index.ts +63 -11
  268. package/src/plugin-api/types.ts +236 -71
  269. package/src/plugins/defaults/compaction/compact.ts +66 -2
  270. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +240 -32
  271. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  272. package/src/{daemon/context-overflow-policy.ts → plugins/defaults/compaction/overflow-policy.ts} +1 -1
  273. package/src/plugins/defaults/compaction/window-manager.ts +303 -1
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +173 -0
  275. package/src/plugins/defaults/empty-response/hooks/stop.ts +11 -115
  276. package/src/plugins/defaults/empty-response/nudge-state-store.ts +46 -0
  277. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +50 -0
  278. package/src/plugins/defaults/history-repair/hooks/stop.ts +22 -0
  279. package/src/plugins/defaults/history-repair/repair-state-store.ts +51 -0
  280. package/src/plugins/defaults/history-repair/terminal.ts +39 -2
  281. package/src/plugins/defaults/image-recovery/detect.ts +25 -0
  282. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +73 -0
  283. package/src/plugins/defaults/image-recovery/hooks/stop.ts +22 -0
  284. package/src/plugins/defaults/image-recovery/image-recovery-state-store.ts +48 -0
  285. package/src/plugins/defaults/image-recovery/package.json +14 -0
  286. package/src/{daemon/persist-unsendable-image.ts → plugins/defaults/image-recovery/recover.ts} +67 -14
  287. package/src/plugins/defaults/index.ts +71 -5
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +76 -112
  289. package/src/plugins/defaults/memory-retrieval/hooks/{user-prompt-submit-temp.ts → user-prompt-submit.ts} +83 -74
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +14 -8
  291. package/src/plugins/defaults/memory-retrieval/injectors.ts +2 -18
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1157 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +683 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +161 -140
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +160 -0
  297. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +335 -316
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +145 -53
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +38 -1
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +18 -8
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +112 -71
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +192 -51
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +4 -16
  304. package/src/plugins/defaults/memory-v3-shadow/card.test.ts +173 -0
  305. package/src/plugins/defaults/memory-v3-shadow/card.ts +116 -0
  306. package/src/plugins/defaults/memory-v3-shadow/core-set.test.ts +104 -0
  307. package/src/plugins/defaults/memory-v3-shadow/core-set.ts +59 -0
  308. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +305 -0
  309. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +278 -0
  310. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +138 -0
  311. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +85 -0
  312. package/src/plugins/defaults/memory-v3-shadow/injector.ts +331 -24
  313. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +119 -13
  314. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +169 -114
  315. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +47 -16
  316. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +144 -66
  317. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +758 -0
  318. package/src/plugins/defaults/memory-v3-shadow/prune.ts +471 -0
  319. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +68 -16
  320. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +19 -12
  321. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +96 -43
  322. package/src/plugins/defaults/memory-v3-shadow/types.ts +34 -17
  323. package/src/plugins/defaults/title-generate/hooks/stop.ts +9 -11
  324. package/src/plugins/pipeline.ts +8 -5
  325. package/src/plugins/types.ts +5 -51
  326. package/src/providers/cache-control.ts +26 -0
  327. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -2
  328. package/src/providers/model-catalog.ts +13 -1
  329. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +147 -0
  330. package/src/providers/openai/chat-completions-provider.ts +46 -0
  331. package/src/providers/openai/responses-provider.ts +45 -0
  332. package/src/providers/registry.ts +0 -8
  333. package/src/runtime/__tests__/agent-wake.test.ts +0 -1
  334. package/src/runtime/agent-wake.ts +13 -0
  335. package/src/runtime/routes/__tests__/acp-routes.test.ts +151 -0
  336. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +12 -50
  337. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +322 -0
  338. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -62
  339. package/src/runtime/routes/__tests__/plugins-routes.test.ts +31 -11
  340. package/src/runtime/routes/acp-routes.test.ts +106 -0
  341. package/src/runtime/routes/acp-routes.ts +248 -2
  342. package/src/runtime/routes/browser-tabs-routes.ts +1 -1
  343. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  344. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +0 -14
  345. package/src/runtime/routes/consolidation-routes.ts +6 -82
  346. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  347. package/src/runtime/routes/conversation-management-routes.ts +71 -0
  348. package/src/runtime/routes/identity-routes.ts +8 -0
  349. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  350. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -45
  351. package/src/runtime/routes/plugins-routes.ts +34 -45
  352. package/src/runtime/routes/schedule-routes.ts +43 -5
  353. package/src/runtime/routes/settings-routes.ts +140 -15
  354. package/src/runtime/routes/skills-routes.ts +18 -6
  355. package/src/runtime/services/__tests__/conversation-serializer.test.ts +140 -0
  356. package/src/runtime/services/conversation-serializer.ts +38 -1
  357. package/src/runtime/verification-outbound-actions.ts +147 -2
  358. package/src/runtime/verification-templates.ts +29 -3
  359. package/src/schedule/schedule-store.ts +19 -0
  360. package/src/skills/catalog-install.ts +77 -13
  361. package/src/tasks/task-scheduler.ts +1 -0
  362. package/src/telemetry/types.ts +66 -1
  363. package/src/telemetry/usage-telemetry-reporter.test.ts +542 -13
  364. package/src/telemetry/usage-telemetry-reporter.ts +213 -20
  365. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +49 -2
  366. package/src/tools/browser/__tests__/browser-status.test.ts +29 -5
  367. package/src/tools/browser/browser-execution.ts +27 -9
  368. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +380 -4
  369. package/src/tools/browser/cdp-client/__tests__/host-bridge-cdp-client.test.ts +107 -0
  370. package/src/tools/browser/cdp-client/__tests__/types.test.ts +6 -1
  371. package/src/tools/browser/cdp-client/factory.ts +217 -17
  372. package/src/tools/browser/cdp-client/host-bridge-cdp-client.ts +67 -0
  373. package/src/tools/browser/cdp-client/types.ts +22 -2
  374. package/src/tools/credential-execution/make-authenticated-request.ts +2 -1
  375. package/src/tools/credential-execution/manage-secure-command-tool.ts +169 -164
  376. package/src/tools/credential-execution/run-authenticated-command.ts +2 -1
  377. package/src/tools/executor.ts +39 -7
  378. package/src/tools/registry.ts +387 -5
  379. package/src/tools/schedule/create.ts +16 -0
  380. package/src/tools/schedule/list.ts +12 -4
  381. package/src/tools/schedule/update.ts +12 -0
  382. package/src/tools/skills/load.ts +11 -6
  383. package/src/tools/terminal/safe-env.ts +2 -0
  384. package/src/tools/types.ts +65 -9
  385. package/src/tools/workspace-tools/loader.ts +673 -0
  386. package/src/usage/attribution.ts +28 -0
  387. package/src/util/device-id.ts +17 -3
  388. package/src/util/platform.ts +16 -0
  389. package/tsconfig.plugin-api.json +13 -0
  390. package/src/__tests__/plugin-external-api.test.ts +0 -68
  391. package/src/__tests__/plugin-skill-contribution.test.ts +0 -355
  392. package/src/daemon/message-types/browser.ts +0 -10
  393. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  394. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +0 -36
  395. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +0 -37
  396. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +0 -106
  397. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +0 -44
  398. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +0 -91
  399. package/src/plugins/external-api.ts +0 -114
  400. package/src/plugins/plugin-skill-contributions.ts +0 -292
@@ -42,11 +42,19 @@ export interface PluginLogger {
42
42
  // ─── Hook function ───────────────────────────────────────────────────────────
43
43
 
44
44
  /**
45
- * A plugin lifecycle hook. Receives a per-lifecycle context shape and
46
- * may return either a transformed context or `void`. Today's runtime
47
- * consumes only the resolved-or-rejected nature of the promise; the
48
- * `TCtx` return is reserved for hooks that fan a transformed context out
49
- * to downstream plugins (e.g. `user-prompt-submit`).
45
+ * A plugin lifecycle hook. Receives a per-lifecycle context shape and may
46
+ * either mutate `ctx` in place (returning `void`) or return a *partial*
47
+ * context whose fields are merged onto the threaded context — only the keys
48
+ * it returns are overwritten, every other field is preserved. Returning a
49
+ * partial lets a hook edit just the subset of fields it cares about without
50
+ * having to re-specify the rest. The merged context is threaded to the next
51
+ * hook in the chain (e.g. `user-prompt-submit`).
52
+ *
53
+ * Because an omitted key means "keep the existing value", every field on a
54
+ * context shape is required (no `?`-optional or `| undefined` members): a
55
+ * present key always carries a concrete value, so "absent from the returned
56
+ * partial" is never ambiguous with "explicitly cleared". Fields that can be
57
+ * empty model that with `| null`, not `| undefined`.
50
58
  *
51
59
  * Each known hook key has a documented context shape:
52
60
  * - `init` — {@link PluginInitContext}
@@ -57,7 +65,9 @@ export interface PluginLogger {
57
65
  * - `stop` — {@link StopContext}
58
66
  * - `post-model-call` — {@link PostModelCallContext}
59
67
  */
60
- export type PluginHookFn<TCtx = unknown> = (ctx: TCtx) => Promise<TCtx | void>;
68
+ export type PluginHookFn<TCtx = unknown> = (
69
+ ctx: TCtx,
70
+ ) => Promise<Partial<TCtx> | void>;
61
71
 
62
72
  // ─── Init context ────────────────────────────────────────────────────────────
63
73
 
@@ -144,6 +154,25 @@ export interface UserPromptSubmitContext {
144
154
  * for the turn and cannot be recovered from the message arrays.
145
155
  */
146
156
  readonly requestId: string;
157
+ /**
158
+ * Active inference profile key to surface in this turn's context, or `null`
159
+ * when the profile is unchanged since the one last announced to the model.
160
+ * Hooks that emit the `model_profile` grounding line resolve the
161
+ * human-readable label (and model id) from this key via the workspace LLM
162
+ * config rather than receiving the rendered string — the key is the minimal
163
+ * turn input the message arrays cannot carry.
164
+ */
165
+ readonly modelProfileKey: string | null;
166
+ /**
167
+ * Whether the turn has no human present to answer clarification questions
168
+ * (e.g. a scheduled, background, or headless run). Resolved once at turn
169
+ * start from the run's interactivity option, falling back to live client
170
+ * presence — a single value the hook reads rather than re-deriving from
171
+ * mutable conversation state that can flip mid-turn. Hooks that assemble the
172
+ * turn's runtime injections forward it so the assembled context reflects the
173
+ * turn's interactivity.
174
+ */
175
+ readonly isNonInteractive: boolean;
147
176
  /**
148
177
  * The text of the user prompt that triggered this turn — the resolved
149
178
  * user message (after slash-command expansion), independent of any
@@ -172,6 +201,69 @@ export interface UserPromptSubmitContext {
172
201
  readonly logger: PluginLogger;
173
202
  }
174
203
 
204
+ // ─── Post-compact hook context ───────────────────────────────────────────────
205
+
206
+ /**
207
+ * Context passed to the `post-compact` hook. Fires after the agent loop
208
+ * compacts a conversation mid-turn — once the running history has been
209
+ * summarized down to fit the context window, and before the turn resumes.
210
+ *
211
+ * Compaction strips the turn's runtime injections (scratchpad, retrieved
212
+ * memory, workspace context, transcript snapshots) along with the raw messages
213
+ * it summarizes. This hook's job is to re-apply whatever injected context must
214
+ * survive onto the freshly compacted history before the next provider call.
215
+ * The default memory-retrieval plugin contributes a hook here that re-injects
216
+ * its memory blocks and re-tracks the memory graph; user hooks can re-apply
217
+ * their own injected context the same way.
218
+ *
219
+ * The hook re-injects by mutating `history` in place (or returning a new
220
+ * context with a replacement `history`) — see {@link PluginHookFn}'s
221
+ * polymorphic return shape. The agent loop reads the settled `history` back off
222
+ * the context and resumes the turn from it. Multiple plugins' hooks chain in
223
+ * registration order, each seeing the previous plugin's edits.
224
+ */
225
+ export interface PostCompactContext {
226
+ /**
227
+ * The compacted message history to re-inject onto. Hooks mutate this in
228
+ * place (or return a new context with a replacement) to re-apply context
229
+ * that compaction stripped; the loop resumes the turn from the settled
230
+ * value.
231
+ */
232
+ history: Message[];
233
+ /**
234
+ * Stable ID for the request that drives this turn. Hooks that perform
235
+ * runtime injection forward it onto the injector turn context so the
236
+ * re-applied blocks are attributed to the originating request; it is fixed
237
+ * for the turn and cannot be recovered from the message history.
238
+ */
239
+ readonly requestId: string;
240
+ /** Conversation ID the turn being compacted is scoped to. */
241
+ readonly conversationId: string;
242
+ /**
243
+ * Whether the turn has no human present to answer clarification questions
244
+ * (e.g. a scheduled, background, or headless run). Mirrors the field of the
245
+ * same name on {@link UserPromptSubmitContext}: resolved once at turn start
246
+ * so re-injection reflects the turn's interactivity rather than mutable
247
+ * client-presence state that can flip mid-turn.
248
+ */
249
+ readonly isNonInteractive: boolean;
250
+ /**
251
+ * Active inference profile key to surface in the re-injected context, or
252
+ * `null` when the profile is unchanged since the one last announced to the
253
+ * model. Mirrors {@link UserPromptSubmitContext.modelProfileKey}: hooks that
254
+ * emit the `model_profile` grounding line resolve the human-readable label
255
+ * from this key rather than receiving the rendered string.
256
+ */
257
+ readonly modelProfileKey: string | null;
258
+ /**
259
+ * Volume of runtime injection to re-apply. `"full"` restores the complete
260
+ * runtime context; `"minimal"` is the reduced volume overflow recovery's
261
+ * injection-downgrade rung selects to keep the re-injected prompt small.
262
+ * Defaults to `"full"` when omitted.
263
+ */
264
+ readonly injectionMode?: "full" | "minimal";
265
+ }
266
+
175
267
  // ─── Post-tool-use hook context ──────────────────────────────────────────────
176
268
 
177
269
  /**
@@ -219,9 +311,9 @@ export interface PostToolUseContext {
219
311
  * a separate block *after* emitting the tool_result, so it reaches the model
220
312
  * without polluting the client-facing or persisted tool output. Mirrors
221
313
  * Claude Code's PostToolUse `hookSpecificOutput.additionalContext` and the
222
- * singular of Codex's `additional_contexts`. Unset means no extra context.
314
+ * singular of Codex's `additional_contexts`. `null` means no extra context.
223
315
  */
224
- additionalContext?: string;
316
+ additionalContext: string | null;
225
317
  /**
226
318
  * The model's context-window size in tokens. Plugins derive their own
227
319
  * character budget from this (e.g. a share of the window) rather than
@@ -239,65 +331,89 @@ export interface PostToolUseContext {
239
331
  // ─── Stop hook context ───────────────────────────────────────────────────────
240
332
 
241
333
  /**
242
- * Binary outcome of the `stop` hook. The agent loop seeds it to `"stop"`
243
- * and acts on the value the chain settles on:
244
- *
245
- * - `"stop"` — let the turn end; the loop yields the assistant response
246
- * to the user. This is the default.
247
- * - `"continue"` — re-query the model. The hook is responsible for appending
248
- * the follow-up turn it wants the model to see to
249
- * {@link StopContext.messages} before returning.
334
+ * Why an agent turn reached a terminal state. Supplied to the `stop` hook via
335
+ * {@link StopContext.exitReason} and emitted on the `agent_loop_exit` event,
336
+ * then persisted onto the final `llm_request_logs` row of the turn (rows from
337
+ * intermediate turns keep a NULL reason, which is how downstream tooling and
338
+ * the LLM Context Inspector tell "loop kept going" from "loop is done").
250
339
  *
251
- * To abort with an error a hook should throw — the loop's error handler
252
- * surfaces it. There is intentionally no error decision value.
340
+ * Values are stable wire/DB strings — they are written to SQLite and surfaced
341
+ * over the inspector wire format, so renaming any of them is a breaking change.
253
342
  */
254
- export type StopDecision = "continue" | "stop";
343
+ export type AgentLoopExitReason =
344
+ /** User cancellation observed before the turn's next provider call. */
345
+ | "aborted_pre_call"
346
+ /** Assistant message had no tool-use blocks (or no tool executor). */
347
+ | "no_tool_calls"
348
+ /** User cancellation observed while building the tool-results message. */
349
+ | "aborted_post_response"
350
+ /** User cancellation observed mid-tool-execution; completed results kept. */
351
+ | "aborted_during_tools"
352
+ /** A tool result requested handing back to the user. */
353
+ | "yield_to_user"
354
+ /** The orchestrator yielded at a checkpoint to process a queued message. */
355
+ | "checkpoint_handoff"
356
+ /** Context-window recovery exhausted and the turn ended with an error. */
357
+ | "context_too_large"
358
+ /**
359
+ * An auto-compress rerun (post-emergency-compaction, post-tier reducer)
360
+ * still yielded at the mid-loop budget checkpoint — the turn terminated with
361
+ * no further recovery layer to re-enter. A pure observability signal so the
362
+ * silent stall is attributable instead of leaving the exit reason NULL.
363
+ */
364
+ | "budget_yield_unrecovered"
365
+ /** Provider stopped because the configured output-token limit was reached. */
366
+ | "max_tokens_reached"
367
+ /** User cancellation landed after a non-terminal checkpoint yield. */
368
+ | "aborted_after_checkpoint"
369
+ /** User cancellation observed while the catch handler synthesized an error turn. */
370
+ | "aborted_via_error"
371
+ /** An unhandled error ended the turn. */
372
+ | "error";
255
373
 
256
374
  /**
257
- * Context passed to the `stop` hook. Fires when the model yields a response
258
- * with no tool calls — the run's stop boundary, where the loop is about to
259
- * hand the turn back to the user. The default empty-response plugin uses it
260
- * to re-query the model when a turn came back empty or as a provider refusal.
375
+ * Context passed to the `stop` hook — the loop's definitive terminal hook.
261
376
  *
262
- * The hook decides the outcome by setting {@link decision}. When it sets
263
- * `"continue"` it must also append the follow-up turn (e.g. a nudge `user`
264
- * message) to {@link messages}; the loop threads those messages into the next
265
- * iteration. {@link messages} is the full conversation history, carried back
266
- * verbatim. A hook that needs to reason about just the current response cycle
267
- * (e.g. whether an earlier turn already delivered visible text) derives that
268
- * boundary from the history itself — the messages after the last genuine user
269
- * prompt — rather than an index, since mid-run compaction can rewrite the
270
- * array.
377
+ * It fires exactly once per run, after the loop has committed to ending and
378
+ * will not run another iteration this run. Unlike `post-model-call` (which owns
379
+ * the model-call-outcome retry decision), `stop` cannot continue the loop: by
380
+ * the time it runs the turn's outcome is settled. That guarantee makes it the
381
+ * home for teardown — a hook can release per-turn resources or clear per-turn
382
+ * state knowing nothing will re-enter the loop this run.
271
383
  *
272
- * Multiple plugins' hooks chain in registration order — each sees the
273
- * previous hook's `decision` and `messages` mutations.
384
+ * It fires on every terminal exit: a no-tool reply, a max-tokens stop, a
385
+ * yield-to-user, an exhausted context-overflow recovery, a user abort, or an
386
+ * unhandled error. It also fires on a `checkpoint_handoff`, which ends the run
387
+ * for teardown purposes even though the orchestrator resumes the conversation
388
+ * in a fresh run. {@link exitReason} reports which one and {@link error}
389
+ * carries the rejection when the turn ended on one, so a hook that should act
390
+ * only on a particular ending guards on {@link exitReason}.
391
+ *
392
+ * Multiple plugins' hooks chain in registration order over the same context.
274
393
  */
275
394
  export interface StopContext {
276
395
  /** Conversation ID the run belongs to. */
277
396
  readonly conversationId: string;
278
397
  /**
279
- * Full conversation history: the inbound conversation followed by every
280
- * message produced this run. A hook that sets `decision` to `"continue"`
281
- * appends its follow-up turn here; the loop carries the result into the
282
- * next iteration.
398
+ * Full conversation history at the terminal stop — the inbound conversation
399
+ * followed by every message produced this run. Provided for inspection;
400
+ * mutating it has no effect, since the loop will not run again this turn.
283
401
  */
284
- messages: Message[];
285
- /**
286
- * Content blocks of the assistant turn that triggered the stop. Guaranteed
287
- * to contain no `tool_use` blocks — the hook only fires at the boundary
288
- * where the model stopped requesting tools.
289
- */
290
- readonly responseContent: ReadonlyArray<ContentBlock>;
402
+ readonly messages: ReadonlyArray<Message>;
291
403
  /**
292
- * Provider-reported stop reason for the assistant turn (e.g. `"refusal"`,
293
- * `"end_turn"`). `null`/`undefined` when the provider didn't report one.
404
+ * The provider rejection that ended the turn, when it ended on one (e.g. an
405
+ * unrecoverable error after recovery hooks declined to retry). Absent on a
406
+ * clean stop.
294
407
  */
295
- readonly stopReason: string | null | undefined;
408
+ readonly error?: Error;
296
409
  /**
297
- * Seeded to `"stop"`. A hook sets it to `"continue"` to force another loop
298
- * iteration; later hooks in the chain may override it.
410
+ * Which terminal state the turn reached. A `checkpoint_handoff` fires this
411
+ * hook for teardown — the run pauses so the orchestrator can drain a queued
412
+ * message — but is not emitted as an `agent_loop_exit`, since the
413
+ * conversation resumes in a fresh run. `aborted_after_checkpoint` is a
414
+ * control transfer that re-enters the loop and so never reaches this hook.
299
415
  */
300
- decision: StopDecision;
416
+ readonly exitReason: AgentLoopExitReason;
301
417
  /**
302
418
  * Logger scoped to the current turn. The same instance is shared by
303
419
  * every hook in the chain, so plugins should tag their structured log
@@ -325,14 +441,14 @@ export interface PreModelCallContext {
325
441
  readonly conversationId: string;
326
442
  /**
327
443
  * The call site this provider call serves — `"mainAgent"` for the user-facing
328
- * reply, or a background/utility site. Omitted by call sites that don't tag one.
444
+ * reply, or a background/utility site. `null` for call sites that don't tag one.
329
445
  */
330
- readonly callSite?: LLMCallSite;
446
+ readonly callSite: LLMCallSite | null;
331
447
  /**
332
448
  * The system prompt about to be sent. A hook may replace it (e.g. strip or
333
449
  * append a section); the loop sends the resulting value.
334
450
  */
335
- systemPrompt: string | undefined;
451
+ systemPrompt: string | null;
336
452
  /**
337
453
  * Seeded `false`. When a hook sets it `true`, the loop suppresses this turn's
338
454
  * live assistant `text_delta` stream; a `post-model-call` hook is then
@@ -348,32 +464,81 @@ export interface PreModelCallContext {
348
464
  // ─── Post-model-call hook context ────────────────────────────────────────────
349
465
 
350
466
  /**
351
- * Context passed to the `post-model-call` hook. Fires for each finalized
352
- * assistant message — once per model call, at the message-complete boundary —
353
- * before the message is persisted and (if deferred) streamed-final. Unlike
354
- * {@link StopContext}'s read-only `responseContent` (which exists for the stop
355
- * decision), {@link content} is mutable: the loop adopts the hook's result as the
356
- * persisted and streamed message.
467
+ * Binary outcome of the `post-model-call` hook. The agent loop seeds it to
468
+ * `"stop"` and acts on the value the chain settles on:
357
469
  *
358
- * Fires on tool-bearing turns too (a reply can carry both text and `tool_use`),
359
- * so a hook should transform only the blocks it owns and leave others — notably
360
- * `tool_use` — intact. Runs for every finalized message regardless of call site;
361
- * hooks MUST self-gate on {@link callSite} / {@link conversationId}. Mutate in
362
- * place or return a new context; throwing is contained by the loop (the original
363
- * content is kept).
470
+ * - `"stop"` — accept the model-call outcome. On a finalized reply the loop
471
+ * keeps the (possibly transformed) message; on a rejection it
472
+ * surfaces the error. This is the default.
473
+ * - `"continue"` — re-query the model. The hook is responsible for leaving
474
+ * {@link PostModelCallContext.messages} as the history the next
475
+ * iteration should send (append a follow-up turn, or replace
476
+ * the array with a repaired one).
477
+ */
478
+ export type PostModelCallDecision = "continue" | "stop";
479
+
480
+ /**
481
+ * Context passed to the `post-model-call` hook. Fires at every model-call
482
+ * outcome — the seam where the loop reacts to what the provider returned:
483
+ *
484
+ * - **Finalized reply.** The provider returned a message. {@link error} is
485
+ * absent, {@link content} holds the reply's blocks (mutable — the loop adopts
486
+ * the hook's result as the persisted and streamed message), and
487
+ * {@link stopReason} carries the provider's stop reason. Fires once per model
488
+ * call, including tool-bearing turns (a reply can carry both text and
489
+ * `tool_use`), so a hook should transform only the blocks it owns and leave
490
+ * others — notably `tool_use` — intact.
491
+ * - **Provider rejection.** The call threw before any reply existed.
492
+ * {@link error} holds the rejection, {@link content} is empty, and
493
+ * {@link stopReason} is `null`. A hook that recognizes the rejection may
494
+ * repair {@link messages} and set {@link decision} to `"continue"` to retry;
495
+ * hooks that only act on a real reply must guard on {@link error} and return
496
+ * early.
497
+ *
498
+ * The retry decision is honored only at actionable outcomes — a no-tool reply
499
+ * or a provider rejection — and is ignored on tool-bearing turns (the loop
500
+ * already runs the tools). The loop does not gate the decision on call site, so
501
+ * a hook that should only retry the user-facing turn MUST self-gate on
502
+ * {@link callSite} / {@link conversationId} to avoid re-querying background,
503
+ * subagent, or compaction calls. Mutate in place or return a new
504
+ * context; throwing is contained by the loop (the original content is kept and
505
+ * the outcome is treated as `"stop"`). Multiple plugins' hooks chain in
506
+ * registration order — each sees the previous hook's `decision` and mutations.
364
507
  */
365
508
  export interface PostModelCallContext {
366
509
  /** Conversation ID the message belongs to. */
367
510
  readonly conversationId: string;
368
- /** The call site this message serves — `"mainAgent"` for the user-facing reply. */
369
- readonly callSite?: LLMCallSite;
511
+ /** The call site this message serves — `"mainAgent"` for the user-facing reply; `null` when untagged. */
512
+ readonly callSite: LLMCallSite | null;
370
513
  /**
371
514
  * The finalized message content. Mutable — transform the text blocks and leave
372
- * `tool_use` (and other non-text blocks) intact.
515
+ * `tool_use` (and other non-text blocks) intact. Empty on a provider rejection.
373
516
  */
374
517
  content: ContentBlock[];
375
- /** Provider-reported stop reason for the turn, when reported. */
376
- readonly stopReason: string | null | undefined;
518
+ /**
519
+ * Full conversation history: the inbound conversation followed by every
520
+ * message produced this run. A hook that sets {@link decision} to
521
+ * `"continue"` leaves this as the history the next iteration should send — a
522
+ * finalized-reply hook appends its follow-up turn (e.g. a nudge `user`
523
+ * message); a rejection-recovery hook replaces the array with a repaired one.
524
+ */
525
+ messages: Message[];
526
+ /** Provider-reported stop reason for the turn; `null` when not reported. */
527
+ readonly stopReason: string | null;
528
+ /**
529
+ * The provider rejection that ended the call, on a rejection outcome. Absent
530
+ * on a finalized reply. A hook that recovers from a specific rejection class
531
+ * inspects this and may repair {@link messages} and set {@link decision} to
532
+ * `"continue"`; hooks that only act on a real reply must return early when it
533
+ * is present.
534
+ */
535
+ readonly error?: Error;
536
+ /**
537
+ * Seeded to `"stop"`. A hook sets it to `"continue"` to force another loop
538
+ * iteration; later hooks in the chain may override it. Honored only at
539
+ * actionable outcomes (see the interface docstring).
540
+ */
541
+ decision: PostModelCallDecision;
377
542
  /** Logger scoped to the current turn (tag structured fields with `{ plugin }`). */
378
543
  readonly logger: PluginLogger;
379
544
  }
@@ -14,7 +14,10 @@ import type { Message } from "../../../providers/types.js";
14
14
  import type { TrustClass } from "../../../runtime/actor-trust-resolver.js";
15
15
  import { PluginExecutionError } from "../../types.js";
16
16
  import { getContextWindowManager } from "./manager-store.js";
17
- import type { ContextWindowResult } from "./window-manager.js";
17
+ import type {
18
+ ContextWindowResult,
19
+ EmergencyCompactOptions,
20
+ } from "./window-manager.js";
18
21
 
19
22
  /**
20
23
  * Name under which the default compaction plugin registers. Exposed so call
@@ -46,6 +49,19 @@ export interface CompactionContext {
46
49
  minKeepRecentUserTurns?: number;
47
50
  /** Trust class of the actor whose turn triggered compaction. */
48
51
  actorTrustClass?: TrustClass;
52
+ /**
53
+ * Set when this compaction is recovering from a provider context-overflow
54
+ * rejection rather than the ordinary auto-threshold trip. Its presence
55
+ * routes the request through the manager's reduction ladder (which escalates
56
+ * one rung per call) instead of plain forced compaction; the agent loop
57
+ * records it in its overflow catch and forwards it on the next gate pass.
58
+ */
59
+ overflowSignal?: {
60
+ /** Provider-reported token count from the rejection, or `null`. */
61
+ actualTokens: number | null;
62
+ /** Whether a human is present this turn (drives the auto-compress policy). */
63
+ isInteractive: boolean;
64
+ };
49
65
  }
50
66
 
51
67
  /**
@@ -56,7 +72,8 @@ export interface CompactionContext {
56
72
  export async function defaultCompact(
57
73
  context: CompactionContext,
58
74
  ): Promise<ContextWindowResult> {
59
- const { conversationId, messages, signal, ...options } = context;
75
+ const { conversationId, messages, signal, overflowSignal, ...options } =
76
+ context;
60
77
  const manager = getContextWindowManager(conversationId);
61
78
  if (manager == null) {
62
79
  throw new PluginExecutionError(
@@ -64,5 +81,52 @@ export async function defaultCompact(
64
81
  DEFAULT_COMPACTION_PLUGIN_NAME,
65
82
  );
66
83
  }
84
+ if (overflowSignal) {
85
+ return manager.recoverContextOverflow(
86
+ messages,
87
+ {
88
+ actualTokens: overflowSignal.actualTokens,
89
+ isInteractive: overflowSignal.isInteractive,
90
+ overrideProfile: options.overrideProfile,
91
+ actorTrustClass: options.actorTrustClass,
92
+ },
93
+ signal,
94
+ );
95
+ }
67
96
  return manager.maybeCompact(messages, signal, options);
68
97
  }
98
+
99
+ /**
100
+ * Self-describing emergency-compaction request handed to
101
+ * {@link defaultEmergencyCompact}. Mirrors {@link CompactionContext} but
102
+ * carries the provider-reported token estimate at the overflow that triggered
103
+ * recovery, which sizes the summarize-around-last-tool-pair cut.
104
+ */
105
+ export interface EmergencyCompactionContext extends EmergencyCompactOptions {
106
+ /** Conversation whose manager performs the emergency compaction. */
107
+ conversationId: string;
108
+ /** Message history to summarize around the last tool_use/tool_result pair. */
109
+ messages: Message[];
110
+ /** Abort signal forwarded to the compaction summary call. */
111
+ signal?: AbortSignal;
112
+ }
113
+
114
+ /**
115
+ * Run emergency mid-turn compaction for the turn: resolves the conversation's
116
+ * context window manager from the compaction store and summarizes everything
117
+ * before the last tool_use/tool_result pair, preserving the agent's most recent
118
+ * action context while aggressively compressing earlier history.
119
+ */
120
+ export async function defaultEmergencyCompact(
121
+ context: EmergencyCompactionContext,
122
+ ): Promise<ContextWindowResult> {
123
+ const { conversationId, messages, signal, ...options } = context;
124
+ const manager = getContextWindowManager(conversationId);
125
+ if (manager == null) {
126
+ throw new PluginExecutionError(
127
+ `default-compaction: no ContextWindowManager registered for conversation ${conversationId} — the conversation must register one before emergency compaction runs`,
128
+ DEFAULT_COMPACTION_PLUGIN_NAME,
129
+ );
130
+ }
131
+ return manager.emergencyCompact(messages, options, signal);
132
+ }