mixdog 1.4.2 → 1.4.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 (417) hide show
  1. package/package.json +2 -2
  2. package/scripts/build-shipped-history.mjs +15 -5
  3. package/scripts/gate-local.mjs +65 -19
  4. package/scripts/graph-parity.mjs +8 -3
  5. package/scripts/lib/gate-scheduler.mjs +2 -1
  6. package/scripts/lib/run-node-tests.mjs +17 -5
  7. package/scripts/lib/test-failure-summary.mjs +1 -8
  8. package/scripts/lib/test-spawn-ledger.mjs +33 -2
  9. package/scripts/post-release-check.mjs +26 -16
  10. package/scripts/provider-pingpong-live.mjs +1 -1
  11. package/scripts/prune-embedding-runtime.mjs +3 -1
  12. package/scripts/release-paths.mjs +7 -1
  13. package/src/defaults/shipped-history.json +20 -0
  14. package/src/defaults/skills/setup/SKILL.md +2 -2
  15. package/src/defaults/skills/setup/references/actions.md +16 -3
  16. package/src/defaults/skills/setup/references/surfaces.md +3 -0
  17. package/src/defaults/skills/setup-guide/SKILL.md +6 -1
  18. package/src/lib/instruction-text.cjs +36 -0
  19. package/src/lib/rules-builder.cjs +34 -20
  20. package/src/orchestration/balanced.md +23 -0
  21. package/src/orchestration/focused.md +22 -0
  22. package/src/orchestration/none.md +5 -0
  23. package/src/orchestration/swarm.md +24 -0
  24. package/src/rules/agent-mode/AGENT_MODE.md +3 -1
  25. package/src/rules/agent-mode/MIXY.md +2 -2
  26. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +0 -1
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +4 -2
  29. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +0 -9
  30. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
  31. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
  32. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  33. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -4
  34. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -1
  35. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +199 -46
  36. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +3 -5
  37. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +9 -3
  38. package/src/runtime/agent/orchestrator/mcp/client.mjs +3 -5
  39. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
  40. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
  41. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
  42. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
  43. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-stop.mjs +3 -3
  46. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
  50. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
  51. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
  52. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +10 -1
  53. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
  54. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +30 -0
  55. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
  56. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
  57. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
  58. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
  59. package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
  60. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
  61. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
  62. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
  63. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
  64. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
  65. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
  66. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
  67. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
  68. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
  69. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
  70. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -48
  71. package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
  72. package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
  73. package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
  74. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +9 -0
  75. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
  76. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
  79. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
  80. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +2 -2
  82. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
  83. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
  84. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
  85. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
  86. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
  87. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
  88. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +1 -1
  89. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +1 -1
  90. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
  92. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
  93. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +1 -2
  94. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
  97. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  99. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
  100. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
  101. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
  102. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
  103. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
  104. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
  105. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
  106. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +6 -1
  107. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  108. package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
  109. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +57 -26
  111. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
  112. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
  113. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
  114. package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
  115. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
  116. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
  117. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
  118. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
  120. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  121. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
  122. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
  123. package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
  125. package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
  126. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +19 -0
  127. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +19 -10
  128. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +31 -0
  131. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +42 -6
  133. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
  134. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +11 -1
  135. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
  137. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
  138. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
  139. package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
  140. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +1 -1
  141. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
  142. package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
  143. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
  145. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
  146. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
  148. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
  149. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
  150. package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
  151. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
  152. package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
  153. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +14 -5
  154. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +2 -2
  155. package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
  156. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
  157. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
  158. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  159. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
  160. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
  162. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
  163. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  165. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
  166. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
  167. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +7 -3
  168. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +27 -9
  169. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
  173. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1 -2
  174. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
  175. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
  176. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
  177. package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
  179. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
  180. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
  181. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
  182. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +2 -2
  183. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +0 -4
  185. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
  186. package/src/runtime/attachments/attachment-reference.mjs +1 -1
  187. package/src/runtime/attachments/pdf-extract.mjs +1 -1
  188. package/src/runtime/attachments/store.d.mts +1 -0
  189. package/src/runtime/attachments/store.mjs +2 -2
  190. package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
  191. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
  192. package/src/runtime/channels/lib/scheduler.mjs +33 -0
  193. package/src/runtime/channels/lib/schedules-db.mjs +11 -4
  194. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
  195. package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
  196. package/src/runtime/channels/lib/whisper-server.mjs +12 -12
  197. package/src/runtime/channels/lib/worker-main.mjs +9 -31
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
  199. package/src/runtime/connectors/connector-accounts-mcp.mjs +169 -33
  200. package/src/runtime/connectors/gmail-app-password.mjs +2 -2
  201. package/src/runtime/connectors/google-mcp.mjs +1 -1
  202. package/src/runtime/effort-judge/judge-client.mjs +2 -2
  203. package/src/runtime/effort-judge/judge-input.mjs +4 -4
  204. package/src/runtime/explore/explorer.mjs +0 -5
  205. package/src/runtime/explore/tool.mjs +3 -3
  206. package/src/runtime/local-provider/hardware.mjs +1 -1
  207. package/src/runtime/media/adapters/codex-image.mjs +3 -3
  208. package/src/runtime/media/adapters/gemini-video.mjs +1 -1
  209. package/src/runtime/media/media-usage.mjs +1 -1
  210. package/src/runtime/media/store.mjs +1 -1
  211. package/src/runtime/memory/index.mjs +11 -1
  212. package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
  213. package/src/runtime/memory/lib/memory-embed.mjs +83 -14
  214. package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
  215. package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
  216. package/src/runtime/memory/lib/memory.mjs +17 -0
  217. package/src/runtime/memory/lib/pg/process.mjs +1 -1
  218. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
  219. package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
  220. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  221. package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
  222. package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
  223. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  224. package/src/runtime/office/capabilities.mjs +1 -1
  225. package/src/runtime/office/core/office-core.mjs +1 -1
  226. package/src/runtime/office/design/content-model.mjs +3 -3
  227. package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
  228. package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
  229. package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
  230. package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
  231. package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
  232. package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
  233. package/src/runtime/office/portable/portable-soffice.mjs +8 -6
  234. package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
  235. package/src/runtime/shared/atomic-file.d.mts +8 -0
  236. package/src/runtime/shared/background-tasks.mjs +22 -4
  237. package/src/runtime/shared/background-wait.mjs +66 -0
  238. package/src/runtime/shared/child-guardian.mjs +17 -7
  239. package/src/runtime/shared/config.mjs +313 -16
  240. package/src/runtime/shared/connector-catalog.d.mts +4 -5
  241. package/src/runtime/shared/connector-catalog.mjs +11 -1
  242. package/src/runtime/shared/file-lock.mjs +8 -3
  243. package/src/runtime/shared/git-runner.mjs +7 -2
  244. package/src/runtime/shared/idle-gc.mjs +30 -7
  245. package/src/runtime/shared/llm/http-agent.mjs +8 -5
  246. package/src/runtime/shared/llm/system-proxy.mjs +2 -1
  247. package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
  248. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
  249. package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
  250. package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
  251. package/src/runtime/shared/maintenance-schedule.mjs +109 -0
  252. package/src/runtime/shared/process-runner.mjs +8 -4
  253. package/src/runtime/shared/routine-trigger.d.mts +13 -0
  254. package/src/runtime/shared/routine-trigger.mjs +34 -0
  255. package/src/runtime/shared/run-child.d.mts +2 -1
  256. package/src/runtime/shared/run-child.mjs +70 -18
  257. package/src/runtime/shared/session-scratch.mjs +14 -2
  258. package/src/runtime/shared/shipped-definitions.mjs +7 -1
  259. package/src/runtime/shared/tool-card-model.golden.json +3 -12
  260. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  261. package/src/runtime/shared/tool-work-units.mjs +31 -6
  262. package/src/runtime/shared/turn-snapshot.mjs +26 -4
  263. package/src/runtime/shared/turn-worktree-snapshot.mjs +6 -11
  264. package/src/runtime/shared/worker-requests.mjs +17 -3
  265. package/src/runtime/shared/worktrees/branch-management.mjs +1 -5
  266. package/src/runtime/shared/worktrees/contract.mjs +16 -6
  267. package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
  268. package/src/runtime/shared/worktrees/disk.mjs +79 -2
  269. package/src/runtime/shared/worktrees/git.mjs +44 -11
  270. package/src/runtime/shared/worktrees/include.mjs +6 -4
  271. package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
  272. package/src/runtime/shared/worktrees/manager.mjs +772 -75
  273. package/src/runtime/shared/worktrees/settings.mjs +33 -7
  274. package/src/runtime/shared/worktrees/test-support.mjs +5 -1
  275. package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
  276. package/src/runtime/tidy/process.mjs +2 -1
  277. package/src/runtime/web-search/index.mjs +3 -22
  278. package/src/runtime/web-search/lib/web-tools.mjs +2 -2
  279. package/src/runtime/web-search/tool-defs.mjs +17 -26
  280. package/src/session-runtime/agent-profile-changes.mjs +55 -4
  281. package/src/session-runtime/boot/apis.mjs +27 -4
  282. package/src/session-runtime/boot/begin.mjs +2 -0
  283. package/src/session-runtime/boot/config.mjs +10 -1
  284. package/src/session-runtime/boot/facade.mjs +1 -0
  285. package/src/session-runtime/boot/providers.mjs +70 -3
  286. package/src/session-runtime/boot/session.mjs +2 -0
  287. package/src/session-runtime/boot/tools.mjs +69 -25
  288. package/src/session-runtime/channel-config-api.mjs +1 -0
  289. package/src/session-runtime/config-change-effects.mjs +179 -0
  290. package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
  291. package/src/session-runtime/config-lifecycle.mjs +160 -24
  292. package/src/session-runtime/conversation-import/discovery.mjs +86 -7
  293. package/src/session-runtime/conversation-import/service.mjs +3 -2
  294. package/src/session-runtime/goal-facade-api.mjs +49 -3
  295. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
  296. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
  297. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +3 -11
  298. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +18 -4
  299. package/src/session-runtime/internal-tool-executor.mjs +12 -19
  300. package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
  301. package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
  302. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
  303. package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
  304. package/src/session-runtime/lifecycle/teardown/session-close.mjs +4 -4
  305. package/src/session-runtime/lifecycle-api.mjs +1 -0
  306. package/src/session-runtime/mcp-glue/server-catalog.mjs +14 -3
  307. package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
  308. package/src/session-runtime/model-route/set-route.mjs +40 -7
  309. package/src/session-runtime/native-web-search/routes.mjs +3 -3
  310. package/src/session-runtime/provider-auth/refresh.mjs +6 -3
  311. package/src/session-runtime/provider-auth/setup.mjs +1 -1
  312. package/src/session-runtime/provider-readiness.mjs +53 -4
  313. package/src/session-runtime/resource-api.mjs +1 -1
  314. package/src/session-runtime/resource-extension-sync.mjs +4 -8
  315. package/src/session-runtime/resource-mcp-connector-accounts.mjs +5 -1
  316. package/src/session-runtime/resource-mcp-secrets.mjs +3 -3
  317. package/src/session-runtime/resource-plugins-api.mjs +4 -0
  318. package/src/session-runtime/routine-executor.mjs +152 -0
  319. package/src/session-runtime/routine-home-turn.mjs +46 -5
  320. package/src/session-runtime/runtime-facade.mjs +5 -0
  321. package/src/session-runtime/runtime-feature-gates.mjs +2 -11
  322. package/src/session-runtime/schedule-session-run.mjs +1 -0
  323. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
  324. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
  325. package/src/session-runtime/services/agent-tool/send-flow.mjs +110 -6
  326. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
  327. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
  328. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +24 -6
  329. package/src/session-runtime/services/agent-tool.mjs +51 -1
  330. package/src/session-runtime/services/channel-admin.mjs +18 -0
  331. package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
  332. package/src/session-runtime/services/plugin-admin.mjs +4 -0
  333. package/src/session-runtime/services/seeds.mjs +7 -0
  334. package/src/session-runtime/services/usage-stats-model.mjs +32 -11
  335. package/src/session-runtime/session-create/materialize.mjs +4 -2
  336. package/src/session-runtime/session-create/session-options.mjs +2 -0
  337. package/src/session-runtime/settings-builtin-tools-api.mjs +1 -9
  338. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +1 -1
  339. package/src/session-runtime/setup-tool/executor.mjs +8 -1
  340. package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
  341. package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
  342. package/src/session-runtime/setup-tool/tool-defs.mjs +26 -1
  343. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
  344. package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
  345. package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
  346. package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
  347. package/src/session-runtime/tool-policy-refresh.mjs +182 -5
  348. package/src/session-runtime/tool-surface.mjs +38 -1
  349. package/src/session-runtime/turn/agent-ops.mjs +10 -2
  350. package/src/session-runtime/turn/session-ops.mjs +2 -0
  351. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
  352. package/src/session-runtime/turn/turn-run.mjs +1 -1
  353. package/src/session-runtime/webhook-session-run.mjs +2 -0
  354. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +1 -4
  355. package/src/session-runtime/workflow-agents-api/agent-route.mjs +3 -10
  356. package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
  357. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
  358. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
  359. package/src/session-runtime/workflow-agents-api.mjs +2 -0
  360. package/src/session-runtime/workspace/project-branches.mjs +1 -1
  361. package/src/session-runtime/workspace/session-view.mjs +1 -1
  362. package/src/session-runtime/workspace/transitions.mjs +20 -4
  363. package/src/session-runtime/workspace/worktree-maintenance.mjs +126 -6
  364. package/src/session-runtime/workspace/worktree-setup.mjs +13 -1
  365. package/src/session-runtime/workspace/worktree-tool.mjs +16 -0
  366. package/src/standalone/daemon-agent-control.mjs +25 -8
  367. package/src/standalone/daemon-desktop-runtime.mjs +6 -2
  368. package/src/standalone/daemon-lag-profiler.mjs +7 -7
  369. package/src/standalone/daemon.mjs +54 -2
  370. package/src/standalone/local-session-runtime.mjs +16 -0
  371. package/src/standalone/session-client/daemon-unavailable.mjs +1 -1
  372. package/src/standalone/session-protocol.mjs +11 -0
  373. package/src/standalone/session-service/agent-route-follow.mjs +23 -20
  374. package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
  375. package/src/standalone/session-service/quota-resume.mjs +9 -0
  376. package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
  377. package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
  378. package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
  379. package/src/standalone/session-service/session-calls.mjs +2 -1
  380. package/src/tui/App.jsx +8 -0
  381. package/src/tui/app/clipboard.mjs +1 -1
  382. package/src/tui/app/create-app-pickers.mjs +2 -0
  383. package/src/tui/app/doctor.mjs +2 -2
  384. package/src/tui/app/panel-signature.mjs +1 -1
  385. package/src/tui/app/settings-picker.mjs +53 -8
  386. package/src/tui/app/shell-layout/row-budgets.mjs +2 -2
  387. package/src/tui/app/slash-commands.mjs +1 -1
  388. package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
  389. package/src/tui/app/slash-dispatch/session-commands.mjs +1 -1
  390. package/src/tui/app/use-prompt-queue-history.mjs +2 -2
  391. package/src/tui/app/use-transcript-activity.mjs +1 -1
  392. package/src/tui/app/use-transcript-window/geometry.mjs +1 -1
  393. package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
  394. package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
  395. package/src/tui/components/question-panel-model.mjs +4 -4
  396. package/src/tui/components/tool-execution/standard-card.jsx +3 -4
  397. package/src/tui/components/user-message-skills.mjs +1 -1
  398. package/src/tui/dist/index.mjs +309 -30
  399. package/src/tui/markdown/render-ansi.mjs +1 -1
  400. package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
  401. package/src/tui/session/agent-job-feed.mjs +2 -0
  402. package/src/tui/session/context-state.mjs +3 -0
  403. package/src/tui/session/quota-resume.mjs +1 -1
  404. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  405. package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
  406. package/src/tui/session/session-api/routes-agent-definitions.mjs +5 -0
  407. package/src/tui/session/session-api/worktree.mjs +13 -1
  408. package/src/tui/session/session-flow/drain.mjs +11 -14
  409. package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
  410. package/src/tui/session/turn-quiet.mjs +1 -1
  411. package/src/tui/session/turn.mjs +3 -0
  412. package/src/tui/session/worktree-setup-notice.mjs +1 -1
  413. package/src/tui/spinner-meta.mjs +3 -3
  414. package/src/tui/spinner-verbs.mjs +2 -2
  415. package/src/defaults/skills/goal-management/SKILL.md +0 -169
  416. package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
  417. package/src/session-runtime/goal-tasks.mjs +0 -1
