@retaw106/mmc-oc 2.3.0 → 2.5.0

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 (216) hide show
  1. package/dist/cli.js +12 -1
  2. package/dist/config/schema/magic-context.d.ts +33 -0
  3. package/dist/config/schema/magic-context.d.ts.map +1 -1
  4. package/dist/config-init.js +12 -1
  5. package/dist/{context-wt7g4f8k.js → context-xx09sh1g.js} +1985 -603
  6. package/dist/features/magic-context/memory-maintainer/launcher.d.ts +13 -4
  7. package/dist/features/magic-context/memory-maintainer/launcher.d.ts.map +1 -1
  8. package/dist/features/magic-context/memory-maintainer/manual-commands.d.ts.map +1 -1
  9. package/dist/features/magic-context/memory-maintainer/model-chain.d.ts +47 -0
  10. package/dist/features/magic-context/memory-maintainer/model-chain.d.ts.map +1 -0
  11. package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts +17 -4
  12. package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts.map +1 -1
  13. package/dist/features/magic-context/memory-maintainer/pipeline.d.ts +6 -0
  14. package/dist/features/magic-context/memory-maintainer/pipeline.d.ts.map +1 -1
  15. package/dist/features/magic-context/message-index-async.d.ts +6 -2
  16. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  17. package/dist/features/magic-context/message-index.d.ts +5 -8
  18. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  19. package/dist/features/magic-context/search.d.ts +5 -1
  20. package/dist/features/magic-context/search.d.ts.map +1 -1
  21. package/dist/features/magic-context/storage-db.d.ts +2 -0
  22. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  23. package/dist/features/magic-context/storage-host-instruction-retention.d.ts +4 -0
  24. package/dist/features/magic-context/storage-host-instruction-retention.d.ts.map +1 -0
  25. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  26. package/dist/features/magic-context/storage-meta-shared.d.ts +2 -2
  27. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  28. package/dist/features/magic-context/storage-session-tables.d.ts +9 -1
  29. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  30. package/dist/features/magic-context/storage-tags.d.ts +4 -0
  31. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  32. package/dist/features/magic-context/transform-decision-log.d.ts +57 -2
  33. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts +34 -0
  35. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts.map +1 -0
  36. package/dist/hooks/magic-context/apply-operations.d.ts +3 -1
  37. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/auto-search-hint.d.ts +3 -0
  39. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -2
  43. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -2
  44. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/compartment-runner.d.ts +4 -0
  47. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/compartment-trigger-error.d.ts +11 -0
  49. package/dist/hooks/magic-context/compartment-trigger-error.d.ts.map +1 -0
  50. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  51. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +1 -0
  53. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts +2 -0
  55. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/diagnostic-log-state.d.ts +4 -0
  57. package/dist/hooks/magic-context/diagnostic-log-state.d.ts.map +1 -0
  58. package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
  59. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/file-token-coverage.d.ts +11 -0
  62. package/dist/hooks/magic-context/file-token-coverage.d.ts.map +1 -0
  63. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  64. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/host-served-rows.d.ts +10 -0
  67. package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
  69. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/lkg-slot.d.ts +1 -1
  73. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts +3 -0
  75. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts.map +1 -0
  76. package/dist/hooks/magic-context/pass-outcome.d.ts +2 -0
  77. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts +14 -0
  79. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -0
  80. package/dist/hooks/magic-context/pending-materialization.d.ts +2 -0
  81. package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -1
  82. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -0
  83. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/provider-visible-parts.d.ts +10 -4
  85. package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  87. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +3 -3
  88. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  89. package/dist/hooks/magic-context/render-options.d.ts +19 -0
  90. package/dist/hooks/magic-context/render-options.d.ts.map +1 -0
  91. package/dist/hooks/magic-context/supersession-reclaim.d.ts +5 -3
  92. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/system-date-refresh.d.ts +3 -2
  94. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts +4 -0
  97. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts.map +1 -0
  98. package/dist/hooks/magic-context/tag-content-primitives.d.ts +1 -1
  99. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/tag-messages.d.ts +15 -2
  101. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts +18 -0
  103. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts.map +1 -0
  104. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -4
  105. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  106. package/dist/hooks/magic-context/text-complete.d.ts +1 -1
  107. package/dist/hooks/magic-context/text-complete.d.ts.map +1 -1
  108. package/dist/hooks/magic-context/todo-view.d.ts +2 -2
  109. package/dist/hooks/magic-context/tool-drop-target.d.ts +3 -2
  110. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/tool-reclaim.d.ts +5 -2
  112. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
  114. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -0
  116. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/transform-stage-logger.d.ts +3 -0
  118. package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -1
  119. package/dist/hooks/magic-context/transform.d.ts +4 -9
  120. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  121. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
  122. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
  123. package/dist/{index-kw21z5pe.js → index-0d40b4q8.js} +17119 -16569
  124. package/dist/{index-z2w1eq3y.js → index-1vxffj5j.js} +558 -211
  125. package/dist/{index-z2g20msd.js → index-azbmnekv.js} +4 -4
  126. package/dist/{index-18yrysyj.js → index-bpjjcdy9.js} +1 -1
  127. package/dist/{index-a5mw0xp3.js → index-k25thxq7.js} +1 -1
  128. package/dist/{index-3gj1ak4c.js → index-mjf0p7yq.js} +1 -1
  129. package/dist/{index-czba8tw3.js → index-pte3cfs9.js} +226 -14
  130. package/dist/index.js +2 -2
  131. package/dist/{message-time-backfill-sykevdax.js → message-time-backfill-g9py24yt.js} +1 -1
  132. package/dist/model-resolution-cvyrrcjw.js +8 -0
  133. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  134. package/dist/plugin/subagent-tool-policy.d.ts +4 -0
  135. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -1
  136. package/dist/{read-session-chunk-863d6c06.js → read-session-chunk-eb3fy45y.js} +3 -3
  137. package/dist/{recomp-orchestrator-wrjy3qym.js → recomp-orchestrator-mmpy5cb7.js} +6 -6
  138. package/dist/{send-session-notification-cz6ev088.js → send-session-notification-zpqs213d.js} +3 -3
  139. package/dist/shared/model-suggestion-retry.d.ts +23 -0
  140. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  141. package/dist/shared/prompt-surface-runtime.d.ts +5 -0
  142. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  143. package/dist/shared/reclaim-distance.d.ts +33 -0
  144. package/dist/shared/reclaim-distance.d.ts.map +1 -0
  145. package/dist/shared/rpc-discovery-cleanup.d.ts +3 -0
  146. package/dist/shared/rpc-discovery-cleanup.d.ts.map +1 -0
  147. package/dist/shared/rpc-server.d.ts +2 -0
  148. package/dist/shared/rpc-server.d.ts.map +1 -1
  149. package/dist/shared/search-text.d.ts +8 -0
  150. package/dist/shared/search-text.d.ts.map +1 -0
  151. package/dist/shared/sqlite.d.ts +8 -1
  152. package/dist/shared/sqlite.d.ts.map +1 -1
  153. package/dist/shared/stable-json.d.ts +7 -0
  154. package/dist/shared/stable-json.d.ts.map +1 -1
  155. package/dist/shared/storage-file-mutex.d.ts.map +1 -1
  156. package/dist/shared/system-directive.d.ts +2 -0
  157. package/dist/shared/system-directive.d.ts.map +1 -1
  158. package/dist/shared/tail-hygiene-json.d.ts +22 -0
  159. package/dist/shared/tail-hygiene-json.d.ts.map +1 -0
  160. package/dist/shared/user-facing-codes.d.ts +2 -2
  161. package/dist/v2/fold/native-replay.d.ts +11 -2
  162. package/dist/v2/fold/native-replay.d.ts.map +1 -1
  163. package/dist/v2/fold/policy.d.ts.map +1 -1
  164. package/dist/v2/fold/restore.d.ts.map +1 -1
  165. package/dist/v2/hidden-completion.d.ts +20 -1
  166. package/dist/v2/hidden-completion.d.ts.map +1 -1
  167. package/dist/v2/hooks/context.d.ts +1 -1
  168. package/dist/v2/hooks/context.d.ts.map +1 -1
  169. package/dist/v2/hooks/generate.d.ts +36 -1
  170. package/dist/v2/hooks/generate.d.ts.map +1 -1
  171. package/dist/v2/hooks/hidden-child.d.ts +22 -1
  172. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  173. package/dist/v2/hooks/lkg-system.d.ts +35 -4
  174. package/dist/v2/hooks/lkg-system.d.ts.map +1 -1
  175. package/dist/v2/hooks/payload.d.ts +10 -1
  176. package/dist/v2/hooks/payload.d.ts.map +1 -1
  177. package/dist/v2/hooks/store.d.ts +2 -0
  178. package/dist/v2/hooks/store.d.ts.map +1 -1
  179. package/dist/v2/hooks/types.d.ts +12 -0
  180. package/dist/v2/hooks/types.d.ts.map +1 -1
  181. package/dist/v2/server.js +16272 -13742
  182. package/dist/v2/store-reader.d.ts +38 -1
  183. package/dist/v2/store-reader.d.ts.map +1 -1
  184. package/dist/web/main.js +262 -17
  185. package/dist/{wrapup-orchestrator-bmybc5p5.js → wrapup-orchestrator-jq589pgr.js} +6 -6
  186. package/package.json +1 -1
  187. package/src/config/latch-permanence-guard.test.ts +8 -0
  188. package/src/config/project-security.test.ts +17 -0
  189. package/src/config/schema/magic-context.test.ts +50 -0
  190. package/src/config/schema/magic-context.ts +34 -1
  191. package/src/shared/model-suggestion-retry.test.ts +52 -0
  192. package/src/shared/model-suggestion-retry.ts +13 -4
  193. package/src/shared/prompt-surface-runtime.ts +12 -0
  194. package/src/shared/reclaim-distance.test.ts +111 -0
  195. package/src/shared/reclaim-distance.ts +91 -0
  196. package/src/shared/root-async-context.probe.mjs +36 -0
  197. package/src/shared/root-async-context.test.ts +49 -0
  198. package/src/shared/rpc-discovery-cleanup.test.ts +125 -0
  199. package/src/shared/rpc-discovery-cleanup.ts +57 -0
  200. package/src/shared/rpc-server.ts +36 -13
  201. package/src/shared/search-text.test.ts +30 -0
  202. package/src/shared/search-text.ts +62 -0
  203. package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
  204. package/src/shared/sqlite-foreground-wait.test.ts +237 -1
  205. package/src/shared/sqlite-turn-deadline.test.ts +286 -0
  206. package/src/shared/sqlite.ts +292 -23
  207. package/src/shared/stable-json.ts +56 -14
  208. package/src/shared/storage-file-mutex.test.ts +51 -2
  209. package/src/shared/storage-file-mutex.ts +11 -1
  210. package/src/shared/system-directive.test.ts +37 -0
  211. package/src/shared/system-directive.ts +19 -1
  212. package/src/shared/tag-transcript.ts +16 -4
  213. package/src/shared/tail-hygiene-json.test.ts +117 -0
  214. package/src/shared/tail-hygiene-json.ts +217 -0
  215. package/src/shared/user-facing-codes.ts +2 -2
  216. package/dist/model-resolution-wazv26n0.js +0 -6
