mixdog 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -8,14 +8,15 @@
8
8
  * later request rebuilds the same history and the prompt cache keeps hitting.
9
9
  * A judge that is missing, slow or failing leaves the step at the effort in
10
10
  * force (the turn's or the previous step's).
11
- * A custom route (snapshot mode 'custom') has no mid-conversation update: the
12
- * judged effort, snapped onto the model's levels, becomes the effort of the
13
- * turn's following requests.
11
+ * A custom route snaps the judged effort onto the model's levels. Without a
12
+ * mid-conversation update (snapshot mode 'custom') it becomes the effort of
13
+ * the turn's following requests; a custom GPT-6+ Responses route (mode
14
+ * 'responses') also marks it as the update.
14
15
  */
15
16
  import { resolveAutoEffort } from '../../providers/auto-effort.mjs';
16
- import { resolveCustomReasoning } from '../../providers/custom-reasoning.mjs';
17
+ import { isCustomProviderName, resolveCustomReasoning } from '../../providers/custom-reasoning.mjs';
17
18
  import { autoEffortModel, stepEffortConfiguration } from '../../providers/effort-configuration.mjs';
18
- import { effortOptionsFor } from '../../runtime-core/effort.mjs';
19
+ import { effortOptionsFor, warnEmptyAutoEffortLadder } from '../../runtime-core/effort.mjs';
19
20
  import { judgeTurn, recordEffortDecision } from '../../../../effort-judge/judge-client.mjs';
20
21
  import { stepResultWindow } from '../../../../effort-judge/judge-input.mjs';
21
22
 
@@ -35,12 +36,58 @@ const argText = (args) =>
35
36
  .slice(0, 600)
36
37
  .join('');
37
38
 
39
+ // A judgment runs beside the next iteration instead of in front of it. Its
40
+ // record lives on the loop state (`state.stepEffort`), so it can only ever
41
+ // reach the turn that started it; its promise settles the record and touches
42
+ // nothing else, so an aborted loop is never mutated afterwards. The result
43
+ // lands on the batch's last tool result in one of two places:
44
+ // - resolved before the next request is projected: on that tool result, so
45
+ // the request carries it (applyStepEffort);
46
+ // - resolved later: the request already went out with the earlier effort and
47
+ // its history is never rewritten (that would break the prompt cache), so
48
+ // the result marks the last tool result of the next batch, and the
49
+ // following request carries it (markStepEffort).
50
+ function applyResult(state, target, result) {
51
+ if (result.level) state.opts.effort = result.level;
52
+ if (result.marked) target.meta = { ...target.meta, effortConfiguration: result.marked };
53
+ }
54
+
55
+ // How long a request waits for its step judgment (measured judge p90 ≈ 284 ms).
56
+ export const STEP_EFFORT_GRACE_MS = 300;
57
+
58
+ /**
59
+ * Before a provider request is projected: wait up to the grace for the pending
60
+ * judgment and apply it if it resolved. A slower one leaves this request at
61
+ * the effort in force and lands on the following request.
62
+ */
63
+ export async function applyStepEffort(state) {
64
+ const pending = state.stepEffort;
65
+ if (!pending || pending.sent) return;
66
+ if (!pending.settled && !state.signal?.aborted) {
67
+ let timer;
68
+ await Promise.race([
69
+ pending.promise,
70
+ new Promise((resolve) => {
71
+ timer = setTimeout(resolve, STEP_EFFORT_GRACE_MS);
72
+ }),
73
+ ]);
74
+ clearTimeout(timer);
75
+ // Another caller may have handled it while this one waited.
76
+ if (pending.sent) return;
77
+ }
78
+ pending.sent = true;
79
+ if (!pending.result || state.signal?.aborted || !state.messages.includes(pending.target)) return;
80
+ applyResult(state, pending.target, pending.result);
81
+ pending.applied = true;
82
+ }
83
+
38
84
  /**
39
- * Judge the step after this batch and mark its last tool result.
85
+ * Start judging the step after this batch (not awaited). The result applies to
86
+ * the next request if it is ready by then, else to the one after.
40
87
  * `state.opts.stepAutoEffort` ({ request, base }) is set only when auto effort
41
88
  * is on for this turn and the installed judge was trained on steps.
42
89
  */
