mixdog 1.3.0 → 1.3.2

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 (423) hide show
  1. package/NOTICE.md +52 -9
  2. package/README.md +8 -4
  3. package/package.json +2 -2
  4. package/scripts/native-release-status.mjs +238 -0
  5. package/src/defaults/shipped-history.json +8 -1
  6. package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
  7. package/src/defaults/skills/setup/SKILL.md +23 -1
  8. package/src/defaults/skills/setup/references/actions.md +54 -4
  9. package/src/defaults/skills/setup/references/surfaces.md +23 -3
  10. package/src/defaults/skills/setup-guide/SKILL.md +17 -10
  11. package/src/defaults/skills/visualize/SKILL.md +9 -6
  12. package/src/defaults/skills/visualize/references/craft.md +8 -1
  13. package/src/help.mjs +1 -1
  14. package/src/lib/keychain-cjs.cjs +4 -1
  15. package/src/lib/rules-builder.cjs +14 -7
  16. package/src/output-styles/common.md +13 -8
  17. package/src/rules/agent-mode/AGENT_MODE.md +9 -6
  18. package/src/rules/agent-mode/MIXY.md +11 -6
  19. package/src/rules/lead/LEAD.md +2 -2
  20. package/src/rules/shared/10-tool-workflow.md +4 -0
  21. package/src/rules/shared/20-research.md +2 -0
  22. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
  23. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
  24. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
  25. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
  26. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
  27. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
  28. package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
  29. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  31. package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
  32. package/src/runtime/agent/orchestrator/config.mjs +11 -0
  33. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +81 -16
  34. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -4
  35. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
  36. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  37. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +80 -31
  38. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  40. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -38
  41. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
  43. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
  44. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +34 -16
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
  46. package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
  47. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
  48. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
  49. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -1
  50. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
  51. package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
  52. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
  53. package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
  54. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
  55. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
  56. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
  57. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
  58. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
  59. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +10 -2
  60. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
  61. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
  62. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
  64. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
  65. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
  66. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
  67. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
  68. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
  69. package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
  70. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
  71. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
  72. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
  73. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +5 -5
  74. package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
  75. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
  76. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +12 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +17 -6
  78. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +41 -10
  79. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +6 -4
  80. package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
  81. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
  83. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
  84. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
  85. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +21 -2
  86. package/src/runtime/agent/orchestrator/session/agent-room.mjs +149 -45
  87. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
  88. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  89. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +14 -11
  90. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
  91. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
  92. package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
  93. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
  94. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
  95. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +5 -1
  96. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -1
  97. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
  99. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +230 -0
  100. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +156 -25
  101. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
  102. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -9
  103. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
  104. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
  105. package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
  106. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
  107. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +189 -105
  108. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
  109. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
  110. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +111 -9
  111. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -14
  112. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
  113. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
  114. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -0
  115. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
  116. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
  117. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
  118. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +46 -4
  119. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
  120. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
  121. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
  122. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  123. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  124. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
  125. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
  126. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
  127. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
  128. package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
  129. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
  130. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
  131. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
  132. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
  133. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
  134. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +62 -47
  135. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +6 -8
  136. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
  137. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
  138. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
  139. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
  140. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +1 -1
  141. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
  142. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +5 -2
  143. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
  144. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
  145. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +35 -4
  146. package/src/runtime/agent/orchestrator/session/routine-result.mjs +179 -16
  147. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
  148. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
  149. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
  150. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
  151. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
  152. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
  153. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +8 -3
  154. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
  155. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -1
  156. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
  157. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
  158. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
  159. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
  160. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
  161. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +49 -14
  162. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +134 -17
  163. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
  164. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
  165. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -3
  166. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
  167. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
  168. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
  169. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
  170. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -14
  171. package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
  172. package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
  173. package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
  174. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
  175. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
  176. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +34 -21
  177. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
  178. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
  179. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
  180. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
  181. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
  182. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
  183. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
  184. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
  185. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
  186. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
  187. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
  188. package/src/runtime/attachments/attachment-reference.mjs +155 -0
  189. package/src/runtime/attachments/limits.mjs +5 -1
  190. package/src/runtime/attachments/office-extract.mjs +3 -6
  191. package/src/runtime/attachments/pdf-extract.mjs +84 -10
  192. package/src/runtime/attachments/store.mjs +55 -30
  193. package/src/runtime/browser-bridge/client.mjs +73 -20
  194. package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
  195. package/src/runtime/channels/lib/scheduler.mjs +14 -7
  196. package/src/runtime/channels/lib/state-file.mjs +15 -15
  197. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
  198. package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
  199. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
  200. package/src/runtime/channels/lib/worker-main.mjs +3 -2
  201. package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
  202. package/src/runtime/effort-judge/judge-client.mjs +6 -3
  203. package/src/runtime/effort-judge/model-install.mjs +16 -8
  204. package/src/runtime/effort-judge/model-manifest.json +7 -7
  205. package/src/runtime/local-provider/asset-installer.mjs +10 -4
  206. package/src/runtime/local-provider/catalog.mjs +5 -2
  207. package/src/runtime/local-provider/registered-models.mjs +64 -27
  208. package/src/runtime/local-provider/server.mjs +2 -3
  209. package/src/runtime/media/adapters/image-api.mjs +89 -0
  210. package/src/runtime/media/auth.mjs +64 -1
  211. package/src/runtime/media/catalog.mjs +66 -4
  212. package/src/runtime/media/jobs.mjs +4 -0
  213. package/src/runtime/media/lanes.mjs +46 -5
  214. package/src/runtime/media/media-usage.mjs +17 -0
  215. package/src/runtime/media/renditions.mjs +15 -15
  216. package/src/runtime/media/store.mjs +36 -35
  217. package/src/runtime/media/tool.mjs +8 -1
  218. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
  219. package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
  220. package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
  221. package/src/runtime/memory/lib/pg/process.mjs +8 -4
  222. package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
  223. package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
  224. package/src/runtime/office/core/journal.mjs +7 -14
  225. package/src/runtime/office/design/library/design-library-core.mjs +4 -16
  226. package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
  227. package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
  228. package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
  229. package/src/runtime/office/pdf/pdf-render.mjs +30 -18
  230. package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
  231. package/src/runtime/office/portable/portable-soffice.mjs +4 -0
  232. package/src/runtime/shared/agent-kind-migration.mjs +200 -0
  233. package/src/runtime/shared/agent-kind.mjs +152 -0
  234. package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
  235. package/src/runtime/shared/agent-message-envelope.mjs +44 -0
  236. package/src/runtime/shared/agent-reap-state.d.mts +4 -0
  237. package/src/runtime/shared/agent-route-config.d.mts +1 -0
  238. package/src/runtime/shared/agent-route-config.mjs +22 -8
  239. package/src/runtime/shared/agent-store.mjs +149 -0
  240. package/src/runtime/shared/agent-task-starts.mjs +27 -0
  241. package/src/runtime/shared/atomic-file.d.mts +50 -0
  242. package/src/runtime/shared/atomic-file.mjs +394 -132
  243. package/src/runtime/shared/background-tasks.mjs +7 -4
  244. package/src/runtime/shared/bot-hops.mjs +30 -0
  245. package/src/runtime/shared/bot-split-migration.mjs +457 -0
  246. package/src/runtime/shared/bounded-download.mjs +4 -2
  247. package/src/runtime/shared/config-patch.mjs +20 -1
  248. package/src/runtime/shared/config.mjs +39 -9
  249. package/src/runtime/shared/connector-catalog.d.mts +1 -2
  250. package/src/runtime/shared/connector-catalog.mjs +2 -4
  251. package/src/runtime/shared/connector-triggers.mjs +2 -0
  252. package/src/runtime/shared/defaults-separation.mjs +6 -2
  253. package/src/runtime/shared/delegated-approval-host.mjs +74 -0
  254. package/src/runtime/shared/err-text.mjs +7 -1
  255. package/src/runtime/shared/error-presentation.mjs +113 -10
  256. package/src/runtime/shared/file-has-data.mjs +28 -0
  257. package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
  258. package/src/runtime/shared/handoff-artifacts.mjs +61 -0
  259. package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
  260. package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
  261. package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
  262. package/src/runtime/shared/model-route-fallback.mjs +79 -7
  263. package/src/runtime/shared/pending-agent-work.mjs +54 -0
  264. package/src/runtime/shared/plain-preview.mjs +22 -17
  265. package/src/runtime/shared/process-lifecycle.mjs +8 -12
  266. package/src/runtime/shared/projects.mjs +50 -41
  267. package/src/runtime/shared/provider-accounts.mjs +17 -12
  268. package/src/runtime/shared/routine-trigger.d.mts +6 -1
  269. package/src/runtime/shared/routine-trigger.mjs +14 -6
  270. package/src/runtime/shared/run-child.d.mts +3 -0
  271. package/src/runtime/shared/run-child.mjs +24 -3
  272. package/src/runtime/shared/sensitive-path-rules.d.mts +15 -0
  273. package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
  274. package/src/runtime/shared/session-baseline-store.mjs +8 -2
  275. package/src/runtime/shared/singleton-owner.mjs +7 -6
  276. package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
  277. package/src/runtime/shared/staged-update.mjs +4 -2
  278. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
  279. package/src/runtime/shared/tool-execution-contract.mjs +6 -0
  280. package/src/runtime/shared/transcript-metadata.mjs +28 -3
  281. package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
  282. package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
  283. package/src/runtime/shared/turn-snapshot.mjs +44 -2
  284. package/src/runtime/shared/usage-readout-totals.mjs +15 -13
  285. package/src/runtime/shared/user-cwd.mjs +9 -4
  286. package/src/runtime/shared/user-data-guard.mjs +46 -44
  287. package/src/runtime/shared/utf8-cut.mjs +10 -0
  288. package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
  289. package/src/runtime/shared/worktrees/registry.mjs +26 -26
  290. package/src/runtime/tidy/core-install.mjs +26 -4
  291. package/src/runtime/tidy/install.mjs +91 -23
  292. package/src/runtime/web-search/lib/config.mjs +4 -16
  293. package/src/session-runtime/agent-home-delivery.mjs +859 -136
  294. package/src/session-runtime/agent-room-delivery.mjs +167 -19
  295. package/src/session-runtime/agent-task-sessions.mjs +831 -69
  296. package/src/session-runtime/agent-tool-routing.mjs +1 -0
  297. package/src/session-runtime/boot/apis.mjs +58 -24
  298. package/src/session-runtime/boot/config.mjs +1 -0
  299. package/src/session-runtime/boot/facade.mjs +11 -1
  300. package/src/session-runtime/boot/infrastructure.mjs +14 -2
  301. package/src/session-runtime/boot/providers.mjs +16 -6
  302. package/src/session-runtime/boot/shared.mjs +12 -6
  303. package/src/session-runtime/boot/tools.mjs +2 -2
  304. package/src/session-runtime/bot-status.mjs +432 -0
  305. package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
  306. package/src/session-runtime/config-lifecycle.mjs +78 -32
  307. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
  308. package/src/session-runtime/handoff-attachments.mjs +593 -0
  309. package/src/session-runtime/held-requests.mjs +36 -33
  310. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
  311. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
  312. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +45 -6
  313. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  314. package/src/session-runtime/lifecycle/teardown.mjs +11 -3
  315. package/src/session-runtime/mcp-glue/connect.mjs +100 -186
  316. package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
  317. package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
  318. package/src/session-runtime/media-api.mjs +5 -2
  319. package/src/session-runtime/model-route/route-persist.mjs +2 -2
  320. package/src/session-runtime/model-route/route-tuning.mjs +11 -2
  321. package/src/session-runtime/model-route/set-route.mjs +82 -2
  322. package/src/session-runtime/native-web-search.mjs +2 -2
  323. package/src/session-runtime/new-session-config.mjs +6 -1
  324. package/src/session-runtime/owned-automation-run.mjs +8 -1
  325. package/src/session-runtime/room-member-gate.mjs +16 -3
  326. package/src/session-runtime/route-resolution.mjs +21 -19
  327. package/src/session-runtime/route-state.mjs +1 -59
  328. package/src/session-runtime/routine-home-turn.mjs +5 -3
  329. package/src/session-runtime/runtime-bootstrap.mjs +5 -3
  330. package/src/session-runtime/runtime-paths.mjs +11 -5
  331. package/src/session-runtime/runtime-tunables.mjs +6 -0
  332. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
  333. package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
  334. package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
  335. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
  336. package/src/session-runtime/services/agent-tool/helpers.mjs +24 -5
  337. package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
  338. package/src/session-runtime/services/agent-tool/send-flow.mjs +36 -24
  339. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -0
  340. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
  341. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +12 -6
  342. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
  343. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  344. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
  345. package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
  346. package/src/session-runtime/services/agent-tool.mjs +6 -0
  347. package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
  348. package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
  349. package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
  350. package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
  351. package/src/session-runtime/services/plugin-admin.mjs +26 -26
  352. package/src/session-runtime/services/provider-admin.mjs +14 -4
  353. package/src/session-runtime/services/schedule-access.mjs +33 -4
  354. package/src/session-runtime/services/seeds.mjs +4 -3
  355. package/src/session-runtime/services/usage-dashboard.mjs +1 -1
  356. package/src/session-runtime/services/usage-stats-model.mjs +2 -1
  357. package/src/session-runtime/session-create/materialize.mjs +2 -3
  358. package/src/session-runtime/session-create/session-options.mjs +15 -2
  359. package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
  360. package/src/session-runtime/settings-compaction-api.mjs +86 -39
  361. package/src/session-runtime/setup-tool/executor.mjs +20 -3
  362. package/src/session-runtime/setup-tool/extended-actions.mjs +19 -7
  363. package/src/session-runtime/setup-tool/settings-contract.mjs +37 -1
  364. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
  365. package/src/session-runtime/skills-api.mjs +12 -5
  366. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +265 -0
  367. package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
  368. package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
  369. package/src/session-runtime/tool-policy/policy-stage.mjs +165 -0
  370. package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
  371. package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
  372. package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
  373. package/src/session-runtime/tool-policy-refresh.mjs +47 -358
  374. package/src/session-runtime/tool-surface.mjs +5 -3
  375. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +99 -81
  376. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  377. package/src/session-runtime/turn/turn-run.mjs +2 -1
  378. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
  379. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +578 -301
  380. package/src/session-runtime/workflow-agents-api/agent-route.mjs +113 -53
  381. package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
  382. package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
  383. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
  384. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
  385. package/src/session-runtime/workspace/workspace-state.mjs +7 -6
  386. package/src/standalone/daemon-agent-control.mjs +4 -1
  387. package/src/standalone/daemon-session-control.mjs +60 -11
  388. package/src/standalone/daemon.mjs +34 -4
  389. package/src/standalone/local-session-runtime.mjs +22 -14
  390. package/src/standalone/session-client.mjs +7 -2
  391. package/src/standalone/session-protocol.mjs +7 -0
  392. package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
  393. package/src/standalone/session-service/agent-tree.mjs +4 -3
  394. package/src/standalone/session-service/session-calls/session-turns.mjs +19 -0
  395. package/src/standalone/session-service.mjs +11 -0
  396. package/src/standalone/session-state-projection.mjs +19 -9
  397. package/src/standalone/session-tool-output.mjs +35 -9
  398. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
  399. package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
  400. package/src/tui/app/slash-commands.mjs +1 -1
  401. package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
  402. package/src/tui/dist/index.mjs +599 -342
  403. package/src/tui/prompt-history-store.mjs +16 -21
  404. package/src/tui/session/context-state.mjs +4 -0
  405. package/src/tui/session/notice-surface.mjs +3 -4
  406. package/src/tui/session/session-api/intake/abort.mjs +19 -1
  407. package/src/tui/session/session-api/media.mjs +2 -1
  408. package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
  409. package/src/tui/session/session-api/routes-write.mjs +203 -0
  410. package/src/tui/session/session-api/routes.mjs +23 -236
  411. package/src/tui/session/session-api/settings.mjs +14 -1
  412. package/src/tui/session/session-flow/drain.mjs +28 -3
  413. package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
  414. package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
  415. package/src/tui/session/session-flow/steering.mjs +8 -3
  416. package/src/tui/session/tool-approval.mjs +185 -20
  417. package/src/tui/session/transcript-intake.mjs +4 -0
  418. package/src/tui/session/turn-live-call.mjs +11 -3
  419. package/src/tui/session/turn.mjs +36 -17
  420. package/src/tui/transcript-tool-failures.mjs +8 -2
  421. package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
  422. package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
  423. package/src/rules/agent-mode/ROUTINE.md +0 -6
