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
@@ -0,0 +1,183 @@
1
+ // Shared by xai-tool-search.test.mjs and the one-off generator that produced
2
+ // xai-tool-search-head-parity.json by running these same captures against the
3
+ // pre-change xAI send path. The WebSocket transport is driven through the real
4
+ // sendViaWebSocket with a scripted socket, so the real stream collector and
5
+ // delta framing run; only the connection is replaced.
6
+ import { mock } from 'node:test';
7
+ import { EventEmitter } from 'node:events';
8
+ import * as realWs from './openai-oauth-ws.mjs';
9
+
10
+ export const ws = { bodies: [], frames: [], scripts: [] };
11
+
12
+ function scriptedEntry() {
13
+ const socket = new EventEmitter();
14
+ socket.readyState = 1;
15
+ socket.close = () => {
16
+ socket.readyState = 3;
17
+ };
18
+ socket.terminate = socket.close;
19
+ return { socket, ephemeral: true };
20
+ }
21
+
22
+ mock.module(new URL('./openai-oauth-ws.mjs', import.meta.url).href, {
23
+ namedExports: {
24
+ ...realWs,
25
+ sendViaWebSocket: (args) => {
26
+ ws.bodies.push(structuredClone(args.body));
27
+ return realWs.sendViaWebSocket({
28
+ ...args,
29
+ _acquireWithRetryFn: async () => ({ entry: scriptedEntry(), reused: false }),
30
+ _sendFrameFn: async (entry, frame) => {
31
+ ws.frames.push(structuredClone(frame));
32
+ const events = ws.scripts.shift() || [COMPLETED_REPLY];
33
+ setImmediate(() => {
34
+ for (const event of events) entry.socket.emit('message', Buffer.from(JSON.stringify(event)));
35
+ });
36
+ },
37
+ });
38
+ },
39
+ },
40
+ });
41
+
42
+ const { sendXaiResponses, sendXaiResponsesWebSocket } = await import('./openai-compat-xai-send.mjs');
43
+ const { nativeHistory, oauthHistory } = await import('./openai-compat-responses-parity.fixtures.mjs');
44
+ export { sendXaiResponses, sendXaiResponsesWebSocket, nativeHistory, oauthHistory };
45
+
46
+ export const REPLY = { type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'ok' }] };
47
+ export const COMPLETED_REPLY = {
48
+ type: 'response.completed',
49
+ response: { id: 'resp-1', model: 'grok-4', status: 'completed', output: [REPLY] },
50
+ };
51
+
52
+ // A recorded xAI server-side tool-search turn (shapes per xAI's OpenAPI schema
53
+ // ToolSearchCall / ToolSearchOutput: execution always "server", call_id null).
54
+ export const ENCRYPTED_REASONING = { type: 'reasoning', id: 'rs_1', encrypted_content: 'ENC', summary: [] };
55
+ export const TS_CALL = {
56
+ type: 'tool_search_call',
57
+ id: 'tsc_1',
58
+ call_id: null,
59
+ execution: 'server',
60
+ status: 'completed',
61
+ arguments: { query: 'mcp__weather__forecast', limit: 1 },
62
+ };
63
+ export const TS_OUTPUT = {
64
+ type: 'tool_search_output',
65
+ id: 'tso_1',
66
+ call_id: null,
67
+ execution: 'server',
68
+ status: 'completed',
69
+ tools: [
70
+ {
71
+ type: 'function',
72
+ name: 'mcp__weather__forecast',
73
+ description: 'Forecast',
74
+ parameters: { type: 'object', properties: { city: { type: 'string' } } },
75
+ defer_loading: true,
76
+ },
77
+ ],
78
+ };
79
+ export const FN_CALL = {
80
+ type: 'function_call',
81
+ id: 'fc_1',
82
+ call_id: 'call_w',
83
+ name: 'mcp__weather__forecast',
84
+ arguments: '{"city":"Seoul"}',
85
+ status: 'completed',
86
+ };
87
+ export const TURN_OUTPUT = [ENCRYPTED_REASONING, TS_CALL, TS_OUTPUT, FN_CALL];
88
+
89
+ /** The stream events one server tool-search turn emits, in wire order. */
90
+ export function serverSearchEvents(model = 'grok-4') {
91
+ return [
92
+ { type: 'response.created', response: { id: 'resp_ts', model } },
93
+ { type: 'response.output_item.done', item: ENCRYPTED_REASONING },
94
+ { type: 'response.output_item.added', item: { ...TS_CALL, status: 'in_progress' } },
95
+ { type: 'response.output_item.done', item: TS_CALL },
96
+ { type: 'response.output_item.added', item: TS_OUTPUT },
97
+ { type: 'response.output_item.done', item: TS_OUTPUT },
98
+ { type: 'response.output_item.added', item: { ...FN_CALL, arguments: '', status: 'in_progress' } },
99
+ { type: 'response.function_call_arguments.done', item_id: 'fc_1', arguments: FN_CALL.arguments },
100
+ { type: 'response.output_item.done', item: FN_CALL },
101
+ {
102
+ type: 'response.completed',
103
+ response: { id: 'resp_ts', model, status: 'completed', output: TURN_OUTPUT },
104
+ },
105
+ ];
106
+ }
107
+
108
+ export const SESSION_TOOLS = [
109
+ { name: 'Read', description: 'Read a file', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
110
+ { name: 'load_tool', description: 'Load tools', inputSchema: { type: 'object', properties: { names: { type: 'array' } } } },
111
+ ];
112
+ export const DEFERRED_TOOLS = [
113
+ ...SESSION_TOOLS,
114
+ {
115
+ name: 'mcp__weather__forecast',
116
+ description: 'Forecast',
117
+ inputSchema: { type: 'object', properties: { city: { type: 'string' } } },
118
+ deferLoading: true,
119
+ },
120
+ ];
121
+
122
+ export function xaiProvider(config = {}, events = null) {
123
+ const requests = [];
124
+ const provider = {
125
+ name: 'xai',
126
+ config: { apiKey: 'test-key', preconnect: false, ...config },
127
+ nativePdf: true,
128
+ client: {
129
+ responses: {
130
+ create: async (params) => {
131
+ requests.push(structuredClone(params));
132
+ return (async function* () {
133
+ for (const event of events || [COMPLETED_REPLY]) yield event;
134
+ })();
135
+ },
136
+ },
137
+ },
138
+ };
139
+ return { provider, requests };
140
+ }
141
+
142
+ /** The history left by a recorded server tool-search turn (replay owner xai-responses). */
143
+ export function serverSearchHistory() {
144
+ return [
145
+ { role: 'user', content: 'weather in Seoul?' },
146
+ {
147
+ role: 'assistant',
148
+ content: '',
149
+ toolCalls: [{ id: 'call_w', name: 'mcp__weather__forecast', arguments: { city: 'Seoul' } }],
150
+ providerReplay: { version: 1, provider: 'xai-responses', items: structuredClone(TURN_OUTPUT) },
151
+ },
152
+ { role: 'tool', toolCallId: 'call_w', content: 'sunny' },
153
+ { role: 'user', content: 'and Busan?' },
154
+ ];
155
+ }
156
+
157
+ export const CASES = [
158
+ ['native/plain-tools', () => nativeHistory(), SESSION_TOOLS],
159
+ ['oauth/plain-tools', () => oauthHistory(), SESSION_TOOLS],
160
+ ['server-replay/plain-tools', () => serverSearchHistory(), SESSION_TOOLS],
161
+ ['server-replay/deferred-tools', () => serverSearchHistory(), DEFERRED_TOOLS],
162
+ ['native/deferred-tools', () => nativeHistory(), DEFERRED_TOOLS],
163
+ ];
164
+
165
+ /** The request body each transport sends for `history`, plus any option overrides. */
166
+ export async function captureBodies(history, tools, { config = {}, opts = {} } = {}) {
167
+ const http = xaiProvider(config);
168
+ await sendXaiResponses(http.provider, history, 'grok-4', tools, { sessionId: 'sess-1', ...opts });
169
+ const before = ws.bodies.length;
170
+ const socket = xaiProvider(config);
171
+ await sendXaiResponsesWebSocket(socket.provider, history, 'grok-4', tools, { sessionId: 'sess-1', iteration: 1, ...opts });
172
+ return { http: http.requests[0], ws: ws.bodies[before] };
173
+ }
174
+
175
+ export async function captureAll() {
176
+ const out = {};
177
+ for (const [label, build, tools] of CASES) {
178
+ const { http, ws: socketBody } = await captureBodies(build(), tools);
179
+ out[`http/${label}`] = http;
180
+ out[`ws/${label}`] = socketBody;
181
+ }
182
+ return out;
183
+ }
@@ -0,0 +1,100 @@
1
+ export const ASK_USER_MAX_QUESTIONS = 4;
2
+ export const ASK_USER_MAX_TEXT = 4000;
3
+ export const ASK_USER_MAX_LABEL = 80;
4
+
5
+ export const ASK_USER_TOOL_DEFS = Object.freeze([
6
+ {
7
+ name: 'ask_user',
8
+ title: 'Ask User',
9
+ trigger: 'Ask the user 1–4 multiple-choice questions and wait; when a plan needs the user to pick between clear options, instead of listing them in chat.',
10
+ description:
11
+ 'Ask the user multiple-choice questions and wait. Only while planning, for a decision only the user can make with clear options; open questions, minor choices and plan approval go in chat. Do not repeat the options in your message.',
12
+ annotations: {
13
+ title: 'Ask User',
14
+ readOnlyHint: true,
15
+ destructiveHint: false,
16
+ idempotentHint: false,
17
+ openWorldHint: false,
18
+ agentHidden: true,
19
+ },
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ questions: {
24
+ type: 'array',
25
+ minItems: 1,
26
+ maxItems: ASK_USER_MAX_QUESTIONS,
27
+ items: {
28
+ type: 'object',
29
+ properties: {
30
+ question: { type: 'string', description: 'Full question, without the options.' },
31
+ header: { type: 'string', maxLength: 12, description: 'Chip label.' },
32
+ options: {
33
+ type: 'array',
34
+ minItems: 2,
35
+ maxItems: 4,
36
+ description: 'Distinct; free text is added, never "Other".',
37
+ items: {
38
+ type: 'object',
39
+ properties: {
40
+ label: { type: 'string', maxLength: 80, description: '1-5 words.' },
41
+ description: { type: 'string', description: 'One-sentence tradeoff.' },
42
+ },
43
+ required: ['label', 'description'],
44
+ additionalProperties: false,
45
+ },
46
+ },
47
+ multi_select: { type: 'boolean' },
48
+ recommended: { type: 'integer', minimum: 0, description: 'Recommended option index.' },
49
+ },
50
+ required: ['question', 'header', 'options'],
51
+ },
52
+ },
53
+ },
54
+ required: ['questions'],
55
+ additionalProperties: false,
56
+ },
57
+ },
58
+ ]);
59
+
60
+ /** Throws a clear error when the questions are malformed; returns the list. */
61
+ export function validateAskUserQuestions(args) {
62
+ const questions = args?.questions;
63
+ if (!Array.isArray(questions) || questions.length < 1 || questions.length > ASK_USER_MAX_QUESTIONS) {
64
+ throw new Error(`ask_user requires 1-${ASK_USER_MAX_QUESTIONS} questions`);
65
+ }
66
+ const seenQuestions = new Set();
67
+ questions.forEach((q, i) => {
68
+ const at = `ask_user question ${i + 1}`;
69
+ if (!q || typeof q !== 'object') throw new Error(`${at} must be an object`);
70
+ if (typeof q.question !== 'string' || !q.question.trim()) throw new Error(`${at} needs question text`);
71
+ if (typeof q.header !== 'string' || !q.header.trim() || q.header.length > 12) {
72
+ throw new Error(`${at} needs a header of at most 12 characters`);
73
+ }
74
+ if (seenQuestions.has(q.question)) throw new Error(`${at} duplicates another question text`);
75
+ seenQuestions.add(q.question);
76
+ if (!Array.isArray(q.options) || q.options.length < 2 || q.options.length > 4) {
77
+ throw new Error(`${at} needs 2-4 options`);
78
+ }
79
+ const labels = new Set();
80
+ for (const option of q.options) {
81
+ if (!option || typeof option.label !== 'string' || !option.label.trim()) {
82
+ throw new Error(`${at} has an option without a label`);
83
+ }
84
+ if (option.label.length > 80) throw new Error(`${at} has an option label over 80 characters`);
85
+ if (typeof option.description !== 'string' || !option.description.trim()) {
86
+ throw new Error(`${at} option "${option.label}" needs a one-sentence description`);
87
+ }
88
+ if (option.description.length > 200) throw new Error(`${at} has an option description over 200 characters`);
89
+ if (Object.keys(option).some((key) => key !== 'label' && key !== 'description')) {
90
+ throw new Error(`${at}: options take only a label and a description`);
91
+ }
92
+ if (labels.has(option.label)) throw new Error(`${at} has duplicate option label "${option.label}"`);
93
+ labels.add(option.label);
94
+ }
95
+ if (q.recommended != null && (!Number.isInteger(q.recommended) || q.recommended < 0 || q.recommended >= q.options.length)) {
96
+ throw new Error(`${at} recommended must be an index below ${q.options.length}`);
97
+ }
98
+ });
99
+ return questions;
100
+ }
@@ -351,6 +351,9 @@ export function normalizeCompactionConfig(value = {}) {
351
351
  return {
352
352
  ...next,
353
353
  auto: raw.auto !== false && raw.enabled !== false,
354
+ // Compact a conversation on its current model before switching it to
355
+ // another one in place (default on).
356
+ onModelChange: raw.onModelChange !== false,
354
357
  };
355
358
  }
