mixdog 0.9.152 → 0.9.154

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 (300) hide show
  1. package/LICENSES/browser-import-NOTICE.txt +11 -0
  2. package/NOTICE.md +11 -0
  3. package/README.md +8 -10
  4. package/package.json +19 -3
  5. package/scripts/computer-task-cost-report.mjs +144 -0
  6. package/scripts/run-office-live-tests.mjs +32 -0
  7. package/src/agents/front-worker/AGENT.md +13 -0
  8. package/src/agents/front-worker/agent.json +6 -0
  9. package/src/agents/heavy-worker/AGENT.md +10 -11
  10. package/src/agents/heavy-worker/agent.json +1 -1
  11. package/src/agents/maintainer/AGENT.md +0 -2
  12. package/src/agents/reviewer/AGENT.md +9 -13
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/agents/security/AGENT.md +14 -0
  15. package/src/agents/security/agent.json +6 -0
  16. package/src/agents/worker/AGENT.md +8 -8
  17. package/src/agents/worker/agent.json +1 -1
  18. package/src/agents/writer/AGENT.md +14 -0
  19. package/src/agents/writer/agent.json +6 -0
  20. package/src/rules/agent/00-common.md +4 -7
  21. package/src/rules/lead/01-general.md +0 -3
  22. package/src/rules/shared/10-tool-workflow.md +10 -2
  23. package/src/rules/shared/60-verification.md +2 -0
  24. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
  25. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
  26. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
  27. package/src/runtime/agent/orchestrator/config.mjs +7 -2
  28. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
  29. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -1
  30. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
  31. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
  32. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +25 -2
  33. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -10
  34. package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
  35. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
  36. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +140 -86
  37. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +9 -13
  38. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +72 -4
  39. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
  40. package/src/runtime/agent/orchestrator/session/compact/handoff.mjs +0 -22
  41. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -2
  42. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +11 -23
  43. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +28 -269
  44. package/src/runtime/agent/orchestrator/session/compact.mjs +0 -6
  45. package/src/runtime/agent/orchestrator/session/context-utils.mjs +86 -11
  46. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
  47. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
  48. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
  49. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
  50. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +80 -18
  51. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
  52. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +3 -0
  53. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
  54. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +80 -21
  55. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +33 -72
  56. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +21 -2
  57. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +25 -51
  58. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
  59. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
  60. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +39 -15
  61. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +14 -4
  62. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +41 -8
  63. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
  64. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +2 -2
  65. package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
  66. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
  67. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
  68. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
  69. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
  70. package/src/runtime/agent/orchestrator/session/store.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
  72. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
  73. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +4 -0
  74. package/src/runtime/attachments/pdf-extract.mjs +3 -0
  75. package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
  76. package/src/runtime/browser-bridge/action-schema.mjs +251 -0
  77. package/src/runtime/browser-bridge/client.mjs +75 -26
  78. package/src/runtime/browser-bridge/tool-defs.mjs +132 -15
  79. package/src/runtime/computer-bridge/action-schema.mjs +653 -0
  80. package/src/runtime/computer-bridge/client.mjs +211 -28
  81. package/src/runtime/computer-bridge/tool-defs.mjs +25 -45
  82. package/src/runtime/office/assurance-benchmark.mjs +358 -0
  83. package/src/runtime/office/assurance.mjs +833 -0
  84. package/src/runtime/office/benchmark.mjs +496 -0
  85. package/src/runtime/office/capabilities.mjs +551 -0
  86. package/src/runtime/office/com-adapter.mjs +283 -0
  87. package/src/runtime/office/content-model.mjs +183 -0
  88. package/src/runtime/office/contract-benchmark.mjs +105 -0
  89. package/src/runtime/office/design-library.mjs +1562 -0
  90. package/src/runtime/office/design-system.mjs +1966 -0
  91. package/src/runtime/office/index.mjs +2413 -0
  92. package/src/runtime/office/journal.mjs +82 -0
  93. package/src/runtime/office/office-com-host.ps1 +3781 -0
  94. package/src/runtime/office/office-com-session-host.ps1 +855 -0
  95. package/src/runtime/office/ooxml-validator.mjs +271 -0
  96. package/src/runtime/office/pagination.mjs +132 -0
  97. package/src/runtime/office/pdf-adapter.mjs +591 -0
  98. package/src/runtime/office/pdf-analysis.mjs +372 -0
  99. package/src/runtime/office/pdf-render.mjs +167 -0
  100. package/src/runtime/office/pdf-security.mjs +63 -0
  101. package/src/runtime/office/polish-benchmark.mjs +190 -0
  102. package/src/runtime/office/portable-ooxml.mjs +1867 -0
  103. package/src/runtime/office/quality-live-benchmark.mjs +486 -0
  104. package/src/runtime/office/quality-pipeline.mjs +136 -0
  105. package/src/runtime/office/tabular.mjs +302 -0
  106. package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
  107. package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
  108. package/src/runtime/office/tool-defs.mjs +113 -0
  109. package/src/runtime/office/visual-diff.mjs +89 -0
  110. package/src/runtime/office/xlsx-assertions.mjs +172 -0
  111. package/src/runtime/office/xlsx-contract.mjs +147 -0
  112. package/src/runtime/shared/agent-route-config.mjs +9 -0
  113. package/src/runtime/shared/tool-execution-contract.mjs +16 -0
  114. package/src/runtime/shared/tool-surface.mjs +9 -0
  115. package/src/session-runtime/context-status.mjs +9 -3
  116. package/src/session-runtime/deferred-tool-delta.mjs +104 -0
  117. package/src/session-runtime/goal-runtime.mjs +617 -197
  118. package/src/session-runtime/lifecycle-api.mjs +50 -8
  119. package/src/session-runtime/provider-request-snapshot.mjs +33 -9
  120. package/src/session-runtime/resource-api.mjs +31 -94
  121. package/src/session-runtime/runtime-core.mjs +78 -26
  122. package/src/session-runtime/session-lifecycle.mjs +34 -12
  123. package/src/session-runtime/session-title.mjs +2 -2
  124. package/src/session-runtime/session-turn-api.mjs +15 -14
  125. package/src/session-runtime/tool-catalog-data.mjs +1 -1
  126. package/src/session-runtime/tool-catalog.mjs +38 -99
  127. package/src/session-runtime/tool-defs.mjs +6 -1
  128. package/src/session-runtime/tool-surface.mjs +18 -8
  129. package/src/session-runtime/workflow-agents-api.mjs +8 -25
  130. package/src/session-runtime/workflow.mjs +8 -6
  131. package/src/standalone/agent-tool/helpers.mjs +2 -2
  132. package/src/standalone/agent-tool/job-views.mjs +3 -1
  133. package/src/standalone/agent-tool/notify.mjs +5 -1
  134. package/src/standalone/agent-tool/render.mjs +3 -0
  135. package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
  136. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  137. package/src/standalone/agent-tool/worker-index.mjs +123 -0
  138. package/src/standalone/agent-tool/worker-rows.mjs +2 -1
  139. package/src/standalone/agent-tool.mjs +57 -10
  140. package/src/standalone/daemon.mjs +105 -6
  141. package/src/standalone/session-runtime-host.mjs +61 -48
  142. package/src/standalone/session-runtime-inline-host.mjs +34 -127
  143. package/src/standalone/session-runtime-worker.mjs +20 -198
  144. package/src/standalone/session-service.mjs +632 -7
  145. package/src/tui/dist/index.mjs +24 -1
  146. package/src/tui/lib/voice-setup.mjs +4 -1
  147. package/src/tui/session/context-state.mjs +2 -13
  148. package/src/tui/session/goal-continuation.mjs +38 -7
  149. package/src/tui/session/session-api-ext.mjs +9 -0
  150. package/src/tui/session/session-api.mjs +15 -1
  151. package/src/tui/session/session-flow.mjs +25 -1
  152. package/src/tui/session/turn.mjs +88 -16
  153. package/src/tui/session-local.mjs +25 -3
  154. package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
  155. package/scripts/generate-voice-runtime-manifest.test.mjs +0 -135
  156. package/scripts/native-binary-arch.test.mjs +0 -111
  157. package/scripts/patch-replay.test.mjs +0 -94
  158. package/src/headless-exec.test.mjs +0 -539
  159. package/src/runtime/agent/orchestrator/agent-trace-timing.test.mjs +0 -57
  160. package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +0 -153
  161. package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +0 -139
  162. package/src/runtime/agent/orchestrator/mcp/features.test.mjs +0 -66
  163. package/src/runtime/agent/orchestrator/mcp/security.test.mjs +0 -80
  164. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +0 -90
  165. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +0 -215
  166. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.test.mjs +0 -165
  167. package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +0 -142
  168. package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +0 -153
  169. package/src/runtime/agent/orchestrator/providers/openai-codex-model.test.mjs +0 -24
  170. package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +0 -190
  171. package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +0 -235
  172. package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +0 -719
  173. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.test.mjs +0 -40
  174. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +0 -176
  175. package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +0 -161
  176. package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +0 -115
  177. package/src/runtime/agent/orchestrator/session/evidence-union.test.mjs +0 -228
  178. package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +0 -245
  179. package/src/runtime/agent/orchestrator/session/lossless-tool-output.test.mjs +0 -125
  180. package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +0 -325
  181. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +0 -70
  182. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +0 -457
  183. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.test.mjs +0 -117
  184. package/src/runtime/agent/orchestrator/session/reduction-metrics.test.mjs +0 -87
  185. package/src/runtime/agent/orchestrator/session/store/serialize.test.mjs +0 -60
  186. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +0 -583
  187. package/src/runtime/agent/orchestrator/session/task-wait-control.test.mjs +0 -78
  188. package/src/runtime/agent/orchestrator/tools/builtin/absence-absorption.test.mjs +0 -43
  189. package/src/runtime/agent/orchestrator/tools/builtin/absolute-glob-expand.test.mjs +0 -63
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +0 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +0 -224
  192. package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +0 -224
  193. package/src/runtime/agent/orchestrator/tools/builtin/enoent-outside-project.test.mjs +0 -56
  194. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +0 -103
  195. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.test.mjs +0 -30
  196. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +0 -390
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.test.mjs +0 -83
  198. package/src/runtime/agent/orchestrator/tools/builtin/grep-output-budget.test.mjs +0 -31
  199. package/src/runtime/agent/orchestrator/tools/builtin/grep-single-file-rescue.test.mjs +0 -106
  200. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.test.mjs +0 -102
  201. package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +0 -152
  202. package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +0 -24
  203. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +0 -24
  204. package/src/runtime/agent/orchestrator/tools/builtin/noise-dir-visibility.test.mjs +0 -69
  205. package/src/runtime/agent/orchestrator/tools/builtin/read-glob-survey.test.mjs +0 -71
  206. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.test.mjs +0 -56
  207. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.test.mjs +0 -16
  208. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-top-k.test.mjs +0 -39
  209. package/src/runtime/agent/orchestrator/tools/builtin/write-symlink.test.mjs +0 -153
  210. package/src/runtime/agent/orchestrator/tools/code-graph/aggregate-anchor-relocation.test.mjs +0 -55
  211. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +0 -88
  212. package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +0 -72
  213. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +0 -54
  214. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.test.mjs +0 -20
  215. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +0 -55
  216. package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +0 -268
  217. package/src/runtime/agent/orchestrator/tools/env-scrub.test.mjs +0 -57
  218. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.test.mjs +0 -19
  219. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +0 -104
  220. package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +0 -661
  221. package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +0 -552
  222. package/src/runtime/agent/orchestrator/tools/patch/patch-symlink.test.mjs +0 -141
  223. package/src/runtime/agent/orchestrator/tools/patch/v4a-pure-move.test.mjs +0 -57
  224. package/src/runtime/agent/orchestrator/tools/patch/v4a-section-coalesce.test.mjs +0 -81
  225. package/src/runtime/agent/orchestrator/tools/spawn-binary-fetcher.test.mjs +0 -52
  226. package/src/runtime/attachments/store.test.mjs +0 -209
  227. package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +0 -17
  228. package/src/runtime/channels/lib/webhook/deliveries.test.mjs +0 -18
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.test.mjs +0 -68
  230. package/src/runtime/media/adapters/codex-image.test.mjs +0 -22
  231. package/src/runtime/media/download.test.mjs +0 -52
  232. package/src/runtime/media/renditions.test.mjs +0 -99
  233. package/src/runtime/media/store.test.mjs +0 -159
  234. package/src/runtime/memory/lib/archive-security.test.mjs +0 -128
  235. package/src/runtime/memory/lib/embedding-model-config.test.mjs +0 -33
  236. package/src/runtime/memory/lib/http-wire.test.mjs +0 -15
  237. package/src/runtime/memory/lib/memory-cycle-packets.test.mjs +0 -49
  238. package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +0 -78
  239. package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +0 -50
  240. package/src/runtime/memory/lib/pg/process.test.mjs +0 -36
  241. package/src/runtime/memory/lib/trace-store.test.mjs +0 -57
  242. package/src/runtime/memory/lib/transcript-ingest.test.mjs +0 -52
  243. package/src/runtime/shared/background-tasks.test.mjs +0 -78
  244. package/src/runtime/shared/bounded-download.test.mjs +0 -41
  245. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -25
  246. package/src/runtime/shared/child-spawn-remote.test.mjs +0 -124
  247. package/src/runtime/shared/remote-intent.test.mjs +0 -40
  248. package/src/runtime/shared/resource-admission.test.mjs +0 -43
  249. package/src/runtime/shared/runtime-root.test.mjs +0 -34
  250. package/src/runtime/shared/schedule-time.test.mjs +0 -29
  251. package/src/runtime/shared/session-runtime-health.test.mjs +0 -83
  252. package/src/runtime/shared/skill-document.test.mjs +0 -81
  253. package/src/runtime/shared/tool-surface.test.mjs +0 -87
  254. package/src/runtime/shared/update-checker.test.mjs +0 -33
  255. package/src/runtime/shared/user-cwd.test.mjs +0 -43
  256. package/src/runtime/shared/webhook-session-run.test.mjs +0 -14
  257. package/src/session-runtime/agent-disable.test.mjs +0 -123
  258. package/src/session-runtime/cwd-plugins.test.mjs +0 -75
  259. package/src/session-runtime/cwd-tool-routing.test.mjs +0 -61
  260. package/src/session-runtime/global-extensions.test.mjs +0 -28
  261. package/src/session-runtime/goal-runtime.test.mjs +0 -108
  262. package/src/session-runtime/lifecycle-api.test.mjs +0 -21
  263. package/src/session-runtime/model-settings-persist.test.mjs +0 -105
  264. package/src/session-runtime/notification-bus.test.mjs +0 -148
  265. package/src/session-runtime/plugin-mcp-standard.test.mjs +0 -177
  266. package/src/session-runtime/prewarm.test.mjs +0 -52
  267. package/src/session-runtime/provider-request-snapshot.test.mjs +0 -37
  268. package/src/session-runtime/resource-api-global.test.mjs +0 -69
  269. package/src/session-runtime/session-lifecycle.test.mjs +0 -125
  270. package/src/session-runtime/session-title.test.mjs +0 -36
  271. package/src/session-runtime/skills-api.test.mjs +0 -99
  272. package/src/session-runtime/tool-policy-surface.test.mjs +0 -331
  273. package/src/standalone/agent-tool/helpers.test.mjs +0 -62
  274. package/src/standalone/agent-tool/notify.test.mjs +0 -37
  275. package/src/standalone/agent-tool/spawn-flow.test.mjs +0 -63
  276. package/src/standalone/channel-restart.test.mjs +0 -145
  277. package/src/standalone/channel-session-router.test.mjs +0 -37
  278. package/src/standalone/channel-worker-heartbeat.test.mjs +0 -30
  279. package/src/standalone/hook-bus/handlers.test.mjs +0 -88
  280. package/src/standalone/plugin-admin.test.mjs +0 -173
  281. package/src/standalone/session-runtime-agent-control-client.test.mjs +0 -71
  282. package/src/standalone/session-runtime-dispatch-cancel.test.mjs +0 -139
  283. package/src/standalone/session-runtime-host-factory.test.mjs +0 -31
  284. package/src/standalone/session-runtime-host-health.test.mjs +0 -160
  285. package/src/standalone/session-runtime-inline-host.test.mjs +0 -83
  286. package/src/standalone/session-runtime-provider-cooldown.test.mjs +0 -80
  287. package/src/standalone/session-runtime-shard-host.test.mjs +0 -569
  288. package/src/standalone/session-runtime-shard-router.test.mjs +0 -101
  289. package/src/tui/app/live-spinner-visibility.test.mjs +0 -44
  290. package/src/tui/app/panel-epoch.test.mjs +0 -1009
  291. package/src/tui/app/panel-handoff.test.mjs +0 -311
  292. package/src/tui/app/prompt-submit.test.mjs +0 -206
  293. package/src/tui/session/completion-card-restore.test.mjs +0 -111
  294. package/src/tui/session/goal-continuation.test.mjs +0 -84
  295. package/src/tui/session/oauth-flows.test.mjs +0 -134
  296. package/src/tui/session/queue-helpers.test.mjs +0 -46
  297. package/src/tui/session/session-action-surface.test.mjs +0 -108
  298. package/src/tui/session/task-wait-submit.test.mjs +0 -80
  299. package/src/tui/session/tool-result-status.test.mjs +0 -131
  300. package/src/tui/session/tui-steering-persist.test.mjs +0 -104
