@effect/ai-openrouter 4.0.0-beta.6 → 4.0.0-beta.8
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/Generated.d.ts +170 -91
- package/dist/Generated.d.ts.map +1 -1
- package/dist/Generated.js +61 -32
- package/dist/Generated.js.map +1 -1
- package/dist/OpenRouterLanguageModel.d.ts +8 -0
- package/dist/OpenRouterLanguageModel.d.ts.map +1 -1
- package/dist/OpenRouterLanguageModel.js +221 -228
- package/dist/OpenRouterLanguageModel.js.map +1 -1
- package/package.json +3 -3
- package/src/Generated.ts +124 -54
- package/src/OpenRouterLanguageModel.ts +216 -224
|
@@ -20,6 +20,7 @@ declare const Config_base: ServiceMap.ServiceClass<Config, "@effect/ai-openroute
|
|
|
20
20
|
readonly top_logprobs?: number | null;
|
|
21
21
|
readonly seed?: number | null;
|
|
22
22
|
readonly stop?: string | readonly string[] | null;
|
|
23
|
+
readonly parallel_tool_calls?: boolean | null;
|
|
23
24
|
readonly reasoning?: {
|
|
24
25
|
readonly effort?: "high" | "low" | "medium" | "none" | "xhigh" | "minimal" | null;
|
|
25
26
|
readonly summary?: "auto" | "concise" | "detailed" | null;
|
|
@@ -82,6 +83,13 @@ declare const Config_base: ServiceMap.ServiceClass<Config, "@effect/ai-openroute
|
|
|
82
83
|
})[];
|
|
83
84
|
readonly route?: "sort" | "fallback" | null;
|
|
84
85
|
readonly session_id?: string;
|
|
86
|
+
readonly trace?: {
|
|
87
|
+
readonly trace_id?: string;
|
|
88
|
+
readonly trace_name?: string;
|
|
89
|
+
readonly span_name?: string;
|
|
90
|
+
readonly generation_name?: string;
|
|
91
|
+
readonly parent_span_id?: string;
|
|
92
|
+
};
|
|
85
93
|
readonly models?: readonly string[];
|
|
86
94
|
readonly image_config?: {};
|
|
87
95
|
readonly modalities?: readonly ("text" | "image")[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenRouterLanguageModel.d.ts","sourceRoot":"","sources":["../src/OpenRouterLanguageModel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAO/C,OAAO,KAAK,aAAa,MAAM,kCAAkC,CAAA;AACjE,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAA;AAQnD,OAAO,KAAK,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAEhD,OAAO,EAAuC,gBAAgB,EAAE,MAAM,uBAAuB,CAAA
|
|
1
|
+
{"version":3,"file":"OpenRouterLanguageModel.d.ts","sourceRoot":"","sources":["../src/OpenRouterLanguageModel.ts"],"names":[],"mappings":"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"}
|
|
@@ -636,267 +636,260 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
636
636
|
usage.outputTokens = computed.outputTokens;
|
|
637
637
|
}
|
|
638
638
|
const choice = event.choices[0];
|
|
639
|
-
if (Predicate.
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
activeReasoningId = openRouterResponseId ?? (yield* idGenerator.generateId());
|
|
639
|
+
if (Predicate.isNotUndefined(choice)) {
|
|
640
|
+
if (Predicate.isNotNullish(choice.finish_reason)) {
|
|
641
|
+
finishReason = resolveFinishReason(choice.finish_reason);
|
|
642
|
+
}
|
|
643
|
+
const delta = choice.delta;
|
|
644
|
+
if (Predicate.isNullish(delta)) {
|
|
645
|
+
return parts;
|
|
646
|
+
}
|
|
647
|
+
const emitReasoning = Effect.fnUntraced(function* (delta, metadata) {
|
|
648
|
+
if (!reasoningStarted) {
|
|
649
|
+
activeReasoningId = openRouterResponseId ?? (yield* idGenerator.generateId());
|
|
650
|
+
parts.push({
|
|
651
|
+
type: "reasoning-start",
|
|
652
|
+
id: activeReasoningId,
|
|
653
|
+
metadata
|
|
654
|
+
});
|
|
655
|
+
reasoningStarted = true;
|
|
656
|
+
}
|
|
658
657
|
parts.push({
|
|
659
|
-
type: "reasoning-
|
|
658
|
+
type: "reasoning-delta",
|
|
660
659
|
id: activeReasoningId,
|
|
660
|
+
delta,
|
|
661
661
|
metadata
|
|
662
662
|
});
|
|
663
|
-
reasoningStarted = true;
|
|
664
|
-
}
|
|
665
|
-
parts.push({
|
|
666
|
-
type: "reasoning-delta",
|
|
667
|
-
id: activeReasoningId,
|
|
668
|
-
delta,
|
|
669
|
-
metadata
|
|
670
663
|
});
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
664
|
+
const reasoningDetails = delta.reasoning_details;
|
|
665
|
+
if (Predicate.isNotUndefined(reasoningDetails) && reasoningDetails.length > 0) {
|
|
666
|
+
// Accumulate reasoning_details to preserve for multi-turn conversations
|
|
667
|
+
// Merge consecutive reasoning.text items into a single entry
|
|
668
|
+
for (const detail of reasoningDetails) {
|
|
669
|
+
if (detail.type === "reasoning.text") {
|
|
670
|
+
const lastDetail = accumulatedReasoningDetails[accumulatedReasoningDetails.length - 1];
|
|
671
|
+
if (Predicate.isNotUndefined(lastDetail) && lastDetail.type === "reasoning.text") {
|
|
672
|
+
// Merge with the previous text detail
|
|
673
|
+
lastDetail.text = (lastDetail.text ?? "") + (detail.text ?? "");
|
|
674
|
+
lastDetail.signature = lastDetail.signature ?? detail.signature ?? null;
|
|
675
|
+
lastDetail.format = lastDetail.format ?? detail.format ?? null;
|
|
676
|
+
} else {
|
|
677
|
+
// Start a new text detail
|
|
678
|
+
accumulatedReasoningDetails.push({
|
|
679
|
+
...detail
|
|
680
|
+
});
|
|
681
|
+
}
|
|
684
682
|
} else {
|
|
685
|
-
//
|
|
686
|
-
accumulatedReasoningDetails.push(
|
|
687
|
-
...detail
|
|
688
|
-
});
|
|
683
|
+
// Non-text details (encrypted, summary) are pushed as-is
|
|
684
|
+
accumulatedReasoningDetails.push(detail);
|
|
689
685
|
}
|
|
690
|
-
} else {
|
|
691
|
-
// Non-text details (encrypted, summary) are pushed as-is
|
|
692
|
-
accumulatedReasoningDetails.push(detail);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
// Emit reasoning_details in providerMetadata for each delta chunk
|
|
696
|
-
// so users can accumulate them on their end before sending back
|
|
697
|
-
const metadata = {
|
|
698
|
-
openrouter: {
|
|
699
|
-
reasoningDetails
|
|
700
686
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
687
|
+
// Emit reasoning_details in providerMetadata for each delta chunk
|
|
688
|
+
// so users can accumulate them on their end before sending back
|
|
689
|
+
const metadata = {
|
|
690
|
+
openrouter: {
|
|
691
|
+
reasoningDetails
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
for (const detail of reasoningDetails) {
|
|
695
|
+
switch (detail.type) {
|
|
696
|
+
case "reasoning.text":
|
|
697
|
+
{
|
|
698
|
+
if (Predicate.isNotNullish(detail.text)) {
|
|
699
|
+
yield* emitReasoning(detail.text, metadata);
|
|
700
|
+
}
|
|
701
|
+
break;
|
|
708
702
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
703
|
+
case "reasoning.summary":
|
|
704
|
+
{
|
|
705
|
+
if (Predicate.isNotNullish(detail.summary)) {
|
|
706
|
+
yield* emitReasoning(detail.summary, metadata);
|
|
707
|
+
}
|
|
708
|
+
break;
|
|
715
709
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
710
|
+
case "reasoning.encrypted":
|
|
711
|
+
{
|
|
712
|
+
if (Predicate.isNotNullish(detail.data)) {
|
|
713
|
+
yield* emitReasoning("[REDACTED]", metadata);
|
|
714
|
+
}
|
|
715
|
+
break;
|
|
722
716
|
}
|
|
723
|
-
|
|
724
|
-
}
|
|
717
|
+
}
|
|
725
718
|
}
|
|
719
|
+
} else if (Predicate.isNotNullish(delta.reasoning)) {
|
|
720
|
+
yield* emitReasoning(delta.reasoning);
|
|
726
721
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
// If reasoning was previously active and now we're starting text content,
|
|
733
|
-
// we should end the reasoning first to maintain proper order
|
|
734
|
-
if (reasoningStarted && !textStarted) {
|
|
735
|
-
parts.push({
|
|
736
|
-
type: "reasoning-end",
|
|
737
|
-
id: activeReasoningId,
|
|
738
|
-
// Include accumulated reasoning_details so the we can update the
|
|
739
|
-
// reasoning part's provider metadata with the correct signature.
|
|
740
|
-
// The signature typically arrives in the last reasoning delta,
|
|
741
|
-
// but reasoning-start only carries the first delta's metadata.
|
|
742
|
-
metadata: accumulatedReasoningDetails.length > 0 ? {
|
|
743
|
-
openRouter: {
|
|
744
|
-
reasoningDetails: accumulatedReasoningDetails
|
|
745
|
-
}
|
|
746
|
-
} : undefined
|
|
747
|
-
});
|
|
748
|
-
reasoningStarted = false;
|
|
749
|
-
}
|
|
750
|
-
if (!textStarted) {
|
|
751
|
-
activeTextId = openRouterResponseId ?? (yield* idGenerator.generateId());
|
|
752
|
-
parts.push({
|
|
753
|
-
type: "text-start",
|
|
754
|
-
id: activeTextId
|
|
755
|
-
});
|
|
756
|
-
textStarted = true;
|
|
757
|
-
}
|
|
758
|
-
parts.push({
|
|
759
|
-
type: "text-delta",
|
|
760
|
-
id: activeTextId,
|
|
761
|
-
delta: content
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
const annotations = delta.annotations;
|
|
765
|
-
if (Predicate.isNotNullish(annotations)) {
|
|
766
|
-
for (const annotation of annotations) {
|
|
767
|
-
if (annotation.type === "url_citation") {
|
|
722
|
+
const content = delta.content;
|
|
723
|
+
if (Predicate.isNotNullish(content)) {
|
|
724
|
+
// If reasoning was previously active and now we're starting text content,
|
|
725
|
+
// we should end the reasoning first to maintain proper order
|
|
726
|
+
if (reasoningStarted && !textStarted) {
|
|
768
727
|
parts.push({
|
|
769
|
-
type: "
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
metadata
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
} : undefined),
|
|
779
|
-
...(Predicate.isNotUndefined(annotation.url_citation.start_index) ? {
|
|
780
|
-
startIndex: annotation.url_citation.start_index
|
|
781
|
-
} : undefined),
|
|
782
|
-
...(Predicate.isNotUndefined(annotation.url_citation.end_index) ? {
|
|
783
|
-
startIndex: annotation.url_citation.end_index
|
|
784
|
-
} : undefined)
|
|
728
|
+
type: "reasoning-end",
|
|
729
|
+
id: activeReasoningId,
|
|
730
|
+
// Include accumulated reasoning_details so the we can update the
|
|
731
|
+
// reasoning part's provider metadata with the correct signature.
|
|
732
|
+
// The signature typically arrives in the last reasoning delta,
|
|
733
|
+
// but reasoning-start only carries the first delta's metadata.
|
|
734
|
+
metadata: accumulatedReasoningDetails.length > 0 ? {
|
|
735
|
+
openRouter: {
|
|
736
|
+
reasoningDetails: accumulatedReasoningDetails
|
|
785
737
|
}
|
|
786
|
-
}
|
|
738
|
+
} : undefined
|
|
739
|
+
});
|
|
740
|
+
reasoningStarted = false;
|
|
741
|
+
}
|
|
742
|
+
if (!textStarted) {
|
|
743
|
+
activeTextId = openRouterResponseId ?? (yield* idGenerator.generateId());
|
|
744
|
+
parts.push({
|
|
745
|
+
type: "text-start",
|
|
746
|
+
id: activeTextId
|
|
787
747
|
});
|
|
788
|
-
|
|
789
|
-
accumulatedFileAnnotations.push(annotation);
|
|
748
|
+
textStarted = true;
|
|
790
749
|
}
|
|
750
|
+
parts.push({
|
|
751
|
+
type: "text-delta",
|
|
752
|
+
id: activeTextId,
|
|
753
|
+
delta: content
|
|
754
|
+
});
|
|
791
755
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
description: "Received tool call delta without a tool call identifier"
|
|
816
|
-
})
|
|
756
|
+
const annotations = delta.annotations;
|
|
757
|
+
if (Predicate.isNotNullish(annotations)) {
|
|
758
|
+
for (const annotation of annotations) {
|
|
759
|
+
if (annotation.type === "url_citation") {
|
|
760
|
+
parts.push({
|
|
761
|
+
type: "source",
|
|
762
|
+
sourceType: "url",
|
|
763
|
+
id: annotation.url_citation.url,
|
|
764
|
+
url: annotation.url_citation.url,
|
|
765
|
+
title: annotation.url_citation.title ?? "",
|
|
766
|
+
metadata: {
|
|
767
|
+
openrouter: {
|
|
768
|
+
...(Predicate.isNotUndefined(annotation.url_citation.content) ? {
|
|
769
|
+
content: annotation.url_citation.content
|
|
770
|
+
} : undefined),
|
|
771
|
+
...(Predicate.isNotUndefined(annotation.url_citation.start_index) ? {
|
|
772
|
+
startIndex: annotation.url_citation.start_index
|
|
773
|
+
} : undefined),
|
|
774
|
+
...(Predicate.isNotUndefined(annotation.url_citation.end_index) ? {
|
|
775
|
+
startIndex: annotation.url_citation.end_index
|
|
776
|
+
} : undefined)
|
|
777
|
+
}
|
|
778
|
+
}
|
|
817
779
|
});
|
|
780
|
+
} else if (annotation.type === "file") {
|
|
781
|
+
accumulatedFileAnnotations.push(annotation);
|
|
818
782
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
const toolCalls = delta.tool_calls;
|
|
786
|
+
if (Predicate.isNotNullish(toolCalls)) {
|
|
787
|
+
for (const toolCall of toolCalls) {
|
|
788
|
+
const index = toolCall.index ?? toolCalls.length - 1;
|
|
789
|
+
let activeToolCall = activeToolCalls[index];
|
|
790
|
+
// Tool call start - OpenRouter returns all information except the
|
|
791
|
+
// tool call parameters in the first chunk
|
|
792
|
+
if (Predicate.isUndefined(activeToolCall)) {
|
|
793
|
+
if (toolCall.type !== "function") {
|
|
794
|
+
return yield* AiError.make({
|
|
795
|
+
module: "OpenRouterLanguageModel",
|
|
796
|
+
method: "makeStreamResponse",
|
|
797
|
+
reason: new AiError.InvalidOutputError({
|
|
798
|
+
description: "Received tool call delta that was not of type: 'function'"
|
|
799
|
+
})
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
if (Predicate.isNullish(toolCall.id)) {
|
|
803
|
+
return yield* AiError.make({
|
|
804
|
+
module: "OpenRouterLanguageModel",
|
|
805
|
+
method: "makeStreamResponse",
|
|
806
|
+
reason: new AiError.InvalidOutputError({
|
|
807
|
+
description: "Received tool call delta without a tool call identifier"
|
|
808
|
+
})
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
if (Predicate.isNullish(toolCall.function?.name)) {
|
|
812
|
+
return yield* AiError.make({
|
|
813
|
+
module: "OpenRouterLanguageModel",
|
|
814
|
+
method: "makeStreamResponse",
|
|
815
|
+
reason: new AiError.InvalidOutputError({
|
|
816
|
+
description: "Received tool call delta without a tool call name"
|
|
817
|
+
})
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
activeToolCall = {
|
|
821
|
+
id: toolCall.id,
|
|
822
|
+
type: "function",
|
|
823
|
+
name: toolCall.function.name,
|
|
824
|
+
params: toolCall.function.arguments ?? ""
|
|
825
|
+
};
|
|
826
|
+
activeToolCalls[index] = activeToolCall;
|
|
827
|
+
parts.push({
|
|
828
|
+
type: "tool-params-start",
|
|
829
|
+
id: activeToolCall.id,
|
|
830
|
+
name: activeToolCall.name
|
|
826
831
|
});
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
});
|
|
840
|
-
// Emit a tool call delta part if parameters were also sent
|
|
841
|
-
if (activeToolCall.params.length > 0) {
|
|
832
|
+
// Emit a tool call delta part if parameters were also sent
|
|
833
|
+
if (activeToolCall.params.length > 0) {
|
|
834
|
+
parts.push({
|
|
835
|
+
type: "tool-params-delta",
|
|
836
|
+
id: activeToolCall.id,
|
|
837
|
+
delta: activeToolCall.params
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
} else {
|
|
841
|
+
// If an active tool call was found, update and emit the delta for
|
|
842
|
+
// the tool call's parameters
|
|
843
|
+
activeToolCall.params += toolCall.function?.arguments ?? "";
|
|
842
844
|
parts.push({
|
|
843
845
|
type: "tool-params-delta",
|
|
844
846
|
id: activeToolCall.id,
|
|
845
847
|
delta: activeToolCall.params
|
|
846
848
|
});
|
|
847
849
|
}
|
|
848
|
-
|
|
849
|
-
//
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
850
|
+
// Check if the tool call is complete
|
|
851
|
+
// @effect-diagnostics-next-line tryCatchInEffectGen:off
|
|
852
|
+
try {
|
|
853
|
+
const params = Tool.unsafeSecureJsonParse(activeToolCall.params);
|
|
854
|
+
parts.push({
|
|
855
|
+
type: "tool-params-end",
|
|
856
|
+
id: activeToolCall.id
|
|
857
|
+
});
|
|
858
|
+
parts.push({
|
|
859
|
+
type: "tool-call",
|
|
860
|
+
id: activeToolCall.id,
|
|
861
|
+
name: activeToolCall.name,
|
|
862
|
+
params,
|
|
863
|
+
// Only attach reasoning_details to the first tool call to avoid
|
|
864
|
+
// duplicating thinking blocks for parallel tool calls (Claude)
|
|
865
|
+
metadata: reasoningDetailsAttachedToToolCall ? undefined : {
|
|
866
|
+
openrouter: {
|
|
867
|
+
reasoningDetails: accumulatedReasoningDetails
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
reasoningDetailsAttachedToToolCall = true;
|
|
872
|
+
// Increment the total tool calls emitted by the stream and
|
|
873
|
+
// remove the active tool call
|
|
874
|
+
totalToolCalls += 1;
|
|
875
|
+
delete activeToolCalls[toolCall.index];
|
|
876
|
+
} catch {
|
|
877
|
+
// Tool call incomplete, continue parsing
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
857
880
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
881
|
+
}
|
|
882
|
+
const images = delta.images;
|
|
883
|
+
if (Predicate.isNotNullish(images)) {
|
|
884
|
+
for (const image of images) {
|
|
862
885
|
parts.push({
|
|
863
|
-
type: "
|
|
864
|
-
|
|
886
|
+
type: "file",
|
|
887
|
+
mediaType: getMediaType(image.image_url.url, "image/jpeg"),
|
|
888
|
+
data: getBase64FromDataUrl(image.image_url.url)
|
|
865
889
|
});
|
|
866
|
-
parts.push({
|
|
867
|
-
type: "tool-call",
|
|
868
|
-
id: activeToolCall.id,
|
|
869
|
-
name: activeToolCall.name,
|
|
870
|
-
params,
|
|
871
|
-
// Only attach reasoning_details to the first tool call to avoid
|
|
872
|
-
// duplicating thinking blocks for parallel tool calls (Claude)
|
|
873
|
-
metadata: reasoningDetailsAttachedToToolCall ? undefined : {
|
|
874
|
-
openrouter: {
|
|
875
|
-
reasoningDetails: accumulatedReasoningDetails
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
});
|
|
879
|
-
reasoningDetailsAttachedToToolCall = true;
|
|
880
|
-
// Increment the total tool calls emitted by the stream and
|
|
881
|
-
// remove the active tool call
|
|
882
|
-
totalToolCalls += 1;
|
|
883
|
-
delete activeToolCalls[toolCall.index];
|
|
884
|
-
} catch {
|
|
885
|
-
// Tool call incomplete, continue parsing
|
|
886
|
-
continue;
|
|
887
890
|
}
|
|
888
891
|
}
|
|
889
892
|
}
|
|
890
|
-
const images = delta.images;
|
|
891
|
-
if (Predicate.isNotNullish(images)) {
|
|
892
|
-
for (const image of images) {
|
|
893
|
-
parts.push({
|
|
894
|
-
type: "file",
|
|
895
|
-
mediaType: getMediaType(image.image_url.url, "image/jpeg"),
|
|
896
|
-
data: getBase64FromDataUrl(image.image_url.url)
|
|
897
|
-
});
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
893
|
// Usage is only emitted by the last part of the stream, so we need to
|
|
901
894
|
// handle flushing any remaining text / reasoning / tool calls
|
|
902
895
|
if (Predicate.isNotUndefined(event.usage)) {
|