356
359
 
@@ -1,3 +1,24 @@
1
+ const lowerName = (name) => String(name || '').toLowerCase();
2
+
3
+ /** The persisted schema allowlist (also the execution allowlist) leaves `name` out. */
4
+ export function sessionAllowlistExcludes(session, name) {
5
+ if (!Array.isArray(session?.schemaAllowedTools)) return false;
6
+ return !session.schemaAllowedTools.some((allowed) => lowerName(allowed) === lowerName(name));
7
+ }
8
+
9
+ /** The session's denied tools name `name`. */
10
+ export function sessionDisallows(session, name) {
11
+ return Array.isArray(session?.disallowedTools) && session.disallowedTools.some((denied) => lowerName(denied) === lowerName(name));
12
+ }
13
+
14
+ /**
15
+ * The session's own tool policy permits `name`: discovery (load_tool by name
16
+ * or query) shows, selects and describes only what execution would run.
17
+ */
18
+ export function isToolPermittedBySessionPolicy(session, name) {
19
+ return !sessionAllowlistExcludes(session, name) && !sessionDisallows(session, name);
20
+ }
21
+
1
22
  // Discovery history retains definitions; only the latest scoped MCP snapshot
2
23
  // grants availability. An absent snapshot preserves pre-initialization behavior.
