@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
@@ -280,6 +280,23 @@ const buildInlineDataBlock = (mimeType, data) => {
280
280
  }
281
281
  };
282
282
  };
283
+ const formatInlineDataBlock = (inlineData, client) => {
284
+ const mimeType = inlineData.mimeType || inlineData.mime_type || 'application/octet-stream';
285
+ let data = inlineData.data;
286
+ if (data instanceof Uint8Array) {
287
+ if (typeof Buffer !== 'undefined') {
288
+ data = Buffer.from(data).toString('base64');
289
+ } else {
290
+ let binary = '';
291
+ for (let i = 0; i < data.length; i++) {
292
+ binary += String.fromCharCode(data[i]);
293
+ }
294
+ data = btoa(binary);
295
+ }
296
+ }
297
+ data = isFullAiCaptureEnabled(client) ? data : redactBase64DataUrl(data, mimeType);
298
+ return buildInlineDataBlock(mimeType, String(data ?? ''));
299
+ };
283
300
  const formatResponseGemini = (response, client) => {
284
301
  const output = [];
285
302
  if (response.candidates && Array.isArray(response.candidates)) {
@@ -301,26 +318,7 @@ const formatResponseGemini = (response, client) => {
301
318
  }
302
319
  });
303
320
  } else if (part.inlineData) {
304
- // Handle inline data (images, audio, documents)
305
- const mimeType = part.inlineData.mimeType || part.inlineData.mime_type || 'application/octet-stream';
306
- let data = part.inlineData.data;
307
-
308
- // Handle binary data (Uint8Array/Buffer -> base64)
309
- if (data instanceof Uint8Array) {
310
- if (typeof Buffer !== 'undefined') {
311
- data = Buffer.from(data).toString('base64');
312
- } else {
313
- let binary = '';
314
- for (let i = 0; i < data.length; i++) {
315
- binary += String.fromCharCode(data[i]);
316
- }
317
- data = btoa(binary);
318
- }
319
- }
320
-
321
- // Sanitize base64 data for images and other large inline data
322
- data = isFullAiCaptureEnabled(client) ? data : redactBase64DataUrl(data, mimeType);
323
- content.push(buildInlineDataBlock(mimeType, data));
321
+ content.push(formatInlineDataBlock(part.inlineData, client));
324
322
  }
325
323
  }
326
324
  if (content.length > 0) {
@@ -422,7 +420,7 @@ function addDefaults(params) {
422
420
  };
423
421
  }
424
422
 
425
- var version = "8.9.2";
423
+ var version = "8.10.0";
426
424
 
427
425
  const DEFAULT_MAX_DEPTH = 3;
428
426
  const MAX_STACK_LINES = 20;
@@ -652,7 +650,9 @@ const captureAiGeneration = async (client, options) => {
652
650
  $ai_time_to_first_token: options.timeToFirstToken
653
651
  } : {}),
654
652
  $ai_trace_id: traceId,
655
- $ai_base_url: options.baseURL ?? '',
653
+ ...(options.baseURL === null ? {} : {
654
+ $ai_base_url: options.baseURL ?? ''
655
+ }),
656
656
  ...options.properties,
657
657
  $ai_tokens_source: getTokensSource(options.properties),
658
658
  ...(options.distinctId ? {} : {
@@ -686,10 +686,33 @@ const captureAiGeneration = async (client, options) => {
686
686
  }
687
687
  } catch (error) {
688
688
  // Telemetry failures must never affect the instrumented provider call.
689
+ try {
690
+ options.onError?.(error);
691
+ } catch {
692
+ // Error reporting must not affect the instrumented provider call either.
693
+ }
689
694
  console.warn('[PostHog AI] Failed to capture generation telemetry:', error);
690
695
  }
691
696
  };
692
697
 
698
+ /** Map Gemini usage metadata to PostHog's provider-agnostic token fields. */
699
+ function mapGeminiUsage(metadata, additionalUsage = {}) {
700
+ return {
701
+ inputTokens: metadata?.promptTokenCount ?? 0,
702
+ outputTokens: metadata?.candidatesTokenCount ?? 0,
703
+ reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
704
+ cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0,
705
+ // Gemini counts cachedContentTokenCount inside promptTokenCount, so declare
706
+ // the accounting model rather than leaving ingestion to infer it. Under
707
+ // explicit context caching the two measurements can differ by a few percent.
708
+ ...(metadata?.cachedContentTokenCount ? {
709
+ cacheReportingExclusive: false
710
+ } : {}),
711
+ ...additionalUsage,
712
+ rawUsage: metadata
713
+ };
714
+ }
715
+
693
716
  class PostHogGoogleGenAI {
694
717
  constructor(config) {
695
718
  const {
@@ -728,21 +751,9 @@ class WrappedModels {
728
751
  baseURL: 'https://generativelanguage.googleapis.com',
729
752
  modelParameters: getModelParams(params),
730
753
  httpStatus: 200,
731
- usage: {
732
- inputTokens: metadata?.promptTokenCount ?? 0,
733
- outputTokens: metadata?.candidatesTokenCount ?? 0,
734
- reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
735
- cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0,
736
- // Gemini counts cachedContentTokenCount inside promptTokenCount, so declare the
737
- // accounting model rather than leaving ingestion to infer it. Under explicit
738
- // context caching the two counts come from separate measurements and can disagree
739
- // by a few percent, which makes inference from the counts alone unreliable.
740
- ...(metadata?.cachedContentTokenCount ? {
741
- cacheReportingExclusive: false
742
- } : {}),
743
- webSearchCount: calculateGoogleWebSearchCount(response),
744
- rawUsage: metadata
745
- },
754
+ usage: mapGeminiUsage(metadata, {
755
+ webSearchCount: calculateGoogleWebSearchCount(response)
756
+ }),
746
757
  stopReason: finishReason ?? undefined,
747
758
  tools: availableTools
748
759
  });
@@ -843,20 +854,9 @@ class WrappedModels {
843
854
 
844
855
  // Update usage metadata - handle both old and new field names
845
856
  if (chunk.usageMetadata) {
846
- const metadata = chunk.usageMetadata;
847
- usage = {
848
- inputTokens: metadata.promptTokenCount ?? 0,
849
- outputTokens: metadata.candidatesTokenCount ?? 0,
850
- reasoningTokens: metadata.thoughtsTokenCount ?? 0,
851
- cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0,
852
- // See the non-streaming path: Gemini counts cachedContentTokenCount inside
853
- // promptTokenCount, so the accounting model is declared rather than inferred.
854
- ...(metadata.cachedContentTokenCount ? {
855
- cacheReportingExclusive: false
856
- } : {}),
857
- webSearchCount: usage.webSearchCount,
858
- rawUsage: metadata
859
- };
857
+ usage = mapGeminiUsage(chunk.usageMetadata, {
858
+ webSearchCount: usage.webSearchCount
859
+ });
860
860
  }
861
861
  yield chunk;
862
862
  }