@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.
- package/dist/cjs/agents/AgentContext.cjs +26 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/constants.cjs +12 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +56 -11
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/executeHooks.cjs +8 -0
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/hooks/index.cjs +2 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +1 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +43 -3
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseTraceShaping.cjs +75 -0
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/toolCache.cjs +1 -1
- package/dist/cjs/llm/fake.cjs +9 -5
- package/dist/cjs/llm/fake.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +3 -7
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/toolCache.cjs +1 -1
- package/dist/cjs/llm/prepareProviderRequest.cjs +2 -2
- package/dist/cjs/llm/providers.cjs +1 -1
- package/dist/cjs/llm/request.cjs +6 -0
- package/dist/cjs/llm/request.cjs.map +1 -1
- package/dist/cjs/llm/truncation.cjs +1 -0
- package/dist/cjs/main.cjs +22 -13
- package/dist/cjs/messages/format.cjs +375 -3
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/messages/prune.cjs +1 -1
- package/dist/cjs/run.cjs +217 -52
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/summarization/index.cjs +1 -0
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +58 -85
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/summarization/semanticIndex.cjs +366 -0
- package/dist/cjs/summarization/semanticIndex.cjs.map +1 -0
- package/dist/cjs/summarization/shared.cjs +83 -0
- package/dist/cjs/summarization/shared.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +5 -5
- package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +1 -1
- package/dist/cjs/tools/runStepResume.cjs +1 -1
- package/dist/cjs/tools/runStepResume.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +8 -12
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +2 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/utils/tokens.cjs +8 -1
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +26 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/constants.mjs +11 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +56 -11
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/executeHooks.mjs +8 -1
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/hooks/index.mjs +2 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +1 -0
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +43 -3
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseTraceShaping.mjs +75 -0
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/bedrock/toolCache.mjs +1 -1
- package/dist/esm/llm/fake.mjs +9 -5
- package/dist/esm/llm/fake.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +3 -7
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openrouter/toolCache.mjs +1 -1
- package/dist/esm/llm/prepareProviderRequest.mjs +2 -2
- package/dist/esm/llm/providers.mjs +1 -1
- package/dist/esm/llm/request.mjs +6 -1
- package/dist/esm/llm/request.mjs.map +1 -1
- package/dist/esm/llm/truncation.mjs +1 -1
- package/dist/esm/main.mjs +15 -14
- package/dist/esm/messages/format.mjs +375 -3
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/messages/prune.mjs +1 -1
- package/dist/esm/run.mjs +217 -52
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +1 -1
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/summarization/index.mjs +1 -0
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +57 -84
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/summarization/semanticIndex.mjs +363 -0
- package/dist/esm/summarization/semanticIndex.mjs.map +1 -0
- package/dist/esm/summarization/shared.mjs +79 -0
- package/dist/esm/summarization/shared.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +5 -5
- package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +1 -1
- package/dist/esm/tools/runStepResume.mjs +1 -1
- package/dist/esm/tools/runStepResume.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +8 -12
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs +2 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/tokens.mjs +8 -2
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +27 -1
- package/dist/types/common/constants.d.ts +17 -0
- package/dist/types/graphs/Graph.d.ts +24 -0
- package/dist/types/hooks/executeHooks.d.ts +5 -2
- package/dist/types/hooks/index.d.ts +7 -2
- package/dist/types/hooks/types.d.ts +45 -7
- package/dist/types/langfuse.d.ts +3 -1
- package/dist/types/llm/fake.d.ts +12 -2
- package/dist/types/llm/request.d.ts +10 -0
- package/dist/types/messages/format.d.ts +17 -2
- package/dist/types/run.d.ts +19 -6
- package/dist/types/summarization/index.d.ts +6 -0
- package/dist/types/summarization/node.d.ts +0 -4
- package/dist/types/summarization/semanticIndex.d.ts +21 -0
- package/dist/types/summarization/shared.d.ts +25 -0
- package/dist/types/types/graph.d.ts +9 -1
- package/dist/types/types/run.d.ts +8 -0
- package/dist/types/types/stream.d.ts +6 -0
- package/dist/types/types/summarize.d.ts +44 -0
- package/dist/types/utils/tokens.d.ts +9 -0
- package/package.json +2 -1
- package/src/agents/AgentContext.ts +63 -6
- package/src/common/constants.ts +19 -0
- package/src/graphs/Graph.ts +86 -8
- package/src/hooks/HookRegistry.ts +3 -1
- package/src/hooks/executeHooks.ts +20 -2
- package/src/hooks/index.ts +12 -1
- package/src/hooks/types.ts +47 -4
- package/src/langfuse.ts +70 -0
- package/src/langfuseTraceShaping.ts +94 -0
- package/src/llm/fake.ts +35 -4
- package/src/llm/invoke.ts +13 -29
- package/src/llm/request.ts +24 -0
- package/src/messages/format.ts +839 -5
- package/src/run.ts +393 -187
- package/src/summarization/index.ts +11 -0
- package/src/summarization/node.ts +202 -158
- package/src/summarization/semanticIndex.ts +662 -0
- package/src/summarization/shared.ts +130 -0
- package/src/tools/runStepResume.ts +9 -0
- package/src/tools/subagent/SubagentExecutor.ts +4 -27
- package/src/tools/subagent/childGraphConfig.ts +3 -0
- package/src/types/graph.ts +9 -0
- package/src/types/run.ts +8 -0
- package/src/types/stream.ts +6 -0
- package/src/types/summarize.ts +57 -0
- package/src/utils/tokens.ts +31 -8
package/src/messages/format.ts
CHANGED
|
@@ -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:
|
|
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
|
|