@posthog/ai 8.0.1 → 8.1.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.
@@ -6,6 +6,9 @@ import { uuidv7 } from '@posthog/core';
6
6
  const isString = value => {
7
7
  return typeof value === 'string';
8
8
  };
9
+ const isObject = value => {
10
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
11
+ };
9
12
 
10
13
  const DATA_URL_PREFIX_RE = /^data:([^;,\s]+)(?:;[^;,\s]+)*;base64,/i;
11
14
  const BASE64_ALPHABET_RE = /^[A-Za-z0-9+/_=-]+$/;
@@ -392,7 +395,7 @@ function sanitizeValues(obj) {
392
395
  return jsonSafe;
393
396
  }
394
397
 
395
- var version = "8.0.1";
398
+ var version = "8.1.1";
396
399
 
397
400
  const DEFAULT_MAX_DEPTH = 3;
398
401
  const MAX_STACK_LINES = 20;
@@ -800,6 +803,36 @@ const extractProvider = model => {
800
803
  return providerName;
801
804
  };
802
805
 
806
+ /**
807
+ * Recover the base URL so gateway calls self-identify via `$ai_base_url` (dedup
808
+ * keys on it). The spec exposes none, so we read the off-spec provider `config`:
809
+ * `@ai-sdk/anthropic` keeps a `config.baseURL` string; `@ai-sdk/openai`/
810
+ * `openai-compatible` bury it in a `config.url({ path })` closure. Unknown shapes
811
+ * degrade to `''` — those providers (or a custom `fetch`) stay invisible to dedup.
812
+ */
813
+ const extractBaseURL = model => {
814
+ try {
815
+ const config = model.config;
816
+ if (!isObject(config)) {
817
+ return '';
818
+ }
819
+ if (isString(config.baseURL)) {
820
+ return config.baseURL;
821
+ }
822
+ const urlFn = config.url;
823
+ if (typeof urlFn === 'function') {
824
+ const url = urlFn({
825
+ path: '',
826
+ modelId: model.modelId
827
+ });
828
+ return isString(url) ? url : '';
829
+ }
830
+ } catch {
831
+ // Unknown config shape or url() threw.
832
+ }
833
+ return '';
834
+ };
835
+
803
836
  // Extract web search count from provider metadata (works for both V2 and V3)
804
837
  const extractWebSearchCount = (providerMetadata, usage) => {
805
838
  // Try Anthropic-specific extraction
@@ -827,32 +860,22 @@ const extractTokenCount = value => {
827
860
  }
828
861
  return undefined;
829
862
  };
830
-
831
- // Helper to extract reasoning tokens from V2 (usage.reasoningTokens) or V3 (usage.outputTokens.reasoning)
832
- const extractReasoningTokens = usage => {
833
- // V2 style: top-level reasoningTokens
834
- if ('reasoningTokens' in usage) {
835
- return usage.reasoningTokens;
863
+ const extractUsageToken = (usage, topLevelKey, nestedObjectKey, nestedValueKey) => {
864
+ if (topLevelKey in usage) {
865
+ return usage[topLevelKey];
836
866
  }
837
- // V3 style: nested in outputTokens.reasoning
838
- if ('outputTokens' in usage && usage.outputTokens && typeof usage.outputTokens === 'object' && 'reasoning' in usage.outputTokens) {
839
- return usage.outputTokens.reasoning;
867
+ const nestedTokens = usage[nestedObjectKey];
868
+ if (nestedTokens && typeof nestedTokens === 'object' && nestedValueKey in nestedTokens) {
869
+ return nestedTokens[nestedValueKey];
840
870
  }
841
871
  return undefined;
842
872
  };
843
873
 
874
+ // Helper to extract reasoning tokens from V2 (usage.reasoningTokens) or V3 (usage.outputTokens.reasoning)
875
+ const extractReasoningTokens = usage => extractUsageToken(usage, 'reasoningTokens', 'outputTokens', 'reasoning');
876
+
844
877
  // Helper to extract cached input tokens from V2 (usage.cachedInputTokens) or V3 (usage.inputTokens.cacheRead)
845
- const extractCacheReadTokens = usage => {
846
- // V2 style: top-level cachedInputTokens
847
- if ('cachedInputTokens' in usage) {
848
- return usage.cachedInputTokens;
849
- }
850
- // V3 style: nested in inputTokens.cacheRead
851
- if ('inputTokens' in usage && usage.inputTokens && typeof usage.inputTokens === 'object' && 'cacheRead' in usage.inputTokens) {
852
- return usage.inputTokens.cacheRead;
853
- }
854
- return undefined;
855
- };
878
+ const extractCacheReadTokens = usage => extractUsageToken(usage, 'cachedInputTokens', 'inputTokens', 'cacheRead');
856
879
 
857
880
  // Helper to extract cache write tokens from V3 (usage.inputTokens.cacheWrite). Providers like
858
881
  // Amazon Bedrock populate this standardized field instead of providerMetadata.anthropic.
@@ -952,11 +975,11 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
952
975
  ...mapVercelParams(params)
953
976
  };
954
977
  const availableTools = extractAvailableToolCalls('vercel', params);
978
+ const baseURL = extractBaseURL(model);
955
979
  try {
956
980
  const result = await model.doGenerate(params);
957
981
  const modelId = mergedOptions.posthogModelOverride ?? (result.response?.modelId ? result.response.modelId : model.modelId);
958
982
  const provider = mergedOptions.posthogProviderOverride ?? extractProvider(model);
959
- const baseURL = ''; // cannot currently get baseURL from vercel
960
983
  // result.content is undefined when the model returns only tool calls with no text output
961
984
  const content = mapVercelOutput(result.content ?? []);
962
985
  const latency = (Date.now() - startTime) / 1000;
@@ -1021,7 +1044,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
1021
1044
  input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
1022
1045
  output: [],
1023
1046
  latency: 0,
1024
- baseURL: '',
1047
+ baseURL,
1025
1048
  modelParameters: getModelParams(mergedParams),
1026
1049
  usage: {
1027
1050
  inputTokens: 0,
@@ -1053,7 +1076,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
1053
1076
  const modelId = mergedOptions.posthogModelOverride ?? model.modelId;
1054
1077
  const provider = mergedOptions.posthogProviderOverride ?? extractProvider(model);
1055
1078
  const availableTools = extractAvailableToolCalls('vercel', params);
1056
- const baseURL = ''; // cannot currently get baseURL from vercel
1079
+ const baseURL = extractBaseURL(model);
1057
1080
 
1058
1081
  // Map to track in-progress tool calls
1059
1082
  const toolCallsInProgress = new Map();
@@ -1211,7 +1234,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
1211
1234
  input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
1212
1235
  output: [],
1213
1236
  latency: 0,
1214
- baseURL: '',
1237
+ baseURL,
1215
1238
  modelParameters: getModelParams(mergedParams),
1216
1239
  usage: {
1217
1240
  inputTokens: 0,