mixdog 1.2.2 → 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 (415) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/provider-pingpong-live.mjs +509 -0
  4. package/src/agents/advisor/AGENT.md +1 -1
  5. package/src/agents/advisor/agent.json +1 -1
  6. package/src/defaults/shipped-history.json +5 -0
  7. package/src/defaults/skills/setup/SKILL.md +6 -1
  8. package/src/defaults/skills/setup/references/actions.md +44 -22
  9. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  10. package/src/headless-exec.mjs +15 -8
  11. package/src/lib/keychain-cjs.cjs +7 -4
  12. package/src/output-styles/common.md +11 -10
  13. package/src/rules/agent/AGENT.md +5 -5
  14. package/src/rules/lead/LEAD.md +5 -5
  15. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  16. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  17. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  18. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  19. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  21. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  22. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  23. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
  28. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  30. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  31. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  32. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
  39. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  40. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
  41. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  42. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
  43. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
  45. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
  49. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  50. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
  51. package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
  52. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  53. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  54. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  55. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  56. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  57. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  59. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
  60. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
  61. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  62. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
  63. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
  64. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  65. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
  66. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
  67. package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
  68. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  71. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  72. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  73. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  74. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  75. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  76. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  77. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  78. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  80. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  81. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  82. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  83. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  84. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  85. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  86. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +121 -61
  89. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  90. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  91. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  92. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  93. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +42 -24
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +53 -5
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  108. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  109. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  110. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  111. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +25 -4
  112. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  114. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  115. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  117. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  119. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  121. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
  122. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  123. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  124. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  125. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  126. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  127. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  130. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +11 -3
  131. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  132. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  133. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  134. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +147 -8
  135. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  136. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
  137. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  138. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  139. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  140. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  141. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  142. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  147. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  148. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  150. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  151. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  154. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
  156. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  157. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  158. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  159. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  160. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  161. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  162. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  163. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  164. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  165. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  167. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  168. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  169. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  170. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  171. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  172. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +63 -20
  173. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
  174. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  175. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  179. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +4 -1
  180. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  181. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +16 -0
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  184. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  187. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  188. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
  189. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  190. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  192. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  193. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  195. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  196. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +13 -0
  197. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  198. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  199. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  200. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  201. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  203. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  204. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  205. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  206. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  207. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  208. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  209. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  210. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  211. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  212. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  213. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  216. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  217. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  218. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  221. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  223. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  224. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  225. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  226. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  227. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  228. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  229. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  230. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  231. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  232. package/src/runtime/github/tool.mjs +92 -2
  233. package/src/runtime/memory/index.mjs +1 -0
  234. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  235. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  236. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  237. package/src/runtime/memory/lib/pg/process.mjs +31 -26
  238. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
  240. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  241. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  242. package/src/runtime/office/README.md +1 -1
  243. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  244. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  245. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  246. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  247. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  248. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  249. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  250. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  251. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  252. package/src/runtime/office/core/office-sessions.mjs +5 -0
  253. package/src/runtime/office/core/office-transactions.mjs +3 -0
  254. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  255. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  256. package/src/runtime/office/index.mjs +30 -0
  257. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  258. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  259. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  260. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  261. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  262. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  263. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  264. package/src/runtime/shared/buffered-appender.mjs +18 -0
  265. package/src/runtime/shared/config.mjs +78 -18
  266. package/src/runtime/shared/err-text.mjs +6 -0
  267. package/src/runtime/shared/file-permissions.d.mts +6 -1
  268. package/src/runtime/shared/file-permissions.mjs +54 -6
  269. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  270. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  271. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  272. package/src/runtime/shared/loopback-listener.mjs +9 -0
  273. package/src/runtime/shared/provider-api-key.mjs +2 -0
  274. package/src/runtime/shared/review-diff.mjs +52 -0
  275. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  276. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  277. package/src/runtime/shared/slow-span.mjs +114 -0
  278. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  279. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  280. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  281. package/src/runtime/shared/tool-card-model.mjs +5 -2
  282. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  283. package/src/runtime/shared/tool-primitives.mjs +13 -0
  284. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  285. package/src/runtime/shared/tool-surface.mjs +18 -3
  286. package/src/runtime/shared/tool-work-units.mjs +40 -4
  287. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  288. package/src/runtime/shared/transcript-writer.mjs +10 -2
  289. package/src/runtime/shared/turn-changes.mjs +268 -100
  290. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  291. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  292. package/src/runtime/shared/turn-snapshot.mjs +857 -683
  293. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  294. package/src/runtime/shared/user-data-guard.mjs +262 -49
  295. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  296. package/src/runtime/shared/worktrees/contract.mjs +34 -0
  297. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  298. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  299. package/src/runtime/shared/worktrees/git.mjs +8 -3
  300. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  301. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  302. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  303. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  304. package/src/runtime/terminal-bridge/client.mjs +44 -11
  305. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  306. package/src/runtime/tidy/apply.mjs +47 -2
  307. package/src/runtime/tidy/run-engines.mjs +11 -5
  308. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  309. package/src/session-runtime/boot/apis.mjs +13 -5
  310. package/src/session-runtime/boot/facade.mjs +1 -0
  311. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  312. package/src/session-runtime/boot/session.mjs +0 -1
  313. package/src/session-runtime/boot/tools.mjs +4 -1
  314. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  315. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  316. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  317. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  318. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  319. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  320. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  321. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  322. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -3
  323. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  324. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  325. package/src/session-runtime/lifecycle/teardown.mjs +72 -7
  326. package/src/session-runtime/lifecycle-api.mjs +1 -0
  327. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  328. package/src/session-runtime/model-route/set-route.mjs +2 -2
  329. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  330. package/src/session-runtime/native-web-search.mjs +10 -1
  331. package/src/session-runtime/new-session-config.mjs +4 -2
  332. package/src/session-runtime/provider-auth/login.mjs +4 -0
  333. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  334. package/src/session-runtime/runtime-review-api.mjs +8 -2
  335. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  336. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  337. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  338. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  339. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  340. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  341. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  342. package/src/session-runtime/services/agent-tool.mjs +3 -0
  343. package/src/session-runtime/services/channel-admin.mjs +19 -3
  344. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  345. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  346. package/src/session-runtime/services/provider-admin.mjs +81 -15
  347. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  348. package/src/session-runtime/session-turn-api.mjs +14 -5
  349. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  350. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  351. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  352. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  353. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  354. package/src/session-runtime/skills-api.mjs +3 -5
  355. package/src/session-runtime/tool-surface.mjs +5 -1
  356. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  357. package/src/session-runtime/turn/session-ops.mjs +7 -5
  358. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  359. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  360. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  361. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  362. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  363. package/src/session-runtime/turn/turn-run.mjs +25 -9
  364. package/src/session-runtime/usage-stats-api.mjs +43 -11
  365. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  366. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  367. package/src/session-runtime/workspace/transitions.mjs +190 -15
  368. package/src/standalone/daemon-agent-control.mjs +9 -1
  369. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  370. package/src/standalone/daemon-owner.mjs +17 -4
  371. package/src/standalone/daemon-pg-stop.mjs +51 -0
  372. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  373. package/src/standalone/daemon-stop-budget.mjs +18 -0
  374. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  375. package/src/standalone/daemon-telemetry.mjs +19 -0
  376. package/src/standalone/daemon.mjs +61 -1
  377. package/src/standalone/desktop-service-registry.mjs +5 -0
  378. package/src/standalone/local-session-runtime.mjs +70 -19
  379. package/src/standalone/session-client.mjs +42 -0
  380. package/src/standalone/session-protocol.mjs +7 -0
  381. package/src/standalone/session-proxy/projection.mjs +41 -4
  382. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  383. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  384. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  385. package/src/standalone/session-service-api.mjs +6 -1
  386. package/src/standalone/session-state-patch.d.mts +2 -1
  387. package/src/standalone/session-state-patch.mjs +41 -1
  388. package/src/tui/App.jsx +25 -0
  389. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  390. package/src/tui/app/btw-controller.mjs +118 -0
  391. package/src/tui/app/create-app-pickers.mjs +2 -0
  392. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  393. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  394. package/src/tui/app/slash-commands.mjs +13 -3
  395. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  396. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  397. package/src/tui/app/use-global-key-input.mjs +5 -12
  398. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  399. package/src/tui/components/BtwPanel.jsx +53 -0
  400. package/src/tui/components/QuestionPanel.jsx +275 -0
  401. package/src/tui/components/question-panel-model.mjs +156 -0
  402. package/src/tui/dist/index.mjs +2413 -1465
  403. package/src/tui/session/context-state.mjs +4 -2
  404. package/src/tui/session/session-api/commands.mjs +10 -0
  405. package/src/tui/session/session-api/controls.mjs +2 -2
  406. package/src/tui/session/session-api/integrations.mjs +9 -2
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  408. package/src/tui/session/session-api/lifecycle.mjs +2 -1
  409. package/src/tui/session/session-api/settings.mjs +6 -0
  410. package/src/tui/session/session-api.mjs +1 -0
  411. package/src/tui/session/tool-approval.mjs +10 -7
  412. package/src/tui/session/transcript-spill.mjs +14 -7
  413. package/src/tui/session/turn-stream.mjs +174 -31
  414. package/src/tui/session/turn.mjs +12 -5
  415. package/src/workflows/default/WORKFLOW.md +3 -1
