@librechat/agents 3.3.9 → 3.3.11
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 +4 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +21 -2
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +228 -16
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +14 -7
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +188 -11
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +4 -3
- package/dist/cjs/messages/core.cjs +592 -27
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/run.cjs +11 -1
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +2 -2
- package/dist/cjs/tools/ToolNode.cjs +1 -1
- package/dist/cjs/tools/search/tool.cjs +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/esm/agents/AgentContext.mjs +4 -0
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +21 -2
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +228 -16
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +14 -7
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +190 -13
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +5 -5
- package/dist/esm/messages/core.mjs +592 -28
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/run.mjs +11 -1
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +2 -2
- package/dist/esm/tools/ToolNode.mjs +1 -1
- package/dist/esm/tools/search/tool.mjs +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/types/agents/AgentContext.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +5 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +1 -0
- package/dist/types/llm/invoke.d.ts +1 -1
- package/dist/types/messages/core.d.ts +11 -6
- package/dist/types/run.d.ts +7 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +5 -0
- package/src/graphs/Graph.ts +39 -0
- package/src/langfuseToolOutputTracing.ts +410 -14
- package/src/llm/custom-chat-models.smoke.test.ts +747 -0
- package/src/llm/invoke.test.ts +98 -0
- package/src/llm/invoke.ts +34 -23
- package/src/llm/openai/index.ts +334 -25
- package/src/llm/openai/llm.spec.ts +107 -6
- package/src/messages/core.ts +1290 -42
- package/src/messages/formatAgentMessages.test.ts +2623 -0
- package/src/run.ts +15 -0
- package/src/specs/discovered-tools.test.ts +217 -0
- package/src/specs/langfuse-tool-output-tracing.test.ts +887 -0
- package/src/specs/preemptSeal.test.ts +374 -5
package/src/messages/core.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
HumanMessage,
|
|
8
8
|
AIMessageChunk,
|
|
9
9
|
} from '@langchain/core/messages';
|
|
10
|
+
import type { ContentBlock as LangChainContentBlock } from '@langchain/core/messages';
|
|
10
11
|
import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
|
|
11
12
|
import type * as t from '@/types';
|
|
12
13
|
import {
|
|
@@ -579,7 +580,9 @@ function cloneAIMessageWithContent(
|
|
|
579
580
|
...lcKwargs,
|
|
580
581
|
value: {
|
|
581
582
|
...(lcKwargs.value as Record<string, unknown>),
|
|
582
|
-
|
|
583
|
+
...(message.response_metadata.output_version === 'v1'
|
|
584
|
+
? { content: undefined, contentBlocks: content }
|
|
585
|
+
: { content }),
|
|
583
586
|
},
|
|
584
587
|
};
|
|
585
588
|
}
|
|
@@ -589,55 +592,1287 @@ function cloneAIMessageWithContent(
|
|
|
589
592
|
) as AIMessage;
|
|
590
593
|
}
|
|
591
594
|
|
|
595
|
+
function cloneAIMessageWithResponsesReplayState(
|
|
596
|
+
message: AIMessage,
|
|
597
|
+
content: AIMessage['content'],
|
|
598
|
+
id: string | undefined,
|
|
599
|
+
additionalKwargs: AIMessage['additional_kwargs'],
|
|
600
|
+
responseMetadata: AIMessage['response_metadata']
|
|
601
|
+
): AIMessage {
|
|
602
|
+
const descriptors = Object.getOwnPropertyDescriptors(message) as Record<
|
|
603
|
+
string,
|
|
604
|
+
PropertyDescriptor | undefined
|
|
605
|
+
>;
|
|
606
|
+
const replacements = {
|
|
607
|
+
content,
|
|
608
|
+
id,
|
|
609
|
+
additional_kwargs: additionalKwargs,
|
|
610
|
+
response_metadata: responseMetadata,
|
|
611
|
+
};
|
|
612
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
613
|
+
const descriptor = descriptors[key];
|
|
614
|
+
descriptors[key] = {
|
|
615
|
+
configurable: descriptor?.configurable ?? true,
|
|
616
|
+
enumerable: descriptor?.enumerable ?? true,
|
|
617
|
+
value,
|
|
618
|
+
writable: descriptor?.writable ?? true,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
const lcKwargs = descriptors.lc_kwargs;
|
|
622
|
+
if (
|
|
623
|
+
lcKwargs != null &&
|
|
624
|
+
'value' in lcKwargs &&
|
|
625
|
+
typeof lcKwargs.value === 'object' &&
|
|
626
|
+
lcKwargs.value != null
|
|
627
|
+
) {
|
|
628
|
+
descriptors.lc_kwargs = {
|
|
629
|
+
...lcKwargs,
|
|
630
|
+
value: {
|
|
631
|
+
...(lcKwargs.value as Record<string, unknown>),
|
|
632
|
+
...replacements,
|
|
633
|
+
...(responseMetadata.output_version === 'v1'
|
|
634
|
+
? { content: undefined, contentBlocks: content }
|
|
635
|
+
: {}),
|
|
636
|
+
},
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
return Object.create(
|
|
640
|
+
Object.getPrototypeOf(message),
|
|
641
|
+
descriptors as PropertyDescriptorMap
|
|
642
|
+
) as AIMessage;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function hasReplayableEncryptedReasoning(reasoning: unknown): boolean {
|
|
646
|
+
if (reasoning == null || typeof reasoning !== 'object') {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
const item = reasoning as {
|
|
650
|
+
encrypted_content?: unknown;
|
|
651
|
+
id?: unknown;
|
|
652
|
+
status?: unknown;
|
|
653
|
+
summary?: unknown;
|
|
654
|
+
type?: unknown;
|
|
655
|
+
};
|
|
656
|
+
return (
|
|
657
|
+
item.type === 'reasoning' &&
|
|
658
|
+
typeof item.id === 'string' &&
|
|
659
|
+
item.id.length > 0 &&
|
|
660
|
+
Array.isArray(item.summary) &&
|
|
661
|
+
typeof item.encrypted_content === 'string' &&
|
|
662
|
+
item.encrypted_content.length > 0 &&
|
|
663
|
+
(item.status === undefined ||
|
|
664
|
+
item.status === 'completed' ||
|
|
665
|
+
item.status === 'incomplete')
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
type ResponsesReplayProjection = 'fallback' | 'native';
|
|
670
|
+
|
|
671
|
+
export const OPENAI_RESPONSES_REPLAY_POSITIONS_KEY =
|
|
672
|
+
'__openai_responses_replay_positions__';
|
|
673
|
+
|
|
674
|
+
export type ResponsesReplayPosition = {
|
|
675
|
+
contentIndex?: number;
|
|
676
|
+
itemId: string;
|
|
677
|
+
kind: 'message' | 'output' | 'reasoning' | 'text';
|
|
678
|
+
outputIndex: number;
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
type CompletedGeneratedImages = {
|
|
682
|
+
blocks: PositionedResponsesReplayBlock[];
|
|
683
|
+
data: Set<string>;
|
|
684
|
+
ids: Set<string>;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
type ResponsesReplayArtifacts = {
|
|
688
|
+
generatedImages: CompletedGeneratedImages;
|
|
689
|
+
messagePositions: ResponsesReplayPosition[];
|
|
690
|
+
positionsByItemId: Map<string, ResponsesReplayItemPosition>;
|
|
691
|
+
positionedServerToolResultIds: Set<string>;
|
|
692
|
+
serverToolResults: PositionedResponsesReplayBlock[];
|
|
693
|
+
textPositions: ResponsesReplayPosition[];
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
type ResponsesReplayItemPosition = Pick<
|
|
697
|
+
PositionedResponsesReplayBlock,
|
|
698
|
+
'outputIndex' | 'textIndex'
|
|
699
|
+
>;
|
|
700
|
+
|
|
701
|
+
type PositionedResponsesReplayBlock = {
|
|
702
|
+
block: LangChainContentBlock.Standard;
|
|
703
|
+
outputIndex: number;
|
|
704
|
+
subIndex: number;
|
|
705
|
+
textIndex?: number;
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
type PositionedResponsesImage = {
|
|
709
|
+
block: LangChainContentBlock.Multimodal.Image;
|
|
710
|
+
textIndex: number;
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
type PositionedResponsesImages = {
|
|
714
|
+
blocks: PositionedResponsesImage[];
|
|
715
|
+
textCount: number;
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
function isProviderGeneratedImageBlock(
|
|
719
|
+
block: LangChainContentBlock.Multimodal.Image,
|
|
720
|
+
generatedImages: CompletedGeneratedImages,
|
|
721
|
+
allowDataFallback = true
|
|
722
|
+
): boolean {
|
|
723
|
+
if (typeof block.id === 'string' && block.id.length > 0) {
|
|
724
|
+
return generatedImages.ids.has(block.id);
|
|
725
|
+
}
|
|
726
|
+
return (
|
|
727
|
+
allowDataFallback &&
|
|
728
|
+
typeof block.data === 'string' &&
|
|
729
|
+
generatedImages.data.has(block.data) &&
|
|
730
|
+
block.metadata != null &&
|
|
731
|
+
typeof block.metadata === 'object' &&
|
|
732
|
+
block.metadata.status === 'completed'
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function hasMeaningfulServerToolOutput(output: unknown): boolean {
|
|
737
|
+
if (output == null || output === '') {
|
|
738
|
+
return false;
|
|
739
|
+
}
|
|
740
|
+
if (Array.isArray(output)) {
|
|
741
|
+
return output.length > 0;
|
|
742
|
+
}
|
|
743
|
+
if (typeof output !== 'object') {
|
|
744
|
+
return true;
|
|
745
|
+
}
|
|
746
|
+
try {
|
|
747
|
+
return Object.keys(output).length > 0;
|
|
748
|
+
} catch {
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function createServerToolResultExtras(toolName?: string): {
|
|
754
|
+
librechatServerToolResult: { toolName?: string };
|
|
755
|
+
} {
|
|
756
|
+
return {
|
|
757
|
+
librechatServerToolResult: {
|
|
758
|
+
...(toolName != null ? { toolName } : {}),
|
|
759
|
+
},
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function createNeutralServerToolResult(
|
|
764
|
+
output: unknown,
|
|
765
|
+
status: 'error' | 'success',
|
|
766
|
+
maxChars: number,
|
|
767
|
+
toolName?: string
|
|
768
|
+
): LangChainContentBlock.Text | undefined {
|
|
769
|
+
if (!hasMeaningfulServerToolOutput(output)) {
|
|
770
|
+
return undefined;
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
type: 'text',
|
|
774
|
+
text: serializeToolContentBounded(
|
|
775
|
+
{
|
|
776
|
+
serverToolResult: {
|
|
777
|
+
librechatResponsesReplay: true,
|
|
778
|
+
...(toolName != null ? { toolName } : {}),
|
|
779
|
+
status,
|
|
780
|
+
output,
|
|
781
|
+
},
|
|
782
|
+
},
|
|
783
|
+
maxChars
|
|
784
|
+
),
|
|
785
|
+
extras: createServerToolResultExtras(toolName),
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function isCompleteToolStreamContentBlock(block: unknown): boolean {
|
|
790
|
+
if (block == null || typeof block !== 'object') {
|
|
791
|
+
return true;
|
|
792
|
+
}
|
|
793
|
+
try {
|
|
794
|
+
if (isProxy(block)) {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
const type = Object.getOwnPropertyDescriptor(block, 'type');
|
|
798
|
+
if (type == null) {
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
if (type.enumerable !== true || !('value' in type)) {
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
if (type.value !== 'text') {
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
const text = Object.getOwnPropertyDescriptor(block, 'text');
|
|
808
|
+
return (
|
|
809
|
+
text?.enumerable === true &&
|
|
810
|
+
'value' in text &&
|
|
811
|
+
typeof text.value === 'string' &&
|
|
812
|
+
text.value !== ''
|
|
813
|
+
);
|
|
814
|
+
} catch {
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function projectPreemptedResponsesV1Content(
|
|
820
|
+
content: AIMessage['content'],
|
|
821
|
+
reasoning: unknown,
|
|
822
|
+
maxChars: number,
|
|
823
|
+
replayProjection: ResponsesReplayProjection,
|
|
824
|
+
generatedImages?: CompletedGeneratedImages,
|
|
825
|
+
originalImages?: PositionedResponsesImages,
|
|
826
|
+
serverToolResults?: PositionedResponsesReplayBlock[],
|
|
827
|
+
positionedServerToolResultIds?: ReadonlySet<string>,
|
|
828
|
+
reasoningPosition?: ResponsesReplayItemPosition,
|
|
829
|
+
textPositions?: readonly ResponsesReplayPosition[],
|
|
830
|
+
messagePositions?: readonly ResponsesReplayPosition[]
|
|
831
|
+
): {
|
|
832
|
+
content: AIMessage['content'];
|
|
833
|
+
preservedServerToolResult: boolean;
|
|
834
|
+
} {
|
|
835
|
+
if (!Array.isArray(content)) {
|
|
836
|
+
return { content, preservedServerToolResult: false };
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const contentBlocks = content as LangChainContentBlock.Standard[];
|
|
840
|
+
const encryptedReasoning =
|
|
841
|
+
replayProjection === 'native' && hasReplayableEncryptedReasoning(reasoning)
|
|
842
|
+
? reasoning
|
|
843
|
+
: undefined;
|
|
844
|
+
const positionedReasoning: PositionedResponsesReplayBlock | undefined =
|
|
845
|
+
encryptedReasoning != null && reasoningPosition != null
|
|
846
|
+
? {
|
|
847
|
+
block: {
|
|
848
|
+
type: 'non_standard' as const,
|
|
849
|
+
value: encryptedReasoning,
|
|
850
|
+
},
|
|
851
|
+
...reasoningPosition,
|
|
852
|
+
subIndex: 0,
|
|
853
|
+
}
|
|
854
|
+
: undefined;
|
|
855
|
+
const projected: LangChainContentBlock.Standard[] = [];
|
|
856
|
+
let changed = false;
|
|
857
|
+
let hasEncryptedReasoning = false;
|
|
858
|
+
let preservedServerToolResult = false;
|
|
859
|
+
let reasoningInsertionIndex: number | undefined;
|
|
860
|
+
let generatedImageIndex = 0;
|
|
861
|
+
let originalImageIndex = 0;
|
|
862
|
+
let reasoningPending = positionedReasoning;
|
|
863
|
+
let serverToolResultIndex = 0;
|
|
864
|
+
let sourceTextIndex = 0;
|
|
865
|
+
const serverToolNamesByCallId = new Map<string, string>();
|
|
866
|
+
|
|
867
|
+
const appendOriginalImages = (throughTextIndex?: number): void => {
|
|
868
|
+
if (replayProjection !== 'native' || originalImages == null) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
while (originalImageIndex < originalImages.blocks.length) {
|
|
872
|
+
const positionedImage = originalImages.blocks[originalImageIndex];
|
|
873
|
+
if (
|
|
874
|
+
throughTextIndex != null &&
|
|
875
|
+
positionedImage.textIndex > throughTextIndex
|
|
876
|
+
) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
originalImageIndex++;
|
|
880
|
+
if (
|
|
881
|
+
generatedImages != null &&
|
|
882
|
+
isProviderGeneratedImageBlock(
|
|
883
|
+
positionedImage.block,
|
|
884
|
+
generatedImages,
|
|
885
|
+
false
|
|
886
|
+
)
|
|
887
|
+
) {
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
projected.push(positionedImage.block);
|
|
891
|
+
changed = true;
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
const appendReplayBlocks = (
|
|
896
|
+
throughTextIndex?: number,
|
|
897
|
+
beforeOutputIndex?: number
|
|
898
|
+
): void => {
|
|
899
|
+
for (;;) {
|
|
900
|
+
const generatedImage = generatedImages?.blocks[generatedImageIndex];
|
|
901
|
+
const serverToolResult = serverToolResults?.[serverToolResultIndex];
|
|
902
|
+
const candidates: Array<{
|
|
903
|
+
kind: 'generatedImage' | 'reasoning' | 'serverToolResult';
|
|
904
|
+
value: PositionedResponsesReplayBlock;
|
|
905
|
+
}> = [];
|
|
906
|
+
if (generatedImage != null) {
|
|
907
|
+
candidates.push({ kind: 'generatedImage', value: generatedImage });
|
|
908
|
+
}
|
|
909
|
+
if (serverToolResult != null) {
|
|
910
|
+
candidates.push({ kind: 'serverToolResult', value: serverToolResult });
|
|
911
|
+
}
|
|
912
|
+
if (reasoningPending != null) {
|
|
913
|
+
candidates.push({ kind: 'reasoning', value: reasoningPending });
|
|
914
|
+
}
|
|
915
|
+
if (candidates.length === 0) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
candidates.sort((a, b) =>
|
|
919
|
+
comparePositionedResponsesReplayBlocks(a.value, b.value)
|
|
920
|
+
);
|
|
921
|
+
const selected = candidates[0];
|
|
922
|
+
const positionedResult = selected.value;
|
|
923
|
+
if (
|
|
924
|
+
throughTextIndex != null &&
|
|
925
|
+
(positionedResult.textIndex == null ||
|
|
926
|
+
positionedResult.textIndex > throughTextIndex)
|
|
927
|
+
) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
if (
|
|
931
|
+
beforeOutputIndex != null &&
|
|
932
|
+
positionedResult.outputIndex >= beforeOutputIndex
|
|
933
|
+
) {
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (selected.kind === 'generatedImage') {
|
|
937
|
+
generatedImageIndex++;
|
|
938
|
+
} else if (selected.kind === 'serverToolResult') {
|
|
939
|
+
serverToolResultIndex++;
|
|
940
|
+
} else {
|
|
941
|
+
reasoningPending = undefined;
|
|
942
|
+
}
|
|
943
|
+
if (
|
|
944
|
+
replayProjection === 'fallback' &&
|
|
945
|
+
positionedResult.block.type === 'text'
|
|
946
|
+
) {
|
|
947
|
+
projected.push({
|
|
948
|
+
type: 'text',
|
|
949
|
+
text: positionedResult.block.text,
|
|
950
|
+
});
|
|
951
|
+
} else {
|
|
952
|
+
projected.push(positionedResult.block);
|
|
953
|
+
}
|
|
954
|
+
changed = true;
|
|
955
|
+
preservedServerToolResult ||= selected.kind === 'serverToolResult';
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
const appendPositionedOriginalImages = (throughTextIndex?: number): void => {
|
|
960
|
+
const nextOriginalImage = originalImages?.blocks[originalImageIndex];
|
|
961
|
+
if (
|
|
962
|
+
nextOriginalImage == null ||
|
|
963
|
+
(throughTextIndex != null &&
|
|
964
|
+
nextOriginalImage.textIndex > throughTextIndex)
|
|
965
|
+
) {
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
const followingTextPosition = textPositions?.[nextOriginalImage.textIndex];
|
|
969
|
+
const imageOnlyMessagePosition =
|
|
970
|
+
originalImages?.textCount === 0 ? messagePositions?.[0] : undefined;
|
|
971
|
+
const outputBoundary = followingTextPosition ?? imageOnlyMessagePosition;
|
|
972
|
+
if (outputBoundary != null) {
|
|
973
|
+
appendReplayBlocks(
|
|
974
|
+
nextOriginalImage.textIndex,
|
|
975
|
+
outputBoundary.outputIndex
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
appendOriginalImages(throughTextIndex);
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
for (let i = 0; i < contentBlocks.length; i++) {
|
|
982
|
+
const block = contentBlocks[i];
|
|
983
|
+
if (!isCompleteToolStreamContentBlock(block)) {
|
|
984
|
+
changed = true;
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
if (block.type === 'reasoning') {
|
|
988
|
+
reasoningInsertionIndex ??= projected.length;
|
|
989
|
+
changed = true;
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
if (block.type === 'non_standard') {
|
|
993
|
+
if (
|
|
994
|
+
replayProjection === 'native' &&
|
|
995
|
+
!hasEncryptedReasoning &&
|
|
996
|
+
hasReplayableEncryptedReasoning(block.value)
|
|
997
|
+
) {
|
|
998
|
+
hasEncryptedReasoning = true;
|
|
999
|
+
if (positionedReasoning == null) {
|
|
1000
|
+
projected.push(block);
|
|
1001
|
+
} else {
|
|
1002
|
+
changed = true;
|
|
1003
|
+
}
|
|
1004
|
+
} else {
|
|
1005
|
+
changed = true;
|
|
1006
|
+
}
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
if (block.type === 'text') {
|
|
1010
|
+
appendPositionedOriginalImages(sourceTextIndex);
|
|
1011
|
+
appendReplayBlocks(sourceTextIndex);
|
|
1012
|
+
if (replayProjection === 'fallback') {
|
|
1013
|
+
projected.push({ type: 'text', text: block.text });
|
|
1014
|
+
changed = true;
|
|
1015
|
+
} else {
|
|
1016
|
+
projected.push(block);
|
|
1017
|
+
}
|
|
1018
|
+
sourceTextIndex++;
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
if (originalImages != null && sourceTextIndex >= originalImages.textCount) {
|
|
1022
|
+
appendPositionedOriginalImages();
|
|
1023
|
+
}
|
|
1024
|
+
if (
|
|
1025
|
+
block.type === 'server_tool_call' ||
|
|
1026
|
+
block.type === 'server_tool_call_chunk'
|
|
1027
|
+
) {
|
|
1028
|
+
if (
|
|
1029
|
+
typeof block.id === 'string' &&
|
|
1030
|
+
block.id.length > 0 &&
|
|
1031
|
+
typeof block.name === 'string' &&
|
|
1032
|
+
block.name.length > 0
|
|
1033
|
+
) {
|
|
1034
|
+
serverToolNamesByCallId.set(block.id, block.name);
|
|
1035
|
+
}
|
|
1036
|
+
changed = true;
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (block.type === 'server_tool_call_result') {
|
|
1040
|
+
if (positionedServerToolResultIds?.has(block.toolCallId) === true) {
|
|
1041
|
+
changed = true;
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
const result = createNeutralServerToolResult(
|
|
1045
|
+
block.output,
|
|
1046
|
+
block.status,
|
|
1047
|
+
maxChars,
|
|
1048
|
+
serverToolNamesByCallId.get(block.toolCallId)
|
|
1049
|
+
);
|
|
1050
|
+
changed = true;
|
|
1051
|
+
if (result != null) {
|
|
1052
|
+
projected.push(
|
|
1053
|
+
replayProjection === 'fallback'
|
|
1054
|
+
? { type: 'text', text: result.text }
|
|
1055
|
+
: result
|
|
1056
|
+
);
|
|
1057
|
+
preservedServerToolResult = true;
|
|
1058
|
+
}
|
|
1059
|
+
continue;
|
|
1060
|
+
}
|
|
1061
|
+
if (block.type === 'image') {
|
|
1062
|
+
if (
|
|
1063
|
+
replayProjection === 'fallback' ||
|
|
1064
|
+
(generatedImages != null &&
|
|
1065
|
+
isProviderGeneratedImageBlock(block, generatedImages))
|
|
1066
|
+
) {
|
|
1067
|
+
changed = true;
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
projected.push(block);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
if (
|
|
1075
|
+
encryptedReasoning != null &&
|
|
1076
|
+
!hasEncryptedReasoning &&
|
|
1077
|
+
positionedReasoning == null
|
|
1078
|
+
) {
|
|
1079
|
+
const reasoningBlock: LangChainContentBlock.Standard = {
|
|
1080
|
+
type: 'non_standard',
|
|
1081
|
+
value: encryptedReasoning,
|
|
1082
|
+
};
|
|
1083
|
+
projected.splice(reasoningInsertionIndex ?? 0, 0, reasoningBlock);
|
|
1084
|
+
changed = true;
|
|
1085
|
+
}
|
|
1086
|
+
appendPositionedOriginalImages();
|
|
1087
|
+
appendReplayBlocks();
|
|
1088
|
+
return {
|
|
1089
|
+
content: changed ? toLangChainContent(projected) : content,
|
|
1090
|
+
preservedServerToolResult,
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
function getAuthoritativeResponsesOutput(message: AIMessage): unknown[] {
|
|
1095
|
+
const responseOutput = message.response_metadata.output;
|
|
1096
|
+
const toolOutputs = message.additional_kwargs.tool_outputs;
|
|
1097
|
+
if (Array.isArray(responseOutput) && responseOutput.length > 0) {
|
|
1098
|
+
return responseOutput;
|
|
1099
|
+
}
|
|
1100
|
+
return Array.isArray(toolOutputs) ? toolOutputs : [];
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
function isResponsesReplayPosition(
|
|
1104
|
+
value: unknown
|
|
1105
|
+
): value is ResponsesReplayPosition {
|
|
1106
|
+
if (value == null || typeof value !== 'object') {
|
|
1107
|
+
return false;
|
|
1108
|
+
}
|
|
1109
|
+
const position = value as Partial<ResponsesReplayPosition>;
|
|
1110
|
+
return (
|
|
1111
|
+
(position.kind === 'message' ||
|
|
1112
|
+
position.kind === 'output' ||
|
|
1113
|
+
position.kind === 'reasoning' ||
|
|
1114
|
+
position.kind === 'text') &&
|
|
1115
|
+
typeof position.itemId === 'string' &&
|
|
1116
|
+
position.itemId.length > 0 &&
|
|
1117
|
+
typeof position.outputIndex === 'number' &&
|
|
1118
|
+
Number.isSafeInteger(position.outputIndex) &&
|
|
1119
|
+
position.outputIndex >= 0 &&
|
|
1120
|
+
(position.contentIndex == null ||
|
|
1121
|
+
(typeof position.contentIndex === 'number' &&
|
|
1122
|
+
Number.isSafeInteger(position.contentIndex) &&
|
|
1123
|
+
position.contentIndex >= 0))
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
function getGeneratedImageMimeType(data: string): string {
|
|
1128
|
+
const bytes = Buffer.from(data.slice(0, 16), 'base64');
|
|
1129
|
+
if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
|
|
1130
|
+
return 'image/jpeg';
|
|
1131
|
+
}
|
|
1132
|
+
if (
|
|
1133
|
+
bytes[0] === 0x52 &&
|
|
1134
|
+
bytes[1] === 0x49 &&
|
|
1135
|
+
bytes[2] === 0x46 &&
|
|
1136
|
+
bytes[3] === 0x46 &&
|
|
1137
|
+
bytes[8] === 0x57 &&
|
|
1138
|
+
bytes[9] === 0x45 &&
|
|
1139
|
+
bytes[10] === 0x42 &&
|
|
1140
|
+
bytes[11] === 0x50
|
|
1141
|
+
) {
|
|
1142
|
+
return 'image/webp';
|
|
1143
|
+
}
|
|
1144
|
+
return 'image/png';
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
function getResponsesReplayItemKey(
|
|
1148
|
+
item: Record<string, unknown>
|
|
1149
|
+
): string | undefined {
|
|
1150
|
+
if (typeof item.id === 'string' && item.id.length > 0) {
|
|
1151
|
+
return item.id;
|
|
1152
|
+
}
|
|
1153
|
+
return typeof item.call_id === 'string' && item.call_id.length > 0
|
|
1154
|
+
? item.call_id
|
|
1155
|
+
: undefined;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
function comparePositionedResponsesReplayBlocks(
|
|
1159
|
+
a: PositionedResponsesReplayBlock,
|
|
1160
|
+
b: PositionedResponsesReplayBlock
|
|
1161
|
+
): number {
|
|
1162
|
+
return (
|
|
1163
|
+
(a.textIndex ?? Number.MAX_SAFE_INTEGER) -
|
|
1164
|
+
(b.textIndex ?? Number.MAX_SAFE_INTEGER) ||
|
|
1165
|
+
a.outputIndex - b.outputIndex ||
|
|
1166
|
+
a.subIndex - b.subIndex
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
const RESPONSES_REPLAY_OUTPUT_TOOL_NAMES = {
|
|
1171
|
+
apply_patch_call_output: 'apply_patch',
|
|
1172
|
+
local_shell_call_output: 'local_shell',
|
|
1173
|
+
shell_call_output: 'shell',
|
|
1174
|
+
} as const;
|
|
1175
|
+
|
|
1176
|
+
function getResponsesReplayArtifacts(
|
|
1177
|
+
output: readonly unknown[],
|
|
1178
|
+
maxChars: number,
|
|
1179
|
+
replayProjection: ResponsesReplayProjection,
|
|
1180
|
+
replayPositionValue?: unknown
|
|
1181
|
+
): ResponsesReplayArtifacts {
|
|
1182
|
+
const blocks: PositionedResponsesReplayBlock[] = [];
|
|
1183
|
+
const data = new Set<string>();
|
|
1184
|
+
const ids = new Set<string>();
|
|
1185
|
+
const emittedData = new Set<string>();
|
|
1186
|
+
const emittedIds = new Set<string>();
|
|
1187
|
+
const positionedServerToolResultIds = new Set<string>();
|
|
1188
|
+
const rawOutputIndices = new Map<Record<string, unknown>, number>();
|
|
1189
|
+
const serverToolResults: PositionedResponsesReplayBlock[] = [];
|
|
1190
|
+
const replayPositions = Array.isArray(replayPositionValue)
|
|
1191
|
+
? replayPositionValue.filter(isResponsesReplayPosition)
|
|
1192
|
+
: [];
|
|
1193
|
+
const authoritativeOutputIndicesByItemId = new Map<string, number>();
|
|
1194
|
+
const messagePositionsByKey = new Map<string, ResponsesReplayPosition>();
|
|
1195
|
+
const outputPositionsByItemId = new Map<string, ResponsesReplayPosition>();
|
|
1196
|
+
const textPositionsByKey = new Map<string, ResponsesReplayPosition>();
|
|
1197
|
+
for (const position of replayPositions) {
|
|
1198
|
+
if (position.kind === 'output' || position.kind === 'reasoning') {
|
|
1199
|
+
outputPositionsByItemId.set(position.itemId, position);
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1202
|
+
if (position.kind === 'message') {
|
|
1203
|
+
messagePositionsByKey.set(
|
|
1204
|
+
`${position.itemId}:${position.outputIndex}`,
|
|
1205
|
+
position
|
|
1206
|
+
);
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
textPositionsByKey.set(
|
|
1210
|
+
`${position.itemId}:${position.outputIndex}:${position.contentIndex ?? 0}`,
|
|
1211
|
+
position
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
let hasAuthoritativeMessage = false;
|
|
1215
|
+
for (let outputIndex = 0; outputIndex < output.length; outputIndex++) {
|
|
1216
|
+
const item = output[outputIndex];
|
|
1217
|
+
if (item == null || typeof item !== 'object') {
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
const itemRecord = item as Record<string, unknown>;
|
|
1221
|
+
rawOutputIndices.set(itemRecord, outputIndex);
|
|
1222
|
+
const itemKey = getResponsesReplayItemKey(itemRecord);
|
|
1223
|
+
if (itemKey != null) {
|
|
1224
|
+
authoritativeOutputIndicesByItemId.set(itemKey, outputIndex);
|
|
1225
|
+
}
|
|
1226
|
+
if (!('type' in item) || item.type !== 'message') {
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
hasAuthoritativeMessage = true;
|
|
1230
|
+
const messageItemId =
|
|
1231
|
+
'id' in item && typeof item.id === 'string'
|
|
1232
|
+
? item.id
|
|
1233
|
+
: `message-${outputIndex}`;
|
|
1234
|
+
messagePositionsByKey.set(`${messageItemId}:${outputIndex}`, {
|
|
1235
|
+
itemId: messageItemId,
|
|
1236
|
+
kind: 'message',
|
|
1237
|
+
outputIndex,
|
|
1238
|
+
});
|
|
1239
|
+
if (!('content' in item) || !Array.isArray(item.content)) {
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
for (
|
|
1243
|
+
let contentIndex = 0;
|
|
1244
|
+
contentIndex < item.content.length;
|
|
1245
|
+
contentIndex++
|
|
1246
|
+
) {
|
|
1247
|
+
const content = item.content[contentIndex];
|
|
1248
|
+
if (
|
|
1249
|
+
content == null ||
|
|
1250
|
+
typeof content !== 'object' ||
|
|
1251
|
+
!('type' in content) ||
|
|
1252
|
+
content.type !== 'output_text' ||
|
|
1253
|
+
!('text' in content) ||
|
|
1254
|
+
typeof content.text !== 'string' ||
|
|
1255
|
+
content.text.length === 0
|
|
1256
|
+
) {
|
|
1257
|
+
continue;
|
|
1258
|
+
}
|
|
1259
|
+
const itemId =
|
|
1260
|
+
'id' in item && typeof item.id === 'string'
|
|
1261
|
+
? item.id
|
|
1262
|
+
: `message-${outputIndex}`;
|
|
1263
|
+
textPositionsByKey.set(`${itemId}:${outputIndex}:${contentIndex}`, {
|
|
1264
|
+
contentIndex,
|
|
1265
|
+
itemId,
|
|
1266
|
+
kind: 'text',
|
|
1267
|
+
outputIndex,
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
if (hasAuthoritativeMessage) {
|
|
1272
|
+
for (const [itemId, outputIndex] of authoritativeOutputIndicesByItemId) {
|
|
1273
|
+
outputPositionsByItemId.set(itemId, {
|
|
1274
|
+
itemId,
|
|
1275
|
+
kind: 'output',
|
|
1276
|
+
outputIndex,
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const textPositions = [...textPositionsByKey.values()].sort(
|
|
1281
|
+
(a, b) =>
|
|
1282
|
+
a.outputIndex - b.outputIndex ||
|
|
1283
|
+
(a.contentIndex ?? 0) - (b.contentIndex ?? 0)
|
|
1284
|
+
);
|
|
1285
|
+
const messagePositions = [...messagePositionsByKey.values()].sort(
|
|
1286
|
+
(a, b) => a.outputIndex - b.outputIndex
|
|
1287
|
+
);
|
|
1288
|
+
const textCountBeforeOutputIndex = new Map<number, number>();
|
|
1289
|
+
const positionedOutputIndexSet = new Set<number>();
|
|
1290
|
+
for (const position of outputPositionsByItemId.values()) {
|
|
1291
|
+
positionedOutputIndexSet.add(position.outputIndex);
|
|
1292
|
+
}
|
|
1293
|
+
if (hasAuthoritativeMessage) {
|
|
1294
|
+
for (const outputIndex of rawOutputIndices.values()) {
|
|
1295
|
+
positionedOutputIndexSet.add(outputIndex);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
const positionedOutputIndices = [...positionedOutputIndexSet].sort(
|
|
1299
|
+
(a, b) => a - b
|
|
1300
|
+
);
|
|
1301
|
+
let textPositionIndex = 0;
|
|
1302
|
+
for (const outputIndex of positionedOutputIndices) {
|
|
1303
|
+
while (
|
|
1304
|
+
textPositionIndex < textPositions.length &&
|
|
1305
|
+
textPositions[textPositionIndex].outputIndex < outputIndex
|
|
1306
|
+
) {
|
|
1307
|
+
textPositionIndex++;
|
|
1308
|
+
}
|
|
1309
|
+
textCountBeforeOutputIndex.set(outputIndex, textPositionIndex);
|
|
1310
|
+
}
|
|
1311
|
+
const positionsByItemId = new Map<string, ResponsesReplayItemPosition>();
|
|
1312
|
+
for (const [itemId, position] of outputPositionsByItemId) {
|
|
1313
|
+
positionsByItemId.set(itemId, {
|
|
1314
|
+
outputIndex: position.outputIndex,
|
|
1315
|
+
textIndex: textCountBeforeOutputIndex.get(position.outputIndex) ?? 0,
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
const getPosition = (
|
|
1319
|
+
item: Record<string, unknown>
|
|
1320
|
+
): ResponsesReplayItemPosition => {
|
|
1321
|
+
const itemId = getResponsesReplayItemKey(item);
|
|
1322
|
+
const position = itemId != null ? positionsByItemId.get(itemId) : undefined;
|
|
1323
|
+
if (position == null) {
|
|
1324
|
+
const rawOutputIndex = rawOutputIndices.get(item);
|
|
1325
|
+
return {
|
|
1326
|
+
outputIndex: rawOutputIndex ?? Number.MAX_SAFE_INTEGER,
|
|
1327
|
+
...(hasAuthoritativeMessage && rawOutputIndex != null
|
|
1328
|
+
? {
|
|
1329
|
+
textIndex: textCountBeforeOutputIndex.get(rawOutputIndex) ?? 0,
|
|
1330
|
+
}
|
|
1331
|
+
: {}),
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
return position;
|
|
1335
|
+
};
|
|
1336
|
+
const pushServerToolResult = (
|
|
1337
|
+
block: LangChainContentBlock.Standard | undefined,
|
|
1338
|
+
item: Record<string, unknown>,
|
|
1339
|
+
subIndex = 0
|
|
1340
|
+
): void => {
|
|
1341
|
+
if (block == null) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
const itemId = getResponsesReplayItemKey(item);
|
|
1345
|
+
if (itemId != null) {
|
|
1346
|
+
positionedServerToolResultIds.add(itemId);
|
|
1347
|
+
}
|
|
1348
|
+
serverToolResults.push({ block, ...getPosition(item), subIndex });
|
|
1349
|
+
};
|
|
1350
|
+
for (const item of output) {
|
|
1351
|
+
if (item == null || typeof item !== 'object' || !('type' in item)) {
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
if (item.type === 'code_interpreter_call') {
|
|
1355
|
+
if (
|
|
1356
|
+
!('outputs' in item) ||
|
|
1357
|
+
!Array.isArray(item.outputs) ||
|
|
1358
|
+
!('status' in item)
|
|
1359
|
+
) {
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
const resultStatus = item.status === 'completed' ? 'success' : 'error';
|
|
1363
|
+
const returnCode = item.status === 'completed' ? 0 : 1;
|
|
1364
|
+
for (
|
|
1365
|
+
let resultIndex = 0;
|
|
1366
|
+
resultIndex < item.outputs.length;
|
|
1367
|
+
resultIndex++
|
|
1368
|
+
) {
|
|
1369
|
+
const result = item.outputs[resultIndex];
|
|
1370
|
+
if (
|
|
1371
|
+
result == null ||
|
|
1372
|
+
typeof result !== 'object' ||
|
|
1373
|
+
!('type' in result)
|
|
1374
|
+
) {
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
if (
|
|
1378
|
+
result.type === 'logs' &&
|
|
1379
|
+
'logs' in result &&
|
|
1380
|
+
typeof result.logs === 'string'
|
|
1381
|
+
) {
|
|
1382
|
+
pushServerToolResult(
|
|
1383
|
+
createNeutralServerToolResult(
|
|
1384
|
+
{
|
|
1385
|
+
type: 'code_interpreter_output',
|
|
1386
|
+
returnCode,
|
|
1387
|
+
stdout: result.logs,
|
|
1388
|
+
},
|
|
1389
|
+
resultStatus,
|
|
1390
|
+
maxChars,
|
|
1391
|
+
'code_interpreter'
|
|
1392
|
+
),
|
|
1393
|
+
item,
|
|
1394
|
+
resultIndex
|
|
1395
|
+
);
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1398
|
+
if (
|
|
1399
|
+
result.type !== 'image' ||
|
|
1400
|
+
!('url' in result) ||
|
|
1401
|
+
typeof result.url !== 'string' ||
|
|
1402
|
+
result.url.length === 0
|
|
1403
|
+
) {
|
|
1404
|
+
continue;
|
|
1405
|
+
}
|
|
1406
|
+
const resultUrl: string = result.url;
|
|
1407
|
+
if (
|
|
1408
|
+
replayProjection === 'native' &&
|
|
1409
|
+
resultUrl.startsWith('data:image/')
|
|
1410
|
+
) {
|
|
1411
|
+
pushServerToolResult(
|
|
1412
|
+
{
|
|
1413
|
+
type: 'image',
|
|
1414
|
+
url: resultUrl,
|
|
1415
|
+
extras: createServerToolResultExtras('code_interpreter'),
|
|
1416
|
+
},
|
|
1417
|
+
item,
|
|
1418
|
+
resultIndex
|
|
1419
|
+
);
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
const mediaResult = createNeutralServerToolResult(
|
|
1423
|
+
{ type: 'code_interpreter_image', url: resultUrl },
|
|
1424
|
+
resultStatus,
|
|
1425
|
+
maxChars,
|
|
1426
|
+
'code_interpreter'
|
|
1427
|
+
);
|
|
1428
|
+
pushServerToolResult(mediaResult, item, resultIndex);
|
|
1429
|
+
}
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
if (item.type === 'file_search_call') {
|
|
1433
|
+
const result = createNeutralServerToolResult(
|
|
1434
|
+
'results' in item && Array.isArray(item.results)
|
|
1435
|
+
? { results: item.results }
|
|
1436
|
+
: undefined,
|
|
1437
|
+
'status' in item && item.status === 'completed' ? 'success' : 'error',
|
|
1438
|
+
maxChars,
|
|
1439
|
+
'file_search'
|
|
1440
|
+
);
|
|
1441
|
+
pushServerToolResult(result, item);
|
|
1442
|
+
continue;
|
|
1443
|
+
}
|
|
1444
|
+
if (item.type === 'web_search_call') {
|
|
1445
|
+
const result = createNeutralServerToolResult(
|
|
1446
|
+
{
|
|
1447
|
+
...('action' in item ? { action: item.action } : {}),
|
|
1448
|
+
...('results' in item && Array.isArray(item.results)
|
|
1449
|
+
? { results: item.results }
|
|
1450
|
+
: {}),
|
|
1451
|
+
},
|
|
1452
|
+
'status' in item && item.status === 'completed' ? 'success' : 'error',
|
|
1453
|
+
maxChars,
|
|
1454
|
+
'web_search'
|
|
1455
|
+
);
|
|
1456
|
+
pushServerToolResult(result, item);
|
|
1457
|
+
continue;
|
|
1458
|
+
}
|
|
1459
|
+
if (item.type === 'tool_search_output') {
|
|
1460
|
+
const result = createNeutralServerToolResult(
|
|
1461
|
+
'tools' in item && Array.isArray(item.tools)
|
|
1462
|
+
? { tools: item.tools }
|
|
1463
|
+
: undefined,
|
|
1464
|
+
'status' in item && item.status === 'completed' ? 'success' : 'error',
|
|
1465
|
+
maxChars,
|
|
1466
|
+
'tool_search'
|
|
1467
|
+
);
|
|
1468
|
+
pushServerToolResult(result, item);
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
if (item.type === 'mcp_list_tools') {
|
|
1472
|
+
const hasError =
|
|
1473
|
+
'error' in item &&
|
|
1474
|
+
typeof item.error === 'string' &&
|
|
1475
|
+
item.error.length > 0;
|
|
1476
|
+
const listToolsResult = createNeutralServerToolResult(
|
|
1477
|
+
{
|
|
1478
|
+
...('server_label' in item && typeof item.server_label === 'string'
|
|
1479
|
+
? { serverLabel: item.server_label }
|
|
1480
|
+
: {}),
|
|
1481
|
+
...('tools' in item && Array.isArray(item.tools)
|
|
1482
|
+
? { tools: item.tools }
|
|
1483
|
+
: {}),
|
|
1484
|
+
...(hasError ? { error: item.error } : {}),
|
|
1485
|
+
},
|
|
1486
|
+
hasError ? 'error' : 'success',
|
|
1487
|
+
maxChars,
|
|
1488
|
+
'mcp_list_tools'
|
|
1489
|
+
);
|
|
1490
|
+
pushServerToolResult(listToolsResult, item);
|
|
1491
|
+
continue;
|
|
1492
|
+
}
|
|
1493
|
+
if (item.type === 'mcp_call') {
|
|
1494
|
+
const hasOutput =
|
|
1495
|
+
'output' in item &&
|
|
1496
|
+
typeof item.output === 'string' &&
|
|
1497
|
+
item.output.length > 0;
|
|
1498
|
+
const hasError =
|
|
1499
|
+
'error' in item &&
|
|
1500
|
+
typeof item.error === 'string' &&
|
|
1501
|
+
item.error.length > 0;
|
|
1502
|
+
if (!hasOutput && !hasError) {
|
|
1503
|
+
continue;
|
|
1504
|
+
}
|
|
1505
|
+
const mcpOutput = {
|
|
1506
|
+
...('name' in item && typeof item.name === 'string'
|
|
1507
|
+
? { name: item.name }
|
|
1508
|
+
: {}),
|
|
1509
|
+
...('server_label' in item && typeof item.server_label === 'string'
|
|
1510
|
+
? { serverLabel: item.server_label }
|
|
1511
|
+
: {}),
|
|
1512
|
+
...('output' in item && typeof item.output === 'string'
|
|
1513
|
+
? { output: item.output }
|
|
1514
|
+
: {}),
|
|
1515
|
+
...('error' in item && typeof item.error === 'string'
|
|
1516
|
+
? { error: item.error }
|
|
1517
|
+
: {}),
|
|
1518
|
+
};
|
|
1519
|
+
const mcpResult = createNeutralServerToolResult(
|
|
1520
|
+
mcpOutput,
|
|
1521
|
+
hasError ||
|
|
1522
|
+
('status' in item &&
|
|
1523
|
+
(item.status === 'failed' || item.status === 'incomplete'))
|
|
1524
|
+
? 'error'
|
|
1525
|
+
: 'success',
|
|
1526
|
+
maxChars,
|
|
1527
|
+
'name' in item && typeof item.name === 'string' && item.name.length > 0
|
|
1528
|
+
? item.name
|
|
1529
|
+
: 'mcp'
|
|
1530
|
+
);
|
|
1531
|
+
pushServerToolResult(mcpResult, item);
|
|
1532
|
+
continue;
|
|
1533
|
+
}
|
|
1534
|
+
if (
|
|
1535
|
+
item.type === 'local_shell_call_output' ||
|
|
1536
|
+
item.type === 'shell_call_output' ||
|
|
1537
|
+
item.type === 'apply_patch_call_output'
|
|
1538
|
+
) {
|
|
1539
|
+
if (!('output' in item)) {
|
|
1540
|
+
continue;
|
|
1541
|
+
}
|
|
1542
|
+
const result = createNeutralServerToolResult(
|
|
1543
|
+
item.output,
|
|
1544
|
+
'status' in item &&
|
|
1545
|
+
(item.status === 'failed' || item.status === 'incomplete')
|
|
1546
|
+
? 'error'
|
|
1547
|
+
: 'success',
|
|
1548
|
+
maxChars,
|
|
1549
|
+
RESPONSES_REPLAY_OUTPUT_TOOL_NAMES[item.type]
|
|
1550
|
+
);
|
|
1551
|
+
pushServerToolResult(result, item);
|
|
1552
|
+
continue;
|
|
1553
|
+
}
|
|
1554
|
+
if (item.type === 'program_output') {
|
|
1555
|
+
if (!('result' in item)) {
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1558
|
+
const result = createNeutralServerToolResult(
|
|
1559
|
+
item.result,
|
|
1560
|
+
'status' in item && item.status === 'incomplete' ? 'error' : 'success',
|
|
1561
|
+
maxChars,
|
|
1562
|
+
'program'
|
|
1563
|
+
);
|
|
1564
|
+
pushServerToolResult(result, item);
|
|
1565
|
+
continue;
|
|
1566
|
+
}
|
|
1567
|
+
if (item.type !== 'image_generation_call') {
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if ('id' in item && typeof item.id === 'string' && item.id.length > 0) {
|
|
1571
|
+
ids.add(item.id);
|
|
1572
|
+
}
|
|
1573
|
+
if (
|
|
1574
|
+
!('result' in item) ||
|
|
1575
|
+
typeof item.result !== 'string' ||
|
|
1576
|
+
item.result.length === 0
|
|
1577
|
+
) {
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
data.add(item.result);
|
|
1581
|
+
if ('status' in item && item.status === 'completed') {
|
|
1582
|
+
const itemId =
|
|
1583
|
+
'id' in item && typeof item.id === 'string' && item.id.length > 0
|
|
1584
|
+
? item.id
|
|
1585
|
+
: undefined;
|
|
1586
|
+
if (
|
|
1587
|
+
(itemId != null && emittedIds.has(itemId)) ||
|
|
1588
|
+
(itemId == null && emittedData.has(item.result))
|
|
1589
|
+
) {
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
if (itemId != null) {
|
|
1593
|
+
emittedIds.add(itemId);
|
|
1594
|
+
} else {
|
|
1595
|
+
emittedData.add(item.result);
|
|
1596
|
+
}
|
|
1597
|
+
blocks.push({
|
|
1598
|
+
block: {
|
|
1599
|
+
type: 'image',
|
|
1600
|
+
mimeType: getGeneratedImageMimeType(item.result),
|
|
1601
|
+
data: item.result,
|
|
1602
|
+
extras: createServerToolResultExtras('image_generation'),
|
|
1603
|
+
},
|
|
1604
|
+
...getPosition(item),
|
|
1605
|
+
subIndex: 0,
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
return {
|
|
1610
|
+
generatedImages: {
|
|
1611
|
+
blocks: blocks.sort(comparePositionedResponsesReplayBlocks),
|
|
1612
|
+
data,
|
|
1613
|
+
ids,
|
|
1614
|
+
},
|
|
1615
|
+
messagePositions,
|
|
1616
|
+
positionedServerToolResultIds,
|
|
1617
|
+
positionsByItemId,
|
|
1618
|
+
serverToolResults: serverToolResults.sort(
|
|
1619
|
+
comparePositionedResponsesReplayBlocks
|
|
1620
|
+
),
|
|
1621
|
+
textPositions,
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
function getSelfContainedResponsesV0Images(
|
|
1626
|
+
message: AIMessage
|
|
1627
|
+
): PositionedResponsesImages {
|
|
1628
|
+
if (!Array.isArray(message.content)) {
|
|
1629
|
+
return { blocks: [], textCount: 0 };
|
|
1630
|
+
}
|
|
1631
|
+
const images: PositionedResponsesImage[] = [];
|
|
1632
|
+
let textCount = 0;
|
|
1633
|
+
for (const block of message.content as LangChainContentBlock.Standard[]) {
|
|
1634
|
+
if (block.type === 'text') {
|
|
1635
|
+
if (isCompleteToolStreamContentBlock(block)) {
|
|
1636
|
+
textCount++;
|
|
1637
|
+
}
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1640
|
+
if (
|
|
1641
|
+
block.type === 'image' &&
|
|
1642
|
+
(('fileId' in block &&
|
|
1643
|
+
typeof block.fileId === 'string' &&
|
|
1644
|
+
block.fileId.length > 0) ||
|
|
1645
|
+
('url' in block &&
|
|
1646
|
+
typeof block.url === 'string' &&
|
|
1647
|
+
block.url.length > 0) ||
|
|
1648
|
+
('data' in block &&
|
|
1649
|
+
((typeof block.data === 'string' && block.data.length > 0) ||
|
|
1650
|
+
(block.data instanceof Uint8Array && block.data.length > 0))))
|
|
1651
|
+
) {
|
|
1652
|
+
images.push({ block, textIndex: textCount });
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
return { blocks: images, textCount };
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
function getResponsesV0ContentBlocks(
|
|
1659
|
+
message: AIMessage,
|
|
1660
|
+
authoritativeOutput: unknown[]
|
|
1661
|
+
): AIMessage['content'] {
|
|
1662
|
+
let content = message.content;
|
|
1663
|
+
if (typeof content === 'string') {
|
|
1664
|
+
content = toLangChainContent(
|
|
1665
|
+
content.length > 0 ? [{ type: 'text', text: content }] : []
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
const translationMessage = cloneAIMessageWithResponsesReplayState(
|
|
1669
|
+
message,
|
|
1670
|
+
content,
|
|
1671
|
+
message.id,
|
|
1672
|
+
{
|
|
1673
|
+
...message.additional_kwargs,
|
|
1674
|
+
tool_outputs: authoritativeOutput,
|
|
1675
|
+
},
|
|
1676
|
+
{
|
|
1677
|
+
...message.response_metadata,
|
|
1678
|
+
model_provider: 'openai',
|
|
1679
|
+
}
|
|
1680
|
+
);
|
|
1681
|
+
return toLangChainContent(translationMessage.contentBlocks);
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
function isPreemptedOpenAIResponsesMessage(message: AIMessage): boolean {
|
|
1685
|
+
const metadata = message.response_metadata;
|
|
1686
|
+
if (metadata.preempted !== true || metadata.model_provider !== 'openai') {
|
|
1687
|
+
return false;
|
|
1688
|
+
}
|
|
1689
|
+
if (
|
|
1690
|
+
message.id?.startsWith('msg_') === true ||
|
|
1691
|
+
message.id?.startsWith('resp_') === true ||
|
|
1692
|
+
(typeof metadata.id === 'string' && metadata.id.startsWith('resp_')) ||
|
|
1693
|
+
Array.isArray(metadata.output) ||
|
|
1694
|
+
metadata.tool_outputs != null ||
|
|
1695
|
+
Array.isArray(message.additional_kwargs.tool_outputs) ||
|
|
1696
|
+
message.additional_kwargs[OPENAI_RESPONSES_REPLAY_POSITIONS_KEY] != null ||
|
|
1697
|
+
message.additional_kwargs.__openai_function_call_ids__ != null ||
|
|
1698
|
+
message.additional_kwargs.__openai_custom_tool_call_ids__ != null ||
|
|
1699
|
+
(message.additional_kwargs.reasoning != null &&
|
|
1700
|
+
typeof message.additional_kwargs.reasoning === 'object')
|
|
1701
|
+
) {
|
|
1702
|
+
return true;
|
|
1703
|
+
}
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
592
1707
|
/**
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
1708
|
+
* A sealed Responses turn cannot prove that provider-side item ids were
|
|
1709
|
+
* retained: the response object does not echo the request's `store` flag.
|
|
1710
|
+
* Project a provider-neutral clone while preserving self-contained encrypted
|
|
1711
|
+
* reasoning and the original graph/checkpoint message.
|
|
596
1712
|
*/
|
|
1713
|
+
function projectPreemptedOpenAIResponsesMessage(
|
|
1714
|
+
message: AIMessage,
|
|
1715
|
+
maxChars: number,
|
|
1716
|
+
replayProjection: ResponsesReplayProjection
|
|
1717
|
+
): AIMessage {
|
|
1718
|
+
if (!isPreemptedOpenAIResponsesMessage(message)) {
|
|
1719
|
+
return message;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
const metadata = message.response_metadata;
|
|
1723
|
+
const additionalKwargs = { ...message.additional_kwargs };
|
|
1724
|
+
const retainsEncryptedReasoning =
|
|
1725
|
+
replayProjection === 'native' &&
|
|
1726
|
+
hasReplayableEncryptedReasoning(additionalKwargs.reasoning);
|
|
1727
|
+
const authoritativeOutput = getAuthoritativeResponsesOutput(message);
|
|
1728
|
+
const {
|
|
1729
|
+
generatedImages,
|
|
1730
|
+
messagePositions,
|
|
1731
|
+
positionedServerToolResultIds,
|
|
1732
|
+
positionsByItemId,
|
|
1733
|
+
serverToolResults,
|
|
1734
|
+
textPositions,
|
|
1735
|
+
} = getResponsesReplayArtifacts(
|
|
1736
|
+
authoritativeOutput,
|
|
1737
|
+
maxChars,
|
|
1738
|
+
replayProjection,
|
|
1739
|
+
additionalKwargs[OPENAI_RESPONSES_REPLAY_POSITIONS_KEY]
|
|
1740
|
+
);
|
|
1741
|
+
const reasoningItemId =
|
|
1742
|
+
retainsEncryptedReasoning &&
|
|
1743
|
+
additionalKwargs.reasoning != null &&
|
|
1744
|
+
typeof additionalKwargs.reasoning === 'object' &&
|
|
1745
|
+
'id' in additionalKwargs.reasoning &&
|
|
1746
|
+
typeof additionalKwargs.reasoning.id === 'string'
|
|
1747
|
+
? additionalKwargs.reasoning.id
|
|
1748
|
+
: undefined;
|
|
1749
|
+
const reasoningPosition =
|
|
1750
|
+
reasoningItemId != null
|
|
1751
|
+
? positionsByItemId.get(reasoningItemId)
|
|
1752
|
+
: undefined;
|
|
1753
|
+
const isV1 = metadata.output_version === 'v1';
|
|
1754
|
+
const translatesV0 =
|
|
1755
|
+
!isV1 &&
|
|
1756
|
+
(replayProjection === 'fallback' || authoritativeOutput.length > 0);
|
|
1757
|
+
const originalImages =
|
|
1758
|
+
replayProjection === 'native' && translatesV0
|
|
1759
|
+
? getSelfContainedResponsesV0Images(message)
|
|
1760
|
+
: undefined;
|
|
1761
|
+
let contentForProjection = message.content;
|
|
1762
|
+
if (!isV1 && translatesV0) {
|
|
1763
|
+
contentForProjection = getResponsesV0ContentBlocks(
|
|
1764
|
+
message,
|
|
1765
|
+
authoritativeOutput
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
const projectedContent = projectPreemptedResponsesV1Content(
|
|
1769
|
+
contentForProjection,
|
|
1770
|
+
isV1 || translatesV0 ? additionalKwargs.reasoning : undefined,
|
|
1771
|
+
maxChars,
|
|
1772
|
+
replayProjection,
|
|
1773
|
+
replayProjection === 'native' ? generatedImages : undefined,
|
|
1774
|
+
originalImages,
|
|
1775
|
+
serverToolResults,
|
|
1776
|
+
positionedServerToolResultIds,
|
|
1777
|
+
reasoningPosition,
|
|
1778
|
+
textPositions,
|
|
1779
|
+
messagePositions
|
|
1780
|
+
);
|
|
1781
|
+
const promotesV0 =
|
|
1782
|
+
!isV1 &&
|
|
1783
|
+
(replayProjection === 'fallback' ||
|
|
1784
|
+
generatedImages.blocks.length > 0 ||
|
|
1785
|
+
projectedContent.preservedServerToolResult);
|
|
1786
|
+
const unpromotedV0Content =
|
|
1787
|
+
contentForProjection === message.content
|
|
1788
|
+
? projectedContent.content
|
|
1789
|
+
: projectPreemptedResponsesV1Content(
|
|
1790
|
+
message.content,
|
|
1791
|
+
undefined,
|
|
1792
|
+
maxChars,
|
|
1793
|
+
replayProjection
|
|
1794
|
+
).content;
|
|
1795
|
+
const content =
|
|
1796
|
+
isV1 || promotesV0 ? projectedContent.content : unpromotedV0Content;
|
|
1797
|
+
const hasUnsafeProviderReferences =
|
|
1798
|
+
content !== message.content ||
|
|
1799
|
+
message.id?.startsWith('msg_') === true ||
|
|
1800
|
+
(!retainsEncryptedReasoning && additionalKwargs.reasoning != null) ||
|
|
1801
|
+
additionalKwargs.tool_outputs != null ||
|
|
1802
|
+
additionalKwargs[OPENAI_RESPONSES_REPLAY_POSITIONS_KEY] != null ||
|
|
1803
|
+
additionalKwargs.__openai_function_call_ids__ != null ||
|
|
1804
|
+
additionalKwargs.__openai_custom_tool_call_ids__ != null ||
|
|
1805
|
+
metadata.id != null ||
|
|
1806
|
+
metadata.output != null ||
|
|
1807
|
+
metadata.tool_outputs != null;
|
|
1808
|
+
if (!hasUnsafeProviderReferences) {
|
|
1809
|
+
return message;
|
|
1810
|
+
}
|
|
1811
|
+
if (!retainsEncryptedReasoning) {
|
|
1812
|
+
delete additionalKwargs.reasoning;
|
|
1813
|
+
}
|
|
1814
|
+
delete additionalKwargs.tool_outputs;
|
|
1815
|
+
delete additionalKwargs[OPENAI_RESPONSES_REPLAY_POSITIONS_KEY];
|
|
1816
|
+
delete additionalKwargs.__openai_function_call_ids__;
|
|
1817
|
+
delete additionalKwargs.__openai_custom_tool_call_ids__;
|
|
1818
|
+
|
|
1819
|
+
const responseMetadata: AIMessage['response_metadata'] = { ...metadata };
|
|
1820
|
+
delete responseMetadata.id;
|
|
1821
|
+
delete responseMetadata.output;
|
|
1822
|
+
delete responseMetadata.tool_outputs;
|
|
1823
|
+
if (promotesV0) {
|
|
1824
|
+
responseMetadata.output_version = 'v1';
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
return cloneAIMessageWithResponsesReplayState(
|
|
1828
|
+
message,
|
|
1829
|
+
content,
|
|
1830
|
+
message.id?.startsWith('msg_') === true ? undefined : message.id,
|
|
1831
|
+
additionalKwargs,
|
|
1832
|
+
responseMetadata
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
/** Applies sealed-Responses safety and drops incomplete streamed text input. */
|
|
597
1837
|
export function projectToolStreamContentForProvider(
|
|
598
|
-
messages: BaseMessage[]
|
|
1838
|
+
messages: BaseMessage[],
|
|
1839
|
+
responsesReplayProjection?: ResponsesReplayProjection,
|
|
1840
|
+
maxChars = HARD_MAX_TOOL_RESULT_CHARS
|
|
599
1841
|
): BaseMessage[] {
|
|
600
1842
|
let projected: BaseMessage[] | undefined;
|
|
601
1843
|
for (let i = 0; i < messages.length; i++) {
|
|
602
1844
|
const message = messages[i];
|
|
603
|
-
if (message.getType() !== 'ai'
|
|
1845
|
+
if (message.getType() !== 'ai') {
|
|
604
1846
|
continue;
|
|
605
1847
|
}
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
return false;
|
|
620
|
-
}
|
|
621
|
-
if (type.value !== 'text') {
|
|
622
|
-
return true;
|
|
623
|
-
}
|
|
624
|
-
const text = Object.getOwnPropertyDescriptor(block, 'text');
|
|
625
|
-
return (
|
|
626
|
-
text?.enumerable === true &&
|
|
627
|
-
'value' in text &&
|
|
628
|
-
typeof text.value === 'string' &&
|
|
629
|
-
text.value !== ''
|
|
630
|
-
);
|
|
631
|
-
} catch {
|
|
632
|
-
return false;
|
|
1848
|
+
const assistantMessage = message as AIMessage;
|
|
1849
|
+
if (
|
|
1850
|
+
responsesReplayProjection != null &&
|
|
1851
|
+
isPreemptedOpenAIResponsesMessage(assistantMessage)
|
|
1852
|
+
) {
|
|
1853
|
+
const replaySafeMessage = projectPreemptedOpenAIResponsesMessage(
|
|
1854
|
+
assistantMessage,
|
|
1855
|
+
maxChars,
|
|
1856
|
+
responsesReplayProjection
|
|
1857
|
+
);
|
|
1858
|
+
if (replaySafeMessage !== assistantMessage) {
|
|
1859
|
+
projected ??= [...messages];
|
|
1860
|
+
projected[i] = replaySafeMessage;
|
|
633
1861
|
}
|
|
634
|
-
|
|
635
|
-
|
|
1862
|
+
continue;
|
|
1863
|
+
}
|
|
1864
|
+
if (!Array.isArray(assistantMessage.content)) {
|
|
1865
|
+
continue;
|
|
1866
|
+
}
|
|
1867
|
+
const content = assistantMessage.content.filter(
|
|
1868
|
+
isCompleteToolStreamContentBlock
|
|
1869
|
+
);
|
|
1870
|
+
if (content.length === assistantMessage.content.length) {
|
|
636
1871
|
continue;
|
|
637
1872
|
}
|
|
638
1873
|
projected ??= [...messages];
|
|
639
1874
|
projected[i] = cloneAIMessageWithContent(
|
|
640
|
-
|
|
1875
|
+
assistantMessage,
|
|
641
1876
|
toLangChainContent(content)
|
|
642
1877
|
);
|
|
643
1878
|
}
|
|
@@ -687,7 +1922,7 @@ function projectStructuredOpenAIToolContent(
|
|
|
687
1922
|
function projectOpenAIToolMessageContentInternal(
|
|
688
1923
|
messages: BaseMessage[],
|
|
689
1924
|
maxChars: number,
|
|
690
|
-
|
|
1925
|
+
nativeResponsesProjection: boolean,
|
|
691
1926
|
cacheControlledTextProjection: CacheControlledTextProjection
|
|
692
1927
|
): BaseMessage[] {
|
|
693
1928
|
const pendingComputerCallIds: string[] = [];
|
|
@@ -699,8 +1934,21 @@ function projectOpenAIToolMessageContentInternal(
|
|
|
699
1934
|
const isAssistant =
|
|
700
1935
|
message.getType() === 'ai' || messageRole === 'assistant';
|
|
701
1936
|
if (isAssistant) {
|
|
1937
|
+
let assistantMessage = message as AIMessage;
|
|
1938
|
+
if (nativeResponsesProjection) {
|
|
1939
|
+
const replaySafeMessage = projectPreemptedOpenAIResponsesMessage(
|
|
1940
|
+
assistantMessage,
|
|
1941
|
+
maxChars,
|
|
1942
|
+
'native'
|
|
1943
|
+
);
|
|
1944
|
+
if (replaySafeMessage !== assistantMessage) {
|
|
1945
|
+
projected ??= [...messages];
|
|
1946
|
+
projected[i] = replaySafeMessage;
|
|
1947
|
+
assistantMessage = replaySafeMessage;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
702
1950
|
const parsedComputerCallIds = new Set<string>();
|
|
703
|
-
const toolCalls =
|
|
1951
|
+
const toolCalls = assistantMessage.tool_calls;
|
|
704
1952
|
if (Array.isArray(toolCalls)) {
|
|
705
1953
|
for (const toolCall of toolCalls) {
|
|
706
1954
|
const record = toolCall as ToolCall & {
|
|
@@ -727,12 +1975,12 @@ function projectOpenAIToolMessageContentInternal(
|
|
|
727
1975
|
}
|
|
728
1976
|
|
|
729
1977
|
const rawOutput = (
|
|
730
|
-
|
|
1978
|
+
assistantMessage.response_metadata as {
|
|
731
1979
|
output?: unknown;
|
|
732
1980
|
}
|
|
733
1981
|
).output;
|
|
734
1982
|
const fallbackOutput = (
|
|
735
|
-
|
|
1983
|
+
assistantMessage.additional_kwargs as {
|
|
736
1984
|
tool_outputs?: unknown;
|
|
737
1985
|
}
|
|
738
1986
|
).tool_outputs;
|
|
@@ -775,7 +2023,7 @@ function projectOpenAIToolMessageContentInternal(
|
|
|
775
2023
|
}
|
|
776
2024
|
|
|
777
2025
|
if (
|
|
778
|
-
|
|
2026
|
+
nativeResponsesProjection &&
|
|
779
2027
|
Array.isArray(toolCalls) &&
|
|
780
2028
|
rawComputerCallIds.size > 0
|
|
781
2029
|
) {
|
|
@@ -794,7 +2042,7 @@ function projectOpenAIToolMessageContentInternal(
|
|
|
794
2042
|
if (projectedToolCalls.length !== toolCalls.length) {
|
|
795
2043
|
projected ??= [...messages];
|
|
796
2044
|
projected[i] = cloneAIMessageWithToolCalls(
|
|
797
|
-
|
|
2045
|
+
assistantMessage,
|
|
798
2046
|
projectedToolCalls,
|
|
799
2047
|
rawComputerCallIds
|
|
800
2048
|
);
|