@@ -3878,6 +3878,8 @@ function displayToolName(name, args = {}) {
3878
3878
  return "Browser";
3879
3879
  case "computer":
3880
3880
  return "Computer";
3881
+ case "office":
3882
+ return "Office";
3881
3883
  case "list_mcp_resources":
3882
3884
  case "list_mcp_resource_templates":
3883
3885
  case "cwd":
@@ -4008,6 +4010,11 @@ function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}) {
4008
4010
  String(a.action || ""),
4009
4011
  a.window ? truncateToolText(a.window, max) : a.ref ? String(a.ref) : a.app ? truncateToolText(a.app, max) : ""
4010
4012
  ]);
4013
+ case "office":
4014
+ return compactParts([
4015
+ String(a.action || ""),
4016
+ a.path ? truncateToolText(a.path, max) : a.session ? String(a.session) : ""
4017
+ ]);
4011
4018
  case "read_mcp_resource":
4012
4019
  return truncateToolText(a.uri || "", max);
4013
4020
  case "list_mcp_resources":
@@ -4276,6 +4283,8 @@ function toolWorkUnit(name, args = {}, category = "") {
4276
4283
  return unitDescriptor("Browser", { count: 1, active: "Browsing", done: "Browsed", noun: "action" });
4277
4284
  case "computer":
4278
4285
  return unitDescriptor("Computer", { count: 1, active: "Operating", done: "Operated", noun: "action" });
4286
+ case "office":
4287
+ return unitDescriptor("Office", { count: 1, active: "Editing", done: "Edited", noun: "document action" });
4279
4288
  case "fetch": {
4280
4289
  const fetchLimit = Number(a.limit ?? a.messages);
4281
4290
  const fetchCount = Number.isFinite(fetchLimit) && fetchLimit > 0 ? Math.floor(fetchLimit) : queryCount(a, "messages") || 1;
@@ -5294,6 +5303,16 @@ import { join as join7 } from "node:path";
5294
5303
  init_plugin_paths();
5295
5304
  init_config();
5296
5305
 
5306
+ // src/runtime/shared/agent-route-config.mjs
5307
+ var DEFAULT_DISABLED_AGENT_IDS = Object.freeze([
5308
+ "worker",
5309
+ "heavy-worker",
5310
+ "reviewer",
5311
+ "security",
5312
+ "front-worker",
5313
+ "writer"
5314
+ ]);
5315
+
5297
5316
  // src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs
5298
5317
  init_plugin_paths();
5299
5318
  import { join as join6 } from "node:path";
@@ -20708,8 +20727,9 @@ function makeThrottledProgressNotice({ pushNotice, setProgressHint } = {}, inter
20708
20727
  const total = Number(progress.total) || 0;
20709
20728
  const downloaded = Number(progress.downloaded) || 0;
20710
20729
  const text = renderProgressBarText(progress.phase, downloaded, total);
20730
+ const percent2 = total > 0 ? Math.max(0, Math.min(100, Math.round(downloaded / total * 100))) : void 0;
20711
20731
  if (typeof setProgressHint === "function") {
20712
- setProgressHint(text, "info");
20732
+ setProgressHint(text, "info", percent2);
20713
20733
  return;
20714
20734
  }
20715
20735
  if (typeof pushNotice === "function") pushNotice(text, "info");
@@ -24113,6 +24133,9 @@ import {
24113
24133
  } from "node:fs/promises";
24114
24134
  import { join as join9 } from "node:path";
24115
24135
 
24136
+ // src/runtime/attachments/pdfjs-runtime.mjs
24137
+ import { definePDFJSModule } from "unpdf";
24138
+
24116
24139
  // src/runtime/attachments/pdf-extract.mjs
24117
24140
  var DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
24118
24141
 
@@ -98,8 +98,11 @@ function makeThrottledProgressNotice({ pushNotice, setProgressHint } = {}, inter
98
98
  const total = Number(progress.total) || 0;
99
99
  const downloaded = Number(progress.downloaded) || 0;
100
100
  const text = renderProgressBarText(progress.phase, downloaded, total);
101
+ const percent = total > 0
102
+ ? Math.max(0, Math.min(100, Math.round((downloaded / total) * 100)))
103
+ : undefined;
101
104
  if (typeof setProgressHint === 'function') {
102
- setProgressHint(text, 'info');
105
+ setProgressHint(text, 'info', percent);
103
106
  return;
104
107
  }
105
108
  if (typeof pushNotice === 'function') pushNotice(text, 'info');
@@ -94,7 +94,6 @@ export function createContextState({ runtime, getState, updateState, getPendingS
94
94
  const syncContextStats = ({
95
95
  allowEstimated = false,
96
96
  invalidateExact = false,
97
- compactedEstimateTokens = null,
98
97
  } = {}) => {
99
98
  if (getPendingSessionReset()) return null;
100
99
  const ctx = runtime.contextStatus?.() || null;
@@ -118,24 +117,14 @@ export function createContextState({ runtime, getState, updateState, getPendingS
118
117
  updateState({ stats });
119
118
  return ctx;
120
119
  }
121
- // A compact completion already carries the estimate measured from the
122
- // replacement transcript. Prefer it for this publication instead of
123
- // letting a lagging contextStatus/provider snapshot repaint the deleted
124
- // pre-compact prefix until the next request lands.
125
- const compactedEstimate = Number(compactedEstimateTokens);
126
- const hasCompactedEstimate = compactedEstimateTokens != null
127
- && Number.isFinite(compactedEstimate)
128
- && compactedEstimate > 0;
129
- const estimatedTokens = hasCompactedEstimate
130
- ? compactedEstimate
131
- : Math.max(0, Number(ctx.currentEstimatedTokens ?? ctx.usedTokens ?? 0));
120
+ const estimatedTokens = Math.max(0, Number(ctx.currentEstimatedTokens ?? ctx.usedTokens ?? 0));
132
121
  const usedTokens = Math.max(0, Number(ctx.usedTokens ?? estimatedTokens ?? 0));
133
122
  const usedSource = String(ctx.usedSource || '').toLowerCase();
134
123
  // A successful pre-send auto-compact rewrites the transcript before the
135
124
  // next provider request can publish fresh usage. Never keep painting the
136
125
  // exact token count measured against the deleted pre-compact prefix during
137
126
  // that gap; publish the compacted transcript estimate immediately.
138
- const forceEstimated = hasCompactedEstimate || (invalidateExact && estimatedTokens > 0);
127
+ const forceEstimated = invalidateExact && estimatedTokens > 0;
139
128
  const shouldPublishEstimate = allowEstimated && (
140
129
  usedSource === 'estimated'
141
130
  || Number(ctx.currentEstimatedTokens) > 0
@@ -16,6 +16,7 @@ export function createGoalContinuation({
16
16
  } = {}) {
17
17
  let scheduled = null;
18
18
  let disposed = false;
19
+ let suppressedCompletedGoalId = '';
19
20
 
20
21
  const cancelQueuedGoalContinuations = () => {
21
22
  const pending = getPending();
@@ -28,8 +29,14 @@ export function createGoalContinuation({
28
29
  return removed;
29
30
  };
30
31
 
32
+ const visibleGoal = (goal) => (
33
+ goal?.status === 'complete' && clean(goal.id) === suppressedCompletedGoalId
34
+ ? null
35
+ : goal || null
36
+ );
37
+
31
38
  const refreshGoalState = () => {
32
- const goal = runtime.goalStatus?.() || null;
39
+ const goal = visibleGoal(runtime.goalStatus?.() || null);
33
40
  if (getState().goal !== goal) set({ goal });
34
41
  return goal;
35
42
  };
@@ -80,8 +87,9 @@ export function createGoalContinuation({
80
87
  const currentSessionId = clean(getState().sessionId || runtime.id);
81
88
  if (clean(event.sessionId) && clean(event.sessionId) !== currentSessionId) return;
82
89
  cancelQueuedGoalContinuations();
83
- set({ goal: event.goal || runtime.goalStatus?.() || null });
84
- if ((event.goal || runtime.goalStatus?.())?.status === 'active') scheduleGoalContinuation();
90
+ const goal = visibleGoal(event.goal || runtime.goalStatus?.() || null);
91
+ set({ goal });
92
+ if (goal?.status === 'active') scheduleGoalContinuation();
85
93
  };
86
94
 
87
95
  const unsubscribe = runtime.onGoalStatusChange?.(onGoalChanged) || (() => {});
@@ -91,14 +99,37 @@ export function createGoalContinuation({
91
99
  refreshGoalState,
92
100
  scheduleGoalContinuation,
93
101
  shouldRunGoalContinuation,
94
- onGoalTurnSettled(status) {
95
- if (status === 'done') scheduleGoalContinuation();
102
+ async onGoalTurnStarted() {
103
+ const goal = await Promise.resolve(runtime.goalTurnStarted?.());
104
+ if (goal !== undefined && getState().goal !== goal) set({ goal: goal || null });
105
+ return goal;
106
+ },
107
+ async onGoalTurnSettled(detail = {}) {
108
+ const status = clean(typeof detail === 'string' ? detail : detail.status).toLowerCase();
109
+ const goal = await Promise.resolve(runtime.goalTurnSettled?.(
110
+ typeof detail === 'string' ? { status } : detail,
111
+ ));
112
+ if (goal !== undefined && getState().goal !== goal) set({ goal: goal || null });
113
+ if (status === 'done' && goal?.status === 'active') scheduleGoalContinuation();
114
+ return goal;
96
115
  },
97
116
  archiveCompletedGoalOnUserInput() {
98
117
  cancelQueuedGoalContinuations();
118
+ const currentGoal = getState().goal || runtime.goalStatus?.() || null;
119
+ const archivedGoalId = currentGoal?.status === 'complete' ? clean(currentGoal.id) : '';
120
+ if (archivedGoalId) {
121
+ suppressedCompletedGoalId = archivedGoalId;
122
+ set({ goal: null });
123
+ }
99
124
  void Promise.resolve(runtime.archiveCompletedGoalOnUserInput?.())
100
- .then(() => refreshGoalState())
101
- .catch(() => {});
125
+ .then(() => {
126
+ if (suppressedCompletedGoalId === archivedGoalId) suppressedCompletedGoalId = '';
127
+ refreshGoalState();
128
+ })
129
+ .catch(() => {
130
+ if (suppressedCompletedGoalId === archivedGoalId) suppressedCompletedGoalId = '';
131
+ refreshGoalState();
132
+ });
102
133
  },
103
134
  disposeGoalContinuation() {
104
135
  disposed = true;
@@ -12,6 +12,7 @@ import { aggregateToolCategoryEntries, aggregateDoneCategories, classifyToolCate
12
12
  import { aggregateBucketForCategory, aggregateRawResult, aggregateToolMembers, failureDetailText, toolCallOutcome } from './tool-result-status.mjs';
13
13
  import {
14
14
  isInternalTranscriptDisplayText,
15
+ isTranscriptHiddenControlToolName,
15
16
  isTranscriptCancelledStatusText,
16
17
  } from '../../runtime/shared/tool-execution-contract.mjs';
17
18
  import { toolResultTerminalStatus } from '../../runtime/shared/tool-status.mjs';
@@ -40,6 +41,7 @@ export function restoredTranscriptMetadata(message) {
40
41
  ...(typeof value.model === 'string' && value.model ? { model: value.model } : {}),
41
42
  ...(typeof value.provider === 'string' && value.provider ? { provider: value.provider } : {}),
42
43
  ...(typeof value.agent === 'string' && value.agent ? { agent: value.agent } : {}),
44
+ ...(typeof value.sender === 'string' && value.sender ? { sender: value.sender } : {}),
43
45
  ...(completion ? { completion } : {}),
44
46
  };
45
47
  }
@@ -71,6 +73,7 @@ function restoredToolCallItems(message, nextId, pendingByCallId) {
71
73
  const items = [];
72
74
  for (const call of calls) {
73
75
  const name = String(call?.function?.name || call?.name || 'tool').trim() || 'tool';
76
+ if (isTranscriptHiddenControlToolName(name)) continue;
74
77
  let args = call?.function?.arguments ?? call?.arguments;
75
78
  if (typeof args === 'string') {
76
79
  try { args = JSON.parse(args); } catch { /* keep the raw string args */ }
@@ -1091,6 +1094,12 @@ export function createSessionApiB(bag) {
1091
1094
  }
1092
1095
  },
1093
1096
 
1097
+ deliverToolCompletion: (sessionId, text, meta = {}) =>
1098
+ runtime.deliverToolCompletion?.(sessionId, text, meta) === true,
1099
+
1100
+ closeCanonicalSession: (reason = 'canonical-session-close') =>
1101
+ runtime.closeCanonicalSession?.(reason) === true,
1102
+
1094
1103
  dispose: async (reason = 'cli-react-exit', options = {}) => {
1095
1104
  if (flags.disposed) return;
1096
1105
  disposeEmit?.();
@@ -86,6 +86,7 @@ export function createSessionApiA(bag) {
86
86
  // normal post-tool boundary, where this queued prompt is injected.
87
87
  if (accepted !== false) {
88
88
  if ((intake.queueOptions.mode || 'prompt') === 'prompt') {
89
+ bag.cancelQueuedGoalContinuations?.();
89
90
  bag.archiveCompletedGoalOnUserInput?.();
90
91
  }
91
92
  try { runtime.interruptTaskWait?.('user-message'); } catch {}
@@ -135,6 +136,19 @@ export function createSessionApiA(bag) {
135
136
  }
136
137
  return await Promise.resolve(enqueueSubmission(intake)) !== false;
137
138
  };
139
+ const submitAndWait = async (text, options = {}) => {
140
+ let resolveSettled;
141
+ const settled = new Promise((resolve) => { resolveSettled = resolve; });
142
+ const accepted = await submitAsync(text, {
143
+ ...options,
144
+ onSettled: (detail) => {
145
+ try { options.onSettled?.(detail); } catch {}
146
+ resolveSettled(detail);
147
+ },
148
+ });
149
+ if (!accepted) return { status: 'rejected', result: null, session: null };
150
+ return await settled;
151
+ };
138
152
  return {
139
153
  getState: () => getPublishedState(),
140
154
  patchItem,
@@ -146,6 +160,7 @@ export function createSessionApiA(bag) {
146
160
  },
147
161
  submit,
148
162
  submitAsync,
163
+ submitAndWait,
149
164
  reserveSession: (sessionId) => {
150
165
  const id = runtime.reserveSessionId?.(sessionId);
151
166
  if (!id) return false;
@@ -760,7 +775,6 @@ export function createSessionApiA(bag) {
760
775
  syncContextStats({
761
776
  allowEstimated: true,
762
777
  invalidateExact: compactChanged,
763
- compactedEstimateTokens: compactChanged ? result.afterTokens : null,
764
778
  });
765
779
  set({ ...routeState(), stats: { ...getState().stats } });
766
780
  if (result) {
@@ -74,6 +74,12 @@ export function createSessionFlow(bag) {
74
74
  pastedTexts: options.pastedTexts && typeof options.pastedTexts === 'object' ? options.pastedTexts : null,
75
75
  images: promptContentImageMeta(text, options.pastedImages),
76
76
  onCommitted: typeof options.onCommitted === 'function' ? options.onCommitted : null,
77
+ onSettled: typeof options.onSettled === 'function' ? options.onSettled : null,
78
+ onToolResult: typeof options.onToolResult === 'function' ? options.onToolResult : null,
79
+ transcriptMeta: options.transcriptMeta && typeof options.transcriptMeta === 'object'
80
+ ? { ...options.transcriptMeta }
81
+ : null,
82
+ context: options.context || null,
77
83
  mode,
78
84
  priority,
79
85
  key: options.key || null,
@@ -242,11 +248,14 @@ export function createSessionFlow(bag) {
242
248
  }
243
249
  continue;
244
250
  }
251
+ const sender = String(entry.transcriptMeta?.sender || '').trim().toLowerCase();
245
252
  pushUserOrSyntheticItem(
246
253
  entry.text,
247
254
  entry.id,
248
255
  isQueuedEntryEditable(entry) ? 'user' : 'injected',
249
- Array.isArray(entry.images) && entry.images.length ? { images: entry.images } : null,
256
+ Array.isArray(entry.images) && entry.images.length
257
+ ? { images: entry.images, ...(sender ? { sender } : {}) }
258
+ : sender ? { sender } : null,
250
259
  );
251
260
  }
252
261
  const nonEditable = batch.filter((entry) => !isQueuedEntryEditable(entry));
@@ -277,6 +286,18 @@ export function createSessionFlow(bag) {
277
286
  restorable: nonEditable.length === 0,
278
287
  requeueOnAbort,
279
288
  discardExecutionPendingResumeKeys,
289
+ transcriptMeta: batch[0]?.transcriptMeta || null,
290
+ context: batch.map((entry) => String(entry.context || '').trim()).filter(Boolean).join('\n\n') || null,
291
+ onToolResult: (message) => {
292
+ for (const entry of batch) {
293
+ try { entry.onToolResult?.(message); } catch {}
294
+ }
295
+ },
296
+ onSettled: (detail) => {
297
+ for (const entry of batch) {
298
+ try { entry.onSettled?.(detail); } catch {}
299
+ }
300
+ },
280
301
  });
281
302
  if (flags.drainEpoch !== drainEpoch) return;
282
303
  // A deferred cleared-session UI sync (from a late-settling abandoned
@@ -365,6 +386,9 @@ export function createSessionFlow(bag) {
365
386
  id: entry.id,
366
387
  submittedAt: entry.submittedAt,
367
388
  ...(Array.isArray(entry.images) && entry.images.length ? { images: entry.images } : {}),
389
+ ...(entry.transcriptMeta && typeof entry.transcriptMeta === 'object'
390
+ ? { transcriptMeta: entry.transcriptMeta }
391
+ : {}),
368
392
  };
369
393
  if (entry.suppressDisplay) {
370
394
  // Model-visible twin of an already-rendered live completion: deliver
@@ -10,9 +10,34 @@ import { toolCallId, toolResultCallId, toolCallName, toolCallArgs } from './tool
10
10
  import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
11
11
  import { TUI_FRAME_MS, yieldToRenderer } from './render-timing.mjs';
12
12
  import { aggregateRawResult, aggregateBucketForCategory, aggregateSummaries, aggregateToolMembers, assignAggregateSummaryOrder, failureDetailText, toolCallOutcome } from './tool-result-status.mjs';
13
+ import { isTranscriptHiddenControlToolName } from '../../runtime/shared/tool-execution-contract.mjs';
13
14
 
14
15
  export const STREAM_BATCH_INTERVAL_MS = TUI_FRAME_MS;
15
16
 
17
+ export function transcriptToolCallDisplayMode(name, args) {
18
+ if (isTaskWaitToolCall(name, args)) return 'task-wait';
19
+ if (isTranscriptHiddenControlToolName(name)) return 'hidden-control';
20
+ return 'visible';
21
+ }
22
+
23
+ export function preserveGoalStateAfterTurn({
24
+ cancelled = false,
25
+ stale = false,
26
+ pendingSessionReset = false,
27
+ disposed = false,
28
+ } = {}) {
29
+ return cancelled === true
30
+ && (stale === true || pendingSessionReset === true || disposed === true);
31
+ }
32
+
33
+ function isUsageLimitError(error) {
34
+ if (!error) return false;
35
+ const status = Number(error?.httpStatus || error?.status || error?.response?.status || 0);
36
+ if (error?.providerQuota === true || error?.quotaExceeded === true || status === 429) return true;
37
+ const text = String(error?.message || error);
38
+ return /\brate[_ -]?limit\b|\bquota\b|too many requests|resource exhausted|insufficient_quota|quota_exceeded/i.test(text);
39
+ }
40
+
16
41
  export function createRunTurn(bag) {
17
42
  const {
18
43
  runtime, nextId, tuiDebug, flags, pending, itemIndexById, getState, set, flushEmit, flushEmitImmediate, pushItem, appendItems, patchItem, replaceItems, updateStreamingTail: updateStreamingTailFromStore, settleStreamingTail: settleStreamingTailFromStore, clearStreamingTail: clearStreamingTailFromStore, pushNotice, pushUserOrSyntheticItem, markToolCallActive, markToolCallDone, clearActiveToolSummary, agentStatusState, routeState, transcriptRouteMetadata, syncContextStats, denyAllToolApprovals, requestToolApproval, patchToolCardResult, flushToolResults, flushDeferredExecutionPendingResumeKick, drainPendingSteering,
@@ -42,9 +67,14 @@ export function createRunTurn(bag) {
42
67
  const turnIndex = getState().stats.turns || 0;
43
68
  const startedAt = Date.now();
44
69
  const completionVerb = pickDoneVerb(turnIndex);
45
- const baseTranscriptMeta = flags.pendingTranscriptMeta
46
- || transcriptRouteMetadata?.(startedAt)
47
- || { at: startedAt };
70
+ const baseTranscriptMeta = {
71
+ ...(flags.pendingTranscriptMeta
72
+ || transcriptRouteMetadata?.(startedAt)
73
+ || { at: startedAt }),
74
+ ...(options.transcriptMeta && typeof options.transcriptMeta === 'object'
75
+ ? options.transcriptMeta
76
+ : {}),
77
+ };
48
78
  const turnTranscriptMeta = { ...baseTranscriptMeta, completionVerb };
49
79
  flags.pendingTranscriptMeta = null;
50
80
  const { at: _userItemAt, ...turnRouteMeta } = turnTranscriptMeta;
@@ -72,6 +102,7 @@ export function createRunTurn(bag) {
72
102
  : [],
73
103
  };
74
104
  set({ busy: true, lastTurn: null, spinner: { active: true, verb: pickVerb(turnIndex), startedAt, responseLength: 0, inputTokens: 0, outputTokens: 0, mode: 'requesting' } });
105
+ try { await bag.onGoalTurnStarted?.(); } catch {}
75
106
 
76
107
  let assistantText = '';
77
108
  let currentAssistantId = null;
@@ -95,6 +126,7 @@ export function createRunTurn(bag) {
95
126
  let cancelled = false;
96
127
  let failed = false;
97
128
  let turnFailureDetail = '';
129
+ let turnFailureUsageLimited = false;
98
130
  let askResult = null;
99
131
  let turnFinishedNormally = false;
100
132
  let transcriptCompactedThisTurn = false;
@@ -109,9 +141,9 @@ export function createRunTurn(bag) {
109
141
  const toolCards = [];
110
142
  const toolGroups = new Map();
111
143
  const resultsDone = new Set();
112
- // `task wait` is passive control flow, not user-visible work. Keep its call
113
- // ids only long enough to suppress live/result cards and drive the spinner.
114
- const suppressedTaskWaitCallIds = new Set();
144
+ // Passive task waits and internal Goal/load controls are runtime flow, not
145
+ // user-visible work. Keep ids only long enough to suppress result cards.
146
+ const suppressedTranscriptCallIds = new Set();
115
147
  const activeTaskWaitCallIds = new Set();
116
148
  const refreshTaskWaitSpinner = () => {
117
149
  if (!getState().spinner) return;
@@ -742,7 +774,7 @@ export function createRunTurn(bag) {
742
774
 
743
775
  const deliverToolResultMessage = (message) => {
744
776
  const suppressedCallId = toolResultCallId(message);
745
- if (suppressedCallId && suppressedTaskWaitCallIds.has(suppressedCallId)) {
777
+ if (suppressedCallId && suppressedTranscriptCallIds.has(suppressedCallId)) {
746
778
  activeTaskWaitCallIds.delete(suppressedCallId);
747
779
  refreshTaskWaitSpinner();
748
780
  return;
@@ -762,6 +794,7 @@ export function createRunTurn(bag) {
762
794
  id: submittedIds[0],
763
795
  submittedAt: options.submittedAt,
764
796
  transcriptMeta: turnTranscriptMeta,
797
+ context: options.context || null,
765
798
  drainSteering: (_sessionId, drainOptions) => (isCurrentTurn() ? drainPendingSteering(drainOptions) : []),
766
799
  onStreamDelta: () => {
767
800
  markTurnProgress('stream-delta');
@@ -799,9 +832,15 @@ export function createRunTurn(bag) {
799
832
  value,
800
833
  steeringIds[0],
801
834
  'injected',
802
- Array.isArray(steeringMeta?.images) && steeringMeta.images.length
803
- ? { images: steeringMeta.images }
804
- : null,
835
+ {
836
+ ...(Array.isArray(steeringMeta?.images) && steeringMeta.images.length
837
+ ? { images: steeringMeta.images }
838
+ : {}),
839
+ ...(typeof steeringMeta?.transcriptMeta?.sender === 'string'
840
+ && steeringMeta.transcriptMeta.sender
841
+ ? { sender: steeringMeta.transcriptMeta.sender }
842
+ : {}),
843
+ },
805
844
  );
806
845
  }
807
846
  },
@@ -817,7 +856,10 @@ export function createRunTurn(bag) {
817
856
  if (batchCalls.length === 0) return;
818
857
  const displayCalls = [];
819
858
  for (const call of batchCalls) {
820
- if (!isTaskWaitToolCall(toolCallName(call), toolCallArgs(call))) {
859
+ const name = toolCallName(call);
860
+ const args = toolCallArgs(call);
861
+ const displayMode = transcriptToolCallDisplayMode(name, args);
862
+ if (displayMode === 'visible') {
821
863
  displayCalls.push(call);
822
864
  continue;
823
865
  }
@@ -829,8 +871,8 @@ export function createRunTurn(bag) {
829
871
  displayCalls.push(call);
830
872
  continue;
831
873
  }
832
- suppressedTaskWaitCallIds.add(callId);
833
- activeTaskWaitCallIds.add(callId);
874
+ suppressedTranscriptCallIds.add(callId);
875
+ if (displayMode === 'task-wait') activeTaskWaitCallIds.add(callId);
834
876
  }
835
877
  if (thinkingText && getState().thinking) {
836
878
  const thinkingLastEndedAt = closeThinkingSegment();
@@ -949,7 +991,7 @@ export function createRunTurn(bag) {
949
991
  const lastTouchedAggregate = [...touchedAggregates].at(-1) || null;
950
992
  lastTouchedAggregate?.ensureVisible?.();
951
993
  for (const [bufferedCallId, bufferedMessage] of earlyResultBuffer) {
952
- if (suppressedTaskWaitCallIds.has(bufferedCallId)) {
994
+ if (suppressedTranscriptCallIds.has(bufferedCallId)) {
953
995
  deliverToolResultMessage(bufferedMessage);
954
996
  earlyResultBuffer.delete(bufferedCallId);
955
997
  continue;
@@ -962,6 +1004,7 @@ export function createRunTurn(bag) {
962
1004
  },
963
1005
  onToolResult: (message) => {
964
1006
  if (!markTurnProgress('tool-result')) return;
1007
+ try { options.onToolResult?.(message); } catch {}
965
1008
  const callId = toolResultCallId(message);
966
1009
  if (callId && !cardByCallId.has(callId) && !resultsDone.has(callId)) {
967
1010
  earlyResultBuffer.set(callId, message);
@@ -969,6 +1012,15 @@ export function createRunTurn(bag) {
969
1012
  }
970
1013
  deliverToolResultMessage(message);
971
1014
  },
1015
+ onToolPhaseCompleted: () => {
1016
+ if (!markTurnProgress('tool-phase-completed')) return;
1017
+ const spinner = getState().spinner;
1018
+ if (!spinner || spinner.mode === 'requesting') return;
1019
+ // A completed tool batch is not the end of the turn. Publish the
1020
+ // provider-resume phase immediately instead of leaving the last tool
1021
+ // state parked on screen until the next model event arrives.
1022
+ set({ spinner: { ...spinner, mode: 'requesting' } });
1023
+ },
972
1024
  onToolApproval: async (request) => {
973
1025
  if (!markTurnProgress('tool-approval')) return { approved: false, reason: 'turn no longer active' };
974
1026
  markPromptCommitted();
@@ -1031,7 +1083,6 @@ export function createRunTurn(bag) {
1031
1083
  syncContextStats({
1032
1084
  allowEstimated: true,
1033
1085
  invalidateExact: compactChanged,
1034
- compactedEstimateTokens: compactChanged ? event?.afterTokens : null,
1035
1086
  });
1036
1087
  // syncContextStats only STAGES its patch on the draft (context-state
1037
1088
  // mjs stages through updateState); publication is the caller's, and
@@ -1277,6 +1328,7 @@ export function createRunTurn(bag) {
1277
1328
  } else {
1278
1329
  failed = true;
1279
1330
  finalizeToolHeaders();
1331
+ turnFailureUsageLimited = isUsageLimitError(error);
1280
1332
  turnFailureDetail = toolErrorDisplay(error, 'turn').replace(/^Error:\s*/i, '');
1281
1333
  pushNotice(turnFailureDetail, 'error');
1282
1334
  }
@@ -1384,7 +1436,27 @@ export function createRunTurn(bag) {
1384
1436
  flushEmit?.();
1385
1437
  _publishedThinkingActive = false; // turn teardown cleared getState().thinking
1386
1438
  const finalStatus = cancelled ? 'cancelled' : (failed ? 'failed' : 'done');
1387
- try { bag.onGoalTurnSettled?.(finalStatus); } catch {}
1439
+ try {
1440
+ await bag.onGoalTurnSettled?.({
1441
+ status: finalStatus,
1442
+ error: turnFailureDetail || null,
1443
+ usageLimited: turnFailureUsageLimited,
1444
+ preserveGoalState: preserveGoalStateAfterTurn({
1445
+ cancelled,
1446
+ stale: !isCurrentTurn(),
1447
+ pendingSessionReset: flags.pendingSessionReset,
1448
+ disposed: flags.disposed,
1449
+ }),
1450
+ });
1451
+ } catch {}
1452
+ try {
1453
+ options.onSettled?.({
1454
+ status: finalStatus,
1455
+ result: askResult,
1456
+ session: runtime.session || null,
1457
+ error: turnFailureDetail || null,
1458
+ });
1459
+ } catch {}
1388
1460
  tuiDebug(`runTurn end turn=${turnIndex} status=${finalStatus} elapsedMs=${Date.now() - startedAt} pending=${pending.length}`);
1389
1461
  return finalStatus;
1390
1462
  }
@@ -217,10 +217,15 @@ export { parseBackgroundTaskEnvelope } from './session/agent-envelope.mjs';
217
217
  export async function createLocalSessionRuntime({
218
218
  provider: providerName,
219
219
  model,
220
+ effort,
221
+ fast,
222
+ modelParameters,
220
223
  toolMode = 'full',
221
224
  remote = false,
222
225
  cwd,
223
226
  desktopSession,
227
+ sessionProfile,
228
+ executeAgentControl,
224
229
  } = {}) {
225
230
  const startedAt = performance.now();
226
231
  bootProfile('session:create:start', { provider: providerName, model, toolMode, remote });
@@ -238,10 +243,15 @@ export async function createLocalSessionRuntime({
238
243
  const runtime = await createMixdogSessionRuntime({
239
244
  provider: providerName,
240
245
  model,
246
+ effort,
247
+ fast,
248
+ modelParameters,
241
249
  toolMode,
242
250
  remote,
243
251
  ...(cwd ? { cwd } : {}),
244
252
  ...(desktopSession ? { desktopSession } : {}),
253
+ ...(sessionProfile && typeof sessionProfile === 'object' ? { sessionProfile } : {}),
254
+ ...(typeof executeAgentControl === 'function' ? { executeAgentControl } : {}),
245
255
  });
246
256
  bootProfile('session:create:runtime-ready', { ms: (performance.now() - startedAt).toFixed(1) });
247
257
  const runtimeCwd = runtime.cwd || process.cwd();
@@ -327,6 +337,7 @@ export async function createLocalSessionRuntime({
327
337
  compactBoundaryTokens: 0,
328
338
  autoCompactTokenLimit: 0,
329
339
  ...initialAgentState,
340
+ goal: runtime.goalStatus?.() || null,
330
341
  toolMode: runtime.toolMode,
331
342
  cwd: runtimeCwd,
332
343
  themeEpoch: 0,
@@ -708,6 +719,7 @@ export async function createLocalSessionRuntime({
708
719
  if (origin === 'user') flags.pendingTranscriptMeta = transcriptMeta;
709
720
  pushItem({
710
721
  kind: 'user', id, text, ...transcriptMeta,
722
+ ...(extra && typeof extra.sender === 'string' && extra.sender ? { sender: extra.sender } : {}),
711
723
  // Byte-free attachment metadata (name/mime/size) from the queue entry —
712
724
  // lets the desktop transcript render image chips without ever carrying
713
725
  // base64 payloads through snapshots.
@@ -788,9 +800,16 @@ export async function createLocalSessionRuntime({
788
800
  // renders until explicitly cleared (setProgressHint('', ...) or a falsy
789
801
  // text), and App.jsx's inputHint falls back to it only when no promptHint
790
802
  // and no live toast currently cover the same line.
791
- const setProgressHint = (text, tone = 'info') => {
803
+ const setProgressHint = (text, tone = 'info', percent) => {
792
804
  const value = String(text ?? '').trim();
793
- set({ progressHint: value ? { text: value, tone } : null });
805
+ const numericPercent = Number(percent);
806
+ set({ progressHint: value ? {
807
+ text: value,
808
+ tone,
809
+ ...(Number.isFinite(numericPercent)
810
+ ? { percent: Math.max(0, Math.min(100, Math.round(numericPercent))) }
811
+ : {}),
812
+ } : null });
794
813
  };
795
814
  const {
796
815
  presentNextToolApproval,
@@ -1179,6 +1198,9 @@ export async function createLocalSessionRuntime({
1179
1198
  remoteAttachTimer.unref?.();
1180
1199
  void Promise.resolve(bag.restoreLeadSteeringFromDisk())
1181
1200
  .catch(() => {})
1182
- .finally(() => bag.scheduleGoalContinuation?.());
1201
+ .finally(() => {
1202
+ bag.refreshGoalState?.();
1203
+ bag.scheduleGoalContinuation?.();
1204
+ });
1183
1205
  return api;
1184
1206
  }