mixdog 1.3.1 → 1.3.3

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 (468) hide show
  1. package/README.md +8 -4
  2. package/package.json +8 -8
  3. package/scripts/native-release-status.mjs +238 -0
  4. package/scripts/verify-runtime-dependency-versions.mjs +158 -0
  5. package/src/agents/reviewer/AGENT.md +5 -7
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +9 -1
  8. package/src/defaults/skills/browser-use/SKILL.md +6 -3
  9. package/src/defaults/skills/local-provider/SKILL.md +33 -6
  10. package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
  11. package/src/defaults/skills/setup/SKILL.md +23 -1
  12. package/src/defaults/skills/setup/references/actions.md +50 -3
  13. package/src/defaults/skills/setup/references/surfaces.md +23 -3
  14. package/src/defaults/skills/setup-guide/SKILL.md +7 -3
  15. package/src/defaults/skills/visualize/SKILL.md +9 -6
  16. package/src/defaults/skills/visualize/references/craft.md +8 -1
  17. package/src/help.mjs +1 -1
  18. package/src/lib/keychain-cjs.cjs +4 -1
  19. package/src/lib/rules-builder.cjs +14 -7
  20. package/src/rules/agent-mode/AGENT_MODE.md +8 -5
  21. package/src/rules/agent-mode/MIXY.md +6 -8
  22. package/src/rules/lead/LEAD.md +7 -10
  23. package/src/rules/shared/10-tool-workflow.md +4 -0
  24. package/src/rules/shared/20-research.md +2 -0
  25. package/src/rules/shared/45-destructive.md +5 -1
  26. package/src/rules/shared/60-verification.md +6 -4
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
  30. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
  31. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
  32. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
  33. package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
  34. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
  35. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
  37. package/src/runtime/agent/orchestrator/config.mjs +11 -0
  38. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
  39. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
  40. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
  41. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
  45. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
  46. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
  48. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  50. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
  51. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
  52. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
  54. package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
  55. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
  56. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
  57. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
  59. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
  60. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
  62. package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
  64. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
  65. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
  68. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
  69. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
  70. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
  72. package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
  73. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
  74. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
  75. package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
  76. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
  78. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
  79. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
  81. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
  82. package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
  83. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
  85. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
  86. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
  87. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
  90. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
  92. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
  93. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
  94. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
  95. package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
  96. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
  97. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
  99. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
  100. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
  102. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
  103. package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
  107. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
  108. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  109. package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
  110. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
  111. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
  112. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
  113. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
  114. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
  115. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
  116. package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
  117. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
  118. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
  119. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
  120. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
  123. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
  124. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
  125. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
  126. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
  127. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
  128. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
  129. package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
  130. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
  131. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
  132. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
  133. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
  134. package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
  135. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
  136. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
  137. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
  138. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
  139. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
  143. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
  144. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
  145. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
  146. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
  148. package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
  150. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
  151. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
  155. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
  156. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
  157. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
  158. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
  160. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
  161. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
  163. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
  166. package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
  167. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
  168. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
  169. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
  170. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
  171. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
  172. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
  178. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
  179. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
  180. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
  181. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
  182. package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
  183. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
  184. package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
  185. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
  186. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
  189. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
  190. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
  196. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
  200. package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
  201. package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
  202. package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
  203. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
  204. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
  206. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
  207. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
  208. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
  209. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
  210. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
  211. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
  212. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
  213. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
  214. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
  215. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
  216. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
  217. package/src/runtime/attachments/attachment-reference.mjs +155 -0
  218. package/src/runtime/attachments/legacy-office.mjs +110 -0
  219. package/src/runtime/attachments/limits.mjs +5 -1
  220. package/src/runtime/attachments/office-extract.mjs +3 -6
  221. package/src/runtime/attachments/pdf-extract.mjs +84 -10
  222. package/src/runtime/attachments/prompt-restore.mjs +70 -0
  223. package/src/runtime/attachments/store.mjs +109 -33
  224. package/src/runtime/browser-bridge/client.mjs +73 -20
  225. package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
  226. package/src/runtime/channels/lib/scheduler.mjs +14 -7
  227. package/src/runtime/channels/lib/state-file.mjs +15 -15
  228. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
  230. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
  231. package/src/runtime/channels/lib/worker-main.mjs +3 -2
  232. package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
  233. package/src/runtime/effort-judge/judge-client.mjs +66 -16
  234. package/src/runtime/effort-judge/model-install.mjs +47 -7
  235. package/src/runtime/local-provider/asset-installer.mjs +10 -4
  236. package/src/runtime/local-provider/catalog.mjs +5 -2
  237. package/src/runtime/local-provider/registered-models.mjs +64 -27
  238. package/src/runtime/local-provider/server.mjs +2 -3
  239. package/src/runtime/media/adapters/image-api.mjs +89 -0
  240. package/src/runtime/media/auth.mjs +64 -1
  241. package/src/runtime/media/catalog.mjs +66 -4
  242. package/src/runtime/media/jobs.mjs +4 -0
  243. package/src/runtime/media/lanes.mjs +46 -5
  244. package/src/runtime/media/media-usage.mjs +17 -0
  245. package/src/runtime/media/renditions.mjs +15 -15
  246. package/src/runtime/media/store.mjs +36 -35
  247. package/src/runtime/media/tool.mjs +8 -1
  248. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
  249. package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
  250. package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
  251. package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
  252. package/src/runtime/memory/lib/pg/process.mjs +8 -4
  253. package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
  254. package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
  255. package/src/runtime/office/core/journal.mjs +7 -14
  256. package/src/runtime/office/design/library/design-library-core.mjs +4 -16
  257. package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
  258. package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
  259. package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
  260. package/src/runtime/office/pdf/pdf-render.mjs +30 -18
  261. package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
  262. package/src/runtime/office/portable/portable-soffice.mjs +135 -29
  263. package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
  264. package/src/runtime/shared/agent-avatar.mjs +3 -2
  265. package/src/runtime/shared/agent-kind-migration.mjs +200 -0
  266. package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
  267. package/src/runtime/shared/agent-message-envelope.mjs +44 -0
  268. package/src/runtime/shared/agent-reap-state.d.mts +4 -0
  269. package/src/runtime/shared/agent-room-host.d.mts +31 -0
  270. package/src/runtime/shared/agent-room-host.mjs +58 -0
  271. package/src/runtime/shared/agent-store.mjs +24 -7
  272. package/src/runtime/shared/agent-task-starts.mjs +27 -0
  273. package/src/runtime/shared/atomic-file.d.mts +50 -0
  274. package/src/runtime/shared/atomic-file.mjs +394 -132
  275. package/src/runtime/shared/background-tasks.mjs +7 -4
  276. package/src/runtime/shared/bot-hops.mjs +35 -0
  277. package/src/runtime/shared/bot-split-migration.mjs +1 -1
  278. package/src/runtime/shared/bounded-download.mjs +4 -2
  279. package/src/runtime/shared/config.mjs +39 -9
  280. package/src/runtime/shared/defaults-separation.mjs +6 -2
  281. package/src/runtime/shared/delegated-approval-host.mjs +74 -0
  282. package/src/runtime/shared/err-text.mjs +4 -0
  283. package/src/runtime/shared/error-presentation.mjs +22 -4
  284. package/src/runtime/shared/file-has-data.mjs +28 -0
  285. package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
  286. package/src/runtime/shared/pending-agent-work.mjs +54 -0
  287. package/src/runtime/shared/process-lifecycle.mjs +8 -12
  288. package/src/runtime/shared/projects.mjs +50 -41
  289. package/src/runtime/shared/provider-accounts.mjs +17 -12
  290. package/src/runtime/shared/redact-directories.mjs +18 -0
  291. package/src/runtime/shared/remove-directory.mjs +28 -0
  292. package/src/runtime/shared/routine-trigger.d.mts +6 -1
  293. package/src/runtime/shared/routine-trigger.mjs +14 -6
  294. package/src/runtime/shared/run-child.d.mts +3 -0
  295. package/src/runtime/shared/run-child.mjs +24 -3
  296. package/src/runtime/shared/session-baseline-store.mjs +8 -2
  297. package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
  298. package/src/runtime/shared/session-sidebar-host.mjs +16 -3
  299. package/src/runtime/shared/singleton-owner.mjs +7 -6
  300. package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
  301. package/src/runtime/shared/staged-update.mjs +4 -2
  302. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
  303. package/src/runtime/shared/tool-execution-contract.mjs +10 -0
  304. package/src/runtime/shared/tool-work-units.mjs +12 -9
  305. package/src/runtime/shared/transcript-metadata.mjs +28 -3
  306. package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
  307. package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
  308. package/src/runtime/shared/turn-snapshot.mjs +277 -124
  309. package/src/runtime/shared/user-cwd.mjs +9 -4
  310. package/src/runtime/shared/user-data-guard.mjs +92 -61
  311. package/src/runtime/shared/utf8-cut.mjs +10 -0
  312. package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
  313. package/src/runtime/shared/worktrees/contract.mjs +11 -3
  314. package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
  315. package/src/runtime/shared/worktrees/manager.mjs +419 -52
  316. package/src/runtime/shared/worktrees/registry.mjs +29 -27
  317. package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
  318. package/src/runtime/tidy/core-install.mjs +26 -4
  319. package/src/runtime/tidy/install.mjs +91 -23
  320. package/src/runtime/tidy/process.mjs +41 -8
  321. package/src/runtime/tidy/resolve.mjs +10 -7
  322. package/src/runtime/web-search/lib/config.mjs +4 -16
  323. package/src/session-runtime/agent-home-delivery.mjs +542 -204
  324. package/src/session-runtime/agent-profile-changes.mjs +16 -0
  325. package/src/session-runtime/agent-room-delivery.mjs +81 -35
  326. package/src/session-runtime/agent-task-sessions.mjs +811 -179
  327. package/src/session-runtime/agent-tool-routing.mjs +1 -0
  328. package/src/session-runtime/boot/apis.mjs +48 -24
  329. package/src/session-runtime/boot/config.mjs +1 -0
  330. package/src/session-runtime/boot/facade.mjs +16 -7
  331. package/src/session-runtime/boot/infrastructure.mjs +14 -2
  332. package/src/session-runtime/boot/providers.mjs +2 -2
  333. package/src/session-runtime/boot/shared.mjs +12 -6
  334. package/src/session-runtime/boot/tools.mjs +23 -3
  335. package/src/session-runtime/bot-status.mjs +432 -0
  336. package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
  337. package/src/session-runtime/config-lifecycle.mjs +60 -55
  338. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
  339. package/src/session-runtime/held-requests.mjs +31 -33
  340. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
  341. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
  342. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
  343. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  344. package/src/session-runtime/lifecycle/teardown.mjs +11 -3
  345. package/src/session-runtime/mcp-glue/connect.mjs +100 -186
  346. package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
  347. package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
  348. package/src/session-runtime/media-api.mjs +5 -2
  349. package/src/session-runtime/model-recency.mjs +1 -0
  350. package/src/session-runtime/model-route/route-tuning.mjs +4 -1
  351. package/src/session-runtime/model-route/set-route.mjs +61 -1
  352. package/src/session-runtime/owned-automation-run.mjs +8 -1
  353. package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
  354. package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
  355. package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
  356. package/src/session-runtime/route-resolution.mjs +16 -8
  357. package/src/session-runtime/route-state.mjs +1 -59
  358. package/src/session-runtime/routine-home-turn.mjs +5 -3
  359. package/src/session-runtime/runtime-bootstrap.mjs +5 -3
  360. package/src/session-runtime/runtime-paths.mjs +11 -5
  361. package/src/session-runtime/runtime-review-api.mjs +4 -1
  362. package/src/session-runtime/runtime-tunables.mjs +6 -0
  363. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
  364. package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
  365. package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
  366. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
  367. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
  368. package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
  369. package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
  370. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
  371. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
  372. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
  373. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
  374. package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
  375. package/src/session-runtime/services/agent-tool.mjs +6 -0
  376. package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
  377. package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
  378. package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
  379. package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
  380. package/src/session-runtime/services/plugin-admin.mjs +26 -26
  381. package/src/session-runtime/services/provider-admin.mjs +26 -6
  382. package/src/session-runtime/services/schedule-access.mjs +33 -4
  383. package/src/session-runtime/services/seeds.mjs +4 -3
  384. package/src/session-runtime/services/usage-dashboard.mjs +1 -1
  385. package/src/session-runtime/services/usage-stats-model.mjs +2 -1
  386. package/src/session-runtime/services/worktree-access.mjs +27 -0
  387. package/src/session-runtime/session-create/materialize.mjs +2 -3
  388. package/src/session-runtime/session-create/session-options.mjs +15 -2
  389. package/src/session-runtime/session-hooks.mjs +9 -17
  390. package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
  391. package/src/session-runtime/settings-compaction-api.mjs +86 -39
  392. package/src/session-runtime/setup-tool/executor.mjs +12 -2
  393. package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
  394. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
  395. package/src/session-runtime/skills-api.mjs +12 -5
  396. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
  397. package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
  398. package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
  399. package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
  400. package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
  401. package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
  402. package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
  403. package/src/session-runtime/tool-policy-refresh.mjs +48 -369
  404. package/src/session-runtime/tool-surface.mjs +10 -4
  405. package/src/session-runtime/turn/session-ops.mjs +8 -0
  406. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
  407. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  408. package/src/session-runtime/turn/turn-run.mjs +7 -2
  409. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
  410. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
  411. package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
  412. package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
  413. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
  414. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
  415. package/src/session-runtime/workspace/transition-steps.mjs +1 -18
  416. package/src/session-runtime/workspace/transitions.mjs +279 -67
  417. package/src/session-runtime/workspace/workspace-state.mjs +7 -6
  418. package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
  419. package/src/standalone/daemon-agent-control.mjs +4 -1
  420. package/src/standalone/daemon-lag-profiler.mjs +3 -1
  421. package/src/standalone/daemon-session-control.mjs +173 -15
  422. package/src/standalone/daemon-telemetry.mjs +9 -0
  423. package/src/standalone/daemon.mjs +33 -10
  424. package/src/standalone/local-session-runtime.mjs +33 -16
  425. package/src/standalone/session-client.mjs +7 -2
  426. package/src/standalone/session-protocol.mjs +8 -0
  427. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
  428. package/src/standalone/session-service/agent-route-follow.mjs +69 -0
  429. package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
  430. package/src/standalone/session-service.mjs +21 -0
  431. package/src/standalone/session-state-projection.mjs +19 -9
  432. package/src/standalone/session-tool-output.mjs +36 -9
  433. package/src/standalone/staged-import.mjs +47 -0
  434. package/src/tui/App.jsx +2 -0
  435. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
  436. package/src/tui/app/message-selector.mjs +15 -2
  437. package/src/tui/app/model-options.mjs +16 -2
  438. package/src/tui/app/model-picker.mjs +2 -1
  439. package/src/tui/app/route-pickers.mjs +3 -1
  440. package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
  441. package/src/tui/app/slash-commands.mjs +1 -1
  442. package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
  443. package/src/tui/dist/index.mjs +617 -369
  444. package/src/tui/paste-attachments.mjs +0 -1
  445. package/src/tui/paste-text-policy.mjs +4 -5
  446. package/src/tui/prompt-history-store.mjs +16 -21
  447. package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
  448. package/src/tui/session/context-state.mjs +4 -0
  449. package/src/tui/session/notice-surface.mjs +3 -0
  450. package/src/tui/session/session-api/intake/abort.mjs +52 -18
  451. package/src/tui/session/session-api/intake/rewind.mjs +39 -4
  452. package/src/tui/session/session-api/media.mjs +2 -1
  453. package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
  454. package/src/tui/session/session-api/routes-write.mjs +203 -0
  455. package/src/tui/session/session-api/routes.mjs +23 -247
  456. package/src/tui/session/session-api/settings.mjs +14 -1
  457. package/src/tui/session/session-flow/drain.mjs +28 -3
  458. package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
  459. package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
  460. package/src/tui/session/session-flow/steering.mjs +8 -3
  461. package/src/tui/session/tool-approval.mjs +142 -14
  462. package/src/tui/session/transcript-intake.mjs +2 -0
  463. package/src/tui/session/turn.mjs +23 -14
  464. package/src/tui/transcript-tool-failures.mjs +8 -2
  465. package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
  466. package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
  467. package/src/rules/agent-mode/ROUTINE.md +0 -6
  468. package/src/session-runtime/room-member-gate.mjs +0 -48
