@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.mjs CHANGED
@@ -6,7 +6,7 @@ import { wrapLanguageModel } from 'ai';
6
6
  import AnthropicOriginal from '@anthropic-ai/sdk';
7
7
  import { GoogleGenAI } from '@google/genai';
8
8
 
9
- var version = "6.5.1";
9
+ var version = "7.0.0";
10
10
 
11
11
  // Type guards for safer type checking
12
12
  const isString = value => {
@@ -277,6 +277,101 @@ const truncate = input => {
277
277
  }
278
278
  return `${truncatedStr}... [truncated]`;
279
279
  };
280
+ /**
281
+ * Calculate web search count from raw API response.
282
+ *
283
+ * Uses a two-tier detection strategy:
284
+ * Priority 1 (Exact Count): Count actual web search calls when available
285
+ * Priority 2 (Binary Detection): Return 1 if web search indicators are present, 0 otherwise
286
+ *
287
+ * @param result - Raw API response from any provider (OpenAI, Perplexity, OpenRouter, Gemini, etc.)
288
+ * @returns Number of web searches performed (exact count or binary 1/0)
289
+ */
290
+ function calculateWebSearchCount(result) {
291
+ if (!result || typeof result !== 'object') {
292
+ return 0;
293
+ }
294
+ // Priority 1: Exact Count
295
+ // Check for OpenAI Responses API web_search_call items
296
+ if ('output' in result && Array.isArray(result.output)) {
297
+ let count = 0;
298
+ for (const item of result.output) {
299
+ if (typeof item === 'object' && item !== null && 'type' in item && item.type === 'web_search_call') {
300
+ count++;
301
+ }
302
+ }
303
+ if (count > 0) {
304
+ return count;
305
+ }
306
+ }
307
+ // Priority 2: Binary Detection (1 or 0)
308
+ // Check for citations at root level (Perplexity)
309
+ if ('citations' in result && Array.isArray(result.citations) && result.citations.length > 0) {
310
+ return 1;
311
+ }
312
+ // Check for search_results at root level (Perplexity via OpenRouter)
313
+ if ('search_results' in result && Array.isArray(result.search_results) && result.search_results.length > 0) {
314
+ return 1;
315
+ }
316
+ // Check for usage.search_context_size (Perplexity via OpenRouter)
317
+ if ('usage' in result && typeof result.usage === 'object' && result.usage !== null) {
318
+ if ('search_context_size' in result.usage && result.usage.search_context_size) {
319
+ return 1;
320
+ }
321
+ }
322
+ // Check for annotations with url_citation in choices[].message or choices[].delta (OpenAI/Perplexity)
323
+ if ('choices' in result && Array.isArray(result.choices)) {
324
+ for (const choice of result.choices) {
325
+ if (typeof choice === 'object' && choice !== null) {
326
+ // Check both message (non-streaming) and delta (streaming) for annotations
327
+ const content = ('message' in choice ? choice.message : null) || ('delta' in choice ? choice.delta : null);
328
+ if (typeof content === 'object' && content !== null && 'annotations' in content) {
329
+ const annotations = content.annotations;
330
+ if (Array.isArray(annotations)) {
331
+ const hasUrlCitation = annotations.some(ann => {
332
+ return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
333
+ });
334
+ if (hasUrlCitation) {
335
+ return 1;
336
+ }
337
+ }
338
+ }
339
+ }
340
+ }
341
+ }
342
+ // Check for annotations in output[].content[] (OpenAI Responses API)
343
+ if ('output' in result && Array.isArray(result.output)) {
344
+ for (const item of result.output) {
345
+ if (typeof item === 'object' && item !== null && 'content' in item) {
346
+ const content = item.content;
347
+ if (Array.isArray(content)) {
348
+ for (const contentItem of content) {
349
+ if (typeof contentItem === 'object' && contentItem !== null && 'annotations' in contentItem) {
350
+ const annotations = contentItem.annotations;
351
+ if (Array.isArray(annotations)) {
352
+ const hasUrlCitation = annotations.some(ann => {
353
+ return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
354
+ });
355
+ if (hasUrlCitation) {
356
+ return 1;
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
365
+ // Check for grounding_metadata (Gemini)
366
+ if ('candidates' in result && Array.isArray(result.candidates)) {
367
+ for (const candidate of result.candidates) {
368
+ if (typeof candidate === 'object' && candidate !== null && 'grounding_metadata' in candidate && candidate.grounding_metadata) {
369
+ return 1;
370
+ }
371
+ }
372
+ }
373
+ return 0;
374
+ }
280
375
  /**
281
376
  * Extract available tool calls from the request parameters.
282
377
  * These are the tools provided to the LLM, not the tool calls in the response.
@@ -411,6 +506,9 @@ const sendEventToPosthog = async ({
411
506
  } : {}),
412
507
  ...(usage.cacheCreationInputTokens ? {
413
508
  $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
509
+ } : {}),
510
+ ...(usage.webSearchCount ? {
511
+ $ai_web_search_count: usage.webSearchCount
414
512
  } : {})
415
513
  };
416
514
  const properties = {
@@ -721,12 +819,17 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
721
819
  let accumulatedContent = '';
722
820
  let usage = {
723
821
  inputTokens: 0,
724
- outputTokens: 0
822
+ outputTokens: 0,
823
+ webSearchCount: 0
725
824
  };
726
825
  // Map to track in-progress tool calls
727
826
  const toolCallsInProgress = new Map();
728
827
  for await (const chunk of stream1) {
729
828
  const choice = chunk?.choices?.[0];
829
+ const chunkWebSearchCount = calculateWebSearchCount(chunk);
830
+ if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
831
+ usage.webSearchCount = chunkWebSearchCount;
832
+ }
730
833
  // Handle text content
731
834
  const deltaContent = choice?.delta?.content;
732
835
  if (deltaContent) {
@@ -765,6 +868,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
765
868
  // Handle usage information
766
869
  if (chunk.usage) {
767
870
  usage = {
871
+ ...usage,
768
872
  inputTokens: chunk.usage.prompt_tokens ?? 0,
769
873
  outputTokens: chunk.usage.completion_tokens ?? 0,
770
874
  reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
@@ -816,7 +920,13 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
816
920
  baseURL: this.baseURL,
817
921
  params: body,
818
922
  httpStatus: 200,
819
- usage,
923
+ usage: {
924
+ inputTokens: usage.inputTokens,
925
+ outputTokens: usage.outputTokens,
926
+ reasoningTokens: usage.reasoningTokens,
927
+ cacheReadInputTokens: usage.cacheReadInputTokens,
928
+ webSearchCount: usage.webSearchCount
929
+ },
820
930
  tools: availableTools
821
931
  });
822
932
  } catch (error) {
@@ -851,13 +961,14 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
851
961
  if ('choices' in result) {
852
962
  const latency = (Date.now() - startTime) / 1000;
853
963
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
964
+ const formattedOutput = formatResponseOpenAI(result);
854
965
  await sendEventToPosthog({
855
966
  client: this.phClient,
856
967
  ...posthogParams,
857
968
  model: openAIParams.model,
858
969
  provider: 'openai',
859
970
  input: sanitizeOpenAI(openAIParams.messages),
860
- output: formatResponseOpenAI(result),
971
+ output: formattedOutput,
861
972
  latency,
862
973
  baseURL: this.baseURL,
863
974
  params: body,
@@ -866,7 +977,8 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
866
977
  inputTokens: result.usage?.prompt_tokens ?? 0,
867
978
  outputTokens: result.usage?.completion_tokens ?? 0,
868
979
  reasoningTokens: result.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
869
- cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0
980
+ cacheReadInputTokens: result.usage?.prompt_tokens_details?.cached_tokens ?? 0,
981
+ webSearchCount: calculateWebSearchCount(result)
870
982
  },
871
983
  tools: availableTools
872
984
  });
@@ -921,14 +1033,22 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
921
1033
  let finalContent = [];
922
1034
  let usage = {
923
1035
  inputTokens: 0,
924
- outputTokens: 0
1036
+ outputTokens: 0,
1037
+ webSearchCount: 0
925
1038
  };
926
1039
  for await (const chunk of stream1) {
1040
+ if ('response' in chunk && chunk.response) {
1041
+ const chunkWebSearchCount = calculateWebSearchCount(chunk.response);
1042
+ if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
1043
+ usage.webSearchCount = chunkWebSearchCount;
1044
+ }
1045
+ }
927
1046
  if (chunk.type === 'response.completed' && 'response' in chunk && chunk.response?.output && chunk.response.output.length > 0) {
928
1047
  finalContent = chunk.response.output;
929
1048
  }
930
1049
  if ('response' in chunk && chunk.response?.usage) {
931
1050
  usage = {
1051
+ ...usage,
932
1052
  inputTokens: chunk.response.usage.input_tokens ?? 0,
933
1053
  outputTokens: chunk.response.usage.output_tokens ?? 0,
934
1054
  reasoningTokens: chunk.response.usage.output_tokens_details?.reasoning_tokens ?? 0,
@@ -950,7 +1070,13 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
950
1070
  baseURL: this.baseURL,
951
1071
  params: body,
952
1072
  httpStatus: 200,
953
- usage,
1073
+ usage: {
1074
+ inputTokens: usage.inputTokens,
1075
+ outputTokens: usage.outputTokens,
1076
+ reasoningTokens: usage.reasoningTokens,
1077
+ cacheReadInputTokens: usage.cacheReadInputTokens,
1078
+ webSearchCount: usage.webSearchCount
1079
+ },
954
1080
  tools: availableTools
955
1081
  });
956
1082
  } catch (error) {
@@ -985,6 +1111,9 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
985
1111
  if ('output' in result) {
986
1112
  const latency = (Date.now() - startTime) / 1000;
987
1113
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
1114
+ const formattedOutput = formatResponseOpenAI({
1115
+ output: result.output
1116
+ });
988
1117
  await sendEventToPosthog({
989
1118
  client: this.phClient,
990
1119
  ...posthogParams,
@@ -992,9 +1121,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
992
1121
  model: openAIParams.model,
993
1122
  provider: 'openai',
994
1123
  input: formatOpenAIResponsesInput(openAIParams.input, openAIParams.instructions),
995
- output: formatResponseOpenAI({
996
- output: result.output
997
- }),
1124
+ output: formattedOutput,
998
1125
  latency,
999
1126
  baseURL: this.baseURL,
1000
1127
  params: body,
@@ -1003,7 +1130,8 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1003
1130
  inputTokens: result.usage?.input_tokens ?? 0,
1004
1131
  outputTokens: result.usage?.output_tokens ?? 0,
1005
1132
  reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
1006
- cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0
1133
+ cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
1134
+ webSearchCount: calculateWebSearchCount(result)
1007
1135
  },
1008
1136
  tools: availableTools
1009
1137
  });
@@ -1041,9 +1169,9 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1041
1169
  } = extractPosthogParams(body);
1042
1170
  const startTime = Date.now();
1043
1171
  const originalCreate = super.create.bind(this);
1044
- const originalSelf = this;
1045
- const tempCreate = originalSelf.create;
1046
- originalSelf.create = originalCreate;
1172
+ const originalSelfRecord = this;
1173
+ const tempCreate = originalSelfRecord['create'];
1174
+ originalSelfRecord['create'] = originalCreate;
1047
1175
  try {
1048
1176
  const parentPromise = super.parse(openAIParams, options);
1049
1177
  const wrappedPromise = parentPromise.then(async result => {
@@ -1092,7 +1220,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1092
1220
  return wrappedPromise;
1093
1221
  } finally {
1094
1222
  // Restore our wrapped create method
1095
- originalSelf.create = tempCreate;
1223
+ originalSelfRecord['create'] = tempCreate;
1096
1224
  }
1097
1225
  }
1098
1226
  };
@@ -1838,11 +1966,29 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1838
1966
  cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
1839
1967
  } : {})
1840
1968
  };
1969
+ // Calculate web search count based on provider
1970
+ let webSearchCount = 0;
1971
+ if (providerMetadata?.anthropic && typeof providerMetadata.anthropic === 'object' && 'server_tool_use' in providerMetadata.anthropic) {
1972
+ // Anthropic-specific extraction
1973
+ const serverToolUse = providerMetadata.anthropic.server_tool_use;
1974
+ if (serverToolUse && typeof serverToolUse === 'object' && 'web_search_requests' in serverToolUse && typeof serverToolUse.web_search_requests === 'number') {
1975
+ webSearchCount = serverToolUse.web_search_requests;
1976
+ }
1977
+ } else {
1978
+ // For other providers through Vercel, pass available metadata to helper
1979
+ // Note: Vercel abstracts provider responses, so we may not have access to
1980
+ // raw citations/annotations unless Vercel exposes them in usage/metadata
1981
+ webSearchCount = calculateWebSearchCount({
1982
+ usage: result.usage,
1983
+ providerMetadata: providerMetadata
1984
+ });
1985
+ }
1841
1986
  const usage = {
1842
1987
  inputTokens: result.usage.inputTokens,
1843
1988
  outputTokens: result.usage.outputTokens,
1844
1989
  reasoningTokens: result.usage.reasoningTokens,
1845
1990
  cacheReadInputTokens: result.usage.cachedInputTokens,
1991
+ webSearchCount,
1846
1992
  ...additionalTokenValues
1847
1993
  };
1848
1994
  await sendEventToPosthog({
@@ -1896,6 +2042,7 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1896
2042
  let generatedText = '';
1897
2043
  let reasoningText = '';
1898
2044
  let usage = {};
2045
+ let providerMetadata = undefined;
1899
2046
  const mergedParams = {
1900
2047
  ...options,
1901
2048
  ...mapVercelParams(params),
@@ -1953,12 +2100,10 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1953
2100
  });
1954
2101
  }
1955
2102
  if (chunk.type === 'finish') {
1956
- const providerMetadata = chunk.providerMetadata;
1957
- const additionalTokenValues = {
1958
- ...(providerMetadata?.anthropic ? {
1959
- cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
1960
- } : {})
1961
- };
2103
+ providerMetadata = chunk.providerMetadata;
2104
+ const additionalTokenValues = providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'cacheCreationInputTokens' in providerMetadata.anthropic ? {
2105
+ cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
2106
+ } : {};
1962
2107
  usage = {
1963
2108
  inputTokens: chunk.usage?.inputTokens,
1964
2109
  outputTokens: chunk.usage?.outputTokens,
@@ -2003,6 +2148,28 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
2003
2148
  role: 'assistant',
2004
2149
  content: content.length === 1 && content[0].type === 'text' ? content[0].text : content
2005
2150
  }] : [];
2151
+ // Calculate web search count based on provider
2152
+ let webSearchCount = 0;
2153
+ if (providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'server_tool_use' in providerMetadata.anthropic) {
2154
+ // Anthropic-specific extraction
2155
+ const serverToolUse = providerMetadata.anthropic.server_tool_use;
2156
+ if (serverToolUse && typeof serverToolUse === 'object' && 'web_search_requests' in serverToolUse && typeof serverToolUse.web_search_requests === 'number') {
2157
+ webSearchCount = serverToolUse.web_search_requests;
2158
+ }
2159
+ } else {
2160
+ // For other providers through Vercel, pass available metadata to helper
2161
+ // Note: Vercel abstracts provider responses, so we may not have access to
2162
+ // raw citations/annotations unless Vercel exposes them in usage/metadata
2163
+ webSearchCount = calculateWebSearchCount({
2164
+ usage: usage,
2165
+ providerMetadata: providerMetadata
2166
+ });
2167
+ }
2168
+ // Update usage with web search count
2169
+ const finalUsage = {
2170
+ ...usage,
2171
+ webSearchCount
2172
+ };
2006
2173
  await sendEventToPosthog({
2007
2174
  client: phClient,
2008
2175
  distinctId: options.posthogDistinctId,
@@ -2015,7 +2182,7 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
2015
2182
  baseURL,
2016
2183
  params: mergedParams,
2017
2184
  httpStatus: 200,
2018
- usage,
2185
+ usage: finalUsage,
2019
2186
  tools: availableTools,
2020
2187
  captureImmediate: options.posthogCaptureImmediate
2021
2188
  });
@@ -2101,7 +2268,8 @@ class WrappedMessages extends AnthropicOriginal.Messages {
2101
2268
  inputTokens: 0,
2102
2269
  outputTokens: 0,
2103
2270
  cacheCreationInputTokens: 0,
2104
- cacheReadInputTokens: 0
2271
+ cacheReadInputTokens: 0,
2272
+ webSearchCount: 0
2105
2273
  };
2106
2274
  if ('tee' in value) {
2107
2275
  const [stream1, stream2] = value.tee();
@@ -2178,9 +2346,14 @@ class WrappedMessages extends AnthropicOriginal.Messages {
2178
2346
  usage.inputTokens = chunk.message.usage.input_tokens ?? 0;
2179
2347
  usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0;
2180
2348
  usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0;
2349
+ usage.webSearchCount = chunk.message.usage.server_tool_use?.web_search_requests ?? 0;
2181
2350
  }
2182
2351
  if ('usage' in chunk) {
2183
2352
  usage.outputTokens = chunk.usage.output_tokens ?? 0;
2353
+ // Update web search count if present in delta
2354
+ if (chunk.usage.server_tool_use?.web_search_requests !== undefined) {
2355
+ usage.webSearchCount = chunk.usage.server_tool_use.web_search_requests;
2356
+ }
2184
2357
  }
2185
2358
  }
2186
2359
  const latency = (Date.now() - startTime) / 1000;
@@ -2257,7 +2430,8 @@ class WrappedMessages extends AnthropicOriginal.Messages {
2257
2430
  inputTokens: result.usage.input_tokens ?? 0,
2258
2431
  outputTokens: result.usage.output_tokens ?? 0,
2259
2432
  cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,
2260
- cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0
2433
+ cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0,
2434
+ webSearchCount: result.usage.server_tool_use?.web_search_requests ?? 0
2261
2435
  },
2262
2436
  tools: availableTools
2263
2437
  });
@@ -2331,7 +2505,8 @@ class WrappedModels {
2331
2505
  inputTokens: metadata?.promptTokenCount ?? 0,
2332
2506
  outputTokens: metadata?.candidatesTokenCount ?? 0,
2333
2507
  reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
2334
- cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0
2508
+ cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0,
2509
+ webSearchCount: calculateGoogleWebSearchCount(response)
2335
2510
  },
2336
2511
  tools: availableTools
2337
2512
  });
@@ -2368,11 +2543,16 @@ class WrappedModels {
2368
2543
  const accumulatedContent = [];
2369
2544
  let usage = {
2370
2545
  inputTokens: 0,
2371
- outputTokens: 0
2546
+ outputTokens: 0,
2547
+ webSearchCount: 0
2372
2548
  };
2373
2549
  try {
2374
2550
  const stream = await this.client.models.generateContentStream(geminiParams);
2375
2551
  for await (const chunk of stream) {
2552
+ const chunkWebSearchCount = calculateGoogleWebSearchCount(chunk);
2553
+ if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) {
2554
+ usage.webSearchCount = chunkWebSearchCount;
2555
+ }
2376
2556
  // Handle text content
2377
2557
  if (chunk.text) {
2378
2558
  // Find if we already have a text item to append to
@@ -2421,7 +2601,8 @@ class WrappedModels {
2421
2601
  inputTokens: metadata.promptTokenCount ?? 0,
2422
2602
  outputTokens: metadata.candidatesTokenCount ?? 0,
2423
2603
  reasoningTokens: metadata.thoughtsTokenCount ?? 0,
2424
- cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0
2604
+ cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0,
2605
+ webSearchCount: usage.webSearchCount
2425
2606
  };
2426
2607
  }
2427
2608
  yield chunk;
@@ -2444,7 +2625,10 @@ class WrappedModels {
2444
2625
  baseURL: 'https://generativelanguage.googleapis.com',
2445
2626
  params: params,
2446
2627
  httpStatus: 200,
2447
- usage,
2628
+ usage: {
2629
+ ...usage,
2630
+ webSearchCount: usage.webSearchCount
2631
+ },
2448
2632
  tools: availableTools
2449
2633
  });
2450
2634
  } catch (error) {
@@ -2587,6 +2771,66 @@ class WrappedModels {
2587
2771
  return messages;
2588
2772
  }
2589
2773
  }
2774
+ /**
2775
+ * Detect if Google Search grounding was used in the response.
2776
+ * Gemini bills per request that uses grounding, not per individual query.
2777
+ * Returns 1 if grounding was used, 0 otherwise.
2778
+ */
2779
+ function calculateGoogleWebSearchCount(response) {
2780
+ if (!response || typeof response !== 'object' || !('candidates' in response)) {
2781
+ return 0;
2782
+ }
2783
+ const candidates = response.candidates;
2784
+ if (!Array.isArray(candidates)) {
2785
+ return 0;
2786
+ }
2787
+ const hasGrounding = candidates.some(candidate => {
2788
+ if (!candidate || typeof candidate !== 'object') {
2789
+ return false;
2790
+ }
2791
+ // Check for grounding metadata
2792
+ if ('groundingMetadata' in candidate && candidate.groundingMetadata) {
2793
+ const metadata = candidate.groundingMetadata;
2794
+ if (typeof metadata === 'object') {
2795
+ // Check if web_search_queries exists and is non-empty
2796
+ if ('webSearchQueries' in metadata && Array.isArray(metadata.webSearchQueries) && metadata.webSearchQueries.length > 0) {
2797
+ return true;
2798
+ }
2799
+ // Check if grounding_chunks exists and is non-empty
2800
+ if ('groundingChunks' in metadata && Array.isArray(metadata.groundingChunks) && metadata.groundingChunks.length > 0) {
2801
+ return true;
2802
+ }
2803
+ }
2804
+ }
2805
+ // Check for google search in function calls
2806
+ if ('content' in candidate && candidate.content && typeof candidate.content === 'object') {
2807
+ const content = candidate.content;
2808
+ if ('parts' in content && Array.isArray(content.parts)) {
2809
+ return content.parts.some(part => {
2810
+ if (!part || typeof part !== 'object' || !('functionCall' in part)) {
2811
+ return false;
2812
+ }
2813
+ const functionCall = part.functionCall;
2814
+ if (functionCall && typeof functionCall === 'object' && 'name' in functionCall && typeof functionCall.name === 'string') {
2815
+ return functionCall.name.includes('google_search') || functionCall.name.includes('grounding');
2816
+ }
2817
+ return false;
2818
+ });
2819
+ }
2820
+ }
2821
+ return false;
2822
+ });
2823
+ return hasGrounding ? 1 : 0;
2824
+ }
2825
+
2826
+ //#region rolldown:runtime
2827
+ var __defProp = Object.defineProperty;
2828
+ var __export = (target, all) => {
2829
+ for (var name in all) __defProp(target, name, {
2830
+ get: all[name],
2831
+ enumerable: true
2832
+ });
2833
+ };
2590
2834
 
2591
2835
  function getDefaultExportFromCjs (x) {
2592
2836
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -2740,370 +2984,304 @@ function requireCamelcase () {
2740
2984
 
2741
2985
  requireCamelcase();
2742
2986
 
2987
+ //#region src/load/map_keys.ts
2743
2988
  function keyToJson(key, map) {
2744
- return map?.[key] || snakeCase(key);
2989
+ return map?.[key] || snakeCase(key);
2745
2990
  }
2746
2991
  function mapKeys(fields, mapper, map) {
2747
- const mapped = {};
2748
- for (const key in fields) {
2749
- if (Object.hasOwn(fields, key)) {
2750
- mapped[mapper(key, map)] = fields[key];
2751
- }
2752
- }
2753
- return mapped;
2992
+ const mapped = {};
2993
+ for (const key in fields) if (Object.hasOwn(fields, key)) mapped[mapper(key, map)] = fields[key];
2994
+ return mapped;
2754
2995
  }
2755
2996
 
2997
+ //#region src/load/serializable.ts
2998
+ var serializable_exports = {};
2999
+ __export(serializable_exports, {
3000
+ Serializable: () => Serializable,
3001
+ get_lc_unique_name: () => get_lc_unique_name
3002
+ });
2756
3003
  function shallowCopy(obj) {
2757
- return Array.isArray(obj) ? [...obj] : { ...obj };
3004
+ return Array.isArray(obj) ? [...obj] : { ...obj };
2758
3005
  }
2759
3006
  function replaceSecrets(root, secretsMap) {
2760
- const result = shallowCopy(root);
2761
- for (const [path, secretId] of Object.entries(secretsMap)) {
2762
- const [last, ...partsReverse] = path.split(".").reverse();
2763
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2764
- let current = result;
2765
- for (const part of partsReverse.reverse()) {
2766
- if (current[part] === undefined) {
2767
- break;
2768
- }
2769
- current[part] = shallowCopy(current[part]);
2770
- current = current[part];
2771
- }
2772
- if (current[last] !== undefined) {
2773
- current[last] = {
2774
- lc: 1,
2775
- type: "secret",
2776
- id: [secretId],
2777
- };
2778
- }
2779
- }
2780
- return result;
3007
+ const result = shallowCopy(root);
3008
+ for (const [path, secretId] of Object.entries(secretsMap)) {
3009
+ const [last, ...partsReverse] = path.split(".").reverse();
3010
+ let current = result;
3011
+ for (const part of partsReverse.reverse()) {
3012
+ if (current[part] === void 0) break;
3013
+ current[part] = shallowCopy(current[part]);
3014
+ current = current[part];
3015
+ }
3016
+ if (current[last] !== void 0) current[last] = {
3017
+ lc: 1,
3018
+ type: "secret",
3019
+ id: [secretId]
3020
+ };
3021
+ }
3022
+ return result;
2781
3023
  }
2782
3024
  /**
2783
- * Get a unique name for the module, rather than parent class implementations.
2784
- * Should not be subclassed, subclass lc_name above instead.
2785
- */
2786
- function get_lc_unique_name(
2787
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
2788
- serializableClass) {
2789
- // "super" here would refer to the parent class of Serializable,
2790
- // when we want the parent class of the module actually calling this method.
2791
- const parentClass = Object.getPrototypeOf(serializableClass);
2792
- const lcNameIsSubclassed = typeof serializableClass.lc_name === "function" &&
2793
- (typeof parentClass.lc_name !== "function" ||
2794
- serializableClass.lc_name() !== parentClass.lc_name());
2795
- if (lcNameIsSubclassed) {
2796
- return serializableClass.lc_name();
2797
- }
2798
- else {
2799
- return serializableClass.name;
2800
- }
2801
- }
2802
- class Serializable {
2803
- /**
2804
- * The name of the serializable. Override to provide an alias or
2805
- * to preserve the serialized module name in minified environments.
2806
- *
2807
- * Implemented as a static method to support loading logic.
2808
- */
2809
- static lc_name() {
2810
- return this.name;
2811
- }
2812
- /**
2813
- * The final serialized identifier for the module.
2814
- */
2815
- get lc_id() {
2816
- return [
2817
- ...this.lc_namespace,
2818
- get_lc_unique_name(this.constructor),
2819
- ];
2820
- }
2821
- /**
2822
- * A map of secrets, which will be omitted from serialization.
2823
- * Keys are paths to the secret in constructor args, e.g. "foo.bar.baz".
2824
- * Values are the secret ids, which will be used when deserializing.
2825
- */
2826
- get lc_secrets() {
2827
- return undefined;
2828
- }
2829
- /**
2830
- * A map of additional attributes to merge with constructor args.
2831
- * Keys are the attribute names, e.g. "foo".
2832
- * Values are the attribute values, which will be serialized.
2833
- * These attributes need to be accepted by the constructor as arguments.
2834
- */
2835
- get lc_attributes() {
2836
- return undefined;
2837
- }
2838
- /**
2839
- * A map of aliases for constructor args.
2840
- * Keys are the attribute names, e.g. "foo".
2841
- * Values are the alias that will replace the key in serialization.
2842
- * This is used to eg. make argument names match Python.
2843
- */
2844
- get lc_aliases() {
2845
- return undefined;
2846
- }
2847
- /**
2848
- * A manual list of keys that should be serialized.
2849
- * If not overridden, all fields passed into the constructor will be serialized.
2850
- */
2851
- get lc_serializable_keys() {
2852
- return undefined;
2853
- }
2854
- constructor(kwargs, ..._args) {
2855
- Object.defineProperty(this, "lc_serializable", {
2856
- enumerable: true,
2857
- configurable: true,
2858
- writable: true,
2859
- value: false
2860
- });
2861
- Object.defineProperty(this, "lc_kwargs", {
2862
- enumerable: true,
2863
- configurable: true,
2864
- writable: true,
2865
- value: void 0
2866
- });
2867
- if (this.lc_serializable_keys !== undefined) {
2868
- this.lc_kwargs = Object.fromEntries(Object.entries(kwargs || {}).filter(([key]) => this.lc_serializable_keys?.includes(key)));
2869
- }
2870
- else {
2871
- this.lc_kwargs = kwargs ?? {};
2872
- }
2873
- }
2874
- toJSON() {
2875
- if (!this.lc_serializable) {
2876
- return this.toJSONNotImplemented();
2877
- }
2878
- if (
2879
- // eslint-disable-next-line no-instanceof/no-instanceof
2880
- this.lc_kwargs instanceof Serializable ||
2881
- typeof this.lc_kwargs !== "object" ||
2882
- Array.isArray(this.lc_kwargs)) {
2883
- // We do not support serialization of classes with arg not a POJO
2884
- // I'm aware the check above isn't as strict as it could be
2885
- return this.toJSONNotImplemented();
2886
- }
2887
- const aliases = {};
2888
- const secrets = {};
2889
- const kwargs = Object.keys(this.lc_kwargs).reduce((acc, key) => {
2890
- acc[key] = key in this ? this[key] : this.lc_kwargs[key];
2891
- return acc;
2892
- }, {});
2893
- // get secrets, attributes and aliases from all superclasses
2894
- for (
2895
- // eslint-disable-next-line @typescript-eslint/no-this-alias
2896
- let current = Object.getPrototypeOf(this); current; current = Object.getPrototypeOf(current)) {
2897
- Object.assign(aliases, Reflect.get(current, "lc_aliases", this));
2898
- Object.assign(secrets, Reflect.get(current, "lc_secrets", this));
2899
- Object.assign(kwargs, Reflect.get(current, "lc_attributes", this));
2900
- }
2901
- // include all secrets used, even if not in kwargs,
2902
- // will be replaced with sentinel value in replaceSecrets
2903
- Object.keys(secrets).forEach((keyPath) => {
2904
- // eslint-disable-next-line @typescript-eslint/no-this-alias, @typescript-eslint/no-explicit-any
2905
- let read = this;
2906
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2907
- let write = kwargs;
2908
- const [last, ...partsReverse] = keyPath.split(".").reverse();
2909
- for (const key of partsReverse.reverse()) {
2910
- if (!(key in read) || read[key] === undefined)
2911
- return;
2912
- if (!(key in write) || write[key] === undefined) {
2913
- if (typeof read[key] === "object" && read[key] != null) {
2914
- write[key] = {};
2915
- }
2916
- else if (Array.isArray(read[key])) {
2917
- write[key] = [];
2918
- }
2919
- }
2920
- read = read[key];
2921
- write = write[key];
2922
- }
2923
- if (last in read && read[last] !== undefined) {
2924
- write[last] = write[last] || read[last];
2925
- }
2926
- });
2927
- return {
2928
- lc: 1,
2929
- type: "constructor",
2930
- id: this.lc_id,
2931
- kwargs: mapKeys(Object.keys(secrets).length ? replaceSecrets(kwargs, secrets) : kwargs, keyToJson, aliases),
2932
- };
2933
- }
2934
- toJSONNotImplemented() {
2935
- return {
2936
- lc: 1,
2937
- type: "not_implemented",
2938
- id: this.lc_id,
2939
- };
2940
- }
3025
+ * Get a unique name for the module, rather than parent class implementations.
3026
+ * Should not be subclassed, subclass lc_name above instead.
3027
+ */
3028
+ function get_lc_unique_name(serializableClass) {
3029
+ const parentClass = Object.getPrototypeOf(serializableClass);
3030
+ const lcNameIsSubclassed = typeof serializableClass.lc_name === "function" && (typeof parentClass.lc_name !== "function" || serializableClass.lc_name() !== parentClass.lc_name());
3031
+ if (lcNameIsSubclassed) return serializableClass.lc_name();
3032
+ else return serializableClass.name;
2941
3033
  }
3034
+ var Serializable = class Serializable {
3035
+ lc_serializable = false;
3036
+ lc_kwargs;
3037
+ /**
3038
+ * The name of the serializable. Override to provide an alias or
3039
+ * to preserve the serialized module name in minified environments.
3040
+ *
3041
+ * Implemented as a static method to support loading logic.
3042
+ */
3043
+ static lc_name() {
3044
+ return this.name;
3045
+ }
3046
+ /**
3047
+ * The final serialized identifier for the module.
3048
+ */
3049
+ get lc_id() {
3050
+ return [...this.lc_namespace, get_lc_unique_name(this.constructor)];
3051
+ }
3052
+ /**
3053
+ * A map of secrets, which will be omitted from serialization.
3054
+ * Keys are paths to the secret in constructor args, e.g. "foo.bar.baz".
3055
+ * Values are the secret ids, which will be used when deserializing.
3056
+ */
3057
+ get lc_secrets() {
3058
+ return void 0;
3059
+ }
3060
+ /**
3061
+ * A map of additional attributes to merge with constructor args.
3062
+ * Keys are the attribute names, e.g. "foo".
3063
+ * Values are the attribute values, which will be serialized.
3064
+ * These attributes need to be accepted by the constructor as arguments.
3065
+ */
3066
+ get lc_attributes() {
3067
+ return void 0;
3068
+ }
3069
+ /**
3070
+ * A map of aliases for constructor args.
3071
+ * Keys are the attribute names, e.g. "foo".
3072
+ * Values are the alias that will replace the key in serialization.
3073
+ * This is used to eg. make argument names match Python.
3074
+ */
3075
+ get lc_aliases() {
3076
+ return void 0;
3077
+ }
3078
+ /**
3079
+ * A manual list of keys that should be serialized.
3080
+ * If not overridden, all fields passed into the constructor will be serialized.
3081
+ */
3082
+ get lc_serializable_keys() {
3083
+ return void 0;
3084
+ }
3085
+ constructor(kwargs, ..._args) {
3086
+ if (this.lc_serializable_keys !== void 0) this.lc_kwargs = Object.fromEntries(Object.entries(kwargs || {}).filter(([key]) => this.lc_serializable_keys?.includes(key)));
3087
+ else this.lc_kwargs = kwargs ?? {};
3088
+ }
3089
+ toJSON() {
3090
+ if (!this.lc_serializable) return this.toJSONNotImplemented();
3091
+ if (this.lc_kwargs instanceof Serializable || typeof this.lc_kwargs !== "object" || Array.isArray(this.lc_kwargs)) return this.toJSONNotImplemented();
3092
+ const aliases = {};
3093
+ const secrets = {};
3094
+ const kwargs = Object.keys(this.lc_kwargs).reduce((acc, key) => {
3095
+ acc[key] = key in this ? this[key] : this.lc_kwargs[key];
3096
+ return acc;
3097
+ }, {});
3098
+ for (let current = Object.getPrototypeOf(this); current; current = Object.getPrototypeOf(current)) {
3099
+ Object.assign(aliases, Reflect.get(current, "lc_aliases", this));
3100
+ Object.assign(secrets, Reflect.get(current, "lc_secrets", this));
3101
+ Object.assign(kwargs, Reflect.get(current, "lc_attributes", this));
3102
+ }
3103
+ Object.keys(secrets).forEach((keyPath) => {
3104
+ let read = this;
3105
+ let write = kwargs;
3106
+ const [last, ...partsReverse] = keyPath.split(".").reverse();
3107
+ for (const key of partsReverse.reverse()) {
3108
+ if (!(key in read) || read[key] === void 0) return;
3109
+ if (!(key in write) || write[key] === void 0) {
3110
+ if (typeof read[key] === "object" && read[key] != null) write[key] = {};
3111
+ else if (Array.isArray(read[key])) write[key] = [];
3112
+ }
3113
+ read = read[key];
3114
+ write = write[key];
3115
+ }
3116
+ if (last in read && read[last] !== void 0) write[last] = write[last] || read[last];
3117
+ });
3118
+ return {
3119
+ lc: 1,
3120
+ type: "constructor",
3121
+ id: this.lc_id,
3122
+ kwargs: mapKeys(Object.keys(secrets).length ? replaceSecrets(kwargs, secrets) : kwargs, keyToJson, aliases)
3123
+ };
3124
+ }
3125
+ toJSONNotImplemented() {
3126
+ return {
3127
+ lc: 1,
3128
+ type: "not_implemented",
3129
+ id: this.lc_id
3130
+ };
3131
+ }
3132
+ };
2942
3133
 
2943
- // Supabase Edge Function provides a `Deno` global object
2944
- // without `version` property
3134
+ //#region src/utils/env.ts
3135
+ var env_exports = {};
3136
+ __export(env_exports, {
3137
+ getEnv: () => getEnv,
3138
+ getEnvironmentVariable: () => getEnvironmentVariable,
3139
+ getRuntimeEnvironment: () => getRuntimeEnvironment,
3140
+ isBrowser: () => isBrowser,
3141
+ isDeno: () => isDeno,
3142
+ isJsDom: () => isJsDom,
3143
+ isNode: () => isNode,
3144
+ isWebWorker: () => isWebWorker
3145
+ });
3146
+ const isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
3147
+ const isWebWorker = () => typeof globalThis === "object" && globalThis.constructor && globalThis.constructor.name === "DedicatedWorkerGlobalScope";
3148
+ const isJsDom = () => typeof window !== "undefined" && window.name === "nodejs" || typeof navigator !== "undefined" && navigator.userAgent.includes("jsdom");
2945
3149
  const isDeno = () => typeof Deno !== "undefined";
3150
+ const isNode = () => typeof process !== "undefined" && typeof process.versions !== "undefined" && typeof process.versions.node !== "undefined" && !isDeno();
3151
+ const getEnv = () => {
3152
+ let env;
3153
+ if (isBrowser()) env = "browser";
3154
+ else if (isNode()) env = "node";
3155
+ else if (isWebWorker()) env = "webworker";
3156
+ else if (isJsDom()) env = "jsdom";
3157
+ else if (isDeno()) env = "deno";
3158
+ else env = "other";
3159
+ return env;
3160
+ };
3161
+ let runtimeEnvironment;
3162
+ function getRuntimeEnvironment() {
3163
+ if (runtimeEnvironment === void 0) {
3164
+ const env = getEnv();
3165
+ runtimeEnvironment = {
3166
+ library: "langchain-js",
3167
+ runtime: env
3168
+ };
3169
+ }
3170
+ return runtimeEnvironment;
3171
+ }
2946
3172
  function getEnvironmentVariable(name) {
2947
- // Certain Deno setups will throw an error if you try to access environment variables
2948
- // https://github.com/langchain-ai/langchainjs/issues/1412
2949
- try {
2950
- if (typeof process !== "undefined") {
2951
- // eslint-disable-next-line no-process-env
2952
- return process.env?.[name];
2953
- }
2954
- else if (isDeno()) {
2955
- return Deno?.env.get(name);
2956
- }
2957
- else {
2958
- return undefined;
2959
- }
2960
- }
2961
- catch (e) {
2962
- return undefined;
2963
- }
3173
+ try {
3174
+ if (typeof process !== "undefined") return process.env?.[name];
3175
+ else if (isDeno()) return Deno?.env.get(name);
3176
+ else return void 0;
3177
+ } catch {
3178
+ return void 0;
3179
+ }
2964
3180
  }
2965
3181
 
3182
+ //#region src/callbacks/base.ts
3183
+ var base_exports = {};
3184
+ __export(base_exports, {
3185
+ BaseCallbackHandler: () => BaseCallbackHandler,
3186
+ callbackHandlerPrefersStreaming: () => callbackHandlerPrefersStreaming,
3187
+ isBaseCallbackHandler: () => isBaseCallbackHandler
3188
+ });
2966
3189
  /**
2967
- * Abstract class that provides a set of optional methods that can be
2968
- * overridden in derived classes to handle various events during the
2969
- * execution of a LangChain application.
2970
- */
2971
- class BaseCallbackHandlerMethodsClass {
3190
+ * Abstract class that provides a set of optional methods that can be
3191
+ * overridden in derived classes to handle various events during the
3192
+ * execution of a LangChain application.
3193
+ */
3194
+ var BaseCallbackHandlerMethodsClass = class {};
3195
+ function callbackHandlerPrefersStreaming(x) {
3196
+ return "lc_prefer_streaming" in x && x.lc_prefer_streaming;
2972
3197
  }
2973
3198
  /**
2974
- * Abstract base class for creating callback handlers in the LangChain
2975
- * framework. It provides a set of optional methods that can be overridden
2976
- * in derived classes to handle various events during the execution of a
2977
- * LangChain application.
2978
- */
2979
- class BaseCallbackHandler extends BaseCallbackHandlerMethodsClass {
2980
- get lc_namespace() {
2981
- return ["langchain_core", "callbacks", this.name];
2982
- }
2983
- get lc_secrets() {
2984
- return undefined;
2985
- }
2986
- get lc_attributes() {
2987
- return undefined;
2988
- }
2989
- get lc_aliases() {
2990
- return undefined;
2991
- }
2992
- get lc_serializable_keys() {
2993
- return undefined;
2994
- }
2995
- /**
2996
- * The name of the serializable. Override to provide an alias or
2997
- * to preserve the serialized module name in minified environments.
2998
- *
2999
- * Implemented as a static method to support loading logic.
3000
- */
3001
- static lc_name() {
3002
- return this.name;
3003
- }
3004
- /**
3005
- * The final serialized identifier for the module.
3006
- */
3007
- get lc_id() {
3008
- return [
3009
- ...this.lc_namespace,
3010
- get_lc_unique_name(this.constructor),
3011
- ];
3012
- }
3013
- constructor(input) {
3014
- super();
3015
- Object.defineProperty(this, "lc_serializable", {
3016
- enumerable: true,
3017
- configurable: true,
3018
- writable: true,
3019
- value: false
3020
- });
3021
- Object.defineProperty(this, "lc_kwargs", {
3022
- enumerable: true,
3023
- configurable: true,
3024
- writable: true,
3025
- value: void 0
3026
- });
3027
- Object.defineProperty(this, "ignoreLLM", {
3028
- enumerable: true,
3029
- configurable: true,
3030
- writable: true,
3031
- value: false
3032
- });
3033
- Object.defineProperty(this, "ignoreChain", {
3034
- enumerable: true,
3035
- configurable: true,
3036
- writable: true,
3037
- value: false
3038
- });
3039
- Object.defineProperty(this, "ignoreAgent", {
3040
- enumerable: true,
3041
- configurable: true,
3042
- writable: true,
3043
- value: false
3044
- });
3045
- Object.defineProperty(this, "ignoreRetriever", {
3046
- enumerable: true,
3047
- configurable: true,
3048
- writable: true,
3049
- value: false
3050
- });
3051
- Object.defineProperty(this, "ignoreCustomEvent", {
3052
- enumerable: true,
3053
- configurable: true,
3054
- writable: true,
3055
- value: false
3056
- });
3057
- Object.defineProperty(this, "raiseError", {
3058
- enumerable: true,
3059
- configurable: true,
3060
- writable: true,
3061
- value: false
3062
- });
3063
- Object.defineProperty(this, "awaitHandlers", {
3064
- enumerable: true,
3065
- configurable: true,
3066
- writable: true,
3067
- value: getEnvironmentVariable("LANGCHAIN_CALLBACKS_BACKGROUND") === "false"
3068
- });
3069
- this.lc_kwargs = input || {};
3070
- if (input) {
3071
- this.ignoreLLM = input.ignoreLLM ?? this.ignoreLLM;
3072
- this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
3073
- this.ignoreAgent = input.ignoreAgent ?? this.ignoreAgent;
3074
- this.ignoreRetriever = input.ignoreRetriever ?? this.ignoreRetriever;
3075
- this.ignoreCustomEvent =
3076
- input.ignoreCustomEvent ?? this.ignoreCustomEvent;
3077
- this.raiseError = input.raiseError ?? this.raiseError;
3078
- this.awaitHandlers =
3079
- this.raiseError || (input._awaitHandler ?? this.awaitHandlers);
3080
- }
3081
- }
3082
- copy() {
3083
- return new this.constructor(this);
3084
- }
3085
- toJSON() {
3086
- return Serializable.prototype.toJSON.call(this);
3087
- }
3088
- toJSONNotImplemented() {
3089
- return Serializable.prototype.toJSONNotImplemented.call(this);
3090
- }
3091
- static fromMethods(methods) {
3092
- class Handler extends BaseCallbackHandler {
3093
- constructor() {
3094
- super();
3095
- Object.defineProperty(this, "name", {
3096
- enumerable: true,
3097
- configurable: true,
3098
- writable: true,
3099
- value: uuid.v4()
3100
- });
3101
- Object.assign(this, methods);
3102
- }
3103
- }
3104
- return new Handler();
3105
- }
3106
- }
3199
+ * Abstract base class for creating callback handlers in the LangChain
3200
+ * framework. It provides a set of optional methods that can be overridden
3201
+ * in derived classes to handle various events during the execution of a
3202
+ * LangChain application.
3203
+ */
3204
+ var BaseCallbackHandler = class extends BaseCallbackHandlerMethodsClass {
3205
+ lc_serializable = false;
3206
+ get lc_namespace() {
3207
+ return [
3208
+ "langchain_core",
3209
+ "callbacks",
3210
+ this.name
3211
+ ];
3212
+ }
3213
+ get lc_secrets() {
3214
+ return void 0;
3215
+ }
3216
+ get lc_attributes() {
3217
+ return void 0;
3218
+ }
3219
+ get lc_aliases() {
3220
+ return void 0;
3221
+ }
3222
+ get lc_serializable_keys() {
3223
+ return void 0;
3224
+ }
3225
+ /**
3226
+ * The name of the serializable. Override to provide an alias or
3227
+ * to preserve the serialized module name in minified environments.
3228
+ *
3229
+ * Implemented as a static method to support loading logic.
3230
+ */
3231
+ static lc_name() {
3232
+ return this.name;
3233
+ }
3234
+ /**
3235
+ * The final serialized identifier for the module.
3236
+ */
3237
+ get lc_id() {
3238
+ return [...this.lc_namespace, get_lc_unique_name(this.constructor)];
3239
+ }
3240
+ lc_kwargs;
3241
+ ignoreLLM = false;
3242
+ ignoreChain = false;
3243
+ ignoreAgent = false;
3244
+ ignoreRetriever = false;
3245
+ ignoreCustomEvent = false;
3246
+ raiseError = false;
3247
+ awaitHandlers = getEnvironmentVariable("LANGCHAIN_CALLBACKS_BACKGROUND") === "false";
3248
+ constructor(input) {
3249
+ super();
3250
+ this.lc_kwargs = input || {};
3251
+ if (input) {
3252
+ this.ignoreLLM = input.ignoreLLM ?? this.ignoreLLM;
3253
+ this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
3254
+ this.ignoreAgent = input.ignoreAgent ?? this.ignoreAgent;
3255
+ this.ignoreRetriever = input.ignoreRetriever ?? this.ignoreRetriever;
3256
+ this.ignoreCustomEvent = input.ignoreCustomEvent ?? this.ignoreCustomEvent;
3257
+ this.raiseError = input.raiseError ?? this.raiseError;
3258
+ this.awaitHandlers = this.raiseError || (input._awaitHandler ?? this.awaitHandlers);
3259
+ }
3260
+ }
3261
+ copy() {
3262
+ return new this.constructor(this);
3263
+ }
3264
+ toJSON() {
3265
+ return Serializable.prototype.toJSON.call(this);
3266
+ }
3267
+ toJSONNotImplemented() {
3268
+ return Serializable.prototype.toJSONNotImplemented.call(this);
3269
+ }
3270
+ static fromMethods(methods) {
3271
+ class Handler extends BaseCallbackHandler {
3272
+ name = uuid.v4();
3273
+ constructor() {
3274
+ super();
3275
+ Object.assign(this, methods);
3276
+ }
3277
+ }
3278
+ return new Handler();
3279
+ }
3280
+ };
3281
+ const isBaseCallbackHandler = (x) => {
3282
+ const callbackHandler = x;
3283
+ return callbackHandler !== void 0 && typeof callbackHandler.copy === "function" && typeof callbackHandler.name === "string" && typeof callbackHandler.awaitHandlers === "boolean";
3284
+ };
3107
3285
 
3108
3286
  class LangChainCallbackHandler extends BaseCallbackHandler {
3109
3287
  constructor(options) {
@@ -3407,6 +3585,9 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3407
3585
  if (additionalTokenData.reasoningTokens) {
3408
3586
  eventProperties['$ai_reasoning_tokens'] = additionalTokenData.reasoningTokens;
3409
3587
  }
3588
+ if (additionalTokenData.webSearchCount !== undefined) {
3589
+ eventProperties['$ai_web_search_count'] = additionalTokenData.webSearchCount;
3590
+ }
3410
3591
  // Handle generations/completions
3411
3592
  let completions;
3412
3593
  if (output.generations && Array.isArray(output.generations)) {
@@ -3572,6 +3753,42 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3572
3753
  } else if (usage.reasoningTokens != null) {
3573
3754
  additionalTokenData.reasoningTokens = usage.reasoningTokens;
3574
3755
  }
3756
+ // Extract web search counts from various provider formats
3757
+ let webSearchCount;
3758
+ // Priority 1: Exact Count
3759
+ // Check Anthropic format (server_tool_use.web_search_requests)
3760
+ if (usage.server_tool_use?.web_search_requests !== undefined) {
3761
+ webSearchCount = usage.server_tool_use.web_search_requests;
3762
+ }
3763
+ // Priority 2: Binary Detection (1 or 0)
3764
+ // Check for citations array (Perplexity)
3765
+ else if (usage.citations && Array.isArray(usage.citations) && usage.citations.length > 0) {
3766
+ webSearchCount = 1;
3767
+ }
3768
+ // Check for search_results array (Perplexity via OpenRouter)
3769
+ else if (usage.search_results && Array.isArray(usage.search_results) && usage.search_results.length > 0) {
3770
+ webSearchCount = 1;
3771
+ }
3772
+ // Check for search_context_size (Perplexity via OpenRouter)
3773
+ else if (usage.search_context_size) {
3774
+ webSearchCount = 1;
3775
+ }
3776
+ // Check for annotations with url_citation type
3777
+ else if (usage.annotations && Array.isArray(usage.annotations)) {
3778
+ const hasUrlCitation = usage.annotations.some(ann => {
3779
+ return ann && typeof ann === 'object' && 'type' in ann && ann.type === 'url_citation';
3780
+ });
3781
+ if (hasUrlCitation) {
3782
+ webSearchCount = 1;
3783
+ }
3784
+ }
3785
+ // Check Gemini format (grounding metadata - binary 0 or 1)
3786
+ else if (usage.grounding_metadata?.grounding_support !== undefined || usage.grounding_metadata?.web_search_queries !== undefined) {
3787
+ webSearchCount = 1;
3788
+ }
3789
+ if (webSearchCount !== undefined) {
3790
+ additionalTokenData.webSearchCount = webSearchCount;
3791
+ }
3575
3792
  // In LangChain, input_tokens is the sum of input and cache read tokens.
3576
3793
  // Our cost calculation expects them to be separate, for Anthropic.
3577
3794
  if (parsedUsage.input && additionalTokenData.cacheReadInputTokens) {