mixdog 0.9.153 → 0.9.155

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 (217) hide show
  1. package/package.json +6 -2
  2. package/scripts/build-voice-runtime-unix.sh +24 -0
  3. package/scripts/voice-runtime-config.json +1 -1
  4. package/src/rules/shared/60-verification.md +2 -0
  5. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  6. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +5 -2
  7. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +5 -2
  8. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +47 -4
  9. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +0 -1
  10. package/src/runtime/agent/orchestrator/session/compact/handoff.mjs +0 -22
  11. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -2
  12. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +9 -22
  13. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +28 -269
  14. package/src/runtime/agent/orchestrator/session/compact.mjs +0 -6
  15. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +80 -18
  16. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +12 -0
  17. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +5 -66
  18. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +7 -0
  19. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +4 -1
  20. package/src/runtime/channels/data/voice-runtime-manifest.json +17 -17
  21. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +59 -0
  22. package/src/runtime/computer-bridge/client.mjs +85 -32
  23. package/src/runtime/office/assurance-benchmark.mjs +67 -1
  24. package/src/runtime/office/assurance.mjs +24 -17
  25. package/src/runtime/office/capabilities.mjs +17 -17
  26. package/src/runtime/office/composition-system.mjs +451 -0
  27. package/src/runtime/office/design-library.mjs +102 -0
  28. package/src/runtime/office/design-system.mjs +357 -168
  29. package/src/runtime/office/index.mjs +149 -20
  30. package/src/runtime/office/office-com-host.ps1 +132 -46
  31. package/src/runtime/office/pdf-render.mjs +203 -35
  32. package/src/runtime/office/portable-ooxml.mjs +1090 -47
  33. package/src/runtime/office/portable-package.mjs +390 -0
  34. package/src/runtime/office/portable-sheet-styles.mjs +241 -0
  35. package/src/runtime/office/portable-slide-shapes.mjs +283 -0
  36. package/src/runtime/office/quality-live-benchmark.mjs +82 -36
  37. package/src/runtime/office/quality-pipeline.mjs +3 -0
  38. package/src/runtime/office/tool-defs.mjs +2 -2
  39. package/src/session-runtime/goal-reminder.mjs +79 -0
  40. package/src/session-runtime/goal-runtime.mjs +105 -45
  41. package/src/session-runtime/goal-text.mjs +58 -0
  42. package/src/session-runtime/lifecycle-api.mjs +10 -1
  43. package/src/session-runtime/runtime-core.mjs +20 -6
  44. package/src/session-runtime/session-lifecycle.mjs +1 -1
  45. package/src/session-runtime/session-turn-api.mjs +5 -0
  46. package/src/standalone/daemon.mjs +17 -0
  47. package/src/standalone/session-runtime-worker.mjs +4 -0
  48. package/src/standalone/session-service.mjs +30 -3
  49. package/src/tui/dist/index.mjs +12 -3
  50. package/src/tui/lib/voice-setup.mjs +19 -3
  51. package/src/tui/session/goal-continuation.mjs +7 -0
  52. package/scripts/generate-voice-runtime-manifest.test.mjs +0 -135
  53. package/scripts/native-binary-arch.test.mjs +0 -111
  54. package/scripts/patch-replay.test.mjs +0 -94
  55. package/src/headless-exec.test.mjs +0 -539
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.test.mjs +0 -378
  57. package/src/runtime/agent/orchestrator/agent-trace-timing.test.mjs +0 -57
  58. package/src/runtime/agent/orchestrator/cache-break-trace.test.mjs +0 -115
  59. package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +0 -153
  60. package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +0 -139
  61. package/src/runtime/agent/orchestrator/mcp/features.test.mjs +0 -66
  62. package/src/runtime/agent/orchestrator/mcp/security.test.mjs +0 -80
  63. package/src/runtime/agent/orchestrator/providers/admission-scheduler-metrics.test.mjs +0 -47
  64. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +0 -90
  65. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +0 -215
  66. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.test.mjs +0 -165
  67. package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +0 -201
  68. package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +0 -224
  69. package/src/runtime/agent/orchestrator/providers/openai-codex-model.test.mjs +0 -24
  70. package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +0 -306
  71. package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +0 -288
  72. package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +0 -719
  73. package/src/runtime/agent/orchestrator/session/agent-loop.test.mjs +0 -222
  74. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.test.mjs +0 -83
  75. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.test.mjs +0 -40
  76. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +0 -288
  77. package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +0 -192
  78. package/src/runtime/agent/orchestrator/session/context-usage-restart.test.mjs +0 -72
  79. package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +0 -189
  80. package/src/runtime/agent/orchestrator/session/evidence-union.test.mjs +0 -228
  81. package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +0 -264
  82. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.test.mjs +0 -28
  83. package/src/runtime/agent/orchestrator/session/lossless-tool-output.test.mjs +0 -125
  84. package/src/runtime/agent/orchestrator/session/manager/ask-session.test.mjs +0 -46
  85. package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +0 -325
  86. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +0 -132
  87. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +0 -593
  88. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.test.mjs +0 -117
  89. package/src/runtime/agent/orchestrator/session/reduction-metrics.test.mjs +0 -87
  90. package/src/runtime/agent/orchestrator/session/store/serialize.test.mjs +0 -60
  91. package/src/runtime/agent/orchestrator/session/store-live-publication.test.mjs +0 -83
  92. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +0 -647
  93. package/src/runtime/agent/orchestrator/session/store-summary-visibility.test.mjs +0 -219
  94. package/src/runtime/agent/orchestrator/session/task-wait-control.test.mjs +0 -78
  95. package/src/runtime/agent/orchestrator/tools/builtin/absence-absorption.test.mjs +0 -43
  96. package/src/runtime/agent/orchestrator/tools/builtin/absolute-glob-expand.test.mjs +0 -63
  97. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +0 -14
  98. package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +0 -224
  99. package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +0 -224
  100. package/src/runtime/agent/orchestrator/tools/builtin/enoent-outside-project.test.mjs +0 -56
  101. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +0 -103
  102. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.test.mjs +0 -30
  103. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +0 -390
  104. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.test.mjs +0 -83
  105. package/src/runtime/agent/orchestrator/tools/builtin/grep-output-budget.test.mjs +0 -31
  106. package/src/runtime/agent/orchestrator/tools/builtin/grep-single-file-rescue.test.mjs +0 -106
  107. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.test.mjs +0 -102
  108. package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +0 -152
  109. package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +0 -24
  110. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +0 -24
  111. package/src/runtime/agent/orchestrator/tools/builtin/noise-dir-visibility.test.mjs +0 -69
  112. package/src/runtime/agent/orchestrator/tools/builtin/read-glob-survey.test.mjs +0 -71
  113. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.test.mjs +0 -56
  114. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.test.mjs +0 -16
  115. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-top-k.test.mjs +0 -39
  116. package/src/runtime/agent/orchestrator/tools/builtin/write-symlink.test.mjs +0 -153
  117. package/src/runtime/agent/orchestrator/tools/code-graph/aggregate-anchor-relocation.test.mjs +0 -55
  118. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +0 -88
  119. package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +0 -72
  120. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +0 -54
  121. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.test.mjs +0 -20
  122. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +0 -55
  123. package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +0 -268
  124. package/src/runtime/agent/orchestrator/tools/env-scrub.test.mjs +0 -57
  125. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.test.mjs +0 -19
  126. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +0 -104
  127. package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +0 -661
  128. package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +0 -552
  129. package/src/runtime/agent/orchestrator/tools/patch/patch-symlink.test.mjs +0 -141
  130. package/src/runtime/agent/orchestrator/tools/patch/v4a-pure-move.test.mjs +0 -57
  131. package/src/runtime/agent/orchestrator/tools/patch/v4a-section-coalesce.test.mjs +0 -81
  132. package/src/runtime/agent/orchestrator/tools/spawn-binary-fetcher.test.mjs +0 -52
  133. package/src/runtime/attachments/store.test.mjs +0 -209
  134. package/src/runtime/bridge-clients.test.mjs +0 -827
  135. package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +0 -17
  136. package/src/runtime/channels/lib/webhook/deliveries.test.mjs +0 -18
  137. package/src/runtime/channels/lib/webhook/relay-tunnel.test.mjs +0 -68
  138. package/src/runtime/media/adapters/codex-image.test.mjs +0 -22
  139. package/src/runtime/media/download.test.mjs +0 -52
  140. package/src/runtime/media/renditions.test.mjs +0 -99
  141. package/src/runtime/media/store.test.mjs +0 -159
  142. package/src/runtime/memory/lib/archive-security.test.mjs +0 -128
  143. package/src/runtime/memory/lib/embedding-model-config.test.mjs +0 -33
  144. package/src/runtime/memory/lib/http-wire.test.mjs +0 -15
  145. package/src/runtime/memory/lib/memory-cycle-packets.test.mjs +0 -49
  146. package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +0 -78
  147. package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +0 -50
  148. package/src/runtime/memory/lib/pg/process.test.mjs +0 -36
  149. package/src/runtime/memory/lib/trace-store.test.mjs +0 -57
  150. package/src/runtime/memory/lib/transcript-ingest.test.mjs +0 -52
  151. package/src/runtime/office/office-assurance.test.mjs +0 -371
  152. package/src/runtime/office/office-live-runtime.test.mjs +0 -819
  153. package/src/runtime/office/office-runtime.test.mjs +0 -2070
  154. package/src/runtime/shared/background-tasks.test.mjs +0 -78
  155. package/src/runtime/shared/bounded-download.test.mjs +0 -41
  156. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -25
  157. package/src/runtime/shared/child-spawn-remote.test.mjs +0 -124
  158. package/src/runtime/shared/remote-intent.test.mjs +0 -40
  159. package/src/runtime/shared/resource-admission.test.mjs +0 -43
  160. package/src/runtime/shared/runtime-root.test.mjs +0 -34
  161. package/src/runtime/shared/schedule-time.test.mjs +0 -29
  162. package/src/runtime/shared/session-runtime-health.test.mjs +0 -83
  163. package/src/runtime/shared/skill-document.test.mjs +0 -81
  164. package/src/runtime/shared/tool-surface.test.mjs +0 -87
  165. package/src/runtime/shared/update-checker.test.mjs +0 -33
  166. package/src/runtime/shared/user-cwd.test.mjs +0 -43
  167. package/src/runtime/shared/webhook-session-run.test.mjs +0 -14
  168. package/src/session-runtime/agent-disable.test.mjs +0 -142
  169. package/src/session-runtime/cwd-plugins.test.mjs +0 -75
  170. package/src/session-runtime/cwd-tool-routing.test.mjs +0 -61
  171. package/src/session-runtime/deferred-tool-delta.test.mjs +0 -40
  172. package/src/session-runtime/global-extensions.test.mjs +0 -28
  173. package/src/session-runtime/global-settings-session-identity.test.mjs +0 -76
  174. package/src/session-runtime/goal-runtime.test.mjs +0 -645
  175. package/src/session-runtime/lifecycle-api.test.mjs +0 -183
  176. package/src/session-runtime/model-settings-persist.test.mjs +0 -105
  177. package/src/session-runtime/notification-bus.test.mjs +0 -148
  178. package/src/session-runtime/plugin-mcp-standard.test.mjs +0 -177
  179. package/src/session-runtime/prewarm.test.mjs +0 -52
  180. package/src/session-runtime/provider-request-snapshot.test.mjs +0 -59
  181. package/src/session-runtime/resource-api-global.test.mjs +0 -109
  182. package/src/session-runtime/session-lifecycle.test.mjs +0 -125
  183. package/src/session-runtime/session-title.test.mjs +0 -36
  184. package/src/session-runtime/skills-api.test.mjs +0 -99
  185. package/src/session-runtime/tool-policy-surface.test.mjs +0 -385
  186. package/src/standalone/agent-tool/helpers.test.mjs +0 -62
  187. package/src/standalone/agent-tool/notify.test.mjs +0 -37
  188. package/src/standalone/agent-tool/spawn-flow.test.mjs +0 -104
  189. package/src/standalone/agent-tool/worker-index.test.mjs +0 -132
  190. package/src/standalone/channel-restart.test.mjs +0 -145
  191. package/src/standalone/channel-session-router.test.mjs +0 -37
  192. package/src/standalone/channel-worker-heartbeat.test.mjs +0 -30
  193. package/src/standalone/hook-bus/handlers.test.mjs +0 -88
  194. package/src/standalone/plugin-admin.test.mjs +0 -173
  195. package/src/standalone/session-runtime-agent-control-client.test.mjs +0 -71
  196. package/src/standalone/session-runtime-dispatch-cancel.test.mjs +0 -139
  197. package/src/standalone/session-runtime-host-factory.test.mjs +0 -31
  198. package/src/standalone/session-runtime-host-health.test.mjs +0 -160
  199. package/src/standalone/session-runtime-inline-host.test.mjs +0 -385
  200. package/src/standalone/session-runtime-provider-cooldown.test.mjs +0 -80
  201. package/src/standalone/session-runtime-shard-host.test.mjs +0 -642
  202. package/src/standalone/session-runtime-shard-router.test.mjs +0 -101
  203. package/src/standalone/session-service-agent-tree.test.mjs +0 -984
  204. package/src/standalone/session-service-goal-recovery.test.mjs +0 -177
  205. package/src/tui/app/live-spinner-visibility.test.mjs +0 -44
  206. package/src/tui/app/panel-epoch.test.mjs +0 -1009
  207. package/src/tui/app/panel-handoff.test.mjs +0 -311
  208. package/src/tui/app/prompt-submit.test.mjs +0 -206
  209. package/src/tui/session/agent-message-source.test.mjs +0 -37
  210. package/src/tui/session/completion-card-restore.test.mjs +0 -161
  211. package/src/tui/session/goal-continuation.test.mjs +0 -203
  212. package/src/tui/session/oauth-flows.test.mjs +0 -134
  213. package/src/tui/session/queue-helpers.test.mjs +0 -46
  214. package/src/tui/session/session-action-surface.test.mjs +0 -190
  215. package/src/tui/session/task-wait-submit.test.mjs +0 -80
  216. package/src/tui/session/tool-result-status.test.mjs +0 -131
  217. package/src/tui/session/tui-steering-persist.test.mjs +0 -104
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixdog",
3
- "version": "0.9.153",
3
+ "version": "0.9.155",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone mixdog coding-agent CLI/TUI workspace.",
@@ -31,6 +31,7 @@
31
31
  "!scripts/bench/",
