@vellumai/assistant 0.8.12 → 0.9.0-staging.2

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 (442) hide show
  1. package/AGENTS.md +0 -14
  2. package/ARCHITECTURE.md +45 -45
  3. package/README.md +1 -1
  4. package/bun.lock +200 -154
  5. package/docs/architecture/integrations.md +3 -3
  6. package/docs/architecture/memory.md +2 -2
  7. package/docs/architecture/security.md +10 -10
  8. package/docs/runbook-trusted-contacts.md +12 -12
  9. package/docs/skills.md +6 -6
  10. package/docs/workflows-testing.md +221 -0
  11. package/docs/workflows.md +510 -0
  12. package/examples/plugins/echo/README.md +5 -5
  13. package/knip.json +2 -0
  14. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +105 -0
  15. package/node_modules/@vellumai/gateway-client/src/index.ts +12 -0
  16. package/openapi.yaml +7197 -5708
  17. package/package.json +8 -4
  18. package/scripts/generate-openapi.ts +66 -114
  19. package/src/__tests__/access-request-seed-content-blocks.test.ts +213 -0
  20. package/src/__tests__/adaptive-thinking-repair.test.ts +32 -3
  21. package/src/__tests__/agent-loop-output-hooks.test.ts +183 -0
  22. package/src/__tests__/agent-loop-regrowth-guard.test.ts +506 -0
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  24. package/src/__tests__/agent-wake-override-profile.test.ts +77 -0
  25. package/src/__tests__/app-compiler.test.ts +7 -1
  26. package/src/__tests__/app-dir-path-guard.test.ts +27 -3
  27. package/src/__tests__/app-executors.test.ts +43 -0
  28. package/src/__tests__/approval-cascade.test.ts +0 -5
  29. package/src/__tests__/approval-routes-http.test.ts +91 -0
  30. package/src/__tests__/assistant-stream-state.test.ts +107 -0
  31. package/src/__tests__/browser-fill-credential.test.ts +3 -3
  32. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -1
  33. package/src/__tests__/compaction-events.test.ts +63 -7
  34. package/src/__tests__/compaction-trail-store.test.ts +74 -1
  35. package/src/__tests__/compaction.benchmark.test.ts +63 -41
  36. package/src/__tests__/compactor-low-watermark-cut.test.ts +349 -0
  37. package/src/__tests__/context-window-manager-compact-retry.test.ts +64 -0
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -5
  39. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -5
  40. package/src/__tests__/conversation-history-web-search.test.ts +7 -0
  41. package/src/__tests__/conversation-process-callsite.test.ts +0 -5
  42. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -5
  43. package/src/__tests__/conversation-queue.test.ts +0 -5
  44. package/src/__tests__/conversation-slash-queue.test.ts +0 -5
  45. package/src/__tests__/conversation-slash-unknown.test.ts +0 -5
  46. package/src/__tests__/conversation-speed-override.test.ts +0 -5
  47. package/src/__tests__/conversation-surfaces-data-persist.test.ts +97 -0
  48. package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
  49. package/src/__tests__/conversation-usage.test.ts +2 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +0 -5
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -5
  52. package/src/__tests__/credential-broker-browser-fill.test.ts +2 -2
  53. package/src/__tests__/credential-broker-server-use.test.ts +2 -2
  54. package/src/__tests__/credential-broker.test.ts +1 -1
  55. package/src/__tests__/credential-prompt-route.test.ts +417 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault.test.ts +37 -0
  58. package/src/__tests__/db-schedule-syntax-migration.test.ts +24 -0
  59. package/src/__tests__/dynamic-page-surface.test.ts +219 -0
  60. package/src/__tests__/empty-state-greeting-cache.test.ts +94 -0
  61. package/src/__tests__/gateway-flag-listener.test.ts +24 -7
  62. package/src/__tests__/guardian-action-sweep.test.ts +56 -219
  63. package/src/__tests__/guardian-routing-invariants.test.ts +138 -0
  64. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  65. package/src/__tests__/list-messages-hidden-metadata.test.ts +99 -0
  66. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +87 -1
  67. package/src/__tests__/llm-resolver.test.ts +115 -0
  68. package/src/__tests__/managed-profile-guard.test.ts +6 -5
  69. package/src/__tests__/max-tokens-continue-hook.test.ts +184 -0
  70. package/src/__tests__/media-generate-image.test.ts +20 -9
  71. package/src/__tests__/mock-gateway-ipc.ts +23 -0
  72. package/src/__tests__/model-intents.test.ts +1 -1
  73. package/src/__tests__/normalize-onboarding.test.ts +26 -0
  74. package/src/__tests__/notification-decision-strategy.test.ts +4 -2
  75. package/src/__tests__/notification-telegram-adapter.test.ts +21 -3
  76. package/src/__tests__/pending-interactions-resolved-event.test.ts +62 -0
  77. package/src/__tests__/post-turn-tool-result-truncation.test.ts +72 -18
  78. package/src/__tests__/require-fresh-approval.test.ts +425 -1
  79. package/src/__tests__/resolve-app-id.test.ts +56 -0
  80. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -0
  81. package/src/__tests__/schedule-routes-workflow-validation.test.ts +408 -0
  82. package/src/__tests__/schedule-routes.test.ts +257 -4
  83. package/src/__tests__/schedule-store.test.ts +60 -0
  84. package/src/__tests__/schedule-tools.test.ts +247 -2
  85. package/src/__tests__/skill-execute-input.test.ts +85 -0
  86. package/src/__tests__/skill-secret-handling-guard.test.ts +21 -20
  87. package/src/__tests__/skills.test.ts +3 -3
  88. package/src/__tests__/slack-app-setup-skill-regression.test.ts +1 -1
  89. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  90. package/src/__tests__/subagent-tool-gate-mode.test.ts +547 -0
  91. package/src/__tests__/system-prompt.test.ts +1 -1
  92. package/src/__tests__/task-progress-nudge-hook.test.ts +372 -0
  93. package/src/__tests__/task-scheduler.test.ts +299 -0
  94. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +209 -0
  95. package/src/__tests__/tool-result-spool.test.ts +3 -1
  96. package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +181 -0
  97. package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +174 -0
  98. package/src/agent/compaction-circuit.ts +11 -0
  99. package/src/agent/loop.ts +181 -12
  100. package/src/api/constants/call-sites.ts +12 -0
  101. package/src/api/events/assistant-thinking-delta.ts +10 -0
  102. package/src/api/events/usage-update.ts +7 -0
  103. package/src/api/index.ts +4 -1
  104. package/src/api/responses/memory-v3-selection-log.ts +18 -11
  105. package/src/approvals/approval-primitive.ts +2 -2
  106. package/src/background-wake/background-wake-routes.test.ts +5 -2
  107. package/src/bundler/compiler-tools.ts +1 -1
  108. package/src/bundler/package-resolver.ts +0 -1
  109. package/src/calls/call-domain.ts +1 -1
  110. package/src/calls/guardian-action-sweep.ts +16 -93
  111. package/src/cli/AGENTS.md +4 -0
  112. package/src/cli/commands/__tests__/schedules.test.ts +430 -1
  113. package/src/cli/commands/credentials.ts +28 -24
  114. package/src/cli/commands/image-generation.ts +23 -9
  115. package/src/cli/commands/notifications.ts +1 -1
  116. package/src/cli/commands/plugins.ts +89 -46
  117. package/src/cli/commands/schedules.ts +384 -11
  118. package/src/cli/lib/__tests__/inspect-plugin.test.ts +69 -5
  119. package/src/cli/lib/__tests__/install-from-github.test.ts +15 -0
  120. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +81 -4
  121. package/src/cli/lib/inspect-plugin.ts +62 -1
  122. package/src/cli/lib/install-from-github.ts +52 -5
  123. package/src/cli/lib/upgrade-plugin.ts +18 -0
  124. package/src/config/__tests__/workflows-schema.test.ts +60 -0
  125. package/src/config/bundled-skills/acp/SKILL.md +2 -2
  126. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  127. package/src/config/bundled-skills/app-builder/tools/app-create.ts +6 -1
  128. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +7 -1
  129. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +7 -1
  130. package/src/config/bundled-skills/app-builder/tools/app-update.ts +10 -1
  131. package/src/config/bundled-skills/image-studio/SKILL.md +66 -19
  132. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -6
  133. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +22 -3
  134. package/src/config/bundled-skills/personal-page/SKILL.md +57 -0
  135. package/src/config/bundled-skills/personal-page/TOOLS.json +27 -0
  136. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +17 -0
  137. package/src/config/bundled-skills/schedule/SKILL.md +7 -2
  138. package/src/config/bundled-skills/schedule/TOOLS.json +48 -4
  139. package/src/config/bundled-skills/workflows/SKILL.md +214 -0
  140. package/src/config/bundled-skills/workflows/TOOLS.json +84 -0
  141. package/src/config/bundled-skills/workflows/tools/manage-workflows.ts +12 -0
  142. package/src/config/bundled-skills/workflows/tools/run-workflow.ts +12 -0
  143. package/src/config/bundled-tool-registry.ts +14 -2
  144. package/src/config/call-site-defaults.ts +5 -0
  145. package/src/config/feature-flag-registry.json +12 -4
  146. package/src/config/llm-context-resolution.ts +8 -0
  147. package/src/config/llm-resolver.ts +30 -0
  148. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +22 -0
  149. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +16 -0
  150. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +77 -0
  151. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +57 -0
  152. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +28 -0
  153. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +234 -0
  154. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +48 -0
  155. package/src/config/preloaded-apps/personal-page/src/components/media.ts +16 -0
  156. package/src/config/preloaded-apps/personal-page/src/index.html +20 -0
  157. package/src/config/preloaded-apps/personal-page/src/main.tsx +7 -0
  158. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +82 -0
  159. package/src/config/preloaded-apps/personal-page/src/styles.css +759 -0
  160. package/src/config/schema.ts +2 -0
  161. package/src/config/schemas/call-site-catalog.ts +7 -0
  162. package/src/config/schemas/heartbeat.ts +4 -1
  163. package/src/config/schemas/llm.ts +33 -26
  164. package/src/config/schemas/memory-retrospective.ts +19 -0
  165. package/src/config/schemas/platform.ts +8 -0
  166. package/src/config/schemas/services.ts +5 -2
  167. package/src/config/schemas/workflows.ts +42 -0
  168. package/src/config/skills.ts +3 -3
  169. package/src/context/compactor.ts +273 -39
  170. package/src/context/post-turn-tool-result-truncation.ts +23 -6
  171. package/src/context/tool-result-spool.ts +12 -17
  172. package/src/credential-execution/executable-discovery.ts +1 -1
  173. package/src/credential-execution/process-manager.ts +37 -3
  174. package/src/credential-execution/prompted-credential.ts +205 -0
  175. package/src/daemon/conversation-agent-loop-handlers.ts +14 -0
  176. package/src/daemon/conversation-process.ts +11 -2
  177. package/src/daemon/conversation-surfaces.ts +167 -3
  178. package/src/daemon/conversation-tool-setup.ts +103 -26
  179. package/src/daemon/conversation-usage.ts +2 -0
  180. package/src/daemon/conversation.ts +115 -11
  181. package/src/daemon/handlers/shared.ts +26 -14
  182. package/src/daemon/host-cu-proxy.ts +15 -12
  183. package/src/daemon/host-file-proxy.ts +15 -12
  184. package/src/daemon/host-transfer-proxy.ts +30 -24
  185. package/src/daemon/lifecycle.ts +40 -3
  186. package/src/daemon/message-protocol.ts +3 -0
  187. package/src/daemon/message-types/messages.ts +2 -10
  188. package/src/daemon/message-types/workflows.ts +49 -0
  189. package/src/daemon/parse-actual-tokens-from-error.test.ts +62 -1
  190. package/src/daemon/parse-actual-tokens-from-error.ts +43 -4
  191. package/src/daemon/process-message.ts +6 -0
  192. package/src/daemon/tool-setup-types.ts +57 -0
  193. package/src/daemon/wake-conversation-ops.ts +18 -0
  194. package/src/heartbeat/heartbeat-run-store.ts +8 -2
  195. package/src/home/feed-types.ts +1 -1
  196. package/src/ipc/gateway-flag-listener.ts +28 -6
  197. package/src/mcp/mcp-auth-state.ts +8 -20
  198. package/src/media/__tests__/image-models.test.ts +57 -0
  199. package/src/media/image-models.ts +66 -0
  200. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +38 -0
  201. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +12 -2
  202. package/src/memory/__tests__/memory-retrospective-job.test.ts +911 -34
  203. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +227 -5
  204. package/src/memory/__tests__/memory-retrospective-state.test.ts +195 -0
  205. package/src/memory/__tests__/preloaded-apps.test.ts +85 -0
  206. package/src/memory/auto-analysis-enqueue.ts +14 -1
  207. package/src/memory/compaction-log-store-clickhouse.ts +6 -4
  208. package/src/memory/conversation-crud.ts +9 -2
  209. package/src/memory/conversation-disk-view.ts +1 -1
  210. package/src/memory/conversation-queries.ts +22 -7
  211. package/src/memory/db-init.ts +20 -0
  212. package/src/memory/db-maintenance.ts +16 -0
  213. package/src/memory/embedding-runtime-manager.ts +1 -1
  214. package/src/memory/llm-request-log-source-clickhouse.ts +112 -14
  215. package/src/memory/llm-request-log-source-local.ts +19 -1
  216. package/src/memory/llm-request-log-source.ts +35 -6
  217. package/src/memory/llm-request-log-store.ts +90 -2
  218. package/src/memory/memory-retrospective-constants.ts +9 -0
  219. package/src/memory/memory-retrospective-enqueue.ts +3 -6
  220. package/src/memory/memory-retrospective-fork-boundary.ts +94 -0
  221. package/src/memory/memory-retrospective-job.ts +500 -208
  222. package/src/memory/memory-retrospective-startup-cleanup.ts +97 -19
  223. package/src/memory/memory-retrospective-state.ts +85 -2
  224. package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +40 -0
  225. package/src/memory/migrations/282-schedule-inference-profile.test.ts +77 -0
  226. package/src/memory/migrations/282-schedule-inference-profile.ts +26 -0
  227. package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +102 -0
  228. package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.ts +53 -0
  229. package/src/memory/migrations/284-workflow-runs.ts +51 -0
  230. package/src/memory/migrations/285-schedule-workflow-mode.ts +26 -0
  231. package/src/memory/migrations/286-workflow-run-trust.ts +27 -0
  232. package/src/memory/migrations/287-conversation-origin-channel-index.ts +15 -0
  233. package/src/memory/migrations/288-backfill-origin-channel-from-bindings.ts +43 -0
  234. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +115 -0
  235. package/src/memory/migrations/290-schedule-capabilities.test.ts +77 -0
  236. package/src/memory/migrations/290-schedule-capabilities.ts +25 -0
  237. package/src/memory/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +96 -0
  238. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +571 -0
  239. package/src/memory/migrations/index.ts +10 -0
  240. package/src/memory/preloaded-apps.ts +116 -0
  241. package/src/memory/schema/infrastructure.ts +4 -0
  242. package/src/memory/schema/memory-core.ts +4 -0
  243. package/src/memory/v2/__tests__/concept-page-frontmatter-schema.test.ts +45 -0
  244. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +11 -7
  245. package/src/memory/v2/__tests__/page-store.test.ts +13 -2
  246. package/src/memory/v2/__tests__/qdrant.test.ts +24 -0
  247. package/src/memory/v2/frontmatter-sweep.ts +7 -6
  248. package/src/memory/v2/page-store.ts +4 -3
  249. package/src/memory/v2/qdrant.ts +42 -3
  250. package/src/memory/v2/types.ts +16 -10
  251. package/src/messaging/draft-store.ts +1 -1
  252. package/src/notifications/access-request-copy.ts +200 -113
  253. package/src/notifications/adapters/slack.ts +250 -111
  254. package/src/notifications/adapters/telegram.ts +7 -44
  255. package/src/notifications/approval-card-builder.ts +93 -0
  256. package/src/notifications/broadcaster.ts +74 -0
  257. package/src/notifications/conversation-pairing.ts +8 -6
  258. package/src/notifications/copy-composer.ts +32 -26
  259. package/src/notifications/decision-engine.ts +59 -7
  260. package/src/notifications/guardian-question-mode.ts +145 -155
  261. package/src/notifications/home-feed-side-effect.ts +28 -11
  262. package/src/notifications/notification-utils.ts +66 -0
  263. package/src/notifications/signal.ts +6 -0
  264. package/src/notifications/tool-approval-copy.ts +142 -0
  265. package/src/notifications/types.ts +19 -0
  266. package/src/permissions/threshold.ts +11 -0
  267. package/src/plugin-api/types.ts +16 -4
  268. package/src/plugins/defaults/compaction/window-manager.ts +44 -0
  269. package/src/plugins/defaults/index.ts +46 -0
  270. package/src/plugins/defaults/max-tokens-continue/continue-state-store.ts +53 -0
  271. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +80 -0
  272. package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +20 -0
  273. package/src/plugins/defaults/max-tokens-continue/package.json +14 -0
  274. package/src/plugins/defaults/memory-retrieval/hooks/__tests__/user-prompt-submit.test.ts +37 -0
  275. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +29 -1
  276. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +8 -3
  277. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +4 -2
  278. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +28 -18
  279. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +67 -0
  280. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +122 -22
  281. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +2 -0
  282. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +63 -1
  283. package/src/plugins/defaults/memory-v3-shadow/injector.ts +61 -18
  284. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +1 -1
  285. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +39 -10
  286. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +34 -1
  287. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +112 -47
  288. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +78 -15
  289. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +206 -0
  290. package/src/plugins/defaults/task-progress-nudge/package.json +15 -0
  291. package/src/prompts/__tests__/system-prompt.test.ts +100 -1
  292. package/src/prompts/__tests__/task-progress-hint-section.test.ts +5 -7
  293. package/src/prompts/normalize-onboarding.ts +2 -0
  294. package/src/prompts/persona-resolver.ts +3 -0
  295. package/src/prompts/system-prompt.ts +51 -2
  296. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +3 -1
  297. package/src/prompts/templates/system-sections.ts +8 -3
  298. package/src/providers/call-site-routing.ts +6 -3
  299. package/src/providers/fireworks/client.ts +3 -0
  300. package/src/providers/inference/auth.ts +52 -46
  301. package/src/providers/model-intents.ts +2 -2
  302. package/src/providers/openai/__tests__/coerce-object-args.test.ts +105 -0
  303. package/src/providers/openai/chat-completions-provider.ts +47 -9
  304. package/src/providers/openai/coerce-object-args.ts +104 -0
  305. package/src/providers/retry.ts +8 -5
  306. package/src/providers/types.ts +10 -0
  307. package/src/runtime/__tests__/agent-wake.test.ts +629 -7
  308. package/src/runtime/access-request-helper.ts +16 -9
  309. package/src/runtime/agent-wake.ts +302 -51
  310. package/src/runtime/assistant-stream-state.ts +141 -8
  311. package/src/runtime/background-job-runner.ts +9 -0
  312. package/src/runtime/channel-approval-types.ts +1 -0
  313. package/src/runtime/channel-invite-transports/telegram.ts +6 -5
  314. package/src/runtime/channel-invite-transports/voice.ts +2 -2
  315. package/src/runtime/channel-invite-types.ts +4 -2
  316. package/src/runtime/channel-retry-sweep.ts +19 -41
  317. package/src/runtime/finalize-event-delivery.ts +72 -0
  318. package/src/runtime/guardian-action-message-composer.ts +0 -54
  319. package/src/runtime/http-server.ts +6 -14
  320. package/src/runtime/http-types.ts +0 -1
  321. package/src/runtime/message-composer-types.ts +0 -9
  322. package/src/runtime/middleware/__tests__/rate-limiter.test.ts +63 -0
  323. package/src/runtime/middleware/auth.ts +27 -3
  324. package/src/runtime/middleware/rate-limiter.ts +28 -1
  325. package/src/runtime/migrations/vbundle-builder.ts +6 -5
  326. package/src/runtime/pending-interactions.ts +20 -1
  327. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +232 -173
  328. package/src/runtime/routes/__tests__/plugins-routes.test.ts +18 -0
  329. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +436 -0
  330. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +11 -0
  331. package/src/runtime/routes/approval-routes.ts +35 -8
  332. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -1
  333. package/src/runtime/routes/btw-routes.ts +37 -1
  334. package/src/runtime/routes/channel-delivery-routes.ts +11 -7
  335. package/src/runtime/routes/channel-route-definitions.ts +3 -0
  336. package/src/runtime/routes/channel-route-shared.ts +3 -1
  337. package/src/runtime/routes/consolidation-routes.ts +17 -13
  338. package/src/runtime/routes/conversation-compaction-routes.ts +159 -119
  339. package/src/runtime/routes/conversation-list-routes.ts +41 -4
  340. package/src/runtime/routes/conversation-query-routes.ts +196 -11
  341. package/src/runtime/routes/conversation-routes.ts +15 -1
  342. package/src/runtime/routes/credential-prompt-routes.ts +39 -17
  343. package/src/runtime/routes/empty-state-greeting-cache.ts +65 -0
  344. package/src/runtime/routes/heartbeat-routes.ts +18 -13
  345. package/src/runtime/routes/image-generation-routes.ts +20 -2
  346. package/src/runtime/routes/inbound-message-handler.ts +13 -12
  347. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +32 -31
  348. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +7 -5
  349. package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -21
  350. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
  351. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +6 -15
  352. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +1 -1
  353. package/src/runtime/routes/index.ts +6 -0
  354. package/src/runtime/routes/log-export/AGENTS.md +1 -1
  355. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  356. package/src/runtime/routes/migration-routes.ts +5 -9
  357. package/src/runtime/routes/plugins-routes.ts +26 -0
  358. package/src/runtime/routes/ps-routes.ts +10 -8
  359. package/src/runtime/routes/retrospective-routes.ts +235 -0
  360. package/src/runtime/routes/runs-pagination.ts +75 -0
  361. package/src/runtime/routes/schedule-routes.ts +367 -59
  362. package/src/runtime/routes/sounds-config-routes.ts +239 -0
  363. package/src/runtime/routes/surface-action-routes.ts +84 -4
  364. package/src/runtime/routes/workflow-routes.test.ts +372 -0
  365. package/src/runtime/routes/workflow-routes.ts +363 -0
  366. package/src/runtime/routes/workspace-routes.test.ts +61 -1
  367. package/src/runtime/routes/workspace-routes.ts +26 -1
  368. package/src/runtime/services/__tests__/analyze-conversation.test.ts +38 -0
  369. package/src/runtime/services/analyze-conversation.ts +26 -13
  370. package/src/schedule/inference-profile.ts +28 -0
  371. package/src/schedule/schedule-store.ts +152 -4
  372. package/src/schedule/scheduler-types.ts +6 -0
  373. package/src/schedule/scheduler.ts +96 -0
  374. package/src/security/secret-allowlist.ts +1 -1
  375. package/src/skills/path-classifier.ts +1 -1
  376. package/src/tools/apps/executors.ts +23 -0
  377. package/src/tools/apps/resolve-app-id.ts +42 -0
  378. package/src/tools/browser/browser-execution.ts +9 -11
  379. package/src/tools/credentials/broker.ts +4 -4
  380. package/src/tools/credentials/vault.ts +26 -137
  381. package/src/tools/executor.ts +69 -0
  382. package/src/tools/flag-gated-tools.test.ts +76 -0
  383. package/src/tools/permission-checker.ts +8 -1
  384. package/src/tools/registry.ts +51 -0
  385. package/src/tools/schedule/create.ts +77 -1
  386. package/src/tools/schedule/list.ts +1 -0
  387. package/src/tools/schedule/update.ts +73 -1
  388. package/src/tools/skills/execute.ts +56 -0
  389. package/src/tools/terminal/shell.ts +1 -1
  390. package/src/tools/ui-surface/definitions.ts +91 -2
  391. package/src/tools/workflows/manage-workflows.ts +183 -0
  392. package/src/tools/workflows/run-workflow.test.ts +442 -0
  393. package/src/tools/workflows/run-workflow.ts +88 -0
  394. package/src/types/onboarding-context.ts +2 -0
  395. package/src/usage/attribution.ts +24 -0
  396. package/src/util/canonicalize-identity.ts +12 -3
  397. package/src/util/platform.ts +17 -17
  398. package/src/watcher/__tests__/engine.test.ts +24 -0
  399. package/src/watcher/__tests__/telemetry.test.ts +135 -0
  400. package/src/watcher/engine.ts +7 -0
  401. package/src/watcher/telemetry.ts +74 -0
  402. package/src/workflows/capabilities.test.ts +365 -0
  403. package/src/workflows/capabilities.ts +359 -0
  404. package/src/workflows/deterministic-stringify.ts +27 -0
  405. package/src/workflows/engine-integration.test.ts +656 -0
  406. package/src/workflows/engine.test.ts +1144 -0
  407. package/src/workflows/engine.ts +1078 -0
  408. package/src/workflows/fanout-load.test.ts +168 -0
  409. package/src/workflows/journal-store.test.ts +369 -0
  410. package/src/workflows/journal-store.ts +470 -0
  411. package/src/workflows/leaf-runner.test.ts +704 -0
  412. package/src/workflows/leaf-runner.ts +589 -0
  413. package/src/workflows/library.test.ts +134 -0
  414. package/src/workflows/library.ts +124 -0
  415. package/src/workflows/run-manager.test.ts +711 -0
  416. package/src/workflows/run-manager.ts +593 -0
  417. package/src/workflows/sandbox-escape.test.ts +339 -0
  418. package/src/workflows/sandbox.test.ts +251 -0
  419. package/src/workflows/sandbox.ts +447 -0
  420. package/src/workspace/adaptive-thinking-repair.ts +33 -11
  421. package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
  422. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
  423. package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
  424. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
  425. package/src/workspace/migrations/031-drop-user-md.ts +1 -4
  426. package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
  427. package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
  428. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
  429. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
  430. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
  431. package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
  432. package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
  433. package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
  434. package/src/workspace/migrations/registry.ts +6 -0
  435. package/src/workspace/migrations/runner.ts +1 -1
  436. package/tsconfig.json +1 -1
  437. package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
  438. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
  439. package/src/__tests__/guardian-action-store.test.ts +0 -106
  440. package/src/daemon/guardian-action-generators.ts +0 -71
  441. package/src/memory/guardian-action-store.ts +0 -484
  442. package/src/runtime/guardian-action-grant-minter.ts +0 -150
