mixdog 1.2.2 → 1.2.4

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 (692) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +6 -4
  4. package/scripts/lib/gate-scheduler.mjs +29 -11
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +599 -0
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/advisor/AGENT.md +1 -1
  9. package/src/agents/advisor/agent.json +1 -1
  10. package/src/agents/maintainer/AGENT.md +1 -1
  11. package/src/agents/maintainer/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +2 -4
  13. package/src/agents/security/AGENT.md +1 -2
  14. package/src/agents/writer/AGENT.md +2 -3
  15. package/src/defaults/shipped-history.json +11 -1
  16. package/src/defaults/skills/image/SKILL.md +21 -23
  17. package/src/defaults/skills/setup/SKILL.md +6 -1
  18. package/src/defaults/skills/setup/references/actions.md +44 -22
  19. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  20. package/src/headless-exec.mjs +15 -8
  21. package/src/lib/keychain-cjs.cjs +20 -15
  22. package/src/output-styles/common.md +11 -10
  23. package/src/rules/agent/AGENT.md +6 -4
  24. package/src/rules/lead/LEAD.md +7 -9
  25. package/src/rules/shared/45-destructive.md +4 -0
  26. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  28. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  29. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  30. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  31. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  32. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  33. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  35. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  36. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +3 -1
  41. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  42. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +9 -9
  43. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  45. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +31 -15
  46. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  48. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  49. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  50. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  51. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  52. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  53. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +10 -0
  56. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  58. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +131 -9
  59. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  60. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +125 -8
  61. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +12 -62
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +117 -41
  63. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  65. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  66. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +39 -5
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +42 -11
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +109 -6
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +17 -4
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -2
  76. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +73 -7
  77. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +75 -6
  78. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  79. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  80. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  81. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +29 -5
  82. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  83. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +36 -13
  84. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +101 -11
  85. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  86. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  88. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +19 -14
  89. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +371 -41
  90. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +97 -49
  92. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +81 -10
  93. package/src/runtime/agent/orchestrator/providers/gemini.mjs +35 -8
  94. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  96. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  97. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  98. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +253 -42
  99. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  100. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  101. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +392 -0
  102. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  103. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  105. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  106. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  107. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +50 -22
  108. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +133 -21
  109. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  110. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  111. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  112. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  113. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +92 -16
  114. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -13
  115. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +133 -62
  117. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  118. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  119. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +39 -7
  120. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  121. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  122. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  123. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +84 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  125. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  126. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +155 -0
  127. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +40 -24
  128. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  129. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +183 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +87 -6
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  138. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +17 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  140. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  141. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  142. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +28 -5
  143. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  144. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  145. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  147. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  148. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  150. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  151. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  152. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +72 -24
  153. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  154. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +50 -16
  155. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -19
  156. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  157. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -36
  158. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  159. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  160. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  161. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -9
  162. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +181 -0
  163. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +78 -70
  164. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +74 -0
  165. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +150 -10
  166. package/src/runtime/agent/orchestrator/providers/registry.mjs +13 -2
  167. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +7 -1
  168. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  169. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  170. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +164 -0
  171. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +522 -0
  172. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  173. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +195 -0
  174. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +104 -0
  175. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  176. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +24 -0
  177. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  178. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  179. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  180. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  181. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  182. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  183. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +16 -3
  184. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  186. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  187. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  188. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +178 -71
  189. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +102 -12
  190. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  191. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  192. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  193. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  194. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  195. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  196. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -11
  197. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  198. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  199. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +16 -93
  200. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  201. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  202. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +148 -0
  203. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  204. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  205. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  206. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  207. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  208. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +3 -2
  209. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  210. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  211. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  212. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +89 -1
  213. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  215. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  216. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -27
  217. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  219. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  220. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +24 -10
  221. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +135 -0
  222. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +31 -4
  223. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  224. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  225. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +10 -10
  226. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  227. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  228. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  229. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +29 -5
  230. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  231. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +147 -0
  232. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -5
  233. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  234. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  235. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +23 -2
  236. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  237. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +54 -13
  238. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  239. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  240. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +11 -0
  241. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +22 -0
  242. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  243. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  244. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  245. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  246. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  247. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +231 -16
  248. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  249. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  250. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +47 -17
  251. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +26 -4
  252. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  253. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +36 -35
  254. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  255. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +6 -3
  256. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  257. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  258. package/src/runtime/agent/orchestrator/session/manager.mjs +4 -10
  259. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  260. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  261. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +17 -1
  262. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  263. package/src/runtime/agent/orchestrator/session/side-question.mjs +197 -0
  264. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +22 -15
  265. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  266. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  267. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  268. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  269. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  270. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  271. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  272. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +44 -37
  273. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  274. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  275. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  276. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  277. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -21
  278. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  279. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  280. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  281. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +4 -2
  282. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  283. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
  284. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  285. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +53 -115
  286. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  287. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  288. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  289. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  290. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +17 -10
  291. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  292. package/src/runtime/agent/orchestrator/session/store.mjs +22 -19
  293. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +12 -12
  294. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +38 -14
  295. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  296. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  297. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  298. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  299. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +79 -0
  300. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  301. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  302. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  303. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  304. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  305. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  306. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  307. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  308. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +218 -20
  309. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  310. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  311. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  312. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  313. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  314. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  315. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  316. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +247 -49
  317. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  318. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  319. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  320. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  321. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  322. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  323. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  324. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  325. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  326. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  327. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  328. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  329. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  330. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  331. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  332. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  333. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  334. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  335. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  336. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  337. package/src/runtime/attachments/store.d.mts +9 -0
  338. package/src/runtime/attachments/store.mjs +80 -9
  339. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  340. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  341. package/src/runtime/computer-bridge/action-schema.mjs +219 -196
  342. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  343. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  344. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  345. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  346. package/src/runtime/github/tool.mjs +208 -17
  347. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  348. package/src/runtime/media/catalog.mjs +4 -4
  349. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  350. package/src/runtime/media/defaults.mjs +37 -0
  351. package/src/runtime/media/jobs.mjs +12 -2
  352. package/src/runtime/media/lanes.mjs +12 -0
  353. package/src/runtime/media/tool-defs.mjs +15 -4
  354. package/src/runtime/media/tool.mjs +41 -12
  355. package/src/runtime/media/upstream-error.mjs +72 -6
  356. package/src/runtime/memory/index.mjs +1 -0
  357. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  358. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  359. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  360. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  361. package/src/runtime/memory/lib/pg/process.mjs +36 -33
  362. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  363. package/src/runtime/memory/lib/pg/supervisor.mjs +112 -4
  364. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  365. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  366. package/src/runtime/office/README.md +1 -1
  367. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  368. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  369. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  370. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  371. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  372. package/src/runtime/office/authoring/pptx-html-measure.mjs +3 -1
  373. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  374. package/src/runtime/office/authoring/xlsx-html-runner.mjs +3 -1
  375. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  376. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  377. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  378. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  379. package/src/runtime/office/core/office-sessions.mjs +5 -0
  380. package/src/runtime/office/core/office-transactions.mjs +3 -0
  381. package/src/runtime/office/core/office-write-ledger.mjs +94 -0
  382. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  383. package/src/runtime/office/index.mjs +29 -0
  384. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  385. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  386. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  387. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  388. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  389. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  390. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  391. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  392. package/src/runtime/shared/atomic-file.d.mts +1 -1
  393. package/src/runtime/shared/background-tasks.mjs +6 -1
  394. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  395. package/src/runtime/shared/bounded-line-diff.mjs +191 -0
  396. package/src/runtime/shared/browser-launch.mjs +15 -0
  397. package/src/runtime/shared/buffered-appender.mjs +18 -0
  398. package/src/runtime/shared/config.mjs +78 -18
  399. package/src/runtime/shared/err-text.mjs +48 -4
  400. package/src/runtime/shared/file-lock.mjs +6 -5
  401. package/src/runtime/shared/file-permissions.d.mts +6 -1
  402. package/src/runtime/shared/file-permissions.mjs +54 -6
  403. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  404. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  405. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  406. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  407. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  408. package/src/runtime/shared/loopback-listener.mjs +9 -0
  409. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  410. package/src/runtime/shared/model-route-chain.mjs +48 -0
  411. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  412. package/src/runtime/shared/pid-liveness.mjs +12 -0
  413. package/src/runtime/shared/provider-api-key.mjs +8 -0
  414. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  415. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  416. package/src/runtime/shared/quiet-progress.mjs +101 -0
  417. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  418. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  419. package/src/runtime/shared/remote-intent.mjs +2 -42
  420. package/src/runtime/shared/review-diff.mjs +52 -0
  421. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  422. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  423. package/src/runtime/shared/slow-span.mjs +121 -0
  424. package/src/runtime/shared/statusline/statusline-segments.mjs +52 -6
  425. package/src/runtime/shared/tool-card-model/card-header.mjs +7 -1
  426. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  427. package/src/runtime/shared/tool-card-model.mjs +5 -2
  428. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  429. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  430. package/src/runtime/shared/tool-primitives.mjs +13 -0
  431. package/src/runtime/shared/tool-result-summary.mjs +22 -1
  432. package/src/runtime/shared/tool-status.mjs +3 -2
  433. package/src/runtime/shared/tool-surface.mjs +20 -6
  434. package/src/runtime/shared/tool-work-units.mjs +54 -11
  435. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  436. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  437. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  438. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  439. package/src/runtime/shared/transcript-writer.mjs +24 -6
  440. package/src/runtime/shared/turn-changes.mjs +269 -100
  441. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  442. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  443. package/src/runtime/shared/turn-snapshot.mjs +865 -683
  444. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  445. package/src/runtime/shared/user-data-guard.mjs +262 -49
  446. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  447. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  448. package/src/runtime/shared/worktrees/carry.mjs +533 -0
  449. package/src/runtime/shared/worktrees/contract.mjs +60 -0
  450. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  451. package/src/runtime/shared/worktrees/file-recovery.mjs +84 -0
  452. package/src/runtime/shared/worktrees/git-head.mjs +214 -0
  453. package/src/runtime/shared/worktrees/git.mjs +8 -3
  454. package/src/runtime/shared/worktrees/include.mjs +125 -7
  455. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  456. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  457. package/src/runtime/shared/worktrees/manager.mjs +525 -31
  458. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  459. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  460. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  461. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  462. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  463. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  464. package/src/runtime/terminal-bridge/client.mjs +57 -20
  465. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  466. package/src/runtime/tidy/apply.mjs +47 -2
  467. package/src/runtime/tidy/run-engines.mjs +11 -5
  468. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  469. package/src/session-runtime/boot/apis.mjs +20 -6
  470. package/src/session-runtime/boot/config.mjs +2 -0
  471. package/src/session-runtime/boot/facade.mjs +4 -0
  472. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  473. package/src/session-runtime/boot/session.mjs +3 -3
  474. package/src/session-runtime/boot/tools.mjs +7 -1
  475. package/src/session-runtime/conversation-import/service.mjs +1 -1
  476. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  477. package/src/session-runtime/goal-facade-api.mjs +2 -2
  478. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +91 -0
  479. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  480. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +15 -5
  481. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +137 -26
  482. package/src/session-runtime/internal-tool-executor.mjs +8 -2
  483. package/src/session-runtime/lifecycle/cold-heir.mjs +187 -0
  484. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  485. package/src/session-runtime/lifecycle/session-catalog.mjs +25 -18
  486. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  487. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +36 -48
  488. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  489. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  490. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  491. package/src/session-runtime/lifecycle/teardown.mjs +70 -14
  492. package/src/session-runtime/lifecycle-api.mjs +1 -0
  493. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  494. package/src/session-runtime/media-api.mjs +8 -0
  495. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  496. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  497. package/src/session-runtime/model-route/set-route.mjs +116 -36
  498. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  499. package/src/session-runtime/model-route-api.mjs +4 -2
  500. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  501. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  502. package/src/session-runtime/native-web-search.mjs +19 -9
  503. package/src/session-runtime/new-session-config.mjs +4 -2
  504. package/src/session-runtime/provider-auth/login.mjs +4 -0
  505. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  506. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  507. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  508. package/src/session-runtime/provider-models.mjs +1 -0
  509. package/src/session-runtime/provider-usage.mjs +4 -0
  510. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  511. package/src/session-runtime/route-resolution.mjs +3 -1
  512. package/src/session-runtime/runtime-core.mjs +4 -0
  513. package/src/session-runtime/runtime-facade.mjs +6 -0
  514. package/src/session-runtime/runtime-review-api.mjs +8 -2
  515. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  516. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  517. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  518. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  519. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  520. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  521. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  522. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  523. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  524. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  525. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  526. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  527. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  528. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  529. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  530. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +82 -13
  531. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  532. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  533. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  534. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  535. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  536. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  537. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  538. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  539. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  540. package/src/session-runtime/services/agent-tool/tag-registry.mjs +18 -10
  541. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  542. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  543. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  544. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  545. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  546. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  547. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  548. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  549. package/src/session-runtime/services/agent-tool/worker-index.mjs +74 -15
  550. package/src/session-runtime/services/agent-tool.mjs +7 -0
  551. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  552. package/src/session-runtime/services/channel-admin.mjs +19 -3
  553. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  554. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  555. package/src/session-runtime/services/provider-admin.mjs +158 -15
  556. package/src/session-runtime/session-create/session-options.mjs +7 -5
  557. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  558. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  559. package/src/session-runtime/session-transcript.mjs +4 -5
  560. package/src/session-runtime/session-turn-api.mjs +17 -14
  561. package/src/session-runtime/settings-builtin-tools-api.mjs +18 -6
  562. package/src/session-runtime/setup-tool/executor.mjs +57 -9
  563. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  564. package/src/session-runtime/setup-tool/settings-contract.mjs +18 -3
  565. package/src/session-runtime/setup-tool/tool-defs.mjs +25 -4
  566. package/src/session-runtime/skills-api.mjs +3 -5
  567. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  568. package/src/session-runtime/tool-surface.mjs +5 -1
  569. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  570. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  571. package/src/session-runtime/turn/session-ops.mjs +7 -5
  572. package/src/session-runtime/turn/side-question-ops.mjs +19 -0
  573. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +7 -1
  574. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +12 -3
  575. package/src/session-runtime/turn/turn-run/turn-settle.mjs +18 -2
  576. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  577. package/src/session-runtime/turn/turn-run.mjs +26 -45
  578. package/src/session-runtime/usage-stats-api.mjs +46 -11
  579. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  580. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  581. package/src/session-runtime/workspace/project-branches.mjs +35 -41
  582. package/src/session-runtime/workspace/transition-steps.mjs +215 -116
  583. package/src/session-runtime/workspace/transitions.mjs +428 -73
  584. package/src/standalone/channel-transport.mjs +3 -4
  585. package/src/standalone/daemon-agent-control.mjs +9 -1
  586. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  587. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  588. package/src/standalone/daemon-owner.mjs +17 -4
  589. package/src/standalone/daemon-pg-stop.mjs +49 -0
  590. package/src/standalone/daemon-session-control.mjs +88 -0
  591. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  592. package/src/standalone/daemon-stop-budget.mjs +18 -0
  593. package/src/standalone/daemon-stored-session-views.mjs +25 -3
  594. package/src/standalone/daemon-telemetry.mjs +19 -0
  595. package/src/standalone/daemon.mjs +63 -1
  596. package/src/standalone/desktop-service-registry.mjs +5 -0
  597. package/src/standalone/local-session-runtime.mjs +80 -30
  598. package/src/standalone/session-client.mjs +42 -0
  599. package/src/standalone/session-protocol.mjs +14 -0
  600. package/src/standalone/session-proxy/projection.mjs +41 -4
  601. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  602. package/src/standalone/session-runtime-inline-host.mjs +3 -0
  603. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  604. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  605. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  606. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  607. package/src/standalone/session-service/agent-tree.mjs +28 -2
  608. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  609. package/src/standalone/session-service/entries.mjs +1 -0
  610. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  611. package/src/standalone/session-service/quota-resume.mjs +28 -13
  612. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  613. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  614. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  615. package/src/standalone/session-service-api.mjs +6 -1
  616. package/src/standalone/session-state-patch.d.mts +2 -1
  617. package/src/standalone/session-state-patch.mjs +41 -1
  618. package/src/standalone/session-tool-output.mjs +82 -0
  619. package/src/tui/App.jsx +25 -0
  620. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  621. package/src/tui/app/app-view.jsx +2 -1
  622. package/src/tui/app/btw-controller.mjs +118 -0
  623. package/src/tui/app/create-app-pickers.mjs +2 -0
  624. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  625. package/src/tui/app/provider-setup-picker.mjs +15 -3
  626. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  627. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  628. package/src/tui/app/slash-commands.mjs +19 -3
  629. package/src/tui/app/slash-dispatch/session-commands.mjs +68 -6
  630. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  631. package/src/tui/app/use-global-key-input.mjs +5 -12
  632. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  633. package/src/tui/components/BtwPanel.jsx +53 -0
  634. package/src/tui/components/QuestionPanel.jsx +275 -0
  635. package/src/tui/components/Spinner.jsx +4 -0
  636. package/src/tui/components/SpinnerByline.jsx +21 -2
  637. package/src/tui/components/question-panel-model.mjs +156 -0
  638. package/src/tui/components/status-line/local-line.mjs +10 -2
  639. package/src/tui/dist/index.mjs +2897 -1722
  640. package/src/tui/session/active-tool-summary.mjs +1 -1
  641. package/src/tui/session/context-state.mjs +4 -5
  642. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  643. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  644. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  645. package/src/tui/session/quota-resume.mjs +140 -61
  646. package/src/tui/session/session-api/commands.mjs +14 -10
  647. package/src/tui/session/session-api/controls.mjs +14 -2
  648. package/src/tui/session/session-api/integrations.mjs +9 -2
  649. package/src/tui/session/session-api/lifecycle/dispose.mjs +3 -9
  650. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  651. package/src/tui/session/session-api/lifecycle.mjs +14 -11
  652. package/src/tui/session/session-api/media.mjs +2 -0
  653. package/src/tui/session/session-api/routes.mjs +81 -57
  654. package/src/tui/session/session-api/settings.mjs +9 -3
  655. package/src/tui/session/session-api/worktree.mjs +3 -2
  656. package/src/tui/session/session-api.mjs +1 -0
  657. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  658. package/src/tui/session/session-flow/drain.mjs +6 -4
  659. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  660. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  661. package/src/tui/session/session-flow/queue.mjs +1 -1
  662. package/src/tui/session/tool-approval.mjs +20 -8
  663. package/src/tui/session/transcript-spill.mjs +14 -7
  664. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  665. package/src/tui/session/tui-steering-persist.mjs +3 -5
  666. package/src/tui/session/turn-quiet.mjs +53 -0
  667. package/src/tui/session/turn-stream.mjs +179 -32
  668. package/src/tui/session/turn.mjs +50 -36
  669. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  670. package/src/tui/spinner-meta.mjs +10 -0
  671. package/src/tui/spinner-verbs.mjs +3 -0
  672. package/src/ui/statusline.mjs +13 -3
  673. package/src/workflows/default/WORKFLOW.md +3 -1
  674. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  675. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  676. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  677. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -246
  678. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  679. package/src/session-runtime/turn/share-ops.mjs +0 -77
  680. package/src/tui/session/cross-surface-share.mjs +0 -406
  681. package/src/tui/session/live-share/delta.mjs +0 -153
  682. package/src/tui/session/live-share/mirror.mjs +0 -106
  683. package/src/tui/session/live-share/owner.mjs +0 -254
  684. package/src/tui/session/live-share/retry.mjs +0 -54
  685. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  686. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  687. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  688. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  689. package/src/tui/session/live-share/viewer.mjs +0 -99
  690. package/src/tui/session/live-share/wire.mjs +0 -44
  691. package/src/tui/session/live-share.mjs +0 -154
  692. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -42,17 +42,43 @@ function customToolArgumentsFromInput(name, input) {
42
42
  return { input: text };
43
43
  }
