@retaw106/mmc-oc 2.4.0 → 2.6.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 (188) hide show
  1. package/dist/{context-c72brxe5.js → context-cfbjrr0n.js} +1636 -513
  2. package/dist/features/magic-context/compaction-marker.d.ts +34 -6
  3. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  4. package/dist/features/magic-context/message-index-async.d.ts +6 -2
  5. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  6. package/dist/features/magic-context/message-index.d.ts +0 -26
  7. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  8. package/dist/features/magic-context/search.d.ts +5 -1
  9. package/dist/features/magic-context/search.d.ts.map +1 -1
  10. package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -1
  11. package/dist/features/magic-context/session-retention.fixture.d.ts +4 -0
  12. package/dist/features/magic-context/session-retention.fixture.d.ts.map +1 -0
  13. package/dist/features/magic-context/storage-db.d.ts +2 -0
  14. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  15. package/dist/features/magic-context/storage-host-instruction-retention.d.ts +4 -0
  16. package/dist/features/magic-context/storage-host-instruction-retention.d.ts.map +1 -0
  17. package/dist/features/magic-context/storage-meta-persisted.d.ts +21 -1
  18. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  19. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  20. package/dist/features/magic-context/storage-meta-shared.d.ts +2 -2
  21. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  22. package/dist/features/magic-context/storage-native-replay.d.ts +2 -0
  23. package/dist/features/magic-context/storage-native-replay.d.ts.map +1 -1
  24. package/dist/features/magic-context/storage-session-tables.d.ts +5 -4
  25. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  26. package/dist/features/magic-context/tool-definition-tokens.d.ts +113 -58
  27. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  28. package/dist/features/magic-context/work-metrics.d.ts +5 -3
  29. package/dist/features/magic-context/work-metrics.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/apply-operations.d.ts +32 -0
  31. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/ask-answer-notice.d.ts +25 -0
  33. package/dist/hooks/magic-context/ask-answer-notice.d.ts.map +1 -0
  34. package/dist/hooks/magic-context/auto-search-hint.d.ts +3 -0
  35. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +5 -5
  39. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/compaction-marker-publication.d.ts +14 -0
  41. package/dist/hooks/magic-context/compaction-marker-publication.d.ts.map +1 -0
  42. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -2
  44. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +11 -0
  45. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/diagnostic-log-state.d.ts +4 -0
  49. package/dist/hooks/magic-context/diagnostic-log-state.d.ts.map +1 -0
  50. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/file-token-coverage.d.ts +11 -0
  52. package/dist/hooks/magic-context/file-token-coverage.d.ts.map +1 -0
  53. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +11 -3
  54. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/historian-history-wait.d.ts +16 -0
  56. package/dist/hooks/magic-context/historian-history-wait.d.ts.map +1 -0
  57. package/dist/hooks/magic-context/history-boundary-repair.d.ts +1 -1
  58. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/host-served-rows.d.ts +10 -0
  61. package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -1
  62. package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
  63. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  64. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts +3 -1
  67. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/lkg-slot.d.ts +3 -1
  71. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts +3 -0
  73. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts.map +1 -0
  74. package/dist/hooks/magic-context/pass-outcome.d.ts +2 -0
  75. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  76. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -1
  77. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -0
  78. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  79. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  80. package/dist/hooks/magic-context/read-session-db.d.ts +8 -2
  81. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  82. package/dist/hooks/magic-context/read-session-raw.d.ts +20 -0
  83. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +3 -3
  85. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts +42 -0
  87. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts.map +1 -0
  88. package/dist/hooks/magic-context/system-date-refresh.d.ts +3 -2
  89. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts +4 -0
  92. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts.map +1 -0
  93. package/dist/hooks/magic-context/tag-content-primitives.d.ts +1 -1
  94. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/tag-messages.d.ts +17 -2
  96. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  97. package/dist/hooks/magic-context/text-complete.d.ts +1 -1
  98. package/dist/hooks/magic-context/text-complete.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/tool-drop-target.d.ts +3 -2
  100. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  101. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
  102. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +6 -0
  104. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/transform-stage-logger.d.ts +3 -0
  106. package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/transform.d.ts +4 -2
  108. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  109. package/dist/{index-27ddyx39.js → index-1np16gxq.js} +1 -1
  110. package/dist/{index-ykq24x1n.js → index-8rmt6s4f.js} +78 -32
  111. package/dist/{index-dwh99z66.js → index-pte3cfs9.js} +194 -5
  112. package/dist/{index-r7s7d350.js → index-s3ebcy63.js} +1 -1
  113. package/dist/{index-48e9znrc.js → index-t0zx3tgz.js} +481 -109
  114. package/dist/{index-kahkxcqw.js → index-xk1dz6q9.js} +870 -315
  115. package/dist/index.js +2 -2
  116. package/dist/{message-time-backfill-j96x1sab.js → message-time-backfill-g9py24yt.js} +1 -1
  117. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  118. package/dist/plugin/subagent-tool-policy.d.ts +4 -0
  119. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -1
  120. package/dist/{read-session-chunk-t8bg6wkz.js → read-session-chunk-2s8x6xps.js} +3 -3
  121. package/dist/{recomp-orchestrator-k760qy1n.js → recomp-orchestrator-51xyaexp.js} +6 -6
  122. package/dist/{send-session-notification-njjf3b4s.js → send-session-notification-vdppp5x6.js} +3 -3
  123. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  124. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  125. package/dist/shared/rpc-discovery-cleanup.d.ts +3 -0
  126. package/dist/shared/rpc-discovery-cleanup.d.ts.map +1 -0
  127. package/dist/shared/rpc-server.d.ts +2 -0
  128. package/dist/shared/rpc-server.d.ts.map +1 -1
  129. package/dist/shared/search-text.d.ts +8 -0
  130. package/dist/shared/search-text.d.ts.map +1 -0
  131. package/dist/shared/sqlite.d.ts +6 -1
  132. package/dist/shared/sqlite.d.ts.map +1 -1
  133. package/dist/shared/storage-file-mutex.d.ts.map +1 -1
  134. package/dist/shared/system-directive.d.ts +2 -0
  135. package/dist/shared/system-directive.d.ts.map +1 -1
  136. package/dist/shared/tag-transcript.d.ts +2 -0
  137. package/dist/shared/tag-transcript.d.ts.map +1 -1
  138. package/dist/shared/transcript.d.ts +3 -1
  139. package/dist/shared/transcript.d.ts.map +1 -1
  140. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  141. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  142. package/dist/tools/parameter-descriptions.d.ts +6 -6
  143. package/dist/tools/parameter-descriptions.d.ts.map +1 -1
  144. package/dist/v2/fold/native-replay.d.ts +11 -2
  145. package/dist/v2/fold/native-replay.d.ts.map +1 -1
  146. package/dist/v2/fold/policy.d.ts.map +1 -1
  147. package/dist/v2/fold/restore.d.ts.map +1 -1
  148. package/dist/v2/hooks/context.d.ts +4 -0
  149. package/dist/v2/hooks/context.d.ts.map +1 -1
  150. package/dist/v2/hooks/generate.d.ts +36 -1
  151. package/dist/v2/hooks/generate.d.ts.map +1 -1
  152. package/dist/v2/hooks/lkg-system.d.ts +35 -4
  153. package/dist/v2/hooks/lkg-system.d.ts.map +1 -1
  154. package/dist/v2/hooks/payload.d.ts +10 -1
  155. package/dist/v2/hooks/payload.d.ts.map +1 -1
  156. package/dist/v2/hooks/store.d.ts +2 -0
  157. package/dist/v2/hooks/store.d.ts.map +1 -1
  158. package/dist/v2/hooks/types.d.ts +12 -0
  159. package/dist/v2/hooks/types.d.ts.map +1 -1
  160. package/dist/v2/message-times.d.ts +17 -0
  161. package/dist/v2/message-times.d.ts.map +1 -0
  162. package/dist/v2/server.js +4692 -2394
  163. package/dist/v2/store-reader.d.ts +21 -0
  164. package/dist/v2/store-reader.d.ts.map +1 -1
  165. package/dist/web/main.js +307 -12
  166. package/dist/{wrapup-orchestrator-b2gswatj.js → wrapup-orchestrator-g0mww1h4.js} +6 -6
  167. package/package.json +1 -1
  168. package/src/config/latch-permanence-guard.test.ts +4 -5
  169. package/src/shared/model-suggestion-retry.test.ts +52 -0
  170. package/src/shared/model-suggestion-retry.ts +8 -3
  171. package/src/shared/prompt-surface-a1-golden.md +6 -7
  172. package/src/shared/rpc-discovery-cleanup.test.ts +125 -0
  173. package/src/shared/rpc-discovery-cleanup.ts +57 -0
  174. package/src/shared/rpc-server.ts +36 -13
  175. package/src/shared/search-text.test.ts +30 -0
  176. package/src/shared/search-text.ts +62 -0
  177. package/src/shared/sqlite-transaction-mode-guard.test.ts +2 -0
  178. package/src/shared/sqlite-turn-deadline.test.ts +286 -0
  179. package/src/shared/sqlite.ts +237 -9
  180. package/src/shared/storage-file-mutex.test.ts +51 -2
  181. package/src/shared/storage-file-mutex.ts +11 -1
  182. package/src/shared/system-directive.test.ts +37 -0
  183. package/src/shared/system-directive.ts +19 -1
  184. package/src/shared/tag-transcript.ts +63 -8
  185. package/src/shared/transcript.ts +1 -1
  186. package/src/shared/write-transaction-attribution.test.ts +1 -6
  187. package/dist/features/magic-context/message-index-sweep.d.ts +0 -11
  188. package/dist/features/magic-context/message-index-sweep.d.ts.map +0 -1
