@lmnr-ai/lmnr 0.8.45 → 0.8.47

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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as __exportAll, S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-BHEE6fmA.cjs";
1
+ import { C as __exportAll, S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-NLPG-oag.cjs";
2
2
  import { ServerResponse } from "node:http";
3
3
  import { ReadableSpan, SpanExporter, SpanProcessor, TimedEvent } from "@opentelemetry/sdk-trace-base";
4
4
  import { AttributeValue, Attributes, Context, Exception, HrTime, Link, Span, Span as Span$1, SpanContext, SpanKind, SpanStatus, TimeInput, Tracer, TracerProvider } from "@opentelemetry/api";
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-BbIIQMLr.mjs";
1
+ import { S as TracingLevel, _ as MaskInputOptions, a as HumanEvaluator, b as SpanType, c as InitializeOptions, d as LaminarClient, f as Dataset, g as LaminarSpanContext, h as Event, i as EvaluatorFunctionReturn, l as EvaluationDataset, m as EvaluationDatapointDatasetLink, o as evaluate, p as EvaluationDatapoint, r as EvaluatorFunction, s as StringUUID, t as Datapoint, u as LaminarDataset, v as PushDatapointsResponse, x as TraceType, y as SessionRecordingOptions } from "./evaluations-C3hpKJYm.mjs";
2
2
  import { AttributeValue, Attributes, Context, Exception, HrTime, Link, Span, Span as Span$1, SpanContext, SpanKind, SpanStatus, TimeInput, Tracer, TracerProvider } from "@opentelemetry/api";
3
3
  import { Instrumentation, InstrumentationBase } from "@opentelemetry/instrumentation";
4
4
  import { ReadableSpan, SpanExporter, SpanProcessor, TimedEvent } from "@opentelemetry/sdk-trace-base";
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { r as __require } from "./rolldown-runtime-2rV9d50f.mjs";
2
- import { A as SPAN_INSTRUMENTATION_SOURCE, B as LaminarClient, C as PARENT_SPAN_IDS_PATH, D as SPAN_INPUT, E as SPAN_IDS_PATH, F as SPAN_TYPE, H as DEBUG_SESSION_FILE, I as TRACE_HAS_BROWSER_SESSION, L as TRACE_TYPE, M as SPAN_OUTPUT, N as SPAN_PATH, O as SPAN_INSTRUMENTATION_SCOPE_NAME, P as SPAN_SDK_VERSION, R as USER_ID, S as LaminarAttributes, T as SESSION_ID, U as TracingLevel, V as DEBUG_SESSION_DIR, W as errorMessage, _ as tryToOtelSpanContext, a as getFrontendUrl, b as ASSOCIATION_PROPERTIES_OVERRIDES, c as loadEnv, d as normalizeOtelSpanId, f as normalizeOtelTraceId, g as truncateSpanPayload, h as parseOtelHeaders, j as SPAN_LANGUAGE_VERSION, k as SPAN_INSTRUMENTATION_SCOPE_VERSION, l as metadataToAttributes, m as otelTraceIdToUUID, n as Semaphore, o as getOtelEnvVar, p as otelSpanIdToUUID, r as deserializeLaminarSpanContext, s as initializeLogger, t as NIL_UUID, u as newUUID, v as validateTracingConfig, w as PARENT_SPAN_PATH, x as HUMAN_EVALUATOR_OPTIONS, y as ASSOCIATION_PROPERTIES, z as version } from "./utils-UmlDPMxe.mjs";
2
+ import { A as SPAN_INSTRUMENTATION_SOURCE, B as LaminarClient, C as PARENT_SPAN_IDS_PATH, D as SPAN_INPUT, E as SPAN_IDS_PATH, F as SPAN_TYPE, H as DEBUG_SESSION_FILE, I as TRACE_HAS_BROWSER_SESSION, L as TRACE_TYPE, M as SPAN_OUTPUT, N as SPAN_PATH, O as SPAN_INSTRUMENTATION_SCOPE_NAME, P as SPAN_SDK_VERSION, R as USER_ID, S as LaminarAttributes, T as SESSION_ID, U as TracingLevel, V as DEBUG_SESSION_DIR, W as errorMessage, _ as tryToOtelSpanContext, a as getFrontendUrl, b as ASSOCIATION_PROPERTIES_OVERRIDES, c as loadEnv, d as normalizeOtelSpanId, f as normalizeOtelTraceId, g as truncateSpanPayload, h as parseOtelHeaders, j as SPAN_LANGUAGE_VERSION, k as SPAN_INSTRUMENTATION_SCOPE_VERSION, l as metadataToAttributes, m as otelTraceIdToUUID, n as Semaphore, o as getOtelEnvVar, p as otelSpanIdToUUID, r as deserializeLaminarSpanContext, s as initializeLogger, t as NIL_UUID, u as newUUID, v as validateTracingConfig, w as PARENT_SPAN_PATH, x as HUMAN_EVALUATOR_OPTIONS, y as ASSOCIATION_PROPERTIES, z as version } from "./utils-BaY7eFxS.mjs";
3
3
  import { n as TRACEPARENT_HEADER, t as LAMINAR_SPAN_CONTEXT_HEADER } from "./consts-CTTu3jhI.mjs";
4
4
  import * as path from "path";
5
5
  import { DiagConsoleLogger, DiagLogLevel, ROOT_CONTEXT, SpanKind, SpanStatusCode, TraceFlags, context, createContextKey, diag, isSpanContextValid, trace } from "@opentelemetry/api";
@@ -176,7 +176,7 @@ var LaminarDataset = class extends EvaluationDataset {
176
176
  */
177
177
  async push(paths, recursive = false) {
178
178
  if (!this.client) throw new Error("Client not set");
179
- const { loadFromPaths } = await import("./file-utils-BtzEDUy6.mjs").then((n) => n.t);
179
+ const { loadFromPaths } = await import("./file-utils-BHkRwkjp.mjs").then((n) => n.t);
180
180
  const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
181
181
  if (data.length === 0) {
182
182
  console.warn("No data to push. Skipping");
@@ -4586,7 +4586,7 @@ const LLM_USAGE_TOTAL_TOKENS = "llm.usage.total_tokens";
4586
4586
  /**
4587
4587
  * Set an attribute on a span only if the value is non-null, non-undefined, and non-empty.
4588
4588
  */
4589
- function safeSetAttribute(span, key, value) {
4589
+ function safeSetAttribute$1(span, key, value) {
4590
4590
  if (value === null || value === void 0) return;
4591
4591
  if (typeof value === "string" && value.length === 0) return;
4592
4592
  if (Array.isArray(value) && value.length === 0) return;
@@ -4648,44 +4648,44 @@ function extractToolDefinitions(config) {
4648
4648
  /**
4649
4649
  * Set request attributes on a span from generateContent params.
4650
4650
  */
4651
- function setRequestAttributes(span, params, traceContent) {
4652
- safeSetAttribute(span, LLM_SYSTEM, "gemini");
4653
- safeSetAttribute(span, LLM_REQUEST_MODEL, params?.model);
4651
+ function setRequestAttributes$1(span, params, traceContent) {
4652
+ safeSetAttribute$1(span, LLM_SYSTEM, "gemini");
4653
+ safeSetAttribute$1(span, LLM_REQUEST_MODEL, params?.model);
4654
4654
  const config = params?.config;
4655
4655
  if (config) {
4656
- safeSetAttribute(span, "gen_ai.request.temperature", config.temperature);
4657
- safeSetAttribute(span, "gen_ai.request.top_p", config.topP);
4658
- safeSetAttribute(span, "gen_ai.request.top_k", config.topK);
4659
- safeSetAttribute(span, "gen_ai.request.max_tokens", config.maxOutputTokens);
4660
- safeSetAttribute(span, "gen_ai.request.frequency_penalty", config.frequencyPenalty);
4661
- safeSetAttribute(span, "gen_ai.request.presence_penalty", config.presencePenalty);
4662
- safeSetAttribute(span, "gen_ai.request.seed", config.seed);
4663
- safeSetAttribute(span, "gen_ai.request.choice_count", config.candidateCount);
4664
- if (config.stopSequences && config.stopSequences.length > 0) safeSetAttribute(span, "gen_ai.request.stop_sequences", JSON.stringify(config.stopSequences));
4656
+ safeSetAttribute$1(span, "gen_ai.request.temperature", config.temperature);
4657
+ safeSetAttribute$1(span, "gen_ai.request.top_p", config.topP);
4658
+ safeSetAttribute$1(span, "gen_ai.request.top_k", config.topK);
4659
+ safeSetAttribute$1(span, "gen_ai.request.max_tokens", config.maxOutputTokens);
4660
+ safeSetAttribute$1(span, "gen_ai.request.frequency_penalty", config.frequencyPenalty);
4661
+ safeSetAttribute$1(span, "gen_ai.request.presence_penalty", config.presencePenalty);
4662
+ safeSetAttribute$1(span, "gen_ai.request.seed", config.seed);
4663
+ safeSetAttribute$1(span, "gen_ai.request.choice_count", config.candidateCount);
4664
+ if (config.stopSequences && config.stopSequences.length > 0) safeSetAttribute$1(span, "gen_ai.request.stop_sequences", JSON.stringify(config.stopSequences));
4665
4665
  const outputSchema = config.responseSchema ?? config.responseJsonSchema;
4666
- if (outputSchema) safeSetAttribute(span, "gen_ai.request.structured_output_schema", JSON.stringify(toDict(outputSchema)));
4666
+ if (outputSchema) safeSetAttribute$1(span, "gen_ai.request.structured_output_schema", JSON.stringify(toDict(outputSchema)));
4667
4667
  const toolDefs = extractToolDefinitions(config);
4668
- if (toolDefs.length > 0) safeSetAttribute(span, "gen_ai.tool.definitions", JSON.stringify(toolDefs));
4668
+ if (toolDefs.length > 0) safeSetAttribute$1(span, "gen_ai.tool.definitions", JSON.stringify(toolDefs));
4669
4669
  }
4670
4670
  if (traceContent) {
4671
4671
  const messages = contentToMessages(params?.contents, config?.systemInstruction);
4672
- if (messages.length > 0) safeSetAttribute(span, "gen_ai.input.messages", JSON.stringify(messages));
4672
+ if (messages.length > 0) safeSetAttribute$1(span, "gen_ai.input.messages", JSON.stringify(messages));
4673
4673
  }
4674
4674
  }
4675
4675
  /**
4676
4676
  * Set response attributes on a span from a GenerateContentResponse.
4677
4677
  */
4678
- function setResponseAttributes(span, response, traceContent) {
4678
+ function setResponseAttributes$1(span, response, traceContent) {
4679
4679
  if (!response) return;
4680
- safeSetAttribute(span, LLM_RESPONSE_MODEL, response.modelVersion);
4680
+ safeSetAttribute$1(span, LLM_RESPONSE_MODEL, response.modelVersion);
4681
4681
  const usage = response.usageMetadata;
4682
4682
  if (usage) {
4683
- safeSetAttribute(span, "gen_ai.usage.input_tokens", usage.promptTokenCount);
4683
+ safeSetAttribute$1(span, "gen_ai.usage.input_tokens", usage.promptTokenCount);
4684
4684
  const outputTokens = (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0);
4685
- if (outputTokens > 0) safeSetAttribute(span, "gen_ai.usage.output_tokens", outputTokens);
4686
- safeSetAttribute(span, LLM_USAGE_TOTAL_TOKENS, usage.totalTokenCount);
4687
- safeSetAttribute(span, "gen_ai.usage.reasoning_tokens", usage.thoughtsTokenCount);
4688
- safeSetAttribute(span, "gen_ai.usage.cache_read_input_tokens", usage.cachedContentTokenCount);
4685
+ if (outputTokens > 0) safeSetAttribute$1(span, "gen_ai.usage.output_tokens", outputTokens);
4686
+ safeSetAttribute$1(span, LLM_USAGE_TOTAL_TOKENS, usage.totalTokenCount);
4687
+ safeSetAttribute$1(span, "gen_ai.usage.reasoning_tokens", usage.thoughtsTokenCount);
4688
+ safeSetAttribute$1(span, "gen_ai.usage.cache_read_input_tokens", usage.cachedContentTokenCount);
4689
4689
  }
4690
4690
  if (traceContent && response.candidates) {
4691
4691
  const outputMessages = [];
@@ -4712,7 +4712,7 @@ function setResponseAttributes(span, response, traceContent) {
4712
4712
  ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
4713
4713
  });
4714
4714
  }
4715
- if (outputMessages.length > 0) safeSetAttribute(span, "gen_ai.output.messages", JSON.stringify(outputMessages));
4715
+ if (outputMessages.length > 0) safeSetAttribute$1(span, "gen_ai.output.messages", JSON.stringify(outputMessages));
4716
4716
  }
4717
4717
  }
4718
4718
  /**
@@ -4777,7 +4777,7 @@ function wrapStreamingResponse(span, asyncGen, traceContent) {
4777
4777
  try {
4778
4778
  if (modelVersion !== void 0 || role !== void 0 || accumulatedParts.length > 0 || sawUsageMetadata) {
4779
4779
  const mergedParts = mergeTextParts(accumulatedParts);
4780
- setResponseAttributes(span, {
4780
+ setResponseAttributes$1(span, {
4781
4781
  modelVersion,
4782
4782
  candidates: [{ content: {
4783
4783
  role: role ?? "model",
@@ -4807,7 +4807,7 @@ function wrapStreamingResponse(span, asyncGen, traceContent) {
4807
4807
  }
4808
4808
  //#endregion
4809
4809
  //#region src/opentelemetry-lib/instrumentation/google-genai/index.ts
4810
- const WRAPPED_SYMBOL = Symbol("lmnr.google-genai.wrapped");
4810
+ const WRAPPED_SYMBOL$1 = Symbol("lmnr.google-genai.wrapped");
4811
4811
  const CLASS_PATCH_DATA_SYMBOL = Symbol("lmnr.google-genai.classPatchData");
4812
4812
  var GoogleGenAiInstrumentation = class extends InstrumentationBase {
4813
4813
  constructor(config) {
@@ -4893,7 +4893,7 @@ var GoogleGenAiInstrumentation = class extends InstrumentationBase {
4893
4893
  if (!models || typeof models !== "object") return;
4894
4894
  if (typeof models.generateContent !== "function") return;
4895
4895
  if (typeof models.generateContentStream !== "function") return;
4896
- if (models[WRAPPED_SYMBOL]) return;
4896
+ if (models[WRAPPED_SYMBOL$1]) return;
4897
4897
  const originalGenerateContent = models.generateContent.bind(models);
4898
4898
  const originalGenerateContentStream = models.generateContentStream.bind(models);
4899
4899
  models.generateContent = async function(params) {
@@ -4902,11 +4902,11 @@ var GoogleGenAiInstrumentation = class extends InstrumentationBase {
4902
4902
  name: "gemini.generate_content",
4903
4903
  spanType: "LLM"
4904
4904
  });
4905
- setRequestAttributes(span, params, classPatchData.traceContent);
4905
+ setRequestAttributes$1(span, params, classPatchData.traceContent);
4906
4906
  return Laminar.withSpan(span, async () => {
4907
4907
  try {
4908
4908
  const response = await originalGenerateContent(params);
4909
- setResponseAttributes(span, response, classPatchData.traceContent);
4909
+ setResponseAttributes$1(span, response, classPatchData.traceContent);
4910
4910
  return response;
4911
4911
  } catch (error) {
4912
4912
  span.setAttribute("error.type", error.constructor?.name ?? "Error");
@@ -4921,7 +4921,7 @@ var GoogleGenAiInstrumentation = class extends InstrumentationBase {
4921
4921
  name: "gemini.generate_content_stream",
4922
4922
  spanType: "LLM"
4923
4923
  });
4924
- setRequestAttributes(span, params, classPatchData.traceContent);
4924
+ setRequestAttributes$1(span, params, classPatchData.traceContent);
4925
4925
  try {
4926
4926
  return wrapStreamingResponse(span, await originalGenerateContentStream(params), classPatchData.traceContent);
4927
4927
  } catch (error) {
@@ -4932,7 +4932,7 @@ var GoogleGenAiInstrumentation = class extends InstrumentationBase {
4932
4932
  throw error;
4933
4933
  }
4934
4934
  };
4935
- models[WRAPPED_SYMBOL] = true;
4935
+ models[WRAPPED_SYMBOL$1] = true;
4936
4936
  }
4937
4937
  };
4938
4938
  //#endregion
@@ -5747,6 +5747,410 @@ var OpencodeInstrumentation = class extends InstrumentationBase {
5747
5747
  }
5748
5748
  };
5749
5749
  //#endregion
5750
+ //#region src/opentelemetry-lib/instrumentation/openrouter/utils.ts
5751
+ const TERMINAL_RESPONSE_EVENTS = new Set([
5752
+ "response.completed",
5753
+ "response.incomplete",
5754
+ "response.failed"
5755
+ ]);
5756
+ const ERROR_RESPONSE_STATUSES = new Set(["failed", "incomplete"]);
5757
+ const safeSetAttribute = (span, key, value) => {
5758
+ if (value === null || value === void 0) return;
5759
+ if (typeof value === "string" && value.length === 0) return;
5760
+ span.setAttribute(key, value);
5761
+ };
5762
+ const recordError = (span, error) => {
5763
+ span.setAttribute("error.type", error?.constructor?.name ?? "Error");
5764
+ span.recordException(error);
5765
+ span.setStatus({ code: SpanStatusCode.ERROR });
5766
+ };
5767
+ const isAsyncIterable = (value) => typeof value?.[Symbol.asyncIterator] === "function";
5768
+ const responsesInputMessages = (request) => {
5769
+ const messages = [];
5770
+ if (request?.instructions) messages.push({
5771
+ role: "system",
5772
+ content: request.instructions
5773
+ });
5774
+ if (typeof request?.input === "string") messages.push({
5775
+ role: "user",
5776
+ content: request.input
5777
+ });
5778
+ else if (Array.isArray(request?.input)) messages.push(...request.input);
5779
+ return messages;
5780
+ };
5781
+ const structuredOutputSchema = (kind, request) => {
5782
+ const format = kind === "chat" ? request?.responseFormat : request?.text?.format;
5783
+ if (format?.type !== "json_schema") return void 0;
5784
+ return kind === "chat" ? format.jsonSchema?.schema : format.schema;
5785
+ };
5786
+ /**
5787
+ * `input` is either one document or a batch of them. A flat array of numbers is
5788
+ * a single token-id sequence, not a batch — the API returns one embedding for it.
5789
+ */
5790
+ const embeddingsInputMessages = (input) => {
5791
+ return (Array.isArray(input) && !(input.length > 0 && typeof input[0] === "number") ? input : [input]).map((content) => ({ content }));
5792
+ };
5793
+ const setRequestAttributes = (span, kind, request, traceContent) => {
5794
+ safeSetAttribute(span, "gen_ai.request.model", request?.model);
5795
+ safeSetAttribute(span, "llm.user", request?.user);
5796
+ if (kind === "embeddings") {
5797
+ if (traceContent && request?.input !== void 0) safeSetAttribute(span, "gen_ai.input.messages", JSON.stringify(embeddingsInputMessages(request.input)));
5798
+ return;
5799
+ }
5800
+ safeSetAttribute(span, "gen_ai.request.temperature", request?.temperature);
5801
+ safeSetAttribute(span, "gen_ai.request.top_p", request?.topP);
5802
+ safeSetAttribute(span, "gen_ai.request.frequency_penalty", request?.frequencyPenalty);
5803
+ safeSetAttribute(span, "gen_ai.request.presence_penalty", request?.presencePenalty);
5804
+ safeSetAttribute(span, "gen_ai.request.reasoning_effort", request?.reasoningEffort ?? request?.reasoning?.effort);
5805
+ safeSetAttribute(span, "gen_ai.request.max_tokens", kind === "chat" ? request?.maxTokens : request?.maxOutputTokens);
5806
+ const schema = structuredOutputSchema(kind, request);
5807
+ if (schema) safeSetAttribute(span, "gen_ai.request.structured_output_schema", JSON.stringify(schema));
5808
+ if (request?.stream) safeSetAttribute(span, "llm.is_streaming", true);
5809
+ if (!traceContent) return;
5810
+ if (Array.isArray(request?.tools) && request.tools.length > 0) safeSetAttribute(span, "gen_ai.tool.definitions", JSON.stringify(request.tools));
5811
+ const messages = kind === "chat" ? request?.messages : responsesInputMessages(request);
5812
+ if (Array.isArray(messages) && messages.length > 0) safeSetAttribute(span, "gen_ai.input.messages", JSON.stringify(messages));
5813
+ };
5814
+ const setUsageAttributes = (span, usage, inputKey, outputKey, inputCostKey, outputCostKey) => {
5815
+ if (!usage) return;
5816
+ safeSetAttribute(span, "gen_ai.usage.input_tokens", usage[inputKey]);
5817
+ safeSetAttribute(span, "gen_ai.usage.output_tokens", usage[outputKey]);
5818
+ safeSetAttribute(span, "llm.usage.total_tokens", usage.totalTokens);
5819
+ const inputDetails = usage[`${inputKey}Details`];
5820
+ safeSetAttribute(span, "gen_ai.usage.cache_read_input_tokens", inputDetails?.cachedTokens);
5821
+ safeSetAttribute(span, "gen_ai.usage.cache_creation_input_tokens", inputDetails?.cacheWriteTokens);
5822
+ safeSetAttribute(span, "gen_ai.usage.reasoning_tokens", usage[`${outputKey}Details`]?.reasoningTokens);
5823
+ safeSetAttribute(span, "gen_ai.usage.cost", usage.cost);
5824
+ safeSetAttribute(span, "gen_ai.usage.input_cost", usage.costDetails?.[inputCostKey]);
5825
+ safeSetAttribute(span, "gen_ai.usage.output_cost", usage.costDetails?.[outputCostKey]);
5826
+ };
5827
+ /** Message to fail the span with, or `undefined` if the response succeeded. */
5828
+ const responsesErrorMessage = (response) => {
5829
+ if (!ERROR_RESPONSE_STATUSES.has(response?.status)) return void 0;
5830
+ return response.error?.message ?? response.incompleteDetails?.reason ?? response.status;
5831
+ };
5832
+ const setResponseAttributes = (span, kind, response, traceContent) => {
5833
+ if (!response) return;
5834
+ safeSetAttribute(span, "gen_ai.response.id", response.id);
5835
+ safeSetAttribute(span, "gen_ai.response.model", response.model);
5836
+ if (kind === "responses") {
5837
+ setUsageAttributes(span, response.usage, "inputTokens", "outputTokens", "upstreamInferenceInputCost", "upstreamInferenceOutputCost");
5838
+ const error = responsesErrorMessage(response);
5839
+ if (error) {
5840
+ span.setAttribute("error.type", response.status);
5841
+ span.setStatus({
5842
+ code: SpanStatusCode.ERROR,
5843
+ message: error
5844
+ });
5845
+ }
5846
+ } else setUsageAttributes(span, response.usage, "promptTokens", "completionTokens", "upstreamInferencePromptCost", "upstreamInferenceCompletionsCost");
5847
+ if (!traceContent || kind === "embeddings") return;
5848
+ const output = kind === "chat" ? response.choices : response.output;
5849
+ if (Array.isArray(output) && output.length > 0) safeSetAttribute(span, "gen_ai.output.messages", JSON.stringify(output));
5850
+ };
5851
+ const aggregateChatChunks = (chunks) => {
5852
+ const result = {
5853
+ id: void 0,
5854
+ model: void 0,
5855
+ usage: void 0
5856
+ };
5857
+ const choices = /* @__PURE__ */ new Map();
5858
+ const toolCalls = /* @__PURE__ */ new Map();
5859
+ for (const chunk of chunks) {
5860
+ result.id ??= chunk?.id;
5861
+ result.model ??= chunk?.model;
5862
+ if (chunk?.usage) result.usage = chunk.usage;
5863
+ for (const choice of chunk?.choices ?? []) {
5864
+ const index = choice.index ?? 0;
5865
+ if (!choices.has(index)) choices.set(index, {
5866
+ index,
5867
+ message: {
5868
+ role: "assistant",
5869
+ content: ""
5870
+ },
5871
+ finishReason: void 0
5872
+ });
5873
+ const accumulated = choices.get(index);
5874
+ const delta = choice.delta ?? {};
5875
+ if (delta.role) accumulated.message.role = delta.role;
5876
+ if (delta.content) accumulated.message.content += delta.content;
5877
+ for (const call of delta.toolCalls ?? []) {
5878
+ if (!toolCalls.has(index)) toolCalls.set(index, /* @__PURE__ */ new Map());
5879
+ const calls = toolCalls.get(index);
5880
+ const callIndex = call.index ?? 0;
5881
+ if (!calls.has(callIndex)) calls.set(callIndex, {
5882
+ id: void 0,
5883
+ type: "function",
5884
+ function: {
5885
+ name: "",
5886
+ arguments: ""
5887
+ }
5888
+ });
5889
+ const slot = calls.get(callIndex);
5890
+ slot.id ??= call.id;
5891
+ slot.function.name += call.function?.name ?? "";
5892
+ slot.function.arguments += call.function?.arguments ?? "";
5893
+ }
5894
+ if (choice.finishReason) accumulated.finishReason = choice.finishReason;
5895
+ }
5896
+ }
5897
+ for (const [index, calls] of toolCalls) choices.get(index).message.toolCalls = [...calls.keys()].sort((a, b) => a - b).map((key) => calls.get(key));
5898
+ result.choices = [...choices.keys()].sort((a, b) => a - b).map((key) => choices.get(key));
5899
+ return result;
5900
+ };
5901
+ const responseFromStreamEvents = (events) => {
5902
+ for (let i = events.length - 1; i >= 0; i--) if (TERMINAL_RESPONSE_EVENTS.has(events[i]?.type)) return events[i].response;
5903
+ };
5904
+ /**
5905
+ * Replaces the stream's async iterator so the span is finalized once the
5906
+ * consumer finishes (or abandons) iteration. The stream object is returned as-is.
5907
+ */
5908
+ const wrapStream = (span, kind, stream, traceContent) => {
5909
+ const originalIterator = stream[Symbol.asyncIterator].bind(stream);
5910
+ async function* wrapper() {
5911
+ const chunks = [];
5912
+ try {
5913
+ for await (const chunk of { [Symbol.asyncIterator]: originalIterator }) {
5914
+ chunks.push(chunk);
5915
+ yield chunk;
5916
+ }
5917
+ } catch (error) {
5918
+ recordError(span, error);
5919
+ throw error;
5920
+ } finally {
5921
+ try {
5922
+ setResponseAttributes(span, kind, kind === "chat" ? aggregateChatChunks(chunks) : responseFromStreamEvents(chunks), traceContent);
5923
+ } finally {
5924
+ span.end();
5925
+ }
5926
+ }
5927
+ }
5928
+ stream[Symbol.asyncIterator] = wrapper;
5929
+ return stream;
5930
+ };
5931
+ //#endregion
5932
+ //#region src/opentelemetry-lib/instrumentation/openrouter/index.ts
5933
+ const WRAPPED_SYMBOL = Symbol("lmnr.openrouter.wrapped");
5934
+ const PATCH_STATE_SYMBOL = Symbol("lmnr.openrouter.patch-state");
5935
+ /** The method each resource sends on, and the key its request is wrapped in. */
5936
+ const RESOURCE_METHODS = {
5937
+ chat: {
5938
+ method: "send",
5939
+ requestKey: "chatRequest"
5940
+ },
5941
+ responses: {
5942
+ method: "send",
5943
+ requestKey: "responsesRequest"
5944
+ },
5945
+ embeddings: {
5946
+ method: "generate",
5947
+ requestKey: "requestBody"
5948
+ }
5949
+ };
5950
+ const RESOURCE_KINDS = Object.keys(RESOURCE_METHODS);
5951
+ var OpenRouterInstrumentation = class extends InstrumentationBase {
5952
+ constructor(config) {
5953
+ super("@lmnr/openrouter-instrumentation", version, { enabled: true });
5954
+ this.traceContent = config?.traceContent ?? true;
5955
+ }
5956
+ init() {
5957
+ return new InstrumentationNodeModuleDefinition("@openrouter/sdk", [">=1.0.0"], this.patch.bind(this), this.unpatch.bind(this));
5958
+ }
5959
+ manuallyInstrument(openRouterModule) {
5960
+ diag.debug("Manually instrumenting @openrouter/sdk");
5961
+ const OpenRouterClass = this.resolveOpenRouterClass(openRouterModule);
5962
+ if (OpenRouterClass) this.patchOpenRouterClass(OpenRouterClass);
5963
+ else diag.warn("Could not find OpenRouter class in openrouter manual instrumentation input. Pass either the OpenRouter class or the module object with an OpenRouter export.");
5964
+ }
5965
+ patch(moduleExports) {
5966
+ diag.debug("Patching @openrouter/sdk");
5967
+ const OpenRouterClass = this.resolveOpenRouterClass(moduleExports);
5968
+ if (OpenRouterClass) this.patchOpenRouterClass(OpenRouterClass);
5969
+ return moduleExports;
5970
+ }
5971
+ unpatch(moduleExports) {
5972
+ diag.debug("Unpatching @openrouter/sdk");
5973
+ const OpenRouterClass = this.resolveOpenRouterClass(moduleExports);
5974
+ if (OpenRouterClass) this.unpatchOpenRouterClass(OpenRouterClass);
5975
+ }
5976
+ resolveOpenRouterClass(moduleOrClass) {
5977
+ if (typeof moduleOrClass === "function") return moduleOrClass;
5978
+ if (typeof moduleOrClass?.OpenRouter === "function") return moduleOrClass.OpenRouter;
5979
+ }
5980
+ patchOpenRouterClass(OpenRouterClass) {
5981
+ const proto = OpenRouterClass.prototype;
5982
+ const existing = proto[PATCH_STATE_SYMBOL];
5983
+ if (existing) {
5984
+ existing.traceContent = this.traceContent;
5985
+ return;
5986
+ }
5987
+ const state = {
5988
+ traceContent: this.traceContent,
5989
+ chat: Object.getOwnPropertyDescriptor(proto, "chat"),
5990
+ responses: Object.getOwnPropertyDescriptor(proto, "responses"),
5991
+ embeddings: Object.getOwnPropertyDescriptor(proto, "embeddings"),
5992
+ callModel: proto.callModel
5993
+ };
5994
+ proto[PATCH_STATE_SYMBOL] = state;
5995
+ for (const kind of RESOURCE_KINDS) patchResourceGetter(proto, kind, state);
5996
+ if (typeof state.callModel === "function") patchCallModel(proto, state);
5997
+ }
5998
+ unpatchOpenRouterClass(OpenRouterClass) {
5999
+ const proto = OpenRouterClass.prototype;
6000
+ const state = proto[PATCH_STATE_SYMBOL];
6001
+ if (!state) return;
6002
+ for (const kind of RESOURCE_KINDS) if (state[kind]) Object.defineProperty(proto, kind, state[kind]);
6003
+ else delete proto[kind];
6004
+ if (state.callModel) proto.callModel = state.callModel;
6005
+ delete proto[PATCH_STATE_SYMBOL];
6006
+ }
6007
+ };
6008
+ const patchResourceGetter = (proto, kind, state) => {
6009
+ const descriptor = state[kind];
6010
+ if (!descriptor?.get || !descriptor.configurable) {
6011
+ diag.warn(`Could not patch OpenRouter.prototype.${kind} getter.`);
6012
+ return;
6013
+ }
6014
+ const originalGet = descriptor.get;
6015
+ Object.defineProperty(proto, kind, {
6016
+ configurable: true,
6017
+ enumerable: descriptor.enumerable ?? false,
6018
+ get() {
6019
+ const resource = originalGet.call(this);
6020
+ patchResourceMethod(resource, kind, state);
6021
+ return resource;
6022
+ }
6023
+ });
6024
+ };
6025
+ const patchResourceMethod = (resource, kind, state) => {
6026
+ if (!resource || resource[WRAPPED_SYMBOL]) return;
6027
+ const { method, requestKey } = RESOURCE_METHODS[kind];
6028
+ if (typeof resource[method] !== "function") return;
6029
+ const original = resource[method].bind(resource);
6030
+ resource[method] = async (request, options) => {
6031
+ if (isTracingSuppressed(context.active())) return original(request, options);
6032
+ const { traceContent } = state;
6033
+ const span = Laminar.startSpan({
6034
+ name: `openrouter.${kind}`,
6035
+ spanType: "LLM"
6036
+ });
6037
+ span.setAttribute("gen_ai.system", "openrouter");
6038
+ setRequestAttributes(span, kind, request?.[requestKey], traceContent);
6039
+ try {
6040
+ const response = await Laminar.withSpan(span, () => original(request, options));
6041
+ if (isAsyncIterable(response)) return wrapStream(span, kind, response, traceContent);
6042
+ setResponseAttributes(span, kind, response, traceContent);
6043
+ span.end();
6044
+ return response;
6045
+ } catch (error) {
6046
+ recordError(span, error);
6047
+ span.end();
6048
+ throw error;
6049
+ }
6050
+ };
6051
+ resource[WRAPPED_SYMBOL] = true;
6052
+ };
6053
+ const patchCallModel = (proto, state) => {
6054
+ const originalCallModel = state.callModel;
6055
+ proto.callModel = function(request, options) {
6056
+ if (isTracingSuppressed(context.active())) return originalCallModel.call(this, request, options);
6057
+ const { traceContent } = state;
6058
+ const span = Laminar.startSpan({
6059
+ name: "openrouter.call_model",
6060
+ input: traceContent ? responsesInputMessages(request) : void 0
6061
+ });
6062
+ const tools = Array.isArray(request?.tools) ? request.tools.map((tool) => wrapTool(tool, span, traceContent)) : void 0;
6063
+ try {
6064
+ const result = Laminar.withSpan(span, () => originalCallModel.call(this, tools ? {
6065
+ ...request,
6066
+ tools
6067
+ } : request, options));
6068
+ instrumentModelResult(result, span, traceContent);
6069
+ return result;
6070
+ } catch (error) {
6071
+ recordError(span, error);
6072
+ span.end();
6073
+ throw error;
6074
+ }
6075
+ };
6076
+ };
6077
+ const wrapTool = (tool, parentSpan, traceContent) => {
6078
+ const fn = tool?.function;
6079
+ if (typeof fn?.execute !== "function" || fn.eventSchema) return tool;
6080
+ const execute = fn.execute;
6081
+ return {
6082
+ ...tool,
6083
+ function: {
6084
+ ...fn,
6085
+ execute: (input, ctx) => Laminar.withSpan(parentSpan, () => {
6086
+ const span = Laminar.startSpan({
6087
+ name: fn.name,
6088
+ spanType: "TOOL",
6089
+ input: traceContent ? input : void 0
6090
+ });
6091
+ return Laminar.withSpan(span, async () => {
6092
+ try {
6093
+ const result = await execute(input, ctx);
6094
+ if (traceContent) span.setOutput(result);
6095
+ return result;
6096
+ } catch (error) {
6097
+ recordError(span, error);
6098
+ throw error;
6099
+ }
6100
+ }, true);
6101
+ })
6102
+ }
6103
+ };
6104
+ };
6105
+ /**
6106
+ * ModelResult runs lazily on first consumption. Each turn's request goes through
6107
+ * getInitialResponse / makeFollowupRequest, and executeToolsIfNeeded is the
6108
+ * memoized promise every consumption path awaits.
6109
+ */
6110
+ const instrumentModelResult = (result, parentSpan, traceContent) => {
6111
+ if (!result || typeof result.executeToolsIfNeeded !== "function") {
6112
+ parentSpan.end();
6113
+ return;
6114
+ }
6115
+ for (const method of ["getInitialResponse", "makeFollowupRequest"]) {
6116
+ if (typeof result[method] !== "function") continue;
6117
+ const original = result[method].bind(result);
6118
+ result[method] = (...args) => Laminar.withSpan(parentSpan, () => {
6119
+ const span = Laminar.startSpan({
6120
+ name: "openrouter.responses",
6121
+ spanType: "LLM"
6122
+ });
6123
+ span.setAttribute("gen_ai.system", "openrouter");
6124
+ return Laminar.withSpan(span, async () => {
6125
+ try {
6126
+ const response = await original(...args);
6127
+ setRequestAttributes(span, "responses", result.resolvedRequest, traceContent);
6128
+ setResponseAttributes(span, "responses", response, traceContent);
6129
+ return response;
6130
+ } catch (error) {
6131
+ recordError(span, error);
6132
+ throw error;
6133
+ }
6134
+ }, true);
6135
+ });
6136
+ }
6137
+ const originalExecute = result.executeToolsIfNeeded.bind(result);
6138
+ let execution;
6139
+ result.executeToolsIfNeeded = () => {
6140
+ if (execution) return execution;
6141
+ const promise = originalExecute();
6142
+ execution = promise;
6143
+ promise.then(() => {
6144
+ if (traceContent && result.finalResponse?.output) parentSpan.setOutput(result.finalResponse.output);
6145
+ parentSpan.end();
6146
+ }, (error) => {
6147
+ recordError(parentSpan, error);
6148
+ parentSpan.end();
6149
+ });
6150
+ return execution;
6151
+ };
6152
+ };
6153
+ //#endregion
5750
6154
  //#region src/version.ts
5751
6155
  const getLangVersion = () => {
5752
6156
  if (process?.versions?.node) return `node@${process.versions.node}`;
@@ -6673,6 +7077,7 @@ const initInstrumentations = (client, suppressContentTracing, sessionRecordingOp
6673
7077
  instrumentations.push(new ClaudeAgentSDKInstrumentation());
6674
7078
  instrumentations.push(new OpencodeInstrumentation());
6675
7079
  instrumentations.push(new OpenAIAgentsInstrumentation());
7080
+ instrumentations.push(new OpenRouterInstrumentation({ traceContent: !suppressContentTracing }));
6676
7081
  return instrumentations;
6677
7082
  };
6678
7083
  const manuallyInitInstrumentations = (client, instrumentModules, suppressContentTracing, sessionRecordingOptions) => {
@@ -6762,6 +7167,11 @@ const manuallyInitInstrumentations = (client, instrumentModules, suppressContent
6762
7167
  instrumentations.push(googleGenAiInstrumentation);
6763
7168
  googleGenAiInstrumentation.manuallyInstrument(instrumentModules.google_genai);
6764
7169
  }
7170
+ if (instrumentModules?.openrouter) {
7171
+ const openRouterInstrumentation = new OpenRouterInstrumentation({ traceContent: !suppressContentTracing });
7172
+ instrumentations.push(openRouterInstrumentation);
7173
+ openRouterInstrumentation.manuallyInstrument(instrumentModules.openrouter);
7174
+ }
6765
7175
  if (instrumentModules?.kernel) {
6766
7176
  const kernelInstrumentation = new KernelInstrumentation();
6767
7177
  instrumentations.push(kernelInstrumentation);