@posthog/ai 3.2.1 → 3.3.1
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 +10 -0
- package/lib/index.cjs.js +157 -18
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.esm.js +157 -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 +111 -15
- package/tests/openai.test.ts +36 -0
package/lib/index.esm.js
CHANGED
|
@@ -73,7 +73,8 @@ const sendEventToPosthog = ({
|
|
|
73
73
|
httpStatus = 200,
|
|
74
74
|
usage = {},
|
|
75
75
|
isError = false,
|
|
76
|
-
error
|
|
76
|
+
error,
|
|
77
|
+
tools
|
|
77
78
|
}) => {
|
|
78
79
|
if (client.capture) {
|
|
79
80
|
let errorData = {};
|
|
@@ -93,6 +94,17 @@ const sendEventToPosthog = ({
|
|
|
93
94
|
$ai_total_cost_usd: inputCostUSD + outputCostUSD
|
|
94
95
|
};
|
|
95
96
|
}
|
|
97
|
+
let additionalTokenValues = {
|
|
98
|
+
...(usage.reasoningTokens ? {
|
|
99
|
+
$ai_reasoning_tokens: usage.reasoningTokens
|
|
100
|
+
} : {}),
|
|
101
|
+
...(usage.cacheReadInputTokens ? {
|
|
102
|
+
$ai_cache_read_input_tokens: usage.cacheReadInputTokens
|
|
103
|
+
} : {}),
|
|
104
|
+
...(usage.cacheCreationInputTokens ? {
|
|
105
|
+
$ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
|
|
106
|
+
} : {})
|
|
107
|
+
};
|
|
96
108
|
client.capture({
|
|
97
109
|
distinctId: distinctId ?? traceId,
|
|
98
110
|
event: '$ai_generation',
|
|
@@ -105,6 +117,7 @@ const sendEventToPosthog = ({
|
|
|
105
117
|
$ai_http_status: httpStatus,
|
|
106
118
|
$ai_input_tokens: usage.inputTokens ?? 0,
|
|
107
119
|
$ai_output_tokens: usage.outputTokens ?? 0,
|
|
120
|
+
...additionalTokenValues,
|
|
108
121
|
$ai_latency: latency,
|
|
109
122
|
$ai_trace_id: traceId,
|
|
110
123
|
$ai_base_url: baseURL,
|
|
@@ -112,6 +125,9 @@ const sendEventToPosthog = ({
|
|
|
112
125
|
...(distinctId ? {} : {
|
|
113
126
|
$process_person_profile: false
|
|
114
127
|
}),
|
|
128
|
+
...(tools ? {
|
|
129
|
+
$ai_tools: tools
|
|
130
|
+
} : {}),
|
|
115
131
|
...errorData,
|
|
116
132
|
...costOverrideData
|
|
117
133
|
},
|
|
@@ -173,7 +189,9 @@ class WrappedCompletions$1 extends OpenAIOrignal.Chat.Completions {
|
|
|
173
189
|
if (chunk.usage) {
|
|
174
190
|
usage = {
|
|
175
191
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
176
|
-
outputTokens: chunk.usage.completion_tokens ?? 0
|
|
192
|
+
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
193
|
+
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
194
|
+
cacheReadInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0
|
|
177
195
|
};
|
|
178
196
|
}
|
|
179
197
|
}
|
|
@@ -240,7 +258,9 @@ class WrappedCompletions$1 extends OpenAIOrignal.Chat.Completions {
|
|
|
240
258
|
httpStatus: 200,
|
|
241
259
|
usage: {
|
|
242
260
|
inputTokens: result.usage?.prompt_tokens ?? 0,
|
|
243
|
-
outputTokens: result.usage?.completion_tokens ?? 0
|
|
261
|
+
outputTokens: result.usage?.completion_tokens ?? 0,
|
|
262
|
+
reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
263
|
+
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
|
|
244
264
|
}
|
|
245
265
|
});
|
|
246
266
|
}
|
|
@@ -329,7 +349,9 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
329
349
|
}
|
|
330
350
|
usage = {
|
|
331
351
|
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
332
|
-
outputTokens: chunk.usage.completion_tokens ?? 0
|
|
352
|
+
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
353
|
+
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
354
|
+
cacheReadInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0
|
|
333
355
|
};
|
|
334
356
|
}
|
|
335
357
|
}
|
|
@@ -401,7 +423,9 @@ class WrappedCompletions extends AzureOpenAI.Chat.Completions {
|
|
|
401
423
|
httpStatus: 200,
|
|
402
424
|
usage: {
|
|
403
425
|
inputTokens: result.usage?.prompt_tokens ?? 0,
|
|
404
|
-
outputTokens: result.usage?.completion_tokens ?? 0
|
|
426
|
+
outputTokens: result.usage?.completion_tokens ?? 0,
|
|
427
|
+
reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
428
|
+
cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
|
|
405
429
|
}
|
|
406
430
|
});
|
|
407
431
|
}
|
|
@@ -446,16 +470,60 @@ const mapVercelParams = params => {
|
|
|
446
470
|
};
|
|
447
471
|
const mapVercelPrompt = prompt => {
|
|
448
472
|
return prompt.map(p => {
|
|
449
|
-
let content =
|
|
473
|
+
let content = {};
|
|
450
474
|
if (Array.isArray(p.content)) {
|
|
451
475
|
content = p.content.map(c => {
|
|
452
476
|
if (c.type === 'text') {
|
|
453
|
-
return
|
|
477
|
+
return {
|
|
478
|
+
type: 'text',
|
|
479
|
+
content: c.text
|
|
480
|
+
};
|
|
481
|
+
} else if (c.type === 'image') {
|
|
482
|
+
return {
|
|
483
|
+
type: 'image',
|
|
484
|
+
content: {
|
|
485
|
+
// if image is a url use it, or use "none supported"
|
|
486
|
+
image: c.image instanceof URL ? c.image.toString() : 'raw images not supported',
|
|
487
|
+
mimeType: c.mimeType
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
} else if (c.type === 'file') {
|
|
491
|
+
return {
|
|
492
|
+
type: 'file',
|
|
493
|
+
content: {
|
|
494
|
+
file: c.data instanceof URL ? c.data.toString() : 'raw files not supported',
|
|
495
|
+
mimeType: c.mimeType
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
} else if (c.type === 'tool-call') {
|
|
499
|
+
return {
|
|
500
|
+
type: 'tool-call',
|
|
501
|
+
content: {
|
|
502
|
+
toolCallId: c.toolCallId,
|
|
503
|
+
toolName: c.toolName,
|
|
504
|
+
args: c.args
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
} else if (c.type === 'tool-result') {
|
|
508
|
+
return {
|
|
509
|
+
type: 'tool-result',
|
|
510
|
+
content: {
|
|
511
|
+
toolCallId: c.toolCallId,
|
|
512
|
+
toolName: c.toolName,
|
|
513
|
+
result: c.result,
|
|
514
|
+
isError: c.isError
|
|
515
|
+
}
|
|
516
|
+
};
|
|
454
517
|
}
|
|
455
|
-
return
|
|
456
|
-
|
|
518
|
+
return {
|
|
519
|
+
content: ''
|
|
520
|
+
};
|
|
521
|
+
});
|
|
457
522
|
} else {
|
|
458
|
-
content =
|
|
523
|
+
content = {
|
|
524
|
+
type: 'text',
|
|
525
|
+
text: p.content
|
|
526
|
+
};
|
|
459
527
|
}
|
|
460
528
|
return {
|
|
461
529
|
role: p.role,
|
|
@@ -463,6 +531,45 @@ const mapVercelPrompt = prompt => {
|
|
|
463
531
|
};
|
|
464
532
|
});
|
|
465
533
|
};
|
|
534
|
+
const mapVercelOutput = result => {
|
|
535
|
+
let output = {
|
|
536
|
+
...(result.text ? {
|
|
537
|
+
text: result.text
|
|
538
|
+
} : {}),
|
|
539
|
+
...(result.object ? {
|
|
540
|
+
object: result.object
|
|
541
|
+
} : {}),
|
|
542
|
+
...(result.reasoning ? {
|
|
543
|
+
reasoning: result.reasoning
|
|
544
|
+
} : {}),
|
|
545
|
+
...(result.response ? {
|
|
546
|
+
response: result.response
|
|
547
|
+
} : {}),
|
|
548
|
+
...(result.finishReason ? {
|
|
549
|
+
finishReason: result.finishReason
|
|
550
|
+
} : {}),
|
|
551
|
+
...(result.usage ? {
|
|
552
|
+
usage: result.usage
|
|
553
|
+
} : {}),
|
|
554
|
+
...(result.warnings ? {
|
|
555
|
+
warnings: result.warnings
|
|
556
|
+
} : {}),
|
|
557
|
+
...(result.providerMetadata ? {
|
|
558
|
+
toolCalls: result.providerMetadata
|
|
559
|
+
} : {})
|
|
560
|
+
};
|
|
561
|
+
// if text and no object or reasoning, return text
|
|
562
|
+
if (output.text && !output.object && !output.reasoning) {
|
|
563
|
+
return [{
|
|
564
|
+
content: output.text,
|
|
565
|
+
role: 'assistant'
|
|
566
|
+
}];
|
|
567
|
+
}
|
|
568
|
+
return [{
|
|
569
|
+
content: JSON.stringify(output),
|
|
570
|
+
role: 'assistant'
|
|
571
|
+
}];
|
|
572
|
+
};
|
|
466
573
|
const extractProvider = model => {
|
|
467
574
|
// vercel provider is in the format of provider.endpoint
|
|
468
575
|
const provider = model.provider.toLowerCase();
|
|
@@ -486,11 +593,21 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
486
593
|
const modelId = options.posthogModelOverride ?? (result.response?.modelId ? result.response.modelId : model.modelId);
|
|
487
594
|
const provider = options.posthogProviderOverride ?? extractProvider(model);
|
|
488
595
|
const baseURL = ''; // cannot currently get baseURL from vercel
|
|
489
|
-
let content = result
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
596
|
+
let content = mapVercelOutput(result);
|
|
597
|
+
// let tools = result.toolCalls
|
|
598
|
+
let providerMetadata = result.providerMetadata;
|
|
599
|
+
let additionalTokenValues = {
|
|
600
|
+
...(providerMetadata?.openai?.reasoningTokens ? {
|
|
601
|
+
reasoningTokens: providerMetadata.openai.reasoningTokens
|
|
602
|
+
} : {}),
|
|
603
|
+
...(providerMetadata?.openai?.cachedPromptTokens ? {
|
|
604
|
+
cacheReadInputTokens: providerMetadata.openai.cachedPromptTokens
|
|
605
|
+
} : {}),
|
|
606
|
+
...(providerMetadata?.anthropic ? {
|
|
607
|
+
cacheReadInputTokens: providerMetadata.anthropic.cacheReadInputTokens,
|
|
608
|
+
cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
|
|
609
|
+
} : {})
|
|
610
|
+
};
|
|
494
611
|
sendEventToPosthog({
|
|
495
612
|
client: phClient,
|
|
496
613
|
distinctId: options.posthogDistinctId,
|
|
@@ -508,7 +625,8 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
508
625
|
httpStatus: 200,
|
|
509
626
|
usage: {
|
|
510
627
|
inputTokens: result.usage.promptTokens,
|
|
511
|
-
outputTokens: result.usage.completionTokens
|
|
628
|
+
outputTokens: result.usage.completionTokens,
|
|
629
|
+
...additionalTokenValues
|
|
512
630
|
}
|
|
513
631
|
});
|
|
514
632
|
return result;
|
|
@@ -565,6 +683,18 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
|
|
|
565
683
|
inputTokens: chunk.usage?.promptTokens,
|
|
566
684
|
outputTokens: chunk.usage?.completionTokens
|
|
567
685
|
};
|
|
686
|
+
if (chunk.providerMetadata?.openai?.reasoningTokens) {
|
|
687
|
+
usage.reasoningTokens = chunk.providerMetadata.openai.reasoningTokens;
|
|
688
|
+
}
|
|
689
|
+
if (chunk.providerMetadata?.openai?.cachedPromptTokens) {
|
|
690
|
+
usage.cacheReadInputTokens = chunk.providerMetadata.openai.cachedPromptTokens;
|
|
691
|
+
}
|
|
692
|
+
if (chunk.providerMetadata?.anthropic?.cacheReadInputTokens) {
|
|
693
|
+
usage.cacheReadInputTokens = chunk.providerMetadata.anthropic.cacheReadInputTokens;
|
|
694
|
+
}
|
|
695
|
+
if (chunk.providerMetadata?.anthropic?.cacheCreationInputTokens) {
|
|
696
|
+
usage.cacheCreationInputTokens = chunk.providerMetadata.anthropic.cacheCreationInputTokens;
|
|
697
|
+
}
|
|
568
698
|
}
|
|
569
699
|
controller.enqueue(chunk);
|
|
570
700
|
},
|
|
@@ -667,7 +797,9 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
667
797
|
let accumulatedContent = '';
|
|
668
798
|
const usage = {
|
|
669
799
|
inputTokens: 0,
|
|
670
|
-
outputTokens: 0
|
|
800
|
+
outputTokens: 0,
|
|
801
|
+
cacheCreationInputTokens: 0,
|
|
802
|
+
cacheReadInputTokens: 0
|
|
671
803
|
};
|
|
672
804
|
if ('tee' in value) {
|
|
673
805
|
const [stream1, stream2] = value.tee();
|
|
@@ -682,6 +814,8 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
682
814
|
}
|
|
683
815
|
if (chunk.type == 'message_start') {
|
|
684
816
|
usage.inputTokens = chunk.message.usage.input_tokens ?? 0;
|
|
817
|
+
usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0;
|
|
818
|
+
usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0;
|
|
685
819
|
}
|
|
686
820
|
if ('usage' in chunk) {
|
|
687
821
|
usage.outputTokens = chunk.usage.output_tokens ?? 0;
|
|
@@ -751,7 +885,9 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
751
885
|
httpStatus: 200,
|
|
752
886
|
usage: {
|
|
753
887
|
inputTokens: result.usage.input_tokens ?? 0,
|
|
754
|
-
outputTokens: result.usage.output_tokens ?? 0
|
|
888
|
+
outputTokens: result.usage.output_tokens ?? 0,
|
|
889
|
+
cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,
|
|
890
|
+
cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0
|
|
755
891
|
}
|
|
756
892
|
});
|
|
757
893
|
}
|
|
@@ -1522,6 +1658,9 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
|
|
|
1522
1658
|
$ai_latency: latency,
|
|
1523
1659
|
$ai_base_url: run.baseUrl
|
|
1524
1660
|
};
|
|
1661
|
+
if (run.tools) {
|
|
1662
|
+
eventProperties['$ai_tools'] = withPrivacyMode(this.client, this.privacyMode, run.tools);
|
|
1663
|
+
}
|
|
1525
1664
|
if (output instanceof Error) {
|
|
1526
1665
|
eventProperties['$ai_http_status'] = output.status || 500;
|
|
1527
1666
|
eventProperties['$ai_error'] = output.toString();
|