44
44
 
45
+ // Responses calls of a tool loaded from a declared namespace carry
46
+ // `namespace` beside `name`. Mixdog declares no namespaces today, so this is
47
+ // parse-side preservation only: a call that carries one keeps it on its
48
+ // record (and in replay), and its dispatch dedupe identity is qualified, so it
49
+ // is never conflated with a same-named top-level tool.
50
+ export function toolCallNamespace(item) {
51
+ return typeof item?.namespace === 'string' && item.namespace ? item.namespace : '';
52
+ }
53
+
54
+ /** Copy the source item's namespace onto a call record (mutates; returns it). */
55
+ export function withToolCallNamespace(call, source) {
56
+ const namespace = toolCallNamespace(source);
57
+ if (call && namespace && !call.namespace) call.namespace = namespace;
58
+ return call;
59
+ }
60
+
61
+ /** Dispatch dedupe identity: the namespace-qualified tool name. */
62
+ export function qualifiedToolCallName(call) {
63
+ const namespace = toolCallNamespace(call);
64
+ const name = call?.name || '';
65
+ return namespace ? `${namespace}.${name}` : name;
66
+ }
67
+
45
68
  export function customToolCallFromResponseItem(item) {
46
69
  if (item?.type !== 'custom_tool_call') return null;
47
70
  const id = item.call_id || item.id || '';
48
71
  const name = item.name || '';
49
72
  if (!id || !name) return null;
50
- return {
51
- id,
52
- name,
53
- arguments: customToolArgumentsFromInput(name, item.input ?? ''),
54
- nativeType: 'custom_tool_call',
55
- };
73
+ return withToolCallNamespace(
74
+ {
75
+ id,
76
+ name,
77
+ arguments: customToolArgumentsFromInput(name, item.input ?? ''),
78
+ nativeType: 'custom_tool_call',
79
+ },
80
+ item
81
+ );
56
82
  }