@@ -0,0 +1,37 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { removeNestedBlocks, removeSystemReminders } from "./system-directive";
3
+
4
+ describe("removeSystemReminders", () => {
5
+ test("removes nested reminders without leaking the outer tail", () => {
6
+ expect(
7
+ removeSystemReminders(
8
+ "before <system-reminder>outer <system-reminder>inner</system-reminder> tail</system-reminder> after",
9
+ ),
10
+ ).toBe("before after");
11
+ });
12
+
13
+ test("removes unclosed reminders through the end", () => {
14
+ expect(
15
+ removeSystemReminders(
16
+ " keep <system-reminder>hidden <system-reminder>nested</system-reminder> tail",
17
+ ),
18
+ ).toBe("keep");
19
+ });
20
+
21
+ test("handles attributes, case, self-closing tags and adjacent blocks", () => {
22
+ expect(
23
+ removeSystemReminders(
24
+ 'a<SYSTEM-REMINDER id="x">hidden</SYSTEM-REMINDER><system-reminder/>b<system-reminder>hidden</system-reminder>c',
25
+ ),
26
+ ).toBe("abc");
27
+ });
28
+
29
+ test("preserves ordinary content and other tags", () => {
30
+ expect(removeSystemReminders(" <other>visible</other> ")).toBe("<other>visible</other>");
31
+ });
32
+ });
33
+
34
+ test("removeNestedBlocks tracks multiple tag names and only closes the matching top", () => {
35
+ expect(removeNestedBlocks("a<one>x<two>y</one>z</two>tail</one>b", ["one", "two"])).toBe("ab");
36
+ expect(removeNestedBlocks(" a<one/>b ", ["one"])).toBe(" ab ");
37
+ });
@@ -5,5 +5,23 @@ export function isSystemDirective(text: string): boolean {
5
5
  }
