@retaw106/mmc-oc 2.3.0 → 2.4.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 (119) 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-c72brxe5.js} +717 -206
  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/storage-tags.d.ts +4 -0
  16. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  17. package/dist/features/magic-context/transform-decision-log.d.ts +57 -2
  18. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts +34 -0
  20. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts.map +1 -0
  21. package/dist/hooks/magic-context/apply-operations.d.ts +3 -1
  22. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -2
  24. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/compartment-runner.d.ts +4 -0
  26. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/compartment-trigger-error.d.ts +11 -0
  28. package/dist/hooks/magic-context/compartment-trigger-error.d.ts.map +1 -0
  29. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  30. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +1 -0
  32. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts +2 -0
  34. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
  36. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  38. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts +14 -0
  40. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -0
  41. package/dist/hooks/magic-context/pending-materialization.d.ts +2 -0
  42. package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/provider-visible-parts.d.ts +10 -4
  44. package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/render-options.d.ts +19 -0
  46. package/dist/hooks/magic-context/render-options.d.ts.map +1 -0
  47. package/dist/hooks/magic-context/supersession-reclaim.d.ts +5 -3
  48. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts +18 -0
  51. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts.map +1 -0
  52. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -4
  53. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/tool-reclaim.d.ts +5 -2
  56. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +2 -0
  59. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/transform.d.ts +0 -7
  61. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  62. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
  63. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
  64. package/dist/{index-3gj1ak4c.js → index-27ddyx39.js} +1 -1
  65. package/dist/{index-z2w1eq3y.js → index-48e9znrc.js} +491 -197
  66. package/dist/{index-z2g20msd.js → index-azbmnekv.js} +4 -4
  67. package/dist/{index-czba8tw3.js → index-dwh99z66.js} +33 -10
  68. package/dist/{index-kw21z5pe.js → index-kahkxcqw.js} +7005 -6903
  69. package/dist/{index-a5mw0xp3.js → index-r7s7d350.js} +1 -1
  70. package/dist/{index-18yrysyj.js → index-ykq24x1n.js} +1 -1
  71. package/dist/index.js +2 -2
  72. package/dist/{message-time-backfill-sykevdax.js → message-time-backfill-j96x1sab.js} +1 -1
  73. package/dist/model-resolution-cvyrrcjw.js +8 -0
  74. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  75. package/dist/{read-session-chunk-863d6c06.js → read-session-chunk-t8bg6wkz.js} +3 -3
  76. package/dist/{recomp-orchestrator-wrjy3qym.js → recomp-orchestrator-k760qy1n.js} +6 -6
  77. package/dist/{send-session-notification-cz6ev088.js → send-session-notification-njjf3b4s.js} +3 -3
  78. package/dist/shared/model-suggestion-retry.d.ts +21 -0
  79. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  80. package/dist/shared/prompt-surface-runtime.d.ts +5 -0
  81. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  82. package/dist/shared/reclaim-distance.d.ts +33 -0
  83. package/dist/shared/reclaim-distance.d.ts.map +1 -0
  84. package/dist/shared/sqlite.d.ts +2 -0
  85. package/dist/shared/sqlite.d.ts.map +1 -1
  86. package/dist/shared/stable-json.d.ts +7 -0
  87. package/dist/shared/stable-json.d.ts.map +1 -1
  88. package/dist/shared/tail-hygiene-json.d.ts +22 -0
  89. package/dist/shared/tail-hygiene-json.d.ts.map +1 -0
  90. package/dist/shared/user-facing-codes.d.ts +2 -2
  91. package/dist/v2/hidden-completion.d.ts +20 -1
  92. package/dist/v2/hidden-completion.d.ts.map +1 -1
  93. package/dist/v2/hooks/context.d.ts.map +1 -1
  94. package/dist/v2/hooks/hidden-child.d.ts +22 -1
  95. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  96. package/dist/v2/server.js +8312 -7354
  97. package/dist/v2/store-reader.d.ts +27 -1
  98. package/dist/v2/store-reader.d.ts.map +1 -1
  99. package/dist/web/main.js +34 -10
  100. package/dist/{wrapup-orchestrator-bmybc5p5.js → wrapup-orchestrator-b2gswatj.js} +6 -6
  101. package/package.json +1 -1
  102. package/src/config/latch-permanence-guard.test.ts +4 -0
  103. package/src/config/project-security.test.ts +17 -0
  104. package/src/config/schema/magic-context.test.ts +50 -0
  105. package/src/config/schema/magic-context.ts +34 -1
  106. package/src/shared/model-suggestion-retry.ts +5 -1
  107. package/src/shared/prompt-surface-runtime.ts +12 -0
  108. package/src/shared/reclaim-distance.test.ts +111 -0
  109. package/src/shared/reclaim-distance.ts +91 -0
  110. package/src/shared/root-async-context.probe.mjs +36 -0
  111. package/src/shared/root-async-context.test.ts +49 -0
  112. package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
  113. package/src/shared/sqlite-foreground-wait.test.ts +237 -1
  114. package/src/shared/sqlite.ts +55 -14
  115. package/src/shared/stable-json.ts +56 -14
  116. package/src/shared/tail-hygiene-json.test.ts +117 -0
  117. package/src/shared/tail-hygiene-json.ts +217 -0
  118. package/src/shared/user-facing-codes.ts +2 -2
  119. 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-dwh99z66.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-ykq24x1n.js";
32
32
 
33
33
  // src/shared/protected-tools-policy.ts
