@lmnr-ai/lmnr 0.8.52 → 0.8.53
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/cli.cjs +2 -2
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/{evaluations-CgcBhNjN.d.cts → evaluations-BXDpgOzM.d.cts} +26 -3
- package/dist/{evaluations-GnmUSvoK.d.mts → evaluations-BwB2JsRa.d.mts} +26 -3
- package/dist/{file-utils-DaZefKLb.mjs → file-utils-CwqjWMsF.mjs} +2 -2
- package/dist/{file-utils-DaZefKLb.mjs.map → file-utils-CwqjWMsF.mjs.map} +1 -1
- package/dist/{file-utils-C_q3Dsf2.cjs → file-utils-CyBBBeeW.cjs} +2 -2
- package/dist/{file-utils-C_q3Dsf2.cjs.map → file-utils-CyBBBeeW.cjs.map} +1 -1
- package/dist/index.cjs +1374 -201
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -6
- package/dist/index.d.mts +19 -6
- package/dist/index.mjs +1375 -202
- package/dist/index.mjs.map +1 -1
- package/dist/{utils-C6gt-rSg.mjs → utils-DavLzQA8.mjs} +5 -4
- package/dist/{utils-C6gt-rSg.mjs.map → utils-DavLzQA8.mjs.map} +1 -1
- package/dist/{utils-vnm5E0kk.cjs → utils-DcdjJ-4n.cjs} +10 -3
- package/dist/{utils-vnm5E0kk.cjs.map → utils-DcdjJ-4n.cjs.map} +1 -1
- package/package.json +15 -12
package/dist/index.mjs
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import { r as __require } from "./rolldown-runtime-B4iAMlE-.mjs";
|
|
2
|
-
import { A as SPAN_INSTRUMENTATION_SOURCE, B as
|
|
2
|
+
import { A as SPAN_INSTRUMENTATION_SOURCE, B as version, C as PARENT_SPAN_IDS_PATH, D as SPAN_INPUT, E as SPAN_IDS_PATH, F as SPAN_SDK_VERSION, G as errorMessage, H as DEBUG_SESSION_DIR, I as SPAN_TYPE, L as TRACE_HAS_BROWSER_SESSION, M as SPAN_OUTPUT, N as SPAN_PATH, O as SPAN_INSTRUMENTATION_SCOPE_NAME, P as SPAN_RELEASE, R as TRACE_TYPE, S as LaminarAttributes, T as SESSION_ID, U as DEBUG_SESSION_FILE, V as LaminarClient, W as TracingLevel, _ 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 USER_ID } from "./utils-DavLzQA8.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";
|
|
6
6
|
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
|
|
7
|
-
import { InstrumentationBase, InstrumentationNodeModuleDefinition, registerInstrumentations } from "@opentelemetry/instrumentation";
|
|
7
|
+
import { InstrumentationBase, InstrumentationNodeModuleDefinition, InstrumentationNodeModuleFile, registerInstrumentations } from "@opentelemetry/instrumentation";
|
|
8
8
|
import { AlwaysOnSampler, BatchSpanProcessor, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
9
9
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
10
10
|
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
|
|
11
11
|
import { BedrockInstrumentation } from "@traceloop/instrumentation-bedrock";
|
|
12
12
|
import { ChromaDBInstrumentation } from "@traceloop/instrumentation-chromadb";
|
|
13
|
-
import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
|
|
14
13
|
import { PineconeInstrumentation } from "@traceloop/instrumentation-pinecone";
|
|
15
14
|
import { QdrantInstrumentation } from "@traceloop/instrumentation-qdrant";
|
|
16
15
|
import { TogetherInstrumentation } from "@traceloop/instrumentation-together";
|
|
17
16
|
import { spawn } from "node:child_process";
|
|
18
17
|
import { randomUUID } from "node:crypto";
|
|
19
|
-
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
20
19
|
import { dirname, join, parse, resolve, sep } from "node:path";
|
|
21
20
|
import * as fs from "fs";
|
|
22
21
|
import * as net from "net";
|
|
23
22
|
import * as os from "os";
|
|
24
23
|
import { AsyncLocalStorage } from "async_hooks";
|
|
25
24
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
26
|
-
import { hrTime, isTracingSuppressed, suppressTracing } from "@opentelemetry/core";
|
|
25
|
+
import { hrTime, isTracingSuppressed, suppressTracing, unsuppressTracing } from "@opentelemetry/core";
|
|
26
|
+
import { AsyncLocalStorage as AsyncLocalStorage$1 } from "node:async_hooks";
|
|
27
27
|
import { Metadata } from "@grpc/grpc-js";
|
|
28
28
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
|
|
29
29
|
import { OTLPTraceExporter as OTLPTraceExporter$1 } from "@opentelemetry/exporter-trace-otlp-proto";
|
|
@@ -188,7 +188,7 @@ var LaminarDataset = class extends EvaluationDataset {
|
|
|
188
188
|
*/
|
|
189
189
|
async push(paths, recursive = false) {
|
|
190
190
|
if (!this.client) throw new Error("Client not set");
|
|
191
|
-
const { loadFromPaths } = await import("./file-utils-
|
|
191
|
+
const { loadFromPaths } = await import("./file-utils-CwqjWMsF.mjs").then((n) => n.t);
|
|
192
192
|
const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
|
|
193
193
|
if (data.length === 0) {
|
|
194
194
|
console.warn("No data to push. Skipping");
|
|
@@ -204,7 +204,7 @@ var LaminarDataset = class extends EvaluationDataset {
|
|
|
204
204
|
};
|
|
205
205
|
//#endregion
|
|
206
206
|
//#region src/opentelemetry-lib/tracing/compat.ts
|
|
207
|
-
const logger$
|
|
207
|
+
const logger$32 = initializeLogger();
|
|
208
208
|
const makeSpanOtelV2Compatible = (span) => {
|
|
209
209
|
const spanAny = span;
|
|
210
210
|
if (spanAny.instrumentationScope && !spanAny.instrumentationLibrary) Object.assign(span, { instrumentationLibrary: spanAny.instrumentationScope });
|
|
@@ -250,7 +250,7 @@ const createResource = (attributes) => {
|
|
|
250
250
|
if (resources.Resource) return new resources.Resource(attributes);
|
|
251
251
|
throw new Error("Unable to create Resource: neither v1 nor v2 API found");
|
|
252
252
|
} catch {
|
|
253
|
-
logger$
|
|
253
|
+
logger$32.debug("Laminar failed to @opentelemetry/resources, continuing without it");
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
256
256
|
};
|
|
@@ -452,7 +452,7 @@ const consumeResponse = async (response) => {
|
|
|
452
452
|
};
|
|
453
453
|
//#endregion
|
|
454
454
|
//#region src/opentelemetry-lib/tracing/stream-utils.ts
|
|
455
|
-
const logger$
|
|
455
|
+
const logger$31 = initializeLogger();
|
|
456
456
|
const pendingStreamProcessing = /* @__PURE__ */ new Set();
|
|
457
457
|
/**
|
|
458
458
|
* Wait for all pending stream processing to complete with a timeout
|
|
@@ -460,7 +460,7 @@ const pendingStreamProcessing = /* @__PURE__ */ new Set();
|
|
|
460
460
|
*/
|
|
461
461
|
const waitForPendingStreams = async (timeoutMs = 5e3) => {
|
|
462
462
|
if (pendingStreamProcessing.size === 0) return;
|
|
463
|
-
logger$
|
|
463
|
+
logger$31.debug(`Waiting for ${pendingStreamProcessing.size} pending stream(s)`);
|
|
464
464
|
const initialCount = pendingStreamProcessing.size;
|
|
465
465
|
const pendingPromises = Array.from(pendingStreamProcessing);
|
|
466
466
|
let timedOut = false;
|
|
@@ -471,7 +471,7 @@ const waitForPendingStreams = async (timeoutMs = 5e3) => {
|
|
|
471
471
|
}, timeoutMs);
|
|
472
472
|
});
|
|
473
473
|
await Promise.race([Promise.allSettled(pendingPromises), timeoutPromise]);
|
|
474
|
-
if (timedOut && pendingStreamProcessing.size > 0) logger$
|
|
474
|
+
if (timedOut && pendingStreamProcessing.size > 0) logger$31.warn(`Timeout waiting for ${pendingStreamProcessing.size} pending stream(s) after ${timeoutMs}ms (started with ${initialCount})`);
|
|
475
475
|
};
|
|
476
476
|
/**
|
|
477
477
|
* Track a background promise and ensure cleanup
|
|
@@ -487,34 +487,34 @@ const trackStreamProcessing = (task) => {
|
|
|
487
487
|
* while passing through the original result to the caller
|
|
488
488
|
*/
|
|
489
489
|
const handleStreamResult = (originalResult, streamInfo, span, ignoreOutput, serialize) => {
|
|
490
|
-
logger$
|
|
490
|
+
logger$31.debug(`Handling stream result of type: ${streamInfo.type}`);
|
|
491
491
|
if (streamInfo.type === "aisdk-result") {
|
|
492
492
|
trackStreamProcessing(async () => {
|
|
493
|
-
logger$
|
|
493
|
+
logger$31.debug("Starting background processing for AI SDK result");
|
|
494
494
|
let partialOutput = {};
|
|
495
495
|
try {
|
|
496
496
|
partialOutput = await consumeAISDKResult(streamInfo.result);
|
|
497
497
|
if (shouldSendTraces() && !ignoreOutput) try {
|
|
498
498
|
span.setAttribute(SPAN_OUTPUT, serialize(partialOutput));
|
|
499
499
|
} catch (error) {
|
|
500
|
-
logger$
|
|
500
|
+
logger$31.warn("Failed to serialize AI SDK stream output: " + errorMessage(error));
|
|
501
501
|
}
|
|
502
502
|
} catch (error) {
|
|
503
503
|
if (Object.keys(partialOutput).length > 0 && shouldSendTraces() && !ignoreOutput) try {
|
|
504
504
|
span.setAttribute(SPAN_OUTPUT, serialize(partialOutput));
|
|
505
505
|
} catch (serError) {
|
|
506
|
-
logger$
|
|
506
|
+
logger$31.warn("Failed to serialize partial AI SDK output: " + errorMessage(serError));
|
|
507
507
|
}
|
|
508
508
|
span.recordException(error);
|
|
509
509
|
} finally {
|
|
510
|
-
logger$
|
|
510
|
+
logger$31.debug("Ending span for AI SDK result");
|
|
511
511
|
span.end();
|
|
512
512
|
}
|
|
513
513
|
});
|
|
514
514
|
return originalResult;
|
|
515
515
|
}
|
|
516
516
|
if (streamInfo.type === "readable-stream") {
|
|
517
|
-
logger$
|
|
517
|
+
logger$31.debug("Setting up background processing for ReadableStream");
|
|
518
518
|
const { stream, dataPromise } = consumeAndTeeReadableStream(streamInfo.stream);
|
|
519
519
|
trackStreamProcessing(async () => {
|
|
520
520
|
try {
|
|
@@ -526,18 +526,18 @@ const handleStreamResult = (originalResult, streamInfo, span, ignoreOutput, seri
|
|
|
526
526
|
};
|
|
527
527
|
span.setAttribute(SPAN_OUTPUT, serialize(output));
|
|
528
528
|
} catch (serError) {
|
|
529
|
-
logger$
|
|
529
|
+
logger$31.warn("Failed to serialize stream output: " + errorMessage(serError));
|
|
530
530
|
}
|
|
531
531
|
if (error) span.recordException(error);
|
|
532
532
|
} finally {
|
|
533
|
-
logger$
|
|
533
|
+
logger$31.debug("Ending span for ReadableStream");
|
|
534
534
|
span.end();
|
|
535
535
|
}
|
|
536
536
|
});
|
|
537
537
|
return stream;
|
|
538
538
|
}
|
|
539
539
|
if (streamInfo.type === "async-iterable") {
|
|
540
|
-
logger$
|
|
540
|
+
logger$31.debug("Setting up background processing for AsyncIterable");
|
|
541
541
|
const { iterable, dataPromise } = consumeAndTeeAsyncIterable(streamInfo.iterable);
|
|
542
542
|
trackStreamProcessing(async () => {
|
|
543
543
|
try {
|
|
@@ -549,18 +549,18 @@ const handleStreamResult = (originalResult, streamInfo, span, ignoreOutput, seri
|
|
|
549
549
|
};
|
|
550
550
|
span.setAttribute(SPAN_OUTPUT, serialize(output));
|
|
551
551
|
} catch (serError) {
|
|
552
|
-
logger$
|
|
552
|
+
logger$31.warn("Failed to serialize async iterable output: " + errorMessage(serError));
|
|
553
553
|
}
|
|
554
554
|
if (error) span.recordException(error);
|
|
555
555
|
} finally {
|
|
556
|
-
logger$
|
|
556
|
+
logger$31.debug("Ending span for AsyncIterable");
|
|
557
557
|
span.end();
|
|
558
558
|
}
|
|
559
559
|
});
|
|
560
560
|
return iterable;
|
|
561
561
|
}
|
|
562
562
|
if (streamInfo.type === "response") {
|
|
563
|
-
logger$
|
|
563
|
+
logger$31.debug("Setting up background processing for Response");
|
|
564
564
|
const originalResponse = streamInfo.response;
|
|
565
565
|
if (!originalResponse.body) {
|
|
566
566
|
span.end();
|
|
@@ -583,19 +583,19 @@ const handleStreamResult = (originalResult, streamInfo, span, ignoreOutput, seri
|
|
|
583
583
|
};
|
|
584
584
|
span.setAttribute(SPAN_OUTPUT, serialize(output));
|
|
585
585
|
} catch (serError) {
|
|
586
|
-
logger$
|
|
586
|
+
logger$31.warn("Failed to serialize response output: " + errorMessage(serError));
|
|
587
587
|
}
|
|
588
588
|
if (error) span.recordException(error);
|
|
589
589
|
} catch (err) {
|
|
590
590
|
span.recordException(err);
|
|
591
591
|
} finally {
|
|
592
|
-
logger$
|
|
592
|
+
logger$31.debug("Ending span for Response");
|
|
593
593
|
span.end();
|
|
594
594
|
}
|
|
595
595
|
});
|
|
596
596
|
return newResponse;
|
|
597
597
|
}
|
|
598
|
-
logger$
|
|
598
|
+
logger$31.warn("Stream type not handled, ending span immediately");
|
|
599
599
|
span.end();
|
|
600
600
|
return originalResult;
|
|
601
601
|
};
|
|
@@ -673,7 +673,7 @@ const writeDebugSessionFile = (file, dir = process.cwd()) => {
|
|
|
673
673
|
* contract. This file is part of the cross-language parity surface — keep its
|
|
674
674
|
* logic line-comparable with the Python `config.py`.
|
|
675
675
|
*/
|
|
676
|
-
const logger$
|
|
676
|
+
const logger$30 = initializeLogger();
|
|
677
677
|
const TRUTHY = /* @__PURE__ */ new Set([
|
|
678
678
|
"true",
|
|
679
679
|
"1",
|
|
@@ -709,7 +709,7 @@ const parseCacheUntil = (value) => {
|
|
|
709
709
|
if (value === void 0 || value === "") return null;
|
|
710
710
|
const spanId = normalizeSpanId(value);
|
|
711
711
|
if (spanId !== null) return spanId;
|
|
712
|
-
logger$
|
|
712
|
+
logger$30.warn(`LMNR_DEBUG_CACHE_UNTIL=${JSON.stringify(value)} is not a span id; ignoring`);
|
|
713
713
|
return null;
|
|
714
714
|
};
|
|
715
715
|
/**
|
|
@@ -1063,7 +1063,7 @@ const resetDebugRuntime = () => {
|
|
|
1063
1063
|
};
|
|
1064
1064
|
//#endregion
|
|
1065
1065
|
//#region src/opentelemetry-lib/tracing/span.ts
|
|
1066
|
-
const logger$
|
|
1066
|
+
const logger$29 = initializeLogger();
|
|
1067
1067
|
/**
|
|
1068
1068
|
* Build the debug block to propagate, or undefined when debug mode is off.
|
|
1069
1069
|
*
|
|
@@ -1213,7 +1213,7 @@ var LaminarSpan = class LaminarSpan {
|
|
|
1213
1213
|
} catch {}
|
|
1214
1214
|
metadata[key.replace(`${ASSOCIATION_PROPERTIES}.metadata.`, "")] = value;
|
|
1215
1215
|
}
|
|
1216
|
-
} else logger$
|
|
1216
|
+
} else logger$29.warn("Attributes object is not available. Most likely the span is not a LaminarSpan and not an OpenTelemetry default SDK Span. Span path and ids path will be empty.");
|
|
1217
1217
|
return {
|
|
1218
1218
|
spanId: otelSpanIdToUUID(this._span.spanContext().spanId),
|
|
1219
1219
|
traceId: otelTraceIdToUUID(this._span.spanContext().traceId),
|
|
@@ -1240,14 +1240,14 @@ var LaminarSpan = class LaminarSpan {
|
|
|
1240
1240
|
}
|
|
1241
1241
|
get tags() {
|
|
1242
1242
|
if (!this._span.attributes) {
|
|
1243
|
-
logger$
|
|
1243
|
+
logger$29.warn("[LaminarSpan.tags] WARNING. Current span does not have attributes object. Possibly, the span was created with a custom OTel SDK. Returning an empty list. Help: OpenTelemetry API does not guarantee reading attributes from a span, but OTel SDK allows it by default. Laminar SDK allows to read attributes too.");
|
|
1244
1244
|
return [];
|
|
1245
1245
|
}
|
|
1246
1246
|
return this._span.attributes[`lmnr.association.properties.tags`] ?? [];
|
|
1247
1247
|
}
|
|
1248
1248
|
get laminarAssociationProperties() {
|
|
1249
1249
|
if (!this._span.attributes) {
|
|
1250
|
-
logger$
|
|
1250
|
+
logger$29.warn("[LaminarSpan.laminarAssociationProperties] WARNING. Current span does not have attributes object. Possibly, the span was created with a custom OTel SDK. Returning an empty object. Help: OpenTelemetry API does not guarantee reading attributes from a span, but OTel SDK allows it by default. Laminar SDK allows to read attributes too.");
|
|
1251
1251
|
return {};
|
|
1252
1252
|
}
|
|
1253
1253
|
try {
|
|
@@ -1443,7 +1443,7 @@ var LaminarContextManager = class {
|
|
|
1443
1443
|
};
|
|
1444
1444
|
//#endregion
|
|
1445
1445
|
//#region src/opentelemetry-lib/instrumentation/claude-agent-sdk/proxy.ts
|
|
1446
|
-
const logger$
|
|
1446
|
+
const logger$28 = initializeLogger();
|
|
1447
1447
|
const DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
1448
1448
|
const DEFAULT_CC_PROXY_PORT = 45667;
|
|
1449
1449
|
const CC_PROXY_PORT_ATTEMPTS = 50;
|
|
@@ -1697,7 +1697,7 @@ const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL,
|
|
|
1697
1697
|
if (foundryBaseUrl) return foundryBaseUrl.replace(/\/$/, "");
|
|
1698
1698
|
const foundryResource = getEnvValue(FOUNDRY_RESOURCE_ENV);
|
|
1699
1699
|
if (foundryResource) return `https://${foundryResource}.services.ai.azure.com/anthropic`;
|
|
1700
|
-
logger$
|
|
1700
|
+
logger$28.error(`${FOUNDRY_USE_ENV} is set but neither ${FOUNDRY_BASE_URL_ENV} nor ${FOUNDRY_RESOURCE_ENV} is configured. Microsoft Foundry requires one of these values.`);
|
|
1701
1701
|
return null;
|
|
1702
1702
|
}
|
|
1703
1703
|
if (isTruthyEnv(getEnvValue(BEDROCK_USE_ENV))) {
|
|
@@ -1709,7 +1709,7 @@ const resolveTargetUrlFromEnv = (envDict, fallback = DEFAULT_ANTHROPIC_BASE_URL,
|
|
|
1709
1709
|
region = getRegionFromAwsConfig(awsProfile) ?? void 0;
|
|
1710
1710
|
}
|
|
1711
1711
|
if (region) return `https://bedrock-runtime.${region}.amazonaws.com`;
|
|
1712
|
-
logger$
|
|
1712
|
+
logger$28.error(`${BEDROCK_USE_ENV} is set but could not determine AWS region. Set ${BEDROCK_AWS_REGION_ENV} or configure a region in ~/.aws/config for the active profile.`);
|
|
1713
1713
|
return null;
|
|
1714
1714
|
}
|
|
1715
1715
|
if (isTruthyEnv(getEnvValue(VERTEX_USE_ENV))) {
|
|
@@ -1792,11 +1792,11 @@ const waitForPort = (port, timeoutMs = 5e3) => new Promise((resolve) => {
|
|
|
1792
1792
|
const registerGlobalProxyShutdown = () => {
|
|
1793
1793
|
if (!globalShutdownRegistered) {
|
|
1794
1794
|
process.on("exit", () => {
|
|
1795
|
-
logger$
|
|
1795
|
+
logger$28.debug("process.on(\"exit\") called - stopping all active proxies");
|
|
1796
1796
|
for (const proxyServer of activeProxyServers) try {
|
|
1797
1797
|
proxyServer.stopServer();
|
|
1798
1798
|
} catch (e) {
|
|
1799
|
-
logger$
|
|
1799
|
+
logger$28.debug(`Failed to stop proxy: ${errorMessage(e)}`);
|
|
1800
1800
|
}
|
|
1801
1801
|
activeProxyServers.clear();
|
|
1802
1802
|
});
|
|
@@ -1811,28 +1811,28 @@ const createProxyInstance = async ({ env, cwd, settingSources, settings, targetU
|
|
|
1811
1811
|
try {
|
|
1812
1812
|
const port = await findAvailablePort(DEFAULT_CC_PROXY_PORT, CC_PROXY_PORT_ATTEMPTS);
|
|
1813
1813
|
if (port === null) {
|
|
1814
|
-
logger$
|
|
1814
|
+
logger$28.warn("Unable to allocate port for cc-proxy.");
|
|
1815
1815
|
return null;
|
|
1816
1816
|
}
|
|
1817
1817
|
const targetUrl = resolvedTargetUrl ?? resolveTargetUrlFromEnv(env, void 0, cwd, settingSources, settings);
|
|
1818
1818
|
if (!targetUrl) {
|
|
1819
|
-
logger$
|
|
1819
|
+
logger$28.warn("Unable to resolve target URL for cc-proxy (provider misconfigured).");
|
|
1820
1820
|
return null;
|
|
1821
1821
|
}
|
|
1822
|
-
logger$
|
|
1822
|
+
logger$28.debug(`Creating proxy instance on port ${port} targeting: ${targetUrl}`);
|
|
1823
1823
|
try {
|
|
1824
1824
|
const { ProxyServer } = __require("@lmnr-ai/claude-code-proxy");
|
|
1825
1825
|
const proxyServer = new ProxyServer(port);
|
|
1826
1826
|
proxyServer.runServer(targetUrl);
|
|
1827
1827
|
if (!await waitForPort(port)) {
|
|
1828
|
-
logger$
|
|
1828
|
+
logger$28.warn(`cc-proxy failed to start on port ${port}`);
|
|
1829
1829
|
proxyServer.stopServer();
|
|
1830
1830
|
return null;
|
|
1831
1831
|
}
|
|
1832
1832
|
const proxyBaseUrl = `http://127.0.0.1:${port}`;
|
|
1833
1833
|
activeProxyServers.add(proxyServer);
|
|
1834
1834
|
registerGlobalProxyShutdown();
|
|
1835
|
-
logger$
|
|
1835
|
+
logger$28.info(`Started claude proxy server on: ${proxyBaseUrl}`);
|
|
1836
1836
|
return {
|
|
1837
1837
|
server: proxyServer,
|
|
1838
1838
|
baseUrl: proxyBaseUrl,
|
|
@@ -1840,11 +1840,11 @@ const createProxyInstance = async ({ env, cwd, settingSources, settings, targetU
|
|
|
1840
1840
|
targetUrl
|
|
1841
1841
|
};
|
|
1842
1842
|
} catch (e) {
|
|
1843
|
-
logger$
|
|
1843
|
+
logger$28.warn(`Unable to start cc-proxy: ${errorMessage(e)}`);
|
|
1844
1844
|
return null;
|
|
1845
1845
|
}
|
|
1846
1846
|
} catch (e) {
|
|
1847
|
-
logger$
|
|
1847
|
+
logger$28.warn(`Failed to create proxy instance: ${errorMessage(e)}`);
|
|
1848
1848
|
return null;
|
|
1849
1849
|
}
|
|
1850
1850
|
};
|
|
@@ -1854,11 +1854,11 @@ const createProxyInstance = async ({ env, cwd, settingSources, settings, targetU
|
|
|
1854
1854
|
const stopProxyInstance = (instance) => {
|
|
1855
1855
|
if (!instance) return;
|
|
1856
1856
|
try {
|
|
1857
|
-
logger$
|
|
1857
|
+
logger$28.debug(`Stopping proxy instance on port ${instance.port}`);
|
|
1858
1858
|
instance.server.stopServer();
|
|
1859
1859
|
activeProxyServers.delete(instance.server);
|
|
1860
1860
|
} catch (e) {
|
|
1861
|
-
logger$
|
|
1861
|
+
logger$28.debug(`Failed to stop proxy instance: ${errorMessage(e)}`);
|
|
1862
1862
|
}
|
|
1863
1863
|
};
|
|
1864
1864
|
/**
|
|
@@ -1866,11 +1866,11 @@ const stopProxyInstance = (instance) => {
|
|
|
1866
1866
|
* Used during shutdown to ensure cleanup
|
|
1867
1867
|
*/
|
|
1868
1868
|
const forceReleaseProxy = () => {
|
|
1869
|
-
logger$
|
|
1869
|
+
logger$28.debug(`Force stopping all ${activeProxyServers.size} active proxy servers`);
|
|
1870
1870
|
for (const proxyServer of activeProxyServers) try {
|
|
1871
1871
|
proxyServer.stopServer();
|
|
1872
1872
|
} catch (e) {
|
|
1873
|
-
logger$
|
|
1873
|
+
logger$28.debug(`Failed to stop proxy: ${errorMessage(e)}`);
|
|
1874
1874
|
}
|
|
1875
1875
|
activeProxyServers.clear();
|
|
1876
1876
|
};
|
|
@@ -1920,14 +1920,14 @@ const setTraceToProxyInstance = async (instance) => {
|
|
|
1920
1920
|
spanPath: payload.span_path,
|
|
1921
1921
|
laminarUrl: payload.laminar_url
|
|
1922
1922
|
});
|
|
1923
|
-
logger$
|
|
1923
|
+
logger$28.debug(`Set trace context to proxy on port ${instance.port}`);
|
|
1924
1924
|
} catch (e) {
|
|
1925
|
-
logger$
|
|
1925
|
+
logger$28.debug(`Unable to set trace context to proxy on port ${instance.port}: ` + errorMessage(e));
|
|
1926
1926
|
}
|
|
1927
1927
|
};
|
|
1928
1928
|
//#endregion
|
|
1929
1929
|
//#region src/opentelemetry-lib/instrumentation/claude-agent-sdk/index.ts
|
|
1930
|
-
const logger$
|
|
1930
|
+
const logger$27 = initializeLogger();
|
|
1931
1931
|
/**
|
|
1932
1932
|
* Create an instrumented version of the claude-agent-sdk query function.
|
|
1933
1933
|
* This can be used when importing the query function before Laminar initialization.
|
|
@@ -1963,9 +1963,9 @@ function instrumentClaudeAgentQuery(originalQuery) {
|
|
|
1963
1963
|
targetUrl
|
|
1964
1964
|
});
|
|
1965
1965
|
if (proxyInstance && targetUrl) {
|
|
1966
|
-
logger$
|
|
1966
|
+
logger$27.debug(`Using proxy on port ${proxyInstance.port}`);
|
|
1967
1967
|
await Laminar.withSpan(span, async () => {
|
|
1968
|
-
logger$
|
|
1968
|
+
logger$27.debug("Setting trace to proxy instance...");
|
|
1969
1969
|
await setTraceToProxyInstance(proxyInstance);
|
|
1970
1970
|
});
|
|
1971
1971
|
const varsToRemove = getEnvVarsToRemove(mergedEnv, sessionCwd, settingSources);
|
|
@@ -1980,13 +1980,13 @@ function instrumentClaudeAgentQuery(originalQuery) {
|
|
|
1980
1980
|
if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_BEDROCK")) subprocessEnv.ANTHROPIC_BEDROCK_BASE_URL = proxyInstance.baseUrl;
|
|
1981
1981
|
if (isProviderEnabledInEnv(subprocessEnv, "CLAUDE_CODE_USE_VERTEX")) subprocessEnv.ANTHROPIC_VERTEX_BASE_URL = proxyInstance.baseUrl;
|
|
1982
1982
|
const flagSettings = buildProxyFlagSettings(callerSettings, proxyInstance.baseUrl, sessionCwd, settingSources);
|
|
1983
|
-
if (flagSettings === null) logger$
|
|
1983
|
+
if (flagSettings === null) logger$27.warn(`Could not read options.settings ${JSON.stringify(callerSettings)}; Claude Code settings that define a base URL will bypass the Laminar proxy and produce no LLM spans.`);
|
|
1984
1984
|
else {
|
|
1985
1985
|
params.options.settings = flagSettings;
|
|
1986
1986
|
const conflicting = Object.entries(readClaudeSettingsEnv(sessionCwd, settingSources)).filter(([key, value]) => PROXY_BASE_URL_ENV_KEYS.includes(key) && value !== "" && value !== proxyInstance?.baseUrl).map(([key]) => key);
|
|
1987
|
-
if (conflicting.length > 0) logger$
|
|
1987
|
+
if (conflicting.length > 0) logger$27.info(`Claude Code settings define ${conflicting.sort().join(", ")}, which outranks the subprocess environment. Injected settings so the Laminar proxy at ${proxyInstance.baseUrl} still intercepts API traffic; your settings files were not modified.`);
|
|
1988
1988
|
}
|
|
1989
|
-
} else logger$
|
|
1989
|
+
} else logger$27.debug("No claude proxy server available. Proceeding without proxy.");
|
|
1990
1990
|
const originalGenerator = originalQuery(params);
|
|
1991
1991
|
for await (const message of originalGenerator) {
|
|
1992
1992
|
collected.push(message);
|
|
@@ -2015,7 +2015,7 @@ var ClaudeAgentSDKInstrumentation = class extends InstrumentationBase {
|
|
|
2015
2015
|
}
|
|
2016
2016
|
manuallyInstrument(claudeAgentModule) {
|
|
2017
2017
|
if (claudeAgentModule.query && typeof claudeAgentModule.query === "function") this._wrap(claudeAgentModule, "query", this.patchQuery());
|
|
2018
|
-
else logger$
|
|
2018
|
+
else logger$27.debug("query function not found in claudeAgentSDK module, skipping instrumentation");
|
|
2019
2019
|
}
|
|
2020
2020
|
patchQuery() {
|
|
2021
2021
|
return (original) => instrumentClaudeAgentQuery(original);
|
|
@@ -2031,9 +2031,19 @@ var ClaudeAgentSDKInstrumentation = class extends InstrumentationBase {
|
|
|
2031
2031
|
}
|
|
2032
2032
|
};
|
|
2033
2033
|
//#endregion
|
|
2034
|
+
//#region src/opentelemetry-lib/instrumentation/langchain/llm-call.ts
|
|
2035
|
+
/**
|
|
2036
|
+
* Context key carrying the LangChain LLM call currently in progress. Set by the
|
|
2037
|
+
* `BaseChatModel` / `BaseLLM` wrappers for the duration of the model call.
|
|
2038
|
+
*
|
|
2039
|
+
* Kept free of other imports: `Laminar._startSpan` reads it to tell a handed
|
|
2040
|
+
* off call that the provider SDK instrumentation did record its span.
|
|
2041
|
+
*/
|
|
2042
|
+
const LLM_CALL_KEY = createContextKey("lmnr.langchain.llm_call");
|
|
2043
|
+
//#endregion
|
|
2034
2044
|
//#region src/laminar.ts
|
|
2035
2045
|
loadEnv();
|
|
2036
|
-
const logger$
|
|
2046
|
+
const logger$26 = initializeLogger();
|
|
2037
2047
|
var Laminar = class Laminar {
|
|
2038
2048
|
static {
|
|
2039
2049
|
this.isInitialized = false;
|
|
@@ -2105,28 +2115,32 @@ var Laminar = class Laminar {
|
|
|
2105
2115
|
* and you want Laminar spans to be children of the existing spans.
|
|
2106
2116
|
* @param {SpanProcessor} props.spanProcessor - The span processor to use. If passed, some of
|
|
2107
2117
|
* the other options will be ignored.
|
|
2118
|
+
* @param {string} props.release - The release of the running code, usually its git commit
|
|
2119
|
+
* SHA. Laminar groups an agent's traces into versions by release. If not specified, read
|
|
2120
|
+
* from the LMNR_RELEASE environment variable, common deploy platform variables (Vercel,
|
|
2121
|
+
* Render, Railway, Heroku, Cloud Run, ...), or the checked-out git commit.
|
|
2108
2122
|
*
|
|
2109
2123
|
* @example
|
|
2110
2124
|
* import { Laminar } from '@lmnr-ai/lmnr';
|
|
2111
2125
|
* import { OpenAI } from 'openai';
|
|
2112
|
-
* import * as
|
|
2126
|
+
* import * as CallbackManagerModule from "@langchain/core/callbacks/manager";
|
|
2113
2127
|
*
|
|
2114
|
-
* // Initialize Laminar while
|
|
2128
|
+
* // Initialize Laminar while instrumenting LangChain and OpenAI modules.
|
|
2115
2129
|
* Laminar.initialize({
|
|
2116
2130
|
* projectApiKey: "<LMNR_PROJECT_API_KEY>",
|
|
2117
2131
|
* instrumentModules: {
|
|
2118
2132
|
* langchain: {
|
|
2119
|
-
*
|
|
2133
|
+
* callbackManagerModule: CallbackManagerModule
|
|
2120
2134
|
* },
|
|
2121
|
-
*
|
|
2135
|
+
* OpenAI: OpenAI
|
|
2122
2136
|
* }
|
|
2123
2137
|
* });
|
|
2124
2138
|
*
|
|
2125
2139
|
* @throws {Error} - If project API key is not set
|
|
2126
2140
|
*/
|
|
2127
|
-
static initialize({ projectApiKey, baseUrl, baseHttpUrl, httpPort, grpcPort, instrumentModules, disableBatch, traceExportTimeoutMillis, logLevel, maxExportBatchSize, maxExportBatchSizeBytes, flushBySize, forceHttp, sessionRecordingOptions, metadata, inheritGlobalContext, spanProcessor } = {}) {
|
|
2141
|
+
static initialize({ projectApiKey, baseUrl, baseHttpUrl, httpPort, grpcPort, instrumentModules, disableBatch, traceExportTimeoutMillis, logLevel, maxExportBatchSize, maxExportBatchSizeBytes, flushBySize, forceHttp, sessionRecordingOptions, metadata, inheritGlobalContext, spanProcessor, release } = {}) {
|
|
2128
2142
|
if (this.isInitialized) {
|
|
2129
|
-
logger$
|
|
2143
|
+
logger$26.warn("Laminar has already been initialized. Skipping initialization.");
|
|
2130
2144
|
return;
|
|
2131
2145
|
}
|
|
2132
2146
|
const key = projectApiKey ?? process?.env?.LMNR_PROJECT_API_KEY;
|
|
@@ -2150,7 +2164,7 @@ var Laminar = class Laminar {
|
|
|
2150
2164
|
...metadata ?? {}
|
|
2151
2165
|
};
|
|
2152
2166
|
if (inheritGlobalContext) LaminarContextManager.inheritGlobalContext = true;
|
|
2153
|
-
if (spanProcessor && !(spanProcessor instanceof LaminarSpanProcessor)) logger$
|
|
2167
|
+
if (spanProcessor && !(spanProcessor instanceof LaminarSpanProcessor)) logger$26.warn("Span processor is not a LaminarSpanProcessor. Some functionality may be impaired.");
|
|
2154
2168
|
this.isInitialized = true;
|
|
2155
2169
|
const urlWithoutSlash = url?.replace(/\/$/, "").replace(/:\d{1,5}$/g, "");
|
|
2156
2170
|
const httpUrlWithoutSlash = httpUrl?.replace(/\/$/, "").replace(/:\d{1,5}$/g, "");
|
|
@@ -2170,7 +2184,8 @@ var Laminar = class Laminar {
|
|
|
2170
2184
|
flushBySize,
|
|
2171
2185
|
traceExportTimeoutMillis,
|
|
2172
2186
|
sessionRecordingOptions,
|
|
2173
|
-
spanProcessor
|
|
2187
|
+
spanProcessor,
|
|
2188
|
+
release
|
|
2174
2189
|
});
|
|
2175
2190
|
this._initDebugRuntime(url, port);
|
|
2176
2191
|
LaminarContextManager.setGlobalMetadata(this.globalMetadata);
|
|
@@ -2197,11 +2212,11 @@ var Laminar = class Laminar {
|
|
|
2197
2212
|
try {
|
|
2198
2213
|
getRuntime()?.recordTraceId(otelTraceIdToUUID(otelSpanContext.traceId));
|
|
2199
2214
|
} catch (e) {
|
|
2200
|
-
logger$
|
|
2215
|
+
logger$26.debug("Failed to record debug trace id from env: " + errorMessage(e));
|
|
2201
2216
|
}
|
|
2202
|
-
logger$
|
|
2217
|
+
logger$26.debug("Initialized Laminar parent context from LMNR_SPAN_CONTEXT.");
|
|
2203
2218
|
} catch (e) {
|
|
2204
|
-
logger$
|
|
2219
|
+
logger$26.warn("LMNR_SPAN_CONTEXT is set but could not be used: " + errorMessage(e));
|
|
2205
2220
|
}
|
|
2206
2221
|
}
|
|
2207
2222
|
/**
|
|
@@ -2245,7 +2260,7 @@ var Laminar = class Laminar {
|
|
|
2245
2260
|
if (projectId) {
|
|
2246
2261
|
runtime.recordProjectId(projectId);
|
|
2247
2262
|
const sessionUrl = runtime.debuggerSessionUrl();
|
|
2248
|
-
logger$
|
|
2263
|
+
logger$26.info(`Laminar debugger session: ${sessionUrl}`);
|
|
2249
2264
|
if (runtime.shouldOpenBrowser) {
|
|
2250
2265
|
const opener = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
2251
2266
|
spawn(opener, [sessionUrl], {
|
|
@@ -2255,7 +2270,7 @@ var Laminar = class Laminar {
|
|
|
2255
2270
|
}
|
|
2256
2271
|
}
|
|
2257
2272
|
}).catch((e) => {
|
|
2258
|
-
logger$
|
|
2273
|
+
logger$26.warn("Failed to register debug session: " + errorMessage(e));
|
|
2259
2274
|
});
|
|
2260
2275
|
this.globalMetadata = {
|
|
2261
2276
|
...this.globalMetadata,
|
|
@@ -2265,7 +2280,7 @@ var Laminar = class Laminar {
|
|
|
2265
2280
|
this.debugExitHook = () => runtime.emitPointer();
|
|
2266
2281
|
process.once("exit", this.debugExitHook);
|
|
2267
2282
|
} catch (e) {
|
|
2268
|
-
logger$
|
|
2283
|
+
logger$26.warn("Failed to initialize debug runtime: " + errorMessage(e));
|
|
2269
2284
|
}
|
|
2270
2285
|
}
|
|
2271
2286
|
/**
|
|
@@ -2312,7 +2327,7 @@ var Laminar = class Laminar {
|
|
|
2312
2327
|
runtime.rolloutSessions.register({ sessionId: runtime.sessionId }).then((projectId) => {
|
|
2313
2328
|
if (projectId) runtime.recordProjectId(projectId);
|
|
2314
2329
|
}).catch((e) => {
|
|
2315
|
-
logger$
|
|
2330
|
+
logger$26.debug("Failed to register downstream debug session: " + errorMessage(e));
|
|
2316
2331
|
});
|
|
2317
2332
|
this.globalMetadata = {
|
|
2318
2333
|
...this.globalMetadata,
|
|
@@ -2321,7 +2336,7 @@ var Laminar = class Laminar {
|
|
|
2321
2336
|
LaminarContextManager.setGlobalMetadata(this.globalMetadata);
|
|
2322
2337
|
}
|
|
2323
2338
|
} catch (e) {
|
|
2324
|
-
logger$
|
|
2339
|
+
logger$26.debug("Failed to arm debug runtime from context: " + errorMessage(e));
|
|
2325
2340
|
}
|
|
2326
2341
|
}
|
|
2327
2342
|
/**
|
|
@@ -2336,7 +2351,7 @@ var Laminar = class Laminar {
|
|
|
2336
2351
|
*/
|
|
2337
2352
|
static patch(modules) {
|
|
2338
2353
|
if (!this.isInitialized) {
|
|
2339
|
-
logger$
|
|
2354
|
+
logger$26.warn("Laminar must be initialized before patching modules. Skipping patch.");
|
|
2340
2355
|
return;
|
|
2341
2356
|
}
|
|
2342
2357
|
if (!modules || Object.keys(modules).length === 0) throw new Error("Pass at least one module to patch");
|
|
@@ -2596,7 +2611,7 @@ var Laminar = class Laminar {
|
|
|
2596
2611
|
const spanContext = tryToOtelSpanContext(laminarContext);
|
|
2597
2612
|
entityContext = trace.setSpan(entityContext, trace.wrapSpanContext(spanContext));
|
|
2598
2613
|
} catch (e) {
|
|
2599
|
-
logger$
|
|
2614
|
+
logger$26.warn("Failed to parse parent span context: " + errorMessage(e));
|
|
2600
2615
|
}
|
|
2601
2616
|
const tagProperties = tags ? { [`${ASSOCIATION_PROPERTIES}.tags`]: Array.from(new Set(tags)) } : {};
|
|
2602
2617
|
const ctxAssociationProperties = LaminarContextManager.getAssociationProperties();
|
|
@@ -2632,6 +2647,10 @@ var Laminar = class Laminar {
|
|
|
2632
2647
|
startTime
|
|
2633
2648
|
}, entityContext));
|
|
2634
2649
|
span.activated = activated ?? false;
|
|
2650
|
+
if (spanType === "LLM") {
|
|
2651
|
+
const llmCall = entityContext.getValue(LLM_CALL_KEY);
|
|
2652
|
+
if (llmCall?.mode === "handoff" && span.isRecording()) llmCall.recorded = true;
|
|
2653
|
+
}
|
|
2635
2654
|
if (input) span.setInput(input);
|
|
2636
2655
|
if (activated) {
|
|
2637
2656
|
entityContext = LaminarContextManager.setAssociationProperties(span, entityContext);
|
|
@@ -2700,13 +2719,13 @@ var Laminar = class Laminar {
|
|
|
2700
2719
|
}
|
|
2701
2720
|
static async flush() {
|
|
2702
2721
|
if (this.isInitialized) {
|
|
2703
|
-
logger$
|
|
2722
|
+
logger$26.debug("Flushing spans");
|
|
2704
2723
|
await forceFlush();
|
|
2705
2724
|
}
|
|
2706
2725
|
}
|
|
2707
2726
|
static async shutdown() {
|
|
2708
2727
|
if (this.isInitialized) {
|
|
2709
|
-
logger$
|
|
2728
|
+
logger$26.debug("Shutting down Laminar");
|
|
2710
2729
|
getRuntime()?.emitPointer();
|
|
2711
2730
|
await forceFlush();
|
|
2712
2731
|
this.isInitialized = false;
|
|
@@ -2841,7 +2860,7 @@ return module.exports;
|
|
|
2841
2860
|
//#endregion
|
|
2842
2861
|
//#region src/browser/utils.ts
|
|
2843
2862
|
const LMNR_SEND_EVENTS_FUNCTION_NAME = "lmnrSendEvents";
|
|
2844
|
-
const logger$
|
|
2863
|
+
const logger$25 = initializeLogger();
|
|
2845
2864
|
/**
|
|
2846
2865
|
* If the first argument is a string, return an object with the name of the method
|
|
2847
2866
|
* and the argument as the value.
|
|
@@ -2864,7 +2883,7 @@ const takeFullSnapshot = async (page) => await page.evaluate(() => {
|
|
|
2864
2883
|
window.lmnrRrweb.record.takeFullSnapshot();
|
|
2865
2884
|
return true;
|
|
2866
2885
|
} catch (error) {
|
|
2867
|
-
logger$
|
|
2886
|
+
logger$25.error("Error taking full snapshot: " + errorMessage(error));
|
|
2868
2887
|
return false;
|
|
2869
2888
|
}
|
|
2870
2889
|
return false;
|
|
@@ -2875,7 +2894,7 @@ const injectSessionRecorder = async (page, sessionRecordingOptions) => {
|
|
|
2875
2894
|
try {
|
|
2876
2895
|
return await script();
|
|
2877
2896
|
} catch (error) {
|
|
2878
|
-
logger$
|
|
2897
|
+
logger$25.error("Operation " + script.name + " failed: " + errorMessage(error));
|
|
2879
2898
|
}
|
|
2880
2899
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2881
2900
|
}
|
|
@@ -2885,20 +2904,20 @@ const injectSessionRecorder = async (page, sessionRecordingOptions) => {
|
|
|
2885
2904
|
try {
|
|
2886
2905
|
isRrwebPresent = await castedPage.evaluate(() => typeof window.lmnrRrweb !== "undefined");
|
|
2887
2906
|
} catch (error) {
|
|
2888
|
-
logger$
|
|
2907
|
+
logger$25.debug("Failed to check if session recorder is loaded: " + errorMessage(error));
|
|
2889
2908
|
}
|
|
2890
2909
|
if (!isRrwebPresent) {
|
|
2891
2910
|
if (!await tryRunScript(async function injectSessionRecorder() {
|
|
2892
2911
|
await castedPage.evaluate(RECORDER);
|
|
2893
2912
|
return true;
|
|
2894
2913
|
})) {
|
|
2895
|
-
logger$
|
|
2914
|
+
logger$25.error("Failed to load session recorder");
|
|
2896
2915
|
return;
|
|
2897
2916
|
}
|
|
2898
2917
|
try {
|
|
2899
2918
|
await castedPage.evaluate(injectScript, sessionRecordingOptions);
|
|
2900
2919
|
} catch (error) {
|
|
2901
|
-
logger$
|
|
2920
|
+
logger$25.debug("Failed to inject session recorder: " + errorMessage(error));
|
|
2902
2921
|
}
|
|
2903
2922
|
}
|
|
2904
2923
|
};
|
|
@@ -3164,7 +3183,7 @@ async function sendEvents(chunk, client, chunkBuffers, sessionId, traceId) {
|
|
|
3164
3183
|
try {
|
|
3165
3184
|
const { batchId, chunkIndex, totalChunks, data } = chunk;
|
|
3166
3185
|
if (!sessionId || !traceId) {
|
|
3167
|
-
logger$
|
|
3186
|
+
logger$25.debug("Missing sessionId or traceId in chunk");
|
|
3168
3187
|
return;
|
|
3169
3188
|
}
|
|
3170
3189
|
if (!chunkBuffers.has(batchId)) chunkBuffers.set(batchId, {
|
|
@@ -3183,7 +3202,7 @@ async function sendEvents(chunk, client, chunkBuffers, sessionId, traceId) {
|
|
|
3183
3202
|
traceId,
|
|
3184
3203
|
events
|
|
3185
3204
|
}).catch((error) => {
|
|
3186
|
-
logger$
|
|
3205
|
+
logger$25.debug("Failed to send events: " + errorMessage(error));
|
|
3187
3206
|
});
|
|
3188
3207
|
chunkBuffers.delete(batchId);
|
|
3189
3208
|
}
|
|
@@ -3191,16 +3210,16 @@ async function sendEvents(chunk, client, chunkBuffers, sessionId, traceId) {
|
|
|
3191
3210
|
const toDelete = [];
|
|
3192
3211
|
for (const [bid, buffer] of chunkBuffers.entries()) if (currentTime - buffer.timestamp > OLD_BUFFER_TIMEOUT) toDelete.push(bid);
|
|
3193
3212
|
for (const bid of toDelete) {
|
|
3194
|
-
logger$
|
|
3213
|
+
logger$25.debug(`Cleaning up incomplete chunk buffer: ${bid}`);
|
|
3195
3214
|
chunkBuffers.delete(bid);
|
|
3196
3215
|
}
|
|
3197
3216
|
} catch (error) {
|
|
3198
|
-
logger$
|
|
3217
|
+
logger$25.debug("Could not send events: " + errorMessage(error));
|
|
3199
3218
|
}
|
|
3200
3219
|
}
|
|
3201
3220
|
//#endregion
|
|
3202
3221
|
//#region src/browser/playwright.ts
|
|
3203
|
-
const logger$
|
|
3222
|
+
const logger$24 = initializeLogger();
|
|
3204
3223
|
var PlaywrightInstrumentation = class extends InstrumentationBase {
|
|
3205
3224
|
constructor(client, sessionRecordingOptions) {
|
|
3206
3225
|
super("@lmnr/playwright-instrumentation", version, { enabled: true });
|
|
@@ -3308,7 +3327,7 @@ var PlaywrightInstrumentation = class extends InstrumentationBase {
|
|
|
3308
3327
|
try {
|
|
3309
3328
|
await injectSessionRecorder(page, this._sessionRecordingOptions);
|
|
3310
3329
|
} catch (error) {
|
|
3311
|
-
logger$
|
|
3330
|
+
logger$24.error("Error in onLoad handler: " + errorMessage(error));
|
|
3312
3331
|
}
|
|
3313
3332
|
});
|
|
3314
3333
|
const chunkBuffers = /* @__PURE__ */ new Map();
|
|
@@ -3318,7 +3337,7 @@ var PlaywrightInstrumentation = class extends InstrumentationBase {
|
|
|
3318
3337
|
await sendEvents(chunk, this._client, chunkBuffers, sessionId, traceId);
|
|
3319
3338
|
});
|
|
3320
3339
|
} catch (error) {
|
|
3321
|
-
logger$
|
|
3340
|
+
logger$24.debug("Could not expose function lmnrSendEvents: " + errorMessage(error));
|
|
3322
3341
|
}
|
|
3323
3342
|
}
|
|
3324
3343
|
};
|
|
@@ -3743,7 +3762,7 @@ var StagehandV2Instrumentation = class extends InstrumentationBase {
|
|
|
3743
3762
|
};
|
|
3744
3763
|
//#endregion
|
|
3745
3764
|
//#region src/browser/puppeteer.ts
|
|
3746
|
-
const logger$
|
|
3765
|
+
const logger$23 = initializeLogger();
|
|
3747
3766
|
var PuppeteerInstrumentation = class extends InstrumentationBase {
|
|
3748
3767
|
constructor(client, sessionRecordingOptions) {
|
|
3749
3768
|
super("@lmnr/puppeteer-instrumentation", version, { enabled: true });
|
|
@@ -3788,10 +3807,10 @@ var PuppeteerInstrumentation = class extends InstrumentationBase {
|
|
|
3788
3807
|
context.on("targetcreated", (target) => {
|
|
3789
3808
|
target.page().then((page) => {
|
|
3790
3809
|
if (page) plugin.patchPage(page, sessionId).catch((error) => {
|
|
3791
|
-
logger$
|
|
3810
|
+
logger$23.error("Failed to patch page: " + errorMessage(error));
|
|
3792
3811
|
});
|
|
3793
3812
|
}).catch((error) => {
|
|
3794
|
-
logger$
|
|
3813
|
+
logger$23.error("Failed to patch page: " + errorMessage(error));
|
|
3795
3814
|
});
|
|
3796
3815
|
});
|
|
3797
3816
|
await Promise.all((await context.pages()).map((page) => plugin.patchPage(page, sessionId)));
|
|
@@ -3809,19 +3828,19 @@ var PuppeteerInstrumentation = class extends InstrumentationBase {
|
|
|
3809
3828
|
context.on("targetcreated", (target) => {
|
|
3810
3829
|
target.page().then((page) => {
|
|
3811
3830
|
if (page) plugin.patchPage(page, sessionId).catch((error) => {
|
|
3812
|
-
logger$
|
|
3831
|
+
logger$23.error("Failed to patch page: " + errorMessage(error));
|
|
3813
3832
|
});
|
|
3814
3833
|
}).catch((error) => {
|
|
3815
|
-
logger$
|
|
3834
|
+
logger$23.error("Failed to patch page: " + errorMessage(error));
|
|
3816
3835
|
});
|
|
3817
3836
|
});
|
|
3818
3837
|
context.on("targetchanged", (target) => {
|
|
3819
3838
|
target.page().then((page) => {
|
|
3820
3839
|
if (page) plugin.patchPage(page, sessionId).catch((error) => {
|
|
3821
|
-
logger$
|
|
3840
|
+
logger$23.error("Failed to patch page: " + errorMessage(error));
|
|
3822
3841
|
});
|
|
3823
3842
|
}).catch((error) => {
|
|
3824
|
-
logger$
|
|
3843
|
+
logger$23.error("Failed to patch page: " + errorMessage(error));
|
|
3825
3844
|
});
|
|
3826
3845
|
});
|
|
3827
3846
|
for (const page of await context.pages()) await plugin.patchPage(page, sessionId);
|
|
@@ -3845,7 +3864,7 @@ var PuppeteerInstrumentation = class extends InstrumentationBase {
|
|
|
3845
3864
|
const traceId = otelTraceId ? otelTraceIdToUUID(otelTraceId) : NIL_UUID;
|
|
3846
3865
|
page.on("domcontentloaded", () => {
|
|
3847
3866
|
injectSessionRecorder(page, this._sessionRecordingOptions).catch((error) => {
|
|
3848
|
-
logger$
|
|
3867
|
+
logger$23.error("Error in onLoad handler: " + errorMessage(error));
|
|
3849
3868
|
});
|
|
3850
3869
|
});
|
|
3851
3870
|
await injectSessionRecorder(page, this._sessionRecordingOptions);
|
|
@@ -3855,13 +3874,13 @@ var PuppeteerInstrumentation = class extends InstrumentationBase {
|
|
|
3855
3874
|
await sendEvents(chunk, this._client, chunkBuffers, sessionId, traceId);
|
|
3856
3875
|
});
|
|
3857
3876
|
} catch (error) {
|
|
3858
|
-
logger$
|
|
3877
|
+
logger$23.debug("Could not expose function lmnrSendEvents: " + errorMessage(error));
|
|
3859
3878
|
}
|
|
3860
3879
|
}
|
|
3861
3880
|
};
|
|
3862
3881
|
//#endregion
|
|
3863
3882
|
//#region src/browser/stagehand/v3/constants.ts
|
|
3864
|
-
const logger$
|
|
3883
|
+
const logger$22 = initializeLogger();
|
|
3865
3884
|
const CDP_OPERATION_TIMEOUT_MS = 1e4;
|
|
3866
3885
|
const SKIP_URL_PATTERNS = [
|
|
3867
3886
|
"about:blank",
|
|
@@ -3912,7 +3931,7 @@ async function getOrCreateIsolatedWorld(page) {
|
|
|
3912
3931
|
frameId
|
|
3913
3932
|
};
|
|
3914
3933
|
} catch (error) {
|
|
3915
|
-
logger$
|
|
3934
|
+
logger$22.debug("Failed to create isolated world: " + errorMessage(error));
|
|
3916
3935
|
return null;
|
|
3917
3936
|
}
|
|
3918
3937
|
}
|
|
@@ -3929,7 +3948,7 @@ async function isRecorderPresent(page, contextId) {
|
|
|
3929
3948
|
if (!result) return true;
|
|
3930
3949
|
return result.result?.value === true;
|
|
3931
3950
|
} catch (error) {
|
|
3932
|
-
logger$
|
|
3951
|
+
logger$22.debug("Failed to check if recorder is present: " + errorMessage(error));
|
|
3933
3952
|
return true;
|
|
3934
3953
|
}
|
|
3935
3954
|
}
|
|
@@ -3942,21 +3961,21 @@ async function injectRecorderViaCDP(page, state, conn, sessionRecordingOptions,
|
|
|
3942
3961
|
try {
|
|
3943
3962
|
url = page.url();
|
|
3944
3963
|
} catch (error) {
|
|
3945
|
-
logger$
|
|
3964
|
+
logger$22.debug("Failed to get page URL, page might be closed: " + errorMessage(error));
|
|
3946
3965
|
return null;
|
|
3947
3966
|
}
|
|
3948
3967
|
if (shouldSkipUrl(url)) {
|
|
3949
|
-
logger$
|
|
3968
|
+
logger$22.debug(`Skipping recorder injection for URL: ${url}`);
|
|
3950
3969
|
return null;
|
|
3951
3970
|
}
|
|
3952
3971
|
const worldResult = await getOrCreateIsolatedWorld(page);
|
|
3953
3972
|
if (!worldResult) {
|
|
3954
|
-
logger$
|
|
3973
|
+
logger$22.debug("Failed to get isolated world for page");
|
|
3955
3974
|
return null;
|
|
3956
3975
|
}
|
|
3957
3976
|
const { contextId, frameId } = worldResult;
|
|
3958
3977
|
if (await isRecorderPresent(page, contextId)) {
|
|
3959
|
-
logger$
|
|
3978
|
+
logger$22.debug("Recorder already present, skipping injection");
|
|
3960
3979
|
state.contextIdToSession.set(contextId, {
|
|
3961
3980
|
sessionId: state.sessionId,
|
|
3962
3981
|
traceId: state.traceId
|
|
@@ -3969,7 +3988,7 @@ async function injectRecorderViaCDP(page, state, conn, sessionRecordingOptions,
|
|
|
3969
3988
|
contextId
|
|
3970
3989
|
});
|
|
3971
3990
|
} catch (error) {
|
|
3972
|
-
logger$
|
|
3991
|
+
logger$22.debug("Failed to inject rrweb: " + errorMessage(error));
|
|
3973
3992
|
return null;
|
|
3974
3993
|
}
|
|
3975
3994
|
const optionsJson = JSON.stringify(sessionRecordingOptions ?? {});
|
|
@@ -3980,14 +3999,14 @@ async function injectRecorderViaCDP(page, state, conn, sessionRecordingOptions,
|
|
|
3980
3999
|
contextId
|
|
3981
4000
|
});
|
|
3982
4001
|
} catch (error) {
|
|
3983
|
-
logger$
|
|
4002
|
+
logger$22.debug("Failed to inject recording setup: " + errorMessage(error));
|
|
3984
4003
|
return null;
|
|
3985
4004
|
}
|
|
3986
4005
|
try {
|
|
3987
4006
|
await sendCDP(page, "Runtime.addBinding", { name: "lmnrSendEvents" });
|
|
3988
|
-
logger$
|
|
4007
|
+
logger$22.debug(`Added binding 'lmnrSendEvents' for page ${frameId}, context ${contextId}`);
|
|
3989
4008
|
} catch (error) {
|
|
3990
|
-
logger$
|
|
4009
|
+
logger$22.debug("Binding may already exist: " + errorMessage(error));
|
|
3991
4010
|
}
|
|
3992
4011
|
if (bindingHandler) try {
|
|
3993
4012
|
const pageTargetId = page.targetId();
|
|
@@ -3997,26 +4016,26 @@ async function injectRecorderViaCDP(page, state, conn, sessionRecordingOptions,
|
|
|
3997
4016
|
const sessionTyped = session;
|
|
3998
4017
|
if (sessionTyped.on) {
|
|
3999
4018
|
sessionTyped.on("Runtime.bindingCalled", bindingHandler);
|
|
4000
|
-
logger$
|
|
4019
|
+
logger$22.debug(`Set up binding handler on session ${sessionId}`);
|
|
4001
4020
|
}
|
|
4002
4021
|
} catch (error) {
|
|
4003
|
-
logger$
|
|
4022
|
+
logger$22.debug(`Failed to set up binding handler on session ${sessionId}: ` + errorMessage(error));
|
|
4004
4023
|
}
|
|
4005
4024
|
state.pageSessionHandlers.set(pageTargetId, bindingHandler);
|
|
4006
4025
|
}
|
|
4007
4026
|
} catch (error) {
|
|
4008
|
-
logger$
|
|
4027
|
+
logger$22.debug("Failed to set up binding handler: " + errorMessage(error));
|
|
4009
4028
|
}
|
|
4010
4029
|
state.contextIdToSession.set(contextId, {
|
|
4011
4030
|
sessionId: state.sessionId,
|
|
4012
4031
|
traceId: state.traceId
|
|
4013
4032
|
});
|
|
4014
|
-
logger$
|
|
4033
|
+
logger$22.debug(`Registered context mapping: contextId=${contextId}, sessionId=${state.sessionId}`);
|
|
4015
4034
|
state.instrumentedPageIds.add(frameId);
|
|
4016
|
-
logger$
|
|
4035
|
+
logger$22.debug(`Successfully injected recorder into page ${frameId}`);
|
|
4017
4036
|
return contextId;
|
|
4018
4037
|
} catch (error) {
|
|
4019
|
-
logger$
|
|
4038
|
+
logger$22.debug("Error injecting recorder: " + errorMessage(error));
|
|
4020
4039
|
return null;
|
|
4021
4040
|
}
|
|
4022
4041
|
}
|
|
@@ -4030,13 +4049,13 @@ function createBindingHandler(state) {
|
|
|
4030
4049
|
if (event.name !== "lmnrSendEvents") return;
|
|
4031
4050
|
const sessionInfo = state.contextIdToSession.get(event.executionContextId);
|
|
4032
4051
|
if (!sessionInfo) {
|
|
4033
|
-
logger$
|
|
4052
|
+
logger$22.debug("No session info found for context ID: " + event.executionContextId);
|
|
4034
4053
|
if (state.contextIdToSession.size > 0) {
|
|
4035
4054
|
const [, fallbackInfo] = state.contextIdToSession.entries().next().value;
|
|
4036
4055
|
if (fallbackInfo) try {
|
|
4037
4056
|
sendEvents(JSON.parse(event.payload), state.client, state.chunkBuffers, fallbackInfo.sessionId, fallbackInfo.traceId);
|
|
4038
4057
|
} catch (error) {
|
|
4039
|
-
logger$
|
|
4058
|
+
logger$22.debug("Failed to parse binding payload: " + errorMessage(error));
|
|
4040
4059
|
}
|
|
4041
4060
|
}
|
|
4042
4061
|
return;
|
|
@@ -4044,7 +4063,7 @@ function createBindingHandler(state) {
|
|
|
4044
4063
|
try {
|
|
4045
4064
|
sendEvents(JSON.parse(event.payload), state.client, state.chunkBuffers, sessionInfo.sessionId, sessionInfo.traceId);
|
|
4046
4065
|
} catch (error) {
|
|
4047
|
-
logger$
|
|
4066
|
+
logger$22.debug("Failed to handle binding event: " + errorMessage(error));
|
|
4048
4067
|
}
|
|
4049
4068
|
};
|
|
4050
4069
|
}
|
|
@@ -4060,10 +4079,10 @@ function createTargetCreatedHandler(context, state, sessionRecordingOptions) {
|
|
|
4060
4079
|
const pageId = page.mainFrameId();
|
|
4061
4080
|
if (!state.instrumentedPageIds.has(pageId)) await injectRecorderViaCDP(page, state, context.conn, sessionRecordingOptions, state.bindingHandler ?? void 0);
|
|
4062
4081
|
} catch (error) {
|
|
4063
|
-
logger$
|
|
4082
|
+
logger$22.debug("Error injecting recorder into new page: " + errorMessage(error));
|
|
4064
4083
|
}
|
|
4065
4084
|
} catch (error) {
|
|
4066
|
-
logger$
|
|
4085
|
+
logger$22.debug("Error handling target created event: " + errorMessage(error));
|
|
4067
4086
|
}
|
|
4068
4087
|
};
|
|
4069
4088
|
}
|
|
@@ -4075,7 +4094,7 @@ function createTargetInfoChangedHandler(context, state, sessionRecordingOptions)
|
|
|
4075
4094
|
if (event.targetInfo.type !== "page") return;
|
|
4076
4095
|
const url = event.targetInfo.url;
|
|
4077
4096
|
if (shouldSkipUrl(url)) return;
|
|
4078
|
-
logger$
|
|
4097
|
+
logger$22.debug(`Target URL changed to ${url}, checking if recorder injection needed`);
|
|
4079
4098
|
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
4080
4099
|
try {
|
|
4081
4100
|
for (const page of context.pages()) if (page.targetId() === event.targetInfo.targetId) {
|
|
@@ -4083,7 +4102,7 @@ function createTargetInfoChangedHandler(context, state, sessionRecordingOptions)
|
|
|
4083
4102
|
break;
|
|
4084
4103
|
}
|
|
4085
4104
|
} catch (error) {
|
|
4086
|
-
logger$
|
|
4105
|
+
logger$22.debug("Error handling target info change: " + errorMessage(error));
|
|
4087
4106
|
}
|
|
4088
4107
|
};
|
|
4089
4108
|
}
|
|
@@ -4244,12 +4263,12 @@ var StagehandInstrumentation = class extends InstrumentationBase {
|
|
|
4244
4263
|
*/
|
|
4245
4264
|
async setupSessionRecording(stagehandInstance, sessionId, traceId) {
|
|
4246
4265
|
if (!this._client) {
|
|
4247
|
-
logger$
|
|
4266
|
+
logger$22.debug("No Laminar client available, skipping session recording setup");
|
|
4248
4267
|
return;
|
|
4249
4268
|
}
|
|
4250
4269
|
const context = stagehandInstance.context;
|
|
4251
4270
|
if (!context || !context.conn) {
|
|
4252
|
-
logger$
|
|
4271
|
+
logger$22.debug("No context or connection available, skipping session recording setup");
|
|
4253
4272
|
return;
|
|
4254
4273
|
}
|
|
4255
4274
|
const recorderState = {
|
|
@@ -4279,11 +4298,11 @@ var StagehandInstrumentation = class extends InstrumentationBase {
|
|
|
4279
4298
|
for (const page of pages) try {
|
|
4280
4299
|
if (await injectRecorderViaCDP(page, recorderState, context.conn, this._sessionRecordingOptions, bindingHandler) !== null) injectedCount++;
|
|
4281
4300
|
} catch (error) {
|
|
4282
|
-
logger$
|
|
4301
|
+
logger$22.debug("Error injecting recorder into page: " + errorMessage(error));
|
|
4283
4302
|
}
|
|
4284
|
-
logger$
|
|
4303
|
+
logger$22.debug(`Injected session recorder into ${injectedCount} of ${pages.length} existing page(s)`);
|
|
4285
4304
|
} catch (error) {
|
|
4286
|
-
logger$
|
|
4305
|
+
logger$22.debug("Error accessing pages for recorder injection: " + errorMessage(error));
|
|
4287
4306
|
}
|
|
4288
4307
|
}
|
|
4289
4308
|
patchStagehandClose() {
|
|
@@ -4313,12 +4332,12 @@ var StagehandInstrumentation = class extends InstrumentationBase {
|
|
|
4313
4332
|
if (recorderState.targetCreatedHandler) try {
|
|
4314
4333
|
context.conn.off("Target.targetCreated", recorderState.targetCreatedHandler);
|
|
4315
4334
|
} catch (error) {
|
|
4316
|
-
logger$
|
|
4335
|
+
logger$22.debug("Error removing target created handler: " + errorMessage(error));
|
|
4317
4336
|
}
|
|
4318
4337
|
if (recorderState.targetInfoChangedHandler) try {
|
|
4319
4338
|
context.conn.off("Target.targetInfoChanged", recorderState.targetInfoChangedHandler);
|
|
4320
4339
|
} catch (error) {
|
|
4321
|
-
logger$
|
|
4340
|
+
logger$22.debug("Error removing target info changed handler: " + errorMessage(error));
|
|
4322
4341
|
}
|
|
4323
4342
|
}
|
|
4324
4343
|
recorderState.contextIdToSession.clear();
|
|
@@ -4329,7 +4348,7 @@ var StagehandInstrumentation = class extends InstrumentationBase {
|
|
|
4329
4348
|
recorderState.targetCreatedHandler = null;
|
|
4330
4349
|
recorderState.targetInfoChangedHandler = null;
|
|
4331
4350
|
this.stagehandInstanceToRecorderState.delete(stagehandInstance);
|
|
4332
|
-
logger$
|
|
4351
|
+
logger$22.debug("Cleaned up session recording for Stagehand instance");
|
|
4333
4352
|
}
|
|
4334
4353
|
patchStagehandGlobalMethod(methodName, sessionId, parentSpan) {
|
|
4335
4354
|
return (original) => async function method(...args) {
|
|
@@ -4680,7 +4699,7 @@ function extractToolDefinitions(config) {
|
|
|
4680
4699
|
* Also used by the google-aiplatform (Vertex AI) instrumentation, which
|
|
4681
4700
|
* reshapes its requests into the same `{model, contents, config}` form.
|
|
4682
4701
|
*/
|
|
4683
|
-
function setRequestAttributes$
|
|
4702
|
+
function setRequestAttributes$6(span, params, traceContent, system = "gemini") {
|
|
4684
4703
|
safeSetAttribute$2(span, LLM_SYSTEM, system);
|
|
4685
4704
|
safeSetAttribute$2(span, LLM_REQUEST_MODEL, params?.model);
|
|
4686
4705
|
const config = params?.config;
|
|
@@ -4707,7 +4726,7 @@ function setRequestAttributes$5(span, params, traceContent, system = "gemini") {
|
|
|
4707
4726
|
/**
|
|
4708
4727
|
* Set response attributes on a span from a GenerateContentResponse.
|
|
4709
4728
|
*/
|
|
4710
|
-
function setResponseAttributes$
|
|
4729
|
+
function setResponseAttributes$6(span, response, traceContent) {
|
|
4711
4730
|
if (!response) return;
|
|
4712
4731
|
safeSetAttribute$2(span, LLM_RESPONSE_MODEL, response.modelVersion);
|
|
4713
4732
|
const usage = response.usageMetadata;
|
|
@@ -4809,7 +4828,7 @@ function wrapStreamingResponse(span, asyncGen, traceContent) {
|
|
|
4809
4828
|
try {
|
|
4810
4829
|
if (modelVersion !== void 0 || role !== void 0 || accumulatedParts.length > 0 || sawUsageMetadata) {
|
|
4811
4830
|
const mergedParts = mergeTextParts(accumulatedParts);
|
|
4812
|
-
setResponseAttributes$
|
|
4831
|
+
setResponseAttributes$6(span, {
|
|
4813
4832
|
modelVersion,
|
|
4814
4833
|
candidates: [{ content: {
|
|
4815
4834
|
role: role ?? "model",
|
|
@@ -4840,22 +4859,22 @@ function wrapStreamingResponse(span, asyncGen, traceContent) {
|
|
|
4840
4859
|
//#endregion
|
|
4841
4860
|
//#region src/opentelemetry-lib/instrumentation/anthropic/utils.ts
|
|
4842
4861
|
const ANTHROPIC_SYSTEM = "anthropic";
|
|
4843
|
-
const INPUT_MESSAGES$
|
|
4844
|
-
const OUTPUT_MESSAGES$
|
|
4862
|
+
const INPUT_MESSAGES$3 = "gen_ai.input.messages";
|
|
4863
|
+
const OUTPUT_MESSAGES$3 = "gen_ai.output.messages";
|
|
4845
4864
|
const createStreamState$1 = () => ({
|
|
4846
4865
|
usage: {},
|
|
4847
4866
|
blocks: [],
|
|
4848
4867
|
completion: ""
|
|
4849
4868
|
});
|
|
4850
|
-
const toJson$
|
|
4869
|
+
const toJson$2 = (value) => {
|
|
4851
4870
|
if (value === void 0 || value === null) return void 0;
|
|
4852
4871
|
return JSON.stringify(value);
|
|
4853
4872
|
};
|
|
4854
4873
|
const extractStructuredOutputSchema$1 = (params) => {
|
|
4855
4874
|
const outputFormat = params?.output_format;
|
|
4856
|
-
if (outputFormat && typeof outputFormat === "object") return toJson$
|
|
4875
|
+
if (outputFormat && typeof outputFormat === "object") return toJson$2(outputFormat.schema ?? outputFormat);
|
|
4857
4876
|
const schema = params?.output_config?.format?.schema;
|
|
4858
|
-
if (schema && typeof schema === "object") return toJson$
|
|
4877
|
+
if (schema && typeof schema === "object") return toJson$2(schema);
|
|
4859
4878
|
};
|
|
4860
4879
|
const buildInputMessages$1 = (params) => {
|
|
4861
4880
|
if (params?.prompt !== void 0 && params?.prompt !== null) return [{
|
|
@@ -4871,7 +4890,7 @@ const buildInputMessages$1 = (params) => {
|
|
|
4871
4890
|
messages.push(...params.messages);
|
|
4872
4891
|
return messages;
|
|
4873
4892
|
};
|
|
4874
|
-
const setRequestAttributes$
|
|
4893
|
+
const setRequestAttributes$5 = (span, params, traceContent) => {
|
|
4875
4894
|
safeSetAttribute$2(span, "gen_ai.system", ANTHROPIC_SYSTEM);
|
|
4876
4895
|
safeSetAttribute$2(span, "gen_ai.request.model", params?.model);
|
|
4877
4896
|
safeSetAttribute$2(span, "gen_ai.request.max_tokens", params?.max_tokens ?? params?.max_tokens_to_sample);
|
|
@@ -4882,8 +4901,8 @@ const setRequestAttributes$4 = (span, params, traceContent) => {
|
|
|
4882
4901
|
safeSetAttribute$2(span, "llm.is_streaming", params?.stream);
|
|
4883
4902
|
safeSetAttribute$2(span, "anthropic.request.service_tier", params?.service_tier);
|
|
4884
4903
|
if (traceContent) {
|
|
4885
|
-
safeSetAttribute$2(span, INPUT_MESSAGES$
|
|
4886
|
-
safeSetAttribute$2(span, "gen_ai.tool.definitions", toJson$
|
|
4904
|
+
safeSetAttribute$2(span, INPUT_MESSAGES$3, toJson$2(buildInputMessages$1(params)));
|
|
4905
|
+
safeSetAttribute$2(span, "gen_ai.tool.definitions", toJson$2(params?.tools));
|
|
4887
4906
|
}
|
|
4888
4907
|
safeSetAttribute$2(span, "gen_ai.request.structured_output_schema", extractStructuredOutputSchema$1(params));
|
|
4889
4908
|
};
|
|
@@ -4903,7 +4922,7 @@ const setUsageAttributes$1 = (span, usage, includeTotal) => {
|
|
|
4903
4922
|
/**
|
|
4904
4923
|
* Response attributes for a non-streaming `Message` (or legacy `Completion`).
|
|
4905
4924
|
*/
|
|
4906
|
-
const setResponseAttributes$
|
|
4925
|
+
const setResponseAttributes$5 = (span, response, traceContent) => {
|
|
4907
4926
|
if (!response || typeof response !== "object") return;
|
|
4908
4927
|
safeSetAttribute$2(span, "gen_ai.response.model", response.model);
|
|
4909
4928
|
safeSetAttribute$2(span, "gen_ai.response.id", response.id);
|
|
@@ -4920,7 +4939,7 @@ const setResponseAttributes$4 = (span, response, traceContent) => {
|
|
|
4920
4939
|
text: response.completion
|
|
4921
4940
|
});
|
|
4922
4941
|
else if (Array.isArray(response.content)) output.content.push(...response.content);
|
|
4923
|
-
safeSetAttribute$2(span, OUTPUT_MESSAGES$
|
|
4942
|
+
safeSetAttribute$2(span, OUTPUT_MESSAGES$3, toJson$2([output]));
|
|
4924
4943
|
}
|
|
4925
4944
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
4926
4945
|
};
|
|
@@ -5013,14 +5032,14 @@ const setStreamingResponseAttributes = (span, state, traceContent) => {
|
|
|
5013
5032
|
content: buildStreamedContent(state)
|
|
5014
5033
|
};
|
|
5015
5034
|
if (state.stopReason) output.stop_reason = state.stopReason;
|
|
5016
|
-
safeSetAttribute$2(span, OUTPUT_MESSAGES$
|
|
5035
|
+
safeSetAttribute$2(span, OUTPUT_MESSAGES$3, toJson$2([output]));
|
|
5017
5036
|
}
|
|
5018
5037
|
};
|
|
5019
5038
|
//#endregion
|
|
5020
5039
|
//#region src/opentelemetry-lib/instrumentation/anthropic/index.ts
|
|
5021
|
-
const logger$
|
|
5022
|
-
const PATCH_DATA_SYMBOL$
|
|
5023
|
-
const hasOwnPatchData$
|
|
5040
|
+
const logger$21 = initializeLogger();
|
|
5041
|
+
const PATCH_DATA_SYMBOL$4 = Symbol("lmnr.anthropic.patchData");
|
|
5042
|
+
const hasOwnPatchData$3 = (proto) => Object.getOwnPropertyDescriptor(proto, PATCH_DATA_SYMBOL$4) !== void 0;
|
|
5024
5043
|
const markSpanError$3 = (span, error) => {
|
|
5025
5044
|
span.recordException(error);
|
|
5026
5045
|
span.setAttribute("error.type", error?.constructor?.name ?? "Error");
|
|
@@ -5033,7 +5052,7 @@ const safely$3 = (fn) => {
|
|
|
5033
5052
|
try {
|
|
5034
5053
|
fn();
|
|
5035
5054
|
} catch (error) {
|
|
5036
|
-
logger$
|
|
5055
|
+
logger$21.debug(`Failed to set anthropic span attributes: ${String(error)}`);
|
|
5037
5056
|
}
|
|
5038
5057
|
};
|
|
5039
5058
|
const isAsyncIterable$3 = (value) => value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
@@ -5084,9 +5103,9 @@ var AnthropicInstrumentation = class extends InstrumentationBase {
|
|
|
5084
5103
|
unpatch(moduleExports) {
|
|
5085
5104
|
diag.debug("Unpatching @anthropic-ai/sdk");
|
|
5086
5105
|
for (const proto of this.resourcePrototypes(moduleExports)) {
|
|
5087
|
-
if (!proto || !hasOwnPatchData$
|
|
5088
|
-
proto.create = proto[PATCH_DATA_SYMBOL$
|
|
5089
|
-
delete proto[PATCH_DATA_SYMBOL$
|
|
5106
|
+
if (!proto || !hasOwnPatchData$3(proto)) continue;
|
|
5107
|
+
proto.create = proto[PATCH_DATA_SYMBOL$4].original;
|
|
5108
|
+
delete proto[PATCH_DATA_SYMBOL$4];
|
|
5090
5109
|
}
|
|
5091
5110
|
}
|
|
5092
5111
|
/**
|
|
@@ -5108,15 +5127,15 @@ var AnthropicInstrumentation = class extends InstrumentationBase {
|
|
|
5108
5127
|
*/
|
|
5109
5128
|
patchCreate(proto, spanName) {
|
|
5110
5129
|
if (!proto || typeof proto.create !== "function") return;
|
|
5111
|
-
if (hasOwnPatchData$
|
|
5112
|
-
proto[PATCH_DATA_SYMBOL$
|
|
5130
|
+
if (hasOwnPatchData$3(proto)) {
|
|
5131
|
+
proto[PATCH_DATA_SYMBOL$4].traceContent = this.traceContent;
|
|
5113
5132
|
return;
|
|
5114
5133
|
}
|
|
5115
5134
|
const patchData = {
|
|
5116
5135
|
traceContent: this.traceContent,
|
|
5117
5136
|
original: proto.create
|
|
5118
5137
|
};
|
|
5119
|
-
Object.defineProperty(proto, PATCH_DATA_SYMBOL$
|
|
5138
|
+
Object.defineProperty(proto, PATCH_DATA_SYMBOL$4, {
|
|
5120
5139
|
value: patchData,
|
|
5121
5140
|
writable: true,
|
|
5122
5141
|
configurable: true,
|
|
@@ -5133,7 +5152,7 @@ const wrapCreate = (patchData, spanName) => function(params, ...rest) {
|
|
|
5133
5152
|
name: spanName,
|
|
5134
5153
|
spanType: "LLM"
|
|
5135
5154
|
});
|
|
5136
|
-
safely$3(() => setRequestAttributes$
|
|
5155
|
+
safely$3(() => setRequestAttributes$5(span, params, traceContent));
|
|
5137
5156
|
let result;
|
|
5138
5157
|
try {
|
|
5139
5158
|
result = Laminar.withSpan(span, () => ({ value: original.call(this, params, ...rest) })).value;
|
|
@@ -5157,7 +5176,7 @@ const wrapCreate = (patchData, spanName) => function(params, ...rest) {
|
|
|
5157
5176
|
return data;
|
|
5158
5177
|
}
|
|
5159
5178
|
ended = true;
|
|
5160
|
-
safely$3(() => setResponseAttributes$
|
|
5179
|
+
safely$3(() => setResponseAttributes$5(span, data, traceContent));
|
|
5161
5180
|
span.end();
|
|
5162
5181
|
return data;
|
|
5163
5182
|
};
|
|
@@ -5207,8 +5226,8 @@ const instrumentStream$2 = (stream, span, traceContent) => {
|
|
|
5207
5226
|
//#endregion
|
|
5208
5227
|
//#region src/opentelemetry-lib/instrumentation/cohere/utils.ts
|
|
5209
5228
|
const COHERE_SYSTEM = "cohere";
|
|
5210
|
-
const INPUT_MESSAGES$
|
|
5211
|
-
const OUTPUT_MESSAGES$
|
|
5229
|
+
const INPUT_MESSAGES$2 = "gen_ai.input.messages";
|
|
5230
|
+
const OUTPUT_MESSAGES$2 = "gen_ai.output.messages";
|
|
5212
5231
|
const OPERATION_NAMES = {
|
|
5213
5232
|
chat: "chat",
|
|
5214
5233
|
completion: "text_completion",
|
|
@@ -5223,7 +5242,7 @@ const V1_ROLES = {
|
|
|
5223
5242
|
};
|
|
5224
5243
|
const asList = (value) => Array.isArray(value) ? value : [];
|
|
5225
5244
|
const asInt = (value) => typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : void 0;
|
|
5226
|
-
const maybeJson = (value) => {
|
|
5245
|
+
const maybeJson$1 = (value) => {
|
|
5227
5246
|
if (typeof value !== "string") return value;
|
|
5228
5247
|
try {
|
|
5229
5248
|
return JSON.parse(value);
|
|
@@ -5291,7 +5310,7 @@ const v2ToolCallParts = (toolCalls) => asList(toolCalls).map((toolCall) => {
|
|
|
5291
5310
|
name: toolCall?.function?.name ?? ""
|
|
5292
5311
|
};
|
|
5293
5312
|
const args = toolCall?.function?.arguments;
|
|
5294
|
-
if (args !== void 0 && args !== null) part.arguments = maybeJson(args);
|
|
5313
|
+
if (args !== void 0 && args !== null) part.arguments = maybeJson$1(args);
|
|
5295
5314
|
return part;
|
|
5296
5315
|
});
|
|
5297
5316
|
const v1ToolCallParts = (toolCalls) => asList(toolCalls).map((toolCall) => ({
|
|
@@ -5381,7 +5400,7 @@ const toolDefinitions = (tools) => asList(tools).map((tool) => {
|
|
|
5381
5400
|
if (parameters) definition.parameters = parameters;
|
|
5382
5401
|
return definition;
|
|
5383
5402
|
});
|
|
5384
|
-
const setRequestAttributes$
|
|
5403
|
+
const setRequestAttributes$4 = (span, params, requestType, isV2, isStreaming, traceContent) => {
|
|
5385
5404
|
safeSetAttribute$2(span, "gen_ai.system", COHERE_SYSTEM);
|
|
5386
5405
|
safeSetAttribute$2(span, "gen_ai.operation.name", OPERATION_NAMES[requestType]);
|
|
5387
5406
|
safeSetAttribute$2(span, "gen_ai.request.model", params?.model);
|
|
@@ -5406,12 +5425,12 @@ const setRequestAttributes$3 = (span, params, requestType, isV2, isStreaming, tr
|
|
|
5406
5425
|
}] : [];
|
|
5407
5426
|
else if (requestType === "rerank") messages = rerankInput(params);
|
|
5408
5427
|
else messages = embedInput(params);
|
|
5409
|
-
if (messages.length > 0) span.setAttribute(INPUT_MESSAGES$
|
|
5428
|
+
if (messages.length > 0) span.setAttribute(INPUT_MESSAGES$2, JSON.stringify(messages));
|
|
5410
5429
|
};
|
|
5411
5430
|
/**
|
|
5412
5431
|
* `usage` (v2) / `meta` (v1): actual `tokens`, falling back to `billedUnits`.
|
|
5413
5432
|
*/
|
|
5414
|
-
const setUsage = (span, usage) => {
|
|
5433
|
+
const setUsage$1 = (span, usage) => {
|
|
5415
5434
|
const inputTokens = asInt(usage?.tokens?.inputTokens) ?? asInt(usage?.billedUnits?.inputTokens);
|
|
5416
5435
|
const outputTokens = asInt(usage?.tokens?.outputTokens) ?? asInt(usage?.billedUnits?.outputTokens);
|
|
5417
5436
|
safeSetAttribute$2(span, "gen_ai.usage.input_tokens", inputTokens);
|
|
@@ -5447,9 +5466,9 @@ const rerankOutput = (response) => {
|
|
|
5447
5466
|
parts
|
|
5448
5467
|
}] : [];
|
|
5449
5468
|
};
|
|
5450
|
-
const setResponseAttributes$
|
|
5469
|
+
const setResponseAttributes$4 = (span, response, requestType, isV2, traceContent) => {
|
|
5451
5470
|
safeSetAttribute$2(span, "gen_ai.response.id", response?.responseId ?? response?.id);
|
|
5452
|
-
setUsage(span, response?.usage ?? response?.meta);
|
|
5471
|
+
setUsage$1(span, response?.usage ?? response?.meta);
|
|
5453
5472
|
let output = [];
|
|
5454
5473
|
if (requestType === "chat") {
|
|
5455
5474
|
const message = isV2 ? v2ChatOutput(response) : v1ChatOutput(response);
|
|
@@ -5461,7 +5480,7 @@ const setResponseAttributes$3 = (span, response, requestType, isV2, traceContent
|
|
|
5461
5480
|
output = [message];
|
|
5462
5481
|
} else if (requestType === "completion") output = completionOutput(response);
|
|
5463
5482
|
else if (requestType === "rerank") output = rerankOutput(response);
|
|
5464
|
-
if (output.length > 0 && traceContent) span.setAttribute(OUTPUT_MESSAGES$
|
|
5483
|
+
if (output.length > 0 && traceContent) span.setAttribute(OUTPUT_MESSAGES$2, JSON.stringify(output));
|
|
5465
5484
|
};
|
|
5466
5485
|
/**
|
|
5467
5486
|
* v1 `chatStream`: the `stream-end` event carries the full response.
|
|
@@ -5578,8 +5597,8 @@ const createV2ChatStreamAccumulator = () => {
|
|
|
5578
5597
|
};
|
|
5579
5598
|
//#endregion
|
|
5580
5599
|
//#region src/opentelemetry-lib/instrumentation/cohere/index.ts
|
|
5581
|
-
const logger$
|
|
5582
|
-
const PATCH_DATA_SYMBOL$
|
|
5600
|
+
const logger$20 = initializeLogger();
|
|
5601
|
+
const PATCH_DATA_SYMBOL$3 = Symbol("lmnr.cohere.patchData");
|
|
5583
5602
|
const SPAN_NAMES = {
|
|
5584
5603
|
chat: "cohere.chat",
|
|
5585
5604
|
completion: "cohere.completion",
|
|
@@ -5635,7 +5654,7 @@ const V2_METHODS = [
|
|
|
5635
5654
|
streaming: false
|
|
5636
5655
|
}
|
|
5637
5656
|
];
|
|
5638
|
-
const ownPatchData = (proto) => Object.getOwnPropertyDescriptor(proto, PATCH_DATA_SYMBOL$
|
|
5657
|
+
const ownPatchData = (proto) => Object.getOwnPropertyDescriptor(proto, PATCH_DATA_SYMBOL$3)?.value;
|
|
5639
5658
|
const markSpanError$2 = (span, error) => {
|
|
5640
5659
|
span.recordException(error);
|
|
5641
5660
|
span.setAttribute("error.type", error?.constructor?.name ?? "Error");
|
|
@@ -5651,7 +5670,7 @@ const safely$2 = (fn) => {
|
|
|
5651
5670
|
try {
|
|
5652
5671
|
fn();
|
|
5653
5672
|
} catch (error) {
|
|
5654
|
-
logger$
|
|
5673
|
+
logger$20.debug(`Failed to set cohere span attributes: ${String(error)}`);
|
|
5655
5674
|
}
|
|
5656
5675
|
};
|
|
5657
5676
|
const isAsyncIterable$2 = (value) => value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
@@ -5758,7 +5777,7 @@ var CohereInstrumentation = class extends InstrumentationBase {
|
|
|
5758
5777
|
}
|
|
5759
5778
|
if (!patched) {
|
|
5760
5779
|
patched = {};
|
|
5761
|
-
Object.defineProperty(proto, PATCH_DATA_SYMBOL$
|
|
5780
|
+
Object.defineProperty(proto, PATCH_DATA_SYMBOL$3, {
|
|
5762
5781
|
value: patched,
|
|
5763
5782
|
writable: true,
|
|
5764
5783
|
configurable: true,
|
|
@@ -5783,7 +5802,7 @@ const wrapMethod$1 = (patchData) => function(request, ...rest) {
|
|
|
5783
5802
|
name: SPAN_NAMES[requestType],
|
|
5784
5803
|
spanType: "LLM"
|
|
5785
5804
|
});
|
|
5786
|
-
safely$2(() => setRequestAttributes$
|
|
5805
|
+
safely$2(() => setRequestAttributes$4(span, request, requestType, isV2, streaming, traceContent));
|
|
5787
5806
|
let result;
|
|
5788
5807
|
try {
|
|
5789
5808
|
result = Laminar.withSpan(span, () => ({ value: original.call(this, request, ...rest) })).value;
|
|
@@ -5807,7 +5826,7 @@ const wrapMethod$1 = (patchData) => function(request, ...rest) {
|
|
|
5807
5826
|
instrumentStream$1(data, span, accumulator, isV2, traceContent);
|
|
5808
5827
|
return data;
|
|
5809
5828
|
}
|
|
5810
|
-
safely$2(() => setResponseAttributes$
|
|
5829
|
+
safely$2(() => setResponseAttributes$4(span, data, requestType, isV2, traceContent));
|
|
5811
5830
|
span.end();
|
|
5812
5831
|
return data;
|
|
5813
5832
|
};
|
|
@@ -5832,7 +5851,7 @@ const instrumentStream$1 = (stream, span, accumulator, isV2, traceContent) => {
|
|
|
5832
5851
|
const end = (error) => {
|
|
5833
5852
|
if (ended) return;
|
|
5834
5853
|
ended = true;
|
|
5835
|
-
safely$2(() => setResponseAttributes$
|
|
5854
|
+
safely$2(() => setResponseAttributes$4(span, accumulator.response(), "chat", isV2, traceContent));
|
|
5836
5855
|
if (error !== void 0) markSpanError$2(span, error);
|
|
5837
5856
|
else span.setStatus({ code: SpanStatusCode.OK });
|
|
5838
5857
|
span.end();
|
|
@@ -5882,7 +5901,7 @@ const fromValue = (value) => {
|
|
|
5882
5901
|
default: return;
|
|
5883
5902
|
}
|
|
5884
5903
|
};
|
|
5885
|
-
const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
5904
|
+
const asRecord$1 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
5886
5905
|
const asNumber = (value) => typeof value === "number" && !Number.isNaN(value) ? value : void 0;
|
|
5887
5906
|
/**
|
|
5888
5907
|
* Strip resource prefixes, e.g.
|
|
@@ -5903,7 +5922,7 @@ const toInputMessages = (instance) => {
|
|
|
5903
5922
|
content: instance.prompt
|
|
5904
5923
|
});
|
|
5905
5924
|
if (Array.isArray(instance.messages)) for (const message of instance.messages) {
|
|
5906
|
-
const record = asRecord(message);
|
|
5925
|
+
const record = asRecord$1(message);
|
|
5907
5926
|
if (!record) continue;
|
|
5908
5927
|
const author = typeof record.author === "string" ? record.author : "user";
|
|
5909
5928
|
messages.push({
|
|
@@ -5920,7 +5939,7 @@ const toInputMessages = (instance) => {
|
|
|
5920
5939
|
const setPredictRequestAttributes = (span, request, traceContent) => {
|
|
5921
5940
|
safeSetAttribute$2(span, "gen_ai.system", VERTEX_AI_SYSTEM);
|
|
5922
5941
|
safeSetAttribute$2(span, "gen_ai.request.model", lastPathSegment(request?.endpoint));
|
|
5923
|
-
const parameters = asRecord(fromValue(request?.parameters));
|
|
5942
|
+
const parameters = asRecord$1(fromValue(request?.parameters));
|
|
5924
5943
|
if (parameters) {
|
|
5925
5944
|
safeSetAttribute$2(span, "gen_ai.request.max_tokens", asNumber(parameters.maxOutputTokens));
|
|
5926
5945
|
safeSetAttribute$2(span, "gen_ai.request.temperature", asNumber(parameters.temperature));
|
|
@@ -5929,16 +5948,16 @@ const setPredictRequestAttributes = (span, request, traceContent) => {
|
|
|
5929
5948
|
}
|
|
5930
5949
|
if (!traceContent || !Array.isArray(request?.instances)) return;
|
|
5931
5950
|
const messages = request.instances.flatMap((instance) => {
|
|
5932
|
-
const record = asRecord(fromValue(instance));
|
|
5951
|
+
const record = asRecord$1(fromValue(instance));
|
|
5933
5952
|
return record ? toInputMessages(record) : [];
|
|
5934
5953
|
});
|
|
5935
5954
|
if (messages.length > 0) safeSetAttribute$2(span, "gen_ai.input.messages", JSON.stringify(messages));
|
|
5936
5955
|
};
|
|
5937
5956
|
const predictionContent = (prediction) => {
|
|
5938
|
-
const record = asRecord(fromValue(prediction));
|
|
5957
|
+
const record = asRecord$1(fromValue(prediction));
|
|
5939
5958
|
if (!record) return void 0;
|
|
5940
5959
|
if (typeof record.content === "string") return record.content;
|
|
5941
|
-
const firstCandidate = Array.isArray(record.candidates) ? asRecord(record.candidates[0]) : void 0;
|
|
5960
|
+
const firstCandidate = Array.isArray(record.candidates) ? asRecord$1(record.candidates[0]) : void 0;
|
|
5942
5961
|
if (typeof firstCandidate?.content === "string") return firstCandidate.content;
|
|
5943
5962
|
};
|
|
5944
5963
|
/**
|
|
@@ -5947,10 +5966,10 @@ const predictionContent = (prediction) => {
|
|
|
5947
5966
|
const setPredictResponseAttributes = (span, response, traceContent) => {
|
|
5948
5967
|
if (!response) return;
|
|
5949
5968
|
safeSetAttribute$2(span, "gen_ai.response.model", lastPathSegment(response.model));
|
|
5950
|
-
const metadata = asRecord(fromValue(response.metadata));
|
|
5951
|
-
const tokenMetadata = asRecord(metadata?.tokenMetadata);
|
|
5952
|
-
const inputTokens = asNumber(asRecord(tokenMetadata?.inputTokenCount)?.totalTokens);
|
|
5953
|
-
const outputTokens = asNumber(asRecord(tokenMetadata?.outputTokenCount)?.totalTokens);
|
|
5969
|
+
const metadata = asRecord$1(fromValue(response.metadata));
|
|
5970
|
+
const tokenMetadata = asRecord$1(metadata?.tokenMetadata);
|
|
5971
|
+
const inputTokens = asNumber(asRecord$1(tokenMetadata?.inputTokenCount)?.totalTokens);
|
|
5972
|
+
const outputTokens = asNumber(asRecord$1(tokenMetadata?.outputTokenCount)?.totalTokens);
|
|
5954
5973
|
safeSetAttribute$2(span, "gen_ai.usage.input_tokens", inputTokens);
|
|
5955
5974
|
safeSetAttribute$2(span, "gen_ai.usage.output_tokens", outputTokens);
|
|
5956
5975
|
if (inputTokens !== void 0 && outputTokens !== void 0) safeSetAttribute$2(span, "llm.usage.total_tokens", inputTokens + outputTokens);
|
|
@@ -5982,9 +6001,9 @@ const toGenAiParams = (model, request) => {
|
|
|
5982
6001
|
};
|
|
5983
6002
|
//#endregion
|
|
5984
6003
|
//#region src/opentelemetry-lib/instrumentation/google-aiplatform/index.ts
|
|
5985
|
-
const logger$
|
|
5986
|
-
const PATCH_DATA_SYMBOL$
|
|
5987
|
-
const hasOwnPatchData$
|
|
6004
|
+
const logger$19 = initializeLogger();
|
|
6005
|
+
const PATCH_DATA_SYMBOL$2 = Symbol("lmnr.google-aiplatform.patchData");
|
|
6006
|
+
const hasOwnPatchData$2 = (proto) => Object.getOwnPropertyDescriptor(proto, PATCH_DATA_SYMBOL$2) !== void 0;
|
|
5988
6007
|
const GENERATIVE_MODEL_CLASSES = ["GenerativeModel", "GenerativeModelPreview"];
|
|
5989
6008
|
const markSpanError$1 = (span, error) => {
|
|
5990
6009
|
span.setAttribute("error.type", error?.constructor?.name ?? "Error");
|
|
@@ -5997,7 +6016,7 @@ const safely$1 = (fn) => {
|
|
|
5997
6016
|
try {
|
|
5998
6017
|
fn();
|
|
5999
6018
|
} catch (error) {
|
|
6000
|
-
logger$
|
|
6019
|
+
logger$19.debug(`Failed to set google-aiplatform span attributes: ${String(error)}`);
|
|
6001
6020
|
}
|
|
6002
6021
|
};
|
|
6003
6022
|
/**
|
|
@@ -6087,13 +6106,13 @@ var GoogleAIPlatformInstrumentation = class extends InstrumentationBase {
|
|
|
6087
6106
|
*/
|
|
6088
6107
|
patchMethod(proto, method, makeWrapper) {
|
|
6089
6108
|
if (!proto || typeof proto[method] !== "function") return;
|
|
6090
|
-
if (!hasOwnPatchData$
|
|
6109
|
+
if (!hasOwnPatchData$2(proto)) Object.defineProperty(proto, PATCH_DATA_SYMBOL$2, {
|
|
6091
6110
|
value: {},
|
|
6092
6111
|
writable: true,
|
|
6093
6112
|
configurable: true,
|
|
6094
6113
|
enumerable: false
|
|
6095
6114
|
});
|
|
6096
|
-
const patches = proto[PATCH_DATA_SYMBOL$
|
|
6115
|
+
const patches = proto[PATCH_DATA_SYMBOL$2];
|
|
6097
6116
|
const existing = patches[method];
|
|
6098
6117
|
if (existing) {
|
|
6099
6118
|
existing.traceContent = this.traceContent;
|
|
@@ -6107,10 +6126,10 @@ var GoogleAIPlatformInstrumentation = class extends InstrumentationBase {
|
|
|
6107
6126
|
proto[method] = makeWrapper(patchData.original, patchData);
|
|
6108
6127
|
}
|
|
6109
6128
|
unpatchMethods(proto) {
|
|
6110
|
-
if (!proto || !hasOwnPatchData$
|
|
6111
|
-
const patches = proto[PATCH_DATA_SYMBOL$
|
|
6129
|
+
if (!proto || !hasOwnPatchData$2(proto)) return;
|
|
6130
|
+
const patches = proto[PATCH_DATA_SYMBOL$2];
|
|
6112
6131
|
for (const [method, patchData] of Object.entries(patches)) proto[method] = patchData.original;
|
|
6113
|
-
delete proto[PATCH_DATA_SYMBOL$
|
|
6132
|
+
delete proto[PATCH_DATA_SYMBOL$2];
|
|
6114
6133
|
}
|
|
6115
6134
|
wrapGenerateContent(original, patchData) {
|
|
6116
6135
|
return function(request, ...rest) {
|
|
@@ -6120,7 +6139,7 @@ var GoogleAIPlatformInstrumentation = class extends InstrumentationBase {
|
|
|
6120
6139
|
spanType: "LLM"
|
|
6121
6140
|
});
|
|
6122
6141
|
const params = toGenAiParams(this, request);
|
|
6123
|
-
safely$1(() => setRequestAttributes$
|
|
6142
|
+
safely$1(() => setRequestAttributes$6(span, params, patchData.traceContent, VERTEX_AI_SYSTEM));
|
|
6124
6143
|
return Laminar.withSpan(span, async () => {
|
|
6125
6144
|
try {
|
|
6126
6145
|
const result = await original.call(this, request, ...rest);
|
|
@@ -6141,7 +6160,7 @@ var GoogleAIPlatformInstrumentation = class extends InstrumentationBase {
|
|
|
6141
6160
|
spanType: "LLM"
|
|
6142
6161
|
});
|
|
6143
6162
|
const params = toGenAiParams(this, request);
|
|
6144
|
-
safely$1(() => setRequestAttributes$
|
|
6163
|
+
safely$1(() => setRequestAttributes$6(span, params, patchData.traceContent, VERTEX_AI_SYSTEM));
|
|
6145
6164
|
let result;
|
|
6146
6165
|
try {
|
|
6147
6166
|
result = await Laminar.withSpan(span, () => original.call(this, request, ...rest));
|
|
@@ -6205,7 +6224,7 @@ var GoogleAIPlatformInstrumentation = class extends InstrumentationBase {
|
|
|
6205
6224
|
}
|
|
6206
6225
|
};
|
|
6207
6226
|
const setGenerateContentResponseAttributes = (span, response, requestModel, traceContent) => {
|
|
6208
|
-
setResponseAttributes$
|
|
6227
|
+
setResponseAttributes$6(span, response, traceContent);
|
|
6209
6228
|
if (!response?.modelVersion) safeSetAttribute$2(span, "gen_ai.response.model", requestModel);
|
|
6210
6229
|
};
|
|
6211
6230
|
//#endregion
|
|
@@ -6305,11 +6324,11 @@ var GoogleGenAiInstrumentation = class extends InstrumentationBase {
|
|
|
6305
6324
|
name: "gemini.generate_content",
|
|
6306
6325
|
spanType: "LLM"
|
|
6307
6326
|
});
|
|
6308
|
-
setRequestAttributes$
|
|
6327
|
+
setRequestAttributes$6(span, params, classPatchData.traceContent);
|
|
6309
6328
|
return Laminar.withSpan(span, async () => {
|
|
6310
6329
|
try {
|
|
6311
6330
|
const response = await originalGenerateContent(params);
|
|
6312
|
-
setResponseAttributes$
|
|
6331
|
+
setResponseAttributes$6(span, response, classPatchData.traceContent);
|
|
6313
6332
|
return response;
|
|
6314
6333
|
} catch (error) {
|
|
6315
6334
|
span.setAttribute("error.type", error.constructor?.name ?? "Error");
|
|
@@ -6324,7 +6343,7 @@ var GoogleGenAiInstrumentation = class extends InstrumentationBase {
|
|
|
6324
6343
|
name: "gemini.generate_content_stream",
|
|
6325
6344
|
spanType: "LLM"
|
|
6326
6345
|
});
|
|
6327
|
-
setRequestAttributes$
|
|
6346
|
+
setRequestAttributes$6(span, params, classPatchData.traceContent);
|
|
6328
6347
|
try {
|
|
6329
6348
|
return wrapStreamingResponse(span, await originalGenerateContentStream(params), classPatchData.traceContent);
|
|
6330
6349
|
} catch (error) {
|
|
@@ -6482,6 +6501,1053 @@ var KernelInstrumentation = class extends InstrumentationBase {
|
|
|
6482
6501
|
this._unwrap(moduleExports.Kernel.prototype, "app");
|
|
6483
6502
|
}
|
|
6484
6503
|
};
|
|
6504
|
+
//#endregion
|
|
6505
|
+
//#region src/opentelemetry-lib/instrumentation/langchain/span-utils.ts
|
|
6506
|
+
const INPUT_MESSAGES$1 = "gen_ai.input.messages";
|
|
6507
|
+
const OUTPUT_MESSAGES$1 = "gen_ai.output.messages";
|
|
6508
|
+
const ROLE_BY_MESSAGE_TYPE = {
|
|
6509
|
+
human: "user",
|
|
6510
|
+
system: "system",
|
|
6511
|
+
ai: "assistant",
|
|
6512
|
+
tool: "tool",
|
|
6513
|
+
function: "tool"
|
|
6514
|
+
};
|
|
6515
|
+
const FINISH_REASON_MAP = {
|
|
6516
|
+
stop: "stop",
|
|
6517
|
+
length: "length",
|
|
6518
|
+
tool_calls: "tool_call",
|
|
6519
|
+
function_call: "tool_call",
|
|
6520
|
+
content_filter: "content_filter",
|
|
6521
|
+
end_turn: "stop",
|
|
6522
|
+
stop_sequence: "stop",
|
|
6523
|
+
tool_use: "tool_call",
|
|
6524
|
+
max_tokens: "length"
|
|
6525
|
+
};
|
|
6526
|
+
const MODEL_KEYS = [
|
|
6527
|
+
"model",
|
|
6528
|
+
"model_name",
|
|
6529
|
+
"model_id",
|
|
6530
|
+
"modelName"
|
|
6531
|
+
];
|
|
6532
|
+
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6533
|
+
const asRecord = (value) => isRecord(value) ? value : {};
|
|
6534
|
+
const isInt = (value) => typeof value === "number" && Number.isInteger(value);
|
|
6535
|
+
/**
|
|
6536
|
+
* `JSON.stringify` that never throws: cycles become `"[Circular]"` and bigints
|
|
6537
|
+
* strings.
|
|
6538
|
+
*/
|
|
6539
|
+
const toJson$1 = (value) => {
|
|
6540
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
6541
|
+
try {
|
|
6542
|
+
return JSON.stringify(value, (_key, item) => {
|
|
6543
|
+
if (typeof item === "bigint") return item.toString();
|
|
6544
|
+
if (item !== null && typeof item === "object") {
|
|
6545
|
+
if (seen.has(item)) return "[Circular]";
|
|
6546
|
+
seen.add(item);
|
|
6547
|
+
}
|
|
6548
|
+
return item;
|
|
6549
|
+
}) ?? "null";
|
|
6550
|
+
} catch {
|
|
6551
|
+
return String(value);
|
|
6552
|
+
}
|
|
6553
|
+
};
|
|
6554
|
+
const maybeJson = (value) => {
|
|
6555
|
+
if (typeof value !== "string") return value;
|
|
6556
|
+
try {
|
|
6557
|
+
return JSON.parse(value);
|
|
6558
|
+
} catch {
|
|
6559
|
+
return value;
|
|
6560
|
+
}
|
|
6561
|
+
};
|
|
6562
|
+
const setIfPresent = (span, key, value) => {
|
|
6563
|
+
if (value === void 0 || value === null) return;
|
|
6564
|
+
if (typeof value === "string" && value.length === 0) return;
|
|
6565
|
+
span.setAttribute(key, value);
|
|
6566
|
+
};
|
|
6567
|
+
const messageType = (message) => {
|
|
6568
|
+
const type = message?.type ?? message?._getType?.() ?? message?.getType?.();
|
|
6569
|
+
return typeof type === "string" ? type : "";
|
|
6570
|
+
};
|
|
6571
|
+
const messageRole = (type) => ROLE_BY_MESSAGE_TYPE[type] ?? (type || "unknown");
|
|
6572
|
+
/**
|
|
6573
|
+
* Convert LangChain message content (string or list of blocks) into GenAI
|
|
6574
|
+
* parts.
|
|
6575
|
+
*/
|
|
6576
|
+
const contentToParts = (content) => {
|
|
6577
|
+
if (typeof content === "string") return content ? [{
|
|
6578
|
+
type: "text",
|
|
6579
|
+
content
|
|
6580
|
+
}] : [];
|
|
6581
|
+
if (!Array.isArray(content)) return content ? [{
|
|
6582
|
+
type: "text",
|
|
6583
|
+
content: String(content)
|
|
6584
|
+
}] : [];
|
|
6585
|
+
const parts = [];
|
|
6586
|
+
for (const block of content) {
|
|
6587
|
+
if (typeof block === "string") {
|
|
6588
|
+
if (block) parts.push({
|
|
6589
|
+
type: "text",
|
|
6590
|
+
content: block
|
|
6591
|
+
});
|
|
6592
|
+
continue;
|
|
6593
|
+
}
|
|
6594
|
+
if (!isRecord(block)) {
|
|
6595
|
+
parts.push({
|
|
6596
|
+
type: "text",
|
|
6597
|
+
content: String(block)
|
|
6598
|
+
});
|
|
6599
|
+
continue;
|
|
6600
|
+
}
|
|
6601
|
+
if (block.type === "text") {
|
|
6602
|
+
if (block.text) parts.push({
|
|
6603
|
+
type: "text",
|
|
6604
|
+
content: block.text
|
|
6605
|
+
});
|
|
6606
|
+
} else if (block.type === "image_url") {
|
|
6607
|
+
const url = isRecord(block.image_url) ? block.image_url.url : block.image_url;
|
|
6608
|
+
if (url) parts.push({
|
|
6609
|
+
type: "uri",
|
|
6610
|
+
modality: "image",
|
|
6611
|
+
uri: url
|
|
6612
|
+
});
|
|
6613
|
+
} else if (block.type === "image" && block.url) parts.push({
|
|
6614
|
+
type: "uri",
|
|
6615
|
+
modality: "image",
|
|
6616
|
+
uri: block.url
|
|
6617
|
+
});
|
|
6618
|
+
else if (block.type === "image") parts.push({
|
|
6619
|
+
type: "blob",
|
|
6620
|
+
modality: "image",
|
|
6621
|
+
mime_type: block.mime_type || block.mimeType || block.media_type || "",
|
|
6622
|
+
content: block.data || block.base64 || ""
|
|
6623
|
+
});
|
|
6624
|
+
else parts.push(block);
|
|
6625
|
+
}
|
|
6626
|
+
return parts;
|
|
6627
|
+
};
|
|
6628
|
+
const toolCallsToParts = (toolCalls) => {
|
|
6629
|
+
if (!Array.isArray(toolCalls)) return [];
|
|
6630
|
+
const parts = [];
|
|
6631
|
+
for (const toolCall of toolCalls) {
|
|
6632
|
+
if (!isRecord(toolCall)) continue;
|
|
6633
|
+
const fn = asRecord(toolCall.function);
|
|
6634
|
+
const part = {
|
|
6635
|
+
type: "tool_call",
|
|
6636
|
+
id: toolCall.id || "",
|
|
6637
|
+
name: toolCall.name || fn.name || ""
|
|
6638
|
+
};
|
|
6639
|
+
const args = toolCall.args ?? fn.arguments;
|
|
6640
|
+
if (args !== void 0 && args !== null) part.arguments = maybeJson(args);
|
|
6641
|
+
parts.push(part);
|
|
6642
|
+
}
|
|
6643
|
+
return parts;
|
|
6644
|
+
};
|
|
6645
|
+
const messageToolCalls = (message) => {
|
|
6646
|
+
if (Array.isArray(message?.tool_calls) && message.tool_calls.length > 0) return message.tool_calls;
|
|
6647
|
+
return message?.additional_kwargs?.tool_calls;
|
|
6648
|
+
};
|
|
6649
|
+
const messageToDict = (message) => {
|
|
6650
|
+
const role = messageRole(messageType(message));
|
|
6651
|
+
const toolCallId = message?.tool_call_id;
|
|
6652
|
+
if (role === "tool" && toolCallId) return {
|
|
6653
|
+
role,
|
|
6654
|
+
parts: [{
|
|
6655
|
+
type: "tool_call_response",
|
|
6656
|
+
id: toolCallId,
|
|
6657
|
+
response: message.content
|
|
6658
|
+
}]
|
|
6659
|
+
};
|
|
6660
|
+
const parts = [...contentToParts(message?.content), ...toolCallsToParts(messageToolCalls(message))];
|
|
6661
|
+
const functionCall = message?.additional_kwargs?.function_call;
|
|
6662
|
+
if (isRecord(functionCall)) parts.push({
|
|
6663
|
+
type: "tool_call",
|
|
6664
|
+
id: "",
|
|
6665
|
+
name: functionCall.name || "",
|
|
6666
|
+
arguments: maybeJson(functionCall.arguments)
|
|
6667
|
+
});
|
|
6668
|
+
return {
|
|
6669
|
+
role,
|
|
6670
|
+
parts
|
|
6671
|
+
};
|
|
6672
|
+
};
|
|
6673
|
+
const firstModel = (...sources) => {
|
|
6674
|
+
for (const source of sources) for (const key of MODEL_KEYS) {
|
|
6675
|
+
const model = source[key];
|
|
6676
|
+
if (typeof model === "string" && model) return model;
|
|
6677
|
+
}
|
|
6678
|
+
};
|
|
6679
|
+
/**
|
|
6680
|
+
* Record the request model and sampling params. Returns the request model.
|
|
6681
|
+
*/
|
|
6682
|
+
const setRequestAttributes$3 = (span, serialized, metadata, extraParams, traceContent) => {
|
|
6683
|
+
const invocationParams = asRecord(extraParams?.invocation_params);
|
|
6684
|
+
const nested = asRecord(invocationParams.params);
|
|
6685
|
+
const params = Object.keys(nested).length > 0 ? nested : invocationParams;
|
|
6686
|
+
const serializedKwargs = asRecord(serialized?.kwargs);
|
|
6687
|
+
let model = firstModel(params, invocationParams, serializedKwargs);
|
|
6688
|
+
if (model === void 0) {
|
|
6689
|
+
const lsModelName = metadata?.ls_model_name;
|
|
6690
|
+
model = typeof lsModelName === "string" && lsModelName ? lsModelName : void 0;
|
|
6691
|
+
}
|
|
6692
|
+
setIfPresent(span, "gen_ai.request.model", model);
|
|
6693
|
+
const param = (...keys) => {
|
|
6694
|
+
for (const source of [params, serializedKwargs]) for (const key of keys) if (source[key] !== void 0 && source[key] !== null) return source[key];
|
|
6695
|
+
};
|
|
6696
|
+
const maxTokens = param("max_tokens", "max_completion_tokens", "max_new_tokens", "maxTokens");
|
|
6697
|
+
const temperature = param("temperature");
|
|
6698
|
+
const topP = param("top_p", "topP");
|
|
6699
|
+
if (isInt(maxTokens)) span.setAttribute("gen_ai.request.max_tokens", maxTokens);
|
|
6700
|
+
if (typeof temperature === "number") span.setAttribute("gen_ai.request.temperature", temperature);
|
|
6701
|
+
if (typeof topP === "number") span.setAttribute("gen_ai.request.top_p", topP);
|
|
6702
|
+
const tools = params.tools || params.functions;
|
|
6703
|
+
if (traceContent && Array.isArray(tools) && tools.length > 0) {
|
|
6704
|
+
const definitions = tools.map((tool) => {
|
|
6705
|
+
const record = asRecord(tool);
|
|
6706
|
+
const fn = isRecord(record.function) ? record.function : record;
|
|
6707
|
+
const definition = { name: fn.name };
|
|
6708
|
+
if (fn.description) definition.description = fn.description;
|
|
6709
|
+
const parameters = fn.parameters || record.input_schema;
|
|
6710
|
+
if (parameters) definition.parameters = parameters;
|
|
6711
|
+
return definition;
|
|
6712
|
+
});
|
|
6713
|
+
span.setAttribute("gen_ai.tool.definitions", toJson$1(definitions));
|
|
6714
|
+
}
|
|
6715
|
+
return model;
|
|
6716
|
+
};
|
|
6717
|
+
const setChatRequest$1 = (span, messages, traceContent) => {
|
|
6718
|
+
if (!traceContent) return;
|
|
6719
|
+
const inputMessages = (messages ?? []).flatMap((batch) => (batch ?? []).map(messageToDict));
|
|
6720
|
+
if (inputMessages.length > 0) span.setAttribute(INPUT_MESSAGES$1, toJson$1(inputMessages));
|
|
6721
|
+
};
|
|
6722
|
+
const setCompletionRequest$1 = (span, prompts, traceContent) => {
|
|
6723
|
+
if (!traceContent) return;
|
|
6724
|
+
const inputMessages = (prompts ?? []).map((prompt) => ({
|
|
6725
|
+
role: "user",
|
|
6726
|
+
parts: [{
|
|
6727
|
+
type: "text",
|
|
6728
|
+
content: prompt
|
|
6729
|
+
}]
|
|
6730
|
+
}));
|
|
6731
|
+
if (inputMessages.length > 0) span.setAttribute(INPUT_MESSAGES$1, toJson$1(inputMessages));
|
|
6732
|
+
};
|
|
6733
|
+
const allGenerations = (response) => Array.isArray(response?.generations) ? response.generations.flatMap((batch) => Array.isArray(batch) ? batch : []) : [];
|
|
6734
|
+
const setUsage = (span, response) => {
|
|
6735
|
+
let inputTokens = 0;
|
|
6736
|
+
let outputTokens = 0;
|
|
6737
|
+
let cacheReadTokens;
|
|
6738
|
+
let cacheCreationTokens;
|
|
6739
|
+
let found = false;
|
|
6740
|
+
for (const generation of allGenerations(response)) {
|
|
6741
|
+
const usage = asRecord(generation?.message?.usage_metadata);
|
|
6742
|
+
if (Object.keys(usage).length === 0) continue;
|
|
6743
|
+
found = true;
|
|
6744
|
+
inputTokens += isInt(usage.input_tokens) ? usage.input_tokens : 0;
|
|
6745
|
+
outputTokens += isInt(usage.output_tokens) ? usage.output_tokens : 0;
|
|
6746
|
+
const details = asRecord(usage.input_token_details);
|
|
6747
|
+
if (isInt(details.cache_read)) cacheReadTokens = (cacheReadTokens ?? 0) + details.cache_read;
|
|
6748
|
+
if (isInt(details.cache_creation)) cacheCreationTokens = (cacheCreationTokens ?? 0) + details.cache_creation;
|
|
6749
|
+
}
|
|
6750
|
+
if (!found) {
|
|
6751
|
+
const llmOutput = asRecord(response?.llmOutput);
|
|
6752
|
+
const tokenUsage = asRecord(llmOutput.tokenUsage ?? llmOutput.token_usage ?? llmOutput.usage);
|
|
6753
|
+
if (Object.keys(tokenUsage).length === 0) return;
|
|
6754
|
+
const pick = (...keys) => {
|
|
6755
|
+
for (const key of keys) if (isInt(tokenUsage[key]) && tokenUsage[key] !== 0) return tokenUsage[key];
|
|
6756
|
+
return 0;
|
|
6757
|
+
};
|
|
6758
|
+
inputTokens = pick("promptTokens", "prompt_tokens", "input_tokens", "input_token_count");
|
|
6759
|
+
outputTokens = pick("completionTokens", "completion_tokens", "output_tokens", "generated_token_count");
|
|
6760
|
+
}
|
|
6761
|
+
span.setAttribute("gen_ai.usage.input_tokens", inputTokens);
|
|
6762
|
+
span.setAttribute("gen_ai.usage.output_tokens", outputTokens);
|
|
6763
|
+
span.setAttribute("llm.usage.total_tokens", inputTokens + outputTokens);
|
|
6764
|
+
setIfPresent(span, "gen_ai.usage.cache_read_input_tokens", cacheReadTokens);
|
|
6765
|
+
setIfPresent(span, "gen_ai.usage.cache_creation_input_tokens", cacheCreationTokens);
|
|
6766
|
+
};
|
|
6767
|
+
const responseModelAndId = (response) => {
|
|
6768
|
+
const llmOutput = asRecord(response?.llmOutput);
|
|
6769
|
+
let model = firstModel(llmOutput);
|
|
6770
|
+
let id = llmOutput.id;
|
|
6771
|
+
for (const generation of allGenerations(response)) {
|
|
6772
|
+
const message = generation?.message;
|
|
6773
|
+
if (model === void 0) model = firstModel(asRecord(message?.response_metadata));
|
|
6774
|
+
if (id === void 0 || id === null) id = message?.id;
|
|
6775
|
+
}
|
|
6776
|
+
return {
|
|
6777
|
+
model,
|
|
6778
|
+
id: typeof id === "string" && id ? id : void 0
|
|
6779
|
+
};
|
|
6780
|
+
};
|
|
6781
|
+
const finishReasonOf = (generation) => {
|
|
6782
|
+
const info = asRecord(generation?.generationInfo);
|
|
6783
|
+
const metadata = asRecord(generation?.message?.response_metadata);
|
|
6784
|
+
const raw = info.finish_reason || info.stop_reason || metadata.finish_reason || metadata.stop_reason;
|
|
6785
|
+
return typeof raw === "string" ? FINISH_REASON_MAP[raw] ?? raw : void 0;
|
|
6786
|
+
};
|
|
6787
|
+
const setResponseAttributes$3 = (span, response, requestModel, traceContent) => {
|
|
6788
|
+
const { model, id } = responseModelAndId(response);
|
|
6789
|
+
setIfPresent(span, "gen_ai.response.model", model ?? requestModel);
|
|
6790
|
+
if (requestModel === void 0) setIfPresent(span, "gen_ai.request.model", model);
|
|
6791
|
+
setIfPresent(span, "gen_ai.response.id", id);
|
|
6792
|
+
setUsage(span, response);
|
|
6793
|
+
const outputMessages = [];
|
|
6794
|
+
const finishReasons = [];
|
|
6795
|
+
for (const generation of allGenerations(response)) {
|
|
6796
|
+
const finishReason = finishReasonOf(generation);
|
|
6797
|
+
if (finishReason && !finishReasons.includes(finishReason)) finishReasons.push(finishReason);
|
|
6798
|
+
if (!traceContent) continue;
|
|
6799
|
+
const message = generation?.message;
|
|
6800
|
+
const outputMessage = message && typeof message === "object" ? messageToDict(message) : {
|
|
6801
|
+
role: "assistant",
|
|
6802
|
+
parts: contentToParts(generation?.text)
|
|
6803
|
+
};
|
|
6804
|
+
outputMessage.finish_reason = finishReason ?? "";
|
|
6805
|
+
outputMessages.push(outputMessage);
|
|
6806
|
+
}
|
|
6807
|
+
if (finishReasons.length > 0) span.setAttribute("gen_ai.response.finish_reasons", finishReasons);
|
|
6808
|
+
if (outputMessages.length > 0) span.setAttribute(OUTPUT_MESSAGES$1, toJson$1(outputMessages));
|
|
6809
|
+
};
|
|
6810
|
+
/**
|
|
6811
|
+
* Return plain-data metadata as is, or undefined for anything else.
|
|
6812
|
+
*
|
|
6813
|
+
* Class instances are dropped rather than stringified: a model, client or
|
|
6814
|
+
* config object routinely carries credentials the caller never meant to
|
|
6815
|
+
* export.
|
|
6816
|
+
*/
|
|
6817
|
+
const metadataValue = (value) => {
|
|
6818
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
6819
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? void 0 : value.toISOString();
|
|
6820
|
+
if (Array.isArray(value)) return value.map(metadataValue).filter((item) => item !== void 0);
|
|
6821
|
+
if (isRecord(value)) {
|
|
6822
|
+
const proto = Object.getPrototypeOf(value);
|
|
6823
|
+
if (proto !== Object.prototype && proto !== null) return void 0;
|
|
6824
|
+
const kept = Object.fromEntries(Object.entries(value).map(([key, item]) => [key, metadataValue(item)]).filter(([, item]) => item !== void 0));
|
|
6825
|
+
return Object.keys(kept).length > 0 ? kept : void 0;
|
|
6826
|
+
}
|
|
6827
|
+
};
|
|
6828
|
+
const sanitizeMetadata = (metadata) => {
|
|
6829
|
+
if (!isRecord(metadata)) return {};
|
|
6830
|
+
return Object.fromEntries(Object.entries(metadata).map(([key, value]) => [key, metadataValue(value)]).filter(([, value]) => value !== void 0));
|
|
6831
|
+
};
|
|
6832
|
+
const retrieverOutput = (documents) => {
|
|
6833
|
+
if (!Array.isArray(documents)) return [];
|
|
6834
|
+
return documents.map((document) => {
|
|
6835
|
+
const pageContent = document?.pageContent ?? document?.page_content;
|
|
6836
|
+
if (pageContent === void 0 || pageContent === null) return document;
|
|
6837
|
+
return {
|
|
6838
|
+
page_content: pageContent,
|
|
6839
|
+
metadata: document?.metadata ?? {}
|
|
6840
|
+
};
|
|
6841
|
+
});
|
|
6842
|
+
};
|
|
6843
|
+
//#endregion
|
|
6844
|
+
//#region src/opentelemetry-lib/instrumentation/langchain/vendor-detection.ts
|
|
6845
|
+
const DEFAULT_VENDOR = "langchain";
|
|
6846
|
+
/**
|
|
6847
|
+
* Lower-cased class-name substrings → `gen_ai.system` vendor, in priority
|
|
6848
|
+
* order (`AzureChatOpenAI` must match azure before openai).
|
|
6849
|
+
*/
|
|
6850
|
+
const VENDOR_RULES = [
|
|
6851
|
+
[["azure"], "azure.ai.openai"],
|
|
6852
|
+
[["openai"], "openai"],
|
|
6853
|
+
[["bedrock", "aws"], "aws.bedrock"],
|
|
6854
|
+
[["anthropic"], "anthropic"],
|
|
6855
|
+
[["vertex"], "gcp.vertex_ai"],
|
|
6856
|
+
[["google", "gemini"], "gcp.gen_ai"],
|
|
6857
|
+
[["cohere"], "cohere"],
|
|
6858
|
+
[["huggingface"], "hugging_face"],
|
|
6859
|
+
[["ollama"], "ollama"],
|
|
6860
|
+
[["together"], "together_ai"],
|
|
6861
|
+
[["replicate"], "replicate"],
|
|
6862
|
+
[["fireworks"], "fireworks"],
|
|
6863
|
+
[["groq"], "groq"],
|
|
6864
|
+
[["mistral"], "mistral_ai"]
|
|
6865
|
+
];
|
|
6866
|
+
/**
|
|
6867
|
+
* Map a LangChain model class name (e.g. `ChatOpenAI`) onto the
|
|
6868
|
+
* `gen_ai.system` vendor string, or `"langchain"` when unknown.
|
|
6869
|
+
*/
|
|
6870
|
+
const detectVendorFromClass = (className) => {
|
|
6871
|
+
if (!className) return DEFAULT_VENDOR;
|
|
6872
|
+
const lower = className.toLowerCase();
|
|
6873
|
+
for (const [patterns, vendor] of VENDOR_RULES) if (patterns.some((pattern) => lower.includes(pattern))) return vendor;
|
|
6874
|
+
return DEFAULT_VENDOR;
|
|
6875
|
+
};
|
|
6876
|
+
//#endregion
|
|
6877
|
+
//#region src/opentelemetry-lib/instrumentation/langchain/callback-handler.ts
|
|
6878
|
+
const logger$18 = initializeLogger();
|
|
6879
|
+
const HANDLER_NAME = "laminar_callback_handler";
|
|
6880
|
+
/**
|
|
6881
|
+
* Callback handlers must never break the user's chain.
|
|
6882
|
+
*/
|
|
6883
|
+
const dontThrow = (fn) => {
|
|
6884
|
+
try {
|
|
6885
|
+
fn();
|
|
6886
|
+
} catch (error) {
|
|
6887
|
+
logger$18.debug(`Failed to record LangChain run: ${String(error)}`);
|
|
6888
|
+
}
|
|
6889
|
+
};
|
|
6890
|
+
const className = (serialized) => {
|
|
6891
|
+
const id = serialized?.id;
|
|
6892
|
+
if (Array.isArray(id) && id.length > 0) return String(id[id.length - 1]);
|
|
6893
|
+
return typeof id === "string" ? id : "";
|
|
6894
|
+
};
|
|
6895
|
+
const runNameOf = (serialized, runName) => {
|
|
6896
|
+
for (const name of [
|
|
6897
|
+
runName,
|
|
6898
|
+
serialized?.kwargs?.name,
|
|
6899
|
+
serialized?.name
|
|
6900
|
+
]) if (typeof name === "string" && name) return name;
|
|
6901
|
+
return className(serialized) || "unknown";
|
|
6902
|
+
};
|
|
6903
|
+
/**
|
|
6904
|
+
* LangGraph's `configurable.thread_id`, the conversation id.
|
|
6905
|
+
*/
|
|
6906
|
+
const threadIdOf = (metadata, extra) => {
|
|
6907
|
+
const threadId = metadata?.thread_id ?? extra?.config?.configurable?.thread_id;
|
|
6908
|
+
return threadId === void 0 || threadId === null ? void 0 : String(threadId);
|
|
6909
|
+
};
|
|
6910
|
+
/**
|
|
6911
|
+
* Drop what only applies to the context a callback fired in (an open LLM
|
|
6912
|
+
* call's marker and its suppression) before parenting a new run from it.
|
|
6913
|
+
*/
|
|
6914
|
+
const cleanContext = (ctx) => unsuppressTracing(ctx).deleteValue(LLM_CALL_KEY);
|
|
6915
|
+
/**
|
|
6916
|
+
* Records LangChain runs as Laminar spans.
|
|
6917
|
+
*
|
|
6918
|
+
* A single instance is injected into every LangChain `CallbackManager`, so all
|
|
6919
|
+
* state is keyed by LangChain's `runId`. Callbacks only start and end spans:
|
|
6920
|
+
* JavaScript callbacks cannot change the context of the code they observe, so
|
|
6921
|
+
* the instrumentation wrappers read `contextFor(runId)` to run user code (a
|
|
6922
|
+
* lambda, a tool, a graph node) and provider SDK calls under the right span.
|
|
6923
|
+
*
|
|
6924
|
+
* Duck-types LangChain's `BaseCallbackHandler` (`name`, `awaitHandlers`,
|
|
6925
|
+
* `copy`), as `@langchain/core` is not a runtime dependency of this package.
|
|
6926
|
+
*/
|
|
6927
|
+
var LaminarCallbackHandler = class {
|
|
6928
|
+
constructor(traceContent) {
|
|
6929
|
+
this.name = HANDLER_NAME;
|
|
6930
|
+
this.awaitHandlers = true;
|
|
6931
|
+
this.raiseError = false;
|
|
6932
|
+
this.ignoreLLM = false;
|
|
6933
|
+
this.ignoreChain = false;
|
|
6934
|
+
this.ignoreAgent = false;
|
|
6935
|
+
this.ignoreRetriever = false;
|
|
6936
|
+
this.ignoreCustomEvent = true;
|
|
6937
|
+
this.lc_serializable = false;
|
|
6938
|
+
this.takeTopology = () => void 0;
|
|
6939
|
+
this.runs = /* @__PURE__ */ new Map();
|
|
6940
|
+
this.handedOff = /* @__PURE__ */ new Map();
|
|
6941
|
+
this.traceContent = traceContent;
|
|
6942
|
+
}
|
|
6943
|
+
copy() {
|
|
6944
|
+
return this;
|
|
6945
|
+
}
|
|
6946
|
+
/**
|
|
6947
|
+
* Context of an open run (or of a handed-off LLM run's parent), for code
|
|
6948
|
+
* that runs under it.
|
|
6949
|
+
*/
|
|
6950
|
+
contextFor(runId) {
|
|
6951
|
+
if (!runId) return void 0;
|
|
6952
|
+
return this.runs.get(runId)?.context ?? this.handedOff.get(runId)?.context;
|
|
6953
|
+
}
|
|
6954
|
+
handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, _runType, runName, extra) {
|
|
6955
|
+
dontThrow(() => {
|
|
6956
|
+
const name = runNameOf(chain, runName);
|
|
6957
|
+
const isRoot = !parentRunId || !this.runs.has(parentRunId) && !this.handedOff.has(parentRunId);
|
|
6958
|
+
const attributes = {};
|
|
6959
|
+
let spanName;
|
|
6960
|
+
if (isRoot) {
|
|
6961
|
+
spanName = `${name}.workflow`;
|
|
6962
|
+
attributes["gen_ai.operation.name"] = "invoke_agent";
|
|
6963
|
+
attributes["gen_ai.agent.name"] = name;
|
|
6964
|
+
attributes["gen_ai.agent.id"] = String(runId);
|
|
6965
|
+
} else {
|
|
6966
|
+
spanName = `execute_task ${name}`;
|
|
6967
|
+
attributes["gen_ai.operation.name"] = "execute_task";
|
|
6968
|
+
}
|
|
6969
|
+
const threadId = threadIdOf(metadata, extra);
|
|
6970
|
+
if (threadId) attributes["gen_ai.conversation.id"] = threadId;
|
|
6971
|
+
const topology = this.takeTopology();
|
|
6972
|
+
if (topology && isRoot) for (const [key, value] of Object.entries(topology)) attributes[`lmnr.association.properties.${key}`] = value;
|
|
6973
|
+
const span = this.startRun(runId, parentRunId, spanName, {
|
|
6974
|
+
attributes,
|
|
6975
|
+
tags,
|
|
6976
|
+
metadata
|
|
6977
|
+
});
|
|
6978
|
+
if (span && this.traceContent) span.setInput(toJson$1(inputs));
|
|
6979
|
+
});
|
|
6980
|
+
}
|
|
6981
|
+
handleChainEnd(outputs, runId) {
|
|
6982
|
+
dontThrow(() => {
|
|
6983
|
+
try {
|
|
6984
|
+
this.setOutput(runId, outputs);
|
|
6985
|
+
} finally {
|
|
6986
|
+
this.endRun(runId);
|
|
6987
|
+
}
|
|
6988
|
+
});
|
|
6989
|
+
}
|
|
6990
|
+
handleChainError(error, runId) {
|
|
6991
|
+
dontThrow(() => this.handleError(error, runId));
|
|
6992
|
+
}
|
|
6993
|
+
handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
6994
|
+
dontThrow(() => this.startLlm(llm, messages, "chat", runId, parentRunId, {
|
|
6995
|
+
extraParams,
|
|
6996
|
+
tags,
|
|
6997
|
+
metadata,
|
|
6998
|
+
runName
|
|
6999
|
+
}));
|
|
7000
|
+
}
|
|
7001
|
+
handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
7002
|
+
dontThrow(() => this.startLlm(llm, prompts, "text_completion", runId, parentRunId, {
|
|
7003
|
+
extraParams,
|
|
7004
|
+
tags,
|
|
7005
|
+
metadata,
|
|
7006
|
+
runName
|
|
7007
|
+
}));
|
|
7008
|
+
}
|
|
7009
|
+
handleLLMEnd(output, runId) {
|
|
7010
|
+
dontThrow(() => {
|
|
7011
|
+
try {
|
|
7012
|
+
const run = this.runs.get(runId);
|
|
7013
|
+
if (run) setResponseAttributes$3(run.span, output, run.requestModel, this.traceContent);
|
|
7014
|
+
else this.recordUnrecordedHandoff(runId, (span, requestModel) => setResponseAttributes$3(span, output, requestModel, this.traceContent));
|
|
7015
|
+
} finally {
|
|
7016
|
+
this.endRun(runId);
|
|
7017
|
+
}
|
|
7018
|
+
});
|
|
7019
|
+
}
|
|
7020
|
+
handleLLMError(error, runId) {
|
|
7021
|
+
dontThrow(() => this.handleError(error, runId));
|
|
7022
|
+
}
|
|
7023
|
+
handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName, toolCallId) {
|
|
7024
|
+
dontThrow(() => {
|
|
7025
|
+
const name = runNameOf(tool, runName);
|
|
7026
|
+
const attributes = {
|
|
7027
|
+
"gen_ai.operation.name": "execute_tool",
|
|
7028
|
+
"gen_ai.tool.name": name,
|
|
7029
|
+
"gen_ai.tool.type": "function"
|
|
7030
|
+
};
|
|
7031
|
+
const description = tool?.description ?? tool?.kwargs?.description;
|
|
7032
|
+
if (typeof description === "string" && description) attributes["gen_ai.tool.description"] = description;
|
|
7033
|
+
if (typeof toolCallId === "string" && toolCallId) attributes["gen_ai.tool.call.id"] = toolCallId;
|
|
7034
|
+
const span = this.startRun(runId, parentRunId, `execute_tool ${name}`, {
|
|
7035
|
+
spanType: "TOOL",
|
|
7036
|
+
attributes,
|
|
7037
|
+
tags,
|
|
7038
|
+
metadata
|
|
7039
|
+
});
|
|
7040
|
+
if (span && this.traceContent) span.setInput(toJson$1(parseJsonObject(input)));
|
|
7041
|
+
});
|
|
7042
|
+
}
|
|
7043
|
+
handleToolEnd(output, runId) {
|
|
7044
|
+
dontThrow(() => {
|
|
7045
|
+
try {
|
|
7046
|
+
this.setOutput(runId, output);
|
|
7047
|
+
} finally {
|
|
7048
|
+
this.endRun(runId);
|
|
7049
|
+
}
|
|
7050
|
+
});
|
|
7051
|
+
}
|
|
7052
|
+
handleToolError(error, runId) {
|
|
7053
|
+
dontThrow(() => this.handleError(error, runId));
|
|
7054
|
+
}
|
|
7055
|
+
handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, runName) {
|
|
7056
|
+
dontThrow(() => {
|
|
7057
|
+
const name = runNameOf(retriever, runName);
|
|
7058
|
+
const span = this.startRun(runId, parentRunId, `vector_db_retrieve ${name}`, {
|
|
7059
|
+
attributes: { "gen_ai.operation.name": "vector_db_retrieve" },
|
|
7060
|
+
tags,
|
|
7061
|
+
metadata
|
|
7062
|
+
});
|
|
7063
|
+
if (span && this.traceContent) span.setInput(toJson$1(query));
|
|
7064
|
+
});
|
|
7065
|
+
}
|
|
7066
|
+
handleRetrieverEnd(documents, runId) {
|
|
7067
|
+
dontThrow(() => {
|
|
7068
|
+
try {
|
|
7069
|
+
this.setOutput(runId, retrieverOutput(documents));
|
|
7070
|
+
} finally {
|
|
7071
|
+
this.endRun(runId);
|
|
7072
|
+
}
|
|
7073
|
+
});
|
|
7074
|
+
}
|
|
7075
|
+
handleRetrieverError(error, runId) {
|
|
7076
|
+
dontThrow(() => this.handleError(error, runId));
|
|
7077
|
+
}
|
|
7078
|
+
parentContext(parentRunId) {
|
|
7079
|
+
return cleanContext(this.contextFor(parentRunId) ?? LaminarContextManager.getContext());
|
|
7080
|
+
}
|
|
7081
|
+
startRun(runId, parentRunId, name, { spanType = "DEFAULT", attributes, tags, metadata, startTime }) {
|
|
7082
|
+
const active = context.active();
|
|
7083
|
+
if (isTracingSuppressed(active) && active.getValue(LLM_CALL_KEY)?.mode !== "own") return;
|
|
7084
|
+
const parentContext = this.parentContext(parentRunId);
|
|
7085
|
+
const span = this.startSpan(name, spanType, parentContext, {
|
|
7086
|
+
attributes,
|
|
7087
|
+
tags,
|
|
7088
|
+
metadata,
|
|
7089
|
+
startTime
|
|
7090
|
+
});
|
|
7091
|
+
const run = {
|
|
7092
|
+
span,
|
|
7093
|
+
context: trace.setSpan(LaminarContextManager.setAssociationProperties(span, parentContext), span),
|
|
7094
|
+
children: []
|
|
7095
|
+
};
|
|
7096
|
+
if (parentRunId) this.runs.get(parentRunId)?.children.push(runId);
|
|
7097
|
+
const stale = this.runs.get(runId);
|
|
7098
|
+
if (stale) {
|
|
7099
|
+
this.runs.delete(runId);
|
|
7100
|
+
stale.span.end();
|
|
7101
|
+
}
|
|
7102
|
+
this.runs.set(runId, run);
|
|
7103
|
+
return span;
|
|
7104
|
+
}
|
|
7105
|
+
startSpan(name, spanType, parentContext, { attributes, tags, metadata, startTime }) {
|
|
7106
|
+
const span = Laminar.startSpan({
|
|
7107
|
+
name,
|
|
7108
|
+
spanType,
|
|
7109
|
+
context: parentContext,
|
|
7110
|
+
startTime
|
|
7111
|
+
});
|
|
7112
|
+
if (attributes) span.setAttributes(attributes);
|
|
7113
|
+
if (tags && tags.length > 0) span.setAttribute("langchain.tags", tags);
|
|
7114
|
+
const sanitized = sanitizeMetadata(metadata);
|
|
7115
|
+
if (Object.keys(sanitized).length > 0) span.setAttribute("langchain.metadata", toJson$1(sanitized));
|
|
7116
|
+
return span;
|
|
7117
|
+
}
|
|
7118
|
+
startLlm(llm, input, operation, runId, parentRunId, { extraParams, tags, metadata, runName }) {
|
|
7119
|
+
const name = runNameOf(llm, runName);
|
|
7120
|
+
const call = context.active().getValue(LLM_CALL_KEY);
|
|
7121
|
+
if (call?.mode === "handoff") {
|
|
7122
|
+
this.handedOff.set(runId, {
|
|
7123
|
+
context: this.parentContext(parentRunId),
|
|
7124
|
+
call,
|
|
7125
|
+
name,
|
|
7126
|
+
operation,
|
|
7127
|
+
serialized: llm,
|
|
7128
|
+
input,
|
|
7129
|
+
extraParams,
|
|
7130
|
+
tags,
|
|
7131
|
+
metadata,
|
|
7132
|
+
startTime: hrTime()
|
|
7133
|
+
});
|
|
7134
|
+
if (parentRunId) this.runs.get(parentRunId)?.children.push(runId);
|
|
7135
|
+
return;
|
|
7136
|
+
}
|
|
7137
|
+
const span = this.startRun(runId, parentRunId, llmSpanName(name, operation), {
|
|
7138
|
+
spanType: "LLM",
|
|
7139
|
+
attributes: llmAttributes(llm, operation),
|
|
7140
|
+
tags,
|
|
7141
|
+
metadata
|
|
7142
|
+
});
|
|
7143
|
+
if (!span) return;
|
|
7144
|
+
const run = this.runs.get(runId);
|
|
7145
|
+
run.requestModel = this.setLlmRequest(span, {
|
|
7146
|
+
serialized: llm,
|
|
7147
|
+
input,
|
|
7148
|
+
operation,
|
|
7149
|
+
extraParams,
|
|
7150
|
+
metadata
|
|
7151
|
+
});
|
|
7152
|
+
}
|
|
7153
|
+
setLlmRequest(span, { serialized, input, operation, extraParams, metadata }) {
|
|
7154
|
+
const requestModel = setRequestAttributes$3(span, serialized, metadata, extraParams, this.traceContent);
|
|
7155
|
+
if (operation === "chat") setChatRequest$1(span, input, this.traceContent);
|
|
7156
|
+
else setCompletionRequest$1(span, input, this.traceContent);
|
|
7157
|
+
return requestModel;
|
|
7158
|
+
}
|
|
7159
|
+
/**
|
|
7160
|
+
* A handed-off LLM run whose provider instrumentation did not record the
|
|
7161
|
+
* call (it is disabled, or the integration bundles its own copy of the
|
|
7162
|
+
* provider SDK) gets its LangChain span after all, spanning the run.
|
|
7163
|
+
*/
|
|
7164
|
+
recordUnrecordedHandoff(runId, finish) {
|
|
7165
|
+
const pending = this.handedOff.get(runId);
|
|
7166
|
+
if (!pending || pending.call.recorded) return;
|
|
7167
|
+
const span = this.startSpan(llmSpanName(pending.name, pending.operation), "LLM", pending.context, {
|
|
7168
|
+
attributes: llmAttributes(pending.serialized, pending.operation),
|
|
7169
|
+
tags: pending.tags,
|
|
7170
|
+
metadata: pending.metadata,
|
|
7171
|
+
startTime: pending.startTime
|
|
7172
|
+
});
|
|
7173
|
+
try {
|
|
7174
|
+
finish(span, this.setLlmRequest(span, pending));
|
|
7175
|
+
} finally {
|
|
7176
|
+
span.end();
|
|
7177
|
+
}
|
|
7178
|
+
}
|
|
7179
|
+
setOutput(runId, output) {
|
|
7180
|
+
const run = this.runs.get(runId);
|
|
7181
|
+
if (run && this.traceContent) run.span.setOutput(toJson$1(output));
|
|
7182
|
+
}
|
|
7183
|
+
handleError(error, runId) {
|
|
7184
|
+
const run = this.runs.get(runId);
|
|
7185
|
+
if (!run) {
|
|
7186
|
+
try {
|
|
7187
|
+
this.recordUnrecordedHandoff(runId, (span) => markError(span, error));
|
|
7188
|
+
} finally {
|
|
7189
|
+
this.handedOff.delete(runId);
|
|
7190
|
+
}
|
|
7191
|
+
return;
|
|
7192
|
+
}
|
|
7193
|
+
try {
|
|
7194
|
+
markError(run.span, error);
|
|
7195
|
+
} finally {
|
|
7196
|
+
this.endRun(runId);
|
|
7197
|
+
}
|
|
7198
|
+
}
|
|
7199
|
+
endRun(runId) {
|
|
7200
|
+
this.handedOff.delete(runId);
|
|
7201
|
+
const run = this.runs.get(runId);
|
|
7202
|
+
if (!run) return;
|
|
7203
|
+
this.runs.delete(runId);
|
|
7204
|
+
for (const childId of run.children) this.endRun(childId);
|
|
7205
|
+
run.span.end();
|
|
7206
|
+
}
|
|
7207
|
+
};
|
|
7208
|
+
const llmSpanName = (name, operation) => `${name}.${operation === "chat" ? "chat" : "completion"}`;
|
|
7209
|
+
const llmAttributes = (serialized, operation) => {
|
|
7210
|
+
const vendor = detectVendorFromClass(className(serialized));
|
|
7211
|
+
return {
|
|
7212
|
+
"gen_ai.operation.name": operation,
|
|
7213
|
+
"gen_ai.system": vendor,
|
|
7214
|
+
"gen_ai.provider.name": vendor
|
|
7215
|
+
};
|
|
7216
|
+
};
|
|
7217
|
+
const markError = (span, error) => {
|
|
7218
|
+
span.setAttribute("error.type", error?.constructor?.name ?? "Error");
|
|
7219
|
+
span.recordException(error);
|
|
7220
|
+
span.setStatus({
|
|
7221
|
+
code: SpanStatusCode.ERROR,
|
|
7222
|
+
message: error?.message ?? String(error)
|
|
7223
|
+
});
|
|
7224
|
+
};
|
|
7225
|
+
const parseJsonObject = (input) => {
|
|
7226
|
+
if (typeof input !== "string") return input;
|
|
7227
|
+
try {
|
|
7228
|
+
const parsed = JSON.parse(input);
|
|
7229
|
+
return parsed !== null && typeof parsed === "object" ? parsed : input;
|
|
7230
|
+
} catch {
|
|
7231
|
+
return input;
|
|
7232
|
+
}
|
|
7233
|
+
};
|
|
7234
|
+
//#endregion
|
|
7235
|
+
//#region src/opentelemetry-lib/instrumentation/langchain/index.ts
|
|
7236
|
+
const logger$17 = initializeLogger();
|
|
7237
|
+
const PATCH_DATA_SYMBOL$1 = Symbol("lmnr.langchain.patchData");
|
|
7238
|
+
const hasOwnPatchData$1 = (target) => Object.getOwnPropertyDescriptor(target, PATCH_DATA_SYMBOL$1) !== void 0;
|
|
7239
|
+
/**
|
|
7240
|
+
* Model classes whose provider SDK Laminar instruments itself (`_llmType()`).
|
|
7241
|
+
* Their LLM calls are handed off: the provider span is the LLM span, with the
|
|
7242
|
+
* provider-specific attributes, and LangChain opens none of its own.
|
|
7243
|
+
*/
|
|
7244
|
+
const HANDOFF_LLM_TYPES = /* @__PURE__ */ new Set([
|
|
7245
|
+
"openai",
|
|
7246
|
+
"azure_openai",
|
|
7247
|
+
"anthropic"
|
|
7248
|
+
]);
|
|
7249
|
+
/**
|
|
7250
|
+
* The single handler injected into every LangChain `CallbackManager`. All its
|
|
7251
|
+
* state is keyed by LangChain run id, so it is shared by every instrumentation
|
|
7252
|
+
* instance (auto and manual) and patched module copy.
|
|
7253
|
+
*/
|
|
7254
|
+
const handler = new LaminarCallbackHandler(true);
|
|
7255
|
+
const topologyStorage = new AsyncLocalStorage$1();
|
|
7256
|
+
handler.takeTopology = () => {
|
|
7257
|
+
const holder = topologyStorage.getStore();
|
|
7258
|
+
const topology = holder?.topology;
|
|
7259
|
+
if (holder) holder.topology = void 0;
|
|
7260
|
+
return topology;
|
|
7261
|
+
};
|
|
7262
|
+
/**
|
|
7263
|
+
* Run `fn` with `ctx` current in both the OTel context (read by OTel-aware
|
|
7264
|
+
* code) and Laminar's context stack (read by `Laminar.startSpan` and
|
|
7265
|
+
* Laminar's own provider instrumentations).
|
|
7266
|
+
*/
|
|
7267
|
+
const runUnder = (ctx, fn) => context.with(ctx, () => LaminarContextManager.runWithIsolatedContext([...LaminarContextManager.getContextStack(), ctx], fn));
|
|
7268
|
+
/**
|
|
7269
|
+
* Wrap an async iterator so each step runs through `run`.
|
|
7270
|
+
* `AsyncLocalStorage.run` and `context.with` only cover the synchronous part
|
|
7271
|
+
* of the call, so every `next` / `return` / `throw` needs its own.
|
|
7272
|
+
*/
|
|
7273
|
+
const wrapIterator = (iterator, run) => ({
|
|
7274
|
+
next: (...args) => run(() => iterator.next(...args)),
|
|
7275
|
+
return: (value) => run(() => typeof iterator.return === "function" ? iterator.return(value) : Promise.resolve({
|
|
7276
|
+
done: true,
|
|
7277
|
+
value
|
|
7278
|
+
})),
|
|
7279
|
+
throw: (error) => run(() => typeof iterator.throw === "function" ? iterator.throw(error) : Promise.reject(error)),
|
|
7280
|
+
[Symbol.asyncIterator]() {
|
|
7281
|
+
return this;
|
|
7282
|
+
}
|
|
7283
|
+
});
|
|
7284
|
+
/**
|
|
7285
|
+
* Replace the own method `target[method]` with `wrap(original)`. Already
|
|
7286
|
+
* patched methods are left alone, so repeated initialization never
|
|
7287
|
+
* double-wraps.
|
|
7288
|
+
*/
|
|
7289
|
+
const patchMethod = (target, method, wrap) => {
|
|
7290
|
+
if (!target || !Object.getOwnPropertyDescriptor(target, method) || typeof target[method] !== "function") return;
|
|
7291
|
+
if (!hasOwnPatchData$1(target)) Object.defineProperty(target, PATCH_DATA_SYMBOL$1, {
|
|
7292
|
+
value: {},
|
|
7293
|
+
enumerable: false,
|
|
7294
|
+
writable: true,
|
|
7295
|
+
configurable: true
|
|
7296
|
+
});
|
|
7297
|
+
const patchData = target[PATCH_DATA_SYMBOL$1];
|
|
7298
|
+
if (patchData[method]) return;
|
|
7299
|
+
const original = target[method];
|
|
7300
|
+
patchData[method] = original;
|
|
7301
|
+
target[method] = wrap(original);
|
|
7302
|
+
};
|
|
7303
|
+
const unpatchMethod = (target, method) => {
|
|
7304
|
+
if (!target || !hasOwnPatchData$1(target)) return;
|
|
7305
|
+
const patchData = target[PATCH_DATA_SYMBOL$1];
|
|
7306
|
+
const original = patchData[method];
|
|
7307
|
+
if (!original) return;
|
|
7308
|
+
target[method] = original;
|
|
7309
|
+
delete patchData[method];
|
|
7310
|
+
if (Object.keys(patchData).length === 0) delete target[PATCH_DATA_SYMBOL$1];
|
|
7311
|
+
};
|
|
7312
|
+
/**
|
|
7313
|
+
* Inject the handler into every `CallbackManager` LangChain configures.
|
|
7314
|
+
* `configure` delegates to the static `_configureSync`, and LangGraph calls
|
|
7315
|
+
* `_configureSync` directly, so this one method covers both.
|
|
7316
|
+
*/
|
|
7317
|
+
const wrapConfigureSync = (original) => function(inheritableHandlers, ...rest) {
|
|
7318
|
+
const manager = original.call(this, inheritableHandlers, ...rest);
|
|
7319
|
+
if (!manager) return original.call(this, [handler], ...rest);
|
|
7320
|
+
try {
|
|
7321
|
+
if (!manager.handlers?.some((h) => h?.name === "laminar_callback_handler") && typeof manager.addHandler === "function") manager.addHandler(handler, true);
|
|
7322
|
+
} catch (error) {
|
|
7323
|
+
logger$17.debug(`Failed to add the Laminar LangChain handler: ${error}`);
|
|
7324
|
+
}
|
|
7325
|
+
return manager;
|
|
7326
|
+
};
|
|
7327
|
+
/**
|
|
7328
|
+
* Run user code that LangChain runs for a run (a lambda, a tool, a graph
|
|
7329
|
+
* node) under that run's span. LangChain passes it the run's child config,
|
|
7330
|
+
* whose callback manager's parent run id is that run.
|
|
7331
|
+
*/
|
|
7332
|
+
const wrapRunWithConfig = (original) => function(config, ...rest) {
|
|
7333
|
+
let ctx;
|
|
7334
|
+
try {
|
|
7335
|
+
ctx = handler.contextFor(config?.callbacks?.getParentRunId?.());
|
|
7336
|
+
} catch {
|
|
7337
|
+
ctx = void 0;
|
|
7338
|
+
}
|
|
7339
|
+
if (!ctx) return original.call(this, config, ...rest);
|
|
7340
|
+
return runUnder(ctx, () => original.call(this, config, ...rest));
|
|
7341
|
+
};
|
|
7342
|
+
/**
|
|
7343
|
+
* The context an LLM call runs under, or undefined to run it untouched (it is
|
|
7344
|
+
* nested in another LLM call, or tracing is suppressed).
|
|
7345
|
+
*
|
|
7346
|
+
* The call is handed off to Laminar's provider instrumentation when the model
|
|
7347
|
+
* wraps a provider SDK it instruments. Otherwise the handler records the LLM
|
|
7348
|
+
* span and provider instrumentations underneath are suppressed, so a call is
|
|
7349
|
+
* never recorded twice.
|
|
7350
|
+
*/
|
|
7351
|
+
const llmCallContext = (model, callbacks, startedRunManagers) => {
|
|
7352
|
+
const active = context.active();
|
|
7353
|
+
if (active.getValue(LLM_CALL_KEY) || isTracingSuppressed(active)) return;
|
|
7354
|
+
let parentRunId;
|
|
7355
|
+
let llmType;
|
|
7356
|
+
try {
|
|
7357
|
+
parentRunId = callbacks?.getParentRunId?.();
|
|
7358
|
+
llmType = model?._llmType?.();
|
|
7359
|
+
} catch {}
|
|
7360
|
+
const base = handler.contextFor(parentRunId) ?? LaminarContextManager.getContext();
|
|
7361
|
+
const mode = llmType && HANDOFF_LLM_TYPES.has(llmType) && !startedRunManagers ? "handoff" : "own";
|
|
7362
|
+
const call = {
|
|
7363
|
+
mode,
|
|
7364
|
+
recorded: false
|
|
7365
|
+
};
|
|
7366
|
+
const ctx = base.setValue(LLM_CALL_KEY, call);
|
|
7367
|
+
return mode === "own" ? suppressTracing(ctx) : ctx;
|
|
7368
|
+
};
|
|
7369
|
+
const wrapGenerateUncached = (original) => function(input, parsedOptions, handledOptions, startedRunManagers, ...rest) {
|
|
7370
|
+
const call = () => original.call(this, input, parsedOptions, handledOptions, startedRunManagers, ...rest);
|
|
7371
|
+
const ctx = llmCallContext(this, handledOptions?.callbacks, startedRunManagers);
|
|
7372
|
+
return ctx ? runUnder(ctx, call) : call();
|
|
7373
|
+
};
|
|
7374
|
+
const wrapModelStreamIterator = (original) => function(input, options, ...rest) {
|
|
7375
|
+
const ctx = llmCallContext(this, options?.callbacks);
|
|
7376
|
+
if (!ctx) return original.call(this, input, options, ...rest);
|
|
7377
|
+
const iterator = runUnder(ctx, () => original.call(this, input, options, ...rest));
|
|
7378
|
+
return wrapIterator(iterator, (fn) => runUnder(ctx, fn));
|
|
7379
|
+
};
|
|
7380
|
+
/**
|
|
7381
|
+
* The graph topology, recorded on the graph's root span the way the Python
|
|
7382
|
+
* SDK does. Only the synchronous `getGraph` is used: it runs before the
|
|
7383
|
+
* graph does, and an async drawing would hold the run back.
|
|
7384
|
+
*/
|
|
7385
|
+
const topologyCache = /* @__PURE__ */ new WeakMap();
|
|
7386
|
+
const graphTopology = (pregel, config) => {
|
|
7387
|
+
const cached = topologyCache.get(pregel);
|
|
7388
|
+
if (cached) return cached;
|
|
7389
|
+
if (typeof pregel?.getGraph !== "function") return void 0;
|
|
7390
|
+
const graph = pregel.getGraph(config);
|
|
7391
|
+
if (!graph || graph instanceof Promise) return void 0;
|
|
7392
|
+
const nodes = Object.values(graph.nodes ?? {}).map((node) => ({
|
|
7393
|
+
id: node.id,
|
|
7394
|
+
name: node.name,
|
|
7395
|
+
metadata: node.metadata ?? null
|
|
7396
|
+
}));
|
|
7397
|
+
const edges = (graph.edges ?? []).map((edge) => ({
|
|
7398
|
+
source: edge.source,
|
|
7399
|
+
target: edge.target,
|
|
7400
|
+
conditional: Boolean(edge.conditional)
|
|
7401
|
+
}));
|
|
7402
|
+
const topology = {
|
|
7403
|
+
"langgraph.nodes": JSON.stringify(nodes),
|
|
7404
|
+
"langgraph.edges": JSON.stringify(edges)
|
|
7405
|
+
};
|
|
7406
|
+
topologyCache.set(pregel, topology);
|
|
7407
|
+
return topology;
|
|
7408
|
+
};
|
|
7409
|
+
/**
|
|
7410
|
+
* Publish the graph topology for the graph's own run, which the handler
|
|
7411
|
+
* starts in the iterator's first step. Each iterator gets its own holder, so
|
|
7412
|
+
* concurrent graph runs never read each other's topology.
|
|
7413
|
+
*/
|
|
7414
|
+
const wrapPregelStreamIterator = (original) => function(input, options, ...rest) {
|
|
7415
|
+
let topology;
|
|
7416
|
+
try {
|
|
7417
|
+
topology = graphTopology(this, options);
|
|
7418
|
+
} catch (error) {
|
|
7419
|
+
logger$17.debug(`Failed to read the LangGraph topology: ${error}`);
|
|
7420
|
+
}
|
|
7421
|
+
const iterator = original.call(this, input, options, ...rest);
|
|
7422
|
+
if (!topology) return iterator;
|
|
7423
|
+
const holder = { topology };
|
|
7424
|
+
return wrapIterator(iterator, (fn) => topologyStorage.run(holder, fn));
|
|
7425
|
+
};
|
|
7426
|
+
/**
|
|
7427
|
+
* `Pregel.prototype` from `@langchain/langgraph/pregel`, or the first
|
|
7428
|
+
* prototype that owns `_streamIterator` above a compiled graph class.
|
|
7429
|
+
*/
|
|
7430
|
+
const pregelPrototype = (module) => {
|
|
7431
|
+
if (typeof module?.Pregel === "function") return module.Pregel.prototype;
|
|
7432
|
+
const graphClass = module?.CompiledStateGraph ?? module?.CompiledGraph ?? module;
|
|
7433
|
+
let proto = typeof graphClass === "function" ? graphClass.prototype : null;
|
|
7434
|
+
while (proto && proto !== Object.prototype) {
|
|
7435
|
+
if (Object.getOwnPropertyDescriptor(proto, "_streamIterator")) return proto;
|
|
7436
|
+
proto = Object.getPrototypeOf(proto);
|
|
7437
|
+
}
|
|
7438
|
+
};
|
|
7439
|
+
const singletonPrototype = (module) => {
|
|
7440
|
+
const singleton = module?.AsyncLocalStorageProviderSingleton;
|
|
7441
|
+
return singleton ? Object.getPrototypeOf(singleton) : void 0;
|
|
7442
|
+
};
|
|
7443
|
+
const CORE_FILES = {
|
|
7444
|
+
callbackManager: ["@langchain/core/dist/callbacks/manager"],
|
|
7445
|
+
singletons: ["@langchain/core/dist/singletons/async_local_storage/index", "@langchain/core/dist/singletons/index"],
|
|
7446
|
+
chatModels: ["@langchain/core/dist/language_models/chat_models"],
|
|
7447
|
+
llms: ["@langchain/core/dist/language_models/llms"]
|
|
7448
|
+
};
|
|
7449
|
+
/**
|
|
7450
|
+
* Instruments LangChain (`@langchain/core`) and LangGraph
|
|
7451
|
+
* (`@langchain/langgraph`) through a callback handler injected into every
|
|
7452
|
+
* callback manager, with wrappers that run user code and provider SDK calls
|
|
7453
|
+
* under the right span.
|
|
7454
|
+
*
|
|
7455
|
+
* Calls made through LangChain's OpenAI and Anthropic integrations are left to
|
|
7456
|
+
* Laminar's OpenAI and Anthropic instrumentations, which record them as the
|
|
7457
|
+
* LLM span. Other model calls are recorded by the handler, with provider
|
|
7458
|
+
* instrumentations underneath suppressed.
|
|
7459
|
+
*/
|
|
7460
|
+
var LangChainInstrumentation = class extends InstrumentationBase {
|
|
7461
|
+
constructor(config) {
|
|
7462
|
+
super("@lmnr/langchain-instrumentation", version, { enabled: true });
|
|
7463
|
+
this.traceContent = config?.traceContent ?? true;
|
|
7464
|
+
}
|
|
7465
|
+
init() {
|
|
7466
|
+
const coreFiles = (names, patch, unpatch) => names.flatMap((name) => [".cjs", ".js"].map((extension) => new InstrumentationNodeModuleFile(`${name}${extension}`, [">=0.3.0"], (exports) => {
|
|
7467
|
+
patch.call(this, exports);
|
|
7468
|
+
return exports;
|
|
7469
|
+
}, (exports) => {
|
|
7470
|
+
if (exports) unpatch.call(this, exports);
|
|
7471
|
+
})));
|
|
7472
|
+
return [new InstrumentationNodeModuleDefinition("@langchain/core", [">=0.3.0"], void 0, void 0, [
|
|
7473
|
+
...coreFiles(CORE_FILES.callbackManager, this.patchCallbackManager, this.unpatchCallbackManager),
|
|
7474
|
+
...coreFiles(CORE_FILES.singletons, this.patchSingletons, this.unpatchSingletons),
|
|
7475
|
+
...coreFiles(CORE_FILES.chatModels, this.patchChatModels, this.unpatchChatModels),
|
|
7476
|
+
...coreFiles(CORE_FILES.llms, this.patchLlms, this.unpatchLlms)
|
|
7477
|
+
]), new InstrumentationNodeModuleDefinition("@langchain/langgraph", [">=0.2.0"], void 0, void 0, [".cjs", ".js"].map((extension) => new InstrumentationNodeModuleFile(`@langchain/langgraph/dist/pregel/index${extension}`, [">=0.2.0"], (exports) => {
|
|
7478
|
+
this.patchLanggraph(exports);
|
|
7479
|
+
return exports;
|
|
7480
|
+
}, (exports) => {
|
|
7481
|
+
if (exports) this.unpatchLanggraph(exports);
|
|
7482
|
+
})))];
|
|
7483
|
+
}
|
|
7484
|
+
/**
|
|
7485
|
+
* Pass every module you use; a module left out is not traced. The model
|
|
7486
|
+
* modules are what lets OpenAI and Anthropic calls be recorded once, by the
|
|
7487
|
+
* provider instrumentation, instead of twice.
|
|
7488
|
+
*/
|
|
7489
|
+
manuallyInstrument(modules) {
|
|
7490
|
+
const { callbackManagerModule, singletonsModule, chatModelsModule, llmsModule, langgraphModule } = modules ?? {};
|
|
7491
|
+
if (!callbackManagerModule && !singletonsModule && !chatModelsModule && !llmsModule && !langgraphModule) {
|
|
7492
|
+
diag.warn("No modules in langchain manual instrumentation input. Pass at least @langchain/core/callbacks/manager as callbackManagerModule.");
|
|
7493
|
+
return;
|
|
7494
|
+
}
|
|
7495
|
+
diag.debug("Manually instrumenting LangChain");
|
|
7496
|
+
if (callbackManagerModule && !chatModelsModule) diag.warn("LangChain chatModelsModule is missing from manual instrumentation input. Chat model calls may be recorded twice. Pass @langchain/core/language_models/chat_models as chatModelsModule.");
|
|
7497
|
+
if (callbackManagerModule) this.patchCallbackManager(callbackManagerModule);
|
|
7498
|
+
if (singletonsModule) this.patchSingletons(singletonsModule);
|
|
7499
|
+
if (chatModelsModule) this.patchChatModels(chatModelsModule);
|
|
7500
|
+
if (llmsModule) this.patchLlms(llmsModule);
|
|
7501
|
+
if (langgraphModule) {
|
|
7502
|
+
if (!pregelPrototype(langgraphModule)) diag.warn("Could not find Pregel in langchain manual instrumentation input. Pass the @langchain/langgraph module as langgraphModule.");
|
|
7503
|
+
else this.patchLanggraph(langgraphModule);
|
|
7504
|
+
}
|
|
7505
|
+
}
|
|
7506
|
+
patchCallbackManager(moduleExports) {
|
|
7507
|
+
diag.debug("Patching @langchain/core CallbackManager");
|
|
7508
|
+
handler.traceContent = this.traceContent;
|
|
7509
|
+
patchMethod(moduleExports?.CallbackManager, "_configureSync", wrapConfigureSync);
|
|
7510
|
+
}
|
|
7511
|
+
unpatchCallbackManager(moduleExports) {
|
|
7512
|
+
unpatchMethod(moduleExports?.CallbackManager, "_configureSync");
|
|
7513
|
+
}
|
|
7514
|
+
patchSingletons(moduleExports) {
|
|
7515
|
+
diag.debug("Patching @langchain/core AsyncLocalStorageProvider");
|
|
7516
|
+
patchMethod(singletonPrototype(moduleExports), "runWithConfig", wrapRunWithConfig);
|
|
7517
|
+
}
|
|
7518
|
+
unpatchSingletons(moduleExports) {
|
|
7519
|
+
unpatchMethod(singletonPrototype(moduleExports), "runWithConfig");
|
|
7520
|
+
}
|
|
7521
|
+
patchChatModels(moduleExports) {
|
|
7522
|
+
diag.debug("Patching @langchain/core BaseChatModel");
|
|
7523
|
+
this.patchModel(moduleExports?.BaseChatModel?.prototype);
|
|
7524
|
+
}
|
|
7525
|
+
unpatchChatModels(moduleExports) {
|
|
7526
|
+
this.unpatchModel(moduleExports?.BaseChatModel?.prototype);
|
|
7527
|
+
}
|
|
7528
|
+
patchLlms(moduleExports) {
|
|
7529
|
+
diag.debug("Patching @langchain/core BaseLLM");
|
|
7530
|
+
this.patchModel(moduleExports?.BaseLLM?.prototype);
|
|
7531
|
+
}
|
|
7532
|
+
unpatchLlms(moduleExports) {
|
|
7533
|
+
this.unpatchModel(moduleExports?.BaseLLM?.prototype);
|
|
7534
|
+
}
|
|
7535
|
+
patchModel(proto) {
|
|
7536
|
+
patchMethod(proto, "_generateUncached", wrapGenerateUncached);
|
|
7537
|
+
patchMethod(proto, "_streamIterator", wrapModelStreamIterator);
|
|
7538
|
+
}
|
|
7539
|
+
unpatchModel(proto) {
|
|
7540
|
+
unpatchMethod(proto, "_generateUncached");
|
|
7541
|
+
unpatchMethod(proto, "_streamIterator");
|
|
7542
|
+
}
|
|
7543
|
+
patchLanggraph(moduleExports) {
|
|
7544
|
+
diag.debug("Patching @langchain/langgraph Pregel");
|
|
7545
|
+
patchMethod(pregelPrototype(moduleExports), "_streamIterator", wrapPregelStreamIterator);
|
|
7546
|
+
}
|
|
7547
|
+
unpatchLanggraph(moduleExports) {
|
|
7548
|
+
unpatchMethod(pregelPrototype(moduleExports), "_streamIterator");
|
|
7549
|
+
}
|
|
7550
|
+
};
|
|
6485
7551
|
const DISABLE_OPENAI_RESPONSES_INSTRUMENTATION_CONTEXT_KEY = createContextKey("LMNR_DISABLE_OPENAI_RESPONSES_INSTRUMENTATION");
|
|
6486
7552
|
const systemInstructionsStorage = new AsyncLocalStorage();
|
|
6487
7553
|
const getCurrentSystemInstructions = () => systemInstructionsStorage.getStore();
|
|
@@ -8578,6 +9644,107 @@ var LaminarSpanExporter = class {
|
|
|
8578
9644
|
return this.exporter.forceFlush?.();
|
|
8579
9645
|
}
|
|
8580
9646
|
};
|
|
9647
|
+
const RELEASE_ENV_VARS = [
|
|
9648
|
+
"GITHUB_SHA",
|
|
9649
|
+
"SENTRY_RELEASE",
|
|
9650
|
+
"VERCEL_GIT_COMMIT_SHA",
|
|
9651
|
+
"RENDER_GIT_COMMIT",
|
|
9652
|
+
"RAILWAY_GIT_COMMIT_SHA",
|
|
9653
|
+
"HEROKU_BUILD_COMMIT",
|
|
9654
|
+
"SOURCE_VERSION",
|
|
9655
|
+
"CODEBUILD_RESOLVED_SOURCE_VERSION",
|
|
9656
|
+
"CIRCLE_SHA1",
|
|
9657
|
+
"K_REVISION",
|
|
9658
|
+
"GAE_DEPLOYMENT_ID",
|
|
9659
|
+
"FLY_IMAGE_REF"
|
|
9660
|
+
];
|
|
9661
|
+
/**
|
|
9662
|
+
* The first available of: `explicit`, `LMNR_RELEASE`, a known platform
|
|
9663
|
+
* variable, a numeric AWS Lambda version, the checked-out git commit.
|
|
9664
|
+
*/
|
|
9665
|
+
const detectRelease = (explicit) => {
|
|
9666
|
+
const candidates = [
|
|
9667
|
+
() => explicit,
|
|
9668
|
+
() => env("LMNR_RELEASE"),
|
|
9669
|
+
...RELEASE_ENV_VARS.map((name) => () => env(name)),
|
|
9670
|
+
lambdaVersion,
|
|
9671
|
+
gitHead
|
|
9672
|
+
];
|
|
9673
|
+
for (const candidate of candidates) {
|
|
9674
|
+
const release = clean(candidate());
|
|
9675
|
+
if (release) return release;
|
|
9676
|
+
}
|
|
9677
|
+
};
|
|
9678
|
+
const env = (name) => {
|
|
9679
|
+
try {
|
|
9680
|
+
return process.env[name];
|
|
9681
|
+
} catch {
|
|
9682
|
+
return;
|
|
9683
|
+
}
|
|
9684
|
+
};
|
|
9685
|
+
const clean = (value) => {
|
|
9686
|
+
const trimmed = value?.trim();
|
|
9687
|
+
if (!trimmed) return;
|
|
9688
|
+
const chars = Array.from(trimmed);
|
|
9689
|
+
return chars.length > 128 ? chars.slice(0, 128).join("") : trimmed;
|
|
9690
|
+
};
|
|
9691
|
+
const lambdaVersion = () => {
|
|
9692
|
+
const version = env("AWS_LAMBDA_FUNCTION_VERSION");
|
|
9693
|
+
const fn = env("AWS_LAMBDA_FUNCTION_NAME");
|
|
9694
|
+
if (!version || !/^\d+$/.test(version) || !fn) return;
|
|
9695
|
+
return `${fn}:${version}`;
|
|
9696
|
+
};
|
|
9697
|
+
const isFile = (path) => {
|
|
9698
|
+
try {
|
|
9699
|
+
return statSync(path).isFile();
|
|
9700
|
+
} catch {
|
|
9701
|
+
return false;
|
|
9702
|
+
}
|
|
9703
|
+
};
|
|
9704
|
+
const isDirectory = (path) => {
|
|
9705
|
+
try {
|
|
9706
|
+
return statSync(path).isDirectory();
|
|
9707
|
+
} catch {
|
|
9708
|
+
return false;
|
|
9709
|
+
}
|
|
9710
|
+
};
|
|
9711
|
+
/** The commit `.git/HEAD` points at, read from disk without running git. */
|
|
9712
|
+
const gitHead = () => {
|
|
9713
|
+
try {
|
|
9714
|
+
const gitDir = findGitDir(process.cwd());
|
|
9715
|
+
if (gitDir === void 0) return;
|
|
9716
|
+
const head = readFileSync(join(gitDir, "HEAD"), "utf8").trim();
|
|
9717
|
+
if (!head.startsWith("ref:")) return head;
|
|
9718
|
+
const ref = head.slice(4).trim();
|
|
9719
|
+
const commonFile = join(gitDir, "commondir");
|
|
9720
|
+
const commonDir = isFile(commonFile) ? resolve(gitDir, readFileSync(commonFile, "utf8").trim()) : gitDir;
|
|
9721
|
+
for (const refsDir of /* @__PURE__ */ new Set([gitDir, commonDir])) {
|
|
9722
|
+
const refFile = join(refsDir, ref);
|
|
9723
|
+
if (isFile(refFile)) return readFileSync(refFile, "utf8").trim();
|
|
9724
|
+
}
|
|
9725
|
+
const packedRefs = join(commonDir, "packed-refs");
|
|
9726
|
+
if (isFile(packedRefs)) for (const line of readFileSync(packedRefs, "utf8").split("\n")) {
|
|
9727
|
+
const space = line.indexOf(" ");
|
|
9728
|
+
if (space !== -1 && line.slice(space + 1).trim() === ref) return line.slice(0, space);
|
|
9729
|
+
}
|
|
9730
|
+
} catch {
|
|
9731
|
+
return;
|
|
9732
|
+
}
|
|
9733
|
+
};
|
|
9734
|
+
const findGitDir = (start) => {
|
|
9735
|
+
let directory = resolve(start);
|
|
9736
|
+
for (;;) {
|
|
9737
|
+
const dotGit = join(directory, ".git");
|
|
9738
|
+
if (isDirectory(dotGit)) return dotGit;
|
|
9739
|
+
if (isFile(dotGit)) {
|
|
9740
|
+
const content = readFileSync(dotGit, "utf8").trim();
|
|
9741
|
+
if (content.startsWith("gitdir:")) return resolve(directory, content.slice(7).trim());
|
|
9742
|
+
}
|
|
9743
|
+
const parent = dirname(directory);
|
|
9744
|
+
if (parent === directory) return;
|
|
9745
|
+
directory = parent;
|
|
9746
|
+
}
|
|
9747
|
+
};
|
|
8581
9748
|
//#endregion
|
|
8582
9749
|
//#region src/opentelemetry-lib/tracing/processor.ts
|
|
8583
9750
|
var LaminarSpanProcessor = class LaminarSpanProcessor {
|
|
@@ -8595,11 +9762,15 @@ var LaminarSpanProcessor = class LaminarSpanProcessor {
|
|
|
8595
9762
|
* @param {boolean} options.forceHttp - Whether to force HTTP and use OpenTelemetry
|
|
8596
9763
|
* HTTP/protobuf exporter.
|
|
8597
9764
|
* Not recommended with Laminar backends.
|
|
9765
|
+
* @param {string} options.release - The release of the running code, usually
|
|
9766
|
+
* its git commit SHA. Detected from the environment if not provided.
|
|
8598
9767
|
*/
|
|
8599
9768
|
constructor(options = {}) {
|
|
8600
9769
|
this._spanIdToPath = /* @__PURE__ */ new Map();
|
|
8601
9770
|
this._spanIdLists = /* @__PURE__ */ new Map();
|
|
8602
9771
|
this.logger = initializeLogger();
|
|
9772
|
+
const wrapped = options.spanProcessor instanceof LaminarSpanProcessor ? options.spanProcessor.release : void 0;
|
|
9773
|
+
this.release = detectRelease(options.release ?? wrapped);
|
|
8603
9774
|
if (options.spanProcessor && options.spanProcessor instanceof LaminarSpanProcessor) {
|
|
8604
9775
|
this.instance = options.spanProcessor.instance;
|
|
8605
9776
|
this._spanIdToPath = options.spanProcessor._spanIdToPath;
|
|
@@ -8645,6 +9816,7 @@ var LaminarSpanProcessor = class LaminarSpanProcessor {
|
|
|
8645
9816
|
span.setAttribute(SPAN_SDK_VERSION, version);
|
|
8646
9817
|
const langVersion = getLangVersion();
|
|
8647
9818
|
if (langVersion) span.setAttribute(SPAN_LANGUAGE_VERSION, langVersion);
|
|
9819
|
+
if (this.release) span.setAttribute(SPAN_RELEASE, this.release);
|
|
8648
9820
|
const globalMetadata = LaminarContextManager.getGlobalMetadata();
|
|
8649
9821
|
if (globalMetadata && Object.keys(globalMetadata).length > 0) span.setAttributes(metadataToAttributes(globalMetadata));
|
|
8650
9822
|
const associationProperties = context.active().getValue(ASSOCIATION_PROPERTIES_KEY);
|
|
@@ -9677,7 +10849,8 @@ const startTracing = (options) => {
|
|
|
9677
10849
|
maxExportBatchSizeBytes: options.maxExportBatchSizeBytes,
|
|
9678
10850
|
flushBySize: options.flushBySize,
|
|
9679
10851
|
exporter: options.exporter,
|
|
9680
|
-
disableBatch: options.disableBatch
|
|
10852
|
+
disableBatch: options.disableBatch,
|
|
10853
|
+
release: options.release
|
|
9681
10854
|
});
|
|
9682
10855
|
const newProvider = new NodeTracerProvider({
|
|
9683
10856
|
spanProcessors: [spanProcessor],
|