@librechat/agents 3.6.8 → 3.6.10
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 +46 -39
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/agents/projection.cjs +2 -2
- package/dist/cjs/agents/projection.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +28 -18
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +87 -16
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +10 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +14 -0
- package/dist/cjs/messages/alternation.cjs +125 -20
- package/dist/cjs/messages/alternation.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +195 -18
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +488 -118
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/handoffCue.cjs +3 -2
- package/dist/cjs/messages/handoffCue.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -0
- package/dist/cjs/messages/injected.cjs +5 -2
- package/dist/cjs/messages/injected.cjs.map +1 -1
- package/dist/cjs/messages/provenance.cjs +411 -0
- package/dist/cjs/messages/provenance.cjs.map +1 -0
- package/dist/cjs/messages/prune.cjs +18 -13
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/toolResultTypes.cjs +663 -0
- package/dist/cjs/messages/toolResultTypes.cjs.map +1 -0
- package/dist/cjs/run.cjs +7 -4
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +21 -4
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CallerCapabilities.cjs +48 -0
- package/dist/cjs/tools/CallerCapabilities.cjs.map +1 -0
- package/dist/cjs/tools/ProgrammaticCallerPolicy.cjs +34 -0
- package/dist/cjs/tools/ProgrammaticCallerPolicy.cjs.map +1 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +21 -4
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +25 -24
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +12 -4
- package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +13 -4
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +47 -11
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
- package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +19 -9
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +2 -1
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/toolContent.cjs +2 -2
- package/dist/cjs/utils/toolContent.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +46 -39
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/agents/projection.mjs +2 -2
- package/dist/esm/agents/projection.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +30 -20
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +87 -16
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +10 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +4 -3
- package/dist/esm/messages/alternation.mjs +125 -20
- package/dist/esm/messages/alternation.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +196 -19
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +488 -119
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/handoffCue.mjs +3 -2
- package/dist/esm/messages/handoffCue.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -0
- package/dist/esm/messages/injected.mjs +5 -2
- package/dist/esm/messages/injected.mjs.map +1 -1
- package/dist/esm/messages/provenance.mjs +401 -0
- package/dist/esm/messages/provenance.mjs.map +1 -0
- package/dist/esm/messages/prune.mjs +18 -13
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/toolResultTypes.mjs +657 -0
- package/dist/esm/messages/toolResultTypes.mjs.map +1 -0
- package/dist/esm/run.mjs +7 -4
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +21 -4
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CallerCapabilities.mjs +45 -0
- package/dist/esm/tools/CallerCapabilities.mjs.map +1 -0
- package/dist/esm/tools/ProgrammaticCallerPolicy.mjs +32 -0
- package/dist/esm/tools/ProgrammaticCallerPolicy.mjs.map +1 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +21 -4
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +25 -24
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +14 -6
- package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +15 -6
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +47 -12
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
- package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +19 -9
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +2 -1
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/toolContent.mjs +2 -2
- package/dist/esm/utils/toolContent.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +8 -13
- package/dist/types/agents/projection.d.ts +3 -1
- package/dist/types/graphs/Graph.d.ts +1 -1
- package/dist/types/llm/openai/index.d.ts +20 -0
- package/dist/types/messages/format.d.ts +5 -0
- package/dist/types/messages/index.d.ts +1 -0
- package/dist/types/messages/provenance.d.ts +85 -0
- package/dist/types/messages/toolResultTypes.d.ts +33 -0
- package/dist/types/tools/CallerCapabilities.d.ts +12 -0
- package/dist/types/tools/ProgrammaticCallerPolicy.d.ts +20 -0
- package/dist/types/tools/ToolNode.d.ts +4 -7
- package/dist/types/tools/local/resolveLocalExecutionTools.d.ts +4 -0
- package/dist/types/tools/ptcTimeout.d.ts +8 -0
- package/dist/types/tools/search/types.d.ts +15 -0
- package/dist/types/types/graph.d.ts +3 -1
- package/dist/types/types/tools.d.ts +13 -2
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +109 -67
- package/src/agents/projection.ts +9 -1
- package/src/graphs/Graph.ts +56 -23
- package/src/graphs/MultiAgentGraph.ts +175 -33
- package/src/llm/openai/index.ts +43 -0
- package/src/messages/alternation.ts +217 -34
- package/src/messages/core.ts +358 -38
- package/src/messages/format.ts +958 -137
- package/src/messages/handoffCue.ts +7 -4
- package/src/messages/index.ts +1 -0
- package/src/messages/injected.ts +9 -6
- package/src/messages/provenance.ts +897 -0
- package/src/messages/prune.ts +28 -10
- package/src/messages/toolResultTypes.ts +1174 -0
- package/src/run.ts +9 -4
- package/src/tools/BashProgrammaticToolCalling.ts +46 -12
- package/src/tools/CallerCapabilities.ts +78 -0
- package/src/tools/ProgrammaticCallerPolicy.ts +97 -0
- package/src/tools/ProgrammaticToolCalling.ts +41 -7
- package/src/tools/ToolNode.ts +70 -52
- package/src/tools/cloudflare/CloudflareProgrammaticToolCalling.ts +24 -26
- package/src/tools/local/LocalProgrammaticToolCalling.ts +28 -23
- package/src/tools/local/resolveLocalExecutionTools.ts +132 -13
- package/src/tools/ptcTimeout.ts +6 -0
- package/src/tools/search/search.ts +25 -8
- package/src/tools/search/tool.ts +2 -0
- package/src/tools/search/types.ts +16 -0
- package/src/tools/subagent/SubagentExecutor.ts +8 -4
- package/src/types/graph.ts +3 -0
- package/src/types/tools.ts +14 -3
- package/src/utils/toolContent.ts +2 -2
package/src/messages/format.ts
CHANGED
|
@@ -28,6 +28,26 @@ import type {
|
|
|
28
28
|
TPayload,
|
|
29
29
|
TMessage,
|
|
30
30
|
} from '@/types';
|
|
31
|
+
import type {
|
|
32
|
+
ProviderMessageAttribution,
|
|
33
|
+
ProviderMessageProvenancePart,
|
|
34
|
+
} from './provenance';
|
|
35
|
+
import type { ProviderToolCallIndex } from './toolResultTypes';
|
|
36
|
+
import {
|
|
37
|
+
appendProviderToolCallDescriptor,
|
|
38
|
+
consumeProviderToolResultPair,
|
|
39
|
+
getBoundedProviderPairingArrayProperty,
|
|
40
|
+
getProviderToolCallPartDescriptor,
|
|
41
|
+
getProviderToolResultPartDescriptor,
|
|
42
|
+
hasStructurallyValidAnthropicWebSearchResultContent,
|
|
43
|
+
} from './toolResultTypes';
|
|
44
|
+
import {
|
|
45
|
+
hasBijectiveProviderContentPartMapping,
|
|
46
|
+
inspectProviderMessageProvenance,
|
|
47
|
+
inspectProviderSourceMessageIds,
|
|
48
|
+
setInvalidProviderMessageProvenance,
|
|
49
|
+
setProviderMessageProvenance,
|
|
50
|
+
} from './provenance';
|
|
31
51
|
import {
|
|
32
52
|
compactToolContent,
|
|
33
53
|
getToolContentCharLength,
|
|
@@ -218,19 +238,27 @@ export const formatMessage = ({
|
|
|
218
238
|
const mediaParts: MessageContentComplex[] = [];
|
|
219
239
|
|
|
220
240
|
if (Array.isArray(documents) && documents.length > 0) {
|
|
221
|
-
|
|
241
|
+
for (const document of documents) {
|
|
242
|
+
mediaParts.push(document);
|
|
243
|
+
}
|
|
222
244
|
}
|
|
223
245
|
|
|
224
246
|
if (Array.isArray(videos) && videos.length > 0) {
|
|
225
|
-
|
|
247
|
+
for (const video of videos) {
|
|
248
|
+
mediaParts.push(video);
|
|
249
|
+
}
|
|
226
250
|
}
|
|
227
251
|
|
|
228
252
|
if (Array.isArray(audios) && audios.length > 0) {
|
|
229
|
-
|
|
253
|
+
for (const audio of audios) {
|
|
254
|
+
mediaParts.push(audio);
|
|
255
|
+
}
|
|
230
256
|
}
|
|
231
257
|
|
|
232
258
|
if (Array.isArray(image_urls) && image_urls.length > 0) {
|
|
233
|
-
|
|
259
|
+
for (const imageUrl of image_urls) {
|
|
260
|
+
mediaParts.push(imageUrl);
|
|
261
|
+
}
|
|
234
262
|
}
|
|
235
263
|
|
|
236
264
|
if (mediaParts.length > 0 && role === 'user') {
|
|
@@ -340,8 +368,13 @@ interface FormatAssistantMessageOptions {
|
|
|
340
368
|
preserveReasoningContent?: boolean;
|
|
341
369
|
provider?: Providers;
|
|
342
370
|
sourceMessageId?: string;
|
|
371
|
+
sourceContentPartOffset?: number;
|
|
372
|
+
sourceContentPartIndices?: readonly SourceContentPartIndices[];
|
|
373
|
+
toolSourceContentPartIndices?: ReadonlySet<number>;
|
|
343
374
|
}
|
|
344
375
|
|
|
376
|
+
type SourceContentPartIndices = number | readonly number[];
|
|
377
|
+
|
|
345
378
|
interface FormatAgentMessagesOptions {
|
|
346
379
|
provider?: Providers;
|
|
347
380
|
/** Reconstruct hidden `reasoning_content` from `THINK` parts onto prior
|
|
@@ -434,21 +467,81 @@ function getToolUseId(part: MessageContentComplex): string | undefined {
|
|
|
434
467
|
return part.tool_use_id;
|
|
435
468
|
}
|
|
436
469
|
|
|
437
|
-
function
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
470
|
+
function collectTrustedToolResultSourceContentPartIndices(
|
|
471
|
+
content: readonly unknown[] | undefined,
|
|
472
|
+
sourceContentPartOffset: number
|
|
473
|
+
): Set<number> | undefined {
|
|
474
|
+
if (content == null) {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
let calls: ProviderToolCallIndex | undefined;
|
|
478
|
+
let trusted: Set<number> | undefined;
|
|
479
|
+
let previousPart: MessageContentComplex | null | undefined;
|
|
480
|
+
for (let index = 0; index < content.length; index++) {
|
|
481
|
+
const part = content[index] as
|
|
482
|
+
| MessageContentComplex
|
|
483
|
+
| null
|
|
484
|
+
| undefined;
|
|
485
|
+
if (part == null) {
|
|
486
|
+
previousPart = part;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
const call = getProviderToolCallPartDescriptor(part);
|
|
490
|
+
if (call != null) {
|
|
491
|
+
calls ??= new Map();
|
|
492
|
+
appendProviderToolCallDescriptor(calls, call);
|
|
493
|
+
}
|
|
494
|
+
const result = getProviderToolResultPartDescriptor(part);
|
|
495
|
+
if (result != null) {
|
|
496
|
+
calls ??= new Map();
|
|
497
|
+
if (consumeProviderToolResultPair(result, calls, previousPart)) {
|
|
498
|
+
trusted ??= new Set();
|
|
499
|
+
trusted.add(sourceContentPartOffset + index);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
previousPart = part;
|
|
503
|
+
}
|
|
504
|
+
return trusted;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function sourceContentPartIndicesAreTrustedToolResult(
|
|
508
|
+
sourceContentPartIndices: SourceContentPartIndices,
|
|
509
|
+
trustedToolSourceContentPartIndices: ReadonlySet<number> | undefined
|
|
510
|
+
): boolean {
|
|
511
|
+
if (typeof sourceContentPartIndices === 'number') {
|
|
512
|
+
return trustedToolSourceContentPartIndices?.has(sourceContentPartIndices) === true;
|
|
513
|
+
}
|
|
514
|
+
if (sourceContentPartIndices.length === 0) {
|
|
443
515
|
return false;
|
|
444
516
|
}
|
|
445
|
-
const
|
|
517
|
+
for (const sourceContentPartIndex of sourceContentPartIndices) {
|
|
518
|
+
if (trustedToolSourceContentPartIndices?.has(sourceContentPartIndex) !== true) {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function isTrustedServerToolResult(
|
|
526
|
+
part: MessageContentComplex,
|
|
527
|
+
sourceContentPartIndices: SourceContentPartIndices,
|
|
528
|
+
trustedToolSourceContentPartIndices: ReadonlySet<number> | undefined
|
|
529
|
+
): boolean {
|
|
530
|
+
const toolUseId = getToolUseId(part);
|
|
446
531
|
return (
|
|
447
|
-
|
|
448
|
-
(
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
532
|
+
toolUseId?.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX) === true &&
|
|
533
|
+
sourceContentPartIndicesAreTrustedToolResult(
|
|
534
|
+
sourceContentPartIndices,
|
|
535
|
+
trustedToolSourceContentPartIndices
|
|
536
|
+
)
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function isServerToolResultForWire(part: MessageContentComplex): boolean {
|
|
541
|
+
const toolUseId = getToolUseId(part);
|
|
542
|
+
return (
|
|
543
|
+
toolUseId?.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX) === true &&
|
|
544
|
+
hasStructurallyValidAnthropicWebSearchResultContent(part)
|
|
452
545
|
);
|
|
453
546
|
}
|
|
454
547
|
|
|
@@ -496,6 +589,155 @@ function endsWithSteerMessage(
|
|
|
496
589
|
return formatted[formatted.length - 1].additional_kwargs.source === 'steer';
|
|
497
590
|
}
|
|
498
591
|
|
|
592
|
+
interface MutableProviderMessageProvenancePart {
|
|
593
|
+
attribution: ProviderMessageAttribution;
|
|
594
|
+
sourceMessageId?: string;
|
|
595
|
+
sourceContentPartIndices?: number[];
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
interface ProviderMessageProvenanceBuilder {
|
|
599
|
+
readonly parts: MutableProviderMessageProvenancePart[];
|
|
600
|
+
lastSeenSourceContentPartIndices?: Set<number>;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function createProviderMessageProvenanceBuilder(): ProviderMessageProvenanceBuilder {
|
|
604
|
+
return { parts: [] };
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function appendProviderProvenanceContribution(
|
|
608
|
+
builder: ProviderMessageProvenanceBuilder,
|
|
609
|
+
attribution: ProviderMessageAttribution,
|
|
610
|
+
sourceMessageId?: string,
|
|
611
|
+
sourceContentPartIndex?: number
|
|
612
|
+
): void {
|
|
613
|
+
const last = builder.parts[builder.parts.length - 1];
|
|
614
|
+
if (
|
|
615
|
+
builder.parts.length === 0 ||
|
|
616
|
+
last.attribution !== attribution ||
|
|
617
|
+
last.sourceMessageId !== sourceMessageId ||
|
|
618
|
+
(last.sourceContentPartIndices == null) !== (sourceContentPartIndex == null)
|
|
619
|
+
) {
|
|
620
|
+
builder.parts.push({
|
|
621
|
+
attribution,
|
|
622
|
+
...(sourceMessageId != null && { sourceMessageId }),
|
|
623
|
+
...(sourceContentPartIndex != null && {
|
|
624
|
+
sourceContentPartIndices: [sourceContentPartIndex],
|
|
625
|
+
}),
|
|
626
|
+
});
|
|
627
|
+
builder.lastSeenSourceContentPartIndices = undefined;
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (sourceContentPartIndex == null) {
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
const sourceContentPartIndices = (last.sourceContentPartIndices ??= []);
|
|
634
|
+
if (sourceContentPartIndices.length === 0) {
|
|
635
|
+
sourceContentPartIndices.push(sourceContentPartIndex);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const seen = (builder.lastSeenSourceContentPartIndices ??= new Set(
|
|
639
|
+
sourceContentPartIndices
|
|
640
|
+
));
|
|
641
|
+
if (!seen.has(sourceContentPartIndex)) {
|
|
642
|
+
seen.add(sourceContentPartIndex);
|
|
643
|
+
sourceContentPartIndices.push(sourceContentPartIndex);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function appendProviderProvenanceIndices(
|
|
648
|
+
builder: ProviderMessageProvenanceBuilder,
|
|
649
|
+
attribution: ProviderMessageAttribution,
|
|
650
|
+
sourceMessageId: string | undefined,
|
|
651
|
+
sourceContentPartIndices?: SourceContentPartIndices,
|
|
652
|
+
toolSourceContentPartIndices?: ReadonlySet<number>
|
|
653
|
+
): void {
|
|
654
|
+
if (typeof sourceContentPartIndices === 'number') {
|
|
655
|
+
appendProviderProvenanceContribution(
|
|
656
|
+
builder,
|
|
657
|
+
toolSourceContentPartIndices?.has(sourceContentPartIndices) === true
|
|
658
|
+
? 'tool'
|
|
659
|
+
: attribution,
|
|
660
|
+
sourceMessageId,
|
|
661
|
+
sourceContentPartIndices
|
|
662
|
+
);
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (
|
|
666
|
+
sourceContentPartIndices == null ||
|
|
667
|
+
sourceContentPartIndices.length === 0
|
|
668
|
+
) {
|
|
669
|
+
appendProviderProvenanceContribution(builder, attribution, sourceMessageId);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
for (const sourceContentPartIndex of sourceContentPartIndices) {
|
|
673
|
+
appendProviderProvenanceContribution(
|
|
674
|
+
builder,
|
|
675
|
+
toolSourceContentPartIndices?.has(sourceContentPartIndex) === true
|
|
676
|
+
? 'tool'
|
|
677
|
+
: attribution,
|
|
678
|
+
sourceMessageId,
|
|
679
|
+
sourceContentPartIndex
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function appendSourceContentPartIndices(
|
|
685
|
+
target: number[],
|
|
686
|
+
sourceContentPartIndices: SourceContentPartIndices
|
|
687
|
+
): void {
|
|
688
|
+
if (typeof sourceContentPartIndices === 'number') {
|
|
689
|
+
target.push(sourceContentPartIndices);
|
|
690
|
+
} else {
|
|
691
|
+
for (const sourceContentPartIndex of sourceContentPartIndices) {
|
|
692
|
+
target.push(sourceContentPartIndex);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function appendProviderProvenanceParts(
|
|
698
|
+
builder: ProviderMessageProvenanceBuilder,
|
|
699
|
+
parts: readonly ProviderMessageProvenancePart[]
|
|
700
|
+
): void {
|
|
701
|
+
for (const part of parts) {
|
|
702
|
+
appendProviderProvenanceIndices(
|
|
703
|
+
builder,
|
|
704
|
+
part.attribution,
|
|
705
|
+
part.sourceMessageId,
|
|
706
|
+
part.sourceContentPartIndices
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function mergeAdjacentProviderProvenanceParts(
|
|
712
|
+
parts: readonly ProviderMessageProvenancePart[]
|
|
713
|
+
): ProviderMessageProvenancePart[] {
|
|
714
|
+
const builder = createProviderMessageProvenanceBuilder();
|
|
715
|
+
appendProviderProvenanceParts(builder, parts);
|
|
716
|
+
return builder.parts;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
function createProviderContentProvenanceParts(
|
|
720
|
+
content: readonly MessageContentComplex[],
|
|
721
|
+
sourceContentPartOffset: number,
|
|
722
|
+
sourceMessageId: string | undefined,
|
|
723
|
+
defaultAttribution: ProviderMessageAttribution
|
|
724
|
+
): ProviderMessageProvenancePart[] {
|
|
725
|
+
const builder = createProviderMessageProvenanceBuilder();
|
|
726
|
+
for (let index = 0; index < content.length; index++) {
|
|
727
|
+
const part = content[index] as MessageContentComplex | null | undefined;
|
|
728
|
+
if (part == null) {
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
appendProviderProvenanceContribution(
|
|
732
|
+
builder,
|
|
733
|
+
defaultAttribution,
|
|
734
|
+
sourceMessageId,
|
|
735
|
+
sourceContentPartOffset + index
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return builder.parts;
|
|
739
|
+
}
|
|
740
|
+
|
|
499
741
|
/**
|
|
500
742
|
* Helper function to format an assistant message
|
|
501
743
|
* @param message The message to format
|
|
@@ -515,67 +757,196 @@ function formatAssistantMessage(
|
|
|
515
757
|
| RoleBearingMessage<ToolMessage>
|
|
516
758
|
| RoleBearingMessage<HumanMessage>
|
|
517
759
|
> = [];
|
|
760
|
+
const formattedMessageProvenance = new Map<
|
|
761
|
+
BaseMessage,
|
|
762
|
+
ProviderMessageProvenanceBuilder
|
|
763
|
+
>();
|
|
518
764
|
const appendFormattedMessage = (
|
|
519
|
-
formattedMessage: (typeof formattedMessages)[number]
|
|
765
|
+
formattedMessage: (typeof formattedMessages)[number],
|
|
766
|
+
attribution: ProviderMessageAttribution,
|
|
767
|
+
sourceContentPartIndices?: SourceContentPartIndices,
|
|
768
|
+
provenanceBuilder?: ProviderMessageProvenanceBuilder
|
|
769
|
+
): void => {
|
|
770
|
+
const builder =
|
|
771
|
+
provenanceBuilder ?? createProviderMessageProvenanceBuilder();
|
|
772
|
+
if (provenanceBuilder == null) {
|
|
773
|
+
appendProviderProvenanceIndices(
|
|
774
|
+
builder,
|
|
775
|
+
attribution,
|
|
776
|
+
options?.sourceMessageId,
|
|
777
|
+
sourceContentPartIndices
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
formattedMessageProvenance.set(formattedMessage, builder);
|
|
781
|
+
formattedMessages.push(formattedMessage);
|
|
782
|
+
};
|
|
783
|
+
const finalizeFormattedMessages = (): typeof formattedMessages => {
|
|
784
|
+
for (let index = 0; index < formattedMessages.length; index++) {
|
|
785
|
+
const formattedMessage = formattedMessages[index];
|
|
786
|
+
stampSourceMessageIdentity(
|
|
787
|
+
formattedMessage,
|
|
788
|
+
options?.sourceMessageId,
|
|
789
|
+
index,
|
|
790
|
+
'model',
|
|
791
|
+
undefined,
|
|
792
|
+
formattedMessageProvenance.get(formattedMessage)?.parts
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
return formattedMessages;
|
|
796
|
+
};
|
|
797
|
+
const appendSourcePartIndices = (
|
|
798
|
+
formattedMessage: (typeof formattedMessages)[number],
|
|
799
|
+
attribution: ProviderMessageAttribution,
|
|
800
|
+
sourceContentPartIndices: SourceContentPartIndices
|
|
520
801
|
): void => {
|
|
521
|
-
|
|
522
|
-
|
|
802
|
+
const builder = formattedMessageProvenance.get(formattedMessage);
|
|
803
|
+
if (builder == null) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
appendProviderProvenanceIndices(
|
|
807
|
+
builder,
|
|
808
|
+
attribution,
|
|
523
809
|
options?.sourceMessageId,
|
|
524
|
-
|
|
810
|
+
sourceContentPartIndices
|
|
525
811
|
);
|
|
526
|
-
|
|
812
|
+
};
|
|
813
|
+
const getSourcePartIndices = (partIndex: number): SourceContentPartIndices =>
|
|
814
|
+
options?.sourceContentPartIndices?.[partIndex] ??
|
|
815
|
+
(options?.sourceContentPartOffset ?? 0) + partIndex;
|
|
816
|
+
const createSourceProvenanceBuilder = (
|
|
817
|
+
sourceContentPartIndices: SourceContentPartIndices,
|
|
818
|
+
attribution: ProviderMessageAttribution,
|
|
819
|
+
applyToolOverrides = false
|
|
820
|
+
): ProviderMessageProvenanceBuilder => {
|
|
821
|
+
const builder = createProviderMessageProvenanceBuilder();
|
|
822
|
+
appendProviderProvenanceIndices(
|
|
823
|
+
builder,
|
|
824
|
+
attribution,
|
|
825
|
+
options?.sourceMessageId,
|
|
826
|
+
sourceContentPartIndices,
|
|
827
|
+
applyToolOverrides ? options?.toolSourceContentPartIndices : undefined
|
|
828
|
+
);
|
|
829
|
+
return builder;
|
|
527
830
|
};
|
|
528
831
|
let currentContent: MessageContentComplex[] = [];
|
|
832
|
+
let currentContentProvenance = createProviderMessageProvenanceBuilder();
|
|
833
|
+
const appendCurrentContentProvenance = (
|
|
834
|
+
sourceContentPartIndices: SourceContentPartIndices,
|
|
835
|
+
attribution: ProviderMessageAttribution,
|
|
836
|
+
applyToolOverrides = false
|
|
837
|
+
): void => {
|
|
838
|
+
appendProviderProvenanceIndices(
|
|
839
|
+
currentContentProvenance,
|
|
840
|
+
attribution,
|
|
841
|
+
options?.sourceMessageId,
|
|
842
|
+
sourceContentPartIndices,
|
|
843
|
+
applyToolOverrides ? options?.toolSourceContentPartIndices : undefined
|
|
844
|
+
);
|
|
845
|
+
};
|
|
529
846
|
let lastAIMessage: RoleBearingMessage<AIMessage> | null = null;
|
|
530
847
|
let hasReasoning = false;
|
|
531
848
|
let pendingReasoningContent = '';
|
|
849
|
+
let pendingReasoningSourcePartIndices: number[] = [];
|
|
532
850
|
const emittedServerToolUseIds = new Set<string>();
|
|
533
|
-
const pendingServerToolUses = new Map<
|
|
851
|
+
const pendingServerToolUses = new Map<
|
|
852
|
+
string,
|
|
853
|
+
{
|
|
854
|
+
content: MessageContentComplex;
|
|
855
|
+
sourceContentPartIndices: SourceContentPartIndices;
|
|
856
|
+
}
|
|
857
|
+
>();
|
|
534
858
|
const shouldPreserveReasoningContent =
|
|
535
859
|
options?.preserveReasoningContent === true;
|
|
536
860
|
const serverToolResultIds = new Set<string>();
|
|
537
861
|
const preferredToolCallParts = new Map<string, MessageContentComplex>();
|
|
538
862
|
|
|
539
|
-
const takePendingReasoningContent = ():
|
|
863
|
+
const takePendingReasoningContent = (): {
|
|
864
|
+
content?: string;
|
|
865
|
+
sourceContentPartIndices: number[];
|
|
866
|
+
} => {
|
|
540
867
|
if (!shouldPreserveReasoningContent || !pendingReasoningContent) {
|
|
541
|
-
return
|
|
868
|
+
return { sourceContentPartIndices: [] };
|
|
542
869
|
}
|
|
543
|
-
const
|
|
870
|
+
const content = pendingReasoningContent;
|
|
871
|
+
const sourceContentPartIndices = pendingReasoningSourcePartIndices;
|
|
544
872
|
pendingReasoningContent = '';
|
|
545
|
-
|
|
873
|
+
pendingReasoningSourcePartIndices = [];
|
|
874
|
+
return { content, sourceContentPartIndices };
|
|
546
875
|
};
|
|
547
876
|
|
|
548
877
|
const createAIMessage = (
|
|
549
878
|
content: MessageContent
|
|
550
|
-
):
|
|
551
|
-
|
|
552
|
-
|
|
879
|
+
): {
|
|
880
|
+
message: RoleBearingMessage<AIMessage>;
|
|
881
|
+
reasoningSourceContentPartIndices: number[];
|
|
882
|
+
} => {
|
|
883
|
+
const reasoning = takePendingReasoningContent();
|
|
884
|
+
const message = withMessageRole(
|
|
553
885
|
new AIMessage({
|
|
554
886
|
content,
|
|
555
|
-
...(
|
|
556
|
-
additional_kwargs: { reasoning_content:
|
|
887
|
+
...(reasoning.content != null && {
|
|
888
|
+
additional_kwargs: { reasoning_content: reasoning.content },
|
|
557
889
|
}),
|
|
558
890
|
}),
|
|
559
891
|
'assistant'
|
|
560
892
|
);
|
|
893
|
+
return {
|
|
894
|
+
message,
|
|
895
|
+
reasoningSourceContentPartIndices: reasoning.sourceContentPartIndices,
|
|
896
|
+
};
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
const appendAIMessage = (
|
|
900
|
+
content: MessageContent,
|
|
901
|
+
provenance: ProviderMessageProvenanceBuilder
|
|
902
|
+
): RoleBearingMessage<AIMessage> => {
|
|
903
|
+
const created = createAIMessage(content);
|
|
904
|
+
let combinedProvenance = provenance;
|
|
905
|
+
if (created.reasoningSourceContentPartIndices.length > 0) {
|
|
906
|
+
combinedProvenance = createProviderMessageProvenanceBuilder();
|
|
907
|
+
appendProviderProvenanceIndices(
|
|
908
|
+
combinedProvenance,
|
|
909
|
+
'model',
|
|
910
|
+
options?.sourceMessageId,
|
|
911
|
+
created.reasoningSourceContentPartIndices
|
|
912
|
+
);
|
|
913
|
+
appendProviderProvenanceParts(combinedProvenance, provenance.parts);
|
|
914
|
+
}
|
|
915
|
+
appendFormattedMessage(
|
|
916
|
+
created.message,
|
|
917
|
+
'model',
|
|
918
|
+
undefined,
|
|
919
|
+
combinedProvenance
|
|
920
|
+
);
|
|
921
|
+
return created.message;
|
|
561
922
|
};
|
|
562
923
|
|
|
563
924
|
const attachPendingReasoningContent = (aiMessage: AIMessage): void => {
|
|
564
|
-
const
|
|
565
|
-
if (
|
|
925
|
+
const reasoning = takePendingReasoningContent();
|
|
926
|
+
if (reasoning.content == null) {
|
|
566
927
|
return;
|
|
567
928
|
}
|
|
568
929
|
aiMessage.additional_kwargs.reasoning_content =
|
|
569
930
|
typeof aiMessage.additional_kwargs.reasoning_content === 'string'
|
|
570
|
-
? `${aiMessage.additional_kwargs.reasoning_content}${
|
|
571
|
-
:
|
|
931
|
+
? `${aiMessage.additional_kwargs.reasoning_content}${reasoning.content}`
|
|
932
|
+
: reasoning.content;
|
|
933
|
+
appendSourcePartIndices(
|
|
934
|
+
aiMessage as (typeof formattedMessages)[number],
|
|
935
|
+
'model',
|
|
936
|
+
reasoning.sourceContentPartIndices
|
|
937
|
+
);
|
|
572
938
|
};
|
|
573
939
|
|
|
574
940
|
const flushPendingServerToolUse = (toolUseId: string): void => {
|
|
575
|
-
for (const [id,
|
|
941
|
+
for (const [id, pending] of pendingServerToolUses) {
|
|
576
942
|
pendingServerToolUses.delete(id);
|
|
577
943
|
if (id === toolUseId) {
|
|
578
|
-
currentContent.push(content);
|
|
944
|
+
currentContent.push(pending.content);
|
|
945
|
+
appendCurrentContentProvenance(
|
|
946
|
+
pending.sourceContentPartIndices,
|
|
947
|
+
'model',
|
|
948
|
+
true
|
|
949
|
+
);
|
|
579
950
|
emittedServerToolUseIds.add(id);
|
|
580
951
|
return;
|
|
581
952
|
}
|
|
@@ -586,12 +957,26 @@ function formatAssistantMessage(
|
|
|
586
957
|
const contentParts = message.content as Array<
|
|
587
958
|
MessageContentComplex | undefined | null
|
|
588
959
|
>;
|
|
960
|
+
let trustedServerToolResultPartIndices: Set<number> | undefined;
|
|
961
|
+
let wireServerToolResultPartIndices: Set<number> | undefined;
|
|
589
962
|
|
|
590
|
-
for (
|
|
963
|
+
for (let partIndex = 0; partIndex < contentParts.length; partIndex++) {
|
|
964
|
+
const part = contentParts[partIndex];
|
|
591
965
|
if (part == null) {
|
|
592
966
|
continue;
|
|
593
967
|
}
|
|
594
|
-
|
|
968
|
+
const isTrustedResult = isTrustedServerToolResult(
|
|
969
|
+
part,
|
|
970
|
+
getSourcePartIndices(partIndex),
|
|
971
|
+
options?.toolSourceContentPartIndices
|
|
972
|
+
);
|
|
973
|
+
if (isTrustedResult) {
|
|
974
|
+
trustedServerToolResultPartIndices ??= new Set();
|
|
975
|
+
trustedServerToolResultPartIndices.add(partIndex);
|
|
976
|
+
}
|
|
977
|
+
if (isTrustedResult || isServerToolResultForWire(part)) {
|
|
978
|
+
wireServerToolResultPartIndices ??= new Set();
|
|
979
|
+
wireServerToolResultPartIndices.add(partIndex);
|
|
595
980
|
serverToolResultIds.add(getToolUseId(part) ?? '');
|
|
596
981
|
}
|
|
597
982
|
if (options?.provider === Providers.ANTHROPIC) {
|
|
@@ -609,22 +994,26 @@ function formatAssistantMessage(
|
|
|
609
994
|
}
|
|
610
995
|
}
|
|
611
996
|
|
|
612
|
-
for (
|
|
997
|
+
for (let partIndex = 0; partIndex < contentParts.length; partIndex++) {
|
|
998
|
+
const part = contentParts[partIndex];
|
|
613
999
|
if (part == null) {
|
|
614
1000
|
continue;
|
|
615
1001
|
}
|
|
1002
|
+
const sourcePartIndices = getSourcePartIndices(partIndex);
|
|
616
1003
|
const toolUseId = getToolUseId(part);
|
|
617
1004
|
if (toolUseId != null) {
|
|
618
|
-
const isServerToolResult =
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
) {
|
|
623
|
-
continue;
|
|
624
|
-
}
|
|
1005
|
+
const isServerToolResult =
|
|
1006
|
+
trustedServerToolResultPartIndices?.has(partIndex) === true;
|
|
1007
|
+
const isWireServerToolResult =
|
|
1008
|
+
wireServerToolResultPartIndices?.has(partIndex) === true;
|
|
625
1009
|
flushPendingServerToolUse(toolUseId);
|
|
626
|
-
if (
|
|
1010
|
+
if (isWireServerToolResult) {
|
|
627
1011
|
currentContent.push(part);
|
|
1012
|
+
appendCurrentContentProvenance(
|
|
1013
|
+
sourcePartIndices,
|
|
1014
|
+
isServerToolResult ? 'tool' : 'model',
|
|
1015
|
+
!isServerToolResult
|
|
1016
|
+
);
|
|
628
1017
|
continue;
|
|
629
1018
|
}
|
|
630
1019
|
} else if (hasMeaningfulAssistantContent(part)) {
|
|
@@ -644,9 +1033,13 @@ function formatAssistantMessage(
|
|
|
644
1033
|
currentContent.some((content) => content.type !== ContentTypes.TEXT)
|
|
645
1034
|
) {
|
|
646
1035
|
currentContent.push(part);
|
|
647
|
-
|
|
648
|
-
|
|
1036
|
+
appendCurrentContentProvenance(sourcePartIndices, 'model', true);
|
|
1037
|
+
lastAIMessage = appendAIMessage(
|
|
1038
|
+
toLangChainContent(currentContent),
|
|
1039
|
+
currentContentProvenance
|
|
1040
|
+
);
|
|
649
1041
|
currentContent = [];
|
|
1042
|
+
currentContentProvenance = createProviderMessageProvenanceBuilder();
|
|
650
1043
|
continue;
|
|
651
1044
|
}
|
|
652
1045
|
let content = currentContent.reduce((acc, curr) => {
|
|
@@ -656,14 +1049,17 @@ function formatAssistantMessage(
|
|
|
656
1049
|
return acc;
|
|
657
1050
|
}, '');
|
|
658
1051
|
content = `${content}\n${getTextContent(part)}`.trim();
|
|
659
|
-
|
|
660
|
-
|
|
1052
|
+
appendCurrentContentProvenance(sourcePartIndices, 'model', true);
|
|
1053
|
+
lastAIMessage = appendAIMessage(content, currentContentProvenance);
|
|
661
1054
|
currentContent = [];
|
|
1055
|
+
currentContentProvenance = createProviderMessageProvenanceBuilder();
|
|
662
1056
|
continue;
|
|
663
1057
|
}
|
|
664
1058
|
// Create a new AIMessage with this text and prepare for tool calls
|
|
665
|
-
lastAIMessage =
|
|
666
|
-
|
|
1059
|
+
lastAIMessage = appendAIMessage(
|
|
1060
|
+
getTextContent(part),
|
|
1061
|
+
createSourceProvenanceBuilder(sourcePartIndices, 'model', true)
|
|
1062
|
+
);
|
|
667
1063
|
} else if (part.type === ContentTypes.TOOL_CALL) {
|
|
668
1064
|
// Skip malformed tool call entries without tool_call property
|
|
669
1065
|
if (part.tool_call == null) {
|
|
@@ -711,20 +1107,26 @@ function formatAssistantMessage(
|
|
|
711
1107
|
continue;
|
|
712
1108
|
}
|
|
713
1109
|
pendingServerToolUses.set(_tool_call.id, {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
1110
|
+
content: {
|
|
1111
|
+
type: 'server_tool_use',
|
|
1112
|
+
id: _tool_call.id,
|
|
1113
|
+
name: _tool_call.name,
|
|
1114
|
+
input: parseServerToolInput(_args),
|
|
1115
|
+
} as MessageContentComplex,
|
|
1116
|
+
sourceContentPartIndices: sourcePartIndices,
|
|
1117
|
+
});
|
|
719
1118
|
continue;
|
|
720
1119
|
}
|
|
721
1120
|
|
|
722
1121
|
if (!lastAIMessage) {
|
|
723
1122
|
// "Heal" the payload by creating an AIMessage to precede the tool call
|
|
724
|
-
lastAIMessage =
|
|
725
|
-
|
|
1123
|
+
lastAIMessage = appendAIMessage(
|
|
1124
|
+
'',
|
|
1125
|
+
createSourceProvenanceBuilder(sourcePartIndices, 'model')
|
|
1126
|
+
);
|
|
726
1127
|
} else {
|
|
727
1128
|
attachPendingReasoningContent(lastAIMessage);
|
|
1129
|
+
appendSourcePartIndices(lastAIMessage, 'model', sourcePartIndices);
|
|
728
1130
|
}
|
|
729
1131
|
|
|
730
1132
|
const tool_call: ToolCallPart = _tool_call;
|
|
@@ -768,7 +1170,9 @@ function formatAssistantMessage(
|
|
|
768
1170
|
content: formatToolCallOutput(output),
|
|
769
1171
|
}),
|
|
770
1172
|
'tool'
|
|
771
|
-
)
|
|
1173
|
+
),
|
|
1174
|
+
'tool',
|
|
1175
|
+
sourcePartIndices
|
|
772
1176
|
);
|
|
773
1177
|
} else if (
|
|
774
1178
|
part.type === ContentTypes.THINK ||
|
|
@@ -779,6 +1183,10 @@ function formatAssistantMessage(
|
|
|
779
1183
|
) {
|
|
780
1184
|
hasReasoning = true;
|
|
781
1185
|
pendingReasoningContent += extractReasoningContent(part);
|
|
1186
|
+
appendSourceContentPartIndices(
|
|
1187
|
+
pendingReasoningSourcePartIndices,
|
|
1188
|
+
sourcePartIndices
|
|
1189
|
+
);
|
|
782
1190
|
continue;
|
|
783
1191
|
} else if (part.type === ContentTypes.STEER) {
|
|
784
1192
|
/*
|
|
@@ -798,18 +1206,20 @@ function formatAssistantMessage(
|
|
|
798
1206
|
if (
|
|
799
1207
|
currentContent.some((content) => content.type !== ContentTypes.TEXT)
|
|
800
1208
|
) {
|
|
801
|
-
|
|
802
|
-
|
|
1209
|
+
appendAIMessage(
|
|
1210
|
+
toLangChainContent(currentContent),
|
|
1211
|
+
currentContentProvenance
|
|
1212
|
+
);
|
|
803
1213
|
} else {
|
|
804
1214
|
const flushed = currentContent
|
|
805
1215
|
.reduce((acc, curr) => `${acc}${getTextContent(curr)}\n`, '')
|
|
806
1216
|
.trim();
|
|
807
1217
|
if (flushed.length > 0) {
|
|
808
|
-
|
|
809
|
-
appendFormattedMessage(lastAIMessage);
|
|
1218
|
+
appendAIMessage(flushed, currentContentProvenance);
|
|
810
1219
|
}
|
|
811
1220
|
}
|
|
812
1221
|
currentContent = [];
|
|
1222
|
+
currentContentProvenance = createProviderMessageProvenanceBuilder();
|
|
813
1223
|
} else if (shouldPreserveReasoningContent && pendingReasoningContent) {
|
|
814
1224
|
/**
|
|
815
1225
|
* Reasoning directly preceding a steer has no `currentContent`
|
|
@@ -818,8 +1228,7 @@ function formatAssistantMessage(
|
|
|
818
1228
|
* `additional_kwargs.reasoning_content`) or the persisted
|
|
819
1229
|
* assistant reasoning silently vanishes on replay.
|
|
820
1230
|
*/
|
|
821
|
-
|
|
822
|
-
appendFormattedMessage(lastAIMessage);
|
|
1231
|
+
appendAIMessage('', createProviderMessageProvenanceBuilder());
|
|
823
1232
|
}
|
|
824
1233
|
const steerPart = part as {
|
|
825
1234
|
steer?: string;
|
|
@@ -836,7 +1245,9 @@ function formatAssistantMessage(
|
|
|
836
1245
|
additional_kwargs: { role: 'user', source: 'steer' },
|
|
837
1246
|
}),
|
|
838
1247
|
'user'
|
|
839
|
-
)
|
|
1248
|
+
),
|
|
1249
|
+
'user',
|
|
1250
|
+
sourcePartIndices
|
|
840
1251
|
);
|
|
841
1252
|
lastAIMessage = null;
|
|
842
1253
|
/** The steer splits the assistant message: the post-steer segment
|
|
@@ -844,6 +1255,7 @@ function formatAssistantMessage(
|
|
|
844
1255
|
* flushed above or intentionally dropped when not preserving). */
|
|
845
1256
|
hasReasoning = false;
|
|
846
1257
|
pendingReasoningContent = '';
|
|
1258
|
+
pendingReasoningSourcePartIndices = [];
|
|
847
1259
|
} else if (
|
|
848
1260
|
part.type === ContentTypes.ERROR ||
|
|
849
1261
|
part.type === ContentTypes.AGENT_UPDATE ||
|
|
@@ -856,10 +1268,16 @@ function formatAssistantMessage(
|
|
|
856
1268
|
continue;
|
|
857
1269
|
}
|
|
858
1270
|
currentContent.push(part);
|
|
1271
|
+
appendCurrentContentProvenance(sourcePartIndices, 'model', true);
|
|
859
1272
|
}
|
|
860
1273
|
}
|
|
861
|
-
for (const
|
|
862
|
-
currentContent.push(content);
|
|
1274
|
+
for (const pending of pendingServerToolUses.values()) {
|
|
1275
|
+
currentContent.push(pending.content);
|
|
1276
|
+
appendCurrentContentProvenance(
|
|
1277
|
+
pending.sourceContentPartIndices,
|
|
1278
|
+
'model',
|
|
1279
|
+
true
|
|
1280
|
+
);
|
|
863
1281
|
}
|
|
864
1282
|
}
|
|
865
1283
|
|
|
@@ -867,34 +1285,44 @@ function formatAssistantMessage(
|
|
|
867
1285
|
let content = '';
|
|
868
1286
|
for (const part of currentContent) {
|
|
869
1287
|
if (part.type !== ContentTypes.TEXT) {
|
|
870
|
-
|
|
871
|
-
|
|
1288
|
+
appendAIMessage(
|
|
1289
|
+
toLangChainContent(currentContent),
|
|
1290
|
+
currentContentProvenance
|
|
872
1291
|
);
|
|
873
|
-
return
|
|
1292
|
+
return finalizeFormattedMessages();
|
|
874
1293
|
}
|
|
875
1294
|
content += `${getTextContent(part)}\n`;
|
|
876
1295
|
}
|
|
877
1296
|
content = content.trim();
|
|
878
1297
|
|
|
879
1298
|
if (content) {
|
|
880
|
-
|
|
1299
|
+
appendAIMessage(content, currentContentProvenance);
|
|
881
1300
|
}
|
|
882
1301
|
} else if (currentContent.length > 0) {
|
|
883
|
-
|
|
1302
|
+
appendAIMessage(
|
|
1303
|
+
toLangChainContent(currentContent),
|
|
1304
|
+
currentContentProvenance
|
|
1305
|
+
);
|
|
884
1306
|
}
|
|
885
1307
|
|
|
886
|
-
return
|
|
1308
|
+
return finalizeFormattedMessages();
|
|
887
1309
|
}
|
|
888
1310
|
|
|
889
1311
|
function getSourceMessageId(message: Partial<TMessage>): string | undefined {
|
|
890
|
-
const
|
|
891
|
-
(message as { messageId?:
|
|
892
|
-
(message as { id?:
|
|
893
|
-
|
|
894
|
-
|
|
1312
|
+
const candidates = [
|
|
1313
|
+
(message as { messageId?: unknown }).messageId,
|
|
1314
|
+
(message as { id?: unknown }).id,
|
|
1315
|
+
];
|
|
1316
|
+
for (const candidate of candidates) {
|
|
1317
|
+
if (typeof candidate !== 'string') {
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
const normalized = candidate.trim();
|
|
1321
|
+
if (normalized.length > 0) {
|
|
1322
|
+
return normalized;
|
|
1323
|
+
}
|
|
895
1324
|
}
|
|
896
|
-
|
|
897
|
-
return normalized.length > 0 ? normalized : undefined;
|
|
1325
|
+
return undefined;
|
|
898
1326
|
}
|
|
899
1327
|
|
|
900
1328
|
/**
|
|
@@ -907,13 +1335,53 @@ function getSourceMessageId(message: Partial<TMessage>): string | undefined {
|
|
|
907
1335
|
function stampSourceMessageIdentity(
|
|
908
1336
|
message: RoleBearingMessage<BaseMessage>,
|
|
909
1337
|
sourceMessageId: string | undefined,
|
|
910
|
-
derivedIndex = 0
|
|
1338
|
+
derivedIndex = 0,
|
|
1339
|
+
attribution: ProviderMessageAttribution = 'model',
|
|
1340
|
+
sourceContentPartIndices?: readonly number[],
|
|
1341
|
+
provenanceParts?: readonly ProviderMessageProvenancePart[]
|
|
911
1342
|
): void {
|
|
912
|
-
if (sourceMessageId
|
|
913
|
-
|
|
1343
|
+
if (sourceMessageId != null) {
|
|
1344
|
+
message.additional_kwargs.sourceMessageId = sourceMessageId;
|
|
1345
|
+
}
|
|
1346
|
+
let partsToStamp: readonly ProviderMessageProvenancePart[];
|
|
1347
|
+
if (provenanceParts != null && provenanceParts.length > 0) {
|
|
1348
|
+
let needsSourceMessageId = false;
|
|
1349
|
+
if (sourceMessageId != null) {
|
|
1350
|
+
for (const part of provenanceParts) {
|
|
1351
|
+
if (part.sourceMessageId == null) {
|
|
1352
|
+
needsSourceMessageId = true;
|
|
1353
|
+
break;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if (needsSourceMessageId) {
|
|
1358
|
+
const completedParts: ProviderMessageProvenancePart[] = [];
|
|
1359
|
+
for (const part of provenanceParts) {
|
|
1360
|
+
completedParts.push({
|
|
1361
|
+
...part,
|
|
1362
|
+
...(part.sourceMessageId == null && { sourceMessageId }),
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
partsToStamp = completedParts;
|
|
1366
|
+
} else {
|
|
1367
|
+
partsToStamp = provenanceParts;
|
|
1368
|
+
}
|
|
1369
|
+
} else {
|
|
1370
|
+
partsToStamp = [
|
|
1371
|
+
{
|
|
1372
|
+
attribution,
|
|
1373
|
+
...(sourceMessageId != null && { sourceMessageId }),
|
|
1374
|
+
...(sourceContentPartIndices != null && {
|
|
1375
|
+
sourceContentPartIndices,
|
|
1376
|
+
}),
|
|
1377
|
+
},
|
|
1378
|
+
];
|
|
914
1379
|
}
|
|
915
|
-
|
|
916
|
-
|
|
1380
|
+
setProviderMessageProvenance(
|
|
1381
|
+
message,
|
|
1382
|
+
partsToStamp
|
|
1383
|
+
);
|
|
1384
|
+
if (sourceMessageId == null || derivedIndex !== 0) {
|
|
917
1385
|
return;
|
|
918
1386
|
}
|
|
919
1387
|
message.id = sourceMessageId;
|
|
@@ -979,7 +1447,9 @@ function labelAllAgentContent(
|
|
|
979
1447
|
} as MessageContentComplex);
|
|
980
1448
|
} else {
|
|
981
1449
|
// No agent ID, pass through as-is
|
|
982
|
-
|
|
1450
|
+
for (const part of agentContentBuffer) {
|
|
1451
|
+
result.push(part);
|
|
1452
|
+
}
|
|
983
1453
|
}
|
|
984
1454
|
|
|
985
1455
|
agentContentBuffer = [];
|
|
@@ -1108,7 +1578,9 @@ export const labelContentByAgent = (
|
|
|
1108
1578
|
}
|
|
1109
1579
|
} else {
|
|
1110
1580
|
// Not from a transfer, add as-is
|
|
1111
|
-
|
|
1581
|
+
for (const part of agentContentBuffer) {
|
|
1582
|
+
result.push(part);
|
|
1583
|
+
}
|
|
1112
1584
|
}
|
|
1113
1585
|
|
|
1114
1586
|
agentContentBuffer = [];
|
|
@@ -1541,12 +2013,12 @@ export const formatAgentMessages = (
|
|
|
1541
2013
|
if (next.role === 'assistant') {
|
|
1542
2014
|
return;
|
|
1543
2015
|
}
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
'assistant'
|
|
1548
|
-
)
|
|
2016
|
+
const anchor = withMessageRole(
|
|
2017
|
+
new AIMessage({ content: STEER_ANCHOR_PLACEHOLDER }),
|
|
2018
|
+
'assistant'
|
|
1549
2019
|
);
|
|
2020
|
+
stampSourceMessageIdentity(anchor, undefined, 0, 'synthetic');
|
|
2021
|
+
messages.push(anchor);
|
|
1550
2022
|
};
|
|
1551
2023
|
// If indexTokenCountMap is provided, create a new map to track the updated indices
|
|
1552
2024
|
const updatedIndexTokenCountMap: Record<number, number> = {};
|
|
@@ -1577,6 +2049,12 @@ export const formatAgentMessages = (
|
|
|
1577
2049
|
continue;
|
|
1578
2050
|
}
|
|
1579
2051
|
|
|
2052
|
+
const sourceContentPartOffset =
|
|
2053
|
+
summaryBoundary?.mode === 'positional' &&
|
|
2054
|
+
summaryBoundary.messageIndex === i
|
|
2055
|
+
? summaryBoundary.contentIndex + 1
|
|
2056
|
+
: 0;
|
|
2057
|
+
|
|
1580
2058
|
// Q: Store the current length of messages to track where this payload message starts in the result?
|
|
1581
2059
|
// const startIndex = messages.length;
|
|
1582
2060
|
if (typeof message.content === 'string') {
|
|
@@ -1599,7 +2077,26 @@ export const formatAgentMessages = (
|
|
|
1599
2077
|
| RoleBearingMessage<HumanMessage>
|
|
1600
2078
|
| RoleBearingMessage<AIMessage>
|
|
1601
2079
|
| RoleBearingMessage<SystemMessage>;
|
|
1602
|
-
|
|
2080
|
+
let attribution: ProviderMessageAttribution = 'synthetic';
|
|
2081
|
+
if (formattedMessage.role === 'user') {
|
|
2082
|
+
attribution = 'user';
|
|
2083
|
+
} else if (formattedMessage.role === 'assistant') {
|
|
2084
|
+
attribution = 'model';
|
|
2085
|
+
}
|
|
2086
|
+
const provenanceParts = createProviderContentProvenanceParts(
|
|
2087
|
+
message.content as MessageContentComplex[],
|
|
2088
|
+
sourceContentPartOffset,
|
|
2089
|
+
sourceMessageId,
|
|
2090
|
+
attribution
|
|
2091
|
+
);
|
|
2092
|
+
stampSourceMessageIdentity(
|
|
2093
|
+
formattedMessage,
|
|
2094
|
+
sourceMessageId,
|
|
2095
|
+
0,
|
|
2096
|
+
attribution,
|
|
2097
|
+
undefined,
|
|
2098
|
+
provenanceParts
|
|
2099
|
+
);
|
|
1603
2100
|
flushSteerAnchor(formattedMessage);
|
|
1604
2101
|
messages.push(formattedMessage);
|
|
1605
2102
|
|
|
@@ -1618,17 +2115,36 @@ export const formatAgentMessages = (
|
|
|
1618
2115
|
* - Dynamically expand the set when tool_search results are encountered
|
|
1619
2116
|
*/
|
|
1620
2117
|
let processedMessage = message;
|
|
2118
|
+
let processedSourceContentPartIndices:
|
|
2119
|
+
| SourceContentPartIndices[]
|
|
2120
|
+
| undefined;
|
|
2121
|
+
const processedToolSourceContentPartIndices =
|
|
2122
|
+
collectTrustedToolResultSourceContentPartIndices(
|
|
2123
|
+
getBoundedProviderPairingArrayProperty(message, 'content'),
|
|
2124
|
+
sourceContentPartOffset
|
|
2125
|
+
);
|
|
1621
2126
|
let pendingSkillNames: Set<string> | undefined;
|
|
1622
2127
|
if (discoveredTools) {
|
|
1623
2128
|
const content = message.content;
|
|
1624
2129
|
if (content != null && Array.isArray(content)) {
|
|
1625
2130
|
const filteredContent: typeof content = [];
|
|
2131
|
+
const filteredSourceContentPartIndices: SourceContentPartIndices[] = [];
|
|
1626
2132
|
const invalidToolCallIds = new Set<string>();
|
|
1627
2133
|
const invalidToolStrings: string[] = [];
|
|
1628
|
-
|
|
1629
|
-
|
|
2134
|
+
const invalidToolSourceContentPartIndices: number[] = [];
|
|
2135
|
+
|
|
2136
|
+
for (let partIndex = 0; partIndex < content.length; partIndex++) {
|
|
2137
|
+
const part = content[partIndex] as
|
|
2138
|
+
| MessageContentComplex
|
|
2139
|
+
| null
|
|
2140
|
+
| undefined;
|
|
2141
|
+
const partSourceContentIndices = sourceContentPartOffset + partIndex;
|
|
2142
|
+
if (part == null || typeof part !== 'object') {
|
|
2143
|
+
continue;
|
|
2144
|
+
}
|
|
1630
2145
|
if (part.type !== ContentTypes.TOOL_CALL) {
|
|
1631
2146
|
filteredContent.push(part);
|
|
2147
|
+
filteredSourceContentPartIndices.push(partSourceContentIndices);
|
|
1632
2148
|
continue;
|
|
1633
2149
|
}
|
|
1634
2150
|
|
|
@@ -1668,6 +2184,7 @@ export const formatAgentMessages = (
|
|
|
1668
2184
|
|
|
1669
2185
|
if (discoveredTools.has(toolName)) {
|
|
1670
2186
|
filteredContent.push(part);
|
|
2187
|
+
filteredSourceContentPartIndices.push(partSourceContentIndices);
|
|
1671
2188
|
if (
|
|
1672
2189
|
toolName === Constants.SKILL_TOOL &&
|
|
1673
2190
|
skills?.size != null &&
|
|
@@ -1688,6 +2205,10 @@ export const formatAgentMessages = (
|
|
|
1688
2205
|
}
|
|
1689
2206
|
const output = part.tool_call.output ?? '';
|
|
1690
2207
|
invalidToolStrings.push(`Tool: ${toolName}, ${output}`);
|
|
2208
|
+
appendSourceContentPartIndices(
|
|
2209
|
+
invalidToolSourceContentPartIndices,
|
|
2210
|
+
partSourceContentIndices
|
|
2211
|
+
);
|
|
1691
2212
|
}
|
|
1692
2213
|
}
|
|
1693
2214
|
|
|
@@ -1734,12 +2255,23 @@ export const formatAgentMessages = (
|
|
|
1734
2255
|
? `${existingText}\n${invalidToolText}`
|
|
1735
2256
|
: invalidToolText,
|
|
1736
2257
|
};
|
|
2258
|
+
const lastTextSourceContentPartIndices =
|
|
2259
|
+
filteredSourceContentPartIndices[lastTextPartIndex];
|
|
2260
|
+
filteredSourceContentPartIndices[lastTextPartIndex] = [
|
|
2261
|
+
...(typeof lastTextSourceContentPartIndices === 'number'
|
|
2262
|
+
? [lastTextSourceContentPartIndices]
|
|
2263
|
+
: lastTextSourceContentPartIndices),
|
|
2264
|
+
...invalidToolSourceContentPartIndices,
|
|
2265
|
+
];
|
|
1737
2266
|
} else {
|
|
1738
2267
|
/** No text part exists, create one */
|
|
1739
2268
|
filteredContent.push({
|
|
1740
2269
|
type: ContentTypes.TEXT,
|
|
1741
2270
|
[ContentTypes.TEXT]: invalidToolText,
|
|
1742
2271
|
});
|
|
2272
|
+
filteredSourceContentPartIndices.push(
|
|
2273
|
+
invalidToolSourceContentPartIndices
|
|
2274
|
+
);
|
|
1743
2275
|
}
|
|
1744
2276
|
}
|
|
1745
2277
|
|
|
@@ -1749,6 +2281,7 @@ export const formatAgentMessages = (
|
|
|
1749
2281
|
invalidToolStrings.length > 0
|
|
1750
2282
|
) {
|
|
1751
2283
|
processedMessage = { ...message, content: filteredContent };
|
|
2284
|
+
processedSourceContentPartIndices = filteredSourceContentPartIndices;
|
|
1752
2285
|
}
|
|
1753
2286
|
}
|
|
1754
2287
|
}
|
|
@@ -1757,8 +2290,12 @@ export const formatAgentMessages = (
|
|
|
1757
2290
|
if (!discoveredTools && skills?.size != null && skills.size > 0) {
|
|
1758
2291
|
const content = processedMessage.content;
|
|
1759
2292
|
if (Array.isArray(content)) {
|
|
1760
|
-
for (const part of content
|
|
2293
|
+
for (const part of content as Array<
|
|
2294
|
+
MessageContentComplex | null | undefined
|
|
2295
|
+
>) {
|
|
1761
2296
|
if (
|
|
2297
|
+
part == null ||
|
|
2298
|
+
typeof part !== 'object' ||
|
|
1762
2299
|
part.type !== ContentTypes.TOOL_CALL ||
|
|
1763
2300
|
part.tool_call?.name !== Constants.SKILL_TOOL
|
|
1764
2301
|
) {
|
|
@@ -1779,6 +2316,9 @@ export const formatAgentMessages = (
|
|
|
1779
2316
|
options?.provider === Providers.DEEPSEEK,
|
|
1780
2317
|
provider: options?.provider,
|
|
1781
2318
|
sourceMessageId,
|
|
2319
|
+
sourceContentPartOffset,
|
|
2320
|
+
sourceContentPartIndices: processedSourceContentPartIndices,
|
|
2321
|
+
toolSourceContentPartIndices: processedToolSourceContentPartIndices,
|
|
1782
2322
|
});
|
|
1783
2323
|
/**
|
|
1784
2324
|
* A steer that ends an assistant message leaves the replay on a
|
|
@@ -1818,7 +2358,9 @@ export const formatAgentMessages = (
|
|
|
1818
2358
|
if (formattedMessages.length > 0) {
|
|
1819
2359
|
flushSteerAnchor(formattedMessages[0]);
|
|
1820
2360
|
}
|
|
1821
|
-
|
|
2361
|
+
for (const formattedMessage of formattedMessages) {
|
|
2362
|
+
messages.push(formattedMessage);
|
|
2363
|
+
}
|
|
1822
2364
|
if (endsWithSteerMessage(formattedMessages)) {
|
|
1823
2365
|
pendingSteerAnchor = true;
|
|
1824
2366
|
}
|
|
@@ -1835,20 +2377,20 @@ export const formatAgentMessages = (
|
|
|
1835
2377
|
}
|
|
1836
2378
|
const body = skills?.get(skillName) ?? '';
|
|
1837
2379
|
if (body) {
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
'user'
|
|
1850
|
-
)
|
|
2380
|
+
const skillMessage = withMessageRole(
|
|
2381
|
+
new HumanMessage({
|
|
2382
|
+
content: body,
|
|
2383
|
+
additional_kwargs: {
|
|
2384
|
+
role: 'user',
|
|
2385
|
+
isMeta: true,
|
|
2386
|
+
source: 'skill',
|
|
2387
|
+
skillName,
|
|
2388
|
+
},
|
|
2389
|
+
}),
|
|
2390
|
+
'user'
|
|
1851
2391
|
);
|
|
2392
|
+
stampSourceMessageIdentity(skillMessage, undefined, 0, 'synthetic');
|
|
2393
|
+
messages.push(skillMessage);
|
|
1852
2394
|
}
|
|
1853
2395
|
}
|
|
1854
2396
|
}
|
|
@@ -2188,14 +2730,160 @@ function serializeFoldedValue(value: unknown): string {
|
|
|
2188
2730
|
.content;
|
|
2189
2731
|
}
|
|
2190
2732
|
|
|
2191
|
-
|
|
2733
|
+
interface FoldedSourceMessage {
|
|
2734
|
+
readonly message: BaseMessage;
|
|
2735
|
+
/** Provider-content positions retained from an array message. Omitted when
|
|
2736
|
+
* string content or tool-call metadata contributed as a whole. */
|
|
2737
|
+
readonly retainedContentPartIndices?: ReadonlySet<number>;
|
|
2738
|
+
readonly mappingAmbiguous?: boolean;
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
function getFoldedSourceAttribution(
|
|
2742
|
+
message: BaseMessage
|
|
2743
|
+
): ProviderMessageAttribution {
|
|
2744
|
+
const messageType = message.getType();
|
|
2745
|
+
if (messageType === 'ai') {
|
|
2746
|
+
return 'model';
|
|
2747
|
+
}
|
|
2748
|
+
if (messageType === 'tool') {
|
|
2749
|
+
return 'tool';
|
|
2750
|
+
}
|
|
2751
|
+
if (messageType === 'system') {
|
|
2752
|
+
return 'synthetic';
|
|
2753
|
+
}
|
|
2754
|
+
return 'user';
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
function getSyntheticProviderContextProvenanceParts(
|
|
2758
|
+
sourceMessages: readonly FoldedSourceMessage[]
|
|
2759
|
+
): ProviderMessageProvenancePart[] | null {
|
|
2760
|
+
/** Fold labels are generated context, while retained source bytes keep their
|
|
2761
|
+
* original attribution so downstream policy can still route them exactly. */
|
|
2762
|
+
const parts: ProviderMessageProvenancePart[] = [
|
|
2763
|
+
{ attribution: 'synthetic' },
|
|
2764
|
+
];
|
|
2765
|
+
for (const source of sourceMessages) {
|
|
2766
|
+
const {
|
|
2767
|
+
message: sourceMessage,
|
|
2768
|
+
retainedContentPartIndices,
|
|
2769
|
+
mappingAmbiguous,
|
|
2770
|
+
} = source;
|
|
2771
|
+
const provenanceState = inspectProviderMessageProvenance(sourceMessage);
|
|
2772
|
+
const sourceMessageIdsState =
|
|
2773
|
+
inspectProviderSourceMessageIds(sourceMessage);
|
|
2774
|
+
if (
|
|
2775
|
+
provenanceState.status === 'invalid' ||
|
|
2776
|
+
sourceMessageIdsState.status === 'invalid'
|
|
2777
|
+
) {
|
|
2778
|
+
return null;
|
|
2779
|
+
}
|
|
2780
|
+
const explicit =
|
|
2781
|
+
provenanceState.status === 'valid'
|
|
2782
|
+
? provenanceState.provenance
|
|
2783
|
+
: undefined;
|
|
2784
|
+
const sourceMessageIds =
|
|
2785
|
+
sourceMessageIdsState.status === 'valid'
|
|
2786
|
+
? sourceMessageIdsState.sourceMessageIds
|
|
2787
|
+
: [];
|
|
2788
|
+
const fallbackAttribution = getFoldedSourceAttribution(sourceMessage);
|
|
2789
|
+
const sourcePartStart = parts.length;
|
|
2790
|
+
const retainedSourceIds = new Set<string>();
|
|
2791
|
+
const contentLength = Array.isArray(sourceMessage.content)
|
|
2792
|
+
? sourceMessage.content.length
|
|
2793
|
+
: undefined;
|
|
2794
|
+
const mapsOneToOne =
|
|
2795
|
+
mappingAmbiguous !== true &&
|
|
2796
|
+
retainedContentPartIndices != null &&
|
|
2797
|
+
contentLength != null &&
|
|
2798
|
+
explicit != null &&
|
|
2799
|
+
hasBijectiveProviderContentPartMapping(explicit.parts, contentLength);
|
|
2800
|
+
const retainedAllContentParts =
|
|
2801
|
+
mappingAmbiguous !== true &&
|
|
2802
|
+
retainedContentPartIndices != null &&
|
|
2803
|
+
contentLength != null &&
|
|
2804
|
+
retainedContentPartIndices.size === contentLength;
|
|
2805
|
+
const retainUnindexedSourceIds =
|
|
2806
|
+
(mappingAmbiguous !== true && retainedContentPartIndices == null) ||
|
|
2807
|
+
retainedAllContentParts ||
|
|
2808
|
+
sourceMessageIds.length <= 1;
|
|
2809
|
+
for (const part of explicit?.parts ?? []) {
|
|
2810
|
+
let sourceContentPartIndices = part.sourceContentPartIndices;
|
|
2811
|
+
if (mappingAmbiguous === true && sourceContentPartIndices != null) {
|
|
2812
|
+
sourceContentPartIndices = undefined;
|
|
2813
|
+
}
|
|
2814
|
+
if (
|
|
2815
|
+
retainedContentPartIndices != null &&
|
|
2816
|
+
sourceContentPartIndices != null &&
|
|
2817
|
+
!retainedAllContentParts
|
|
2818
|
+
) {
|
|
2819
|
+
if (!mapsOneToOne) {
|
|
2820
|
+
sourceContentPartIndices = undefined;
|
|
2821
|
+
} else {
|
|
2822
|
+
const retainedSourceContentPartIndices: number[] = [];
|
|
2823
|
+
for (const sourceContentPartIndex of sourceContentPartIndices) {
|
|
2824
|
+
if (retainedContentPartIndices.has(sourceContentPartIndex)) {
|
|
2825
|
+
retainedSourceContentPartIndices.push(sourceContentPartIndex);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
if (retainedSourceContentPartIndices.length === 0) {
|
|
2829
|
+
continue;
|
|
2830
|
+
}
|
|
2831
|
+
sourceContentPartIndices = retainedSourceContentPartIndices;
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
const sourceMessageId =
|
|
2835
|
+
sourceContentPartIndices != null || retainUnindexedSourceIds
|
|
2836
|
+
? part.sourceMessageId
|
|
2837
|
+
: undefined;
|
|
2838
|
+
parts.push({
|
|
2839
|
+
attribution: part.attribution,
|
|
2840
|
+
...(sourceMessageId != null && {
|
|
2841
|
+
sourceMessageId,
|
|
2842
|
+
}),
|
|
2843
|
+
...(sourceContentPartIndices != null && {
|
|
2844
|
+
sourceContentPartIndices,
|
|
2845
|
+
}),
|
|
2846
|
+
});
|
|
2847
|
+
if (sourceMessageId != null) {
|
|
2848
|
+
retainedSourceIds.add(sourceMessageId);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
for (const sourceMessageId of sourceMessageIds) {
|
|
2852
|
+
if (!retainUnindexedSourceIds) {
|
|
2853
|
+
break;
|
|
2854
|
+
}
|
|
2855
|
+
if (!retainedSourceIds.has(sourceMessageId)) {
|
|
2856
|
+
parts.push({ attribution: fallbackAttribution, sourceMessageId });
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
if (parts.length === sourcePartStart) {
|
|
2860
|
+
parts.push({ attribution: fallbackAttribution });
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
return mergeAdjacentProviderProvenanceParts(parts);
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
function markSyntheticProviderContext<T extends BaseMessage>(
|
|
2867
|
+
message: T,
|
|
2868
|
+
sourceMessages: readonly FoldedSourceMessage[] = []
|
|
2869
|
+
): T {
|
|
2192
2870
|
syntheticProviderContextMessages.add(message);
|
|
2871
|
+
const parts = getSyntheticProviderContextProvenanceParts(sourceMessages);
|
|
2872
|
+
if (parts == null) {
|
|
2873
|
+
setInvalidProviderMessageProvenance(message);
|
|
2874
|
+
return message;
|
|
2875
|
+
}
|
|
2876
|
+
setProviderMessageProvenance(
|
|
2877
|
+
message,
|
|
2878
|
+
parts.length > 0 ? parts : [{ attribution: 'synthetic' }]
|
|
2879
|
+
);
|
|
2193
2880
|
return message;
|
|
2194
2881
|
}
|
|
2195
2882
|
|
|
2196
2883
|
function appendSyntheticProviderContextMessage(
|
|
2197
2884
|
result: BaseMessage[],
|
|
2198
|
-
parts: MessageContentComplex[]
|
|
2885
|
+
parts: MessageContentComplex[],
|
|
2886
|
+
sourceMessages: readonly FoldedSourceMessage[] = []
|
|
2199
2887
|
): boolean {
|
|
2200
2888
|
if (parts.length === 0) {
|
|
2201
2889
|
return false;
|
|
@@ -2205,7 +2893,8 @@ function appendSyntheticProviderContextMessage(
|
|
|
2205
2893
|
withMessageRole(
|
|
2206
2894
|
new HumanMessage({ content: toLangChainContent(parts) }),
|
|
2207
2895
|
'user'
|
|
2208
|
-
)
|
|
2896
|
+
),
|
|
2897
|
+
sourceMessages
|
|
2209
2898
|
)
|
|
2210
2899
|
);
|
|
2211
2900
|
return true;
|
|
@@ -2222,6 +2911,34 @@ export function isSyntheticProviderContextMessage(
|
|
|
2222
2911
|
return syntheticProviderContextMessages.has(message);
|
|
2223
2912
|
}
|
|
2224
2913
|
|
|
2914
|
+
/** Compacts a folded provider-context message without retaining source claims
|
|
2915
|
+
* for bytes whose mapping cannot survive the lossy compaction. The unsourced
|
|
2916
|
+
* user/tool parts intentionally make security consumers inspect the exact
|
|
2917
|
+
* compacted wire under both external trust domains. */
|
|
2918
|
+
export function compactSyntheticProviderContextMessage(
|
|
2919
|
+
message: HumanMessage,
|
|
2920
|
+
maxChars: number
|
|
2921
|
+
): HumanMessage {
|
|
2922
|
+
const compactedContent = compactToolContent(message.content, maxChars);
|
|
2923
|
+
if (!compactedContent.changed) {
|
|
2924
|
+
return message;
|
|
2925
|
+
}
|
|
2926
|
+
const compacted = new HumanMessage({
|
|
2927
|
+
content: compactedContent.content,
|
|
2928
|
+
id: message.id,
|
|
2929
|
+
name: message.name,
|
|
2930
|
+
additional_kwargs: { ...message.additional_kwargs },
|
|
2931
|
+
response_metadata: message.response_metadata,
|
|
2932
|
+
});
|
|
2933
|
+
syntheticProviderContextMessages.add(compacted);
|
|
2934
|
+
setProviderMessageProvenance(compacted, [
|
|
2935
|
+
{ attribution: 'synthetic' },
|
|
2936
|
+
{ attribution: 'user' },
|
|
2937
|
+
{ attribution: 'tool' },
|
|
2938
|
+
]);
|
|
2939
|
+
return compacted;
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2225
2942
|
/** Flushes accumulated text chunks into `parts` as a single text block. */
|
|
2226
2943
|
function flushTextChunks(
|
|
2227
2944
|
textChunks: string[],
|
|
@@ -2254,29 +2971,53 @@ function appendMessageContent(
|
|
|
2254
2971
|
textChunks: string[],
|
|
2255
2972
|
parts: MessageContentComplex[],
|
|
2256
2973
|
budget: FoldContextBudget
|
|
2257
|
-
):
|
|
2974
|
+
): FoldedSourceMessage | undefined {
|
|
2258
2975
|
const { content } = msg;
|
|
2259
2976
|
|
|
2260
2977
|
if (typeof content === 'string') {
|
|
2261
|
-
|
|
2262
|
-
|
|
2978
|
+
const remainingCharsBefore = budget.remainingChars;
|
|
2979
|
+
let contentComplete = true;
|
|
2980
|
+
if (content) {
|
|
2981
|
+
contentComplete =
|
|
2982
|
+
consumeFoldedWork(textChunks, budget) &&
|
|
2983
|
+
appendFoldedLine(textChunks, budget, [`${role}: `, content]);
|
|
2263
2984
|
}
|
|
2264
|
-
appendToolCalls(msg, role, textChunks, budget);
|
|
2265
|
-
return
|
|
2985
|
+
const toolCalls = appendToolCalls(msg, role, textChunks, budget);
|
|
2986
|
+
return budget.remainingChars < remainingCharsBefore || toolCalls.contributed
|
|
2987
|
+
? {
|
|
2988
|
+
message: msg,
|
|
2989
|
+
...((!contentComplete || !toolCalls.complete) && {
|
|
2990
|
+
mappingAmbiguous: true,
|
|
2991
|
+
}),
|
|
2992
|
+
}
|
|
2993
|
+
: undefined;
|
|
2266
2994
|
}
|
|
2267
2995
|
|
|
2268
2996
|
if (!Array.isArray(content)) {
|
|
2269
|
-
appendToolCalls(msg, role, textChunks, budget);
|
|
2270
|
-
return
|
|
2997
|
+
const toolCalls = appendToolCalls(msg, role, textChunks, budget);
|
|
2998
|
+
return toolCalls.contributed
|
|
2999
|
+
? {
|
|
3000
|
+
message: msg,
|
|
3001
|
+
...(!toolCalls.complete && { mappingAmbiguous: true }),
|
|
3002
|
+
}
|
|
3003
|
+
: undefined;
|
|
2271
3004
|
}
|
|
2272
3005
|
|
|
2273
3006
|
let hasToolUseBlock = false;
|
|
3007
|
+
const retainedContentPartIndices = new Set<number>();
|
|
2274
3008
|
|
|
2275
|
-
for (
|
|
3009
|
+
for (let blockIndex = 0; blockIndex < content.length; blockIndex++) {
|
|
3010
|
+
const block = content[blockIndex] as ExtendedMessageContent;
|
|
2276
3011
|
if (!consumeFoldedWork(textChunks, budget)) {
|
|
2277
3012
|
hasToolUseBlock = true;
|
|
2278
3013
|
break;
|
|
2279
3014
|
}
|
|
3015
|
+
const remainingCharsBefore = budget.remainingChars;
|
|
3016
|
+
const markBlockRetained = (): void => {
|
|
3017
|
+
if (budget.remainingChars < remainingCharsBefore) {
|
|
3018
|
+
retainedContentPartIndices.add(blockIndex);
|
|
3019
|
+
}
|
|
3020
|
+
};
|
|
2280
3021
|
const blockTypeValue = readFoldedDataProperty(block, 'type');
|
|
2281
3022
|
const blockType =
|
|
2282
3023
|
typeof blockTypeValue === 'string' ? blockTypeValue : undefined;
|
|
@@ -2293,6 +3034,7 @@ function appendMessageContent(
|
|
|
2293
3034
|
appendFoldedLine(textChunks, budget, [
|
|
2294
3035
|
`${role}: [${blockType ?? 'media'} omitted: folded context limit]`,
|
|
2295
3036
|
]);
|
|
3037
|
+
markBlockRetained();
|
|
2296
3038
|
continue;
|
|
2297
3039
|
}
|
|
2298
3040
|
flushTextChunks(textChunks, parts);
|
|
@@ -2304,6 +3046,7 @@ function appendMessageContent(
|
|
|
2304
3046
|
serializeFoldedValue(block),
|
|
2305
3047
|
]);
|
|
2306
3048
|
}
|
|
3049
|
+
markBlockRetained();
|
|
2307
3050
|
continue;
|
|
2308
3051
|
}
|
|
2309
3052
|
|
|
@@ -2315,6 +3058,7 @@ function appendMessageContent(
|
|
|
2315
3058
|
`${role}: [tool_use] ${typeof name === 'string' ? name : ''} `,
|
|
2316
3059
|
serializeFoldedValue(input ?? {}),
|
|
2317
3060
|
]);
|
|
3061
|
+
markBlockRetained();
|
|
2318
3062
|
continue;
|
|
2319
3063
|
}
|
|
2320
3064
|
|
|
@@ -2350,6 +3094,7 @@ function appendMessageContent(
|
|
|
2350
3094
|
typeof output === 'string' ? output : serializeFoldedValue(output),
|
|
2351
3095
|
]);
|
|
2352
3096
|
}
|
|
3097
|
+
markBlockRetained();
|
|
2353
3098
|
continue;
|
|
2354
3099
|
}
|
|
2355
3100
|
|
|
@@ -2419,6 +3164,7 @@ function appendMessageContent(
|
|
|
2419
3164
|
serializeFoldedValue(inner),
|
|
2420
3165
|
]);
|
|
2421
3166
|
}
|
|
3167
|
+
markBlockRetained();
|
|
2422
3168
|
continue;
|
|
2423
3169
|
}
|
|
2424
3170
|
|
|
@@ -2427,6 +3173,7 @@ function appendMessageContent(
|
|
|
2427
3173
|
readFoldedDataProperty(block, 'input');
|
|
2428
3174
|
if (typeof text === 'string' && text) {
|
|
2429
3175
|
appendFoldedLine(textChunks, budget, [`${role}: `, text]);
|
|
3176
|
+
markBlockRetained();
|
|
2430
3177
|
continue;
|
|
2431
3178
|
}
|
|
2432
3179
|
|
|
@@ -2437,13 +3184,23 @@ function appendMessageContent(
|
|
|
2437
3184
|
serializeFoldedValue(block),
|
|
2438
3185
|
]);
|
|
2439
3186
|
}
|
|
3187
|
+
markBlockRetained();
|
|
2440
3188
|
}
|
|
2441
3189
|
|
|
2442
3190
|
// If content array had no tool_use blocks, fall back to tool_calls metadata
|
|
2443
3191
|
// (handles edge case: empty content array with tool_calls populated)
|
|
2444
|
-
|
|
2445
|
-
appendToolCalls(msg, role, textChunks, budget)
|
|
3192
|
+
const toolCalls = !hasToolUseBlock
|
|
3193
|
+
? appendToolCalls(msg, role, textChunks, budget)
|
|
3194
|
+
: { contributed: false, complete: true };
|
|
3195
|
+
if (toolCalls.contributed) {
|
|
3196
|
+
return {
|
|
3197
|
+
message: msg,
|
|
3198
|
+
...(!toolCalls.complete && { mappingAmbiguous: true }),
|
|
3199
|
+
};
|
|
2446
3200
|
}
|
|
3201
|
+
return retainedContentPartIndices.size > 0
|
|
3202
|
+
? { message: msg, retainedContentPartIndices }
|
|
3203
|
+
: undefined;
|
|
2447
3204
|
}
|
|
2448
3205
|
|
|
2449
3206
|
function appendToolCalls(
|
|
@@ -2451,14 +3208,37 @@ function appendToolCalls(
|
|
|
2451
3208
|
role: string,
|
|
2452
3209
|
textChunks: string[],
|
|
2453
3210
|
budget: FoldContextBudget
|
|
2454
|
-
):
|
|
3211
|
+
): { contributed: boolean; complete: boolean } {
|
|
2455
3212
|
if (role !== 'AI') {
|
|
2456
|
-
return;
|
|
3213
|
+
return { contributed: false, complete: true };
|
|
2457
3214
|
}
|
|
3215
|
+
const remainingCharsBefore = budget.remainingChars;
|
|
3216
|
+
let complete = true;
|
|
2458
3217
|
const aiMsg = msg as AIMessage;
|
|
2459
3218
|
if (aiMsg.tool_calls && aiMsg.tool_calls.length > 0) {
|
|
3219
|
+
const rawToolCalls = aiMsg.additional_kwargs.tool_calls;
|
|
3220
|
+
if (Array.isArray(rawToolCalls)) {
|
|
3221
|
+
if (rawToolCalls.length !== aiMsg.tool_calls.length) {
|
|
3222
|
+
complete = false;
|
|
3223
|
+
} else {
|
|
3224
|
+
for (let index = 0; index < rawToolCalls.length; index++) {
|
|
3225
|
+
const rawToolCall = rawToolCalls[index];
|
|
3226
|
+
const parsedToolCall = aiMsg.tool_calls[index];
|
|
3227
|
+
const fn = readFoldedDataProperty(rawToolCall, 'function');
|
|
3228
|
+
const rawId = readFoldedDataProperty(rawToolCall, 'id');
|
|
3229
|
+
const rawName = readFoldedDataProperty(fn, 'name');
|
|
3230
|
+
const parsedId = readFoldedDataProperty(parsedToolCall, 'id');
|
|
3231
|
+
const parsedName = readFoldedDataProperty(parsedToolCall, 'name');
|
|
3232
|
+
if (fn == null || rawId !== parsedId || rawName !== parsedName) {
|
|
3233
|
+
complete = false;
|
|
3234
|
+
break;
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
2460
3239
|
for (const tc of aiMsg.tool_calls) {
|
|
2461
3240
|
if (!consumeFoldedWork(textChunks, budget)) {
|
|
3241
|
+
complete = false;
|
|
2462
3242
|
break;
|
|
2463
3243
|
}
|
|
2464
3244
|
const name = readFoldedDataProperty(tc, 'name');
|
|
@@ -2469,19 +3249,24 @@ function appendToolCalls(
|
|
|
2469
3249
|
')',
|
|
2470
3250
|
]);
|
|
2471
3251
|
}
|
|
2472
|
-
return
|
|
3252
|
+
return {
|
|
3253
|
+
contributed: budget.remainingChars < remainingCharsBefore,
|
|
3254
|
+
complete,
|
|
3255
|
+
};
|
|
2473
3256
|
}
|
|
2474
3257
|
// Fall back to raw provider tool calls kept only in additional_kwargs.
|
|
2475
3258
|
const rawToolCalls = aiMsg.additional_kwargs.tool_calls;
|
|
2476
3259
|
if (!Array.isArray(rawToolCalls)) {
|
|
2477
|
-
return;
|
|
3260
|
+
return { contributed: false, complete: true };
|
|
2478
3261
|
}
|
|
2479
3262
|
for (const tc of rawToolCalls) {
|
|
2480
3263
|
if (!consumeFoldedWork(textChunks, budget)) {
|
|
3264
|
+
complete = false;
|
|
2481
3265
|
break;
|
|
2482
3266
|
}
|
|
2483
3267
|
const fn = readFoldedDataProperty(tc, 'function');
|
|
2484
3268
|
if (fn == null) {
|
|
3269
|
+
complete = false;
|
|
2485
3270
|
continue;
|
|
2486
3271
|
}
|
|
2487
3272
|
const name = readFoldedDataProperty(fn, 'name');
|
|
@@ -2492,6 +3277,10 @@ function appendToolCalls(
|
|
|
2492
3277
|
')',
|
|
2493
3278
|
]);
|
|
2494
3279
|
}
|
|
3280
|
+
return {
|
|
3281
|
+
contributed: budget.remainingChars < remainingCharsBefore,
|
|
3282
|
+
complete,
|
|
3283
|
+
};
|
|
2495
3284
|
}
|
|
2496
3285
|
|
|
2497
3286
|
/**
|
|
@@ -2644,24 +3433,43 @@ export function ensureThinkingBlockInMessages(
|
|
|
2644
3433
|
// binary data as text (which caused 174× token amplification).
|
|
2645
3434
|
const parts: MessageContentComplex[] = [];
|
|
2646
3435
|
const textChunks: string[] = [];
|
|
3436
|
+
const foldedSourceMessages: FoldedSourceMessage[] = [];
|
|
2647
3437
|
appendFoldedLine(textChunks, foldBudget, ['[Previous agent context]']);
|
|
2648
3438
|
|
|
2649
|
-
|
|
3439
|
+
const aiSource = appendMessageContent(
|
|
3440
|
+
msg,
|
|
3441
|
+
'AI',
|
|
3442
|
+
textChunks,
|
|
3443
|
+
parts,
|
|
3444
|
+
foldBudget
|
|
3445
|
+
);
|
|
3446
|
+
if (aiSource != null) {
|
|
3447
|
+
foldedSourceMessages.push(aiSource);
|
|
3448
|
+
}
|
|
2650
3449
|
|
|
2651
3450
|
let j = i + 1;
|
|
2652
3451
|
while (j < messages.length && isToolMessage(messages[j])) {
|
|
2653
|
-
appendMessageContent(
|
|
3452
|
+
const toolSource = appendMessageContent(
|
|
2654
3453
|
messages[j],
|
|
2655
3454
|
'Tool',
|
|
2656
3455
|
textChunks,
|
|
2657
3456
|
parts,
|
|
2658
3457
|
foldBudget
|
|
2659
3458
|
);
|
|
3459
|
+
if (toolSource != null) {
|
|
3460
|
+
foldedSourceMessages.push(toolSource);
|
|
3461
|
+
}
|
|
2660
3462
|
j++;
|
|
2661
3463
|
}
|
|
2662
3464
|
|
|
2663
3465
|
flushTextChunks(textChunks, parts);
|
|
2664
|
-
if (
|
|
3466
|
+
if (
|
|
3467
|
+
appendSyntheticProviderContextMessage(
|
|
3468
|
+
result,
|
|
3469
|
+
parts,
|
|
3470
|
+
foldedSourceMessages
|
|
3471
|
+
)
|
|
3472
|
+
) {
|
|
2665
3473
|
emitAgentLog(
|
|
2666
3474
|
config,
|
|
2667
3475
|
'warn',
|
|
@@ -2779,25 +3587,38 @@ export function foldToolBlocksForToollessAgent(
|
|
|
2779
3587
|
|
|
2780
3588
|
const parts: MessageContentComplex[] = [];
|
|
2781
3589
|
const textChunks: string[] = [];
|
|
3590
|
+
const foldedSourceMessages: FoldedSourceMessage[] = [];
|
|
2782
3591
|
appendFoldedLine(textChunks, foldBudget, ['[Previous tool interaction]']);
|
|
2783
|
-
appendMessageContent(
|
|
3592
|
+
const initialSource = appendMessageContent(
|
|
2784
3593
|
msg,
|
|
2785
3594
|
isToolResultMessage(msg) ? 'Tool' : 'AI',
|
|
2786
3595
|
textChunks,
|
|
2787
3596
|
parts,
|
|
2788
3597
|
foldBudget
|
|
2789
3598
|
);
|
|
3599
|
+
if (initialSource != null) {
|
|
3600
|
+
foldedSourceMessages.push(initialSource);
|
|
3601
|
+
}
|
|
2790
3602
|
foldedCount++;
|
|
2791
3603
|
|
|
2792
3604
|
let j = i + 1;
|
|
2793
3605
|
while (j < messages.length && isToolResultMessage(messages[j])) {
|
|
2794
|
-
|
|
3606
|
+
const toolSource = appendMessageContent(
|
|
3607
|
+
messages[j],
|
|
3608
|
+
'Tool',
|
|
3609
|
+
textChunks,
|
|
3610
|
+
parts,
|
|
3611
|
+
foldBudget
|
|
3612
|
+
);
|
|
3613
|
+
if (toolSource != null) {
|
|
3614
|
+
foldedSourceMessages.push(toolSource);
|
|
3615
|
+
}
|
|
2795
3616
|
foldedCount++;
|
|
2796
3617
|
j++;
|
|
2797
3618
|
}
|
|
2798
3619
|
|
|
2799
3620
|
flushTextChunks(textChunks, parts);
|
|
2800
|
-
appendSyntheticProviderContextMessage(result, parts);
|
|
3621
|
+
appendSyntheticProviderContextMessage(result, parts, foldedSourceMessages);
|
|
2801
3622
|
i = j;
|
|
2802
3623
|
}
|
|
2803
3624
|
|