@@ -0,0 +1,35 @@
1
+ // The report a finished ask hands its caller (an agent's owner).
2
+ //
3
+ // A turn's `content` is what the live view still needs at its end: the text
4
+ // since the last tool batch. An answer the turn kept going past (a todo
5
+ // reminder or queued input arrived after it) and a turn that queued input
6
+ // followed in the same ask are both older than that, so the result carries
7
+ // them in `reportContent`, ahead of the newest text.
8
+
9
+ export function joinReports(parts) {
10
+ return parts
11
+ .map((part) => String(part || '').trim())
12
+ .filter(Boolean)
13
+ .join('\n\n');
14
+ }
15
+
16
+ /** The whole report of a result: `reportContent` when the ask carried earlier
17
+ * answers, else its content. */
18
+ export function turnReportText(result) {
19
+ if (typeof result?.reportContent === 'string') return result.reportContent;
20
+ return typeof result?.content === 'string' ? result.content : '';
21
+ }
22
+
23
+ /** `result` with `earlier` answers ahead of its own report. */
24
+ export function withEarlierReport(result, earlier) {
25
+ if (!earlier) return result;
26
+ return { ...result, reportContent: joinReports([earlier, turnReportText(result)]) };
27
+ }
28
+
29
+ /** A turn that fails after such answers still hands them on: `error` carries
30
+ * them (`carriedReport`, earliest first) to whoever reports the failure. */
31
+ export function carryReportOnError(error, earlier) {
32
+ if (!earlier || !error || typeof error !== 'object') return error;
33
+ error.carriedReport = joinReports([earlier, typeof error.carriedReport === 'string' ? error.carriedReport : '']);
34
+ return error;
35
+ }
@@ -90,7 +90,7 @@ const SUMMED_USAGE_FIELDS = [
90
90
  ];
