mixdog 1.3.5 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (515) hide show
  1. package/NOTICE.md +2 -2
  2. package/README.md +2 -2
  3. package/package.json +2 -11
  4. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/gate-local.mjs +16 -5
  7. package/scripts/latest-guard.mjs +21 -9
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +37 -37
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +123 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/native-release-status.mjs +2 -2
  14. package/scripts/post-release-check.mjs +1 -6
  15. package/scripts/pptx-kit-index.mjs +17 -4
  16. package/scripts/recall-history-cases.json +1 -1
  17. package/scripts/suite-health.mjs +20 -2
  18. package/scripts/test-data-dir.mjs +10 -7
  19. package/scripts/test.mjs +7 -11
  20. package/src/agents/reviewer/AGENT.md +7 -11
  21. package/src/agents/reviewer/agent.json +1 -1
  22. package/src/app.mjs +4 -0
  23. package/src/defaults/shipped-history.json +22 -1
  24. package/src/defaults/skills/browser-use/SKILL.md +62 -12
  25. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  26. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  27. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  28. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  29. package/src/defaults/skills/computer-use/SKILL.md +35 -9
  30. package/src/defaults/skills/setup/SKILL.md +22 -0
  31. package/src/defaults/skills/setup/references/actions.md +39 -5
  32. package/src/defaults/skills/setup/references/surfaces.md +11 -2
  33. package/src/defaults/skills/visualize/SKILL.md +2 -1
  34. package/src/lib/rules-builder.cjs +39 -20
  35. package/src/output-styles/common.md +2 -2
  36. package/src/output-styles/simple.md +1 -1
  37. package/src/rules/agent/AGENT.md +11 -10
  38. package/src/rules/lead/LEAD.md +23 -20
  39. package/src/rules/shared/05-tool-calls.md +5 -6
  40. package/src/rules/shared/10-tool-workflow.md +4 -0
  41. package/src/rules/shared/45-destructive.md +0 -2
  42. package/src/rules/shared/50-execution.md +2 -0
  43. package/src/rules/shared/60-verification.md +7 -5
  44. package/src/rules/shared/70-delivery.md +7 -9
  45. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
  46. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  47. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  48. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  49. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  50. package/src/runtime/agent/orchestrator/config.mjs +17 -1
  51. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  52. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +73 -68
  53. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
  54. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  55. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
  56. package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
  57. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
  58. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
  59. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
  60. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  63. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  66. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  67. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  70. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
  71. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  72. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
  73. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  74. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  75. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
  76. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  77. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  78. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  79. package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  82. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
  83. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  84. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  85. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  87. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  88. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  89. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  90. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  91. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  92. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  93. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  106. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  107. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
  109. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  113. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  116. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
  117. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  118. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  119. package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -0
  120. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  121. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  122. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +49 -16
  123. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  124. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  125. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  126. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
  127. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
  131. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  132. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  133. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
  134. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  136. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  137. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  138. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
  139. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  140. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  141. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  142. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
  143. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
  144. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  145. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  146. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
  147. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
  148. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
  149. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
  150. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  151. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +51 -25
  153. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -3
  154. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
  155. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  158. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
  159. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +5 -4
  162. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  163. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  164. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +49 -21
  165. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  166. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
  167. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  168. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  172. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  173. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  174. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +24 -14
  175. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  176. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  177. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +130 -0
  178. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
  179. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  181. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
  182. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
  183. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
  185. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  187. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
  188. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
  189. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  191. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
  192. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  193. package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
  194. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  195. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  196. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  197. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  198. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  199. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  200. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  201. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  203. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -3
  209. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  210. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  211. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  212. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  213. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +79 -3
  214. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  217. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  218. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  221. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  222. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  224. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  225. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
  226. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
  227. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  228. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
  229. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  231. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  232. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  233. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  234. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  235. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  236. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  237. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  238. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  239. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  240. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  241. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
  243. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  244. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  245. package/src/runtime/browser-bridge/client.mjs +73 -8
  246. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  247. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  248. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  249. package/src/runtime/channels/lib/config.mjs +6 -61
  250. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  251. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  252. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  253. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  254. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  255. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  256. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  257. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  258. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  259. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  260. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  261. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  262. package/src/runtime/channels/lib/scheduler.mjs +33 -147
  263. package/src/runtime/channels/lib/schedules-db.mjs +34 -11
  264. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  265. package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
  266. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  267. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  268. package/src/runtime/channels/lib/whisper-port.mjs +10 -1
  269. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  270. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  271. package/src/runtime/channels/lib/worker-main.mjs +10 -34
  272. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  273. package/src/runtime/computer-bridge/actions.mjs +9 -1
  274. package/src/runtime/computer-bridge/client.mjs +180 -8
  275. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  276. package/src/runtime/computer-bridge/error-recovery.mjs +28 -2
  277. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  278. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  279. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  280. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  281. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  282. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  283. package/src/runtime/connectors/google-mcp.mjs +10 -12
  284. package/src/runtime/local-provider/server-process.mjs +2 -1
  285. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  286. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  287. package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
  288. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  289. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  290. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  291. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  292. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  293. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  294. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  295. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  296. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  297. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  298. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  299. package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
  300. package/src/runtime/office/quality/design-review.mjs +1 -5
  301. package/src/runtime/office/quality/document-brief.mjs +1 -5
  302. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  303. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  304. package/src/runtime/session-search/session-search-db.mjs +73 -9
  305. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  306. package/src/runtime/shared/abort-race.mjs +89 -0
  307. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  308. package/src/runtime/shared/agent-kind.mjs +4 -3
  309. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  310. package/src/runtime/shared/bounded-download.mjs +8 -3
  311. package/src/runtime/shared/config.mjs +2 -13
  312. package/src/runtime/shared/connector-accounts.mjs +20 -10
  313. package/src/runtime/shared/connector-catalog.d.mts +29 -0
  314. package/src/runtime/shared/connector-catalog.mjs +150 -0
  315. package/src/runtime/shared/connector-triggers.mjs +22 -19
  316. package/src/runtime/shared/defaults-separation.mjs +2 -17
  317. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  318. package/src/runtime/shared/err-text.mjs +24 -15
  319. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  320. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  321. package/src/runtime/shared/file-permissions.d.mts +0 -8
  322. package/src/runtime/shared/file-permissions.mjs +0 -11
  323. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  324. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  325. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  326. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  327. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  328. package/src/runtime/shared/idle-auto-clear-gate.mjs +126 -0
  329. package/src/runtime/shared/llm/cost.mjs +5 -1
  330. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  331. package/src/runtime/shared/loopback-listener.mjs +25 -2
  332. package/src/runtime/shared/mixy-presence.mjs +22 -0
  333. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  334. package/src/runtime/shared/model-route-chain.mjs +22 -4
  335. package/src/runtime/shared/open-url.mjs +10 -0
  336. package/src/runtime/shared/orchestration.d.mts +2 -0
  337. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  338. package/src/runtime/shared/profile-config.cjs +1 -1
  339. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  340. package/src/runtime/shared/prompt-origin.mjs +21 -0
  341. package/src/runtime/shared/provider-accounts.mjs +7 -1
  342. package/src/runtime/shared/provider-display-name.mjs +29 -0
  343. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  344. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  345. package/src/runtime/shared/routine-trigger.mjs +10 -0
  346. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  347. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  348. package/src/runtime/shared/session-activity-signal.mjs +48 -1
  349. package/src/runtime/shared/session-scratch.mjs +37 -0
  350. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  351. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  352. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  353. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  354. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  355. package/src/runtime/shared/tool-result-summary.mjs +2 -15
  356. package/src/runtime/shared/tool-surface.mjs +3 -0
  357. package/src/runtime/shared/tool-work-units.mjs +2 -0
  358. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  359. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  360. package/src/runtime/shared/worktrees/git.mjs +15 -0
  361. package/src/runtime/shared/worktrees/manager.mjs +87 -38
  362. package/src/runtime/shared/worktrees/test-support.mjs +14 -13
  363. package/src/runtime/terminal-bridge/client.mjs +10 -1
  364. package/src/runtime/visualize-bridge/client.mjs +29 -8
  365. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  366. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  367. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  368. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  369. package/src/session-runtime/agent-home-delivery.mjs +489 -185
  370. package/src/session-runtime/agent-task-sessions.mjs +467 -229
  371. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  372. package/src/session-runtime/boot/apis.mjs +9 -0
  373. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  374. package/src/session-runtime/boot/providers.mjs +3 -0
  375. package/src/session-runtime/boot/tools.mjs +11 -2
  376. package/src/session-runtime/bot-status.mjs +12 -6
  377. package/src/session-runtime/bot-target.mjs +38 -0
  378. package/src/session-runtime/channel-config-api.mjs +6 -1
  379. package/src/session-runtime/config-lifecycle.mjs +6 -0
  380. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  381. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  382. package/src/session-runtime/conversation-import/discovery.mjs +271 -25
  383. package/src/session-runtime/conversation-import/service.mjs +26 -5
  384. package/src/session-runtime/handoff-attachments.mjs +82 -31
  385. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
  386. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
  387. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  388. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
  389. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  390. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  391. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  392. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  393. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  394. package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
  395. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  396. package/src/session-runtime/mixy-heartbeat.mjs +153 -33
  397. package/src/session-runtime/model-route/set-route.mjs +11 -2
  398. package/src/session-runtime/notification-bus.mjs +31 -117
  399. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  400. package/src/session-runtime/notification-listeners.mjs +76 -0
  401. package/src/session-runtime/owned-automation-run.mjs +2 -1
  402. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  403. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  404. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  405. package/src/session-runtime/provider-models.mjs +4 -2
  406. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  407. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  408. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  409. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  410. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  411. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  412. package/src/session-runtime/resource-recall-api.mjs +6 -1
  413. package/src/session-runtime/routine-owner.mjs +40 -9
  414. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  415. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  416. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  417. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  418. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  419. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  420. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  422. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  423. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  424. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  425. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  426. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  427. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  428. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  429. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  430. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  431. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  432. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  433. package/src/session-runtime/services/channel-admin.mjs +7 -13
  434. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  435. package/src/session-runtime/services/provider-admin.mjs +2 -1
  436. package/src/session-runtime/services/seeds.mjs +0 -28
  437. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  438. package/src/session-runtime/session-create/session-options.mjs +1 -0
  439. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  440. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  441. package/src/session-runtime/settings-system-api.mjs +13 -1
  442. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  443. package/src/session-runtime/setup-tool/executor.mjs +145 -22
  444. package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
  445. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  446. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
  447. package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
  448. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  449. package/src/session-runtime/tool-policy/policy-stage.mjs +17 -2
  450. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  451. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  452. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
  453. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  454. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  455. package/src/session-runtime/workspace/transitions.mjs +25 -0
  456. package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
  457. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  458. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  459. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  460. package/src/standalone/channel-transport.mjs +1 -1
  461. package/src/standalone/daemon-channels-loader.mjs +10 -8
  462. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  463. package/src/standalone/daemon-session-control/request.mjs +51 -0
  464. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  465. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  466. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  467. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  468. package/src/standalone/daemon-session-control.mjs +142 -190
  469. package/src/standalone/daemon.mjs +26 -3
  470. package/src/standalone/session-client.mjs +7 -3
  471. package/src/standalone/session-protocol.mjs +5 -0
  472. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  473. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  474. package/src/standalone/session-service/quota-resume.mjs +3 -0
  475. package/src/standalone/session-service/retention/busy.mjs +65 -1
  476. package/src/standalone/session-service/session-calls/session-action.mjs +30 -2
  477. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  478. package/src/standalone/session-tool-output.mjs +15 -7
  479. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  480. package/src/tui/app/app-view/floating-panel.jsx +7 -4
  481. package/src/tui/app/model-options.mjs +3 -28
  482. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  483. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  484. package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
  485. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  486. package/src/tui/app/provider-setup-picker.mjs +9 -5
  487. package/src/tui/components/QuestionPanel.jsx +13 -4
  488. package/src/tui/dist/index.mjs +133 -92
  489. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  490. package/src/tui/session/initial-state.mjs +3 -0
  491. package/src/tui/session/notice-surface.mjs +7 -1
  492. package/src/tui/session/queue-helpers.mjs +3 -42
  493. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  494. package/src/tui/session/session-api/routes-write.mjs +5 -1
  495. package/src/tui/session/session-api/routes.mjs +1 -0
  496. package/src/tui/session/session-api/settings.mjs +17 -1
  497. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  498. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  499. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  500. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  501. package/src/tui/session/session-flow/drain.mjs +118 -149
  502. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  503. package/src/tui/session/session-flow/queue/take-entries.mjs +16 -2
  504. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  505. package/src/tui/session/tool-approval-request.mjs +39 -0
  506. package/src/tui/session/tool-approval-settle.mjs +62 -0
  507. package/src/tui/session/tool-approval.mjs +69 -115
  508. package/src/tui/session/tui-steering-persist.mjs +8 -1
  509. package/src/tui/session/turn-stream.mjs +19 -2
  510. package/src/tui/session/turn.mjs +1 -0
  511. package/src/ui/statusline-agents.mjs +1 -3
  512. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  513. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  514. package/scripts/code-graph-description-contract.mjs +0 -188
  515. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -6,7 +6,13 @@
