@lmnr-ai/lmnr 0.8.46 → 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.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-CVvi-lCc.cjs");
3
- const require_utils = require("./utils-BC1-3ycw.cjs");
3
+ const require_utils = require("./utils-Cibdqbyh.cjs");
4
4
  const require_consts = require("./consts-9rSS0oeR.cjs");
5
5
  let path = require("path");
6
6
  path = require_rolldown_runtime.__toESM(path);
@@ -183,7 +183,7 @@ var LaminarDataset = class extends EvaluationDataset {
183
183
  */
184
184
  async push(paths, recursive = false) {
185
185
  if (!this.client) throw new Error("Client not set");
186
- const { loadFromPaths } = await Promise.resolve().then(() => require("./file-utils-ChUoEaNR.cjs")).then((n) => n.file_utils_exports);
186
+ const { loadFromPaths } = await Promise.resolve().then(() => require("./file-utils-D8HN2emo.cjs")).then((n) => n.file_utils_exports);
187
187
  const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
188
188
  if (data.length === 0) {
189
189
  console.warn("No data to push. Skipping");
@@ -4593,7 +4593,7 @@ const LLM_USAGE_TOTAL_TOKENS = "llm.usage.total_tokens";
4593
4593
  /**
4594
4594
  * Set an attribute on a span only if the value is non-null, non-undefined, and non-empty.
4595
4595
  */
4596
- function safeSetAttribute(span, key, value) {
4596
+ function safeSetAttribute$1(span, key, value) {
4597
4597
  if (value === null || value === void 0) return;
4598
4598
  if (typeof value === "string" && value.length === 0) return;
4599
4599
  if (Array.isArray(value) && value.length === 0) return;
@@ -4655,44 +4655,44 @@ function extractToolDefinitions(config) {
4655
4655
  /**
4656
4656
  * Set request attributes on a span from generateContent params.
4657
4657
  */
4658
- function setRequestAttributes(span, params, traceContent) {
4659
- safeSetAttribute(span, LLM_SYSTEM, "gemini");
4660
- safeSetAttribute(span, LLM_REQUEST_MODEL, params?.model);
4658
+ function setRequestAttributes$1(span, params, traceContent) {
4659
+ safeSetAttribute$1(span, LLM_SYSTEM, "gemini");
4660
+ safeSetAttribute$1(span, LLM_REQUEST_MODEL, params?.model);
4661
4661
  const config = params?.config;
4662
4662
  if (config) {
4663
- safeSetAttribute(span, "gen_ai.request.temperature", config.temperature);
4664
- safeSetAttribute(span, "gen_ai.request.top_p", config.topP);
4665
- safeSetAttribute(span, "gen_ai.request.top_k", config.topK);
4666
- safeSetAttribute(span, "gen_ai.request.max_tokens", config.maxOutputTokens);
4667
- safeSetAttribute(span, "gen_ai.request.frequency_penalty", config.frequencyPenalty);
4668
- safeSetAttribute(span, "gen_ai.request.presence_penalty", config.presencePenalty);
4669
- safeSetAttribute(span, "gen_ai.request.seed", config.seed);
4670
- safeSetAttribute(span, "gen_ai.request.choice_count", config.candidateCount);
4671
- if (config.stopSequences && config.stopSequences.length > 0) safeSetAttribute(span, "gen_ai.request.stop_sequences", JSON.stringify(config.stopSequences));
4663
+ safeSetAttribute$1(span, "gen_ai.request.temperature", config.temperature);
4664
+ safeSetAttribute$1(span, "gen_ai.request.top_p", config.topP);
4665
+ safeSetAttribute$1(span, "gen_ai.request.top_k", config.topK);
4666
+ safeSetAttribute$1(span, "gen_ai.request.max_tokens", config.maxOutputTokens);
4667
+ safeSetAttribute$1(span, "gen_ai.request.frequency_penalty", config.frequencyPenalty);
4668
+ safeSetAttribute$1(span, "gen_ai.request.presence_penalty", config.presencePenalty);
4669
+ safeSetAttribute$1(span, "gen_ai.request.seed", config.seed);
4670
+ safeSetAttribute$1(span, "gen_ai.request.choice_count", config.candidateCount);
4671
+ if (config.stopSequences && config.stopSequences.length > 0) safeSetAttribute$1(span, "gen_ai.request.stop_sequences", JSON.stringify(config.stopSequences));
4672
4672
  const outputSchema = config.responseSchema ?? config.responseJsonSchema;
4673
- if (outputSchema) safeSetAttribute(span, "gen_ai.request.structured_output_schema", JSON.stringify(toDict(outputSchema)));
4673
+ if (outputSchema) safeSetAttribute$1(span, "gen_ai.request.structured_output_schema", JSON.stringify(toDict(outputSchema)));
4674
4674
  const toolDefs = extractToolDefinitions(config);
4675
- if (toolDefs.length > 0) safeSetAttribute(span, "gen_ai.tool.definitions", JSON.stringify(toolDefs));
4675
+ if (toolDefs.length > 0) safeSetAttribute$1(span, "gen_ai.tool.definitions", JSON.stringify(toolDefs));
4676
4676
  }
4677
4677
  if (traceContent) {
4678
4678
  const messages = contentToMessages(params?.contents, config?.systemInstruction);
4679
- if (messages.length > 0) safeSetAttribute(span, "gen_ai.input.messages", JSON.stringify(messages));
4679
+ if (messages.length > 0) safeSetAttribute$1(span, "gen_ai.input.messages", JSON.stringify(messages));
4680
4680
  }
4681
4681
  }
4682
4682
  /**
4683
4683
  * Set response attributes on a span from a GenerateContentResponse.
4684
4684
  */
4685
- function setResponseAttributes(span, response, traceContent) {
4685
+ function setResponseAttributes$1(span, response, traceContent) {
4686
4686
  if (!response) return;
4687
- safeSetAttribute(span, LLM_RESPONSE_MODEL, response.modelVersion);
4687
+ safeSetAttribute$1(span, LLM_RESPONSE_MODEL, response.modelVersion);
4688
4688
  const usage = response.usageMetadata;
4689
4689
  if (usage) {
4690
- safeSetAttribute(span, "gen_ai.usage.input_tokens", usage.promptTokenCount);
4690
+ safeSetAttribute$1(span, "gen_ai.usage.input_tokens", usage.promptTokenCount);
4691
4691
  const outputTokens = (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0);
4692
- if (outputTokens > 0) safeSetAttribute(span, "gen_ai.usage.output_tokens", outputTokens);
4693
- safeSetAttribute(span, LLM_USAGE_TOTAL_TOKENS, usage.totalTokenCount);
4694
- safeSetAttribute(span, "gen_ai.usage.reasoning_tokens", usage.thoughtsTokenCount);
4695
- safeSetAttribute(span, "gen_ai.usage.cache_read_input_tokens", usage.cachedContentTokenCount);
4692
+ if (outputTokens > 0) safeSetAttribute$1(span, "gen_ai.usage.output_tokens", outputTokens);
4693
+ safeSetAttribute$1(span, LLM_USAGE_TOTAL_TOKENS, usage.totalTokenCount);
4694
+ safeSetAttribute$1(span, "gen_ai.usage.reasoning_tokens", usage.thoughtsTokenCount);
4695
+ safeSetAttribute$1(span, "gen_ai.usage.cache_read_input_tokens", usage.cachedContentTokenCount);
4696
4696
  }
4697
4697
  if (traceContent && response.candidates) {
4698
4698
  const outputMessages = [];
@@ -4719,7 +4719,7 @@ function setResponseAttributes(span, response, traceContent) {
4719
4719
  ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
4720
4720
  });
4721
4721
  }
4722
- if (outputMessages.length > 0) safeSetAttribute(span, "gen_ai.output.messages", JSON.stringify(outputMessages));
4722
+ if (outputMessages.length > 0) safeSetAttribute$1(span, "gen_ai.output.messages", JSON.stringify(outputMessages));
4723
4723
  }
4724
4724
  }
4725
4725
  /**
@@ -4784,7 +4784,7 @@ function wrapStreamingResponse(span, asyncGen, traceContent) {
4784
4784
  try {
4785
4785
  if (modelVersion !== void 0 || role !== void 0 || accumulatedParts.length > 0 || sawUsageMetadata) {
4786
4786
  const mergedParts = mergeTextParts(accumulatedParts);
4787
- setResponseAttributes(span, {
4787
+ setResponseAttributes$1(span, {
4788
4788
  modelVersion,
4789
4789
  candidates: [{ content: {
4790
4790
  role: role ?? "model",
@@ -4814,7 +4814,7 @@ function wrapStreamingResponse(span, asyncGen, traceContent) {
4814
4814
  }
4815
4815
  //#endregion
4816
4816
  //#region src/opentelemetry-lib/instrumentation/google-genai/index.ts
4817
- const WRAPPED_SYMBOL = Symbol("lmnr.google-genai.wrapped");
4817
+ const WRAPPED_SYMBOL$1 = Symbol("lmnr.google-genai.wrapped");
4818
4818
  const CLASS_PATCH_DATA_SYMBOL = Symbol("lmnr.google-genai.classPatchData");
4819
4819
  var GoogleGenAiInstrumentation = class extends _opentelemetry_instrumentation.InstrumentationBase {
4820
4820
  constructor(config) {
@@ -4900,7 +4900,7 @@ var GoogleGenAiInstrumentation = class extends _opentelemetry_instrumentation.In
4900
4900
  if (!models || typeof models !== "object") return;
4901
4901
  if (typeof models.generateContent !== "function") return;
4902
4902
  if (typeof models.generateContentStream !== "function") return;
4903
- if (models[WRAPPED_SYMBOL]) return;
4903
+ if (models[WRAPPED_SYMBOL$1]) return;
4904
4904
  const originalGenerateContent = models.generateContent.bind(models);
4905
4905
  const originalGenerateContentStream = models.generateContentStream.bind(models);
4906
4906
  models.generateContent = async function(params) {
@@ -4909,11 +4909,11 @@ var GoogleGenAiInstrumentation = class extends _opentelemetry_instrumentation.In
4909
4909
  name: "gemini.generate_content",
4910
4910
  spanType: "LLM"
4911
4911
  });
4912
- setRequestAttributes(span, params, classPatchData.traceContent);
4912
+ setRequestAttributes$1(span, params, classPatchData.traceContent);
4913
4913
  return Laminar.withSpan(span, async () => {
4914
4914
  try {
4915
4915
  const response = await originalGenerateContent(params);
4916
- setResponseAttributes(span, response, classPatchData.traceContent);
4916
+ setResponseAttributes$1(span, response, classPatchData.traceContent);
4917
4917
  return response;
4918
4918
  } catch (error) {
4919
4919
  span.setAttribute("error.type", error.constructor?.name ?? "Error");
@@ -4928,7 +4928,7 @@ var GoogleGenAiInstrumentation = class extends _opentelemetry_instrumentation.In
4928
4928
  name: "gemini.generate_content_stream",
4929
4929
  spanType: "LLM"
4930
4930
  });
4931
- setRequestAttributes(span, params, classPatchData.traceContent);
4931
+ setRequestAttributes$1(span, params, classPatchData.traceContent);
4932
4932
  try {
4933
4933
  return wrapStreamingResponse(span, await originalGenerateContentStream(params), classPatchData.traceContent);
4934
4934
  } catch (error) {
@@ -4939,7 +4939,7 @@ var GoogleGenAiInstrumentation = class extends _opentelemetry_instrumentation.In
4939
4939
  throw error;
4940
4940
  }
4941
4941
  };
4942
- models[WRAPPED_SYMBOL] = true;
4942
+ models[WRAPPED_SYMBOL$1] = true;
4943
4943
  }
4944
4944
  };
4945
4945
  //#endregion
@@ -5754,6 +5754,410 @@ var OpencodeInstrumentation = class extends _opentelemetry_instrumentation.Instr
5754
5754
  }
5755
5755
  };
5756
5756
  //#endregion
5757
+ //#region src/opentelemetry-lib/instrumentation/openrouter/utils.ts
5758
+ const TERMINAL_RESPONSE_EVENTS = new Set([
5759
+ "response.completed",
5760
+ "response.incomplete",
5761
+ "response.failed"
5762
+ ]);
5763
+ const ERROR_RESPONSE_STATUSES = new Set(["failed", "incomplete"]);
5764
+ const safeSetAttribute = (span, key, value) => {
5765
+ if (value === null || value === void 0) return;
5766
+ if (typeof value === "string" && value.length === 0) return;
5767
+ span.setAttribute(key, value);
5768
+ };
5769
+ const recordError = (span, error) => {
5770
+ span.setAttribute("error.type", error?.constructor?.name ?? "Error");
5771
+ span.recordException(error);
5772
+ span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
5773
+ };
5774
+ const isAsyncIterable = (value) => typeof value?.[Symbol.asyncIterator] === "function";
5775
+ const responsesInputMessages = (request) => {
5776
+ const messages = [];
5777
+ if (request?.instructions) messages.push({
5778
+ role: "system",
5779
+ content: request.instructions
5780
+ });
5781
+ if (typeof request?.input === "string") messages.push({
5782
+ role: "user",
5783
+ content: request.input
5784
+ });
5785
+ else if (Array.isArray(request?.input)) messages.push(...request.input);
5786
+ return messages;
5787
+ };
5788
+ const structuredOutputSchema = (kind, request) => {
5789
+ const format = kind === "chat" ? request?.responseFormat : request?.text?.format;
5790
+ if (format?.type !== "json_schema") return void 0;
5791
+ return kind === "chat" ? format.jsonSchema?.schema : format.schema;
5792
+ };
5793
+ /**
5794
+ * `input` is either one document or a batch of them. A flat array of numbers is
5795
+ * a single token-id sequence, not a batch — the API returns one embedding for it.
5796
+ */
5797
+ const embeddingsInputMessages = (input) => {
5798
+ return (Array.isArray(input) && !(input.length > 0 && typeof input[0] === "number") ? input : [input]).map((content) => ({ content }));
5799
+ };
5800
+ const setRequestAttributes = (span, kind, request, traceContent) => {
5801
+ safeSetAttribute(span, "gen_ai.request.model", request?.model);
5802
+ safeSetAttribute(span, "llm.user", request?.user);
5803
+ if (kind === "embeddings") {
5804
+ if (traceContent && request?.input !== void 0) safeSetAttribute(span, "gen_ai.input.messages", JSON.stringify(embeddingsInputMessages(request.input)));
5805
+ return;
5806
+ }
5807
+ safeSetAttribute(span, "gen_ai.request.temperature", request?.temperature);
5808
+ safeSetAttribute(span, "gen_ai.request.top_p", request?.topP);
5809
+ safeSetAttribute(span, "gen_ai.request.frequency_penalty", request?.frequencyPenalty);
5810
+ safeSetAttribute(span, "gen_ai.request.presence_penalty", request?.presencePenalty);
5811
+ safeSetAttribute(span, "gen_ai.request.reasoning_effort", request?.reasoningEffort ?? request?.reasoning?.effort);
5812
+ safeSetAttribute(span, "gen_ai.request.max_tokens", kind === "chat" ? request?.maxTokens : request?.maxOutputTokens);
5813
+ const schema = structuredOutputSchema(kind, request);
5814
+ if (schema) safeSetAttribute(span, "gen_ai.request.structured_output_schema", JSON.stringify(schema));
5815
+ if (request?.stream) safeSetAttribute(span, "llm.is_streaming", true);
5816
+ if (!traceContent) return;
5817
+ if (Array.isArray(request?.tools) && request.tools.length > 0) safeSetAttribute(span, "gen_ai.tool.definitions", JSON.stringify(request.tools));
5818
+ const messages = kind === "chat" ? request?.messages : responsesInputMessages(request);
5819
+ if (Array.isArray(messages) && messages.length > 0) safeSetAttribute(span, "gen_ai.input.messages", JSON.stringify(messages));
5820
+ };
5821
+ const setUsageAttributes = (span, usage, inputKey, outputKey, inputCostKey, outputCostKey) => {
5822
+ if (!usage) return;
5823
+ safeSetAttribute(span, "gen_ai.usage.input_tokens", usage[inputKey]);
5824
+ safeSetAttribute(span, "gen_ai.usage.output_tokens", usage[outputKey]);
5825
+ safeSetAttribute(span, "llm.usage.total_tokens", usage.totalTokens);
5826
+ const inputDetails = usage[`${inputKey}Details`];
5827
+ safeSetAttribute(span, "gen_ai.usage.cache_read_input_tokens", inputDetails?.cachedTokens);
5828
+ safeSetAttribute(span, "gen_ai.usage.cache_creation_input_tokens", inputDetails?.cacheWriteTokens);
5829
+ safeSetAttribute(span, "gen_ai.usage.reasoning_tokens", usage[`${outputKey}Details`]?.reasoningTokens);
5830
+ safeSetAttribute(span, "gen_ai.usage.cost", usage.cost);
5831
+ safeSetAttribute(span, "gen_ai.usage.input_cost", usage.costDetails?.[inputCostKey]);
5832
+ safeSetAttribute(span, "gen_ai.usage.output_cost", usage.costDetails?.[outputCostKey]);
5833
+ };
5834
+ /** Message to fail the span with, or `undefined` if the response succeeded. */
5835
+ const responsesErrorMessage = (response) => {
5836
+ if (!ERROR_RESPONSE_STATUSES.has(response?.status)) return void 0;
5837
+ return response.error?.message ?? response.incompleteDetails?.reason ?? response.status;
5838
+ };
5839
+ const setResponseAttributes = (span, kind, response, traceContent) => {
5840
+ if (!response) return;
5841
+ safeSetAttribute(span, "gen_ai.response.id", response.id);
5842
+ safeSetAttribute(span, "gen_ai.response.model", response.model);
5843
+ if (kind === "responses") {
5844
+ setUsageAttributes(span, response.usage, "inputTokens", "outputTokens", "upstreamInferenceInputCost", "upstreamInferenceOutputCost");
5845
+ const error = responsesErrorMessage(response);
5846
+ if (error) {
5847
+ span.setAttribute("error.type", response.status);
5848
+ span.setStatus({
5849
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
5850
+ message: error
5851
+ });
5852
+ }
5853
+ } else setUsageAttributes(span, response.usage, "promptTokens", "completionTokens", "upstreamInferencePromptCost", "upstreamInferenceCompletionsCost");
5854
+ if (!traceContent || kind === "embeddings") return;
5855
+ const output = kind === "chat" ? response.choices : response.output;
5856
+ if (Array.isArray(output) && output.length > 0) safeSetAttribute(span, "gen_ai.output.messages", JSON.stringify(output));
5857
+ };
5858
+ const aggregateChatChunks = (chunks) => {
5859
+ const result = {
5860
+ id: void 0,
5861
+ model: void 0,
5862
+ usage: void 0
5863
+ };
5864
+ const choices = /* @__PURE__ */ new Map();
5865
+ const toolCalls = /* @__PURE__ */ new Map();
5866
+ for (const chunk of chunks) {
5867
+ result.id ??= chunk?.id;
5868
+ result.model ??= chunk?.model;
5869
+ if (chunk?.usage) result.usage = chunk.usage;
5870
+ for (const choice of chunk?.choices ?? []) {
5871
+ const index = choice.index ?? 0;
5872
+ if (!choices.has(index)) choices.set(index, {
5873
+ index,
5874
+ message: {
5875
+ role: "assistant",
5876
+ content: ""
5877
+ },
5878
+ finishReason: void 0
5879
+ });
5880
+ const accumulated = choices.get(index);
5881
+ const delta = choice.delta ?? {};
5882
+ if (delta.role) accumulated.message.role = delta.role;
5883
+ if (delta.content) accumulated.message.content += delta.content;
5884
+ for (const call of delta.toolCalls ?? []) {
5885
+ if (!toolCalls.has(index)) toolCalls.set(index, /* @__PURE__ */ new Map());
5886
+ const calls = toolCalls.get(index);
5887
+ const callIndex = call.index ?? 0;
5888
+ if (!calls.has(callIndex)) calls.set(callIndex, {
5889
+ id: void 0,
5890
+ type: "function",
5891
+ function: {
5892
+ name: "",
5893
+ arguments: ""
5894
+ }
5895
+ });
5896
+ const slot = calls.get(callIndex);
5897
+ slot.id ??= call.id;
5898
+ slot.function.name += call.function?.name ?? "";
5899
+ slot.function.arguments += call.function?.arguments ?? "";
5900
+ }
5901
+ if (choice.finishReason) accumulated.finishReason = choice.finishReason;
5902
+ }
5903
+ }
5904
+ for (const [index, calls] of toolCalls) choices.get(index).message.toolCalls = [...calls.keys()].sort((a, b) => a - b).map((key) => calls.get(key));
5905
+ result.choices = [...choices.keys()].sort((a, b) => a - b).map((key) => choices.get(key));
5906
+ return result;
5907
+ };
5908
+ const responseFromStreamEvents = (events) => {
5909
+ for (let i = events.length - 1; i >= 0; i--) if (TERMINAL_RESPONSE_EVENTS.has(events[i]?.type)) return events[i].response;
5910
+ };
5911
+ /**
5912
+ * Replaces the stream's async iterator so the span is finalized once the
5913
+ * consumer finishes (or abandons) iteration. The stream object is returned as-is.
5914
+ */
5915
+ const wrapStream = (span, kind, stream, traceContent) => {
5916
+ const originalIterator = stream[Symbol.asyncIterator].bind(stream);
5917
+ async function* wrapper() {
5918
+ const chunks = [];
5919
+ try {
5920
+ for await (const chunk of { [Symbol.asyncIterator]: originalIterator }) {
5921
+ chunks.push(chunk);
5922
+ yield chunk;
5923
+ }
5924
+ } catch (error) {
5925
+ recordError(span, error);
5926
+ throw error;
5927
+ } finally {
5928
+ try {
5929
+ setResponseAttributes(span, kind, kind === "chat" ? aggregateChatChunks(chunks) : responseFromStreamEvents(chunks), traceContent);
5930
+ } finally {
5931
+ span.end();
5932
+ }
5933
+ }
5934
+ }
5935
+ stream[Symbol.asyncIterator] = wrapper;
5936
+ return stream;
5937
+ };
5938
+ //#endregion
5939
+ //#region src/opentelemetry-lib/instrumentation/openrouter/index.ts
5940
+ const WRAPPED_SYMBOL = Symbol("lmnr.openrouter.wrapped");
5941
+ const PATCH_STATE_SYMBOL = Symbol("lmnr.openrouter.patch-state");
5942
+ /** The method each resource sends on, and the key its request is wrapped in. */
5943
+ const RESOURCE_METHODS = {
5944
+ chat: {
5945
+ method: "send",
5946
+ requestKey: "chatRequest"
5947
+ },
5948
+ responses: {
5949
+ method: "send",
5950
+ requestKey: "responsesRequest"
5951
+ },
5952
+ embeddings: {
5953
+ method: "generate",
5954
+ requestKey: "requestBody"
5955
+ }
5956
+ };
5957
+ const RESOURCE_KINDS = Object.keys(RESOURCE_METHODS);
5958
+ var OpenRouterInstrumentation = class extends _opentelemetry_instrumentation.InstrumentationBase {
5959
+ constructor(config) {
5960
+ super("@lmnr/openrouter-instrumentation", require_utils.version, { enabled: true });
5961
+ this.traceContent = config?.traceContent ?? true;
5962
+ }
5963
+ init() {
5964
+ return new _opentelemetry_instrumentation.InstrumentationNodeModuleDefinition("@openrouter/sdk", [">=1.0.0"], this.patch.bind(this), this.unpatch.bind(this));
5965
+ }
5966
+ manuallyInstrument(openRouterModule) {
5967
+ _opentelemetry_api.diag.debug("Manually instrumenting @openrouter/sdk");
5968
+ const OpenRouterClass = this.resolveOpenRouterClass(openRouterModule);
5969
+ if (OpenRouterClass) this.patchOpenRouterClass(OpenRouterClass);
5970
+ else _opentelemetry_api.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.");
5971
+ }
5972
+ patch(moduleExports) {
5973
+ _opentelemetry_api.diag.debug("Patching @openrouter/sdk");
5974
+ const OpenRouterClass = this.resolveOpenRouterClass(moduleExports);
5975
+ if (OpenRouterClass) this.patchOpenRouterClass(OpenRouterClass);
5976
+ return moduleExports;
5977
+ }
5978
+ unpatch(moduleExports) {
5979
+ _opentelemetry_api.diag.debug("Unpatching @openrouter/sdk");
5980
+ const OpenRouterClass = this.resolveOpenRouterClass(moduleExports);
5981
+ if (OpenRouterClass) this.unpatchOpenRouterClass(OpenRouterClass);
5982
+ }
5983
+ resolveOpenRouterClass(moduleOrClass) {
5984
+ if (typeof moduleOrClass === "function") return moduleOrClass;
5985
+ if (typeof moduleOrClass?.OpenRouter === "function") return moduleOrClass.OpenRouter;
5986
+ }
5987
+ patchOpenRouterClass(OpenRouterClass) {
5988
+ const proto = OpenRouterClass.prototype;
5989
+ const existing = proto[PATCH_STATE_SYMBOL];
5990
+ if (existing) {
5991
+ existing.traceContent = this.traceContent;
5992
+ return;
5993
+ }
5994
+ const state = {
5995
+ traceContent: this.traceContent,
5996
+ chat: Object.getOwnPropertyDescriptor(proto, "chat"),
5997
+ responses: Object.getOwnPropertyDescriptor(proto, "responses"),
5998
+ embeddings: Object.getOwnPropertyDescriptor(proto, "embeddings"),
5999
+ callModel: proto.callModel
6000
+ };
6001
+ proto[PATCH_STATE_SYMBOL] = state;
6002
+ for (const kind of RESOURCE_KINDS) patchResourceGetter(proto, kind, state);
6003
+ if (typeof state.callModel === "function") patchCallModel(proto, state);
6004
+ }
6005
+ unpatchOpenRouterClass(OpenRouterClass) {
6006
+ const proto = OpenRouterClass.prototype;
6007
+ const state = proto[PATCH_STATE_SYMBOL];
6008
+ if (!state) return;
6009
+ for (const kind of RESOURCE_KINDS) if (state[kind]) Object.defineProperty(proto, kind, state[kind]);
6010
+ else delete proto[kind];
6011
+ if (state.callModel) proto.callModel = state.callModel;
6012
+ delete proto[PATCH_STATE_SYMBOL];
6013
+ }
6014
+ };
6015
+ const patchResourceGetter = (proto, kind, state) => {
6016
+ const descriptor = state[kind];
6017
+ if (!descriptor?.get || !descriptor.configurable) {
6018
+ _opentelemetry_api.diag.warn(`Could not patch OpenRouter.prototype.${kind} getter.`);
6019
+ return;
6020
+ }
6021
+ const originalGet = descriptor.get;
6022
+ Object.defineProperty(proto, kind, {
6023
+ configurable: true,
6024
+ enumerable: descriptor.enumerable ?? false,
6025
+ get() {
6026
+ const resource = originalGet.call(this);
6027
+ patchResourceMethod(resource, kind, state);
6028
+ return resource;
6029
+ }
6030
+ });
6031
+ };
6032
+ const patchResourceMethod = (resource, kind, state) => {
6033
+ if (!resource || resource[WRAPPED_SYMBOL]) return;
6034
+ const { method, requestKey } = RESOURCE_METHODS[kind];
6035
+ if (typeof resource[method] !== "function") return;
6036
+ const original = resource[method].bind(resource);
6037
+ resource[method] = async (request, options) => {
6038
+ if ((0, _opentelemetry_core.isTracingSuppressed)(_opentelemetry_api.context.active())) return original(request, options);
6039
+ const { traceContent } = state;
6040
+ const span = Laminar.startSpan({
6041
+ name: `openrouter.${kind}`,
6042
+ spanType: "LLM"
6043
+ });
6044
+ span.setAttribute("gen_ai.system", "openrouter");
6045
+ setRequestAttributes(span, kind, request?.[requestKey], traceContent);
6046
+ try {
6047
+ const response = await Laminar.withSpan(span, () => original(request, options));
6048
+ if (isAsyncIterable(response)) return wrapStream(span, kind, response, traceContent);
6049
+ setResponseAttributes(span, kind, response, traceContent);
6050
+ span.end();
6051
+ return response;
6052
+ } catch (error) {
6053
+ recordError(span, error);
6054
+ span.end();
6055
+ throw error;
6056
+ }
6057
+ };
6058
+ resource[WRAPPED_SYMBOL] = true;
6059
+ };
6060
+ const patchCallModel = (proto, state) => {
6061
+ const originalCallModel = state.callModel;
6062
+ proto.callModel = function(request, options) {
6063
+ if ((0, _opentelemetry_core.isTracingSuppressed)(_opentelemetry_api.context.active())) return originalCallModel.call(this, request, options);
6064
+ const { traceContent } = state;
6065
+ const span = Laminar.startSpan({
6066
+ name: "openrouter.call_model",
6067
+ input: traceContent ? responsesInputMessages(request) : void 0
6068
+ });
6069
+ const tools = Array.isArray(request?.tools) ? request.tools.map((tool) => wrapTool(tool, span, traceContent)) : void 0;
6070
+ try {
6071
+ const result = Laminar.withSpan(span, () => originalCallModel.call(this, tools ? {
6072
+ ...request,
6073
+ tools
6074
+ } : request, options));
6075
+ instrumentModelResult(result, span, traceContent);
6076
+ return result;
6077
+ } catch (error) {
6078
+ recordError(span, error);
6079
+ span.end();
6080
+ throw error;
6081
+ }
6082
+ };
6083
+ };
6084
+ const wrapTool = (tool, parentSpan, traceContent) => {
6085
+ const fn = tool?.function;
6086
+ if (typeof fn?.execute !== "function" || fn.eventSchema) return tool;
6087
+ const execute = fn.execute;
6088
+ return {
6089
+ ...tool,
6090
+ function: {
6091
+ ...fn,
6092
+ execute: (input, ctx) => Laminar.withSpan(parentSpan, () => {
6093
+ const span = Laminar.startSpan({
6094
+ name: fn.name,
6095
+ spanType: "TOOL",
6096
+ input: traceContent ? input : void 0
6097
+ });
6098
+ return Laminar.withSpan(span, async () => {
6099
+ try {
6100
+ const result = await execute(input, ctx);
6101
+ if (traceContent) span.setOutput(result);
6102
+ return result;
6103
+ } catch (error) {
6104
+ recordError(span, error);
6105
+ throw error;
6106
+ }
6107
+ }, true);
6108
+ })
6109
+ }
6110
+ };
6111
+ };
6112
+ /**
6113
+ * ModelResult runs lazily on first consumption. Each turn's request goes through
6114
+ * getInitialResponse / makeFollowupRequest, and executeToolsIfNeeded is the
6115
+ * memoized promise every consumption path awaits.
6116
+ */
6117
+ const instrumentModelResult = (result, parentSpan, traceContent) => {
6118
+ if (!result || typeof result.executeToolsIfNeeded !== "function") {
6119
+ parentSpan.end();
6120
+ return;
6121
+ }
6122
+ for (const method of ["getInitialResponse", "makeFollowupRequest"]) {
6123
+ if (typeof result[method] !== "function") continue;
6124
+ const original = result[method].bind(result);
6125
+ result[method] = (...args) => Laminar.withSpan(parentSpan, () => {
6126
+ const span = Laminar.startSpan({
6127
+ name: "openrouter.responses",
6128
+ spanType: "LLM"
6129
+ });
6130
+ span.setAttribute("gen_ai.system", "openrouter");
6131
+ return Laminar.withSpan(span, async () => {
6132
+ try {
6133
+ const response = await original(...args);
6134
+ setRequestAttributes(span, "responses", result.resolvedRequest, traceContent);
6135
+ setResponseAttributes(span, "responses", response, traceContent);
6136
+ return response;
6137
+ } catch (error) {
6138
+ recordError(span, error);
6139
+ throw error;
6140
+ }
6141
+ }, true);
6142
+ });
6143
+ }
6144
+ const originalExecute = result.executeToolsIfNeeded.bind(result);
6145
+ let execution;
6146
+ result.executeToolsIfNeeded = () => {
6147
+ if (execution) return execution;
6148
+ const promise = originalExecute();
6149
+ execution = promise;
6150
+ promise.then(() => {
6151
+ if (traceContent && result.finalResponse?.output) parentSpan.setOutput(result.finalResponse.output);
6152
+ parentSpan.end();
6153
+ }, (error) => {
6154
+ recordError(parentSpan, error);
6155
+ parentSpan.end();
6156
+ });
6157
+ return execution;
6158
+ };
6159
+ };
6160
+ //#endregion
5757
6161
  //#region src/version.ts
5758
6162
  const getLangVersion = () => {
5759
6163
  if (process?.versions?.node) return `node@${process.versions.node}`;
@@ -6680,6 +7084,7 @@ const initInstrumentations = (client, suppressContentTracing, sessionRecordingOp
6680
7084
  instrumentations.push(new ClaudeAgentSDKInstrumentation());
6681
7085
  instrumentations.push(new OpencodeInstrumentation());
6682
7086
  instrumentations.push(new OpenAIAgentsInstrumentation());
7087
+ instrumentations.push(new OpenRouterInstrumentation({ traceContent: !suppressContentTracing }));
6683
7088
  return instrumentations;
6684
7089
  };
6685
7090
  const manuallyInitInstrumentations = (client, instrumentModules, suppressContentTracing, sessionRecordingOptions) => {
@@ -6769,6 +7174,11 @@ const manuallyInitInstrumentations = (client, instrumentModules, suppressContent
6769
7174
  instrumentations.push(googleGenAiInstrumentation);
6770
7175
  googleGenAiInstrumentation.manuallyInstrument(instrumentModules.google_genai);
6771
7176
  }
7177
+ if (instrumentModules?.openrouter) {
7178
+ const openRouterInstrumentation = new OpenRouterInstrumentation({ traceContent: !suppressContentTracing });
7179
+ instrumentations.push(openRouterInstrumentation);
7180
+ openRouterInstrumentation.manuallyInstrument(instrumentModules.openrouter);
7181
+ }
6772
7182
  if (instrumentModules?.kernel) {
6773
7183
  const kernelInstrumentation = new KernelInstrumentation();
6774
7184
  instrumentations.push(kernelInstrumentation);