@posthog/ai 6.1.1 → 6.1.2
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/anthropic/index.cjs +80 -4
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +80 -4
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +80 -29
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.d.ts +3 -21
- package/dist/gemini/index.mjs +80 -29
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +359 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -21
- package/dist/index.mjs +359 -55
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +89 -11
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +89 -11
- package/dist/openai/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +49 -3
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +49 -3
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -258,9 +258,8 @@ const extractAvailableToolCalls = (provider, params) => {
|
|
|
258
258
|
}
|
|
259
259
|
return null;
|
|
260
260
|
} else if (provider === 'vercel') {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return params.mode.tools;
|
|
261
|
+
if (params.tools) {
|
|
262
|
+
return params.tools;
|
|
264
263
|
}
|
|
265
264
|
return null;
|
|
266
265
|
}
|
|
@@ -615,14 +614,52 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
615
614
|
const [stream1, stream2] = value.tee();
|
|
616
615
|
(async () => {
|
|
617
616
|
try {
|
|
617
|
+
const contentBlocks = [];
|
|
618
618
|
let accumulatedContent = '';
|
|
619
619
|
let usage = {
|
|
620
620
|
inputTokens: 0,
|
|
621
621
|
outputTokens: 0
|
|
622
622
|
};
|
|
623
|
+
// Map to track in-progress tool calls
|
|
624
|
+
const toolCallsInProgress = new Map();
|
|
623
625
|
for await (const chunk of stream1) {
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
+
const choice = chunk?.choices?.[0];
|
|
627
|
+
// Handle text content
|
|
628
|
+
const deltaContent = choice?.delta?.content;
|
|
629
|
+
if (deltaContent) {
|
|
630
|
+
accumulatedContent += deltaContent;
|
|
631
|
+
}
|
|
632
|
+
// Handle tool calls
|
|
633
|
+
const deltaToolCalls = choice?.delta?.tool_calls;
|
|
634
|
+
if (deltaToolCalls && Array.isArray(deltaToolCalls)) {
|
|
635
|
+
for (const toolCall of deltaToolCalls) {
|
|
636
|
+
const index = toolCall.index;
|
|
637
|
+
if (index !== undefined) {
|
|
638
|
+
if (!toolCallsInProgress.has(index)) {
|
|
639
|
+
// New tool call
|
|
640
|
+
toolCallsInProgress.set(index, {
|
|
641
|
+
id: toolCall.id || '',
|
|
642
|
+
name: toolCall.function?.name || '',
|
|
643
|
+
arguments: ''
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
const inProgressCall = toolCallsInProgress.get(index);
|
|
647
|
+
if (inProgressCall) {
|
|
648
|
+
// Update tool call data
|
|
649
|
+
if (toolCall.id) {
|
|
650
|
+
inProgressCall.id = toolCall.id;
|
|
651
|
+
}
|
|
652
|
+
if (toolCall.function?.name) {
|
|
653
|
+
inProgressCall.name = toolCall.function.name;
|
|
654
|
+
}
|
|
655
|
+
if (toolCall.function?.arguments) {
|
|
656
|
+
inProgressCall.arguments += toolCall.function.arguments;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// Handle usage information
|
|
626
663
|
if (chunk.usage) {
|
|
627
664
|
usage = {
|
|
628
665
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
@@ -632,6 +669,37 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
632
669
|
};
|
|
633
670
|
}
|
|
634
671
|
}
|
|
672
|
+
// Build final content blocks
|
|
673
|
+
if (accumulatedContent) {
|
|
674
|
+
contentBlocks.push({
|
|
675
|
+
type: 'text',
|
|
676
|
+
text: accumulatedContent
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
// Add completed tool calls to content blocks
|
|
680
|
+
for (const toolCall of toolCallsInProgress.values()) {
|
|
681
|
+
if (toolCall.name) {
|
|
682
|
+
contentBlocks.push({
|
|
683
|
+
type: 'function',
|
|
684
|
+
id: toolCall.id,
|
|
685
|
+
function: {
|
|
686
|
+
name: toolCall.name,
|
|
687
|
+
arguments: toolCall.arguments
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
// Format output to match non-streaming version
|
|
693
|
+
const formattedOutput = contentBlocks.length > 0 ? [{
|
|
694
|
+
role: 'assistant',
|
|
695
|
+
content: contentBlocks
|
|
696
|
+
}] : [{
|
|
697
|
+
role: 'assistant',
|
|
698
|
+
content: [{
|
|
699
|
+
type: 'text',
|
|
700
|
+
text: ''
|
|
701
|
+
}]
|
|
702
|
+
}];
|
|
635
703
|
const latency = (Date.now() - startTime) / 1000;
|
|
636
704
|
const availableTools = extractAvailableToolCalls('openai', openAIParams);
|
|
637
705
|
await sendEventToPosthog({
|
|
@@ -641,10 +709,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
641
709
|
model: openAIParams.model,
|
|
642
710
|
provider: 'openai',
|
|
643
711
|
input: sanitizeOpenAI(openAIParams.messages),
|
|
644
|
-
output:
|
|
645
|
-
content: accumulatedContent,
|
|
646
|
-
role: 'assistant'
|
|
647
|
-
}],
|
|
712
|
+
output: formattedOutput,
|
|
648
713
|
latency,
|
|
649
714
|
baseURL: this.baseURL ?? '',
|
|
650
715
|
params: body,
|
|
@@ -654,6 +719,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
654
719
|
captureImmediate: posthogCaptureImmediate
|
|
655
720
|
});
|
|
656
721
|
} catch (error) {
|
|
722
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
657
723
|
await sendEventToPosthog({
|
|
658
724
|
client: this.phClient,
|
|
659
725
|
distinctId: posthogDistinctId,
|
|
@@ -665,7 +731,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
665
731
|
latency: 0,
|
|
666
732
|
baseURL: this.baseURL ?? '',
|
|
667
733
|
params: body,
|
|
668
|
-
httpStatus
|
|
734
|
+
httpStatus,
|
|
669
735
|
usage: {
|
|
670
736
|
inputTokens: 0,
|
|
671
737
|
outputTokens: 0
|
|
@@ -710,6 +776,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
710
776
|
}
|
|
711
777
|
return result;
|
|
712
778
|
}, async error => {
|
|
779
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
713
780
|
await sendEventToPosthog({
|
|
714
781
|
client: this.phClient,
|
|
715
782
|
distinctId: posthogDistinctId,
|
|
@@ -721,7 +788,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
721
788
|
latency: 0,
|
|
722
789
|
baseURL: this.baseURL ?? '',
|
|
723
790
|
params: body,
|
|
724
|
-
httpStatus
|
|
791
|
+
httpStatus,
|
|
725
792
|
usage: {
|
|
726
793
|
inputTokens: 0,
|
|
727
794
|
outputTokens: 0
|
|
@@ -800,6 +867,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
800
867
|
captureImmediate: posthogCaptureImmediate
|
|
801
868
|
});
|
|
802
869
|
} catch (error) {
|
|
870
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
803
871
|
await sendEventToPosthog({
|
|
804
872
|
client: this.phClient,
|
|
805
873
|
distinctId: posthogDistinctId,
|
|
@@ -812,7 +880,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
812
880
|
latency: 0,
|
|
813
881
|
baseURL: this.baseURL ?? '',
|
|
814
882
|
params: body,
|
|
815
|
-
httpStatus
|
|
883
|
+
httpStatus,
|
|
816
884
|
usage: {
|
|
817
885
|
inputTokens: 0,
|
|
818
886
|
outputTokens: 0
|
|
@@ -859,6 +927,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
859
927
|
}
|
|
860
928
|
return result;
|
|
861
929
|
}, async error => {
|
|
930
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
862
931
|
await sendEventToPosthog({
|
|
863
932
|
client: this.phClient,
|
|
864
933
|
distinctId: posthogDistinctId,
|
|
@@ -871,7 +940,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
871
940
|
latency: 0,
|
|
872
941
|
baseURL: this.baseURL ?? '',
|
|
873
942
|
params: body,
|
|
874
|
-
httpStatus
|
|
943
|
+
httpStatus,
|
|
875
944
|
usage: {
|
|
876
945
|
inputTokens: 0,
|
|
877
946
|
outputTokens: 0
|
|
@@ -930,6 +999,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
930
999
|
});
|
|
931
1000
|
return result;
|
|
932
1001
|
}, async error => {
|
|
1002
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
933
1003
|
await sendEventToPosthog({
|
|
934
1004
|
client: this.phClient,
|
|
935
1005
|
distinctId: posthogDistinctId,
|
|
@@ -942,7 +1012,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
942
1012
|
latency: 0,
|
|
943
1013
|
baseURL: this.baseURL ?? '',
|
|
944
1014
|
params: body,
|
|
945
|
-
httpStatus
|
|
1015
|
+
httpStatus,
|
|
946
1016
|
usage: {
|
|
947
1017
|
inputTokens: 0,
|
|
948
1018
|
outputTokens: 0
|
|
@@ -1004,14 +1074,52 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1004
1074
|
const [stream1, stream2] = value.tee();
|
|
1005
1075
|
(async () => {
|
|
1006
1076
|
try {
|
|
1077
|
+
const contentBlocks = [];
|
|
1007
1078
|
let accumulatedContent = '';
|
|
1008
1079
|
let usage = {
|
|
1009
1080
|
inputTokens: 0,
|
|
1010
1081
|
outputTokens: 0
|
|
1011
1082
|
};
|
|
1083
|
+
// Map to track in-progress tool calls
|
|
1084
|
+
const toolCallsInProgress = new Map();
|
|
1012
1085
|
for await (const chunk of stream1) {
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1086
|
+
const choice = chunk?.choices?.[0];
|
|
1087
|
+
// Handle text content
|
|
1088
|
+
const deltaContent = choice?.delta?.content;
|
|
1089
|
+
if (deltaContent) {
|
|
1090
|
+
accumulatedContent += deltaContent;
|
|
1091
|
+
}
|
|
1092
|
+
// Handle tool calls
|
|
1093
|
+
const deltaToolCalls = choice?.delta?.tool_calls;
|
|
1094
|
+
if (deltaToolCalls && Array.isArray(deltaToolCalls)) {
|
|
1095
|
+
for (const toolCall of deltaToolCalls) {
|
|
1096
|
+
const index = toolCall.index;
|
|
1097
|
+
if (index !== undefined) {
|
|
1098
|
+
if (!toolCallsInProgress.has(index)) {
|
|
1099
|
+
// New tool call
|
|
1100
|
+
toolCallsInProgress.set(index, {
|
|
1101
|
+
id: toolCall.id || '',
|
|
1102
|
+
name: toolCall.function?.name || '',
|
|
1103
|
+
arguments: ''
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
const inProgressCall = toolCallsInProgress.get(index);
|
|
1107
|
+
if (inProgressCall) {
|
|
1108
|
+
// Update tool call data
|
|
1109
|
+
if (toolCall.id) {
|
|
1110
|
+
inProgressCall.id = toolCall.id;
|
|
1111
|
+
}
|
|
1112
|
+
if (toolCall.function?.name) {
|
|
1113
|
+
inProgressCall.name = toolCall.function.name;
|
|
1114
|
+
}
|
|
1115
|
+
if (toolCall.function?.arguments) {
|
|
1116
|
+
inProgressCall.arguments += toolCall.function.arguments;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
// Handle usage information
|
|
1015
1123
|
if (chunk.usage) {
|
|
1016
1124
|
usage = {
|
|
1017
1125
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
@@ -1021,6 +1129,37 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1021
1129
|
};
|
|
1022
1130
|
}
|
|
1023
1131
|
}
|
|
1132
|
+
// Build final content blocks
|
|
1133
|
+
if (accumulatedContent) {
|
|
1134
|
+
contentBlocks.push({
|
|
1135
|
+
type: 'text',
|
|
1136
|
+
text: accumulatedContent
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
// Add completed tool calls to content blocks
|
|
1140
|
+
for (const toolCall of toolCallsInProgress.values()) {
|
|
1141
|
+
if (toolCall.name) {
|
|
1142
|
+
contentBlocks.push({
|
|
1143
|
+
type: 'function',
|
|
1144
|
+
id: toolCall.id,
|
|
1145
|
+
function: {
|
|
1146
|
+
name: toolCall.name,
|
|
1147
|
+
arguments: toolCall.arguments
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
// Format output to match non-streaming version
|
|
1153
|
+
const formattedOutput = contentBlocks.length > 0 ? [{
|
|
1154
|
+
role: 'assistant',
|
|
1155
|
+
content: contentBlocks
|
|
1156
|
+
}] : [{
|
|
1157
|
+
role: 'assistant',
|
|
1158
|
+
content: [{
|
|
1159
|
+
type: 'text',
|
|
1160
|
+
text: ''
|
|
1161
|
+
}]
|
|
1162
|
+
}];
|
|
1024
1163
|
const latency = (Date.now() - startTime) / 1000;
|
|
1025
1164
|
await sendEventToPosthog({
|
|
1026
1165
|
client: this.phClient,
|
|
@@ -1029,10 +1168,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1029
1168
|
model: openAIParams.model,
|
|
1030
1169
|
provider: 'azure',
|
|
1031
1170
|
input: openAIParams.messages,
|
|
1032
|
-
output:
|
|
1033
|
-
content: accumulatedContent,
|
|
1034
|
-
role: 'assistant'
|
|
1035
|
-
}],
|
|
1171
|
+
output: formattedOutput,
|
|
1036
1172
|
latency,
|
|
1037
1173
|
baseURL: this.baseURL ?? '',
|
|
1038
1174
|
params: body,
|
|
@@ -1041,6 +1177,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1041
1177
|
captureImmediate: posthogCaptureImmediate
|
|
1042
1178
|
});
|
|
1043
1179
|
} catch (error) {
|
|
1180
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1044
1181
|
await sendEventToPosthog({
|
|
1045
1182
|
client: this.phClient,
|
|
1046
1183
|
distinctId: posthogDistinctId,
|
|
@@ -1052,7 +1189,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1052
1189
|
latency: 0,
|
|
1053
1190
|
baseURL: this.baseURL ?? '',
|
|
1054
1191
|
params: body,
|
|
1055
|
-
httpStatus
|
|
1192
|
+
httpStatus,
|
|
1056
1193
|
usage: {
|
|
1057
1194
|
inputTokens: 0,
|
|
1058
1195
|
outputTokens: 0
|
|
@@ -1095,6 +1232,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1095
1232
|
}
|
|
1096
1233
|
return result;
|
|
1097
1234
|
}, async error => {
|
|
1235
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1098
1236
|
await sendEventToPosthog({
|
|
1099
1237
|
client: this.phClient,
|
|
1100
1238
|
distinctId: posthogDistinctId,
|
|
@@ -1106,7 +1244,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
|
|
|
1106
1244
|
latency: 0,
|
|
1107
1245
|
baseURL: this.baseURL ?? '',
|
|
1108
1246
|
params: body,
|
|
1109
|
-
httpStatus
|
|
1247
|
+
httpStatus,
|
|
1110
1248
|
usage: {
|
|
1111
1249
|
inputTokens: 0,
|
|
1112
1250
|
outputTokens: 0
|
|
@@ -1183,6 +1321,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
|
|
|
1183
1321
|
captureImmediate: posthogCaptureImmediate
|
|
1184
1322
|
});
|
|
1185
1323
|
} catch (error) {
|
|
1324
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1186
1325
|
await sendEventToPosthog({
|
|
1187
1326
|
client: this.phClient,
|
|
1188
1327
|
distinctId: posthogDistinctId,
|
|
@@ -1195,7 +1334,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
|
|
|
1195
1334
|
latency: 0,
|
|
1196
1335
|
baseURL: this.baseURL ?? '',
|
|
1197
1336
|
params: body,
|
|
1198
|
-
httpStatus
|
|
1337
|
+
httpStatus,
|
|
1199
1338
|
usage: {
|
|
1200
1339
|
inputTokens: 0,
|
|
1201
1340
|
outputTokens: 0
|
|
@@ -1238,6 +1377,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
|
|
|
1238
1377
|
}
|
|
1239
1378
|
return result;
|
|
1240
1379
|
}, async error => {
|
|
1380
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1241
1381
|
await sendEventToPosthog({
|
|
1242
1382
|
client: this.phClient,
|
|
1243
1383
|
distinctId: posthogDistinctId,
|
|
@@ -1250,7 +1390,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
|
|
|
1250
1390
|
latency: 0,
|
|
1251
1391
|
baseURL: this.baseURL ?? '',
|
|
1252
1392
|
params: body,
|
|
1253
|
-
httpStatus
|
|
1393
|
+
httpStatus,
|
|
1254
1394
|
usage: {
|
|
1255
1395
|
inputTokens: 0,
|
|
1256
1396
|
outputTokens: 0
|
|
@@ -1617,6 +1757,8 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
1617
1757
|
const provider = options.posthogProviderOverride ?? extractProvider(model);
|
|
1618
1758
|
const availableTools = extractAvailableToolCalls('vercel', params);
|
|
1619
1759
|
const baseURL = ''; // cannot currently get baseURL from vercel
|
|
1760
|
+
// Map to track in-progress tool calls
|
|
1761
|
+
const toolCallsInProgress = new Map();
|
|
1620
1762
|
try {
|
|
1621
1763
|
const {
|
|
1622
1764
|
stream,
|
|
@@ -1631,6 +1773,34 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
1631
1773
|
if (chunk.type === 'reasoning-delta') {
|
|
1632
1774
|
reasoningText += chunk.delta; // New in v5
|
|
1633
1775
|
}
|
|
1776
|
+
// Handle tool call chunks
|
|
1777
|
+
if (chunk.type === 'tool-input-start') {
|
|
1778
|
+
// Initialize a new tool call
|
|
1779
|
+
toolCallsInProgress.set(chunk.id, {
|
|
1780
|
+
toolCallId: chunk.id,
|
|
1781
|
+
toolName: chunk.toolName,
|
|
1782
|
+
input: ''
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
if (chunk.type === 'tool-input-delta') {
|
|
1786
|
+
// Accumulate tool call arguments
|
|
1787
|
+
const toolCall = toolCallsInProgress.get(chunk.id);
|
|
1788
|
+
if (toolCall) {
|
|
1789
|
+
toolCall.input += chunk.delta;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
if (chunk.type === 'tool-input-end') {
|
|
1793
|
+
// Tool call is complete, keep it in the map for final processing
|
|
1794
|
+
// Nothing specific to do here, the tool call is already complete
|
|
1795
|
+
}
|
|
1796
|
+
if (chunk.type === 'tool-call') {
|
|
1797
|
+
// Direct tool call chunk (complete tool call)
|
|
1798
|
+
toolCallsInProgress.set(chunk.toolCallId, {
|
|
1799
|
+
toolCallId: chunk.toolCallId,
|
|
1800
|
+
toolName: chunk.toolName,
|
|
1801
|
+
input: chunk.input
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1634
1804
|
if (chunk.type === 'finish') {
|
|
1635
1805
|
const providerMetadata = chunk.providerMetadata;
|
|
1636
1806
|
const additionalTokenValues = {
|
|
@@ -1664,6 +1834,19 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
1664
1834
|
text: truncate(generatedText)
|
|
1665
1835
|
});
|
|
1666
1836
|
}
|
|
1837
|
+
// Add completed tool calls to content
|
|
1838
|
+
for (const toolCall of toolCallsInProgress.values()) {
|
|
1839
|
+
if (toolCall.toolName) {
|
|
1840
|
+
content.push({
|
|
1841
|
+
type: 'tool-call',
|
|
1842
|
+
id: toolCall.toolCallId,
|
|
1843
|
+
function: {
|
|
1844
|
+
name: toolCall.toolName,
|
|
1845
|
+
arguments: toolCall.input
|
|
1846
|
+
}
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1667
1850
|
// Structure output like mapVercelOutput does
|
|
1668
1851
|
const output = content.length > 0 ? [{
|
|
1669
1852
|
role: 'assistant',
|
|
@@ -1766,6 +1949,9 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1766
1949
|
if (anthropicParams.stream) {
|
|
1767
1950
|
return parentPromise.then(value => {
|
|
1768
1951
|
let accumulatedContent = '';
|
|
1952
|
+
const contentBlocks = [];
|
|
1953
|
+
const toolsInProgress = new Map();
|
|
1954
|
+
let currentTextBlock = null;
|
|
1769
1955
|
const usage = {
|
|
1770
1956
|
inputTokens: 0,
|
|
1771
1957
|
outputTokens: 0,
|
|
@@ -1777,10 +1963,70 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1777
1963
|
(async () => {
|
|
1778
1964
|
try {
|
|
1779
1965
|
for await (const chunk of stream1) {
|
|
1966
|
+
// Handle content block start events
|
|
1967
|
+
if (chunk.type === 'content_block_start') {
|
|
1968
|
+
if (chunk.content_block?.type === 'text') {
|
|
1969
|
+
currentTextBlock = {
|
|
1970
|
+
type: 'text',
|
|
1971
|
+
text: ''
|
|
1972
|
+
};
|
|
1973
|
+
contentBlocks.push(currentTextBlock);
|
|
1974
|
+
} else if (chunk.content_block?.type === 'tool_use') {
|
|
1975
|
+
const toolBlock = {
|
|
1976
|
+
type: 'function',
|
|
1977
|
+
id: chunk.content_block.id,
|
|
1978
|
+
function: {
|
|
1979
|
+
name: chunk.content_block.name,
|
|
1980
|
+
arguments: {}
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
contentBlocks.push(toolBlock);
|
|
1984
|
+
toolsInProgress.set(chunk.content_block.id, {
|
|
1985
|
+
block: toolBlock,
|
|
1986
|
+
inputString: ''
|
|
1987
|
+
});
|
|
1988
|
+
currentTextBlock = null;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
// Handle text delta events
|
|
1780
1992
|
if ('delta' in chunk) {
|
|
1781
1993
|
if ('text' in chunk.delta) {
|
|
1782
1994
|
const delta = chunk?.delta?.text ?? '';
|
|
1783
1995
|
accumulatedContent += delta;
|
|
1996
|
+
if (currentTextBlock) {
|
|
1997
|
+
currentTextBlock.text += delta;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
// Handle tool input delta events
|
|
2002
|
+
if (chunk.type === 'content_block_delta' && chunk.delta?.type === 'input_json_delta') {
|
|
2003
|
+
const block = chunk.index !== undefined ? contentBlocks[chunk.index] : undefined;
|
|
2004
|
+
const toolId = block?.type === 'function' ? block.id : undefined;
|
|
2005
|
+
if (toolId && toolsInProgress.has(toolId)) {
|
|
2006
|
+
const tool = toolsInProgress.get(toolId);
|
|
2007
|
+
if (tool) {
|
|
2008
|
+
tool.inputString += chunk.delta.partial_json || '';
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
// Handle content block stop events
|
|
2013
|
+
if (chunk.type === 'content_block_stop') {
|
|
2014
|
+
currentTextBlock = null;
|
|
2015
|
+
// Parse accumulated tool input
|
|
2016
|
+
if (chunk.index !== undefined) {
|
|
2017
|
+
const block = contentBlocks[chunk.index];
|
|
2018
|
+
if (block?.type === 'function' && block.id && toolsInProgress.has(block.id)) {
|
|
2019
|
+
const tool = toolsInProgress.get(block.id);
|
|
2020
|
+
if (tool) {
|
|
2021
|
+
try {
|
|
2022
|
+
block.function.arguments = JSON.parse(tool.inputString);
|
|
2023
|
+
} catch (e) {
|
|
2024
|
+
// Keep empty object if parsing fails
|
|
2025
|
+
console.error('Error parsing tool input:', e);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
toolsInProgress.delete(block.id);
|
|
2029
|
+
}
|
|
1784
2030
|
}
|
|
1785
2031
|
}
|
|
1786
2032
|
if (chunk.type == 'message_start') {
|
|
@@ -1794,6 +2040,17 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1794
2040
|
}
|
|
1795
2041
|
const latency = (Date.now() - startTime) / 1000;
|
|
1796
2042
|
const availableTools = extractAvailableToolCalls('anthropic', anthropicParams);
|
|
2043
|
+
// Format output to match non-streaming version
|
|
2044
|
+
const formattedOutput = contentBlocks.length > 0 ? [{
|
|
2045
|
+
role: 'assistant',
|
|
2046
|
+
content: contentBlocks
|
|
2047
|
+
}] : [{
|
|
2048
|
+
role: 'assistant',
|
|
2049
|
+
content: [{
|
|
2050
|
+
type: 'text',
|
|
2051
|
+
text: accumulatedContent
|
|
2052
|
+
}]
|
|
2053
|
+
}];
|
|
1797
2054
|
await sendEventToPosthog({
|
|
1798
2055
|
client: this.phClient,
|
|
1799
2056
|
distinctId: posthogDistinctId,
|
|
@@ -1801,10 +2058,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1801
2058
|
model: anthropicParams.model,
|
|
1802
2059
|
provider: 'anthropic',
|
|
1803
2060
|
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),
|
|
1804
|
-
output:
|
|
1805
|
-
content: accumulatedContent,
|
|
1806
|
-
role: 'assistant'
|
|
1807
|
-
}],
|
|
2061
|
+
output: formattedOutput,
|
|
1808
2062
|
latency,
|
|
1809
2063
|
baseURL: this.baseURL ?? '',
|
|
1810
2064
|
params: body,
|
|
@@ -1929,6 +2183,7 @@ class WrappedModels {
|
|
|
1929
2183
|
const response = await this.client.models.generateContent(geminiParams);
|
|
1930
2184
|
const latency = (Date.now() - startTime) / 1000;
|
|
1931
2185
|
const availableTools = extractAvailableToolCalls('gemini', geminiParams);
|
|
2186
|
+
const metadata = response.usageMetadata;
|
|
1932
2187
|
await sendEventToPosthog({
|
|
1933
2188
|
client: this.phClient,
|
|
1934
2189
|
distinctId: posthogDistinctId,
|
|
@@ -1942,10 +2197,10 @@ class WrappedModels {
|
|
|
1942
2197
|
params: params,
|
|
1943
2198
|
httpStatus: 200,
|
|
1944
2199
|
usage: {
|
|
1945
|
-
inputTokens:
|
|
1946
|
-
outputTokens:
|
|
1947
|
-
reasoningTokens:
|
|
1948
|
-
cacheReadInputTokens:
|
|
2200
|
+
inputTokens: metadata?.promptTokenCount ?? 0,
|
|
2201
|
+
outputTokens: metadata?.candidatesTokenCount ?? 0,
|
|
2202
|
+
reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
|
|
2203
|
+
cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0
|
|
1949
2204
|
},
|
|
1950
2205
|
tools: availableTools,
|
|
1951
2206
|
captureImmediate: posthogCaptureImmediate
|
|
@@ -1987,7 +2242,7 @@ class WrappedModels {
|
|
|
1987
2242
|
} = params;
|
|
1988
2243
|
const traceId = posthogTraceId ?? uuid.v4();
|
|
1989
2244
|
const startTime = Date.now();
|
|
1990
|
-
|
|
2245
|
+
const accumulatedContent = [];
|
|
1991
2246
|
let usage = {
|
|
1992
2247
|
inputTokens: 0,
|
|
1993
2248
|
outputTokens: 0
|
|
@@ -1995,21 +2250,66 @@ class WrappedModels {
|
|
|
1995
2250
|
try {
|
|
1996
2251
|
const stream = await this.client.models.generateContentStream(geminiParams);
|
|
1997
2252
|
for await (const chunk of stream) {
|
|
2253
|
+
// Handle text content
|
|
1998
2254
|
if (chunk.text) {
|
|
1999
|
-
|
|
2255
|
+
// Find if we already have a text item to append to
|
|
2256
|
+
let lastTextItem;
|
|
2257
|
+
for (let i = accumulatedContent.length - 1; i >= 0; i--) {
|
|
2258
|
+
if (accumulatedContent[i].type === 'text') {
|
|
2259
|
+
lastTextItem = accumulatedContent[i];
|
|
2260
|
+
break;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
if (lastTextItem && lastTextItem.type === 'text') {
|
|
2264
|
+
lastTextItem.text += chunk.text;
|
|
2265
|
+
} else {
|
|
2266
|
+
accumulatedContent.push({
|
|
2267
|
+
type: 'text',
|
|
2268
|
+
text: chunk.text
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2000
2271
|
}
|
|
2272
|
+
// Handle function calls from candidates
|
|
2273
|
+
if (chunk.candidates && Array.isArray(chunk.candidates)) {
|
|
2274
|
+
for (const candidate of chunk.candidates) {
|
|
2275
|
+
if (candidate.content && candidate.content.parts) {
|
|
2276
|
+
for (const part of candidate.content.parts) {
|
|
2277
|
+
// Type-safe check for functionCall
|
|
2278
|
+
if ('functionCall' in part) {
|
|
2279
|
+
const funcCall = part.functionCall;
|
|
2280
|
+
if (funcCall?.name) {
|
|
2281
|
+
accumulatedContent.push({
|
|
2282
|
+
type: 'function',
|
|
2283
|
+
function: {
|
|
2284
|
+
name: funcCall.name,
|
|
2285
|
+
arguments: funcCall.args || {}
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
// Update usage metadata - handle both old and new field names
|
|
2001
2295
|
if (chunk.usageMetadata) {
|
|
2296
|
+
const metadata = chunk.usageMetadata;
|
|
2002
2297
|
usage = {
|
|
2003
|
-
inputTokens:
|
|
2004
|
-
outputTokens:
|
|
2005
|
-
reasoningTokens:
|
|
2006
|
-
cacheReadInputTokens:
|
|
2298
|
+
inputTokens: metadata.promptTokenCount ?? 0,
|
|
2299
|
+
outputTokens: metadata.candidatesTokenCount ?? 0,
|
|
2300
|
+
reasoningTokens: metadata.thoughtsTokenCount ?? 0,
|
|
2301
|
+
cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0
|
|
2007
2302
|
};
|
|
2008
2303
|
}
|
|
2009
2304
|
yield chunk;
|
|
2010
2305
|
}
|
|
2011
2306
|
const latency = (Date.now() - startTime) / 1000;
|
|
2012
2307
|
const availableTools = extractAvailableToolCalls('gemini', geminiParams);
|
|
2308
|
+
// Format output similar to formatResponseGemini
|
|
2309
|
+
const output = accumulatedContent.length > 0 ? [{
|
|
2310
|
+
role: 'assistant',
|
|
2311
|
+
content: accumulatedContent
|
|
2312
|
+
}] : [];
|
|
2013
2313
|
await sendEventToPosthog({
|
|
2014
2314
|
client: this.phClient,
|
|
2015
2315
|
distinctId: posthogDistinctId,
|
|
@@ -2017,10 +2317,7 @@ class WrappedModels {
|
|
|
2017
2317
|
model: geminiParams.model,
|
|
2018
2318
|
provider: 'gemini',
|
|
2019
2319
|
input: this.formatInputForPostHog(geminiParams.contents),
|
|
2020
|
-
output
|
|
2021
|
-
content: accumulatedContent,
|
|
2022
|
-
role: 'assistant'
|
|
2023
|
-
}],
|
|
2320
|
+
output,
|
|
2024
2321
|
latency,
|
|
2025
2322
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
2026
2323
|
params: params,
|
|
@@ -2070,22 +2367,28 @@ class WrappedModels {
|
|
|
2070
2367
|
};
|
|
2071
2368
|
}
|
|
2072
2369
|
if (item && typeof item === 'object') {
|
|
2073
|
-
|
|
2370
|
+
const obj = item;
|
|
2371
|
+
if ('text' in obj && obj.text) {
|
|
2074
2372
|
return {
|
|
2075
|
-
role:
|
|
2076
|
-
content:
|
|
2373
|
+
role: obj.role || 'user',
|
|
2374
|
+
content: obj.text
|
|
2077
2375
|
};
|
|
2078
2376
|
}
|
|
2079
|
-
if (
|
|
2377
|
+
if ('content' in obj && obj.content) {
|
|
2080
2378
|
return {
|
|
2081
|
-
role:
|
|
2082
|
-
content:
|
|
2379
|
+
role: obj.role || 'user',
|
|
2380
|
+
content: obj.content
|
|
2083
2381
|
};
|
|
2084
2382
|
}
|
|
2085
|
-
if (
|
|
2383
|
+
if ('parts' in obj && Array.isArray(obj.parts)) {
|
|
2086
2384
|
return {
|
|
2087
|
-
role:
|
|
2088
|
-
content:
|
|
2385
|
+
role: obj.role || 'user',
|
|
2386
|
+
content: obj.parts.map(part => {
|
|
2387
|
+
if (part && typeof part === 'object' && 'text' in part) {
|
|
2388
|
+
return part.text;
|
|
2389
|
+
}
|
|
2390
|
+
return part;
|
|
2391
|
+
})
|
|
2089
2392
|
};
|
|
2090
2393
|
}
|
|
2091
2394
|
}
|
|
@@ -2096,16 +2399,17 @@ class WrappedModels {
|
|
|
2096
2399
|
});
|
|
2097
2400
|
}
|
|
2098
2401
|
if (contents && typeof contents === 'object') {
|
|
2099
|
-
|
|
2402
|
+
const obj = contents;
|
|
2403
|
+
if ('text' in obj && obj.text) {
|
|
2100
2404
|
return [{
|
|
2101
2405
|
role: 'user',
|
|
2102
|
-
content:
|
|
2406
|
+
content: obj.text
|
|
2103
2407
|
}];
|
|
2104
2408
|
}
|
|
2105
|
-
if (
|
|
2409
|
+
if ('content' in obj && obj.content) {
|
|
2106
2410
|
return [{
|
|
2107
2411
|
role: 'user',
|
|
2108
|
-
content:
|
|
2412
|
+
content: obj.content
|
|
2109
2413
|
}];
|
|
2110
2414
|
}
|
|
2111
2415
|
}
|