@posthog/ai 8.9.2 → 8.10.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.
Files changed (39) hide show
  1. package/dist/adk/index.cjs +1267 -0
  2. package/dist/adk/index.cjs.map +1 -0
  3. package/dist/adk/index.d.ts +149 -0
  4. package/dist/adk/index.mjs +1265 -0
  5. package/dist/adk/index.mjs.map +1 -0
  6. package/dist/anthropic/index.cjs +9 -2
  7. package/dist/anthropic/index.cjs.map +1 -1
  8. package/dist/anthropic/index.mjs +9 -2
  9. package/dist/anthropic/index.mjs.map +1 -1
  10. package/dist/gemini/index.cjs +51 -51
  11. package/dist/gemini/index.cjs.map +1 -1
  12. package/dist/gemini/index.mjs +51 -51
  13. package/dist/gemini/index.mjs.map +1 -1
  14. package/dist/index.cjs +9 -2
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +7 -1
  17. package/dist/index.mjs +9 -2
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/langchain/index.cjs +6 -2
  20. package/dist/langchain/index.cjs.map +1 -1
  21. package/dist/langchain/index.mjs +6 -2
  22. package/dist/langchain/index.mjs.map +1 -1
  23. package/dist/langchain/middleware/index.cjs +6 -2
  24. package/dist/langchain/middleware/index.cjs.map +1 -1
  25. package/dist/langchain/middleware/index.mjs +6 -2
  26. package/dist/langchain/middleware/index.mjs.map +1 -1
  27. package/dist/openai/index.cjs +9 -2
  28. package/dist/openai/index.cjs.map +1 -1
  29. package/dist/openai/index.mjs +9 -2
  30. package/dist/openai/index.mjs.map +1 -1
  31. package/dist/openai-agents/index.cjs +1 -1
  32. package/dist/openai-agents/index.cjs.map +1 -1
  33. package/dist/openai-agents/index.mjs +1 -1
  34. package/dist/openai-agents/index.mjs.map +1 -1
  35. package/dist/vercel/index.cjs +9 -2
  36. package/dist/vercel/index.cjs.map +1 -1
  37. package/dist/vercel/index.mjs +9 -2
  38. package/dist/vercel/index.mjs.map +1 -1
  39. package/package.json +13 -3
@@ -276,6 +276,23 @@ const buildInlineDataBlock = (mimeType, data) => {
276
276
  }
277
277
  };
278
278
  };
279
+ const formatInlineDataBlock = (inlineData, client) => {
280
+ const mimeType = inlineData.mimeType || inlineData.mime_type || 'application/octet-stream';
281
+ let data = inlineData.data;
282
+ if (data instanceof Uint8Array) {
283
+ if (typeof Buffer !== 'undefined') {
284
+ data = Buffer.from(data).toString('base64');
285
+ } else {
286
+ let binary = '';
287
+ for (let i = 0; i < data.length; i++) {
288
+ binary += String.fromCharCode(data[i]);
289
+ }
290
+ data = btoa(binary);
291
+ }
292
+ }
293
+ data = isFullAiCaptureEnabled(client) ? data : redactBase64DataUrl(data, mimeType);
294
+ return buildInlineDataBlock(mimeType, String(data ?? ''));
295
+ };
279
296
  const formatResponseGemini = (response, client) => {
280
297
  const output = [];
281
298
  if (response.candidates && Array.isArray(response.candidates)) {
@@ -297,26 +314,7 @@ const formatResponseGemini = (response, client) => {
297
314
  }
298
315
  });
299
316
  } else if (part.inlineData) {
300
- // Handle inline data (images, audio, documents)
301
- const mimeType = part.inlineData.mimeType || part.inlineData.mime_type || 'application/octet-stream';
302
- let data = part.inlineData.data;
303
-
304
- // Handle binary data (Uint8Array/Buffer -> base64)
305
- if (data instanceof Uint8Array) {
306
- if (typeof Buffer !== 'undefined') {
307
- data = Buffer.from(data).toString('base64');
308
- } else {
309
- let binary = '';
310
- for (let i = 0; i < data.length; i++) {
311
- binary += String.fromCharCode(data[i]);
312
- }
313
- data = btoa(binary);
314
- }
315
- }
316
-
317
- // Sanitize base64 data for images and other large inline data
318
- data = isFullAiCaptureEnabled(client) ? data : redactBase64DataUrl(data, mimeType);
319
- content.push(buildInlineDataBlock(mimeType, data));
317
+ content.push(formatInlineDataBlock(part.inlineData, client));
320
318
  }
321
319
  }