@@ -279,7 +279,7 @@ function _stripResponseItemsFromHead(items, responseItems) {
279
279
  // Official OpenAI Responses WebSocket guide: response.create WS frames mirror
280
280
  // the Responses body EXCEPT the transport-only fields `stream`/`background`,
281
281
  // which the socket carries implicitly and the guide says to omit. This set is
282
- // stripped from a frame (any build shape) only when omitTransportFields is on.
282
+ // always stripped from a frame (any build shape).
283
283
  const TRANSPORT_ONLY_FRAME_FIELDS = new Set(['stream', 'background']);
284
284
 
285
285
  // Canonical response.create frame builder. Every WS send (main full-frame
@@ -293,14 +293,12 @@ const TRANSPORT_ONLY_FRAME_FIELDS = new Set(['stream', 'background']);
293
293
  // response, so dropping them here strips the system/lead prompt from every
294
294
  // continuation turn. Only an empty instructions string is omitted.
295
295
  // Full frames pass the body unchanged and keep every key in place.
296
- // omitTransportFields is used by wire-parity helpers to drop stream/background.
297
296
  export function _buildResponseCreateFrame(
298
297
  body,
299
- { previousResponseId = null, inputOverride, omitTransportFields = false } = {}
298
+ { previousResponseId = null, inputOverride } = {}
300
299
  ) {
301
300
  const src = body && typeof body === 'object' ? body : {};
302
301
  if (previousResponseId == null && inputOverride === undefined) {
303
- if (!omitTransportFields) return { type: 'response.create', ...src };
304
302
  const frame = { type: 'response.create' };
305
303
  for (const key of Object.keys(src)) {
306
304
  if (TRANSPORT_ONLY_FRAME_FIELDS.has(key)) continue;
@@ -310,7 +308,7 @@ export function _buildResponseCreateFrame(
310
308
  }
311
309
  const frame = { type: 'response.create' };
312
310
  for (const key of Object.keys(src)) {
313
- if (omitTransportFields && TRANSPORT_ONLY_FRAME_FIELDS.has(key)) continue;
311
+ if (TRANSPORT_ONLY_FRAME_FIELDS.has(key)) continue;
314
312
  if (key === 'instructions') {
315
313
  const instr = src.instructions;
316
314
  if (typeof instr === 'string' && instr.length) frame.instructions = instr;
@@ -366,17 +364,10 @@ export function _computeDelta({ entry, body, traceProvider }) {
366
364
  if (!entry?.lastRequestSansInput || !entry.lastResponseId) {
367
365
  return { mode: 'full', reason: 'no_anchor', frame: buildFrame(body) };
368
366
  }
369
- // Public OpenAI resolves previous_response_id out of its response STORE, so
370
- // an anchor only exists when the anchored response was stored. store:false
371
- // there — e.g. an explicit MIXDOG_OAI_STORE=0 opt-out on the openai-direct
372
- // provider — makes a continuation frame fail with
373
- // previous_response_not_found, so the opt-out degrades to full frames.
374
- // openai-oauth/Codex (per-WS-session server state) and xAI (in-connection
375
- // ZDR continuation with encrypted reasoning) both anchor without the store
376
- // and are deliberately excluded from this gate.
377
- if (traceProvider === 'openai-direct' && body?.store !== true) {
378
- return { mode: 'full', reason: 'store_disabled', frame: buildFrame(body) };
379
- }
367
+ // WebSocket mode keeps the latest response in a connection-local cache, so
368
+ // previous_response_id continues on the same socket even with store:false.
369
+ // If the server no longer has the anchor (previous_response_not_found), the
370
+ // caller recovers with a full-context frame.
380
371
  if (!deltaForce && !deltaRefs && !entry.turnState) {
381
372
  return { mode: 'full', reason: 'delta_missing_turn_state', frame: buildFrame(body) };
382
373
  }
@@ -0,0 +1,60 @@
1
+ // Refusal content of one Responses stream. The model's refusal arrives as
2
+ // `response.refusal.delta` / `response.refusal.done` and as a
3
+ // `{type:'refusal', refusal}` content part of the message item
4
+ // (output_item.done and the terminal output bundle). Parts are keyed by item
5
+ // id + content index so the streamed, item-done and terminal copies of one
6
+ // part fold into one text; a full (done / final-part) text replaces the
7
+ // accumulated deltas. Shared by the WS and HTTP/SSE collectors.
8
+ export function createRefusals() {
9
+ const parts = new Map();
10
+ const keyOf = (itemId, contentIndex) => `${itemId || ''}:${Number.isInteger(contentIndex) ? contentIndex : 0}`;
11
+
12
+ return {
13
+ /** response.refusal.delta */
14
+ delta(event) {
15
+ if (typeof event?.delta !== 'string') return;
16
+ const key = keyOf(event.item_id, event.content_index);
17
+ parts.set(key, (parts.get(key) || '') + event.delta);
18
+ },
19
+ /** response.refusal.done */
20
+ done(event) {
21
+ if (typeof event?.refusal !== 'string') return;
22
+ parts.set(keyOf(event.item_id, event.content_index), event.refusal);
23
+ },
24
+ /** A message item's refusal parts. Returns whether it carried any. */
25
+ absorbMessage(item) {
26
+ if (item?.type !== 'message' || !Array.isArray(item.content)) return false;
27
+ let found = false;
28
+ item.content.forEach((part, index) => {
29
+ if (part?.type !== 'refusal' || typeof part.refusal !== 'string') return;
30
+ found = true;
31
+ // An id-less item cannot be matched to its streamed copy; the
32
+ // streamed text already stands for it.
33
+ if (!item.id && parts.size > 0) return;
34
+ parts.set(keyOf(item.id, index), part.refusal);
35
+ });
36
+ return found;
37
+ },
38
+ get seen() {
39
+ return parts.size > 0;
40
+ },
41
+ get text() {
42
+ return [...parts.values()].filter(Boolean).join('\n');
43
+ },
44
+ };
45
+ }
46
+
47
+ /** The typed stop reason of a refused turn (read by the agent loop). */
48
+ export const REFUSAL_STOP_REASON = 'refusal';
49
+
50
+ /** Result fields for a refused turn — the shared result shape:
51
+ * stopReason: REFUSAL_STOP_REASON
52
+ * refusal: the refusal text (joined parts; may be '')
53
+ * content: the output_text, or the refusal text when there was none
54
+ * so a refusal never reads as an empty successful answer. Empty object when
55
+ * the response carried no refusal. */
56
+ export function refusalResultFields(refusals, content) {
57
+ if (!refusals.seen) return {};
58
+ const refusal = refusals.text;
59
+ return { content: content || refusal, refusal, stopReason: REFUSAL_STOP_REASON };
60
+ }
@@ -1,7 +1,12 @@
1
1
  import { makeInvalidToolArgsMarker } from '../lib/openai-tool-args.mjs';
2
2
  import { synthLeakedOpenAICall } from '../openai-compat-stream-common.mjs';
3
3
  import { createToolCallDedupe, dedupeToolCallList } from '../lib/leaked-toolcall.mjs';
4
- import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from '../custom-tool-wire.mjs';
4
+ import {
5
+ customToolCallFromResponseItem,
6
+ nativeToolSearchCallFromArguments,
7
+ qualifiedToolCallName,
8
+ withToolCallNamespace,
9
+ } from '../custom-tool-wire.mjs';
5
10
  import { createActiveToolItemTracker } from '../tool-stream-state.mjs';
6
11
 
7
12
  // tool_search_call.arguments parse. Module-scope (exported) for direct test
@@ -64,7 +69,7 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
64
69
  } catch {}
65
70
  }
66
71
  function emit(call) {
67
- if (!toolDedupe.shouldDispatch(call?.name, call?.arguments, call?.id)) return;
72
+ if (!toolDedupe.shouldDispatch(qualifiedToolCallName(call), call?.arguments, call?.id)) return;
68
73
  fire(call);
69
74
  }
70
75
  function settle() {
@@ -84,6 +89,8 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
84
89
  }
85
90
  function pushToolSearchCall(item) {
86
91
  if (item?.type !== 'tool_search_call') return;
92
+ // Server-executed search already ran inside the response; replay-only.
93
+ if (item.execution === 'server') return;
87
94
  const callId = item.call_id || item.id || '';
88
95
  if (!callId || toolCalls.some((call) => call.id === callId)) return;
89
96
  const call = nativeToolSearchCallFromArguments(callId, parseToolSearchArgs(item.arguments));
@@ -106,7 +113,10 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
106
113
  const type = item?.type;
107
114
  if (type === 'function_call') {
108
115
  markStarted(item);
109
- pendingCalls.set(item.id || '', { name: item.name || '', callId: item.call_id || '' });
116
+ pendingCalls.set(
117
+ item.id || '',
118
+ withToolCallNamespace({ name: item.name || '', callId: item.call_id || '' }, item)
119
+ );
110
120
  } else if (type === 'custom_tool_call' || type === 'tool_search_call') {
111
121
  // tool_search is marked in-flight at item-added time too, so the
112
122
  // semantic-idle stall gate's pendingToolUse never drops a mid-flight
@@ -134,7 +144,7 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
134
144
  argumentsText: event.arguments || JSON.stringify(args),
135
145
  });
136
146
  if (pending?.callId && pending?.name) {
137
- const call = { id: pending.callId, name: pending.name, arguments: args };
147
+ const call = withToolCallNamespace({ id: pending.callId, name: pending.name, arguments: args }, pending);
138
148
  toolCalls.push(call);
139
149
  emit(call);
140
150
  pendingCalls.delete(itemId);
@@ -150,31 +160,45 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
150
160
  // bundle. If salvage also fails the stream fails explicitly — masking the
151
161
  // gap with a synthetic id just shifts the failure one turn later under a
152
162
  // confusing "No tool output found for function call" error.
153
- toolCalls.push({
154
- id: pending?.callId || '',
155
- name: pending?.name || '',
156
- arguments: args,
157
- _pendingItemId: itemId,
158
- _deferred: true,
159
- });
163
+ toolCalls.push(
164
+ withToolCallNamespace(
165
+ {
166
+ id: pending?.callId || '',
167
+ name: pending?.name || '',
168
+ arguments: args,
169
+ _pendingItemId: itemId,
170
+ _deferred: true,
171
+ },
172
+ pending
173
+ )
174
+ );
160
175
  }
161
176
 
162
- /** response.output_item.done for a function_call item */
177
+ /** A complete function_call item (output_item.done, or the terminal
178
+ * response output bundle) through the one deduplicated collector: it
179
+ * resolves the deferred placeholder for its item (canonical call_id/name
180
+ * from the item, missing ones kept from the placeholder), is skipped when
181
+ * its call_id is already recorded, and is otherwise created and
182
+ * dispatched — so a call present only in the terminal bundle still runs. */
163
183
  function completeFunctionCallItem(item) {
164
184
  const itemId = item.id || '';
165
185
  const callId = item.call_id || '';
166
186
  const name = item.name || '';
167
187
  const args = parseFunctionCallArgs(argsTextOf(item.arguments));
168
188
  const deferred = toolCalls.find((tc) => tc?._deferred && (!itemId || tc._pendingItemId === itemId));
169
- if (deferred && callId && name) {
170
- deferred.id = callId;
171
- deferred.name = name;
172
- deferred.arguments = deferred.arguments && Object.keys(deferred.arguments).length > 0 ? deferred.arguments : args;
173
- delete deferred._deferred;
174
- delete deferred._pendingItemId;
175
- emit(deferred);
189
+ if (deferred) {
190
+ deferred.id = callId || deferred.id;
191
+ deferred.name = name || deferred.name;
192
+ withToolCallNamespace(deferred, item);
193
+ if (deferred.id && deferred.name) {
194
+ deferred.arguments =
195
+ deferred.arguments && Object.keys(deferred.arguments).length > 0 ? deferred.arguments : args;
196
+ delete deferred._deferred;
197
+ delete deferred._pendingItemId;
198
+ emit(deferred);
199
+ }
176
200
  } else if (callId && name && !toolCalls.some((tc) => tc?.id === callId)) {
177
- const call = { id: callId, name, arguments: args };
201
+ const call = withToolCallNamespace({ id: callId, name, arguments: args }, item);
178
202
  toolCalls.push(call);
179
203
  emit(call);
180
204
  }
@@ -193,20 +217,6 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
193
217
  settle();
194
218
  }
195
219
 
196
- /** response.completed salvage: when arguments.done fired before (or
197
- * without) a matching output_item.added, the deferred placeholder has an
198
- * empty id/name; the bundle carries the canonical call_id/name. */
199
- function salvageFunctionCall(item) {
200
- const tc = toolCalls.find((t) => t._deferred && t._pendingItemId === (item.id || ''));
201
- if (!tc) return;
202
- if (!tc.id && item.call_id) tc.id = item.call_id;
203
- if (!tc.name && item.name) tc.name = item.name;
204
- if (tc.id && tc.name) {
205
- delete tc._deferred;
206
- delete tc._pendingItemId;
207
- emit(tc);
208
- }
209
- }
210
220
 
211
221
  return {
212
222
  get calls() {
@@ -238,6 +248,12 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
238
248
  completeFunctionCallItem,
239
249
  completeToolSearchItem,
240
250
  completeCustomToolItem,
241
- salvageFunctionCall,
251
+ /** A server-truncated call item: kept in flight, never collected. */
252
+ holdIncompleteItem: markStarted,
253
+ // Terminal-bundle salvage (response.completed / success response.done):
254
+ // the same collector as output_item.done. When arguments.done fired
255
+ // before (or without) output_item.added, the deferred placeholder has an
256
+ // empty id/name and the bundle carries the canonical call_id/name.
257
+ salvageFunctionCall: completeFunctionCallItem,
242
258
  };
243
259
  }
@@ -13,6 +13,8 @@ import { createReplayItems } from './openai-ws-response-state/replay-items.mjs';
13
13
  import { createCitations } from './openai-ws-response-state/citations.mjs';
14
14
  import { createWsToolCalls } from './openai-ws-response-state/tool-calls.mjs';
15
15
  import { normalizeWsUsage } from './openai-ws-response-state/usage.mjs';
16
+ import { createRefusals, refusalResultFields } from './openai-ws-response-state/refusals.mjs';
17
+ import { isIncompleteToolItem } from './lib/responses-terminal-fields.mjs';
16
18
 
17
19
  export { parseToolSearchArgs } from './openai-ws-response-state/tool-calls.mjs';
18
20
 
@@ -37,6 +39,7 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
37
39
  const reasoningDeltas = { text: 0, summary: 0, other: 0 };
38
40
  const replayItems = createReplayItems();
39
41
  const citations = createCitations();
42
+ const refusals = createRefusals();
40
43
  const tools = createWsToolCalls({ onToolCall, midState, replayItems });
41
44
  const replayProvider = traceProvider === 'xai' ? 'xai-responses' : 'openai-responses';
42
45
  const progress = (kind) => {
@@ -49,6 +52,11 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
49
52
  // anything the per-item events never carried. Returns whether any progress
50
53
  // was reported.
51
54
  function salvageCompletedItem(item, relayFinalText) {
55
+ if (isIncompleteToolItem(item)) {
56
+ tools.holdIncompleteItem(item);
57
+ progress('tool');
58
+ return true;
59
+ }
52
60
  replayItems.push(item);
53
61
  let reported = false;
54
62
  if (item.type === 'message') {
@@ -64,6 +72,10 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
64
72
  }
65
73
  citations.pushOutputTextAnnotations(c);
66
74
  }
75
+ if (refusals.absorbMessage(item)) {
76
+ progress('semantic');
77
+ reported = true;
78
+ }
67
79
  }
68
80
  if (item.type === 'web_search_call') {
69
81
  citations.pushWebSearchCall(item);
@@ -146,10 +158,19 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
146
158
  noteToolInputDelta: tools.noteToolInputDelta,
147
159
  /** response.function_call_arguments.done */
148
160
  completeFunctionCallArguments: tools.completeFunctionCallArguments,
161
+ /** response.refusal.delta */
162
+ noteRefusalDelta: refusals.delta,
163
+ /** response.refusal.done */
164
+ noteRefusalDone: refusals.done,
149
165
  /** response.output_item.done. Returns the progress kind to report. */
150
166
  completeOutputItem(item) {
167
+ if (isIncompleteToolItem(item)) {
168
+ tools.holdIncompleteItem(item);
169
+ return 'tool';
170
+ }
151
171
  replayItems.push(item);
152
172
  const type = item?.type || '';
173
+ if (type === 'message') refusals.absorbMessage(item);
153
174
  // function_call / output_text already arrive via their dedicated
154
175
  // streaming events; `reasoning` carries encrypted_content that keeps the
155
176
  // openai-oauth server-side prompt cache prefix warm.
@@ -189,6 +210,13 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
189
210
  if (!responseId && response?.id) responseId = response.id;
190
211
  return usage;
191
212
  },
213
+ /** A cutoff frame's output bundle: call items the server truncated stay
214
+ * in flight so the cutoff reads as a pending-tool turn. */
215
+ holdIncompleteBundleItems(response) {
216
+ for (const item of response?.output || []) {
217
+ if (isIncompleteToolItem(item)) tools.holdIncompleteItem(item);
218
+ }
219
+ },
192
220
  /** max_output_tokens maps cleanly to Anthropic's stop_reason=max_tokens. */
193
221
  markMaxOutputIncomplete(reason) {
194
222
  incompleteReason = reason;
@@ -227,6 +255,8 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
227
255
  ...(typeof endTurn === 'boolean' ? { endTurn } : {}),
228
256
  responseId: responseId || undefined,
229
257
  serviceTier: responseServiceTier || undefined,
258
+ // A refused turn: typed stop reason and the refusal text.
259
+ ...refusalResultFields(refusals, content),
230
260
  };
231
261
  },
232
262
  };
@@ -88,6 +88,18 @@ export function createWsEventSwitch({ response, textRelay, watchdogs, midState,
88
88
  progress('tool');
89
89
  watchdogs.bumpSemantic();
90
90
  break;
91
+ // Refusal text is model output but never visible answer text: it is
92
+ // collected for the typed refusal result, not relayed live.
93
+ case 'response.refusal.delta':
94
+ response.noteRefusalDelta(event);
95
+ progress('semantic');
96
+ watchdogs.bumpSemantic();
97
+ break;
98
+ case 'response.refusal.done':
99
+ response.noteRefusalDone(event);
100
+ progress('semantic');
101
+ watchdogs.bumpSemantic();
102
+ break;
91
103
  case 'response.output_item.done': {
92
104
  const kind = response.completeOutputItem(event.item);
93
105
  // Item-done is genuine lifecycle progress — reset semantic idle so
@@ -27,11 +27,30 @@ export function createTerminalFrameHandlers({ response, textRelay, midState, err
27
27
 
28
28
  // Most incomplete reasons are real failures. max_output_tokens maps cleanly
29
29
  // to Anthropic's stop_reason=max_tokens; treating it as an error makes
30
- // Claude retry the same over-budget turn.
30
+ // Claude retry the same over-budget turn — unless a tool call's input was
31
+ // still streaming: its arguments were truncated, so the cutoff is a
32
+ // stalled pending-tool turn (same guard as HTTP/SSE), never a clean length
33
+ // completion that would surface the partial call as successful.
31
34
  function settleIncomplete(event, label, options) {
32
35
  const usage = response.noteTerminal(event.response);
33
36
  const reasonStr = _incompleteReasonFromEvent(event);
34
37
  if (_isMaxOutputIncompleteReason(reasonStr)) {
38
+ response.holdIncompleteBundleItems(event.response);
39
+ if (response.pendingToolUse) {
40
+ const error = new Error(`${label} (max_output_tokens) with tool call in flight`);
41
+ try {
42
+ textRelay.flush();
43
+ } catch {
44
+ /* best-effort */
45
+ }
46
+ Object.assign(error, response.partialState());
47
+ error.streamStalled = true;
48
+ error.pendingToolUse = true;
49
+ error.incompleteReason = reasonStr;
50
+ if (usage) error.partialUsage = usage;
51
+ failWith(error, options);
52
+ return;
53
+ }
35
54
  response.markMaxOutputIncomplete(reasonStr);
36
55
  completeTurn();
37
56
  return;
@@ -105,11 +124,11 @@ export function createTerminalFrameHandlers({ response, textRelay, midState, err
105
124
  failWith(responseDoneStatusError(status, `${errLabel} response.done unexpected status`), { markDone: true });
106
125
  return;
107
126
  }
108
- // Success-shaped response.done (status '' or 'completed') carries the
109
- // same optional end_turn, and the response's usage.
110
- response.noteTerminal(event.response);
111
- response.setEndTurn(_endTurnFromEvent(event));
112
- completeTurn();
127
+ // Success-shaped response.done (status '' or 'completed') is the same
128
+ // terminal as response.completed: usage, end_turn, and its output bundle
129
+ // reconciled through the same deduplicated collectors (calls that appear
130
+ // only in the bundle are created; unresolvable deferred calls fail).
131
+ onResponseCompleted(event);
113
132
  }
114
133
 
115
134
  function onResponseIncomplete(event) {
@@ -111,6 +111,10 @@ export class OpenAIDirectProvider {
111
111
  }
112
112
  return null;
113
113
  }
114
+ /** Drop a disposed transport scope's sticky transport record. */
115
+ releaseTransportScope(scope) {
116
+ this._httpFallbackPoolKeys.delete(scope);
117
+ }
114
118
  send(messages, model, tools, sendOpts) {
115
119
  return withEffortConfigurationFallback('openai', model, sendOpts || {}, (opts) =>
116
120
  this._sendOnce(messages, model, tools, opts)
@@ -139,8 +143,9 @@ export class OpenAIDirectProvider {
139
143
  // poolKey MUST be sessionId-only. Falling back to promptCacheKey would
140
144
  // let unrelated raw sessions sharing the same provider-scoped cache
141
145
  // bucket reuse each other's pooled socket and inherit lastResponseId
142
- // delta state, producing cross-session prompt corruption.
143
- const poolKey = opts.sessionId || null;
146
+ // delta state, producing cross-session prompt corruption. A forked
147
+ // request runs in its own transport scope (transport-scope.mjs).
148
+ const poolKey = opts.transportScope || opts.sessionId || null;
144
149
  // cacheKey (prompt_cache_key) only groups the server-side prefix-cache
145
150
  // shard — safe to share across sessions, unlike the sessionId poolKey
146
151
  // above. buildRequestBody derives it from the base namespace plus a
@@ -228,7 +233,10 @@ export class OpenAIDirectProvider {
228
233
  // ws-delta only affects the delta gate inside openai-ws-delta.mjs.
229
234
  if (
230
235
  transportPolicy.transport === 'http' ||
231
- (poolKey && httpFallbackEnabled && this._httpFallbackPoolKeys.has(poolKey))
236
+ (poolKey &&
237
+ httpFallbackEnabled &&
238
+ // A forked scope follows its session's refusal; it records its own.
239
+ (this._httpFallbackPoolKeys.has(poolKey) || this._httpFallbackPoolKeys.has(opts.sessionId)))
232
240
  ) {
233
241
  return await sendHttpWithKeyReload(auth);
234
242
  }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * OpenCode Go's Gemini route: `@ai-sdk/google` models are served by the
3
+ * gateway's generateContent endpoint, `{base}/models/{id}:streamGenerateContent`
4
+ * (https://opencode.ai/docs/go/ — Endpoints table). This engine reuses the
5
+ * direct Gemini adapter's request builder, stream consumer, retry ladder and
6
+ * result shaping, and only moves the transport onto the gateway: the Go key
7
+ * (never GEMINI_API_KEY) goes to the Go origin only, as a bearer token and the
8
+ * `x-goog-api-key` header, with the session / User-Agent headers of every Go
9
+ * request. Gateway models have no explicit cachedContents.
10
+ */
11
+ import { GeminiProvider, geminiRestError } from './gemini.mjs';
12
+ import { GEMINI_FIRST_BYTE_TIMEOUT_MS, consumeGeminiRestStreamResponse } from './gemini-stream.mjs';
13
+ import { geminiBareModelId } from './gemini-cache-policy.mjs';
14
+ import { geminiFailureUsage } from './gemini-response.mjs';
15
+ import { geminiEndsWithFunctionResponse, runGeminiStreamAttempts } from './gemini-retry-policy.mjs';
16
+ import { geminiTextLeakGuardFor } from './gemini-sdk-request.mjs';
17
+ import { emitProviderRetryStage } from './retry-classifier.mjs';
18
+ import { originBoundFetch } from './lib/origin-bound-fetch.mjs';
19
+ import { createPassthroughSignal, createTimeoutSignal } from '../stall-policy.mjs';
20
+ import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
21
+ import { reloadProviderApiKey, resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
22
+
23
+ const PROVIDER = 'opencode-go';
24
+
25
+ /** The generateContent request body for a built Gemini request. */
26
+ export function openCodeGoGeminiBody({ contents, systemInstruction, geminiTools, toolConfig, generationConfig, safetySettings }) {
27
+ return {
28
+ contents,
29
+ ...(systemInstruction ? { systemInstruction: { parts: [{ text: systemInstruction }] } } : {}),
30
+ ...(geminiTools ? { tools: geminiTools } : {}),
31
+ ...(toolConfig ? { toolConfig } : {}),
32
+ ...(generationConfig ? { generationConfig } : {}),
33
+ ...(safetySettings ? { safetySettings } : {}),
34
+ };
35
+ }
36
+
37
+ export class OpenCodeGoGeminiEngine extends GeminiProvider {
38
+ name = PROVIDER;
39
+
40
+ /** @param {object} config the Go provider config; `baseURL` is the OpenAI-style `.../v1` base */
41
+ constructor(config) {
42
+ const base = String(config.baseURL || '').replace(/\/+$/, '');
43
+ super({
44
+ ...config,
45
+ fetchFn: originBoundFetch(new URL(base).origin, config.fetchImpl, PROVIDER),
46
+ // No Google host to warm and no Google SDK client: this engine never uses either.
47
+ preconnectFn: () => {},
48
+ createGenAI: () => null,
49
+ });
50
+ this.gatewayBase = base;
51
+ }
52
+
53
+ _getApiKey() {
54
+ return resolveProviderApiKey(PROVIDER, this.config);
55
+ }
56
+
57
+ reloadApiKey() {
58
+ const key = reloadProviderApiKey(PROVIDER, this.config);
59
+ if (key) this.config = { ...(this.config || {}), apiKey: key };
60
+ return key || '';
61
+ }
62
+
63
+ async isAvailable() {
64
+ return Boolean(this._getApiKey());
65
+ }
66
+
67
+ // The gateway has no cachedContents resource.
68
+ async _ensureGeminiCache() {
69
+ return null;
70
+ }
71
+
72
+ _headers(opts) {
73
+ const key = this._getApiKey();
74
+ return {
75
+ 'Content-Type': 'application/json',
76
+ ...(key ? { Authorization: `Bearer ${key}`, 'x-goog-api-key': key } : {}),
77
+ ...(this.config?.extraHeaders || {}),
78
+ ...(opts?.requestHeaders || {}),
79
+ };
80
+ }
81
+
82
+ _url(model, method) {
83
+ return `${this.gatewayBase}/models/${encodeURIComponent(geminiBareModelId(model))}:${method}`;
84
+ }
85
+
86
+ async _openGatewayStream(url, body, opts, attemptSignal) {
87
+ const openFirstByte = createTimeoutSignal(attemptSignal, GEMINI_FIRST_BYTE_TIMEOUT_MS, 'OpenCode Go Gemini first byte');
88
+ let res;
89
+ try {
90
+ res = await this._fetch(url, {
91
+ method: 'POST',
92
+ headers: this._headers(opts),
93
+ body: JSON.stringify(body),
94
+ signal: openFirstByte.signal,
95
+ dispatcher: getLlmDispatcher(),
96
+ });
97
+ } finally {
98
+ openFirstByte.cleanup();
99
+ }
100
+ if (!res.ok) {
101
+ throw geminiRestError(res, await res.text().catch(() => ''), 'OpenCode Go Gemini streamGenerateContent');
102
+ }
103
+ return res;
104
+ }
105
+
106
+ async _generateContent(model, body, opts, signal) {
107
+ const res = await this._fetch(this._url(model, 'generateContent'), {
108
+ method: 'POST',
109
+ headers: this._headers(opts),
110
+ body: JSON.stringify(body),
111
+ signal,
112
+ dispatcher: getLlmDispatcher(),
113
+ });
114
+ if (!res.ok) {
115
+ throw geminiRestError(res, await res.text().catch(() => ''), 'OpenCode Go Gemini generateContent');
116
+ }
117
+ return await res.json();
118
+ }
119
+
120
+ async _streamViaSdk(stream) {
121
+ const { opts, signal, useModel, contents, callbacks } = stream;
122
+ const body = openCodeGoGeminiBody(stream);
123
+ const url = `${this._url(useModel, 'streamGenerateContent')}?alt=sse`;
124
+ const passthrough = createPassthroughSignal(signal);
125
+ try {
126
+ return await runGeminiStreamAttempts({
127
+ signal: passthrough.signal,
128
+ sleepFn: this.config?.sleepFn,
129
+ onRetry: ({ attempt, maxAttempts, lastErr, delayMs }) => {
130
+ emitProviderRetryStage(opts.onStageChange, { attempt: attempt + 1, maxAttempts, lastErr, delayMs });
131
+ process.stderr.write(
132
+ `[opencode-go:gemini] retry attempt ${attempt + 1} after ${lastErr?.message || lastErr?.code || 'transient error'}\n`
133
+ );
134
+ },
135
+ afterToolResult: geminiEndsWithFunctionResponse(contents),
136
+ run: async ({ signal: attemptSignal, connected }) => {
137
+ try {
138
+ opts.onStageChange?.('requesting');
139
+ } catch {
140
+ /* heartbeat best-effort */
141
+ }
142
+ const res = await this._openGatewayStream(url, body, opts, attemptSignal);
143
+ connected();
144
+ const textLeakGuard = geminiTextLeakGuardFor(stream);
145
+ const response = await consumeGeminiRestStreamResponse(res, {
146
+ signal: attemptSignal,
147
+ onStreamDelta: callbacks.onStreamDelta,
148
+ onTextDelta: callbacks.onTextDelta,
149
+ textLeakGuard,
150
+ label: 'OpenCode Go Gemini streamGenerateContent',
151
+ failureUsage: geminiFailureUsage(opts, null, useModel),
152
+ });
153
+ return { response, textLeakGuard };
154
+ },
155
+ });
156
+ } catch (err) {
157
+ const recovered = await this._recoverGeminiNonStreaming({
158
+ streamErr: err,
159
+ signal: passthrough.signal,
160
+ opts,
161
+ model: useModel,
162
+ generate: (fallbackSignal) => this._generateContent(useModel, body, opts, fallbackSignal),
163
+ });
164
+ if (!recovered) throw err;
165
+ return { response: recovered, textLeakGuard: null };
166
+ } finally {
167
+ passthrough.cleanup();
168
+ }
169
+ }
170
+ }