@anvia/langfuse 0.3.9 → 0.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/README.md +26 -22
- package/dist/index.d.ts +4 -1
- package/dist/index.js +518 -145
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -20,21 +20,30 @@ function modelParameters(request) {
|
|
|
20
20
|
return params;
|
|
21
21
|
}
|
|
22
22
|
function usageDetails(usage) {
|
|
23
|
+
if (usage.details !== void 0 && Object.keys(usage.details).length > 0) {
|
|
24
|
+
return { ...usage.details };
|
|
25
|
+
}
|
|
23
26
|
return {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
cachedInputTokens: usage.cachedInputTokens,
|
|
28
|
-
cacheCreationInputTokens: usage.cacheCreationInputTokens
|
|
27
|
+
input: usage.inputTokens,
|
|
28
|
+
output: usage.outputTokens,
|
|
29
|
+
total: usage.totalTokens
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
function usageDetailsFromRecord(usage) {
|
|
33
|
+
if (isRecord(usage.details)) {
|
|
34
|
+
const details = Object.fromEntries(
|
|
35
|
+
Object.entries(usage.details).filter(
|
|
36
|
+
(entry) => typeof entry[1] === "number" && Number.isFinite(entry[1]) && entry[1] >= 0
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
if (Object.keys(details).length > 0) {
|
|
40
|
+
return details;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
32
43
|
return {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
cachedInputTokens: numberValue(usage.cachedInputTokens) ?? 0,
|
|
37
|
-
cacheCreationInputTokens: numberValue(usage.cacheCreationInputTokens) ?? 0
|
|
44
|
+
input: numberValue(usage.inputTokens) ?? 0,
|
|
45
|
+
output: numberValue(usage.outputTokens) ?? 0,
|
|
46
|
+
total: numberValue(usage.totalTokens) ?? (numberValue(usage.inputTokens) ?? 0) + (numberValue(usage.outputTokens) ?? 0)
|
|
38
47
|
};
|
|
39
48
|
}
|
|
40
49
|
function childMetadata(args, agentId, agentName, childTurn) {
|
|
@@ -121,6 +130,8 @@ var LangfuseScoreError = class extends Error {
|
|
|
121
130
|
}
|
|
122
131
|
}
|
|
123
132
|
};
|
|
133
|
+
var RetryableLangfuseScoreError = class extends LangfuseScoreError {
|
|
134
|
+
};
|
|
124
135
|
var defaultSleep = (ms) => new Promise((resolve) => {
|
|
125
136
|
setTimeout(resolve, ms);
|
|
126
137
|
});
|
|
@@ -139,6 +150,7 @@ var ScoreQueue = class {
|
|
|
139
150
|
pending = [];
|
|
140
151
|
timer = null;
|
|
141
152
|
flushing = null;
|
|
153
|
+
closed = false;
|
|
142
154
|
baseUrl;
|
|
143
155
|
publicKey;
|
|
144
156
|
secretKey;
|
|
@@ -164,9 +176,12 @@ var ScoreQueue = class {
|
|
|
164
176
|
this.clearTimer = options.clearTimer ?? defaultClearTimer;
|
|
165
177
|
}
|
|
166
178
|
enqueue(score) {
|
|
179
|
+
if (this.closed) {
|
|
180
|
+
throw new Error("Langfuse score queue is shut down");
|
|
181
|
+
}
|
|
167
182
|
this.pending.push(score);
|
|
168
183
|
if (this.pending.length >= this.batchSize) {
|
|
169
|
-
|
|
184
|
+
this.triggerBackgroundFlush();
|
|
170
185
|
return;
|
|
171
186
|
}
|
|
172
187
|
this.scheduleTimer();
|
|
@@ -175,24 +190,36 @@ var ScoreQueue = class {
|
|
|
175
190
|
return this.pending.length;
|
|
176
191
|
}
|
|
177
192
|
async flush() {
|
|
178
|
-
if (this.flushing !== null) {
|
|
179
|
-
await this.flushing;
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (this.pending.length === 0) {
|
|
183
|
-
this.clearScheduledTimer();
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const batch = this.pending.splice(0, this.pending.length);
|
|
187
193
|
this.clearScheduledTimer();
|
|
188
|
-
|
|
189
|
-
this.flushing
|
|
190
|
-
|
|
191
|
-
|
|
194
|
+
while (true) {
|
|
195
|
+
if (this.flushing !== null) {
|
|
196
|
+
await this.flushing;
|
|
197
|
+
if (this.pending.length === 0) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (this.pending.length === 0) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const draining = this.drain();
|
|
206
|
+
this.flushing = draining;
|
|
207
|
+
try {
|
|
208
|
+
await draining;
|
|
209
|
+
} finally {
|
|
210
|
+
if (this.flushing === draining) {
|
|
211
|
+
this.flushing = null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
192
215
|
}
|
|
193
216
|
async shutdown() {
|
|
217
|
+
this.closed = true;
|
|
194
218
|
this.clearScheduledTimer();
|
|
195
|
-
|
|
219
|
+
try {
|
|
220
|
+
await this.flush();
|
|
221
|
+
} catch {
|
|
222
|
+
}
|
|
196
223
|
}
|
|
197
224
|
scheduleTimer() {
|
|
198
225
|
if (this.timer !== null) {
|
|
@@ -200,9 +227,13 @@ var ScoreQueue = class {
|
|
|
200
227
|
}
|
|
201
228
|
this.timer = this.setTimer(() => {
|
|
202
229
|
this.timer = null;
|
|
203
|
-
|
|
230
|
+
this.triggerBackgroundFlush();
|
|
204
231
|
}, this.flushIntervalMs);
|
|
205
232
|
}
|
|
233
|
+
triggerBackgroundFlush() {
|
|
234
|
+
void this.flush().catch(() => {
|
|
235
|
+
});
|
|
236
|
+
}
|
|
206
237
|
clearScheduledTimer() {
|
|
207
238
|
if (this.timer !== null) {
|
|
208
239
|
this.clearTimer(this.timer);
|
|
@@ -245,12 +276,35 @@ var ScoreQueue = class {
|
|
|
245
276
|
await this.sleep(computeBackoff(attempt));
|
|
246
277
|
}
|
|
247
278
|
}
|
|
248
|
-
throw new
|
|
279
|
+
throw new RetryableLangfuseScoreError(
|
|
249
280
|
`Langfuse score batch failed after ${this.maxRetries} attempts`,
|
|
250
281
|
scores,
|
|
251
282
|
lastError
|
|
252
283
|
);
|
|
253
284
|
}
|
|
285
|
+
async drain() {
|
|
286
|
+
let permanentError;
|
|
287
|
+
while (this.pending.length > 0) {
|
|
288
|
+
const batch = this.pending.splice(0, this.batchSize);
|
|
289
|
+
try {
|
|
290
|
+
await this.sendBatch(batch);
|
|
291
|
+
} catch (error) {
|
|
292
|
+
if (error instanceof RetryableLangfuseScoreError) {
|
|
293
|
+
this.pending.unshift(...batch);
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
if (error instanceof LangfuseScoreError) {
|
|
297
|
+
permanentError ??= error;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
this.pending.unshift(...batch);
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (permanentError !== void 0) {
|
|
305
|
+
throw permanentError;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
254
308
|
};
|
|
255
309
|
function buildScoreBody(score) {
|
|
256
310
|
const body = {
|
|
@@ -947,29 +1001,42 @@ function cloneRegex(source, flags) {
|
|
|
947
1001
|
}
|
|
948
1002
|
function redactValue(value, depth, redactStringFn) {
|
|
949
1003
|
if (depth > MAX_DEPTH) return value;
|
|
950
|
-
if (typeof value === "string")
|
|
1004
|
+
if (typeof value === "string") {
|
|
1005
|
+
return isBase64DataUrl(value) ? value : redactStringFn(value);
|
|
1006
|
+
}
|
|
951
1007
|
if (Array.isArray(value))
|
|
952
1008
|
return value.map((entry) => redactValue(entry, depth + 1, redactStringFn));
|
|
953
1009
|
if (value !== null && typeof value === "object") {
|
|
1010
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
1011
|
+
return value;
|
|
1012
|
+
}
|
|
1013
|
+
const record = value;
|
|
954
1014
|
const out = {};
|
|
955
|
-
for (const [key, entry] of Object.entries(
|
|
956
|
-
|
|
1015
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
1016
|
+
if (key === "data" && typeof entry === "string" && (record.type === "base64" || record.type === "image" || record.type === "encrypted" || record.type === "redacted")) {
|
|
1017
|
+
out[key] = entry;
|
|
1018
|
+
} else {
|
|
1019
|
+
out[key] = redactValue(entry, depth + 1, redactStringFn);
|
|
1020
|
+
}
|
|
957
1021
|
}
|
|
958
1022
|
return out;
|
|
959
1023
|
}
|
|
960
1024
|
return value;
|
|
961
1025
|
}
|
|
962
1026
|
function redactMessage(message, redactStringFn) {
|
|
963
|
-
if (
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
return
|
|
1027
|
+
if (message.role === "system") {
|
|
1028
|
+
return { ...message, content: redactStringFn(message.content) };
|
|
1029
|
+
}
|
|
1030
|
+
return {
|
|
1031
|
+
...message,
|
|
1032
|
+
content: redactMessageContent(message.content, redactStringFn)
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
function redactMessageContent(value, redactStringFn) {
|
|
1036
|
+
return redactValue(value, 0, redactStringFn);
|
|
1037
|
+
}
|
|
1038
|
+
function isBase64DataUrl(value) {
|
|
1039
|
+
return /^data:[^;,]+;base64,/i.test(value);
|
|
973
1040
|
}
|
|
974
1041
|
|
|
975
1042
|
// src/tracing.ts
|
|
@@ -982,6 +1049,107 @@ import {
|
|
|
982
1049
|
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
983
1050
|
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
984
1051
|
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
1052
|
+
|
|
1053
|
+
// src/capture.ts
|
|
1054
|
+
var DEFAULT_CAPTURE_MAX_BYTES = 262144;
|
|
1055
|
+
var MIN_CAPTURE_MAX_BYTES = 96;
|
|
1056
|
+
function validateCaptureMaxBytes(value) {
|
|
1057
|
+
const resolved = value ?? DEFAULT_CAPTURE_MAX_BYTES;
|
|
1058
|
+
if (!Number.isInteger(resolved) || resolved < MIN_CAPTURE_MAX_BYTES) {
|
|
1059
|
+
throw new TypeError(
|
|
1060
|
+
`Langfuse captureMaxBytes must be an integer of at least ${MIN_CAPTURE_MAX_BYTES}`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
return resolved;
|
|
1064
|
+
}
|
|
1065
|
+
function sanitizeTraceValue(value, maxBytes) {
|
|
1066
|
+
validateCaptureMaxBytes(maxBytes);
|
|
1067
|
+
const sanitized = sanitizeValue(value, 0, /* @__PURE__ */ new WeakSet());
|
|
1068
|
+
let serialized;
|
|
1069
|
+
try {
|
|
1070
|
+
serialized = JSON.stringify(sanitized) ?? String(sanitized);
|
|
1071
|
+
} catch {
|
|
1072
|
+
return omitted("unserializable");
|
|
1073
|
+
}
|
|
1074
|
+
const originalBytes = utf8Bytes(serialized);
|
|
1075
|
+
if (originalBytes <= maxBytes) {
|
|
1076
|
+
return sanitized;
|
|
1077
|
+
}
|
|
1078
|
+
const preview = boundedPreview(serialized, originalBytes, maxBytes);
|
|
1079
|
+
return {
|
|
1080
|
+
anviaTraceValue: "truncated",
|
|
1081
|
+
originalBytes,
|
|
1082
|
+
preview
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function sanitizeValue(value, depth, seen) {
|
|
1086
|
+
if (depth > 16) {
|
|
1087
|
+
return omitted("depth");
|
|
1088
|
+
}
|
|
1089
|
+
if (typeof value === "string") {
|
|
1090
|
+
if (/^data:[^;,]+;base64,/i.test(value)) {
|
|
1091
|
+
return omitted("base64", utf8Bytes(value));
|
|
1092
|
+
}
|
|
1093
|
+
return value;
|
|
1094
|
+
}
|
|
1095
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
1096
|
+
const byteLength = value.byteLength;
|
|
1097
|
+
return omitted("binary", byteLength);
|
|
1098
|
+
}
|
|
1099
|
+
if (value === null || typeof value !== "object") {
|
|
1100
|
+
return value;
|
|
1101
|
+
}
|
|
1102
|
+
if (seen.has(value)) {
|
|
1103
|
+
return omitted("circular");
|
|
1104
|
+
}
|
|
1105
|
+
seen.add(value);
|
|
1106
|
+
if (Array.isArray(value)) {
|
|
1107
|
+
const result2 = value.map((entry) => sanitizeValue(entry, depth + 1, seen));
|
|
1108
|
+
seen.delete(value);
|
|
1109
|
+
return result2;
|
|
1110
|
+
}
|
|
1111
|
+
const record = value;
|
|
1112
|
+
const result = {};
|
|
1113
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
1114
|
+
if (key === "data" && typeof entry === "string" && (record.type === "base64" || record.type === "image" && typeof record.mediaType === "string")) {
|
|
1115
|
+
result[key] = omitted("base64", utf8Bytes(entry));
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
result[key] = sanitizeValue(entry, depth + 1, seen);
|
|
1119
|
+
}
|
|
1120
|
+
seen.delete(value);
|
|
1121
|
+
return result;
|
|
1122
|
+
}
|
|
1123
|
+
function omitted(reason, originalBytes) {
|
|
1124
|
+
return {
|
|
1125
|
+
anviaTraceValue: "omitted",
|
|
1126
|
+
reason,
|
|
1127
|
+
...originalBytes === void 0 ? {} : { originalBytes }
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
function boundedPreview(value, originalBytes, maxBytes) {
|
|
1131
|
+
let low = 0;
|
|
1132
|
+
let high = value.length;
|
|
1133
|
+
while (low < high) {
|
|
1134
|
+
const middle = Math.ceil((low + high) / 2);
|
|
1135
|
+
const candidate = {
|
|
1136
|
+
anviaTraceValue: "truncated",
|
|
1137
|
+
originalBytes,
|
|
1138
|
+
preview: value.slice(0, middle)
|
|
1139
|
+
};
|
|
1140
|
+
if (utf8Bytes(JSON.stringify(candidate)) <= maxBytes) {
|
|
1141
|
+
low = middle;
|
|
1142
|
+
} else {
|
|
1143
|
+
high = middle - 1;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return value.slice(0, low);
|
|
1147
|
+
}
|
|
1148
|
+
function utf8Bytes(value) {
|
|
1149
|
+
return typeof Buffer === "undefined" ? new TextEncoder().encode(value).byteLength : Buffer.byteLength(value, "utf8");
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// src/tracing.ts
|
|
985
1153
|
var langfuse = {
|
|
986
1154
|
create(options = {}) {
|
|
987
1155
|
return new LangfuseAgentObserver(options);
|
|
@@ -1001,6 +1169,8 @@ var LangfuseAgentObserver = class {
|
|
|
1001
1169
|
redactor;
|
|
1002
1170
|
redactInputs;
|
|
1003
1171
|
redactOutputs;
|
|
1172
|
+
captureMode;
|
|
1173
|
+
captureMaxBytes;
|
|
1004
1174
|
constructor(options) {
|
|
1005
1175
|
const resolvedConfig = resolveLangfuseConfig(options);
|
|
1006
1176
|
this[langfuseResolvedConfigSymbol] = resolvedConfig;
|
|
@@ -1041,23 +1211,31 @@ var LangfuseAgentObserver = class {
|
|
|
1041
1211
|
}) : null;
|
|
1042
1212
|
this.redactInputs = options.redactInputs;
|
|
1043
1213
|
this.redactOutputs = options.redactOutputs;
|
|
1214
|
+
this.captureMode = options.captureMode ?? "safe";
|
|
1215
|
+
this.captureMaxBytes = validateCaptureMaxBytes(options.captureMaxBytes);
|
|
1044
1216
|
this.redactor = options.redactInputs !== void 0 || options.redactOutputs !== void 0 ? createPiiRedactor(options.redaction) : void 0;
|
|
1045
1217
|
}
|
|
1046
1218
|
async startRun(args) {
|
|
1047
1219
|
const traceId = args.trace?.traceId;
|
|
1048
|
-
const
|
|
1220
|
+
const capturedInput = this.captureInput({
|
|
1221
|
+
instructions: args.instructions,
|
|
1049
1222
|
prompt: args.prompt,
|
|
1050
1223
|
history: args.history
|
|
1051
1224
|
});
|
|
1225
|
+
const capturedTraceMetadata = this.captureInput(args.trace?.metadata ?? {});
|
|
1052
1226
|
const metadata = {
|
|
1053
1227
|
agentName: args.agentName,
|
|
1054
1228
|
agentDescription: args.agentDescription,
|
|
1055
1229
|
maxTurns: args.maxTurns
|
|
1056
1230
|
};
|
|
1057
1231
|
if (this.serviceName !== void 0) metadata.serviceName = this.serviceName;
|
|
1058
|
-
|
|
1232
|
+
if (isRecord(capturedTraceMetadata)) {
|
|
1233
|
+
Object.assign(metadata, capturedTraceMetadata);
|
|
1234
|
+
} else {
|
|
1235
|
+
metadata.traceMetadata = capturedTraceMetadata;
|
|
1236
|
+
}
|
|
1059
1237
|
const rootAttributes = {
|
|
1060
|
-
input:
|
|
1238
|
+
input: capturedInput,
|
|
1061
1239
|
metadata
|
|
1062
1240
|
};
|
|
1063
1241
|
if (args.trace?.version !== void 0) {
|
|
@@ -1075,7 +1253,7 @@ var LangfuseAgentObserver = class {
|
|
|
1075
1253
|
}
|
|
1076
1254
|
}
|
|
1077
1255
|
);
|
|
1078
|
-
applyTraceAttributes(root, args);
|
|
1256
|
+
applyTraceAttributes(root, args, capturedTraceMetadata);
|
|
1079
1257
|
const promptRef = resolvePromptRef(args);
|
|
1080
1258
|
const runObserver = new LangfuseRunObserver(
|
|
1081
1259
|
root,
|
|
@@ -1087,7 +1265,9 @@ var LangfuseAgentObserver = class {
|
|
|
1087
1265
|
{
|
|
1088
1266
|
redactor: this.redactor,
|
|
1089
1267
|
redactInputs: this.redactInputs,
|
|
1090
|
-
redactOutputs: this.redactOutputs
|
|
1268
|
+
redactOutputs: this.redactOutputs,
|
|
1269
|
+
captureMode: this.captureMode,
|
|
1270
|
+
captureMaxBytes: this.captureMaxBytes
|
|
1091
1271
|
}
|
|
1092
1272
|
);
|
|
1093
1273
|
this.currentHandle = runObserver.getHandle();
|
|
@@ -1118,13 +1298,9 @@ var LangfuseAgentObserver = class {
|
|
|
1118
1298
|
getCurrentTrace() {
|
|
1119
1299
|
return this.currentHandle;
|
|
1120
1300
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
return
|
|
1124
|
-
}
|
|
1125
|
-
maybeRedactOutput(value) {
|
|
1126
|
-
if (this.redactor === void 0 || this.redactOutputs === void 0) return value;
|
|
1127
|
-
return applyRedaction(this.redactor, value, this.redactOutputs);
|
|
1301
|
+
captureInput(value) {
|
|
1302
|
+
const redacted = this.redactor === void 0 || this.redactInputs === void 0 ? value : applyRedaction(this.redactor, value, this.redactInputs);
|
|
1303
|
+
return sanitizeTraceValue(redacted, this.captureMaxBytes);
|
|
1128
1304
|
}
|
|
1129
1305
|
async score(args) {
|
|
1130
1306
|
if (args.traceId === void 0 || args.traceId.length === 0) {
|
|
@@ -1196,7 +1372,7 @@ function buildScoreBody2(score) {
|
|
|
1196
1372
|
}
|
|
1197
1373
|
return body;
|
|
1198
1374
|
}
|
|
1199
|
-
function applyTraceAttributes(root, args) {
|
|
1375
|
+
function applyTraceAttributes(root, args, capturedMetadata) {
|
|
1200
1376
|
const traceName = args.trace?.name ?? args.agentName;
|
|
1201
1377
|
if (traceName !== void 0) {
|
|
1202
1378
|
root.otelSpan.setAttribute(LangfuseOtelSpanAttributes.TRACE_NAME, traceName);
|
|
@@ -1210,7 +1386,9 @@ function applyTraceAttributes(root, args) {
|
|
|
1210
1386
|
if (args.trace?.tags !== void 0) {
|
|
1211
1387
|
root.otelSpan.setAttribute(LangfuseOtelSpanAttributes.TRACE_TAGS, args.trace.tags);
|
|
1212
1388
|
}
|
|
1213
|
-
for (const [key, value] of Object.entries(
|
|
1389
|
+
for (const [key, value] of Object.entries(
|
|
1390
|
+
isRecord(capturedMetadata) ? capturedMetadata : { value: capturedMetadata }
|
|
1391
|
+
)) {
|
|
1214
1392
|
const serialized = serializeMetadataValue(value);
|
|
1215
1393
|
if (serialized === void 0) {
|
|
1216
1394
|
continue;
|
|
@@ -1238,9 +1416,6 @@ function applyRedaction(redactor, value, mode) {
|
|
|
1238
1416
|
if (typeof value === "string") {
|
|
1239
1417
|
return redactor.redactString(value);
|
|
1240
1418
|
}
|
|
1241
|
-
if (Array.isArray(value)) {
|
|
1242
|
-
return redactor.redactMessages(value);
|
|
1243
|
-
}
|
|
1244
1419
|
if (value !== null && typeof value === "object") {
|
|
1245
1420
|
return redactor.redactObject(value);
|
|
1246
1421
|
}
|
|
@@ -1250,6 +1425,9 @@ function resolvePromptRef(args) {
|
|
|
1250
1425
|
if (args.promptRef !== void 0) {
|
|
1251
1426
|
return args.promptRef;
|
|
1252
1427
|
}
|
|
1428
|
+
if (args.trace?.promptRef !== void 0) {
|
|
1429
|
+
return args.trace.promptRef;
|
|
1430
|
+
}
|
|
1253
1431
|
const metadata = args.trace?.metadata;
|
|
1254
1432
|
if (metadata === void 0) {
|
|
1255
1433
|
return void 0;
|
|
@@ -1291,6 +1469,19 @@ function serializeMetadataValue(value) {
|
|
|
1291
1469
|
return "<failed to serialize>";
|
|
1292
1470
|
}
|
|
1293
1471
|
}
|
|
1472
|
+
function asMetadata(value) {
|
|
1473
|
+
return isRecord(value) ? value : { value };
|
|
1474
|
+
}
|
|
1475
|
+
function eventStartTime(value) {
|
|
1476
|
+
if (value instanceof Date) {
|
|
1477
|
+
return Number.isNaN(value.getTime()) ? void 0 : value;
|
|
1478
|
+
}
|
|
1479
|
+
if (typeof value !== "string") {
|
|
1480
|
+
return void 0;
|
|
1481
|
+
}
|
|
1482
|
+
const parsed = new Date(value);
|
|
1483
|
+
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
1484
|
+
}
|
|
1294
1485
|
var LangfuseRunObserver = class {
|
|
1295
1486
|
constructor(root, trace, promptRef, redaction) {
|
|
1296
1487
|
this.root = root;
|
|
@@ -1300,6 +1491,8 @@ var LangfuseRunObserver = class {
|
|
|
1300
1491
|
this.redactor = redaction.redactor;
|
|
1301
1492
|
this.redactInputs = redaction.redactInputs;
|
|
1302
1493
|
this.redactOutputs = redaction.redactOutputs;
|
|
1494
|
+
this.captureMode = redaction.captureMode;
|
|
1495
|
+
this.captureMaxBytes = redaction.captureMaxBytes;
|
|
1303
1496
|
}
|
|
1304
1497
|
root;
|
|
1305
1498
|
trace;
|
|
@@ -1313,24 +1506,41 @@ var LangfuseRunObserver = class {
|
|
|
1313
1506
|
redactor;
|
|
1314
1507
|
redactInputs;
|
|
1315
1508
|
redactOutputs;
|
|
1509
|
+
captureMode;
|
|
1510
|
+
captureMaxBytes;
|
|
1316
1511
|
redactInputValue(value) {
|
|
1317
|
-
|
|
1318
|
-
return
|
|
1512
|
+
const redacted = this.redactor === void 0 || this.redactInputs === void 0 ? value : applyRedaction(this.redactor, value, this.redactInputs);
|
|
1513
|
+
return sanitizeTraceValue(redacted, this.captureMaxBytes);
|
|
1319
1514
|
}
|
|
1320
1515
|
redactOutputValue(value) {
|
|
1321
|
-
|
|
1322
|
-
return
|
|
1516
|
+
const redacted = this.redactor === void 0 || this.redactOutputs === void 0 ? value : applyRedaction(this.redactor, value, this.redactOutputs);
|
|
1517
|
+
return sanitizeTraceValue(redacted, this.captureMaxBytes);
|
|
1323
1518
|
}
|
|
1324
1519
|
startGeneration(args) {
|
|
1325
1520
|
this.closeEarlierTurns(args.turn);
|
|
1326
1521
|
const turn = this.turnSpan(args.turn);
|
|
1327
|
-
const
|
|
1522
|
+
const safeInput = {
|
|
1523
|
+
instructions: args.request.instructions,
|
|
1524
|
+
messages: modelInputMessages(args.request.chatHistory)
|
|
1525
|
+
};
|
|
1526
|
+
if (this.captureMode === "full") {
|
|
1527
|
+
safeInput.documents = args.request.documents;
|
|
1528
|
+
safeInput.tools = args.request.tools;
|
|
1529
|
+
safeInput.providerTools = args.request.providerTools;
|
|
1530
|
+
safeInput.outputSchema = args.request.outputSchema;
|
|
1531
|
+
safeInput.additionalParams = args.request.additionalParams;
|
|
1532
|
+
}
|
|
1328
1533
|
const metadata = {
|
|
1329
1534
|
turn: args.turn,
|
|
1330
|
-
|
|
1331
|
-
|
|
1535
|
+
documentCount: args.request.documents.length,
|
|
1536
|
+
toolNames: args.request.tools.map((tool) => tool.name),
|
|
1537
|
+
providerToolNames: args.request.providerTools?.map((tool) => tool.name) ?? [],
|
|
1538
|
+
hasOutputSchema: args.request.outputSchema !== void 0,
|
|
1539
|
+
additionalParamKeys: isRecord(args.request.additionalParams) ? Object.keys(args.request.additionalParams) : []
|
|
1332
1540
|
};
|
|
1333
|
-
if (args.providerRequest !== void 0)
|
|
1541
|
+
if (this.captureMode === "full" && args.providerRequest !== void 0) {
|
|
1542
|
+
metadata.providerRequest = args.providerRequest;
|
|
1543
|
+
}
|
|
1334
1544
|
if (args.modelInfo !== void 0) {
|
|
1335
1545
|
const modelInfo = {
|
|
1336
1546
|
provider: args.modelInfo.provider,
|
|
@@ -1342,36 +1552,43 @@ var LangfuseRunObserver = class {
|
|
|
1342
1552
|
metadata.modelInfo = modelInfo;
|
|
1343
1553
|
}
|
|
1344
1554
|
Object.assign(metadata, promptMetadata(this.promptRef));
|
|
1345
|
-
const
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1555
|
+
const generationAttributes = {
|
|
1556
|
+
input: this.redactInputValue(safeInput),
|
|
1557
|
+
model: args.request.model ?? args.modelInfo?.defaultModel ?? "default",
|
|
1558
|
+
modelParameters: modelParameters(args.request),
|
|
1559
|
+
metadata: asMetadata(this.redactInputValue(metadata))
|
|
1560
|
+
};
|
|
1561
|
+
if (this.promptRef?.version !== void 0) {
|
|
1562
|
+
generationAttributes.prompt = {
|
|
1563
|
+
name: this.promptRef.name,
|
|
1564
|
+
version: this.promptRef.version,
|
|
1565
|
+
isFallback: false
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
const generation = turn.startObservation(`model.turn.${args.turn}`, generationAttributes, {
|
|
1569
|
+
asType: "generation"
|
|
1570
|
+
});
|
|
1571
|
+
return new LangfuseGenerationObserver(generation, this, /* @__PURE__ */ new Date());
|
|
1356
1572
|
}
|
|
1357
1573
|
startTool(args) {
|
|
1358
1574
|
const turn = this.turnSpan(args.turn);
|
|
1359
|
-
const redactedArgs = this.redactInputValue(args.args);
|
|
1360
1575
|
const metadata = {
|
|
1361
1576
|
turn: args.turn,
|
|
1362
1577
|
internalCallId: args.internalCallId,
|
|
1363
1578
|
toolCallId: args.toolCallId
|
|
1364
1579
|
};
|
|
1365
|
-
if (
|
|
1366
|
-
|
|
1580
|
+
if (this.captureMode === "full") {
|
|
1581
|
+
if (args.toolDefinition !== void 0) metadata.toolDefinition = args.toolDefinition;
|
|
1582
|
+
if (args.toolMetadata !== void 0) metadata.toolMetadata = args.toolMetadata;
|
|
1583
|
+
}
|
|
1367
1584
|
const tool = turn.startObservation(
|
|
1368
1585
|
`tool.${args.toolName}`,
|
|
1369
1586
|
{
|
|
1370
|
-
input: {
|
|
1371
|
-
args:
|
|
1587
|
+
input: this.redactInputValue({
|
|
1588
|
+
args: args.args,
|
|
1372
1589
|
toolCall: args.toolCall
|
|
1373
|
-
},
|
|
1374
|
-
metadata
|
|
1590
|
+
}),
|
|
1591
|
+
metadata: asMetadata(this.redactInputValue(metadata))
|
|
1375
1592
|
},
|
|
1376
1593
|
{ asType: "tool" }
|
|
1377
1594
|
);
|
|
@@ -1380,34 +1597,52 @@ var LangfuseRunObserver = class {
|
|
|
1380
1597
|
end(args) {
|
|
1381
1598
|
this.closeAllTurns();
|
|
1382
1599
|
const redactedOutput = this.redactOutputValue(args.output);
|
|
1600
|
+
const metadata = {
|
|
1601
|
+
usage: args.usage,
|
|
1602
|
+
messageCount: args.messages.length,
|
|
1603
|
+
sources: this.redactOutputValue(args.sources),
|
|
1604
|
+
providerToolCalls: this.redactOutputValue(args.providerToolCalls)
|
|
1605
|
+
};
|
|
1606
|
+
if (this.captureMode === "full") {
|
|
1607
|
+
metadata.messages = this.redactTranscript(args.messages);
|
|
1608
|
+
}
|
|
1383
1609
|
this.root.update({
|
|
1384
1610
|
output: redactedOutput,
|
|
1385
|
-
metadata
|
|
1386
|
-
usage: args.usage,
|
|
1387
|
-
messages: args.messages
|
|
1388
|
-
}
|
|
1611
|
+
metadata
|
|
1389
1612
|
}).end();
|
|
1390
1613
|
this.clearCurrentHandle?.();
|
|
1391
1614
|
}
|
|
1392
1615
|
error(args) {
|
|
1393
1616
|
this.closeAllTurns();
|
|
1617
|
+
const redactedError = this.redactOutputValue(errorMessage(args.error));
|
|
1618
|
+
const metadata = {
|
|
1619
|
+
usage: args.usage,
|
|
1620
|
+
messageCount: args.messages.length
|
|
1621
|
+
};
|
|
1622
|
+
if (this.captureMode === "full") {
|
|
1623
|
+
metadata.messages = this.redactTranscript(args.messages);
|
|
1624
|
+
}
|
|
1394
1625
|
this.root.update({
|
|
1395
1626
|
level: "ERROR",
|
|
1396
|
-
statusMessage:
|
|
1627
|
+
statusMessage: typeof redactedError === "string" ? redactedError : "Agent run failed",
|
|
1397
1628
|
output: {
|
|
1398
|
-
error:
|
|
1629
|
+
error: redactedError
|
|
1399
1630
|
},
|
|
1400
|
-
metadata
|
|
1401
|
-
usage: args.usage,
|
|
1402
|
-
messages: args.messages
|
|
1403
|
-
}
|
|
1631
|
+
metadata
|
|
1404
1632
|
}).end();
|
|
1405
1633
|
this.clearCurrentHandle?.();
|
|
1406
1634
|
}
|
|
1407
1635
|
event(args) {
|
|
1408
|
-
const metadata = {};
|
|
1409
|
-
|
|
1410
|
-
|
|
1636
|
+
const metadata = asMetadata(this.redactOutputValue(args.attributes ?? {}));
|
|
1637
|
+
const attributes = { metadata };
|
|
1638
|
+
if (args.level !== void 0) {
|
|
1639
|
+
attributes.level = args.level;
|
|
1640
|
+
}
|
|
1641
|
+
const startTime = eventStartTime(args.timestamp);
|
|
1642
|
+
this.root.startObservation(args.name, attributes, {
|
|
1643
|
+
asType: "event",
|
|
1644
|
+
...startTime === void 0 ? {} : { startTime }
|
|
1645
|
+
});
|
|
1411
1646
|
}
|
|
1412
1647
|
getHandle() {
|
|
1413
1648
|
return this.handle;
|
|
@@ -1417,13 +1652,15 @@ var LangfuseRunObserver = class {
|
|
|
1417
1652
|
traceId: this.trace.traceId ?? "",
|
|
1418
1653
|
observationId: this.trace.observationId ?? "",
|
|
1419
1654
|
addAttributes: (attributes) => {
|
|
1420
|
-
this.root.update({ metadata: attributes });
|
|
1655
|
+
this.root.update({ metadata: asMetadata(this.redactOutputValue(attributes)) });
|
|
1421
1656
|
this.setCurrentHandle?.(this.handle);
|
|
1422
1657
|
},
|
|
1423
1658
|
addEvent: (name, attributes) => {
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1659
|
+
this.root.startObservation(
|
|
1660
|
+
name,
|
|
1661
|
+
{ metadata: asMetadata(this.redactOutputValue(attributes ?? {})) },
|
|
1662
|
+
{ asType: "event" }
|
|
1663
|
+
);
|
|
1427
1664
|
this.setCurrentHandle?.(this.handle);
|
|
1428
1665
|
}
|
|
1429
1666
|
};
|
|
@@ -1457,17 +1694,27 @@ var LangfuseRunObserver = class {
|
|
|
1457
1694
|
}
|
|
1458
1695
|
this.turnSpans.clear();
|
|
1459
1696
|
}
|
|
1697
|
+
isFullCapture() {
|
|
1698
|
+
return this.captureMode === "full";
|
|
1699
|
+
}
|
|
1700
|
+
redactTranscript(messages) {
|
|
1701
|
+
const inputRedacted = this.redactor === void 0 || this.redactInputs === void 0 ? messages : applyRedaction(this.redactor, messages, this.redactInputs);
|
|
1702
|
+
const outputRedacted = this.redactor === void 0 || this.redactOutputs === void 0 ? inputRedacted : applyRedaction(this.redactor, inputRedacted, this.redactOutputs);
|
|
1703
|
+
return sanitizeTraceValue(outputRedacted, this.captureMaxBytes);
|
|
1704
|
+
}
|
|
1460
1705
|
};
|
|
1461
1706
|
var LangfuseGenerationObserver = class {
|
|
1462
|
-
constructor(generation, run) {
|
|
1707
|
+
constructor(generation, run, startedAt) {
|
|
1463
1708
|
this.generation = generation;
|
|
1464
1709
|
this.run = run;
|
|
1710
|
+
this.startedAt = startedAt;
|
|
1465
1711
|
}
|
|
1466
1712
|
generation;
|
|
1467
1713
|
run;
|
|
1714
|
+
startedAt;
|
|
1468
1715
|
update(args) {
|
|
1469
1716
|
this.generation.update({
|
|
1470
|
-
output: { delta: args.delta }
|
|
1717
|
+
output: this.run.redactOutputValue({ delta: args.delta })
|
|
1471
1718
|
});
|
|
1472
1719
|
}
|
|
1473
1720
|
end(args) {
|
|
@@ -1475,21 +1722,30 @@ var LangfuseGenerationObserver = class {
|
|
|
1475
1722
|
const redactedChoice = this.run.redactOutputValue(args.response.choice);
|
|
1476
1723
|
const metadata = { turn: args.turn };
|
|
1477
1724
|
if (args.firstDeltaMs !== void 0) metadata.firstDeltaMs = args.firstDeltaMs;
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1725
|
+
const output = {
|
|
1726
|
+
messageId: args.response.messageId,
|
|
1727
|
+
content: redactedChoice,
|
|
1728
|
+
text: redactedText,
|
|
1729
|
+
sources: this.run.redactOutputValue(args.response.sources),
|
|
1730
|
+
providerToolCalls: this.run.redactOutputValue(args.response.providerToolCalls)
|
|
1731
|
+
};
|
|
1732
|
+
const completionStartTime = args.firstDeltaMs === void 0 ? void 0 : new Date(this.startedAt.getTime() + args.firstDeltaMs);
|
|
1733
|
+
const update = {
|
|
1734
|
+
output,
|
|
1484
1735
|
usageDetails: usageDetails(args.response.usage),
|
|
1485
1736
|
metadata
|
|
1486
|
-
}
|
|
1737
|
+
};
|
|
1738
|
+
if (completionStartTime !== void 0) {
|
|
1739
|
+
update.completionStartTime = completionStartTime;
|
|
1740
|
+
}
|
|
1741
|
+
this.generation.update(update).end();
|
|
1487
1742
|
}
|
|
1488
1743
|
error(args) {
|
|
1744
|
+
const redactedError = this.run.redactOutputValue(errorMessage(args.error));
|
|
1489
1745
|
this.generation.update({
|
|
1490
1746
|
level: "ERROR",
|
|
1491
|
-
statusMessage:
|
|
1492
|
-
output: { error:
|
|
1747
|
+
statusMessage: typeof redactedError === "string" ? redactedError : "Generation failed",
|
|
1748
|
+
output: { error: redactedError },
|
|
1493
1749
|
metadata: { turn: args.turn }
|
|
1494
1750
|
}).end();
|
|
1495
1751
|
}
|
|
@@ -1515,36 +1771,129 @@ var LangfuseToolObserver = class {
|
|
|
1515
1771
|
const childTurn = typeof child.turn === "number" ? child.turn : args.turn;
|
|
1516
1772
|
const agent = this.childAgent(agentId, agentName, args);
|
|
1517
1773
|
if (child.type === "turn_start") {
|
|
1774
|
+
const promptMessage = isRecord(child.prompt) ? child.prompt : void 0;
|
|
1775
|
+
const historyMessages = Array.isArray(child.history) ? child.history.filter(isRecord) : [];
|
|
1776
|
+
agent.startObservation(
|
|
1777
|
+
`${agentLabel(agentId, agentName)}.turn.${childTurn}.start`,
|
|
1778
|
+
{
|
|
1779
|
+
input: this.run.redactInputValue({
|
|
1780
|
+
prompt: promptMessage === void 0 ? void 0 : modelInputMessage(promptMessage),
|
|
1781
|
+
history: modelInputMessages(historyMessages)
|
|
1782
|
+
}),
|
|
1783
|
+
metadata: asMetadata(
|
|
1784
|
+
this.run.redactInputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1785
|
+
)
|
|
1786
|
+
},
|
|
1787
|
+
{ asType: "event" }
|
|
1788
|
+
);
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
if (child.type === "generation_start" && isRecord(child.request)) {
|
|
1792
|
+
const request = child.request;
|
|
1793
|
+
const modelInfo = isRecord(child.modelInfo) ? child.modelInfo : void 0;
|
|
1794
|
+
const messages = Array.isArray(request.chatHistory) ? modelInputMessages(request.chatHistory.filter(isRecord)) : [];
|
|
1795
|
+
const input = {
|
|
1796
|
+
instructions: typeof request.instructions === "string" ? request.instructions : void 0,
|
|
1797
|
+
messages
|
|
1798
|
+
};
|
|
1799
|
+
if (this.run.isFullCapture()) {
|
|
1800
|
+
input.documents = request.documents;
|
|
1801
|
+
input.tools = request.tools;
|
|
1802
|
+
input.providerTools = request.providerTools;
|
|
1803
|
+
input.outputSchema = request.outputSchema;
|
|
1804
|
+
input.additionalParams = request.additionalParams;
|
|
1805
|
+
}
|
|
1806
|
+
const toolNames = Array.isArray(request.tools) ? request.tools.filter(isRecord).map((tool) => tool.name).filter((name) => typeof name === "string") : [];
|
|
1807
|
+
const providerToolNames = Array.isArray(request.providerTools) ? request.providerTools.filter(isRecord).map((tool) => tool.name).filter((name) => typeof name === "string") : [];
|
|
1518
1808
|
const generation = agent.startObservation(
|
|
1519
1809
|
`${agentLabel(agentId, agentName)}.model.turn.${childTurn}`,
|
|
1520
1810
|
{
|
|
1521
|
-
input:
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1811
|
+
input: this.run.redactInputValue(input),
|
|
1812
|
+
model: typeof request.model === "string" ? request.model : typeof modelInfo?.defaultModel === "string" ? modelInfo.defaultModel : "default",
|
|
1813
|
+
modelParameters: modelParameters(request),
|
|
1814
|
+
metadata: asMetadata(
|
|
1815
|
+
this.run.redactInputValue({
|
|
1816
|
+
...childMetadata(args, agentId, agentName, childTurn),
|
|
1817
|
+
documentCount: Array.isArray(request.documents) ? request.documents.length : 0,
|
|
1818
|
+
toolNames,
|
|
1819
|
+
providerToolNames,
|
|
1820
|
+
hasOutputSchema: request.outputSchema !== void 0,
|
|
1821
|
+
modelInfo
|
|
1822
|
+
})
|
|
1823
|
+
)
|
|
1526
1824
|
},
|
|
1527
1825
|
{ asType: "generation" }
|
|
1528
1826
|
);
|
|
1529
|
-
this.childGenerations.set(generationKey(agentId, childTurn),
|
|
1827
|
+
this.childGenerations.set(generationKey(agentId, childTurn), {
|
|
1828
|
+
generation,
|
|
1829
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
1830
|
+
});
|
|
1530
1831
|
return;
|
|
1531
1832
|
}
|
|
1532
1833
|
if (child.type === "turn_end") {
|
|
1533
|
-
const
|
|
1534
|
-
if (
|
|
1834
|
+
const childGeneration = this.childGenerations.get(generationKey(agentId, childTurn));
|
|
1835
|
+
if (childGeneration !== void 0) {
|
|
1535
1836
|
const update = {
|
|
1536
|
-
output: child.response,
|
|
1537
|
-
metadata:
|
|
1837
|
+
output: this.run.redactOutputValue(child.response),
|
|
1838
|
+
metadata: asMetadata(
|
|
1839
|
+
this.run.redactOutputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1840
|
+
)
|
|
1538
1841
|
};
|
|
1539
1842
|
if (isRecord(child.response) && isRecord(child.response.usage)) {
|
|
1540
1843
|
update.usageDetails = usageDetailsFromRecord(child.response.usage);
|
|
1541
1844
|
}
|
|
1542
|
-
|
|
1845
|
+
if (typeof child.firstDeltaMs === "number") {
|
|
1846
|
+
update.completionStartTime = new Date(
|
|
1847
|
+
childGeneration.startedAt.getTime() + child.firstDeltaMs
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
childGeneration.generation.update(update).end();
|
|
1543
1851
|
this.childGenerations.delete(generationKey(agentId, childTurn));
|
|
1544
1852
|
}
|
|
1545
1853
|
return;
|
|
1546
1854
|
}
|
|
1855
|
+
if (child.type === "text_delta" || child.type === "reasoning_delta" || child.type === "tool_call_delta") {
|
|
1856
|
+
const childGeneration = this.childGenerations.get(generationKey(agentId, childTurn));
|
|
1857
|
+
childGeneration?.generation.update({
|
|
1858
|
+
output: this.run.redactOutputValue({ delta: child })
|
|
1859
|
+
});
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
if (child.type === "source" || child.type === "provider_tool_call") {
|
|
1863
|
+
const childGeneration = this.childGenerations.get(generationKey(agentId, childTurn));
|
|
1864
|
+
const parent = childGeneration?.generation ?? agent;
|
|
1865
|
+
parent.startObservation(
|
|
1866
|
+
`${agentLabel(agentId, agentName)}.${child.type}`,
|
|
1867
|
+
{
|
|
1868
|
+
output: this.run.redactOutputValue(
|
|
1869
|
+
child.type === "source" ? child.source : child.toolCall
|
|
1870
|
+
),
|
|
1871
|
+
metadata: asMetadata(
|
|
1872
|
+
this.run.redactOutputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1873
|
+
)
|
|
1874
|
+
},
|
|
1875
|
+
{ asType: "event" }
|
|
1876
|
+
);
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
if (child.type === "guardrail_decision") {
|
|
1880
|
+
agent.startObservation(
|
|
1881
|
+
`${agentLabel(agentId, agentName)}.guardrail`,
|
|
1882
|
+
{
|
|
1883
|
+
output: this.run.redactOutputValue(child.decision),
|
|
1884
|
+
metadata: asMetadata(
|
|
1885
|
+
this.run.redactOutputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1886
|
+
)
|
|
1887
|
+
},
|
|
1888
|
+
{ asType: "guardrail" }
|
|
1889
|
+
).end();
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1547
1892
|
if (child.type === "tool_call" && isRecord(child.toolCall)) {
|
|
1893
|
+
const childGeneration = this.childGenerations.get(generationKey(agentId, childTurn));
|
|
1894
|
+
childGeneration?.generation.update({
|
|
1895
|
+
output: this.run.redactOutputValue({ toolCall: child.toolCall })
|
|
1896
|
+
});
|
|
1548
1897
|
const toolCall = child.toolCall;
|
|
1549
1898
|
const toolCallFunction = isRecord(toolCall.function) ? toolCall.function : void 0;
|
|
1550
1899
|
const toolName = typeof toolCallFunction?.name === "string" ? toolCallFunction.name : "tool";
|
|
@@ -1552,15 +1901,17 @@ var LangfuseToolObserver = class {
|
|
|
1552
1901
|
const childTool = agent.startObservation(
|
|
1553
1902
|
`${agentLabel(agentId, agentName)}.${toolName}`,
|
|
1554
1903
|
{
|
|
1555
|
-
input: {
|
|
1904
|
+
input: this.run.redactInputValue({
|
|
1556
1905
|
args: toolCallFunction?.arguments ?? {},
|
|
1557
1906
|
toolCall
|
|
1558
|
-
},
|
|
1559
|
-
metadata:
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1907
|
+
}),
|
|
1908
|
+
metadata: asMetadata(
|
|
1909
|
+
this.run.redactInputValue({
|
|
1910
|
+
...childMetadata(args, agentId, agentName, childTurn),
|
|
1911
|
+
toolName,
|
|
1912
|
+
toolCallId
|
|
1913
|
+
})
|
|
1914
|
+
)
|
|
1564
1915
|
},
|
|
1565
1916
|
{ asType: "tool" }
|
|
1566
1917
|
);
|
|
@@ -1581,30 +1932,49 @@ var LangfuseToolObserver = class {
|
|
|
1581
1932
|
if (childTool !== void 0) {
|
|
1582
1933
|
childTool.ended = true;
|
|
1583
1934
|
childTool.tool.update({
|
|
1584
|
-
output:
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1935
|
+
output: this.run.redactOutputValue(
|
|
1936
|
+
typeof child.result === "string" ? child.result : child
|
|
1937
|
+
),
|
|
1938
|
+
metadata: asMetadata(
|
|
1939
|
+
this.run.redactInputValue({
|
|
1940
|
+
...childMetadata(args, agentId, agentName, childTurn),
|
|
1941
|
+
toolName,
|
|
1942
|
+
toolCallId,
|
|
1943
|
+
internalCallId: typeof child.internalCallId === "string" ? child.internalCallId : void 0,
|
|
1944
|
+
args: typeof child.args === "string" ? child.args : void 0
|
|
1945
|
+
})
|
|
1946
|
+
)
|
|
1592
1947
|
}).end();
|
|
1593
1948
|
}
|
|
1594
1949
|
return;
|
|
1595
1950
|
}
|
|
1596
1951
|
if (child.type === "final") {
|
|
1597
|
-
const update = {
|
|
1598
|
-
|
|
1952
|
+
const update = {
|
|
1953
|
+
output: this.run.redactOutputValue(child.output)
|
|
1954
|
+
};
|
|
1955
|
+
const metadata = {};
|
|
1956
|
+
if (isRecord(child.usage)) metadata.usage = child.usage;
|
|
1957
|
+
if (this.run.isFullCapture() && Array.isArray(child.messages)) {
|
|
1958
|
+
metadata.messages = this.run.redactTranscript(child.messages);
|
|
1959
|
+
}
|
|
1960
|
+
if (Object.keys(metadata).length > 0) update.metadata = metadata;
|
|
1599
1961
|
agent.update(update).end();
|
|
1600
1962
|
this.childAgents.delete(agentId);
|
|
1601
1963
|
return;
|
|
1602
1964
|
}
|
|
1603
1965
|
if (child.type === "error") {
|
|
1966
|
+
const redactedError = this.run.redactOutputValue(errorMessage(child.error));
|
|
1967
|
+
const childGeneration = this.childGenerations.get(generationKey(agentId, childTurn));
|
|
1968
|
+
childGeneration?.generation.update({
|
|
1969
|
+
level: "ERROR",
|
|
1970
|
+
statusMessage: typeof redactedError === "string" ? redactedError : "Generation failed",
|
|
1971
|
+
output: { error: redactedError }
|
|
1972
|
+
}).end();
|
|
1973
|
+
this.childGenerations.delete(generationKey(agentId, childTurn));
|
|
1604
1974
|
const update = {
|
|
1605
1975
|
level: "ERROR",
|
|
1606
|
-
statusMessage:
|
|
1607
|
-
output: { error:
|
|
1976
|
+
statusMessage: typeof redactedError === "string" ? redactedError : "Child agent failed",
|
|
1977
|
+
output: { error: redactedError }
|
|
1608
1978
|
};
|
|
1609
1979
|
if (isRecord(child.usage)) update.metadata = { usage: child.usage };
|
|
1610
1980
|
agent.update(update).end();
|
|
@@ -1634,10 +2004,11 @@ var LangfuseToolObserver = class {
|
|
|
1634
2004
|
}
|
|
1635
2005
|
error(args) {
|
|
1636
2006
|
this.endOpenChildren();
|
|
2007
|
+
const redactedError = this.run.redactOutputValue(errorMessage(args.error));
|
|
1637
2008
|
this.tool.update({
|
|
1638
2009
|
level: "ERROR",
|
|
1639
|
-
statusMessage:
|
|
1640
|
-
output: { error:
|
|
2010
|
+
statusMessage: typeof redactedError === "string" ? redactedError : "Tool failed",
|
|
2011
|
+
output: { error: redactedError },
|
|
1641
2012
|
metadata: {
|
|
1642
2013
|
turn: args.turn,
|
|
1643
2014
|
internalCallId: args.internalCallId,
|
|
@@ -1653,7 +2024,9 @@ var LangfuseToolObserver = class {
|
|
|
1653
2024
|
const agent = this.tool.startObservation(
|
|
1654
2025
|
`${agentLabel(agentId, agentName)}.run`,
|
|
1655
2026
|
{
|
|
1656
|
-
metadata:
|
|
2027
|
+
metadata: asMetadata(
|
|
2028
|
+
this.run.redactInputValue(childMetadata(args, agentId, agentName, args.turn))
|
|
2029
|
+
)
|
|
1657
2030
|
},
|
|
1658
2031
|
{ asType: "agent" }
|
|
1659
2032
|
);
|
|
@@ -1674,7 +2047,7 @@ var LangfuseToolObserver = class {
|
|
|
1674
2047
|
}
|
|
1675
2048
|
endOpenChildren() {
|
|
1676
2049
|
for (const generation of this.childGenerations.values()) {
|
|
1677
|
-
generation.end();
|
|
2050
|
+
generation.generation.end();
|
|
1678
2051
|
}
|
|
1679
2052
|
this.childGenerations.clear();
|
|
1680
2053
|
for (const tool of this.childTools) {
|