91
91
 
92
92
  /** What `total` added after the running total `earlier` (both from addUsage); null when nothing. */
93
- export function usageSince(total, earlier) {
93
+ function usageSince(total, earlier) {
94
94
  if (!total) return null;
95
95
  if (!earlier) return { ...total };
96
96
  const delta = {};
@@ -15,9 +15,10 @@ import { drainPendingMessages, hydratePendingMessages } from './pending-messages
15
15
  import { _unlinkParentAbortListener, _getRuntimeEntry, _evictTerminalSessionRuntime } from './runtime-liveness.mjs';
16
16
  import { acquireSessionLock } from './session-lock.mjs';
17
17
  import { createAskPromptQueue } from './ask-queue.mjs';
18
- import { armTurnDurability, claimTurnRuntime } from './ask-turn-open.mjs';
18
+ import { armTurnDurability, claimTurnRuntime, settleTurnBase } from './ask-turn-open.mjs';
19
19
  import { prepareAskTurn, runAskAgentLoop } from './ask-turn-execute.mjs';
20
20
  import { commitAskTurn, publishAskTurn } from './ask-turn-settle.mjs';
21
+ import { carryReportOnError, turnReportText, withEarlierReport } from '../loop/turn-report.mjs';
21
22
  import { finalizeAskTurnFailure } from './ask-turn-failure.mjs';
22
23
  import { armTurnTimeoutOnProviderError, reapTurnShellJobs } from './turn-reap.mjs';
23
24
  import { cacheWarmTurnKind, endCacheWarmTurn, failedTurnProvenance, noteCacheWarmTurn } from '../cache-warm.mjs';
@@ -78,7 +79,17 @@ export function createAskTranscriptMeta(rawTranscriptMeta) {
78
79
  /** One opened turn from provider call to terminal publish; a failure unwinds
79
80
  * the turn state and rethrows. Returns the terminal result preview and the
80
81
  * follow-ups drained right after the provider accepted the turn. */
81
- async function runAskTurn({ sessionId, opened, input, askOpts, onToolCall, cwdOverride, transcript, askStartedAt }) {
82
+ async function runAskTurn({
83
+ sessionId,
84
+ opened,
85
+ input,
86
+ askOpts,
87
+ onToolCall,
88
+ cwdOverride,
89
+ transcript,
90
+ askStartedAt,
91
+ earlierReport,
92
+ }) {
82
93
  let releaseWorkspace;
83
94
  try {
84
95
  releaseWorkspace = await admitWorkspaceActivity(
@@ -98,6 +109,8 @@ async function runAskTurn({ sessionId, opened, input, askOpts, onToolCall, cwdOv
98
109
  // them with what the model was told. Asked again for every user turn
99
110
  // the ask runs, queued and background follow-ups included.
100
111
  currentAgents: askOpts?.agentsNow?.(),
112
+ // The session runtime's in-memory settings (the file trails them).
113
+ agentConfig: askOpts?.agentConfig?.() || null,
101
114
  });
102
115
  const result = await runAskAgentLoop({
103
116
  sessionId,
@@ -108,14 +121,19 @@ async function runAskTurn({ sessionId, opened, input, askOpts, onToolCall, cwdOv
108
121
  onToolCall,
109
122
  takeAssistantTranscriptMetadata: transcript.takeAssistant,
110
123
  });
111
- const terminalResultPreview = await commitAskTurn({
112
- sessionId,
113
- opened,
114
- prepared,
115
- result,
116
- rawTranscriptMeta: transcript.raw,
117
- askStartedAt,
118
- });
124
+ // The earlier turns of this ask relayed nothing (publishAskTurn relays
125
+ // only a turn no queued input follows): their reports lead this one's.
126
+ const terminalResultPreview = withEarlierReport(
127
+ await commitAskTurn({
128
+ sessionId,
129
+ opened,
130
+ prepared,
131
+ result,
132
+ rawTranscriptMeta: transcript.raw,
133
+ askStartedAt,
134
+ }),
135
+ earlierReport
136
+ );
119
137
  const drained = publishAskTurn({
120
138
  sessionId,
121
139
  opened,
@@ -143,7 +161,8 @@ async function runAskTurn({ sessionId, opened, input, askOpts, onToolCall, cwdOv
143
161
  askStartedAt,
144
162
  });
145
163
  reapTurnShellJobs(sessionId, opened.runtime);
146
- throw err;
164
+ // Queued work that fails still hands on the reports of the turns before it.
165
+ throw carryReportOnError(err, earlierReport);
147
166
  } finally {
148
167
  // The result is already published; this only holds the session lock until
149
168
  // the reader lease is removed, so the next turn's admission follows it. A
@@ -255,21 +274,32 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
255
274
  input.retryAttemptId = askOpts.retryAttemptId;
256
275
  retryTurnId = null;
257
276
  }
258
- // Synchronous pre-await setup (must happen before any await so
259
- // closeSession() can't interleave between load and registration).
260
- const claimed = claimTurnRuntime({
261
- sessionId,
262
- askOpts,
263
- recoverCheckpoint: firstTurn,
264
- emitStart: firstTurn,
265
- });
266
- warmTurn = noteTurnForCacheWarm(sessionId, claimed, input);
267
- firstTurn = false;
268
- askGeneration = claimed.askGeneration;
269
- const opened = {
270
- ...claimed,
271
- ...armTurnDurability({ sessionId, ...claimed, pendingEntries: input.pendingEntries }),
272
- };
277
+ // The earlier turns of this ask relayed nothing (publishAskTurn relays
278
+ // only a turn no queued input follows): this turn failing before it
279
+ // runs (runAskTurn carries the report once it has) still hands them on.
280
+ const earlierReport = result ? turnReportText(result) : '';
281
+ let opened;
282
+ try {
283
+ // The previous turn's save has landed and this turn's base is on disk
284
+ // before the turn touches the session (one unsettled turn per session).
285
+ await settleTurnBase(sessionId, { recoverCheckpoint: firstTurn });
286
+ // Synchronous pre-await setup (must happen before any await so
287
+ // closeSession() can't interleave between load and registration).
288
+ const claimed = claimTurnRuntime({
289
+ sessionId,
290
+ askOpts,
291
+ emitStart: firstTurn,
292
+ });
293
+ warmTurn = noteTurnForCacheWarm(sessionId, claimed, input);
294
+ firstTurn = false;
295
+ askGeneration = claimed.askGeneration;
296
+ opened = {
297
+ ...claimed,
298
+ ...armTurnDurability({ sessionId, ...claimed, pendingEntries: input.pendingEntries }),
299
+ };
300
+ } catch (error) {
301
+ throw carryReportOnError(error, earlierReport);
302
+ }
273
303
  // From here the turn's own unwind (ask-turn-failure) acks or releases
274
304
  // its entries; the queue keeps owning only the not-yet-started ones.
275
305
  queue.markStarted();
@@ -282,6 +312,7 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
282
312
  cwdOverride,
283
313
  transcript,
284
314
  askStartedAt,
315
+ earlierReport,
285
316
  });
286
317
  result = turn.result;
287
318
  endCacheWarmTurn(sessionId, warmTurn);
@@ -50,19 +50,21 @@ export function turnStepAutoEffort(autoEffort, effortConfiguration) {
50
50
  : null;
51
51
  }
52
52
 
53
- export function autoEffortMode() {
53
+ // `config`: a session runtime's in-memory agent config (its file copy trails
54
+ // it by a debounce); other callers read the file.
55
+ export function autoEffortMode(config = null) {
54
56
  if (process.env.MIXDOG_AUTO_EFFORT) return normalizeAutoEffortMode(process.env.MIXDOG_AUTO_EFFORT);
55
57
  try {
56
- return builtinFeatureActive(readSection('agent'), 'autoEffort') ? 'on' : 'off';
58
+ return builtinFeatureActive(config || readSection('agent'), 'autoEffort') ? 'on' : 'off';
57
59
  } catch {
58
60
  return 'off';
59
61
  }
60
62
  }
61
63
 
62
64
  /** The global "Auto reasoning base" setting; absent or unreadable is medium. */
63
- export function autoEffortBaseSetting() {
65
+ export function autoEffortBaseSetting(config = null) {
64
66
  try {
65
- return autoEffortBase(readSection('agent')?.autoEffortBase);
67
+ return autoEffortBase((config || readSection('agent'))?.autoEffortBase);
66
68
  } catch {
67
69
  return autoEffortBase(undefined);
68
70
  }
@@ -99,8 +101,8 @@ function lastText(messages, role) {
99
101
  * briefly (its first-use load is the longest wait): a missing, still-loading,
100
102
  * or slow model yields null and the default effort.
101
103
  */
102
- export async function resolveTurnAutoEffort({ sessionId, session, provider, input }) {
103
- const mode = autoEffortMode();
104
+ export async function resolveTurnAutoEffort({ sessionId, session, provider, input, config = null }) {
105
+ const mode = autoEffortMode(config);
104
106
  // promptSource marks runtime-injected turns (completion notices, queued work).
105
107
  // Agent sessions are judged like any other: their spawn brief and later Lead
106
108
  // `send` messages arrive as plain prompts.
@@ -113,7 +115,7 @@ export async function resolveTurnAutoEffort({ sessionId, session, provider, inpu
113
115
  if (!turnEffortConfigurationMode(session, provider)) return null;
114
116
  const chosen = String(session.effort || '').toLowerCase();
115
117
  const options = effortOptionsFor(session.provider, autoEffortModel(session.provider, provider, session.model));
116
- const setting = autoEffortBaseSetting();
118
+ const setting = autoEffortBaseSetting(config);
117
119
  const base = clampAutoEffortBase({ base: setting, options }) ?? autoEffortBase(setting);
118
120
  const record = {
119
121
  at: new Date().toISOString(),
@@ -59,7 +59,13 @@ function retainedUserTurn(session, retained, transcriptMeta, currentAgents) {
59
59
  },
60
60
  currentAgents
61
61
  );
62
- return { historyMessages, userTurnMessage, outgoing: [...historyMessages, userTurnMessage] };
62
+ const noticeRevision = retained.message.meta?.promptSettingsNoticeRevision;
63
+ return {
64
+ historyMessages,
65
+ userTurnMessage,
66
+ outgoing: [...historyMessages, userTurnMessage],
67
+ promptSettingsNotice: noticeRevision ? { revision: noticeRevision } : null,
68
+ };
63
69
  }
64
70
 
65
71
  // The turn's user message: the retained one of a retried failed turn, or a
@@ -147,7 +153,15 @@ function persistTurnPreflight(session, { turnToken, startedAt, checkpoint, askGe
147
153
 
148
154
  /** Resolves the provider, builds the user turn and pre-commits it; returns
149
155
  * what the loop and the commit need from this preparation. */
150
- export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, transcriptMeta, currentAgents }) {
156
+ export async function prepareAskTurn({
157
+ sessionId,
158
+ opened,
159
+ input,
160
+ cwdOverride,
161
+ transcriptMeta,
162
+ currentAgents,
163
+ agentConfig = null,
164
+ }) {
151
165
  const { turn, runtime, turnSignal, askGeneration, checkpoint, turnToken, startedAt, codexTurnId } = opened;
152
166
  const session = turn.session;
153
167
  // Where the turn sits in a bot-to-bot chain (session-runtime/bot-hops.mjs).
@@ -167,7 +181,7 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
167
181
  // reads the session as the turn found it (synchronously, on this call).
168
182
  // The first request still carries its decision: it is awaited below,
169
183
  // together with the user turn, before the effort configuration is stamped.
170
- const autoEffortPending = resolveTurnAutoEffort({ sessionId, session, provider, input });
184
+ const autoEffortPending = resolveTurnAutoEffort({ sessionId, session, provider, input, config: agentConfig });
171
185
  autoEffortPending.catch(() => {});
172
186
  applyTurnContextMeta(session, provider);
173
187
  const effectiveCwd = cwdOverride || session.cwd;
@@ -206,6 +220,9 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
206
220
  if (effortConfiguration) stampTurnEffort(userTurn.userTurnMessage, effortConfiguration);
207
221
  const { historyMessages, outgoing } = userTurn;
208
222
  turn.userTurnContent = userTurn.userTurnMessage.content;
223
+ // The turn opens right after the history it was built on: its checkpoint
224
+ // boundary, never looked up again by the prompt's text.
225
+ turn.boundary = historyMessages.length;
209
226
  turn.outgoing = outgoing;
210
227
  precommitUserTurn(session, outgoing, historyMessages, input);
211
228
  persistTurnPreflight(session, { turnToken, startedAt, checkpoint, askGeneration });
@@ -236,6 +253,7 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
236
253
  deferredToolDelta: userTurn.deferredToolDelta,
237
254
  goalReminder: userTurn.goalReminder,
238
255
  workflowNotice: userTurn.workflowNotice,
256
+ promptSettingsNotice: userTurn.promptSettingsNotice,
239
257
  orchestrationModeNotice: userTurn.orchestrationModeNotice,
240
258
  workspaceNotice: userTurn.workspaceNotice,
241
259
  setupNotice: userTurn.setupNotice,
@@ -16,7 +16,7 @@ import {
16
16
  } from './pending-messages.mjs';
17
17
  import { _getRuntimeEntry, markSessionCancelled, markSessionError } from './runtime-liveness.mjs';
18
18
  import { SessionClosedError } from './session-errors.mjs';
19
- import { clearTurnCheckpoint } from './turn-checkpoint.mjs';
19
+ import { holdTurnUntilDurable, turnCoveredOnDisk } from './turn-durability.mjs';
20
20
  import { attachFailedTurnCompletion } from './ask-turn-settle.mjs';
21
21
  import { turnFailureRecord } from '../turn-failure.mjs';
22
22
  import { transcriptRouteMetadataFields } from '../../../../shared/transcript-metadata.mjs';
@@ -97,6 +97,17 @@ async function persistFinalizedSession({ session, sessionId, generation, pending
97
97
  }
98
98
  }
99
99
 
100
+ /** Keep the failed turn's checkpoint until a landed save covers its
101
+ * finalized transcript (turn-durability.mjs); returns the save issued for
102
+ * it, or null when an earlier one already landed it. */
103
+ function holdFinalizedTurn({ sessionId, session, turnToken, generation }) {
104
+ const save = turnCoveredOnDisk(session, turnToken)
105
+ ? null
106
+ : saveSessionAsync(session, { expectedGeneration: generation });
107
+ holdTurnUntilDurable({ sessionId, session, turnToken, generation, save });
108
+ return save;
109
+ }
110
+
100
111
  /** A SessionClosedError unwind: keeps the interruption snapshot unless the
101
112
  * runtime already closed, in which case the consumed queue entries are
102
113
  * released untouched. */
@@ -119,14 +130,14 @@ async function finalizeCancelledTurn({
119
130
  if (currentRuntime?.prepareCloseSnapshot === prepareCloseSnapshot) {
120
131
  currentRuntime.prepareCloseSnapshot = null;
121
132
  }
122
- const settled = await persistFinalizedSession({
133
+ await persistFinalizedSession({
123
134
  session,
124
135
  sessionId,
125
136
  generation,
126
137
  pendingEntries: turn.pendingEntries,
127
138
  promptSurvived: finalized.responsePreserved,
128
139
  });
129
- if (settled) clearTurnCheckpoint(sessionId, turnCheckpointToken);
140
+ holdFinalizedTurn({ sessionId, session, turnToken: turnCheckpointToken, generation });
130
141
  if (currentRuntime) currentRuntime.session = session;
131
142
  markSessionCancelled(sessionId);
132
143
  }
@@ -169,6 +180,9 @@ export async function finalizeAskTurnFailure({
169
180
  if (session) {
170
181
  session.liveTurnMessages = null;
171
182
  delete session.activeTurnCheckpoint;
183
+ // Every record saved from here on carries this turn as finalized: a
184
+ // crash after one lands deletes the checkpoint instead of replaying it.
185
+ session.turnCoverage = turnCheckpointToken;
172
186
  // The provider prefix snapshot commits per successful send INSIDE the
173
187
  // turn, while the transcript unwinds to its pre-turn/finalized shape
174
188
  // below. A surviving mid-turn snapshot flags every retry as
@@ -206,7 +220,8 @@ export async function finalizeAskTurnFailure({
206
220
  // contract answers "did the provider produce output we must commit?" for
207
221
  // every transport. Anthropic's stall/truncation errors carry neither
208
222
  // liveTextEmitted nor unsafeToRetry — only partialContent/partialToolCalls
209
- // — and used to drop the streamed summary from history on that provider.
223
+ // — so consulting the flags would drop the streamed summary from history on
224
+ // that provider.
210
225
  const providerOutcome = readStreamOutcome(err);
211
226
  const preserveProviderPartial =
212
227
  restoredResetText ||
@@ -252,15 +267,16 @@ export async function finalizeAskTurnFailure({
252
267
  releasePendingMessages(sessionId, turn.pendingEntries);
253
268
  }
254
269
  }
255
- if (!errorStateDurable && session) {
256
- try {
257
- errorStateDurable = (await settleAskCleanup(saveSessionAsync(session, { expectedGeneration: generation })))
258
- .settled;
259
- } catch {
260
- /* retain checkpoint when canonical persistence fails */
270
+ if (session) {
271
+ const save = holdFinalizedTurn({ sessionId, session, turnToken: turnCheckpointToken, generation });
272
+ if (save && !errorStateDurable) {
273
+ try {
274
+ await settleAskCleanup(save);
275
+ } catch {
276
+ /* the checkpoint stays until a save covering the turn lands */
277
+ }
261
278
  }
262
279
  }
263
- if (errorStateDurable) clearTurnCheckpoint(sessionId, turnCheckpointToken);
264
280
  logAskError(sessionId, err, providerOutcome);
265
281
  markSessionError(sessionId, err?.message ? err.message : String(err));
266
282
  }
@@ -1,25 +1,50 @@
1
1
  // manager/ask-turn-open.mjs
2
- // Opening one turn: load and reconcile the stored session and claim the
2
+ // Opening one turn: settle the previous turn's durability and the durable
3
+ // base this turn opens on (settleTurnBase, awaited before anything below),
4
+ // load and reconcile the stored session and claim the
3
5
  // runtime entry with a fresh abort controller (claimTurnRuntime), then arm
4
6
  // the turn's durability — the crash-checkpoint scheduler and the close
5
7
  // snapshot hook (armTurnDurability). Both are synchronous so closeSession()
6
8
  // cannot interleave between load and registration.
7
9
  import { randomUUID } from 'node:crypto';
8
- import { loadSession, saveSession, readSessionLifecycleFromDisk } from '../store.mjs';
10
+ import { loadSession } from '../store.mjs';
11
+ import { durableTranscriptBase } from '../store/transcript-durability.mjs';
9
12
  import { createAbortController } from '../../../../shared/abort-controller.mjs';
10
13
  import { normalizeStaleCompactingStage } from './compaction-runner.mjs';
11
14
  import { linkParentSignalToSession, markSessionAskStart, _touchRuntime } from './runtime-liveness.mjs';
12
15
  import { SessionClosedError } from './session-errors.mjs';
13
16
  import { ensureCodexWireSessionId, mintUuidV7 } from './session-id.mjs';
14
17
  import { createTurnInterruptionTracker } from './turn-interruption.mjs';
15
- import { clearTurnCheckpoint, recoverTurnCheckpoint } from './turn-checkpoint.mjs';
18
+ import { _recoverTurnCheckpointDurably, setAsideUnrecoveredCheckpoint } from './turn-checkpoint-recovery.mjs';
19
+ import { adoptDiskGeneration, awaitPreviousTurnDurable, ensureDurableTranscript } from './turn-durability.mjs';
16
20
  import { emitAskSessionStart } from './ask-support.mjs';
21
+ import { applyHeldSessionRoute } from './session-lifecycle.mjs';
17
22
  import { createAskTurnState, createCloseSnapshot, createTurnCheckpointScheduler } from './ask-turn-state.mjs';
18
23
 
24
+ /** Before a turn claims the session: the previous turn's finalized
25
+ * transcript is durably saved (its checkpoint deleted only then), a crashed
26
+ * turn's checkpoint is recovered (`recoverCheckpoint`, once per ask), and
27
+ * the transcript the turn opens on is the one a landed save holds — so the
28
+ * new checkpoint names a base that is on disk. Throws TurnPersistenceError
29
+ * when a save does not land; other sessions never wait on this one. */
30
+ export async function settleTurnBase(sessionId, { recoverCheckpoint }) {
31
+ await awaitPreviousTurnDurable(sessionId);
32
+ const session = loadSession(sessionId);
33
+ // claimTurnRuntime reports a missing or closed session.
34
+ if (!session || session.closed === true) return;
35
+ adoptDiskGeneration(session, sessionId);
36
+ if (recoverCheckpoint) _recoverTurnCheckpointDurably(session, sessionId);
37
+ await ensureDurableTranscript(session);
38
+ // This turn's checkpoint replaces the session's checkpoint file. Whatever
39
+ // is still there (a conflict, an unreadable header, a crashed turn this
40
+ // ask did not recover) is set aside first, never overwritten.
41
+ setAsideUnrecoveredCheckpoint(session, sessionId);
42
+ }
43
+
19
44
  /** Loads the session for a new turn and reconciles its on-disk lifecycle:
20
- * crash-checkpoint recovery (once per ask), a stale compacting stage, and
21
- * split-brain re-adoption of a disk generation another surface bumped. */
22
- function loadTurnSession(sessionId, { recoverCheckpoint }) {
45
+ * a stale compacting stage and split-brain re-adoption of a disk generation
46
+ * another surface bumped. */
47
+ function loadTurnSession(sessionId) {
23
48
  const session = loadSession(sessionId);
24
49
  if (!session) {
25
50
  throw new Error(`Session "${sessionId}" not found`);
@@ -28,44 +53,21 @@ function loadTurnSession(sessionId, { recoverCheckpoint }) {
28
53
  throw new SessionClosedError(sessionId, 'session already closed');
29
54
  }
30
55
  const codexWireSessionId = ensureCodexWireSessionId(session);
31
- if (recoverCheckpoint) {
32
- const recovery = recoverTurnCheckpoint(session);
33
- if (recovery.changed) {
34
- saveSession(session, {
35
- sync: true,
36
- expectedGeneration: session.generation,
37
- });
38
- if (recovery.turnToken) clearTurnCheckpoint(sessionId, recovery.turnToken);
39
- }
40
- }
41
56
  // A prior crash/partial-save during compaction may have pinned
42
57
  // compaction.lastStage='compacting'. This ask is starting fresh, so
43
58
  // recover the stale transient stage before the loop's pre-send compact
44
59
  // path runs (it will overwrite lastStage with real telemetry).
45
60
  normalizeStaleCompactingStage(session);
46
- // Split-brain re-adoption: another surface (e.g. desktop click-through
47
- // of a session still actively owned by this process) may have
48
- // resumed-and-detached this session, bumping the ON-DISK generation
49
- // while the conversation kept going here. Every save from this process
50
- // would then be silently dropped by _shouldDrop's ownership rule and
51
- // the on-disk transcript would freeze at the last landed save. A new
52
- // ask on a NON-closed session is an explicit ownership claim: adopt
53
- // the disk generation so this turn's commits land and heal the file.
54
- const diskLifecycle = readSessionLifecycleFromDisk(sessionId);
55
- if (
56
- diskLifecycle &&
57
- diskLifecycle.closed !== true &&
58
- diskLifecycle.generation > (typeof session.generation === 'number' ? session.generation : 0)
59
- ) {
60
- session.generation = diskLifecycle.generation;
61
- }
61
+ adoptDiskGeneration(session, sessionId);
62
+ // A route saved while the previous turn ran applies from this turn.
63
+ applyHeldSessionRoute(session);
62
64
  return { session, codexWireSessionId };
63
65
  }
64
66
 
65
67
  /** Loads the session and installs this turn's controller on the runtime
66
68
  * entry, re-cascading any parent abort link and marking the ask started. */
67
- export function claimTurnRuntime({ sessionId, askOpts, recoverCheckpoint, emitStart }) {
68
- const { session: preSession, codexWireSessionId } = loadTurnSession(sessionId, { recoverCheckpoint });
69
+ export function claimTurnRuntime({ sessionId, askOpts, emitStart }) {
70
+ const { session: preSession, codexWireSessionId } = loadTurnSession(sessionId);
69
71
  const askGeneration = typeof preSession.generation === 'number' ? preSession.generation : 0;
70
72
  const runtime = _touchRuntime(sessionId);
71
73
  // Preserve any parent-abort link agent-dispatch established BEFORE we
@@ -121,6 +123,7 @@ export function armTurnDurability({
121
123
  startedAt,
122
124
  turn,
123
125
  interruption,
126
+ base: durableTranscriptBase(preSession),
124
127
  });
125
128
  const prepareCloseSnapshot = createCloseSnapshot({ turn, interruption, checkpoint, runtime });
126
129
  // closeSession is synchronous and generation-first by design. Expose a
@@ -9,6 +9,7 @@ import { positiveInt } from '../../../../shared/numbers.mjs';
9
9
  import { appendAgentTrace } from '../../agent-trace.mjs';
10
10
  import { snapshotPendingDeferredToolDelta } from '../../runtime-core/deferred-tool-delta.mjs';
11
11
  import { snapshotPendingGoalReminder } from '../../runtime-core/goal-reminder.mjs';
12
+ import { beginTodoTurn, todoStartReminder } from '../loop/no-tool-turn/todo-check.mjs';
12
13
  import { resolveSessionContextMeta } from './context-meta.mjs';
13
14
  import {
14
15
  promptContentText,
@@ -20,6 +21,7 @@ import {
20
21
  snapshotPendingSetupNotice,
21
22
  } from './prompt-utils.mjs';
22
23
  import { snapshotPendingWorkflowNotice } from './workflow-switch-notice.mjs';
24
+ import { snapshotPendingPromptSettingsNotice } from './prompt-settings.mjs';
23
25
  import { snapshotPendingOrchestrationModeNotice } from './orchestration-mode-switch-notice.mjs';
24
26
  import { buildAgentListingNotice } from './agent-listing-notice.mjs';
25
27
  import { codexWireSendOpts } from './session-id.mjs';
@@ -175,6 +177,12 @@ export async function buildUserTurn({
175
177
  }
176
178
  const currentTimeBlock = buildCurrentTimeBlock(prompt);
177
179
  const deferredToolDelta = snapshotPendingDeferredToolDelta(session);
180
+ // A real prompt (no runtime source: not a Goal turn or task notification)
181
+ // opens a new todo reminder cycle; every turn clears the last turn's waits.
182
+ const genuinePrompt = !turnPromptSource?.source;
183
+ beginTodoTurn(session, { genuine: genuinePrompt });
184
+ // An agent's new brief or follow-up with no open list asks for one, once.
185
+ const todoStart = genuinePrompt ? todoStartReminder(session) : null;
178
186
  // Read paused state after hydration and queue selection, not at
179
187
  // input intake: either can precede the previous turn's pause.
180
188
  // This supplies context only; it never resumes the Goal.
@@ -192,8 +200,11 @@ export async function buildUserTurn({
192
200
  const orchestrationModeNotice = snapshotPendingOrchestrationModeNotice(session);
193
201
  // Agents enabled or switched off since the conversation was last told.
194
202
  const agentListingNotice = buildAgentListingNotice(session, currentAgents);
203
+ // Prompt-shaping settings changed since the prompt was built (told once).
204
+ const promptSettingsNotice = snapshotPendingPromptSettingsNotice(session);
195
205
  const reminderBlock = [
196
206
  workflowNotice?.content || '',
207
+ promptSettingsNotice?.content || '',
197
208
  orchestrationModeNotice?.content || '',
198
209
  agentListingNotice?.content || '',
199
210
  workspaceNotice?.content || '',
@@ -201,6 +212,7 @@ export async function buildUserTurn({
201
212
  currentTimeBlock ? `<system-reminder>\n# Current Time\n${currentTimeBlock}\n</system-reminder>` : '',
202
213
  deferredToolDelta?.content || '',
203
214
  goalReminder?.content || '',
215
+ todoStart || '',
204
216
  ]
205
217
  .filter(Boolean)
206
218
  .join('\n\n');
@@ -212,6 +224,8 @@ export async function buildUserTurn({
212
224
  ...(effortConfiguration ? { effortConfiguration } : {}),
213
225
  // What its reminder told, read back by later turns (agent-listing-notice.mjs).
214
226
  ...(agentListingNotice ? { agentListing: agentListingNotice.meta } : {}),
227
+ // A retry resubmits this message as is: it acknowledges the same notice.
228
+ ...(promptSettingsNotice ? { promptSettingsNoticeRevision: promptSettingsNotice.revision } : {}),
215
229
  };
216
230
  const userTurnMessage = withRuntimeUserContext(
217
231
  {
@@ -228,6 +242,7 @@ export async function buildUserTurn({
228
242
  goalReminder,
229
243
  workflowNotice,
230
244
  orchestrationModeNotice,
245
+ promptSettingsNotice,
231
246
  agentListingNotice,
232
247
  workspaceNotice,
233
248
  setupNotice,
@@ -10,6 +10,7 @@ import { acknowledgePendingDeferredToolDelta } from '../../runtime-core/deferred
10
10
  import { acknowledgePendingGoalReminder } from '../../runtime-core/goal-reminder.mjs';
11
11
  import { acknowledgePendingSetupNotice, acknowledgePendingWorkspaceNotice } from './prompt-utils.mjs';
12
12
  import { acknowledgePendingWorkflowNotice } from './workflow-switch-notice.mjs';
13
+ import { acknowledgePendingPromptSettingsNotice } from './prompt-settings.mjs';
13
14
  import { acknowledgePendingOrchestrationModeNotice } from './orchestration-mode-switch-notice.mjs';
14
15
  import {
15
16
  finalizePendingMessageDelivery,
@@ -20,7 +21,7 @@ import { applyAskTerminalUsageTotals } from './usage-metrics.mjs';
20
21
  import { markSessionDone, markSessionEmptyFinal, _getRuntimeEntry } from './runtime-liveness.mjs';
21
22
  import { SessionClosedError } from './session-errors.mjs';
22
23
  import { filterModelVisibleSessionMessages } from './message-sanitize.mjs';
23
- import { clearTurnCheckpoint } from './turn-checkpoint.mjs';
24
+ import { holdTurnUntilDurable } from './turn-durability.mjs';
24
25
  import { recordProviderContextBaseline } from '../loop/compact-policy.mjs';
25
26
  import { throwIfAborted } from '../../../../shared/abort-race.mjs';
26
27
  import { appendAssistantTurnMessage, persistProviderState, recordAskUsage } from './ask-turn-commit.mjs';
@@ -94,7 +95,7 @@ export function attachFailedTurnCompletion(messages, completion) {
94
95
  /** Commits the loop result into the session: messages, usage, provider state
95
96
  * and queue acknowledgements. Returns the terminal result preview. */
96
97
  export async function commitAskTurn({ sessionId, opened, prepared, result, rawTranscriptMeta, askStartedAt }) {
97
- const { turn, runtime, turnSignal, askGeneration, checkpoint, prepareCloseSnapshot } = opened;
98
+ const { turn, runtime, turnSignal, askGeneration, prepareCloseSnapshot } = opened;
98
99
  const session = turn.session;
99
100
  throwIfAborted(turnSignal);
100
101
  // Post-loop validation: if closeSession() landed while we were awaiting,
@@ -111,7 +112,8 @@ export async function commitAskTurn({ sessionId, opened, prepared, result, rawTr
111
112
  // Turn committed into session.messages; drop the live-turn alias so
112
113
  // contextStatus() reverts to the authoritative committed transcript.
113
114
  session.liveTurnMessages = null;
114
- checkpoint.stop();
115
+ // The checkpoint keeps recording until publishAskTurn seals the finished
116
+ // transcript into it.
115
117
  delete session.activeTurnCheckpoint;
116
118
  appendAssistantTurnMessage({
117
119
  session,
@@ -142,6 +144,9 @@ export async function commitAskTurn({ sessionId, opened, prepared, result, rawTr
142
144
  acknowledgePendingGoalReminder(session, prepared.goalReminder.revision);
143
145
  }
144
146
  if (prepared.workflowNotice) acknowledgePendingWorkflowNotice(session, prepared.workflowNotice.revision);
147
+ if (prepared.promptSettingsNotice) {
148
+ acknowledgePendingPromptSettingsNotice(session, prepared.promptSettingsNotice.revision);
149
+ }
145
150
  if (prepared.orchestrationModeNotice) {
146
151
  acknowledgePendingOrchestrationModeNotice(session, prepared.orchestrationModeNotice.revision);
147
152
  }
@@ -160,7 +165,7 @@ export async function commitAskTurn({ sessionId, opened, prepared, result, rawTr
160
165
  * starts the durable save and marks the session done. Returns the
161
166
  * follow-up entries drained right after the provider accepted the turn. */
162
167
  export function publishAskTurn({ sessionId, opened, terminalResultPreview, askOpts, rawTranscriptMeta, askStartedAt }) {
163
- const { turn, runtime, askGeneration, turnToken } = opened;
168
+ const { turn, runtime, askGeneration, turnToken, checkpoint } = opened;
164
169
  const session = turn.session;
165
170
  // The provider accepted this queued turn: only now remove its
166
171
  // durable ids. A crash before here leaves them for at-least-once
@@ -197,19 +202,23 @@ export function publishAskTurn({ sessionId, opened, terminalResultPreview, askOp
197
202
  // query/provider send (agentLoop pre-send), not after the previous
198
203
  // answer. This lets queued follow-up prompts resume immediately;
199
204
  // if they need compaction, their own spinner shows compacting first.
200
- // Fire-and-forget terminal save. The result is already produced and
201
- // (for agent surfaces) relayed via onTerminalResult above. When
202
- // completion was relayed to the UI, yield before postMessage
203
- // structured-clones the full session. Queued follow-up turns retain
204
- // the original immediate-save ordering; they did not inject a
205
- // terminal card and may mutate this same session on the next loop.
205
+ // The finished transcript (final assistant message, completion) is sealed
206
+ // into the checkpoint, and the record the terminal save writes names the
207
+ // turn it covers: a crash before that save lands replays the sealed turn,
208
+ // one after it deletes the checkpoint without a duplicate.
209
+ session.turnCoverage = turnToken;
210
+ checkpoint.seal();
211
+ // Terminal save. The result is already produced and (for agent surfaces)
212
+ // relayed via onTerminalResult above. When completion was relayed to the
213
+ // UI, yield before postMessage structured-clones the full session. Queued
214
+ // follow-up turns retain the original immediate-save ordering. Its landed
215
+ // acknowledgement is this session's next-turn gate (turn-durability.mjs),
216
+ // which alone deletes the checkpoint.
206
217
  const saveTerminalSession = terminalRelayed ? saveSessionAsyncDeferred : saveSessionAsync;
207
218
  const terminalSave = saveTerminalSession(session, { expectedGeneration: askGeneration });
219
+ holdTurnUntilDurable({ sessionId, session, turnToken, generation: askGeneration, save: terminalSave });
208
220
  terminalSave.then(
209
- () => {
210
- clearTurnCheckpoint(sessionId, turnToken);
211
- ingestSessionTurn(session);
212
- },
221
+ () => ingestSessionTurn(session),
213
222
  () => {}
214
223
  );
215
224
  finalizePendingMessageDelivery(session, turn.pendingEntries, terminalSave, () =>
@@ -227,7 +236,8 @@ export function publishAskTurn({ sessionId, opened, terminalResultPreview, askOp
227
236
  const isEmptyFinal =
228
237
  !terminalResultPreview.content &&
229
238
  !terminalResultPreview.reasoningContent &&
230
- !terminalResultPreview.reactionCompleted;
239
+ !terminalResultPreview.reactionCompleted &&
240
+ !terminalResultPreview.reportContent;
231
241
  if (isEmptyFinal) {
232
242
  markSessionEmptyFinal(sessionId);
233
243
  }