@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 CHANGED
@@ -1,3 +1,13 @@
1
+ # 3.3.1 - 2025-03-13
2
+
3
+ - fix: fix vercel output mapping and token caching
4
+
5
+ # 3.3.0 - 2025-03-08
6
+
7
+ - feat: add reasoning and cache tokens to openai and anthropic
8
+ - feat: add tool support for vercel
9
+ - feat: add support for other media types vercel
10
+
1
11
  # 3.2.1 - 2025-02-11
2
12
 
3
13
  - 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 c.text;
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
- }).join('');
545
+ return {
546
+ content: ''
547
+ };
548
+ });
484
549
  } else {
485
- content = p.content;
550
+ content = {
551
+ type: 'text',
552
+ text: p.content
553
+ };
486
554
  }
487
555
  return {
488
556
  role: p.role,
@@ -490,6 +558,45 @@ const mapVercelPrompt = prompt => {
490
558
  };
491
559
  });
492
560
  };
561
+ const mapVercelOutput = result => {
562
+ let output = {
563
+ ...(result.text ? {
564
+ text: result.text
565
+ } : {}),
566
+ ...(result.object ? {
567
+ object: result.object
568
+ } : {}),
569
+ ...(result.reasoning ? {
570
+ reasoning: result.reasoning
571
+ } : {}),
572
+ ...(result.response ? {
573
+ response: result.response
574
+ } : {}),
575
+ ...(result.finishReason ? {
576
+ finishReason: result.finishReason
577
+ } : {}),
578
+ ...(result.usage ? {
579
+ usage: result.usage
580
+ } : {}),
581
+ ...(result.warnings ? {
582
+ warnings: result.warnings
583
+ } : {}),
584
+ ...(result.providerMetadata ? {
585
+ toolCalls: result.providerMetadata
586
+ } : {})
587
+ };
588
+ // if text and no object or reasoning, return text
589
+ if (output.text && !output.object && !output.reasoning) {
590
+ return [{
591
+ content: output.text,
592
+ role: 'assistant'
593
+ }];
594
+ }
595
+ return [{
596
+ content: JSON.stringify(output),
597
+ role: 'assistant'
598
+ }];
599
+ };
493
600
  const extractProvider = model => {
494
601
  // vercel provider is in the format of provider.endpoint
495
602
  const provider = model.provider.toLowerCase();
@@ -513,11 +620,21 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
513
620
  const modelId = options.posthogModelOverride ?? (result.response?.modelId ? result.response.modelId : model.modelId);
514
621
  const provider = options.posthogProviderOverride ?? extractProvider(model);
515
622
  const baseURL = ''; // cannot currently get baseURL from vercel
516
- let content = result.text;
517
- if (!content) {
518
- // support generate Object
519
- content = result.toolCalls?.[0].args || JSON.stringify(result);
520
- }
623
+ let content = mapVercelOutput(result);
624
+ // let tools = result.toolCalls
625
+ let providerMetadata = result.providerMetadata;
626
+ let additionalTokenValues = {
627
+ ...(providerMetadata?.openai?.reasoningTokens ? {
628
+ reasoningTokens: providerMetadata.openai.reasoningTokens
629
+ } : {}),
630
+ ...(providerMetadata?.openai?.cachedPromptTokens ? {
631
+ cacheReadInputTokens: providerMetadata.openai.cachedPromptTokens
632
+ } : {}),
633
+ ...(providerMetadata?.anthropic ? {
634
+ cacheReadInputTokens: providerMetadata.anthropic.cacheReadInputTokens,
635
+ cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
636
+ } : {})
637
+ };
521
638
  sendEventToPosthog({
522
639
  client: phClient,
523
640
  distinctId: options.posthogDistinctId,
@@ -535,7 +652,8 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
535
652
  httpStatus: 200,
536
653
  usage: {
537
654
  inputTokens: result.usage.promptTokens,
538
- outputTokens: result.usage.completionTokens
655
+ outputTokens: result.usage.completionTokens,
656
+ ...additionalTokenValues
539
657
  }
540
658
  });
541
659
  return result;
@@ -592,6 +710,18 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
592
710
  inputTokens: chunk.usage?.promptTokens,
593
711
  outputTokens: chunk.usage?.completionTokens
594
712
  };
713
+ if (chunk.providerMetadata?.openai?.reasoningTokens) {
714
+ usage.reasoningTokens = chunk.providerMetadata.openai.reasoningTokens;
715
+ }
716
+ if (chunk.providerMetadata?.openai?.cachedPromptTokens) {
717
+ usage.cacheReadInputTokens = chunk.providerMetadata.openai.cachedPromptTokens;
718
+ }
719
+ if (chunk.providerMetadata?.anthropic?.cacheReadInputTokens) {
720
+ usage.cacheReadInputTokens = chunk.providerMetadata.anthropic.cacheReadInputTokens;
721
+ }
722
+ if (chunk.providerMetadata?.anthropic?.cacheCreationInputTokens) {
723
+ usage.cacheCreationInputTokens = chunk.providerMetadata.anthropic.cacheCreationInputTokens;
724
+ }
595
725
  }
596
726
  controller.enqueue(chunk);
597
727
  },
@@ -694,7 +824,9 @@ class WrappedMessages extends AnthropicOriginal__default["default"].Messages {
694
824
  let accumulatedContent = '';
695
825
  const usage = {
696
826
  inputTokens: 0,
697
- outputTokens: 0
827
+ outputTokens: 0,
828
+ cacheCreationInputTokens: 0,
829
+ cacheReadInputTokens: 0
698
830
  };
699
831
  if ('tee' in value) {
700
832
  const [stream1, stream2] = value.tee();
@@ -709,6 +841,8 @@ class WrappedMessages extends AnthropicOriginal__default["default"].Messages {
709
841
  }
710
842
  if (chunk.type == 'message_start') {
711
843
  usage.inputTokens = chunk.message.usage.input_tokens ?? 0;
844
+ usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0;
845
+ usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0;
712
846
  }
713
847
  if ('usage' in chunk) {
714
848
  usage.outputTokens = chunk.usage.output_tokens ?? 0;
@@ -778,7 +912,9 @@ class WrappedMessages extends AnthropicOriginal__default["default"].Messages {
778
912
  httpStatus: 200,
779
913
  usage: {
780
914
  inputTokens: result.usage.input_tokens ?? 0,
781
- outputTokens: result.usage.output_tokens ?? 0
915
+ outputTokens: result.usage.output_tokens ?? 0,
916
+ cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,
917
+ cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0
782
918
  }
783
919
  });
784
920
  }
@@ -1549,6 +1685,9 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
1549
1685
  $ai_latency: latency,
1550
1686
  $ai_base_url: run.baseUrl
1551
1687
  };
1688
+ if (run.tools) {
1689
+ eventProperties['$ai_tools'] = withPrivacyMode(this.client, this.privacyMode, run.tools);
1690
+ }
1552
1691
  if (output instanceof Error) {
1553
1692
  eventProperties['$ai_http_status'] = output.status || 500;
1554
1693
  eventProperties['$ai_error'] = output.toString();