@posthog/ai 3.2.1 → 3.3.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/CHANGELOG.md +6 -0
- package/lib/index.cjs.js +118 -18
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.esm.js +118 -18
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-ai/src/utils.d.ts +5 -1
- package/package.json +1 -1
- package/src/anthropic/index.ts +12 -1
- package/src/langchain/callbacks.ts +6 -0
- package/src/openai/azure.ts +10 -1
- package/src/openai/index.ts +13 -2
- package/src/utils.ts +17 -1
- package/src/vercel/middleware.ts +93 -15
- package/tests/openai.test.ts +36 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# 3.3.0 - 2025-03-08
|
|
2
|
+
|
|
3
|
+
- feat: add reasoning and cache tokens to openai and anthropic
|
|
4
|
+
- feat: add tool support for vercel
|
|
5
|
+
- feat: add support for other media types vercel
|
|
6
|
+
|
|
1
7
|
# 3.2.1 - 2025-02-11
|
|
2
8
|
|
|
3
9
|
- fix: add experimental_wrapLanguageModel to vercel middleware supporting older versions of ai
|
package/lib/index.cjs.js
CHANGED
|
@@ -100,7 +100,8 @@ const sendEventToPosthog = ({
|
|
|
100
100
|
httpStatus = 200,
|
|
101
101
|
usage = {},
|
|
102
102
|
isError = false,
|
|
103
|
-
error
|
|
103
|
+
error,
|
|
104
|
+
tools
|
|
104
105
|
}) => {
|
|
105
106
|
if (client.capture) {
|
|
106
107
|
let errorData = {};
|
|
@@ -120,6 +121,17 @@ const sendEventToPosthog = ({
|
|
|
120
121
|
$ai_total_cost_usd: inputCostUSD + outputCostUSD
|
|
121
122
|
};
|
|
122
123
|
}
|
|
124
|
+
let additionalTokenValues = {
|
|
125
|
+
...(usage.reasoningTokens ? {
|
|
126
|
+
$ai_reasoning_tokens: usage.reasoningTokens
|
|
127
|
+
} : {}),
|
|
128
|
+
...(usage.cacheReadInputTokens ? {
|
|
129
|
+
$ai_cache_read_input_tokens: usage.cacheReadInputTokens
|
|
130
|
+
} : {}),
|
|
131
|
+
...(usage.cacheCreationInputTokens ? {
|
|
132
|
+
$ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
|
|
133
|
+
} : {})
|
|
134
|
+
};
|
|
123
135
|
client.capture({
|
|
124
136
|
distinctId: distinctId ?? traceId,
|
|
125
137
|
event: '$ai_generation',
|
|
@@ -132,6 +144,7 @@ const sendEventToPosthog = ({
|
|
|
132
144
|
$ai_http_status: httpStatus,
|
|
133
145
|
$ai_input_tokens: usage.inputTokens ?? 0,
|
|
134
146
|
$ai_output_tokens: usage.outputTokens ?? 0,
|
|
147
|
+
...additionalTokenValues,
|
|
135
148
|
$ai_latency: latency,
|
|
136
149
|
$ai_trace_id: traceId,
|
|
137
150
|
$ai_base_url: baseURL,
|
|
@@ -139,6 +152,9 @@ const sendEventToPosthog = ({
|
|
|
139
152
|
...(distinctId ? {} : {
|
|
140
153
|
$process_person_profile: false
|
|
141
154
|
}),
|
|
155
|
+
...(tools ? {
|
|
156
|
+
$ai_tools: tools
|
|
157
|
+
} : {}),
|
|
142
158
|
...errorData,
|
|
143
159
|
...costOverrideData
|
|
144
160
|
},
|
|
@@ -200,7 +216,9 @@ class WrappedCompletions$1 extends OpenAIOrignal__default["default"].Chat.Comple
|
|
|
200
216
|
if (chunk.usage) {
|
|
201
217
|
usage = {
|
|
202
218
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
203
|
-
outputTokens: chunk.usage.completion_tokens ?? 0
|
|
219
|
+
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
220
|
+
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
221
|
+
cacheReadInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0
|
|
204
222
|
};
|
|
205
223
|
}
|
|
206
224
|
}
|
|
@@ -267,7 +285,9 @@ class WrappedCompletions$1 extends OpenAIOrignal__default["default"].Chat.Comple
|
|
|
267
285
|
httpStatus: 200,
|
|
268
286
|
usage: {
|
|
269
287
|
inputTokens: result.usage?.prompt_tokens ?? 0,
|
|
270
|
-
outputTokens: result.usage?.completion_tokens ?? 0
|
|
288
|
+
outputTokens: result.usage?.completion_tokens ?? 0,
|
|
289
|
+
reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
290
|
+
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
|
|
271
291
|
}
|
|
272
292
|
});
|
|
273
293
|
}
|
|
@@ -356,7 +376,9 @@ class WrappedCompletions extends OpenAIOrignal.AzureOpenAI.Chat.Completions {
|
|
|
356
376
|
}
|
|
357
377
|
usage = {
|
|
358
378
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
359
|
-
outputTokens: chunk.usage.completion_tokens ?? 0
|
|
379
|
+
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
380
|
+
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
381
|
+
cacheReadInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0
|
|
360
382
|
};
|
|
361
383
|
}
|
|
362
384
|
}
|
|
@@ -428,7 +450,9 @@ class WrappedCompletions extends OpenAIOrignal.AzureOpenAI.Chat.Completions {
|
|
|
428
450
|
httpStatus: 200,
|
|
429
451
|
usage: {
|
|
430
452
|
inputTokens: result.usage?.prompt_tokens ?? 0,
|
|
431
|
-
outputTokens: result.usage?.completion_tokens ?? 0
|
|
453
|
+
outputTokens: result.usage?.completion_tokens ?? 0,
|
|
454
|
+
reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
455
|
+
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
|
|
432
456
|
}
|
|
433
457
|
});
|
|
434
458
|
}
|
|
@@ -473,16 +497,60 @@ const mapVercelParams = params => {
|
|
|
473
497
|
};
|
|
474
498
|
const mapVercelPrompt = prompt => {
|
|
475
499
|
return prompt.map(p => {
|
|
476
|
-
let content =
|
|
500
|
+
let content = {};
|
|
477
501
|
if (Array.isArray(p.content)) {
|
|
478
502
|
content = p.content.map(c => {
|
|
479
503
|
if (c.type === 'text') {
|
|
480
|
-
return
|
|
504
|
+
return {
|
|
505
|
+
type: 'text',
|
|
506
|
+
content: c.text
|
|
507
|
+
};
|
|
508
|
+
} else if (c.type === 'image') {
|
|
509
|
+
return {
|
|
510
|
+
type: 'image',
|
|
511
|
+
content: {
|
|
512
|
+
// if image is a url use it, or use "none supported"
|
|
513
|
+
image: c.image instanceof URL ? c.image.toString() : 'raw images not supported',
|
|
514
|
+
mimeType: c.mimeType
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
} else if (c.type === 'file') {
|
|
518
|
+
return {
|
|
519
|
+
type: 'file',
|
|
520
|
+
content: {
|
|
521
|
+
file: c.data instanceof URL ? c.data.toString() : 'raw files not supported',
|
|
522
|
+
mimeType: c.mimeType
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
} else if (c.type === 'tool-call') {
|
|
526
|
+
return {
|
|
527
|
+
type: 'tool-call',
|
|
528
|
+
content: {
|
|
529
|
+
toolCallId: c.toolCallId,
|
|
530
|
+
toolName: c.toolName,
|
|
531
|
+
args: c.args
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
} else if (c.type === 'tool-result') {
|
|
535
|
+
return {
|
|
536
|
+
type: 'tool-result',
|
|
537
|
+
content: {
|
|
538
|
+
toolCallId: c.toolCallId,
|
|
539
|
+
toolName: c.toolName,
|
|
540
|
+
result: c.result,
|
|
541
|
+
isError: c.isError
|
|
542
|
+
}
|
|
543
|
+
};
|
|
481
544
|
}
|
|
482
|
-
return
|
|
483
|
-
|
|
545
|
+
return {
|
|
546
|
+
content: ''
|
|
547
|
+
};
|
|
548
|
+
});
|
|
484
549
|
} else {
|
|
485
|
-
content =
|
|
550
|
+
content = {
|
|
551
|
+
type: 'text',
|
|
552
|
+
text: p.content
|
|
553
|
+
};
|
|
486
554
|
}
|
|
487
555
|
return {
|
|
488
556
|
role: p.role,
|
|
@@ -513,11 +581,21 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
513
581
|
const modelId = options.posthogModelOverride ?? (result.response?.modelId ? result.response.modelId : model.modelId);
|
|
514
582
|
const provider = options.posthogProviderOverride ?? extractProvider(model);
|
|
515
583
|
const baseURL = ''; // cannot currently get baseURL from vercel
|
|
516
|
-
let content = result.text;
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
584
|
+
let content = result.text || JSON.stringify(result);
|
|
585
|
+
// let tools = result.toolCalls
|
|
586
|
+
let providerMetadata = result.providerMetadata;
|
|
587
|
+
let additionalTokenValues = {
|
|
588
|
+
...(providerMetadata?.openai?.reasoningTokens ? {
|
|
589
|
+
reasoningTokens: providerMetadata.openai.reasoningTokens
|
|
590
|
+
} : {}),
|
|
591
|
+
...(providerMetadata?.openai?.cachedPromptToken ? {
|
|
592
|
+
cacheReadInputTokens: providerMetadata.openai.cachedPromptTokens
|
|
593
|
+
} : {}),
|
|
594
|
+
...(providerMetadata?.anthropic ? {
|
|
595
|
+
cacheReadInputTokens: providerMetadata.anthropic.cacheReadInputTokens,
|
|
596
|
+
cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
|
|
597
|
+
} : {})
|
|
598
|
+
};
|
|
521
599
|
sendEventToPosthog({
|
|
522
600
|
client: phClient,
|
|
523
601
|
distinctId: options.posthogDistinctId,
|
|
@@ -535,7 +613,8 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
535
613
|
httpStatus: 200,
|
|
536
614
|
usage: {
|
|
537
615
|
inputTokens: result.usage.promptTokens,
|
|
538
|
-
outputTokens: result.usage.completionTokens
|
|
616
|
+
outputTokens: result.usage.completionTokens,
|
|
617
|
+
...additionalTokenValues
|
|
539
618
|
}
|
|
540
619
|
});
|
|
541
620
|
return result;
|
|
@@ -592,6 +671,18 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
592
671
|
inputTokens: chunk.usage?.promptTokens,
|
|
593
672
|
outputTokens: chunk.usage?.completionTokens
|
|
594
673
|
};
|
|
674
|
+
if (chunk.providerMetadata?.openai?.reasoningTokens) {
|
|
675
|
+
usage.reasoningTokens = chunk.providerMetadata.openai.reasoningTokens;
|
|
676
|
+
}
|
|
677
|
+
if (chunk.providerMetadata?.openai?.cachedPromptToken) {
|
|
678
|
+
usage.cacheReadInputTokens = chunk.providerMetadata.openai.cachedPromptToken;
|
|
679
|
+
}
|
|
680
|
+
if (chunk.providerMetadata?.anthropic?.cacheReadInputTokens) {
|
|
681
|
+
usage.cacheReadInputTokens = chunk.providerMetadata.anthropic.cacheReadInputTokens;
|
|
682
|
+
}
|
|
683
|
+
if (chunk.providerMetadata?.anthropic?.cacheCreationInputTokens) {
|
|
684
|
+
usage.cacheCreationInputTokens = chunk.providerMetadata.anthropic.cacheCreationInputTokens;
|
|
685
|
+
}
|
|
595
686
|
}
|
|
596
687
|
controller.enqueue(chunk);
|
|
597
688
|
},
|
|
@@ -694,7 +785,9 @@ class WrappedMessages extends AnthropicOriginal__default["default"].Messages {
|
|
|
694
785
|
let accumulatedContent = '';
|
|
695
786
|
const usage = {
|
|
696
787
|
inputTokens: 0,
|
|
697
|
-
outputTokens: 0
|
|
788
|
+
outputTokens: 0,
|
|
789
|
+
cacheCreationInputTokens: 0,
|
|
790
|
+
cacheReadInputTokens: 0
|
|
698
791
|
};
|
|
699
792
|
if ('tee' in value) {
|
|
700
793
|
const [stream1, stream2] = value.tee();
|
|
@@ -709,6 +802,8 @@ class WrappedMessages extends AnthropicOriginal__default["default"].Messages {
|
|
|
709
802
|
}
|
|
710
803
|
if (chunk.type == 'message_start') {
|
|
711
804
|
usage.inputTokens = chunk.message.usage.input_tokens ?? 0;
|
|
805
|
+
usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0;
|
|
806
|
+
usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0;
|
|
712
807
|
}
|
|
713
808
|
if ('usage' in chunk) {
|
|
714
809
|
usage.outputTokens = chunk.usage.output_tokens ?? 0;
|
|
@@ -778,7 +873,9 @@ class WrappedMessages extends AnthropicOriginal__default["default"].Messages {
|
|
|
778
873
|
httpStatus: 200,
|
|
779
874
|
usage: {
|
|
780
875
|
inputTokens: result.usage.input_tokens ?? 0,
|
|
781
|
-
outputTokens: result.usage.output_tokens ?? 0
|
|
876
|
+
outputTokens: result.usage.output_tokens ?? 0,
|
|
877
|
+
cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,
|
|
878
|
+
cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0
|
|
782
879
|
}
|
|
783
880
|
});
|
|
784
881
|
}
|
|
@@ -1549,6 +1646,9 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
|
|
|
1549
1646
|
$ai_latency: latency,
|
|
1550
1647
|
$ai_base_url: run.baseUrl
|
|
1551
1648
|
};
|
|
1649
|
+
if (run.tools) {
|
|
1650
|
+
eventProperties['$ai_tools'] = withPrivacyMode(this.client, this.privacyMode, run.tools);
|
|
1651
|
+
}
|
|
1552
1652
|
if (output instanceof Error) {
|
|
1553
1653
|
eventProperties['$ai_http_status'] = output.status || 500;
|
|
1554
1654
|
eventProperties['$ai_error'] = output.toString();
|