netra-sdk 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1333 -771
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +1328 -767
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@ import { createRequire } from 'module';
|
|
|
4
4
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
5
5
|
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
6
6
|
import { initialize } from '@traceloop/node-server-sdk';
|
|
7
|
-
import * as dotenv from 'dotenv';
|
|
8
7
|
import shimmer from 'shimmer';
|
|
8
|
+
import * as dotenv from 'dotenv';
|
|
9
9
|
import { CompositePropagator, W3CTraceContextPropagator, W3CBaggagePropagator, ExportResultCode } from '@opentelemetry/core';
|
|
10
10
|
import * as http from 'http';
|
|
11
11
|
import * as https from 'https';
|
|
@@ -22,6 +22,9 @@ var Logger = class {
|
|
|
22
22
|
static get isDebug() {
|
|
23
23
|
return this._debugMode || ["1", "true"].includes((process.env.NETRA_DEBUG ?? "").toLowerCase());
|
|
24
24
|
}
|
|
25
|
+
static isDebugMode() {
|
|
26
|
+
return this.isDebug;
|
|
27
|
+
}
|
|
25
28
|
static debug(...args) {
|
|
26
29
|
if (this.isDebug) console.debug(PREFIX, ...args);
|
|
27
30
|
}
|
|
@@ -575,6 +578,9 @@ var Usage = class {
|
|
|
575
578
|
}
|
|
576
579
|
};
|
|
577
580
|
|
|
581
|
+
// src/version.ts
|
|
582
|
+
var SDK_VERSION = "1.4.0";
|
|
583
|
+
|
|
578
584
|
// src/config.ts
|
|
579
585
|
var NetraInstruments = /* @__PURE__ */ ((NetraInstruments2) => {
|
|
580
586
|
NetraInstruments2["ALL"] = "__all__";
|
|
@@ -610,7 +616,8 @@ var DEFAULT_INSTRUMENTS_FOR_ROOT = /* @__PURE__ */ new Set([
|
|
|
610
616
|
// AI frameworks
|
|
611
617
|
"langchain" /* LANGCHAIN */,
|
|
612
618
|
"langgraph" /* LANGGRAPH */,
|
|
613
|
-
"llama_index" /* LLAMA_INDEX
|
|
619
|
+
"llama_index" /* LLAMA_INDEX */,
|
|
620
|
+
"openai_agents" /* OPENAI_AGENTS */
|
|
614
621
|
]);
|
|
615
622
|
var DEFAULT_INSTRUMENTS = /* @__PURE__ */ new Set([
|
|
616
623
|
...DEFAULT_INSTRUMENTS_FOR_ROOT,
|
|
@@ -772,11 +779,34 @@ var Config = class {
|
|
|
772
779
|
const headerStr = Object.entries(this.headers).map(([k, v]) => `${k}=${v}`).join(",");
|
|
773
780
|
process.env.TRACELOOP_HEADERS = headerStr;
|
|
774
781
|
}
|
|
782
|
+
this._setResourceAttributesEnv();
|
|
783
|
+
}
|
|
784
|
+
_setResourceAttributesEnv() {
|
|
785
|
+
const attrs = {
|
|
786
|
+
"deployment.environment": this.environment,
|
|
787
|
+
"service.name": this.appName
|
|
788
|
+
};
|
|
789
|
+
for (const [k, v] of Object.entries(this.resourceAttributes)) {
|
|
790
|
+
attrs[k] = String(v);
|
|
791
|
+
}
|
|
792
|
+
const existing = process.env.OTEL_RESOURCE_ATTRIBUTES;
|
|
793
|
+
if (existing) {
|
|
794
|
+
for (const pair of existing.split(",")) {
|
|
795
|
+
const eqIdx = pair.indexOf("=");
|
|
796
|
+
if (eqIdx <= 0) continue;
|
|
797
|
+
const key = decodeURIComponent(pair.slice(0, eqIdx).trim());
|
|
798
|
+
if (key) {
|
|
799
|
+
attrs[key] = decodeURIComponent(pair.slice(eqIdx + 1).trim());
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const encodeAttrValue = (s) => encodeURIComponent(s);
|
|
804
|
+
process.env.OTEL_RESOURCE_ATTRIBUTES = Object.entries(attrs).map(([k, v]) => `${encodeAttrValue(k)}=${encodeAttrValue(v)}`).join(",");
|
|
775
805
|
}
|
|
776
806
|
};
|
|
777
807
|
Config.SDK_NAME = "netra";
|
|
778
808
|
Config.LIBRARY_NAME = "netra";
|
|
779
|
-
Config.LIBRARY_VERSION =
|
|
809
|
+
Config.LIBRARY_VERSION = SDK_VERSION;
|
|
780
810
|
Config.TRIAL_BLOCK_DURATION_SECONDS = 900;
|
|
781
811
|
// 15 minutes
|
|
782
812
|
Config.ATTRIBUTE_MAX_LEN = parseInt(
|
|
@@ -785,6 +815,9 @@ Config.ATTRIBUTE_MAX_LEN = parseInt(
|
|
|
785
815
|
Config.CONVERSATION_MAX_LEN = parseInt(
|
|
786
816
|
process.env.NETRA_CONVERSATION_CONTENT_MAX_LEN || "50000"
|
|
787
817
|
);
|
|
818
|
+
Config.SPAN_ATTRIBUTE_MAX_SIZE = parseInt(
|
|
819
|
+
process.env.NETRA_SPAN_ATTRIBUTE_MAX_SIZE || "30000"
|
|
820
|
+
);
|
|
788
821
|
|
|
789
822
|
// src/utils/pattern-matching.ts
|
|
790
823
|
function compilePatterns(patterns) {
|
|
@@ -1046,6 +1079,57 @@ var ConversationType = /* @__PURE__ */ ((ConversationType3) => {
|
|
|
1046
1079
|
return ConversationType3;
|
|
1047
1080
|
})(ConversationType || {});
|
|
1048
1081
|
|
|
1082
|
+
// src/utils/serialization.ts
|
|
1083
|
+
var ELLIPSIS = "...";
|
|
1084
|
+
function truncate(s, maxLength) {
|
|
1085
|
+
if (s.length <= maxLength) return s;
|
|
1086
|
+
if (maxLength <= ELLIPSIS.length) return s.slice(0, maxLength);
|
|
1087
|
+
return s.slice(0, maxLength - ELLIPSIS.length) + ELLIPSIS;
|
|
1088
|
+
}
|
|
1089
|
+
function safeStringify(value, maxLength) {
|
|
1090
|
+
if (typeof value === "string") {
|
|
1091
|
+
if (maxLength && value.length > maxLength) {
|
|
1092
|
+
return truncate(value, maxLength);
|
|
1093
|
+
}
|
|
1094
|
+
return value;
|
|
1095
|
+
}
|
|
1096
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1097
|
+
let result;
|
|
1098
|
+
try {
|
|
1099
|
+
result = JSON.stringify(value, (_key, val) => {
|
|
1100
|
+
if (typeof val === "function")
|
|
1101
|
+
return `[Function: ${val.name || "anonymous"}]`;
|
|
1102
|
+
if (typeof val === "symbol") return val.toString();
|
|
1103
|
+
if (typeof val === "bigint") return val.toString();
|
|
1104
|
+
if (val !== null && typeof val === "object") {
|
|
1105
|
+
if (seen.has(val)) return "[Circular]";
|
|
1106
|
+
seen.add(val);
|
|
1107
|
+
const name = val.constructor?.name;
|
|
1108
|
+
if (name && name !== "Object" && name !== "Array" && Object.keys(val).length > 20) {
|
|
1109
|
+
return `[${name}]`;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return val;
|
|
1113
|
+
}) ?? String(value);
|
|
1114
|
+
} catch {
|
|
1115
|
+
result = value?.constructor?.name ? `[${value.constructor.name}]` : String(value);
|
|
1116
|
+
}
|
|
1117
|
+
if (maxLength && result.length > maxLength) {
|
|
1118
|
+
return truncate(result, maxLength);
|
|
1119
|
+
}
|
|
1120
|
+
return result;
|
|
1121
|
+
}
|
|
1122
|
+
function serializeValue(value, maxLength) {
|
|
1123
|
+
if (value === null || value === void 0) return String(value);
|
|
1124
|
+
const t = typeof value;
|
|
1125
|
+
if (t === "string" || t === "number" || t === "boolean") {
|
|
1126
|
+
const s = String(value);
|
|
1127
|
+
if (maxLength && s.length > maxLength) return truncate(s, maxLength);
|
|
1128
|
+
return s;
|
|
1129
|
+
}
|
|
1130
|
+
return safeStringify(value, maxLength);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1049
1133
|
// src/session-manager.ts
|
|
1050
1134
|
var MODULE_NAME = "netra.session-manager";
|
|
1051
1135
|
var entityStorage = new AsyncLocalStorage();
|
|
@@ -1059,12 +1143,6 @@ var globalFallbackContext = {
|
|
|
1059
1143
|
function getEntityContext() {
|
|
1060
1144
|
return entityStorage.getStore() ?? globalFallbackContext;
|
|
1061
1145
|
}
|
|
1062
|
-
function serializeValue(value) {
|
|
1063
|
-
if (typeof value === "string") {
|
|
1064
|
-
return value.substring(0, Config.ATTRIBUTE_MAX_LEN);
|
|
1065
|
-
}
|
|
1066
|
-
return JSON.stringify(value).substring(0, Config.ATTRIBUTE_MAX_LEN);
|
|
1067
|
-
}
|
|
1068
1146
|
var SessionManager = class _SessionManager {
|
|
1069
1147
|
// Span registry (name → stack)
|
|
1070
1148
|
static registerSpan(name, span2) {
|
|
@@ -1179,7 +1257,10 @@ var SessionManager = class _SessionManager {
|
|
|
1179
1257
|
*/
|
|
1180
1258
|
static setInput(value) {
|
|
1181
1259
|
try {
|
|
1182
|
-
_SessionManager.setAttributeOnActiveSpan(
|
|
1260
|
+
_SessionManager.setAttributeOnActiveSpan(
|
|
1261
|
+
"netra.user.input",
|
|
1262
|
+
serializeValue(value, Config.ATTRIBUTE_MAX_LEN)
|
|
1263
|
+
);
|
|
1183
1264
|
} catch (e) {
|
|
1184
1265
|
Logger.error("setInput failed:", e);
|
|
1185
1266
|
}
|
|
@@ -1191,7 +1272,10 @@ var SessionManager = class _SessionManager {
|
|
|
1191
1272
|
*/
|
|
1192
1273
|
static setOutput(value) {
|
|
1193
1274
|
try {
|
|
1194
|
-
_SessionManager.setAttributeOnActiveSpan(
|
|
1275
|
+
_SessionManager.setAttributeOnActiveSpan(
|
|
1276
|
+
"netra.user.output",
|
|
1277
|
+
serializeValue(value, Config.ATTRIBUTE_MAX_LEN)
|
|
1278
|
+
);
|
|
1195
1279
|
} catch (e) {
|
|
1196
1280
|
Logger.error("setOutput failed:", e);
|
|
1197
1281
|
}
|
|
@@ -1203,7 +1287,10 @@ var SessionManager = class _SessionManager {
|
|
|
1203
1287
|
*/
|
|
1204
1288
|
static setRootInput(value) {
|
|
1205
1289
|
try {
|
|
1206
|
-
RootSpanProcessor.setAttributeOnRootSpan(
|
|
1290
|
+
RootSpanProcessor.setAttributeOnRootSpan(
|
|
1291
|
+
"netra.user.input",
|
|
1292
|
+
serializeValue(value, Config.ATTRIBUTE_MAX_LEN)
|
|
1293
|
+
);
|
|
1207
1294
|
} catch (e) {
|
|
1208
1295
|
Logger.error("setRootInput failed:", e);
|
|
1209
1296
|
}
|
|
@@ -1215,7 +1302,10 @@ var SessionManager = class _SessionManager {
|
|
|
1215
1302
|
*/
|
|
1216
1303
|
static setRootOutput(value) {
|
|
1217
1304
|
try {
|
|
1218
|
-
RootSpanProcessor.setAttributeOnRootSpan(
|
|
1305
|
+
RootSpanProcessor.setAttributeOnRootSpan(
|
|
1306
|
+
"netra.user.output",
|
|
1307
|
+
serializeValue(value, Config.ATTRIBUTE_MAX_LEN)
|
|
1308
|
+
);
|
|
1219
1309
|
} catch (e) {
|
|
1220
1310
|
Logger.error("setRootOutput failed:", e);
|
|
1221
1311
|
}
|
|
@@ -2782,6 +2872,58 @@ var Prompts = class {
|
|
|
2782
2872
|
}
|
|
2783
2873
|
};
|
|
2784
2874
|
|
|
2875
|
+
// src/processors/attribute-size-limit-processor.ts
|
|
2876
|
+
var DEFAULT_MAX_ATTRIBUTE_SIZE = 32e3;
|
|
2877
|
+
var AttributeSizeLimitProcessor = class {
|
|
2878
|
+
constructor(maxAttributeSize) {
|
|
2879
|
+
this.maxAttributeSize = maxAttributeSize ?? DEFAULT_MAX_ATTRIBUTE_SIZE;
|
|
2880
|
+
}
|
|
2881
|
+
onStart(span2, _parentContext) {
|
|
2882
|
+
try {
|
|
2883
|
+
this._wrapSetAttribute(span2);
|
|
2884
|
+
} catch (e) {
|
|
2885
|
+
Logger.debug("AttributeSizeLimitProcessor.onStart error:", e);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
onEnd(_span) {
|
|
2889
|
+
}
|
|
2890
|
+
shutdown() {
|
|
2891
|
+
return Promise.resolve();
|
|
2892
|
+
}
|
|
2893
|
+
forceFlush() {
|
|
2894
|
+
return Promise.resolve();
|
|
2895
|
+
}
|
|
2896
|
+
_wrapSetAttribute(span2) {
|
|
2897
|
+
const original = span2.setAttribute.bind(span2);
|
|
2898
|
+
const maxLen = this.maxAttributeSize;
|
|
2899
|
+
const patched = (key, value) => {
|
|
2900
|
+
try {
|
|
2901
|
+
return original(key, truncateValue(value, maxLen));
|
|
2902
|
+
} catch {
|
|
2903
|
+
try {
|
|
2904
|
+
return original(key, value);
|
|
2905
|
+
} catch {
|
|
2906
|
+
return span2;
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
};
|
|
2910
|
+
span2.setAttribute = patched;
|
|
2911
|
+
}
|
|
2912
|
+
};
|
|
2913
|
+
function truncateValue(value, maxLen) {
|
|
2914
|
+
if (typeof value === "string") {
|
|
2915
|
+
return value.length > maxLen ? value.substring(0, maxLen) : value;
|
|
2916
|
+
}
|
|
2917
|
+
if (Array.isArray(value)) {
|
|
2918
|
+
const serialized = JSON.stringify(value);
|
|
2919
|
+
if (serialized.length > maxLen) {
|
|
2920
|
+
return serialized.substring(0, maxLen);
|
|
2921
|
+
}
|
|
2922
|
+
return value;
|
|
2923
|
+
}
|
|
2924
|
+
return value;
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2785
2927
|
// src/processors/instrumentation-span-processor.ts
|
|
2786
2928
|
var ALLOWED_INSTRUMENTATION_NAMES = /* @__PURE__ */ new Set([
|
|
2787
2929
|
"openai",
|
|
@@ -3187,6 +3329,9 @@ function setSessionBaggage(key, value) {
|
|
|
3187
3329
|
}
|
|
3188
3330
|
}
|
|
3189
3331
|
var SessionSpanProcessor = class {
|
|
3332
|
+
constructor(environment = "local") {
|
|
3333
|
+
this.environment = environment;
|
|
3334
|
+
}
|
|
3190
3335
|
/**
|
|
3191
3336
|
* Called when a span starts. Adds session and entity context attributes.
|
|
3192
3337
|
*/
|
|
@@ -3195,6 +3340,7 @@ var SessionSpanProcessor = class {
|
|
|
3195
3340
|
span2.setAttribute("library.name", Config.LIBRARY_NAME);
|
|
3196
3341
|
span2.setAttribute("library.version", Config.LIBRARY_VERSION);
|
|
3197
3342
|
span2.setAttribute("sdk.name", Config.SDK_NAME);
|
|
3343
|
+
span2.setAttribute("deployment.environment", this.environment);
|
|
3198
3344
|
const ctxToUse = parentContext || context.active();
|
|
3199
3345
|
const baggage = propagation.getBaggage(ctxToUse);
|
|
3200
3346
|
const sessionId = baggage?.getEntry("session_id")?.value ?? sessionValues.get("session_id");
|
|
@@ -3601,6 +3747,184 @@ var SpanIOProcessor = class {
|
|
|
3601
3747
|
}
|
|
3602
3748
|
};
|
|
3603
3749
|
|
|
3750
|
+
// src/instrumentation/anthropic/version.ts
|
|
3751
|
+
var __version__ = "1.0.0";
|
|
3752
|
+
|
|
3753
|
+
// src/utils/response-handler.ts
|
|
3754
|
+
function isAsyncIterable(value) {
|
|
3755
|
+
return value != null && typeof value[Symbol.asyncIterator] === "function";
|
|
3756
|
+
}
|
|
3757
|
+
function isPromise(value) {
|
|
3758
|
+
return value != null && typeof value.then === "function";
|
|
3759
|
+
}
|
|
3760
|
+
var ITERATOR_METHODS = /* @__PURE__ */ new Set(["next", "return", "throw"]);
|
|
3761
|
+
function wrapAsyncIterable(source, callbacks) {
|
|
3762
|
+
function createWrappedIterator() {
|
|
3763
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
3764
|
+
let done = false;
|
|
3765
|
+
const safeFinalize = (status) => {
|
|
3766
|
+
if (done) return;
|
|
3767
|
+
done = true;
|
|
3768
|
+
try {
|
|
3769
|
+
callbacks.finalize(status);
|
|
3770
|
+
} catch (e) {
|
|
3771
|
+
Logger.error("netra: finalize callback error", e);
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3774
|
+
return {
|
|
3775
|
+
async next(value) {
|
|
3776
|
+
try {
|
|
3777
|
+
const result = await callbacks.withContext(() => iterator.next(value));
|
|
3778
|
+
if (!result.done) {
|
|
3779
|
+
try {
|
|
3780
|
+
callbacks.onChunk?.(result.value);
|
|
3781
|
+
} catch (e) {
|
|
3782
|
+
Logger.error("netra: onChunk callback error", e);
|
|
3783
|
+
}
|
|
3784
|
+
} else {
|
|
3785
|
+
safeFinalize("ok");
|
|
3786
|
+
}
|
|
3787
|
+
return result;
|
|
3788
|
+
} catch (e) {
|
|
3789
|
+
try {
|
|
3790
|
+
callbacks.onError(e);
|
|
3791
|
+
} catch {
|
|
3792
|
+
Logger.error("netra: onError callback error", e);
|
|
3793
|
+
}
|
|
3794
|
+
safeFinalize("error");
|
|
3795
|
+
throw e;
|
|
3796
|
+
}
|
|
3797
|
+
},
|
|
3798
|
+
async return(value) {
|
|
3799
|
+
try {
|
|
3800
|
+
const result = await callbacks.withContext(
|
|
3801
|
+
() => iterator.return?.(value) ?? { done: true, value }
|
|
3802
|
+
);
|
|
3803
|
+
safeFinalize("ok");
|
|
3804
|
+
return result;
|
|
3805
|
+
} catch (e) {
|
|
3806
|
+
try {
|
|
3807
|
+
callbacks.onError(e);
|
|
3808
|
+
} catch {
|
|
3809
|
+
Logger.error("netra: onError callback error", e);
|
|
3810
|
+
}
|
|
3811
|
+
safeFinalize("error");
|
|
3812
|
+
throw e;
|
|
3813
|
+
}
|
|
3814
|
+
},
|
|
3815
|
+
async throw(e) {
|
|
3816
|
+
try {
|
|
3817
|
+
const result = await callbacks.withContext(() => {
|
|
3818
|
+
if (iterator.throw) return iterator.throw(e);
|
|
3819
|
+
throw e;
|
|
3820
|
+
});
|
|
3821
|
+
if (result.done) safeFinalize("ok");
|
|
3822
|
+
return result;
|
|
3823
|
+
} catch (err) {
|
|
3824
|
+
try {
|
|
3825
|
+
callbacks.onError(err);
|
|
3826
|
+
} catch {
|
|
3827
|
+
Logger.error("netra: onError callback error", err);
|
|
3828
|
+
}
|
|
3829
|
+
safeFinalize("error");
|
|
3830
|
+
throw err;
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
};
|
|
3834
|
+
}
|
|
3835
|
+
let directIterator = null;
|
|
3836
|
+
return new Proxy(source, {
|
|
3837
|
+
get(target, prop) {
|
|
3838
|
+
if (prop === Symbol.asyncIterator) {
|
|
3839
|
+
return () => createWrappedIterator();
|
|
3840
|
+
}
|
|
3841
|
+
if (typeof prop === "string" && ITERATOR_METHODS.has(prop)) {
|
|
3842
|
+
if (!directIterator) directIterator = createWrappedIterator();
|
|
3843
|
+
return directIterator[prop].bind(directIterator);
|
|
3844
|
+
}
|
|
3845
|
+
const value = target[prop];
|
|
3846
|
+
if (typeof value === "function") return value.bind(target);
|
|
3847
|
+
return value;
|
|
3848
|
+
}
|
|
3849
|
+
});
|
|
3850
|
+
}
|
|
3851
|
+
function wrapPromise(promise, callbacks, options) {
|
|
3852
|
+
let finalized = false;
|
|
3853
|
+
function safeFinalize(status) {
|
|
3854
|
+
if (finalized) return;
|
|
3855
|
+
finalized = true;
|
|
3856
|
+
try {
|
|
3857
|
+
callbacks.finalize(status);
|
|
3858
|
+
} catch (e) {
|
|
3859
|
+
Logger.error("netra: finalize callback error", e);
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
const instrumentedPromise = (async () => {
|
|
3863
|
+
try {
|
|
3864
|
+
const value = await promise;
|
|
3865
|
+
if (isAsyncIterable(value)) {
|
|
3866
|
+
return wrapAsyncIterable(value, callbacks);
|
|
3867
|
+
}
|
|
3868
|
+
try {
|
|
3869
|
+
callbacks.onSuccess?.(value);
|
|
3870
|
+
} catch (e) {
|
|
3871
|
+
Logger.error("netra: onSuccess callback error", e);
|
|
3872
|
+
}
|
|
3873
|
+
safeFinalize("ok");
|
|
3874
|
+
return value;
|
|
3875
|
+
} catch (error) {
|
|
3876
|
+
try {
|
|
3877
|
+
callbacks.onError(error);
|
|
3878
|
+
} catch {
|
|
3879
|
+
Logger.error("netra: onError callback error", error);
|
|
3880
|
+
}
|
|
3881
|
+
safeFinalize("error");
|
|
3882
|
+
throw error;
|
|
3883
|
+
}
|
|
3884
|
+
})();
|
|
3885
|
+
if (!options?.preserveOriginal) {
|
|
3886
|
+
return instrumentedPromise;
|
|
3887
|
+
}
|
|
3888
|
+
const original = options.preserveOriginal;
|
|
3889
|
+
return new Proxy(instrumentedPromise, {
|
|
3890
|
+
get(target, prop, receiver) {
|
|
3891
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
3892
|
+
const value2 = Reflect.get(target, prop, receiver);
|
|
3893
|
+
if (typeof value2 === "function") return value2.bind(target);
|
|
3894
|
+
return value2;
|
|
3895
|
+
}
|
|
3896
|
+
const originalValue = original[prop];
|
|
3897
|
+
if (originalValue !== void 0) {
|
|
3898
|
+
if (typeof originalValue === "function")
|
|
3899
|
+
return originalValue.bind(original);
|
|
3900
|
+
return originalValue;
|
|
3901
|
+
}
|
|
3902
|
+
const value = Reflect.get(target, prop, receiver);
|
|
3903
|
+
if (typeof value === "function") return value.bind(target);
|
|
3904
|
+
return value;
|
|
3905
|
+
}
|
|
3906
|
+
});
|
|
3907
|
+
}
|
|
3908
|
+
function wrapResponse(response, callbacks, options) {
|
|
3909
|
+
if (isAsyncIterable(response)) {
|
|
3910
|
+
return wrapAsyncIterable(response, callbacks);
|
|
3911
|
+
}
|
|
3912
|
+
if (isPromise(response)) {
|
|
3913
|
+
return wrapPromise(response, callbacks, options);
|
|
3914
|
+
}
|
|
3915
|
+
try {
|
|
3916
|
+
callbacks.onSuccess?.(response);
|
|
3917
|
+
} catch (e) {
|
|
3918
|
+
Logger.error("netra: onSuccess callback error", e);
|
|
3919
|
+
}
|
|
3920
|
+
try {
|
|
3921
|
+
callbacks.finalize("ok");
|
|
3922
|
+
} catch (e) {
|
|
3923
|
+
Logger.error("netra: finalize callback error", e);
|
|
3924
|
+
}
|
|
3925
|
+
return response;
|
|
3926
|
+
}
|
|
3927
|
+
|
|
3604
3928
|
// src/instrumentation/span-attributes.ts
|
|
3605
3929
|
var SpanAttributes2 = {
|
|
3606
3930
|
LLM_SYSTEM: "gen_ai.system",
|
|
@@ -3611,10 +3935,14 @@ var SpanAttributes2 = {
|
|
|
3611
3935
|
LLM_REQUEST_TOP_P: "gen_ai.request.top_p",
|
|
3612
3936
|
LLM_REQUEST_REASONING: "gen_ai.request.reasoning",
|
|
3613
3937
|
LLM_REQUEST_REASONING_EFFORT: "gen_ai.request.reasoning_effort",
|
|
3938
|
+
LLM_REQUEST_TOOL_NAME: "gen_ai.request.tool.name",
|
|
3939
|
+
LLM_REQUEST_TOOL_ID: "gen_ai.request.tool.id",
|
|
3614
3940
|
LLM_RESPONSE_MODEL: "gen_ai.response.model",
|
|
3941
|
+
LLM_RESPONSE_FINISH_REASON: "llm.response.finish_reason",
|
|
3615
3942
|
LLM_USAGE_PROMPT_TOKENS: "gen_ai.usage.prompt_tokens",
|
|
3616
3943
|
LLM_USAGE_COMPLETION_TOKENS: "gen_ai.usage.completion_tokens",
|
|
3617
3944
|
LLM_USAGE_CACHE_READ_INPUT_TOKENS: "gen_ai.usage.cache_read_input_tokens",
|
|
3945
|
+
LLM_USAGE_CACHE_CREATION_INPUT_TOKENS: "gen_ai.usage.cache_creation_input_tokens",
|
|
3618
3946
|
LLM_USAGE_REASONING_TOKENS: "gen_ai.usage.reasoning_tokens",
|
|
3619
3947
|
LLM_USAGE_TOTAL_TOKENS: "llm.usage.total_tokens",
|
|
3620
3948
|
LLM_FREQUENCY_PENALTY: "llm.frequency_penalty",
|
|
@@ -3624,16 +3952,18 @@ var SpanAttributes2 = {
|
|
|
3624
3952
|
LLM_COMPLETIONS: "gen_ai.completion",
|
|
3625
3953
|
LLM_PROMPTS: "gen_ai.prompt"
|
|
3626
3954
|
};
|
|
3627
|
-
|
|
3628
|
-
|
|
3955
|
+
var VALID_NATIVE_TRACING_MODES = /* @__PURE__ */ new Set(["both", "netra", "netra-strict"]);
|
|
3956
|
+
function parseNativeTracingEnv(name) {
|
|
3957
|
+
const val = process.env[name];
|
|
3958
|
+
if (val === void 0 || val === "") return void 0;
|
|
3959
|
+
if (VALID_NATIVE_TRACING_MODES.has(val)) return val;
|
|
3960
|
+
return void 0;
|
|
3961
|
+
}
|
|
3629
3962
|
var SUPPRESS_INSTRUMENTATION_KEY = /* @__PURE__ */ Symbol("netra.suppress_instrumentation");
|
|
3630
3963
|
function shouldSuppressInstrumentation() {
|
|
3631
3964
|
const ctx = context.active();
|
|
3632
3965
|
return ctx.getValue(SUPPRESS_INSTRUMENTATION_KEY) === true;
|
|
3633
3966
|
}
|
|
3634
|
-
function isPromise(value) {
|
|
3635
|
-
return value instanceof Promise;
|
|
3636
|
-
}
|
|
3637
3967
|
function defineHidden(target, key, value) {
|
|
3638
3968
|
Object.defineProperty(target, key, {
|
|
3639
3969
|
value,
|
|
@@ -3663,18 +3993,6 @@ function isTraceContentEnabled() {
|
|
|
3663
3993
|
const raw = process.env.TRACELOOP_TRACE_CONTENT ?? process.env.NETRA_TRACE_CONTENT ?? "";
|
|
3664
3994
|
return ["1", "true"].includes(String(raw).toLowerCase());
|
|
3665
3995
|
}
|
|
3666
|
-
function safeStringify(value) {
|
|
3667
|
-
if (typeof value === "string") return value;
|
|
3668
|
-
try {
|
|
3669
|
-
return JSON.stringify(value);
|
|
3670
|
-
} catch {
|
|
3671
|
-
return String(value);
|
|
3672
|
-
}
|
|
3673
|
-
}
|
|
3674
|
-
function truncate(value, maxLen) {
|
|
3675
|
-
if (!value || value.length <= maxLen) return value;
|
|
3676
|
-
return value.slice(0, maxLen) + "...(truncated)";
|
|
3677
|
-
}
|
|
3678
3996
|
function hasContent(value) {
|
|
3679
3997
|
if (value === void 0 || value === null) return false;
|
|
3680
3998
|
if (typeof value === "string") return value.length > 0;
|
|
@@ -3705,7 +4023,7 @@ function setModelParams(span2, kwargs) {
|
|
|
3705
4023
|
}
|
|
3706
4024
|
function buildInputMessages(kwargs, requestType) {
|
|
3707
4025
|
const messages = [];
|
|
3708
|
-
if (requestType === "chat") {
|
|
4026
|
+
if (requestType === "chat" || requestType === "beta") {
|
|
3709
4027
|
if (hasContent(kwargs.system)) {
|
|
3710
4028
|
const systemContent = typeof kwargs.system === "string" ? kwargs.system : safeStringify(kwargs.system);
|
|
3711
4029
|
messages.push({ role: "system", content: systemContent });
|
|
@@ -3713,12 +4031,34 @@ function buildInputMessages(kwargs, requestType) {
|
|
|
3713
4031
|
const rawMessages = kwargs.messages;
|
|
3714
4032
|
if (!Array.isArray(rawMessages)) return messages;
|
|
3715
4033
|
for (const msg of rawMessages) {
|
|
3716
|
-
if (!isDict(msg))
|
|
3717
|
-
|
|
4034
|
+
if (!isDict(msg) || !hasContent(msg.role) || !hasContent(msg.content)) {
|
|
4035
|
+
continue;
|
|
4036
|
+
}
|
|
4037
|
+
if (msg.role !== "user" || !Array.isArray(msg.content)) {
|
|
3718
4038
|
messages.push({
|
|
3719
4039
|
role: msg.role,
|
|
3720
4040
|
content: safeStringify(msg.content)
|
|
3721
4041
|
});
|
|
4042
|
+
continue;
|
|
4043
|
+
}
|
|
4044
|
+
const isToolResult = (b) => isDict(b) && b.type === "tool_result";
|
|
4045
|
+
const userBlocks = msg.content.filter((b) => !isToolResult(b));
|
|
4046
|
+
if (userBlocks.length) {
|
|
4047
|
+
messages.push({
|
|
4048
|
+
role: "user",
|
|
4049
|
+
content: safeStringify(userBlocks)
|
|
4050
|
+
});
|
|
4051
|
+
}
|
|
4052
|
+
for (const block of msg.content) {
|
|
4053
|
+
if (!isToolResult(block)) continue;
|
|
4054
|
+
messages.push({
|
|
4055
|
+
role: "tool",
|
|
4056
|
+
content: safeStringify({
|
|
4057
|
+
tool_use_id: block.tool_use_id,
|
|
4058
|
+
content: block.content,
|
|
4059
|
+
is_error: block.is_error ?? false
|
|
4060
|
+
}, Config.CONVERSATION_MAX_LEN)
|
|
4061
|
+
});
|
|
3722
4062
|
}
|
|
3723
4063
|
}
|
|
3724
4064
|
} else if (requestType === "response") {
|
|
@@ -3747,10 +4087,7 @@ function buildInputMessages(kwargs, requestType) {
|
|
|
3747
4087
|
} else {
|
|
3748
4088
|
const input = kwargs.input ?? kwargs.inputs;
|
|
3749
4089
|
if (hasContent(input)) {
|
|
3750
|
-
const content =
|
|
3751
|
-
safeStringify(input),
|
|
3752
|
-
Config.CONVERSATION_MAX_LEN
|
|
3753
|
-
);
|
|
4090
|
+
const content = safeStringify(input, Config.CONVERSATION_MAX_LEN);
|
|
3754
4091
|
messages.push({ role: "user", content });
|
|
3755
4092
|
}
|
|
3756
4093
|
}
|
|
@@ -3817,7 +4154,7 @@ function buildOutputMessages(response) {
|
|
|
3817
4154
|
} else if (block.type === "tool_use" && block.name) {
|
|
3818
4155
|
messages.push({
|
|
3819
4156
|
role: "tool",
|
|
3820
|
-
content: JSON.stringify({ name: block.name, input: block.input })
|
|
4157
|
+
content: JSON.stringify({ id: block.id, name: block.name, input: block.input })
|
|
3821
4158
|
});
|
|
3822
4159
|
}
|
|
3823
4160
|
}
|
|
@@ -3827,13 +4164,14 @@ function buildOutputMessages(response) {
|
|
|
3827
4164
|
function writePromptAttributes(span2, messages) {
|
|
3828
4165
|
if (messages.length === 0) return;
|
|
3829
4166
|
for (let i = 0; i < messages.length; i++) {
|
|
4167
|
+
const msg = messages[i];
|
|
3830
4168
|
span2.setAttribute(
|
|
3831
4169
|
`${SpanAttributes2.LLM_PROMPTS}.${i}.role`,
|
|
3832
|
-
|
|
4170
|
+
msg.role
|
|
3833
4171
|
);
|
|
3834
4172
|
span2.setAttribute(
|
|
3835
4173
|
`${SpanAttributes2.LLM_PROMPTS}.${i}.content`,
|
|
3836
|
-
|
|
4174
|
+
msg.content
|
|
3837
4175
|
);
|
|
3838
4176
|
}
|
|
3839
4177
|
span2.setAttribute("input", JSON.stringify(messages));
|
|
@@ -3885,6 +4223,9 @@ function setRequestAttributes(span2, kwargs, requestType, system) {
|
|
|
3885
4223
|
span2.setAttribute(SpanAttributes2.LLM_REQUEST_MODEL, String(kwargs.model));
|
|
3886
4224
|
}
|
|
3887
4225
|
setModelParams(span2, kwargs);
|
|
4226
|
+
if (Array.isArray(kwargs.tools)) {
|
|
4227
|
+
span2.setAttribute("tools", safeStringify(kwargs.tools, Config.ATTRIBUTE_MAX_LEN));
|
|
4228
|
+
}
|
|
3888
4229
|
if (kwargs.reasoning !== void 0) {
|
|
3889
4230
|
span2.setAttribute(
|
|
3890
4231
|
SpanAttributes2.LLM_REQUEST_REASONING,
|
|
@@ -3897,7 +4238,7 @@ function setRequestAttributes(span2, kwargs, requestType, system) {
|
|
|
3897
4238
|
if (kwargs.suffix !== void 0) {
|
|
3898
4239
|
span2.setAttribute(
|
|
3899
4240
|
"llm.request.suffix",
|
|
3900
|
-
|
|
4241
|
+
safeStringify(kwargs.suffix, Config.CONVERSATION_MAX_LEN)
|
|
3901
4242
|
);
|
|
3902
4243
|
}
|
|
3903
4244
|
}
|
|
@@ -3920,12 +4261,20 @@ function setResponseAttributes(span2, response) {
|
|
|
3920
4261
|
}
|
|
3921
4262
|
}
|
|
3922
4263
|
function setFinishReason(span2, response) {
|
|
4264
|
+
if (response.stop_reason) {
|
|
4265
|
+
span2.setAttribute(
|
|
4266
|
+
SpanAttributes2.LLM_RESPONSE_FINISH_REASON,
|
|
4267
|
+
String(response.stop_reason)
|
|
4268
|
+
);
|
|
4269
|
+
span2.setAttribute("gen_ai.response.finish_reason", String(response.stop_reason));
|
|
4270
|
+
}
|
|
3923
4271
|
const choices = response.choices;
|
|
3924
|
-
if (
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
4272
|
+
if (Array.isArray(choices) && choices.length > 0) {
|
|
4273
|
+
const reason = choices[0].finish_reason ?? choices[0].finishReason;
|
|
4274
|
+
if (reason) {
|
|
4275
|
+
span2.setAttribute(SpanAttributes2.LLM_RESPONSE_FINISH_REASON, String(reason));
|
|
4276
|
+
span2.setAttribute("gen_ai.response.finish_reason", String(reason));
|
|
4277
|
+
}
|
|
3929
4278
|
}
|
|
3930
4279
|
}
|
|
3931
4280
|
function setUsageAttributes(span2, response) {
|
|
@@ -3952,11 +4301,18 @@ function setUsageAttributes(span2, response) {
|
|
|
3952
4301
|
Number(totalTokens)
|
|
3953
4302
|
);
|
|
3954
4303
|
}
|
|
3955
|
-
const
|
|
3956
|
-
if (
|
|
4304
|
+
const cacheReadTokens = usage.cache_read_input_tokens ?? (usage.prompt_tokens_details ?? usage.input_tokens_details)?.cached_tokens;
|
|
4305
|
+
if (cacheReadTokens !== void 0) {
|
|
3957
4306
|
span2.setAttribute(
|
|
3958
4307
|
SpanAttributes2.LLM_USAGE_CACHE_READ_INPUT_TOKENS,
|
|
3959
|
-
Number(
|
|
4308
|
+
Number(cacheReadTokens)
|
|
4309
|
+
);
|
|
4310
|
+
}
|
|
4311
|
+
const cacheCreationTokens = usage.cache_creation_input_tokens;
|
|
4312
|
+
if (cacheCreationTokens !== void 0) {
|
|
4313
|
+
span2.setAttribute(
|
|
4314
|
+
SpanAttributes2.LLM_USAGE_CACHE_CREATION_INPUT_TOKENS,
|
|
4315
|
+
Number(cacheCreationTokens)
|
|
3960
4316
|
);
|
|
3961
4317
|
}
|
|
3962
4318
|
const reasoningTokens = (usage.completion_tokens_details ?? usage.output_tokens_details)?.reasoning_tokens;
|
|
@@ -3978,188 +4334,181 @@ function setEmbeddingResponseMeta(span2, response) {
|
|
|
3978
4334
|
}
|
|
3979
4335
|
}
|
|
3980
4336
|
|
|
3981
|
-
// src/instrumentation/anthropic/
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
if (!span2.isRecording()) {
|
|
3991
|
-
Logger.log("Span is not recording");
|
|
3992
|
-
return;
|
|
3993
|
-
}
|
|
3994
|
-
if (response?.type === "message_batch") {
|
|
3995
|
-
span2.setAttribute("status", response?.processing_status);
|
|
3996
|
-
}
|
|
3997
|
-
setResponseAttributes(span2, response);
|
|
3998
|
-
}
|
|
4337
|
+
// src/instrumentation/anthropic/types.ts
|
|
4338
|
+
var SPAN_NAMES = {
|
|
4339
|
+
CHAT: "anthropic.chat",
|
|
4340
|
+
STREAM: "anthropic.stream",
|
|
4341
|
+
BATCHES: "anthropic.batches",
|
|
4342
|
+
BETA: "anthropic.beta",
|
|
4343
|
+
BETA_STREAM: "anthropic.beta.stream",
|
|
4344
|
+
BETA_TOOL_RUNNER: "anthropic.beta.tool.runner"
|
|
4345
|
+
};
|
|
3999
4346
|
|
|
4000
|
-
// src/instrumentation/anthropic/
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
return function wrapper(wrapped, instance, args, kwargs) {
|
|
4008
|
-
if (shouldSuppressInstrumentation()) {
|
|
4009
|
-
const result = wrapped.call(instance, ...args);
|
|
4010
|
-
return isPromise(result) ? result.then((value) => value) : result;
|
|
4011
|
-
}
|
|
4012
|
-
const currentContext = context.active();
|
|
4013
|
-
const isStreaming = args[0]?.stream === true;
|
|
4014
|
-
const activeSpan = trace.getSpan(context.active());
|
|
4015
|
-
Logger.debug(`Anthropic invoke (${requestType}). Active TraceId: ${activeSpan?.spanContext().traceId}, SpanId: ${activeSpan?.spanContext().spanId}`);
|
|
4016
|
-
if (isStreaming && STREAM_ENABLED_REQUESTS.includes(requestType)) {
|
|
4017
|
-
const span2 = tracer.startSpan(
|
|
4018
|
-
spanName + ".create",
|
|
4019
|
-
{
|
|
4020
|
-
kind: SpanKind.CLIENT,
|
|
4021
|
-
attributes: {
|
|
4022
|
-
"llm.request.type": requestType,
|
|
4023
|
-
"llm.streaming": true
|
|
4024
|
-
}
|
|
4025
|
-
},
|
|
4026
|
-
currentContext
|
|
4027
|
-
);
|
|
4028
|
-
try {
|
|
4029
|
-
setRequestAttributes2(span2, kwargs, requestType);
|
|
4030
|
-
const startTime = Date.now();
|
|
4031
|
-
const spanContext = trace.setSpan(currentContext, span2);
|
|
4032
|
-
const response = context.with(spanContext, () => wrapped.call(instance, ...args));
|
|
4033
|
-
if (isPromise(response)) {
|
|
4034
|
-
return (async () => {
|
|
4035
|
-
try {
|
|
4036
|
-
const stream = await response;
|
|
4037
|
-
return new AsyncStreamingWrapper(span2, stream, startTime, kwargs, spanContext);
|
|
4038
|
-
} catch (error) {
|
|
4039
|
-
Logger.error("netra.instrumentation.anthropic:", error);
|
|
4040
|
-
span2.setStatus({
|
|
4041
|
-
code: SpanStatusCode.ERROR,
|
|
4042
|
-
message: error instanceof Error ? error.message : String(error)
|
|
4043
|
-
});
|
|
4044
|
-
span2.recordException(error);
|
|
4045
|
-
span2.end();
|
|
4046
|
-
throw error;
|
|
4047
|
-
}
|
|
4048
|
-
})();
|
|
4049
|
-
} else {
|
|
4050
|
-
return new AsyncStreamingWrapper(span2, response, startTime, kwargs, spanContext);
|
|
4347
|
+
// src/instrumentation/anthropic/utils.ts
|
|
4348
|
+
function processStreamChunk(completeResponse, chunk, span2) {
|
|
4349
|
+
try {
|
|
4350
|
+
switch (chunk.type) {
|
|
4351
|
+
case "message_start": {
|
|
4352
|
+
if (chunk.message?.model) {
|
|
4353
|
+
completeResponse.model = chunk.message.model;
|
|
4051
4354
|
}
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
message: error instanceof Error ? error.message : String(error)
|
|
4057
|
-
});
|
|
4058
|
-
span2.recordException(error);
|
|
4059
|
-
span2.end();
|
|
4060
|
-
throw error;
|
|
4355
|
+
if (chunk.message?.usage) {
|
|
4356
|
+
completeResponse.usage = chunk.message.usage;
|
|
4357
|
+
}
|
|
4358
|
+
break;
|
|
4061
4359
|
}
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
return value2;
|
|
4108
|
-
}
|
|
4109
|
-
const responseValue = response[prop];
|
|
4110
|
-
if (responseValue !== void 0) {
|
|
4111
|
-
if (typeof responseValue === "function") {
|
|
4112
|
-
return responseValue.bind(response);
|
|
4113
|
-
}
|
|
4114
|
-
return responseValue;
|
|
4115
|
-
}
|
|
4116
|
-
const value = Reflect.get(target, prop, receiver);
|
|
4117
|
-
if (typeof value === "function") {
|
|
4118
|
-
return value.bind(target);
|
|
4119
|
-
}
|
|
4120
|
-
return value;
|
|
4121
|
-
}
|
|
4122
|
-
});
|
|
4123
|
-
} else {
|
|
4124
|
-
const endTime = Date.now();
|
|
4125
|
-
const responseDict = modelAsDict(response);
|
|
4126
|
-
setResponseAttributes2(span2, responseDict);
|
|
4127
|
-
span2.setAttribute(
|
|
4128
|
-
"llm.response.duration",
|
|
4129
|
-
(endTime - startTime) / 1e3
|
|
4360
|
+
case "content_block_start": {
|
|
4361
|
+
if (!completeResponse.content) {
|
|
4362
|
+
completeResponse.content = [];
|
|
4363
|
+
}
|
|
4364
|
+
const block = chunk.content_block;
|
|
4365
|
+
if (!block) break;
|
|
4366
|
+
if (block.type === "tool_use") {
|
|
4367
|
+
completeResponse.content.push({
|
|
4368
|
+
type: "tool_use",
|
|
4369
|
+
id: block.id,
|
|
4370
|
+
name: block.name,
|
|
4371
|
+
input: ""
|
|
4372
|
+
});
|
|
4373
|
+
} else {
|
|
4374
|
+
completeResponse.content.push({
|
|
4375
|
+
type: block.type,
|
|
4376
|
+
text: ""
|
|
4377
|
+
});
|
|
4378
|
+
}
|
|
4379
|
+
break;
|
|
4380
|
+
}
|
|
4381
|
+
case "content_block_delta": {
|
|
4382
|
+
if (!completeResponse.content || completeResponse.content.length === 0) {
|
|
4383
|
+
completeResponse.content = [{ type: "text", text: "" }];
|
|
4384
|
+
}
|
|
4385
|
+
const targetIndex = chunk.index ?? completeResponse.content.length - 1;
|
|
4386
|
+
const targetBlock = completeResponse.content[targetIndex];
|
|
4387
|
+
if (!targetBlock) break;
|
|
4388
|
+
if (chunk.delta?.type === "input_json_delta" && targetBlock.type === "tool_use") {
|
|
4389
|
+
targetBlock.input += chunk.delta.partial_json ?? "";
|
|
4390
|
+
} else if (chunk.delta?.text) {
|
|
4391
|
+
targetBlock.text += chunk.delta.text;
|
|
4392
|
+
}
|
|
4393
|
+
break;
|
|
4394
|
+
}
|
|
4395
|
+
case "content_block_stop": {
|
|
4396
|
+
const blocks = completeResponse.content;
|
|
4397
|
+
if (blocks && blocks.length > 0) {
|
|
4398
|
+
const finishedBlock = blocks[blocks.length - 1];
|
|
4399
|
+
if (finishedBlock?.type === "tool_use" && typeof finishedBlock.input === "string") {
|
|
4400
|
+
try {
|
|
4401
|
+
finishedBlock.input = JSON.parse(finishedBlock.input);
|
|
4402
|
+
} catch {
|
|
4403
|
+
Logger.warn(
|
|
4404
|
+
"netra.instrumentation.anthropic: Failed to parse tool use input"
|
|
4130
4405
|
);
|
|
4131
|
-
span2.setStatus({ code: SpanStatusCode.OK });
|
|
4132
|
-
span2.end();
|
|
4133
|
-
return response;
|
|
4134
4406
|
}
|
|
4135
|
-
} catch (error) {
|
|
4136
|
-
Logger.error("netra.instrumentation.anthropic:", error);
|
|
4137
|
-
span2.setStatus({
|
|
4138
|
-
code: SpanStatusCode.ERROR,
|
|
4139
|
-
message: error instanceof Error ? error.message : String(error)
|
|
4140
|
-
});
|
|
4141
|
-
span2.recordException(error);
|
|
4142
|
-
span2.end();
|
|
4143
|
-
throw error;
|
|
4144
4407
|
}
|
|
4145
4408
|
}
|
|
4146
|
-
|
|
4409
|
+
break;
|
|
4410
|
+
}
|
|
4411
|
+
case "message_delta": {
|
|
4412
|
+
if (chunk.delta?.stop_reason) {
|
|
4413
|
+
completeResponse.stop_reason = chunk.delta.stop_reason;
|
|
4414
|
+
}
|
|
4415
|
+
const usageData = chunk.usage ?? chunk.delta?.usage;
|
|
4416
|
+
if (usageData) {
|
|
4417
|
+
completeResponse.usage = {
|
|
4418
|
+
...completeResponse.usage ?? {},
|
|
4419
|
+
...usageData
|
|
4420
|
+
};
|
|
4421
|
+
}
|
|
4422
|
+
break;
|
|
4423
|
+
}
|
|
4424
|
+
case "message_stop": {
|
|
4425
|
+
if (chunk.usage) {
|
|
4426
|
+
completeResponse.usage = {
|
|
4427
|
+
...completeResponse.usage ?? {},
|
|
4428
|
+
...chunk.usage
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
break;
|
|
4432
|
+
}
|
|
4147
4433
|
}
|
|
4148
|
-
|
|
4434
|
+
if (Logger.isDebugMode()) {
|
|
4435
|
+
span2.addEvent("llm.content.completion.chunk", {
|
|
4436
|
+
"chunk.type": chunk.type
|
|
4437
|
+
});
|
|
4438
|
+
}
|
|
4439
|
+
} catch (e) {
|
|
4440
|
+
Logger.error(
|
|
4441
|
+
"netra.instrumentation.anthropic: processStreamChunk error",
|
|
4442
|
+
e
|
|
4443
|
+
);
|
|
4444
|
+
}
|
|
4149
4445
|
}
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4446
|
+
function finalizeStreamSpan(span2, completeResponse, startTime, code) {
|
|
4447
|
+
try {
|
|
4448
|
+
const endTime = Date.now();
|
|
4449
|
+
setResponseAttributes2(span2, {
|
|
4450
|
+
model: completeResponse.model,
|
|
4451
|
+
content: completeResponse.content,
|
|
4452
|
+
usage: completeResponse.usage,
|
|
4453
|
+
stop_reason: completeResponse.stop_reason
|
|
4454
|
+
});
|
|
4455
|
+
span2.setAttribute("llm.response.duration", (endTime - startTime) / 1e3);
|
|
4456
|
+
span2.setStatus({ code });
|
|
4457
|
+
} catch (e) {
|
|
4458
|
+
Logger.error(
|
|
4459
|
+
"netra.instrumentation.anthropic: finalizeStreamSpan error",
|
|
4460
|
+
e
|
|
4461
|
+
);
|
|
4462
|
+
} finally {
|
|
4463
|
+
span2.end();
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
function setRequestAttributes2(span2, kwargs, requestType) {
|
|
4467
|
+
try {
|
|
4468
|
+
if (!span2.isRecording()) {
|
|
4469
|
+
Logger.log("Span is not recording");
|
|
4470
|
+
return;
|
|
4471
|
+
}
|
|
4472
|
+
setRequestAttributes(span2, kwargs, requestType, "anthropic");
|
|
4473
|
+
} catch (e) {
|
|
4474
|
+
Logger.error(
|
|
4475
|
+
"netra.instrumentation.anthropic: setRequestAttributes error",
|
|
4476
|
+
e
|
|
4477
|
+
);
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
function setResponseAttributes2(span2, response) {
|
|
4481
|
+
try {
|
|
4482
|
+
if (!span2.isRecording()) {
|
|
4483
|
+
Logger.log("Span is not recording");
|
|
4484
|
+
return;
|
|
4485
|
+
}
|
|
4486
|
+
if (response?.type === "message_batch") {
|
|
4487
|
+
span2.setAttribute("status", response?.processing_status);
|
|
4488
|
+
}
|
|
4489
|
+
setResponseAttributes(span2, response);
|
|
4490
|
+
} catch (e) {
|
|
4491
|
+
Logger.error(
|
|
4492
|
+
"netra.instrumentation.anthropic: setResponseAttributes error",
|
|
4493
|
+
e
|
|
4494
|
+
);
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
|
|
4498
|
+
// src/instrumentation/anthropic/wrappers.ts
|
|
4153
4499
|
var WRAPPER_OWN_PROPS = /* @__PURE__ */ new Set([
|
|
4154
4500
|
"span",
|
|
4155
4501
|
"messageStream",
|
|
4156
4502
|
"startTime",
|
|
4157
4503
|
"requestKwargs",
|
|
4158
4504
|
"completeResponse",
|
|
4159
|
-
"
|
|
4160
|
-
"finalizeSpan",
|
|
4505
|
+
"finalizeSpanOnce",
|
|
4161
4506
|
"processEventData",
|
|
4162
|
-
"finalizeSpanFromMessage"
|
|
4507
|
+
"finalizeSpanFromMessage",
|
|
4508
|
+
"parentContext",
|
|
4509
|
+
"spanFinalized",
|
|
4510
|
+
"completionPending",
|
|
4511
|
+
"listenerMap"
|
|
4163
4512
|
]);
|
|
4164
4513
|
var EVENT_EMITTER_METHODS = /* @__PURE__ */ new Set([
|
|
4165
4514
|
"on",
|
|
@@ -4173,20 +4522,90 @@ var EVENT_EMITTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
4173
4522
|
"listenerCount"
|
|
4174
4523
|
]);
|
|
4175
4524
|
var LISTENER_REGISTRATION_METHODS = /* @__PURE__ */ new Set(["on", "once", "addListener"]);
|
|
4525
|
+
var LISTENER_REMOVAL_METHODS = /* @__PURE__ */ new Set(["off", "removeListener"]);
|
|
4176
4526
|
var COMPLETION_METHODS = /* @__PURE__ */ new Set(["finalMessage", "done", "finalText"]);
|
|
4177
|
-
var TRACKED_STREAM_EVENTS = /* @__PURE__ */ new Set([
|
|
4527
|
+
var TRACKED_STREAM_EVENTS = /* @__PURE__ */ new Set([
|
|
4528
|
+
"message",
|
|
4529
|
+
"contentBlock",
|
|
4530
|
+
"text",
|
|
4531
|
+
"finalMessage"
|
|
4532
|
+
]);
|
|
4533
|
+
var MAX_TOOL_ATTR_LENGTH = 4096;
|
|
4534
|
+
function wrapRunnableTools(tools, tracer, parentContext) {
|
|
4535
|
+
return tools.map((tool) => {
|
|
4536
|
+
if (typeof tool.run !== "function") return tool;
|
|
4537
|
+
const originalRun = tool.run;
|
|
4538
|
+
const toolName = tool.name ?? "unknown_tool";
|
|
4539
|
+
const wrappedRun = async function(input, runContext) {
|
|
4540
|
+
const toolUseId = runContext?.toolUse?.id ?? runContext?.toolUseBlock?.id;
|
|
4541
|
+
const traceContent = isTraceContentEnabled();
|
|
4542
|
+
const attrs = {
|
|
4543
|
+
"netra.span.type": "TOOL",
|
|
4544
|
+
[SpanAttributes2.LLM_REQUEST_TOOL_NAME]: toolName
|
|
4545
|
+
};
|
|
4546
|
+
if (toolUseId) attrs[SpanAttributes2.LLM_REQUEST_TOOL_ID] = toolUseId;
|
|
4547
|
+
if (traceContent) {
|
|
4548
|
+
attrs.input = safeStringify(input, MAX_TOOL_ATTR_LENGTH);
|
|
4549
|
+
}
|
|
4550
|
+
const span2 = tracer.startSpan(
|
|
4551
|
+
toolName,
|
|
4552
|
+
{ kind: SpanKind.INTERNAL, attributes: attrs },
|
|
4553
|
+
parentContext
|
|
4554
|
+
);
|
|
4555
|
+
const spanCtx = trace.setSpan(parentContext, span2);
|
|
4556
|
+
try {
|
|
4557
|
+
const result = await context.with(
|
|
4558
|
+
spanCtx,
|
|
4559
|
+
() => originalRun.call(this, input, runContext)
|
|
4560
|
+
);
|
|
4561
|
+
if (traceContent) {
|
|
4562
|
+
span2.setAttribute(
|
|
4563
|
+
"output",
|
|
4564
|
+
safeStringify(result, MAX_TOOL_ATTR_LENGTH)
|
|
4565
|
+
);
|
|
4566
|
+
}
|
|
4567
|
+
span2.setStatus({ code: SpanStatusCode.OK });
|
|
4568
|
+
return result;
|
|
4569
|
+
} catch (error) {
|
|
4570
|
+
span2.setStatus({
|
|
4571
|
+
code: SpanStatusCode.ERROR,
|
|
4572
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4573
|
+
});
|
|
4574
|
+
span2.recordException(error);
|
|
4575
|
+
throw error;
|
|
4576
|
+
} finally {
|
|
4577
|
+
span2.end();
|
|
4578
|
+
}
|
|
4579
|
+
};
|
|
4580
|
+
const wrapped = Object.create(
|
|
4581
|
+
Object.getPrototypeOf(tool),
|
|
4582
|
+
Object.getOwnPropertyDescriptors(tool)
|
|
4583
|
+
);
|
|
4584
|
+
wrapped.run = wrappedRun;
|
|
4585
|
+
return wrapped;
|
|
4586
|
+
});
|
|
4587
|
+
}
|
|
4178
4588
|
var MessageStreamWrapper = class {
|
|
4179
|
-
constructor(span2, messageStream, startTime, requestKwargs, spanContext) {
|
|
4589
|
+
constructor(span2, messageStream, startTime, requestKwargs, spanContext, parentContext) {
|
|
4180
4590
|
this.completeResponse = {
|
|
4181
4591
|
content: [],
|
|
4182
4592
|
model: "",
|
|
4183
4593
|
usage: {}
|
|
4184
4594
|
};
|
|
4595
|
+
this.spanFinalized = false;
|
|
4596
|
+
this.completionPending = false;
|
|
4597
|
+
this.listenerMap = /* @__PURE__ */ new WeakMap();
|
|
4185
4598
|
defineHidden(this, "span", span2);
|
|
4186
4599
|
defineHidden(this, "messageStream", messageStream);
|
|
4187
4600
|
defineHidden(this, "startTime", startTime);
|
|
4188
4601
|
defineHidden(this, "requestKwargs", requestKwargs);
|
|
4189
|
-
defineHidden(
|
|
4602
|
+
defineHidden(
|
|
4603
|
+
this,
|
|
4604
|
+
"spanContext",
|
|
4605
|
+
spanContext || trace.setSpan(context.active(), span2)
|
|
4606
|
+
);
|
|
4607
|
+
defineHidden(this, "parentContext", parentContext || context.active());
|
|
4608
|
+
this.registerSafetyNetListeners();
|
|
4190
4609
|
return new Proxy(this, {
|
|
4191
4610
|
get(target, prop, receiver) {
|
|
4192
4611
|
if (prop === "toJSON") {
|
|
@@ -4200,67 +4619,135 @@ var MessageStreamWrapper = class {
|
|
|
4200
4619
|
}
|
|
4201
4620
|
if (typeof prop === "string" && EVENT_EMITTER_METHODS.has(prop)) {
|
|
4202
4621
|
const method = target.messageStream[prop];
|
|
4203
|
-
if (typeof method
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4622
|
+
if (typeof method !== "function") return method;
|
|
4623
|
+
if (LISTENER_REGISTRATION_METHODS.has(prop)) {
|
|
4624
|
+
return function(event, listener) {
|
|
4625
|
+
const wrappedListener = (...args) => {
|
|
4626
|
+
try {
|
|
4207
4627
|
target.span.addEvent(`messagestream.event.${event}`, {
|
|
4208
4628
|
"event.type": event
|
|
4209
4629
|
});
|
|
4210
|
-
if (TRACKED_STREAM_EVENTS.has(event)) {
|
|
4211
|
-
|
|
4212
|
-
target.processEventData(event, args[0]);
|
|
4213
|
-
}
|
|
4630
|
+
if (TRACKED_STREAM_EVENTS.has(event) && args[0]) {
|
|
4631
|
+
target.processEventData(event, args[0]);
|
|
4214
4632
|
}
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4633
|
+
} catch (e) {
|
|
4634
|
+
Logger.error(
|
|
4635
|
+
"netra.instrumentation.anthropic: event tracking error",
|
|
4636
|
+
e
|
|
4637
|
+
);
|
|
4638
|
+
}
|
|
4639
|
+
return listener(...args);
|
|
4218
4640
|
};
|
|
4219
|
-
|
|
4220
|
-
|
|
4641
|
+
let eventMap = target.listenerMap.get(listener);
|
|
4642
|
+
if (!eventMap) {
|
|
4643
|
+
eventMap = /* @__PURE__ */ new Map();
|
|
4644
|
+
target.listenerMap.set(listener, eventMap);
|
|
4645
|
+
}
|
|
4646
|
+
let wrappers = eventMap.get(event);
|
|
4647
|
+
if (!wrappers) {
|
|
4648
|
+
wrappers = [];
|
|
4649
|
+
eventMap.set(event, wrappers);
|
|
4650
|
+
}
|
|
4651
|
+
wrappers.push(wrappedListener);
|
|
4652
|
+
return method.call(target.messageStream, event, wrappedListener);
|
|
4653
|
+
};
|
|
4654
|
+
}
|
|
4655
|
+
if (LISTENER_REMOVAL_METHODS.has(prop)) {
|
|
4656
|
+
return function(event, listener) {
|
|
4657
|
+
const eventMap = target.listenerMap.get(listener);
|
|
4658
|
+
const wrappers = eventMap?.get(event);
|
|
4659
|
+
const wrapped = wrappers?.shift() ?? listener;
|
|
4660
|
+
if (wrappers && wrappers.length === 0) eventMap?.delete(event);
|
|
4661
|
+
return method.call(target.messageStream, event, wrapped);
|
|
4662
|
+
};
|
|
4221
4663
|
}
|
|
4222
|
-
|
|
4664
|
+
if (prop === "removeAllListeners") {
|
|
4665
|
+
return function(event) {
|
|
4666
|
+
target.listenerMap = /* @__PURE__ */ new WeakMap();
|
|
4667
|
+
return method.call(target.messageStream, event);
|
|
4668
|
+
};
|
|
4669
|
+
}
|
|
4670
|
+
return method.bind(target.messageStream);
|
|
4223
4671
|
}
|
|
4224
4672
|
if (typeof prop === "string" && COMPLETION_METHODS.has(prop)) {
|
|
4225
4673
|
const method = target.messageStream[prop];
|
|
4226
|
-
if (typeof method
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4674
|
+
if (typeof method !== "function") return method;
|
|
4675
|
+
return async function(...args) {
|
|
4676
|
+
target.completionPending = true;
|
|
4677
|
+
try {
|
|
4678
|
+
const result = await method.call(target.messageStream, ...args);
|
|
4679
|
+
if (prop === "finalMessage" || prop === "done") {
|
|
4680
|
+
target.finalizeSpanFromMessage(result);
|
|
4681
|
+
} else if (prop === "finalText") {
|
|
4682
|
+
if (typeof result === "string" && result.length > 0) {
|
|
4683
|
+
target.completeResponse.content = [
|
|
4684
|
+
{ type: "text", text: result }
|
|
4685
|
+
];
|
|
4686
|
+
} else {
|
|
4687
|
+
target.flushCurrentText();
|
|
4232
4688
|
}
|
|
4233
|
-
|
|
4234
|
-
} catch (error) {
|
|
4235
|
-
target.finalizeSpan(SpanStatusCode.ERROR);
|
|
4236
|
-
throw error;
|
|
4689
|
+
target.finalizeSpanOnce(SpanStatusCode.OK);
|
|
4237
4690
|
}
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4691
|
+
return result;
|
|
4692
|
+
} catch (error) {
|
|
4693
|
+
target.finalizeSpanOnce(SpanStatusCode.ERROR);
|
|
4694
|
+
throw error;
|
|
4695
|
+
}
|
|
4696
|
+
};
|
|
4241
4697
|
}
|
|
4242
4698
|
const value = target.messageStream[prop];
|
|
4243
|
-
if (typeof value === "function")
|
|
4699
|
+
if (typeof value === "function")
|
|
4244
4700
|
return value.bind(target.messageStream);
|
|
4245
|
-
}
|
|
4246
4701
|
return value;
|
|
4247
4702
|
}
|
|
4248
4703
|
});
|
|
4249
4704
|
}
|
|
4705
|
+
registerSafetyNetListeners() {
|
|
4706
|
+
try {
|
|
4707
|
+
if (typeof this.messageStream?.on !== "function") return;
|
|
4708
|
+
this.messageStream.on("end", () => {
|
|
4709
|
+
if (!this.completionPending) {
|
|
4710
|
+
this.finalizeSpanOnce(SpanStatusCode.OK);
|
|
4711
|
+
}
|
|
4712
|
+
});
|
|
4713
|
+
this.messageStream.on("error", (err) => {
|
|
4714
|
+
if (err && !this.spanFinalized) {
|
|
4715
|
+
this.span.setStatus({
|
|
4716
|
+
code: SpanStatusCode.ERROR,
|
|
4717
|
+
message: err instanceof Error ? err.message : String(err)
|
|
4718
|
+
});
|
|
4719
|
+
this.span.recordException(
|
|
4720
|
+
err instanceof Error ? err : new Error(String(err))
|
|
4721
|
+
);
|
|
4722
|
+
}
|
|
4723
|
+
this.finalizeSpanOnce(SpanStatusCode.ERROR);
|
|
4724
|
+
});
|
|
4725
|
+
} catch (e) {
|
|
4726
|
+
Logger.error(
|
|
4727
|
+
"netra.instrumentation.anthropic: safety net listener registration failed",
|
|
4728
|
+
e
|
|
4729
|
+
);
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4250
4732
|
toJSON() {
|
|
4251
4733
|
return this.completeResponse;
|
|
4252
4734
|
}
|
|
4253
4735
|
async *[Symbol.asyncIterator]() {
|
|
4736
|
+
let errorOccurred = false;
|
|
4254
4737
|
try {
|
|
4255
4738
|
for await (const chunk of this.messageStream) {
|
|
4256
|
-
this.
|
|
4739
|
+
processStreamChunk(this.completeResponse, chunk, this.span);
|
|
4257
4740
|
yield chunk;
|
|
4258
4741
|
}
|
|
4259
|
-
this.finalizeSpan(SpanStatusCode.OK);
|
|
4260
4742
|
} catch (err) {
|
|
4743
|
+
errorOccurred = true;
|
|
4261
4744
|
Logger.error("netra.instrumentation.anthropic: Stream error", err);
|
|
4262
|
-
this.
|
|
4745
|
+
this.finalizeSpanOnce(SpanStatusCode.ERROR);
|
|
4263
4746
|
throw err;
|
|
4747
|
+
} finally {
|
|
4748
|
+
if (!errorOccurred) {
|
|
4749
|
+
this.finalizeSpanOnce(SpanStatusCode.OK);
|
|
4750
|
+
}
|
|
4264
4751
|
}
|
|
4265
4752
|
}
|
|
4266
4753
|
getSpanContext() {
|
|
@@ -4269,12 +4756,8 @@ var MessageStreamWrapper = class {
|
|
|
4269
4756
|
processEventData(eventType, data) {
|
|
4270
4757
|
switch (eventType) {
|
|
4271
4758
|
case "message":
|
|
4272
|
-
if (data.model)
|
|
4273
|
-
|
|
4274
|
-
}
|
|
4275
|
-
if (data.usage) {
|
|
4276
|
-
this.completeResponse.usage = data.usage;
|
|
4277
|
-
}
|
|
4759
|
+
if (data.model) this.completeResponse.model = data.model;
|
|
4760
|
+
if (data.usage) this.completeResponse.usage = data.usage;
|
|
4278
4761
|
break;
|
|
4279
4762
|
case "text":
|
|
4280
4763
|
if (!this.completeResponse.currentText) {
|
|
@@ -4295,250 +4778,359 @@ var MessageStreamWrapper = class {
|
|
|
4295
4778
|
break;
|
|
4296
4779
|
}
|
|
4297
4780
|
}
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
}
|
|
4304
|
-
if (chunk.message?.usage) {
|
|
4305
|
-
this.completeResponse.usage = chunk.message.usage;
|
|
4306
|
-
}
|
|
4307
|
-
break;
|
|
4308
|
-
}
|
|
4309
|
-
case "content_block_start": {
|
|
4310
|
-
if (!this.completeResponse.content) {
|
|
4311
|
-
this.completeResponse.content = [];
|
|
4312
|
-
}
|
|
4313
|
-
const block = chunk.content_block;
|
|
4314
|
-
if (block.type === "tool_use") {
|
|
4315
|
-
this.completeResponse.content.push({
|
|
4316
|
-
type: "tool_use",
|
|
4317
|
-
id: block.id,
|
|
4318
|
-
name: block.name,
|
|
4319
|
-
input: ""
|
|
4320
|
-
});
|
|
4321
|
-
} else {
|
|
4322
|
-
this.completeResponse.content.push({
|
|
4323
|
-
type: block.type,
|
|
4324
|
-
text: ""
|
|
4325
|
-
});
|
|
4326
|
-
}
|
|
4327
|
-
break;
|
|
4328
|
-
}
|
|
4329
|
-
case "content_block_delta": {
|
|
4330
|
-
if (!this.completeResponse.content || this.completeResponse.content.length === 0) {
|
|
4331
|
-
this.completeResponse.content = [{ type: "text", text: "" }];
|
|
4332
|
-
}
|
|
4333
|
-
const lastBlock = this.completeResponse.content[this.completeResponse.content.length - 1];
|
|
4334
|
-
if (chunk.delta?.type === "input_json_delta" && lastBlock?.type === "tool_use") {
|
|
4335
|
-
lastBlock.input += chunk.delta.partial_json ?? "";
|
|
4336
|
-
} else if (lastBlock && chunk.delta?.text) {
|
|
4337
|
-
lastBlock.text += chunk.delta.text;
|
|
4338
|
-
}
|
|
4339
|
-
break;
|
|
4340
|
-
}
|
|
4341
|
-
case "content_block_stop": {
|
|
4342
|
-
const blocks = this.completeResponse.content;
|
|
4343
|
-
if (blocks && blocks.length > 0) {
|
|
4344
|
-
const finishedBlock = blocks[blocks.length - 1];
|
|
4345
|
-
if (finishedBlock?.type === "tool_use" && typeof finishedBlock.input === "string") {
|
|
4346
|
-
try {
|
|
4347
|
-
finishedBlock.input = JSON.parse(finishedBlock.input);
|
|
4348
|
-
} catch {
|
|
4349
|
-
Logger.warn("netra.instrumentation.anthropic: Failed to parse tool use input", finishedBlock.input);
|
|
4350
|
-
}
|
|
4351
|
-
}
|
|
4352
|
-
}
|
|
4353
|
-
break;
|
|
4354
|
-
}
|
|
4355
|
-
case "message_delta": {
|
|
4356
|
-
if (chunk.delta?.usage) {
|
|
4357
|
-
this.completeResponse.usage = {
|
|
4358
|
-
...this.completeResponse.usage,
|
|
4359
|
-
...chunk.delta.usage
|
|
4360
|
-
};
|
|
4361
|
-
}
|
|
4362
|
-
break;
|
|
4363
|
-
}
|
|
4364
|
-
case "message_stop": {
|
|
4365
|
-
if (chunk.usage) {
|
|
4366
|
-
this.completeResponse.usage = chunk.usage;
|
|
4367
|
-
}
|
|
4368
|
-
break;
|
|
4369
|
-
}
|
|
4781
|
+
flushCurrentText() {
|
|
4782
|
+
if (this.completeResponse.currentText && (!this.completeResponse.content || this.completeResponse.content.length === 0)) {
|
|
4783
|
+
this.completeResponse.content = [
|
|
4784
|
+
{ type: "text", text: this.completeResponse.currentText }
|
|
4785
|
+
];
|
|
4370
4786
|
}
|
|
4371
|
-
this.span.addEvent("llm.content.completion.chunk", {
|
|
4372
|
-
"chunk.type": chunk.type
|
|
4373
|
-
});
|
|
4374
4787
|
}
|
|
4375
4788
|
finalizeSpanFromMessage(message) {
|
|
4376
4789
|
if (message) {
|
|
4377
4790
|
if (message.model) this.completeResponse.model = message.model;
|
|
4378
4791
|
if (message.content) this.completeResponse.content = message.content;
|
|
4379
4792
|
if (message.usage) this.completeResponse.usage = message.usage;
|
|
4793
|
+
if (message.stop_reason)
|
|
4794
|
+
this.completeResponse.stop_reason = message.stop_reason;
|
|
4380
4795
|
}
|
|
4381
|
-
this.
|
|
4796
|
+
this.finalizeSpanOnce(SpanStatusCode.OK);
|
|
4382
4797
|
}
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
model: this.completeResponse.model,
|
|
4388
|
-
content: this.completeResponse.content,
|
|
4389
|
-
usage: this.completeResponse.usage
|
|
4390
|
-
});
|
|
4391
|
-
this.span.setAttribute("llm.response.duration", duration);
|
|
4392
|
-
this.span.setStatus({ code });
|
|
4393
|
-
this.span.end();
|
|
4798
|
+
finalizeSpanOnce(code) {
|
|
4799
|
+
if (this.spanFinalized) return;
|
|
4800
|
+
this.spanFinalized = true;
|
|
4801
|
+
finalizeStreamSpan(this.span, this.completeResponse, this.startTime, code);
|
|
4394
4802
|
}
|
|
4395
4803
|
};
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
model: ""
|
|
4402
|
-
};
|
|
4403
|
-
defineHidden(this, "span", span2);
|
|
4404
|
-
defineHidden(this, "response", response);
|
|
4405
|
-
defineHidden(this, "startTime", startTime);
|
|
4406
|
-
defineHidden(this, "requestKwargs", requestKwargs);
|
|
4407
|
-
defineHidden(this, "spanContext", spanContext || trace.setSpan(context.active(), span2));
|
|
4408
|
-
}
|
|
4409
|
-
toJSON() {
|
|
4410
|
-
return this.completeResponse;
|
|
4411
|
-
}
|
|
4412
|
-
[Symbol.asyncIterator]() {
|
|
4413
|
-
return this;
|
|
4414
|
-
}
|
|
4415
|
-
async next() {
|
|
4416
|
-
try {
|
|
4417
|
-
if (!this.iterator) {
|
|
4418
|
-
if (Symbol.asyncIterator in this.response) {
|
|
4419
|
-
this.iterator = this.response[Symbol.asyncIterator]();
|
|
4420
|
-
} else if (typeof this.response.next === "function") {
|
|
4421
|
-
this.iterator = this.response;
|
|
4422
|
-
} else {
|
|
4423
|
-
throw new Error("Response is not iterable");
|
|
4424
|
-
}
|
|
4425
|
-
}
|
|
4426
|
-
const result = await context.with(this.spanContext, () => this.iterator.next());
|
|
4427
|
-
if (result.done) {
|
|
4428
|
-
this.finalizeSpan(SpanStatusCode.OK);
|
|
4429
|
-
return result;
|
|
4430
|
-
}
|
|
4431
|
-
this.processChunk(result.value);
|
|
4432
|
-
return result;
|
|
4433
|
-
} catch (error) {
|
|
4434
|
-
this.finalizeSpan(SpanStatusCode.ERROR);
|
|
4435
|
-
throw error;
|
|
4436
|
-
}
|
|
4437
|
-
}
|
|
4438
|
-
processChunk(chunk) {
|
|
4439
|
-
switch (chunk.type) {
|
|
4440
|
-
case "message_start": {
|
|
4441
|
-
if (chunk.message?.model) {
|
|
4442
|
-
this.completeResponse.model = chunk.message.model;
|
|
4443
|
-
}
|
|
4444
|
-
if (chunk.message?.usage) {
|
|
4445
|
-
this.completeResponse.usage = chunk.message.usage;
|
|
4446
|
-
}
|
|
4447
|
-
break;
|
|
4448
|
-
}
|
|
4449
|
-
case "content_block_start": {
|
|
4450
|
-
const content = this.completeResponse.content || [];
|
|
4451
|
-
this.completeResponse.content = content;
|
|
4452
|
-
const block = chunk.content_block;
|
|
4453
|
-
if (block.type === "tool_use") {
|
|
4454
|
-
content.push({
|
|
4455
|
-
type: "tool_use",
|
|
4456
|
-
id: block.id,
|
|
4457
|
-
name: block.name,
|
|
4458
|
-
input: ""
|
|
4459
|
-
});
|
|
4460
|
-
} else {
|
|
4461
|
-
content.push({
|
|
4462
|
-
type: block.type,
|
|
4463
|
-
text: ""
|
|
4464
|
-
});
|
|
4465
|
-
}
|
|
4466
|
-
break;
|
|
4804
|
+
function anthropicWrapper(tracer, spanName, requestType) {
|
|
4805
|
+
return function wrapper(original) {
|
|
4806
|
+
return function(...args) {
|
|
4807
|
+
if (shouldSuppressInstrumentation()) {
|
|
4808
|
+
return original.apply(this, args);
|
|
4467
4809
|
}
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
}
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4810
|
+
const attributes = args[0] || {};
|
|
4811
|
+
const currentContext = context.active();
|
|
4812
|
+
const isStreaming = attributes.stream === true;
|
|
4813
|
+
const activeSpan = trace.getSpan(currentContext);
|
|
4814
|
+
Logger.debug(
|
|
4815
|
+
`Anthropic invoke (${requestType}). Active TraceId: ${activeSpan?.spanContext().traceId}, SpanId: ${activeSpan?.spanContext().spanId}`
|
|
4816
|
+
);
|
|
4817
|
+
return tracer.startActiveSpan(
|
|
4818
|
+
spanName,
|
|
4819
|
+
{
|
|
4820
|
+
kind: SpanKind.CLIENT,
|
|
4821
|
+
attributes: { "llm.request.type": requestType }
|
|
4822
|
+
},
|
|
4823
|
+
(span2) => {
|
|
4824
|
+
try {
|
|
4825
|
+
setRequestAttributes2(span2, attributes, requestType);
|
|
4826
|
+
if (isStreaming) {
|
|
4827
|
+
span2.setAttribute("llm.streaming", true);
|
|
4828
|
+
}
|
|
4829
|
+
const startTime = Date.now();
|
|
4830
|
+
const spanContext = trace.setSpan(currentContext, span2);
|
|
4831
|
+
const response = context.with(
|
|
4832
|
+
spanContext,
|
|
4833
|
+
() => original.apply(this, args)
|
|
4834
|
+
);
|
|
4835
|
+
const completeResponse = {
|
|
4836
|
+
content: [],
|
|
4837
|
+
model: "",
|
|
4838
|
+
usage: {}
|
|
4839
|
+
};
|
|
4840
|
+
return wrapResponse(
|
|
4841
|
+
response,
|
|
4842
|
+
{
|
|
4843
|
+
withContext: (fn) => context.with(spanContext, fn),
|
|
4844
|
+
onChunk: (chunk) => processStreamChunk(completeResponse, chunk, span2),
|
|
4845
|
+
onError: (error) => {
|
|
4846
|
+
Logger.error("netra.instrumentation.anthropic:", error);
|
|
4847
|
+
span2.setStatus({
|
|
4848
|
+
code: SpanStatusCode.ERROR,
|
|
4849
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4850
|
+
});
|
|
4851
|
+
span2.recordException(error);
|
|
4852
|
+
},
|
|
4853
|
+
onSuccess: (value) => {
|
|
4854
|
+
const endTime = Date.now();
|
|
4855
|
+
const responseDict = modelAsDict(value);
|
|
4856
|
+
setResponseAttributes2(span2, responseDict);
|
|
4857
|
+
span2.setAttribute(
|
|
4858
|
+
"llm.response.duration",
|
|
4859
|
+
(endTime - startTime) / 1e3
|
|
4860
|
+
);
|
|
4861
|
+
},
|
|
4862
|
+
finalize: (status) => {
|
|
4863
|
+
const hasStreamData = completeResponse.content?.length || completeResponse.model || completeResponse.usage?.input_tokens !== void 0 || completeResponse.usage?.output_tokens !== void 0;
|
|
4864
|
+
if (status === "ok" && hasStreamData) {
|
|
4865
|
+
finalizeStreamSpan(
|
|
4866
|
+
span2,
|
|
4867
|
+
completeResponse,
|
|
4868
|
+
startTime,
|
|
4869
|
+
SpanStatusCode.OK
|
|
4870
|
+
);
|
|
4871
|
+
} else {
|
|
4872
|
+
if (status === "ok") {
|
|
4873
|
+
span2.setStatus({ code: SpanStatusCode.OK });
|
|
4874
|
+
}
|
|
4875
|
+
span2.end();
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4878
|
+
},
|
|
4879
|
+
{ preserveOriginal: response }
|
|
4880
|
+
);
|
|
4881
|
+
} catch (error) {
|
|
4882
|
+
Logger.error("netra.instrumentation.anthropic:", error);
|
|
4883
|
+
span2.setStatus({
|
|
4884
|
+
code: SpanStatusCode.ERROR,
|
|
4885
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4886
|
+
});
|
|
4887
|
+
span2.recordException(error);
|
|
4888
|
+
span2.end();
|
|
4889
|
+
throw error;
|
|
4890
|
+
}
|
|
4479
4891
|
}
|
|
4480
|
-
|
|
4892
|
+
);
|
|
4893
|
+
};
|
|
4894
|
+
};
|
|
4895
|
+
}
|
|
4896
|
+
function streamWrapper(tracer, spanName, requestType, originalCreate) {
|
|
4897
|
+
return function wrapper(original) {
|
|
4898
|
+
return function(...args) {
|
|
4899
|
+
if (shouldSuppressInstrumentation()) {
|
|
4900
|
+
return original.apply(this, args);
|
|
4481
4901
|
}
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4902
|
+
const attributes = args[0] || {};
|
|
4903
|
+
const currentContext = context.active();
|
|
4904
|
+
const span2 = tracer.startSpan(
|
|
4905
|
+
spanName,
|
|
4906
|
+
{
|
|
4907
|
+
kind: SpanKind.CLIENT,
|
|
4908
|
+
attributes: {
|
|
4909
|
+
"llm.request.type": requestType,
|
|
4910
|
+
"llm.streaming": true,
|
|
4911
|
+
"llm.operation": "stream"
|
|
4492
4912
|
}
|
|
4913
|
+
},
|
|
4914
|
+
currentContext
|
|
4915
|
+
);
|
|
4916
|
+
const spanContext = trace.setSpan(currentContext, span2);
|
|
4917
|
+
setRequestAttributes2(span2, attributes, requestType);
|
|
4918
|
+
const startTime = Date.now();
|
|
4919
|
+
const callTarget = originalCreate ? new Proxy(this, {
|
|
4920
|
+
get(target, prop) {
|
|
4921
|
+
if (prop === "create") return originalCreate.bind(target);
|
|
4922
|
+
const value = target[prop];
|
|
4923
|
+
if (typeof value === "function") return value.bind(target);
|
|
4924
|
+
return value;
|
|
4493
4925
|
}
|
|
4494
|
-
|
|
4926
|
+
}) : this;
|
|
4927
|
+
try {
|
|
4928
|
+
const messageStream = context.with(
|
|
4929
|
+
spanContext,
|
|
4930
|
+
() => original.call(callTarget, ...args)
|
|
4931
|
+
);
|
|
4932
|
+
return new MessageStreamWrapper(
|
|
4933
|
+
span2,
|
|
4934
|
+
messageStream,
|
|
4935
|
+
startTime,
|
|
4936
|
+
attributes,
|
|
4937
|
+
spanContext,
|
|
4938
|
+
currentContext
|
|
4939
|
+
);
|
|
4940
|
+
} catch (error) {
|
|
4941
|
+
span2.setStatus({
|
|
4942
|
+
code: SpanStatusCode.ERROR,
|
|
4943
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4944
|
+
});
|
|
4945
|
+
span2.recordException(error);
|
|
4946
|
+
span2.end();
|
|
4947
|
+
throw error;
|
|
4495
4948
|
}
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
break;
|
|
4949
|
+
};
|
|
4950
|
+
};
|
|
4951
|
+
}
|
|
4952
|
+
function toolRunnerWrapper(tracer, spanName, requestType) {
|
|
4953
|
+
return function wrapper(original) {
|
|
4954
|
+
return function(...args) {
|
|
4955
|
+
if (shouldSuppressInstrumentation()) {
|
|
4956
|
+
return original.apply(this, args);
|
|
4505
4957
|
}
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4958
|
+
const attributes = args[0] || {};
|
|
4959
|
+
const currentContext = context.active();
|
|
4960
|
+
const span2 = tracer.startSpan(
|
|
4961
|
+
spanName,
|
|
4962
|
+
{
|
|
4963
|
+
kind: SpanKind.CLIENT,
|
|
4964
|
+
attributes: {
|
|
4965
|
+
"llm.request.type": requestType,
|
|
4966
|
+
"netra.span.type": "AGENT",
|
|
4967
|
+
"llm.operation": "tool.runner"
|
|
4968
|
+
}
|
|
4969
|
+
},
|
|
4970
|
+
currentContext
|
|
4971
|
+
);
|
|
4972
|
+
let spanEnded = false;
|
|
4973
|
+
const endSpanOnce = (code, error) => {
|
|
4974
|
+
if (spanEnded) return;
|
|
4975
|
+
spanEnded = true;
|
|
4976
|
+
if (error) {
|
|
4977
|
+
span2.setStatus({ code, message: error.message });
|
|
4978
|
+
span2.recordException(error);
|
|
4979
|
+
} else {
|
|
4980
|
+
span2.setStatus({ code });
|
|
4509
4981
|
}
|
|
4510
|
-
|
|
4982
|
+
span2.end();
|
|
4983
|
+
};
|
|
4984
|
+
try {
|
|
4985
|
+
setRequestAttributes2(span2, attributes, "beta");
|
|
4986
|
+
const spanContext = trace.setSpan(currentContext, span2);
|
|
4987
|
+
const wrappedTools = Array.isArray(attributes.tools) ? wrapRunnableTools(attributes.tools, tracer, spanContext) : attributes.tools;
|
|
4988
|
+
const wrappedArgs = [
|
|
4989
|
+
{ ...attributes, tools: wrappedTools },
|
|
4990
|
+
...args.slice(1)
|
|
4991
|
+
];
|
|
4992
|
+
const runner = context.with(
|
|
4993
|
+
spanContext,
|
|
4994
|
+
() => original.apply(this, wrappedArgs)
|
|
4995
|
+
);
|
|
4996
|
+
if (runner == null) {
|
|
4997
|
+
endSpanOnce(SpanStatusCode.OK);
|
|
4998
|
+
return runner;
|
|
4999
|
+
}
|
|
5000
|
+
return new Proxy(runner, {
|
|
5001
|
+
get(target, prop, receiver) {
|
|
5002
|
+
if (prop === Symbol.asyncIterator) {
|
|
5003
|
+
return function() {
|
|
5004
|
+
const originalIterator = target[Symbol.asyncIterator]();
|
|
5005
|
+
return {
|
|
5006
|
+
[Symbol.asyncIterator]() {
|
|
5007
|
+
return this;
|
|
5008
|
+
},
|
|
5009
|
+
async next() {
|
|
5010
|
+
try {
|
|
5011
|
+
const result = await context.with(
|
|
5012
|
+
spanContext,
|
|
5013
|
+
() => originalIterator.next()
|
|
5014
|
+
);
|
|
5015
|
+
if (result.done) endSpanOnce(SpanStatusCode.OK);
|
|
5016
|
+
return result;
|
|
5017
|
+
} catch (error) {
|
|
5018
|
+
endSpanOnce(SpanStatusCode.ERROR, error);
|
|
5019
|
+
throw error;
|
|
5020
|
+
}
|
|
5021
|
+
},
|
|
5022
|
+
async return(value2) {
|
|
5023
|
+
try {
|
|
5024
|
+
const result = await (originalIterator.return?.(
|
|
5025
|
+
value2
|
|
5026
|
+
) ?? {
|
|
5027
|
+
done: true,
|
|
5028
|
+
value: value2
|
|
5029
|
+
});
|
|
5030
|
+
return result;
|
|
5031
|
+
} finally {
|
|
5032
|
+
endSpanOnce(SpanStatusCode.OK);
|
|
5033
|
+
}
|
|
5034
|
+
},
|
|
5035
|
+
async throw(error) {
|
|
5036
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
5037
|
+
if (originalIterator.throw) {
|
|
5038
|
+
try {
|
|
5039
|
+
const result = await originalIterator.throw(error);
|
|
5040
|
+
if (result.done) {
|
|
5041
|
+
endSpanOnce(SpanStatusCode.ERROR, err);
|
|
5042
|
+
}
|
|
5043
|
+
return result;
|
|
5044
|
+
} catch (e) {
|
|
5045
|
+
endSpanOnce(
|
|
5046
|
+
SpanStatusCode.ERROR,
|
|
5047
|
+
e instanceof Error ? e : new Error(String(e))
|
|
5048
|
+
);
|
|
5049
|
+
throw e;
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
endSpanOnce(SpanStatusCode.ERROR, err);
|
|
5053
|
+
throw error;
|
|
5054
|
+
}
|
|
5055
|
+
};
|
|
5056
|
+
};
|
|
5057
|
+
}
|
|
5058
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
5059
|
+
const originalMethod = target[prop];
|
|
5060
|
+
if (typeof originalMethod !== "function") return originalMethod;
|
|
5061
|
+
if (prop === "then") {
|
|
5062
|
+
return function(onFulfilled, onRejected) {
|
|
5063
|
+
return originalMethod.call(
|
|
5064
|
+
target,
|
|
5065
|
+
(v) => {
|
|
5066
|
+
endSpanOnce(SpanStatusCode.OK);
|
|
5067
|
+
return onFulfilled ? onFulfilled(v) : v;
|
|
5068
|
+
},
|
|
5069
|
+
(e) => {
|
|
5070
|
+
endSpanOnce(
|
|
5071
|
+
SpanStatusCode.ERROR,
|
|
5072
|
+
e instanceof Error ? e : new Error(String(e))
|
|
5073
|
+
);
|
|
5074
|
+
if (onRejected) return onRejected(e);
|
|
5075
|
+
throw e;
|
|
5076
|
+
}
|
|
5077
|
+
);
|
|
5078
|
+
};
|
|
5079
|
+
}
|
|
5080
|
+
if (prop === "catch") {
|
|
5081
|
+
return function(onRejected) {
|
|
5082
|
+
return receiver.then(void 0, onRejected);
|
|
5083
|
+
};
|
|
5084
|
+
}
|
|
5085
|
+
if (prop === "finally") {
|
|
5086
|
+
return function(onFinally) {
|
|
5087
|
+
return receiver.then(
|
|
5088
|
+
(v) => {
|
|
5089
|
+
onFinally?.();
|
|
5090
|
+
return v;
|
|
5091
|
+
},
|
|
5092
|
+
(e) => {
|
|
5093
|
+
onFinally?.();
|
|
5094
|
+
throw e;
|
|
5095
|
+
}
|
|
5096
|
+
);
|
|
5097
|
+
};
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
const value = target[prop];
|
|
5101
|
+
if (typeof value === "function") return value.bind(target);
|
|
5102
|
+
return value;
|
|
5103
|
+
}
|
|
5104
|
+
});
|
|
5105
|
+
} catch (error) {
|
|
5106
|
+
endSpanOnce(
|
|
5107
|
+
SpanStatusCode.ERROR,
|
|
5108
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5109
|
+
);
|
|
5110
|
+
throw error;
|
|
4511
5111
|
}
|
|
4512
|
-
}
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
model: this.completeResponse.model,
|
|
4522
|
-
content: this.completeResponse.content,
|
|
4523
|
-
usage: this.completeResponse.usage
|
|
4524
|
-
});
|
|
4525
|
-
this.span.setAttribute("llm.response.duration", duration);
|
|
4526
|
-
this.span.setStatus({ code });
|
|
4527
|
-
this.span.end();
|
|
4528
|
-
}
|
|
4529
|
-
};
|
|
5112
|
+
};
|
|
5113
|
+
};
|
|
5114
|
+
}
|
|
5115
|
+
var chatWrapper = (tracer) => anthropicWrapper(tracer, SPAN_NAMES.CHAT, "chat");
|
|
5116
|
+
var betaWrapper = (tracer) => anthropicWrapper(tracer, SPAN_NAMES.BETA, "beta");
|
|
5117
|
+
var batchesWrapper = (tracer) => anthropicWrapper(tracer, SPAN_NAMES.BATCHES, "batches");
|
|
5118
|
+
var chatStreamWrapper = (tracer, originalCreate) => streamWrapper(tracer, SPAN_NAMES.STREAM, "chat", originalCreate);
|
|
5119
|
+
var betaStreamWrapper = (tracer, originalCreate) => streamWrapper(tracer, SPAN_NAMES.BETA_STREAM, "beta", originalCreate);
|
|
5120
|
+
var betaToolRunnerWrapper = (tracer) => toolRunnerWrapper(tracer, SPAN_NAMES.BETA_TOOL_RUNNER, "beta");
|
|
4530
5121
|
|
|
4531
5122
|
// src/instrumentation/anthropic/index.ts
|
|
4532
5123
|
var INSTRUMENTATION_NAME = "netra.instrumentation.anthropic";
|
|
4533
5124
|
var INSTRUMENTS = ["anthropic >= 0.71.2"];
|
|
4534
|
-
var originalMethods = /* @__PURE__ */ new Map();
|
|
4535
5125
|
var isInstrumented = false;
|
|
4536
5126
|
var anthropicClasses = [];
|
|
4537
|
-
async function
|
|
5127
|
+
async function resolveAnthropic() {
|
|
4538
5128
|
if (anthropicClasses.length > 0) return anthropicClasses;
|
|
4539
5129
|
try {
|
|
4540
5130
|
const anthropicModule = await import('@anthropic-ai/sdk');
|
|
4541
|
-
anthropicClasses.push(
|
|
5131
|
+
anthropicClasses.push(
|
|
5132
|
+
anthropicModule.Anthropic || anthropicModule.default || anthropicModule
|
|
5133
|
+
);
|
|
4542
5134
|
} catch {
|
|
4543
5135
|
Logger.warn("Failed to resolve Anthropic ESM module");
|
|
4544
5136
|
}
|
|
@@ -4554,9 +5146,6 @@ async function resolveAnthropicAsync() {
|
|
|
4554
5146
|
}
|
|
4555
5147
|
return anthropicClasses;
|
|
4556
5148
|
}
|
|
4557
|
-
function resolveAnthropic() {
|
|
4558
|
-
return anthropicClasses;
|
|
4559
|
-
}
|
|
4560
5149
|
var NetraAnthropicInstrumentor = class {
|
|
4561
5150
|
constructor() {
|
|
4562
5151
|
this.tracer = null;
|
|
@@ -4564,15 +5153,13 @@ var NetraAnthropicInstrumentor = class {
|
|
|
4564
5153
|
instrumentationDependencies() {
|
|
4565
5154
|
return INSTRUMENTS;
|
|
4566
5155
|
}
|
|
4567
|
-
async
|
|
5156
|
+
async instrument(options = {}) {
|
|
4568
5157
|
if (isInstrumented) {
|
|
4569
5158
|
Logger.warn("Anthropic is already instrumented");
|
|
4570
5159
|
return this;
|
|
4571
5160
|
}
|
|
4572
|
-
const classes = await
|
|
4573
|
-
if (classes.length === 0)
|
|
4574
|
-
return this;
|
|
4575
|
-
}
|
|
5161
|
+
const classes = await resolveAnthropic();
|
|
5162
|
+
if (classes.length === 0) return this;
|
|
4576
5163
|
try {
|
|
4577
5164
|
this.tracerProvider = options.tracerProvider;
|
|
4578
5165
|
if (this.tracerProvider) {
|
|
@@ -4587,10 +5174,10 @@ var NetraAnthropicInstrumentor = class {
|
|
|
4587
5174
|
Logger.error(`Failed to initialize tracer: ${error}`);
|
|
4588
5175
|
return this;
|
|
4589
5176
|
}
|
|
4590
|
-
classes.forEach((AnthropicSDK
|
|
4591
|
-
this._instrumentMessages(AnthropicSDK
|
|
4592
|
-
this._instrumentBetaMessages(AnthropicSDK
|
|
4593
|
-
this._instrumentBatchMessages(AnthropicSDK
|
|
5177
|
+
classes.forEach((AnthropicSDK) => {
|
|
5178
|
+
this._instrumentMessages(AnthropicSDK);
|
|
5179
|
+
this._instrumentBetaMessages(AnthropicSDK);
|
|
5180
|
+
this._instrumentBatchMessages(AnthropicSDK);
|
|
4594
5181
|
});
|
|
4595
5182
|
isInstrumented = true;
|
|
4596
5183
|
return this;
|
|
@@ -4600,185 +5187,137 @@ var NetraAnthropicInstrumentor = class {
|
|
|
4600
5187
|
Logger.warn("Anthropic is not instrumented");
|
|
4601
5188
|
return;
|
|
4602
5189
|
}
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
this.
|
|
4606
|
-
this.
|
|
4607
|
-
this._uninstrumentBatchMessages(AnthropicSDK, index);
|
|
5190
|
+
anthropicClasses.forEach((AnthropicSDK) => {
|
|
5191
|
+
this._uninstrumentMessages(AnthropicSDK);
|
|
5192
|
+
this._uninstrumentBetaMessages(AnthropicSDK);
|
|
5193
|
+
this._uninstrumentBatchMessages(AnthropicSDK);
|
|
4608
5194
|
});
|
|
4609
|
-
originalMethods.clear();
|
|
4610
5195
|
anthropicClasses = [];
|
|
4611
5196
|
isInstrumented = false;
|
|
4612
5197
|
}
|
|
4613
5198
|
isInstrumented() {
|
|
4614
5199
|
return isInstrumented;
|
|
4615
5200
|
}
|
|
4616
|
-
_instrumentMessages(AnthropicSDK
|
|
5201
|
+
_instrumentMessages(AnthropicSDK) {
|
|
4617
5202
|
if (!this.tracer) {
|
|
4618
5203
|
Logger.warn("Anthropic instrumentation: No tracer available");
|
|
4619
5204
|
return;
|
|
4620
5205
|
}
|
|
4621
5206
|
try {
|
|
4622
5207
|
const MessagesClass = AnthropicSDK.Messages;
|
|
4623
|
-
if (!MessagesClass) {
|
|
5208
|
+
if (!MessagesClass?.prototype) {
|
|
4624
5209
|
Logger.error(
|
|
4625
|
-
"Anthropic instrumentation: Could not find
|
|
5210
|
+
"Anthropic instrumentation: Could not find Messages class"
|
|
4626
5211
|
);
|
|
4627
5212
|
return;
|
|
4628
5213
|
}
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
const currentContext = context.active();
|
|
4637
|
-
const span2 = tracer.startSpan("anthropic.stream", {
|
|
4638
|
-
kind: SpanKind.CLIENT,
|
|
4639
|
-
attributes: {
|
|
4640
|
-
"llm.request.type": "chat",
|
|
4641
|
-
"llm.streaming": true,
|
|
4642
|
-
"llm.operation": "stream"
|
|
4643
|
-
}
|
|
4644
|
-
}, currentContext);
|
|
4645
|
-
const spanContext = trace.setSpan(currentContext, span2);
|
|
4646
|
-
setRequestAttributes2(span2, kwargs, "chat");
|
|
4647
|
-
const startTime = Date.now();
|
|
4648
|
-
const instrumentedCreate = this.create;
|
|
4649
|
-
const originalCreate = originalMethods.get(`messages.create-${index}`);
|
|
4650
|
-
if (originalCreate) {
|
|
4651
|
-
this.create = originalCreate;
|
|
4652
|
-
}
|
|
4653
|
-
try {
|
|
4654
|
-
const messageStream = context.with(spanContext, () => original(...args));
|
|
4655
|
-
return new MessageStreamWrapper(span2, messageStream, startTime, kwargs, spanContext);
|
|
4656
|
-
} finally {
|
|
4657
|
-
if (originalCreate) {
|
|
4658
|
-
this.create = instrumentedCreate;
|
|
4659
|
-
}
|
|
4660
|
-
}
|
|
4661
|
-
};
|
|
5214
|
+
const originalCreate = MessagesClass.prototype.create;
|
|
5215
|
+
if (typeof MessagesClass.prototype.create === "function") {
|
|
5216
|
+
shimmer.wrap(
|
|
5217
|
+
MessagesClass.prototype,
|
|
5218
|
+
"create",
|
|
5219
|
+
chatWrapper(this.tracer)
|
|
5220
|
+
);
|
|
4662
5221
|
}
|
|
4663
|
-
if (MessagesClass
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
const original = originalCreate.bind(this);
|
|
4670
|
-
const kwargs = args[0] || {};
|
|
4671
|
-
return wrapper(
|
|
4672
|
-
(...a) => original(...a),
|
|
4673
|
-
this,
|
|
4674
|
-
args,
|
|
4675
|
-
kwargs
|
|
4676
|
-
);
|
|
4677
|
-
};
|
|
5222
|
+
if (typeof MessagesClass.prototype.stream === "function") {
|
|
5223
|
+
shimmer.wrap(
|
|
5224
|
+
MessagesClass.prototype,
|
|
5225
|
+
"stream",
|
|
5226
|
+
chatStreamWrapper(this.tracer, originalCreate)
|
|
5227
|
+
);
|
|
4678
5228
|
}
|
|
4679
5229
|
} catch (error) {
|
|
4680
5230
|
Logger.error(`Failed to instrument messages: ${error}`);
|
|
4681
5231
|
}
|
|
4682
5232
|
}
|
|
4683
|
-
_instrumentBetaMessages(AnthropicSDK
|
|
5233
|
+
_instrumentBetaMessages(AnthropicSDK) {
|
|
4684
5234
|
if (!this.tracer) {
|
|
4685
5235
|
Logger.warn("Anthropic instrumentation: No tracer available");
|
|
4686
5236
|
return;
|
|
4687
5237
|
}
|
|
4688
5238
|
try {
|
|
4689
5239
|
const BetaMessagesClass = AnthropicSDK.Beta?.Messages;
|
|
4690
|
-
if (!BetaMessagesClass) {
|
|
5240
|
+
if (!BetaMessagesClass?.prototype) {
|
|
4691
5241
|
Logger.error(
|
|
4692
|
-
"Anthropic instrumentation: Could not find
|
|
5242
|
+
"Anthropic instrumentation: Could not find Beta Messages class"
|
|
4693
5243
|
);
|
|
4694
5244
|
return;
|
|
4695
5245
|
}
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
5246
|
+
const originalCreate = BetaMessagesClass.prototype.create;
|
|
5247
|
+
if (typeof BetaMessagesClass.prototype.create === "function") {
|
|
5248
|
+
shimmer.wrap(
|
|
5249
|
+
BetaMessagesClass.prototype,
|
|
5250
|
+
"create",
|
|
5251
|
+
betaWrapper(this.tracer)
|
|
5252
|
+
);
|
|
5253
|
+
}
|
|
5254
|
+
if (typeof BetaMessagesClass.prototype.stream === "function") {
|
|
5255
|
+
shimmer.wrap(
|
|
5256
|
+
BetaMessagesClass.prototype,
|
|
5257
|
+
"stream",
|
|
5258
|
+
betaStreamWrapper(this.tracer, originalCreate)
|
|
5259
|
+
);
|
|
5260
|
+
}
|
|
5261
|
+
if (typeof BetaMessagesClass.prototype.toolRunner === "function") {
|
|
5262
|
+
shimmer.wrap(
|
|
5263
|
+
BetaMessagesClass.prototype,
|
|
5264
|
+
"toolRunner",
|
|
5265
|
+
betaToolRunnerWrapper(this.tracer)
|
|
5266
|
+
);
|
|
4711
5267
|
}
|
|
4712
5268
|
} catch (error) {
|
|
4713
5269
|
Logger.error(`Failed to instrument beta: ${error}`);
|
|
4714
5270
|
}
|
|
4715
5271
|
}
|
|
4716
|
-
_instrumentBatchMessages(AnthropicSDK
|
|
5272
|
+
_instrumentBatchMessages(AnthropicSDK) {
|
|
4717
5273
|
if (!this.tracer) {
|
|
4718
5274
|
Logger.warn("Anthropic instrumentation: No tracer available");
|
|
4719
5275
|
return;
|
|
4720
5276
|
}
|
|
4721
5277
|
try {
|
|
4722
5278
|
const BatchMessageClass = AnthropicSDK.Messages?.Batches;
|
|
4723
|
-
if (!BatchMessageClass) {
|
|
4724
|
-
Logger.error(
|
|
4725
|
-
"Anthropic instrumentation: Could not find Anthropic Batches class to instrument"
|
|
4726
|
-
);
|
|
5279
|
+
if (!BatchMessageClass?.prototype) {
|
|
5280
|
+
Logger.error("Anthropic instrumentation: Could not find Batches class");
|
|
4727
5281
|
return;
|
|
4728
5282
|
}
|
|
4729
|
-
if (BatchMessageClass
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
const original = originalCreate.bind(this);
|
|
4736
|
-
const kwargs = args[0] || {};
|
|
4737
|
-
return wrapper(
|
|
4738
|
-
(...a) => original(...a),
|
|
4739
|
-
this,
|
|
4740
|
-
args,
|
|
4741
|
-
kwargs
|
|
4742
|
-
);
|
|
4743
|
-
};
|
|
5283
|
+
if (typeof BatchMessageClass.prototype.create === "function") {
|
|
5284
|
+
shimmer.wrap(
|
|
5285
|
+
BatchMessageClass.prototype,
|
|
5286
|
+
"create",
|
|
5287
|
+
batchesWrapper(this.tracer)
|
|
5288
|
+
);
|
|
4744
5289
|
}
|
|
4745
5290
|
} catch (error) {
|
|
4746
5291
|
Logger.error(`Failed to instrument batches: ${error}`);
|
|
4747
5292
|
}
|
|
4748
5293
|
}
|
|
4749
|
-
_uninstrumentMessages(AnthropicSDK
|
|
5294
|
+
_uninstrumentMessages(AnthropicSDK) {
|
|
4750
5295
|
try {
|
|
4751
|
-
const
|
|
4752
|
-
|
|
4753
|
-
if (
|
|
4754
|
-
|
|
4755
|
-
}
|
|
4756
|
-
const originalStream = originalMethods.get(`messages.stream-${index}`);
|
|
4757
|
-
if (originalStream && MessagesClass?.prototype) {
|
|
4758
|
-
MessagesClass.prototype.stream = originalStream;
|
|
4759
|
-
}
|
|
5296
|
+
const proto = AnthropicSDK.Messages?.prototype;
|
|
5297
|
+
if (!proto) return;
|
|
5298
|
+
if (typeof proto.create === "function") shimmer.unwrap(proto, "create");
|
|
5299
|
+
if (typeof proto.stream === "function") shimmer.unwrap(proto, "stream");
|
|
4760
5300
|
} catch (error) {
|
|
4761
5301
|
Logger.error(`Failed to uninstrument messages: ${error}`);
|
|
4762
5302
|
}
|
|
4763
5303
|
}
|
|
4764
|
-
_uninstrumentBetaMessages(AnthropicSDK
|
|
5304
|
+
_uninstrumentBetaMessages(AnthropicSDK) {
|
|
4765
5305
|
try {
|
|
4766
|
-
const
|
|
4767
|
-
|
|
4768
|
-
if (
|
|
4769
|
-
|
|
4770
|
-
|
|
5306
|
+
const proto = AnthropicSDK.Beta?.Messages?.prototype;
|
|
5307
|
+
if (!proto) return;
|
|
5308
|
+
if (typeof proto.create === "function") shimmer.unwrap(proto, "create");
|
|
5309
|
+
if (typeof proto.stream === "function") shimmer.unwrap(proto, "stream");
|
|
5310
|
+
if (typeof proto.toolRunner === "function")
|
|
5311
|
+
shimmer.unwrap(proto, "toolRunner");
|
|
4771
5312
|
} catch (error) {
|
|
4772
5313
|
Logger.error(`Failed to uninstrument beta: ${error}`);
|
|
4773
5314
|
}
|
|
4774
5315
|
}
|
|
4775
|
-
_uninstrumentBatchMessages(AnthropicSDK
|
|
5316
|
+
_uninstrumentBatchMessages(AnthropicSDK) {
|
|
4776
5317
|
try {
|
|
4777
|
-
const
|
|
4778
|
-
|
|
4779
|
-
if (
|
|
4780
|
-
BatchMessagesClass.prototype.create = originalCreate;
|
|
4781
|
-
}
|
|
5318
|
+
const proto = AnthropicSDK.Messages?.Batches?.prototype;
|
|
5319
|
+
if (!proto) return;
|
|
5320
|
+
if (typeof proto.create === "function") shimmer.unwrap(proto, "create");
|
|
4782
5321
|
} catch (error) {
|
|
4783
5322
|
Logger.error(`Failed to uninstrument batches: ${error}`);
|
|
4784
5323
|
}
|
|
@@ -5194,7 +5733,7 @@ function _setEmbeddingResponseAttributes(span2, response) {
|
|
|
5194
5733
|
}
|
|
5195
5734
|
|
|
5196
5735
|
// src/instrumentation/google-genai/wrappers.ts
|
|
5197
|
-
var
|
|
5736
|
+
var CHAT_SPAN_NAME = "google_genai.chat";
|
|
5198
5737
|
var EMBEDDING_SPAN_NAME = "google_genai.embedding";
|
|
5199
5738
|
function googleGenAIWrapper(tracer, spanName, requestType) {
|
|
5200
5739
|
return function wrapper(original) {
|
|
@@ -5473,10 +6012,10 @@ function googleGenAIStartChatWrapper(tracer, spanName, requestType) {
|
|
|
5473
6012
|
};
|
|
5474
6013
|
};
|
|
5475
6014
|
}
|
|
5476
|
-
var chatWrapper2 = (tracer) => googleGenAIWrapper(tracer,
|
|
6015
|
+
var chatWrapper2 = (tracer) => googleGenAIWrapper(tracer, CHAT_SPAN_NAME, "chat");
|
|
5477
6016
|
var embeddingsWrapper = (tracer) => googleGenAIWrapper(tracer, EMBEDDING_SPAN_NAME, "embedding");
|
|
5478
|
-
var
|
|
5479
|
-
var startChatWrapper = (tracer) => googleGenAIStartChatWrapper(tracer,
|
|
6017
|
+
var chatStreamWrapper2 = (tracer) => googleGenAIStreamWrapper(tracer, CHAT_SPAN_NAME, "chat");
|
|
6018
|
+
var startChatWrapper = (tracer) => googleGenAIStartChatWrapper(tracer, CHAT_SPAN_NAME, "chat");
|
|
5480
6019
|
var INSTRUMENTATION_NAME2 = "netra.instrumentation.google_genai";
|
|
5481
6020
|
var INSTRUMENTS2 = ["@google/genai >= 0.24.1"];
|
|
5482
6021
|
var isInstrumented2 = false;
|
|
@@ -5602,7 +6141,7 @@ var NetraGoogleGenerativeAIInstrumentor = class {
|
|
|
5602
6141
|
shimmer.wrap(
|
|
5603
6142
|
GenerativeModel.prototype,
|
|
5604
6143
|
"generateContentStream",
|
|
5605
|
-
|
|
6144
|
+
chatStreamWrapper2(tracer)
|
|
5606
6145
|
);
|
|
5607
6146
|
shimmer.wrap(
|
|
5608
6147
|
GenerativeModel.prototype,
|
|
@@ -5664,8 +6203,8 @@ function setResponseAttributes4(span2, response) {
|
|
|
5664
6203
|
}
|
|
5665
6204
|
|
|
5666
6205
|
// src/instrumentation/groq/wrappers.ts
|
|
5667
|
-
var
|
|
5668
|
-
var
|
|
6206
|
+
var CHAT_SPAN_NAME2 = "groq.chat";
|
|
6207
|
+
var STREAM_ENABLED_REQUESTS = ["chat"];
|
|
5669
6208
|
function groqWrapper(tracer, spanName, requestType) {
|
|
5670
6209
|
return function wrapper(wrapped, instance, args, kwargs) {
|
|
5671
6210
|
if (shouldSuppressInstrumentation()) {
|
|
@@ -5673,7 +6212,7 @@ function groqWrapper(tracer, spanName, requestType) {
|
|
|
5673
6212
|
return isPromise(result) ? result.then((value) => value) : result;
|
|
5674
6213
|
}
|
|
5675
6214
|
const isStreaming = kwargs.stream === true;
|
|
5676
|
-
if (isStreaming &&
|
|
6215
|
+
if (isStreaming && STREAM_ENABLED_REQUESTS.includes(requestType)) {
|
|
5677
6216
|
const currentContext = context.active();
|
|
5678
6217
|
const span2 = tracer.startSpan(
|
|
5679
6218
|
spanName,
|
|
@@ -5691,7 +6230,7 @@ function groqWrapper(tracer, spanName, requestType) {
|
|
|
5691
6230
|
return (async () => {
|
|
5692
6231
|
try {
|
|
5693
6232
|
const stream = await response;
|
|
5694
|
-
return new
|
|
6233
|
+
return new AsyncStreamingWrapper(span2, stream, startTime, kwargs);
|
|
5695
6234
|
} catch (error) {
|
|
5696
6235
|
Logger.error("netra.instrumentation.groq:", error);
|
|
5697
6236
|
span2.setStatus({
|
|
@@ -5780,7 +6319,7 @@ function groqWrapper(tracer, spanName, requestType) {
|
|
|
5780
6319
|
}
|
|
5781
6320
|
};
|
|
5782
6321
|
}
|
|
5783
|
-
var chatWrapper3 = (tracer) => groqWrapper(tracer,
|
|
6322
|
+
var chatWrapper3 = (tracer) => groqWrapper(tracer, CHAT_SPAN_NAME2, "chat");
|
|
5784
6323
|
var StreamingWrapper = class {
|
|
5785
6324
|
constructor(span2, response, startTime, requestKwargs) {
|
|
5786
6325
|
this.iterator = null;
|
|
@@ -5878,7 +6417,7 @@ var StreamingWrapper = class {
|
|
|
5878
6417
|
this.span.end();
|
|
5879
6418
|
}
|
|
5880
6419
|
};
|
|
5881
|
-
var
|
|
6420
|
+
var AsyncStreamingWrapper = class {
|
|
5882
6421
|
constructor(span2, response, startTime, requestKwargs) {
|
|
5883
6422
|
this.iterator = null;
|
|
5884
6423
|
this.completeResponse = {
|
|
@@ -5998,7 +6537,7 @@ var AsyncStreamingWrapper2 = class {
|
|
|
5998
6537
|
// src/instrumentation/groq/index.ts
|
|
5999
6538
|
var INSTRUMENTATION_NAME3 = "netra.instrumentation.groq";
|
|
6000
6539
|
var INSTRUMENTS3 = ["groq-sdk >= 0.3.0"];
|
|
6001
|
-
var
|
|
6540
|
+
var originalMethods = /* @__PURE__ */ new Map();
|
|
6002
6541
|
var isInstrumented3 = false;
|
|
6003
6542
|
var groqClasses = [];
|
|
6004
6543
|
async function resolveGroqAsync() {
|
|
@@ -6109,7 +6648,7 @@ var NetraGroqInstrumentor = class {
|
|
|
6109
6648
|
classes.forEach((Groq, index) => {
|
|
6110
6649
|
this._uninstrumentChatCompletions(Groq, index);
|
|
6111
6650
|
});
|
|
6112
|
-
|
|
6651
|
+
originalMethods.clear();
|
|
6113
6652
|
groqClasses = [];
|
|
6114
6653
|
isInstrumented3 = false;
|
|
6115
6654
|
}
|
|
@@ -6130,7 +6669,7 @@ var NetraGroqInstrumentor = class {
|
|
|
6130
6669
|
return;
|
|
6131
6670
|
}
|
|
6132
6671
|
const originalCreate = CompletionsClass.prototype.create;
|
|
6133
|
-
|
|
6672
|
+
originalMethods.set(`chat.completions.create-${index}`, originalCreate);
|
|
6134
6673
|
const tracer = this.tracer;
|
|
6135
6674
|
const wrapper = chatWrapper3(tracer);
|
|
6136
6675
|
CompletionsClass.prototype.create = function(...args) {
|
|
@@ -6148,7 +6687,7 @@ var NetraGroqInstrumentor = class {
|
|
|
6148
6687
|
_uninstrumentChatCompletions(Groq, index) {
|
|
6149
6688
|
try {
|
|
6150
6689
|
const CompletionsClass = Groq.Chat?.Completions;
|
|
6151
|
-
const originalCreate =
|
|
6690
|
+
const originalCreate = originalMethods.get(`chat.completions.create-${index}`);
|
|
6152
6691
|
if (originalCreate && CompletionsClass?.prototype) {
|
|
6153
6692
|
CompletionsClass.prototype.create = originalCreate;
|
|
6154
6693
|
}
|
|
@@ -6987,7 +7526,7 @@ var INSTRUMENTATION_NAME4 = "netra.instrumentation.langgraph";
|
|
|
6987
7526
|
var INSTRUMENTS4 = ["langgraph >= 1.1.1"];
|
|
6988
7527
|
var isInstrumented4 = false;
|
|
6989
7528
|
var LanggraphClass = null;
|
|
6990
|
-
var
|
|
7529
|
+
var originalMethods2 = /* @__PURE__ */ new Map();
|
|
6991
7530
|
function findModuleInCache(moduleName) {
|
|
6992
7531
|
if (typeof __require !== "undefined" && __require.cache) {
|
|
6993
7532
|
const cache = __require.cache;
|
|
@@ -7083,7 +7622,7 @@ var NetraLanggraphInstrumentor = class {
|
|
|
7083
7622
|
this._uninstrumentInvoke(Langgraph);
|
|
7084
7623
|
this._uninstrumentStream(Langgraph);
|
|
7085
7624
|
}
|
|
7086
|
-
|
|
7625
|
+
originalMethods2.clear();
|
|
7087
7626
|
LanggraphClass = null;
|
|
7088
7627
|
isInstrumented4 = false;
|
|
7089
7628
|
}
|
|
@@ -7100,8 +7639,8 @@ var NetraLanggraphInstrumentor = class {
|
|
|
7100
7639
|
}
|
|
7101
7640
|
Logger.debug(`Found invoke on prototype: ${targetProto.constructor?.name}`);
|
|
7102
7641
|
const originalInvoke = targetProto.invoke;
|
|
7103
|
-
|
|
7104
|
-
|
|
7642
|
+
originalMethods2.set("langgraph.graph.invoke", originalInvoke);
|
|
7643
|
+
originalMethods2.set("langgraph.graph.invoke.proto", targetProto);
|
|
7105
7644
|
const tracer = this.tracer;
|
|
7106
7645
|
const wrapper = new LanggraphWrapper(tracer);
|
|
7107
7646
|
const patchedInvoke = async function(input, config2, ...rest) {
|
|
@@ -7135,8 +7674,8 @@ var NetraLanggraphInstrumentor = class {
|
|
|
7135
7674
|
}
|
|
7136
7675
|
Logger.debug(`Found stream on prototype: ${targetProto.constructor?.name}`);
|
|
7137
7676
|
const originalStream = targetProto.stream;
|
|
7138
|
-
|
|
7139
|
-
|
|
7677
|
+
originalMethods2.set("langgraph.graph.stream", originalStream);
|
|
7678
|
+
originalMethods2.set("langgraph.graph.stream.proto", targetProto);
|
|
7140
7679
|
const tracer = this.tracer;
|
|
7141
7680
|
const wrapper = new LanggraphWrapper(tracer);
|
|
7142
7681
|
targetProto.stream = async function(input, config2, ...rest) {
|
|
@@ -7156,8 +7695,8 @@ var NetraLanggraphInstrumentor = class {
|
|
|
7156
7695
|
}
|
|
7157
7696
|
_uninstrumentInvoke(Langgraph) {
|
|
7158
7697
|
try {
|
|
7159
|
-
const originalInvoke =
|
|
7160
|
-
const targetProto =
|
|
7698
|
+
const originalInvoke = originalMethods2.get("langgraph.graph.invoke");
|
|
7699
|
+
const targetProto = originalMethods2.get("langgraph.graph.invoke.proto") || Langgraph?.prototype;
|
|
7161
7700
|
if (originalInvoke && targetProto?.invoke) {
|
|
7162
7701
|
targetProto.invoke = originalInvoke;
|
|
7163
7702
|
}
|
|
@@ -7168,8 +7707,8 @@ var NetraLanggraphInstrumentor = class {
|
|
|
7168
7707
|
}
|
|
7169
7708
|
_uninstrumentStream(Langgraph) {
|
|
7170
7709
|
try {
|
|
7171
|
-
const originalStream =
|
|
7172
|
-
const targetProto =
|
|
7710
|
+
const originalStream = originalMethods2.get("langgraph.graph.stream");
|
|
7711
|
+
const targetProto = originalMethods2.get("langgraph.graph.stream.proto") || Langgraph?.prototype;
|
|
7173
7712
|
if (originalStream && targetProto?.stream) {
|
|
7174
7713
|
targetProto.stream = originalStream;
|
|
7175
7714
|
}
|
|
@@ -7209,11 +7748,11 @@ function setResponseAttributes5(span2, response) {
|
|
|
7209
7748
|
}
|
|
7210
7749
|
|
|
7211
7750
|
// src/instrumentation/mistralai/wrappers.ts
|
|
7212
|
-
var
|
|
7751
|
+
var CHAT_SPAN_NAME3 = "mistralai.chat";
|
|
7213
7752
|
var EMBEDDING_SPAN_NAME2 = "mistralai.embedding";
|
|
7214
7753
|
var FIM_SPAN_NAME = "mistralai.fim";
|
|
7215
7754
|
var AGENTS_SPAN_NAME = "mistralai.agents";
|
|
7216
|
-
var CHAT_STREAM_SPAN_NAME =
|
|
7755
|
+
var CHAT_STREAM_SPAN_NAME = CHAT_SPAN_NAME3;
|
|
7217
7756
|
var FIM_STREAM_SPAN_NAME = FIM_SPAN_NAME;
|
|
7218
7757
|
var AGENTS_STREAM_SPAN_NAME = AGENTS_SPAN_NAME;
|
|
7219
7758
|
function mistralWrapper(tracer, spanName, requestType) {
|
|
@@ -7308,7 +7847,7 @@ function mistralStreamWrapper(tracer, spanName, requestType) {
|
|
|
7308
7847
|
try {
|
|
7309
7848
|
const stream = await response;
|
|
7310
7849
|
if (stream && typeof stream === "object" && Symbol.asyncIterator in stream) {
|
|
7311
|
-
return new
|
|
7850
|
+
return new AsyncStreamingWrapper2(span2, stream, startTime, kwargs);
|
|
7312
7851
|
}
|
|
7313
7852
|
return new StreamingWrapper2(span2, stream, startTime, kwargs);
|
|
7314
7853
|
} catch (error) {
|
|
@@ -7324,7 +7863,7 @@ function mistralStreamWrapper(tracer, spanName, requestType) {
|
|
|
7324
7863
|
})();
|
|
7325
7864
|
}
|
|
7326
7865
|
if (response && typeof response === "object" && Symbol.asyncIterator in response) {
|
|
7327
|
-
return new
|
|
7866
|
+
return new AsyncStreamingWrapper2(span2, response, startTime, kwargs);
|
|
7328
7867
|
}
|
|
7329
7868
|
return new StreamingWrapper2(span2, response, startTime, kwargs);
|
|
7330
7869
|
} catch (error) {
|
|
@@ -7339,8 +7878,8 @@ function mistralStreamWrapper(tracer, spanName, requestType) {
|
|
|
7339
7878
|
}
|
|
7340
7879
|
};
|
|
7341
7880
|
}
|
|
7342
|
-
var chatWrapper4 = (tracer) => mistralWrapper(tracer,
|
|
7343
|
-
var
|
|
7881
|
+
var chatWrapper4 = (tracer) => mistralWrapper(tracer, CHAT_SPAN_NAME3, "chat");
|
|
7882
|
+
var chatStreamWrapper3 = (tracer) => mistralStreamWrapper(tracer, CHAT_STREAM_SPAN_NAME, "chat");
|
|
7344
7883
|
var embeddingsWrapper2 = (tracer) => mistralWrapper(tracer, EMBEDDING_SPAN_NAME2, "embedding");
|
|
7345
7884
|
var fimWrapper = (tracer) => mistralWrapper(tracer, FIM_SPAN_NAME, "fim");
|
|
7346
7885
|
var fimStreamWrapper = (tracer) => mistralStreamWrapper(tracer, FIM_STREAM_SPAN_NAME, "fim");
|
|
@@ -7491,7 +8030,7 @@ var StreamingWrapper2 = class {
|
|
|
7491
8030
|
this.span.end();
|
|
7492
8031
|
}
|
|
7493
8032
|
};
|
|
7494
|
-
var
|
|
8033
|
+
var AsyncStreamingWrapper2 = class {
|
|
7495
8034
|
constructor(span2, response, startTime, requestKwargs) {
|
|
7496
8035
|
this.iterator = null;
|
|
7497
8036
|
defineHidden(this, "span", span2);
|
|
@@ -7641,7 +8180,7 @@ var AsyncStreamingWrapper3 = class {
|
|
|
7641
8180
|
// src/instrumentation/mistralai/index.ts
|
|
7642
8181
|
var INSTRUMENTATION_NAME5 = "netra.instrumentation.mistral_ai";
|
|
7643
8182
|
var INSTRUMENTS5 = ["@mistralai/mistralai >= 1.0.0"];
|
|
7644
|
-
var
|
|
8183
|
+
var originalMethods3 = /* @__PURE__ */ new Map();
|
|
7645
8184
|
var isInstrumented5 = false;
|
|
7646
8185
|
var mistralClasses = [];
|
|
7647
8186
|
async function resolveMistralAsync() {
|
|
@@ -7790,7 +8329,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7790
8329
|
this._uninstrumentFIM(Mistral, index);
|
|
7791
8330
|
this._uninstrumentAgents(Mistral, index);
|
|
7792
8331
|
});
|
|
7793
|
-
|
|
8332
|
+
originalMethods3.clear();
|
|
7794
8333
|
mistralClasses = [];
|
|
7795
8334
|
isInstrumented5 = false;
|
|
7796
8335
|
}
|
|
@@ -7836,7 +8375,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7836
8375
|
let didPatch = false;
|
|
7837
8376
|
if (ChatClass?.prototype?.complete) {
|
|
7838
8377
|
const originalComplete = ChatClass.prototype.complete;
|
|
7839
|
-
|
|
8378
|
+
originalMethods3.set(`chat.complete-${index}`, originalComplete);
|
|
7840
8379
|
const tracer = this.tracer;
|
|
7841
8380
|
const wrapper = chatWrapper4(tracer);
|
|
7842
8381
|
ChatClass.prototype.complete = function(...args) {
|
|
@@ -7853,9 +8392,9 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7853
8392
|
}
|
|
7854
8393
|
if (ChatClass?.prototype?.stream) {
|
|
7855
8394
|
const originalStream = ChatClass.prototype.stream;
|
|
7856
|
-
|
|
8395
|
+
originalMethods3.set(`chat.stream-${index}`, originalStream);
|
|
7857
8396
|
const tracer = this.tracer;
|
|
7858
|
-
const wrapper =
|
|
8397
|
+
const wrapper = chatStreamWrapper3(tracer);
|
|
7859
8398
|
ChatClass.prototype.stream = function(...args) {
|
|
7860
8399
|
const original = originalStream.bind(this);
|
|
7861
8400
|
const kwargs = args[0] || {};
|
|
@@ -7881,7 +8420,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7881
8420
|
let didPatch = false;
|
|
7882
8421
|
if (EmbeddingsClass?.prototype?.create) {
|
|
7883
8422
|
const originalCreate = EmbeddingsClass.prototype.create;
|
|
7884
|
-
|
|
8423
|
+
originalMethods3.set(`embeddings.create-${index}`, originalCreate);
|
|
7885
8424
|
const tracer = this.tracer;
|
|
7886
8425
|
const wrapper = embeddingsWrapper2(tracer);
|
|
7887
8426
|
EmbeddingsClass.prototype.create = function(...args) {
|
|
@@ -7909,7 +8448,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7909
8448
|
let didPatch = false;
|
|
7910
8449
|
if (FimClass?.prototype?.complete) {
|
|
7911
8450
|
const originalComplete = FimClass.prototype.complete;
|
|
7912
|
-
|
|
8451
|
+
originalMethods3.set(`fim.complete-${index}`, originalComplete);
|
|
7913
8452
|
const tracer = this.tracer;
|
|
7914
8453
|
const wrapper = fimWrapper(tracer);
|
|
7915
8454
|
FimClass.prototype.complete = function(...args) {
|
|
@@ -7926,7 +8465,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7926
8465
|
}
|
|
7927
8466
|
if (FimClass?.prototype?.stream) {
|
|
7928
8467
|
const originalStream = FimClass.prototype.stream;
|
|
7929
|
-
|
|
8468
|
+
originalMethods3.set(`fim.stream-${index}`, originalStream);
|
|
7930
8469
|
const tracer = this.tracer;
|
|
7931
8470
|
const wrapper = fimStreamWrapper(tracer);
|
|
7932
8471
|
FimClass.prototype.stream = function(...args) {
|
|
@@ -7954,7 +8493,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7954
8493
|
let didPatch = false;
|
|
7955
8494
|
if (AgentsClass?.prototype?.complete) {
|
|
7956
8495
|
const originalComplete = AgentsClass.prototype.complete;
|
|
7957
|
-
|
|
8496
|
+
originalMethods3.set(`agents.complete-${index}`, originalComplete);
|
|
7958
8497
|
const tracer = this.tracer;
|
|
7959
8498
|
const wrapper = agentsWrapper(tracer);
|
|
7960
8499
|
AgentsClass.prototype.complete = function(...args) {
|
|
@@ -7971,7 +8510,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7971
8510
|
}
|
|
7972
8511
|
if (AgentsClass?.prototype?.stream) {
|
|
7973
8512
|
const originalStream = AgentsClass.prototype.stream;
|
|
7974
|
-
|
|
8513
|
+
originalMethods3.set(`agents.stream-${index}`, originalStream);
|
|
7975
8514
|
const tracer = this.tracer;
|
|
7976
8515
|
const wrapper = agentsStreamWrapper(tracer);
|
|
7977
8516
|
AgentsClass.prototype.stream = function(...args) {
|
|
@@ -7995,11 +8534,11 @@ var NetraMistralAIInstrumentor = class {
|
|
|
7995
8534
|
_uninstrumentChat(Mistral, index) {
|
|
7996
8535
|
try {
|
|
7997
8536
|
const ChatClass = this._getCtor(Mistral, "chat");
|
|
7998
|
-
const originalComplete =
|
|
8537
|
+
const originalComplete = originalMethods3.get(`chat.complete-${index}`);
|
|
7999
8538
|
if (originalComplete && ChatClass?.prototype) {
|
|
8000
8539
|
ChatClass.prototype.complete = originalComplete;
|
|
8001
8540
|
}
|
|
8002
|
-
const originalStream =
|
|
8541
|
+
const originalStream = originalMethods3.get(`chat.stream-${index}`);
|
|
8003
8542
|
if (originalStream && ChatClass?.prototype) {
|
|
8004
8543
|
ChatClass.prototype.stream = originalStream;
|
|
8005
8544
|
}
|
|
@@ -8010,7 +8549,7 @@ var NetraMistralAIInstrumentor = class {
|
|
|
8010
8549
|
_uninstrumentEmbeddings(Mistral, index) {
|
|
8011
8550
|
try {
|
|
8012
8551
|
const EmbeddingsClass = this._getCtor(Mistral, "embeddings");
|
|
8013
|
-
const originalCreate =
|
|
8552
|
+
const originalCreate = originalMethods3.get(`embeddings.create-${index}`);
|
|
8014
8553
|
if (originalCreate && EmbeddingsClass?.prototype) {
|
|
8015
8554
|
EmbeddingsClass.prototype.create = originalCreate;
|
|
8016
8555
|
}
|
|
@@ -8021,11 +8560,11 @@ var NetraMistralAIInstrumentor = class {
|
|
|
8021
8560
|
_uninstrumentFIM(Mistral, index) {
|
|
8022
8561
|
try {
|
|
8023
8562
|
const FimClass = this._getCtor(Mistral, "fim");
|
|
8024
|
-
const originalComplete =
|
|
8563
|
+
const originalComplete = originalMethods3.get(`fim.complete-${index}`);
|
|
8025
8564
|
if (originalComplete && FimClass?.prototype) {
|
|
8026
8565
|
FimClass.prototype.complete = originalComplete;
|
|
8027
8566
|
}
|
|
8028
|
-
const originalStream =
|
|
8567
|
+
const originalStream = originalMethods3.get(`fim.stream-${index}`);
|
|
8029
8568
|
if (originalStream && FimClass?.prototype) {
|
|
8030
8569
|
FimClass.prototype.stream = originalStream;
|
|
8031
8570
|
}
|
|
@@ -8036,11 +8575,11 @@ var NetraMistralAIInstrumentor = class {
|
|
|
8036
8575
|
_uninstrumentAgents(Mistral, index) {
|
|
8037
8576
|
try {
|
|
8038
8577
|
const AgentsClass = this._getCtor(Mistral, "agents");
|
|
8039
|
-
const originalComplete =
|
|
8578
|
+
const originalComplete = originalMethods3.get(`agents.complete-${index}`);
|
|
8040
8579
|
if (originalComplete && AgentsClass?.prototype) {
|
|
8041
8580
|
AgentsClass.prototype.complete = originalComplete;
|
|
8042
8581
|
}
|
|
8043
|
-
const originalStream =
|
|
8582
|
+
const originalStream = originalMethods3.get(`agents.stream-${index}`);
|
|
8044
8583
|
if (originalStream && AgentsClass?.prototype) {
|
|
8045
8584
|
AgentsClass.prototype.stream = originalStream;
|
|
8046
8585
|
}
|
|
@@ -8068,7 +8607,7 @@ function setResponseAttributes6(span2, response) {
|
|
|
8068
8607
|
}
|
|
8069
8608
|
|
|
8070
8609
|
// src/instrumentation/openai/wrappers.ts
|
|
8071
|
-
var
|
|
8610
|
+
var SPAN_NAMES2 = {
|
|
8072
8611
|
chat: "openai.chat",
|
|
8073
8612
|
embedding: "openai.embedding",
|
|
8074
8613
|
response: "openai.response"
|
|
@@ -8209,7 +8748,7 @@ var StreamingWrapper3 = class extends BaseStreamHandler {
|
|
|
8209
8748
|
throw new Error("Response is not iterable");
|
|
8210
8749
|
}
|
|
8211
8750
|
};
|
|
8212
|
-
var
|
|
8751
|
+
var AsyncStreamingWrapper3 = class extends BaseStreamHandler {
|
|
8213
8752
|
constructor(span2, response, startTime, requestKwargs) {
|
|
8214
8753
|
super(span2, startTime, requestKwargs);
|
|
8215
8754
|
this.iterator = null;
|
|
@@ -8265,7 +8804,7 @@ function executeStreaming(span2, ctx, kwargs, requestType, call) {
|
|
|
8265
8804
|
return (async () => {
|
|
8266
8805
|
try {
|
|
8267
8806
|
const stream = await response;
|
|
8268
|
-
return new
|
|
8807
|
+
return new AsyncStreamingWrapper3(span2, stream, startTime, kwargs);
|
|
8269
8808
|
} catch (error) {
|
|
8270
8809
|
handleSpanError(span2, error);
|
|
8271
8810
|
throw error;
|
|
@@ -8303,7 +8842,7 @@ function executeNonStreaming(span2, kwargs, requestType, call) {
|
|
|
8303
8842
|
}
|
|
8304
8843
|
}
|
|
8305
8844
|
function openAIWrapper(tracer, requestType) {
|
|
8306
|
-
const spanName =
|
|
8845
|
+
const spanName = SPAN_NAMES2[requestType];
|
|
8307
8846
|
const spanOpts = { kind: SpanKind.CLIENT, attributes: { "llm.request.type": requestType } };
|
|
8308
8847
|
return (wrapped, instance, args, kwargs) => {
|
|
8309
8848
|
if (shouldSuppressInstrumentation()) {
|
|
@@ -9132,6 +9671,8 @@ var cachedAgentsModule = null;
|
|
|
9132
9671
|
var isInstrumented6 = false;
|
|
9133
9672
|
var activeTracer = null;
|
|
9134
9673
|
var activeProcessor = null;
|
|
9674
|
+
var originalProcessors = null;
|
|
9675
|
+
var didReplaceProcessors = false;
|
|
9135
9676
|
async function resolveAgentsModule() {
|
|
9136
9677
|
if (cachedAgentsModule) return cachedAgentsModule;
|
|
9137
9678
|
try {
|
|
@@ -9184,20 +9725,51 @@ var NetraOpenAIAgentsInstrumentor = class {
|
|
|
9184
9725
|
}
|
|
9185
9726
|
const systemName = options.systemName ?? DEFAULT_LLM_SYSTEM;
|
|
9186
9727
|
activeProcessor = new NetraAgentsTracingProcessor(activeTracer, systemName);
|
|
9728
|
+
const mode = options.nativeTracing ?? parseNativeTracingEnv("NATIVE_TRACING_MODE") ?? "netra-strict";
|
|
9729
|
+
const canSet = typeof agentsModule.setTraceProcessors === "function";
|
|
9730
|
+
const canAdd = typeof agentsModule.addTraceProcessor === "function";
|
|
9731
|
+
let strategy;
|
|
9732
|
+
if (mode === "both" || mode === "netra" && !canSet) {
|
|
9733
|
+
strategy = "append";
|
|
9734
|
+
} else if (canSet) {
|
|
9735
|
+
strategy = "replace";
|
|
9736
|
+
} else {
|
|
9737
|
+
strategy = "skip";
|
|
9738
|
+
}
|
|
9187
9739
|
try {
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
"OpenAI Agents
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9740
|
+
switch (strategy) {
|
|
9741
|
+
case "replace":
|
|
9742
|
+
if (typeof agentsModule.getTraceProcessors === "function") {
|
|
9743
|
+
originalProcessors = agentsModule.getTraceProcessors();
|
|
9744
|
+
}
|
|
9745
|
+
agentsModule.setTraceProcessors([activeProcessor]);
|
|
9746
|
+
didReplaceProcessors = true;
|
|
9747
|
+
Logger.debug("OpenAI Agents native tracing disabled \u2014 traces will only be sent to Netra.");
|
|
9748
|
+
break;
|
|
9749
|
+
case "append":
|
|
9750
|
+
if (canAdd) {
|
|
9751
|
+
agentsModule.addTraceProcessor(activeProcessor);
|
|
9752
|
+
} else {
|
|
9753
|
+
Logger.warn("OpenAI Agents SDK does not expose addTraceProcessor or setTraceProcessors.");
|
|
9754
|
+
activeProcessor = null;
|
|
9755
|
+
activeTracer = null;
|
|
9756
|
+
return this;
|
|
9757
|
+
}
|
|
9758
|
+
if (mode === "netra") {
|
|
9759
|
+
Logger.warn(
|
|
9760
|
+
"Cannot exclusively replace native trace processors in this @openai/agents version.",
|
|
9761
|
+
"Traces may still be sent to OpenAI."
|
|
9762
|
+
);
|
|
9763
|
+
}
|
|
9764
|
+
break;
|
|
9765
|
+
case "skip":
|
|
9766
|
+
Logger.warn(
|
|
9767
|
+
'nativeTracing is "netra-strict" but the installed @openai/agents version',
|
|
9768
|
+
"does not support processor replacement. Skipping instrumentation."
|
|
9769
|
+
);
|
|
9770
|
+
activeProcessor = null;
|
|
9771
|
+
activeTracer = null;
|
|
9772
|
+
return this;
|
|
9201
9773
|
}
|
|
9202
9774
|
} catch (error) {
|
|
9203
9775
|
Logger.warn("Failed to register trace processor with @openai/agents:", error);
|
|
@@ -9217,6 +9789,21 @@ var NetraOpenAIAgentsInstrumentor = class {
|
|
|
9217
9789
|
activeProcessor.shutdown();
|
|
9218
9790
|
activeProcessor = null;
|
|
9219
9791
|
}
|
|
9792
|
+
if (didReplaceProcessors && cachedAgentsModule) {
|
|
9793
|
+
try {
|
|
9794
|
+
if (originalProcessors && typeof cachedAgentsModule.setTraceProcessors === "function") {
|
|
9795
|
+
cachedAgentsModule.setTraceProcessors(originalProcessors);
|
|
9796
|
+
Logger.debug("Restored original OpenAI Agents trace processors");
|
|
9797
|
+
} else if (typeof cachedAgentsModule.setDefaultOpenAITracingExporter === "function") {
|
|
9798
|
+
cachedAgentsModule.setDefaultOpenAITracingExporter();
|
|
9799
|
+
Logger.debug("Restored default OpenAI Agents tracing exporter");
|
|
9800
|
+
}
|
|
9801
|
+
} catch (error) {
|
|
9802
|
+
Logger.debug("Failed to restore original trace processors:", error);
|
|
9803
|
+
}
|
|
9804
|
+
}
|
|
9805
|
+
originalProcessors = null;
|
|
9806
|
+
didReplaceProcessors = false;
|
|
9220
9807
|
activeTracer = null;
|
|
9221
9808
|
cachedAgentsModule = null;
|
|
9222
9809
|
isInstrumented6 = false;
|
|
@@ -9481,7 +10068,7 @@ function repositoryQueryWrapper(tracer) {
|
|
|
9481
10068
|
var __version__8 = "1.0.0";
|
|
9482
10069
|
var require2 = createRequire(import.meta.url);
|
|
9483
10070
|
var INSTRUMENTATION_NAME8 = "netra.instrumentation.typeorm";
|
|
9484
|
-
var
|
|
10071
|
+
var originalMethods4 = /* @__PURE__ */ new Map();
|
|
9485
10072
|
var isInstrumented7 = false;
|
|
9486
10073
|
var NetraTypeORMInstrumentor = class {
|
|
9487
10074
|
constructor() {
|
|
@@ -9515,7 +10102,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9515
10102
|
});
|
|
9516
10103
|
this._uninstrumentRepository().catch(() => {
|
|
9517
10104
|
});
|
|
9518
|
-
|
|
10105
|
+
originalMethods4.clear();
|
|
9519
10106
|
isInstrumented7 = false;
|
|
9520
10107
|
}
|
|
9521
10108
|
isInstrumented() {
|
|
@@ -9534,7 +10121,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9534
10121
|
}
|
|
9535
10122
|
if (DataSource.prototype?.query) {
|
|
9536
10123
|
const originalQuery = DataSource.prototype.query;
|
|
9537
|
-
|
|
10124
|
+
originalMethods4.set("DataSource.prototype.query", originalQuery);
|
|
9538
10125
|
const tracer = this.tracer;
|
|
9539
10126
|
const wrapper = queryWrapper(tracer);
|
|
9540
10127
|
DataSource.prototype.query = function(...args) {
|
|
@@ -9559,7 +10146,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9559
10146
|
}
|
|
9560
10147
|
if (EntityManager.prototype?.query) {
|
|
9561
10148
|
const originalQuery = EntityManager.prototype.query;
|
|
9562
|
-
|
|
10149
|
+
originalMethods4.set("EntityManager.prototype.query", originalQuery);
|
|
9563
10150
|
const tracer = this.tracer;
|
|
9564
10151
|
const wrapper = managerQueryWrapper(tracer);
|
|
9565
10152
|
EntityManager.prototype.query = function(...args) {
|
|
@@ -9584,7 +10171,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9584
10171
|
}
|
|
9585
10172
|
if (Repository.prototype?.query) {
|
|
9586
10173
|
const originalQuery = Repository.prototype.query;
|
|
9587
|
-
|
|
10174
|
+
originalMethods4.set("Repository.prototype.query", originalQuery);
|
|
9588
10175
|
const tracer = this.tracer;
|
|
9589
10176
|
const wrapper = repositoryQueryWrapper(tracer);
|
|
9590
10177
|
Repository.prototype.query = function(...args) {
|
|
@@ -9600,7 +10187,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9600
10187
|
try {
|
|
9601
10188
|
const typeorm = require2("typeorm");
|
|
9602
10189
|
const DataSource = typeorm.DataSource || typeorm.default?.DataSource;
|
|
9603
|
-
const originalQuery =
|
|
10190
|
+
const originalQuery = originalMethods4.get("DataSource.prototype.query");
|
|
9604
10191
|
if (originalQuery && DataSource?.prototype) {
|
|
9605
10192
|
DataSource.prototype.query = originalQuery;
|
|
9606
10193
|
}
|
|
@@ -9612,7 +10199,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9612
10199
|
try {
|
|
9613
10200
|
const typeorm = require2("typeorm");
|
|
9614
10201
|
const EntityManager = typeorm.EntityManager || typeorm.default?.EntityManager;
|
|
9615
|
-
const originalQuery =
|
|
10202
|
+
const originalQuery = originalMethods4.get("EntityManager.prototype.query");
|
|
9616
10203
|
if (originalQuery && EntityManager?.prototype) {
|
|
9617
10204
|
EntityManager.prototype.query = originalQuery;
|
|
9618
10205
|
}
|
|
@@ -9624,7 +10211,7 @@ var NetraTypeORMInstrumentor = class {
|
|
|
9624
10211
|
try {
|
|
9625
10212
|
const typeorm = require2("typeorm");
|
|
9626
10213
|
const Repository = typeorm.Repository || typeorm.default?.Repository;
|
|
9627
|
-
const originalQuery =
|
|
10214
|
+
const originalQuery = originalMethods4.get("Repository.prototype.query");
|
|
9628
10215
|
if (originalQuery && Repository?.prototype) {
|
|
9629
10216
|
Repository.prototype.query = originalQuery;
|
|
9630
10217
|
}
|
|
@@ -10099,7 +10686,9 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
|
|
|
10099
10686
|
mistral: false,
|
|
10100
10687
|
langgraph: false,
|
|
10101
10688
|
googleGenAI: false,
|
|
10102
|
-
anthropic: false
|
|
10689
|
+
anthropic: false,
|
|
10690
|
+
openAiAgents: false
|
|
10691
|
+
};
|
|
10103
10692
|
const resolved = enableAll ? new Set(Object.values(NetraInstruments).filter((v) => v !== "__all__" /* ALL */)) : instruments && instruments.size > 0 ? instruments : DEFAULT_INSTRUMENTS;
|
|
10104
10693
|
instrumentModules.google_vertexai = false;
|
|
10105
10694
|
instrumentModules.langchain = false;
|
|
@@ -10147,6 +10736,9 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
|
|
|
10147
10736
|
if (resolved.has("anthropic" /* ANTHROPIC */)) {
|
|
10148
10737
|
customInstrumentModules.anthropic = true;
|
|
10149
10738
|
}
|
|
10739
|
+
if (resolved.has("openai_agents" /* OPENAI_AGENTS */)) {
|
|
10740
|
+
customInstrumentModules.openAiAgents = true;
|
|
10741
|
+
}
|
|
10150
10742
|
if (blockInstruments && blockInstruments.size > 0) {
|
|
10151
10743
|
const blockAll = blockInstruments.has("__all__" /* ALL */);
|
|
10152
10744
|
if (blockAll || blockInstruments.has("openai" /* OPENAI */)) customInstrumentModules.openai = false;
|
|
@@ -10155,6 +10747,7 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
|
|
|
10155
10747
|
if (blockAll || blockInstruments.has("langgraph" /* LANGGRAPH */)) customInstrumentModules.langgraph = false;
|
|
10156
10748
|
if (blockAll || blockInstruments.has("google_genai" /* GOOGLE_GENERATIVE_AI */)) customInstrumentModules.googleGenAI = false;
|
|
10157
10749
|
if (blockAll || blockInstruments.has("anthropic" /* ANTHROPIC */)) customInstrumentModules.anthropic = false;
|
|
10750
|
+
if (blockAll || blockInstruments.has("openai_agents" /* OPENAI_AGENTS */)) customInstrumentModules.openAiAgents = false;
|
|
10158
10751
|
if (blockAll || blockInstruments.has("vertexai" /* VERTEX_AI */)) instrumentModules.google_vertexai = false;
|
|
10159
10752
|
if (blockAll || blockInstruments.has("langchain" /* LANGCHAIN */)) instrumentModules.langchain = false;
|
|
10160
10753
|
if (blockAll || blockInstruments.has("llama_index" /* LLAMA_INDEX */)) instrumentModules.llamaIndex = false;
|
|
@@ -10271,13 +10864,13 @@ async function initCustomInstrumentationsAsync(config2, tracerProvider, customIn
|
|
|
10271
10864
|
}
|
|
10272
10865
|
if (customInstrumentModules.anthropic) {
|
|
10273
10866
|
try {
|
|
10274
|
-
await anthropicInstrumentor.
|
|
10867
|
+
await anthropicInstrumentor.instrument({ tracerProvider });
|
|
10275
10868
|
Logger.debug("Custom Anthropic instrumentation enabled");
|
|
10276
10869
|
} catch (e) {
|
|
10277
10870
|
Logger.debug("Failed to initialize custom Anthropic instrumentation:", e);
|
|
10278
10871
|
}
|
|
10279
10872
|
}
|
|
10280
|
-
if (customInstrumentModules.
|
|
10873
|
+
if (customInstrumentModules.openAiAgents && !blockInstruments?.has("openai_agents" /* OPENAI_AGENTS */)) {
|
|
10281
10874
|
try {
|
|
10282
10875
|
await openaiAgentsInstrumentor.instrument({ tracerProvider });
|
|
10283
10876
|
Logger.debug("Custom OpenAI Agents SDK instrumentation enabled");
|
|
@@ -10423,7 +11016,7 @@ function addCustomSpanProcessors(tracerProvider, config2, rootInstrumentNames) {
|
|
|
10423
11016
|
}
|
|
10424
11017
|
const instrumentationProcessor = new InstrumentationSpanProcessor();
|
|
10425
11018
|
provider.addSpanProcessor(instrumentationProcessor);
|
|
10426
|
-
const sessionProcessor = new SessionSpanProcessor();
|
|
11019
|
+
const sessionProcessor = new SessionSpanProcessor(config2.environment);
|
|
10427
11020
|
provider.addSpanProcessor(sessionProcessor);
|
|
10428
11021
|
const spanIOProcessor = new SpanIOProcessor();
|
|
10429
11022
|
provider.addSpanProcessor(spanIOProcessor);
|
|
@@ -10435,6 +11028,10 @@ function addCustomSpanProcessors(tracerProvider, config2, rootInstrumentNames) {
|
|
|
10435
11028
|
const scrubbingProcessor = new ScrubbingSpanProcessor();
|
|
10436
11029
|
provider.addSpanProcessor(scrubbingProcessor);
|
|
10437
11030
|
}
|
|
11031
|
+
const sizeLimitProcessor = new AttributeSizeLimitProcessor(
|
|
11032
|
+
Config.SPAN_ATTRIBUTE_MAX_SIZE
|
|
11033
|
+
);
|
|
11034
|
+
provider.addSpanProcessor(sizeLimitProcessor);
|
|
10438
11035
|
Logger.debug("Custom span processors registered successfully");
|
|
10439
11036
|
return provider;
|
|
10440
11037
|
} catch (e) {
|
|
@@ -11083,33 +11680,6 @@ var Tracer17 = class {
|
|
|
11083
11680
|
}
|
|
11084
11681
|
}
|
|
11085
11682
|
};
|
|
11086
|
-
function safeStringify3(value, maxLen = 1e3) {
|
|
11087
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
11088
|
-
try {
|
|
11089
|
-
return JSON.stringify(value, (_key, val) => {
|
|
11090
|
-
if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`;
|
|
11091
|
-
if (typeof val === "symbol") return val.toString();
|
|
11092
|
-
if (typeof val === "bigint") return val.toString();
|
|
11093
|
-
if (val !== null && typeof val === "object") {
|
|
11094
|
-
if (seen.has(val)) return "[Circular]";
|
|
11095
|
-
seen.add(val);
|
|
11096
|
-
const name = val.constructor?.name;
|
|
11097
|
-
if (name && name !== "Object" && name !== "Array" && Object.keys(val).length > 20) {
|
|
11098
|
-
return `[${name}]`;
|
|
11099
|
-
}
|
|
11100
|
-
}
|
|
11101
|
-
return val;
|
|
11102
|
-
}).substring(0, maxLen);
|
|
11103
|
-
} catch {
|
|
11104
|
-
return value?.constructor?.name ? `[${value.constructor.name}]` : String(typeof value);
|
|
11105
|
-
}
|
|
11106
|
-
}
|
|
11107
|
-
function serializeValue2(value) {
|
|
11108
|
-
if (value === null || value === void 0) return String(value);
|
|
11109
|
-
const t = typeof value;
|
|
11110
|
-
if (t === "string" || t === "number" || t === "boolean") return String(value);
|
|
11111
|
-
return safeStringify3(value);
|
|
11112
|
-
}
|
|
11113
11683
|
function spanHasOutput(span2) {
|
|
11114
11684
|
try {
|
|
11115
11685
|
for (const field of ["attributes", "_attributes"]) {
|
|
@@ -11124,13 +11694,13 @@ function spanHasOutput(span2) {
|
|
|
11124
11694
|
function addInputAttributes(span2, args, entityType) {
|
|
11125
11695
|
span2.setAttribute(`${Config.LIBRARY_NAME}.entity.type`, entityType);
|
|
11126
11696
|
if (args.length > 0) {
|
|
11127
|
-
span2.setAttribute("input",
|
|
11697
|
+
span2.setAttribute("input", safeStringify(args, Config.ATTRIBUTE_MAX_LEN));
|
|
11128
11698
|
}
|
|
11129
11699
|
}
|
|
11130
11700
|
function addOutputAttributes(span2, result) {
|
|
11131
11701
|
if (spanHasOutput(span2)) return;
|
|
11132
11702
|
try {
|
|
11133
|
-
span2.setAttribute("output",
|
|
11703
|
+
span2.setAttribute("output", serializeValue(result, Config.ATTRIBUTE_MAX_LEN));
|
|
11134
11704
|
} catch (e) {
|
|
11135
11705
|
span2.setAttribute("output_error", String(e));
|
|
11136
11706
|
}
|
|
@@ -11150,69 +11720,63 @@ function createFunctionWrapper(func, entityType, name, asType = "SPAN" /* SPAN *
|
|
|
11150
11720
|
span2.setAttribute("netra.span.type", asType);
|
|
11151
11721
|
SessionManager.registerSpan(spanName, span2);
|
|
11152
11722
|
};
|
|
11153
|
-
const
|
|
11723
|
+
const recordError = (span2, e) => {
|
|
11154
11724
|
span2.setAttribute(`${Config.LIBRARY_NAME}.entity.error`, String(e));
|
|
11155
11725
|
span2.setStatus({
|
|
11156
11726
|
code: SpanStatusCode.ERROR,
|
|
11157
11727
|
message: e instanceof Error ? e.message : String(e)
|
|
11158
11728
|
});
|
|
11159
11729
|
span2.recordException(e);
|
|
11160
|
-
throw e;
|
|
11161
11730
|
};
|
|
11162
11731
|
const cleanup = (span2) => {
|
|
11163
11732
|
span2.end();
|
|
11164
11733
|
SessionManager.unregisterSpan(spanName, span2);
|
|
11165
11734
|
SessionManager.popEntity(entityType);
|
|
11166
11735
|
};
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
}
|
|
11212
|
-
});
|
|
11213
|
-
};
|
|
11214
|
-
return wrapper;
|
|
11215
|
-
}
|
|
11736
|
+
const wrapperFn = isAsync ? async function(...args) {
|
|
11737
|
+
SessionManager.pushEntity(entityType, spanName);
|
|
11738
|
+
const tracer = trace.getTracer(moduleName);
|
|
11739
|
+
return tracer.startActiveSpan(spanName, async (span2) => {
|
|
11740
|
+
try {
|
|
11741
|
+
initSpan(span2);
|
|
11742
|
+
addInputAttributes(span2, args, entityType);
|
|
11743
|
+
const result = await func.call(this, ...args);
|
|
11744
|
+
const spanCtx = trace.setSpan(context.active(), span2);
|
|
11745
|
+
return wrapResponse(result, {
|
|
11746
|
+
withContext: (fn) => context.with(spanCtx, fn),
|
|
11747
|
+
onError: (e) => recordError(span2, e),
|
|
11748
|
+
onSuccess: (value) => addOutputAttributes(span2, value),
|
|
11749
|
+
finalize: () => cleanup(span2)
|
|
11750
|
+
});
|
|
11751
|
+
} catch (e) {
|
|
11752
|
+
recordError(span2, e);
|
|
11753
|
+
cleanup(span2);
|
|
11754
|
+
throw e;
|
|
11755
|
+
}
|
|
11756
|
+
});
|
|
11757
|
+
} : function(...args) {
|
|
11758
|
+
SessionManager.pushEntity(entityType, spanName);
|
|
11759
|
+
const tracer = trace.getTracer(moduleName);
|
|
11760
|
+
return tracer.startActiveSpan(spanName, (span2) => {
|
|
11761
|
+
try {
|
|
11762
|
+
initSpan(span2);
|
|
11763
|
+
addInputAttributes(span2, args, entityType);
|
|
11764
|
+
const result = func.call(this, ...args);
|
|
11765
|
+
const spanCtx = trace.setSpan(context.active(), span2);
|
|
11766
|
+
return wrapResponse(result, {
|
|
11767
|
+
withContext: (fn) => context.with(spanCtx, fn),
|
|
11768
|
+
onError: (e) => recordError(span2, e),
|
|
11769
|
+
onSuccess: (value) => addOutputAttributes(span2, value),
|
|
11770
|
+
finalize: () => cleanup(span2)
|
|
11771
|
+
});
|
|
11772
|
+
} catch (e) {
|
|
11773
|
+
recordError(span2, e);
|
|
11774
|
+
cleanup(span2);
|
|
11775
|
+
throw e;
|
|
11776
|
+
}
|
|
11777
|
+
});
|
|
11778
|
+
};
|
|
11779
|
+
return wrapperFn;
|
|
11216
11780
|
}
|
|
11217
11781
|
var SKIP_STATIC_PROPS = /* @__PURE__ */ new Set([
|
|
11218
11782
|
"length",
|
|
@@ -11599,14 +12163,11 @@ Received ${signal}. Shutting down Netra SDK...`);
|
|
|
11599
12163
|
spanWrapper.end();
|
|
11600
12164
|
throw e;
|
|
11601
12165
|
}
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
}
|
|
11608
|
-
spanWrapper.end();
|
|
11609
|
-
return result;
|
|
12166
|
+
return wrapResponse(result, {
|
|
12167
|
+
withContext: (fn2) => spanWrapper.withActive(fn2),
|
|
12168
|
+
onError: (e) => spanWrapper.setError(e instanceof Error ? e.message : String(e)),
|
|
12169
|
+
finalize: () => spanWrapper.end()
|
|
12170
|
+
});
|
|
11610
12171
|
});
|
|
11611
12172
|
}
|
|
11612
12173
|
};
|
|
@@ -11616,6 +12177,6 @@ Netra._metricsEnabled = false;
|
|
|
11616
12177
|
Netra.withBlockedSpansLocal = withBlockedSpansLocal;
|
|
11617
12178
|
var index_default = Netra;
|
|
11618
12179
|
|
|
11619
|
-
export { Aggregation, BaseTask, ChartType, Config, ConversationType, DEFAULT_INSTRUMENTS, DEFAULT_INSTRUMENTS_FOR_ROOT, Dashboard, DimensionField, EntryStatus, Evaluation, FilterField, FilterType, FilteringSpanExporter, GroupBy, InstrumentationSpanProcessor, Measure, Netra, NetraAgentsTracingProcessor, NetraInstruments, NetraOpenAIAgentsInstrumentor, Operator, Prompts, RunEntryContext, RunStatus, Scope, ScrubbingSpanProcessor, SessionSpanProcessor, Simulation, SpanIOProcessor, SpanType, TrialAwareOTLPExporter, Usage, agent, index_default as default, metadataField, mistralAIInstrumentor, netraExpressMiddleware, openaiAgentsInstrumentor, runWithExtractedContext, span, task, workflow };
|
|
12180
|
+
export { Aggregation, AttributeSizeLimitProcessor, BaseTask, ChartType, Config, ConversationType, DEFAULT_INSTRUMENTS, DEFAULT_INSTRUMENTS_FOR_ROOT, Dashboard, DimensionField, EntryStatus, Evaluation, FilterField, FilterType, FilteringSpanExporter, GroupBy, InstrumentationSpanProcessor, Measure, Netra, NetraAgentsTracingProcessor, NetraInstruments, NetraOpenAIAgentsInstrumentor, Operator, Prompts, RunEntryContext, RunStatus, Scope, ScrubbingSpanProcessor, SessionSpanProcessor, Simulation, SpanIOProcessor, SpanType, TrialAwareOTLPExporter, Usage, agent, index_default as default, metadataField, mistralAIInstrumentor, netraExpressMiddleware, openaiAgentsInstrumentor, runWithExtractedContext, span, task, workflow };
|
|
11620
12181
|
//# sourceMappingURL=index.js.map
|
|
11621
12182
|
//# sourceMappingURL=index.js.map
|