32
32
  "!scripts/recall-bench-*.txt",
33
33
  "!scripts/*-test.mjs",
34
+ "!scripts/*.test.mjs",
34
35
  "!scripts/*-smoke.mjs",
35
36
  "!scripts/smoke-loop*.mjs",
36
37
  "!scripts/*-bench.mjs",
@@ -40,6 +41,8 @@
40
41
  "!scripts/*.jsx",
41
42
  "src/",
42
43
  "!src/tui/dev",
44
+ "!src/**/*.test.mjs",
45
+ "!src/**/*.test.jsx",
43
46
  "vendor/"
44
47
  ],
45
48
  "scripts": {
@@ -68,7 +71,8 @@
68
71
  "test:spec-advisory": "node scripts/advisory-spec-test.mjs && npm run test:spec-advisory --prefix apps/desktop",
69
72
  "test:session-transport": "node --test scripts/session-transport-test.mjs scripts/daemon-bootstrap-test.mjs src/runtime/shared/child-spawn-remote.test.mjs src/standalone/session-runtime-agent-control-client.test.mjs src/standalone/session-runtime-dispatch-cancel.test.mjs src/standalone/session-runtime-host-factory.test.mjs src/standalone/session-runtime-inline-host.test.mjs src/standalone/session-runtime-provider-cooldown.test.mjs src/standalone/session-runtime-shard-host.test.mjs src/standalone/session-runtime-shard-router.test.mjs",
70
73
  "test:session": "node --test scripts/runtime-turn-contract-test.mjs scripts/session-save-fault-store-test.mjs scripts/turn-review-revert-test.mjs src/runtime/shared/tool-surface.test.mjs src/runtime/bridge-clients.test.mjs",
71
- "test:office": "node --test src/runtime/office/office-runtime.test.mjs src/runtime/office/office-assurance.test.mjs && npm run test:office-approval --prefix apps/desktop",
74
+ "test:quick": "npm run test:session && npm run test:session-transport && npm run test:desktop-main --prefix apps/desktop",
75
+ "test:office": "node --test src/runtime/office/office-runtime.test.mjs src/runtime/office/office-assurance.test.mjs src/runtime/office/portable-authoring.test.mjs && npm run test:office-approval --prefix apps/desktop",
72
76
  "test:office:live": "node scripts/run-office-live-tests.mjs",
73
77
  "test:media": "node --test src/runtime/media/store.test.mjs src/runtime/media/renditions.test.mjs src/runtime/media/adapters/codex-image.test.mjs",
74
78
  "failures": "node scripts/tool-failures.mjs",
@@ -41,17 +41,41 @@ curl --fail --location --retry 3 \
41
41
  --output "${WORK_ROOT}/source.tar.gz"
42
42
  tar -xzf "${WORK_ROOT}/source.tar.gz" -C "${WORK_ROOT}"
43
43
 
44
+ # Portability baseline (GGML_NATIVE=OFF + explicit ISA on x86-64).
45
+ #
46
+ # ggml defaults GGML_NATIVE=ON, which tunes the binary to the BUILD machine.
47
+ # CI runners are wider than consumer hardware, so a native build ships
48
+ # instructions the target CPU may not have and aborts with SIGILL /
49
+ # STATUS_ILLEGAL_INSTRUCTION right after backend init — the `--help` smoke
50
+ # below cannot catch it, because on the build machine it passes.
51
+ #
52
+ # x86-64 pins an AVX2/FMA/F16C baseline (Haswell 2013+); AVX-512, AVX-VNNI and
53
+ # BMI2 stay OFF because they are not universal on current consumer CPUs.
54
+ # arm64 needs no ISA pins — NEON is baseline — but must still disable NATIVE.
44
55
  CMAKE_ARGS=(
45
56
  -S "${SOURCE_ROOT}"
46
57
  -B "${BUILD_ROOT}"
47
58
  -DCMAKE_BUILD_TYPE=Release
48
59
  -DBUILD_SHARED_LIBS=OFF
60
+ -DGGML_NATIVE=OFF
49
61
  -DWHISPER_BUILD_EXAMPLES=ON
50
62
  -DWHISPER_BUILD_SERVER=ON
51
63
  -DWHISPER_BUILD_TESTS=OFF
52
64
  -DWHISPER_SDL2=OFF
53
65
  )
54
66
 
67
+ if [[ "${TARGET_ARCH}" == "x64" ]]; then
68
+ CMAKE_ARGS+=(
69
+ -DGGML_AVX=ON
70
+ -DGGML_AVX2=ON
71
+ -DGGML_FMA=ON
72
+ -DGGML_F16C=ON
73
+ -DGGML_AVX512=OFF
74
+ -DGGML_AVX_VNNI=OFF
75
+ -DGGML_BMI2=OFF
76
+ )
77
+ fi
78
+
55
79
  case "${BACKEND}" in
56
80
  vulkan)
