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
@@ -3,7 +3,7 @@ import { types } from 'node:util';
3
3
  import { clean } from './session-text.mjs';
4
4
  import { isDeferredToolAvailable } from './deferred-tool-availability.mjs';
5
5
  import { finalizeProviderRequestTools } from './provider-request-tools.mjs';
6
- import { parseToolSelection, ANTHROPIC_NATIVE_PROVIDERS } from './tool-catalog-schema.mjs';
6
+ import { parseToolSelection, nativeProviderFamily, ANTHROPIC_NATIVE_PROVIDERS } from './tool-catalog-schema.mjs';
7
7
 
8
8
  const OMIT_REQUEST_TOOL_VALUE = Symbol('omit-request-tool-value');
9
9
  const MAX_PROVIDER_SNAPSHOT_ARRAY_LENGTH = 1_000_000;
@@ -378,9 +378,13 @@ const requestToolSnapshotMemo = new WeakMap();
378
378
  export function snapshotProviderRequestTools(options = {}) {
379
379
  const { provider, tools, nativeTools, messages, session } = options;
380
380
  const normalizedProvider = clean(provider || session?.provider).toLowerCase();
381
- const anthropic = ANTHROPIC_NATIVE_PROVIDERS.has(normalizedProvider);
381
+ // Server-hosted definitions stay first-party Anthropic only; defer_loading
382
+ // expansion follows the session's native family, which a gateway gets from
383
+ // its pinned Messages route with verified support.
384
+ const firstPartyAnthropic = ANTHROPIC_NATIVE_PROVIDERS.has(normalizedProvider);
385
+ const anthropic = nativeProviderFamily(normalizedProvider, session?.wireRoute) === 'anthropic';
382
386
  const activeTools = entriesOf(tools);
383
- const nativeList = anthropic ? entriesOf(nativeTools) : NO_ENTRIES;
387
+ const nativeList = firstPartyAnthropic ? entriesOf(nativeTools) : NO_ENTRIES;
384
388
  const mcpNames = Array.isArray(session?.deferredMcpToolNames) ? session.deferredMcpToolNames : null;
385
389
  let base = Array.isArray(tools) ? requestToolSnapshotMemo.get(tools) : null;
386
390
  if (
@@ -15,6 +15,26 @@ function hasMeaningfulTitleText(value) {
15
15
  return /[\p{L}\p{N}]/u.test(String(value || ''));
16
16
  }
17
17
 
18
+ const graphemeSegmenter =
19
+ typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'
20
+ ? new Intl.Segmenter(undefined, { granularity: 'grapheme' })
21
+ : null;
22
+
23
+ /** The longest prefix of `text` within `limit` UTF-16 units that ends on a
24
+ * grapheme (else code point) boundary, so a surrogate pair or emoji sequence
25
+ * is never split. */
26
+ function prefixWithinLimit(text, limit) {
27
+ const pieces = graphemeSegmenter
28
+ ? Array.from(graphemeSegmenter.segment(text), (part) => part.segment)
29
+ : Array.from(text);
30
+ let head = '';
31
+ for (const piece of pieces) {
32
+ if (head.length + piece.length > limit) break;
33
+ head += piece;
34
+ }
35
+ return head;
36
+ }
37
+
18
38
  export function compactSessionTitle(value, maximum = 32) {
19
39
  const line =
20
40
  String(value || '')
@@ -25,7 +45,7 @@ export function compactSessionTitle(value, maximum = 32) {
25
45
  const text = cleanSessionPreview(line, Math.max(maximum * 4, 128));
26
46
  if (!hasMeaningfulTitleText(text)) return '';
27
47
  if (text.length <= maximum) return text;
28
- const clipped = text.slice(0, maximum - 1);
48
+ const clipped = prefixWithinLimit(text, maximum - 1);
29
49
  const boundary = clipped.lastIndexOf(' ');
30
50
  const head = boundary >= Math.floor(maximum * 0.6) ? clipped.slice(0, boundary) : clipped;
31
51
  return `${head.trimEnd()}…`;
@@ -3,6 +3,7 @@
3
3
  import { deferredCatalogUnion, selectDeferredTools, toolSearchNativePayload } from './tool-catalog.mjs';
4
4
  import { preDispatchDenyForSession } from '../session/loop/pre-dispatch-deny.mjs';
5
5
  import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
6
+ import { isToolBridgeEnabled } from './tool-exposure.mjs';
6
7
 
7
8
  export function loadSkillToolDependencies(envelope, session, mode) {
8
9
  if (!envelope?.__toolEnvelope) return envelope;
@@ -46,11 +47,22 @@ export function loadSkillToolDependencies(envelope, session, mode) {
46
47
  if (loaded.length) {
47
48
  session.skillLoadedTools = [...new Set([...(session.skillLoadedTools || []), ...loaded])];
48
49
  }
50
+ const eager = new Set((session?.tools || []).map((tool) => tool.name));
51
+ // Bridge exposure never promotes a schema: deferred dependencies stay
52
+ // reachable through call_tool while the eager surface keeps its bytes.
53
+ const bridged = isToolBridgeEnabled(session) ? loaded.filter((name) => !eager.has(name)) : [];
54
+ const direct = loaded.filter((name) => !bridged.includes(name));
49
55
  const summary = [
50
56
  envelope.result,
51
- ...(loaded.length
57
+ ...(direct.length && !isToolBridgeEnabled(session)
52
58
  ? [
53
- `Required tools loaded: ${loaded.join(', ')}. Their full definitions are available on your next request; use them directly without load_tool.`,
59
+ `Required tools loaded: ${direct.join(', ')}. Their full definitions are available on your next request; use them directly without load_tool.`,
60
+ ]
61
+ : []),
62
+ ...(direct.length && isToolBridgeEnabled(session) ? [`Required tools available directly: ${direct.join(', ')}.`] : []),
63
+ ...(bridged.length
64
+ ? [
65
+ `Required tools available through call_tool: ${bridged.join(', ')}. Read a definition with load_tool, then run it with call_tool {name, arguments}.`,
54
66
  ]
55
67
  : []),
56
68
  ...(unavailable.length
@@ -60,7 +72,6 @@ export function loadSkillToolDependencies(envelope, session, mode) {
60
72
  ]
61
73
  : []),
62
74
  ].join('\n');
63
- const eager = new Set((session?.tools || []).map((tool) => tool.name));
64
75
  const native = selection?.native
65
76
  ? toolSearchNativePayload(
66
77
  [...catalog.values()],
@@ -0,0 +1,526 @@
1
+ // Fixed tool bridge for sessions whose toolExposureMode is 'bridge-v1'
2
+ // (non-native providers, see tool-exposure.mjs): the shared load_tool
3
+ // describes tools by name (never loads them), and call_tool runs one target
4
+ // through the ordinary execution pipeline (the loop projects it into a call
5
+ // of the target itself, see session/loop/tool-call-resolution.mjs). The
6
+ // deferred roster names what exists. Discovery and description never grant
7
+ // execution permission; continuation tokens only carry a position and grant
8
+ // no authority.
9
+ import { createHash } from 'node:crypto';
10
+ import { clean } from './session-text.mjs';
11
+ import { isDeferredToolAvailable } from './deferred-tool-availability.mjs';
12
+ import {
13
+ deferredCatalogUnion,
14
+ filterSessionToolPolicy,
15
+ isReadonlySelectable,
16
+ toolSearchMatches,
17
+ } from './tool-catalog.mjs';
18
+ import { parseToolSelection, sortedCatalogByMeasuredUsage } from './tool-catalog-schema.mjs';
19
+ import { DEFERRED_SELECT_ALIASES } from './tool-catalog-data.mjs';
20
+ import { estimateTokens } from '../session/token-estimate.mjs';
21
+ import { preDispatchDenyForSession } from '../session/loop/pre-dispatch-deny.mjs';
22
+ import { resolveDeferredSelectMode } from '../session/loop/deferred-call-through.mjs';
23
+ import { providerToolExclusionReason, routeToolExclusionReason } from '../session/loop/provider-tool-exclusions.mjs';
24
+
25
+ export { isToolBridgeEnabled } from './tool-exposure.mjs';
26
+
27
+ export const BRIDGE_LOAD_TOOL_NAME = 'load_tool';
28
+ export const BRIDGE_CALL_TOOL_NAME = 'call_tool';
29
+ // Names call_tool may never target and search never lists.
30
+ const BRIDGE_META_TOOL_NAMES = new Set(['load_tool', 'call_tool', 'tool_search']);
31
+
32
+ const DESCRIBE_MAX_NAMES = 8;
33
+ // Most definitions one request resolves to: every name an alias of the widest
34
+ // alias. A token naming more was not issued by this tool.
35
+ const MAX_ALIAS_MEMBERS = Math.max(1, ...Object.values(DEFERRED_SELECT_ALIASES).map((members) => members.length));
36
+
37
+ export const BRIDGE_LIMITS = Object.freeze({
38
+ nameMaxChars: 256,
39
+ continuationMaxChars: 4096,
40
+ continuationMaxTargets: DESCRIBE_MAX_NAMES * MAX_ALIAS_MEMBERS,
41
+ describeMaxNames: DESCRIBE_MAX_NAMES,
42
+ describeMaxBytes: 16 * 1024,
43
+ describeMaxTokens: 4096,
44
+ });
45
+
46
+ // A continuation token travels in load_tool's own `names` field. Provider tool
47
+ // names never contain '@' or ':', so the prefix cannot name a tool.
48
+ export const BRIDGE_CONTINUATION_PREFIX = '@continue:';
49
+
50
+ const DESCRIBE_KEYS = new Set(['names']);
51
+ // What a bridge describe result tells the model to do with the definitions.
52
+ const DESCRIBE_NOTE =
53
+ 'Run a deferred tool with call_tool {name, arguments}; call directly defined tools directly. When continueWith is set, call load_tool again with exactly those arguments for the rest.';
54
+
55
+ export function bridgeError(code, message) {
56
+ return { error: { code, message } };
57
+ }
58
+
59
+ export function bridgeErrorText(code, message) {
60
+ return `Error: ${code}: ${message}`;
61
+ }
62
+
63
+ /** Model-visible text for a bridge result object. */
64
+ export function formatBridgeResult(result) {
65
+ if (result?.error) return bridgeErrorText(result.error.code, result.error.message);
66
+ return JSON.stringify(result);
67
+ }
68
+
69
+ const isPlainObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
70
+ const hashText = (text) => createHash('sha256').update(text).digest('hex').slice(0, 16);
71
+
72
+ function unknownKeysError(args, allowed, toolName) {
73
+ if (!isPlainObject(args)) return bridgeError('INVALID_ARGUMENTS', `${toolName} requires an arguments object.`);
74
+ const extra = Object.keys(args).filter((key) => !allowed.has(key));
75
+ if (!extra.length) return null;
76
+ return bridgeError('INVALID_ARGUMENTS', `${toolName} does not accept: ${extra.join(', ')}.`);
77
+ }
78
+
79
+ function fitsBudget(value, maxBytes, maxTokens) {
80
+ const text = JSON.stringify(value);
81
+ return Buffer.byteLength(text, 'utf8') <= maxBytes && estimateTokens(text) <= maxTokens;
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Continuation tokens: prefix + base64url JSON of the definitions still being
86
+ // paged (their indexes in the session's own available-tool list), their
87
+ // schema revision and the offset into the first of them. Requested, missing
88
+ // and blocked names never travel, so a token stays far below the decoder
89
+ // bound whatever names the request carried.
90
+
91
+ function encodeContinuation(indexes, revision, offset) {
92
+ const payload = Buffer.from(JSON.stringify({ v: 2, t: indexes, r: revision, o: offset }), 'utf8');
93
+ return `${BRIDGE_CONTINUATION_PREFIX}${payload.toString('base64url')}`;
94
+ }
95
+
96
+ // Longest token a page over `count` definitions of `available` tools can emit,
97
+ // used to reserve room while filling it.
98
+ const reserveContinuation = (count, available) =>
99
+ encodeContinuation(Array(count).fill(available), 'f'.repeat(16), 99_999_999);
100
+
101
+ const invalidContinuation = () =>
102
+ bridgeError('INVALID_CONTINUATION', 'names holds a continuation token this tool did not return.');
103
+
104
+ // The token's payload, or an error; the revision is checked once the names resolve.
105
+ function decodeContinuation(token) {
106
+ if (token.length > BRIDGE_LIMITS.continuationMaxChars) return invalidContinuation();
107
+ let payload = null;
108
+ try {
109
+ const body = token.slice(BRIDGE_CONTINUATION_PREFIX.length);
110
+ const bytes = Buffer.from(body, 'base64url');
111
+ // Only the canonical encoding this tool emits is accepted.
112
+ if (bytes.toString('base64url') !== body) return invalidContinuation();
113
+ payload = JSON.parse(bytes.toString('utf8'));
114
+ } catch {
115
+ payload = null;
116
+ }
117
+ const indexes = payload?.t;
118
+ if (
119
+ payload?.v !== 2 ||
120
+ typeof payload.r !== 'string' ||
121
+ !isIndex(payload.o) ||
122
+ !Array.isArray(indexes) ||
123
+ !indexes.length ||
124
+ indexes.length > BRIDGE_LIMITS.continuationMaxTargets ||
125
+ !indexes.every(isIndex) ||
126
+ new Set(indexes).size !== indexes.length
127
+ ) {
128
+ return invalidContinuation();
129
+ }
130
+ return { indexes, revision: payload.r, offset: payload.o };
131
+ }
132
+
133
+ // A whole names value that is exactly one token: no padding, separators or other text.
134
+ const CONTINUATION_TOKEN_PATTERN = new RegExp(`^\\s*${BRIDGE_CONTINUATION_PREFIX}[A-Za-z0-9_-]+\\s*$`);
135
+
136
+ const catalogChanged = () =>
137
+ bridgeError(
138
+ 'CATALOG_CHANGED',
139
+ 'the described tools or their schemas changed since this continuation was issued; describe them again by name.'
140
+ );
141
+
142
+ // The `continueWith` arguments for the definitions still to page.
143
+ function continuationFor(remaining, offset, revisionOf) {
144
+ const token = encodeContinuation(
145
+ remaining.map((doc) => doc.index),
146
+ revisionOf(remaining),
147
+ offset
148
+ );
149
+ return { names: token };
150
+ }
151
+
152
+ // A token's definitions in the session's current scope, or null when any is
153
+ // gone or now refused (the session changed; the token grants nothing).
154
+ function continuationTargets(session, indexes, available, mode) {
155
+ const eagerNames = eagerToolNames(session);
156
+ const tools = indexes.map((index) => available[index]);
157
+ if (tools.some((tool) => !tool || bridgeBlockReason(session, tool, mode, eagerNames))) return null;
158
+ return tools;
159
+ }
160
+
161
+ const isIndex = (value) => Number.isSafeInteger(value) && value >= 0;
162
+
163
+ // ---------------------------------------------------------------------------
164
+ // Session catalog: eager surface + deferred catalog union, current scope only.
165
+
166
+ function eagerToolNames(session) {
167
+ return new Set((Array.isArray(session?.tools) ? session.tools : []).map((tool) => clean(tool?.name)).filter(Boolean));
168
+ }
169
+
170
+ /**
171
+ * Every tool currently available to the session (eager first wins), within
172
+ * its own policy: a tool its allowlist or denied tools exclude is unknown
173
+ * here (never described, listed or named as blocked).
174
+ */
175
+ function availableBridgeTools(session) {
176
+ const eager = Array.isArray(session?.tools) ? session.tools : [];
177
+ const seen = new Set();
178
+ const out = [];
179
+ for (const tool of filterSessionToolPolicy([...eager, ...deferredCatalogUnion(session)], session)) {
180
+ const name = clean(tool?.name);
181
+ if (!name || seen.has(name) || !isDeferredToolAvailable(session, name)) continue;
182
+ seen.add(name);
183
+ out.push(tool);
184
+ }
185
+ return sortedCatalogByMeasuredUsage(out);
186
+ }
187
+
188
+ export function isBridgeReadonlySession(session, mode) {
189
+ return (
190
+ mode === 'readonly' ||
191
+ session?.deferredSurfaceMode === 'readonly' ||
192
+ resolveDeferredSelectMode(session) === 'readonly'
193
+ );
194
+ }
195
+
196
+ // Why a currently available tool cannot run in this session, or null. Eager
197
+ // tools already passed the surface's own readonly filter.
198
+ function bridgeBlockReason(session, tool, mode, eagerNames) {
199
+ const name = clean(tool?.name);
200
+ const denial = preDispatchDenyForSession(session, { name, arguments: {} });
201
+ if (denial) return denial.replace(/^Error:\s*/, '');
202
+ // An eager tool the route never sends is not "directly available"; deferred
203
+ // ones run through call_tool and need no declaration.
204
+ const unsent = eagerNames.has(name) ? routeToolExclusionReason(session, tool) : null;
205
+ if (unsent) return unsent;
206
+ if (!eagerNames.has(name) && isBridgeReadonlySession(session, mode) && !isReadonlySelectable(tool)) {
207
+ return 'readonly mode';
208
+ }
209
+ return null;
210
+ }
211
+
212
+ function lookupByName(tools, name) {
213
+ const key = clean(name);
214
+ if (!key) return null;
215
+ const lower = key.toLowerCase();
216
+ return (
217
+ tools.find((tool) => clean(tool?.name) === key) ||
218
+ tools.find((tool) => clean(tool?.name).toLowerCase() === lower) ||
219
+ null
220
+ );
221
+ }
222
+
223
+ // ---------------------------------------------------------------------------
224
+ // load_tool (bridge mode): describe only.
225
+
226
+ const schemaRevisionOf = (document) => hashText(JSON.stringify(document));
227
+
228
+ // An offset between the halves of a surrogate pair is not a code point boundary.
229
+ function splitsSurrogatePair(text, offset) {
230
+ if (offset <= 0 || offset >= text.length) return false;
231
+ const before = text.charCodeAt(offset - 1);
232
+ const after = text.charCodeAt(offset);
233
+ return before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff;
234
+ }
235
+
236
+ function toolDocument(tool) {
237
+ return {
238
+ name: clean(tool?.name),
239
+ description: typeof tool?.description === 'string' ? tool.description : '',
240
+ inputSchema:
241
+ tool?.inputSchema && typeof tool.inputSchema === 'object' ? tool.inputSchema : { type: 'object', properties: {} },
242
+ annotations: isPlainObject(tool?.annotations) ? tool.annotations : {},
243
+ };
244
+ }
245
+
246
+ function describeNames(raw) {
247
+ if (typeof raw !== 'string' && (!Array.isArray(raw) || raw.some((item) => typeof item !== 'string'))) return null;
248
+ const names = [...new Set(parseToolSelection(raw))];
249
+ if (!names.length || names.length > BRIDGE_LIMITS.describeMaxNames) return null;
250
+ if (names.some((name) => name.length > BRIDGE_LIMITS.nameMaxChars)) return null;
251
+ return names;
252
+ }
253
+
254
+ // Requested names → available tools; an alias that names no tool expands to
255
+ // its members (existing load_tool alias compatibility).
256
+ function resolveDescribeTargets(session, names, mode, available) {
257
+ const eagerNames = eagerToolNames(session);
258
+ const targets = [];
259
+ const missing = [];
260
+ const blocked = [];
261
+ const seen = new Set();
262
+ const add = (tool) => {
263
+ const name = clean(tool?.name);
264
+ if (seen.has(name)) return;
265
+ seen.add(name);
266
+ const reason = bridgeBlockReason(session, tool, mode, eagerNames);
267
+ if (reason) blocked.push({ name, reason });
268
+ else targets.push(tool);
269
+ };
270
+ for (const requested of names) {
271
+ const tool = lookupByName(available, requested);
272
+ if (tool) {
273
+ add(tool);
274
+ continue;
275
+ }
276
+ const members = (DEFERRED_SELECT_ALIASES[requested.toLowerCase()] || [])
277
+ .map((member) => lookupByName(available, member))
278
+ .filter(Boolean);
279
+ if (members.length) members.forEach(add);
280
+ else missing.push(requested);
281
+ }
282
+ return { targets, missing, blocked };
283
+ }
284
+
285
+ const SEARCH_MAX_MATCHES = 20;
286
+ const SEARCH_DESCRIPTION_CHARS = 100;
287
+
288
+ // A requested name that is no tool is a keyword: a case-insensitive substring
289
+ // search over the deferred tools this session can run (the same availability,
290
+ // allow/deny and read-only rules as a lookup, so nothing the session cannot
291
+ // run is ever listed). Keywords with no hit stay in `missing`.
292
+ function searchKeywords(session, keywords, mode, available) {
293
+ const eagerNames = eagerToolNames(session);
294
+ const matches = [];
295
+ const missing = [];
296
+ let remaining = SEARCH_MAX_MATCHES;
297
+ for (const keyword of keywords) {
298
+ const tools = available
299
+ .filter((tool) => {
300
+ const name = clean(tool?.name);
301
+ return (
302
+ !eagerNames.has(name) &&
303
+ !BRIDGE_META_TOOL_NAMES.has(name.toLowerCase()) &&
304
+ toolSearchMatches(tool, keyword) &&
305
+ !bridgeBlockReason(session, tool, mode, eagerNames)
306
+ );
307
+ })
308
+ .slice(0, remaining)
309
+ .map((tool) => ({
310
+ name: clean(tool.name),
311
+ description: clean(tool.description).slice(0, SEARCH_DESCRIPTION_CHARS),
312
+ }));
313
+ if (!tools.length) {
314
+ missing.push(keyword);
315
+ continue;
316
+ }
317
+ remaining -= tools.length;
318
+ matches.push({ keyword, tools });
319
+ }
320
+ return { matches, missing };
321
+ }
322
+
323
+ // Largest code-point-aligned chunk of `text` from `offset` that keeps the page
324
+ // within budget; 0 when nothing more fits.
325
+ function largestChunk(text, offset, buildPage) {
326
+ const fits = (length) =>
327
+ fitsBudget(
328
+ buildPage(text.slice(offset, offset + length)),
329
+ BRIDGE_LIMITS.describeMaxBytes,
330
+ BRIDGE_LIMITS.describeMaxTokens
331
+ );
332
+ let low = 0;
333
+ let high = text.length - offset;
334
+ while (low < high) {
335
+ const middle = Math.ceil((low + high) / 2);
336
+ if (fits(middle)) low = middle;
337
+ else high = middle - 1;
338
+ }
339
+ // Never end a chunk between the halves of a surrogate pair (UTF-8 boundary).
340
+ const last = text.charCodeAt(offset + low - 1);
341
+ if (low > 0 && offset + low < text.length && last >= 0xd800 && last <= 0xdbff) low -= 1;
342
+ return low;
343
+ }
344
+
345
+ export function describeBridgeTools(session, args = {}, { mode } = {}) {
346
+ const invalid = unknownKeysError(args, DESCRIBE_KEYS, BRIDGE_LOAD_TOOL_NAME);
347
+ if (invalid) {
348
+ const hint = isPlainObject(args) && 'query' in args ? ' Pass exact names; the deferred tool list names them.' : '';
349
+ return bridgeError(invalid.error.code, `${invalid.error.message}${hint}`);
350
+ }
351
+ // A continuation token resumes an earlier request. It travels alone: names
352
+ // is split exactly as for a lookup, and a token beside any other value is
353
+ // refused rather than read as a missing name.
354
+ const raw = args.names;
355
+ const strings =
356
+ typeof raw === 'string' ? [raw] : Array.isArray(raw) && raw.every((item) => typeof item === 'string') ? raw : [];
357
+ let continuation = null;
358
+ if (strings.some((item) => item.includes(BRIDGE_CONTINUATION_PREFIX))) {
359
+ if (strings.length !== 1 || !CONTINUATION_TOKEN_PATTERN.test(strings[0])) {
360
+ return bridgeError('INVALID_ARGUMENTS', 'pass a continuation token alone in names.');
361
+ }
362
+ continuation = decodeContinuation(strings[0].trim());
363
+ if (continuation.error) return continuation;
364
+ }
365
+ const available = availableBridgeTools(session);
366
+ let targets;
367
+ let missing = [];
368
+ let blocked = [];
369
+ let matches = [];
370
+ if (continuation) {
371
+ targets = continuationTargets(session, continuation.indexes, available, mode);
372
+ if (!targets) return catalogChanged();
373
+ } else {
374
+ const names = describeNames(raw);
375
+ if (!names) {
376
+ return bridgeError(
377
+ 'INVALID_ARGUMENTS',
378
+ `names must be 1-${BRIDGE_LIMITS.describeMaxNames} exact tool names of at most ${BRIDGE_LIMITS.nameMaxChars} characters.`
379
+ );
380
+ }
381
+ ({ targets, missing, blocked } = resolveDescribeTargets(session, names, mode, available));
382
+ ({ matches, missing } = searchKeywords(session, missing, mode, available));
383
+ }
384
+ const found = matches.length ? { matches } : {};
385
+ const docs = targets.map((tool) => {
386
+ const document = toolDocument(tool);
387
+ return {
388
+ index: available.indexOf(tool),
389
+ name: document.name,
390
+ schemaRevision: schemaRevisionOf(document),
391
+ value: document,
392
+ text: JSON.stringify(document),
393
+ };
394
+ });
395
+ const revisionOf = (list) => hashText(JSON.stringify(list.map((doc) => [doc.name, doc.schemaRevision])));
396
+ let entryIndex = 0;
397
+ let offset = 0;
398
+ if (continuation) {
399
+ if (continuation.revision !== revisionOf(docs)) return catalogChanged();
400
+ const at = continuation.offset;
401
+ if (at > docs[0].text.length || splitsSurrogatePair(docs[0].text, at)) return invalidContinuation();
402
+ offset = at;
403
+ }
404
+ const entries = [];
405
+ const reserve = { names: reserveContinuation(docs.length, available.length) };
406
+ const page = (extra) => ({
407
+ entries: [...entries, extra],
408
+ missing,
409
+ blocked,
410
+ ...found,
411
+ note: DESCRIBE_NOTE,
412
+ continueWith: reserve,
413
+ });
414
+ const fits = (value) => fitsBudget(value, BRIDGE_LIMITS.describeMaxBytes, BRIDGE_LIMITS.describeMaxTokens);
415
+ let nextPosition = null;
416
+ for (; entryIndex < docs.length; entryIndex += 1, offset = 0) {
417
+ const doc = docs[entryIndex];
418
+ const head = { name: doc.name, schemaRevision: doc.schemaRevision };
419
+ if (offset === 0) {
420
+ const whole = { ...head, complete: true, document: doc.value };
421
+ if (fits(page(whole))) {
422
+ entries.push(whole);
423
+ continue;
424
+ }
425
+ // A document that fits on a page of its own starts the next page whole.
426
+ if (
427
+ entries.length &&
428
+ fits({ entries: [whole], missing, blocked, ...found, note: DESCRIBE_NOTE, continueWith: reserve })
429
+ ) {
430
+ nextPosition = [entryIndex, 0];
431
+ break;
432
+ }
433
+ }
434
+ const chunkEntry = (chunk) => ({
435
+ ...head,
436
+ complete: offset + chunk.length >= doc.text.length,
437
+ offset,
438
+ jsonTextChunk: chunk,
439
+ });
440
+ const length = largestChunk(doc.text, offset, (chunk) => page(chunkEntry(chunk)));
441
+ if (length === 0) {
442
+ if (!entries.length) return bridgeError('RESULT_TOO_LARGE', 'the description cannot fit in one result.');
443
+ nextPosition = [entryIndex, offset];
444
+ break;
445
+ }
446
+ const chunk = doc.text.slice(offset, offset + length);
447
+ entries.push(chunkEntry(chunk));
448
+ if (offset + length < doc.text.length) {
449
+ nextPosition = [entryIndex, offset + length];
450
+ break;
451
+ }
452
+ }
453
+ const continueWith = nextPosition ? continuationFor(docs.slice(nextPosition[0]), nextPosition[1], revisionOf) : null;
454
+ // Never hand out a token the decoder would refuse.
455
+ if (continueWith && continueWith.names.length > BRIDGE_LIMITS.continuationMaxChars) {
456
+ return bridgeError(
457
+ 'RESULT_TOO_LARGE',
458
+ 'the remaining definitions cannot be continued; describe fewer tools at once.'
459
+ );
460
+ }
461
+ return { entries, missing, blocked, ...found, note: DESCRIBE_NOTE, continueWith };
462
+ }
463
+
464
+ // ---------------------------------------------------------------------------
465
+ // call_tool target resolution (session-scoped; rechecked at execution).
466
+
467
+ function catalogTool(session, name) {
468
+ return lookupByName(deferredCatalogUnion(session), name);
469
+ }
470
+
471
+ /**
472
+ * The deferred tool a call_tool request names, or an error. Policy (allow /
473
+ * deny, readonly, worker scoping, approvals) is left to the target's ordinary
474
+ * execution path so a bridged call is judged exactly like a direct one.
475
+ */
476
+ export function resolveBridgeTarget(session, rawName) {
477
+ const name = typeof rawName === 'string' ? rawName.trim() : '';
478
+ if (!name || name.length > BRIDGE_LIMITS.nameMaxChars) {
479
+ return bridgeError('INVALID_ARGUMENTS', `name must be 1-${BRIDGE_LIMITS.nameMaxChars} characters.`);
480
+ }
481
+ if (BRIDGE_META_TOOL_NAMES.has(name.toLowerCase())) {
482
+ return bridgeError('BRIDGE_RECURSION', `call_tool cannot run the bridge tool "${name}"; call it directly.`);
483
+ }
484
+ const eager = lookupByName(Array.isArray(session?.tools) ? session.tools : [], name);
485
+ if (eager) {
486
+ const direct = clean(eager.name);
487
+ const excluded = providerToolExclusionReason(session, direct) || routeToolExclusionReason(session, eager);
488
+ if (excluded) return bridgeError('TOOL_EXCLUDED', excluded);
489
+ return bridgeError(
490
+ 'USE_DIRECT_TOOL',
491
+ `"${direct}" is directly available; call ${direct} directly instead of call_tool.`
492
+ );
493
+ }
494
+ const tool = catalogTool(session, name);
495
+ if (!tool) {
496
+ return bridgeError(
497
+ 'TOOL_NOT_FOUND',
498
+ `no tool named "${name}" is available in this session; find tools with load_tool {names: keyword}.`
499
+ );
500
+ }
501
+ const canonical = clean(tool.name);
502
+ if (!isDeferredToolAvailable(session, canonical)) {
503
+ return bridgeError(
504
+ 'TOOL_UNAVAILABLE',
505
+ `tool "${canonical}" is unavailable in the current session catalog; no call was sent.`
506
+ );
507
+ }
508
+ return { name: canonical, tool };
509
+ }
510
+
511
+ /** Execution-time recheck of a projected target (after hooks), or null. */
512
+ export function bridgeTargetUnavailable(session, name) {
513
+ const key = clean(name);
514
+ if (lookupByName(Array.isArray(session?.tools) ? session.tools : [], key)) return null;
515
+ const tool = catalogTool(session, key);
516
+ if (!tool) {
517
+ return bridgeErrorText('TOOL_NOT_FOUND', `no tool named "${key}" is available in this session; no call was sent.`);
518
+ }
519
+ if (!isDeferredToolAvailable(session, clean(tool.name))) {
520
+ return bridgeErrorText(
521
+ 'TOOL_UNAVAILABLE',
522
+ `tool "${clean(tool.name)}" is unavailable in the current session catalog; no call was sent.`
523
+ );
524
+ }
525
+ return null;
526
+ }
@@ -74,6 +74,9 @@ export const DEFERRED_DEFAULT_LEAD_TOOLS = Object.freeze([
74
74
  'shell',
75
75
  'task',
76
76
  'agent',
77
+ // Always on the Lead surface (native and bridge alike): a question is an
78
+ // optional move the model skips when it costs a load or call_tool hop.
79
+ 'ask_user',
77
80
  'Skill',
78
81
  'load_tool',
79
82
  ]);