43
- export async function markStepEffort(state, assistantTurnMsg) {
90
+ export function markStepEffort(state, assistantTurnMsg) {
44
91
  const auto = state.opts?.stepAutoEffort;
45
92
  const snapshot = state.opts?.effortConfiguration;
46
93
  if (!auto || !snapshot || state.signal?.aborted) return;
@@ -55,11 +102,27 @@ export async function markStepEffort(state, assistantTurnMsg) {
55
102
  }
56
103
  }
57
104
  if (!last) return;
105
+ const previous = state.stepEffort;
106
+ if (previous) {
107
+ // It resolved after its request went out: this batch carries it. One still
108
+ // running is superseded: the newest step's judgment queues behind it and
109
+ // any judgment still waiting in between is skipped (latest wins), so the
110
+ // judge never has more than one running and one queued.
111
+ if (previous.settled) {
112
+ if (previous.result && !previous.applied) applyResult(state, last, previous.result);
113
+ } else {
114
+ previous.superseded = true;
115
+ }
116
+ }
58
117
  state.autoEffortSteps = (state.autoEffortSteps || 0) + 1;
59
118
  const step = state.autoEffortSteps;
60
119
  const provider = state.sessionRef?.provider;
61
120
  const model = state.model;
62
- const judged = await judgeTurn({
121
+ const pending = { target: last, sent: false, settled: false, applied: false, superseded: false, result: null };
122
+ const behind = previous && !previous.settled ? previous.promise : Promise.resolve();
123
+ state.stepEffort = pending;
124
+ const context = { auto, snapshot, step, provider, model, providerClient: state.provider, sessionId: state.sessionId };
125
+ const input = {
63
126
  step: {
64
127
  request: auto.request,
65
128
  step,
@@ -70,11 +133,26 @@ export async function markStepEffort(state, assistantTurnMsg) {
70
133
  result: stepResultWindow(textOf(results.get(call.id)?.content)),
71
134
  })),
72
135
  },
73
- });
136
+ };
137
+ pending.promise = behind
138
+ .then(() => (pending.superseded ? null : judgeTurn(input)))
139
+ .then((judged) => (judged ? stepResult(context, judged) : null))
140
+ // A failed judgment leaves the step at the effort in force.
141
+ .catch(() => null)
142
+ .then((result) => {
143
+ // Only this record changes here; the loop reads it at its next boundary.
144
+ pending.result = result;
145
+ pending.settled = true;
146
+ });
147
+ }
148
+
149
+ // What a resolved judgment sets: `{ marked, level }` (the tool result's effort
150
+ // configuration, and the per-request effort of a custom route), or null.
151
+ function stepResult({ auto, snapshot, step, provider, model, providerClient, sessionId }, judged) {
74
152
  // `atStep` numbers the tool-result step; `step` in a resolved decision is the ladder move.
75
153
  const record = {
76
154
  at: new Date().toISOString(),
77
- sessionId: state.sessionId,
155
+ sessionId,
78
156
  provider,
79
157
  model,
80
158
  mode: 'on',
@@ -82,9 +160,9 @@ export async function markStepEffort(state, assistantTurnMsg) {
82
160
  };
83
161
  if (!judged.probs) {
84
162
  recordEffortDecision({ ...record, skipped: judged.skipped });
85
- return;
163
+ return null;
86
164
  }
87
- const modelMeta = autoEffortModel(provider, state.provider, model);
165
+ const modelMeta = autoEffortModel(provider, providerClient, model);
88
166
  const resolved = resolveAutoEffort({
89
167
  base: auto.base,
90
168
  options: effortOptionsFor(provider, modelMeta),
@@ -96,19 +174,26 @@ export async function markStepEffort(state, assistantTurnMsg) {
96
174
  ms: judged.ms,
97
175
  probs: judged.probs.map((value) => Number(value.toFixed(3))),
98
176
  });
99
- if (snapshot.mode === 'custom') {
177
+ if (!resolved) warnEmptyAutoEffortLadder(provider, model, auto.base);
178
+ if (isCustomProviderName(provider)) {
100
179
  const level =
101
180
  resolved &&
102
181
  resolveCustomReasoning({
103
- protocol: state.provider?.customConfig?.protocol,
182
+ protocol: providerClient?.customConfig?.protocol,
104
183
  model: modelMeta,
105
184
  effort: resolved.effort,
106
185
  }).level;
107
- if (!level) return;
108
- state.opts.effort = level;
109
- last.meta = { ...last.meta, effortConfiguration: { ...snapshot, effort: level } };
110
- return;
186
+ if (!level) return null;
187
+ // The per-request effort also carries the step on an update route,
188
+ // where a rejected update replays the request with it.
189
+ return {
190
+ level,
191
+ marked:
192
+ snapshot.mode === 'custom'
193
+ ? { ...snapshot, effort: level }
194
+ : stepEffortConfiguration(snapshot, provider, model, level),
195
+ };
111
196
  }
112
197
  const marked = resolved && stepEffortConfiguration(snapshot, provider, model, resolved.effort);
113
- if (marked) last.meta = { ...last.meta, effortConfiguration: marked };
198
+ return marked ? { level: null, marked } : null;
114
199
  }
@@ -0,0 +1,95 @@
1
+ // Execution-call projection for the fixed tool bridge. A wire call
2
+ // `call_tool {name: T, arguments: A}` (id X) becomes the execution call
3
+ // `{ id: X, name: T, arguments: A, wireCall }` before eager admission and
4
+ // classification, so every policy, ordering, cache, hook, approval and audit
5
+ // layer sees the target itself. The tool result still answers wire id X and
6
+ // the transcript keeps the original wire call (`wireCall`, an immutable copy).
7
+ // Non-bridge sessions and every other call pass through unchanged.
8
+ import { formatInvalidToolArgsResult, isInvalidToolArgsMarker } from '../../providers/lib/openai-tool-args.mjs';
9
+ import {
10
+ BRIDGE_CALL_TOOL_NAME,
11
+ bridgeErrorText,
12
+ isToolBridgeEnabled,
13
+ resolveBridgeTarget,
14
+ } from '../../runtime-core/tool-bridge.mjs';
15
+
16
+ const CALL_TOOL_KEYS = new Set(['name', 'arguments']);
17
+
18
+ const isPlainObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
19
+
20
+ function deepFreeze(value) {
21
+ if (value && typeof value === 'object' && !Object.isFrozen(value)) {
22
+ Object.freeze(value);
23
+ for (const key of Object.keys(value)) deepFreeze(value[key]);
24
+ }
25
+ return value;
26
+ }
27
+
28
+ function projectionFailure(wireCall, wire, text) {
29
+ return { id: wireCall.id, name: wireCall.name, arguments: wireCall.arguments, wireCall: wire, bridgeError: text };
30
+ }
31
+
32
+ /**
33
+ * @returns the execution call for `wireCall`: the projected target call, a
34
+ * call carrying `bridgeError` (answered with that error, never executed),
35
+ * or `wireCall` itself when no projection applies. Idempotent.
36
+ */
37
+ export function resolveExecutionToolCall(wireCall, session) {
38
+ if (!wireCall || wireCall.name !== BRIDGE_CALL_TOOL_NAME || wireCall.wireCall || !isToolBridgeEnabled(session)) {
39
+ return wireCall;
40
+ }
41
+ const wire = deepFreeze(structuredClone(wireCall));
42
+ const args = wireCall.arguments;
43
+ if (isInvalidToolArgsMarker(args)) return projectionFailure(wireCall, wire, formatInvalidToolArgsResult(wireCall));
44
+ if (!isPlainObject(args)) {
45
+ return projectionFailure(
46
+ wireCall,
47
+ wire,
48
+ bridgeErrorText('INVALID_ARGUMENTS', 'call_tool requires {name, arguments}.')
49
+ );
50
+ }
51
+ const extra = Object.keys(args).filter((key) => !CALL_TOOL_KEYS.has(key));
52
+ if (extra.length) {
53
+ return projectionFailure(
54
+ wireCall,
55
+ wire,
56
+ bridgeErrorText('INVALID_ARGUMENTS', `call_tool does not accept: ${extra.join(', ')}.`)
57
+ );
58
+ }
59
+ if (!isPlainObject(args.arguments)) {
60
+ return projectionFailure(
61
+ wireCall,
62
+ wire,
63
+ bridgeErrorText('INVALID_ARGUMENTS', 'call_tool arguments must be an object of the target tool arguments.')
64
+ );
65
+ }
66
+ const target = resolveBridgeTarget(session, args.name);
67
+ if (target.error) return projectionFailure(wireCall, wire, bridgeErrorText(target.error.code, target.error.message));
68
+ const call = { id: wireCall.id, name: target.name, arguments: structuredClone(args.arguments), wireCall: wire };
69
+ // The target definition drives read-only classification of the call; it is
70
+ // never serialized with the call.
71
+ Object.defineProperty(call, 'bridgeTool', { value: target.tool, enumerable: false });
72
+ return call;
73
+ }
74
+
75
+ export function resolveExecutionToolCalls(calls, session) {
76
+ return Array.isArray(calls) ? calls.map((call) => resolveExecutionToolCall(call, session)) : calls;
77
+ }
78
+
79
+ /**
80
+ * The classification tool list for `calls`: `tools` plus the definitions of
81
+ * bridged targets that are not on it, so a bridged target is classified
82
+ * (read-only, dedup, stale-read invalidation) exactly like a direct call.
83
+ */
84
+ export function bridgeClassificationTools(tools, calls) {
85
+ const base = Array.isArray(tools) ? tools : [];
86
+ const seen = new Set(base.map((tool) => tool?.name));
87
+ const extra = [];
88
+ for (const call of calls || []) {
89
+ const definition = call?.bridgeTool;
90
+ if (!definition || seen.has(definition.name)) continue;
91
+ seen.add(definition.name);
92
+ extra.push(definition);
93
+ }
94
+ return extra.length ? [...base, ...extra] : tools;
95
+ }
@@ -4,11 +4,12 @@
4
4
  */
5
5
  import { resolvePreToolAskApproval } from '../tool-helpers.mjs';
6
6
  import { runAbortable, throwIfAborted } from '../../../../../shared/abort-race.mjs';
7
+ import { evaluateExecPolicy } from '../../../tools/bash-policy-scan.mjs';
7
8
  import { beginSessionApprovalWait } from '../../manager/runtime-liveness.mjs';
8
9
 
9
10
  const isArgsObject = (value) => value && typeof value === 'object' && !Array.isArray(value);
10
11
 
11
- async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHook, decision }) {
12
+ async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHook, decision, keepArgs = false }) {
12
13
  const askReason = String(decision?.reason || 'approval requested by hook').trim();
13
14
  // While the user decides, the session is waiting on them, not working.
14
15
  const releaseApprovalWait = beginSessionApprovalWait(callerSessionId);
@@ -30,10 +31,35 @@ async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHoo
30
31
  }