@@ -16,7 +16,8 @@ import { isOffReadonlySurface } from './deferred-call-through.mjs';
16
16
  import { BRIDGE_CALL_TOOL_NAME, bridgeErrorText, isToolBridgeEnabled } from '../../runtime-core/tool-bridge.mjs';
17
17
  import { sessionAllowlistExcludes, sessionDisallows } from '../../runtime-core/deferred-tool-availability.mjs';
18
18
  import { providerToolExclusionReason } from './provider-tool-exclusions.mjs';
19
- import { agentMcpToolPermission, projectMcpToolDisabled } from '../../mcp/agent-connectors.mjs';
19
+ import { workflowOverlayDenial } from '../manager/workflow-switch-notice.mjs';
20
+ import { agentMcpToolPermission, connectorPolicyAgentOf, projectMcpToolDisabled } from '../../mcp/agent-connectors.mjs';
20
21
 
21
22
  const WORKER_DENIED_TOOLS = new Set(['agent', 'ask_user', 'session']);
22
23
  const BRIDGE_DISCOVERY_TOOL_NAMES = new Set(['load_tool']);
@@ -120,12 +121,15 @@ export function preDispatchDenyForSession(sessionRef, call) {
120
121
  if (!bridgeDiscovery && sessionAllowlistExcludes(sessionRef, schemaName)) {
121
122
  return `Error: tool "${name}" is not available on this session's schema allowlist.`;
122
123
  }
124
+ // A workflow switched mid-conversation keeps the schema; its denials apply here.
125
+ const workflowDenial = workflowOverlayDenial(sessionRef, schemaName);
126
+ if (workflowDenial) return workflowDenial;
123
127
  if (sessionDisallows(sessionRef, schemaName)) {
124
128
  return `Error: tool "${name}" is not available in this session.`;
125
129
  }
126
130
  // An agent's connectors: a tool of a server it does not mount, or one set
127
131
  // to `disabled`, stays refused though the process-wide registry knows it.
128
- if (agentMcpToolPermission(sessionRef?.agent, schemaName) === 'disabled') {
132
+ if (agentMcpToolPermission(connectorPolicyAgentOf(sessionRef), schemaName) === 'disabled') {
129
133
  return `Error: tool "${name}" is not available to this agent.`;
130
134
  }
131
135
  // The project the session runs in may switch a connector off as well.
@@ -67,8 +67,7 @@ function annotateEndedChain(session, error, skipped = null) {
67
67
 
68
68
  // A context overflow moves only to a model whose window is larger.
69
69
  async function nextContextGrows(state, next) {
70
- const config = ensureProviderEnabled(loadConfig(), next.provider);
71
- await initProviders(config.providers, { signal: state.signal });
70
+ await initProviders(ensureProviderEnabled(loadConfig(), next.provider), { signal: state.signal });
72
71
  state.throwIfAborted();
73
72
  const provider = getProvider(next.provider);
74
73
  if (!provider) return false;
@@ -93,8 +92,7 @@ export async function advanceAgentRoute(state, error) {
93
92
  return false;
94
93
  }
95
94
  state.throwIfAborted();
96
- const config = ensureProviderEnabled(loadConfig(), next.provider);
97
- await initProviders(config.providers, { signal: state.signal });
95
+ await initProviders(ensureProviderEnabled(loadConfig(), next.provider), { signal: state.signal });
98
96
  state.throwIfAborted();
99
97
  const provider = getProvider(next.provider);
100
98
  if (!provider) throw new Error(`Provider "${next.provider}" not available`);
@@ -128,7 +126,9 @@ export async function advanceAgentRoute(state, error) {
128
126
  contextTokens: next.contextTokens,
129
127
  selectedContextWindow: resolveSessionContextMeta(provider, next.model, next).rawContextWindow,
130
128
  },
131
- { crossProvider: true }
129
+ // The live turn object is what changes: the route is applied to it in place, never to
130
+ // another copy of the id (a disk reload after a generation takeover).
131
+ { crossProvider: true, session }
132
132
  );
133
133
  if (!updated) throw new Error('agent session closed during model fallback');
134
134
  updated.routeFallbackIndex = index + 1;
@@ -4,6 +4,7 @@
4
4
  * consume a retry verdict, and settle a completed send into the loop state.
5
5
  */
6
6
  import { traceCacheBreak } from '../../cache-break-trace.mjs';
7
+ import { anthropicPrefixChanges } from '../../providers/lib/anthropic-prefix-trace.mjs';
7
8
  import { resolveLiveToolCwd } from './tool-exec.mjs';
8
9
  import { notifySkillsApplied, prepareExplicitSkills, recordAppliedSkills } from '../explicit-skills.mjs';
9
10
  import { addUsage, usageDeltaEvent } from './usage.mjs';
@@ -185,10 +186,16 @@ export async function sendProviderRequest(state, round) {
185
186
  // included: the span the usage ledger recorded as `duration_ms` (stamped on
186
187
  // the response); wall time only for a response no ledger row timed.
187
188
  const requestStartedAt = Date.now();
189
+ // The output-limit escalation is one-shot: take it off the shared options
190
+ // before sending, so this attempt alone carries it whatever the outcome
191
+ // (retry, route fallback, thrown error, abort).
192
+ const maxOutputTokensOverride = opts.maxOutputTokensOverride;
193
+ delete opts.maxOutputTokensOverride;
188
194
  let result;
189
195
  try {
190
196
  result = await runWithProviderRequestToolsScope(round.requestToolScope, () =>
191
197
  sendWithRecovery({
198
+ maxOutputTokensOverride,
192
199
  provider,
193
200
  messages: providerMessages,
194
201
  recoveryMessages: messageSource,
@@ -352,6 +359,8 @@ function traceActualCacheMiss(state, sent, response, { previousGuardState, previ
352
359
  previousCachedPrefixTokens: baseline,
353
360
  idleMs,
354
361
  missingPrefixGuardBaseline: !previousGuardState,
362
+ // Which wire block moved ('none': same bytes, so the cache itself dropped it).
363
+ ...anthropicPrefixChanges(sessionId),
355
364
  },
356
365
  state.cacheBreakTraceOptions
357
366
  );
@@ -381,6 +390,7 @@ export function settleSendResult(state, round, sent) {
381
390
  if (state.imageStrip) settleImageStrip(state, round, sent);
382
391
  opts.onToolCall = undefined;
383
392
  delete opts.cacheBreakIntent;
393
+ state.lastStreamedChars = sent.result.streamedChars || 0;
384
394
  state.contextOverflowRetryUsed = false;
385
395
  // A completed send ends the outage this budget was covering; the next
386
396
  // iteration is a fresh request and must get the full replay budget again.
@@ -1,6 +1,7 @@
1
1
  // Steering-message normalization/merge helpers.
2
2
  // Merges queued steering entries into a single content payload + display text.
3
3
  import { stableMessageId } from '../../../../shared/transcript-metadata.mjs';
4
+ import { raiseTurnHop } from '../../../../shared/bot-hops.mjs';
4
5
 
5
6
  function steeringContentText(content) {
6
7
  if (typeof content === 'string') return content;
@@ -140,6 +141,8 @@ function injectSteeringEntry(merged, { messages, opts, stage, onSkillPrompt }) {
140
141
  // gets it back (onSteerMessage) for the row it draws. A steered prompt
141
142
  // keeps the id the surface gave it, else gets one.
142
143
  const messageId = stableMessageId(merged.transcriptMeta?.messageId);
144
+ // A bot's message at a higher hop makes the running turn bot-descended at that hop.
145
+ raiseTurnHop(opts.session, merged.transcriptMeta);
143
146
  const steeringTranscriptMeta =
144
147
  merged.transcriptMeta && typeof merged.transcriptMeta === 'object'
145
148
  ? { at: submittedAt ?? injectedAt, ...merged.transcriptMeta, messageId }
@@ -6,15 +6,15 @@ import { resolvePreToolAskApproval } from '../tool-helpers.mjs';
6
6
  import { runAbortable, throwIfAborted } from '../../../../../shared/abort-race.mjs';
7
7
  import { evaluateExecPolicy } from '../../../tools/bash-policy-scan.mjs';
8
8
  import { beginSessionApprovalWait } from '../../manager/runtime-liveness.mjs';
9
- import { agentMcpToolPermission } from '../../../mcp/agent-connectors.mjs';
10
- import { humanGateDecision, recordHumanDecision } from '../../human-gate/gate.mjs';
9
+ import { agentMcpToolPermission, writeAgentMcpToolPermission } from '../../../mcp/agent-connectors.mjs';
10
+ import { actingBotId, actingContactBotId, humanGateDecision, recordHumanDecision } from '../../human-gate/gate.mjs';
11
11
  import { applyEditedArgs } from '../../human-gate/requests.mjs';
12
12
 
13
13
  const isArgsObject = (value) => value && typeof value === 'object' && !Array.isArray(value);
14
14
 
15
15
  async function askApproval(
16
16
  call,
17
- { callerSessionId, executeOpts, toolApprovalHook, decision, request = null, gate = null }
17
+ { callerSessionId, executeOpts, toolApprovalHook, decision, request = null, gate = null, onApproved = null }
18
18
  ) {
19
19
  const askReason = String(decision?.reason || 'approval requested by hook').trim();
20
20
  // While the user decides, the session is waiting on them, not working.
@@ -46,26 +46,49 @@ async function askApproval(
46
46
  }
47
47
  // The user approved this very call on the richer outbound card.
48
48
  if (request?.kind === 'outbound') call.outboundApproved = true;
49
+ await onApproved?.(approval);
49
50
  return null;
50
51
  }
51
52
 
53
+ /** The renderer translates this exact text (desktop-toasts.tsx ALLOW_NOT_SAVED_TEXT). */
54
+ export const ALLOW_NOT_SAVED_NOTICE = 'Allowed this once. The setting could not be saved.';
52
55
  export const CONNECTOR_APPROVAL_REASON = 'This connector tool is set to ask before it runs for this agent.';
53
56
 
54
57
  /**
55
- * A connector tool the running agent set to `needs_approval` asks through the
56
- * ordinary approval hook, whatever the PreToolUse hooks decided. Run after
57
- * them, on the final call: a renamed call is judged under its final name.
58
- * A call the outbound card already got approved is not asked a second time.
58
+ * A connector tool a bot's own session (its home chat or room seat; a
59
+ * schedule/webhook run, which the approval hook then answers by run policy)
60
+ * runs, and the bot set to `needs_approval`, asks through the ordinary
61
+ * approval hook, whatever the PreToolUse hooks decided. Any other session (a
62
+ * coding Lead, a task session, a workflow agent, a sub-agent) runs it unasked.
63
+ * Run after the hooks, on the final call: a renamed call is judged under its
64
+ * final name. A call the outbound gate owns (its card approved it, or a
65
+ * remembered outbound grant answered it) is not asked a second time.
59
66
  * @returns {Promise<{ denial: string } | null>} the denial, or null to run
60
67
  */
61
68
  export function applyConnectorApproval(call, { agentId, callerSessionId, executeOpts, toolApprovalHook }) {
62
69
  if (call.outboundApproved) return null;
70
+ if (!actingBotId(callerSessionId)) return null;
63
71
  if (agentMcpToolPermission(agentId, call.name) !== 'needs_approval') return null;
72
+ // "Always allow" is offered only to the contact bot that is acting, for its
73
+ // own policy entry for this one tool: never another bot or Mixy.
74
+ const botId = actingContactBotId(callerSessionId);
75
+ const rememberable = Boolean(botId) && botId === agentId;
64
76
  return askApproval(call, {
65
77
  callerSessionId,
66
78
  executeOpts,
67
79
  toolApprovalHook,
68
80
  decision: { reason: CONNECTOR_APPROVAL_REASON },
81
+ request: rememberable ? { kind: 'approval', agentId: botId, remember: ['once', 'agent'] } : null,
82
+ onApproved: async (approval) => {
83
+ if (!rememberable || approval?.remember !== 'agent') return;
84
+ try {
85
+ if (await writeAgentMcpToolPermission(botId, call.name, 'auto')) return;
86
+ } catch {
87
+ // fall through to the notice below
88
+ }
89
+ // Not saved: this call still runs once, and the next one asks again.
90
+ toolApprovalHook?.notice?.(ALLOW_NOT_SAVED_NOTICE, 'warn');
91
+ },
69
92
  });
70
93
  }
71
94
 
@@ -120,7 +143,7 @@ export async function applyBeforeToolHook({
120
143
  // Judged as the call will run: only a rewriting decision changes name/args.
121
144
  const hookAction = String(hookDecision?.action || hookDecision?.decision || '').toLowerCase();
122
145
  const rewritten = hookAction === 'ask' || hookAction === 'modify' || hookAction === 'rewrite';
123
- const { decision, request, gate } = await humanGateDecision(
146
+ const { decision, request, gate, remembered } = await humanGateDecision(
124
147
  {
125
148
  name:
126
149
  rewritten && typeof hookDecision?.name === 'string' && hookDecision.name.trim()
@@ -132,6 +155,8 @@ export async function applyBeforeToolHook({
132
155
  { sessionId: callerSessionId, mcpScopeId }
133
156
  );
134
157
  const action = String(decision?.action || decision?.decision || '').toLowerCase();
158
+ // A remembered outbound grant answered this call: the connector ask is not repeated.
159
+ if (remembered) call.outboundApproved = true;
135
160
  if (action === 'deny' || action === 'block') {
136
161
  const reason = decision?.reason ? `: ${decision.reason}` : '';
137
162
  return { denial: `Error: tool "${name}" denied by hook${reason}` };
@@ -7,6 +7,7 @@ import { enqueuePendingMessage, markCompletionEntry } from '../../manager/pendin
7
7
  import { markSessionToolOutputTail } from '../../manager/runtime-liveness.mjs';
8
8
  import { createScopedCacheOutcome } from '../../cache/scoped-cache-outcome.mjs';
9
9
  import { modelVisibleToolCompletionMessage } from '../../../../../shared/tool-execution-contract.mjs';
10
+ import { turnHopOf } from '../../../../../shared/bot-hops.mjs';
10
11
  import { _isScopedCacheableTool } from '../tool-classify.mjs';
11
12
  import { refreshDeferredMcpToolCatalog } from '../../../runtime-core/tool-catalog.mjs';
12
13
  import { coerceToolArgsForSession } from '../arg-schema-coerce.mjs';
@@ -84,8 +85,12 @@ export function prepareToolCall(name, args, cwd, callerSessionId, sessionRef, ex
84
85
  const notificationSessionId = resolveToolCompletionSessionId({ callerSessionId });
85
86
  const notifyFn =
86
87
  typeof executeOpts.notifyFn === 'function' ? executeOpts.notifyFn : completionNotifier(notificationSessionId);
88
+ // Background work launched in a bot-descended turn reports back at that hop:
89
+ // it rides the job's notify context, so every completion's meta carries it.
90
+ const hop = turnHopOf(sessionRef);
87
91
  const completionToolOpts = {
88
92
  ...toolOpts,
93
+ ...(hop > 0 ? { hop } : {}),
89
94
  sessionId: callerSessionId,
90
95
  agent: sessionRef?.agent || null,
91
96
  callerSessionId: notificationSessionId || callerSessionId,
@@ -17,6 +17,32 @@ import { isOnDeferredToolSurface } from '../deferred-call-through.mjs';
17
17
  import { _executeCodeGraphToolLazy } from '../../manager/runtime-loaders.mjs';
18
18
  import { requiresReadBody } from '../tool-classify.mjs';
19
19
  import { executeCursorNativeBuiltin } from '../../../tools/builtin/external-tool-adapters.mjs';
20
+ import { providerModelVisionOverride, providerNativePdf, providerReadsImages } from '../../../providers/registry.mjs';
21
+ import { getModelMetadataSync } from '../../../../../shared/llm/model-catalog.mjs';
22
+
23
+ /**
24
+ * How read returns a PDF to this session's model. Native PDF support decides
25
+ * only whether a short PDF may arrive whole as a document block. A scanned
26
+ * page arrives as a page image whenever the model sees images — the provider
27
+ * sends image input (only the text-only local runtime does not) and the
28
+ * catalog does not say the model lacks it — and as OCR text otherwise. A
29
+ * custom model's own image-input setting (on or off) beats the catalog.
30
+ */
31
+ export function pdfReadModes(
32
+ sessionRef,
33
+ {
34
+ nativePdf = providerNativePdf,
35
+ readsImages = providerReadsImages,
36
+ catalogRow = getModelMetadataSync,
37
+ visionOverride = providerModelVisionOverride,
38
+ } = {}
39
+ ) {
40
+ const provider = sessionRef?.provider;
41
+ const model = sessionRef?.model;
42
+ const vision = model ? (visionOverride(provider, model) ?? catalogRow(model, provider)?.supportsVision) : undefined;
43
+ const seesImages = readsImages(provider) && vision !== false;
44
+ return { pdfPageMode: seesImages ? 'image' : 'ocr', pdfNativeDocument: nativePdf(provider) };
45
+ }
20
46
 
21
47
  function dispatchMcp(name, args, { cwd, callerSessionId, sessionRef, executeOpts }) {
22
48
  const mcpScopeId = sessionRef?.mcpScopeId || null;
@@ -107,6 +133,7 @@ export function dispatchToolCall({ name, args }, ctx) {
107
133
  : {}),
108
134
  // Runtime-granted only; any value inherited from executeOpts is overridden.
109
135
  elevationApproved: ctx.elevationApproved === true,
136
+ ...pdfReadModes(sessionRef),
110
137
  };
111
138
  return executeCursorNativeBuiltin(
112
139
  name,
@@ -6,6 +6,7 @@
6
6
  // tool-exec/after-hook.mjs — PostToolUse result override
7
7
  // tool-exec/read-only-deadline.mjs — bounded read-only I/O with partial-output grace
8
8
  import { isMcpTool } from '../../mcp/client.mjs';
9
+ import { connectorPolicyAgentOf } from '../../mcp/agent-connectors.mjs';
9
10
  import { prepareDeferredToolCallThrough } from './deferred-call-through.mjs';
10
11
  import { refreshDeferredMcpToolCatalog } from '../../runtime-core/tool-catalog.mjs';
11
12
  import { bridgeTargetUnavailable } from '../../runtime-core/tool-bridge.mjs';
@@ -54,7 +55,7 @@ async function executeToolOwned(name, args, cwd, callerSessionId, sessionRef, ex
54
55
  });
55
56
  if (hooked.denial) return hooked.denial;
56
57
  const connectorDenied = await applyConnectorApproval(hooked, {
57
- agentId: sessionRef?.agent,
58
+ agentId: connectorPolicyAgentOf(sessionRef),
58
59
  callerSessionId,
59
60
  executeOpts,
60
61
  toolApprovalHook,
@@ -8,6 +8,7 @@ import {
8
8
  bridgeSurfaceOutdated,
9
9
  sessionToolExposure,
10
10
  TOOL_EXPOSURE_BRIDGE,
11
+ TOOL_EXPOSURE_NATIVE,
11
12
  TOOL_SURFACE_MIGRATION_INTENT,
12
13
  toolExposureMigrationNeeded,
13
14
  toolExposureModeForProvider,
@@ -122,6 +123,17 @@ export function applyAgentToolExposure(session, { existing = false } = {}) {
122
123
  const bridge =
123
124
  !allowlisted && toolExposureModeForProvider(session.provider, session.wireRoute) === TOOL_EXPOSURE_BRIDGE;
124
125
  if (!bridge && before === null) return false;
126
+ // A native deferred surface (the session runtime builds one) stays one:
127
+ // re-selected over the tools just resolved, never stripped to the full
128
+ // array. Native → native is no exposure change, so nothing is tagged.
129
+ if (!bridge && before === TOOL_EXPOSURE_NATIVE) {
130
+ session.tools = session.tools.slice();
131
+ applyDeferredToolSurface(session, session.deferredSurfaceMode || 'full', [], {
132
+ provider: session.provider,
133
+ model: session.model,
134
+ });
135
+ return false;
136
+ }
125
137
  // A surface an earlier bridge revision built is rebuilt now.
126
138
  const outdated = bridgeSurfaceOutdated(session);
127
139
  // The tools just resolved are the whole authority: no earlier catalog, MCP
@@ -3,6 +3,7 @@
3
3
  // native tool-search payload parsing, bash-session routing, and approval.
4
4
  import { isMcpTool } from '../../mcp/client.mjs';
5
5
  import { unattendedApprovalPort } from '../human-gate/gate.mjs';
6
+ import { isGrantedRun, runAskOutcome } from '../human-gate/run-policy.mjs';
6
7
  import { isBuiltinTool } from '../../tools/builtin.mjs';
7
8
  import { isInternalTool } from '../../internal-tools.mjs';
8
9
  import { loadSkillToolDependencies } from '../../runtime-core/skill-tool-loading.mjs';
@@ -212,12 +213,13 @@ export async function resolvePreToolAskApproval({
212
213
  }) {
213
214
  const name = String(toolName || 'tool');
214
215
  const reason = String(askReason || 'approval requested by hook').trim();
215
- // Unattended runs never auto-approve and have no card: a schedule or webhook
216
- // run always holds the request for its owner; a room member does when no
216
+ // A schedule or webhook run never asks: saving it was the user's grant
217
+ // (human-gate/run-policy.mjs). A room member is held for its owner when no
217
218
  // approval UI is attached (session-runtime/held-requests.mjs).
218
219
  const unattended = unattendedApprovalPort();
219
220
  const run = unattended?.runOf?.(sessionId) || null;
220
- const held = run && (run.kind !== 'room' || typeof toolApprovalHook !== 'function');
221
+ if (isGrantedRun(run)) return runAskOutcome({ name, request });
222
+ const held = run && typeof toolApprovalHook !== 'function';
221
223
  const ask = held ? unattended.hold : toolApprovalHook;
222
224
  if (typeof ask !== 'function') {
223
225
  return { denial: formatMissingToolApprovalUiDenial(name, reason) };
@@ -238,8 +240,12 @@ export async function resolvePreToolAskApproval({
238
240
  return { denial: `Error: tool "${name}" denied by hook: ${detail}` };
239
241
  }
240
242
  if (!approvalGranted(approval)) {
241
- const detail = approvalReason(approval, reason || 'not approved');
242
- return { denial: `Error: tool "${name}" denied by hook: ${detail}`, approval };
243
+ // A person (or the hold for one) said no: never a policy hook to work around.
244
+ const detail = String(approvalReason(approval, reason || 'not approved')).replace(/[.\s]+$/, '');
245
+ return {
246
+ denial: `Error: tool "${name}" was not approved: ${detail}. Do not retry it or reach the same result another way; report it.`,
247
+ approval,
248
+ };
243
249
  }
244
250
  return { approval };
245
251
  }
@@ -0,0 +1,102 @@
1
+ // manager/agent-listing-notice.mjs
2
+ // The agents a coding Lead may delegate to, kept current without touching the
3
+ // request prefix (the workflow switch's pattern, workflow-switch-notice.mjs).
4
+ // What the conversation was told is read from the conversation itself, every
5
+ // turn: the "# Available Agents" list the system prompt carries (the one the
6
+ // session was built with: a rebuilt prompt keeps it, prompt-utils.mjs
7
+ // presentedAgentCatalogSlice), then each agent list reminder still in
8
+ // `session.messages`, in order (the user turn that carried one records its
9
+ // change as `meta.agentListing`). A turn whose message stays (answered or
10
+ // failed) counts; one rolled back or compacted away does not, so its change is
11
+ // told again. When the agents enabled at this turn's start (resolved by the
12
+ // session runtime, passed in with the turn) differ from that, the turn carries
13
+ // one reminder naming the agents added and removed.
14
+ import { agentListEntries, presentedAgentCatalogSlice, suffixUserTurnReminders } from './prompt-utils.mjs';
15
+ import { stripRuntimeUserContext, withRuntimeUserContext } from '../runtime-user-context.mjs';
16
+
17
+ /** The agent list the system prompt carries: one complete generated slice of
18
+ * the BP3 block, [] when it carries none (or none valid). */
19
+ function promptAgentList(session) {
20
+ return (session && agentListEntries(presentedAgentCatalogSlice(session) || '')) || [];
21
+ }
22
+
23
+ const ref = (entry) => ({ id: String(entry.id), name: String(entry.name) });
24
+
25
+ /** The agents the conversation was told about: the prompt's list, then every
26
+ * agent list reminder the conversation still holds, in order. */
27
+ export function announcedAgents(session) {
28
+ const told = new Map(promptAgentList(session).map((entry) => [entry.id, ref(entry)]));
29
+ for (const message of Array.isArray(session?.messages) ? session.messages : []) {
30
+ const change = message?.role === 'user' ? message.meta?.agentListing : null;
31
+ if (!change) continue;
32
+ for (const entry of Array.isArray(change.removed) ? change.removed : []) told.delete(entry?.id);
33
+ for (const entry of Array.isArray(change.added) ? change.added : []) {
34
+ if (entry?.id) told.set(entry.id, ref(entry));
35
+ }
36
+ }
37
+ return [...told.values()];
38
+ }
39
+
40
+ function agentListingContent(added, removed, current) {
41
+ return [
42
+ '<system-reminder>',
43
+ '# Available Agents Changed',
44
+ 'This updates the Available Agents list in the system prompt and every earlier Available Agents Changed reminder.',
45
+ ...(added.length
46
+ ? ['New agents are now available to delegate to with `agent`:', ...added.map((entry) => entry.line)]
47
+ : []),
48
+ ...(removed.length
49
+ ? [
50
+ 'These agents are no longer available; an `agent` call naming one is refused:',
51
+ ...removed.map((entry) => `- ${entry.name} (${entry.id})`),
52
+ ]
53
+ : []),
54
+ ...(current.length ? [] : ['No agents are enabled now: do the work yourself until one is enabled.']),
55
+ '</system-reminder>',
56
+ ].join('\n');
57
+ }
58
+
59
+ /**
60
+ * The agent list reminder this user turn carries, or null when the
61
+ * conversation already knows `current`, the agents enabled at this turn's
62
+ * start (`agentListEntries` entries, from the session runtime's ask options;
63
+ * absent for agent-mode threads and delegated workers: no reminder).
64
+ * @returns {{ content: string, meta: { added: object[], removed: object[] } } | null}
65
+ */
66
+ export function buildAgentListingNotice(session, current) {
67
+ if (!Array.isArray(current)) return null;
68
+ const announced = announcedAgents(session);
69
+ const now = new Set(current.map((entry) => entry.id));
70
+ const told = new Set(announced.map((entry) => entry.id));
71
+ const added = current.filter((entry) => !told.has(entry.id));
72
+ const removed = announced.filter((entry) => !now.has(entry.id));
73
+ if (!added.length && !removed.length) return null;
74
+ return {
75
+ content: agentListingContent(added, removed, current),
76
+ meta: { added: added.map(ref), removed: removed.map(ref) },
77
+ };
78
+ }
79
+
80
+ /**
81
+ * A retained failed turn resubmitted as it was (its own message, its input
82
+ * untouched) learns what changed since: the reminder joins its runtime
83
+ * context, and `meta.agentListing` becomes the net change against what the
84
+ * conversation was told before that message, so later turns read it back as a
85
+ * normal turn's. `index` is the message's place in `session.messages`.
86
+ */
87
+ export function withAgentListingNotice(session, index, message, current) {
88
+ const notice = buildAgentListingNotice(session, current);
89
+ if (!notice) return message;
90
+ const before = { ...session, messages: session.messages.filter((_, i) => i !== index) };
91
+ const net = buildAgentListingNotice(before, current);
92
+ const { agentListing: _told, ...meta } = message.meta || {};
93
+ const stripped = stripRuntimeUserContext({ ...message, meta });
94
+ const owned = stripped.meta?.runtimeUserContext ? null : message.meta?.runtimeUserContext;
95
+ return withRuntimeUserContext(
96
+ { ...stripped, meta: { ...stripped.meta, ...(net ? { agentListing: net.meta } : {}) } },
97
+ {
98
+ prefix: owned?.prefix || '',
99
+ suffix: `${owned?.suffix || ''}${suffixUserTurnReminders('', notice.content)}`,
100
+ }
101
+ );
102
+ }
@@ -34,6 +34,7 @@ const promptSourceFields = (source, execution) => {
34
34
  const tailTurnFor = (group) => ({
35
35
  content: group.content,
36
36
  entries: group.entries,
37
+ ...(group.hop ? { hop: group.hop } : {}),
37
38
  ...(group.mode === PENDING_MODE_TASK_NOTIFICATION
38
39
  ? promptSourceFields(PENDING_MODE_TASK_NOTIFICATION, group.execution)
39
40
  : {}),
@@ -46,6 +47,7 @@ const queuedTurnInput = (tailTurn) => ({
46
47
  context: null,
47
48
  explicitPrefetch: null,
48
49
  pendingEntries: tailTurn.entries,
50
+ ...(tailTurn.hop ? { hop: tailTurn.hop } : {}),
49
51
  promptSource: promptSourceFields(tailTurn.source, tailTurn.execution),
50
52
  });
51
53
 
@@ -84,7 +84,19 @@ async function runAskTurn({ sessionId, opened, input, askOpts, onToolCall, cwdOv
84
84
  cwdOverride || opened.turn.session.cwd || process.cwd(),
85
85
  opened.runtime.controller?.signal
86
86
  );
87
- const prepared = await prepareAskTurn({ sessionId, opened, input, cwdOverride, transcriptMeta: transcript.user });
87
+ const prepared = await prepareAskTurn({
88
+ sessionId,
89
+ opened,
90
+ input,
91
+ cwdOverride,
92
+ // A task notification resumes the bot-chain hop of the turn that launched its work.
93
+ transcriptMeta: input.hop ? { ...transcript.user, hop: input.hop } : transcript.user,
94
+ // The agents enabled as this user turn is prepared (the session
95
+ // runtime's resolver; coding Leads): the agent list reminder compares
96
+ // them with what the model was told. Asked again for every user turn
97
+ // the ask runs, queued and background follow-ups included.
98
+ currentAgents: askOpts?.agentsNow?.(),
99
+ });
88
100
  const result = await runAskAgentLoop({
89
101
  sessionId,
90
102
  opened,
@@ -11,6 +11,7 @@ import { autoEffortModel, turnEffortConfigurationMode } from '../../providers/ef
11
11
  import {
12
12
  autoEffortApplicable,
13
13
  autoEffortBase,
14
+ clampAutoEffortBase,
14
15
  normalizeAutoEffortMode,
15
16
  resolveAutoEffort,
16
17
  } from '../../providers/auto-effort.mjs';
@@ -58,6 +59,15 @@ export function autoEffortMode() {
58
59
  }
59
60
  }
60
61
 
62
+ /** The global "Auto reasoning base" setting; absent or unreadable is medium. */
63
+ export function autoEffortBaseSetting() {
64
+ try {
65
+ return autoEffortBase(readSection('agent')?.autoEffortBase);
66
+ } catch {
67
+ return autoEffortBase(undefined);
68
+ }
69
+ }
70
+
61
71
  /**
62
72
  * Starts the judge worker when a session is created or opened on a route that
63
73
  * Auto effort can judge, so the first judged turn does not wait for the cold
@@ -102,7 +112,9 @@ export async function resolveTurnAutoEffort({ sessionId, session, provider, inpu
102
112
  if (!request || request.startsWith('<')) return null;
103
113
  if (!turnEffortConfigurationMode(session, provider)) return null;
104
114
  const chosen = String(session.effort || '').toLowerCase();
105
- const base = autoEffortBase(chosen);
115
+ const options = effortOptionsFor(session.provider, autoEffortModel(session.provider, provider, session.model));
116
+ const setting = autoEffortBaseSetting();
117
+ const base = clampAutoEffortBase({ base: setting, options }) ?? autoEffortBase(setting);
106
118
  const record = {
107
119
  at: new Date().toISOString(),
108
120
  sessionId,
@@ -113,7 +125,6 @@ export async function resolveTurnAutoEffort({ sessionId, session, provider, inpu
113
125
  base,
114
126
  requestChars: request.length,
115
127
  };
116
- const options = effortOptionsFor(session.provider, autoEffortModel(session.provider, provider, session.model));
117
128
  // No judged outcome can apply when the base is off the model's ladder, so
118
129
  // the judge is not asked (in observe mode too: nothing would be logged).
119
130
  if (!autoEffortApplicable({ base, options })) {
@@ -15,16 +15,20 @@ import { filterModelVisibleSessionMessages } from './message-sanitize.mjs';
15
15
  import { _getAgentLoop } from './runtime-loaders.mjs';
16
16
  import { runAbortable, throwIfAborted } from '../../../../shared/abort-race.mjs';
17
17
  import { applyTurnContextMeta, buildUserTurn, startProviderPrewarm, traceTurnContext } from './ask-turn-prepare.mjs';
18
+ import { withAgentListingNotice } from './agent-listing-notice.mjs';
18
19
  import { retainedFailedTurnInput, rewindUnansweredPrompt } from './failed-turn-rewind.mjs';
19
20
  import { buildAgentLoopOptions, trackedToolCallHook } from './ask-turn-loop-options.mjs';
20
21
  import { _api_call_with_interrupt } from './ask-call-interrupt.mjs';
21
22
  import { backfillFallbackSessionTitle } from './session-fallback-title.mjs';
23
+ import { stampTurnHop } from '../../../../shared/bot-hops.mjs';
22
24
 
23
25
  /** Resolves the provider, builds the user turn and pre-commits it; returns
24
26
  * what the loop and the commit need from this preparation. */
25
- export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, transcriptMeta }) {
27
+ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, transcriptMeta, currentAgents }) {
26
28
  const { turn, runtime, turnSignal, askGeneration, checkpoint, turnToken, startedAt, codexTurnId } = opened;
27
29
  const session = turn.session;
30
+ // Where the turn sits in a bot-to-bot chain (session-runtime/bot-hops.mjs).
31
+ stampTurnHop(session, transcriptMeta);
28
32
  const retained = input.retryTurnId
29
33
  ? retainedFailedTurnInput(session.messages, input.retryTurnId, input.retryAttemptId)
30
34
  : null;
@@ -68,21 +72,28 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
68
72
  ? (() => {
69
73
  const historyMessages = filterModelVisibleSessionMessages(session.messages.slice(0, retained.index));
70
74
  const { completion, ...previousTranscript } = retained.message.meta.transcript;
71
- const userTurnMessage = {
72
- ...retained.message,
73
- meta: {
74
- ...retained.message.meta,
75
- transcript: {
76
- ...previousTranscript,
77
- ...transcriptMeta,
78
- messageId: previousTranscript.messageId,
79
- previousCompletions: [
80
- ...(previousTranscript.previousCompletions || []),
81
- { ...completion, at: completion.at ?? previousTranscript.at },
82
- ],
75
+ // The retained message keeps its input; agents enabled or switched
76
+ // off since it was built ride its runtime context.
77
+ const userTurnMessage = withAgentListingNotice(
78
+ session,
79
+ retained.index,
80
+ {
81
+ ...retained.message,
82
+ meta: {
83
+ ...retained.message.meta,
84
+ transcript: {
85
+ ...previousTranscript,
86
+ ...transcriptMeta,
87
+ messageId: previousTranscript.messageId,
88
+ previousCompletions: [
89
+ ...(previousTranscript.previousCompletions || []),
90
+ { ...completion, at: completion.at ?? previousTranscript.at },
91
+ ],
92
+ },
83
93
  },
84
94
  },
85
- };
95
+ currentAgents
96
+ );
86
97
  return { historyMessages, userTurnMessage, outgoing: [...historyMessages, userTurnMessage] };
87
98
  })()
88
99
  : buildUserTurn({
@@ -94,6 +105,7 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
94
105
  transcriptMeta,
95
106
  turnPromptSource: input.promptSource,
96
107
  effortConfiguration: null,
108
+ currentAgents,
97
109
  }),
98
110
  wireRoutePending,
99
111
  ]);
@@ -187,6 +199,7 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
187
199
  deferredToolDelta: userTurn.deferredToolDelta,
188
200
  goalReminder: userTurn.goalReminder,
189
201
  workflowNotice: userTurn.workflowNotice,
202
+ orchestrationModeNotice: userTurn.orchestrationModeNotice,
190
203
  workspaceNotice: userTurn.workspaceNotice,
191
204
  setupNotice: userTurn.setupNotice,
192
205
  };