34
34
  var DEFAULT_PROTECTED_TOOLS = {
@@ -847,6 +847,21 @@ function isThinkingPart(part) {
847
847
  return candidate.type === "thinking" || candidate.type === "reasoning";
848
848
  }
849
849
 
850
+ // src/hooks/magic-context/tail-hygiene-output-count.ts
851
+ var CURRENT_OUTPUT_COUNT = Symbol.for("magic-context.current-reclaimable-tool-output-count");
852
+ function countReclaimableToolOutputs(parts) {
853
+ return parts.filter((part) => part.kind === "toolOutput" && part.uTokens > 0).length;
854
+ }
855
+ function rememberCurrentToolOutputCount(baseline, measurement) {
856
+ return Object.assign(baseline, {
857
+ [CURRENT_OUTPUT_COUNT]: countReclaimableToolOutputs(measurement.parts)
858
+ });
859
+ }
860
+ function currentReclaimableToolOutputCount(baseline) {
861
+ if (!baseline || !Object.hasOwn(baseline, CURRENT_OUTPUT_COUNT))
862
+ return 0;
863
+ return baseline[CURRENT_OUTPUT_COUNT];
864
+ }
850
865
  // src/shared/record-type-guard.ts
851
866
  function isRecord(value) {
852
867
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -855,32 +870,32 @@ function isRecord(value) {
855
870
  // src/shared/stable-json.ts
856
871
  function stableStringify(value, seen = new WeakSet) {
857
872
  const pieces = [];
858
- writeStable(value, seen, pieces);
873
+ writeStable(value, seen, (piece) => pieces.push(piece));
859
874
  return pieces.join("");
860
875
  }
861
- function writeStable(value, seen, pieces) {
876
+ function writeStable(value, seen, write) {
862
877
  if (value === undefined) {
863
- pieces.push("undefined");
878
+ write("undefined");
864
879
  return;
865
880
  }
866
881
  if (value === null || typeof value !== "object") {
867
- pieces.push(JSON.stringify(value) ?? String(value));
882
+ write(JSON.stringify(value) ?? String(value));
868
883
  return;
869
884
  }
870
885
  if (seen.has(value)) {
871
- pieces.push('"[Circular]"');
886
+ write('"[Circular]"');
872
887
  return;
873
888
  }
874
889
  seen.add(value);
875
890
  if (Array.isArray(value)) {
876
- pieces.push("[");
891
+ write("[");
877
892
  for (let index = 0;index < value.length; index += 1) {
878
893
  if (index > 0)
879
- pieces.push(",");
894
+ write(",");
880
895
  if (index in value)
881
- writeStable(value[index], seen, pieces);
896
+ writeStable(value[index], seen, write);
882
897
  }
883
- pieces.push("]");
898
+ write("]");
884
899
  return;
885
900
  }
886
901
  const entries = Object.entries(value).sort(([a], [b]) => {
@@ -890,14 +905,34 @@ function writeStable(value, seen, pieces) {
890
905
  return 1;
891
906
  return 0;
892
907
  });
893
- pieces.push("{");
908
+ 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))) {
909
+ write(JSON.stringify(Object.fromEntries(entries)));
910
+ return;
911
+ }
912
+ write("{");
894
913
  entries.forEach(([key, child], index) => {
895
914
  if (index > 0)
896
- pieces.push(",");
897
- pieces.push(JSON.stringify(key), ":");
898
- writeStable(child, seen, pieces);
915
+ write(",");
916
+ write(JSON.stringify(key));
917
+ write(":");
918
+ writeStable(child, seen, write);
899
919
  });
900
- pieces.push("}");
920
+ write("}");
921
+ }
922
+ function stableStringifyHash(value, prefix = "") {
923
+ const sink = jsonHashSink(prefix);
924
+ writeStable(value, new WeakSet, sink.write);
925
+ return sink.digest();
926
+ }
927
+ function jsonHashSink(prefix = "") {
928
+ let hash = 2166136261;
929
+ const write = (piece) => {
930
+ for (let index = 0;index < piece.length; index++) {
931
+ hash = Math.imul(hash ^ piece.charCodeAt(index), 16777619);
932
+ }
933
+ };
934
+ write(prefix);
935
+ return { write, digest: () => (hash >>> 0).toString(16).padStart(8, "0") };
901
936
  }
902
937
 
903
938
  // src/shared/tag-owner-id.ts
@@ -914,6 +949,127 @@ function contentTagOwnerMessageId(contentId) {
914
949
  return contentId;
915
950
  }
916
951
 
952
+ // src/shared/tail-hygiene-json.ts
953
+ var MAX_MEMO_BYTES = 64 * 1024 * 1024;
954
+ var MAX_MEMO_ENTRIES = 1e4;
955
+
956
+ class TailHygieneJsonMemo {
957
+ entries = new Map;
958
+ bytes = 0;
959
+ passText = new WeakMap;
960
+ passHash = new WeakMap;
961
+ beginPass() {
962
+ this.passText = new WeakMap;
963
+ this.passHash = new WeakMap;
964
+ }
965
+ get(key, value, compute, fingerprint = false) {
966
+ const pass = fingerprint ? this.passHash : this.passText;
967
+ const object = value !== null && typeof value === "object" ? value : undefined;
968
+ const local = object ? pass.get(object) : undefined;
969
+ if (local !== undefined)
970
+ return local;
971
+ const previous = this.entries.get(key);
972
+ if (previous && sameJson(previous.snapshot, value)) {
973
+ if (object)
974
+ pass.set(object, previous.result);
975
+ return previous.result;
976
+ }
977
+ const result = compute();
978
+ if (previous) {
979
+ this.bytes -= previous.bytes;
980
+ this.entries.delete(key);
981
+ }
982
+ try {
983
+ const copy = copyJson(value);
984
+ const bytes = copy.bytes + (key.length + result.length) * 2;
985
+ if (bytes <= MAX_MEMO_BYTES) {
986
+ this.entries.set(key, { snapshot: copy.value, result, bytes });
987
+ this.bytes += bytes;
988
+ if (object)
989
+ pass.set(object, result);
990
+ }
991
+ } catch {}
992
+ while (this.bytes > MAX_MEMO_BYTES || this.entries.size > MAX_MEMO_ENTRIES) {
993
+ const oldest = this.entries.entries().next().value;
994
+ if (!oldest)
995
+ break;
996
+ this.bytes -= oldest[1].bytes;
997
+ this.entries.delete(oldest[0]);
998
+ }
999
+ return result;
1000
+ }
1001
+ }
1002
+ function copyJson(value) {
1003
+ const seen = new Map;
1004
+ let bytes = 0;
1005
+ const copy = (current) => {
1006
+ bytes += 16;
1007
+ if (typeof current === "string")
1008
+ bytes += current.length * 2;
1009
+ if (bytes > MAX_MEMO_BYTES)
1010
+ throw new Error("memo capacity");
1011
+ if (current === null || typeof current !== "object") {
1012
+ if (["function", "symbol", "bigint"].includes(typeof current))
1013
+ throw new Error("exotic");
1014
+ return current;
1015
+ }
1016
+ if (seen.has(current))
1017
+ return seen.get(current);
1018
+ const prototype = Object.getPrototypeOf(current);
1019
+ if (!Array.isArray(current) && prototype !== Object.prototype && prototype !== null)
1020
+ throw new Error("exotic");
1021
+ const result = Array.isArray(current) ? new Array(current.length) : Object.create(prototype);
1022
+ seen.set(current, result);
1023
+ for (const key of Object.keys(current)) {
1024
+ const descriptor = Object.getOwnPropertyDescriptor(current, key);
1025
+ if (!descriptor || !("value" in descriptor))
1026
+ throw new Error("accessor");
1027
+ bytes += key.length * 2 + 16;
1028
+ if (key === "__proto__") {
1029
+ Object.defineProperty(result, key, {
1030
+ value: copy(descriptor.value),
1031
+ enumerable: true,
1032
+ writable: true,
1033
+ configurable: true
1034
+ });
1035
+ } else
1036
+ result[key] = copy(descriptor.value);
1037
+ }
1038
+ return result;
1039
+ };
1040
+ return { value: copy(value), bytes };
1041
+ }
1042
+ function sameJson(before, after) {
1043
+ const forward = new Map;
1044
+ const reverse = new Set;
1045
+ const same = (left, right) => {
1046
+ if (left === null || right === null || typeof left !== "object" || typeof right !== "object")
1047
+ return Object.is(left, right);
1048
+ if (forward.has(left))
1049
+ return forward.get(left) === right;
1050
+ if (reverse.has(right) || Object.getPrototypeOf(left) !== Object.getPrototypeOf(right))
1051
+ return false;
1052
+ forward.set(left, right);
1053
+ reverse.add(right);
1054
+ if (Array.isArray(left) && (!Array.isArray(right) || left.length !== right.length))
1055
+ return false;
1056
+ const keys = Object.keys(left);
1057
+ const otherKeys = Object.keys(right);
1058
+ if (keys.length !== otherKeys.length)
1059
+ return false;
1060
+ for (let index = 0;index < keys.length; index++) {
1061
+ const key = keys[index];
1062
+ if (key !== otherKeys[index])
1063
+ return false;
1064
+ const descriptor = Object.getOwnPropertyDescriptor(right, key);
1065
+ if (!descriptor || !("value" in descriptor) || !same(left[key], descriptor.value))
1066
+ return false;
1067
+ }
1068
+ return true;
1069
+ };
1070
+ return same(before, after);
1071
+ }
1072
+
917
1073
  // src/hooks/magic-context/image-token-estimate.ts
918
1074
  var IMAGE_TOKEN_DIVISOR = 750;
919
1075
  var IMAGE_FALLBACK_TOKENS = 1200;
@@ -1106,6 +1262,151 @@ function readUint32BE(b, offset) {
1106
1262
  return (b[offset] << 24 | b[offset + 1] << 16 | b[offset + 2] << 8 | b[offset + 3]) >>> 0;
1107
1263
  }
1108
1264
 
1265
+ // src/hooks/magic-context/provider-visible-parts.ts
1266
+ function isRecord2(value) {
1267
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1268
+ }
1269
+ var KEPT_TOOL_STATE_FIELDS = new Set([
1270
+ "status",
1271
+ "input",
1272
+ "output",
1273
+ "error",
1274
+ "attachments",
1275
+ "content"
1276
+ ]);
1277
+ var KEPT_TOOL_STATE_TIME_FIELD = "compacted";
1278
+ function tailProviderVisibleToolState(state, openCode1) {
1279
+ const view = {};
1280
+ for (const key of Object.keys(state)) {
1281
+ if (tailToolStateFieldIsKept(key, openCode1)) {
1282
+ view[key] = state[key];
1283
+ } else if (key === "time" && openCode1) {
1284
+ const value = state.time;
1285
+ if (isRecord2(value)) {
1286
+ view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
1287
+ }
1288
+ } else if (key === "metadata" && openCode1 && state.status === "error") {
1289
+ const metadata = state.metadata;
1290
+ if (isRecord2(metadata) && metadata.interrupted === true) {
1291
+ const output = metadata.output;
1292
+ if (typeof output === "string")
1293
+ view.metadata = { interrupted: true, output };
1294
+ }
1295
+ }
1296
+ }
1297
+ return view;
1298
+ }
1299
+ function tailToolStateFieldIsKept(key, openCode1) {
1300
+ return KEPT_TOOL_STATE_FIELDS.has(key) && (key !== "content" || !openCode1);
1301
+ }
1302
+ function tailToolStateIsReduced(state, openCode1) {
1303
+ for (const key of Object.keys(state)) {
1304
+ if (tailToolStateFieldIsKept(key, openCode1))
1305
+ continue;
1306
+ return false;
1307
+ }
1308
+ return true;
1309
+ }
1310
+ function providerVisiblePart(part) {
1311
+ if (!isRecord2(part) || part.type !== "tool" || !isRecord2(part.state))
1312
+ return part;
1313
+ if (toolStateIsReduced(part.state))
1314
+ return part;
1315
+ return { ...part, state: providerVisibleToolState(part.state) };
1316
+ }
1317
+ function providerVisiblePartForTailHygiene(part) {
1318
+ return providerVisiblePartForHost(part, true);
1319
+ }
1320
+ function providerVisiblePartForOpenCode2(part) {
1321
+ return providerVisiblePartForHost(part, false);
1322
+ }
1323
+ function providerVisiblePartForHost(part, openCode1) {
1324
+ if (!isRecord2(part))
1325
+ return part;
1326
+ if (part.type !== "tool") {
1327
+ if (!Object.hasOwn(part, "state"))
1328
+ return part;
1329
+ const view = {};
1330
+ for (const key of Object.keys(part)) {
1331
+ if (key !== "state")
1332
+ view[key] = part[key];
1333
+ }
1334
+ return view;
1335
+ }
1336
+ if (!isRecord2(part.state))
1337
+ return part;
1338
+ if (tailToolStateIsReduced(part.state, openCode1))
1339
+ return part;
1340
+ return { ...part, state: tailProviderVisibleToolState(part.state, openCode1) };
1341
+ }
1342
+ var KEPT_ERROR_METADATA_FIELDS = ["interrupted", "output"];
1343
+ function providerVisibleToolState(state) {
1344
+ const view = {};
1345
+ for (const key of Object.keys(state)) {
1346
+ const value = state[key];
1347
+ if (KEPT_TOOL_STATE_FIELDS.has(key)) {
1348
+ view[key] = value;
1349
+ } else if (key === "time" && isRecord2(value)) {
1350
+ view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
1351
+ } else if (key === "metadata" && state.status === "error" && isRecord2(value)) {
1352
+ const kept = {};
1353
+ for (const field of KEPT_ERROR_METADATA_FIELDS) {
1354
+ if (Object.hasOwn(value, field))
1355
+ kept[field] = value[field];
1356
+ }
1357
+ view.metadata = kept;
1358
+ }
1359
+ }
1360
+ return view;
1361
+ }
1362
+ function toolStateIsReduced(state) {
1363
+ for (const key of Object.keys(state)) {
1364
+ if (KEPT_TOOL_STATE_FIELDS.has(key))
1365
+ continue;
1366
+ const value = state[key];
1367
+ if (key === "time" && isRecord2(value)) {
1368
+ const keys = Object.keys(value);
1369
+ if (keys.length === 0)
1370
+ continue;
1371
+ if (keys.length === 1 && keys[0] === KEPT_TOOL_STATE_TIME_FIELD)
1372
+ continue;
1373
+ return false;
1374
+ }
1375
+ if (key === "metadata" && state.status === "error" && isRecord2(value)) {
1376
+ const extra = Object.keys(value).some((field) => !KEPT_ERROR_METADATA_FIELDS.includes(field));
1377
+ if (!extra)
1378
+ continue;
1379
+ }
1380
+ return false;
1381
+ }
1382
+ return true;
1383
+ }
1384
+ function providerVisibleMessage(message) {
1385
+ return projectMessage(message, providerVisiblePart);
1386
+ }
1387
+ function providerVisibleMessageForTailHygiene(message) {
1388
+ return projectMessage(message, providerVisiblePartForTailHygiene);
1389
+ }
1390
+ function providerVisibleMessageForOpenCode2(message) {
1391
+ return projectMessage(message, providerVisiblePartForOpenCode2);
1392
+ }
1393
+ function projectMessage(message, projectPart) {
1394
+ if (!isRecord2(message) || !Array.isArray(message.parts))
1395
+ return message;
1396
+ let parts;
1397
+ for (let index = 0;index < message.parts.length; index += 1) {
1398
+ const part = message.parts[index];
1399
+ const view = projectPart(part);
1400
+ if (view !== part) {
1401
+ parts ??= message.parts.slice(0, index);
1402
+ parts.push(view);
1403
+ } else if (parts) {
1404
+ parts.push(part);
1405
+ }
1406
+ }
1407
+ return parts ? { ...message, parts } : message;
1408
+ }
1409
+
1109
1410
  // src/hooks/magic-context/todo-view.ts
1110
1411
  import { createHash } from "node:crypto";
1111
1412
  var TODO_STATUS_PENDING = "pending";
@@ -1223,7 +1524,7 @@ function isTodoItem(value) {
1223
1524
 
1224
1525
  // src/hooks/magic-context/tail-hygiene-walk.ts
1225
1526
  var MAX_CONTENT_MEMO_ENTRIES = 1e5;
1226
- var MAX_CONTENT_MEMO_BYTES = 64 * 1024 * 1024;
1527
+ var MAX_CONTENT_MEMO_BYTES = 256 * 1024 * 1024;
1227
1528
  var contentMemo = new Map;
1228
1529
  var contentMemoOrder = new Set;
1229
1530
  var contentMemoBytes = 0;
@@ -1407,41 +1708,46 @@ function stripChannel1ReminderSpans(output) {
1407
1708
  return stripped;
1408
1709
  }
1409
1710
  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) {
1711
+ let stripped = content.trimStart();
1712
+ const tag = TAG_PREFIX.exec(stripped);
1713
+ if (tag)
1714
+ stripped = stripped.slice(tag[0].length).trimStart();
1715
+ return DROP_PREFIXES.some((prefix) => stripped.slice(0, prefix.length).toLowerCase() === prefix);
1716
+ }
1717
+ function toolOutputText(part, key) {
1718
+ const serialize = (value) => partJsonMemo.get(key, value, () => safeStableStringify(value));
1414
1719
  if (part.type === "tool") {
1415
1720
  const state = isRecord(part.state) ? part.state : null;
1416
1721
  if (!state)
1417
1722
  return null;
1418
1723
  if (state.output !== undefined)
1419
- return safeStableStringify(state.output);
1724
+ return serialize(state.output);
1420
1725
  if (state.error !== undefined)
1421
- return safeStableStringify(state.error);
1726
+ return serialize(state.error);
1422
1727
  if (state.result !== undefined)
1423
- return safeStableStringify(state.result);
1728
+ return serialize(state.result);
1424
1729
  return null;
1425
1730
  }
1426
1731
  if (part.type === "tool_result") {
1427
1732
  const value = part.content ?? part.output ?? part.result;
1428
- return value === undefined ? null : safeStableStringify(value);
1733
+ return value === undefined ? null : serialize(value);
1429
1734
  }
1430
1735
  return null;
1431
1736
  }
1432
- function toolInputText(part) {
1737
+ function toolInputText(part, key) {
1738
+ const serialize = (value) => partJsonMemo.get(key, value, () => safeStableStringify(value));
1433
1739
  if (part.type === "tool") {
1434
1740
  const state = isRecord(part.state) ? part.state : null;
1435
1741
  if (!state || state.input === undefined)
1436
1742
  return null;
1437
- return safeStableStringify(state.input);
1743
+ return serialize(state.input);
1438
1744
  }
1439
1745
  if (part.type === "tool-invocation") {
1440
1746
  const value = part.args ?? part.input;
1441
- return value === undefined ? null : safeStableStringify(value);
1747
+ return value === undefined ? null : serialize(value);
1442
1748
  }
1443
1749
  if (part.type === "tool_use") {
1444
- return part.input === undefined ? null : safeStableStringify(part.input);
1750
+ return part.input === undefined ? null : serialize(part.input);
1445
1751
  }
1446
1752
  return null;
1447
1753
  }
@@ -1452,8 +1758,8 @@ function messageIdForTag(tag) {
1452
1758
  }
1453
1759
  function resolveProtectedTagNumbers(tags, protectedTagNumbersInput, protectedToolTags) {
1454
1760
  const protectedNumbers = new Set(protectedTagNumbersInput);
1455
- const protectedExemplars = protectedToolTags ?? protectedToolTagNumbers(tags);
1456
- for (const tagNumber of protectedExemplars)
1761
+ const protectedCtxReduceTags = protectedToolTags ?? protectedToolTagNumbers(tags);
1762
+ for (const tagNumber of protectedCtxReduceTags)
1457
1763
  protectedNumbers.add(tagNumber);
1458
1764
  return protectedNumbers;
1459
1765
  }
@@ -1568,17 +1874,28 @@ function snapshot(args) {
1568
1874
  queuedForDrop
1569
1875
  };
1570
1876
  }
1877
+ var partJsonMemo = new TailHygieneJsonMemo;
1571
1878
  function excludedSnapshot(key, part) {
1572
- const content = safeStableStringify(part);
1573
- return snapshot({
1879
+ const contentHash = partJsonMemo.get(key, part, () => {
1880
+ if (part === null || part === undefined || typeof part === "string")
1881
+ return memoizedContent("excluded", safeStableStringify(part)).hash;
1882
+ try {
1883
+ return stableStringifyHash(part, "excluded\x00");
1884
+ } catch {
1885
+ return memoizedContent("excluded", String(part)).hash;
1886
+ }
1887
+ }, true);
1888
+ return {
1574
1889
  key,
1890
+ contentHash,
1575
1891
  kind: "excluded",
1576
- content,
1577
1892
  tokens: 0,
1578
- tag: undefined,
1579
- protectedNumbers: new Set,
1580
- pendingDropTagNumbers: new Set
1581
- });
1893
+ uTokens: 0,
1894
+ tagNumber: null,
1895
+ tagStatus: null,
1896
+ protected: false,
1897
+ queuedForDrop: false
1898
+ };
1582
1899
  }
1583
1900
  function fileContentAndTokens(part) {
1584
1901
  const mime = typeof part.mime === "string" ? part.mime : "";
@@ -1618,12 +1935,12 @@ function structuralSize(value) {
1618
1935
  }
1619
1936
  return 0;
1620
1937
  }
1621
- function tailHygieneStructuralSignature(messages) {
1938
+ function tailHygieneStructuralSignature(messages, opencode2 = false) {
1622
1939
  const partCounts = [];
1623
1940
  let totalBytes = 0;
1624
1941
  for (const message of messages) {
1625
1942
  partCounts.push(message.parts.length);
1626
- totalBytes += structuralSize(message);
1943
+ totalBytes += structuralSize(opencode2 ? providerVisibleMessageForOpenCode2(message) : providerVisibleMessageForTailHygiene(message));
1627
1944
  }
1628
1945
  return { messageCount: messages.length, partCounts, totalBytes };
1629
1946
  }
@@ -1637,10 +1954,22 @@ function measureTailHygiene(input) {
1637
1954
  return measureWithReplay(input);
1638
1955
  }
1639
1956
  function measureWithReplay(input, replay) {
1957
+ partJsonMemo.beginPass();
1958
+ const projectPart = input.opencode2 ? providerVisiblePartForOpenCode2 : providerVisiblePartForTailHygiene;
1959
+ const views = new WeakMap;
1960
+ const excluded = (key, part) => {
1961
+ let view = part !== null && typeof part === "object" ? views.get(part) : undefined;
1962
+ if (view === undefined) {
1963
+ view = projectPart(part);
1964
+ if (part !== null && typeof part === "object")
1965
+ views.set(part, view);
1966
+ }
1967
+ return excludedSnapshot(key, view);
1968
+ };
1640
1969
  const pendingDropTagNumbers = input.pendingDropTagNumbers ?? new Set;
1641
1970
  const unchanged = input.messages.map((message, index) => {
1642
1971
  const previous = replay?.messages[index];
1643
- return previous !== undefined && sameReplayMessage(previous, message);
1972
+ return previous !== undefined && sameReplayMessage(previous, message, projectPart);
1644
1973
  });
1645
1974
  const toolIdentities = collectToolPartIdentities(input.messages);
1646
1975
  const attribution = buildTagAttribution({
@@ -1650,7 +1979,7 @@ function measureWithReplay(input, replay) {
1650
1979
  protectedTagNumbers: input.protectedTagNumbers,
1651
1980
  protectedToolTags: input.protectedToolTags
1652
1981
  });
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));
1982
+ 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
1983
  const outputByPart = new Map;
1655
1984
  input.messages.forEach((message, index) => {
1656
1985
  message.parts.forEach((part, partIndex) => {
@@ -1716,19 +2045,19 @@ function measureWithReplay(input, replay) {
1716
2045
  const part = message.parts[partIndex];
1717
2046
  const key = `${messageKey}\x00${partIndex}`;
1718
2047
  if (messageSynthetic || isSyntheticPart(part) || !isRecord(part)) {
1719
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2048
+ parts.push(excluded(`${key}\x00excluded`, part));
1720
2049
  continue;
1721
2050
  }
1722
2051
  const type = typeof part.type === "string" ? part.type : "";
1723
2052
  if (type === "reasoning" || type === "thinking" || type === "redacted_thinking" || type === "signature") {
1724
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2053
+ parts.push(excluded(`${key}\x00excluded`, part));
1725
2054
  continue;
1726
2055
  }
1727
2056
  if (type === "text") {
1728
2057
  const rawContent = firstString(part, ["text", "content"]);
1729
2058
  const content = rawContent === null ? null : stripChannel1ReminderSpans(rawContent);
1730
2059
  if (!content || isDropSentinel(content)) {
1731
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2060
+ parts.push(excluded(`${key}\x00excluded`, part));
1732
2061
  continue;
1733
2062
  }
1734
2063
  const tokens = memoizedTokens("text", content);
@@ -1750,7 +2079,7 @@ function measureWithReplay(input, replay) {
1750
2079
  if (type === "file" || type.includes("image") || type === "source") {
1751
2080
  const file = fileContentAndTokens(part);
1752
2081
  if (!file.content || isDropSentinel(file.content)) {
1753
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2082
+ parts.push(excluded(`${key}\x00excluded`, part));
1754
2083
  continue;
1755
2084
  }
1756
2085
  const tag = attribution.messageTags.get(`${message.info.id}:file${partIndex}`);
@@ -1772,11 +2101,11 @@ function measureWithReplay(input, replay) {
1772
2101
  if (toolIdentity) {
1773
2102
  const ownerKey = `${toolIdentity.ownerMessageId}\x00${toolIdentity.callId}`;
1774
2103
  if (droppedToolOwners.has(ownerKey)) {
1775
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2104
+ parts.push(excluded(`${key}\x00excluded`, part));
1776
2105
  continue;
1777
2106
  }
1778
2107
  const tag = attribution.toolTagsByPart.get(part);
1779
- const inputText = toolInputText(part);
2108
+ const inputText = toolInputText(part, `${key}\x00input`);
1780
2109
  if (inputText !== null) {
1781
2110
  const tokens = memoizedTokens("toolInput", inputText);
1782
2111
  const measured = snapshot({
@@ -1796,7 +2125,7 @@ function measureWithReplay(input, replay) {
1796
2125
  if (rawOutput !== null) {
1797
2126
  const output = stripChannel1ReminderSpans(rawOutput);
1798
2127
  if (isDropSentinel(output)) {
1799
- parts.push(excludedSnapshot(`${key}\x00excludedOutput`, output));
2128
+ parts.push(excluded(`${key}\x00excludedOutput`, output));
1800
2129
  } else {
1801
2130
  const tokens = memoizedTokens("toolOutput", output) + (part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0);
1802
2131
  const measured = snapshot({
@@ -1814,11 +2143,11 @@ function measureWithReplay(input, replay) {
1814
2143
  }
1815
2144
  }
1816
2145
  if (inputText === null && rawOutput === null) {
1817
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2146
+ parts.push(excluded(`${key}\x00excluded`, part));
1818
2147
  }
1819
2148
  continue;
1820
2149
  }
1821
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2150
+ parts.push(excluded(`${key}\x00excluded`, part));
1822
2151
  }
1823
2152
  }
1824
2153
  return {
@@ -1959,16 +2288,19 @@ function sameNumbers(before, after) {
1959
2288
  return false;
1960
2289
  return true;
1961
2290
  }
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);
2291
+ function sameReplayMessage(left, right, projectPart = providerVisiblePartForTailHygiene) {
2292
+ 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));
1964
2293
  }
1965
- function sameReplayMessages(before, after) {
2294
+ function replaySnapshotParts(parts, projectPart = providerVisiblePartForTailHygiene) {
2295
+ return copyReplayValue(parts.map(projectPart));
2296
+ }
2297
+ function sameReplayMessages(before, after, projectPart = providerVisiblePartForTailHygiene) {
1966
2298
  if (before.length !== after.length)
1967
2299
  return false;
1968
2300
  for (let index = 0;index < before.length; index += 1) {
1969
2301
  const left = before[index];
1970
2302
  const right = after[index];
1971
- if (!sameReplayMessage(left, right))
2303
+ if (!sameReplayMessage(left, right, projectPart))
1972
2304
  return false;
1973
2305
  }
1974
2306
  return true;
@@ -2027,8 +2359,10 @@ function refreshTailHygieneBaseline(input) {
2027
2359
  protectedTagNumbers: new Set([...input.protectedTagNumbers, ...protectedToolTags])
2028
2360
  };
2029
2361
  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);
2362
+ const priorMemo = input.previous ? baselineMeasurementMemo.get(input.previous.baselineParts) : undefined;
2363
+ const cached = priorMemo?.opencode2 === !!input.opencode2 ? priorMemo : undefined;
2364
+ const projectPart = input.opencode2 ? providerVisiblePartForOpenCode2 : providerVisiblePartForTailHygiene;
2365
+ 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
2366
  const rawMeasured = hit ? cached.measured : measureWithReplay(input, cached);
2033
2367
  const frozenCalibration = !input.cacheBusting && input.previous ? {
2034
2368
  toolsRatio: input.previous.toolsRatio,
@@ -2048,19 +2382,20 @@ function refreshTailHygieneBaseline(input) {
2048
2382
  })
2049
2383
  };
2050
2384
  const memo = hit ? cached : {
2051
- messages: input.messages.map((message, index) => cached?.messages[index] && sameReplayMessage(cached.messages[index], message) ? cached.messages[index] : {
2385
+ opencode2: !!input.opencode2,
2386
+ messages: input.messages.map((message, index) => cached?.messages[index] && sameReplayMessage(cached.messages[index], message, projectPart) ? cached.messages[index] : {
2052
2387
  info: {
2053
2388
  id: message.info.id,
2054
2389
  role: message.info.role,
2055
2390
  summary: message.info.summary
2056
2391
  },
2057
- parts: copyReplayValue(message.parts)
2392
+ parts: replaySnapshotParts(message.parts, projectPart)
2058
2393
  }),
2059
2394
  tags: structuredClone(input.tags),
2060
2395
  protectedTagNumbers: new Set(input.protectedTagNumbers),
2061
2396
  pendingDropTagNumbers: new Set(pendingDropTagNumbers),
2062
2397
  measured: rawMeasured,
2063
- size: 2 * structuralSize(input.messages) + 512 * input.tags.length
2398
+ size: 2 * structuralSize(input.messages.map(input.opencode2 ? providerVisibleMessageForOpenCode2 : providerVisibleMessageForTailHygiene)) + 512 * input.tags.length
2064
2399
  };
2065
2400
  if (!hit) {
2066
2401
  const owners = new Map;
@@ -2077,8 +2412,9 @@ function refreshTailHygieneBaseline(input) {
2077
2412
  const refrozen = (mismatch) => {
2078
2413
  const frozen = freezeTailHygieneMeasurement(measured);
2079
2414
  retainBaselineMeasurement(frozen.baselineParts, memo);
2080
- return {
2415
+ return rememberCurrentToolOutputCount({
2081
2416
  ...frozen,
2417
+ protectedToolsPolicy,
2082
2418
  hygieneUnitsVersion: frozenCalibration.hygieneUnitsVersion,
2083
2419
  toolsRatio: frozenCalibration.toolsRatio,
2084
2420
  proseRatio: frozenCalibration.proseRatio,
@@ -2088,9 +2424,8 @@ function refreshTailHygieneBaseline(input) {
2088
2424
  generationInvalidated: false,
2089
2425
  contentSignature: measured.contentSignature,
2090
2426
  channel1PostReduceGrace: input.previous?.channel1PostReduceGrace,
2091
- lastPrefixMismatch: mismatch,
2092
- protectedToolsPolicy
2093
- };
2427
+ lastPrefixMismatch: mismatch
2428
+ }, measured);
2094
2429
  };
2095
2430
  if (input.cacheBusting || !input.previous)
2096
2431
  return refrozen();
@@ -2106,7 +2441,7 @@ function refreshTailHygieneBaseline(input) {
2106
2441
  if (part.kind !== "toolOutput" || !part.protected)
2107
2442
  turnDeltaU += part.uTokens;
2108
2443
  }
2109
- return {
2444
+ return rememberCurrentToolOutputCount({
2110
2445
  ...input.previous,
2111
2446
  protectedToolsPolicy,
2112
2447
  turnDeltaU,
@@ -2115,7 +2450,7 @@ function refreshTailHygieneBaseline(input) {
2115
2450
  generationInvalidated: false,
2116
2451
  contentSignature: measured.contentSignature,
2117
2452
  lastPrefixMismatch: undefined
2118
- };
2453
+ }, measured);
2119
2454
  }
2120
2455
  function effectiveTailHygiene(baseline) {
2121
2456
  const t = Math.ceil(Math.max(0, baseline.baselineT + baseline.turnDeltaT));
@@ -2387,7 +2722,7 @@ function formatOldestReclaimableHint(hint) {
2387
2722
  oldest reclaimable: ${rendered}.` : "";
2388
2723
  }
2389
2724
  function reclaimableToolOutputCount(parts) {
2390
- return parts.filter((part) => part.kind === "toolOutput" && part.uTokens > 0).length;
2725
+ return countReclaimableToolOutputs(parts);
2391
2726
  }
2392
2727
  function formatReclaimableOutputSummary(count, tokens) {
2393
2728
  const outputCount = Math.max(0, Math.floor(count));
@@ -3418,6 +3753,19 @@ function insertTag(db, sessionId, messageId, type, byteSize, tagNumber, reasonin
3418
3753
  function updateTagStatus(db, sessionId, tagId, status) {
3419
3754
  getUpdateTagStatusStatement(db).run(status, sessionId, tagId);
3420
3755
  }
3756
+ var droppedTagStatements = new WeakMap;
3757
+ function markTagDropped(db, sessionId, tagId, mode) {
3758
+ if (!mode) {
3759
+ updateTagStatus(db, sessionId, tagId, "dropped");
3760
+ return;
3761
+ }
3762
+ let statement = droppedTagStatements.get(db);
3763
+ if (!statement) {
3764
+ statement = db.prepare("UPDATE tags SET status = ?, drop_mode = ? WHERE session_id = ? AND tag_number = ?");
3765
+ droppedTagStatements.set(db, statement);
3766
+ }
3767
+ statement.run("dropped", mode, sessionId, tagId);
3768
+ }
3421
3769
  var inertWhitespaceStatements = new WeakMap;
3422
3770
  function markWhitespaceAssistantTagInert(db, sessionId, tagNumber, contentId) {
3423
3771
  db.prepare(`UPDATE tags
@@ -3868,7 +4216,7 @@ function getNewestToolTagNumbers(db, sessionId, limit) {
3868
4216
  let statement = newestToolTagNumberStatements.get(db);
3869
4217
  if (!statement) {
3870
4218
  statement = db.prepare(`SELECT tag_number FROM tags
3871
- WHERE session_id = ? AND type = 'tool'
4219
+ WHERE session_id = ? AND +type = 'tool'
3872
4220
  AND typeof(message_id) = 'text'
3873
4221
  AND typeof(status) = 'text'
3874
4222
  AND typeof(byte_size) IN ('integer', 'real')
@@ -4376,85 +4724,6 @@ function isHostRenderedSystemMessage(message) {
4376
4724
  return (typeof id !== "string" || id.length === 0) && message.info.role === "system";
4377
4725
  }
4378
4726
 
4379
- // src/hooks/magic-context/provider-visible-parts.ts
4380
- function isRecord2(value) {
4381
- return value !== null && typeof value === "object" && !Array.isArray(value);
4382
- }
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;
4411
- }
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;
4431
- }
4432
- return true;
4433
- }
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;
4456
- }
4457
-
4458
4727
  // src/hooks/magic-context/read-session-true-raw-tokens.ts
4459
4728
  function completedToolArcCrossesBoundary(invOrdinal, resOrdinal, boundary) {
4460
4729
  return invOrdinal < boundary && boundary <= resOrdinal;
@@ -5292,6 +5561,12 @@ function safeSlice(str, maxLen) {
5292
5561
  function isEditTool(name) {
5293
5562
  return name === "edit" || name === "write";
5294
5563
  }
5564
+ function needsEditMarker(input) {
5565
+ return Object.keys(input).some((key) => {
5566
+ const value = input[key];
5567
+ return DIFF_KEYS.has(key) && typeof value === "string" && value.length > EDIT_REGION_HINT_LEN && !value.endsWith(TRUNCATION_SENTINEL);
5568
+ });
5569
+ }
5295
5570
  function applyEditMarkerToInput(input) {
5296
5571
  for (const key of Object.keys(input)) {
5297
5572
  if (PATH_KEYS.has(key))
@@ -5453,6 +5728,17 @@ function serializedTokens(value, bounded = false) {
5453
5728
  return Buffer.byteLength(serialized);
5454
5729
  return serialized ? wireTextTokens(serialized) : 0;
5455
5730
  }
5731
+ function estimatePartImageTokens(raw) {
5732
+ if (!raw || typeof raw !== "object")
5733
+ return 0;
5734
+ const part = raw;
5735
+ if (part.ignored)
5736
+ return 0;
5737
+ if (part.type === "file" && part.mime?.startsWith("image/")) {
5738
+ return typeof part.url === "string" && part.url.startsWith("data:") ? estimateImageTokensFromDataUrl(part.url) : 1200;
5739
+ }
5740
+ return part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0;
5741
+ }
5456
5742
  function visitWireContent(message, visit) {
5457
5743
  for (const part of message.parts) {
5458
5744
  if (!part || typeof part !== "object")
@@ -5481,15 +5767,13 @@ function visitWireContent(message, visit) {
5481
5767
  text(p.data);
5482
5768
  break;
5483
5769
  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
- }
5770
+ visit.image("conversation", estimatePartImageTokens(part));
5487
5771
  break;
5488
5772
  case "tool":
5489
5773
  tool(p.state?.input ?? p.input ?? p.args);
5490
5774
  tool(p.state?.output ?? p.state?.content ?? p.output ?? p.result ?? p.content);
5491
5775
  tool(p.state?.error);
5492
- visit.image("toolCall", estimateToolAttachmentImageTokens(p.state));
5776
+ visit.image("toolCall", estimatePartImageTokens(part));
5493
5777
  break;
5494
5778
  case "tool-call":
5495
5779
  tool(p.input ?? p.args);
@@ -6139,24 +6423,18 @@ function setToolContent(part, content) {
6139
6423
  }
6140
6424
  }
6141
6425
  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
- }
6426
+ return {
6427
+ ...part,
6428
+ ...isRecord(part.state) ? { state: { ...part.state } } : {}
6429
+ };
6153
6430
  }
6154
6431
  function clampCloneInPlace(occurrence, clamp) {
6155
- const clone = clonePart(occurrence.part);
6156
- clamp(clone);
6157
6432
  const parts = occurrence.message.parts;
6158
6433
  const index = parts.indexOf(servedPart(occurrence));
6159
6434
  if (index >= 0) {
6435
+ const clone = clamp(occurrence.part);
6436
+ if (clone === servedPart(occurrence))
6437
+ return;
6160
6438
  parts[index] = clone;
6161
6439
  occurrence.served = clone;
6162
6440
  }
@@ -6166,17 +6444,24 @@ function servedPart(occurrence) {
6166
6444
  }
6167
6445
  function skeletonRealToolPart(part, tagId, stripAttachments = false) {
6168
6446
  if (!isRecord(part))
6169
- return;
6447
+ return part;
6170
6448
  const sentinel = `[dropped §${tagId}§]`;
6171
6449
  if (part.type === "tool" && isRecord(part.state)) {
6172
- part.state.output = sentinel;
6450
+ if (part.state.output === sentinel && !needsAttachmentStrip(part.state, stripAttachments))
6451
+ return part;
6452
+ const clone = clonePart(part);
6453
+ const state = clone.state;
6454
+ state.output = sentinel;
6173
6455
  if (stripAttachments)
6174
- part.state.attachments = [];
6175
- return;
6176
- }
6177
- if (part.type === "tool_result") {
6178
- part.content = sentinel;
6456
+ state.attachments = [];
6457
+ return clone;
6179
6458
  }
6459
+ if (part.type === "tool_result" && part.content !== sentinel)
6460
+ return { ...part, content: sentinel };
6461
+ return part;
6462
+ }
6463
+ function needsAttachmentStrip(state, strip) {
6464
+ return strip && (!Array.isArray(state.attachments) || state.attachments.length !== 0);
6180
6465
  }
6181
6466
  function readToolPartRawInput(part) {
6182
6467
  if (!isRecord(part))
@@ -6189,51 +6474,62 @@ function readToolPartRawInput(part) {
6189
6474
  return part.input;
6190
6475
  return;
6191
6476
  }
6477
+ function isDroppedInput(input, sentinel) {
6478
+ return isRecord(input) && Object.keys(input).length === 1 && Object.hasOwn(input, "dropped") && input.dropped === sentinel;
6479
+ }
6192
6480
  function truncateToolPart(part, tagId) {
6193
6481
  if (!isRecord(part))
6194
- return;
6482
+ return part;
6195
6483
  const sentinel = `[dropped §${tagId}§]`;
6196
6484
  if (part.type === "tool" && isRecord(part.state)) {
6197
- const state = part.state;
6485
+ if (part.state.output === sentinel && isDroppedInput(part.state.input, sentinel))
6486
+ return part;
6487
+ const clone = clonePart(part);
6488
+ const state = clone.state;
6198
6489
  state.output = sentinel;
6199
6490
  state.input = droppedInputMarker(tagId);
6200
- return;
6491
+ return clone;
6201
6492
  }
6202
6493
  if (part.type === "tool_result") {
6203
- part.content = sentinel;
6204
- return;
6494
+ return part.content === sentinel ? part : { ...part, content: sentinel };
6205
6495
  }
6206
6496
  if (part.type === "tool-invocation") {
6207
- part.args = droppedInputMarker(tagId);
6208
- return;
6497
+ return isDroppedInput(part.args, sentinel) ? part : { ...part, args: droppedInputMarker(tagId) };
6209
6498
  }
6210
6499
  if (part.type === "tool_use") {
6211
- part.input = droppedInputMarker(tagId);
6500
+ return isDroppedInput(part.input, sentinel) ? part : { ...part, input: droppedInputMarker(tagId) };
6212
6501
  }
6502
+ return part;
6213
6503
  }
6214
6504
  function editMarkerToolPart(part, tagId, stripAttachments = false) {
6215
6505
  if (!isRecord(part))
6216
- return;
6506
+ return part;
6217
6507
  const sentinel = `[dropped §${tagId}§]`;
6508
+ const input = readToolPartInput(part);
6509
+ const rewriteInput = input !== null && needsEditMarker(input);
6218
6510
  if (part.type === "tool" && isRecord(part.state)) {
6219
- part.state.output = sentinel;
6511
+ if (part.state.output === sentinel && !rewriteInput && !needsAttachmentStrip(part.state, stripAttachments))
6512
+ return part;
6513
+ const clone = clonePart(part);
6514
+ const state = clone.state;
6515
+ state.output = sentinel;
6220
6516
  if (stripAttachments)
6221
- part.state.attachments = [];
6222
- if (isRecord(part.state.input))
6223
- applyEditMarkerToInput(part.state.input);
6224
- return;
6517
+ state.attachments = [];
6518
+ if (rewriteInput) {
6519
+ state.input = { ...input };
6520
+ applyEditMarkerToInput(state.input);
6521
+ }
6522
+ return clone;
6225
6523
  }
6226
6524
  if (part.type === "tool_result") {
6227
- part.content = sentinel;
6228
- return;
6229
- }
6230
- if (part.type === "tool-invocation" && isRecord(part.args)) {
6231
- applyEditMarkerToInput(part.args);
6232
- return;
6525
+ return part.content === sentinel ? part : { ...part, content: sentinel };
6233
6526
  }
6234
- if (part.type === "tool_use" && isRecord(part.input)) {
6235
- applyEditMarkerToInput(part.input);
6527
+ if (rewriteInput) {
6528
+ const markedInput = { ...input };
6529
+ applyEditMarkerToInput(markedInput);
6530
+ return { ...part, [part.type === "tool-invocation" ? "args" : "input"]: markedInput };
6236
6531
  }
6532
+ return part;
6237
6533
  }
6238
6534
  function readToolPartInput(part) {
6239
6535
  if (!isRecord(part))
@@ -6462,9 +6758,7 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
6462
6758
  parts
6463
6759
  });
6464
6760
  const before = count(parts);
6465
- const retained = skeleton ? structuredClone(parts) : [];
6466
- for (const part of retained)
6467
- skeletonRealToolPart(part, tagId);
6761
+ const retained = skeleton ? parts.map((part) => skeletonRealToolPart(part, tagId)) : [];
6468
6762
  const after = count(retained);
6469
6763
  return {
6470
6764
  beforeTools: before.toolCall,
@@ -7374,4 +7668,4 @@ function readSessionChunk2(sessionId, tokenBudget, offset = 1, eligibleEndOrdina
7374
7668
  toolResultBoundaries
7375
7669
  };
7376
7670
  }
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 };
7671
+ export { toolTemplateError, DEFAULT_PROTECTED_TOOLS, normalizeProtectedToolName, mergeProtectedTools, detectLatestTurnThinkingMismatch, isPrefixBoundThinkingModel, detectOverflow, stripWellFormedLeadingTagPrefix, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, isRecord, protectedToolTagNumbers, protectedToolTokenCount, textMentionsRecentCommit, removeSystemReminders, 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, 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, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, stripSystemInjection, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, 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 };