@posthog/ai 6.5.1 → 7.0.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.
package/dist/index.cjs CHANGED
@@ -26,7 +26,7 @@ function _interopNamespaceDefault(e) {
26
26
 
27
27
  var uuid__namespace = /*#__PURE__*/_interopNamespaceDefault(uuid);
28
28
 
29
- var version = "6.5.1";
29
+ var version = "7.0.0";
30
30
 
31
31
  // Type guards for safer type checking
32
32
  const isString = value => {
@@ -297,6 +297,101 @@ const truncate = input => {
297
297
  }
298
298
  return `${truncatedStr}... [truncated]`;
299
299
  };
300
+ /**
301
+ * Calculate web search count from raw API response.
302
+ *
303
+ * Uses a two-tier detection strategy:
304
+ * Priority 1 (Exact Count): Count actual web search calls when available
305
+ * Priority 2 (Binary Detection): Return 1 if web search indicators are present, 0 otherwise
306
+ *
307
+ * @param result - Raw API response from any provider (OpenAI, Perplexity, OpenRouter, Gemini, etc.)
308
+ * @returns Number of web searches performed (exact count or binary 1/0)
309
+ */
310
+ function calculateWebSearchCount(result) {
311
+ if (!result || typeof result !== 'object') {
312
+ return 0;
313
+ }
314
+ // Priority 1: Exact Count
315
+ // Check for OpenAI Responses API web_search_call items
316
+ if ('output' in result && Array.isArray(result.output)) {
317
+ let count = 0;
318
+ for (const item of result.output) {
319
+ if (typeof item === 'object' && item !== null && 'type' in item && item.type === 'web_search_call') {
320
+ count++;
321
+ }
322
+ }
323
+ if (count > 0) {
324
+ return count;
325
+ }
326
+ }
327
+ // Priority 2: Binary Detection (1 or 0)
328
+ // Check for citations at root level (Perplexity)
329
+ if ('citations' in result && Array.isArray(result.citations) && result.citations.length > 0) {
330
+ return 1;
331
+ }
332
+ // Check for search_results at root level (Perplexity via OpenRouter)
333
+ if ('search_results' in result && Array.isArray(result.search_results) && result.search_results.length > 0) {
334
+ return 1;
335
+ }
336
+ // Check for usage.search_context_size (Perplexity via OpenRouter)
337
+ if ('usage' in result && typeof result.usage === 'object' && result.usage !== null) {
338
+ if ('search_context_size' in result.usage && result.usage.search_context_size) {
339
+ return 1;
340
+ }
341
+ }
342
+ // Check for annotations with url_citation in choices[].message or choices[].delta (OpenAI/Perplexity)
343
+ if ('choices' in result && Array.isArray(result.choices)) {
344
+ for (const choice of result.choices) {
345
+ if (typeof choice === 'object' && choice !== null) {
346
+ // Check both message (non-streaming) and delta (streaming) for annotations
347
+ const content = ('message' in choice ? choice.message : null) || ('delta' in choice ? choice.delta : null);
348
+ if (typeof content === 'object' && content !== null && 'annotations' in content) {
349
+ const annotations = content.annotations;
350
+ if (Array.isArray(annotations)) {
351
+ const hasUrlCitation = annotations.some(ann => {
352
+ return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
353
+ });
354
+ if (hasUrlCitation) {
355
+ return 1;
356
+ }
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ // Check for annotations in output[].content[] (OpenAI Responses API)
363
+ if ('output' in result && Array.isArray(result.output)) {
364
+ for (const item of result.output) {
365
+ if (typeof item === 'object' && item !== null && 'content' in item) {
366
+ const content = item.content;
367
+ if (Array.isArray(content)) {
368
+ for (const contentItem of content) {
369
+ if (typeof contentItem === 'object' && contentItem !== null && 'annotations' in contentItem) {
370
+ const annotations = contentItem.annotations;
371
+ if (Array.isArray(annotations)) {
372
+ const hasUrlCitation = annotations.some(ann => {
373
+ return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
374
+ });
375
+ if (hasUrlCitation) {
376
+ return 1;
377
+ }
378
+ }
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ }
385
+ // Check for grounding_metadata (Gemini)
386
+ if ('candidates' in result && Array.isArray(result.candidates)) {
387
+ for (const candidate of result.candidates) {
388
+ if (typeof candidate === 'object' && candidate !== null && 'grounding_metadata' in candidate && candidate.grounding_metadata) {
389
+ return 1;
390
+ }
391
+ }
392
+ }
393
+ return 0;
394
+ }
300
395
  /**
301
396
  * Extract available tool calls from the request parameters.
302
397
  * These are the tools provided to the LLM, not the tool calls in the response.
@@ -431,6 +526,9 @@ const sendEventToPosthog = async ({
431
526
  } : {}),
432
527
  ...(usage.cacheCreationInputTokens ? {
433
528
  $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
529
+ } : {}),
530
+ ...(usage.webSearchCount ? {
531
+ $ai_web_search_count: usage.webSearchCount
434
532
  } : {})
435
533
  };
436
534
  const properties = {
@@ -741,12 +839,17 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
741
839
  let accumulatedContent = '';
742
840
  let usage = {
743
841
  inputTokens: 0,
744
- outputTokens: 0
842
+ outputTokens: 0,
843
+ webSearchCount: 0
745
844
  };
746
845
  // Map to track in-progress tool calls
747
846
  const toolCallsInProgress = new Map();
748
847
  for await (const chunk of stream1) {
749
848
  const choice = chunk?.choices?.[0];
849
+ const chunkWebSearchCount = calculateWebSearchCount(chunk);
850
+ if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
851
+ usage.webSearchCount = chunkWebSearchCount;
852
+ }
750
853
  // Handle text content
751
854
  const deltaContent = choice?.delta?.content;
752
855
  if (deltaContent) {
@@ -785,6 +888,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
785
888
  // Handle usage information
786
889
  if (chunk.usage) {
787
890
  usage = {
891
+ ...usage,
788
892
  inputTokens: chunk.usage.prompt_tokens ?? 0,
789
893
  outputTokens: chunk.usage.completion_tokens ?? 0,
790
894
  reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
@@ -836,7 +940,13 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
836
940
  baseURL: this.baseURL,
837
941
  params: body,
838
942
  httpStatus: 200,
839
- usage,
943
+ usage: {
944
+ inputTokens: usage.inputTokens,
945
+ outputTokens: usage.outputTokens,
946
+ reasoningTokens: usage.reasoningTokens,
947
+ cacheReadInputTokens: usage.cacheReadInputTokens,
948
+ webSearchCount: usage.webSearchCount
949
+ },
840
950
  tools: availableTools
841
951
  });
842
952
  } catch (error) {
@@ -871,13 +981,14 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
871
981
  if ('choices' in result) {
872
982
  const latency = (Date.now() - startTime) / 1000;
873
983
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
984
+ const formattedOutput = formatResponseOpenAI(result);
874
985
  await sendEventToPosthog({
875
986
  client: this.phClient,
876
987
  ...posthogParams,
877
988
  model: openAIParams.model,
878
989
  provider: 'openai',
879
990
  input: sanitizeOpenAI(openAIParams.messages),
880
- output: formatResponseOpenAI(result),
991
+ output: formattedOutput,
881
992
  latency,
882
993
  baseURL: this.baseURL,
883
994
  params: body,
@@ -886,7 +997,8 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
886
997
  inputTokens: result.usage?.prompt_tokens ?? 0,
887
998
  outputTokens: result.usage?.completion_tokens ?? 0,
888
999
  reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
889
- cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
1000
+ cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0,
1001
+ webSearchCount: calculateWebSearchCount(result)
890
1002
  },
891
1003
  tools: availableTools
892
1004
  });
@@ -941,14 +1053,22 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
941
1053
  let finalContent = [];
942
1054
  let usage = {
943
1055
  inputTokens: 0,
944
- outputTokens: 0
1056
+ outputTokens: 0,
1057
+ webSearchCount: 0
945
1058
  };
946
1059
  for await (const chunk of stream1) {
1060
+ if ('response' in chunk && chunk.response) {
1061
+ const chunkWebSearchCount = calculateWebSearchCount(chunk.response);
1062
+ if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
1063
+ usage.webSearchCount = chunkWebSearchCount;
1064
+ }
1065
+ }
947
1066
  if (chunk.type === 'response.completed' && 'response' in chunk && chunk.response?.output && chunk.response.output.length > 0) {
948
1067
  finalContent = chunk.response.output;
949
1068
  }
950
1069
  if ('response' in chunk && chunk.response?.usage) {
951
1070
  usage = {
1071
+ ...usage,
952
1072
  inputTokens: chunk.response.usage.input_tokens ?? 0,
953
1073
  outputTokens: chunk.response.usage.output_tokens ?? 0,
954
1074
  reasoningTokens: chunk.response.usage.output_tokens_details?.reasoning_tokens ?? 0,
@@ -970,7 +1090,13 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
970
1090
  baseURL: this.baseURL,
971
1091
  params: body,
972
1092
  httpStatus: 200,
973
- usage,
1093
+ usage: {
1094
+ inputTokens: usage.inputTokens,
1095
+ outputTokens: usage.outputTokens,
1096
+ reasoningTokens: usage.reasoningTokens,
1097
+ cacheReadInputTokens: usage.cacheReadInputTokens,
1098
+ webSearchCount: usage.webSearchCount
1099
+ },
974
1100
  tools: availableTools
975
1101
  });
976
1102
  } catch (error) {
@@ -1005,6 +1131,9 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1005
1131
  if ('output' in result) {
1006
1132
  const latency = (Date.now() - startTime) / 1000;
1007
1133
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
1134
+ const formattedOutput = formatResponseOpenAI({
1135
+ output: result.output
1136
+ });
1008
1137
  await sendEventToPosthog({
1009
1138
  client: this.phClient,
1010
1139
  ...posthogParams,
@@ -1012,9 +1141,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1012
1141
  model: openAIParams.model,
1013
1142
  provider: 'openai',
1014
1143
  input: formatOpenAIResponsesInput(openAIParams.input, openAIParams.instructions),
1015
- output: formatResponseOpenAI({
1016
- output: result.output
1017
- }),
1144
+ output: formattedOutput,
1018
1145
  latency,
1019
1146
  baseURL: this.baseURL,
1020
1147
  params: body,
@@ -1023,7 +1150,8 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1023
1150
  inputTokens: result.usage?.input_tokens ?? 0,
1024
1151
  outputTokens: result.usage?.output_tokens ?? 0,
1025
1152
  reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
1026
- cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0
1153
+ cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
1154
+ webSearchCount: calculateWebSearchCount(result)
1027
1155
  },
1028
1156
  tools: availableTools
1029
1157
  });
@@ -1061,9 +1189,9 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1061
1189
  } = extractPosthogParams(body);
1062
1190
  const startTime = Date.now();
1063
1191
  const originalCreate = super.create.bind(this);
1064
- const originalSelf = this;
1065
- const tempCreate = originalSelf.create;
1066
- originalSelf.create = originalCreate;
1192
+ const originalSelfRecord = this;
1193
+ const tempCreate = originalSelfRecord['create'];
1194
+ originalSelfRecord['create'] = originalCreate;
1067
1195
  try {
1068
1196
  const parentPromise = super.parse(openAIParams, options);
1069
1197
  const wrappedPromise = parentPromise.then(async result => {
@@ -1112,7 +1240,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1112
1240
  return wrappedPromise;
1113
1241
  } finally {
1114
1242
  // Restore our wrapped create method
1115
- originalSelf.create = tempCreate;
1243
+ originalSelfRecord['create'] = tempCreate;
1116
1244
  }
1117
1245
  }
1118
1246
  };
@@ -1858,11 +1986,29 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1858
1986
  cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
1859
1987
  } : {})
1860
1988
  };
1989
+ // Calculate web search count based on provider
1990
+ let webSearchCount = 0;
1991
+ if (providerMetadata?.anthropic && typeof providerMetadata.anthropic === 'object' && 'server_tool_use' in providerMetadata.anthropic) {
1992
+ // Anthropic-specific extraction
1993
+ const serverToolUse = providerMetadata.anthropic.server_tool_use;
1994
+ if (serverToolUse && typeof serverToolUse === 'object' && 'web_search_requests' in serverToolUse && typeof serverToolUse.web_search_requests === 'number') {
1995
+ webSearchCount = serverToolUse.web_search_requests;
1996
+ }
1997
+ } else {
1998
+ // For other providers through Vercel, pass available metadata to helper
1999
+ // Note: Vercel abstracts provider responses, so we may not have access to
2000
+ // raw citations/annotations unless Vercel exposes them in usage/metadata
2001
+ webSearchCount = calculateWebSearchCount({
2002
+ usage: result.usage,
2003
+ providerMetadata: providerMetadata
2004
+ });
2005
+ }
1861
2006
  const usage = {
1862
2007
  inputTokens: result.usage.inputTokens,
1863
2008
  outputTokens: result.usage.outputTokens,
1864
2009
  reasoningTokens: result.usage.reasoningTokens,
1865
2010
  cacheReadInputTokens: result.usage.cachedInputTokens,
2011
+ webSearchCount,
1866
2012
  ...additionalTokenValues
1867
2013
  };
1868
2014
  await sendEventToPosthog({
@@ -1916,6 +2062,7 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1916
2062
  let generatedText = '';
1917
2063
  let reasoningText = '';
1918
2064
  let usage = {};
2065
+ let providerMetadata = undefined;
1919
2066
  const mergedParams = {
1920
2067
  ...options,
1921
2068
  ...mapVercelParams(params),
@@ -1973,12 +2120,10 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1973
2120
  });
1974
2121
  }
1975
2122
  if (chunk.type === 'finish') {
1976
- const providerMetadata = chunk.providerMetadata;
1977
- const additionalTokenValues = {
1978
- ...(providerMetadata?.anthropic ? {
1979
- cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
1980
- } : {})
1981
- };
2123
+ providerMetadata = chunk.providerMetadata;
2124
+ const additionalTokenValues = providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'cacheCreationInputTokens' in providerMetadata.anthropic ? {
2125
+ cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
2126
+ } : {};
1982
2127
  usage = {
1983
2128
  inputTokens: chunk.usage?.inputTokens,
1984
2129
  outputTokens: chunk.usage?.outputTokens,
@@ -2023,6 +2168,28 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
2023
2168
  role: 'assistant',
2024
2169
  content: content.length === 1 && content[0].type === 'text' ? content[0].text : content
2025
2170
  }] : [];
2171
+ // Calculate web search count based on provider
2172
+ let webSearchCount = 0;
2173
+ if (providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'server_tool_use' in providerMetadata.anthropic) {
2174
+ // Anthropic-specific extraction
2175
+ const serverToolUse = providerMetadata.anthropic.server_tool_use;
2176
+ if (serverToolUse && typeof serverToolUse === 'object' && 'web_search_requests' in serverToolUse && typeof serverToolUse.web_search_requests === 'number') {
2177
+ webSearchCount = serverToolUse.web_search_requests;
2178
+ }
2179
+ } else {
2180
+ // For other providers through Vercel, pass available metadata to helper
2181
+ // Note: Vercel abstracts provider responses, so we may not have access to
2182
+ // raw citations/annotations unless Vercel exposes them in usage/metadata
2183
+ webSearchCount = calculateWebSearchCount({
2184
+ usage: usage,
2185
+ providerMetadata: providerMetadata
2186
+ });
2187
+ }
2188
+ // Update usage with web search count
2189
+ const finalUsage = {
2190
+ ...usage,
2191
+ webSearchCount
2192
+ };
2026
2193
  await sendEventToPosthog({
2027
2194
  client: phClient,
2028
2195
  distinctId: options.posthogDistinctId,
@@ -2035,7 +2202,7 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
2035
2202
  baseURL,
2036
2203
  params: mergedParams,
2037
2204
  httpStatus: 200,
2038
- usage,
2205
+ usage: finalUsage,
2039
2206
  tools: availableTools,
2040
2207
  captureImmediate: options.posthogCaptureImmediate
2041
2208
  });
@@ -2121,7 +2288,8 @@ class WrappedMessages extends AnthropicOriginal.Messages {
2121
2288
  inputTokens: 0,
2122
2289
  outputTokens: 0,
2123
2290
  cacheCreationInputTokens: 0,
2124
- cacheReadInputTokens: 0
2291
+ cacheReadInputTokens: 0,
2292
+ webSearchCount: 0
2125
2293
  };
2126
2294
  if ('tee' in value) {
2127
2295
  const [stream1, stream2] = value.tee();
@@ -2198,9 +2366,14 @@ class WrappedMessages extends AnthropicOriginal.Messages {
2198
2366
  usage.inputTokens = chunk.message.usage.input_tokens ?? 0;
2199
2367
  usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0;
2200
2368
  usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0;
2369
+ usage.webSearchCount = chunk.message.usage.server_tool_use?.web_search_requests ?? 0;
2201
2370
  }
2202
2371
  if ('usage' in chunk) {
2203
2372
  usage.outputTokens = chunk.usage.output_tokens ?? 0;
2373
+ // Update web search count if present in delta
2374
+ if (chunk.usage.server_tool_use?.web_search_requests !== undefined) {
2375
+ usage.webSearchCount = chunk.usage.server_tool_use.web_search_requests;
2376
+ }
2204
2377
  }
2205
2378
  }
2206
2379
  const latency = (Date.now() - startTime) / 1000;
@@ -2277,7 +2450,8 @@ class WrappedMessages extends AnthropicOriginal.Messages {
2277
2450
  inputTokens: result.usage.input_tokens ?? 0,
2278
2451
  outputTokens: result.usage.output_tokens ?? 0,
2279
2452
  cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,
2280
- cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0
2453
+ cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0,
2454
+ webSearchCount: result.usage.server_tool_use?.web_search_requests ?? 0
2281
2455
  },
2282
2456
  tools: availableTools
2283
2457
  });
@@ -2351,7 +2525,8 @@ class WrappedModels {
2351
2525
  inputTokens: metadata?.promptTokenCount ?? 0,
2352
2526
  outputTokens: metadata?.candidatesTokenCount ?? 0,
2353
2527
  reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
2354
- cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0
2528
+ cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0,
2529
+ webSearchCount: calculateGoogleWebSearchCount(response)
2355
2530
  },
2356
2531
  tools: availableTools
2357
2532
  });
@@ -2388,11 +2563,16 @@ class WrappedModels {
2388
2563
  const accumulatedContent = [];
2389
2564
  let usage = {
2390
2565
  inputTokens: 0,
2391
- outputTokens: 0
2566
+ outputTokens: 0,
2567
+ webSearchCount: 0
2392
2568
  };
2393
2569
  try {
2394
2570
  const stream = await this.client.models.generateContentStream(geminiParams);
2395
2571
  for await (const chunk of stream) {
2572
+ const chunkWebSearchCount = calculateGoogleWebSearchCount(chunk);
2573
+ if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
2574
+ usage.webSearchCount = chunkWebSearchCount;
2575
+ }
2396
2576
  // Handle text content
2397
2577
  if (chunk.text) {
2398
2578
  // Find if we already have a text item to append to
@@ -2441,7 +2621,8 @@ class WrappedModels {
2441
2621
  inputTokens: metadata.promptTokenCount ?? 0,
2442
2622
  outputTokens: metadata.candidatesTokenCount ?? 0,
2443
2623
  reasoningTokens: metadata.thoughtsTokenCount ?? 0,
2444
- cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0
2624
+ cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0,
2625
+ webSearchCount: usage.webSearchCount
2445
2626
  };
2446
2627
  }
2447
2628
  yield chunk;
@@ -2464,7 +2645,10 @@ class WrappedModels {
2464
2645
  baseURL: 'https://generativelanguage.googleapis.com',
2465
2646
  params: params,
2466
2647
  httpStatus: 200,
2467
- usage,
2648
+ usage: {
2649
+ ...usage,
2650
+ webSearchCount: usage.webSearchCount
2651
+ },
2468
2652
  tools: availableTools
2469
2653
  });
2470
2654
  } catch (error) {
@@ -2607,6 +2791,66 @@ class WrappedModels {
2607
2791
  return messages;
2608
2792
  }
2609
2793
  }
2794
+ /**
2795
+ * Detect if Google Search grounding was used in the response.
2796
+ * Gemini bills per request that uses grounding, not per individual query.
2797
+ * Returns 1 if grounding was used, 0 otherwise.
2798
+ */
2799
+ function calculateGoogleWebSearchCount(response) {
2800
+ if (!response || typeof response !== 'object' || !('candidates' in response)) {
2801
+ return 0;
2802
+ }
2803
+ const candidates = response.candidates;
2804
+ if (!Array.isArray(candidates)) {
2805
+ return 0;
2806
+ }
2807
+ const hasGrounding = candidates.some(candidate => {
2808
+ if (!candidate || typeof candidate !== 'object') {
2809
+ return false;
2810
+ }
2811
+ // Check for grounding metadata
2812
+ if ('groundingMetadata' in candidate && candidate.groundingMetadata) {
2813
+ const metadata = candidate.groundingMetadata;
2814
+ if (typeof metadata === 'object') {
2815
+ // Check if web_search_queries exists and is non-empty
2816
+ if ('webSearchQueries' in metadata && Array.isArray(metadata.webSearchQueries) && metadata.webSearchQueries.length > 0) {
2817
+ return true;
2818
+ }
2819
+ // Check if grounding_chunks exists and is non-empty
2820
+ if ('groundingChunks' in metadata && Array.isArray(metadata.groundingChunks) && metadata.groundingChunks.length > 0) {
2821
+ return true;
2822
+ }
2823
+ }
2824
+ }
2825
+ // Check for google search in function calls
2826
+ if ('content' in candidate && candidate.content && typeof candidate.content === 'object') {
2827
+ const content = candidate.content;
2828
+ if ('parts' in content && Array.isArray(content.parts)) {
2829
+ return content.parts.some(part => {
2830
+ if (!part || typeof part !== 'object' || !('functionCall' in part)) {
2831
+ return false;
2832
+ }
2833
+ const functionCall = part.functionCall;
2834
+ if (functionCall && typeof functionCall === 'object' && 'name' in functionCall && typeof functionCall.name === 'string') {
2835
+ return functionCall.name.includes('google_search') || functionCall.name.includes('grounding');
2836
+ }
2837
+ return false;
2838
+ });
2839
+ }
2840
+ }
2841
+ return false;
2842
+ });
2843
+ return hasGrounding ? 1 : 0;
2844
+ }
2845
+
2846
+ //#region rolldown:runtime
2847
+ var __defProp = Object.defineProperty;
2848
+ var __export = (target, all) => {
2849
+ for (var name in all) __defProp(target, name, {
2850
+ get: all[name],
2851
+ enumerable: true
2852
+ });
2853
+ };
2610
2854
 
2611
2855
  function getDefaultExportFromCjs (x) {
2612
2856
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -2760,370 +3004,304 @@ function requireCamelcase () {
2760
3004
 
2761
3005
  requireCamelcase();
2762
3006
 
3007
+ //#region src/load/map_keys.ts
2763
3008
  function keyToJson(key, map) {
2764
- return map?.[key] || snakeCase(key);
3009
+ return map?.[key] || snakeCase(key);
2765
3010
  }
2766
3011
  function mapKeys(fields, mapper, map) {
2767
- const mapped = {};
2768
- for (const key in fields) {
2769
- if (Object.hasOwn(fields, key)) {
2770
- mapped[mapper(key, map)] = fields[key];
2771
- }
2772
- }
2773
- return mapped;
3012
+ const mapped = {};
3013
+ for (const key in fields) if (Object.hasOwn(fields, key)) mapped[mapper(key, map)] = fields[key];
3014
+ return mapped;
2774
3015
  }
2775
3016
 
3017
+ //#region src/load/serializable.ts
3018
+ var serializable_exports = {};
3019
+ __export(serializable_exports, {
3020
+ Serializable: () => Serializable,
3021
+ get_lc_unique_name: () => get_lc_unique_name
3022
+ });
2776
3023
  function shallowCopy(obj) {
2777
- return Array.isArray(obj) ? [...obj] : { ...obj };
3024
+ return Array.isArray(obj) ? [...obj] : { ...obj };
2778
3025
  }
2779
3026
  function replaceSecrets(root, secretsMap) {
2780
- const result = shallowCopy(root);
2781
- for (const [path, secretId] of Object.entries(secretsMap)) {
2782
- const [last, ...partsReverse] = path.split(".").reverse();
2783
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2784
- let current = result;
2785
- for (const part of partsReverse.reverse()) {
2786
- if (current[part] === undefined) {
2787
- break;
2788
- }
2789
- current[part] = shallowCopy(current[part]);
2790
- current = current[part];
2791
- }
2792
- if (current[last] !== undefined) {
2793
- current[last] = {
2794
- lc: 1,
2795
- type: "secret",
2796
- id: [secretId],
2797
- };
2798
- }
2799
- }
2800
- return result;
3027
+ const result = shallowCopy(root);
3028
+ for (const [path, secretId] of Object.entries(secretsMap)) {
3029
+ const [last, ...partsReverse] = path.split(".").reverse();
3030
+ let current = result;
3031
+ for (const part of partsReverse.reverse()) {
3032
+ if (current[part] === void 0) break;
3033
+ current[part] = shallowCopy(current[part]);
3034
+ current = current[part];
3035
+ }
3036
+ if (current[last] !== void 0) current[last] = {
3037
+ lc: 1,
3038
+ type: "secret",
3039
+ id: [secretId]
3040
+ };
3041
+ }
3042
+ return result;
2801
3043
  }
2802
3044
  /**
2803
- * Get a unique name for the module, rather than parent class implementations.
2804
- * Should not be subclassed, subclass lc_name above instead.
2805
- */
2806
- function get_lc_unique_name(
2807
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
2808
- serializableClass) {
2809
- // "super" here would refer to the parent class of Serializable,
2810
- // when we want the parent class of the module actually calling this method.
2811
- const parentClass = Object.getPrototypeOf(serializableClass);
2812
- const lcNameIsSubclassed = typeof serializableClass.lc_name === "function" &&
2813
- (typeof parentClass.lc_name !== "function" ||
2814
- serializableClass.lc_name() !== parentClass.lc_name());
2815
- if (lcNameIsSubclassed) {
2816
- return serializableClass.lc_name();
2817
- }
2818
- else {
2819
- return serializableClass.name;
2820
- }
2821
- }
2822
- class Serializable {
2823
- /**
2824
- * The name of the serializable. Override to provide an alias or
2825
- * to preserve the serialized module name in minified environments.
2826
- *
2827
- * Implemented as a static method to support loading logic.
2828
- */
2829
- static lc_name() {
2830
- return this.name;
2831
- }
2832
- /**
2833
- * The final serialized identifier for the module.
2834
- */
2835
- get lc_id() {
2836
- return [
2837
- ...this.lc_namespace,
2838
- get_lc_unique_name(this.constructor),
2839
- ];
2840
- }
2841
- /**
2842
- * A map of secrets, which will be omitted from serialization.
2843
- * Keys are paths to the secret in constructor args, e.g. "foo.bar.baz".
2844
- * Values are the secret ids, which will be used when deserializing.
2845
- */
2846
- get lc_secrets() {
2847
- return undefined;
2848
- }
2849
- /**
2850
- * A map of additional attributes to merge with constructor args.
2851
- * Keys are the attribute names, e.g. "foo".
2852
- * Values are the attribute values, which will be serialized.
2853
- * These attributes need to be accepted by the constructor as arguments.
2854
- */
2855
- get lc_attributes() {
2856
- return undefined;
2857
- }
2858
- /**
2859
- * A map of aliases for constructor args.
2860
- * Keys are the attribute names, e.g. "foo".
2861
- * Values are the alias that will replace the key in serialization.
2862
- * This is used to eg. make argument names match Python.
2863
- */
2864
- get lc_aliases() {
2865
- return undefined;
2866
- }
2867
- /**
2868
- * A manual list of keys that should be serialized.
2869
- * If not overridden, all fields passed into the constructor will be serialized.
2870
- */
2871
- get lc_serializable_keys() {
2872
- return undefined;
2873
- }
2874
- constructor(kwargs, ..._args) {
2875
- Object.defineProperty(this, "lc_serializable", {
2876
- enumerable: true,
2877
- configurable: true,
2878
- writable: true,
2879
- value: false
2880
- });
2881
- Object.defineProperty(this, "lc_kwargs", {
2882
- enumerable: true,
2883
- configurable: true,
2884
- writable: true,
2885
- value: void 0
2886
- });
2887
- if (this.lc_serializable_keys !== undefined) {
2888
- this.lc_kwargs = Object.fromEntries(Object.entries(kwargs || {}).filter(([key]) => this.lc_serializable_keys?.includes(key)));
2889
- }
2890
- else {
2891
- this.lc_kwargs = kwargs ?? {};
2892
- }
2893
- }
2894
- toJSON() {
2895
- if (!this.lc_serializable) {
2896
- return this.toJSONNotImplemented();
2897
- }
2898
- if (
2899
- // eslint-disable-next-line no-instanceof/no-instanceof
2900
- this.lc_kwargs instanceof Serializable ||
2901
- typeof this.lc_kwargs !== "object" ||
2902
- Array.isArray(this.lc_kwargs)) {
2903
- // We do not support serialization of classes with arg not a POJO
2904
- // I'm aware the check above isn't as strict as it could be
2905
- return this.toJSONNotImplemented();
2906
- }
2907
- const aliases = {};
2908
- const secrets = {};
2909
- const kwargs = Object.keys(this.lc_kwargs).reduce((acc, key) => {
2910
- acc[key] = key in this ? this[key] : this.lc_kwargs[key];
2911
- return acc;
2912
- }, {});
2913
- // get secrets, attributes and aliases from all superclasses
2914
- for (
2915
- // eslint-disable-next-line @typescript-eslint/no-this-alias
2916
- let current = Object.getPrototypeOf(this); current; current = Object.getPrototypeOf(current)) {
2917
- Object.assign(aliases, Reflect.get(current, "lc_aliases", this));
2918
- Object.assign(secrets, Reflect.get(current, "lc_secrets", this));
2919
- Object.assign(kwargs, Reflect.get(current, "lc_attributes", this));
2920
- }
2921
- // include all secrets used, even if not in kwargs,
2922
- // will be replaced with sentinel value in replaceSecrets
2923
- Object.keys(secrets).forEach((keyPath) => {
2924
- // eslint-disable-next-line @typescript-eslint/no-this-alias, @typescript-eslint/no-explicit-any
2925
- let read = this;
2926
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2927
- let write = kwargs;
2928
- const [last, ...partsReverse] = keyPath.split(".").reverse();
2929
- for (const key of partsReverse.reverse()) {
2930
- if (!(key in read) || read[key] === undefined)
2931
- return;
2932
- if (!(key in write) || write[key] === undefined) {
2933
- if (typeof read[key] === "object" && read[key] != null) {
2934
- write[key] = {};
2935
- }
2936
- else if (Array.isArray(read[key])) {
2937
- write[key] = [];
2938
- }
2939
- }
2940
- read = read[key];
2941
- write = write[key];
2942
- }
2943
- if (last in read && read[last] !== undefined) {
2944
- write[last] = write[last] || read[last];
2945
- }
2946
- });
2947
- return {
2948
- lc: 1,
2949
- type: "constructor",
2950
- id: this.lc_id,
2951
- kwargs: mapKeys(Object.keys(secrets).length ? replaceSecrets(kwargs, secrets) : kwargs, keyToJson, aliases),
2952
- };
2953
- }
2954
- toJSONNotImplemented() {
2955
- return {
2956
- lc: 1,
2957
- type: "not_implemented",
2958
- id: this.lc_id,
2959
- };
2960
- }
3045
+ * Get a unique name for the module, rather than parent class implementations.
3046
+ * Should not be subclassed, subclass lc_name above instead.
3047
+ */
3048
+ function get_lc_unique_name(serializableClass) {
3049
+ const parentClass = Object.getPrototypeOf(serializableClass);
3050
+ const lcNameIsSubclassed = typeof serializableClass.lc_name === "function" && (typeof parentClass.lc_name !== "function" || serializableClass.lc_name() !== parentClass.lc_name());
3051
+ if (lcNameIsSubclassed) return serializableClass.lc_name();
3052
+ else return serializableClass.name;
2961
3053
  }
3054
+ var Serializable = class Serializable {
3055
+ lc_serializable = false;
3056
+ lc_kwargs;
3057
+ /**
3058
+ * The name of the serializable. Override to provide an alias or
3059
+ * to preserve the serialized module name in minified environments.
3060
+ *
3061
+ * Implemented as a static method to support loading logic.
3062
+ */
3063
+ static lc_name() {
3064
+ return this.name;
3065
+ }
3066
+ /**
3067
+ * The final serialized identifier for the module.
3068
+ */
3069
+ get lc_id() {
3070
+ return [...this.lc_namespace, get_lc_unique_name(this.constructor)];
3071
+ }
3072
+ /**
3073
+ * A map of secrets, which will be omitted from serialization.
3074
+ * Keys are paths to the secret in constructor args, e.g. "foo.bar.baz".
3075
+ * Values are the secret ids, which will be used when deserializing.
3076
+ */
3077
+ get lc_secrets() {
3078
+ return void 0;
3079
+ }
3080
+ /**
3081
+ * A map of additional attributes to merge with constructor args.
3082
+ * Keys are the attribute names, e.g. "foo".
3083
+ * Values are the attribute values, which will be serialized.
3084
+ * These attributes need to be accepted by the constructor as arguments.
3085
+ */
3086
+ get lc_attributes() {
3087
+ return void 0;
3088
+ }
3089
+ /**
3090
+ * A map of aliases for constructor args.
3091
+ * Keys are the attribute names, e.g. "foo".
3092
+ * Values are the alias that will replace the key in serialization.
3093
+ * This is used to eg. make argument names match Python.
3094
+ */
3095
+ get lc_aliases() {
3096
+ return void 0;
3097
+ }
3098
+ /**
3099
+ * A manual list of keys that should be serialized.
3100
+ * If not overridden, all fields passed into the constructor will be serialized.
3101
+ */
3102
+ get lc_serializable_keys() {
3103
+ return void 0;
3104
+ }
3105
+ constructor(kwargs, ..._args) {
3106
+ if (this.lc_serializable_keys !== void 0) this.lc_kwargs = Object.fromEntries(Object.entries(kwargs || {}).filter(([key]) => this.lc_serializable_keys?.includes(key)));
3107
+ else this.lc_kwargs = kwargs ?? {};
3108
+ }
3109
+ toJSON() {
3110
+ if (!this.lc_serializable) return this.toJSONNotImplemented();
3111
+ if (this.lc_kwargs instanceof Serializable || typeof this.lc_kwargs !== "object" || Array.isArray(this.lc_kwargs)) return this.toJSONNotImplemented();
3112
+ const aliases = {};
3113
+ const secrets = {};
3114
+ const kwargs = Object.keys(this.lc_kwargs).reduce((acc, key) => {
3115
+ acc[key] = key in this ? this[key] : this.lc_kwargs[key];
3116
+ return acc;
3117
+ }, {});
3118
+ for (let current = Object.getPrototypeOf(this); current; current = Object.getPrototypeOf(current)) {
3119
+ Object.assign(aliases, Reflect.get(current, "lc_aliases", this));
3120
+ Object.assign(secrets, Reflect.get(current, "lc_secrets", this));
3121
+ Object.assign(kwargs, Reflect.get(current, "lc_attributes", this));
3122
+ }
3123
+ Object.keys(secrets).forEach((keyPath) => {
3124
+ let read = this;
3125
+ let write = kwargs;
3126
+ const [last, ...partsReverse] = keyPath.split(".").reverse();
3127
+ for (const key of partsReverse.reverse()) {
3128
+ if (!(key in read) || read[key] === void 0) return;
3129
+ if (!(key in write) || write[key] === void 0) {
3130
+ if (typeof read[key] === "object" && read[key] != null) write[key] = {};
3131
+ else if (Array.isArray(read[key])) write[key] = [];
3132
+ }
3133
+ read = read[key];
3134
+ write = write[key];
3135
+ }
3136
+ if (last in read && read[last] !== void 0) write[last] = write[last] || read[last];
3137
+ });
3138
+ return {
3139
+ lc: 1,
3140
+ type: "constructor",
3141
+ id: this.lc_id,
3142
+ kwargs: mapKeys(Object.keys(secrets).length ? replaceSecrets(kwargs, secrets) : kwargs, keyToJson, aliases)
3143
+ };
3144
+ }
3145
+ toJSONNotImplemented() {
3146
+ return {
3147
+ lc: 1,
3148
+ type: "not_implemented",
3149
+ id: this.lc_id
3150
+ };
3151
+ }
3152
+ };
2962
3153
 
2963
- // Supabase Edge Function provides a `Deno` global object
2964
- // without `version` property
3154
+ //#region src/utils/env.ts
3155
+ var env_exports = {};
3156
+ __export(env_exports, {
3157
+ getEnv: () => getEnv,
3158
+ getEnvironmentVariable: () => getEnvironmentVariable,
3159
+ getRuntimeEnvironment: () => getRuntimeEnvironment,
3160
+ isBrowser: () => isBrowser,
3161
+ isDeno: () => isDeno,
3162
+ isJsDom: () => isJsDom,
3163
+ isNode: () => isNode,
3164
+ isWebWorker: () => isWebWorker
3165
+ });
3166
+ const isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
3167
+ const isWebWorker = () => typeof globalThis === "object" && globalThis.constructor && globalThis.constructor.name === "DedicatedWorkerGlobalScope";
3168
+ const isJsDom = () => typeof window !== "undefined" && window.name === "nodejs" || typeof navigator !== "undefined" && navigator.userAgent.includes("jsdom");
2965
3169
  const isDeno = () => typeof Deno !== "undefined";
3170
+ const isNode = () => typeof process !== "undefined" && typeof process.versions !== "undefined" && typeof process.versions.node !== "undefined" && !isDeno();
3171
+ const getEnv = () => {
3172
+ let env;
3173
+ if (isBrowser()) env = "browser";
3174
+ else if (isNode()) env = "node";
3175
+ else if (isWebWorker()) env = "webworker";
3176
+ else if (isJsDom()) env = "jsdom";
3177
+ else if (isDeno()) env = "deno";
3178
+ else env = "other";
3179
+ return env;
3180
+ };
3181
+ let runtimeEnvironment;
3182
+ function getRuntimeEnvironment() {
3183
+ if (runtimeEnvironment === void 0) {
3184
+ const env = getEnv();
3185
+ runtimeEnvironment = {
3186
+ library: "langchain-js",
3187
+ runtime: env
3188
+ };
3189
+ }
3190
+ return runtimeEnvironment;
3191
+ }
2966
3192
  function getEnvironmentVariable(name) {
2967
- // Certain Deno setups will throw an error if you try to access environment variables
2968
- // https://github.com/langchain-ai/langchainjs/issues/1412
2969
- try {
2970
- if (typeof process !== "undefined") {
2971
- // eslint-disable-next-line no-process-env
2972
- return process.env?.[name];
2973
- }
2974
- else if (isDeno()) {
2975
- return Deno?.env.get(name);
2976
- }
2977
- else {
2978
- return undefined;
2979
- }
2980
- }
2981
- catch (e) {
2982
- return undefined;
2983
- }
3193
+ try {
3194
+ if (typeof process !== "undefined") return process.env?.[name];
3195
+ else if (isDeno()) return Deno?.env.get(name);
3196
+ else return void 0;
3197
+ } catch {
3198
+ return void 0;
3199
+ }
2984
3200
  }
2985
3201
 
3202
+ //#region src/callbacks/base.ts
3203
+ var base_exports = {};
3204
+ __export(base_exports, {
3205
+ BaseCallbackHandler: () => BaseCallbackHandler,
3206
+ callbackHandlerPrefersStreaming: () => callbackHandlerPrefersStreaming,
3207
+ isBaseCallbackHandler: () => isBaseCallbackHandler
3208
+ });
2986
3209
  /**
2987
- * Abstract class that provides a set of optional methods that can be
2988
- * overridden in derived classes to handle various events during the
2989
- * execution of a LangChain application.
2990
- */
2991
- class BaseCallbackHandlerMethodsClass {
3210
+ * Abstract class that provides a set of optional methods that can be
3211
+ * overridden in derived classes to handle various events during the
3212
+ * execution of a LangChain application.
3213
+ */
3214
+ var BaseCallbackHandlerMethodsClass = class {};
3215
+ function callbackHandlerPrefersStreaming(x) {
3216
+ return "lc_prefer_streaming" in x && x.lc_prefer_streaming;
2992
3217
  }
2993
3218
  /**
2994
- * Abstract base class for creating callback handlers in the LangChain
2995
- * framework. It provides a set of optional methods that can be overridden
2996
- * in derived classes to handle various events during the execution of a
2997
- * LangChain application.
2998
- */
2999
- class BaseCallbackHandler extends BaseCallbackHandlerMethodsClass {
3000
- get lc_namespace() {
3001
- return ["langchain_core", "callbacks", this.name];
3002
- }
3003
- get lc_secrets() {
3004
- return undefined;
3005
- }
3006
- get lc_attributes() {
3007
- return undefined;
3008
- }
3009
- get lc_aliases() {
3010
- return undefined;
3011
- }
3012
- get lc_serializable_keys() {
3013
- return undefined;
3014
- }
3015
- /**
3016
- * The name of the serializable. Override to provide an alias or
3017
- * to preserve the serialized module name in minified environments.
3018
- *
3019
- * Implemented as a static method to support loading logic.
3020
- */
3021
- static lc_name() {
3022
- return this.name;
3023
- }
3024
- /**
3025
- * The final serialized identifier for the module.
3026
- */
3027
- get lc_id() {
3028
- return [
3029
- ...this.lc_namespace,
3030
- get_lc_unique_name(this.constructor),
3031
- ];
3032
- }
3033
- constructor(input) {
3034
- super();
3035
- Object.defineProperty(this, "lc_serializable", {
3036
- enumerable: true,
3037
- configurable: true,
3038
- writable: true,
3039
- value: false
3040
- });
3041
- Object.defineProperty(this, "lc_kwargs", {
3042
- enumerable: true,
3043
- configurable: true,
3044
- writable: true,
3045
- value: void 0
3046
- });
3047
- Object.defineProperty(this, "ignoreLLM", {
3048
- enumerable: true,
3049
- configurable: true,
3050
- writable: true,
3051
- value: false
3052
- });
3053
- Object.defineProperty(this, "ignoreChain", {
3054
- enumerable: true,
3055
- configurable: true,
3056
- writable: true,
3057
- value: false
3058
- });
3059
- Object.defineProperty(this, "ignoreAgent", {
3060
- enumerable: true,
3061
- configurable: true,
3062
- writable: true,
3063
- value: false
3064
- });
3065
- Object.defineProperty(this, "ignoreRetriever", {
3066
- enumerable: true,
3067
- configurable: true,
3068
- writable: true,
3069
- value: false
3070
- });
3071
- Object.defineProperty(this, "ignoreCustomEvent", {
3072
- enumerable: true,
3073
- configurable: true,
3074
- writable: true,
3075
- value: false
3076
- });
3077
- Object.defineProperty(this, "raiseError", {
3078
- enumerable: true,
3079
- configurable: true,
3080
- writable: true,
3081
- value: false
3082
- });
3083
- Object.defineProperty(this, "awaitHandlers", {
3084
- enumerable: true,
3085
- configurable: true,
3086
- writable: true,
3087
- value: getEnvironmentVariable("LANGCHAIN_CALLBACKS_BACKGROUND") === "false"
3088
- });
3089
- this.lc_kwargs = input || {};
3090
- if (input) {
3091
- this.ignoreLLM = input.ignoreLLM ?? this.ignoreLLM;
3092
- this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
3093
- this.ignoreAgent = input.ignoreAgent ?? this.ignoreAgent;
3094
- this.ignoreRetriever = input.ignoreRetriever ?? this.ignoreRetriever;
3095
- this.ignoreCustomEvent =
3096
- input.ignoreCustomEvent ?? this.ignoreCustomEvent;
3097
- this.raiseError = input.raiseError ?? this.raiseError;
3098
- this.awaitHandlers =
3099
- this.raiseError || (input._awaitHandler ?? this.awaitHandlers);
3100
- }
3101
- }
3102
- copy() {
3103
- return new this.constructor(this);
3104
- }
3105
- toJSON() {
3106
- return Serializable.prototype.toJSON.call(this);
3107
- }
3108
- toJSONNotImplemented() {
3109
- return Serializable.prototype.toJSONNotImplemented.call(this);
3110
- }
3111
- static fromMethods(methods) {
3112
- class Handler extends BaseCallbackHandler {
3113
- constructor() {
3114
- super();
3115
- Object.defineProperty(this, "name", {
3116
- enumerable: true,
3117
- configurable: true,
3118
- writable: true,
3119
- value: uuid__namespace.v4()
3120
- });
3121
- Object.assign(this, methods);
3122
- }
3123
- }
3124
- return new Handler();
3125
- }
3126
- }
3219
+ * Abstract base class for creating callback handlers in the LangChain
3220
+ * framework. It provides a set of optional methods that can be overridden
3221
+ * in derived classes to handle various events during the execution of a
3222
+ * LangChain application.
3223
+ */
3224
+ var BaseCallbackHandler = class extends BaseCallbackHandlerMethodsClass {
3225
+ lc_serializable = false;
3226
+ get lc_namespace() {
3227
+ return [
3228
+ "langchain_core",
3229
+ "callbacks",
3230
+ this.name
3231
+ ];
3232
+ }
3233
+ get lc_secrets() {
3234
+ return void 0;
3235
+ }
3236
+ get lc_attributes() {
3237
+ return void 0;
3238
+ }
3239
+ get lc_aliases() {
3240
+ return void 0;
3241
+ }
3242
+ get lc_serializable_keys() {
3243
+ return void 0;
3244
+ }
3245
+ /**
3246
+ * The name of the serializable. Override to provide an alias or
3247
+ * to preserve the serialized module name in minified environments.
3248
+ *
3249
+ * Implemented as a static method to support loading logic.
3250
+ */
3251
+ static lc_name() {
3252
+ return this.name;
3253
+ }
3254
+ /**
3255
+ * The final serialized identifier for the module.
3256
+ */
3257
+ get lc_id() {
3258
+ return [...this.lc_namespace, get_lc_unique_name(this.constructor)];
3259
+ }
3260
+ lc_kwargs;
3261
+ ignoreLLM = false;
3262
+ ignoreChain = false;
3263
+ ignoreAgent = false;
3264
+ ignoreRetriever = false;
3265
+ ignoreCustomEvent = false;
3266
+ raiseError = false;
3267
+ awaitHandlers = getEnvironmentVariable("LANGCHAIN_CALLBACKS_BACKGROUND") === "false";
3268
+ constructor(input) {
3269
+ super();
3270
+ this.lc_kwargs = input || {};
3271
+ if (input) {
3272
+ this.ignoreLLM = input.ignoreLLM ?? this.ignoreLLM;
3273
+ this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
3274
+ this.ignoreAgent = input.ignoreAgent ?? this.ignoreAgent;
3275
+ this.ignoreRetriever = input.ignoreRetriever ?? this.ignoreRetriever;
3276
+ this.ignoreCustomEvent = input.ignoreCustomEvent ?? this.ignoreCustomEvent;
3277
+ this.raiseError = input.raiseError ?? this.raiseError;
3278
+ this.awaitHandlers = this.raiseError || (input._awaitHandler ?? this.awaitHandlers);
3279
+ }
3280
+ }
3281
+ copy() {
3282
+ return new this.constructor(this);
3283
+ }
3284
+ toJSON() {
3285
+ return Serializable.prototype.toJSON.call(this);
3286
+ }
3287
+ toJSONNotImplemented() {
3288
+ return Serializable.prototype.toJSONNotImplemented.call(this);
3289
+ }
3290
+ static fromMethods(methods) {
3291
+ class Handler extends BaseCallbackHandler {
3292
+ name = uuid__namespace.v4();
3293
+ constructor() {
3294
+ super();
3295
+ Object.assign(this, methods);
3296
+ }
3297
+ }
3298
+ return new Handler();
3299
+ }
3300
+ };
3301
+ const isBaseCallbackHandler = (x) => {
3302
+ const callbackHandler = x;
3303
+ return callbackHandler !== void 0 && typeof callbackHandler.copy === "function" && typeof callbackHandler.name === "string" && typeof callbackHandler.awaitHandlers === "boolean";
3304
+ };
3127
3305
 
3128
3306
  class LangChainCallbackHandler extends BaseCallbackHandler {
3129
3307
  constructor(options) {
@@ -3427,6 +3605,9 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3427
3605
  if (additionalTokenData.reasoningTokens) {
3428
3606
  eventProperties['$ai_reasoning_tokens'] = additionalTokenData.reasoningTokens;
3429
3607
  }
3608
+ if (additionalTokenData.webSearchCount !== undefined) {
3609
+ eventProperties['$ai_web_search_count'] = additionalTokenData.webSearchCount;
3610
+ }
3430
3611
  // Handle generations/completions
3431
3612
  let completions;
3432
3613
  if (output.generations && Array.isArray(output.generations)) {
@@ -3592,6 +3773,42 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3592
3773
  } else if (usage.reasoningTokens != null) {
3593
3774
  additionalTokenData.reasoningTokens = usage.reasoningTokens;
3594
3775
  }
3776
+ // Extract web search counts from various provider formats
3777
+ let webSearchCount;
3778
+ // Priority 1: Exact Count
3779
+ // Check Anthropic format (server_tool_use.web_search_requests)
3780
+ if (usage.server_tool_use?.web_search_requests !== undefined) {
3781
+ webSearchCount = usage.server_tool_use.web_search_requests;
3782
+ }
3783
+ // Priority 2: Binary Detection (1 or 0)
3784
+ // Check for citations array (Perplexity)
3785
+ else if (usage.citations && Array.isArray(usage.citations) && usage.citations.length > 0) {
3786
+ webSearchCount = 1;
3787
+ }
3788
+ // Check for search_results array (Perplexity via OpenRouter)
3789
+ else if (usage.search_results && Array.isArray(usage.search_results) && usage.search_results.length > 0) {
3790
+ webSearchCount = 1;
3791
+ }
3792
+ // Check for search_context_size (Perplexity via OpenRouter)
3793
+ else if (usage.search_context_size) {
3794
+ webSearchCount = 1;
3795
+ }
3796
+ // Check for annotations with url_citation type
3797
+ else if (usage.annotations && Array.isArray(usage.annotations)) {
3798
+ const hasUrlCitation = usage.annotations.some(ann => {
3799
+ return ann && typeof ann === 'object' && 'type' in ann && ann.type === 'url_citation';
3800
+ });
3801
+ if (hasUrlCitation) {
3802
+ webSearchCount = 1;
3803
+ }
3804
+ }
3805
+ // Check Gemini format (grounding metadata - binary 0 or 1)
3806
+ else if (usage.grounding_metadata?.grounding_support !== undefined || usage.grounding_metadata?.web_search_queries !== undefined) {
3807
+ webSearchCount = 1;
3808
+ }
3809
+ if (webSearchCount !== undefined) {
3810
+ additionalTokenData.webSearchCount = webSearchCount;
3811
+ }
3595
3812
  // In LangChain, input_tokens is the sum of input and cache read tokens.
3596
3813
  // Our cost calculation expects them to be separate, for Anthropic.
3597
3814
  if (parsedUsage.input && additionalTokenData.cacheReadInputTokens) {