31
32
  if (askOutcome.denial) return { denial: askOutcome.denial };
32
33
  const approval = askOutcome.approval;
33
- if (approval && typeof approval === 'object' && isArgsObject(approval.args)) call.args = approval.args;
34
+ if (!keepArgs && approval && typeof approval === 'object' && isArgsObject(approval.args)) call.args = approval.args;
34
35
  return null;
35
36
  }
36
37
 
38
+ /**
39
+ * Approval gate for a shell call (or a terminal `run`) whose exec policy
40
+ * decision is 'ask' (elevated launch). Runs after the final call is known. The
41
+ * approval is granted for the exact command being asked about: an approval
42
+ * reply cannot rewrite the args.
43
+ * @returns {Promise<{ denial: string } | { elevationApproved: boolean }>}
44
+ */
45
+ export async function applyShellElevationGate(call, { callerSessionId, executeOpts, toolApprovalHook }) {
46
+ const gated = call.name === 'shell' || (call.name === 'terminal' && call.args?.action === 'run');
47
+ if (!gated || !isArgsObject(call.args) || call.args.command == null) {
48
+ return { elevationApproved: false };
49
+ }
50
+ const decision = evaluateExecPolicy(String(call.args.command));
51
+ if (decision.decision !== 'ask') return { elevationApproved: false };
52
+ const denied = await askApproval(call, {
53
+ callerSessionId,
54
+ executeOpts,
55
+ toolApprovalHook,
56
+ decision,
57
+ keepArgs: true,
58
+ });
59
+ if (denied) return denied;
60
+ return { elevationApproved: true };
61
+ }
62
+
37
63
  /**
38
64
  * @returns {Promise<{ denial: string } | { name: string, args: any }>}
39
65
  * the call as the hook left it, or the denial text to return instead
@@ -48,7 +74,8 @@ export async function applyBeforeToolHook({
48
74
  toolApprovalHook,
49
75
  }) {
50
76
  const call = { name, args, cwd };
51
- if (!beforeToolHook) return call;
77
+ // ask_user is itself the user prompt; it never goes through the ordinary approval gate.
78
+ if (!beforeToolHook || name === 'ask_user') return call;
52
79
  try {
53
80
  const decision = await runAbortable(executeOpts.signal, () =>
54
81
  beforeToolHook(
@@ -35,13 +35,19 @@ function dispatchMcp(name, args, { cwd, callerSessionId, sessionRef, executeOpts
35
35
  });
36
36
  }
37
37
 
38
- function dispatchInternal(name, args, { cwd, callerSessionId, sessionRef, executeOpts, notifyFn, toolApprovalHook }) {
38
+ function dispatchInternal(
39
+ name,
40
+ args,
41
+ { cwd, callerSessionId, sessionRef, executeOpts, notifyFn, toolApprovalHook, elevationApproved }
42
+ ) {
39
43
  // callerSessionId propagates into server.mjs dispatchTool so that
40
44
  // dispatchAiWrapped can detect and reject recursive calls from a
41
45
  // hidden-role session (recall/search → self).
42
46
  return executeInternalTool(name, args, {
43
47
  scopeId: sessionRef?.mcpScopeId || null,
44
48
  callerSessionId,
49
+ // The calling session itself: bridge tools answer within its scope.
50
+ callerSession: sessionRef || null,
45
51
  callerCwd: cwd,
46
52
  setCallerCwd: async (nextCwd) => {
47
53
  const applyForCaller = sessionRef?._applyResolvedCwdForCaller;
@@ -58,6 +64,8 @@ function dispatchInternal(name, args, { cwd, callerSessionId, sessionRef, execut
58
64
  notifyFn,
59
65
  toolApprovalHook,
60
66
  toolCallId: executeOpts.toolCallId || null,
67
+ // Runtime-granted for this call only (terminal run); never from model args.
68
+ elevationApproved: elevationApproved === true,
61
69
  invocationSource: 'model-tool',
62
70
  });
63
71
  }
@@ -90,9 +98,12 @@ export function dispatchToolCall({ name, args }, ctx) {
90
98
  // variants) adapt to a native execution inside executeBuiltinTool's default
91
99
  // case; on a shape mismatch it falls back to the redirect guidance message.
92
100
  if (name === 'shell' || isBuiltinTool(name) || isExternalAdapterTool(name)) {
93
- const builtinOpts = executeOpts.suppressReadUnchangedStub
94
- ? { ...completionToolOpts, suppressReadUnchangedStub: true }
95
- : completionToolOpts;
101
+ const builtinOpts = {
102
+ ...completionToolOpts,
103
+ ...(executeOpts.suppressReadUnchangedStub ? { suppressReadUnchangedStub: true } : {}),
104
+ // Runtime-granted only; any value inherited from executeOpts is overridden.
105
+ elevationApproved: ctx.elevationApproved === true,
106
+ };
96
107
  return executeBuiltinTool(name, args, cwd, builtinOpts);
97
108
  }
98
109
  return formatUnknownBuiltinToolMessage(name, args, 'tool');
@@ -8,12 +8,13 @@
8
8
  import { isMcpTool } from '../../mcp/client.mjs';
9
9
  import { prepareDeferredToolCallThrough } from './deferred-call-through.mjs';
10
10
  import { refreshDeferredMcpToolCatalog } from '../../runtime-core/tool-catalog.mjs';
11
+ import { bridgeTargetUnavailable } from '../../runtime-core/tool-bridge.mjs';
11
12
  import { preDispatchDenyForSession, routeWebFetchCall } from './pre-dispatch-deny.mjs';
12
13
  import { runWithToolExecutionOwner } from '../../../../shared/tool-execution-owner.mjs';
13
14
  import { runWithLocalSearchTelemetry } from '../../tools/builtin/local-search-telemetry.mjs';
14
15
  import { throwIfAborted } from '../../../../shared/abort-race.mjs';
15
16
  import { prepareToolCall } from './tool-exec/call-prep.mjs';
16
- import { applyBeforeToolHook } from './tool-exec/before-hook.mjs';
17
+ import { applyBeforeToolHook, applyShellElevationGate } from './tool-exec/before-hook.mjs';
17
18
  import { dispatchToolCall } from './tool-exec/dispatch.mjs';
18
19
  import { applyAfterToolHook } from './tool-exec/after-hook.mjs';
19
20
  import { runReadOnlyIoWithDeadline } from './tool-exec/read-only-deadline.mjs';
@@ -65,6 +66,18 @@ async function executeToolOwned(name, args, cwd, callerSessionId, sessionRef, ex
65
66
  if (isMcpTool(call.name)) refreshDeferredMcpToolCatalog(sessionRef);
66
67
  const deferredPrep = prepareDeferredToolCallThrough(sessionRef, call.name);
67
68
  if (deferredPrep?.deny) return deferredPrep.deny;
69
+ // A bridged target was resolved when its call_tool was projected; it must
70
+ // still be available in this session's scope (also after a hook rewrite).
71
+ // The authorized identity is the public tool name, not its transport
72
+ // (web_fetch routed to local_fetch/image_fetch stays web_fetch here).
73
+ if (executeOpts.bridgeWireCall) {
74
+ const unavailable = bridgeTargetUnavailable(sessionRef, finalCall.schemaName || finalCall.name);
75
+ if (unavailable) return unavailable;
76
+ }
77
+ // Elevated launches ask the user first; denied / no approval UI refuses the call.
78
+ const elevation = await applyShellElevationGate(call, { callerSessionId, executeOpts, toolApprovalHook });
79
+ if (elevation.denial) return elevation.denial;
80
+ throwIfAborted(executeOpts.signal);
68
81
  const result = await runReadOnlyIoWithDeadline(call.name, executeOpts.signal || null, async (deadlineSignal) => {
69
82
  let callOpts = executeOpts;
70
83
  if (deadlineSignal !== executeOpts.signal) {
@@ -80,6 +93,7 @@ async function executeToolOwned(name, args, cwd, callerSessionId, sessionRef, ex
80
93
  completionToolOpts,
81
94
  notifyFn,
82
95
  toolApprovalHook,
96
+ elevationApproved: elevation.elevationApproved === true,
83
97
  });
84
98
  });
85
99
  return applyAfterToolHook(result, hookFrom(executeOpts, sessionRef, 'afterToolHook'), {
@@ -0,0 +1,150 @@
1
+ // Tool-exposure migration (native ↔ bridge-v1, and pre-versioned fixed
2
+ // surfaces → bridge-v1). The surface itself is rebuilt by
3
+ // applyDeferredToolSurface; this module adds what a changed request prefix
4
+ // invalidates: provider state, the prefix guard, the context baseline and the
5
+ // cache-break tag. Historical tool calls are never rewritten.
6
+ import {
7
+ applyDeferredToolSurface,
8
+ rebuildDeferredToolSurfaceForProvider,
9
+ } from '../../runtime-core/tool-catalog.mjs';
10
+ import {
11
+ bridgeSurfaceOutdated,
12
+ sessionToolExposure,
13
+ TOOL_EXPOSURE_BRIDGE,
14
+ TOOL_SURFACE_MIGRATION_INTENT,
15
+ toolExposureMigrationNeeded,
16
+ toolExposureModeForProvider,
17
+ } from '../../runtime-core/tool-exposure.mjs';
18
+ import { applyInitialDeferredToolManifestToBp2 } from '../../context/collect.mjs';
19
+ import { isAgentOwner } from '../../agent-owner.mjs';
20
+ import { honoredSchemaAllowlist } from '../manager/session-tool-surface.mjs';
21
+ import { syncSystemPrefix } from '../manager/prompt-utils.mjs';
22
+ import { invalidateProviderContextBaseline } from './compact-policy.mjs';
23
+
24
+ /** Drop everything measured against the previous tool surface. */
25
+ function invalidateForToolSurfaceMigration(session) {
26
+ delete session.providerState;
27
+ delete session._providerPrefixGuardState;
28
+ invalidateProviderContextBaseline(session);
29
+ session.updatedAt = Date.now();
30
+ }
31
+
32
+ /**
33
+ * After a surface re-apply outside a request (resume, provider switch)
34
+ * migrated the exposure: the first send of the next turn carries the tag.
35
+ */
36
+ export function markToolSurfaceMigrated(session) {
37
+ invalidateForToolSurfaceMigration(session);
38
+ session.pendingCacheBreakIntent = TOOL_SURFACE_MIGRATION_INTENT;
39
+ }
40
+
41
+ /** Provider switch: rebuild the surface for `provider`, migrating bridge ↔ native. */
42
+ export function rebuildToolSurfaceForProviderWithMigration(session, provider) {
43
+ if (!session) return false;
44
+ const migrating = toolExposureMigrationNeeded(session, provider);
45
+ rebuildDeferredToolSurfaceForProvider(session, provider);
46
+ if (migrating) markToolSurfaceMigrated(session);
47
+ return migrating;
48
+ }
49
+
50
+ // The latest assistant tool turn still waits for a result: not a safe boundary.
51
+ function hasUnansweredToolCalls(messages) {
52
+ const list = Array.isArray(messages) ? messages : [];
53
+ const index = list.findLastIndex((message) => message?.role === 'assistant' && message.toolCalls?.length);
54
+ if (index < 0) return false;
55
+ const answered = new Set(
56
+ list.slice(index + 1).flatMap((message) => (message?.role === 'tool' ? [message.toolCallId] : []))
57
+ );
58
+ return list[index].toolCalls.some((call) => call?.id && !answered.has(call.id));
59
+ }
60
+
61
+ /**
62
+ * Request-boundary migration of a live session whose persisted exposure
63
+ * differs from its provider's. `messages` is the transcript the request is
64
+ * built from; the fixed-guidance rewrite lands there (and on the session).
65
+ * Returns true when the surface changed; the caller drops its frozen tool
66
+ * snapshot and provider state and tags the send.
67
+ */
68
+ export function migrateToolExposureAtBoundary(session, messages) {
69
+ if (!session || !toolExposureMigrationNeeded(session) || hasUnansweredToolCalls(messages)) return false;
70
+ const stored = session.messages;
71
+ const working = Array.isArray(messages) ? messages : stored;
72
+ if (Array.isArray(working)) session.messages = working;
73
+ try {
74
+ applyDeferredToolSurface(session, session.deferredSurfaceMode || 'lead', [], {
75
+ provider: session.provider,
76
+ model: session.model,
77
+ });
78
+ } finally {
79
+ if (Array.isArray(working) && session.messages !== working) {
80
+ // The rewrite may drop an emptied system message: keep the request
81
+ // transcript array identity the loop holds.
82
+ working.splice(0, working.length, ...session.messages);
83
+ }
84
+ session.messages = stored;
85
+ }
86
+ // The rewritten prompt messages are fresh objects; the canonical transcript
87
+ // the save path persists takes them too, so the next save writes the new
88
+ // prompt together with the new exposure.
89
+ if (Array.isArray(stored) && Array.isArray(working) && stored !== working) syncSystemPrefix(stored, working);
90
+ invalidateForToolSurfaceMigration(session);
91
+ return true;
92
+ }
93
+
94
+ // Bridge state an agent surface carries; dropped when it returns to the full array.
95
+ const AGENT_BRIDGE_FIELDS = [
96
+ 'toolExposureMode',
97
+ 'deferredProviderMode',
98
+ 'deferredNativeTools',
99
+ 'deferredSurfaceMode',
100
+ 'deferredToolUsage',
101
+ 'deferredDefaultTools',
102
+ 'deferredSelectedTools',
103
+ 'deferredDiscoveredTools',
104
+ 'deferredCallableTools',
105
+ 'deferredAnnouncedTools',
106
+ 'deferredToolDeltaRevision',
107
+ 'nativeDeferredDiscovery',
108
+ 'mcpServerInstructions',
109
+ ];
110
+
111
+ /**
112
+ * Agent (worker) sessions. Call right after their tools were resolved
113
+ * (create, resume, route change): on a bridge provider the eager surface
114
+ * becomes the full-mode core plus the bridge, built only from those
115
+ * role/policy-filtered tools; a native provider keeps the full array. A
116
+ * session honouring its own schema allowlist (a hidden specialist role) is
117
+ * already a small explicit surface and keeps it. `existing`: the session had
118
+ * a surface before, so a changed exposure is a migration.
119
+ */
120
+ export function applyAgentToolExposure(session, { existing = false } = {}) {
121
+ if (!session || !Array.isArray(session.tools) || !isAgentOwner(session)) return false;
122
+ const before = sessionToolExposure(session);
123
+ const allowlisted = honoredSchemaAllowlist(session.schemaAllowedTools, { ownerIsAgent: true, agent: session.agent });
124
+ const bridge =
125
+ !allowlisted && toolExposureModeForProvider(session.provider, session.wireRoute) === TOOL_EXPOSURE_BRIDGE;
126
+ if (!bridge && before === null) return false;
127
+ // A surface an earlier bridge revision built is rebuilt now.
128
+ const outdated = bridgeSurfaceOutdated(session);
129
+ // The tools just resolved are the whole authority: no earlier catalog, MCP
130
+ // availability snapshot or pending MCP delta survives. (A bridge surface
131
+ // re-takes the snapshot at its next request boundary; a native agent has no
132
+ // refresh, so a stale snapshot would hide a connected server's tools.)
133
+ delete session.deferredToolCatalog;
134
+ delete session.deferredLateToolCatalog;
135
+ delete session.deferredMcpToolNames;
136
+ delete session.pendingDeferredToolDelta;
137
+ if (bridge) {
138
+ // The resolved list may be shared (prepared-resume cache): rebuild a copy.
139
+ session.tools = session.tools.slice();
140
+ applyDeferredToolSurface(session, 'full', [], { provider: session.provider, model: session.model });
141
+ } else {
142
+ for (const field of AGENT_BRIDGE_FIELDS) delete session[field];
143
+ // Without bridge state the fixed slot composes empty: the guidance goes.
144
+ if (Array.isArray(session.messages)) applyInitialDeferredToolManifestToBp2(session, [], { rebuild: true });
145
+ delete session.deferredToolBp2Applied;
146
+ }
147
+ const changed = before !== sessionToolExposure(session) || outdated;
148
+ if (existing && changed) markToolSurfaceMigrated(session);
149
+ return changed;
150
+ }
@@ -8,6 +8,7 @@ import { traceLoopPhaseTiming } from './diagnostics.mjs';
8
8
  import { processToolBatch } from '../tool-batch.mjs';