@@ -7,7 +7,7 @@ import {
7
7
  } from "./index-x37vg474.js";
8
8
  import {
9
9
  getTagIdentityWriteGeneration
10
- } from "./index-czba8tw3.js";
10
+ } from "./index-pte3cfs9.js";
11
11
  import {
12
12
  getHarness,
13
13
  sessionLog
@@ -28,7 +28,7 @@ import {
28
28
  withReadOnlySessionDb,
29
29
  getRawSessionMessageCountFromDb,
30
30
  getMessageTimesFromOpenCodeDb
31
- } from "./index-18yrysyj.js";
31
+ } from "./index-bpjjcdy9.js";
32
32
 
33
33
  // src/shared/protected-tools-policy.ts
34
34
  var DEFAULT_PROTECTED_TOOLS = {
@@ -102,7 +102,27 @@ function isSystemDirective(text) {
102
102
  return text.trimStart().startsWith(SYSTEM_DIRECTIVE_PREFIX);
103
103
  }
104
104
  function removeSystemReminders(text) {
105
- return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
105
+ return removeNestedBlocks(text, ["system-reminder"]).trim();
106
+ }
107
+ function removeNestedBlocks(text, names) {
108
+ const tags = new RegExp(`<(/?)(${names.join("|")})(?:\\s[^<>]*?)?\\s*(/?)>`, "gi");
109
+ const stack = [];
110
+ let end = 0;
111
+ let result = "";
112
+ for (const match of text.matchAll(tags)) {
113
+ if (stack.length === 0)
114
+ result += text.slice(end, match.index);
115
+ const name = match[2].toLowerCase();
116
+ if (match[1]) {
117
+ if (stack[stack.length - 1] === name)
118
+ stack.pop();
119
+ } else if (!match[3])
120
+ stack.push(name);
121
+ end = match.index + match[0].length;
122
+ }
123
+ if (stack.length === 0)
124
+ result += text.slice(end);
125
+ return result;
106
126
  }
107
127
 
108
128
  // src/hooks/magic-context/token-count-exact.ts
@@ -807,13 +827,16 @@ function stripDanglingTagNotationGlobally(value) {
807
827
  function stripTagSectionCharacters(value) {
808
828
  return value.replace(STRAY_SECTION_CHAR_REGEX, "");
809
829
  }
810
- function stripPersistedAssistantText(value) {
830
+ function stripPersistedAssistantText(value, acceptsEmpty = true) {
831
+ if (!acceptsEmpty && !value.includes("§") && !value.trim())
832
+ return value;
811
833
  let text = stripWellFormedLeadingTagPrefix(value);
812
834
  text = stripCompleteTagPairsGlobally(text);
813
835
  text = stripMalformedTagNotationGlobally(text);
814
836
  text = stripDanglingTagNotationGlobally(text);
815
837
  text = stripTagSectionCharacters(text);
816
- return text.trim();
838
+ const stripped = text.trim();
839
+ return !acceptsEmpty && value.trim().length > 0 && stripped.length === 0 ? value : stripped;
817
840
  }
818
841
  function byteSize(value) {
819
842
  return encoder.encode(value).length;
@@ -847,6 +870,21 @@ function isThinkingPart(part) {
847
870
  return candidate.type === "thinking" || candidate.type === "reasoning";
848
871
  }
849
872
 
873
+ // src/hooks/magic-context/tail-hygiene-output-count.ts
874
+ var CURRENT_OUTPUT_COUNT = Symbol.for("magic-context.current-reclaimable-tool-output-count");
875
+ function countReclaimableToolOutputs(parts) {
876
+ return parts.filter((part) => part.kind === "toolOutput" && part.uTokens > 0).length;
877
+ }
878
+ function rememberCurrentToolOutputCount(baseline, measurement) {
879
+ return Object.assign(baseline, {
880
+ [CURRENT_OUTPUT_COUNT]: countReclaimableToolOutputs(measurement.parts)
881
+ });
882
+ }
883
+ function currentReclaimableToolOutputCount(baseline) {
884
+ if (!baseline || !Object.hasOwn(baseline, CURRENT_OUTPUT_COUNT))
885
+ return 0;
886
+ return baseline[CURRENT_OUTPUT_COUNT];
887
+ }
850
888
  // src/shared/record-type-guard.ts
851
889
  function isRecord(value) {
852
890
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -855,32 +893,32 @@ function isRecord(value) {
855
893
  // src/shared/stable-json.ts
856
894
  function stableStringify(value, seen = new WeakSet) {
857
895
  const pieces = [];
858
- writeStable(value, seen, pieces);
896
+ writeStable(value, seen, (piece) => pieces.push(piece));
859
897
  return pieces.join("");
860
898
  }
861
- function writeStable(value, seen, pieces) {
899
+ function writeStable(value, seen, write) {
862
900
  if (value === undefined) {
863
- pieces.push("undefined");
901
+ write("undefined");
864
902
  return;
865
903
  }
866
904
  if (value === null || typeof value !== "object") {
867
- pieces.push(JSON.stringify(value) ?? String(value));
905
+ write(JSON.stringify(value) ?? String(value));
868
906
  return;
869
907
  }
870
908
  if (seen.has(value)) {
871
- pieces.push('"[Circular]"');
909
+ write('"[Circular]"');
872
910
  return;
873
911
  }
874
912
  seen.add(value);
875
913
  if (Array.isArray(value)) {
876
- pieces.push("[");
914
+ write("[");
877
915
  for (let index = 0;index < value.length; index += 1) {
878
916
  if (index > 0)
879
- pieces.push(",");
917
+ write(",");
880
918
  if (index in value)
881
- writeStable(value[index], seen, pieces);
919
+ writeStable(value[index], seen, write);
882
920
  }
883
- pieces.push("]");
921
+ write("]");
884
922
  return;
885
923
  }
886
924
  const entries = Object.entries(value).sort(([a], [b]) => {
@@ -890,14 +928,34 @@ function writeStable(value, seen, pieces) {
890
928
  return 1;
891
929
  return 0;
892
930
  });
893
- pieces.push("{");
931
+ if (entries.length > 0 && entries.length <= 16 && entries.every(([key, child]) => key.length <= 4096 && !/^(0|[1-9]\d*)$/.test(key) && (child === null || typeof child === "number" || typeof child === "boolean" || typeof child === "string" && child.length <= 4096))) {
932
+ write(JSON.stringify(Object.fromEntries(entries)));
933
+ return;
934
+ }
935
+ write("{");
894
936
  entries.forEach(([key, child], index) => {
895
937
  if (index > 0)
896
- pieces.push(",");
897
- pieces.push(JSON.stringify(key), ":");
898
- writeStable(child, seen, pieces);
938
+ write(",");
939
+ write(JSON.stringify(key));
940
+ write(":");
941
+ writeStable(child, seen, write);
899
942
  });
900
- pieces.push("}");
943
+ write("}");
944
+ }
945
+ function stableStringifyHash(value, prefix = "") {
946
+ const sink = jsonHashSink(prefix);
947
+ writeStable(value, new WeakSet, sink.write);
948
+ return sink.digest();
949
+ }
950
+ function jsonHashSink(prefix = "") {
951
+ let hash = 2166136261;
952
+ const write = (piece) => {
953
+ for (let index = 0;index < piece.length; index++) {
954
+ hash = Math.imul(hash ^ piece.charCodeAt(index), 16777619);
955
+ }
956
+ };
957
+ write(prefix);
958
+ return { write, digest: () => (hash >>> 0).toString(16).padStart(8, "0") };
901
959
  }
902
960
 
903
961
  // src/shared/tag-owner-id.ts
@@ -914,6 +972,127 @@ function contentTagOwnerMessageId(contentId) {
914
972
  return contentId;
915
973
  }
916
974
 
975
+ // src/shared/tail-hygiene-json.ts
976
+ var MAX_MEMO_BYTES = 64 * 1024 * 1024;
977
+ var MAX_MEMO_ENTRIES = 1e4;
978
+
979
+ class TailHygieneJsonMemo {
980
+ entries = new Map;
981
+ bytes = 0;
982
+ passText = new WeakMap;
983
+ passHash = new WeakMap;
984
+ beginPass() {
985
+ this.passText = new WeakMap;
986
+ this.passHash = new WeakMap;
987
+ }
988
+ get(key, value, compute, fingerprint = false) {
989
+ const pass = fingerprint ? this.passHash : this.passText;
990
+ const object = value !== null && typeof value === "object" ? value : undefined;
991
+ const local = object ? pass.get(object) : undefined;
992
+ if (local !== undefined)
993
+ return local;
994
+ const previous = this.entries.get(key);
995
+ if (previous && sameJson(previous.snapshot, value)) {
996
+ if (object)
997
+ pass.set(object, previous.result);
998
+ return previous.result;
999
+ }
1000
+ const result = compute();
1001
+ if (previous) {
1002
+ this.bytes -= previous.bytes;
1003
+ this.entries.delete(key);
1004
+ }
1005
+ try {
1006
+ const copy = copyJson(value);
1007
+ const bytes = copy.bytes + (key.length + result.length) * 2;
1008
+ if (bytes <= MAX_MEMO_BYTES) {
1009
+ this.entries.set(key, { snapshot: copy.value, result, bytes });
1010
+ this.bytes += bytes;
1011
+ if (object)
1012
+ pass.set(object, result);
1013
+ }
1014
+ } catch {}
1015
+ while (this.bytes > MAX_MEMO_BYTES || this.entries.size > MAX_MEMO_ENTRIES) {
1016
+ const oldest = this.entries.entries().next().value;
1017
+ if (!oldest)
1018
+ break;
1019
+ this.bytes -= oldest[1].bytes;
1020
+ this.entries.delete(oldest[0]);
1021
+ }
1022
+ return result;
1023
+ }
1024
+ }
1025
+ function copyJson(value) {
1026
+ const seen = new Map;
1027
+ let bytes = 0;
1028
+ const copy = (current) => {
1029
+ bytes += 16;
1030
+ if (typeof current === "string")
1031
+ bytes += current.length * 2;
1032
+ if (bytes > MAX_MEMO_BYTES)
1033
+ throw new Error("memo capacity");
1034
+ if (current === null || typeof current !== "object") {
1035
+ if (["function", "symbol", "bigint"].includes(typeof current))
1036
+ throw new Error("exotic");
1037
+ return current;
1038
+ }
1039
+ if (seen.has(current))
1040
+ return seen.get(current);
1041
+ const prototype = Object.getPrototypeOf(current);
1042
+ if (!Array.isArray(current) && prototype !== Object.prototype && prototype !== null)
1043
+ throw new Error("exotic");
1044
+ const result = Array.isArray(current) ? new Array(current.length) : Object.create(prototype);
1045
+ seen.set(current, result);
1046
+ for (const key of Object.keys(current)) {
1047
+ const descriptor = Object.getOwnPropertyDescriptor(current, key);
1048
+ if (!descriptor || !("value" in descriptor))
1049
+ throw new Error("accessor");
1050
+ bytes += key.length * 2 + 16;
1051
+ if (key === "__proto__") {
1052
+ Object.defineProperty(result, key, {
1053
+ value: copy(descriptor.value),
1054
+ enumerable: true,
1055
+ writable: true,
1056
+ configurable: true
1057
+ });
1058
+ } else
1059
+ result[key] = copy(descriptor.value);
1060
+ }
1061
+ return result;
1062
+ };
1063
+ return { value: copy(value), bytes };
1064
+ }
1065
+ function sameJson(before, after) {
1066
+ const forward = new Map;
1067
+ const reverse = new Set;
1068
+ const same = (left, right) => {
1069
+ if (left === null || right === null || typeof left !== "object" || typeof right !== "object")
1070
+ return Object.is(left, right);
1071
+ if (forward.has(left))
1072
+ return forward.get(left) === right;
1073
+ if (reverse.has(right) || Object.getPrototypeOf(left) !== Object.getPrototypeOf(right))
1074
+ return false;
1075
+ forward.set(left, right);
1076
+ reverse.add(right);
1077
+ if (Array.isArray(left) && (!Array.isArray(right) || left.length !== right.length))
1078
+ return false;
1079
+ const keys = Object.keys(left);
1080
+ const otherKeys = Object.keys(right);
1081
+ if (keys.length !== otherKeys.length)
1082
+ return false;
1083
+ for (let index = 0;index < keys.length; index++) {
1084
+ const key = keys[index];
1085
+ if (key !== otherKeys[index])
1086
+ return false;
1087
+ const descriptor = Object.getOwnPropertyDescriptor(right, key);
1088
+ if (!descriptor || !("value" in descriptor) || !same(left[key], descriptor.value))
1089
+ return false;
1090
+ }
1091
+ return true;
1092
+ };
1093
+ return same(before, after);
1094
+ }
1095
+
917
1096
  // src/hooks/magic-context/image-token-estimate.ts
918
1097
  var IMAGE_TOKEN_DIVISOR = 750;
919
1098
  var IMAGE_FALLBACK_TOKENS = 1200;
@@ -1106,6 +1285,151 @@ function readUint32BE(b, offset) {
1106
1285
  return (b[offset] << 24 | b[offset + 1] << 16 | b[offset + 2] << 8 | b[offset + 3]) >>> 0;
1107
1286
  }
1108
1287
 
1288
+ // src/hooks/magic-context/provider-visible-parts.ts
1289
+ function isRecord2(value) {
1290
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1291
+ }
1292
+ var KEPT_TOOL_STATE_FIELDS = new Set([
1293
+ "status",
1294
+ "input",
1295
+ "output",
1296
+ "error",
1297
+ "attachments",
1298
+ "content"
1299
+ ]);
1300
+ var KEPT_TOOL_STATE_TIME_FIELD = "compacted";
1301
+ function tailProviderVisibleToolState(state, openCode1) {
1302
+ const view = {};
1303
+ for (const key of Object.keys(state)) {
1304
+ if (tailToolStateFieldIsKept(key, openCode1)) {
1305
+ view[key] = state[key];
1306
+ } else if (key === "time" && openCode1) {
1307
+ const value = state.time;
1308
+ if (isRecord2(value)) {
1309
+ view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
1310
+ }
1311
+ } else if (key === "metadata" && openCode1 && state.status === "error") {
1312
+ const metadata = state.metadata;
1313
+ if (isRecord2(metadata) && metadata.interrupted === true) {
1314
+ const output = metadata.output;
1315
+ if (typeof output === "string")
1316
+ view.metadata = { interrupted: true, output };
1317
+ }
1318
+ }
1319
+ }
1320
+ return view;
1321
+ }
1322
+ function tailToolStateFieldIsKept(key, openCode1) {
1323
+ return KEPT_TOOL_STATE_FIELDS.has(key) && (key !== "content" || !openCode1);
1324
+ }
1325
+ function tailToolStateIsReduced(state, openCode1) {
1326
+ for (const key of Object.keys(state)) {
1327
+ if (tailToolStateFieldIsKept(key, openCode1))
1328
+ continue;
1329
+ return false;
1330
+ }
1331
+ return true;
1332
+ }
1333
+ function providerVisiblePart(part) {
1334
+ if (!isRecord2(part) || part.type !== "tool" || !isRecord2(part.state))
1335
+ return part;
1336
+ if (toolStateIsReduced(part.state))
1337
+ return part;
1338
+ return { ...part, state: providerVisibleToolState(part.state) };
1339
+ }
1340
+ function providerVisiblePartForTailHygiene(part) {
1341
+ return providerVisiblePartForHost(part, true);
1342
+ }
1343
+ function providerVisiblePartForOpenCode2(part) {
1344
+ return providerVisiblePartForHost(part, false);
1345
+ }
1346
+ function providerVisiblePartForHost(part, openCode1) {
1347
+ if (!isRecord2(part))
1348
+ return part;
1349
+ if (part.type !== "tool") {
1350
+ if (!Object.hasOwn(part, "state"))
1351
+ return part;
1352
+ const view = {};
1353
+ for (const key of Object.keys(part)) {
1354
+ if (key !== "state")
1355
+ view[key] = part[key];
1356
+ }
1357
+ return view;
1358
+ }
1359
+ if (!isRecord2(part.state))
1360
+ return part;
1361
+ if (tailToolStateIsReduced(part.state, openCode1))
1362
+ return part;
1363
+ return { ...part, state: tailProviderVisibleToolState(part.state, openCode1) };
1364
+ }
1365
+ var KEPT_ERROR_METADATA_FIELDS = ["interrupted", "output"];
1366
+ function providerVisibleToolState(state) {
1367
+ const view = {};
1368
+ for (const key of Object.keys(state)) {
1369
+ const value = state[key];
1370
+ if (KEPT_TOOL_STATE_FIELDS.has(key)) {
1371
+ view[key] = value;
1372
+ } else if (key === "time" && isRecord2(value)) {
1373
+ view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
1374
+ } else if (key === "metadata" && state.status === "error" && isRecord2(value)) {
1375
+ const kept = {};
1376
+ for (const field of KEPT_ERROR_METADATA_FIELDS) {
1377
+ if (Object.hasOwn(value, field))
1378
+ kept[field] = value[field];
1379
+ }
1380
+ view.metadata = kept;
1381
+ }
1382
+ }
1383
+ return view;
1384
+ }
1385
+ function toolStateIsReduced(state) {
1386
+ for (const key of Object.keys(state)) {
1387
+ if (KEPT_TOOL_STATE_FIELDS.has(key))
1388
+ continue;
1389
+ const value = state[key];
1390
+ if (key === "time" && isRecord2(value)) {
1391
+ const keys = Object.keys(value);
1392
+ if (keys.length === 0)
1393
+ continue;
1394
+ if (keys.length === 1 && keys[0] === KEPT_TOOL_STATE_TIME_FIELD)
1395
+ continue;
1396
+ return false;
1397
+ }
1398
+ if (key === "metadata" && state.status === "error" && isRecord2(value)) {
1399
+ const extra = Object.keys(value).some((field) => !KEPT_ERROR_METADATA_FIELDS.includes(field));
1400
+ if (!extra)
1401
+ continue;
1402
+ }
1403
+ return false;
1404
+ }
1405
+ return true;
1406
+ }
1407
+ function providerVisibleMessage(message) {
1408
+ return projectMessage(message, providerVisiblePart);
1409
+ }
1410
+ function providerVisibleMessageForTailHygiene(message) {
1411
+ return projectMessage(message, providerVisiblePartForTailHygiene);
1412
+ }
1413
+ function providerVisibleMessageForOpenCode2(message) {
1414
+ return projectMessage(message, providerVisiblePartForOpenCode2);
1415
+ }
1416
+ function projectMessage(message, projectPart) {
1417
+ if (!isRecord2(message) || !Array.isArray(message.parts))
1418
+ return message;
1419
+ let parts;
1420
+ for (let index = 0;index < message.parts.length; index += 1) {
1421
+ const part = message.parts[index];
1422
+ const view = projectPart(part);
1423
+ if (view !== part) {
1424
+ parts ??= message.parts.slice(0, index);
1425
+ parts.push(view);
1426
+ } else if (parts) {
1427
+ parts.push(part);
1428
+ }
1429
+ }
1430
+ return parts ? { ...message, parts } : message;
1431
+ }
1432
+
1109
1433
  // src/hooks/magic-context/todo-view.ts
1110
1434
  import { createHash } from "node:crypto";
1111
1435
  var TODO_STATUS_PENDING = "pending";
@@ -1223,7 +1547,7 @@ function isTodoItem(value) {
1223
1547
 
1224
1548
  // src/hooks/magic-context/tail-hygiene-walk.ts
1225
1549
  var MAX_CONTENT_MEMO_ENTRIES = 1e5;
1226
- var MAX_CONTENT_MEMO_BYTES = 64 * 1024 * 1024;
1550
+ var MAX_CONTENT_MEMO_BYTES = 256 * 1024 * 1024;
1227
1551
  var contentMemo = new Map;
1228
1552
  var contentMemoOrder = new Set;
1229
1553
  var contentMemoBytes = 0;
@@ -1407,41 +1731,46 @@ function stripChannel1ReminderSpans(output) {
1407
1731
  return stripped;
1408
1732
  }
1409
1733
  function isDropSentinel(content) {
1410
- const stripped = content.trimStart().replace(TAG_PREFIX, "").trimStart().toLowerCase();
1411
- return DROP_PREFIXES.some((prefix) => stripped.startsWith(prefix));
1412
- }
1413
- function toolOutputText(part) {
1734
+ let stripped = content.trimStart();
1735
+ const tag = TAG_PREFIX.exec(stripped);
1736
+ if (tag)
1737
+ stripped = stripped.slice(tag[0].length).trimStart();
1738
+ return DROP_PREFIXES.some((prefix) => stripped.slice(0, prefix.length).toLowerCase() === prefix);
1739
+ }
1740
+ function toolOutputText(part, key) {
1741
+ const serialize = (value) => partJsonMemo.get(key, value, () => safeStableStringify(value));
1414
1742
  if (part.type === "tool") {
1415
1743
  const state = isRecord(part.state) ? part.state : null;
1416
1744
  if (!state)
1417
1745
  return null;
1418
1746
  if (state.output !== undefined)
1419
- return safeStableStringify(state.output);
1747
+ return serialize(state.output);
1420
1748
  if (state.error !== undefined)
1421
- return safeStableStringify(state.error);
1749
+ return serialize(state.error);
1422
1750
  if (state.result !== undefined)
1423
- return safeStableStringify(state.result);
1751
+ return serialize(state.result);
1424
1752
  return null;
1425
1753
  }
1426
1754
  if (part.type === "tool_result") {
1427
1755
  const value = part.content ?? part.output ?? part.result;
1428
- return value === undefined ? null : safeStableStringify(value);
1756
+ return value === undefined ? null : serialize(value);
1429
1757
  }
1430
1758
  return null;
1431
1759
  }
1432
- function toolInputText(part) {
1760
+ function toolInputText(part, key) {
1761
+ const serialize = (value) => partJsonMemo.get(key, value, () => safeStableStringify(value));
1433
1762
  if (part.type === "tool") {
1434
1763
  const state = isRecord(part.state) ? part.state : null;
1435
1764
  if (!state || state.input === undefined)
1436
1765
  return null;
1437
- return safeStableStringify(state.input);
1766
+ return serialize(state.input);
1438
1767
  }
1439
1768
  if (part.type === "tool-invocation") {
1440
1769
  const value = part.args ?? part.input;
1441
- return value === undefined ? null : safeStableStringify(value);
1770
+ return value === undefined ? null : serialize(value);
1442
1771
  }
1443
1772
  if (part.type === "tool_use") {
1444
- return part.input === undefined ? null : safeStableStringify(part.input);
1773
+ return part.input === undefined ? null : serialize(part.input);
1445
1774
  }
1446
1775
  return null;
1447
1776
  }
@@ -1452,8 +1781,8 @@ function messageIdForTag(tag) {
1452
1781
  }
1453
1782
  function resolveProtectedTagNumbers(tags, protectedTagNumbersInput, protectedToolTags) {
1454
1783
  const protectedNumbers = new Set(protectedTagNumbersInput);
1455
- const protectedExemplars = protectedToolTags ?? protectedToolTagNumbers(tags);
1456
- for (const tagNumber of protectedExemplars)
1784
+ const protectedCtxReduceTags = protectedToolTags ?? protectedToolTagNumbers(tags);
1785
+ for (const tagNumber of protectedCtxReduceTags)
1457
1786
  protectedNumbers.add(tagNumber);
1458
1787
  return protectedNumbers;
1459
1788
  }
@@ -1568,17 +1897,28 @@ function snapshot(args) {
1568
1897
  queuedForDrop
1569
1898
  };
1570
1899
  }
1900
+ var partJsonMemo = new TailHygieneJsonMemo;
1571
1901
  function excludedSnapshot(key, part) {
1572
- const content = safeStableStringify(part);
1573
- return snapshot({
1902
+ const contentHash = partJsonMemo.get(key, part, () => {
1903
+ if (part === null || part === undefined || typeof part === "string")
1904
+ return memoizedContent("excluded", safeStableStringify(part)).hash;
1905
+ try {
1906
+ return stableStringifyHash(part, "excluded\x00");
1907
+ } catch {
1908
+ return memoizedContent("excluded", String(part)).hash;
1909
+ }
1910
+ }, true);
1911
+ return {
1574
1912
  key,
1913
+ contentHash,
1575
1914
  kind: "excluded",
1576
- content,
1577
1915
  tokens: 0,
1578
- tag: undefined,
1579
- protectedNumbers: new Set,
1580
- pendingDropTagNumbers: new Set
1581
- });
1916
+ uTokens: 0,
1917
+ tagNumber: null,
1918
+ tagStatus: null,
1919
+ protected: false,
1920
+ queuedForDrop: false
1921
+ };
1582
1922
  }
1583
1923
  function fileContentAndTokens(part) {
1584
1924
  const mime = typeof part.mime === "string" ? part.mime : "";
@@ -1618,12 +1958,12 @@ function structuralSize(value) {
1618
1958
  }
1619
1959
  return 0;
1620
1960
  }
1621
- function tailHygieneStructuralSignature(messages) {
1961
+ function tailHygieneStructuralSignature(messages, opencode2 = false) {
1622
1962
  const partCounts = [];
1623
1963
  let totalBytes = 0;
1624
1964
  for (const message of messages) {
1625
1965
  partCounts.push(message.parts.length);
1626
- totalBytes += structuralSize(message);
1966
+ totalBytes += structuralSize(opencode2 ? providerVisibleMessageForOpenCode2(message) : providerVisibleMessageForTailHygiene(message));
1627
1967
  }
1628
1968
  return { messageCount: messages.length, partCounts, totalBytes };
1629
1969
  }
@@ -1637,10 +1977,22 @@ function measureTailHygiene(input) {
1637
1977
  return measureWithReplay(input);
1638
1978
  }
1639
1979
  function measureWithReplay(input, replay) {
1980
+ partJsonMemo.beginPass();
1981
+ const projectPart = input.opencode2 ? providerVisiblePartForOpenCode2 : providerVisiblePartForTailHygiene;
1982
+ const views = new WeakMap;
1983
+ const excluded = (key, part) => {
1984
+ let view = part !== null && typeof part === "object" ? views.get(part) : undefined;
1985
+ if (view === undefined) {
1986
+ view = projectPart(part);
1987
+ if (part !== null && typeof part === "object")
1988
+ views.set(part, view);
1989
+ }
1990
+ return excludedSnapshot(key, view);
1991
+ };
1640
1992
  const pendingDropTagNumbers = input.pendingDropTagNumbers ?? new Set;
1641
1993
  const unchanged = input.messages.map((message, index) => {
1642
1994
  const previous = replay?.messages[index];
1643
- return previous !== undefined && sameReplayMessage(previous, message);
1995
+ return previous !== undefined && sameReplayMessage(previous, message, projectPart);
1644
1996
  });
1645
1997
  const toolIdentities = collectToolPartIdentities(input.messages);
1646
1998
  const attribution = buildTagAttribution({
@@ -1650,7 +2002,7 @@ function measureWithReplay(input, replay) {
1650
2002
  protectedTagNumbers: input.protectedTagNumbers,
1651
2003
  protectedToolTags: input.protectedToolTags
1652
2004
  });
1653
- const toolOutputs = input.messages.map((message, index) => message.parts.map((part, partIndex) => unchanged[index] ? replay?.measured.toolOutputs[index][partIndex] ?? null : isRecord(part) ? toolOutputText(part) : null));
2005
+ const toolOutputs = input.messages.map((message, index) => message.parts.map((part, partIndex) => unchanged[index] ? replay?.measured.toolOutputs[index][partIndex] ?? null : isRecord(part) ? toolOutputText(part, `${messageIdentity(message, index)}\x00${partIndex}\x00output`) : null));
1654
2006
  const outputByPart = new Map;
1655
2007
  input.messages.forEach((message, index) => {
1656
2008
  message.parts.forEach((part, partIndex) => {
@@ -1716,19 +2068,19 @@ function measureWithReplay(input, replay) {
1716
2068
  const part = message.parts[partIndex];
1717
2069
  const key = `${messageKey}\x00${partIndex}`;
1718
2070
  if (messageSynthetic || isSyntheticPart(part) || !isRecord(part)) {
1719
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2071
+ parts.push(excluded(`${key}\x00excluded`, part));
1720
2072
  continue;
1721
2073
  }
1722
2074
  const type = typeof part.type === "string" ? part.type : "";
1723
2075
  if (type === "reasoning" || type === "thinking" || type === "redacted_thinking" || type === "signature") {
1724
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2076
+ parts.push(excluded(`${key}\x00excluded`, part));
1725
2077
  continue;
1726
2078
  }
1727
2079
  if (type === "text") {
1728
2080
  const rawContent = firstString(part, ["text", "content"]);
1729
2081
  const content = rawContent === null ? null : stripChannel1ReminderSpans(rawContent);
1730
2082
  if (!content || isDropSentinel(content)) {
1731
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2083
+ parts.push(excluded(`${key}\x00excluded`, part));
1732
2084
  continue;
1733
2085
  }
1734
2086
  const tokens = memoizedTokens("text", content);
@@ -1750,7 +2102,7 @@ function measureWithReplay(input, replay) {
1750
2102
  if (type === "file" || type.includes("image") || type === "source") {
1751
2103
  const file = fileContentAndTokens(part);
1752
2104
  if (!file.content || isDropSentinel(file.content)) {
1753
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2105
+ parts.push(excluded(`${key}\x00excluded`, part));
1754
2106
  continue;
1755
2107
  }
1756
2108
  const tag = attribution.messageTags.get(`${message.info.id}:file${partIndex}`);
@@ -1772,11 +2124,11 @@ function measureWithReplay(input, replay) {
1772
2124
  if (toolIdentity) {
1773
2125
  const ownerKey = `${toolIdentity.ownerMessageId}\x00${toolIdentity.callId}`;
1774
2126
  if (droppedToolOwners.has(ownerKey)) {
1775
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2127
+ parts.push(excluded(`${key}\x00excluded`, part));
1776
2128
  continue;
1777
2129
  }
1778
2130
  const tag = attribution.toolTagsByPart.get(part);
1779
- const inputText = toolInputText(part);
2131
+ const inputText = toolInputText(part, `${key}\x00input`);
1780
2132
  if (inputText !== null) {
1781
2133
  const tokens = memoizedTokens("toolInput", inputText);
1782
2134
  const measured = snapshot({
@@ -1796,7 +2148,7 @@ function measureWithReplay(input, replay) {
1796
2148
  if (rawOutput !== null) {
1797
2149
  const output = stripChannel1ReminderSpans(rawOutput);
1798
2150
  if (isDropSentinel(output)) {
1799
- parts.push(excludedSnapshot(`${key}\x00excludedOutput`, output));
2151
+ parts.push(excluded(`${key}\x00excludedOutput`, output));
1800
2152
  } else {
1801
2153
  const tokens = memoizedTokens("toolOutput", output) + (part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0);
1802
2154
  const measured = snapshot({
@@ -1814,11 +2166,11 @@ function measureWithReplay(input, replay) {
1814
2166
  }
1815
2167
  }
1816
2168
  if (inputText === null && rawOutput === null) {
1817
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2169
+ parts.push(excluded(`${key}\x00excluded`, part));
1818
2170
  }
1819
2171
  continue;
1820
2172
  }
1821
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2173
+ parts.push(excluded(`${key}\x00excluded`, part));
1822
2174
  }
1823
2175
  }
1824
2176
  return {
@@ -1959,16 +2311,19 @@ function sameNumbers(before, after) {
1959
2311
  return false;
1960
2312
  return true;
1961
2313
  }
1962
- function sameReplayMessage(left, right) {
1963
- return left.info.id === right.info.id && left.info.role === right.info.role && left.info.summary === right.info.summary && sameReplayValue(left.parts, right.parts);
2314
+ function sameReplayMessage(left, right, projectPart = providerVisiblePartForTailHygiene) {
2315
+ return left.info.id === right.info.id && left.info.role === right.info.role && left.info.summary === right.info.summary && sameReplayValue(left.parts, right.parts.map(projectPart));
2316
+ }
2317
+ function replaySnapshotParts(parts, projectPart = providerVisiblePartForTailHygiene) {
2318
+ return copyReplayValue(parts.map(projectPart));
1964
2319
  }
1965
- function sameReplayMessages(before, after) {
2320
+ function sameReplayMessages(before, after, projectPart = providerVisiblePartForTailHygiene) {
1966
2321
  if (before.length !== after.length)
1967
2322
  return false;
1968
2323
  for (let index = 0;index < before.length; index += 1) {
1969
2324
  const left = before[index];
1970
2325
  const right = after[index];
1971
- if (!sameReplayMessage(left, right))
2326
+ if (!sameReplayMessage(left, right, projectPart))
1972
2327
  return false;
1973
2328
  }
1974
2329
  return true;
@@ -2027,8 +2382,10 @@ function refreshTailHygieneBaseline(input) {
2027
2382
  protectedTagNumbers: new Set([...input.protectedTagNumbers, ...protectedToolTags])
2028
2383
  };
2029
2384
  const pendingDropTagNumbers = input.pendingDropTagNumbers ?? new Set;
2030
- const cached = input.previous ? baselineMeasurementMemo.get(input.previous.baselineParts) : undefined;
2031
- const hit = !input.cacheBusting && cached && sameReplayMessages(cached.messages, input.messages) && sameReplayValue(cached.tags, input.tags) && sameNumbers(cached.protectedTagNumbers, input.protectedTagNumbers) && sameNumbers(cached.pendingDropTagNumbers, pendingDropTagNumbers);
2385
+ const priorMemo = input.previous ? baselineMeasurementMemo.get(input.previous.baselineParts) : undefined;
2386
+ const cached = priorMemo?.opencode2 === !!input.opencode2 ? priorMemo : undefined;
2387
+ const projectPart = input.opencode2 ? providerVisiblePartForOpenCode2 : providerVisiblePartForTailHygiene;
2388
+ const hit = !input.cacheBusting && cached && sameReplayMessages(cached.messages, input.messages, projectPart) && sameReplayValue(cached.tags, input.tags) && sameNumbers(cached.protectedTagNumbers, input.protectedTagNumbers) && sameNumbers(cached.pendingDropTagNumbers, pendingDropTagNumbers);
2032
2389
  const rawMeasured = hit ? cached.measured : measureWithReplay(input, cached);
2033
2390
  const frozenCalibration = !input.cacheBusting && input.previous ? {
2034
2391
  toolsRatio: input.previous.toolsRatio,
@@ -2048,19 +2405,20 @@ function refreshTailHygieneBaseline(input) {
2048
2405
  })
2049
2406
  };
2050
2407
  const memo = hit ? cached : {
2051
- messages: input.messages.map((message, index) => cached?.messages[index] && sameReplayMessage(cached.messages[index], message) ? cached.messages[index] : {
2408
+ opencode2: !!input.opencode2,
2409
+ messages: input.messages.map((message, index) => cached?.messages[index] && sameReplayMessage(cached.messages[index], message, projectPart) ? cached.messages[index] : {
2052
2410
  info: {
2053
2411
  id: message.info.id,
2054
2412
  role: message.info.role,
2055
2413
  summary: message.info.summary
2056
2414
  },
2057
- parts: copyReplayValue(message.parts)
2415
+ parts: replaySnapshotParts(message.parts, projectPart)
2058
2416
  }),
2059
2417
  tags: structuredClone(input.tags),
2060
2418
  protectedTagNumbers: new Set(input.protectedTagNumbers),
2061
2419
  pendingDropTagNumbers: new Set(pendingDropTagNumbers),
2062
2420
  measured: rawMeasured,
2063
- size: 2 * structuralSize(input.messages) + 512 * input.tags.length
2421
+ size: 2 * structuralSize(input.messages.map(input.opencode2 ? providerVisibleMessageForOpenCode2 : providerVisibleMessageForTailHygiene)) + 512 * input.tags.length
2064
2422
  };
2065
2423
  if (!hit) {
2066
2424
  const owners = new Map;
@@ -2077,8 +2435,9 @@ function refreshTailHygieneBaseline(input) {
2077
2435
  const refrozen = (mismatch) => {
2078
2436
  const frozen = freezeTailHygieneMeasurement(measured);
2079
2437
  retainBaselineMeasurement(frozen.baselineParts, memo);
2080
- return {
2438
+ return rememberCurrentToolOutputCount({
2081
2439
  ...frozen,
2440
+ protectedToolsPolicy,
2082
2441
  hygieneUnitsVersion: frozenCalibration.hygieneUnitsVersion,
2083
2442
  toolsRatio: frozenCalibration.toolsRatio,
2084
2443
  proseRatio: frozenCalibration.proseRatio,
@@ -2088,9 +2447,8 @@ function refreshTailHygieneBaseline(input) {
2088
2447
  generationInvalidated: false,
2089
2448
  contentSignature: measured.contentSignature,
2090
2449
  channel1PostReduceGrace: input.previous?.channel1PostReduceGrace,
2091
- lastPrefixMismatch: mismatch,
2092
- protectedToolsPolicy
2093
- };
2450
+ lastPrefixMismatch: mismatch
2451
+ }, measured);
2094
2452
  };
2095
2453
  if (input.cacheBusting || !input.previous)
2096
2454
  return refrozen();
@@ -2106,7 +2464,7 @@ function refreshTailHygieneBaseline(input) {
2106
2464
  if (part.kind !== "toolOutput" || !part.protected)
2107
2465
  turnDeltaU += part.uTokens;
2108
2466
  }
2109
- return {
2467
+ return rememberCurrentToolOutputCount({
2110
2468
  ...input.previous,
2111
2469
  protectedToolsPolicy,
2112
2470
  turnDeltaU,
@@ -2115,7 +2473,7 @@ function refreshTailHygieneBaseline(input) {
2115
2473
  generationInvalidated: false,
2116
2474
  contentSignature: measured.contentSignature,
2117
2475
  lastPrefixMismatch: undefined
2118
- };
2476
+ }, measured);
2119
2477
  }
2120
2478
  function effectiveTailHygiene(baseline) {
2121
2479
  const t = Math.ceil(Math.max(0, baseline.baselineT + baseline.turnDeltaT));
@@ -2387,7 +2745,7 @@ function formatOldestReclaimableHint(hint) {
2387
2745
  oldest reclaimable: ${rendered}.` : "";
2388
2746
  }
2389
2747
  function reclaimableToolOutputCount(parts) {
2390
- return parts.filter((part) => part.kind === "toolOutput" && part.uTokens > 0).length;
2748
+ return countReclaimableToolOutputs(parts);
2391
2749
  }
2392
2750
  function formatReclaimableOutputSummary(count, tokens) {
2393
2751
  const outputCount = Math.max(0, Math.floor(count));
@@ -2497,9 +2855,11 @@ function planEmergencyDrop(input) {
2497
2855
  const workingSpan = Math.max(ceilingTokens - fixedFloor, 0);
2498
2856
  const target = fixedFloor + TARGET_FRACTION * workingSpan;
2499
2857
  const reclaimTokens = Math.round(currentTotalInputTokens - target);
2500
- const floorNote = fixedFloor > ceilingTokens ? `; fixed floor ≈${Math.round(fixedFloor)} already exceeds ceiling ${Math.round(ceilingTokens)}: tool drops cannot reach the target` : "";
2858
+ if (fixedFloor > ceilingTokens) {
2859
+ return noop(`fixed floor ≈${Math.round(fixedFloor)} already exceeds ceiling ${Math.round(ceilingTokens)}: tool drops cannot reach the target`);
2860
+ }
2501
2861
  if (reclaimTokens <= EMERGENCY_REARM_MIN_TOKENS) {
2502
- return noop(`reclaim<=min (${reclaimTokens} <= ${EMERGENCY_REARM_MIN_TOKENS})${floorNote}`);
2862
+ return noop(`reclaim<=min (${reclaimTokens} <= ${EMERGENCY_REARM_MIN_TOKENS})`);
2503
2863
  }
2504
2864
  const cutoff = input.protectedCutoff;
2505
2865
  const windowYields = absoluteEmergency;
@@ -2554,16 +2914,16 @@ function planEmergencyDrop(input) {
2554
2914
  }
2555
2915
  }
2556
2916
  if (selected.length === 0) {
2557
- return noop(`no-candidates${floorNote}`);
2917
+ return noop("no-candidates");
2558
2918
  }
2559
2919
  if (!input.passAlreadyPriced && reclaimed < EMERGENCY_MIN_ACHIEVABLE_RECLAIM_TOKENS) {
2560
- return noop(`achievable reclaim below minimum (${selected.length} tags, reclaim≈${Math.round(reclaimed)} < ${EMERGENCY_MIN_ACHIEVABLE_RECLAIM_TOKENS} against gap ${reclaimTokens})${floorNote}`);
2920
+ return noop(`achievable reclaim below minimum (${selected.length} tags, reclaim≈${Math.round(reclaimed)} < ${EMERGENCY_MIN_ACHIEVABLE_RECLAIM_TOKENS} against gap ${reclaimTokens})`);
2561
2921
  }
2562
2922
  return {
2563
2923
  shouldDrop: true,
2564
2924
  tagNumbers: selected,
2565
2925
  reclaimTokens,
2566
- reason: `tiered drop: ${selected.length} tags, reclaim≈${reclaimed}/${reclaimTokens} tokens (floor≈${fixedFloor}, ceiling=${Math.round(ceilingTokens)})${floorNote}`
2926
+ reason: `tiered drop: ${selected.length} tags, reclaim≈${reclaimed}/${reclaimTokens} tokens (floor≈${fixedFloor}, ceiling=${Math.round(ceilingTokens)})`
2567
2927
  };
2568
2928
  }
2569
2929
  function measureEmergencyTag(tag, target, calibration, skeleton) {
@@ -3418,6 +3778,19 @@ function insertTag(db, sessionId, messageId, type, byteSize, tagNumber, reasonin
3418
3778
  function updateTagStatus(db, sessionId, tagId, status) {
3419
3779
  getUpdateTagStatusStatement(db).run(status, sessionId, tagId);
3420
3780
  }
3781
+ var droppedTagStatements = new WeakMap;
3782
+ function markTagDropped(db, sessionId, tagId, mode) {
3783
+ if (!mode) {
3784
+ updateTagStatus(db, sessionId, tagId, "dropped");
3785
+ return;
3786
+ }
3787
+ let statement = droppedTagStatements.get(db);
3788
+ if (!statement) {
3789
+ statement = db.prepare("UPDATE tags SET status = ?, drop_mode = ? WHERE session_id = ? AND tag_number = ?");
3790
+ droppedTagStatements.set(db, statement);
3791
+ }
3792
+ statement.run("dropped", mode, sessionId, tagId);
3793
+ }
3421
3794
  var inertWhitespaceStatements = new WeakMap;
3422
3795
  function markWhitespaceAssistantTagInert(db, sessionId, tagNumber, contentId) {
3423
3796
  db.prepare(`UPDATE tags
@@ -3868,7 +4241,7 @@ function getNewestToolTagNumbers(db, sessionId, limit) {
3868
4241
  let statement = newestToolTagNumberStatements.get(db);
3869
4242
  if (!statement) {
3870
4243
  statement = db.prepare(`SELECT tag_number FROM tags
3871
- WHERE session_id = ? AND type = 'tool'
4244
+ WHERE session_id = ? AND +type = 'tool'
3872
4245
  AND typeof(message_id) = 'text'
3873
4246
  AND typeof(status) = 'text'
3874
4247
  AND typeof(byte_size) IN ('integer', 'real')
@@ -4375,84 +4748,34 @@ function isHostRenderedSystemMessage(message) {
4375
4748
  const id = message.info.id;
4376
4749
  return (typeof id !== "string" || id.length === 0) && message.info.role === "system";
4377
4750
  }
4378
-
4379
- // src/hooks/magic-context/provider-visible-parts.ts
4380
- function isRecord2(value) {
4381
- return value !== null && typeof value === "object" && !Array.isArray(value);
4751
+ var COVERED_INSTRUCTION_ROW = "coveredInstructionRow";
4752
+ function markCoveredInstructionRow(target) {
4753
+ Object.defineProperty(target, COVERED_INSTRUCTION_ROW, {
4754
+ value: true,
4755
+ enumerable: false,
4756
+ configurable: true
4757
+ });
4758
+ return target;
4382
4759
  }
4383
- var KEPT_TOOL_STATE_FIELDS = new Set([
4384
- "status",
4385
- "input",
4386
- "output",
4387
- "error",
4388
- "attachments",
4389
- "content"
4390
- ]);
4391
- var KEPT_TOOL_STATE_TIME_FIELD = "compacted";
4392
- var KEPT_ERROR_METADATA_FIELDS = ["interrupted", "output"];
4393
- function providerVisibleToolState(state) {
4394
- const view = {};
4395
- for (const key of Object.keys(state)) {
4396
- const value = state[key];
4397
- if (KEPT_TOOL_STATE_FIELDS.has(key)) {
4398
- view[key] = value;
4399
- } else if (key === "time" && isRecord2(value)) {
4400
- view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
4401
- } else if (key === "metadata" && state.status === "error" && isRecord2(value)) {
4402
- const kept = {};
4403
- for (const field of KEPT_ERROR_METADATA_FIELDS) {
4404
- if (Object.hasOwn(value, field))
4405
- kept[field] = value[field];
4406
- }
4407
- view.metadata = kept;
4408
- }
4409
- }
4410
- return view;
4760
+ function isCoveredInstructionRow(value) {
4761
+ return typeof value === "object" && value !== null && value[COVERED_INSTRUCTION_ROW] === true;
4411
4762
  }
4412
- function toolStateIsReduced(state) {
4413
- for (const key of Object.keys(state)) {
4414
- if (KEPT_TOOL_STATE_FIELDS.has(key))
4415
- continue;
4416
- const value = state[key];
4417
- if (key === "time" && isRecord2(value)) {
4418
- const keys = Object.keys(value);
4419
- if (keys.length === 0)
4420
- continue;
4421
- if (keys.length === 1 && keys[0] === KEPT_TOOL_STATE_TIME_FIELD)
4422
- continue;
4423
- return false;
4424
- }
4425
- if (key === "metadata" && state.status === "error" && isRecord2(value)) {
4426
- const extra = Object.keys(value).some((field) => !KEPT_ERROR_METADATA_FIELDS.includes(field));
4427
- if (!extra)
4428
- continue;
4429
- }
4430
- return false;
4763
+ function takeCoveredInstructionRows(messages) {
4764
+ const taken = messages.filter((message) => isCoveredInstructionRow(message.info));
4765
+ if (taken.length > 0) {
4766
+ const kept = messages.filter((message) => !isCoveredInstructionRow(message.info));
4767
+ messages.splice(0, messages.length, ...kept);
4431
4768
  }
4432
- return true;
4769
+ return taken;
4433
4770
  }
4434
- function providerVisiblePart(part) {
4435
- if (!isRecord2(part) || part.type !== "tool" || !isRecord2(part.state))
4436
- return part;
4437
- if (toolStateIsReduced(part.state))
4438
- return part;
4439
- return { ...part, state: providerVisibleToolState(part.state) };
4440
- }
4441
- function providerVisibleMessage(message) {
4442
- if (!isRecord2(message) || !Array.isArray(message.parts))
4443
- return message;
4444
- let parts;
4445
- for (let index = 0;index < message.parts.length; index += 1) {
4446
- const part = message.parts[index];
4447
- const view = providerVisiblePart(part);
4448
- if (view !== part) {
4449
- parts ??= message.parts.slice(0, index);
4450
- parts.push(view);
4451
- } else if (parts) {
4452
- parts.push(part);
4453
- }
4454
- }
4455
- return parts ? { ...message, parts } : message;
4771
+ function cloneKeepingCoveredInstructionMarks(messages) {
4772
+ const copy = structuredClone(messages);
4773
+ messages.forEach((message, index) => {
4774
+ const copied = copy[index];
4775
+ if (copied && isCoveredInstructionRow(message.info))
4776
+ markCoveredInstructionRow(copied.info);
4777
+ });
4778
+ return copy;
4456
4779
  }
4457
4780
 
4458
4781
  // src/hooks/magic-context/read-session-true-raw-tokens.ts
@@ -5086,11 +5409,6 @@ function isFilePart(part) {
5086
5409
  const p = part;
5087
5410
  return p.type === "file" && typeof p.url === "string";
5088
5411
  }
5089
- function buildFileSourceContent(parts) {
5090
- const content = parts.filter(isTextPart).map((part) => stripTagPrefix(part.text)).join(`
5091
- `).trim();
5092
- return content.length > 0 ? content : null;
5093
- }
5094
5412
 
5095
5413
  // src/shared/user-answer.ts
5096
5414
  function hasUserAnswerMetadata(value) {
@@ -5292,6 +5610,12 @@ function safeSlice(str, maxLen) {
5292
5610
  function isEditTool(name) {
5293
5611
  return name === "edit" || name === "write";
5294
5612
  }
5613
+ function needsEditMarker(input) {
5614
+ return Object.keys(input).some((key) => {
5615
+ const value = input[key];
5616
+ return DIFF_KEYS.has(key) && typeof value === "string" && value.length > EDIT_REGION_HINT_LEN && !value.endsWith(TRUNCATION_SENTINEL);
5617
+ });
5618
+ }
5295
5619
  function applyEditMarkerToInput(input) {
5296
5620
  for (const key of Object.keys(input)) {
5297
5621
  if (PATH_KEYS.has(key))
@@ -5453,6 +5777,17 @@ function serializedTokens(value, bounded = false) {
5453
5777
  return Buffer.byteLength(serialized);
5454
5778
  return serialized ? wireTextTokens(serialized) : 0;
5455
5779
  }
5780
+ function estimatePartImageTokens(raw) {
5781
+ if (!raw || typeof raw !== "object")
5782
+ return 0;
5783
+ const part = raw;
5784
+ if (part.ignored)
5785
+ return 0;
5786
+ if (part.type === "file" && part.mime?.startsWith("image/")) {
5787
+ return typeof part.url === "string" && part.url.startsWith("data:") ? estimateImageTokensFromDataUrl(part.url) : 1200;
5788
+ }
5789
+ return part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0;
5790
+ }
5456
5791
  function visitWireContent(message, visit) {
5457
5792
  for (const part of message.parts) {
5458
5793
  if (!part || typeof part !== "object")
@@ -5481,15 +5816,13 @@ function visitWireContent(message, visit) {
5481
5816
  text(p.data);
5482
5817
  break;
5483
5818
  case "file":
5484
- if (typeof p.mime === "string" && p.mime.startsWith("image/")) {
5485
- visit.image("conversation", typeof p.url === "string" && p.url.startsWith("data:") ? estimateImageTokensFromDataUrl(p.url) : 1200);
5486
- }
5819
+ visit.image("conversation", estimatePartImageTokens(part));
5487
5820
  break;
5488
5821
  case "tool":
5489
5822
  tool(p.state?.input ?? p.input ?? p.args);
5490
5823
  tool(p.state?.output ?? p.state?.content ?? p.output ?? p.result ?? p.content);
5491
5824
  tool(p.state?.error);
5492
- visit.image("toolCall", estimateToolAttachmentImageTokens(p.state));
5825
+ visit.image("toolCall", estimatePartImageTokens(part));
5493
5826
  break;
5494
5827
  case "tool-call":
5495
5828
  tool(p.input ?? p.args);
@@ -6139,24 +6472,18 @@ function setToolContent(part, content) {
6139
6472
  }
6140
6473
  }
6141
6474
  function clonePart(part) {
6142
- if (part === null || typeof part !== "object")
6143
- return part;
6144
- try {
6145
- return structuredClone(part);
6146
- } catch {
6147
- try {
6148
- return JSON.parse(JSON.stringify(part));
6149
- } catch {
6150
- return part;
6151
- }
6152
- }
6475
+ return {
6476
+ ...part,
6477
+ ...isRecord(part.state) ? { state: { ...part.state } } : {}
6478
+ };
6153
6479
  }
6154
6480
  function clampCloneInPlace(occurrence, clamp) {
6155
- const clone = clonePart(occurrence.part);
6156
- clamp(clone);
6157
6481
  const parts = occurrence.message.parts;
6158
6482
  const index = parts.indexOf(servedPart(occurrence));
6159
6483
  if (index >= 0) {
6484
+ const clone = clamp(occurrence.part);
6485
+ if (clone === servedPart(occurrence))
6486
+ return;
6160
6487
  parts[index] = clone;
6161
6488
  occurrence.served = clone;
6162
6489
  }
@@ -6166,17 +6493,24 @@ function servedPart(occurrence) {
6166
6493
  }
6167
6494
  function skeletonRealToolPart(part, tagId, stripAttachments = false) {
6168
6495
  if (!isRecord(part))
6169
- return;
6496
+ return part;
6170
6497
  const sentinel = `[dropped §${tagId}§]`;
6171
6498
  if (part.type === "tool" && isRecord(part.state)) {
6172
- part.state.output = sentinel;
6499
+ if (part.state.output === sentinel && !needsAttachmentStrip(part.state, stripAttachments))
6500
+ return part;
6501
+ const clone = clonePart(part);
6502
+ const state = clone.state;
6503
+ state.output = sentinel;
6173
6504
  if (stripAttachments)
6174
- part.state.attachments = [];
6175
- return;
6176
- }
6177
- if (part.type === "tool_result") {
6178
- part.content = sentinel;
6505
+ state.attachments = [];
6506
+ return clone;
6179
6507
  }
6508
+ if (part.type === "tool_result" && part.content !== sentinel)
6509
+ return { ...part, content: sentinel };
6510
+ return part;
6511
+ }
6512
+ function needsAttachmentStrip(state, strip) {
6513
+ return strip && (!Array.isArray(state.attachments) || state.attachments.length !== 0);
6180
6514
  }
6181
6515
  function readToolPartRawInput(part) {
6182
6516
  if (!isRecord(part))
@@ -6189,51 +6523,62 @@ function readToolPartRawInput(part) {
6189
6523
  return part.input;
6190
6524
  return;
6191
6525
  }
6526
+ function isDroppedInput(input, sentinel) {
6527
+ return isRecord(input) && Object.keys(input).length === 1 && Object.hasOwn(input, "dropped") && input.dropped === sentinel;
6528
+ }
6192
6529
  function truncateToolPart(part, tagId) {
6193
6530
  if (!isRecord(part))
6194
- return;
6531
+ return part;
6195
6532
  const sentinel = `[dropped §${tagId}§]`;
6196
6533
  if (part.type === "tool" && isRecord(part.state)) {
6197
- const state = part.state;
6534
+ if (part.state.output === sentinel && isDroppedInput(part.state.input, sentinel))
6535
+ return part;
6536
+ const clone = clonePart(part);
6537
+ const state = clone.state;
6198
6538
  state.output = sentinel;
6199
6539
  state.input = droppedInputMarker(tagId);
6200
- return;
6540
+ return clone;
6201
6541
  }
6202
6542
  if (part.type === "tool_result") {
6203
- part.content = sentinel;
6204
- return;
6543
+ return part.content === sentinel ? part : { ...part, content: sentinel };
6205
6544
  }
6206
6545
  if (part.type === "tool-invocation") {
6207
- part.args = droppedInputMarker(tagId);
6208
- return;
6546
+ return isDroppedInput(part.args, sentinel) ? part : { ...part, args: droppedInputMarker(tagId) };
6209
6547
  }
6210
6548
  if (part.type === "tool_use") {
6211
- part.input = droppedInputMarker(tagId);
6549
+ return isDroppedInput(part.input, sentinel) ? part : { ...part, input: droppedInputMarker(tagId) };
6212
6550
  }
6551
+ return part;
6213
6552
  }
6214
6553
  function editMarkerToolPart(part, tagId, stripAttachments = false) {
6215
6554
  if (!isRecord(part))
6216
- return;
6555
+ return part;
6217
6556
  const sentinel = `[dropped §${tagId}§]`;
6557
+ const input = readToolPartInput(part);
6558
+ const rewriteInput = input !== null && needsEditMarker(input);
6218
6559
  if (part.type === "tool" && isRecord(part.state)) {
6219
- part.state.output = sentinel;
6560
+ if (part.state.output === sentinel && !rewriteInput && !needsAttachmentStrip(part.state, stripAttachments))
6561
+ return part;
6562
+ const clone = clonePart(part);
6563
+ const state = clone.state;
6564
+ state.output = sentinel;
6220
6565
  if (stripAttachments)
6221
- part.state.attachments = [];
6222
- if (isRecord(part.state.input))
6223
- applyEditMarkerToInput(part.state.input);
6224
- return;
6566
+ state.attachments = [];
6567
+ if (rewriteInput) {
6568
+ state.input = { ...input };
6569
+ applyEditMarkerToInput(state.input);
6570
+ }
6571
+ return clone;
6225
6572
  }
6226
6573
  if (part.type === "tool_result") {
6227
- part.content = sentinel;
6228
- return;
6574
+ return part.content === sentinel ? part : { ...part, content: sentinel };
6229
6575
  }
6230
- if (part.type === "tool-invocation" && isRecord(part.args)) {
6231
- applyEditMarkerToInput(part.args);
6232
- return;
6233
- }
6234
- if (part.type === "tool_use" && isRecord(part.input)) {
6235
- applyEditMarkerToInput(part.input);
6576
+ if (rewriteInput) {
6577
+ const markedInput = { ...input };
6578
+ applyEditMarkerToInput(markedInput);
6579
+ return { ...part, [part.type === "tool-invocation" ? "args" : "input"]: markedInput };
6236
6580
  }
6581
+ return part;
6237
6582
  }
6238
6583
  function readToolPartInput(part) {
6239
6584
  if (!isRecord(part))
@@ -6320,7 +6665,7 @@ class ToolMutationBatch {
6320
6665
  this.partsToRemove.add(servedPart(occurrence));
6321
6666
  this.affectedMessages.add(occurrence.message);
6322
6667
  }
6323
- wouldStrandConversationEnd(occurrences) {
6668
+ wouldStrandConversationEnd(occurrences, plannedRemovals) {
6324
6669
  const served = this.servedMessages ?? this.messages;
6325
6670
  let end;
6326
6671
  for (let i = served.length - 1;i >= 0 && end === undefined; i -= 1) {
@@ -6330,7 +6675,7 @@ class ToolMutationBatch {
6330
6675
  if (!end || !occurrences.some((occurrence) => occurrence.message === end))
6331
6676
  return false;
6332
6677
  const leaving = new Set(occurrences.map(servedPart));
6333
- const survives = (part) => !leaving.has(part) && !this.partsToRemove.has(part);
6678
+ const survives = (part) => !leaving.has(part) && !this.partsToRemove.has(part) && !plannedRemovals?.has(part);
6334
6679
  return end.info.role === "assistant" ? !end.parts.some((part) => partHasCompletedResult(part) && survives(part)) : !end.parts.some((part) => hasMeaningfulPart(part) && survives(part));
6335
6680
  }
6336
6681
  finalize() {
@@ -6462,9 +6807,7 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
6462
6807
  parts
6463
6808
  });
6464
6809
  const before = count(parts);
6465
- const retained = skeleton ? structuredClone(parts) : [];
6466
- for (const part of retained)
6467
- skeletonRealToolPart(part, tagId);
6810
+ const retained = skeleton ? parts.map((part) => skeletonRealToolPart(part, tagId)) : [];
6468
6811
  const after = count(retained);
6469
6812
  return {
6470
6813
  beforeTools: before.toolCall,
@@ -6506,11 +6849,16 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
6506
6849
  return null;
6507
6850
  return toolInputStringBytes(readRawInput());
6508
6851
  },
6509
- wouldStrandConversationEnd: () => {
6852
+ wouldStrandConversationEnd: (plannedRemovals) => {
6510
6853
  const entry = index.get(compositeKey);
6511
6854
  if (!entry || entry.occurrences.length === 0)
6512
6855
  return false;
6513
- return batch.wouldStrandConversationEnd(entry.occurrences);
6856
+ return batch.wouldStrandConversationEnd(entry.occurrences, plannedRemovals);
6857
+ },
6858
+ notePlannedRemoval: (plannedRemovals) => {
6859
+ for (const occurrence of index.get(compositeKey)?.occurrences ?? []) {
6860
+ plannedRemovals.add(servedPart(occurrence));
6861
+ }
6514
6862
  },
6515
6863
  prepareDrop: () => {
6516
6864
  const entry = index.get(compositeKey);
@@ -6602,9 +6950,8 @@ function setBoundedRawMessageProvider2(sessionId, provider) {
6602
6950
  }
6603
6951
  return setRawMessageProvider(sessionId, wrapper);
6604
6952
  }
6605
- var SYSTEM_REMINDER_BLOCK_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
6606
6953
  function cleanUserText2(text) {
6607
- return stripOutsideSteeringWrappers(text, (segment) => segment.replace(SYSTEM_REMINDER_BLOCK_REGEX, "").replace(OMO_INTERNAL_INITIATOR_MARKER, "")).trim();
6954
+ return stripOutsideSteeringWrappers(text, (segment) => removeSystemReminders(segment).replace(OMO_INTERNAL_INITIATOR_MARKER, "")).trim();
6608
6955
  }
6609
6956
  function hasMeaningfulChunkUserText(parts) {
6610
6957
  for (const part of parts) {
@@ -7374,4 +7721,4 @@ function readSessionChunk2(sessionId, tokenBudget, offset = 1, eligibleEndOrdina
7374
7721
  toolResultBoundaries
7375
7722
  };
7376
7723
  }
7377
- export { toolTemplateError, DEFAULT_PROTECTED_TOOLS, normalizeProtectedToolName, mergeProtectedTools, isRecord, protectedToolTagNumbers, protectedToolTokenCount, textMentionsRecentCommit, removeSystemReminders, hasMeaningfulUserText2, extractTexts2, getTokenizerNativeMemoryStats, preloadTokenizer, estimateTokens, estimateFixedPromptTokens, stripWellFormedLeadingTagPrefix, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, stableStringify, contentTagOwnerMessageId, estimateImageTokensFromDataUrl, estimateToolAttachmentImageTokens, normalizeTodoStateJson, buildSyntheticTodoPart, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, formatTailHygienePrefixMismatch, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchangedIfEnabled, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, isDroppedToolOutput, toolOutputTokens, decideChannel1, evaluateChannel2, formatChannel1Evaluation, formatChannel2Evaluation, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, measureEmergencyTag, installV3PerfSchema, queuePendingOp, queuePendingDropForUnchangedTag, getPendingOps, getPendingOpsCount, clearPendingOps, removePendingOp, tagTombstoneOwnerRange, tagTombstoneOwnerKey, tagRevisionKey, tagIdentityRevisionKey, installTagIdentityRevisionTrigger, deleteTagIdentityRevisions, getRecentTagOwnerMessageIds, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, getAllStatusTagTokenTotalsFlat, getReasoningTokenEstimatesByMessage, tryGetReasoningTokenEstimatesByMessage, getMaxTagNumberByOwnerMessage, scanTagOwnerSummary, isTagOwnerSummaryReady, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, markWhitespaceAssistantTagInert, getInertWhitespaceAssistantTags, getInertWhitespaceAssistantTagsByNumbers, updateTagDropMode, updateCavemanDepth, updateTagMessageId, foldShrunkPartTags, markTagsCompactedByMessageIds, getMaxTagNumberBySession, getTagNumberByMessageId, getAssignableTagNumberByMessageId, deriveTagLoadFloor, TAG_SELECT_COLUMNS, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getTagsByNumbers, getNewestToolTagNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getTagById, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, expandToolPart, markHostUnservedRow, retreatPastHostUnservedRows, snapTerminalCompartmentToServedRow, isHostRenderedSystemMessage, providerVisibleMessage, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, stripSystemInjection, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, toolPartHasUserAnswer, recordToolParameters, createDroppedInputGuard, assertExecutableToolInput, isEditTool, getCurrentToolSetHash, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getMeasuredToolDefinitionTokens, describeFinalWireTail, estimateMessageTokens, wireContentBytes, createFinalWireUsageTracker, estimateFinalWireInputTokens, detectLatestTurnThinkingMismatch, isPrefixBoundThinkingModel, detectOverflow, modelAcceptsEmptyContent, isAnthropicFamilyRoute, neutralizeDroppedReasoningPart, restoreNeutralizedReasoningPart, isNeutralizedReasoningPart, neutralizedReasoningSource, variantChangeBustsProviderCache, makeSentinel, makeWholeMessageSentinel, neutralizeWholeMessage, isSentinel, replaySentinelByMessageIds, SKELETON_REAL_INPUT_MAX_BYTES, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, resolveHostServedBoundaryId2, hasRawMessageProvider2, setBoundedRawMessageProvider2, cleanUserText2, withRawSessionMessageCache2, readRawSessionMessages2, readRawSessionMessagePage2, getRawSessionMessageOrdinalCount2, visitRawSessionMessages2, readRawSessionMessageRange2, prepareRawSessionOrdinals2, primeTailRawMessageCache2, getCachedAbsoluteMessageCount2, primeInMemoryTailRawMessageCache2, readRawSessionMessageIdOrdinalsForRange2, hasRawSessionMessageById2, readRawSessionMessageOrdinalById2, compareRawSessionMessageOrder2, readRawSessionMessageById2, getRawSessionMessageCount2, getRawSessionTagKeysThrough2, getLegacyProtectedTailStartOrdinal2, readSessionChunk2 };
7724
+ export { toolTemplateError, DEFAULT_PROTECTED_TOOLS, normalizeProtectedToolName, mergeProtectedTools, detectLatestTurnThinkingMismatch, isPrefixBoundThinkingModel, detectOverflow, stripWellFormedLeadingTagPrefix, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, isRecord, protectedToolTagNumbers, protectedToolTokenCount, textMentionsRecentCommit, removeSystemReminders, removeNestedBlocks, hasMeaningfulUserText2, extractTexts2, getTokenizerNativeMemoryStats, preloadTokenizer, estimateTokens, estimateFixedPromptTokens, currentReclaimableToolOutputCount, stableStringify, contentTagOwnerMessageId, estimateImageTokensFromDataUrl, estimateToolAttachmentImageTokens, providerVisibleMessage, normalizeTodoStateJson, buildSyntheticTodoPart, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, formatTailHygienePrefixMismatch, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchangedIfEnabled, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, isDroppedToolOutput, toolOutputTokens, decideChannel1, evaluateChannel2, formatChannel1Evaluation, formatChannel2Evaluation, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, measureEmergencyTag, installV3PerfSchema, queuePendingOp, queuePendingDropForUnchangedTag, getPendingOps, getPendingOpsCount, clearPendingOps, removePendingOp, TAG_TOMBSTONE_OWNER_PREFIX, tagTombstoneOwnerRange, tagTombstoneOwnerKey, tagRevisionKey, tagIdentityRevisionKey, installTagIdentityRevisionTrigger, deleteTagIdentityRevisions, getRecentTagOwnerMessageIds, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, getAllStatusTagTokenTotalsFlat, getReasoningTokenEstimatesByMessage, tryGetReasoningTokenEstimatesByMessage, getMaxTagNumberByOwnerMessage, scanTagOwnerSummary, isTagOwnerSummaryReady, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, markTagDropped, markWhitespaceAssistantTagInert, getInertWhitespaceAssistantTags, getInertWhitespaceAssistantTagsByNumbers, updateTagDropMode, updateCavemanDepth, updateTagMessageId, foldShrunkPartTags, markTagsCompactedByMessageIds, getMaxTagNumberBySession, getTagNumberByMessageId, getAssignableTagNumberByMessageId, deriveTagLoadFloor, TAG_SELECT_COLUMNS, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getTagsByNumbers, getNewestToolTagNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getTagById, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, expandToolPart, markHostUnservedRow, retreatPastHostUnservedRows, snapTerminalCompartmentToServedRow, isHostRenderedSystemMessage, markCoveredInstructionRow, isCoveredInstructionRow, takeCoveredInstructionRows, cloneKeepingCoveredInstructionMarks, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, stripSystemInjection, isTextPart, isToolPartWithOutput, isFilePart, toolPartHasUserAnswer, recordToolParameters, createDroppedInputGuard, assertExecutableToolInput, isEditTool, getCurrentToolSetHash, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getMeasuredToolDefinitionTokens, describeFinalWireTail, estimatePartImageTokens, estimateMessageTokens, wireContentBytes, createFinalWireUsageTracker, estimateFinalWireInputTokens, modelAcceptsEmptyContent, isAnthropicFamilyRoute, neutralizeDroppedReasoningPart, restoreNeutralizedReasoningPart, isNeutralizedReasoningPart, neutralizedReasoningSource, variantChangeBustsProviderCache, makeSentinel, makeWholeMessageSentinel, neutralizeWholeMessage, isSentinel, replaySentinelByMessageIds, SKELETON_REAL_INPUT_MAX_BYTES, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, resolveHostServedBoundaryId2, hasRawMessageProvider2, setBoundedRawMessageProvider2, cleanUserText2, withRawSessionMessageCache2, readRawSessionMessages2, readRawSessionMessagePage2, getRawSessionMessageOrdinalCount2, visitRawSessionMessages2, readRawSessionMessageRange2, prepareRawSessionOrdinals2, primeTailRawMessageCache2, getCachedAbsoluteMessageCount2, primeInMemoryTailRawMessageCache2, readRawSessionMessageIdOrdinalsForRange2, hasRawSessionMessageById2, readRawSessionMessageOrdinalById2, compareRawSessionMessageOrder2, readRawSessionMessageById2, getRawSessionMessageCount2, getRawSessionTagKeysThrough2, getLegacyProtectedTailStartOrdinal2, readSessionChunk2 };