6
6
 
7
7
  export function removeSystemReminders(text: string): string {
8
- return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
8
+ return removeNestedBlocks(text, ["system-reminder"]).trim();
9
+ }
10
+
11
+ /** Remove matching tagged regions, including nested regions and regions with no closing tag. */
12
+ export function removeNestedBlocks(text: string, names: readonly string[]): string {
13
+ const tags = new RegExp(`<(/?)(${names.join("|")})(?:\\s[^<>]*?)?\\s*(/?)>`, "gi");
14
+ const stack: string[] = [];
15
+ let end = 0;
16
+ let result = "";
17
+ for (const match of text.matchAll(tags)) {
18
+ if (stack.length === 0) result += text.slice(end, match.index);
19
+ const name = match[2].toLowerCase();
20
+ if (match[1]) {
21
+ if (stack[stack.length - 1] === name) stack.pop();
22
+ } else if (!match[3]) stack.push(name);
23
+ end = match.index + match[0].length;
24
+ }
25
+ if (stack.length === 0) result += text.slice(end);
26
+ return result;
9
27
  }
@@ -75,6 +75,8 @@ import type { Transcript, TranscriptMessage, TranscriptPart } from "./transcript
75
75
  export { TEXT_TAG_IDENTITY_MARKER };
76
76
 
