@posthog/ai 6.5.1 → 7.0.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 +590 -373
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +590 -373
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +330 -346
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +330 -346
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +152 -15
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.mjs +152 -15
- package/dist/openai/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +157 -8
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +157 -8
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +10 -10
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 = "
|
|
5
|
+
var version = "7.0.0";
|
|
6
6
|
|
|
7
7
|
// Type guards for safer type checking
|
|
8
8
|
|
|
@@ -147,6 +147,110 @@ 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 or choices[].delta (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) {
|
|
202
|
+
// Check both message (non-streaming) and delta (streaming) for annotations
|
|
203
|
+
const content = ('message' in choice ? choice.message : null) || ('delta' in choice ? choice.delta : null);
|
|
204
|
+
if (typeof content === 'object' && content !== null && 'annotations' in content) {
|
|
205
|
+
const annotations = content.annotations;
|
|
206
|
+
if (Array.isArray(annotations)) {
|
|
207
|
+
const hasUrlCitation = annotations.some(ann => {
|
|
208
|
+
return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
|
|
209
|
+
});
|
|
210
|
+
if (hasUrlCitation) {
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Check for annotations in output[].content[] (OpenAI Responses API)
|
|
220
|
+
if ('output' in result && Array.isArray(result.output)) {
|
|
221
|
+
for (const item of result.output) {
|
|
222
|
+
if (typeof item === 'object' && item !== null && 'content' in item) {
|
|
223
|
+
const content = item.content;
|
|
224
|
+
if (Array.isArray(content)) {
|
|
225
|
+
for (const contentItem of content) {
|
|
226
|
+
if (typeof contentItem === 'object' && contentItem !== null && 'annotations' in contentItem) {
|
|
227
|
+
const annotations = contentItem.annotations;
|
|
228
|
+
if (Array.isArray(annotations)) {
|
|
229
|
+
const hasUrlCitation = annotations.some(ann => {
|
|
230
|
+
return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
|
|
231
|
+
});
|
|
232
|
+
if (hasUrlCitation) {
|
|
233
|
+
return 1;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Check for grounding_metadata (Gemini)
|
|
244
|
+
if ('candidates' in result && Array.isArray(result.candidates)) {
|
|
245
|
+
for (const candidate of result.candidates) {
|
|
246
|
+
if (typeof candidate === 'object' && candidate !== null && 'grounding_metadata' in candidate && candidate.grounding_metadata) {
|
|
247
|
+
return 1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
150
254
|
/**
|
|
151
255
|
* Extract available tool calls from the request parameters.
|
|
152
256
|
* These are the tools provided to the LLM, not the tool calls in the response.
|
|
@@ -265,6 +369,9 @@ const sendEventToPosthog = async ({
|
|
|
265
369
|
} : {}),
|
|
266
370
|
...(usage.cacheCreationInputTokens ? {
|
|
267
371
|
$ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
|
|
372
|
+
} : {}),
|
|
373
|
+
...(usage.webSearchCount ? {
|
|
374
|
+
$ai_web_search_count: usage.webSearchCount
|
|
268
375
|
} : {})
|
|
269
376
|
};
|
|
270
377
|
const properties = {
|
|
@@ -506,13 +613,18 @@ class WrappedCompletions extends Completions {
|
|
|
506
613
|
let accumulatedContent = '';
|
|
507
614
|
let usage = {
|
|
508
615
|
inputTokens: 0,
|
|
509
|
-
outputTokens: 0
|
|
616
|
+
outputTokens: 0,
|
|
617
|
+
webSearchCount: 0
|
|
510
618
|
};
|
|
511
619
|
|
|
512
620
|
// Map to track in-progress tool calls
|
|
513
621
|
const toolCallsInProgress = new Map();
|
|
514
622
|
for await (const chunk of stream1) {
|
|
515
623
|
const choice = chunk?.choices?.[0];
|
|
624
|
+
const chunkWebSearchCount = calculateWebSearchCount(chunk);
|
|
625
|
+
if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
|
|
626
|
+
usage.webSearchCount = chunkWebSearchCount;
|
|
627
|
+
}
|
|
516
628
|
|
|
517
629
|
// Handle text content
|
|
518
630
|
const deltaContent = choice?.delta?.content;
|
|
@@ -554,6 +666,7 @@ class WrappedCompletions extends Completions {
|
|
|
554
666
|
// Handle usage information
|
|
555
667
|
if (chunk.usage) {
|
|
556
668
|
usage = {
|
|
669
|
+
...usage,
|
|
557
670
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
558
671
|
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
559
672
|
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
@@ -608,7 +721,13 @@ class WrappedCompletions extends Completions {
|
|
|
608
721
|
baseURL: this.baseURL,
|
|
609
722
|
params: body,
|
|
610
723
|
httpStatus: 200,
|
|
611
|
-
usage
|
|
724
|
+
usage: {
|
|
725
|
+
inputTokens: usage.inputTokens,
|
|
726
|
+
outputTokens: usage.outputTokens,
|
|
727
|
+
reasoningTokens: usage.reasoningTokens,
|
|
728
|
+
cacheReadInputTokens: usage.cacheReadInputTokens,
|
|
729
|
+
webSearchCount: usage.webSearchCount
|
|
730
|
+
},
|
|
612
731
|
tools: availableTools
|
|
613
732
|
});
|
|
614
733
|
} catch (error) {
|
|
@@ -644,13 +763,14 @@ class WrappedCompletions extends Completions {
|
|
|
644
763
|
if ('choices' in result) {
|
|
645
764
|
const latency = (Date.now() - startTime) / 1000;
|
|
646
765
|
const availableTools = extractAvailableToolCalls('openai', openAIParams);
|
|
766
|
+
const formattedOutput = formatResponseOpenAI(result);
|
|
647
767
|
await sendEventToPosthog({
|
|
648
768
|
client: this.phClient,
|
|
649
769
|
...posthogParams,
|
|
650
770
|
model: openAIParams.model,
|
|
651
771
|
provider: 'openai',
|
|
652
772
|
input: sanitizeOpenAI(openAIParams.messages),
|
|
653
|
-
output:
|
|
773
|
+
output: formattedOutput,
|
|
654
774
|
latency,
|
|
655
775
|
baseURL: this.baseURL,
|
|
656
776
|
params: body,
|
|
@@ -659,7 +779,8 @@ class WrappedCompletions extends Completions {
|
|
|
659
779
|
inputTokens: result.usage?.prompt_tokens ?? 0,
|
|
660
780
|
outputTokens: result.usage?.completion_tokens ?? 0,
|
|
661
781
|
reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
662
|
-
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
|
|
782
|
+
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0,
|
|
783
|
+
webSearchCount: calculateWebSearchCount(result)
|
|
663
784
|
},
|
|
664
785
|
tools: availableTools
|
|
665
786
|
});
|
|
@@ -721,14 +842,22 @@ class WrappedResponses extends Responses {
|
|
|
721
842
|
let finalContent = [];
|
|
722
843
|
let usage = {
|
|
723
844
|
inputTokens: 0,
|
|
724
|
-
outputTokens: 0
|
|
845
|
+
outputTokens: 0,
|
|
846
|
+
webSearchCount: 0
|
|
725
847
|
};
|
|
726
848
|
for await (const chunk of stream1) {
|
|
849
|
+
if ('response' in chunk && chunk.response) {
|
|
850
|
+
const chunkWebSearchCount = calculateWebSearchCount(chunk.response);
|
|
851
|
+
if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
|
|
852
|
+
usage.webSearchCount = chunkWebSearchCount;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
727
855
|
if (chunk.type === 'response.completed' && 'response' in chunk && chunk.response?.output && chunk.response.output.length > 0) {
|
|
728
856
|
finalContent = chunk.response.output;
|
|
729
857
|
}
|
|
730
858
|
if ('response' in chunk && chunk.response?.usage) {
|
|
731
859
|
usage = {
|
|
860
|
+
...usage,
|
|
732
861
|
inputTokens: chunk.response.usage.input_tokens ?? 0,
|
|
733
862
|
outputTokens: chunk.response.usage.output_tokens ?? 0,
|
|
734
863
|
reasoningTokens: chunk.response.usage.output_tokens_details?.reasoning_tokens ?? 0,
|
|
@@ -750,7 +879,13 @@ class WrappedResponses extends Responses {
|
|
|
750
879
|
baseURL: this.baseURL,
|
|
751
880
|
params: body,
|
|
752
881
|
httpStatus: 200,
|
|
753
|
-
usage
|
|
882
|
+
usage: {
|
|
883
|
+
inputTokens: usage.inputTokens,
|
|
884
|
+
outputTokens: usage.outputTokens,
|
|
885
|
+
reasoningTokens: usage.reasoningTokens,
|
|
886
|
+
cacheReadInputTokens: usage.cacheReadInputTokens,
|
|
887
|
+
webSearchCount: usage.webSearchCount
|
|
888
|
+
},
|
|
754
889
|
tools: availableTools
|
|
755
890
|
});
|
|
756
891
|
} catch (error) {
|
|
@@ -785,6 +920,9 @@ class WrappedResponses extends Responses {
|
|
|
785
920
|
if ('output' in result) {
|
|
786
921
|
const latency = (Date.now() - startTime) / 1000;
|
|
787
922
|
const availableTools = extractAvailableToolCalls('openai', openAIParams);
|
|
923
|
+
const formattedOutput = formatResponseOpenAI({
|
|
924
|
+
output: result.output
|
|
925
|
+
});
|
|
788
926
|
await sendEventToPosthog({
|
|
789
927
|
client: this.phClient,
|
|
790
928
|
...posthogParams,
|
|
@@ -792,9 +930,7 @@ class WrappedResponses extends Responses {
|
|
|
792
930
|
model: openAIParams.model,
|
|
793
931
|
provider: 'openai',
|
|
794
932
|
input: formatOpenAIResponsesInput(openAIParams.input, openAIParams.instructions),
|
|
795
|
-
output:
|
|
796
|
-
output: result.output
|
|
797
|
-
}),
|
|
933
|
+
output: formattedOutput,
|
|
798
934
|
latency,
|
|
799
935
|
baseURL: this.baseURL,
|
|
800
936
|
params: body,
|
|
@@ -803,7 +939,8 @@ class WrappedResponses extends Responses {
|
|
|
803
939
|
inputTokens: result.usage?.input_tokens ?? 0,
|
|
804
940
|
outputTokens: result.usage?.output_tokens ?? 0,
|
|
805
941
|
reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
|
|
806
|
-
cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0
|
|
942
|
+
cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
943
|
+
webSearchCount: calculateWebSearchCount(result)
|
|
807
944
|
},
|
|
808
945
|
tools: availableTools
|
|
809
946
|
});
|
|
@@ -841,9 +978,9 @@ class WrappedResponses extends Responses {
|
|
|
841
978
|
} = extractPosthogParams(body);
|
|
842
979
|
const startTime = Date.now();
|
|
843
980
|
const originalCreate = super.create.bind(this);
|
|
844
|
-
const
|
|
845
|
-
const tempCreate =
|
|
846
|
-
|
|
981
|
+
const originalSelfRecord = this;
|
|
982
|
+
const tempCreate = originalSelfRecord['create'];
|
|
983
|
+
originalSelfRecord['create'] = originalCreate;
|
|
847
984
|
try {
|
|
848
985
|
const parentPromise = super.parse(openAIParams, options);
|
|
849
986
|
const wrappedPromise = parentPromise.then(async result => {
|
|
@@ -892,7 +1029,7 @@ class WrappedResponses extends Responses {
|
|
|
892
1029
|
return wrappedPromise;
|
|
893
1030
|
} finally {
|
|
894
1031
|
// Restore our wrapped create method
|
|
895
|
-
|
|
1032
|
+
originalSelfRecord['create'] = tempCreate;
|
|
896
1033
|
}
|
|
897
1034
|
}
|
|
898
1035
|
}
|