9
9
  import { CROSS_TURN_CAP, REPEAT_FAIL_LIMIT } from './loop-state.mjs';
10
10
  import { markStepEffort } from './step-auto-effort.mjs';
11
+ import { resolveExecutionToolCalls } from './tool-call-resolution.mjs';
11
12
 
12
13
  function isSleepLikeToolCall(call) {
13
14
  const name = String(call?.name || call?.toolName || call?.function?.name || '').toLowerCase();
@@ -34,7 +35,9 @@ export async function runToolPhase(state, round, sent, onToolCall) {
34
35
  }
35
36
  // Per-turn batch shape — one row per assistant turn so trace consumers can
36
37
  // derive the multi-tool adoption ratio without scanning message bodies.
37
- const toolBatchId = recordToolBatch(sessionId, calls, state.iterations);
38
+ // Audit records what runs: a bridged call_tool is recorded as its target.
39
+ // The wire calls stay the transcript identity (assistant turn below).
40
+ const toolBatchId = recordToolBatch(sessionId, resolveExecutionToolCalls(calls, sessionRef), state.iterations);
38
41
  await Promise.resolve(onToolCall?.(state.iterations, calls));
39
42
  const assistantTurnMsg = buildToolCallAssistantMessage(response, { calls, suppressMidTurnText, opts });
40
43
  commitAssistantMessage(messages, assistantTurnMsg, opts);
@@ -70,7 +73,9 @@ export async function runToolPhase(state, round, sent, onToolCall) {
70
73
  // carries a runtime notice for the model, delivered after its results.
71
74
  if (response.recoveryNotice) messages.push(response.recoveryNotice);
72
75
  const toolsEndedAt = Date.now();
73
- await markStepEffort(state, assistantTurnMsg);
76
+ // Starts the step judgment; the next request uses it if it has resolved by
77
+ // then (send-phase.mjs applyStepEffort), else the one after.
78
+ markStepEffort(state, assistantTurnMsg);
74
79
  try {
75
80
  opts.onToolPhaseCompleted?.({
76
81
  iteration: round.nextIteration,
@@ -54,6 +54,12 @@ export function createAskPromptQueue({ sessionId, promptSource }) {
54
54
  // after each turn — keeps queued `agent type=send` messages in order.
55
55
  const tail = [];
56
56
  let initialPromptSource = initialPromptSourceFor(promptSource);
57
+ // Queue entries of the input nextTurn handed out that no turn owns yet.
58
+ // Once a turn starts, its failure path acks or releases them instead.
59
+ let unstartedEntries = [];
60
+ const release = (entries) => {
61
+ if (entries?.length > 0) releasePendingMessages(sessionId, entries);
62
+ };
57
63
 
58
64
  /** The next turn's input — prompt, caller context, consumed queue entries
59
65
  * and provenance — or null when nothing model-visible is left to run. */
@@ -83,7 +89,26 @@ export function createAskPromptQueue({ sessionId, promptSource }) {
83
89
  tail.unshift(...groups.slice(1).map(tailTurnFor));
84
90
  input = queuedTurnInput(tailTurnFor(first));
85
91
  }
86
- return hasModelVisiblePromptContent(input.prompt) ? input : null;
92
+ if (!hasModelVisiblePromptContent(input.prompt)) {
93
+ release(input.pendingEntries);
94
+ return null;
95
+ }
96
+ unstartedEntries = input.pendingEntries;
97
+ return input;
98
+ };
99
+
100
+ /** The turn for the last nextTurn input started: it now owns its entries. */
101
+ const markStarted = () => {
102
+ unstartedEntries = [];
103
+ };
104
+
105
+ /** Hands every drained entry no turn started back to the pending queue —
106
+ * the waiting follow-up turns and an input whose turn never opened.
107
+ * Called once when the ask unwinds; each entry is released once. */
108
+ const releaseUnstarted = () => {
109
+ const entries = [...unstartedEntries, ...tail.splice(0).flatMap((turn) => turn.entries || [])];
110
+ unstartedEntries = [];
111
+ release(entries);
87
112
  };
88
113
 
89
114
  /** Queues drained pending-message entries as follow-up turns; true when
@@ -101,5 +126,8 @@ export function createAskPromptQueue({ sessionId, promptSource }) {
101
126
  return true;
102
127
  };
103
128
 
104
- return { nextTurn, pushDrained };
129
+ /** True while drained follow-up turns are still waiting to run. */
130
+ const hasQueuedTurns = () => tail.length > 0;
131
+
132
+ return { nextTurn, pushDrained, hasQueuedTurns, markStarted, releaseUnstarted };
105
133
  }