@posthog/ai 6.5.0 → 6.6.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 +13 -3
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +13 -3
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +74 -5
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.mjs +74 -5
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +306 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +306 -28
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +48 -1
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +48 -1
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +151 -15
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.mjs +151 -15
- package/dist/openai/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +156 -8
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +156 -8
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/openai/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { OpenAI } from 'openai';
|
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
3
|
import { v4 } from 'uuid';
|
|
4
4
|
|
|
5
|
-
var version = "6.
|
|
5
|
+
var version = "6.6.0";
|
|
6
6
|
|
|
7
7
|
// Type guards for safer type checking
|
|
8
8
|
|
|
@@ -147,6 +147,109 @@ const withPrivacyMode = (client, privacyMode, input) => {
|
|
|
147
147
|
return client.privacy_mode || privacyMode ? null : input;
|
|
148
148
|
};
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Calculate web search count from raw API response.
|
|
152
|
+
*
|
|
153
|
+
* Uses a two-tier detection strategy:
|
|
154
|
+
* Priority 1 (Exact Count): Count actual web search calls when available
|
|
155
|
+
* Priority 2 (Binary Detection): Return 1 if web search indicators are present, 0 otherwise
|
|
156
|
+
*
|
|
157
|
+
* @param result - Raw API response from any provider (OpenAI, Perplexity, OpenRouter, Gemini, etc.)
|
|
158
|
+
* @returns Number of web searches performed (exact count or binary 1/0)
|
|
159
|
+
*/
|
|
160
|
+
function calculateWebSearchCount(result) {
|
|
161
|
+
if (!result || typeof result !== 'object') {
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Priority 1: Exact Count
|
|
166
|
+
// Check for OpenAI Responses API web_search_call items
|
|
167
|
+
if ('output' in result && Array.isArray(result.output)) {
|
|
168
|
+
let count = 0;
|
|
169
|
+
for (const item of result.output) {
|
|
170
|
+
if (typeof item === 'object' && item !== null && 'type' in item && item.type === 'web_search_call') {
|
|
171
|
+
count++;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (count > 0) {
|
|
175
|
+
return count;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Priority 2: Binary Detection (1 or 0)
|
|
180
|
+
|
|
181
|
+
// Check for citations at root level (Perplexity)
|
|
182
|
+
if ('citations' in result && Array.isArray(result.citations) && result.citations.length > 0) {
|
|
183
|
+
return 1;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check for search_results at root level (Perplexity via OpenRouter)
|
|
187
|
+
if ('search_results' in result && Array.isArray(result.search_results) && result.search_results.length > 0) {
|
|
188
|
+
return 1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check for usage.search_context_size (Perplexity via OpenRouter)
|
|
192
|
+
if ('usage' in result && typeof result.usage === 'object' && result.usage !== null) {
|
|
193
|
+
if ('search_context_size' in result.usage && result.usage.search_context_size) {
|
|
194
|
+
return 1;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check for annotations with url_citation in choices[].message (OpenAI/Perplexity)
|
|
199
|
+
if ('choices' in result && Array.isArray(result.choices)) {
|
|
200
|
+
for (const choice of result.choices) {
|
|
201
|
+
if (typeof choice === 'object' && choice !== null && 'message' in choice) {
|
|
202
|
+
const message = choice.message;
|
|
203
|
+
if (typeof message === 'object' && message !== null && 'annotations' in message) {
|
|
204
|
+
const annotations = message.annotations;
|
|
205
|
+
if (Array.isArray(annotations)) {
|
|
206
|
+
const hasUrlCitation = annotations.some(ann => {
|
|
207
|
+
return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
|
|
208
|
+
});
|
|
209
|
+
if (hasUrlCitation) {
|
|
210
|
+
return 1;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Check for annotations in output[].content[] (OpenAI Responses API)
|
|
219
|
+
if ('output' in result && Array.isArray(result.output)) {
|
|
220
|
+
for (const item of result.output) {
|
|
221
|
+
if (typeof item === 'object' && item !== null && 'content' in item) {
|
|
222
|
+
const content = item.content;
|
|
223
|
+
if (Array.isArray(content)) {
|
|
224
|
+
for (const contentItem of content) {
|
|
225
|
+
if (typeof contentItem === 'object' && contentItem !== null && 'annotations' in contentItem) {
|
|
226
|
+
const annotations = contentItem.annotations;
|
|
227
|
+
if (Array.isArray(annotations)) {
|
|
228
|
+
const hasUrlCitation = annotations.some(ann => {
|
|
229
|
+
return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
|
|
230
|
+
});
|
|
231
|
+
if (hasUrlCitation) {
|
|
232
|
+
return 1;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Check for grounding_metadata (Gemini)
|
|
243
|
+
if ('candidates' in result && Array.isArray(result.candidates)) {
|
|
244
|
+
for (const candidate of result.candidates) {
|
|
245
|
+
if (typeof candidate === 'object' && candidate !== null && 'grounding_metadata' in candidate && candidate.grounding_metadata) {
|
|
246
|
+
return 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
150
253
|
/**
|
|
151
254
|
* Extract available tool calls from the request parameters.
|
|
152
255
|
* These are the tools provided to the LLM, not the tool calls in the response.
|
|
@@ -265,6 +368,9 @@ const sendEventToPosthog = async ({
|
|
|
265
368
|
} : {}),
|
|
266
369
|
...(usage.cacheCreationInputTokens ? {
|
|
267
370
|
$ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
|
|
371
|
+
} : {}),
|
|
372
|
+
...(usage.webSearchCount ? {
|
|
373
|
+
$ai_web_search_count: usage.webSearchCount
|
|
268
374
|
} : {})
|
|
269
375
|
};
|
|
270
376
|
const properties = {
|
|
@@ -506,13 +612,18 @@ class WrappedCompletions extends Completions {
|
|
|
506
612
|
let accumulatedContent = '';
|
|
507
613
|
let usage = {
|
|
508
614
|
inputTokens: 0,
|
|
509
|
-
outputTokens: 0
|
|
615
|
+
outputTokens: 0,
|
|
616
|
+
webSearchCount: 0
|
|
510
617
|
};
|
|
511
618
|
|
|
512
619
|
// Map to track in-progress tool calls
|
|
513
620
|
const toolCallsInProgress = new Map();
|
|
514
621
|
for await (const chunk of stream1) {
|
|
515
622
|
const choice = chunk?.choices?.[0];
|
|
623
|
+
const chunkWebSearchCount = calculateWebSearchCount(chunk);
|
|
624
|
+
if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
|
|
625
|
+
usage.webSearchCount = chunkWebSearchCount;
|
|
626
|
+
}
|
|
516
627
|
|
|
517
628
|
// Handle text content
|
|
518
629
|
const deltaContent = choice?.delta?.content;
|
|
@@ -554,6 +665,7 @@ class WrappedCompletions extends Completions {
|
|
|
554
665
|
// Handle usage information
|
|
555
666
|
if (chunk.usage) {
|
|
556
667
|
usage = {
|
|
668
|
+
...usage,
|
|
557
669
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
558
670
|
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
559
671
|
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
@@ -608,7 +720,13 @@ class WrappedCompletions extends Completions {
|
|
|
608
720
|
baseURL: this.baseURL,
|
|
609
721
|
params: body,
|
|
610
722
|
httpStatus: 200,
|
|
611
|
-
usage
|
|
723
|
+
usage: {
|
|
724
|
+
inputTokens: usage.inputTokens,
|
|
725
|
+
outputTokens: usage.outputTokens,
|
|
726
|
+
reasoningTokens: usage.reasoningTokens,
|
|
727
|
+
cacheReadInputTokens: usage.cacheReadInputTokens,
|
|
728
|
+
webSearchCount: usage.webSearchCount
|
|
729
|
+
},
|
|
612
730
|
tools: availableTools
|
|
613
731
|
});
|
|
614
732
|
} catch (error) {
|
|
@@ -644,13 +762,14 @@ class WrappedCompletions extends Completions {
|
|
|
644
762
|
if ('choices' in result) {
|
|
645
763
|
const latency = (Date.now() - startTime) / 1000;
|
|
646
764
|
const availableTools = extractAvailableToolCalls('openai', openAIParams);
|
|
765
|
+
const formattedOutput = formatResponseOpenAI(result);
|
|
647
766
|
await sendEventToPosthog({
|
|
648
767
|
client: this.phClient,
|
|
649
768
|
...posthogParams,
|
|
650
769
|
model: openAIParams.model,
|
|
651
770
|
provider: 'openai',
|
|
652
771
|
input: sanitizeOpenAI(openAIParams.messages),
|
|
653
|
-
output:
|
|
772
|
+
output: formattedOutput,
|
|
654
773
|
latency,
|
|
655
774
|
baseURL: this.baseURL,
|
|
656
775
|
params: body,
|
|
@@ -659,7 +778,8 @@ class WrappedCompletions extends Completions {
|
|
|
659
778
|
inputTokens: result.usage?.prompt_tokens ?? 0,
|
|
660
779
|
outputTokens: result.usage?.completion_tokens ?? 0,
|
|
661
780
|
reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
662
|
-
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
|
|
781
|
+
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0,
|
|
782
|
+
webSearchCount: calculateWebSearchCount(result)
|
|
663
783
|
},
|
|
664
784
|
tools: availableTools
|
|
665
785
|
});
|
|
@@ -721,14 +841,22 @@ class WrappedResponses extends Responses {
|
|
|
721
841
|
let finalContent = [];
|
|
722
842
|
let usage = {
|
|
723
843
|
inputTokens: 0,
|
|
724
|
-
outputTokens: 0
|
|
844
|
+
outputTokens: 0,
|
|
845
|
+
webSearchCount: 0
|
|
725
846
|
};
|
|
726
847
|
for await (const chunk of stream1) {
|
|
848
|
+
if ('response' in chunk && chunk.response) {
|
|
849
|
+
const chunkWebSearchCount = calculateWebSearchCount(chunk.response);
|
|
850
|
+
if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
|
|
851
|
+
usage.webSearchCount = chunkWebSearchCount;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
727
854
|
if (chunk.type === 'response.completed' && 'response' in chunk && chunk.response?.output && chunk.response.output.length > 0) {
|
|
728
855
|
finalContent = chunk.response.output;
|
|
729
856
|
}
|
|
730
857
|
if ('response' in chunk && chunk.response?.usage) {
|
|
731
858
|
usage = {
|
|
859
|
+
...usage,
|
|
732
860
|
inputTokens: chunk.response.usage.input_tokens ?? 0,
|
|
733
861
|
outputTokens: chunk.response.usage.output_tokens ?? 0,
|
|
734
862
|
reasoningTokens: chunk.response.usage.output_tokens_details?.reasoning_tokens ?? 0,
|
|
@@ -750,7 +878,13 @@ class WrappedResponses extends Responses {
|
|
|
750
878
|
baseURL: this.baseURL,
|
|
751
879
|
params: body,
|
|
752
880
|
httpStatus: 200,
|
|
753
|
-
usage
|
|
881
|
+
usage: {
|
|
882
|
+
inputTokens: usage.inputTokens,
|
|
883
|
+
outputTokens: usage.outputTokens,
|
|
884
|
+
reasoningTokens: usage.reasoningTokens,
|
|
885
|
+
cacheReadInputTokens: usage.cacheReadInputTokens,
|
|
886
|
+
webSearchCount: usage.webSearchCount
|
|
887
|
+
},
|
|
754
888
|
tools: availableTools
|
|
755
889
|
});
|
|
756
890
|
} catch (error) {
|
|
@@ -785,6 +919,9 @@ class WrappedResponses extends Responses {
|
|
|
785
919
|
if ('output' in result) {
|
|
786
920
|
const latency = (Date.now() - startTime) / 1000;
|
|
787
921
|
const availableTools = extractAvailableToolCalls('openai', openAIParams);
|
|
922
|
+
const formattedOutput = formatResponseOpenAI({
|
|
923
|
+
output: result.output
|
|
924
|
+
});
|
|
788
925
|
await sendEventToPosthog({
|
|
789
926
|
client: this.phClient,
|
|
790
927
|
...posthogParams,
|
|
@@ -792,9 +929,7 @@ class WrappedResponses extends Responses {
|
|
|
792
929
|
model: openAIParams.model,
|
|
793
930
|
provider: 'openai',
|
|
794
931
|
input: formatOpenAIResponsesInput(openAIParams.input, openAIParams.instructions),
|
|
795
|
-
output:
|
|
796
|
-
output: result.output
|
|
797
|
-
}),
|
|
932
|
+
output: formattedOutput,
|
|
798
933
|
latency,
|
|
799
934
|
baseURL: this.baseURL,
|
|
800
935
|
params: body,
|
|
@@ -803,7 +938,8 @@ class WrappedResponses extends Responses {
|
|
|
803
938
|
inputTokens: result.usage?.input_tokens ?? 0,
|
|
804
939
|
outputTokens: result.usage?.output_tokens ?? 0,
|
|
805
940
|
reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
|
|
806
|
-
cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0
|
|
941
|
+
cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
942
|
+
webSearchCount: calculateWebSearchCount(result)
|
|
807
943
|
},
|
|
808
944
|
tools: availableTools
|
|
809
945
|
});
|
|
@@ -841,9 +977,9 @@ class WrappedResponses extends Responses {
|
|
|
841
977
|
} = extractPosthogParams(body);
|
|
842
978
|
const startTime = Date.now();
|
|
843
979
|
const originalCreate = super.create.bind(this);
|
|
844
|
-
const
|
|
845
|
-
const tempCreate =
|
|
846
|
-
|
|
980
|
+
const originalSelfRecord = this;
|
|
981
|
+
const tempCreate = originalSelfRecord['create'];
|
|
982
|
+
originalSelfRecord['create'] = originalCreate;
|
|
847
983
|
try {
|
|
848
984
|
const parentPromise = super.parse(openAIParams, options);
|
|
849
985
|
const wrappedPromise = parentPromise.then(async result => {
|
|
@@ -892,7 +1028,7 @@ class WrappedResponses extends Responses {
|
|
|
892
1028
|
return wrappedPromise;
|
|
893
1029
|
} finally {
|
|
894
1030
|
// Restore our wrapped create method
|
|
895
|
-
|
|
1031
|
+
originalSelfRecord['create'] = tempCreate;
|
|
896
1032
|
}
|
|
897
1033
|
}
|
|
898
1034
|
}
|