57
83
 
58
84
  export function isCustomToolCallRecord(call) {
@@ -0,0 +1,67 @@
1
+ /**
2
+ * DeepSeek: Chat Completions at https://api.deepseek.com plus the Anthropic
3
+ * Messages endpoint at https://api.deepseek.com/anthropic (the SDK appends
4
+ * /v1/messages). Per DeepSeek's Anthropic API docs that endpoint carries
5
+ * thinking and tool_use/tool_result blocks and ignores cache_control and
6
+ * anthropic-beta; agent/tool sessions use it, tool-less one-shot requests stay
7
+ * on Chat (wire-route.mjs). DeepSeek has no Responses endpoint.
8
+ */
9
+ import { WireGatewayProvider, messagesBaseFromOpenAIBase } from './wire-gateway.mjs';
10
+ import { OPENAI_COMPAT_PRESETS } from './openai-compat-presets.mjs';
11
+
12
+ export function deepSeekMessagesBaseURL(configuredBaseURL) {
13
+ return `${messagesBaseFromOpenAIBase(configuredBaseURL || OPENAI_COMPAT_PRESETS.deepseek.baseURL)}/anthropic`;
14
+ }
15
+
16
+ // Requested effort → output_config.effort (thinking_mode docs: minimal/low →
17
+ // low, medium/high/xhigh → high, max/ultra → max).
18
+ const DEEPSEEK_EFFORT = Object.freeze({
19
+ minimal: 'low',
20
+ low: 'low',
21
+ medium: 'high',
22
+ high: 'high',
23
+ xhigh: 'high',
24
+ max: 'max',
25
+ ultra: 'max',
26
+ });
27
+ const DEEPSEEK_OFF = new Set(['none', 'off', 'disabled']);
28
+
29
+ /**
30
+ * DeepSeek's own effort contract on its Messages endpoint: thinking is on by
31
+ * default and `budget_tokens` is ignored, so an effort goes in
32
+ * `output_config.effort`; off is `thinking:{type:'disabled'}` together with the
33
+ * documented Anthropic-format toggle `reasoning:{effort:'none'}`. No effort
34
+ * leaves the default (thinking on, effort high). Always handles the request.
35
+ */
36
+ export function deepSeekEffortProjection(body, { effort } = {}) {
37
+ const level = String(effort ?? '')
38
+ .trim()
39
+ .toLowerCase();
40
+ if (DEEPSEEK_OFF.has(level)) {
41
+ body.thinking = { type: 'disabled' };
42
+ body.reasoning = { effort: 'none' };
43
+ return true;
44
+ }
45
+ const mapped = DEEPSEEK_EFFORT[level];
46
+ if (mapped) {
47
+ const existing = body.output_config && typeof body.output_config === 'object' ? body.output_config : {};
48
+ body.output_config = { ...existing, effort: mapped };
49
+ }
50
+ return true;
51
+ }
52
+
53
+ export class DeepSeekProvider extends WireGatewayProvider {
54
+ constructor(config = {}) {
55
+ super('deepseek', config, {
56
+ baseURL: deepSeekMessagesBaseURL(config.baseURL),
57
+ // The endpoint has no document block of any kind (PDFs included).
58
+ nativePdf: false,
59
+ nativeDocuments: false,
60
+ // disable_parallel_tool_use is ignored on every tool_choice.
61
+ supportsDisableParallelToolUse: false,
62
+ // Image `source.type: file` needs the Files API beta, on those requests only.
63
+ fileIdImageBeta: 'files-api-2025-04-14',
64
+ messagesEffortProjection: deepSeekEffortProjection,
65
+ });
66
+ }
67
+ }
@@ -1,3 +1,4 @@
1
+ import { isVisibleStreamProgress } from '../../../shared/stream-progress.mjs';
1
2
  import { anthropicEffortLevelsFor, normalizeAnthropicEffortInput } from './anthropic-effort.mjs';
2
3
  import { CUSTOM_EFFORT_LEVELS, customEffortLevels, isCustomProviderName } from './custom-reasoning.mjs';
3
4
  import { codexModelSupportsEffortUpdates } from './openai-oauth-catalog.mjs';
@@ -72,19 +73,40 @@ export function isEffortConfigurationRejection(status, text) {
72
73
  /**
73
74
  * Runs `send(opts)`; when the model rejects the mid-conversation effort
74
75
  * update, switches the updates off for it and replays the request once
75
- * without them. The rejection happens before any output streams.
76
+ * without them. Never replay after output reached the caller, cancellation,
77
+ * or an explicit opt-out; a late error is not evidence of missing support.
76
78
  */
77
79
  export async function withEffortConfigurationFallback(provider, model, opts, send) {
80
+ let streamed = false;
81
+ const track =
82
+ (callback, isProgress = false) =>
83
+ (...args) => {
84
+ if (!isProgress || isVisibleStreamProgress(args[0])) streamed = true;
85
+ return callback(...args);
86
+ };
87
+ const tracked = { ...opts };
88
+ if (typeof opts?.onStreamDelta === 'function') tracked.onStreamDelta = track(opts.onStreamDelta, true);
89
+ if (typeof opts?.onTextDelta === 'function') tracked.onTextDelta = track(opts.onTextDelta);
90
+ if (typeof opts?.onToolCall === 'function') tracked.onToolCall = track(opts.onToolCall);
78
91
  try {
79
- return await send(opts);
92
+ return await send(tracked);
80
93
  } catch (error) {
81
94
  const status = error?.status ?? error?.httpStatus;
82
- if (opts?._effortConfigurationRetry || !isEffortConfigurationRejection(status, error?.message)) throw error;
95
+ const emitted =
96
+ streamed || error?.liveTextEmitted === true || error?.emittedToolCall === true || error?.unsafeToRetry === true;
97
+ if (
98
+ opts?._effortConfigurationRetry ||
99
+ opts?.effortConfigurationEnabled === false ||
100
+ opts?.signal?.aborted ||
101
+ emitted ||
102
+ !isEffortConfigurationRejection(status, error?.message)
103
+ )
104
+ throw error;
83
105
  markEffortConfigurationUnsupported(provider, model);
84
106
  process.stderr.write(
85
107
  `[${provider}] ${model} rejected the mid-conversation effort update; retrying once without it\n`
86
108
  );
87
- return send({ ...opts, effortConfigurationEnabled: false, _effortConfigurationRetry: true });
109
+ return send({ ...tracked, effortConfigurationEnabled: false, _effortConfigurationRetry: true });
88
110
  }
89
111
  }
90
112
  const OPENAI_PROVIDERS = new Set(['openai', 'openai-oauth']);
@@ -183,7 +205,9 @@ export function autoEffortModel(providerName, providerImpl, model) {
183
205
  // list from falling back to a family ladder.
184
206
  return { id: model, reasoningLevels: anthropicEffortLevelsFor(model), customReasoning: true };
185
207
  }
186
- if (!isCustomProviderName(providerName)) return { id: model };
208
+ // Every other route reads the provider's own cached model row, the source
209
+ // route resolution (lookupModelMeta) uses; a bare id has no levels and
210
+ // skips the judge.
187
211
  return { ...(providerImpl?.getCachedModelInfo?.(model) || {}), id: model };
188
212
  }
189
213
 
@@ -14,7 +14,7 @@
14
14
  import { appendAgentTrace } from '../agent-trace.mjs';
15
15
  import {
16
16
  _estimateGeminiCacheTokens,
17
- _geminiCacheMinTokens,
17
+ geminiExplicitCacheMinTokens,
18
18
  _geminiCachePrefixCount,
19
19
  _geminiCachePrefixContents,
20
20
  _geminiCachePrefixHash,
@@ -146,6 +146,12 @@ export function awaitSharedCreate(task, signal) {
146
146
  // role='user' or 'model'; generateContent uses role='function' for
147
147
  // tool_result turns, so that is collapsed to 'user' (functionResponse parts
148
148
  // remain inside).
149
+ // The model id without its `models/` resource prefix; every URL and body that
150
+ // adds the prefix itself starts from this.
151
+ export function geminiBareModelId(model) {
152
+ return String(model || '').replace(/^models\//i, '');
153
+ }
154
+
149
155
  export function geminiCacheCreateBody({
150
156
  model,
151
157
  ttlSeconds,
@@ -157,7 +163,7 @@ export function geminiCacheCreateBody({
157
163
  }) {
158
164
  const cachePrefixContents = _geminiCachePrefixContents(contents, cachePrefixContentCount);
159
165
  const body = {
160
- model: `models/${model}`,
166
+ model: `models/${geminiBareModelId(model)}`,
161
167
  ttl: `${ttlSeconds}s`,
162
168
  };
163
169
  if (systemInstruction) {
@@ -252,9 +258,10 @@ export function dropRejectedGeminiCache(cachedContent, opts) {
252
258
  // the model-specific minimum. Skip the POST entirely when the estimate
253
259
  // is under threshold so we don't spam 400 responses turn-after-turn.
254
260
  export function geminiPrefixBelowMinimum({ model, systemInstruction, geminiTools, contents, opts, currentIter }) {
255
- const minTokens = _geminiCacheMinTokens();
261
+ // null: the model is excluded from explicit caching, so never create one.
262
+ const minTokens = geminiExplicitCacheMinTokens(model);
256
263
  const estimatedTokens = _estimateGeminiCacheTokens(systemInstruction, geminiTools, contents);
257
- if (estimatedTokens >= minTokens) return false;
264
+ if (minTokens !== null && estimatedTokens >= minTokens) return false;
258
265
  traceGeminiCache(opts, currentIter, 'gemini_cache_skip', {
259
266
  reason: 'prefix_below_min',
260
267
  estimatedTokens,
@@ -66,17 +66,30 @@ export function _estimateGeminiCacheTokens(systemInstruction, geminiTools, conte
66
66
  return Math.ceil(chars / 4);
67
67
  }
68
68
 
69
- // No catalog publishes the cachedContents floor and the published minimums
70
- // differ per model and change between releases, so one floor serves every id:
71
- // the highest published minimum. Skipping a small prefix only falls back to the
72
- // implicit cache, whereas a floor that is too low would POST a create that the
73
- // server rejects on every turn.
69
+ // Explicit-cache eligibility and minimum prefix size per model, from the
70
+ // caching docs: explicit caching works on Gemini 3 and 2.5 and is not supported
71
+ // from Gemini 4 onward; documented minimums are 4096 for Gemini 3.x and 2048
72
+ // for 2.5 Flash/Pro. Other ids keep the conservative 4096 floor (skipping a
73
+ // small prefix only falls back to the implicit cache, whereas a floor that is
74
+ // too low would POST a create the server rejects every turn).
74
75
  const GEMINI_CACHE_MIN_TOKENS = 4096;
75
76
 
76
- export function _geminiCacheMinTokens() {
77
+ // Minimum prefix tokens for an explicit cache, or null when the docs exclude
78
+ // the model from explicit caching.
79
+ export function geminiExplicitCacheMinTokens(model) {
80
+ const bare = String(model || '')
81
+ .replace(/^models\//i, '')
82
+ .toLowerCase();
83
+ const major = /^gemini-(\d+)/.exec(bare);
84
+ if (major && Number(major[1]) >= 4) return null;
85
+ if (/^gemini-2\.5-(?:pro|flash)(?!-lite)(?:-|$)/.test(bare)) return 2048;
77
86
  return GEMINI_CACHE_MIN_TOKENS;
78
87
  }
79
88
 
89
+ export function _geminiCacheMinTokens(model) {
90
+ return geminiExplicitCacheMinTokens(model) ?? GEMINI_CACHE_MIN_TOKENS;
91
+ }
92
+
80
93
  export function _geminiCachePrefixCount(contents) {
81
94
  return Array.isArray(contents) && contents.length > 1 ? contents.length - 1 : 0;
82
95
  }
@@ -128,8 +141,10 @@ export function markGeminiExplicitCacheRefused(model, err) {
128
141
  return true;
129
142
  }
130
143
 
144
+ // True when explicit cache creates must not be attempted: the docs exclude the
145
+ // model, or the server already refused it.
131
146
  export function geminiExplicitCacheRefused(model) {
132
- return geminiExplicitCacheRefusedModels.has(String(model || ''));
147
+ return geminiExplicitCacheMinTokens(model) === null || geminiExplicitCacheRefusedModels.has(String(model || ''));
133
148
  }
134
149
 
135
150
  export function _geminiCredentialFingerprint(apiKey) {
@@ -245,20 +260,28 @@ export function _resolveGeminiCacheUsage({ usageMetadata, cachedContent, provide
245
260
  firstFinite(usageMetadata?.thoughtsTokenCount, usageMetadata?.thoughts_token_count);
246
261
  const hasExplicitPromptTokens =
247
262
  Object.hasOwn(usageMetadata || {}, 'promptTokenCount') || Object.hasOwn(usageMetadata || {}, 'prompt_token_count');
248
- const inputTokens = hasExplicitPromptTokens ? promptTokens : Math.max(0, totalTokens - outputTokens);
249
- const reportedCachedTokens = firstFinite(
263
+ // toolUsePromptTokenCount (tool-result prompt tokens) is billed as input and
264
+ // reported separately from promptTokenCount; cached tokens stay a subset of
265
+ // the prompt portion.
266
+ const toolUseTokens = firstFinite(usageMetadata?.toolUsePromptTokenCount, usageMetadata?.tool_use_prompt_token_count);
267
+ const inputTokens = hasExplicitPromptTokens ? promptTokens + toolUseTokens : Math.max(0, totalTokens - outputTokens);
268
+ const reportedCachedCount = [
250
269
  // generateContent UsageMetadata field.
251
270
  usageMetadata?.cachedContentTokenCount,
252
271
  usageMetadata?.cached_content_token_count,
253
272
  // Newer SDK convenience alias documented for implicit cache hits.
254
273
  usageMetadata?.totalCachedTokens,
255
- usageMetadata?.total_cached_tokens
256
- );
274
+ usageMetadata?.total_cached_tokens,
275
+ ]
276
+ .map((value) => (value == null ? NaN : Number(value)))
277
+ .find((value) => Number.isFinite(value) && value >= 0);
278
+ const reportedCachedTokens = reportedCachedCount ?? 0;
257
279
  const cachedFallbackTokens = cachedContent ? Number(providerState?.gemini?.cacheTokenSize || 0) || 0 : 0;
258
- const rawCachedTokens = reportedCachedTokens > 0 ? reportedCachedTokens : cachedFallbackTokens;
280
+ // An explicit zero is a measured miss, not missing usage metadata.
281
+ const rawCachedTokens = reportedCachedCount ?? cachedFallbackTokens;
259
282
  const cachedTokens = inputTokens > 0 ? Math.min(rawCachedTokens, inputTokens) : rawCachedTokens;
260
283
  let cacheTokenSource = 'none';
261
- if (reportedCachedTokens > 0) cacheTokenSource = 'usage_metadata';
284
+ if (reportedCachedCount !== undefined) cacheTokenSource = 'usage_metadata';
262
285
  else if (cachedFallbackTokens > 0) cacheTokenSource = 'cache_create_fallback';
263
286
  return {
264
287
  inputTokens,
@@ -97,7 +97,10 @@ export function geminiErrorContract({ details, errorDetails, googleStatus, messa
97
97
  const scope = scopeOf(String(violation?.quotaId || ''));
98
98
  if (scope) scopes.add(scope);
99
99
  // A spent allowance is named by the typed violation, not by prose.
100
- if (String(violation?.quotaValue ?? '').trim() === '0' || LIMIT_ZERO_RE.test(String(violation?.description || ''))) {
100
+ if (
101
+ String(violation?.quotaValue ?? '').trim() === '0' ||
102
+ LIMIT_ZERO_RE.test(String(violation?.description || ''))
103
+ ) {
101
104
  zeroLimit = true;
102
105
  }
103
106
  }
@@ -121,7 +124,9 @@ export function geminiErrorContract({ details, errorDetails, googleStatus, messa
121
124
  CAPACITY_REASONS.has(reason) ||
122
125
  (!reason && scopes.size === 0 && retryAfterMs === undefined && CAPACITY_MESSAGE_RE.test(text));
123
126
  // A per-day violation outlasts any per-minute one reported with it.
124
- let quotaScope = scopes.has('day') ? 'day' : scopes.has('minute') ? 'minute' : undefined;
127
+ let quotaScope;
128
+ if (scopes.has('day')) quotaScope = 'day';
129
+ else if (scopes.has('minute')) quotaScope = 'minute';
125
130
  if (retryAfterMs === undefined) {
126
131
  const named = MESSAGE_DELAY_RE.exec(text);
127
132
  if (named) retryAfterMs = adviceMs(named[1]);
@@ -158,10 +163,13 @@ export function geminiInBandError(chunk, label) {
158
163
  if (!detail || (typeof detail !== 'object' && typeof detail !== 'string')) return null;
159
164
  const body = typeof detail === 'object' ? detail : { message: detail };
160
165
  const googleStatus = typeof body.status === 'string' ? body.status : '';
161
- const status = Number.isFinite(Number(body.code)) && Number(body.code) > 0
162
- ? Number(body.code)
163
- : GOOGLE_STATUS_HTTP[googleStatus.toUpperCase()];
164
- const err = new Error(`${label} in-band error${status ? ` ${status}` : ''}: ${String(body.message || googleStatus || 'unknown').slice(0, 300)}`);
166
+ const status =
167
+ Number.isFinite(Number(body.code)) && Number(body.code) > 0
168
+ ? Number(body.code)
169
+ : GOOGLE_STATUS_HTTP[googleStatus.toUpperCase()];
170
+ const err = new Error(
171
+ `${label} in-band error${status ? ` ${status}` : ''}: ${String(body.message || googleStatus || 'unknown').slice(0, 300)}`
172
+ );
165
173
  err.name = 'GeminiInBandError';
166
174
  if (status) {
167
175
  err.status = status;
@@ -180,12 +188,94 @@ export function assertNoGeminiInBandError(chunk, label) {
180
188
  if (err) throw err;
181
189
  }
182
190
 
183
- const SAFETY_FINISH = /^(?:PROMPT_)?(?:SAFETY|IMAGE_SAFETY|BLOCKLIST|PROHIBITED_CONTENT|SPII|IMAGE_PROHIBITED_CONTENT)$/;
191
+ const FINISH_KINDS = new Map(
192
+ Object.entries({
193
+ complete: ['STOP'],
194
+ output_limit: ['MAX_TOKENS'],
195
+ // Content refused by policy: deterministic, never re-asked.
196
+ policy: [
197
+ 'SAFETY',
198
+ 'BLOCKLIST',
199
+ 'PROHIBITED_CONTENT',
200
+ 'SPII',
201
+ 'IMAGE_SAFETY',
202
+ 'IMAGE_PROHIBITED_CONTENT',
203
+ 'ESCALATION',
204
+ 'PUP_LIMITED_DISABLED',
205
+ ],
206
+ language: ['LANGUAGE'],
207
+ recitation: ['RECITATION', 'IMAGE_RECITATION'],
208
+ // The model produced no usable call: the same request is re-asked.
209
+ invalid_tool_call: ['MALFORMED_FUNCTION_CALL', 'UNEXPECTED_TOOL_CALL', 'MALFORMED_RESPONSE'],
210
+ // Tool-call terminals a re-ask cannot fix.
211
+ tool_call: ['TOO_MANY_TOOL_CALLS', 'MISSING_THOUGHT_SIGNATURE'],
212
+ continuation: ['CONTINUATION'],
213
+ other: ['OTHER', 'IMAGE_OTHER', 'NO_IMAGE'],
214
+ }).flatMap(([kind, reasons]) => reasons.map((reason) => [reason, kind]))
215
+ );
216
+
217
+ /** Finish (or `PROMPT_`-prefixed block) reason without wire prefixes. */
218
+ export function geminiNormalizeFinishReason(finishReason) {
219
+ return String(finishReason || '')
220
+ .replace(/^FINISH_REASON_/, '')
221
+ .replace(/^PROMPT_/, '')
222
+ .replace(/^BLOCK_REASON_/, '');
223
+ }
224
+
225
+ /**
226
+ * Kind of a documented finishReason / blockReason: 'none' (absent or
227
+ * UNSPECIFIED: the stream is unfinished), 'complete', 'output_limit',
228
+ * 'policy', 'language', 'recitation', 'invalid_tool_call', 'tool_call',
229
+ * 'continuation' or 'other' (OTHER and any undocumented future reason).
230
+ */
231
+ export function geminiFinishReasonKind(finishReason) {
232
+ const reason = geminiNormalizeFinishReason(finishReason);
233
+ if (!reason || reason === 'UNSPECIFIED') return 'none';
234
+ return FINISH_KINDS.get(reason) || 'other';
235
+ }
184
236
 
185
237
  /** Policy-refusal code for a finishReason, or null for any other reason. */
186
238
  export function geminiPolicyFinishCode(finishReason) {
187
- const reason = String(finishReason || '').replace(/^FINISH_REASON_/, '');
188
- if (SAFETY_FINISH.test(reason)) return 'safety';
189
- if (/^(?:PROMPT_)?RECITATION$/.test(reason)) return 'recitation';
190
- return null;
239
+ switch (geminiFinishReasonKind(finishReason)) {
240
+ case 'policy':
241
+ return 'safety';
242
+ case 'recitation':
243
+ return 'recitation';
244
+ case 'language':
245
+ return 'content_filter';
246
+ default:
247
+ return null;
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Evidence a terminal response carries beyond its finishReason: candidate and
253
+ * prompt safety ratings, the finish message, the prompt block reason and any
254
+ * continuation token. Only present fields are returned.
255
+ */
256
+ export function geminiFinishErrorFields(response) {
257
+ const candidate = response?.candidates?.[0];
258
+ const feedback = response?.promptFeedback;
259
+ const fields = {
260
+ finishMessage: candidate?.finishMessage,
261
+ safetyRatings: candidate?.safetyRatings,
262
+ blockReason: feedback?.blockReason,
263
+ promptSafetyRatings: feedback?.safetyRatings,
264
+ continuationToken: candidate?.continuationToken,
265
+ };
266
+ return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));
267
+ }
268
+
269
+ /**
270
+ * Typed result for a CONTINUATION finish, which this client cannot resume
271
+ * (Gemini direct only). Keeps the original error's partial turn and the
272
+ * token so a caller can continue it out of band.
273
+ */
274
+ export function geminiContinuationUnsupportedError(incomplete, response) {
275
+ return Object.assign(incomplete, geminiFinishErrorFields(response), {
276
+ name: 'GeminiContinuationUnsupportedError',
277
+ code: 'CONTINUATION_UNSUPPORTED',
278
+ continuationUnsupported: true,
279
+ message: 'Gemini response stopped with finishReason=CONTINUATION; continuation is not supported by this client',
280
+ });
191
281
  }
@@ -12,6 +12,30 @@ import { geminiThinkingConfig } from './gemini-thinking.mjs';
12
12
  import { toGeminiContents, toGeminiRequestTools, toGeminiToolConfig } from './gemini-schema.mjs';
13
13
 
14
14
  // Request pieces shared by the cached REST path and the SDK path.
15
+ // Caller-supplied generation controls the wire carries in generationConfig.
16
+ // maxOutputTokens counts thought tokens too (see the thinking docs). Anything
17
+ // invalid is rejected here instead of being dropped. (safetySettings is a
18
+ // request-level field, forwarded separately.)
19
+ function geminiGenerationControls(opts) {
20
+ const controls = {};
21
+ const maxRaw = opts.maxOutputTokens ?? opts.max_output_tokens;
22
+ if (maxRaw !== undefined && maxRaw !== null) {
23
+ const max = Number(maxRaw);
24
+ if (!Number.isInteger(max) || max <= 0) {
25
+ throw new TypeError('maxOutputTokens must be a positive integer (it includes thinking tokens).');
26
+ }
27
+ controls.maxOutputTokens = max;
28
+ }
29
+ if (opts.temperature !== undefined && opts.temperature !== null) {
30
+ const temperature = Number(opts.temperature);
31
+ if (!Number.isFinite(temperature) || temperature < 0 || temperature > 2) {
32
+ throw new TypeError('temperature must be a number between 0 and 2.');
33
+ }
34
+ controls.temperature = temperature;
35
+ }
36
+ return controls;
37
+ }
38
+
15
39
  export function buildGeminiRequest(messages, useModel, tools, opts) {
16
40
  // Gemini returns thought summaries only when the request asks for them.
17
41
  // Without this the reasoning channel stays empty for the whole turn and
@@ -19,7 +43,11 @@ export function buildGeminiRequest(messages, useModel, tools, opts) {
19
43
  // round reads as another preamble. On by default for every model; an
20
44
  // explicit opts.includeThoughts still wins.
21
45
  const thinkingConfig = geminiThinkingConfig(useModel, opts, { includeThoughts: true });
22
- const generationConfig = thinkingConfig ? { thinkingConfig } : undefined;
46
+ const controls = geminiGenerationControls(opts);
47
+ let generationConfig;
48
+ if (thinkingConfig || Object.keys(controls).length) {
49
+ generationConfig = { ...(thinkingConfig ? { thinkingConfig } : {}), ...controls };
50
+ }
23
51
  const systemInstruction =
24
52
  messages
25
53
  .filter((m) => m.role === 'system')
@@ -29,17 +57,24 @@ export function buildGeminiRequest(messages, useModel, tools, opts) {
29
57
  const contents = toGeminiContents(chatMsgs, useModel);
30
58
  if (!contents.length) throw new Error('No messages to send');
31
59
 
32
- const requestTools = toGeminiRequestTools(tools, opts.nativeTools);
60
+ const requestTools = toGeminiRequestTools(tools, opts.nativeTools, { onToolExcluded: opts.onToolExcluded });
33
61
  const geminiTools = requestTools.length ? requestTools : undefined;
34
- const toolConfig = tools?.length ? toGeminiToolConfig(opts.toolChoice) : undefined;
35
- return { generationConfig, systemInstruction, contents, geminiTools, toolConfig };
62
+ // Tool config only accompanies function declarations that were kept.
63
+ const toolConfig = requestTools.some((entry) => entry.functionDeclarations?.length)
64
+ ? toGeminiToolConfig(opts.toolChoice)
65
+ : undefined;
66
+ if (opts.safetySettings !== undefined && opts.safetySettings !== null && !Array.isArray(opts.safetySettings)) {
67
+ throw new TypeError('safetySettings must be an array of { category, threshold } entries.');
68
+ }
69
+ const safetySettings = opts.safetySettings?.length ? opts.safetySettings : undefined;
70
+ return { generationConfig, systemInstruction, contents, geminiTools, toolConfig, safetySettings };
36
71
  }
37
72
 
38
73
  // The generateContent body for a cached prefix. The cache carries the
39
74
  // recorded prefix; every uncached tail turn is sent, not just the last
40
75
  // message, so reused cachedContents preserve full conversation context
41
76
  // between periodic refreshes.
42
- export function geminiCachedRestBody({ opts, contents, cachedContent, generationConfig }) {
77
+ export function geminiCachedRestBody({ opts, contents, cachedContent, generationConfig, safetySettings }) {
43
78
  const cachedPrefixContentCount = Number.isFinite(Number(opts.providerState?.gemini?.cachePrefixContentCount))
44
79
  ? Math.max(0, Math.min(contents.length, Math.trunc(Number(opts.providerState.gemini.cachePrefixContentCount))))
45
80
  : 0;
@@ -48,5 +83,6 @@ export function geminiCachedRestBody({ opts, contents, cachedContent, generation
48
83
  contents: deltaContents.length ? deltaContents : contents.slice(-1),
49
84
  cachedContent,
50
85
  ...(generationConfig ? { generationConfig } : {}),
86
+ ...(safetySettings ? { safetySettings } : {}),
51
87
  };
52
88
  }
@@ -149,6 +149,7 @@ export function resolveGeminiUsage(response, opts, cachedContent, useModel) {
149
149
  }
150
150
 
151
151
  export function geminiSendResult(parsed, useModel, opts, resolvedUsage) {
152
+ if (parsed.providerReplay) parsed.providerReplay.requestContext = { model: useModel };
152
153
  return {
153
154
  content: parsed.content,
154
155
  model: useModel,
@@ -1,7 +1,11 @@
1
1
  // First-byte and idle watchdogs of one Gemini REST SSE body. Either timeout
2
2
  // cancels the reader and fails the pending read, so the caller surfaces a typed
3
- // timeout instead of waiting on a stalled socket.
4
- import { PROVIDER_SSE_IDLE_TIMEOUT_MS, PROVIDER_SSE_IDLE_WATCHDOG_ENABLED } from '../../stall-policy.mjs';
3
+ // timeout instead of waiting on a stalled socket. The idle timer re-arms only
4
+ // on decoded payloads (semantic progress), so it uses the semantic window.
5
+ // Each timeout names its phase (`timeoutPhase`): 'first-chunk' before any
6
+ // payload, 'idle' after one.
7
+ import { PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS, PROVIDER_SSE_IDLE_WATCHDOG_ENABLED } from '../../stall-policy.mjs';
8
+ import { TIMEOUT_PHASE } from '../../../../shared/provider-timeout-phase.mjs';
5
9
 
6
10
  export function createRestStreamWatchdogs({ reader, label, firstByteTimeoutMs, timeoutError }) {
7
11
  let idleTimedOut = false;
@@ -19,11 +23,18 @@ export function createRestStreamWatchdogs({ reader, label, firstByteTimeoutMs, t
19
23
  pendingReject = null;
20
24
  reject(err);
21
25
  };
22
- const idleError = () => timeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
26
+ const idleError = () =>
27
+ Object.assign(timeoutError(`${label} SSE idle`, PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS), {
28
+ timeoutPhase: TIMEOUT_PHASE.IDLE,
29
+ });
23
30
 
24
31
  let firstByteTimer = setTimeout(() => {
25
32
  cancelReader('first byte timeout');
26
- failPending(timeoutError(`${label} first byte`, firstByteTimeoutMs));
33
+ failPending(
34
+ Object.assign(timeoutError(`${label} first byte`, firstByteTimeoutMs), {
35
+ timeoutPhase: TIMEOUT_PHASE.FIRST_CHUNK,
36
+ })
37
+ );
27
38
  }, firstByteTimeoutMs);
28
39
  firstByteTimer.unref?.();
29
40
  const clearFirstByte = () => {
@@ -46,7 +57,7 @@ export function createRestStreamWatchdogs({ reader, label, firstByteTimeoutMs, t
46
57
  idleTimedOut = true;
47
58
  cancelReader('SSE idle timeout');
48
59
  failPending(idleError());
49
- }, PROVIDER_SSE_IDLE_TIMEOUT_MS);
60
+ }, PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS);
50
61
  idleTimer.unref?.();
51
62
  },
52
63
  // One reader.read() with its reject handle registered for the watchdogs;
@@ -11,8 +11,9 @@
11
11
  * re-issues the whole request up to 4 attempts total at
12
12
  * 1s / 2s / 4s. A response that finished with no finish
13
13
  * reason is never judged here, and right after a tool
14
- * result an empty response (no finish reason or no text)
15
- * is accepted as the model's answer. An empty answer that
14
+ * result an empty STOP answer is accepted as the model's
15
+ * answer (an empty stream with no finish reason is still
16
+ * unfinished). An empty answer that
16
17
  * survives all 4 attempts throws a typed, provider-terminal
17
18
  * invalid-stream error instead of returning nothing.
18
19
  * long advice a server wait over 300s ends recovery on both phases
@@ -25,6 +26,7 @@
25
26
  import { readStreamOutcome } from './lib/stream-outcome.mjs';
26
27
  import { DETERMINISTIC_KINDS, providerErrorKind, typedCodeKind } from './provider-error-kind.mjs';
27
28
  import { midstreamRetryDelayMs } from './retry-backoff.mjs';
29
+ import { geminiFinishReasonKind, geminiNormalizeFinishReason } from './gemini-error-contract.mjs';
28
30
  import { classifyError, markProviderRecoveryExhausted, sleepWithAbort, withRetry } from './retry-classifier.mjs';
29
31
 
30
32
  export const GEMINI_REQUEST_RETRY = Object.freeze({
@@ -80,16 +82,13 @@ export function geminiMidstreamDelayMs(err, streamAttempt, signal = null) {
80
82
 
81
83
  const statusOf = (err) => Number(err?.httpStatus || err?.status || 0);
82
84
 
83
- const INVALID_TOOL_CALL_FINISH = new Set(['MALFORMED_FUNCTION_CALL', 'UNEXPECTED_TOOL_CALL']);
84
- // Empty-text finishes that are deterministic refusals or output-limit stops,
85
- // owned by the policy / incomplete handling instead of a re-ask.
86
- const EMPTY_TEXT_TERMINAL_FINISH = new Set(['MAX_TOKENS', 'SAFETY', 'RECITATION']);
87
-
88
85
  /**
89
86
  * Invalid stream: the reason a finished response is unusable
90
- * ('MALFORMED_FUNCTION_CALL' | 'UNEXPECTED_TOOL_CALL' | 'NO_RESPONSE_TEXT'),
91
- * or null. A response that carried a tool call, or whose text was already
92
- * relayed, is never invalid (and never replayed).
87
+ * ('MALFORMED_FUNCTION_CALL' | 'UNEXPECTED_TOOL_CALL' | 'MALFORMED_RESPONSE' |
88
+ * 'NO_RESPONSE_TEXT'), or null. A response that carried a tool call, or whose
89
+ * text was already relayed, is never invalid (and never replayed). Only a
90
+ * STOP with no text is "no text"; every other documented finish (policy,
91
+ * output limit, continuation, OTHER, ...) is owned by the incomplete handling.
93
92
  */
94
93
  export function geminiInvalidStreamReason(response, textLeakGuard = null, { afterToolResult = false } = {}) {
95
94
  const candidate = response?.candidates?.[0];
@@ -97,9 +96,10 @@ export function geminiInvalidStreamReason(response, textLeakGuard = null, { afte
97
96
  if (parts.some((part) => part?.functionCall)) return null;
98
97
  if ((textLeakGuard?.getLeakedToolCalls?.() || []).length > 0) return null;
99
98
  if ((textLeakGuard?.getRelayedText?.() || '').length > 0) return null;
100
- const finish = String(candidate?.finishReason || '').replace(/^FINISH_REASON_/, '');
101
- if (INVALID_TOOL_CALL_FINISH.has(finish)) return finish;
102
- if (!finish || EMPTY_TEXT_TERMINAL_FINISH.has(finish)) return null;
99
+ const finish = geminiNormalizeFinishReason(candidate?.finishReason);
100
+ const kind = geminiFinishReasonKind(finish);
101
+ if (kind === 'invalid_tool_call') return finish;
102
+ if (kind !== 'complete') return null;
103
103
  // Right after a tool result the model may legitimately answer with nothing.
104
104
  if (afterToolResult) return null;
105
105
  const text = parts
@@ -148,7 +148,12 @@ export async function runGeminiStreamAttempts({ run, signal, onRetry, sleepFn, a
148
148
  } catch (err) {
149
149
  const waitMs = connected ? geminiMidstreamDelayMs(err, streamAttempt, signal) : null;
150
150
  if (waitMs == null) throw err;
151
- onRetry?.({ attempt: streamAttempt + 1, maxAttempts: GEMINI_MIDSTREAM_MAX_ATTEMPTS, lastErr: err, delayMs: waitMs });
151
+ onRetry?.({
152
+ attempt: streamAttempt + 1,
153
+ maxAttempts: GEMINI_MIDSTREAM_MAX_ATTEMPTS,
154
+ lastErr: err,
155
+ delayMs: waitMs,
156
+ });
152
157
  await sleepWithAbort(waitMs, signal, sleepFn, 'Gemini stream retry wait aborted');
153
158
  continue;
154
159
  }