@@ -26,6 +26,7 @@ import {
26
26
  ACTIVITY_SKIP_SET,
27
27
  injectActivityField,
28
28
  } from "../tools/schema-transforms.js";
29
+ import { resolveSkillExecuteInput } from "../tools/skills/execute.js";
29
30
  import { resolveToolInvocationAlias } from "../tools/tool-name-aliases.js";
30
31
  import {
31
32
  isDiskPressureCleanupToolName,
@@ -61,8 +62,16 @@ import {
61
62
  buildSwitchInferenceProfileToolDef,
62
63
  SWITCH_INFERENCE_PROFILE_TOOL_NAME,
63
64
  } from "./switch-inference-profile-tool.js";
64
- import type { ToolSetupContext } from "./tool-setup-types.js";
65
- export type { ToolSetupContext } from "./tool-setup-types.js";
65
+ import type {
66
+ SubagentToolGateMode,
67
+ ToolSetupContext,
68
+ WakeToolContextPin,
69
+ } from "./tool-setup-types.js";
70
+ export type {
71
+ SubagentToolGateMode,
72
+ ToolSetupContext,
73
+ WakeToolContextPin,
74
+ } from "./tool-setup-types.js";
66
75
 
67
76
  // ── resolveConversationAttribution ───────────────────────────────────
68
77
 
@@ -128,6 +137,23 @@ export function createToolExecutor(
128
137
  ctx.sendToClient(msg),
129
138
  );
130
139
 
140
+ // Execution-layer allowlist gate (`subagentToolGateMode === "execution"`,
141
+ // see {@link SubagentToolGateMode}): rejects non-allowlisted calls BEFORE
142
+ // any executor dispatch, so a non-allowlisted tool's executor never runs.
143
+ // The error tool_result lets the model continue or finish.
144
+ const rejectNonAllowlistedTool = (
145
+ toolName: string,
146
+ ): ToolExecutionResult | null => {
147
+ if (ctx.subagentToolGateMode !== "execution") return null;
148
+ const allowlist = ctx.subagentAllowedTools;
149
+ if (!allowlist || allowlist.has(toolName)) return null;
150
+ const allowed = [...allowlist].sort().join(", ");
151
+ return {
152
+ content: `This background pass may only use: ${allowed}.`,
153
+ isError: true,
154
+ };
155
+ };
156
+
131
157
  return async (
132
158
  name: string,
133
159
  input: Record<string, unknown>,
@@ -137,6 +163,17 @@ export function createToolExecutor(
137
163
  const { name: executionName, input: executionInput } =
138
164
  resolveToolInvocationAlias(name, input, ctx.allowedToolNames);
139
165
 
166
+ // The execution-layer gate must run FIRST — before any interception or
167
+ // pre-execution side effect (switch_inference_profile profile switching,
168
+ // DoorDash step marking) — so a non-allowlisted tool can neither run nor
169
+ // mutate conversation state. `skill_execute` is dispatch indirection: it
170
+ // is gated on its resolved inner tool name inside the interception below,
171
+ // mirroring how wire mode gates the underlying tool, not the wrapper.
172
+ if (executionName !== "skill_execute") {
173
+ const rejection = rejectNonAllowlistedTool(executionName);
174
+ if (rejection) return rejection;
175
+ }
176
+
140
177
  if (isDoordashCommand(executionName, executionInput)) {
141
178
  markDoordashStepInProgress(ctx, executionInput);
142
179
  }
@@ -260,10 +297,7 @@ export function createToolExecutor(
260
297
  if (executionName === "skill_execute") {
261
298
  const rawToolName =
262
299
  typeof executionInput.tool === "string" ? executionInput.tool : "";
263
- const rawToolInput =
264
- executionInput.input != null && typeof executionInput.input === "object"
265
- ? (executionInput.input as Record<string, unknown>)
266
- : {};
300
+ const rawToolInput = resolveSkillExecuteInput(executionInput);
267
301
 
268
302
  // Clone to avoid mutating shared input objects
269
303
  const { name: toolName, input: toolInput } = resolveToolInvocationAlias(
@@ -280,6 +314,12 @@ export function createToolExecutor(
280
314
  };
281
315
  }
282
316
 
317
+ // Gate the resolved inner tool, not the skill_execute wrapper — the
318
+ // wrapper is dispatch indirection, mirroring how wire mode gates the
319
+ // underlying tool via the executor's allowedToolNames check.
320
+ const innerRejection = rejectNonAllowlistedTool(toolName);
321
+ if (innerRejection) return innerRejection;
322
+
283
323
  const result = await executor.execute(toolName, toolInput, toolContext);
284
324
  if (toolContext.approvedViaPrompt) {
285
325
  ctx.approvedViaPromptThisTurn = true;
@@ -361,6 +401,18 @@ export interface SkillProjectionContext {
361
401
  readonly hasNoClient?: boolean;
362
402
  /** When set, only tools in this set are included in the resolved tool list (subagent delegation). */
363
403
  subagentAllowedTools?: Set<string>;
404
+ /**
405
+ * How {@link subagentAllowedTools} is enforced — see
406
+ * {@link SubagentToolGateMode}. Absent means `"wire"`.
407
+ */
408
+ subagentToolGateMode?: SubagentToolGateMode;
409
+ /**
410
+ * When set (execution-gate-mode wakes), tool-definition resolution reads
411
+ * `hasNoClient` / `transportInterface` / `channelCapabilities` exclusively
412
+ * from this pin instead of the live conversation — see
413
+ * {@link WakeToolContextPin}.
414
+ */
415
+ readonly toolContextPin?: WakeToolContextPin;
364
416
  /** True when the current turn is restricted to disk-pressure cleanup-safe tools. */
365
417
  diskPressureCleanupModeActive?: boolean;
366
418
  /** True when this conversation belongs to a subagent spawned by SubagentManager. */
@@ -479,10 +531,29 @@ export function isToolActiveForContext(
479
531
  name: string,
480
532
  ctx: SkillProjectionContext,
481
533
  ): boolean {
534
+ // Execution-gate-mode wakes pin the client-context inputs so the wire tool
535
+ // surface matches the SOURCE conversation's live turns rather than the
536
+ // fork's clientless hydration (see {@link WakeToolContextPin}). When the
537
+ // pin is present it replaces all three values — channel capabilities pin
538
+ // to `undefined` (see the pin's doc for why unset IS parity), never
539
+ // falling through to live state.
540
+ const pin = ctx.toolContextPin;
541
+ const hasNoClient = pin ? pin.hasNoClient : ctx.hasNoClient;
542
+ const channelCapabilities = pin ? undefined : ctx.channelCapabilities;
543
+ const transportInterface = pin
544
+ ? pin.transportInterface
545
+ : ctx.transportInterface;
546
+
482
547
  // When the conversation is acting as a subagent, the parent orchestrator
483
548
  // restricts the tool list. A tool that isn't on the allowlist is not
484
549
  // available for this turn, so short-circuit before any capability checks.
485
- if (ctx.subagentAllowedTools && !ctx.subagentAllowedTools.has(name)) {
550
+ // In execution gate mode the allowlist is enforced at execution time
551
+ // instead — the full tool surface stays visible on the wire.
552
+ if (
553
+ ctx.subagentAllowedTools &&
554
+ ctx.subagentToolGateMode !== "execution" &&
555
+ !ctx.subagentAllowedTools.has(name)
556
+ ) {
486
557
  return false;
487
558
  }
488
559
  // `createResolveToolsCallback` returns an empty tool list when tools are
@@ -507,16 +578,16 @@ export function isToolActiveForContext(
507
578
  }
508
579
  if (UI_SURFACE_TOOL_NAMES.has(name)) {
509
580
  if (
510
- ctx.channelCapabilities?.channel === "slack" &&
581
+ channelCapabilities?.channel === "slack" &&
511
582
  SLACK_TASK_PROGRESS_UI_TOOL_NAMES.has(name)
512
583
  ) {
513
- return !ctx.hasNoClient;
584
+ return !hasNoClient;
514
585
  }
515
- return ctx.channelCapabilities?.supportsDynamicUi ?? !ctx.hasNoClient;
586
+ return channelCapabilities?.supportsDynamicUi ?? !hasNoClient;
516
587
  }
517
588
  if (HOST_TOOL_NAMES.has(name)) {
518
589
  const capability = HOST_TOOL_TO_CAPABILITY.get(name);
519
- const transport = ctx.transportInterface;
590
+ const transport = transportInterface;
520
591
 
521
592
  // Per-capability check is authoritative for structural support: if the
522
593
  // transport cannot service this capability, the tool is filtered out.
@@ -535,7 +606,7 @@ export function isToolActiveForContext(
535
606
  capability &&
536
607
  CROSS_CLIENT_EXPOSED_CAPABILITIES.has(capability) &&
537
608
  transport !== "chrome-extension" &&
538
- !ctx.hasNoClient &&
609
+ !hasNoClient &&
539
610
  assistantEventHub.listClientsByCapability(capability).length > 0
540
611
  ) {
541
612
  return true;
@@ -555,23 +626,20 @@ export function isToolActiveForContext(
555
626
  // For transports that surface approvals over SSE (macos, backwards-compat
556
627
  // fallback), deny when no client is present so the guardian auto-approve
557
628
  // path cannot execute host commands unattended.
558
- return !ctx.hasNoClient;
629
+ return !hasNoClient;
559
630
  }
560
631
  if (CLIENT_CAPABILITY_TOOL_NAMES.has(name)) {
561
- if (
562
- name === "ask_question" &&
563
- ctx.channelCapabilities?.clientOS === "macos"
564
- ) {
632
+ if (name === "ask_question" && channelCapabilities?.clientOS === "macos") {
565
633
  // macOS has no UI handler for question_request yet; hiding the tool
566
634
  // avoids a 5-minute prompter timeout when the LLM would otherwise call it.
567
635
  return false;
568
636
  }
569
- return !ctx.hasNoClient;
637
+ return !hasNoClient;
570
638
  }
571
639
  if (PLATFORM_TOOL_NAMES.has(name)) {
572
640
  // Check the *client's* platform, not the daemon's process.platform.
573
641
  // In Docker the daemon runs on Linux but the connected client may be macOS.
574
- return ctx.channelCapabilities?.clientOS === "macos" && !ctx.hasNoClient;
642
+ return channelCapabilities?.clientOS === "macos" && !hasNoClient;
575
643
  }
576
644
  if (SUBAGENT_ONLY_TOOL_NAMES.has(name)) {
577
645
  return ctx.isSubagent === true;
@@ -628,9 +696,16 @@ export function createResolveToolsCallback(
628
696
  );
629
697
 
630
698
  // When the conversation is acting as a subagent, restrict core tools to
631
- // only those explicitly allowed by the parent orchestrator.
632
- const scopedCoreDefs = ctx.subagentAllowedTools
633
- ? filteredCoreDefs.filter((d) => ctx.subagentAllowedTools!.has(d.name))
699
+ // only those explicitly allowed by the parent orchestrator. In
700
+ // `"execution"` gate mode the allowlist is NOT applied to the wire
701
+ // definitions (see {@link SubagentToolGateMode}) the executor callback
702
+ // rejects non-allowlisted calls at execution time instead.
703
+ const wireAllowlist =
704
+ ctx.subagentToolGateMode === "execution"
705
+ ? undefined
706
+ : ctx.subagentAllowedTools;
707
+ const scopedCoreDefs = wireAllowlist
708
+ ? filteredCoreDefs.filter((d) => wireAllowlist.has(d.name))
634
709
  : filteredCoreDefs;
635
710
 
636
711
  // Re-read MCP tool definitions from the registry each turn so conversations
@@ -644,8 +719,8 @@ export function createResolveToolsCallback(
644
719
  },
645
720
  "MCP tools resolved for turn",
646
721
  );
647
- const scopedMcpDefs = ctx.subagentAllowedTools
648
- ? currentMcpDefs.filter((d) => ctx.subagentAllowedTools!.has(d.name))
722
+ const scopedMcpDefs = wireAllowlist
723
+ ? currentMcpDefs.filter((d) => wireAllowlist.has(d.name))
649
724
  : currentMcpDefs;
650
725
  const excluded = new Set(getConfig().tools.exclude);
651
726
  const allBaseDefs = [...scopedCoreDefs, ...scopedMcpDefs].filter(
@@ -676,8 +751,10 @@ export function createResolveToolsCallback(
676
751
  });
677
752
  const turnAllowed = new Set(allBaseDefs.map((d) => d.name));
678
753
  for (const name of projection.allowedToolNames) {
679
- // When a subagent allowlist is active, exclude skill tools not on it.
680
- if (ctx.subagentAllowedTools && !ctx.subagentAllowedTools.has(name)) {
754
+ // When a wire-gated subagent allowlist is active, exclude skill tools
755
+ // not on it. (Execution gate mode keeps them available here and
756
+ // rejects non-allowlisted calls in the executor callback instead.)
757
+ if (wireAllowlist && !wireAllowlist.has(name)) {
681
758
  continue;
682
759
  }
683
760
  if (excluded.has(name)) continue;
@@ -214,6 +214,8 @@ export function recordUsage(
214
214
  conversationId: ctx.conversationId,
215
215
  inputTokens,
216
216
  outputTokens,
217
+ cacheCreationInputTokens: normalizedCacheCreationInputTokens,
218
+ cacheReadInputTokens: normalizedCacheReadInputTokens,
217
219
  totalInputTokens: ctx.usageStats.inputTokens,
218
220
  totalOutputTokens: ctx.usageStats.outputTokens,
219
221
  estimatedCost,
@@ -76,6 +76,7 @@ import { filterPrunedCardSections } from "../plugins/defaults/memory-v3-shadow/p
76
76
  import {
77
77
  applyBootstrapTemplate,
78
78
  buildSystemPrompt,
79
+ type SystemPromptPersonaOverride,
79
80
  } from "../prompts/system-prompt.js";
80
81
  import type { ContentBlock, Message } from "../providers/types.js";
81
82
  import type { Provider } from "../providers/types.js";
@@ -146,7 +147,11 @@ import {
146
147
  handleSurfaceUndo as handleSurfaceUndoImpl,
147
148
  type SurfaceActionResult,
148
149
  } from "./conversation-surfaces.js";
149
- import type { ToolSetupContext } from "./conversation-tool-setup.js";
150
+ import type {
151
+ SubagentToolGateMode,
152
+ ToolSetupContext,
153
+ WakeToolContextPin,
154
+ } from "./conversation-tool-setup.js";
150
155
  import {
151
156
  createResolveToolsCallback,
152
157
  createToolExecutor,
@@ -177,6 +182,26 @@ export interface CleanResult {
177
182
  preservedMessages: number;
178
183
  }
179
184
 
185
+ /**
186
+ * Optional context-window sizing inputs for {@link Conversation.maybeCompact}.
187
+ *
188
+ * The auto-threshold gate sizes its window against `mainAgent` by default,
189
+ * but an agent wake can run under a different call site (and a forced
190
+ * override profile) that resolves a SMALLER effective window — sized against
191
+ * `mainAgent`, such a wake passes the gate un-compacted and then overflows at
192
+ * the provider. Wakes thread their already-resolved inputs here so the gate's
193
+ * threshold matches the window the wake's calls actually get. Sizing only:
194
+ * the compaction execution (summary call profile) is unchanged.
195
+ */
196
+ export interface CompactionSizing {
197
+ /** Call site the upcoming run resolves its context window against. */
198
+ callSite: LLMCallSite;
199
+ /** Inference profile the run resolves under, if any. */
200
+ overrideProfile?: string;
201
+ /** Float `overrideProfile` above the call-site layers (resolver escape hatch). */
202
+ forceOverrideProfile?: boolean;
203
+ }
204
+
180
205
  export { findLastUndoableUserMessageIndex } from "./conversation-history.js";
181
206
  export type {
182
207
  QueueDrainReason,
@@ -220,6 +245,21 @@ export class Conversation {
220
245
  /** @internal */ toolsDisabledDepth = 0;
221
246
  /** @internal */ preactivatedSkillIds?: string[];
222
247
  /** @internal */ subagentAllowedTools?: Set<string>;
248
+ /**
249
+ * How {@link subagentAllowedTools} is enforced — see
250
+ * {@link SubagentToolGateMode}. Set and restored alongside the allowlist
251
+ * by `scopeWakeAllowedTools`.
252
+ * @internal
253
+ */
254
+ subagentToolGateMode?: SubagentToolGateMode;
255
+ /**
256
+ * Client-context pin for execution-gate-mode wakes — see
257
+ * {@link WakeToolContextPin}. Set and restored alongside the allowlist by
258
+ * `scopeWakeAllowedTools`; read only by tool-DEFINITION resolution
259
+ * (`isToolActiveForContext`), never by executor or host-proxy paths.
260
+ * @internal
261
+ */
262
+ toolContextPin?: WakeToolContextPin;
223
263
  /** @internal */ coreToolNames: Set<string>;
224
264
  /** @internal */ readonly skillProjectionState = new Map<string, string>();
225
265
  /** @internal */ readonly skillProjectionCache: SkillProjectionCache = {};
@@ -295,6 +335,18 @@ export class Conversation {
295
335
  */
296
336
  currentTurnInboundActorContext?: InboundActorContext | null;
297
337
  /** @internal */ currentTurnChannelCapabilities?: ChannelCapabilities;
338
+ /**
339
+ * Explicit persona/channel slugs for the system-prompt build, set (and
340
+ * cleared) by `wakeAgentForOpportunity` around a wake's agent-loop run.
341
+ * Wakes bypass the orchestrator's turn-start snapshots above, so without
342
+ * this their prompt is built from whatever snapshot the conversation
343
+ * already holds (for a freshly hydrated conversation: the no-trust-context
344
+ * persona derivation) regardless of which actor/channel the conversation
345
+ * belongs to. Takes precedence over the trust-context derivation when set.
346
+ * Persona selection only — never read for trust/approval decisions.
347
+ * @internal
348
+ */
349
+ wakePersonaOverride?: SystemPromptPersonaOverride;
298
350
  /** @internal */ currentTurnOverrideProfile?: string;
299
351
  /** @internal */ toolRoutedProfile?: string;
300
352
  /** @internal */ authContext?: AuthContext;
@@ -594,6 +646,7 @@ export class Conversation {
594
646
  hasNoClient: this.hasNoClient,
595
647
  trustContext: this.currentTurnTrustContext,
596
648
  channelCapabilities: this.currentTurnChannelCapabilities,
649
+ personaOverride: this.wakePersonaOverride,
597
650
  onboardingContext: this.getOnboardingContext(),
598
651
  conversationId: this.conversationId,
599
652
  }),
@@ -729,6 +782,7 @@ export class Conversation {
729
782
  hasNoClient: this.hasNoClient,
730
783
  trustContext: this.currentTurnTrustContext,
731
784
  channelCapabilities: this.currentTurnChannelCapabilities,
785
+ personaOverride: this.wakePersonaOverride,
732
786
  onboardingContext: this.getOnboardingContext(),
733
787
  conversationId: this.conversationId,
734
788
  });
@@ -1503,17 +1557,65 @@ export class Conversation {
1503
1557
  }
1504
1558
 
1505
1559
  async forceCompact(): Promise<ContextWindowResult> {
1560
+ return this.runCompaction(true);
1561
+ }
1562
+
1563
+ /**
1564
+ * Auto-threshold compaction gate. Runs the same durable compaction
1565
+ * pipeline as {@link forceCompact} (summary call, circuit-breaker
1566
+ * accounting, Slack provenance, in-memory + DB commit) but honors the
1567
+ * `compaction.autoThreshold` check — an under-threshold history is a
1568
+ * cheap no-op — and the compaction circuit breaker, returning `null`
1569
+ * without estimating anything while the breaker is open. Used by the
1570
+ * agent-wake path (`runtime/agent-wake.ts`), which bypasses the daemon
1571
+ * orchestrator's in-loop budget gate and needs an equivalent turn-start
1572
+ * compaction before snapshotting its run input.
1573
+ *
1574
+ * `sizing` lets a wake thread its own call-site/profile resolution into
1575
+ * the gate's context-window sizing — see {@link CompactionSizing}. Absent,
1576
+ * the gate sizes against `mainAgent` (the live-turn behavior).
1577
+ */
1578
+ async maybeCompact(
1579
+ sizing?: CompactionSizing,
1580
+ ): Promise<ContextWindowResult | null> {
1581
+ if (await this.agentLoop.compactionCircuit.isOpen()) {
1582
+ return null;
1583
+ }
1584
+ return this.runCompaction(false, sizing);
1585
+ }
1586
+
1587
+ /**
1588
+ * Shared compaction pipeline behind {@link forceCompact} and
1589
+ * {@link maybeCompact}. `force` skips the auto-threshold check inside the
1590
+ * context-window manager (user-initiated `/compact`); without it the
1591
+ * manager no-ops below the threshold.
1592
+ */
1593
+ private async runCompaction(
1594
+ force: boolean,
1595
+ sizing?: CompactionSizing,
1596
+ ): Promise<ContextWindowResult> {
1506
1597
  const overrideProfile = resolveOverrideProfile(this) ?? null;
1507
1598
  const config = getConfig();
1599
+ // Threshold/window sizing. The default (`mainAgent` + the conversation's
1600
+ // own pinned profile) matches live turns; caller-supplied `sizing` makes
1601
+ // the gate's threshold reflect the window the caller's run will actually
1602
+ // resolve. Sizing only — the summary call below still runs under the
1603
+ // conversation's own profile.
1604
+ const sizingCallSite = sizing?.callSite ?? "mainAgent";
1605
+ const sizingOverrideProfile = sizing
1606
+ ? sizing.overrideProfile
1607
+ : (overrideProfile ?? undefined);
1508
1608
  const effectiveContextWindow = resolveEffectiveContextWindow({
1509
1609
  llm: config.llm,
1510
- callSite: "mainAgent",
1511
- overrideProfile: overrideProfile ?? undefined,
1610
+ callSite: sizingCallSite,
1611
+ overrideProfile: sizingOverrideProfile,
1612
+ forceOverrideProfile: sizing?.forceOverrideProfile,
1512
1613
  });
1513
1614
  this.contextWindowManager.updateConfig(
1514
1615
  contextWindowConfigFromEffective(
1515
- resolveCallSiteConfig("mainAgent", config.llm, {
1516
- overrideProfile: overrideProfile ?? undefined,
1616
+ resolveCallSiteConfig(sizingCallSite, config.llm, {
1617
+ overrideProfile: sizingOverrideProfile,
1618
+ forceOverrideProfile: sizing?.forceOverrideProfile,
1517
1619
  }).contextWindow,
1518
1620
  effectiveContextWindow,
1519
1621
  ),
@@ -1538,15 +1640,17 @@ export class Conversation {
1538
1640
  conversationId: this.conversationId,
1539
1641
  messages: messagesToCompact,
1540
1642
  signal: this.abortController?.signal ?? undefined,
1541
- force: true,
1643
+ force,
1542
1644
  overrideProfile,
1543
1645
  actorTrustClass: this.trustContext?.trustClass,
1544
1646
  });
1545
- // Track circuit-breaker state for user-initiated `/compact` and other
1546
- // forced paths so a successful forced compaction clears a stuck counter
1547
- // and a run of forced failures still trips the breaker. `summaryFailed`
1548
- // is `undefined` on early-return paths (no eligible messages, disabled,
1549
- // etc.) skip those so they don't silently reset the counter.
1647
+ // Track circuit-breaker state for every compaction that ran a summary
1648
+ // call user-initiated `/compact`, other forced paths, and the wake's
1649
+ // auto gate — so a success clears a stuck counter and a run of failures
1650
+ // still trips the breaker. `summaryFailed` is `undefined` on
1651
+ // early-return paths (no eligible messages, disabled, below the auto
1652
+ // threshold, etc.) — skip those so they don't silently reset the
1653
+ // counter.
1550
1654
  if (result.summaryFailed !== undefined) {
1551
1655
  await this.agentLoop.compactionCircuit.recordOutcome(
1552
1656
  result.summaryFailed,
@@ -13,6 +13,7 @@ import type { SecretPromptResult } from "../../permissions/secret-prompter.js";
13
13
  import { isPlaceholderSentinelText } from "../../providers/placeholder-sentinels.js";
14
14
  import { broadcastMessage } from "../../runtime/assistant-event-hub.js";
15
15
  import type { AuthContext } from "../../runtime/auth/types.js";
16
+ import * as pendingInteractions from "../../runtime/pending-interactions.js";
16
17
  import { unwrapExternalContentForDisplay } from "../../security/untrusted-content.js";
17
18
  import { getLogger } from "../../util/logger.js";
18
19
  import { estimateBase64Bytes } from "../assistant-attachments.js";
@@ -28,15 +29,6 @@ export const CONFIG_RELOAD_DEBOUNCE_MS = 300;
28
29
 
29
30
  const HISTORY_ATTACHMENT_TEXT_LIMIT = 500;
30
31
 
31
- // Module-level map for non-conversation secret prompts (e.g. publish_page)
32
- const pendingStandaloneSecrets = new Map<
33
- string,
34
- {
35
- resolve: (result: SecretPromptResult) => void;
36
- timer: ReturnType<typeof setTimeout>;
37
- }
38
- >();
39
-
40
32
  /**
41
33
  * A single tool call rendered into a history row. Alias of the canonical
42
34
  * wire-contract type so `renderHistoryContent` (the producer) cannot drift
@@ -166,6 +158,13 @@ export interface ConversationCreateOptions {
166
158
  * `resolveCallSiteConfig` instead of the global default.
167
159
  */
168
160
  callSite?: LLMCallSite;
161
+ /**
162
+ * Optional ad-hoc inference-profile override (`llm.profiles` key) applied
163
+ * to every LLM call the turn issues. Background callers with a pinned
164
+ * profile (e.g. schedules) pass it here so the agent loop layers the
165
+ * profile via `SendMessageOptions.config.overrideProfile`.
166
+ */
167
+ overrideProfile?: string;
169
168
  /**
170
169
  * Slack inbound metadata captured at the channel ingress boundary. When
171
170
  * present (and the turn channel resolves to Slack), persistence writes a
@@ -697,9 +696,15 @@ export function renderHistoryContent(
697
696
  }
698
697
 
699
698
  /**
700
- * Send a `secret_request` to the client and wait for the response,
701
- * outside of a conversation context (e.g. from IPC routes like
702
- * credentials/prompt).
699
+ * Send a `secret_request` to the client and wait for the response, outside of a
700
+ * conversation context (e.g. from IPC routes like credentials/prompt).
701
+ *
702
+ * Lifecycle state (resolver, timer) is registered in pendingInteractions — the
703
+ * same tracker the in-conversation SecretPrompter uses — so `POST /v1/secret`
704
+ * resolves the prompt generically. When a `conversationId` is supplied (the CLI
705
+ * `credentials prompt` command forwards `__CONVERSATION_ID`), the broadcast is
706
+ * scoped to that conversation so clients deliver it; otherwise it is
707
+ * conversation-less.
703
708
  */
704
709
  export function requestSecretStandalone(params: {
705
710
  service: string;
@@ -710,15 +715,21 @@ export function requestSecretStandalone(params: {
710
715
  purpose?: string;
711
716
  allowedTools?: string[];
712
717
  allowedDomains?: string[];
718
+ conversationId?: string;
713
719
  }): Promise<SecretPromptResult> {
714
720
  const requestId = uuid();
715
721
  const config = getConfig();
716
722
  return new Promise((resolve) => {
717
723
  const timer = setTimeout(() => {
718
- pendingStandaloneSecrets.delete(requestId);
724
+ pendingInteractions.resolve(requestId, "cancelled");
719
725
  resolve({ value: null, delivery: "store" });
720
726
  }, config.timeouts.permissionTimeoutSec * 1000);
721
- pendingStandaloneSecrets.set(requestId, { resolve, timer });
727
+ pendingInteractions.register(requestId, {
728
+ conversationId: params.conversationId,
729
+ kind: "secret",
730
+ rpcResolve: resolve as (value: unknown) => void,
731
+ timer,
732
+ });
722
733
  broadcastMessage({
723
734
  type: "secret_request",
724
735
  requestId,
@@ -727,6 +738,7 @@ export function requestSecretStandalone(params: {
727
738
  label: params.label,
728
739
  description: params.description,
729
740
  placeholder: params.placeholder,
741
+ conversationId: params.conversationId,
730
742
  purpose: params.purpose,
731
743
  allowedTools: params.allowedTools,
732
744
  allowedDomains: params.allowedDomains,
@@ -473,19 +473,22 @@ export class HostCuProxy {
473
473
  for (const requestId of this._ownedRequests) {
474
474
  const entry = pendingInteractions.resolve(requestId, "cancelled");
475
475
  if (!entry) continue;
476
+ const { conversationId } = entry;
476
477
  try {
477
- broadcastMessage(
478
- {
479
- type: "host_cu_cancel",
480
- requestId,
481
- conversationId: entry.conversationId,
482
- ...(entry.targetClientId != null
483
- ? { targetClientId: entry.targetClientId }
484
- : {}),
485
- },
486
- entry.conversationId,
487
- { targetClientId: entry.targetClientId as string | undefined },
488
- );
478
+ if (conversationId !== undefined) {
479
+ broadcastMessage(
480
+ {
481
+ type: "host_cu_cancel",
482
+ requestId,
483
+ conversationId,
484
+ ...(entry.targetClientId != null
485
+ ? { targetClientId: entry.targetClientId }
486
+ : {}),
487
+ },
488
+ conversationId,
489
+ { targetClientId: entry.targetClientId as string | undefined },
490
+ );
491
+ }
489
492
  } catch {
490
493
  // Best-effort cancel notification
491
494
  }
@@ -277,19 +277,22 @@ export class HostFileProxy {
277
277
  dispose(): void {
278
278
  for (const entry of pendingInteractions.getByKind("host_file")) {
279
279
  pendingInteractions.resolve(entry.requestId, "cancelled");
280
+ const { conversationId } = entry;
280
281
  try {
281
- broadcastMessage(
282
- {
283
- type: "host_file_cancel",
284
- requestId: entry.requestId,
285
- conversationId: entry.conversationId,
286
- ...(entry.targetClientId != null
287
- ? { targetClientId: entry.targetClientId }
288
- : {}),
289
- },
290
- entry.conversationId,
291
- { targetClientId: entry.targetClientId as string | undefined },
292
- );
282
+ if (conversationId !== undefined) {
283
+ broadcastMessage(
284
+ {
285
+ type: "host_file_cancel",
286
+ requestId: entry.requestId,
287
+ conversationId,
288
+ ...(entry.targetClientId != null
289
+ ? { targetClientId: entry.targetClientId }
290
+ : {}),
291
+ },
292
+ conversationId,
293
+ { targetClientId: entry.targetClientId as string | undefined },
294
+ );
295
+ }
293
296
  } catch {
294
297
  // Best-effort cancel notification
295
298
  }