@posthog/ai 6.1.1 → 6.2.0
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 +84 -4
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +84 -4
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +84 -29
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.d.ts +3 -21
- package/dist/gemini/index.mjs +84 -29
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +380 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -21
- package/dist/index.mjs +367 -55
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +6 -0
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +6 -0
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +93 -11
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +93 -11
- package/dist/openai/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +53 -3
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +53 -3
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -6,6 +6,8 @@ import { wrapLanguageModel } from 'ai';
|
|
|
6
6
|
import AnthropicOriginal from '@anthropic-ai/sdk';
|
|
7
7
|
import { GoogleGenAI } from '@google/genai';
|
|
8
8
|
|
|
9
|
+
var version = "6.2.0";
|
|
10
|
+
|
|
9
11
|
// limit large outputs by truncating to 200kb (approx 200k bytes)
|
|
10
12
|
const MAX_OUTPUT_SIZE = 200000;
|
|
11
13
|
const STRING_FORMAT = 'utf8';
|
|
@@ -238,9 +240,8 @@ const extractAvailableToolCalls = (provider, params) => {
|
|
|
238
240
|
}
|
|
239
241
|
return null;
|
|
240
242
|
} else if (provider === 'vercel') {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return params.mode.tools;
|
|
243
|
+
if (params.tools) {
|
|
244
|
+
return params.tools;
|
|
244
245
|
}
|
|
245
246
|
return null;
|
|
246
247
|
}
|
|
@@ -314,6 +315,8 @@ const sendEventToPosthog = async ({
|
|
|
314
315
|
} : {})
|
|
315
316
|
};
|
|
316
317
|
const properties = {
|
|
318
|
+
$ai_lib: 'posthog-ai',
|
|
319
|
+
$ai_lib_version: version,
|
|
317
320
|
$ai_provider: params.posthogProviderOverride ?? provider,
|
|
318
321
|
$ai_model: params.posthogModelOverride ?? model,
|
|
319
322
|
$ai_model_parameters: getModelParams(params),
|
|
@@ -595,14 +598,52 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
595
598
|
const [stream1, stream2] = value.tee();
|
|
596
599
|
(async () => {
|
|
597
600
|
try {
|
|
601
|
+
const contentBlocks = [];
|
|
598
602
|
let accumulatedContent = '';
|
|
599
603
|
let usage = {
|
|
600
604
|
inputTokens: 0,
|
|
601
605
|
outputTokens: 0
|
|
602
606
|
};
|
|
607
|
+
// Map to track in-progress tool calls
|
|
608
|
+
const toolCallsInProgress = new Map();
|
|
603
609
|
for await (const chunk of stream1) {
|
|
604
|
-
const
|
|
605
|
-
|
|
610
|
+
const choice = chunk?.choices?.[0];
|
|
611
|
+
// Handle text content
|
|
612
|
+
const deltaContent = choice?.delta?.content;
|
|
613
|
+
if (deltaContent) {
|
|
614
|
+
accumulatedContent += deltaContent;
|
|
615
|
+
}
|
|
616
|
+
// Handle tool calls
|
|
617
|
+
const deltaToolCalls = choice?.delta?.tool_calls;
|
|
618
|
+
if (deltaToolCalls && Array.isArray(deltaToolCalls)) {
|
|
619
|
+
for (const toolCall of deltaToolCalls) {
|
|
620
|
+
const index = toolCall.index;
|
|
621
|
+
if (index !== undefined) {
|
|
622
|
+
if (!toolCallsInProgress.has(index)) {
|
|
623
|
+
// New tool call
|
|
624
|
+
toolCallsInProgress.set(index, {
|
|
625
|
+
id: toolCall.id || '',
|
|
626
|
+
name: toolCall.function?.name || '',
|
|
627
|
+
arguments: ''
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
const inProgressCall = toolCallsInProgress.get(index);
|
|
631
|
+
if (inProgressCall) {
|
|
632
|
+
// Update tool call data
|
|
633
|
+
if (toolCall.id) {
|
|
634
|
+
inProgressCall.id = toolCall.id;
|
|
635
|
+
}
|
|
636
|
+
if (toolCall.function?.name) {
|
|
637
|
+
inProgressCall.name = toolCall.function.name;
|
|
638
|
+
}
|
|
639
|
+
if (toolCall.function?.arguments) {
|
|
640
|
+
inProgressCall.arguments += toolCall.function.arguments;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
// Handle usage information
|
|
606
647
|
if (chunk.usage) {
|
|
607
648
|
usage = {
|
|
608
649
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
@@ -612,6 +653,37 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
612
653
|
};
|
|
613
654
|
}
|
|
614
655
|
}
|
|
656
|
+
// Build final content blocks
|
|
657
|
+
if (accumulatedContent) {
|
|
658
|
+
contentBlocks.push({
|
|
659
|
+
type: 'text',
|
|
660
|
+
text: accumulatedContent
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
// Add completed tool calls to content blocks
|
|
664
|
+
for (const toolCall of toolCallsInProgress.values()) {
|
|
665
|
+
if (toolCall.name) {
|
|
666
|
+
contentBlocks.push({
|
|
667
|
+
type: 'function',
|
|
668
|
+
id: toolCall.id,
|
|
669
|
+
function: {
|
|
670
|
+
name: toolCall.name,
|
|
671
|
+
arguments: toolCall.arguments
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
// Format output to match non-streaming version
|
|
677
|
+
const formattedOutput = contentBlocks.length > 0 ? [{
|
|
678
|
+
role: 'assistant',
|
|
679
|
+
content: contentBlocks
|
|
680
|
+
}] : [{
|
|
681
|
+
role: 'assistant',
|
|
682
|
+
content: [{
|
|
683
|
+
type: 'text',
|
|
684
|
+
text: ''
|
|
685
|
+
}]
|
|
686
|
+
}];
|
|
615
687
|
const latency = (Date.now() - startTime) / 1000;
|
|
616
688
|
const availableTools = extractAvailableToolCalls('openai', openAIParams);
|
|
617
689
|
await sendEventToPosthog({
|
|
@@ -621,10 +693,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
621
693
|
model: openAIParams.model,
|
|
622
694
|
provider: 'openai',
|
|
623
695
|
input: sanitizeOpenAI(openAIParams.messages),
|
|
624
|
-
output:
|
|
625
|
-
content: accumulatedContent,
|
|
626
|
-
role: 'assistant'
|
|
627
|
-
}],
|
|
696
|
+
output: formattedOutput,
|
|
628
697
|
latency,
|
|
629
698
|
baseURL: this.baseURL ?? '',
|
|
630
699
|
params: body,
|
|
@@ -634,6 +703,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
634
703
|
captureImmediate: posthogCaptureImmediate
|
|
635
704
|
});
|
|
636
705
|
} catch (error) {
|
|
706
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
637
707
|
await sendEventToPosthog({
|
|
638
708
|
client: this.phClient,
|
|
639
709
|
distinctId: posthogDistinctId,
|
|
@@ -645,7 +715,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
645
715
|
latency: 0,
|
|
646
716
|
baseURL: this.baseURL ?? '',
|
|
647
717
|
params: body,
|
|
648
|
-
httpStatus
|
|
718
|
+
httpStatus,
|
|
649
719
|
usage: {
|
|
650
720
|
inputTokens: 0,
|
|
651
721
|
outputTokens: 0
|
|
@@ -690,6 +760,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
690
760
|
}
|
|
691
761
|
return result;
|
|
692
762
|
}, async error => {
|
|
763
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
693
764
|
await sendEventToPosthog({
|
|
694
765
|
client: this.phClient,
|
|
695
766
|
distinctId: posthogDistinctId,
|
|
@@ -701,7 +772,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
|
|
|
701
772
|
latency: 0,
|
|
702
773
|
baseURL: this.baseURL ?? '',
|
|
703
774
|
params: body,
|
|
704
|
-
httpStatus
|
|
775
|
+
httpStatus,
|
|
705
776
|
usage: {
|
|
706
777
|
inputTokens: 0,
|
|
707
778
|
outputTokens: 0
|
|
@@ -780,6 +851,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
780
851
|
captureImmediate: posthogCaptureImmediate
|
|
781
852
|
});
|
|
782
853
|
} catch (error) {
|
|
854
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
783
855
|
await sendEventToPosthog({
|
|
784
856
|
client: this.phClient,
|
|
785
857
|
distinctId: posthogDistinctId,
|
|
@@ -792,7 +864,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
792
864
|
latency: 0,
|
|
793
865
|
baseURL: this.baseURL ?? '',
|
|
794
866
|
params: body,
|
|
795
|
-
httpStatus
|
|
867
|
+
httpStatus,
|
|
796
868
|
usage: {
|
|
797
869
|
inputTokens: 0,
|
|
798
870
|
outputTokens: 0
|
|
@@ -839,6 +911,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
839
911
|
}
|
|
840
912
|
return result;
|
|
841
913
|
}, async error => {
|
|
914
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
842
915
|
await sendEventToPosthog({
|
|
843
916
|
client: this.phClient,
|
|
844
917
|
distinctId: posthogDistinctId,
|
|
@@ -851,7 +924,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
851
924
|
latency: 0,
|
|
852
925
|
baseURL: this.baseURL ?? '',
|
|
853
926
|
params: body,
|
|
854
|
-
httpStatus
|
|
927
|
+
httpStatus,
|
|
855
928
|
usage: {
|
|
856
929
|
inputTokens: 0,
|
|
857
930
|
outputTokens: 0
|
|
@@ -910,6 +983,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
910
983
|
});
|
|
911
984
|
return result;
|
|
912
985
|
}, async error => {
|
|
986
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
913
987
|
await sendEventToPosthog({
|
|
914
988
|
client: this.phClient,
|
|
915
989
|
distinctId: posthogDistinctId,
|
|
@@ -922,7 +996,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
|
|
|
922
996
|
latency: 0,
|
|
923
997
|
baseURL: this.baseURL ?? '',
|
|
924
998
|
params: body,
|
|
925
|
-
httpStatus
|
|
999
|
+
httpStatus,
|
|
926
1000
|
usage: {
|
|
927
1001
|
inputTokens: 0,
|
|
928
1002
|
outputTokens: 0
|
|
@@ -984,14 +1058,52 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
984
1058
|
const [stream1, stream2] = value.tee();
|
|
985
1059
|
(async () => {
|
|
986
1060
|
try {
|
|
1061
|
+
const contentBlocks = [];
|
|
987
1062
|
let accumulatedContent = '';
|
|
988
1063
|
let usage = {
|
|
989
1064
|
inputTokens: 0,
|
|
990
1065
|
outputTokens: 0
|
|
991
1066
|
};
|
|
1067
|
+
// Map to track in-progress tool calls
|
|
1068
|
+
const toolCallsInProgress = new Map();
|
|
992
1069
|
for await (const chunk of stream1) {
|
|
993
|
-
const
|
|
994
|
-
|
|
1070
|
+
const choice = chunk?.choices?.[0];
|
|
1071
|
+
// Handle text content
|
|
1072
|
+
const deltaContent = choice?.delta?.content;
|
|
1073
|
+
if (deltaContent) {
|
|
1074
|
+
accumulatedContent += deltaContent;
|
|
1075
|
+
}
|
|
1076
|
+
// Handle tool calls
|
|
1077
|
+
const deltaToolCalls = choice?.delta?.tool_calls;
|
|
1078
|
+
if (deltaToolCalls && Array.isArray(deltaToolCalls)) {
|
|
1079
|
+
for (const toolCall of deltaToolCalls) {
|
|
1080
|
+
const index = toolCall.index;
|
|
1081
|
+
if (index !== undefined) {
|
|
1082
|
+
if (!toolCallsInProgress.has(index)) {
|
|
1083
|
+
// New tool call
|
|
1084
|
+
toolCallsInProgress.set(index, {
|
|
1085
|
+
id: toolCall.id || '',
|
|
1086
|
+
name: toolCall.function?.name || '',
|
|
1087
|
+
arguments: ''
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
const inProgressCall = toolCallsInProgress.get(index);
|
|
1091
|
+
if (inProgressCall) {
|
|
1092
|
+
// Update tool call data
|
|
1093
|
+
if (toolCall.id) {
|
|
1094
|
+
inProgressCall.id = toolCall.id;
|
|
1095
|
+
}
|
|
1096
|
+
if (toolCall.function?.name) {
|
|
1097
|
+
inProgressCall.name = toolCall.function.name;
|
|
1098
|
+
}
|
|
1099
|
+
if (toolCall.function?.arguments) {
|
|
1100
|
+
inProgressCall.arguments += toolCall.function.arguments;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
// Handle usage information
|
|
995
1107
|
if (chunk.usage) {
|
|
996
1108
|
usage = {
|
|
997
1109
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
@@ -1001,6 +1113,37 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
1001
1113
|
};
|
|
1002
1114
|
}
|
|
1003
1115
|
}
|
|
1116
|
+
// Build final content blocks
|
|
1117
|
+
if (accumulatedContent) {
|
|
1118
|
+
contentBlocks.push({
|
|
1119
|
+
type: 'text',
|
|
1120
|
+
text: accumulatedContent
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
// Add completed tool calls to content blocks
|
|
1124
|
+
for (const toolCall of toolCallsInProgress.values()) {
|
|
1125
|
+
if (toolCall.name) {
|
|
1126
|
+
contentBlocks.push({
|
|
1127
|
+
type: 'function',
|
|
1128
|
+
id: toolCall.id,
|
|
1129
|
+
function: {
|
|
1130
|
+
name: toolCall.name,
|
|
1131
|
+
arguments: toolCall.arguments
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
// Format output to match non-streaming version
|
|
1137
|
+
const formattedOutput = contentBlocks.length > 0 ? [{
|
|
1138
|
+
role: 'assistant',
|
|
1139
|
+
content: contentBlocks
|
|
1140
|
+
}] : [{
|
|
1141
|
+
role: 'assistant',
|
|
1142
|
+
content: [{
|
|
1143
|
+
type: 'text',
|
|
1144
|
+
text: ''
|
|
1145
|
+
}]
|
|
1146
|
+
}];
|
|
1004
1147
|
const latency = (Date.now() - startTime) / 1000;
|
|
1005
1148
|
await sendEventToPosthog({
|
|
1006
1149
|
client: this.phClient,
|
|
@@ -1009,10 +1152,7 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
1009
1152
|
model: openAIParams.model,
|
|
1010
1153
|
provider: 'azure',
|
|
1011
1154
|
input: openAIParams.messages,
|
|
1012
|
-
output:
|
|
1013
|
-
content: accumulatedContent,
|
|
1014
|
-
role: 'assistant'
|
|
1015
|
-
}],
|
|
1155
|
+
output: formattedOutput,
|
|
1016
1156
|
latency,
|
|
1017
1157
|
baseURL: this.baseURL ?? '',
|
|
1018
1158
|
params: body,
|
|
@@ -1021,6 +1161,7 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
1021
1161
|
captureImmediate: posthogCaptureImmediate
|
|
1022
1162
|
});
|
|
1023
1163
|
} catch (error) {
|
|
1164
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1024
1165
|
await sendEventToPosthog({
|
|
1025
1166
|
client: this.phClient,
|
|
1026
1167
|
distinctId: posthogDistinctId,
|
|
@@ -1032,7 +1173,7 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
1032
1173
|
latency: 0,
|
|
1033
1174
|
baseURL: this.baseURL ?? '',
|
|
1034
1175
|
params: body,
|
|
1035
|
-
httpStatus
|
|
1176
|
+
httpStatus,
|
|
1036
1177
|
usage: {
|
|
1037
1178
|
inputTokens: 0,
|
|
1038
1179
|
outputTokens: 0
|
|
@@ -1075,6 +1216,7 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
1075
1216
|
}
|
|
1076
1217
|
return result;
|
|
1077
1218
|
}, async error => {
|
|
1219
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1078
1220
|
await sendEventToPosthog({
|
|
1079
1221
|
client: this.phClient,
|
|
1080
1222
|
distinctId: posthogDistinctId,
|
|
@@ -1086,7 +1228,7 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
1086
1228
|
latency: 0,
|
|
1087
1229
|
baseURL: this.baseURL ?? '',
|
|
1088
1230
|
params: body,
|
|
1089
|
-
httpStatus
|
|
1231
|
+
httpStatus,
|
|
1090
1232
|
usage: {
|
|
1091
1233
|
inputTokens: 0,
|
|
1092
1234
|
outputTokens: 0
|
|
@@ -1163,6 +1305,7 @@ class WrappedResponses extends AzureOpenAI.Responses {
|
|
|
1163
1305
|
captureImmediate: posthogCaptureImmediate
|
|
1164
1306
|
});
|
|
1165
1307
|
} catch (error) {
|
|
1308
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1166
1309
|
await sendEventToPosthog({
|
|
1167
1310
|
client: this.phClient,
|
|
1168
1311
|
distinctId: posthogDistinctId,
|
|
@@ -1175,7 +1318,7 @@ class WrappedResponses extends AzureOpenAI.Responses {
|
|
|
1175
1318
|
latency: 0,
|
|
1176
1319
|
baseURL: this.baseURL ?? '',
|
|
1177
1320
|
params: body,
|
|
1178
|
-
httpStatus
|
|
1321
|
+
httpStatus,
|
|
1179
1322
|
usage: {
|
|
1180
1323
|
inputTokens: 0,
|
|
1181
1324
|
outputTokens: 0
|
|
@@ -1218,6 +1361,7 @@ class WrappedResponses extends AzureOpenAI.Responses {
|
|
|
1218
1361
|
}
|
|
1219
1362
|
return result;
|
|
1220
1363
|
}, async error => {
|
|
1364
|
+
const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
|
|
1221
1365
|
await sendEventToPosthog({
|
|
1222
1366
|
client: this.phClient,
|
|
1223
1367
|
distinctId: posthogDistinctId,
|
|
@@ -1230,7 +1374,7 @@ class WrappedResponses extends AzureOpenAI.Responses {
|
|
|
1230
1374
|
latency: 0,
|
|
1231
1375
|
baseURL: this.baseURL ?? '',
|
|
1232
1376
|
params: body,
|
|
1233
|
-
httpStatus
|
|
1377
|
+
httpStatus,
|
|
1234
1378
|
usage: {
|
|
1235
1379
|
inputTokens: 0,
|
|
1236
1380
|
outputTokens: 0
|
|
@@ -1597,6 +1741,8 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
1597
1741
|
const provider = options.posthogProviderOverride ?? extractProvider(model);
|
|
1598
1742
|
const availableTools = extractAvailableToolCalls('vercel', params);
|
|
1599
1743
|
const baseURL = ''; // cannot currently get baseURL from vercel
|
|
1744
|
+
// Map to track in-progress tool calls
|
|
1745
|
+
const toolCallsInProgress = new Map();
|
|
1600
1746
|
try {
|
|
1601
1747
|
const {
|
|
1602
1748
|
stream,
|
|
@@ -1611,6 +1757,34 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
1611
1757
|
if (chunk.type === 'reasoning-delta') {
|
|
1612
1758
|
reasoningText += chunk.delta; // New in v5
|
|
1613
1759
|
}
|
|
1760
|
+
// Handle tool call chunks
|
|
1761
|
+
if (chunk.type === 'tool-input-start') {
|
|
1762
|
+
// Initialize a new tool call
|
|
1763
|
+
toolCallsInProgress.set(chunk.id, {
|
|
1764
|
+
toolCallId: chunk.id,
|
|
1765
|
+
toolName: chunk.toolName,
|
|
1766
|
+
input: ''
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
if (chunk.type === 'tool-input-delta') {
|
|
1770
|
+
// Accumulate tool call arguments
|
|
1771
|
+
const toolCall = toolCallsInProgress.get(chunk.id);
|
|
1772
|
+
if (toolCall) {
|
|
1773
|
+
toolCall.input += chunk.delta;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
if (chunk.type === 'tool-input-end') {
|
|
1777
|
+
// Tool call is complete, keep it in the map for final processing
|
|
1778
|
+
// Nothing specific to do here, the tool call is already complete
|
|
1779
|
+
}
|
|
1780
|
+
if (chunk.type === 'tool-call') {
|
|
1781
|
+
// Direct tool call chunk (complete tool call)
|
|
1782
|
+
toolCallsInProgress.set(chunk.toolCallId, {
|
|
1783
|
+
toolCallId: chunk.toolCallId,
|
|
1784
|
+
toolName: chunk.toolName,
|
|
1785
|
+
input: chunk.input
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1614
1788
|
if (chunk.type === 'finish') {
|
|
1615
1789
|
const providerMetadata = chunk.providerMetadata;
|
|
1616
1790
|
const additionalTokenValues = {
|
|
@@ -1644,6 +1818,19 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
1644
1818
|
text: truncate(generatedText)
|
|
1645
1819
|
});
|
|
1646
1820
|
}
|
|
1821
|
+
// Add completed tool calls to content
|
|
1822
|
+
for (const toolCall of toolCallsInProgress.values()) {
|
|
1823
|
+
if (toolCall.toolName) {
|
|
1824
|
+
content.push({
|
|
1825
|
+
type: 'tool-call',
|
|
1826
|
+
id: toolCall.toolCallId,
|
|
1827
|
+
function: {
|
|
1828
|
+
name: toolCall.toolName,
|
|
1829
|
+
arguments: toolCall.input
|
|
1830
|
+
}
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1647
1834
|
// Structure output like mapVercelOutput does
|
|
1648
1835
|
const output = content.length > 0 ? [{
|
|
1649
1836
|
role: 'assistant',
|
|
@@ -1746,6 +1933,9 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1746
1933
|
if (anthropicParams.stream) {
|
|
1747
1934
|
return parentPromise.then(value => {
|
|
1748
1935
|
let accumulatedContent = '';
|
|
1936
|
+
const contentBlocks = [];
|
|
1937
|
+
const toolsInProgress = new Map();
|
|
1938
|
+
let currentTextBlock = null;
|
|
1749
1939
|
const usage = {
|
|
1750
1940
|
inputTokens: 0,
|
|
1751
1941
|
outputTokens: 0,
|
|
@@ -1757,10 +1947,70 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1757
1947
|
(async () => {
|
|
1758
1948
|
try {
|
|
1759
1949
|
for await (const chunk of stream1) {
|
|
1950
|
+
// Handle content block start events
|
|
1951
|
+
if (chunk.type === 'content_block_start') {
|
|
1952
|
+
if (chunk.content_block?.type === 'text') {
|
|
1953
|
+
currentTextBlock = {
|
|
1954
|
+
type: 'text',
|
|
1955
|
+
text: ''
|
|
1956
|
+
};
|
|
1957
|
+
contentBlocks.push(currentTextBlock);
|
|
1958
|
+
} else if (chunk.content_block?.type === 'tool_use') {
|
|
1959
|
+
const toolBlock = {
|
|
1960
|
+
type: 'function',
|
|
1961
|
+
id: chunk.content_block.id,
|
|
1962
|
+
function: {
|
|
1963
|
+
name: chunk.content_block.name,
|
|
1964
|
+
arguments: {}
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1967
|
+
contentBlocks.push(toolBlock);
|
|
1968
|
+
toolsInProgress.set(chunk.content_block.id, {
|
|
1969
|
+
block: toolBlock,
|
|
1970
|
+
inputString: ''
|
|
1971
|
+
});
|
|
1972
|
+
currentTextBlock = null;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
// Handle text delta events
|
|
1760
1976
|
if ('delta' in chunk) {
|
|
1761
1977
|
if ('text' in chunk.delta) {
|
|
1762
1978
|
const delta = chunk?.delta?.text ?? '';
|
|
1763
1979
|
accumulatedContent += delta;
|
|
1980
|
+
if (currentTextBlock) {
|
|
1981
|
+
currentTextBlock.text += delta;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
// Handle tool input delta events
|
|
1986
|
+
if (chunk.type === 'content_block_delta' && chunk.delta?.type === 'input_json_delta') {
|
|
1987
|
+
const block = chunk.index !== undefined ? contentBlocks[chunk.index] : undefined;
|
|
1988
|
+
const toolId = block?.type === 'function' ? block.id : undefined;
|
|
1989
|
+
if (toolId && toolsInProgress.has(toolId)) {
|
|
1990
|
+
const tool = toolsInProgress.get(toolId);
|
|
1991
|
+
if (tool) {
|
|
1992
|
+
tool.inputString += chunk.delta.partial_json || '';
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
// Handle content block stop events
|
|
1997
|
+
if (chunk.type === 'content_block_stop') {
|
|
1998
|
+
currentTextBlock = null;
|
|
1999
|
+
// Parse accumulated tool input
|
|
2000
|
+
if (chunk.index !== undefined) {
|
|
2001
|
+
const block = contentBlocks[chunk.index];
|
|
2002
|
+
if (block?.type === 'function' && block.id && toolsInProgress.has(block.id)) {
|
|
2003
|
+
const tool = toolsInProgress.get(block.id);
|
|
2004
|
+
if (tool) {
|
|
2005
|
+
try {
|
|
2006
|
+
block.function.arguments = JSON.parse(tool.inputString);
|
|
2007
|
+
} catch (e) {
|
|
2008
|
+
// Keep empty object if parsing fails
|
|
2009
|
+
console.error('Error parsing tool input:', e);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
toolsInProgress.delete(block.id);
|
|
2013
|
+
}
|
|
1764
2014
|
}
|
|
1765
2015
|
}
|
|
1766
2016
|
if (chunk.type == 'message_start') {
|
|
@@ -1774,6 +2024,17 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1774
2024
|
}
|
|
1775
2025
|
const latency = (Date.now() - startTime) / 1000;
|
|
1776
2026
|
const availableTools = extractAvailableToolCalls('anthropic', anthropicParams);
|
|
2027
|
+
// Format output to match non-streaming version
|
|
2028
|
+
const formattedOutput = contentBlocks.length > 0 ? [{
|
|
2029
|
+
role: 'assistant',
|
|
2030
|
+
content: contentBlocks
|
|
2031
|
+
}] : [{
|
|
2032
|
+
role: 'assistant',
|
|
2033
|
+
content: [{
|
|
2034
|
+
type: 'text',
|
|
2035
|
+
text: accumulatedContent
|
|
2036
|
+
}]
|
|
2037
|
+
}];
|
|
1777
2038
|
await sendEventToPosthog({
|
|
1778
2039
|
client: this.phClient,
|
|
1779
2040
|
distinctId: posthogDistinctId,
|
|
@@ -1781,10 +2042,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1781
2042
|
model: anthropicParams.model,
|
|
1782
2043
|
provider: 'anthropic',
|
|
1783
2044
|
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),
|
|
1784
|
-
output:
|
|
1785
|
-
content: accumulatedContent,
|
|
1786
|
-
role: 'assistant'
|
|
1787
|
-
}],
|
|
2045
|
+
output: formattedOutput,
|
|
1788
2046
|
latency,
|
|
1789
2047
|
baseURL: this.baseURL ?? '',
|
|
1790
2048
|
params: body,
|
|
@@ -1909,6 +2167,7 @@ class WrappedModels {
|
|
|
1909
2167
|
const response = await this.client.models.generateContent(geminiParams);
|
|
1910
2168
|
const latency = (Date.now() - startTime) / 1000;
|
|
1911
2169
|
const availableTools = extractAvailableToolCalls('gemini', geminiParams);
|
|
2170
|
+
const metadata = response.usageMetadata;
|
|
1912
2171
|
await sendEventToPosthog({
|
|
1913
2172
|
client: this.phClient,
|
|
1914
2173
|
distinctId: posthogDistinctId,
|
|
@@ -1922,10 +2181,10 @@ class WrappedModels {
|
|
|
1922
2181
|
params: params,
|
|
1923
2182
|
httpStatus: 200,
|
|
1924
2183
|
usage: {
|
|
1925
|
-
inputTokens:
|
|
1926
|
-
outputTokens:
|
|
1927
|
-
reasoningTokens:
|
|
1928
|
-
cacheReadInputTokens:
|
|
2184
|
+
inputTokens: metadata?.promptTokenCount ?? 0,
|
|
2185
|
+
outputTokens: metadata?.candidatesTokenCount ?? 0,
|
|
2186
|
+
reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
|
|
2187
|
+
cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0
|
|
1929
2188
|
},
|
|
1930
2189
|
tools: availableTools,
|
|
1931
2190
|
captureImmediate: posthogCaptureImmediate
|
|
@@ -1967,7 +2226,7 @@ class WrappedModels {
|
|
|
1967
2226
|
} = params;
|
|
1968
2227
|
const traceId = posthogTraceId ?? v4();
|
|
1969
2228
|
const startTime = Date.now();
|
|
1970
|
-
|
|
2229
|
+
const accumulatedContent = [];
|
|
1971
2230
|
let usage = {
|
|
1972
2231
|
inputTokens: 0,
|
|
1973
2232
|
outputTokens: 0
|
|
@@ -1975,21 +2234,66 @@ class WrappedModels {
|
|
|
1975
2234
|
try {
|
|
1976
2235
|
const stream = await this.client.models.generateContentStream(geminiParams);
|
|
1977
2236
|
for await (const chunk of stream) {
|
|
2237
|
+
// Handle text content
|
|
1978
2238
|
if (chunk.text) {
|
|
1979
|
-
|
|
2239
|
+
// Find if we already have a text item to append to
|
|
2240
|
+
let lastTextItem;
|
|
2241
|
+
for (let i = accumulatedContent.length - 1; i >= 0; i--) {
|
|
2242
|
+
if (accumulatedContent[i].type === 'text') {
|
|
2243
|
+
lastTextItem = accumulatedContent[i];
|
|
2244
|
+
break;
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
if (lastTextItem && lastTextItem.type === 'text') {
|
|
2248
|
+
lastTextItem.text += chunk.text;
|
|
2249
|
+
} else {
|
|
2250
|
+
accumulatedContent.push({
|
|
2251
|
+
type: 'text',
|
|
2252
|
+
text: chunk.text
|
|
2253
|
+
});
|
|
2254
|
+
}
|
|
1980
2255
|
}
|
|
2256
|
+
// Handle function calls from candidates
|
|
2257
|
+
if (chunk.candidates && Array.isArray(chunk.candidates)) {
|
|
2258
|
+
for (const candidate of chunk.candidates) {
|
|
2259
|
+
if (candidate.content && candidate.content.parts) {
|
|
2260
|
+
for (const part of candidate.content.parts) {
|
|
2261
|
+
// Type-safe check for functionCall
|
|
2262
|
+
if ('functionCall' in part) {
|
|
2263
|
+
const funcCall = part.functionCall;
|
|
2264
|
+
if (funcCall?.name) {
|
|
2265
|
+
accumulatedContent.push({
|
|
2266
|
+
type: 'function',
|
|
2267
|
+
function: {
|
|
2268
|
+
name: funcCall.name,
|
|
2269
|
+
arguments: funcCall.args || {}
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
// Update usage metadata - handle both old and new field names
|
|
1981
2279
|
if (chunk.usageMetadata) {
|
|
2280
|
+
const metadata = chunk.usageMetadata;
|
|
1982
2281
|
usage = {
|
|
1983
|
-
inputTokens:
|
|
1984
|
-
outputTokens:
|
|
1985
|
-
reasoningTokens:
|
|
1986
|
-
cacheReadInputTokens:
|
|
2282
|
+
inputTokens: metadata.promptTokenCount ?? 0,
|
|
2283
|
+
outputTokens: metadata.candidatesTokenCount ?? 0,
|
|
2284
|
+
reasoningTokens: metadata.thoughtsTokenCount ?? 0,
|
|
2285
|
+
cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0
|
|
1987
2286
|
};
|
|
1988
2287
|
}
|
|
1989
2288
|
yield chunk;
|
|
1990
2289
|
}
|
|
1991
2290
|
const latency = (Date.now() - startTime) / 1000;
|
|
1992
2291
|
const availableTools = extractAvailableToolCalls('gemini', geminiParams);
|
|
2292
|
+
// Format output similar to formatResponseGemini
|
|
2293
|
+
const output = accumulatedContent.length > 0 ? [{
|
|
2294
|
+
role: 'assistant',
|
|
2295
|
+
content: accumulatedContent
|
|
2296
|
+
}] : [];
|
|
1993
2297
|
await sendEventToPosthog({
|
|
1994
2298
|
client: this.phClient,
|
|
1995
2299
|
distinctId: posthogDistinctId,
|
|
@@ -1997,10 +2301,7 @@ class WrappedModels {
|
|
|
1997
2301
|
model: geminiParams.model,
|
|
1998
2302
|
provider: 'gemini',
|
|
1999
2303
|
input: this.formatInputForPostHog(geminiParams.contents),
|
|
2000
|
-
output
|
|
2001
|
-
content: accumulatedContent,
|
|
2002
|
-
role: 'assistant'
|
|
2003
|
-
}],
|
|
2304
|
+
output,
|
|
2004
2305
|
latency,
|
|
2005
2306
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
2006
2307
|
params: params,
|
|
@@ -2050,22 +2351,28 @@ class WrappedModels {
|
|
|
2050
2351
|
};
|
|
2051
2352
|
}
|
|
2052
2353
|
if (item && typeof item === 'object') {
|
|
2053
|
-
|
|
2354
|
+
const obj = item;
|
|
2355
|
+
if ('text' in obj && obj.text) {
|
|
2054
2356
|
return {
|
|
2055
|
-
role:
|
|
2056
|
-
content:
|
|
2357
|
+
role: obj.role || 'user',
|
|
2358
|
+
content: obj.text
|
|
2057
2359
|
};
|
|
2058
2360
|
}
|
|
2059
|
-
if (
|
|
2361
|
+
if ('content' in obj && obj.content) {
|
|
2060
2362
|
return {
|
|
2061
|
-
role:
|
|
2062
|
-
content:
|
|
2363
|
+
role: obj.role || 'user',
|
|
2364
|
+
content: obj.content
|
|
2063
2365
|
};
|
|
2064
2366
|
}
|
|
2065
|
-
if (
|
|
2367
|
+
if ('parts' in obj && Array.isArray(obj.parts)) {
|
|
2066
2368
|
return {
|
|
2067
|
-
role:
|
|
2068
|
-
content:
|
|
2369
|
+
role: obj.role || 'user',
|
|
2370
|
+
content: obj.parts.map(part => {
|
|
2371
|
+
if (part && typeof part === 'object' && 'text' in part) {
|
|
2372
|
+
return part.text;
|
|
2373
|
+
}
|
|
2374
|
+
return part;
|
|
2375
|
+
})
|
|
2069
2376
|
};
|
|
2070
2377
|
}
|
|
2071
2378
|
}
|
|
@@ -2076,16 +2383,17 @@ class WrappedModels {
|
|
|
2076
2383
|
});
|
|
2077
2384
|
}
|
|
2078
2385
|
if (contents && typeof contents === 'object') {
|
|
2079
|
-
|
|
2386
|
+
const obj = contents;
|
|
2387
|
+
if ('text' in obj && obj.text) {
|
|
2080
2388
|
return [{
|
|
2081
2389
|
role: 'user',
|
|
2082
|
-
content:
|
|
2390
|
+
content: obj.text
|
|
2083
2391
|
}];
|
|
2084
2392
|
}
|
|
2085
|
-
if (
|
|
2393
|
+
if ('content' in obj && obj.content) {
|
|
2086
2394
|
return [{
|
|
2087
2395
|
role: 'user',
|
|
2088
|
-
content:
|
|
2396
|
+
content: obj.content
|
|
2089
2397
|
}];
|
|
2090
2398
|
}
|
|
2091
2399
|
}
|
|
@@ -2850,6 +3158,8 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
|
|
|
2850
3158
|
const eventName = parentRunId ? '$ai_span' : '$ai_trace';
|
|
2851
3159
|
const latency = run.endTime ? (run.endTime - run.startTime) / 1000 : 0;
|
|
2852
3160
|
const eventProperties = {
|
|
3161
|
+
$ai_lib: 'posthog-ai',
|
|
3162
|
+
$ai_lib_version: version,
|
|
2853
3163
|
$ai_trace_id: traceId,
|
|
2854
3164
|
$ai_input_state: withPrivacyMode(this.client, this.privacyMode, run.input),
|
|
2855
3165
|
$ai_latency: latency,
|
|
@@ -2890,6 +3200,8 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
|
|
|
2890
3200
|
_captureGeneration(traceId, runId, run, output, parentRunId) {
|
|
2891
3201
|
const latency = run.endTime ? (run.endTime - run.startTime) / 1000 : 0;
|
|
2892
3202
|
const eventProperties = {
|
|
3203
|
+
$ai_lib: 'posthog-ai',
|
|
3204
|
+
$ai_lib_version: version,
|
|
2893
3205
|
$ai_trace_id: traceId,
|
|
2894
3206
|
$ai_span_id: runId,
|
|
2895
3207
|
$ai_span_name: run.name,
|