6
6
  */
7
7
  import { createClaudeReducer } from './claude.mjs';
8
8
  import { createCodexReducer } from './codex.mjs';
9
- import { IMPORT_WARNING_MALFORMED, conversationTitle, normalizeTurns } from './turns.mjs';
9
+ import {
10
+ IMPORT_ERROR_INTERNAL,
11
+ IMPORT_WARNING_HISTORY_PARTIAL,
12
+ IMPORT_WARNING_MALFORMED,
13
+ conversationTitle,
14
+ normalizeTurns,
15
+ } from './turns.mjs';
10
16
 
11
17
  export const IMPORT_SOURCES = Object.freeze(['codex', 'claude']);
12
18
  /** A line or converted transcript beyond the import limits fails the file. */
@@ -35,7 +41,9 @@ const transcriptChars = (turns) => turns.reduce((total, turn) => total + turn.te
35
41
  * (an over-long line or file). `result()` may be called repeatedly and also
36
42
  * holds the normalized turns to `maxTranscriptChars`.
37
43
  * `errorCode` is null for an importable result, else one of `empty` |
38
- * `malformed` | `unsupported` | `tooLarge` (whose turns are not returned).
44
+ * `malformed` | `unsupported` | `internalRecord` (the source app's own
45
+ * subagent/review record; `internalKind` names it) | `tooLarge` (whose turns
46
+ * are not returned).
39
47
  */
40
48
  export function createConversationConverter(
41
49
  source,
@@ -47,18 +55,37 @@ export function createConversationConverter(
47
55
  ) {
48
56
  if (!isImportSource(source)) throw new TypeError('source must be codex or claude.');
49
57
  const reducer = source === 'codex' ? createCodexReducer() : createClaudeReducer();
50
- let lines = 0;
51
58
  let records = 0;
52
59
  let malformed = 0;
53
60
  let tooLarge = false;
61
+ let historyPartial = false;
54
62
  return {
63
+ /** True while every message seen so far is a Claude sidechain message. */
64
+ get sidechainOnly() {
65
+ return reducer.sidechainOnly === true;
66
+ },
55
67
  markTooLarge() {
56
68
  tooLarge = true;
57
69
  },
58
- pushLine(raw) {
70
+ /** A history base could not be followed in full. */
71
+ markHistoryPartial() {
72
+ historyPartial = true;
73
+ },
74
+ /** Feed a line for the stored title only (Claude Code's tail window); other sources ignore it. */
75
+ pushTitleLine(raw) {
76
+ let value;
77
+ try {
78
+ value = JSON.parse(String(raw).trim());
79
+ } catch {
80
+ return;
81
+ }
82
+ if (value && typeof value === 'object') reducer.pushTitle?.(value);
83
+ },
84
+ /** `inherited` lines belong to a history base followed ahead of this file's own lines. */
85
+ pushLine(raw, { inherited = false } = {}) {
59
86
  if (tooLarge) return false;
60
87
  let line = String(raw);
61
- if (lines++ === 0 && line.charCodeAt(0) === 0xfeff) line = line.slice(1);
88
+ if (line.charCodeAt(0) === 0xfeff) line = line.slice(1);
62
89
  if (line.endsWith('\r')) line = line.slice(0, -1);
63
90
  if (!line.trim()) return true;
64
91
  let value;
@@ -73,7 +100,7 @@ export function createConversationConverter(
73
100
  return true;
74
101
  }
75
102
  records += 1;
76
- reducer.push(value);
103
+ reducer.push(value, inherited);
77
104
  if (
78
105
  reducer.chars > maxTranscriptChars ||
79
106
  reducer.entries > maxRetainedEntries ||
@@ -90,8 +117,10 @@ export function createConversationConverter(
90
117
  if (transcriptChars(turns) > maxTranscriptChars) tooLarge = true;
91
118
  const warnings = new Set(parsed.warnings);
92
119
  if (malformed) warnings.add(IMPORT_WARNING_MALFORMED);
120
+ if (historyPartial) warnings.add(IMPORT_WARNING_HISTORY_PARTIAL);
93
121
  let errorCode = null;
94
122
  if (tooLarge) errorCode = IMPORT_ERROR_TOO_LARGE;
123
+ else if (parsed.internalKind) errorCode = IMPORT_ERROR_INTERNAL;
95
124
  else if (!records) errorCode = malformed ? 'malformed' : 'empty';
96
125
  else if (!parsed.recognized) errorCode = 'unsupported';
97
126
  else if (!turns.length) errorCode = 'empty';
@@ -100,8 +129,10 @@ export function createConversationConverter(
100
129
  errorCode,
101
130
  foreignSessionId: parsed.foreignSessionId,
102
131
  cwd: parsed.cwd,
132
+ internalKind: parsed.internalKind,
133
+ historyBase: parsed.historyBase ?? null,
103
134
  turns: tooLarge ? [] : turns,
104
- title: conversationTitle(turns),
135
+ title: parsed.storedTitle || conversationTitle(turns),
105
136
  messageCount: tooLarge ? 0 : turns.length,
106
137
  warnings: [...warnings],
107
138
  };
@@ -70,6 +70,9 @@ export function importedTranscriptMessages(turns, importedAt) {
70
70
  content: turn.text,
71
71
  meta: {
72
72
  source: IMPORTED_MESSAGE_SOURCE,
73
+ // Where the text holds a run of tool use, and which tools: the desktop
74
+ // draws each run as a native activity row.
75
+ ...(turn.toolRuns?.length ? { importedToolRuns: turn.toolRuns } : {}),
73
76
  transcript: { messageId: newTranscriptMessageId(), at: turn.at || importedAt },
74
77
  },
75
78
  }));
@@ -9,6 +9,11 @@
9
9
  export const IMPORT_WARNING_IMAGE_OMITTED = 'imageOmitted';
10
10
  export const IMPORT_WARNING_MALFORMED = 'malformed';
11
11
  export const IMPORT_WARNING_CWD_MISSING = 'cwdMissing';
12
+ /** The conversation continues a history stored in another file that was not followed. */
13
+ export const IMPORT_WARNING_HISTORY_PARTIAL = 'historyPartial';
14
+
15
+ /** Failure code of a record the source app writes for its own use (not a conversation). */
16
+ export const IMPORT_ERROR_INTERNAL = 'internalRecord';
12
17
 
13
18
  /** Stands in for an image the importer does not carry over. */
14
19
  export const IMAGE_OMITTED_TEXT = '[image omitted]';
@@ -17,12 +22,49 @@ export const IMPORTED_USER_STUB_TEXT = '[Imported conversation continues from an
17
22
 
18
23
  const TITLE_MAX_CHARS = 100;
19
24
 
20
- /** Plain-text note for a tool call: its name only, never its arguments. */
25
+ /** Note for a tool call: its name only, never its arguments. A run of notes
26
+ * becomes one compact line in the text and one structured entry in `toolRuns`. */
21
27
  export function toolNote(name) {
22
- const clean = String(name || '')
23
- .replace(/\s+/g, ' ')
24
- .trim();
25
- return { text: `[ran tool: ${clean || 'unknown'}]`, note: true };
28
+ const clean =
29
+ String(name || '')
30
+ .replace(/\s+/g, ' ')
31
+ .trim() || 'unknown';
32
+ return { text: `[ran tool: ${clean}]`, note: true, tool: clean };
33
+ }
34
+
35
+ /** Longest model-facing run line, and the longest tool name shown in it. */
36
+ export const TOOL_RUN_LINE_MAX_CHARS = 400;
37
+ const TOOL_RUN_NAME_MAX_CHARS = 40;
38
+
39
+ /**
40
+ * Model-facing line for one run of tool notes: `[ran tools: shell ×6, Read ×2]`.
41
+ * Bounded: names are clipped, and tools that do not fit are counted as
42
+ * `, +N more`. Deterministic in `tools`, so a stored line can be re-derived.
43
+ */
44
+ export function toolRunLine(tools) {
45
+ const entries = tools.map(({ name, count }) => {
46
+ const chars = Array.from(String(name));
47
+ const shown =
48
+ chars.length > TOOL_RUN_NAME_MAX_CHARS ? `${chars.slice(0, TOOL_RUN_NAME_MAX_CHARS - 1).join('')}…` : name;
49
+ return `${shown} ×${count}`;
50
+ });
51
+ const omittedSuffix = (omitted) => (omitted > 0 ? `, +${omitted} more` : '');
52
+ let body = '';
53
+ let shownCount = 0;
54
+ for (const entry of entries) {
55
+ const next = shownCount ? `${body}, ${entry}` : entry;
56
+ const length = `[ran tools: ${next}${omittedSuffix(entries.length - shownCount - 1)}]`.length;
57
+ if (shownCount && length > TOOL_RUN_LINE_MAX_CHARS) break;
58
+ body = next;
59
+ shownCount += 1;
60
+ }
61
+ return `[ran tools: ${body}${omittedSuffix(entries.length - shownCount)}]`;
62
+ }
63
+
64
+ function toolRunCounts(notes) {
65
+ const counts = new Map();
66
+ for (const note of notes) counts.set(note.tool, (counts.get(note.tool) || 0) + 1);
67
+ return [...counts].map(([name, count]) => ({ name, count }));
26
68
  }
27
69
 
28
70
  export function textPart(text) {
@@ -42,18 +84,31 @@ export function timestampMs(value) {
42
84
  return Number.isFinite(ms) && ms > 0 ? ms : null;
43
85
  }
44
86
 
45
- // Consecutive tool notes stay one per line; every other boundary is a blank line.
87
+ // Each run of consecutive tool notes collapses into one compact line; every
88
+ // boundary is a blank line. `toolRuns` locates those lines in `text`.
46
89
  function joinParts(parts) {
47
- let text = '';
48
- let previous = null;
90
+ const blocks = [];
49
91
  for (const part of parts) {
50
92
  const piece = String(part.text || '').trim();
51
93
  if (!piece) continue;
52
- if (previous) text += previous.note && part.note ? '\n' : '\n\n';
53
- text += piece;
54
- previous = part;
94
+ const last = blocks[blocks.length - 1];
95
+ if (part.note && last?.notes) last.notes.push(part);
96
+ else blocks.push(part.note ? { notes: [part] } : { text: piece });
97
+ }
98
+ let text = '';
99
+ const toolRuns = [];
100
+ for (const block of blocks) {
101
+ if (text) text += '\n\n';
102
+ if (block.notes) {
103
+ const tools = toolRunCounts(block.notes);
104
+ const line = toolRunLine(tools);
105
+ toolRuns.push({ start: text.length, end: text.length + line.length, tools });
106
+ text += line;
107
+ } else {
108
+ text += block.text;
109
+ }
55
110
  }
56
- return { text, last: previous };
111
+ return { text, toolRuns };
57
112
  }
58
113
 
59
114
  /**
@@ -72,9 +127,15 @@ export function normalizeTurns(rawTurns) {
72
127
  else merged.push({ role: raw.role, parts: [...parts], at: timestampMs(raw.at) });
73
128
  }
74
129
  const turns = merged.map(({ role, parts, at }) => {
75
- const turn = { role, text: joinParts(parts).text, at };
76
- // A carried-over compaction summary never names the conversation.
77
- if (parts.some((part) => part.summary)) turn.titleText = joinParts(parts.filter((part) => !part.summary)).text;
130
+ const joined = joinParts(parts);
131
+ const turn = { role, text: joined.text, at };
132
+ if (joined.toolRuns.length) turn.toolRuns = joined.toolRuns;
133
+ // A carried-over compaction summary never names the conversation; a slash
134
+ // command only when no typed prompt does.
135
+ if (parts.some((part) => part.summary || part.command)) {
136
+ turn.titleText = joinParts(parts.filter((part) => !part.summary && !part.command)).text;
137
+ }
138
+ if (parts.some((part) => part.command)) turn.commandText = joinParts(parts.filter((part) => part.command)).text;
78
139
  return turn;
79
140
  });
80
141
  if (turns[0]?.role === 'assistant') {
@@ -83,19 +144,26 @@ export function normalizeTurns(rawTurns) {
83
144
  return turns;
84
145
  }
85
146
 
86
- const titleLines = (turn) =>
87
- (turn.titleText ?? turn.text)
147
+ const textLines = (text) =>
148
+ String(text ?? '')
88
149
  .split('\n')
89
150
  .map((value) => value.replace(/\s+/g, ' ').trim())
90
151
  .filter(Boolean);
91
152
 
153
+ const titleLines = (turn) => textLines(turn.titleText ?? turn.text);
154
+
155
+ /** First non-empty line of a title text, whitespace-normalized, ≤100 chars. */
156
+ export function titleFromText(text) {
157
+ const line = textLines(text)[0];
158
+ if (!line) return null;
159
+ return Array.from(line).slice(0, TITLE_MAX_CHARS).join('').trim() || null;
160
+ }
161
+
92
162
  /** First line of the first genuine user turn, whitespace-normalized, ≤100 chars
93
- * (an image marker only when the turn has no text line). */
163
+ * (an image marker only when the turn has no text line), else the first slash command. */
94
164
  export function conversationTitle(turns) {
95
165
  const first = turns.find((turn) => turn.role === 'user' && !turn.stub && titleLines(turn).length);
96
- if (!first) return null;
166
+ if (!first) return titleFromText(turns.find((turn) => turn.role === 'user' && turn.commandText)?.commandText);
97
167
  const lines = titleLines(first);
98
- const line = lines.find((value) => value !== IMAGE_OMITTED_TEXT) || lines[0];
99
- if (!line) return null;
100
- return Array.from(line).slice(0, TITLE_MAX_CHARS).join('').trim() || null;
168
+ return titleFromText(lines.find((value) => value !== IMAGE_OMITTED_TEXT) || lines[0]);
101
169
  }
@@ -24,6 +24,7 @@ export function createEagerDispatcher({
24
24
  getIterations,
25
25
  getNextIteration,
26
26
  repeatFailLimit,
27
+ isTurnLimitNoticed = () => false,
27
28
  executeToolFn = executeTool,
28
29
  }) {
29
30
  const pending = new Map();
@@ -56,7 +57,9 @@ export function createEagerDispatcher({
56
57
  const startEagerTool = (wireCall) => {
57
58
  // Streamed call_tool requests are admitted, ordered and executed as their
58
59
  // targets; a projection error is answered by the serial batch instead.
59
- if (capped) return null;
60
+ // Once the turn was told to reply (any limit), no call runs: the batch
61
+ // refuses them, so none may start while the wrap-up response streams.
62
+ if (capped || isTurnLimitNoticed()) return null;
60
63
  const call = resolveExecutionToolCall(wireCall, sessionRef);
61
64
  if (!call?.id || pending.has(call.id) || !isParallelDispatchable(call.name)) return null;
62
65
  const admitted = admission.admit(call);
@@ -98,7 +98,8 @@ const LEAD_NAME = 'Lead';
98
98
  * bot-created task session, a bot's home chat or room member session) and
99
99
  * the names from there down to the asker ("Lead › Reviewer", "사무관 ›
100
100
  * Worker"). Only where the card shows: no bot identity, grant or remember
101
- * scope follows from it. Null for a top-level session. */
101
+ * scope follows from it. Null for a top-level session (whose requests show
102
+ * in the chats handing it work instead: tui/session/tool-approval.mjs). */
102
103
  export function approvalSurface(sessionId) {
103
104
  const delegation = delegationOf(sessionId);
104
105
  if (delegation.state !== 'resolved') return null;
@@ -156,7 +157,13 @@ async function describeEmails(call, outbound, ctx) {
156
157
  const { executeMcpTool } = await import('../../mcp/client.mjs');
157
158
  const ids = outbound.category === 'trash' && Array.isArray(call.args?.ids) ? call.args.ids.map(String) : [];
158
159
  const shown = ids.slice(0, PREVIEW_MESSAGES);
159
- const raw = await executeMcpTool(name, { ids: shown }, { scopeId: ctx.mcpScopeId });
160
+ // The account the call acts as (one server holds every Gmail account).
161
+ const chosen = typeof call.args?.account === 'string' ? call.args.account.trim() : '';
162
+ const raw = await executeMcpTool(
163
+ name,
164
+ { ids: shown, ...(chosen ? { account: chosen } : {}) },
165
+ { scopeId: ctx.mcpScopeId }
166
+ );
160
167
  const { account, emails } = JSON.parse(raw);
161
168
  const messages = (Array.isArray(emails) ? emails : []).map((mail) =>
162
169
  [mail.from, mail.subject, String(mail.date || '').slice(0, 10)].filter(Boolean).join(' · ')
@@ -231,10 +238,9 @@ export async function humanGateDecision(call, decision, ctx = {}) {
231
238
  editable: outbound.editable,
232
239
  details: outbound.details,
233
240
  },
234
- remember: ['once'],
241
+ // "Don't ask again" is the bot's permission.
242
+ remember: outboundRemember(outbound.category),
235
243
  };
236
- // "Don't ask again" is the bot's permission.
237
- request.remember = outboundRemember(outbound.category);
238
244
  const store = ctx.store || (await humanGateStore());
239
245
  const mode = await store.modeFor({ agentId, action: outbound.category });
240
246
  const base = decision && typeof decision === 'object' ? decision : {};
@@ -74,8 +74,6 @@ const MCP_OUTBOUND = new Map([
74
74
  'slack_post_message',
75
75
  'slack_reply_to_thread',
76
76
  'chat_post_message',
77
- 'discord_send_message',
78
- 'telegram_send_message',
79
77
  ].map((name) => [name, 'message']),
80
78
  ...['create_post', 'publish_post', 'create_tweet', 'post_tweet', 'send_tweet'].map((name) => [name, 'publish']),
81
79
  ['submit_form', 'form'],
@@ -12,10 +12,23 @@
12
12
  // the scopes it allows and can leave out `always`. Nothing here ever carries a
13
13
  // secret value: a decision that names one is stripped to its verdict.
14
14
 
15
- export const HUMAN_REQUEST_KINDS = Object.freeze(['approval', 'outbound', 'secret', 'takeover', 'permission']);
16
- export const HUMAN_RESPONSES = Object.freeze(['approve', 'deny', 'edit-and-approve', 'provide-secret', 'skip', 'done']);
17
- export const REMEMBER_SCOPES = Object.freeze(['once', 'agent', 'always']);
15
+ const HUMAN_REQUEST_KINDS = Object.freeze(['approval', 'outbound', 'secret', 'takeover', 'permission']);
16
+ const HUMAN_RESPONSES = Object.freeze(['approve', 'deny', 'edit-and-approve', 'provide-secret', 'skip', 'done']);
17
+ const REMEMBER_SCOPES = Object.freeze(['once', 'agent', 'always']);
18
18
  export const SECRET_REQUEST_TIMEOUT_MS = 120_000;
19
+ /** What a secret's bound field is: a sign-in form (아이디 + 비밀번호), a lone
20
+ * password, a new password, or a one-time code; '' when unknown (computer). */
21
+ export const SECRET_FORMS = Object.freeze(['login', 'password', 'new-password', 'otp']);
22
+ /** Every result a secret handoff (and a declined or expired takeover) gives
23
+ * the agent: facts, never a verdict about the site. */
24
+ export const HANDOFF_OUTCOMES = Object.freeze([
25
+ 'entered',
26
+ 'user_skipped',
27
+ 'no_field',
28
+ 'page_changed',
29
+ 'blocked',
30
+ 'expired',
31
+ ]);
19
32
 
20
33
  const RESPONSES_BY_KIND = Object.freeze({
21
34
  approval: ['approve', 'deny'],
@@ -49,7 +62,7 @@ const text = (value, limit = TEXT_LIMIT) => (typeof value === 'string' ? value.t
49
62
 
50
63
  /** The human kind of a request; anything else (ask_user's 'question', a
51
64
  * hook's bare ask) is an ordinary approval for responses. */
52
- export function humanRequestKind(request) {
65
+ function humanRequestKind(request) {
53
66
  return HUMAN_REQUEST_KINDS.includes(request?.kind) ? request.kind : 'approval';
54
67
  }
55
68
 
@@ -103,11 +116,21 @@ export function humanRequestFields(input = {}) {
103
116
  }
104
117
  if (kind === 'secret') {
105
118
  const secret = isRecord(input.secret) ? input.secret : {};
119
+ // The bound page's origin and what its field is (the desktop read it at
120
+ // request time, ask-user-tool.mjs): the card's title and inputs; no value.
121
+ const origin = loginPageUrl(secret.origin)?.origin || '';
122
+ const form = SECRET_FORMS.includes(secret.form) ? secret.form : '';
123
+ // A code's length is the bound field's own (credential-autofill.ts
124
+ // codeLength); absent, it stays unspecified.
125
+ const length = Number.isInteger(secret.length) && secret.length > 0 ? secret.length : 0;
106
126
  fields.secret = {
107
127
  requestId: text(secret.requestId),
108
128
  surface: secret.surface === 'computer' ? 'computer' : 'browser',
109
129
  target: text(secret.target),
110
130
  field: text(secret.field),
131
+ ...(origin ? { origin } : {}),
132
+ ...(form ? { form } : {}),
133
+ ...(form === 'otp' && length ? { length } : {}),
111
134
  };
112
135
  fields.args = { surface: fields.secret.surface, target: fields.secret.target, field: fields.secret.field };
113
136
  fields.remember = ['once'];
@@ -132,12 +155,21 @@ export function humanRequestFields(input = {}) {
132
155
  // A login takeover (purpose 'login') opens the desktop's sign-in window on
133
156
  // its validated page instead of handing over the side panel.
134
157
  const login = surface === 'browser' && takeover.purpose === 'login' ? loginPageUrl(takeover.url) : null;
158
+ // The saved logins of the sign-in page's origin: opaque ids and masked
159
+ // labels only (profile-import.ts credentialSuggestions), never a password.
160
+ const accounts = (login && Array.isArray(takeover.accounts) ? takeover.accounts : [])
161
+ .filter((account) => isRecord(account) && token(account.id, 128) && text(account.label, 120))
162
+ .map((account) => ({ id: token(account.id, 128), label: text(account.label, 120) }));
163
+ // The page those logins may be filled into, bound by the desktop at
164
+ // request time (ask-user-tool.mjs fillId): without it none is offered.
165
+ const fillId = /^secret_[A-Za-z0-9-]{8,80}$/.test(text(takeover.fillId, 100)) ? text(takeover.fillId, 100) : '';
135
166
  fields.takeover = {
136
167
  surface,
137
168
  instructions: text(takeover.instructions, 2_000),
138
169
  ...(text(takeover.target) ? { target: text(takeover.target) } : {}),
139
170
  ...identity,
140
171
  ...(login ? { purpose: 'login', url: login.url, origin: login.origin } : {}),
172
+ ...(accounts.length && fillId ? { accounts, fillId } : {}),
141
173
  };
142
174
  fields.remember = ['once'];
143
175
  }
@@ -17,7 +17,7 @@ import { ACTION_KINDS, isRememberableAction } from './outbound-policy.mjs';
17
17
  const ANY_AGENT = '*';
18
18
  const FIELD_LIMIT = 200;
19
19
  const AUDIT_KEYS = ['agentId', 'kind', 'action', 'tool', 'target', 'decision', 'device'];
20
- const PERMISSION_MODES = Object.freeze(['ask', 'allow', 'block']);
20
+ export const PERMISSION_MODES = Object.freeze(['ask', 'allow', 'block']);
21
21
 
22
22
  const field = (value) => String(value ?? '').slice(0, FIELD_LIMIT);
23
23
  const grantId = (agentId, action) =>
@@ -16,11 +16,15 @@ import { CONTEXT_SHARE_RATIO, COMPACT_TARGET_MIN_TOKENS, COMPACT_SAFETY_PERCENT
16
16
  import { HANDOFF_TIMEOUT_MAX_MS } from '../compact/constants.mjs';
17
17
  import { envFlag, envPositiveInt } from '../../../../shared/env.mjs';
18
18
  import { positiveInt } from '../../../../shared/numbers.mjs';
19
+ import { cacheWarmUseFor, lastCacheWarmUseAt } from '../../../../shared/idle-auto-clear-gate.mjs';
20
+ import { ACCOUNT_PROVIDERS } from '../../../../shared/provider-accounts.mjs';
21
+ import { plannedAccountId } from '../../providers/account-pool.mjs';
19
22
  import { isAgentOwner } from '../../agent-owner.mjs';
20
23
  import { isAgentModeSession } from '../agent-mode.mjs';
21
24
  import { providerInputExcludesCache, providerNativePdf } from '../../providers/registry.mjs';
22
25
  import { contentMediaBytes, contentMediaCount } from '../../providers/media-normalization.mjs';
23
26
  import { splitProtectedContext } from '../compact/messages.mjs';
27
+ import { withLiveCompactionConfig } from '../../runtime-core/compaction-config-keys.mjs';
24
28
 
25
29
  // Unified context-share rule (compact/constants.mjs CONTEXT_SHARE_RATIO): the
26
30
  // post-compaction target is 25% of the boundary/context window. One
@@ -394,13 +398,6 @@ export function invalidateProviderContextBaseline(sessionRef) {
394
398
  delete sessionRef.contextPressureUnanchoredReason;
395
399
  }
396
400
 
397
- // A baseline is refreshed on every provider_send/turn-end. When the transcript
398
- // has grown but no fresh recording landed for this long, recording is failing
399
- // (zero/absent usage keeps the OLD baseline because record() only returns
400
- // false) — distrust it and fall back to the estimate. An idle session whose
401
- // transcript did NOT grow keeps its baseline regardless of age.
402
- const BASELINE_MAX_STALE_GROWTH_MS = 30 * 60 * 1000;
403
-
404
401
  /**
405
402
  * Does this anchor still describe this message prefix?
406
403
  *
@@ -480,17 +477,19 @@ function providerBaselinePressureTokens(messages, sessionRef, policy, { includeC
480
477
  ? Math.max(0, tokens - Math.round(storedRequestReserve) + currentRequestReserve)
481
478
  : tokens + currentRequestReserve;
482
479
  }
483
- // Staleness means a baseline that stopped being refreshed WHILE the session
484
- // kept working — never age on the wall clock. Measured against `now`, this
485
- // discarded the reading of every session that simply sat unopened for a
486
- // while (88 of 983 stored sessions), and the whole-transcript estimate that
487
- // replaced it was the less accurate number in both directions: 1.12x over
488
- // on the median, 0.82x under on a session already past its window.
489
- // Comparing against the session's own last activity keeps the rule aimed at
490
- // its actual target — a live session whose usage recording is failing while
491
- // its transcript grows — and leaves a session at rest on its measurement.
492
- const activityAt = Math.max(Number(sessionRef.updatedAt) || 0, Number(sessionRef.lastContextTokensUpdatedAt) || 0);
493
- if (messages.length > count && baselineAt > 0 && activityAt - baselineAt > BASELINE_MAX_STALE_GROWTH_MS) return null;
480
+ // Staleness means usage recording is failing: a provider request completed
481
+ // AFTER this reading without replacing it (every send records its usage
482
+ // after it starts, so a working recorder always leaves the reading newer
483
+ // than the last send) — zero/absent usage keeps the OLD baseline because
484
+ // record() only returns false. Never age on a clock: measured against `now`
485
+ // it discarded the reading of every session that sat unopened for a while
486
+ // (88 of 983 stored sessions), and measured against the session's last
487
+ // activity it discarded it whenever anything was appended more than half an
488
+ // hour after the last request — a user back from a break, an agent's result
489
+ // posted to a waiting Lead — so the next send compacted on the
490
+ // whole-transcript estimate, far above the provider's own count.
491
+ const lastSendAt = Number(sessionRef.lastProviderSendAt) || 0;
492
+ if (messages.length > count && baselineAt > 0 && lastSendAt > baselineAt) return null;
494
493
  try {
495
494
  // Baseline tokens are authoritative provider billing; only the growth
496
495
  // after the baseline is a local estimate and needs billing calibration.
@@ -707,13 +706,40 @@ export function shouldCompactForRequestMedia(messages, provider = '') {
707
706
  // Anthropic's 5m message-tail TTL (agent-runtime/cache-strategy.mjs gives it
708
707
  // to agent sessions). A send this long after the previous one finds the tail
709
708
  // cache expired and would rewrite the whole accumulated transcript; compacting
710
- // first makes that cold write the compacted transcript instead.
709
+ // first makes that cold write the compacted transcript instead. The tail was
710
+ // last used by the session's own send or by a successful cache warm
711
+ // (cache-warm.mjs), which reads and refreshes it without moving
712
+ // lastProviderSendAt: a warmed tail has not expired — for a request on the
713
+ // warm's provider, model and account only, since the entry lives there.
711
714
  const AGENT_MESSAGE_CACHE_TTL_MS = 5 * 60_000;
712
715
 
713
- export function shouldCompactForExpiredAgentCache(sessionRef, opts) {
716
+ // The account the request would be served by: the roster's first pick for a
717
+ // provider with accounts (account-pool.mjs), '' for one without a roster.
718
+ function requestAccountId(provider, model, sessionRef, opts, messages) {
719
+ if (!ACCOUNT_PROVIDERS.includes(provider)) return '';
720
+ return plannedAccountId(provider, {
721
+ sessionId: opts?.sessionId || sessionRef?.id || null,
722
+ messages,
723
+ providerState: opts?.providerState,
724
+ model,
725
+ });
726
+ }
727
+
728
+ /** Whether the agent session's 5m message tail expired before this request
729
+ * on `provider` / `model` (default: the session's route). */
730
+ export function shouldCompactForExpiredAgentCache(sessionRef, opts, { provider, model, messages = [] } = {}) {
714
731
  if (!isAgentOwner(sessionRef) || opts?.cacheStrategy?.messages !== '5m') return false;
715
732
  const lastSendAt = Number(sessionRef.lastProviderSendAt);
716
- return lastSendAt > 0 && Date.now() - lastSendAt > AGENT_MESSAGE_CACHE_TTL_MS;
733
+ if (!(lastSendAt > 0)) return false;
734
+ const now = Date.now();
735
+ if (now - lastSendAt <= AGENT_MESSAGE_CACHE_TTL_MS) return false;
736
+ // No warm since the last send: the tail expired.
737
+ if (!(lastCacheWarmUseAt(sessionRef.id) > lastSendAt)) return true;
738
+ const route = { provider: provider || sessionRef.provider || '', model: model || sessionRef.model || '' };
739
+ const accountId = requestAccountId(route.provider, route.model, sessionRef, opts, messages);
740
+ if (accountId === null) return true;
741
+ const warmAt = cacheWarmUseFor(sessionRef.id, { ...route, accountId });
742
+ return now - Math.max(lastSendAt, warmAt) > AGENT_MESSAGE_CACHE_TTL_MS;
717
743
  }
718
744
 
719
745
  export function shouldCompactForSession(
@@ -795,9 +821,9 @@ function compactionTelemetryRecord(sessionRef, policy, meta, prev) {
795
821
  if (terminalSuccess) return null;
796
822
  return present ? (next ?? null) : (previous ?? null);
797
823
  };
798
- return {
799
- ...prev,
800
- auto: policy.auto !== false,
824
+ // Config-owned fields stay the live ones (withLiveCompactionConfig): `policy`
825
+ // was resolved before a compaction that a reload may have outlived.
826
+ return withLiveCompactionConfig(prev, {
801
827
  requestReserveTokens: policy.requestReserveTokens || 0,
802
828
  reserveTokens: policy.reserveTokens || 0,
803
829
  boundaryTokens: policy.boundaryTokens || null,
@@ -848,7 +874,7 @@ function compactionTelemetryRecord(sessionRef, policy, meta, prev) {
848
874
  compactCount: (prev.compactCount || 0) + (changed ? 1 : 0),
849
875
  singleShotConsumed:
850
876
  policy.singleShot === true && meta.stage === 'compacting' ? true : prev.singleShotConsumed === true,
851
- };
877
+ });
852
878
  }
853
879
 
854
880
  // Postmortem ring buffer: the per-check telemetry record is overwritten on
@@ -18,6 +18,9 @@ import { summarizeOnSharedPrefix } from '../compact/forked-summary.mjs';
18
18
  import { normalizeCompactionSummaryMode } from '../compact/summary-mode.mjs';
19
19
  import { compactionCacheWarm, lighterSubscriptionModel } from '../compact/summary-route.mjs';
20
20
  import { retireCompactionFork } from '../side-question-store.mjs';
21
+ import { buildSkillToolEnvelope, collectSkillsCached, currentSkillDelivery } from '../../context/collect.mjs';
22
+ import { loadSkillToolDependencies } from '../../runtime-core/skill-tool-loading.mjs';
23
+ import { parseNativeToolSearchPayload } from './tool-helpers.mjs';
21
24
 
22
25
  // Conversation summarization triggers independently of the post-compact target:
23
26
  // at 5% of the window, capped so a large window does not carry tens of
@@ -262,11 +265,42 @@ function freshContextBudget({ compactPolicy, sessionRef, provider, compactBudget
262
265
  return { contextWindow, hardBudget, conversationInput, conversationTokens, conversationThresholdTokens };
263
266
  }
264
267
 
268
+ // Compact restores each active skill from its current source, as the Skill
269
+ // tool would deliver it in this session now (null: it no longer loads). The
270
+ // real pass also re-arms the skill's current tool dependencies on the session
271
+ // surface and answers the native tool-search payload they produce (or, with
272
+ // none, the Skill result summary); a preview never touches the surface and
273
+ // keeps the transcript's loader pairs.
274
+ function currentSkillResolver(sessionRef, { preview = false } = {}) {
275
+ const cwd = sessionRef?.cwd || null;
276
+ const config = loadConfig({ secrets: false });
277
+ const skills = collectSkillsCached(cwd);
278
+ return (name) => {
279
+ const delivery = currentSkillDelivery(name, cwd, config, skills);
280
+ if (!delivery) return null;
281
+ const { resource } = delivery;
282
+ // The tools whose use counts as use of the skill: its tool dependencies,
283
+ // an MCP server as `mcp:<server>`.
284
+ const tools = (resource.toolDependencies || []).flatMap(({ type, value }) =>
285
+ type === 'tool' ? [value] : type === 'mcp' ? [`mcp:${value}`] : []
286
+ );
287
+ if (preview) return { body: delivery.body, native: undefined, tools };
288
+ const envelope = loadSkillToolDependencies(
289
+ buildSkillToolEnvelope(name, resource.content, resource.dir, resource),
290
+ sessionRef
291
+ );
292
+ const native = parseNativeToolSearchPayload('Skill', envelope.result);
293
+ return { body: delivery.body, native, summary: native?.summary ?? envelope.result, tools };
294
+ };
295
+ }
296
+
265
297
  function freshContextBuildOptions(
266
- { compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
298
+ { sessionRef, compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments, preview },
267
299
  budget
268
300
  ) {
269
301
  return {
302
+ // A sessionless call (no session gates to apply) keeps the transcript copies.
303
+ currentSkill: sessionRef ? currentSkillResolver(sessionRef, { preview }) : null,
270
304
  reserveTokens: compactPolicy.reserveTokens,
271
305
  maxBudgetTokens: budget.hardBudget,
272
306
  force: true,
@@ -287,7 +321,7 @@ export function previewFreshContextCompaction(input) {
287
321
  const budget = freshContextBudget(input);
288
322
  const summaryTriggered = budget.conversationTokens >= budget.conversationThresholdTokens;
289
323
  const result = freshContextCompactMessages(input.messages, input.compactBudgetTokens, {
290
- ...freshContextBuildOptions(input, budget),
324
+ ...freshContextBuildOptions({ ...input, preview: true }, budget),
291
325
  preview: true,
292
326
  previewSummary: summaryTriggered,
293
327
  });
@@ -346,7 +380,7 @@ export async function runFreshContextCompact({
346
380
  });
347
381
  const summaryTriggered = conversationTokens >= conversationThresholdTokens;
348
382
  const buildOptions = freshContextBuildOptions(
349
- { compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
383
+ { sessionRef, compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
350
384
  { contextWindow, hardBudget }
351
385
  );
352
386
  const build = (handoffText) =>
@@ -120,7 +120,9 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
120
120
  messages.push(message);
121
121
  try {
122
122
  opts.onToolResult?.(message);
123
- } catch {}
123
+ } catch {
124
+ // the tool-result observer is advisory
125
+ }
124
126
  };
125
127
  state.drainSteering = createSteeringDrain({
126
128
  messages,
@@ -44,7 +44,7 @@ export function createNoToolTurnResolver({
44
44
  // whether it answered that input.
45
45
  reactions: [],
46
46
  // Structured provider continuation signals honored this turn. Diagnostic
47
- // only: the loop has no iteration cap, so this count bounds nothing. A
47
+ // only: this count bounds nothing. A
48
48
  // text-only continuation runaway is bounded by continuationsSinceToolBatch
49
49
  // below; continuations interleaved with tool batches are not limited.
50
50
  providerContinuationCount: 0,