3
24
  export function isDeferredToolAvailable(session, name) {
@@ -114,6 +114,21 @@ function catalogEffortOptions(provider, model) {
114
114
  return providerAllowed ? [...providerAllowed] : [];
115
115
  }
116
116
 
117
+ const warnedEmptyLadders = new Set();
118
+
119
+ /**
120
+ * Auto effort skipped a judgment because the base is off the model's ladder.
121
+ * A user-chosen max/ultra is expected to skip; any other base means the route
122
+ * has no usable ladder, so say so once per provider/model per process.
123
+ */
124
+ export function warnEmptyAutoEffortLadder(provider, model, base) {
125
+ if (base === 'max' || base === 'ultra') return;
126
+ const key = `${provider}/${model}`;
127
+ if (warnedEmptyLadders.has(key)) return;
128
+ warnedEmptyLadders.add(key);
129
+ process.stderr.write(`[auto-effort] no effort ladder for ${key}; judge skipped\n`);
130
+ }
131
+
117
132
  export function coerceEffortFor(provider, model, effort) {
118
133
  if (!effort) return null;
119
134
  if (model?.customReasoning) return snapCustomEffort(customEffortLevels(model), effort);
@@ -80,21 +80,3 @@ export function acknowledgePendingGoalReminder(session, revision) {
80
80
  session.updatedAt = Date.now();
81
81
  return true;
82
82
  }
83
-
84
- export function prependGoalReminderToLatestUserMessage(messages, content) {
85
- const reminder = clean(content);
86
- const out = Array.isArray(messages) ? [...messages] : [];
87
- if (!reminder) return out;
88
- for (let index = out.length - 1; index >= 0; index -= 1) {
89
- const message = out[index];
90
- if (message?.role !== 'user') continue;
91
- const current = message.content;
92
- const nextContent = Array.isArray(current)
93
- ? [{ type: 'text', text: `${reminder}\n\n` }, ...current]
94
- : `${reminder}\n\n${String(current ?? '')}`;
95
- out[index] = { ...message, content: nextContent };
96
- return out;
97
- }
98
- out.push({ role: 'user', content: reminder });
99
- return out;
100
- }
@@ -7,6 +7,7 @@ import { modelSupportsServiceTier } from '../providers/model-service-tiers.mjs';
7
7
  import { openAiDirectSupportsFast, openAiDirectSupportsUltrafast } from '../providers/openai-direct-request.mjs';
8
8
  import { supportsAnthropicFastMode } from '../../../shared/llm/anthropic-betas.mjs';
9
9
  import { normalizeContextTokens } from '../../../shared/llm/default-context-window.mjs';
10
+ import { getModelMetadataSync } from '../../../shared/llm/model-catalog.mjs';
10
11
 
11
12
  const FAST_CAPABLE_PROVIDERS = new Set([
12
13
  'anthropic',
@@ -24,41 +25,59 @@ export function routeFastKey(provider, model) {
24
25
  return p && m ? `${p}/${m}` : '';
25
26
  }
26
27
 
27
- function openAiModelSupportsHostedWebSearch(model) {
28
- const id = clean(model?.id || model).toLowerCase();
29
- if (!id) return false;
30
- if (model?.supportsWebSearch === true) return true;
28
+ // What one catalog row states about hosted web search: its own
29
+ // `supportsWebSearch` flag (true or false), else a web_search tool in its tool
30
+ // lists. Null when the row says nothing, which leaves the answer to the id
31
+ // fallback of each family.
32
+ function rowWebSearchDeclaration(row) {
33
+ if (!row || typeof row !== 'object') return null;
34
+ if (typeof row.supportsWebSearch === 'boolean') return row.supportsWebSearch;
31
35
  const tools = [
32
- ...(Array.isArray(model?.supportedTools) ? model.supportedTools : []),
33
- ...(Array.isArray(model?.tools) ? model.tools : []),
34
- ...(Array.isArray(model?.capabilities?.tools) ? model.capabilities.tools : []),
36
+ ...(Array.isArray(row.supportedTools) ? row.supportedTools : []),
37
+ ...(Array.isArray(row.tools) ? row.tools : []),
38
+ ...(Array.isArray(row.capabilities?.tools) ? row.capabilities.tools : []),
35
39
  ].map((tool) => clean(tool?.type || tool?.name || tool).toLowerCase());
36
- if (tools.some((tool) => tool === 'web_search' || tool === 'web_search_preview')) return true;
37
- if (/codex|image|audio|tts|stt|embedding|rerank|moderation|search-preview/.test(id)) return false;
38
- return /^gpt-(5(?:\.|$|-)|4\.1(?:-|$)|4o(?:-|$)|4\.5(?:-|$))/.test(id) || /^o[34](?:-|$)/.test(id);
39
- }
40
-
41
- function grokModelSupportsHostedWebSearch(model) {
42
- const id = clean(model?.id || model).toLowerCase();
43
- if (!id || /imagine|image|video|composer/.test(id)) return false;
44
- if (id === 'grok-build') return false;
45
- return /^grok-/.test(id);
40
+ return tools.some((tool) => tool === 'web_search' || tool === 'web_search_preview') ? true : null;
46
41
  }
47
42
 
48
- function geminiModelSupportsHostedWebSearch(model) {
49
- const id = clean(model?.id || model).toLowerCase();
50
- if (!id || /embedding|aqa|imagen|veo|tts|image|computer-use|customtools/.test(id)) return false;
51
- return /^gemini-(3(?:\.|-|$)|2\.5-|2\.0-flash)/.test(id);
43
+ // The route's own row first, then the provider catalog's row for the model.
44
+ function hostedWebSearchDeclared(model, catalogRow) {
45
+ return rowWebSearchDeclaration(model) ?? rowWebSearchDeclaration(catalogRow);
52
46
  }
53
47
 
54
- function anthropicModelSupportsHostedWebSearch(model) {
48
+ // When neither the route row nor the catalog states hosted web search, the
49
+ // vendor family (already fixed by the provider) is taken as capable unless the
50
+ // id names a non-chat modality or a retired generation. Only those closed,
51
+ // frozen sets are matched by id, so a model released later needs no entry here;
52
+ // guessing "capable" wrongly would hard-fail the request, which is why the
53
+ // retired generations stay excluded.
54
+ function hostedWebSearchFallback(model, catalogRow, unsupportedId) {
55
55
  const id = clean(model?.id || model).toLowerCase();
56
56
  if (!id) return false;
57
- const match = id.match(/^claude-(opus|sonnet|haiku|fable|mythos)-(\d+)(?:[-.](\d+))?/);
58
- if (!match) return false;
59
- return (Number(match[2]) || 0) >= 4;
57
+ const declared = hostedWebSearchDeclared(model, catalogRow);
58
+ if (declared !== null) return declared;
59
+ return !unsupportedId.test(id);
60
60
  }
61
61
 
62
+ const NON_CHAT_ID = 'embedding|rerank|moderation|image|imagen|imagine|video|veo|audio|tts|stt|aqa|search-preview';
63
+
64
+ const OPENAI_UNSUPPORTED = new RegExp(
65
+ `${NON_CHAT_ID}|codex|^gpt-(?:3|4(?:$|-))|^o[12](?:-|$)|^(?:babbage|davinci|text-)`
66
+ );
67
+ const GROK_UNSUPPORTED = new RegExp(`${NON_CHAT_ID}|composer|^grok-build$|^grok-[123](?:[.-]|$)`);
68
+ // The Gemini family is also reached through a relay serving other vendors'
69
+ // models, whose hosted search is Gemini's alone, so a non-Gemini id is out.
70
+ const GEMINI_UNSUPPORTED = new RegExp(
71
+ `${NON_CHAT_ID}|^(?!gemini-)|computer-use|customtools|^gemini-(?:1[.-]|pro|ultra)|^gemini-2\\.0-(?!flash)`
72
+ );
73
+ const ANTHROPIC_UNSUPPORTED = /^claude-(?:\d|instant)|^claude-[a-z]+-[123](?:[-.]|$)/;
74
+
75
+ const openAiModelSupportsHostedWebSearch = (model, row) => hostedWebSearchFallback(model, row, OPENAI_UNSUPPORTED);
76
+ const grokModelSupportsHostedWebSearch = (model, row) => hostedWebSearchFallback(model, row, GROK_UNSUPPORTED);
77
+ const geminiModelSupportsHostedWebSearch = (model, row) => hostedWebSearchFallback(model, row, GEMINI_UNSUPPORTED);
78
+ const anthropicModelSupportsHostedWebSearch = (model, row) =>
79
+ hostedWebSearchFallback(model, row, ANTHROPIC_UNSUPPORTED);
80
+
62
81
  export function fastCapableFor(provider, model, effort = null, modelParameters = {}) {
63
82
  const p = clean(provider);
64
83
  if (!FAST_CAPABLE_PROVIDERS.has(p)) return false;
@@ -77,8 +96,13 @@ export function fastCapableFor(provider, model, effort = null, modelParameters =
77
96
  }
78
97
  return !selectedEffort || fastEfforts.length === 0 || fastEfforts.includes(selectedEffort);
79
98
  }
80
- if (p === 'openai') return openAiDirectSupportsFast(model);
81
99
  if (p === 'openai-oauth') return modelSupportsServiceTier(model, 'priority');
100
+ // The route row's own declaration first, then the catalog via the helpers.
101
+ if (typeof model?.supportsFastMode === 'boolean') return model.supportsFastMode;
102
+ const modelId = clean(model?.id || model);
103
+ const declaredFast = modelId ? getModelMetadataSync(modelId, p)?.supportsFastMode : undefined;
104
+ if (typeof declaredFast === 'boolean') return declaredFast;
105
+ if (p === 'openai') return openAiDirectSupportsFast(model);
82
106
  if (p === 'anthropic' || p === 'anthropic-oauth') return supportsAnthropicFastMode(clean(model?.id || model));
83
107
  return false;
84
108
  }
@@ -100,10 +124,15 @@ const HOSTED_WEB_SEARCH_BY_FAMILY = {
100
124
  // webSearchCapableFor needs the web-search family mapping, which lives in
101
125
  // workflow.mjs and is pure. Wire it in via a factory to keep this module free
102
126
  // of a circular import at load time.
103
- export function makeWebSearchCapableFor(webSearchProviderFamily) {
127
+ // `catalogRowFor(provider, id)` is the provider catalog's row for the model;
128
+ // callers that hold only a bare id (or a row the provider list left silent)
129
+ // still get the catalog's answer before the id fallback applies.
130
+ export function makeWebSearchCapableFor(webSearchProviderFamily, catalogRowFor = getModelMetadataSync) {
104
131
  return function webSearchCapableFor(provider, model) {
105
132
  const supports = HOSTED_WEB_SEARCH_BY_FAMILY[webSearchProviderFamily(provider)];
106
- return supports ? supports(model) : false;
133
+ if (!supports) return false;
134
+ const id = clean(model?.id || model);
135
+ return supports(model, id ? catalogRowFor(id, provider) : null);
107
136
  };
108
137
  }
109
138
 
@@ -2,16 +2,14 @@ import { normalizeOrchestrationMode } from '../../../shared/orchestration.mjs';
2
2
 
3
3
  const BATCHING = {
4
4
  focused: `Lead executes the main scope directly. Delegate only substantial,
5
- self-contained supporting work. Batch closely related tasks into one
6
- coherent assignment; do not split them merely to increase parallelism.`,
7
- balanced: `Delegate independent work by coherent feature or module. Batch related
8
- tasks within the same change scope into one assignment rather than
9
- splitting every file or step.
10
- If the plan has only one scope, Lead executes it directly.`,
11
- swarm: `Delegate every substantial independent scope to its own agent. Treat
12
- disjoint file or module sets as independent and merge scopes only on a true
13
- output dependency. Prefer parallel scopes over sequential slices in one agent.
14
- If the plan has only one scope, Lead executes it directly.`,
5
+ self-contained supporting work, one agent per role; batch related tasks
6
+ rather than splitting them for parallelism.`,
7
+ balanced: `Delegate independent work by coherent feature or module, one agent per
8
+ scope. Batch related tasks within the same change scope rather than
9
+ splitting every file or step.`,
10
+ swarm: `Delegate every independent scope to its own agent. Treat disjoint file or
11
+ module sets as independent and merge scopes only on a true output
12
+ dependency. Prefer parallel scopes over sequential slices in one agent.`,
15
13
  };
16
14
 
17
15
  const SOLO = `# Orchestration Mode: Solo
@@ -27,6 +25,12 @@ export function orchestrationInstructions(value) {
27
25
 
28
26
  ${BATCHING[mode]}
29
27
 
28
+ The mode sets how work splits; an agent's description sets its role and when
29
+ it runs. Splitting applies to every role alike — implementation, review,
30
+ investigation, writing — by file, module, commit range or risk area.
31
+ If the plan has only one implementation scope, Lead executes it directly; a
32
+ role tied to a point in the work, such as the final check, still runs then.
33
+
30
34
  Delegation is for work whose size justifies a brief. When the brief would have
31
35
  to spell out the edits themselves — a few localized changes whose sites Lead
32
36
  already holds — Lead makes them directly in every mode; the number of files or
@@ -34,10 +38,9 @@ scopes does not change this.
34
38
 
35
39
  Dispatch all ready independent scopes in one turn. Only a scope that requires
36
40
  another's output waits. Brief each agent as the Lead rules describe.
37
- Use only available agents; Lead handles work without a suitable agent.
38
-
39
- If the reviewer is disabled or unavailable, Lead alone reviews the result
40
- against the approved scope and performs the required verification. Do not
41
- change settings, enable the reviewer, or delegate review to a substitute agent.
42
- Do not skip review or describe Lead's own review as independent review.`;
41
+ Use only available agents; when none fits a role, Lead does that work itself
42
+ and never changes settings to enable one. If the reviewer is disabled or
43
+ unavailable, Lead alone reviews the result against the approved scope and
44
+ performs the required verification, without a substitute agent; never skip
45
+ review or describe Lead's own review as independent.`;
43
46
  }
@@ -1,17 +1,5 @@
1
1
  // Plugin/project MCP server discovery + normalization, and skill-file counting.
2
- import {
3
- chmodSync,
4
- closeSync,
5
- existsSync,
6
- fsyncSync,
7
- openSync,
8
- readFileSync,
9
- readdirSync,
10
- renameSync,
11
- statSync,
12
- unlinkSync,
13
- writeFileSync,
14
- } from 'node:fs';
2
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
15
3
  import { join, relative, sep } from 'node:path';
16
4
  import { clean } from './session-text.mjs';
17
5
  import {
@@ -54,90 +42,6 @@ export function mergeMcpServerConfig(existing, next) {
54
42
  return { ...merged, ...next };
55
43
  }
56
44
 
57
- function readProjectMcpDocument(cwd, allowMissing = false) {
58
- const path = join(cwd || '.', '.mcp.json');
59
- if (!existsSync(path)) {
60
- if (allowMissing) return { path, raw: { mcpServers: {} }, usesWrapper: true };
61
- throw new Error(`MCP config file not found: ${path}`);
62
- }
63
- let raw;
64
- try {
65
- raw = JSON.parse(readFileSync(path, 'utf8'));
66
- } catch (error) {
67
- throw new Error(`cannot read ${path}: ${error?.message || String(error)}`);
68
- }
69
- if (!isPlainObject(raw)) throw new Error(`unexpected .mcp.json shape at ${path}`);
70
- if (Object.hasOwn(raw, 'mcpServers') && !isPlainObject(raw.mcpServers)) {
71
- throw new Error(`unexpected .mcp.json shape at ${path}`);
72
- }
73
- const usesWrapper = isPlainObject(raw.mcpServers);
74
- return { path, raw, usesWrapper };
75
- }
76
-
77
- function writeProjectMcpDocument(path, raw) {
78
- let mode = 0o644;
79
- try {
80
- mode = statSync(path).mode;
81
- } catch {
82
- /* new file */
83
- }
84
- const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;
85
- let fd = null;
86
- try {
87
- fd = openSync(tempPath, 'w', mode);
88
- writeFileSync(fd, `${JSON.stringify(raw, null, 2)}\n`, 'utf8');
89
- fsyncSync(fd);
90
- closeSync(fd);
91
- fd = null;
92
- chmodSync(tempPath, mode);
93
- renameSync(tempPath, path);
94
- } catch (error) {
95
- if (fd !== null) {
96
- try {
97
- closeSync(fd);
98
- } catch {
99
- /* best effort */
100
- }
101
- }
102
- try {
103
- unlinkSync(tempPath);
104
- } catch {
105
- /* best effort */
106
- }
107
- throw error;
108
- }
109
- }
110
-
111
- // The stored key for `key`: an exact own key first, else one that trims to it.
112
- function mcpEntryKey(map, key) {
113
- return Object.hasOwn(map, key) ? key : Object.keys(map).find((candidate) => String(candidate || '').trim() === key);
114
- }
115
-
116
- export function readProjectMcpServerConfig(cwd, name) {
117
- const { raw, usesWrapper } = readProjectMcpDocument(cwd);
118
- const map = usesWrapper ? raw.mcpServers : raw;
119
- const entryKey = mcpEntryKey(map, String(name || '').trim());
120
- return entryKey && isPlainObject(map[entryKey]) ? { name: entryKey, config: { ...map[entryKey] } } : null;
121
- }
122
-
123
- export function saveProjectMcpServer(cwd, { originalName = '', name, config }) {
124
- const { path, raw, usesWrapper } = readProjectMcpDocument(cwd, !originalName);
125
- const map = usesWrapper ? raw.mcpServers : raw;
126
- const target = String(name || '').trim();
127
- const original = String(originalName || '').trim();
128
- if (!target) throw new Error('MCP server name is required');
129
- const entryKey = original ? mcpEntryKey(map, original) : null;
130
- if (original && !entryKey) throw new Error(`MCP server not defined in ${path}: ${original}`);
131
- if (target !== entryKey && Object.hasOwn(map, target)) {
132
- throw new Error(`MCP server already exists in ${path}: ${target}`);
133
- }
134
- const existing = entryKey ? map[entryKey] : {};
135
- if (entryKey && entryKey !== target) delete map[entryKey];
136
- map[target] = mergeMcpServerConfig(existing, config);
137
- writeProjectMcpDocument(path, raw);
138
- return { name: target, source: 'project', path, config: { ...map[target] } };
139
- }
140
-
141
45
  // Manifest + contained-path resolution live in the shared module so skill
142
46
  // discovery and this status surface read the same roots.
143
47
  export { pluginManifest, resolveContainedPluginPath };