@@ -10,6 +10,7 @@
10
10
  * anthropic-turn-result.mjs); nothing here touches the socket.
11
11
  */
12
12
  import { prepareAnthropicImages } from './lib/anthropic-image-input.mjs';
13
+ import { anthropicPrefixFingerprint, recordAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
13
14
  import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
14
15
  import { applyAnthropicServerFallback } from './anthropic-server-fallback.mjs';
15
16
  import { fastModeAvailable } from './anthropic-fast-mode.mjs';
@@ -17,6 +18,7 @@ import { applyAnthropicEffortToBody, shouldIncludeEffortBeta } from './anthropic
17
18
  import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
18
19
  import {
19
20
  anthropicThinkingActive,
21
+ appendAnthropicTailReminder,
20
22
  applyAnthropicCacheMarkers,
21
23
  clampAnthropicThinkingBudget as clampThinkingBudgetTokens,
22
24
  resolveAnthropicCacheTtls as resolveCacheTtls,
@@ -24,6 +26,7 @@ import {
24
26
  sharedCachePrefixBoundary,
25
27
  toAnthropicToolChoice,
26
28
  } from './lib/anthropic-request-utils.mjs';
29
+ import { splitTailReminder } from './lib/tail-reminder-split.mjs';
27
30
  import {
28
31
  buildSystemBlocks,
29
32
  resolveMaxTokens,
@@ -50,7 +53,7 @@ import {
50
53
  export async function buildAnthropicApiRequest({
51
54
  name,
52
55
  config,
53
- messages,
56
+ messages: requestMessages,
54
57
  useModel,
55
58
  tools,
56
59
  opts,
@@ -67,6 +70,7 @@ export async function buildAnthropicApiRequest({
67
70
  // the global by-model-id capability index and the Claude-id ladders are
68
71
  // first-party knowledge and must not leak onto (or from) a custom endpoint.
69
72
  const isCustom = isCustomProviderName(name);
73
+ const { messages, reminder } = splitTailReminder(requestMessages);
70
74
  const maxTokens = resolveMaxTokens(capabilityModel, { modelMaxOutputTokens });
71
75
  const effortOptions = { ...config, ...opts, disableBetaHeaders: config?.disableBetaHeaders };
72
76
  const gatewayEffort = typeof config?.messagesEffort === 'function' ? config.messagesEffort(opts) : null;
@@ -108,7 +112,9 @@ export async function buildAnthropicApiRequest({
108
112
  model: useModel,
109
113
  max_tokens: maxTokens,
110
114
  system: systemBlocks.length ? systemBlocks : undefined,
111
- messages: await prepareAnthropicImages(anthropicMessages, { signal: opts.signal }),
115
+ messages: await prepareAnthropicImages(appendAnthropicTailReminder(anthropicMessages, reminder), {
116
+ signal: opts.signal,
117
+ }),
112
118
  };
113
119
  // Server-side fallback and fast mode are decided from Claude model ids:
114
120
  // first-party knowledge, never applied to a custom endpoint.
@@ -135,6 +141,55 @@ export async function buildAnthropicApiRequest({
135
141
  .map((t) => (t && typeof t.name === 'string' ? t.name : null))
136
142
  .filter(Boolean)
137
143
  );
144
+ applyRequestReasoning(params, {
145
+ isCustom,
146
+ name,
147
+ config,
148
+ opts,
149
+ modelInfo,
150
+ capabilityModel,
151
+ maxTokens,
152
+ gatewayEffort,
153
+ effortProjection,
154
+ });
155
+ if (params.tools) resolveRequestToolChoice(params, opts, config);
156
+ // Fast mode → speed: "fast" on models Anthropic marks as speed-capable.
157
+ // Suppressed while the fast capacity pool is cooling down.
158
+ let fastLatched = fastModeLatched;
159
+ if (!isCustom && opts.fast === true && supportsAnthropicFastMode(useModel) && fastModeAvailable()) {
160
+ params.speed = 'fast';
161
+ fastLatched = true;
162
+ }
163
+ // NOTE: do NOT sanitize here. params.messages was already sanitized
164
+ // once inside toAnthropicMessages and then had cache markers applied.
165
+ // Re-sanitizing after marking could drop/reorder a marked block and
166
+ // move the provider-visible cache breakpoint off the cached one — the
167
+ // exact COLD-turn bug this change fixes. Order: build → sanitize
168
+ // (once) → mark → prepare image bytes → send.
169
+ params.stream = true;
170
+ // Diagnostic: per-block prefix hashes of exactly what is sent.
171
+ recordAnthropicPrefix(opts.sessionId || opts.session?.id || null, anthropicPrefixFingerprint(params));
172
+
173
+ const requestHeaders = requestHeadersFor(params, {
174
+ config,
175
+ opts,
176
+ isCustom,
177
+ fastLatched,
178
+ hasDeferredTools,
179
+ capabilityModel,
180
+ effortProjection,
181
+ });
182
+
183
+ return { params, requestHeaders, knownToolNames, fastModeLatched: fastLatched };
184
+ }
185
+
186
+ /** The turn's thinking/effort fields on `params` (in place): a custom
187
+ * provider's from its own model row, else the turn effort (or a gateway's
188
+ * own `messagesEffort`; 'none' sends no thinking at all). */
189
+ function applyRequestReasoning(
190
+ params,
191
+ { isCustom, name, config, opts, modelInfo, capabilityModel, maxTokens, gatewayEffort, effortProjection }
192
+ ) {
138
193
  if (isCustom) {
139
194
  const { fields } = resolveCustomReasoning({
140
195
  protocol: 'anthropic',
@@ -156,32 +211,29 @@ export async function buildAnthropicApiRequest({
156
211
  progressUpdates: config?.disableBetaHeaders !== true,
157
212
  });
158
213
  }
159
- if (params.tools) {
160
- const toolChoice = toAnthropicToolChoice(opts.toolChoice, {
161
- thinking: anthropicThinkingActive(params),
162
- disableParallelToolUse: opts.disableParallelToolUse === true,
163
- // A gateway that cannot honour disable_parallel_tool_use declares so.
164
- supportsDisableParallelToolUse: config?.supportsDisableParallelToolUse !== false,
165
- onThinkingConflict: opts.toolChoiceThinkingConflict,
166
- });
167
- if (toolChoice) params.tool_choice = toolChoice;
168
- else delete params.tool_choice;
169
- }
170
- // Fast mode → speed: "fast" on models Anthropic marks as speed-capable.
171
- // Suppressed while the fast capacity pool is cooling down.
172
- let fastLatched = fastModeLatched;
173
- if (!isCustom && opts.fast === true && supportsAnthropicFastMode(useModel) && fastModeAvailable()) {
174
- params.speed = 'fast';
175
- fastLatched = true;
176
- }
177
- // NOTE: do NOT sanitize here. params.messages was already sanitized
178
- // once inside toAnthropicMessages and then had cache markers applied.
179
- // Re-sanitizing after marking could drop/reorder a marked block and
180
- // move the provider-visible cache breakpoint off the cached one — the
181
- // exact COLD-turn bug this change fixes. Order: build → sanitize
182
- // (once) → mark → prepare image bytes → send.
183
- params.stream = true;
214
+ }
184
215
 
216
+ /** The reserved `tool_choice` of a request with tools, resolved once
217
+ * thinking is known (forced any/tool is invalid while thinking is on);
218
+ * dropped when none applies. */
219
+ function resolveRequestToolChoice(params, opts, config) {
220
+ const toolChoice = toAnthropicToolChoice(opts.toolChoice, {
221
+ thinking: anthropicThinkingActive(params),
222
+ disableParallelToolUse: opts.disableParallelToolUse === true,
223
+ // A gateway that cannot honour disable_parallel_tool_use declares so.
224
+ supportsDisableParallelToolUse: config?.supportsDisableParallelToolUse !== false,
225
+ onThinkingConflict: opts.toolChoiceThinkingConflict,
226
+ });
227
+ if (toolChoice) params.tool_choice = toolChoice;
228
+ else delete params.tool_choice;
229
+ }
230
+
231
+ /** The per-request headers of the final body `params`: the anthropic-beta
232
+ * set it needs, then the caller's `opts.requestHeaders`; null when none. */
233
+ function requestHeadersFor(
234
+ params,
235
+ { config, opts, isCustom, fastLatched, hasDeferredTools, capabilityModel, effortProjection }
236
+ ) {
185
237
  // Per-call headers override the client defaultHeaders, so the
186
238
  // constructor-level disableBetaHeaders opt-out must be honoured here
187
239
  // too — otherwise opencode-go's anthropic-compatible routing
@@ -205,8 +257,5 @@ export async function buildAnthropicApiRequest({
205
257
  ].filter(Boolean);
206
258
  if (betas.length) betaHeaders = { 'anthropic-beta': betas.join(',') };
207
259
  }
208
- const requestHeaders =
209
- betaHeaders || opts.requestHeaders ? { ...(betaHeaders || {}), ...(opts.requestHeaders || {}) } : null;
210
-
211
- return { params, requestHeaders, knownToolNames, fastModeLatched: fastLatched };
260
+ return betaHeaders || opts.requestHeaders ? { ...(betaHeaders || {}), ...(opts.requestHeaders || {}) } : null;
212
261
  }
@@ -149,7 +149,7 @@ function _markLatestByFamily(models) {
149
149
  for (const m of byFamily.values()) m.latest = true;
150
150
  }
151
151
 
152
- function _compareVersion(a, b) {
152
+ export function _compareVersion(a, b) {
153
153
  const na = (a.match(/^claude-[a-z]+-(\d+)(?:-(\d+))?/i) || []).slice(1).map(Number);
154
154
  const nb = (b.match(/^claude-[a-z]+-(\d+)(?:-(\d+))?/i) || []).slice(1).map(Number);
155
155
  for (let i = 0; i < Math.max(na.length, nb.length); i++) {
@@ -10,7 +10,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
10
10
  // source release just to advance the user-agent version.
11
11
  // Claude Opus 5.5 requires 2.1.280 or newer. The release workflow raises this
12
12
  // to the published CLI version (scripts/sync-client-version-floors.mjs).
13
- export const DEFAULT_CLI_VERSION = '2.1.304';
13
+ export const DEFAULT_CLI_VERSION = '2.1.307';
14
14
  export const CLAUDE_CLI_NPM_PACKAGE = '@anthropic-ai/claude-code';
15
15
 
16
16
  const CACHE_SCHEMA_VERSION = 1;
@@ -6,6 +6,11 @@
6
6
  * from anthropic.mjs. agent-trace instrumented.
7
7
  */
8
8
  import { traceAgentSse, traceAgentUsage } from '../agent-trace.mjs';
9
+ import {
10
+ anthropicPrefixFingerprint,
11
+ latestAnthropicPrefix,
12
+ recordAnthropicPrefix,
13
+ } from './lib/anthropic-prefix-trace.mjs';
9
14
  import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
10
15
  import { resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
11
16
  import { MODELS } from './lib/anthropic-models.mjs';
@@ -56,6 +61,7 @@ import { ANTHROPIC_EFFORT_LEVELS, withEffortRejectionFallback } from './effort-r
56
61
  import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
57
62
  import {
58
63
  anthropicThinkingActive,
64
+ appendAnthropicTailReminder,
59
65
  applyAnthropicCacheMarkers,
60
66
  clampAnthropicThinkingBudget as clampThinkingBudgetTokens,
61
67
  deferredAnthropicTools as sharedDeferredAnthropicTools,
@@ -67,6 +73,7 @@ import {
67
73
  toAnthropicMessages,
68
74
  toAnthropicToolChoice,
69
75
  } from './lib/anthropic-request-utils.mjs';
76
+ import { splitTailReminder } from './lib/tail-reminder-split.mjs';
70
77
  import {
71
78
  EFFORT_CONFIGURATION_BETA,
72
79
  isEffortConfigurationRejection,
@@ -189,7 +196,8 @@ function requestAnthropicTools(tools, messages, opts) {
189
196
  // the tier3 1h cache_control to that block; BP1/BP2 take the system TTL. No
190
197
  // `<system-reminder>` user message / sentinel scan is involved anymore.
191
198
 
192
- function buildRequestBody(messages, model, tools, sendOpts) {
199
+ function buildRequestBody(requestMessages, model, tools, sendOpts) {
200
+ const { messages, reminder } = splitTailReminder(requestMessages);
193
201
  const systemMsgs = messages.filter((m) => m.role === 'system');
194
202
  const chatMsgs = messages.filter((m) => m.role !== 'system');
195
203
  const opts = sendOpts || {};
@@ -229,7 +237,7 @@ function buildRequestBody(messages, model, tools, sendOpts) {
229
237
  const body = {
230
238
  model,
231
239
  max_tokens: maxTokens,
232
- messages: anthropicMessages,
240
+ messages: appendAnthropicTailReminder(anthropicMessages, reminder),
233
241
  stream: true,
234
242
  };
235
243
  applyAnthropicServerFallback(body, model, {
@@ -463,6 +471,8 @@ export class AnthropicOAuthProvider {
463
471
  const useModel = model || (await ensureLatestAnthropicModel(this));
464
472
  const body = buildRequestBody(messages, useModel, tools, sendOpts);
465
473
  body.messages = await prepareAnthropicImages(body.messages, { signal: externalSignal });
474
+ // Diagnostic: per-block prefix hashes of exactly what is sent.
475
+ recordAnthropicPrefix(opts.sessionId || null, anthropicPrefixFingerprint(body));
466
476
  if (body.speed === 'fast') {
467
477
  this.fastModeBetaHeaderLatched = true;
468
478
  }
@@ -544,42 +554,15 @@ export class AnthropicOAuthProvider {
544
554
  let maxTokensAdjusted = false;
545
555
  try {
546
556
  for (let attemptIndex = 0; attemptIndex <= ANTHROPIC_MAX_MIDSTREAM_RETRIES; attemptIndex++) {
547
- let response, controller, cancelHandler;
548
- ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
549
-
550
- // Refresh on 401, and only Anthropic's exact official revoked-token
551
- // 403 signature. Ordinary permission/policy 403s are terminal.
552
- let rejectedAuthBody = null;
553
- if (response.status === 401 || response.status === 403) {
554
- rejectedAuthBody = await response.text().catch(() => '');
555
- }
556
- if (isRefreshableAuthRejection(response.status, rejectedAuthBody)) {
557
- process.stderr.write(`[anthropic-oauth] ${response.status} — forcing refresh and retrying once\n`);
558
- cleanupCancelHandler(cancelHandler);
559
- // Body was drained above; abort closes any remaining transport
560
- // resources before the credential-refresh replay.
561
- try {
562
- controller?.abort?.();
563
- } catch {}
564
- auth.creds = await this.ensureAuth({ forceRefresh: true, reason: String(response.status) });
565
- ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
566
- rejectedAuthBody = null;
567
- }
568
-
569
- // "input length and max_tokens exceed context limit": shrink max_tokens
570
- // to what the context has room for and replay once.
571
- if (response.status === 400 && !maxTokensAdjusted) {
572
- rejectedAuthBody = await response.text().catch(() => '');
573
- if (adjustMaxTokensForContextOverflow(body, 400, rejectedAuthBody)) {
574
- maxTokensAdjusted = true;
575
- cleanupCancelHandler(cancelHandler);
576
- try {
577
- controller?.abort?.();
578
- } catch {}
579
- ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
580
- rejectedAuthBody = null;
581
- }
582
- }
557
+ const opened = await this._openResponse({
558
+ requestWithRetry,
559
+ cleanupCancelHandler,
560
+ auth,
561
+ body,
562
+ maxTokensAdjusted,
563
+ });
564
+ const { response, controller, cancelHandler, rejectedAuthBody } = opened;
565
+ maxTokensAdjusted = opened.maxTokensAdjusted;
583
566
  if (!response.ok) {
584
567
  cleanupCancelHandler(cancelHandler);
585
568
  return await this._resendAfterRejection({
@@ -657,6 +640,51 @@ export class AnthropicOAuthProvider {
657
640
  }
658
641
  }
659
642
 
643
+ // One attempt's initial response: a 401 (or Anthropic's exact revoked-token
644
+ // 403) refreshes the credentials in `auth` and replays once; a context
645
+ // overflow 400 shrinks `body.max_tokens` and replays once per send
646
+ // (`maxTokensAdjusted`). `rejectedAuthBody`: the drained text of a final
647
+ // rejected response, null when none was read.
648
+ async _openResponse({ requestWithRetry, cleanupCancelHandler, auth, body, maxTokensAdjusted }) {
649
+ let response, controller, cancelHandler;
650
+ ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
651
+
652
+ // Refresh on 401, and only Anthropic's exact official revoked-token
653
+ // 403 signature. Ordinary permission/policy 403s are terminal.
654
+ let rejectedAuthBody = null;
655
+ if (response.status === 401 || response.status === 403) {
656
+ rejectedAuthBody = await response.text().catch(() => '');
657
+ }
658
+ if (isRefreshableAuthRejection(response.status, rejectedAuthBody)) {
659
+ process.stderr.write(`[anthropic-oauth] ${response.status} — forcing refresh and retrying once\n`);
660
+ cleanupCancelHandler(cancelHandler);
661
+ // Body was drained above; abort closes any remaining transport
662
+ // resources before the credential-refresh replay.
663
+ try {
664
+ controller?.abort?.();
665
+ } catch {}
666
+ auth.creds = await this.ensureAuth({ forceRefresh: true, reason: String(response.status) });
667
+ ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
668
+ rejectedAuthBody = null;
669
+ }
670
+
671
+ // "input length and max_tokens exceed context limit": shrink max_tokens
672
+ // to what the context has room for and replay once.
673
+ if (response.status === 400 && !maxTokensAdjusted) {
674
+ rejectedAuthBody = await response.text().catch(() => '');
675
+ if (adjustMaxTokensForContextOverflow(body, 400, rejectedAuthBody)) {
676
+ maxTokensAdjusted = true;
677
+ cleanupCancelHandler(cancelHandler);
678
+ try {
679
+ controller?.abort?.();
680
+ } catch {}
681
+ ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
682
+ rejectedAuthBody = null;
683
+ }
684
+ }
685
+ return { response, controller, cancelHandler, rejectedAuthBody, maxTokensAdjusted };
686
+ }
687
+
660
688
  // A non-OK initial response: quota errors surface as-is; a CLI-version
661
689
  // floor or an unknown/retired model replays the turn ONCE through send().
662
690
  async _resendAfterRejection({ response, rejectedAuthBody, messages, model, useModel, tools, opts, onStageChange }) {
@@ -780,6 +808,7 @@ export class AnthropicOAuthProvider {
780
808
  rawUsage: result.usage?.raw || null,
781
809
  provider: 'anthropic-oauth',
782
810
  requestKind,
811
+ prefixBlocks: latestAnthropicPrefix(sessionId),
783
812
  });
784
813
 
785
814
  // Phase I: if the live response surfaced a model id we don't know
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import { traceAgentUsage } from '../agent-trace.mjs';
13
13
  import { reportedCostUsd } from './lib/usage-primitives.mjs';
14
+ import { latestAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
14
15
 
15
16
  /**
16
17
  * @param {object} parseResult the assembled turn (streaming or normalized non-streaming)
@@ -47,6 +48,7 @@ export function buildAnthropicTurnResult(parseResult, { provider, useModel, opts
47
48
  // Anthropic usage is additive at this inner transport
48
49
  // boundary, even when OpenCode Go supplies the provider id.
49
50
  inputTokensInclusive: false,
51
+ prefixBlocks: latestAnthropicPrefix(opts.sessionId || opts.session?.id || null),
50
52
  });
51
53
  }
52
54
 
@@ -187,9 +187,14 @@ export function normalizeAntigravityCatalog(rawModels) {
187
187
  return models.sort((a, b) => a.display.localeCompare(b.display));
188
188
  }
189
189
 
190
- /** Catalog to resolve wire ids against: in-memory mirror, disk cache, then the curated fallback. */
190
+ /**
191
+ * Catalog to resolve wire ids against: in-memory mirror, disk cache, then the
192
+ * curated fallback. Sends never refresh the catalog, so the account's last live
193
+ * list is used even past its TTL: it names the wire ids this account was
194
+ * offered, which the curated list can only approximate.
195
+ */
191
196
  function antigravityCatalogModels() {
192
- if (!_mirror) _mirror = antigravityModelCache.loadSync();
197
+ if (!_mirror) _mirror = antigravityModelCache.loadSync({ allowStale: true });
193
198
  return _mirror || ANTIGRAVITY_MODELS;
194
199
  }
195
200
 
@@ -3,6 +3,7 @@ import { createProviderReplay, providerReplayItems } from './lib/provider-replay
3
3
  import { toGeminiContents, toGeminiRequestTools, toGeminiToolConfig } from './gemini-schema.mjs';
4
4
  import { geminiThinkingConfig } from './gemini-thinking.mjs';
5
5
  import { isGeminiFamilyModel } from './gemini-family.mjs';
6
+ import { splitTailReminder } from './lib/tail-reminder-split.mjs';
6
7
 
7
8
  const THOUGHT_SIGNATURE_SENTINEL = 'skip_thought_signature_validator';
8
9
  const CLAUDE_MAX_OUTPUT_TOKENS = 64000;
@@ -219,7 +220,10 @@ function antigravityGeminiThinkingConfig(model, opts) {
219
220
  });
220
221
  }
221
222
 
222
- export function buildAntigravityRequest(messages, model, tools, opts = {}, projectId) {
223
+ export function buildAntigravityRequest(requestMessages, model, tools, opts = {}, projectId) {
224
+ // The tail reminder is not history: the tool-loop closure below must see the
225
+ // real tail, so the reminder is appended to the wire contents last.
226
+ const { messages, reminder } = splitTailReminder(requestMessages);
223
227
  const systemText = messages
224
228
  .filter((message) => message.role === 'system')
225
229
  .map((message) => message.content)
@@ -234,7 +238,7 @@ export function buildAntigravityRequest(messages, model, tools, opts = {}, proje
234
238
  ...(claude ? { maxOutputTokens: CLAUDE_MAX_OUTPUT_TOKENS } : {}),
235
239
  ...(thinkingConfig ? { thinkingConfig } : {}),
236
240
  };
237
- const request = { contents };
241
+ const request = { contents: reminder ? [...contents, { role: 'user', parts: [{ text: reminder }] }] : contents };
238
242
  if (systemText) request.systemInstruction = { role: 'user', parts: [{ text: systemText }] };
239
243
  const requestTools = claude
240
244
  ? claudeRequestTools(tools, opts.nativeTools, opts.onToolExcluded)
@@ -3,24 +3,43 @@
3
3
  // Every turn starts again from the base, so a run of hard turns never
4
4
  // ratchets the effort upward.
5
5
  //
6
- // The base is `medium` on every model: raised only when the request needs it,
7
- // lowered when it is easy. The ladder is the model's supported efforts from
6
+ // The base is the global "Auto reasoning base" setting (`autoEffortBase` in the
7
+ // agent config; low / medium / high, default `medium`), the same on every model
8
+ // and independent of the effort last chosen: raised only when the request needs
9
+ // it, lowered when it is easy. The ladder is the model's supported efforts from
8
10
  // `low` up to the tier below the top: `none`/`minimal` switch thinking off and
9
- // `max`/`ultra` are reserved for an explicit user choice, so auto never picks
10
- // them. A chosen `max`/`ultra` is left untouched.
11
+ // `max`/`ultra` are reserved for an explicit (fixed, Auto off) user choice, so
12
+ // auto never picks them. A base the model does not offer is clamped to the
13
+ // nearest ladder level.
11
14
 
12
15
  const EFFORT_ORDER = Object.freeze(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra']);
13
16
  const FLOOR_INDEX = EFFORT_ORDER.indexOf('low');
14
17
  const RESERVED_TOP = new Set(['max', 'ultra']);
15
18
 
16
19
  export const AUTO_EFFORT_BASE = 'medium';
20
+ /** The "Auto reasoning base" choices: the levels Auto can work around. */
21
+ export const AUTO_EFFORT_BASES = Object.freeze(['low', 'medium', 'high']);
17
22
 
18
- /** The effort auto moves from: `medium`, unless the user chose `max`/`ultra`. */
19
- export function autoEffortBase(chosen) {
20
- const effort = String(chosen ?? '')
23
+ /** The effort auto moves from: the global "Auto reasoning base" setting
24
+ * (`autoEffortBase` in the agent config); absent or invalid is `medium`. */
25
+ export function autoEffortBase(setting) {
26
+ const effort = String(setting ?? '')
21
27
  .trim()
22
28
  .toLowerCase();
23
- return RESERVED_TOP.has(effort) ? effort : AUTO_EFFORT_BASE;
29
+ return AUTO_EFFORT_BASES.includes(effort) ? effort : AUTO_EFFORT_BASE;
30
+ }
31
+
32
+ /** The base on the model's ladder: the setting itself, else the nearest
33
+ * ladder level (the lower one on a tie); null when the ladder is empty. */
34
+ export function clampAutoEffortBase({ base, options }) {
35
+ const ladder = autoEffortLadder(options);
36
+ if (!ladder.length) return null;
37
+ const want = EFFORT_ORDER.indexOf(autoEffortBase(base));
38
+ let best = ladder[0];
39
+ for (const level of ladder) {
40
+ if (Math.abs(EFFORT_ORDER.indexOf(level) - want) < Math.abs(EFFORT_ORDER.indexOf(best) - want)) best = level;
41
+ }
42
+ return best;
24
43
  }
25
44
 
26
45
  export const AUTO_EFFORT_MODES = Object.freeze(['off', 'observe', 'on']);
@@ -31,14 +50,14 @@ export const AUTO_EFFORT_LEVELS = Object.freeze(['easy', 'normal', 'hard', 'very
31
50
  const STEP_OF_LEVEL = [-1, 0, 1, 2];
32
51
 
33
52
  // The chosen level minimises the expected cost under the judge distribution.
34
- // A miss costs one per level, plus extra for an opposite call and for a
35
- // needless "very hard" (xhigh). Opposite calls are asymmetric: "easy" for a
36
- // hard turn degrades the answer, "hard" for an easy turn only costs tokens.
37
- // On the held-out test splits the heavier under-call cost cut hard-as-easy
38
- // calls by a third (20 -> 13 of 7,180) for -0.2 points of exact accuracy.
53
+ // A miss costs one per level, plus extra for an opposite call. Opposite calls
54
+ // are asymmetric: "easy" for a hard turn degrades the answer, "hard" for an
55
+ // easy turn only costs tokens. On the held-out test splits the heavier
56
+ // under-call cost cut hard-as-easy calls by a third (20 -> 13 of 7,180) for
57
+ // -0.2 points of exact accuracy. "Very hard" carries no extra cost: an extra
58
+ // penalty there let judge v7 pick xhigh on only 17% of very hard turns.
39
59
  export const AUTO_EFFORT_UNDER_OPPOSITE_COST = 3;
40
60
  export const AUTO_EFFORT_OVER_OPPOSITE_COST = 1;
41
- export const AUTO_EFFORT_FALSE_VERY_HARD_COST = 1;
42
61
  // Ties keep the default first, then the cheaper side.
43
62
  const TIE_ORDER = [1, 0, 2, 3];
44
63
 
@@ -49,8 +68,7 @@ function expectedCost(values, level) {
49
68
  p *
50
69
  (Math.abs(level - actual) +
51
70
  (level === 0 && actual >= 2 ? AUTO_EFFORT_UNDER_OPPOSITE_COST : 0) +
52
- (actual === 0 && level >= 2 ? AUTO_EFFORT_OVER_OPPOSITE_COST : 0) +
53
- (level === 3 && actual < 3 ? AUTO_EFFORT_FALSE_VERY_HARD_COST : 0));
71
+ (actual === 0 && level >= 2 ? AUTO_EFFORT_OVER_OPPOSITE_COST : 0));
54
72
  });
55
73
  return cost;
56
74
  }
@@ -40,8 +40,10 @@ import {
40
40
  textContent,
41
41
  } from './cursor-wire-request.mjs';
42
42
  import { handleExecMessage, heartbeatFrame, sendToolResult } from './cursor-wire-exec.mjs';
43
+ import { releaseCursorNativeCall } from './cursor-native-context.mjs';
43
44
  import { completionChunk, createStreamSink } from './cursor-wire-stream-sink.mjs';
44
45
  import { createBridgeController } from './cursor-wire-stream-bridge.mjs';
46
+ import { markProviderRecoveryExhausted } from './retry-classifier.mjs';
45
47
  import { TRANSPORT_SCOPE_DISPOSED } from './transport-scope.mjs';
46
48
 
47
49
  export { clearModelCache, getCursorModels, getCursorUsage } from './cursor-wire-models.mjs';
@@ -70,16 +72,22 @@ function storeActiveRun(key, active) {
70
72
  activeRuns.set(key, active);
71
73
  }
72
74
 
73
- // Tear down one stored run: drop it from the registry, stop its 5s heartbeat
74
- // interval, and close the Cursor bridge it was holding open.
75
- function closeActiveRun(key, active, error) {
76
- if (!forgetActiveRun(key, active)) return false;
75
+ function disposeActiveRun(active, error) {
77
76
  clearInterval(active.heartbeat);
77
+ for (const pending of active.pending) releaseCursorNativeCall(pending);
78
+ active.pending = [];
78
79
  try {
79
80
  active.bridge.close(error);
80
81
  } catch {
81
82
  /* already closing */
82
83
  }
84
+ }
85
+
86
+ // Tear down one stored run: drop it from the registry, stop its 5s heartbeat
87
+ // interval, and close the Cursor bridge it was holding open.
88
+ function closeActiveRun(key, active, error) {
89
+ if (!forgetActiveRun(key, active)) return false;
90
+ disposeActiveRun(active, error);
83
91
  return true;
84
92
  }
85
93
 
@@ -458,6 +466,25 @@ function resumeRun(active, toolResults, userText, model, key) {
458
466
  }
459
467
  sendToolResult(active.bridge, pending, payload, result.isError !== true);
460
468
  }
469
+ // Every pending call was already handed to the executor. Re-emitting the
470
+ // same batch without accepting a result makes the transcript rename its
471
+ // ids, breaks native authorization, and can loop without another model call.
472
+ // Partial progress is valid; an unchanged pending batch is a terminal
473
+ // handoff failure, not a transport retry or an invitation to execute again.
474
+ if (remaining.length > 0 && remaining.length === active.pending.length) {
475
+ const error = markProviderRecoveryExhausted(
476
+ cursorError(
477
+ `Cursor tool-result handoff made no progress: ${remaining.length} pending call(s) received no matching result. Stopped to avoid repeating tool execution.`,
478
+ { status: 400, code: 'tool_result_no_progress' }
479
+ ),
480
+ { owner: 'cursor-wire', terminal: true }
481
+ );
482
+ // handleChatCompletion already detached this run; direct partial-batch
483
+ // resumes may still own its registry entry and expiry timer.
484
+ forgetActiveRun(key, active);
485
+ disposeActiveRun(active, error);
486
+ throw error;
487
+ }
461
488
  active.pending = remaining;
462
489
  active.pendingUserText = userTextDelivered ? '' : pendingUserText;
463
490
  if (remaining.length > 0) {
@@ -35,7 +35,10 @@ async function loadCursorRuntime() {
35
35
  function toCursorMessages(messages, providerName, { nativePdf } = {}) {
36
36
  const output = [];
37
37
  for (const message of messages || []) {
38
- const converted = toOpenAIMessages([message], providerName, { nativePdf });
38
+ // This is a local envelope over Cursor's execution protocol, not an
39
+ // OpenAI request. Its pending executions and native capabilities require
40
+ // the exact original id, including ids longer than OpenAI's 40-char cap.
41
+ const converted = toOpenAIMessages([message], providerName, { nativePdf, preserveToolCallIds: true });
39
42
  if (message?.role !== 'tool') {
40
43
  output.push(...converted);
41
44
  continue;
@@ -40,6 +40,7 @@ function sanitizeDiscoveryError(error, apiKey) {
40
40
  if (apiKey) message = message.split(apiKey).join('[redacted]');
41
41
  const out = new Error(message);
42
42
  if (Number.isInteger(error?.status)) out.status = error.status;
43
+ if (error?.code === 'EPROVIDERTIMEOUT' || error?.name === 'TimeoutError') out.code = 'EPROVIDERTIMEOUT';
43
44
  return out;
44
45
  }
45
46
 
@@ -82,11 +83,13 @@ function withCustomModels(Base, discover) {
82
83
  const first = rows.find((row) => !row.hidden);
83
84
  if (first) this.defaultModel = first.id;
84
85
  }
85
- async listModels({ signal = null, throwOnError = false } = {}) {
86
+ // `timeoutMs` lets an interactive caller wait longer than the default
87
+ // catalog timeout (slow gateways); the runtime refresh keeps the default.
88
+ async listModels({ signal = null, throwOnError = false, timeoutMs } = {}) {
86
89
  let failure = null;
87
90
  try {
88
91
  this._assertCustomKey();
89
- this._customDiscovered = await discover(this, signal);
92
+ this._customDiscovered = await discover(this, signal, timeoutMs);
90
93
  this.customDiscoveryError = null;
91
94
  } catch (error) {
92
95
  if (signal?.aborted) throw error;
@@ -109,8 +112,8 @@ function withCustomModels(Base, discover) {
109
112
  };
110
113
  }
111
114
 
112
- async function discoverAnthropicModels(provider, signal) {
113
- const timeout = AbortSignal.timeout(DISCOVERY_TIMEOUT_MS);
115
+ async function discoverAnthropicModels(provider, signal, timeoutMs = DISCOVERY_TIMEOUT_MS) {
116
+ const timeout = AbortSignal.timeout(timeoutMs);
114
117
  const res = await fetch(`${provider.config.baseURL}/v1/models`, {
115
118
  method: 'GET',
116
119
  signal: signal ? AbortSignal.any([signal, timeout]) : timeout,
@@ -182,8 +185,8 @@ export async function createCustomProvider(id, config) {
182
185
  }
183
186
  class CompatBase extends OpenAICompatProvider {
184
187
  messagesEngine = messagesEngine;
185
- _fetchModelItems({ signal = null } = {}) {
186
- return fetchCompatModelItems(this, { signal, keyless: this._customKeyless });
188
+ _fetchModelItems({ signal = null, timeoutMs } = {}) {
189
+ return fetchCompatModelItems(this, { signal, timeoutMs, keyless: this._customKeyless });
187
190
  }
188
191
  resolveWireRoute(model, ctx = {}) {
189
192
  return resolveWireRoute(this.name, model, { ...ctx, override: cfg.modelWires?.[model] ?? null });
@@ -203,8 +206,8 @@ export async function createCustomProvider(id, config) {
203
206
  });
204
207
  }
205
208
  }
206
- const Custom = withCustomModels(CompatBase, (self, signal) =>
207
- listCompatModels(self, { throwOnError: true, signal })
209
+ const Custom = withCustomModels(CompatBase, (self, signal, timeoutMs) =>
210
+ listCompatModels(self, { throwOnError: true, signal, timeoutMs })
208
211
  );
209
212
  provider = new Custom(providerId, engine);
210
213
  }