57
81
  CMAKE_ARGS+=(-DGGML_VULKAN=ON)
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "1.9.2",
2
+ "runtimeVersion": "1.9.3",
3
3
  "whisperCommit": "306c88f4d1286aec1bf96e544632897886af5501",
4
4
  "vulkanSdkVersion": "1.4.309.0",
5
5
  "platforms": [
@@ -9,6 +9,8 @@
9
9
  buildability invariants. Treat mutable behavior, UX, exact text, snapshots,
10
10
  and implementation shape as advisory specifications; update them when the
11
11
  requested behavior changes instead of preserving obsolete behavior.
12
+ - A new test asserts observable behavior, never source text or implementation
13
+ shape, and never re-asserts a contract another test already owns.
12
14
  - A check runs at the strictness the task requires; never raise a tool's own
13
15
  severity beyond it.
14
16
  - If verification fails, collect all failures, leave Verification, complete all
@@ -240,8 +240,8 @@ export function requestAnthropicTools(tools, messages, opts) {
240
240
  // Test-only: expose the lowering so the steering-provenance test can assert
241
241
  // the API-key provider keeps steering-tagged user turns distinct (mirrors
242
242
  // anthropic-oauth._buildRequestBodyForCacheSmoke coverage).
243
- export function _toAnthropicMessagesForTest(messages) {
244
- return toAnthropicMessages(messages);
243
+ export function _toAnthropicMessagesForTest(messages, availableTools) {
244
+ return toAnthropicMessages(messages, availableTools);
245
245
  }
246
246
 
247
247
  // Applies cache_control markers to the FINAL, already-sanitized Anthropic
@@ -296,12 +296,16 @@ function buildRequestBody(messages, model, tools, sendOpts) {
296
296
  // Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is shared
297
297
  // with anthropic.mjs — see resolveAnthropicMessageCacheSlots.
298
298
  const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls);
299
+ // Tools are resolved BEFORE the messages: the lowering needs the final
300
+ // tool list to drop tool_reference blocks whose tool no longer ships in
301
+ // this request (otherwise the API rejects the whole turn).
302
+ const requestTools = requestAnthropicTools(tools, chatMsgs, opts);
299
303
  // Build → sanitize (once, inside toAnthropicMessages) → mark. Markers are
300
304
  // applied to the FINAL sanitized array by invariant, so block drops /
301
305
  // inserts / reorders performed by the sanitizer can never move or delete a
302
306
  // marked block. NEVER sanitize again after this (see send path).
303
307
  const anthropicMessages = applyAnthropicCacheMarkers(
304
- toAnthropicMessages(chatMsgs),
308
+ toAnthropicMessages(chatMsgs, requestTools),
305
309
  messageCacheSlots,
306
310
  );
307
311
 
@@ -317,7 +321,6 @@ function buildRequestBody(messages, model, tools, sendOpts) {
317
321
 
318
322
  if (systemBlocks.length) body.system = systemBlocks;
319
323
 
320
- const requestTools = requestAnthropicTools(tools, chatMsgs, opts);
321
324
  if (requestTools.length) {
322
325
  // No cache_control on tools — the systemBase BP already covers the
323
326
  // tools prefix via Anthropic's prompt cache prefix semantics (order:
@@ -145,12 +145,16 @@ export class AnthropicProvider {
145
145
  // Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is
146
146
  // shared with anthropic-oauth — see resolveAnthropicMessageCacheSlots.
147
147
  const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls);
148
+ // Tools are resolved BEFORE the messages: the lowering needs the final
149
+ // tool list to drop tool_reference blocks whose tool no longer ships
150
+ // in this request (otherwise the API rejects the whole turn).
151
+ const requestTools = requestAnthropicTools(tools, chatMsgs, opts);
148
152
  // Build → sanitize (once, inside toAnthropicMessages) → mark. Markers
149
153
  // are applied to the FINAL sanitized array by invariant, so block
150
154
  // drops / inserts / reorders performed by the sanitizer can never move
151
155
  // or delete a marked block. NEVER sanitize again after this.
152
156
  const anthropicMessages = applyAnthropicCacheMarkers(
153
- toAnthropicMessages(chatMsgs),
157
+ toAnthropicMessages(chatMsgs, requestTools),
154
158
  messageCacheSlots,
155
159
  );
156
160
 
@@ -163,7 +167,6 @@ export class AnthropicProvider {
163
167
  applyAnthropicServerFallback(params, useModel, {
164
168
  enabled: this.config?.disableBetaHeaders !== true && opts.serverFallback !== false,
165
169
  });
166
- const requestTools = requestAnthropicTools(tools, chatMsgs, opts);
167
170
  if (requestTools.length) {
168
171
  // No cache_control on tools — the system BP covers tools via
169
172
  // Anthropic prefix semantics (order: tools → system → messages).
@@ -89,7 +89,39 @@ export function resolveAnthropicMessageCacheSlots(systemBlocks, ttls) {
89
89
  // root cause of the sporadic COLD-turn cache miss: pre-sanitize markers landed
90
90
  // on blocks the sanitizer then rewrote, so the provider-visible breakpoint
91
91
  // diverged from the cached one).
92
- export function toAnthropicMessages(messages) {
92
+ // Optional `availableTools`: the exact tool list this request will ship. A
93
+ // tool_reference whose tool is absent from that list makes the API reject the
94
+ // WHOLE request ("Tool reference '<name>' not found in available tools"), and
95
+ // the dangling block lives in the transcript — so once a loaded tool leaves
96
+ // the deferred catalog (feature toggle, provider/model rebuild, disconnected
97
+ // MCP server) every later turn of that session fails identically. Passing the
98
+ // list lets the lowering drop unresolvable references instead. Omitted =>
99
+ // every reference is kept verbatim.
100
+ function anthropicToolNameSet(availableTools) {
101
+ if (!Array.isArray(availableTools)) return null;
102
+ const names = new Set();
103
+ for (const tool of availableTools) {
104
+ const name = typeof tool?.name === 'string' ? tool.name.trim() : '';
105
+ if (name) names.add(name);
106
+ }
107
+ return names;
108
+ }
109
+
110
+ // Replacement content for a tool_result whose references were all dropped.
111
+ // The stored text result (the deferred-load summary) is the natural fallback;
112
+ // an EMPTY tool_result is itself a 400, so a blank result gets a placeholder.
113
+ function toolResultContentWithoutReferences(message, droppedNames) {
114
+ const normalized = normalizeContentForAnthropic(message.content);
115
+ if (typeof normalized === 'string' && normalized.trim()) return normalized;
116
+ if (Array.isArray(normalized) && normalized.length > 0) return normalized;
117
+ return [{
118
+ type: 'text',
119
+ text: `[tool references dropped - no longer available: ${droppedNames.join(', ')}]`,
120
+ }];
121
+ }
122
+
123
+ export function toAnthropicMessages(messages, availableTools) {
124
+ const availableNames = anthropicToolNameSet(availableTools);
93
125
  const result = [];
94
126
  for (let idx = 0; idx < messages.length; idx++) {
95
127
  const m = messages[idx];
@@ -136,12 +168,23 @@ export function toAnthropicMessages(messages) {
136
168
  && Array.isArray(native?.toolReferences)
137
169
  ? native.toolReferences.map((name) => String(name || '').trim()).filter(Boolean)
138
170
  : [];
171
+ // Keep only references this request can actually back with a
172
+ // definition; a reference without one is a hard 400 on every turn
173
+ // that replays it (see anthropicToolNameSet).
174
+ const usableReferences = availableNames
175
+ ? references.filter((name) => availableNames.has(name))
176
+ : references;
177
+ const droppedReferences = usableReferences.length === references.length
178
+ ? []
179
+ : references.filter((name) => !usableReferences.includes(name));
139
180
  const block = {
140
181
  type: 'tool_result',
141
182
  tool_use_id: m.toolCallId || '',
142
- content: references.length
143
- ? references.map((tool_name) => ({ type: 'tool_reference', tool_name }))
144
- : normalizeContentForAnthropic(m.content),
183
+ content: usableReferences.length
184
+ ? usableReferences.map((tool_name) => ({ type: 'tool_reference', tool_name }))
185
+ : (droppedReferences.length
186
+ ? toolResultContentWithoutReferences(m, droppedReferences)
187
+ : normalizeContentForAnthropic(m.content)),
145
188
  ...((m.toolKind === 'error' || m.isError === true) ? { is_error: true } : {}),
146
189
  };
147
190
  if (last?.role === 'user' && Array.isArray(last.content)) {
@@ -27,7 +27,6 @@ import {
27
27
  _intraTurnSig,
28
28
  } from './loop/tool-classify.mjs';
29
29
  import { preDispatchDenyForSession } from './loop/pre-dispatch-deny.mjs';
30
- import { runRecallFastTrackCompact } from './loop/recall-fasttrack.mjs';
31
30
  import { executeTool, _scopedCacheOutcomeForCall, resolveLiveToolCwd } from './loop/tool-exec.mjs';
32
31
 
33
32
  // classifyResultKind is imported from result-classification.mjs at the top of
@@ -239,28 +239,6 @@ export function collectWorkingFileGroups(messages, cap = Number.POSITIVE_INFINIT
239
239
  }, prior, limit, cwd);
240
240
  }
241
241
 
242
- export function collectWorkingFiles(messages, cap = Number.POSITIVE_INFINITY, options = {}) {
243
- const groups = collectWorkingFileGroups(messages, cap, options);
244
- return [...groups.modified, ...groups.referenced].map((entry) => entry.path);
245
- }
246
-
247
- export function stripWorkingFileSections(text) {
248
- const out = [];
249
- let skipping = false;
250
- for (const raw of String(text || '').split('\n')) {
251
- const line = raw.trim();
252
- if (line === '## Working files') {
253
- skipping = true;
254
- continue;
255
- }
256
- if (skipping && (/^##\s+/.test(line) || /^<\/?prior-compacted-context>$/.test(line))) {
257
- skipping = false;
258
- }
259
- if (!skipping) out.push(raw);
260
- }
261
- return out.join('\n').replace(/\n{3,}/g, '\n\n');
262
- }
263
-
264
242
  function indexToolResults(messages) {
265
243
  const map = new Map();
266
244
  for (const m of messages || []) {
@@ -43,8 +43,8 @@ export function isProtectedContextUserMessage(m) {
43
43
  // content prefix (the `<skill>` envelope from buildSkillResultEnvelope) so the
44
44
  // check survives even if the synthetic `meta` field is dropped during a tail
45
45
  // rebuild. It is NOT the human's latest prompt and must be excluded from
46
- // "latest human request" selection (deriveCurrentRequest /
47
- // buildRecallFastTrackQuery). The `meta:'skill'` marker is also honoured.
46
+ // "latest human request" selection (deriveCurrentRequest). The `meta:'skill'`
47
+ // marker is also honoured.
48
48
  export function isInjectedSkillBodyMessage(m) {
49
49
  if (m?.role !== 'user') return false;
50
50
  if (m.meta === 'skill') return true;
@@ -717,13 +717,6 @@ function truncateTailToCap(messages, cap) {
717
717
  return estimateMessagesTokens(sanitized) <= cap ? sanitized : [];
718
718
  }
719
719
 
720
- function splitRecallFitInputs(recallText) {
721
- return {
722
- recall: String(recallText || '').trim(),
723
- prior: '',
724
- };
725
- }
726
-
727
720
  function recallTailStartIndex(live, tail) {
728
721
  if (!tail.length) return live.length;
729
722
  const first = tail[0];
@@ -837,9 +830,9 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
837
830
  head: recallHead,
838
831
  lastTurnStartIdx = recallHead.length,
839
832
  } = selectRecallPreservedTail(live, recallTailOpts);
840
- const recallFit = splitRecallFitInputs(opts.recallText);
833
+ const recallText = String(opts.recallText || '').trim();
841
834
  if (recallHead.length === 0
842
- && !(recallFit.recall || recallFit.prior || opts.allowEmptyRecall === true)) {
835
+ && !(recallText || opts.allowEmptyRecall === true)) {
843
836
  throw new Error('recallFastTrackCompactMessages: no compactable prior history before preserved tail');
844
837
  }
845
838
 
@@ -851,7 +844,7 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
851
844
  }
852
845
  const budgetRaisedBy = Math.max(0, budget - originalBudget);
853
846
 
854
- if (!recallFit.recall && !recallFit.prior && opts.allowEmptyRecall !== true) {
847
+ if (!recallText && opts.allowEmptyRecall !== true) {
855
848
  throw new Error('recallFastTrackCompactMessages: recall text is empty');
856
849
  }
857
850
  const oldHistory = recallHead;
@@ -871,14 +864,14 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
871
864
  ? Math.min(recallRoomUncapped, Math.max(512, recallTokenCap - tailTokens))
872
865
  : recallRoomUncapped;
873
866
  const toolLines = collectToolOutcomeLines(recallHead)
874
- .filter((line) => !recallFit.recall.includes(String(line || '').trim()));
867
+ .filter((line) => !recallText.includes(String(line || '').trim()));
875
868
  const workingFiles = collectWorkingFileGroups(recallHead, undefined, {
876
869
  cwd: opts.cwd,
877
870
  previousSummary: '',
878
871
  now: Date.now(),
879
872
  });
880
873
  const conversationLines = excludeTailFromConversation(
881
- conversationLinesFromMemoryText(recallFit.recall),
874
+ conversationLinesFromMemoryText(recallText),
882
875
  recallTail,
883
876
  );
884
877
  const composedRecall = composeRecallHandoff({
@@ -894,7 +887,6 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
894
887
  fittedRecall,
895
888
  recallRoom,
896
889
  recallMeta,
897
- '',
898
890
  );
899
891
  if (!summaryMessage) {
900
892
  throw new Error(`recallFastTrackCompactMessages: summary cannot fit remaining budget=${recallRoom}`);
@@ -936,20 +928,15 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
936
928
  remainingTokens: budget - mandatoryCost,
937
929
  recallTokenCap: (Number.isFinite(recallTokenCap) && recallTokenCap > 0) ? recallTokenCap : null,
938
930
  recallRoom,
939
- recallChars: recallFit.recall.length,
940
- recallBytes: textByteLength(recallFit.recall),
941
- priorChars: 0,
942
- priorBytes: 0,
931
+ recallChars: recallText.length,
932
+ recallBytes: textByteLength(recallText),
943
933
  summaryMessageChars: summaryContent.length,
944
934
  summaryMessageBytes: textByteLength(summaryContent),
945
- recallEmpty: !recallFit.recall,
946
- priorEmpty: !recallFit.prior,
947
- recallTruncatedInSummary: !!recallFit.recall && !summaryContent.includes(recallFit.recall),
948
- priorTruncatedInSummary: false,
935
+ recallEmpty: !recallText,
936
+ recallTruncatedInSummary: !!recallText && !summaryContent.includes(recallText),
949
937
  tailTruncated: recallTail.some((m) => messageContentHasMarker(m, RECALL_TAIL_TRUNCATION_MARKER) || messageContentHasMarker(m, RECALL_TAIL_SHORT_TRUNCATION_MARKER)),
950
938
  fileReattached: reattach.reattached,
951
939
  tailOptions: recallTailOpts,
952
- previousSummary: false,
953
940
  durationMs: Date.now() - startedAt,
954
941
  };
955
942
  compactDebugLog('recall-fasttrack result', diagnostics);