77
77
  export interface TagTranscriptOptions {
78
+ /** Independently validated text sources; does not authorize tool accounting reuse. */
79
+ reuseTextMessageIds?: ReadonlySet<string>;
78
80
  /**
79
81
  * When true, skip injecting `§N§` prefix into visible text. Tags
80
82
  * still get assigned in the DB so historian/drops can reference
@@ -305,6 +307,12 @@ interface ToolAggregate {
305
307
  maxByteSize: number;
306
308
  /** Token count paired with maxByteSize (the same output occurrence). */
307
309
  maxTokenCount: number;
310
+ /**
311
+ * Whether maxTokenCount is a real count. Legacy rows can store bytes with a
312
+ * NULL token_count; seeding 0 from that must not look like a stored count,
313
+ * or unchanged results would never be recounted.
314
+ */
315
+ tokenCountKnown: boolean;
308
316
  /** Tool name from the first occurrence we see one on. */
309
317
  toolName: string | null;
310
318
  /** Input byte size from the invocation occurrence (for storage projection). */
@@ -417,7 +425,10 @@ export function tagTranscript(
417
425
  targets,
418
426
  skipPrefixInjection,
419
427
  entryFingerprint: options.entryFingerprintByMessageId?.get(messageId) ?? null,
420
- reuseIdentity: reuseIdentity || contentDerivedTextIds !== undefined,
428
+ reuseIdentity:
429
+ reuseIdentity ||
430
+ options.reuseTextMessageIds?.has(messageId) === true ||
431
+ contentDerivedTextIds !== undefined,
421
432
  timing,
422
433
  textIdentitySourceCache: options.textIdentitySourceCache,
423
434
  textTokenCache: options.textTokenCache,
@@ -508,6 +519,13 @@ export function tagTranscript(
508
519
  timing,
509
520
  options.toolTokenCache,
510
521
  tokenCacheKey,
522
+ {
523
+ byteSize: existing.maxByteSize,
524
+ tokenCount: existing.tokenCountKnown
525
+ ? existing.maxTokenCount
526
+ : null,
527
+ inputTokenCount: existing.inputTokenCount,
528
+ },
511
529
  );
512
530
  text = accounting.text;
513
531
  if (part.kind === "tool_result") {
@@ -596,6 +614,7 @@ export function tagTranscript(
596
614
  // genuinely larger folded result can still bump accounting.
597
615
  maxByteSize: reusableAccounting.byteSize,
598
616
  maxTokenCount: reusableAccounting.tokenCount ?? 0,
617
+ tokenCountKnown: reusableAccounting.tokenCount !== null,
599
618
  toolName: null,
600
619
  inputByteSize: reusableAccounting.inputByteSize,
601
620
  inputTokenCount: reusableAccounting.inputTokenCount,
@@ -623,6 +642,7 @@ export function tagTranscript(
623
642
  timing,
624
643
  options.toolTokenCache,
625
644
  tokenCacheKey,
645
+ tagger.getToolTagAccounting(sessionId, callId, messageId),
626
646
  );
627
647
  text = accounting.text;
628
648
  const outputByteSize = part.kind === "tool_result" ? accounting.byteSize : 0;
@@ -657,6 +677,11 @@ export function tagTranscript(
657
677
  occurrences: [{ message, part, kind: part.kind }],
658
678
  maxByteSize: persistedAccounting?.byteSize ?? outputByteSize,
659
679
  maxTokenCount: persistedAccounting?.tokenCount ?? outputTokenCount,
680
+ // A fresh allocation just wrote outputTokenCount (0 for an
681
+ // invocation); an existing row keeps its NULL as unknown.
682
+ tokenCountKnown: persistedAccounting
683
+ ? persistedAccounting.tokenCount !== null
684
+ : true,
660
685
  toolName: accounting.toolName,
661
686
  inputByteSize:
662
687
  persistedAccounting?.inputByteSize ??
@@ -745,7 +770,9 @@ function syncToolAggregateAccounting(
745
770
  ): void {
746
771
  tagger.setToolTagAccounting(sessionId, aggregate.tagId, {
747
772
  byteSize: aggregate.maxByteSize,
748
- tokenCount: aggregate.maxTokenCount,
773
+ // Unknown stays unknown so the next occurrence/pass recounts instead of
774
+ // caching a fabricated 0 for a legacy row.
775
+ tokenCount: aggregate.tokenCountKnown ? aggregate.maxTokenCount : null,
749
776
  inputByteSize: aggregate.inputByteSize,
750
777
  inputTokenCount: aggregate.inputTokenCount,
751
778
  });
@@ -770,6 +797,7 @@ function applyGrownToolResultAccounting(args: GrownToolResultAccountingArgs): vo
770
797
  }
771
798
  args.aggregate.maxByteSize = args.byteSize;
772
799
  args.aggregate.maxTokenCount = tokenCount;
800
+ args.aggregate.tokenCountKnown = true;
773
801
  updateTagByteSize(args.db, args.sessionId, args.aggregate.tagId, args.byteSize);
774
802
  updateTagTokenCount(args.db, args.sessionId, args.aggregate.tagId, tokenCount);
775
803
  syncToolAggregateAccounting(args.tagger, args.sessionId, args.aggregate);
@@ -780,12 +808,22 @@ function readAggregateToolAccounting(
780
808
  timing: TagTranscriptTiming | undefined,
781
809
  tokenCache?: Map<string, { text: string; tokenCount: number }>,
782
810
  tokenCacheKey?: string,
811
+ persisted?: { byteSize: number; tokenCount: number | null; inputTokenCount: number | null },
783
812
  ): AggregateToolAccounting {
784
813
  const text = part.getText() ?? "";
785
814
  const byteSize = getToolPartByteSize(part, text);
786
- const metadata = part.getToolMetadata();
815
+ // Persisted tool-result accounting tracks the largest byte size seen. Skip
816
+ // output tokenization when that size has not grown and a count is stored;
817
+ // known input counts also need no tokenization. Growth and missing counts still take
818
+ // the original counting path, even when the identity was not reusable.
819
+ const metadata = part.getToolMetadata({
820
+ skipInputTokenCount: persisted?.inputTokenCount != null,
821
+ });
787
822
  let tokenCount = 0;
788
- if (part.kind === "tool_result") {
823
+ if (
824
+ part.kind === "tool_result" &&
825
+ (!persisted || persisted.tokenCount === null || byteSize > persisted.byteSize)
826
+ ) {
789
827
  const tokenStart = timing ? performance.now() : 0;
790
828
  tokenCount = getCachedToolPartTokenCount(part, text, tokenCache, tokenCacheKey);
791
829
  if (timing) timing.tokenCounting += performance.now() - tokenStart;
@@ -835,12 +873,17 @@ class ConversationEndGuard {
835
873
  }
836
874
  }
837
875
 
838
- wouldStrand(occurrences: readonly ToolOccurrence[]): boolean {
876
+ wouldStrand(
877
+ occurrences: readonly ToolOccurrence[],
878
+ plannedRemovals?: ReadonlySet<unknown>,
879
+ ): boolean {
839
880
  const end = this.end;
840
881
  if (!end || !occurrences.some((occ) => occ.message === end)) return false;
841
882
  const leaving = new Set(occurrences.map((occ) => partKey(occ.part)));
842
883
  const survives = (part: TranscriptPart) =>
843
- !leaving.has(partKey(part)) && !this.removed.has(partKey(part));
884
+ !leaving.has(partKey(part)) &&
885
+ !this.removed.has(partKey(part)) &&
886
+ !plannedRemovals?.has(partKey(part));
844
887
  return end.info.role === "assistant"
845
888
  ? !end.parts.some((part) => part.kind === "tool_result" && survives(part))
846
889
  : !end.parts.some((part) => partHasContent(part) && survives(part));
@@ -1379,8 +1422,11 @@ function buildAggregateTarget(
1379
1422
  }
1380
1423
  return null;
1381
1424
  },
1382
- wouldStrandConversationEnd(): boolean {
1383
- return conversationEnd?.wouldStrand(occurrences) ?? false;
1425
+ wouldStrandConversationEnd(plannedRemovals): boolean {
1426
+ return conversationEnd?.wouldStrand(occurrences, plannedRemovals) ?? false;
1427
+ },
1428
+ notePlannedRemoval(plannedRemovals): void {
1429
+ for (const occ of occurrences) plannedRemovals.add(partKey(occ.part));
1384
1430
  },
1385
1431
  editMarker(): "truncated" | "absent" {
1386
1432
  // Edit-marker: preserve the tool_use input's filePath + a region
@@ -1406,6 +1452,11 @@ function buildAggregateTarget(
1406
1452
  },
1407
1453
  // Open invocations still belong to the current turn; only complete arcs reclaim.
1408
1454
  prepareDrop: () => !occurrences.some((occ) => occ.part.canRemove?.() === "defer"),
1455
+ prepareReplayDrop: () => {
1456
+ if (complete() && !requiresToolArcSkeleton) {
1457
+ for (const occ of occurrences) occ.part.canRemove?.();
1458
+ }
1459
+ },
1409
1460
  canDrop: () => complete() && !occurrences.some((occ) => occ.part.hasUserAnswer?.()),
1410
1461
  requiresToolArcSkeleton,
1411
1462
  // Non-mutating read of the invocation input (the tool_use occurrence
@@ -1443,6 +1494,10 @@ function buildTextTarget(
1443
1494
  return {
1444
1495
  mutationParts: [{ message: { info: message.info, parts: [] }, part }],
1445
1496
  textPrefix,
1497
+ canSetContent(content): boolean {
1498
+ const current = part.getText();
1499
+ return typeof current === "string" && current !== content;
1500
+ },
1446
1501
  setContent(content: string): boolean {
1447
1502
  return part.setText(content);
1448
1503
  },
@@ -132,7 +132,7 @@ export interface TranscriptPart {
132
132
  *
133
133
  * For non-tool parts both byte fields are undefined/0.
134
134
  */
135
- getToolMetadata(): {
135
+ getToolMetadata(options?: { skipInputTokenCount?: boolean }): {
136
136
  toolName: string | undefined;
137
137
  inputByteSize: number;
138
138
  inputTokenCount: number;
@@ -14,11 +14,7 @@ const fencedSources: Array<{ path: string; sites: string[]; reporterCalls?: stri
14
14
  },
15
15
  {
16
16
  path: "packages/plugin/src/features/magic-context/message-index.ts",
17
- sites: [
18
- "message_index_incremental",
19
- "message_index_reconcile",
20
- "message_index_orphan_sweep",
21
- ],
17
+ sites: ["message_index_incremental", "message_index_reconcile"],
22
18
  },
23
19
  {
24
20
  path: "packages/plugin/src/features/magic-context/storage-meta-persisted.ts",
@@ -101,7 +97,6 @@ const newlyCoveredSites = [
101
97
  "opencode_soft_refresh_cache",
102
98
  "message_index_incremental",
103
99
  "message_index_reconcile",
104
- "message_index_orphan_sweep",
105
100
  "message_index_clear",
106
101
  "message_fts_rowid_backfill",
107
102
  "storage_meta_wrapup_expiry_cleanup",
@@ -1,11 +0,0 @@
1
- import type { Database } from "../../shared/sqlite";
2
- import { type MessageHistoryOrphanSweepOptions, type MessageHistoryOrphanSweepResult } from "./message-index";
3
- /**
4
- * Scope wrapper for the background sweep. It lives beside `message-index` rather
5
- * than inside it: importing the transform-pass scope helpers into
6
- * `message-index.ts` itself changes the bundled module graph in a way that hits
7
- * a Bun 1.4.2 packaging bug (a top-level `__promiseAll` init call is emitted
8
- * without its definition, which crashes node hosts at import time).
9
- */
10
- export declare function sweepOrphanedOpenCodeMessageIndexes(db: Database, openReadableOpenCodeDb: () => Database | null, options?: MessageHistoryOrphanSweepOptions): MessageHistoryOrphanSweepResult;
11
- //# sourceMappingURL=message-index-sweep.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message-index-sweep.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/message-index-sweep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACH,KAAK,gCAAgC,EACrC,KAAK,+BAA+B,EAEvC,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAC/C,EAAE,EAAE,QAAQ,EACZ,sBAAsB,EAAE,MAAM,QAAQ,GAAG,IAAI,EAC7C,OAAO,GAAE,gCAAqC,GAC/C,+BAA+B,CAMjC"}