@librechat/agents 3.7.7 → 3.7.9

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 (167) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +26 -5
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/constants.cjs +12 -0
  4. package/dist/cjs/common/constants.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +56 -11
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
  8. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  9. package/dist/cjs/hooks/executeHooks.cjs +8 -0
  10. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  11. package/dist/cjs/hooks/index.cjs +2 -0
  12. package/dist/cjs/hooks/index.cjs.map +1 -1
  13. package/dist/cjs/hooks/types.cjs +1 -0
  14. package/dist/cjs/hooks/types.cjs.map +1 -1
  15. package/dist/cjs/langfuse.cjs +43 -3
  16. package/dist/cjs/langfuse.cjs.map +1 -1
  17. package/dist/cjs/langfuseTraceShaping.cjs +75 -0
  18. package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
  19. package/dist/cjs/llm/bedrock/toolCache.cjs +1 -1
  20. package/dist/cjs/llm/fake.cjs +9 -5
  21. package/dist/cjs/llm/fake.cjs.map +1 -1
  22. package/dist/cjs/llm/invoke.cjs +3 -7
  23. package/dist/cjs/llm/invoke.cjs.map +1 -1
  24. package/dist/cjs/llm/openrouter/toolCache.cjs +1 -1
  25. package/dist/cjs/llm/prepareProviderRequest.cjs +2 -2
  26. package/dist/cjs/llm/providers.cjs +1 -1
  27. package/dist/cjs/llm/request.cjs +6 -0
  28. package/dist/cjs/llm/request.cjs.map +1 -1
  29. package/dist/cjs/llm/truncation.cjs +1 -0
  30. package/dist/cjs/main.cjs +22 -13
  31. package/dist/cjs/messages/format.cjs +375 -3
  32. package/dist/cjs/messages/format.cjs.map +1 -1
  33. package/dist/cjs/messages/index.cjs +1 -1
  34. package/dist/cjs/messages/prune.cjs +1 -1
  35. package/dist/cjs/run.cjs +217 -52
  36. package/dist/cjs/run.cjs.map +1 -1
  37. package/dist/cjs/session/AgentSession.cjs +1 -1
  38. package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
  39. package/dist/cjs/stream.cjs +1 -1
  40. package/dist/cjs/summarization/index.cjs +1 -0
  41. package/dist/cjs/summarization/index.cjs.map +1 -1
  42. package/dist/cjs/summarization/node.cjs +58 -85
  43. package/dist/cjs/summarization/node.cjs.map +1 -1
  44. package/dist/cjs/summarization/semanticIndex.cjs +366 -0
  45. package/dist/cjs/summarization/semanticIndex.cjs.map +1 -0
  46. package/dist/cjs/summarization/shared.cjs +83 -0
  47. package/dist/cjs/summarization/shared.cjs.map +1 -0
  48. package/dist/cjs/tools/ToolNode.cjs +5 -5
  49. package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
  50. package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
  51. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +1 -1
  52. package/dist/cjs/tools/runStepResume.cjs +1 -1
  53. package/dist/cjs/tools/runStepResume.cjs.map +1 -1
  54. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +8 -12
  55. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  56. package/dist/cjs/tools/subagent/childGraphConfig.cjs +2 -1
  57. package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
  58. package/dist/cjs/utils/index.cjs +1 -1
  59. package/dist/cjs/utils/tokens.cjs +8 -1
  60. package/dist/cjs/utils/tokens.cjs.map +1 -1
  61. package/dist/esm/agents/AgentContext.mjs +26 -5
  62. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  63. package/dist/esm/common/constants.mjs +11 -1
  64. package/dist/esm/common/constants.mjs.map +1 -1
  65. package/dist/esm/graphs/Graph.mjs +56 -11
  66. package/dist/esm/graphs/Graph.mjs.map +1 -1
  67. package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
  68. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  69. package/dist/esm/hooks/executeHooks.mjs +8 -1
  70. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  71. package/dist/esm/hooks/index.mjs +2 -1
  72. package/dist/esm/hooks/index.mjs.map +1 -1
  73. package/dist/esm/hooks/types.mjs +1 -0
  74. package/dist/esm/hooks/types.mjs.map +1 -1
  75. package/dist/esm/langfuse.mjs +43 -3
  76. package/dist/esm/langfuse.mjs.map +1 -1
  77. package/dist/esm/langfuseTraceShaping.mjs +75 -0
  78. package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
  79. package/dist/esm/llm/bedrock/toolCache.mjs +1 -1
  80. package/dist/esm/llm/fake.mjs +9 -5
  81. package/dist/esm/llm/fake.mjs.map +1 -1
  82. package/dist/esm/llm/invoke.mjs +3 -7
  83. package/dist/esm/llm/invoke.mjs.map +1 -1
  84. package/dist/esm/llm/openrouter/toolCache.mjs +1 -1
  85. package/dist/esm/llm/prepareProviderRequest.mjs +2 -2
  86. package/dist/esm/llm/providers.mjs +1 -1
  87. package/dist/esm/llm/request.mjs +6 -1
  88. package/dist/esm/llm/request.mjs.map +1 -1
  89. package/dist/esm/llm/truncation.mjs +1 -1
  90. package/dist/esm/main.mjs +15 -14
  91. package/dist/esm/messages/format.mjs +375 -3
  92. package/dist/esm/messages/format.mjs.map +1 -1
  93. package/dist/esm/messages/index.mjs +1 -1
  94. package/dist/esm/messages/prune.mjs +1 -1
  95. package/dist/esm/run.mjs +217 -52
  96. package/dist/esm/run.mjs.map +1 -1
  97. package/dist/esm/session/AgentSession.mjs +1 -1
  98. package/dist/esm/session/JsonlSessionStore.mjs +1 -1
  99. package/dist/esm/stream.mjs +1 -1
  100. package/dist/esm/summarization/index.mjs +1 -0
  101. package/dist/esm/summarization/index.mjs.map +1 -1
  102. package/dist/esm/summarization/node.mjs +57 -84
  103. package/dist/esm/summarization/node.mjs.map +1 -1
  104. package/dist/esm/summarization/semanticIndex.mjs +363 -0
  105. package/dist/esm/summarization/semanticIndex.mjs.map +1 -0
  106. package/dist/esm/summarization/shared.mjs +79 -0
  107. package/dist/esm/summarization/shared.mjs.map +1 -0
  108. package/dist/esm/tools/ToolNode.mjs +5 -5
  109. package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
  110. package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
  111. package/dist/esm/tools/local/LocalExecutionEngine.mjs +1 -1
  112. package/dist/esm/tools/runStepResume.mjs +1 -1
  113. package/dist/esm/tools/runStepResume.mjs.map +1 -1
  114. package/dist/esm/tools/subagent/SubagentExecutor.mjs +8 -12
  115. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  116. package/dist/esm/tools/subagent/childGraphConfig.mjs +2 -1
  117. package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
  118. package/dist/esm/utils/index.mjs +1 -1
  119. package/dist/esm/utils/tokens.mjs +8 -2
  120. package/dist/esm/utils/tokens.mjs.map +1 -1
  121. package/dist/types/agents/AgentContext.d.ts +27 -1
  122. package/dist/types/common/constants.d.ts +17 -0
  123. package/dist/types/graphs/Graph.d.ts +24 -0
  124. package/dist/types/hooks/executeHooks.d.ts +5 -2
  125. package/dist/types/hooks/index.d.ts +7 -2
  126. package/dist/types/hooks/types.d.ts +45 -7
  127. package/dist/types/langfuse.d.ts +3 -1
  128. package/dist/types/llm/fake.d.ts +12 -2
  129. package/dist/types/llm/request.d.ts +10 -0
  130. package/dist/types/messages/format.d.ts +17 -2
  131. package/dist/types/run.d.ts +19 -6
  132. package/dist/types/summarization/index.d.ts +6 -0
  133. package/dist/types/summarization/node.d.ts +0 -4
  134. package/dist/types/summarization/semanticIndex.d.ts +21 -0
  135. package/dist/types/summarization/shared.d.ts +25 -0
  136. package/dist/types/types/graph.d.ts +9 -1
  137. package/dist/types/types/run.d.ts +8 -0
  138. package/dist/types/types/stream.d.ts +6 -0
  139. package/dist/types/types/summarize.d.ts +44 -0
  140. package/dist/types/utils/tokens.d.ts +9 -0
  141. package/package.json +2 -1
  142. package/src/agents/AgentContext.ts +63 -6
  143. package/src/common/constants.ts +19 -0
  144. package/src/graphs/Graph.ts +86 -8
  145. package/src/hooks/HookRegistry.ts +3 -1
  146. package/src/hooks/executeHooks.ts +20 -2
  147. package/src/hooks/index.ts +12 -1
  148. package/src/hooks/types.ts +47 -4
  149. package/src/langfuse.ts +70 -0
  150. package/src/langfuseTraceShaping.ts +94 -0
  151. package/src/llm/fake.ts +35 -4
  152. package/src/llm/invoke.ts +13 -29
  153. package/src/llm/request.ts +24 -0
  154. package/src/messages/format.ts +839 -5
  155. package/src/run.ts +393 -187
  156. package/src/summarization/index.ts +11 -0
  157. package/src/summarization/node.ts +202 -158
  158. package/src/summarization/semanticIndex.ts +662 -0
  159. package/src/summarization/shared.ts +130 -0
  160. package/src/tools/runStepResume.ts +9 -0
  161. package/src/tools/subagent/SubagentExecutor.ts +4 -27
  162. package/src/tools/subagent/childGraphConfig.ts +3 -0
  163. package/src/types/graph.ts +9 -0
  164. package/src/types/run.ts +8 -0
  165. package/src/types/stream.ts +6 -0
  166. package/src/types/summarize.ts +57 -0
  167. package/src/utils/tokens.ts +31 -8