322
320
  if (content.length > 0) {
@@ -418,7 +416,7 @@ function addDefaults(params) {
418
416
  };
419
417
  }
420
418
 
421
- var version = "8.9.2";
419
+ var version = "8.10.0";
422
420
 
423
421
  const DEFAULT_MAX_DEPTH = 3;
424
422
  const MAX_STACK_LINES = 20;
@@ -648,7 +646,9 @@ const captureAiGeneration = async (client, options) => {
648
646
  $ai_time_to_first_token: options.timeToFirstToken
649
647
  } : {}),
650
648
  $ai_trace_id: traceId,
651
- $ai_base_url: options.baseURL ?? '',
649
+ ...(options.baseURL === null ? {} : {
650
+ $ai_base_url: options.baseURL ?? ''
651
+ }),
652
652
  ...options.properties,
653
653
  $ai_tokens_source: getTokensSource(options.properties),
654
654
  ...(options.distinctId ? {} : {
@@ -682,10 +682,33 @@ const captureAiGeneration = async (client, options) => {
682
682
  }
683
683
  } catch (error) {
684
684
  // Telemetry failures must never affect the instrumented provider call.
685
+ try {
686
+ options.onError?.(error);
687
+ } catch {
688
+ // Error reporting must not affect the instrumented provider call either.
689
+ }
685
690
  console.warn('[PostHog AI] Failed to capture generation telemetry:', error);
686
691
  }
687
692
  };
688
693
 
694
+ /** Map Gemini usage metadata to PostHog's provider-agnostic token fields. */
695
+ function mapGeminiUsage(metadata, additionalUsage = {}) {
696
+ return {
697
+ inputTokens: metadata?.promptTokenCount ?? 0,
698
+ outputTokens: metadata?.candidatesTokenCount ?? 0,
699
+ reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
700
+ cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0,
701
+ // Gemini counts cachedContentTokenCount inside promptTokenCount, so declare
702
+ // the accounting model rather than leaving ingestion to infer it. Under
703
+ // explicit context caching the two measurements can differ by a few percent.
704
+ ...(metadata?.cachedContentTokenCount ? {
705
+ cacheReportingExclusive: false
706
+ } : {}),
707
+ ...additionalUsage,
708
+ rawUsage: metadata
709
+ };
710
+ }
711
+
689
712
  class PostHogGoogleGenAI {
690
713
  constructor(config) {
691
714
  const {
@@ -724,21 +747,9 @@ class WrappedModels {
724
747
  baseURL: 'https://generativelanguage.googleapis.com',
725
748
  modelParameters: getModelParams(params),
726
749
  httpStatus: 200,
727
- usage: {
728
- inputTokens: metadata?.promptTokenCount ?? 0,
729
- outputTokens: metadata?.candidatesTokenCount ?? 0,
730
- reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
731
- cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0,
732
- // Gemini counts cachedContentTokenCount inside promptTokenCount, so declare the
733
- // accounting model rather than leaving ingestion to infer it. Under explicit
734
- // context caching the two counts come from separate measurements and can disagree
735
- // by a few percent, which makes inference from the counts alone unreliable.
736
- ...(metadata?.cachedContentTokenCount ? {
737
- cacheReportingExclusive: false
738
- } : {}),
739
- webSearchCount: calculateGoogleWebSearchCount(response),
740
- rawUsage: metadata
741
- },
750
+ usage: mapGeminiUsage(metadata, {
751
+ webSearchCount: calculateGoogleWebSearchCount(response)
752
+ }),
742
753
  stopReason: finishReason ?? undefined,
743
754
  tools: availableTools
744
755
  });
@@ -839,20 +850,9 @@ class WrappedModels {
839
850
 
840
851
  // Update usage metadata - handle both old and new field names
841
852
  if (chunk.usageMetadata) {
842
- const metadata = chunk.usageMetadata;
843
- usage = {
844
- inputTokens: metadata.promptTokenCount ?? 0,
845
- outputTokens: metadata.candidatesTokenCount ?? 0,
846
- reasoningTokens: metadata.thoughtsTokenCount ?? 0,
847
- cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0,
848
- // See the non-streaming path: Gemini counts cachedContentTokenCount inside
849
- // promptTokenCount, so the accounting model is declared rather than inferred.
850
- ...(metadata.cachedContentTokenCount ? {
851
- cacheReportingExclusive: false
852
- } : {}),
853
- webSearchCount: usage.webSearchCount,
854
- rawUsage: metadata
855
- };
853
+ usage = mapGeminiUsage(chunk.usageMetadata, {
854
+ webSearchCount: usage.webSearchCount
855
+ });
856
856
  }
857
857
  yield chunk;
858
858
  }