@@ -28,6 +28,9 @@ import type {
28
28
  TPayload,
29
29
  TMessage,
30
30
  ProviderName,
31
+ CompactionSemanticIndex,
32
+ CompactionSemanticIndexEntry,
33
+ CompactionSemanticIndexSnapshot,
31
34
  } from '@/types';
32
35
  import type {
33
36
  ProviderMessageAttribution,
@@ -50,17 +53,27 @@ import {
50
53
  setInvalidProviderMessageProvenance,
51
54
  setProviderMessageProvenance,
52
55
  } from './provenance';
56
+ import {
57
+ snapshotCompactionSemanticIndex,
58
+ getCompactionSemanticIndexProvidedEntryCount,
59
+ setCompactionSemanticIndexProvidedEntryCount,
60
+ } from '@/summarization/semanticIndex';
53
61
  import {
54
62
  compactToolContent,
55
63
  getToolContentCharLength,
56
64
  isAtomicToolContentBlock,
57
65
  serializeStructuredValueBounded,
58
66
  } from '@/utils/toolContent';
67
+ import {
68
+ Providers,
69
+ ContentTypes,
70
+ Constants,
71
+ COMPACTION_SEMANTIC_INDEX_LIMITS,
72
+ } from '@/common';
59
73
  import { normalizeAnthropicToolCallId } from '@/llm/anthropic/utils/message_inputs';
60
74
  import { toLangChainContent, toLangChainMessageFields } from './langchain';
61
75
  import { flattenLegacyContent, isLegacyConvertible } from './content';
62
76
  import { HARD_MAX_TOOL_RESULT_CHARS } from '@/utils/truncation';
63
- import { Providers, ContentTypes, Constants } from '@/common';
64
77
  import { emitAgentLog } from '@/utils/events';
65
78
 
66
79
  interface MediaMessageParams {
@@ -367,9 +380,12 @@ export const formatFromLangChain = (
367
380
  };
368
381
 
369
382
  interface FormatAssistantMessageOptions {
383
+ compactionSemanticIndex?: DerivedCompactionSemanticIndexCollector;
384
+ intentToolNames?: ReadonlySet<string>;
370
385
  preserveUnpairedServerToolUses?: boolean;
371
386
  preserveReasoningContent?: boolean;
372
387
  provider?: ProviderName;
388
+ retainedSourceContentEnd?: number;
373
389
  sourceMessageId?: string;
374
390
  sourceContentPartOffset?: number;
375
391
  sourceContentPartIndices?: readonly SourceContentPartIndices[];
@@ -378,7 +394,7 @@ interface FormatAssistantMessageOptions {
378
394
 
379
395
  type SourceContentPartIndices = number | readonly number[];
380
396
 
381
- interface FormatAgentMessagesOptions {
397
+ export interface FormatAgentMessagesOptions {
382
398
  provider?: ProviderName;
383
399
  /** Emit flattenable text content as the joined string the legacy-content
384
400
  * projection would produce, so the per-request `formatContentStrings` pass
@@ -394,6 +410,17 @@ interface FormatAgentMessagesOptions {
394
410
  * historical `skill` tool_calls are not reconstructed into a HumanMessage,
395
411
  * so the same SKILL.md body is not injected twice in one request. */
396
412
  skipSkillBodyNames?: Set<string>;
413
+ /** Derive bounded compaction guidance during the formatter's existing
414
+ * persisted-content analysis. Tool intents are accepted only for names
415
+ * the host identifies as semantic-label fields; business `intent`
416
+ * parameters must remain ordinary tool input. */
417
+ compactionSemanticIndex?: {
418
+ /** Previously committed, serializable guidance to evolve with entries
419
+ * derived from this payload. The formatter snapshots and validates
420
+ * caller-owned data before scanning the new messages. */
421
+ baseSnapshot?: CompactionSemanticIndexSnapshot;
422
+ intentToolNames?: ReadonlySet<string>;
423
+ };
397
424
  }
398
425
 
399
426
  function extractReasoningContent(
@@ -476,6 +503,712 @@ function getToolUseId(part: MessageContentComplex): string | undefined {
476
503
  return part.tool_use_id;
477
504
  }
478
505
 
506
+ type CompactionSemanticContentPart = MessageContentComplex & {
507
+ activity_label?: string;
508
+ activity_label_type?: string;
509
+ activity_label_revision?: number;
510
+ activity_start_index?: number;
511
+ pending?: boolean;
512
+ reasoning_label?: string;
513
+ reasoning_label_revision?: number;
514
+ reasoning_label_status?: string;
515
+ reasoning_label_step_id?: string;
516
+ };
517
+
518
+ type OrderedCompactionSemanticIndexEntry = {
519
+ entry: CompactionSemanticIndexEntry;
520
+ identityHash: number;
521
+ order: number;
522
+ retentionCount: number;
523
+ };
524
+
525
+ type CompactionSemanticEntryRing = {
526
+ entries: OrderedCompactionSemanticIndexEntry[];
527
+ cursor: number;
528
+ };
529
+
530
+ type CompactionSemanticTypeCoverage = {
531
+ head: OrderedCompactionSemanticIndexEntry[];
532
+ tail: CompactionSemanticEntryRing;
533
+ };
534
+
535
+ type CompactionSemanticCoverageState = {
536
+ head: OrderedCompactionSemanticIndexEntry[];
537
+ tail: CompactionSemanticEntryRing;
538
+ latestByIdentityHash: Map<number, OrderedCompactionSemanticIndexEntry[]>;
539
+ typeCoverage: Map<
540
+ CompactionSemanticIndexEntry['type'],
541
+ CompactionSemanticTypeCoverage
542
+ >;
543
+ };
544
+
545
+ type CompactionSemanticRevisionFloor = {
546
+ entry: CompactionSemanticIndexEntry;
547
+ order: number;
548
+ };
549
+
550
+ type DerivedCompactionSemanticIndexCollector = {
551
+ entries: CompactionSemanticIndexEntry[];
552
+ entryCount: number;
553
+ baseEntryCount: number;
554
+ omittedBaseEntryCount: number;
555
+ baseRevisionFloors?: Map<number, CompactionSemanticRevisionFloor[]>;
556
+ coverage?: CompactionSemanticCoverageState;
557
+ };
558
+
559
+ const DERIVED_SEMANTIC_HEAD_LIMIT =
560
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxInputEntries / 4;
561
+ const DERIVED_SEMANTIC_TAIL_LIMIT =
562
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxInputEntries / 2;
563
+ const DERIVED_SEMANTIC_TYPE_EDGE_LIMIT =
564
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxInputEntries / 32;
565
+ const DERIVED_SEMANTIC_TYPE_HASH: Readonly<
566
+ Record<CompactionSemanticIndexEntry['type'], number>
567
+ > = Object.freeze({
568
+ tool_intent: 1,
569
+ tool_outcome: 2,
570
+ activity_phase: 3,
571
+ reasoning_label: 4,
572
+ });
573
+
574
+ function createDerivedCompactionSemanticIndexCollector(
575
+ baseSnapshot?: CompactionSemanticIndexSnapshot
576
+ ): DerivedCompactionSemanticIndexCollector {
577
+ const collector: DerivedCompactionSemanticIndexCollector = {
578
+ entries: [],
579
+ entryCount: 0,
580
+ baseEntryCount: 0,
581
+ omittedBaseEntryCount: 0,
582
+ };
583
+ let baseEntries: CompactionSemanticIndex | undefined;
584
+ let serializedProvidedEntryCount: number | undefined;
585
+ try {
586
+ baseEntries = baseSnapshot?.entries;
587
+ serializedProvidedEntryCount = baseSnapshot?.providedEntryCount;
588
+ } catch {
589
+ return collector;
590
+ }
591
+ const snapshot = snapshotCompactionSemanticIndex(baseEntries);
592
+ if (snapshot == null) {
593
+ return collector;
594
+ }
595
+ const snapshotProvidedEntryCount =
596
+ getCompactionSemanticIndexProvidedEntryCount(snapshot);
597
+ const validSerializedProvidedEntryCount =
598
+ typeof serializedProvidedEntryCount === 'number' &&
599
+ Number.isSafeInteger(serializedProvidedEntryCount) &&
600
+ serializedProvidedEntryCount >= snapshotProvidedEntryCount;
601
+ const providedEntryCount =
602
+ validSerializedProvidedEntryCount &&
603
+ serializedProvidedEntryCount != null
604
+ ? serializedProvidedEntryCount
605
+ : snapshotProvidedEntryCount;
606
+ collector.omittedBaseEntryCount = Math.max(
607
+ 0,
608
+ providedEntryCount - snapshot.length
609
+ );
610
+ for (let index = 0; index < snapshot.length; index++) {
611
+ appendDerivedCompactionSemanticEntry(collector, snapshot[index], true);
612
+ }
613
+ collector.baseEntryCount = collector.entryCount;
614
+ return collector;
615
+ }
616
+
617
+ function createCompactionSemanticCoverageState(): CompactionSemanticCoverageState {
618
+ return {
619
+ head: [],
620
+ tail: { entries: [], cursor: 0 },
621
+ latestByIdentityHash: new Map(),
622
+ typeCoverage: new Map(),
623
+ };
624
+ }
625
+
626
+ function getDerivedCompactionSemanticLocalId(
627
+ entry: CompactionSemanticIndexEntry
628
+ ): string {
629
+ if (entry.type === 'reasoning_label') {
630
+ return entry.reasoningStepId.trim();
631
+ }
632
+ if (entry.type !== 'activity_phase') {
633
+ return entry.toolCallId.trim();
634
+ }
635
+ return '';
636
+ }
637
+
638
+ function hashDerivedCompactionSemanticIdentityString(
639
+ initialHash: number,
640
+ value: string
641
+ ): number {
642
+ let hash = initialHash;
643
+ for (let index = 0; index < value.length; index++) {
644
+ hash ^= value.charCodeAt(index);
645
+ hash = Math.imul(hash, 16_777_619);
646
+ }
647
+ return hash;
648
+ }
649
+
650
+ function hashDerivedCompactionSemanticIdentity(
651
+ entry: CompactionSemanticIndexEntry
652
+ ): number {
653
+ let hash = 2_166_136_261 ^ DERIVED_SEMANTIC_TYPE_HASH[entry.type];
654
+ hash = Math.imul(hash, 16_777_619);
655
+ hash = hashDerivedCompactionSemanticIdentityString(
656
+ hash,
657
+ entry.sourceMessageId.trim()
658
+ );
659
+ hash ^= entry.sourceContentIndex;
660
+ hash = Math.imul(hash, 16_777_619);
661
+ hash = hashDerivedCompactionSemanticIdentityString(
662
+ hash,
663
+ getDerivedCompactionSemanticLocalId(entry)
664
+ );
665
+ return hash >>> 0;
666
+ }
667
+
668
+ function entriesShareDerivedCompactionSemanticIdentity(
669
+ left: CompactionSemanticIndexEntry,
670
+ right: CompactionSemanticIndexEntry
671
+ ): boolean {
672
+ return (
673
+ left.type === right.type &&
674
+ left.sourceMessageId.trim() === right.sourceMessageId.trim() &&
675
+ left.sourceContentIndex === right.sourceContentIndex &&
676
+ getDerivedCompactionSemanticLocalId(left) ===
677
+ getDerivedCompactionSemanticLocalId(right)
678
+ );
679
+ }
680
+
681
+ function entriesHaveConflictingSemanticState(
682
+ left: CompactionSemanticIndexEntry,
683
+ right: CompactionSemanticIndexEntry
684
+ ): boolean {
685
+ return (
686
+ left.status !== right.status ||
687
+ (left.redacted === true) !== (right.redacted === true) ||
688
+ left.text.replace(/\s+/g, ' ').trim() !==
689
+ right.text.replace(/\s+/g, ' ').trim()
690
+ );
691
+ }
692
+
693
+ function findCompactionSemanticRevisionFloor(
694
+ collector: DerivedCompactionSemanticIndexCollector,
695
+ entry: CompactionSemanticIndexEntry,
696
+ identityHash: number
697
+ ): CompactionSemanticRevisionFloor | undefined {
698
+ return collector.baseRevisionFloors
699
+ ?.get(identityHash)
700
+ ?.find((floor) =>
701
+ entriesShareDerivedCompactionSemanticIdentity(floor.entry, entry)
702
+ );
703
+ }
704
+
705
+ function seedCompactionSemanticRevisionFloor(
706
+ collector: DerivedCompactionSemanticIndexCollector,
707
+ entry: CompactionSemanticIndexEntry,
708
+ order: number
709
+ ): void {
710
+ collector.baseRevisionFloors ??= new Map();
711
+ const identityHash = hashDerivedCompactionSemanticIdentity(entry);
712
+ const existing = findCompactionSemanticRevisionFloor(
713
+ collector,
714
+ entry,
715
+ identityHash
716
+ );
717
+ if (existing != null) {
718
+ if (entry.revision > existing.entry.revision) {
719
+ existing.entry = entry;
720
+ existing.order = order;
721
+ }
722
+ return;
723
+ }
724
+ const floor = { entry, order };
725
+ const bucket = collector.baseRevisionFloors.get(identityHash);
726
+ if (bucket == null) {
727
+ collector.baseRevisionFloors.set(identityHash, [floor]);
728
+ return;
729
+ }
730
+ bucket.push(floor);
731
+ }
732
+
733
+ function updateCompactionSemanticRevisionFloor(
734
+ collector: DerivedCompactionSemanticIndexCollector,
735
+ orderedEntry: OrderedCompactionSemanticIndexEntry
736
+ ): void {
737
+ const floor = findCompactionSemanticRevisionFloor(
738
+ collector,
739
+ orderedEntry.entry,
740
+ orderedEntry.identityHash
741
+ );
742
+ if (floor == null || orderedEntry.entry.revision <= floor.entry.revision) {
743
+ return;
744
+ }
745
+ floor.entry = orderedEntry.entry;
746
+ floor.order = orderedEntry.order;
747
+ }
748
+
749
+ function shouldRejectCompactionSemanticEntryBelowBaseFloor(
750
+ collector: DerivedCompactionSemanticIndexCollector,
751
+ orderedEntry: OrderedCompactionSemanticIndexEntry
752
+ ): boolean {
753
+ const floor = findCompactionSemanticRevisionFloor(
754
+ collector,
755
+ orderedEntry.entry,
756
+ orderedEntry.identityHash
757
+ );
758
+ if (floor == null || orderedEntry.order === floor.order) {
759
+ return false;
760
+ }
761
+ const currentBucket = collector.coverage?.latestByIdentityHash.get(
762
+ orderedEntry.identityHash
763
+ );
764
+ const current = currentBucket?.find(({ entry }) =>
765
+ entriesShareDerivedCompactionSemanticIdentity(entry, orderedEntry.entry)
766
+ );
767
+ if (current != null) {
768
+ return false;
769
+ }
770
+ return orderedEntry.entry.revision <= floor.entry.revision;
771
+ }
772
+
773
+ function retainCompactionSemanticEntry(
774
+ entry: OrderedCompactionSemanticIndexEntry
775
+ ): void {
776
+ entry.retentionCount++;
777
+ }
778
+
779
+ function releaseCompactionSemanticEntry(
780
+ coverage: CompactionSemanticCoverageState,
781
+ entry: OrderedCompactionSemanticIndexEntry
782
+ ): void {
783
+ entry.retentionCount--;
784
+ if (
785
+ entry.retentionCount === 0 &&
786
+ coverage.latestByIdentityHash.has(entry.identityHash)
787
+ ) {
788
+ const bucket = coverage.latestByIdentityHash.get(entry.identityHash);
789
+ if (bucket == null) {
790
+ return;
791
+ }
792
+ const entryIndex = bucket.indexOf(entry);
793
+ if (entryIndex >= 0) {
794
+ bucket.splice(entryIndex, 1);
795
+ }
796
+ if (bucket.length === 0) {
797
+ coverage.latestByIdentityHash.delete(entry.identityHash);
798
+ }
799
+ }
800
+ }
801
+
802
+ function appendCompactionSemanticEntryRing(
803
+ coverage: CompactionSemanticCoverageState,
804
+ ring: CompactionSemanticEntryRing,
805
+ entry: OrderedCompactionSemanticIndexEntry,
806
+ limit: number
807
+ ): void {
808
+ if (ring.entries.length < limit) {
809
+ ring.entries.push(entry);
810
+ retainCompactionSemanticEntry(entry);
811
+ return;
812
+ }
813
+ releaseCompactionSemanticEntry(coverage, ring.entries[ring.cursor]);
814
+ ring.entries[ring.cursor] = entry;
815
+ retainCompactionSemanticEntry(entry);
816
+ ring.cursor = (ring.cursor + 1) % limit;
817
+ }
818
+
819
+ function renewCompactionSemanticEntryRing(
820
+ coverage: CompactionSemanticCoverageState,
821
+ ring: CompactionSemanticEntryRing,
822
+ entry: OrderedCompactionSemanticIndexEntry,
823
+ limit: number
824
+ ): void {
825
+ const existingIndex = ring.entries.indexOf(entry);
826
+ if (existingIndex < 0) {
827
+ appendCompactionSemanticEntryRing(coverage, ring, entry, limit);
828
+ return;
829
+ }
830
+ if (ring.entries.length < limit) {
831
+ ring.entries.splice(existingIndex, 1);
832
+ ring.entries.push(entry);
833
+ return;
834
+ }
835
+ const newestIndex =
836
+ (ring.cursor + ring.entries.length - 1) % ring.entries.length;
837
+ let currentIndex = existingIndex;
838
+ for (
839
+ let offset = 0;
840
+ currentIndex !== newestIndex && offset < ring.entries.length;
841
+ offset++
842
+ ) {
843
+ const nextIndex = (currentIndex + 1) % ring.entries.length;
844
+ ring.entries[currentIndex] = ring.entries[nextIndex];
845
+ currentIndex = nextIndex;
846
+ }
847
+ ring.entries[newestIndex] = entry;
848
+ }
849
+
850
+ function renewCoverageBalancedCompactionSemanticEntry(
851
+ coverage: CompactionSemanticCoverageState,
852
+ entry: OrderedCompactionSemanticIndexEntry
853
+ ): void {
854
+ renewCompactionSemanticEntryRing(
855
+ coverage,
856
+ coverage.tail,
857
+ entry,
858
+ DERIVED_SEMANTIC_TAIL_LIMIT
859
+ );
860
+ const typeCoverage = coverage.typeCoverage.get(entry.entry.type);
861
+ if (typeCoverage == null) {
862
+ return;
863
+ }
864
+ renewCompactionSemanticEntryRing(
865
+ coverage,
866
+ typeCoverage.tail,
867
+ entry,
868
+ DERIVED_SEMANTIC_TYPE_EDGE_LIMIT
869
+ );
870
+ }
871
+
872
+ function appendDerivedCompactionSemanticEntry(
873
+ collector: DerivedCompactionSemanticIndexCollector,
874
+ entry: CompactionSemanticIndexEntry,
875
+ baseEntry = false
876
+ ): void {
877
+ let boundedEntry = entry;
878
+ if (entry.status === 'pending') {
879
+ boundedEntry = { ...entry, text: '' };
880
+ } else if (
881
+ entry.text.length > COMPACTION_SEMANTIC_INDEX_LIMITS.maxInputTextChars
882
+ ) {
883
+ boundedEntry = { ...entry, text: '', redacted: true };
884
+ }
885
+ const order = collector.entryCount;
886
+ collector.entryCount++;
887
+ if (
888
+ collector.coverage == null &&
889
+ collector.entries.length < COMPACTION_SEMANTIC_INDEX_LIMITS.maxInputEntries
890
+ ) {
891
+ collector.entries.push(boundedEntry);
892
+ if (!baseEntry && collector.baseRevisionFloors != null) {
893
+ updateCompactionSemanticRevisionFloor(collector, {
894
+ entry: boundedEntry,
895
+ identityHash: hashDerivedCompactionSemanticIdentity(boundedEntry),
896
+ order,
897
+ retentionCount: 0,
898
+ });
899
+ }
900
+ return;
901
+ }
902
+ const orderedEntry = {
903
+ entry: boundedEntry,
904
+ identityHash: hashDerivedCompactionSemanticIdentity(boundedEntry),
905
+ order,
906
+ retentionCount: 0,
907
+ };
908
+ if (collector.coverage == null) {
909
+ for (let order = 0; order < collector.baseEntryCount; order++) {
910
+ seedCompactionSemanticRevisionFloor(
911
+ collector,
912
+ collector.entries[order],
913
+ order
914
+ );
915
+ }
916
+ collector.coverage = createCompactionSemanticCoverageState();
917
+ for (let order = 0; order < collector.entries.length; order++) {
918
+ const bufferedEntry = {
919
+ entry: collector.entries[order],
920
+ identityHash: hashDerivedCompactionSemanticIdentity(
921
+ collector.entries[order]
922
+ ),
923
+ order,
924
+ retentionCount: 0,
925
+ };
926
+ if (
927
+ shouldRejectCompactionSemanticEntryBelowBaseFloor(
928
+ collector,
929
+ bufferedEntry
930
+ )
931
+ ) {
932
+ continue;
933
+ }
934
+ appendCoverageBalancedCompactionSemanticEntry(
935
+ collector.coverage,
936
+ bufferedEntry
937
+ );
938
+ if (order >= collector.baseEntryCount) {
939
+ updateCompactionSemanticRevisionFloor(collector, bufferedEntry);
940
+ }
941
+ }
942
+ collector.entries = [];
943
+ }
944
+ if (
945
+ !baseEntry &&
946
+ shouldRejectCompactionSemanticEntryBelowBaseFloor(collector, orderedEntry)
947
+ ) {
948
+ return;
949
+ }
950
+ appendCoverageBalancedCompactionSemanticEntry(
951
+ collector.coverage,
952
+ orderedEntry
953
+ );
954
+ if (!baseEntry) {
955
+ updateCompactionSemanticRevisionFloor(collector, orderedEntry);
956
+ }
957
+ }
958
+
959
+ function appendCoverageBalancedCompactionSemanticEntry(
960
+ coverage: CompactionSemanticCoverageState,
961
+ orderedEntry: OrderedCompactionSemanticIndexEntry
962
+ ): void {
963
+ const identityHash = orderedEntry.identityHash;
964
+ const identityBucket = coverage.latestByIdentityHash.get(identityHash);
965
+ const current = identityBucket?.find(({ entry }) =>
966
+ entriesShareDerivedCompactionSemanticIdentity(entry, orderedEntry.entry)
967
+ );
968
+ if (current != null) {
969
+ if (orderedEntry.entry.revision < current.entry.revision) {
970
+ return;
971
+ }
972
+ if (orderedEntry.entry.revision === current.entry.revision) {
973
+ if (
974
+ entriesHaveConflictingSemanticState(current.entry, orderedEntry.entry)
975
+ ) {
976
+ current.entry = { ...current.entry, text: '', redacted: true };
977
+ current.order = orderedEntry.order;
978
+ renewCoverageBalancedCompactionSemanticEntry(coverage, current);
979
+ }
980
+ return;
981
+ }
982
+ current.entry = orderedEntry.entry;
983
+ current.order = orderedEntry.order;
984
+ renewCoverageBalancedCompactionSemanticEntry(coverage, current);
985
+ return;
986
+ }
987
+ if (identityBucket == null) {
988
+ coverage.latestByIdentityHash.set(identityHash, [orderedEntry]);
989
+ } else {
990
+ identityBucket.push(orderedEntry);
991
+ }
992
+ if (coverage.head.length < DERIVED_SEMANTIC_HEAD_LIMIT) {
993
+ coverage.head.push(orderedEntry);
994
+ retainCompactionSemanticEntry(orderedEntry);
995
+ }
996
+ appendCompactionSemanticEntryRing(
997
+ coverage,
998
+ coverage.tail,
999
+ orderedEntry,
1000
+ DERIVED_SEMANTIC_TAIL_LIMIT
1001
+ );
1002
+ let typeCoverage = coverage.typeCoverage.get(orderedEntry.entry.type);
1003
+ if (typeCoverage == null) {
1004
+ typeCoverage = { head: [], tail: { entries: [], cursor: 0 } };
1005
+ coverage.typeCoverage.set(orderedEntry.entry.type, typeCoverage);
1006
+ }
1007
+ if (typeCoverage.head.length < DERIVED_SEMANTIC_TYPE_EDGE_LIMIT) {
1008
+ typeCoverage.head.push(orderedEntry);
1009
+ retainCompactionSemanticEntry(orderedEntry);
1010
+ }
1011
+ appendCompactionSemanticEntryRing(
1012
+ coverage,
1013
+ typeCoverage.tail,
1014
+ orderedEntry,
1015
+ DERIVED_SEMANTIC_TYPE_EDGE_LIMIT
1016
+ );
1017
+ }
1018
+
1019
+ function finalizeDerivedCompactionSemanticIndexSnapshot(
1020
+ collector: DerivedCompactionSemanticIndexCollector | undefined
1021
+ ): CompactionSemanticIndexSnapshot | undefined {
1022
+ if (
1023
+ collector == null ||
1024
+ (collector.entryCount === 0 && collector.omittedBaseEntryCount === 0)
1025
+ ) {
1026
+ return undefined;
1027
+ }
1028
+ const providedEntryCount = Math.min(
1029
+ Number.MAX_SAFE_INTEGER,
1030
+ collector.entryCount + collector.omittedBaseEntryCount
1031
+ );
1032
+ if (collector.coverage == null) {
1033
+ setCompactionSemanticIndexProvidedEntryCount(
1034
+ collector.entries,
1035
+ providedEntryCount
1036
+ );
1037
+ return { entries: collector.entries, providedEntryCount };
1038
+ }
1039
+ const retained = new Map<number, CompactionSemanticIndexEntry>();
1040
+ const retain = (
1041
+ entries: readonly OrderedCompactionSemanticIndexEntry[]
1042
+ ): void => {
1043
+ for (const { entry, order } of entries) {
1044
+ retained.set(order, entry);
1045
+ }
1046
+ };
1047
+ retain(collector.coverage.head);
1048
+ retain(collector.coverage.tail.entries);
1049
+ for (const typeCoverage of collector.coverage.typeCoverage.values()) {
1050
+ retain(typeCoverage.head);
1051
+ retain(typeCoverage.tail.entries);
1052
+ }
1053
+ const result = [...retained.entries()]
1054
+ .sort(([left], [right]) => left - right)
1055
+ .map(([, entry]) => entry);
1056
+ setCompactionSemanticIndexProvidedEntryCount(result, providedEntryCount);
1057
+ return { entries: result, providedEntryCount };
1058
+ }
1059
+
1060
+ function collectCompactionSemanticEntriesFromPart(
1061
+ collector: DerivedCompactionSemanticIndexCollector,
1062
+ part: CompactionSemanticContentPart,
1063
+ sourceMessageId: string,
1064
+ sourceContentIndex: number,
1065
+ retainedSourceContentStart: number,
1066
+ retainedSourceContentEnd: number,
1067
+ intentToolNames?: ReadonlySet<string>,
1068
+ parsedToolInput?: ToolCallPart['args']
1069
+ ): void {
1070
+ if (
1071
+ sourceMessageId.length > COMPACTION_SEMANTIC_INDEX_LIMITS.maxIdentityChars
1072
+ ) {
1073
+ return;
1074
+ }
1075
+
1076
+ if (part.type === ContentTypes.TOOL_CALL) {
1077
+ if (
1078
+ sourceContentIndex < 0 ||
1079
+ sourceContentIndex >
1080
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxSourceContentIndex
1081
+ ) {
1082
+ return;
1083
+ }
1084
+ const toolCall = part.tool_call;
1085
+ const toolCallId = toolCall?.id;
1086
+ if (
1087
+ typeof toolCallId !== 'string' ||
1088
+ toolCallId === '' ||
1089
+ toolCallId.length > COMPACTION_SEMANTIC_INDEX_LIMITS.maxIdentityChars
1090
+ ) {
1091
+ return;
1092
+ }
1093
+ if (
1094
+ typeof toolCall.name === 'string' &&
1095
+ intentToolNames?.has(toolCall.name) === true
1096
+ ) {
1097
+ const intent =
1098
+ parsedToolInput != null &&
1099
+ typeof parsedToolInput === 'object' &&
1100
+ !Array.isArray(parsedToolInput)
1101
+ ? parsedToolInput.intent
1102
+ : undefined;
1103
+ if (typeof intent === 'string' && intent !== '') {
1104
+ appendDerivedCompactionSemanticEntry(collector, {
1105
+ type: 'tool_intent',
1106
+ sourceMessageId,
1107
+ sourceContentIndex,
1108
+ revision: 0,
1109
+ status: 'committed',
1110
+ text: intent,
1111
+ toolCallId,
1112
+ });
1113
+ }
1114
+ }
1115
+ if (typeof toolCall.outcome === 'string' && toolCall.outcome !== '') {
1116
+ appendDerivedCompactionSemanticEntry(collector, {
1117
+ type: 'tool_outcome',
1118
+ sourceMessageId,
1119
+ sourceContentIndex,
1120
+ revision: 0,
1121
+ status: 'committed',
1122
+ text: toolCall.outcome,
1123
+ toolCallId,
1124
+ });
1125
+ }
1126
+ return;
1127
+ }
1128
+
1129
+ if (part.type === ContentTypes.THINK) {
1130
+ if (
1131
+ sourceContentIndex < 0 ||
1132
+ sourceContentIndex >
1133
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxSourceContentIndex
1134
+ ) {
1135
+ return;
1136
+ }
1137
+ const reasoningStepId = part.reasoning_label_step_id;
1138
+ const revision = part.reasoning_label_revision;
1139
+ const status = part.reasoning_label_status;
1140
+ const text = part.reasoning_label;
1141
+ if (
1142
+ typeof reasoningStepId !== 'string' ||
1143
+ reasoningStepId === '' ||
1144
+ reasoningStepId.length >
1145
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxIdentityChars ||
1146
+ typeof revision !== 'number' ||
1147
+ !Number.isSafeInteger(revision) ||
1148
+ revision < 0
1149
+ ) {
1150
+ return;
1151
+ }
1152
+ const malformedState =
1153
+ (status !== 'complete' && status !== 'streaming') ||
1154
+ typeof text !== 'string';
1155
+ appendDerivedCompactionSemanticEntry(collector, {
1156
+ type: 'reasoning_label',
1157
+ sourceMessageId,
1158
+ sourceContentIndex,
1159
+ revision,
1160
+ status:
1161
+ status === 'streaming' || malformedState ? 'pending' : 'committed',
1162
+ text: typeof text === 'string' ? text : '',
1163
+ reasoningStepId,
1164
+ ...(malformedState ? { redacted: true } : {}),
1165
+ });
1166
+ return;
1167
+ }
1168
+
1169
+ if (
1170
+ part.type !== ContentTypes.ACTIVITY_LABEL ||
1171
+ part.activity_label_type !== 'phase'
1172
+ ) {
1173
+ return;
1174
+ }
1175
+ const activitySourceContentIndex = part.activity_start_index;
1176
+ if (
1177
+ typeof activitySourceContentIndex !== 'number' ||
1178
+ !Number.isSafeInteger(activitySourceContentIndex) ||
1179
+ activitySourceContentIndex < retainedSourceContentStart ||
1180
+ activitySourceContentIndex >= retainedSourceContentEnd ||
1181
+ activitySourceContentIndex >
1182
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxSourceContentIndex
1183
+ ) {
1184
+ return;
1185
+ }
1186
+ const revision = part.activity_label_revision;
1187
+ if (
1188
+ revision !== undefined &&
1189
+ (typeof revision !== 'number' ||
1190
+ !Number.isSafeInteger(revision) ||
1191
+ revision < 0)
1192
+ ) {
1193
+ return;
1194
+ }
1195
+ const malformedPending =
1196
+ part.pending !== undefined && typeof part.pending !== 'boolean';
1197
+ const malformedText = typeof part.activity_label !== 'string';
1198
+ const malformedState = malformedPending || malformedText;
1199
+ const text =
1200
+ typeof part.activity_label === 'string' ? part.activity_label : '';
1201
+ appendDerivedCompactionSemanticEntry(collector, {
1202
+ type: 'activity_phase',
1203
+ sourceMessageId,
1204
+ sourceContentIndex: activitySourceContentIndex,
1205
+ revision: revision ?? 0,
1206
+ status: part.pending === true || malformedPending ? 'pending' : 'committed',
1207
+ text,
1208
+ ...(malformedState ? { redacted: true } : {}),
1209
+ });
1210
+ }
1211
+
479
1212
  function collectTrustedToolResultSourceContentPartIndices(
480
1213
  content: readonly unknown[] | undefined,
481
1214
  sourceContentPartOffset: number
@@ -868,6 +1601,17 @@ function formatAssistantMessage(
868
1601
  >();
869
1602
  const shouldPreserveReasoningContent =
870
1603
  options?.preserveReasoningContent === true;
1604
+ const compactionSemanticIndex = options?.compactionSemanticIndex;
1605
+ const semanticSourceMessageId =
1606
+ compactionSemanticIndex != null &&
1607
+ options?.sourceMessageId != null &&
1608
+ options.sourceMessageId.length <=
1609
+ COMPACTION_SEMANTIC_INDEX_LIMITS.maxIdentityChars
1610
+ ? options.sourceMessageId
1611
+ : undefined;
1612
+ const retainedSourceContentStart = options?.sourceContentPartOffset ?? 0;
1613
+ const retainedSourceContentEnd =
1614
+ options?.retainedSourceContentEnd ?? retainedSourceContentStart;
871
1615
  const serverToolResultIds = new Set<string>();
872
1616
  const preferredToolCallParts = new Map<string, MessageContentComplex>();
873
1617
 
@@ -976,6 +1720,9 @@ function formatAssistantMessage(
976
1720
  if (part == null) {
977
1721
  continue;
978
1722
  }
1723
+ if (part.type === ContentTypes.ACTIVITY_LABEL) {
1724
+ continue;
1725
+ }
979
1726
  const isTrustedResult = isTrustedServerToolResult(
980
1727
  part,
981
1728
  getSourcePartIndices(partIndex),
@@ -1011,6 +1758,24 @@ function formatAssistantMessage(
1011
1758
  continue;
1012
1759
  }
1013
1760
  const sourcePartIndices = getSourcePartIndices(partIndex);
1761
+ if (part.type === ContentTypes.ACTIVITY_LABEL) {
1762
+ if (
1763
+ compactionSemanticIndex != null &&
1764
+ semanticSourceMessageId != null &&
1765
+ typeof sourcePartIndices === 'number'
1766
+ ) {
1767
+ collectCompactionSemanticEntriesFromPart(
1768
+ compactionSemanticIndex,
1769
+ part,
1770
+ semanticSourceMessageId,
1771
+ sourcePartIndices,
1772
+ retainedSourceContentStart,
1773
+ retainedSourceContentEnd,
1774
+ options?.intentToolNames
1775
+ );
1776
+ }
1777
+ continue;
1778
+ }
1014
1779
  const toolUseId = getToolUseId(part);
1015
1780
  if (toolUseId != null) {
1016
1781
  const isServerToolResult =
@@ -1117,12 +1882,29 @@ function formatAssistantMessage(
1117
1882
  ) {
1118
1883
  continue;
1119
1884
  }
1885
+ const serverToolInput = parseServerToolInput(_args);
1886
+ if (
1887
+ compactionSemanticIndex != null &&
1888
+ semanticSourceMessageId != null &&
1889
+ typeof sourcePartIndices === 'number'
1890
+ ) {
1891
+ collectCompactionSemanticEntriesFromPart(
1892
+ compactionSemanticIndex,
1893
+ part,
1894
+ semanticSourceMessageId,
1895
+ sourcePartIndices,
1896
+ retainedSourceContentStart,
1897
+ retainedSourceContentEnd,
1898
+ options.intentToolNames,
1899
+ serverToolInput
1900
+ );
1901
+ }
1120
1902
  pendingServerToolUses.set(_tool_call.id, {
1121
1903
  content: {
1122
1904
  type: 'server_tool_use',
1123
1905
  id: _tool_call.id,
1124
1906
  name: _tool_call.name,
1125
- input: parseServerToolInput(_args),
1907
+ input: serverToolInput,
1126
1908
  } as MessageContentComplex,
1127
1909
  sourceContentPartIndices: sourcePartIndices,
1128
1910
  });
@@ -1154,6 +1936,22 @@ function formatAssistantMessage(
1154
1936
  }
1155
1937
 
1156
1938
  tool_call.args = args;
1939
+ if (
1940
+ compactionSemanticIndex != null &&
1941
+ semanticSourceMessageId != null &&
1942
+ typeof sourcePartIndices === 'number'
1943
+ ) {
1944
+ collectCompactionSemanticEntriesFromPart(
1945
+ compactionSemanticIndex,
1946
+ part,
1947
+ semanticSourceMessageId,
1948
+ sourcePartIndices,
1949
+ retainedSourceContentStart,
1950
+ retainedSourceContentEnd,
1951
+ options?.intentToolNames,
1952
+ args
1953
+ );
1954
+ }
1157
1955
  if (
1158
1956
  options?.provider === Providers.ANTHROPIC &&
1159
1957
  Array.isArray(lastAIMessage.content)
@@ -1192,6 +1990,22 @@ function formatAssistantMessage(
1192
1990
  part.type === ContentTypes.REASONING_CONTENT ||
1193
1991
  part.type === 'redacted_thinking'
1194
1992
  ) {
1993
+ if (
1994
+ part.type === ContentTypes.THINK &&
1995
+ compactionSemanticIndex != null &&
1996
+ semanticSourceMessageId != null &&
1997
+ typeof sourcePartIndices === 'number'
1998
+ ) {
1999
+ collectCompactionSemanticEntriesFromPart(
2000
+ compactionSemanticIndex,
2001
+ part,
2002
+ semanticSourceMessageId,
2003
+ sourcePartIndices,
2004
+ retainedSourceContentStart,
2005
+ retainedSourceContentEnd,
2006
+ options?.intentToolNames
2007
+ );
2008
+ }
1195
2009
  hasReasoning = true;
1196
2010
  pendingReasoningContent += extractReasoningContent(part);
1197
2011
  appendSourceContentPartIndices(
@@ -1270,8 +2084,7 @@ function formatAssistantMessage(
1270
2084
  } else if (
1271
2085
  part.type === ContentTypes.ERROR ||
1272
2086
  part.type === ContentTypes.AGENT_UPDATE ||
1273
- part.type === ContentTypes.SUMMARY ||
1274
- part.type === ContentTypes.ACTIVITY_LABEL
2087
+ part.type === ContentTypes.SUMMARY
1275
2088
  ) {
1276
2089
  continue;
1277
2090
  } else {
@@ -1991,6 +2804,10 @@ export const formatAgentMessages = (
1991
2804
  /** When a positional summary boundary sliced content from a message, the token
1992
2805
  * count was proportionally reduced. Returned so the caller can log it. */
1993
2806
  boundaryTokenAdjustment?: SummaryTokenAdjustment;
2807
+ /** Bounded semantic guidance derived during persisted-content analysis. */
2808
+ compactionSemanticIndex?: CompactionSemanticIndex;
2809
+ /** Serializable continuation state for incrementally evolving the index. */
2810
+ compactionSemanticIndexSnapshot?: CompactionSemanticIndexSnapshot;
1994
2811
  } => {
1995
2812
  const messages: Array<
1996
2813
  | RoleBearingMessage<HumanMessage>
@@ -2005,6 +2822,12 @@ export const formatAgentMessages = (
2005
2822
  * nothing cannot leave the anchor stranded as the final turn.
2006
2823
  */
2007
2824
  const legacyContentEnabled = options?.legacyContent === true;
2825
+ const compactionSemanticIndexCollector =
2826
+ options?.compactionSemanticIndex != null
2827
+ ? createDerivedCompactionSemanticIndexCollector(
2828
+ options.compactionSemanticIndex.baseSnapshot
2829
+ )
2830
+ : undefined;
2008
2831
  /** Emission choke point: every formatted message enters the result here, so
2009
2832
  * the legacy flatten happens once per message with no closing rescan. The
2010
2833
  * summary boundary slices payload entries before formatting, and nothing
@@ -2334,11 +3157,16 @@ export const formatAgentMessages = (
2334
3157
  }
2335
3158
 
2336
3159
  const formattedMessages = formatAssistantMessage(processedMessage, {
3160
+ compactionSemanticIndex: compactionSemanticIndexCollector,
3161
+ intentToolNames: options?.compactionSemanticIndex?.intentToolNames,
2337
3162
  preserveUnpairedServerToolUses: i === payload.length - 1,
2338
3163
  preserveReasoningContent:
2339
3164
  options?.preserveReasoningContent ??
2340
3165
  options?.provider === Providers.DEEPSEEK,
2341
3166
  provider: options?.provider,
3167
+ retainedSourceContentEnd:
3168
+ sourceContentPartOffset +
3169
+ (Array.isArray(message.content) ? message.content.length : 0),
2342
3170
  sourceMessageId,
2343
3171
  sourceContentPartOffset,
2344
3172
  sourceContentPartIndices: processedSourceContentPartIndices,
@@ -2601,6 +3429,10 @@ export const formatAgentMessages = (
2601
3429
  }
2602
3430
  }
2603
3431
 
3432
+ const compactionSemanticIndexSnapshot =
3433
+ finalizeDerivedCompactionSemanticIndexSnapshot(
3434
+ compactionSemanticIndexCollector
3435
+ );
2604
3436
  return {
2605
3437
  messages,
2606
3438
  indexTokenCountMap: indexTokenCountMap
@@ -2610,6 +3442,8 @@ export const formatAgentMessages = (
2610
3442
  ? { text: summaryBoundary.text, tokenCount: summaryBoundary.tokenCount }
2611
3443
  : undefined,
2612
3444
  boundaryTokenAdjustment,
3445
+ compactionSemanticIndex: compactionSemanticIndexSnapshot?.entries,
3446
+ compactionSemanticIndexSnapshot,
2613
3447
  };
2614
3448
  };
2615
3449