@anvia/langfuse 1.0.0-rc.1 → 1.0.0-rc.2
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 +118 -448
- package/dist/index.d.ts +83 -46
- package/dist/index.js +755 -621
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,116 +1,155 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
// src/redaction.ts
|
|
2
|
+
var DEFAULT_REPLACEMENT = "[REDACTED]";
|
|
3
|
+
var MAX_DEPTH = 16;
|
|
4
|
+
function createPiiRedactor(options = {}) {
|
|
5
|
+
const patterns = options.patterns ?? DEFAULT_PATTERNS;
|
|
6
|
+
const replacement = options.replacement ?? DEFAULT_REPLACEMENT;
|
|
7
|
+
const compiled = patterns.map((p) => ({
|
|
8
|
+
name: p.name,
|
|
9
|
+
regex: cloneRegex(p.regex, "g")
|
|
10
|
+
}));
|
|
11
|
+
const patternNamesList = patterns.map((p) => p.name);
|
|
12
|
+
function redactString(input) {
|
|
13
|
+
if (typeof input !== "string") return input;
|
|
14
|
+
let out = input;
|
|
15
|
+
for (const { name, regex } of compiled) {
|
|
16
|
+
out = applyPattern(out, name, regex, replacement);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
15
19
|
}
|
|
16
|
-
|
|
20
|
+
function redactObject(input) {
|
|
21
|
+
return redactValue(input, 0, redactString);
|
|
22
|
+
}
|
|
23
|
+
function redactMessages(input) {
|
|
24
|
+
return input.map((message) => redactMessage(message, redactString));
|
|
25
|
+
}
|
|
26
|
+
function patternNames() {
|
|
27
|
+
return patternNamesList;
|
|
28
|
+
}
|
|
29
|
+
return { redactString, redactObject, redactMessages, patternNames };
|
|
17
30
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
var DEFAULT_PATTERNS = [
|
|
32
|
+
{ name: "email", regex: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g },
|
|
33
|
+
{ name: "creditCard", regex: /\b(?:\d[ -]?){13,19}\b/g },
|
|
34
|
+
{ name: "ipv4", regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g },
|
|
35
|
+
{
|
|
36
|
+
name: "phone",
|
|
37
|
+
regex: /(?<!\d)(?:\+\d{1,3}[\s.-]?)?(?:\(\d{2,4}\)[\s.-]?)?\d{3,4}[\s.-]?\d{3,4}(?:[\s.-]?\d{3,4})?(?!\d)/g
|
|
38
|
+
},
|
|
39
|
+
{ name: "jwt", regex: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g },
|
|
40
|
+
{
|
|
41
|
+
name: "apiKey",
|
|
42
|
+
regex: /\b(?:sk|pk|api|key|token)[-_][A-Za-z0-9]{16,}\b/gi
|
|
21
43
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
44
|
+
];
|
|
45
|
+
function applyPattern(input, name, regex, replacement) {
|
|
46
|
+
if (name === "creditCard") {
|
|
47
|
+
return redactCreditCards(input, replacement);
|
|
48
|
+
}
|
|
49
|
+
return input.replace(regex, replacement);
|
|
27
50
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
function redactCreditCards(input, replacement) {
|
|
52
|
+
let out = "";
|
|
53
|
+
let i = 0;
|
|
54
|
+
while (i < input.length) {
|
|
55
|
+
const ch = input.charAt(i);
|
|
56
|
+
if (/\d/.test(ch)) {
|
|
57
|
+
const { length, valid } = longestLuhnChunk(input.slice(i));
|
|
58
|
+
if (valid) {
|
|
59
|
+
out += replacement;
|
|
60
|
+
i += length;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
37
63
|
}
|
|
64
|
+
out += ch;
|
|
65
|
+
i += 1;
|
|
38
66
|
}
|
|
39
|
-
return
|
|
40
|
-
input: numberValue(usage.inputTokens) ?? 0,
|
|
41
|
-
output: numberValue(usage.outputTokens) ?? 0,
|
|
42
|
-
total: numberValue(usage.totalTokens) ?? (numberValue(usage.inputTokens) ?? 0) + (numberValue(usage.outputTokens) ?? 0)
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
function childMetadata(args, agentId, agentName, childTurn) {
|
|
46
|
-
return {
|
|
47
|
-
source: "agent_tool_event",
|
|
48
|
-
childAgentId: agentId,
|
|
49
|
-
childAgentName: agentName,
|
|
50
|
-
childTurn,
|
|
51
|
-
parentToolName: args.toolName,
|
|
52
|
-
parentInternalCallId: args.internalCallId,
|
|
53
|
-
parentToolCallId: args.toolCallId
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
function generationKey(agentId, turn) {
|
|
57
|
-
return `${agentId}:${turn}`;
|
|
67
|
+
return out;
|
|
58
68
|
}
|
|
59
|
-
function
|
|
60
|
-
|
|
69
|
+
function longestLuhnChunk(s) {
|
|
70
|
+
let length = 0;
|
|
71
|
+
let bestValid = 0;
|
|
72
|
+
while (length < s.length && length < 40) {
|
|
73
|
+
const ch = s.charAt(length);
|
|
74
|
+
if (!/\d/.test(ch) && ch !== "-") break;
|
|
75
|
+
length += 1;
|
|
76
|
+
const candidate = s.slice(0, length).replace(/\D/g, "");
|
|
77
|
+
if (candidate.length >= 13 && candidate.length <= 19) {
|
|
78
|
+
if (startsWithKnownPrefix(candidate) && passesLuhn(candidate)) {
|
|
79
|
+
bestValid = length;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { length: bestValid, valid: bestValid > 0 };
|
|
61
84
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
85
|
+
function startsWithKnownPrefix(digits) {
|
|
86
|
+
if (digits.startsWith("4")) return true;
|
|
87
|
+
const two = digits.slice(0, 2);
|
|
88
|
+
if (two === "51" || two === "52" || two === "53" || two === "54" || two === "55") return true;
|
|
89
|
+
const four = digits.slice(0, 4);
|
|
90
|
+
if (four === "2221" || four === "2720") return true;
|
|
91
|
+
const twoAgain = digits.slice(0, 2);
|
|
92
|
+
if (twoAgain === "34" || twoAgain === "37") return true;
|
|
93
|
+
if (four === "6011" || twoAgain === "65") return true;
|
|
94
|
+
return digits.startsWith("35");
|
|
64
95
|
}
|
|
65
|
-
function
|
|
66
|
-
|
|
96
|
+
function passesLuhn(digits) {
|
|
97
|
+
if (!/^\d+$/.test(digits)) return false;
|
|
98
|
+
let sum = 0;
|
|
99
|
+
let alt = false;
|
|
100
|
+
for (let i = digits.length - 1; i >= 0; i -= 1) {
|
|
101
|
+
const raw = digits.charCodeAt(i) - 48;
|
|
102
|
+
let value = raw;
|
|
103
|
+
if (alt) {
|
|
104
|
+
value *= 2;
|
|
105
|
+
if (value > 9) value -= 9;
|
|
106
|
+
}
|
|
107
|
+
sum += value;
|
|
108
|
+
alt = !alt;
|
|
109
|
+
}
|
|
110
|
+
return sum % 10 === 0;
|
|
67
111
|
}
|
|
68
|
-
function
|
|
69
|
-
return
|
|
112
|
+
function cloneRegex(source, flags) {
|
|
113
|
+
return new RegExp(source.source, flags + source.flags.replace(/g/g, ""));
|
|
70
114
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
115
|
+
function redactValue(value, depth, redactStringFn) {
|
|
116
|
+
if (depth > MAX_DEPTH) return value;
|
|
117
|
+
if (typeof value === "string") {
|
|
118
|
+
return isBase64DataUrl(value) ? value : redactStringFn(value);
|
|
119
|
+
}
|
|
120
|
+
if (Array.isArray(value))
|
|
121
|
+
return value.map((entry) => redactValue(entry, depth + 1, redactStringFn));
|
|
122
|
+
if (value !== null && typeof value === "object") {
|
|
123
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
const record = value;
|
|
127
|
+
const out = {};
|
|
128
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
129
|
+
if (key === "data" && typeof entry === "string" && (record.type === "base64" || record.type === "image" || record.type === "encrypted" || record.type === "redacted")) {
|
|
130
|
+
out[key] = entry;
|
|
131
|
+
} else {
|
|
132
|
+
out[key] = redactValue(entry, depth + 1, redactStringFn);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
return value;
|
|
73
138
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
79
|
-
function resolveLangfuseConfig(options = {}, fallback) {
|
|
139
|
+
function redactMessage(message, redactStringFn) {
|
|
140
|
+
if (message.role === "system") {
|
|
141
|
+
return { ...message, content: redactStringFn(message.content) };
|
|
142
|
+
}
|
|
80
143
|
return {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
fallback?.publicKey,
|
|
84
|
-
process.env.LANGFUSE_PUBLIC_KEY
|
|
85
|
-
),
|
|
86
|
-
secretKey: resolveStringOption(
|
|
87
|
-
options.secretKey,
|
|
88
|
-
fallback?.secretKey,
|
|
89
|
-
process.env.LANGFUSE_SECRET_KEY
|
|
90
|
-
),
|
|
91
|
-
baseUrl: resolveStringOption(options.baseUrl, fallback?.baseUrl, process.env.LANGFUSE_BASE_URL) ?? "https://cloud.langfuse.com",
|
|
92
|
-
environment: resolveStringOption(
|
|
93
|
-
options.environment,
|
|
94
|
-
fallback?.environment,
|
|
95
|
-
process.env.LANGFUSE_TRACING_ENVIRONMENT
|
|
96
|
-
),
|
|
97
|
-
release: resolveStringOption(options.release, fallback?.release, process.env.LANGFUSE_RELEASE),
|
|
98
|
-
serviceName: resolveStringOption(
|
|
99
|
-
options.serviceName,
|
|
100
|
-
fallback?.serviceName,
|
|
101
|
-
process.env.LANGFUSE_SERVICE_NAME
|
|
102
|
-
),
|
|
103
|
-
timeoutMs: options.timeoutMs ?? fallback?.timeoutMs ?? 3e4
|
|
144
|
+
...message,
|
|
145
|
+
content: redactMessageContent(message.content, redactStringFn)
|
|
104
146
|
};
|
|
105
147
|
}
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
return void 0;
|
|
109
|
-
}
|
|
110
|
-
return value[langfuseResolvedConfigSymbol];
|
|
148
|
+
function redactMessageContent(value, redactStringFn) {
|
|
149
|
+
return redactValue(value, 0, redactStringFn);
|
|
111
150
|
}
|
|
112
|
-
function
|
|
113
|
-
return
|
|
151
|
+
function isBase64DataUrl(value) {
|
|
152
|
+
return /^data:[^;,]+;base64,/i.test(value);
|
|
114
153
|
}
|
|
115
154
|
|
|
116
155
|
// src/scoring.ts
|
|
@@ -153,7 +192,7 @@ var ScoreQueue = class {
|
|
|
153
192
|
timeoutMs;
|
|
154
193
|
batchSize;
|
|
155
194
|
flushIntervalMs;
|
|
156
|
-
|
|
195
|
+
maxAttempts;
|
|
157
196
|
fetchImpl;
|
|
158
197
|
sleep;
|
|
159
198
|
setTimer;
|
|
@@ -165,7 +204,7 @@ var ScoreQueue = class {
|
|
|
165
204
|
this.timeoutMs = options.timeoutMs;
|
|
166
205
|
this.batchSize = options.batchSize;
|
|
167
206
|
this.flushIntervalMs = options.flushIntervalMs;
|
|
168
|
-
this.
|
|
207
|
+
this.maxAttempts = options.maxAttempts;
|
|
169
208
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
170
209
|
this.sleep = options.sleep ?? defaultSleep;
|
|
171
210
|
this.setTimer = options.setTimer ?? defaultSetTimer;
|
|
@@ -212,10 +251,7 @@ var ScoreQueue = class {
|
|
|
212
251
|
async shutdown() {
|
|
213
252
|
this.closed = true;
|
|
214
253
|
this.clearScheduledTimer();
|
|
215
|
-
|
|
216
|
-
await this.flush();
|
|
217
|
-
} catch {
|
|
218
|
-
}
|
|
254
|
+
await this.flush();
|
|
219
255
|
}
|
|
220
256
|
scheduleTimer() {
|
|
221
257
|
if (this.timer !== null) {
|
|
@@ -239,7 +275,7 @@ var ScoreQueue = class {
|
|
|
239
275
|
async sendBatch(scores) {
|
|
240
276
|
const body = scores.map((score) => buildScoreBody(score));
|
|
241
277
|
let lastError;
|
|
242
|
-
for (let attempt = 0; attempt < this.
|
|
278
|
+
for (let attempt = 0; attempt < this.maxAttempts; attempt += 1) {
|
|
243
279
|
try {
|
|
244
280
|
const response = await this.fetchImpl(`${this.baseUrl}/api/public/scores`, {
|
|
245
281
|
method: "POST",
|
|
@@ -268,12 +304,12 @@ var ScoreQueue = class {
|
|
|
268
304
|
}
|
|
269
305
|
lastError = error;
|
|
270
306
|
}
|
|
271
|
-
if (attempt < this.
|
|
307
|
+
if (attempt < this.maxAttempts - 1) {
|
|
272
308
|
await this.sleep(computeBackoff(attempt));
|
|
273
309
|
}
|
|
274
310
|
}
|
|
275
311
|
throw new RetryableLangfuseScoreError(
|
|
276
|
-
`Langfuse score batch failed after ${this.
|
|
312
|
+
`Langfuse score batch failed after ${this.maxAttempts} attempts`,
|
|
277
313
|
scores,
|
|
278
314
|
lastError
|
|
279
315
|
);
|
|
@@ -308,17 +344,251 @@ function buildScoreBody(score) {
|
|
|
308
344
|
name: score.name,
|
|
309
345
|
value: score.value
|
|
310
346
|
};
|
|
311
|
-
if (score.observationId !== void 0) body.observationId = score.observationId;
|
|
312
|
-
if (score.dataType !== void 0) body.dataType = score.dataType;
|
|
313
|
-
if (score.comment !== void 0) body.comment = score.comment;
|
|
314
|
-
if (score.metadata !== void 0) body.metadata = score.metadata;
|
|
315
|
-
const configId = score.configId ?? score.scoreConfigId;
|
|
316
|
-
if (configId !== void 0) body.configId = configId;
|
|
317
|
-
if (score.environment !== void 0) body.environment = score.environment;
|
|
318
|
-
if (score.timestamp !== void 0) {
|
|
319
|
-
body.timestamp = score.timestamp instanceof Date ? score.timestamp.toISOString() : score.timestamp;
|
|
347
|
+
if (score.observationId !== void 0) body.observationId = score.observationId;
|
|
348
|
+
if (score.dataType !== void 0) body.dataType = score.dataType;
|
|
349
|
+
if (score.comment !== void 0) body.comment = score.comment;
|
|
350
|
+
if (score.metadata !== void 0) body.metadata = score.metadata;
|
|
351
|
+
const configId = score.configId ?? score.scoreConfigId;
|
|
352
|
+
if (configId !== void 0) body.configId = configId;
|
|
353
|
+
if (score.environment !== void 0) body.environment = score.environment;
|
|
354
|
+
if (score.timestamp !== void 0) {
|
|
355
|
+
body.timestamp = score.timestamp instanceof Date ? score.timestamp.toISOString() : score.timestamp;
|
|
356
|
+
}
|
|
357
|
+
return body;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/tracing.ts
|
|
361
|
+
import { LangfuseSpanProcessor } from "@langfuse/otel";
|
|
362
|
+
import {
|
|
363
|
+
LangfuseAgent,
|
|
364
|
+
LangfuseEvent,
|
|
365
|
+
LangfuseGeneration,
|
|
366
|
+
LangfuseGuardrail,
|
|
367
|
+
LangfuseOtelSpanAttributes,
|
|
368
|
+
LangfuseSpan,
|
|
369
|
+
LangfuseTool
|
|
370
|
+
} from "@langfuse/tracing";
|
|
371
|
+
import {
|
|
372
|
+
ROOT_CONTEXT,
|
|
373
|
+
TraceFlags,
|
|
374
|
+
trace
|
|
375
|
+
} from "@opentelemetry/api";
|
|
376
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
377
|
+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
378
|
+
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
379
|
+
|
|
380
|
+
// src/capture.ts
|
|
381
|
+
var DEFAULT_CAPTURE_MAX_BYTES = 262144;
|
|
382
|
+
var MIN_CAPTURE_MAX_BYTES = 96;
|
|
383
|
+
function validateCaptureMaxBytes(value) {
|
|
384
|
+
const resolved = value ?? DEFAULT_CAPTURE_MAX_BYTES;
|
|
385
|
+
if (!Number.isInteger(resolved) || resolved < MIN_CAPTURE_MAX_BYTES) {
|
|
386
|
+
throw new TypeError(
|
|
387
|
+
`Langfuse captureMaxBytes must be an integer of at least ${MIN_CAPTURE_MAX_BYTES}`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
return resolved;
|
|
391
|
+
}
|
|
392
|
+
function sanitizeTraceValue(value, maxBytes) {
|
|
393
|
+
validateCaptureMaxBytes(maxBytes);
|
|
394
|
+
const sanitized = sanitizeValue(value, 0, /* @__PURE__ */ new WeakSet());
|
|
395
|
+
let serialized;
|
|
396
|
+
try {
|
|
397
|
+
serialized = JSON.stringify(sanitized) ?? String(sanitized);
|
|
398
|
+
} catch {
|
|
399
|
+
return omitted("unserializable");
|
|
400
|
+
}
|
|
401
|
+
const originalBytes = utf8Bytes(serialized);
|
|
402
|
+
if (originalBytes <= maxBytes) {
|
|
403
|
+
return sanitized;
|
|
404
|
+
}
|
|
405
|
+
const preview = boundedPreview(serialized, originalBytes, maxBytes);
|
|
406
|
+
return {
|
|
407
|
+
anviaTraceValue: "truncated",
|
|
408
|
+
originalBytes,
|
|
409
|
+
preview
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function sanitizeValue(value, depth, seen) {
|
|
413
|
+
if (depth > 16) {
|
|
414
|
+
return omitted("depth");
|
|
415
|
+
}
|
|
416
|
+
if (typeof value === "string") {
|
|
417
|
+
if (/^data:[^;,]+;base64,/i.test(value)) {
|
|
418
|
+
return omitted("base64", utf8Bytes(value));
|
|
419
|
+
}
|
|
420
|
+
return value;
|
|
421
|
+
}
|
|
422
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
423
|
+
const byteLength = value.byteLength;
|
|
424
|
+
return omitted("binary", byteLength);
|
|
425
|
+
}
|
|
426
|
+
if (value === null || typeof value !== "object") {
|
|
427
|
+
return value;
|
|
428
|
+
}
|
|
429
|
+
if (seen.has(value)) {
|
|
430
|
+
return omitted("circular");
|
|
431
|
+
}
|
|
432
|
+
seen.add(value);
|
|
433
|
+
if (Array.isArray(value)) {
|
|
434
|
+
const result2 = value.map((entry) => sanitizeValue(entry, depth + 1, seen));
|
|
435
|
+
seen.delete(value);
|
|
436
|
+
return result2;
|
|
437
|
+
}
|
|
438
|
+
const record = value;
|
|
439
|
+
const result = {};
|
|
440
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
441
|
+
if (key === "data" && typeof entry === "string" && (record.type === "base64" || record.type === "image" && typeof record.mediaType === "string")) {
|
|
442
|
+
result[key] = omitted("base64", utf8Bytes(entry));
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
result[key] = sanitizeValue(entry, depth + 1, seen);
|
|
446
|
+
}
|
|
447
|
+
seen.delete(value);
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
function omitted(reason, originalBytes) {
|
|
451
|
+
return {
|
|
452
|
+
anviaTraceValue: "omitted",
|
|
453
|
+
reason,
|
|
454
|
+
...originalBytes === void 0 ? {} : { originalBytes }
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function boundedPreview(value, originalBytes, maxBytes) {
|
|
458
|
+
let low = 0;
|
|
459
|
+
let high = value.length;
|
|
460
|
+
while (low < high) {
|
|
461
|
+
const middle = Math.ceil((low + high) / 2);
|
|
462
|
+
const candidate = {
|
|
463
|
+
anviaTraceValue: "truncated",
|
|
464
|
+
originalBytes,
|
|
465
|
+
preview: value.slice(0, middle)
|
|
466
|
+
};
|
|
467
|
+
if (utf8Bytes(JSON.stringify(candidate)) <= maxBytes) {
|
|
468
|
+
low = middle;
|
|
469
|
+
} else {
|
|
470
|
+
high = middle - 1;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return value.slice(0, low);
|
|
474
|
+
}
|
|
475
|
+
function utf8Bytes(value) {
|
|
476
|
+
return typeof Buffer === "undefined" ? new TextEncoder().encode(value).byteLength : Buffer.byteLength(value, "utf8");
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/helpers.ts
|
|
480
|
+
function modelInputMessage(message) {
|
|
481
|
+
const { metadata: _metadata, ...result } = message;
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
function modelInputMessages(messages) {
|
|
485
|
+
return messages.map(modelInputMessage);
|
|
486
|
+
}
|
|
487
|
+
function modelParameters(request) {
|
|
488
|
+
const params = {};
|
|
489
|
+
if (request.temperature !== void 0) params.temperature = request.temperature;
|
|
490
|
+
if (request.maxTokens !== void 0) params.maxTokens = request.maxTokens;
|
|
491
|
+
if (request.toolChoice !== void 0) {
|
|
492
|
+
params.toolChoice = typeof request.toolChoice === "string" ? request.toolChoice : request.toolChoice.name;
|
|
493
|
+
}
|
|
494
|
+
return params;
|
|
495
|
+
}
|
|
496
|
+
function usageDetails(usage) {
|
|
497
|
+
if (usage.details !== void 0 && Object.keys(usage.details).length > 0) {
|
|
498
|
+
return { ...usage.details };
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
input: usage.inputTokens,
|
|
502
|
+
output: usage.outputTokens,
|
|
503
|
+
total: usage.totalTokens
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
function usageDetailsFromRecord(usage) {
|
|
507
|
+
if (isRecord(usage.details)) {
|
|
508
|
+
const details = Object.fromEntries(
|
|
509
|
+
Object.entries(usage.details).filter(
|
|
510
|
+
(entry) => typeof entry[1] === "number" && Number.isFinite(entry[1]) && entry[1] >= 0
|
|
511
|
+
)
|
|
512
|
+
);
|
|
513
|
+
if (Object.keys(details).length > 0) {
|
|
514
|
+
return details;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
input: numberValue(usage.inputTokens) ?? 0,
|
|
519
|
+
output: numberValue(usage.outputTokens) ?? 0,
|
|
520
|
+
total: numberValue(usage.totalTokens) ?? (numberValue(usage.inputTokens) ?? 0) + (numberValue(usage.outputTokens) ?? 0)
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
function childMetadata(args, agentId, agentName, childTurn) {
|
|
524
|
+
return {
|
|
525
|
+
source: "agent_tool_event",
|
|
526
|
+
childAgentId: agentId,
|
|
527
|
+
childAgentName: agentName,
|
|
528
|
+
childTurn,
|
|
529
|
+
parentToolName: args.toolName,
|
|
530
|
+
parentInternalCallId: args.internalCallId,
|
|
531
|
+
parentToolCallId: args.toolCallId
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
function generationKey(agentId, turn) {
|
|
535
|
+
return `${agentId}:${turn}`;
|
|
536
|
+
}
|
|
537
|
+
function agentLabel(agentId, agentName) {
|
|
538
|
+
return (agentName ?? agentId).replaceAll(/\s+/g, "_");
|
|
539
|
+
}
|
|
540
|
+
function isRecord(value) {
|
|
541
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
542
|
+
}
|
|
543
|
+
function numberValue(value) {
|
|
544
|
+
return typeof value === "number" ? value : void 0;
|
|
545
|
+
}
|
|
546
|
+
function emptyToUndefined(value) {
|
|
547
|
+
return value === void 0 || value.length === 0 ? void 0 : value;
|
|
548
|
+
}
|
|
549
|
+
function errorMessage(error) {
|
|
550
|
+
return error instanceof Error ? error.message : String(error);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// src/config.ts
|
|
554
|
+
var langfuseResolvedConfigSymbol = /* @__PURE__ */ Symbol.for(
|
|
555
|
+
"@anvia/langfuse.resolvedConfig"
|
|
556
|
+
);
|
|
557
|
+
function resolveLangfuseConfig(options = {}, fallback) {
|
|
558
|
+
return {
|
|
559
|
+
publicKey: resolveStringOption(
|
|
560
|
+
options.publicKey,
|
|
561
|
+
fallback?.publicKey,
|
|
562
|
+
process.env.LANGFUSE_PUBLIC_KEY
|
|
563
|
+
),
|
|
564
|
+
secretKey: resolveStringOption(
|
|
565
|
+
options.secretKey,
|
|
566
|
+
fallback?.secretKey,
|
|
567
|
+
process.env.LANGFUSE_SECRET_KEY
|
|
568
|
+
),
|
|
569
|
+
baseUrl: resolveStringOption(options.baseUrl, fallback?.baseUrl, process.env.LANGFUSE_BASE_URL) ?? "https://cloud.langfuse.com",
|
|
570
|
+
environment: resolveStringOption(
|
|
571
|
+
options.environment,
|
|
572
|
+
fallback?.environment,
|
|
573
|
+
process.env.LANGFUSE_TRACING_ENVIRONMENT
|
|
574
|
+
),
|
|
575
|
+
release: resolveStringOption(options.release, fallback?.release, process.env.LANGFUSE_RELEASE),
|
|
576
|
+
serviceName: resolveStringOption(
|
|
577
|
+
options.serviceName,
|
|
578
|
+
fallback?.serviceName,
|
|
579
|
+
process.env.LANGFUSE_SERVICE_NAME
|
|
580
|
+
),
|
|
581
|
+
timeoutMs: options.timeoutMs ?? fallback?.timeoutMs ?? 3e4
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function getResolvedLangfuseConfig(value) {
|
|
585
|
+
if (typeof value !== "object" || value === null) {
|
|
586
|
+
return void 0;
|
|
320
587
|
}
|
|
321
|
-
return
|
|
588
|
+
return value[langfuseResolvedConfigSymbol];
|
|
589
|
+
}
|
|
590
|
+
function resolveStringOption(option, fallback, envVar) {
|
|
591
|
+
return emptyToUndefined(option) ?? emptyToUndefined(fallback) ?? emptyToUndefined(envVar);
|
|
322
592
|
}
|
|
323
593
|
|
|
324
594
|
// src/dataset-client.ts
|
|
@@ -377,7 +647,8 @@ function createLangfuseDatasetClient(tracing, options = {}) {
|
|
|
377
647
|
if (dataset.metadata !== void 0) result.metadata = dataset.metadata;
|
|
378
648
|
return result;
|
|
379
649
|
},
|
|
380
|
-
async getDataset(
|
|
650
|
+
async getDataset(options2) {
|
|
651
|
+
const { name } = options2;
|
|
381
652
|
const items = [];
|
|
382
653
|
let description;
|
|
383
654
|
let metadata;
|
|
@@ -417,7 +688,8 @@ function createLangfuseDatasetClient(tracing, options = {}) {
|
|
|
417
688
|
if (metadata !== void 0) dataset.metadata = metadata;
|
|
418
689
|
return dataset;
|
|
419
690
|
},
|
|
420
|
-
async upsertItems(
|
|
691
|
+
async upsertItems(options2) {
|
|
692
|
+
const { name, items } = options2;
|
|
421
693
|
const url = `${baseUrl}/api/public/datasets/${encodeURIComponent(name)}/items`;
|
|
422
694
|
await request(url, {
|
|
423
695
|
method: "POST",
|
|
@@ -427,7 +699,7 @@ function createLangfuseDatasetClient(tracing, options = {}) {
|
|
|
427
699
|
async runExperiment(opts) {
|
|
428
700
|
let items = opts.items;
|
|
429
701
|
if (items === void 0) {
|
|
430
|
-
const dataset = await this.getDataset(opts.datasetName);
|
|
702
|
+
const dataset = await this.getDataset({ name: opts.datasetName });
|
|
431
703
|
items = dataset.items;
|
|
432
704
|
}
|
|
433
705
|
if (items === void 0 || items.length === 0) {
|
|
@@ -508,7 +780,8 @@ import {
|
|
|
508
780
|
} from "@anvia/core/evals";
|
|
509
781
|
var DEFAULT_TRUNCATE_BYTES = 2048;
|
|
510
782
|
function createLangfuseEvalReporter(tracing, options = {}) {
|
|
511
|
-
const onMissingTrace = options.onMissingTrace ??
|
|
783
|
+
const onMissingTrace = options.onMissingTrace ?? "ignore";
|
|
784
|
+
const traceObserver = options.traceObserver ?? "langfuse";
|
|
512
785
|
const truncateAt = options.truncateInputAt ?? DEFAULT_TRUNCATE_BYTES;
|
|
513
786
|
const includeMessages = options.includeMessages ?? true;
|
|
514
787
|
const includeContext = options.includeContext ?? false;
|
|
@@ -517,18 +790,20 @@ function createLangfuseEvalReporter(tracing, options = {}) {
|
|
|
517
790
|
if (args.outcome.outcome === "invalid" && options.publishInvalid !== true) {
|
|
518
791
|
return;
|
|
519
792
|
}
|
|
520
|
-
const
|
|
793
|
+
const trace2 = args.trace ?? resolveEvalTraceRef({
|
|
521
794
|
output: args.output,
|
|
522
795
|
input: args.case.input,
|
|
523
796
|
metadata: args.case.metadata
|
|
524
797
|
});
|
|
525
|
-
if (
|
|
798
|
+
if (trace2?.traceId === void 0 || trace2.traceId.length === 0 || trace2.observer !== void 0 && trace2.observer !== traceObserver) {
|
|
526
799
|
if (onMissingTrace === "throw") {
|
|
527
|
-
throw new Error(
|
|
800
|
+
throw new Error(
|
|
801
|
+
`Langfuse eval reporter requires traceId from observer ${JSON.stringify(traceObserver)}`
|
|
802
|
+
);
|
|
528
803
|
}
|
|
529
804
|
if (onMissingTrace === "warn") {
|
|
530
805
|
console.warn(
|
|
531
|
-
"[anvia/langfuse] eval reporter dropped score because no
|
|
806
|
+
"[anvia/langfuse] eval reporter dropped score because no matching trace was found",
|
|
532
807
|
{ caseId: args.case.id, metric: args.metric.name }
|
|
533
808
|
);
|
|
534
809
|
}
|
|
@@ -547,11 +822,11 @@ function createLangfuseEvalReporter(tracing, options = {}) {
|
|
|
547
822
|
});
|
|
548
823
|
const configId = resolveConfigId(args.metric);
|
|
549
824
|
const score = {
|
|
550
|
-
traceId:
|
|
825
|
+
traceId: trace2.traceId,
|
|
551
826
|
name: args.metric.name,
|
|
552
827
|
value: projection.value
|
|
553
828
|
};
|
|
554
|
-
if (
|
|
829
|
+
if (trace2.observationId !== void 0) score.observationId = trace2.observationId;
|
|
555
830
|
if (args.metric.dataType !== void 0) score.dataType = args.metric.dataType;
|
|
556
831
|
if (configId !== void 0) score.configId = configId;
|
|
557
832
|
if (projection.explanation !== void 0) score.comment = projection.explanation;
|
|
@@ -649,18 +924,20 @@ function readMessages(output) {
|
|
|
649
924
|
|
|
650
925
|
// src/experiment-runner.ts
|
|
651
926
|
import { runEvalSuite } from "@anvia/core/evals";
|
|
652
|
-
async function
|
|
927
|
+
async function runLangfuseEvalExperiment(client, options) {
|
|
928
|
+
const evalOptions = options.suite;
|
|
929
|
+
const experimentOptions = options.experiment;
|
|
653
930
|
const clientOptions = {};
|
|
654
931
|
if (experimentOptions.pageSize !== void 0) clientOptions.pageSize = experimentOptions.pageSize;
|
|
655
932
|
if (experimentOptions.timeoutMs !== void 0)
|
|
656
933
|
clientOptions.timeoutMs = experimentOptions.timeoutMs;
|
|
657
|
-
const
|
|
934
|
+
const datasetClient = client.datasetClient(clientOptions);
|
|
658
935
|
const suiteOptions = experimentOptions.publishScores === true ? {
|
|
659
936
|
...evalOptions,
|
|
660
937
|
reporters: [
|
|
661
938
|
...evalOptions.reporters ?? [],
|
|
662
939
|
createLangfuseEvalReporter(
|
|
663
|
-
|
|
940
|
+
client,
|
|
664
941
|
experimentOptions.reporterOptions
|
|
665
942
|
)
|
|
666
943
|
]
|
|
@@ -705,30 +982,30 @@ async function runEvalAsExperiment(evalOptions, experimentOptions) {
|
|
|
705
982
|
};
|
|
706
983
|
}
|
|
707
984
|
const output = result.output ?? void 0;
|
|
708
|
-
const
|
|
709
|
-
return { output, trace };
|
|
985
|
+
const trace2 = readTraceFromOutput(result.output);
|
|
986
|
+
return { output, trace: trace2 };
|
|
710
987
|
}
|
|
711
988
|
};
|
|
712
989
|
if (experimentOptions.description !== void 0) {
|
|
713
990
|
runOptions.description = experimentOptions.description;
|
|
714
991
|
}
|
|
715
992
|
if (experimentOptions.metadata !== void 0) runOptions.metadata = experimentOptions.metadata;
|
|
716
|
-
const datasetRun = await
|
|
993
|
+
const datasetRun = await datasetClient.runExperiment(runOptions);
|
|
717
994
|
return { suite, datasetRun };
|
|
718
995
|
}
|
|
719
996
|
function readTraceFromOutput(output) {
|
|
720
997
|
if (typeof output !== "object" || output === null || !("trace" in output)) {
|
|
721
998
|
return void 0;
|
|
722
999
|
}
|
|
723
|
-
const
|
|
724
|
-
if (typeof
|
|
1000
|
+
const trace2 = output.trace;
|
|
1001
|
+
if (typeof trace2 !== "object" || trace2 === null) {
|
|
725
1002
|
return void 0;
|
|
726
1003
|
}
|
|
727
|
-
const traceId =
|
|
1004
|
+
const traceId = trace2.traceId;
|
|
728
1005
|
if (typeof traceId !== "string") {
|
|
729
1006
|
return void 0;
|
|
730
1007
|
}
|
|
731
|
-
const observationId =
|
|
1008
|
+
const observationId = trace2.observationId;
|
|
732
1009
|
if (typeof observationId === "string") {
|
|
733
1010
|
return { traceId, observationId };
|
|
734
1011
|
}
|
|
@@ -761,7 +1038,8 @@ function createLangfusePromptClient(tracing, options = {}) {
|
|
|
761
1038
|
}
|
|
762
1039
|
return await response.json();
|
|
763
1040
|
}
|
|
764
|
-
async function getPrompt(
|
|
1041
|
+
async function getPrompt(options2) {
|
|
1042
|
+
const { name, ...opts } = options2;
|
|
765
1043
|
const key = `${name}::${opts.version ?? ""}::${opts.label ?? ""}`;
|
|
766
1044
|
const ttl = opts.cacheTtlMs ?? defaultTtl;
|
|
767
1045
|
if (opts.refresh !== true) {
|
|
@@ -790,18 +1068,18 @@ function createLangfusePromptClient(tracing, options = {}) {
|
|
|
790
1068
|
cache.set(key, { prompt, expiresAt: Date.now() + ttl });
|
|
791
1069
|
return prompt;
|
|
792
1070
|
}
|
|
793
|
-
function getPromptText(
|
|
794
|
-
return getPrompt(
|
|
1071
|
+
function getPromptText(options2) {
|
|
1072
|
+
return getPrompt(options2).then((prompt) => {
|
|
795
1073
|
if (typeof prompt.prompt !== "string") {
|
|
796
|
-
throw new Error(`Prompt ${name} is a chat prompt; expected text`);
|
|
1074
|
+
throw new Error(`Prompt ${options2.name} is a chat prompt; expected text`);
|
|
797
1075
|
}
|
|
798
1076
|
return prompt.prompt;
|
|
799
1077
|
});
|
|
800
1078
|
}
|
|
801
|
-
function getPromptChat(
|
|
802
|
-
return getPrompt(
|
|
1079
|
+
function getPromptChat(options2) {
|
|
1080
|
+
return getPrompt(options2).then((prompt) => {
|
|
803
1081
|
if (typeof prompt.prompt === "string") {
|
|
804
|
-
throw new Error(`Prompt ${name} is a text prompt; expected chat`);
|
|
1082
|
+
throw new Error(`Prompt ${options2.name} is a text prompt; expected chat`);
|
|
805
1083
|
}
|
|
806
1084
|
return prompt.prompt;
|
|
807
1085
|
});
|
|
@@ -809,332 +1087,94 @@ function createLangfusePromptClient(tracing, options = {}) {
|
|
|
809
1087
|
function refresh() {
|
|
810
1088
|
cache.clear();
|
|
811
1089
|
}
|
|
812
|
-
return { getPrompt, getPromptText, getPromptChat, refresh };
|
|
813
|
-
}
|
|
814
|
-
function normalizePrompt(raw, type) {
|
|
815
|
-
if (type === "text") {
|
|
816
|
-
if (typeof raw === "string") return raw;
|
|
817
|
-
throw new Error("Expected text prompt to be a string");
|
|
818
|
-
}
|
|
819
|
-
if (!Array.isArray(raw)) {
|
|
820
|
-
throw new Error("Expected chat prompt to be an array of messages");
|
|
821
|
-
}
|
|
822
|
-
return raw.map((entry) => {
|
|
823
|
-
if (typeof entry !== "object" || entry === null) {
|
|
824
|
-
throw new Error("Expected chat message to be an object");
|
|
825
|
-
}
|
|
826
|
-
const role = entry.role;
|
|
827
|
-
const content = entry.content;
|
|
828
|
-
if (typeof content !== "string") {
|
|
829
|
-
throw new Error("Expected chat message content to be a string");
|
|
830
|
-
}
|
|
831
|
-
if (role !== "system" && role !== "user" && role !== "assistant" && role !== "tool") {
|
|
832
|
-
throw new Error(`Unexpected chat message role: ${String(role)}`);
|
|
833
|
-
}
|
|
834
|
-
return { role, content };
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
function buildAuthHeader2(publicKey, secretKey) {
|
|
838
|
-
if (publicKey === void 0 || secretKey === void 0) {
|
|
839
|
-
return {};
|
|
840
|
-
}
|
|
841
|
-
const encoded = Buffer.from(`${publicKey}:${secretKey}`).toString("base64");
|
|
842
|
-
return { Authorization: `Basic ${encoded}` };
|
|
843
|
-
}
|
|
844
|
-
async function readErrorBody2(response) {
|
|
845
|
-
try {
|
|
846
|
-
return await response.text();
|
|
847
|
-
} catch {
|
|
848
|
-
return "<unreadable>";
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
// src/redaction.ts
|
|
853
|
-
var DEFAULT_REPLACEMENT = "[REDACTED]";
|
|
854
|
-
var MAX_DEPTH = 16;
|
|
855
|
-
function createPiiRedactor(options = {}) {
|
|
856
|
-
const patterns = options.patterns ?? DEFAULT_PATTERNS;
|
|
857
|
-
const replacement = options.replacement ?? DEFAULT_REPLACEMENT;
|
|
858
|
-
const compiled = patterns.map((p) => ({
|
|
859
|
-
name: p.name,
|
|
860
|
-
regex: cloneRegex(p.regex, "g")
|
|
861
|
-
}));
|
|
862
|
-
const patternNamesList = patterns.map((p) => p.name);
|
|
863
|
-
function redactString(input) {
|
|
864
|
-
if (typeof input !== "string") return input;
|
|
865
|
-
let out = input;
|
|
866
|
-
for (const { name, regex } of compiled) {
|
|
867
|
-
out = applyPattern(out, name, regex, replacement);
|
|
868
|
-
}
|
|
869
|
-
return out;
|
|
870
|
-
}
|
|
871
|
-
function redactObject(input) {
|
|
872
|
-
return redactValue(input, 0, redactString);
|
|
873
|
-
}
|
|
874
|
-
function redactMessages(input) {
|
|
875
|
-
return input.map((message) => redactMessage(message, redactString));
|
|
876
|
-
}
|
|
877
|
-
function patternNames() {
|
|
878
|
-
return patternNamesList;
|
|
879
|
-
}
|
|
880
|
-
return { redactString, redactObject, redactMessages, patternNames };
|
|
881
|
-
}
|
|
882
|
-
var DEFAULT_PATTERNS = [
|
|
883
|
-
{ name: "email", regex: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g },
|
|
884
|
-
{ name: "creditCard", regex: /\b(?:\d[ -]?){13,19}\b/g },
|
|
885
|
-
{ name: "ipv4", regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g },
|
|
886
|
-
{
|
|
887
|
-
name: "phone",
|
|
888
|
-
regex: /(?<!\d)(?:\+\d{1,3}[\s.-]?)?(?:\(\d{2,4}\)[\s.-]?)?\d{3,4}[\s.-]?\d{3,4}(?:[\s.-]?\d{3,4})?(?!\d)/g
|
|
889
|
-
},
|
|
890
|
-
{ name: "jwt", regex: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g },
|
|
891
|
-
{
|
|
892
|
-
name: "apiKey",
|
|
893
|
-
regex: /\b(?:sk|pk|api|key|token)[-_][A-Za-z0-9]{16,}\b/gi
|
|
894
|
-
}
|
|
895
|
-
];
|
|
896
|
-
function applyPattern(input, name, regex, replacement) {
|
|
897
|
-
if (name === "creditCard") {
|
|
898
|
-
return redactCreditCards(input, replacement);
|
|
899
|
-
}
|
|
900
|
-
return input.replace(regex, replacement);
|
|
901
|
-
}
|
|
902
|
-
function redactCreditCards(input, replacement) {
|
|
903
|
-
let out = "";
|
|
904
|
-
let i = 0;
|
|
905
|
-
while (i < input.length) {
|
|
906
|
-
const ch = input.charAt(i);
|
|
907
|
-
if (/\d/.test(ch)) {
|
|
908
|
-
const { length, valid } = longestLuhnChunk(input.slice(i));
|
|
909
|
-
if (valid) {
|
|
910
|
-
out += replacement;
|
|
911
|
-
i += length;
|
|
912
|
-
continue;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
out += ch;
|
|
916
|
-
i += 1;
|
|
917
|
-
}
|
|
918
|
-
return out;
|
|
919
|
-
}
|
|
920
|
-
function longestLuhnChunk(s) {
|
|
921
|
-
let length = 0;
|
|
922
|
-
let bestValid = 0;
|
|
923
|
-
while (length < s.length && length < 40) {
|
|
924
|
-
const ch = s.charAt(length);
|
|
925
|
-
if (!/\d/.test(ch) && ch !== "-") break;
|
|
926
|
-
length += 1;
|
|
927
|
-
const candidate = s.slice(0, length).replace(/\D/g, "");
|
|
928
|
-
if (candidate.length >= 13 && candidate.length <= 19) {
|
|
929
|
-
if (startsWithKnownPrefix(candidate) && passesLuhn(candidate)) {
|
|
930
|
-
bestValid = length;
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
return { length: bestValid, valid: bestValid > 0 };
|
|
935
|
-
}
|
|
936
|
-
function startsWithKnownPrefix(digits) {
|
|
937
|
-
if (digits.startsWith("4")) return true;
|
|
938
|
-
const two = digits.slice(0, 2);
|
|
939
|
-
if (two === "51" || two === "52" || two === "53" || two === "54" || two === "55") return true;
|
|
940
|
-
const four = digits.slice(0, 4);
|
|
941
|
-
if (four === "2221" || four === "2720") return true;
|
|
942
|
-
const twoAgain = digits.slice(0, 2);
|
|
943
|
-
if (twoAgain === "34" || twoAgain === "37") return true;
|
|
944
|
-
if (four === "6011" || twoAgain === "65") return true;
|
|
945
|
-
return digits.startsWith("35");
|
|
946
|
-
}
|
|
947
|
-
function passesLuhn(digits) {
|
|
948
|
-
if (!/^\d+$/.test(digits)) return false;
|
|
949
|
-
let sum = 0;
|
|
950
|
-
let alt = false;
|
|
951
|
-
for (let i = digits.length - 1; i >= 0; i -= 1) {
|
|
952
|
-
const raw = digits.charCodeAt(i) - 48;
|
|
953
|
-
let value = raw;
|
|
954
|
-
if (alt) {
|
|
955
|
-
value *= 2;
|
|
956
|
-
if (value > 9) value -= 9;
|
|
957
|
-
}
|
|
958
|
-
sum += value;
|
|
959
|
-
alt = !alt;
|
|
960
|
-
}
|
|
961
|
-
return sum % 10 === 0;
|
|
962
|
-
}
|
|
963
|
-
function cloneRegex(source, flags) {
|
|
964
|
-
return new RegExp(source.source, flags + source.flags.replace(/g/g, ""));
|
|
965
|
-
}
|
|
966
|
-
function redactValue(value, depth, redactStringFn) {
|
|
967
|
-
if (depth > MAX_DEPTH) return value;
|
|
968
|
-
if (typeof value === "string") {
|
|
969
|
-
return isBase64DataUrl(value) ? value : redactStringFn(value);
|
|
970
|
-
}
|
|
971
|
-
if (Array.isArray(value))
|
|
972
|
-
return value.map((entry) => redactValue(entry, depth + 1, redactStringFn));
|
|
973
|
-
if (value !== null && typeof value === "object") {
|
|
974
|
-
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
975
|
-
return value;
|
|
976
|
-
}
|
|
977
|
-
const record = value;
|
|
978
|
-
const out = {};
|
|
979
|
-
for (const [key, entry] of Object.entries(record)) {
|
|
980
|
-
if (key === "data" && typeof entry === "string" && (record.type === "base64" || record.type === "image" || record.type === "encrypted" || record.type === "redacted")) {
|
|
981
|
-
out[key] = entry;
|
|
982
|
-
} else {
|
|
983
|
-
out[key] = redactValue(entry, depth + 1, redactStringFn);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
return out;
|
|
987
|
-
}
|
|
988
|
-
return value;
|
|
1090
|
+
return { getPrompt, getPromptText, getPromptChat, refresh };
|
|
989
1091
|
}
|
|
990
|
-
function
|
|
991
|
-
if (
|
|
992
|
-
|
|
1092
|
+
function normalizePrompt(raw, type) {
|
|
1093
|
+
if (type === "text") {
|
|
1094
|
+
if (typeof raw === "string") return raw;
|
|
1095
|
+
throw new Error("Expected text prompt to be a string");
|
|
993
1096
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1097
|
+
if (!Array.isArray(raw)) {
|
|
1098
|
+
throw new Error("Expected chat prompt to be an array of messages");
|
|
1099
|
+
}
|
|
1100
|
+
return raw.map((entry) => {
|
|
1101
|
+
if (typeof entry !== "object" || entry === null) {
|
|
1102
|
+
throw new Error("Expected chat message to be an object");
|
|
1103
|
+
}
|
|
1104
|
+
const role = entry.role;
|
|
1105
|
+
const content = entry.content;
|
|
1106
|
+
if (typeof content !== "string") {
|
|
1107
|
+
throw new Error("Expected chat message content to be a string");
|
|
1108
|
+
}
|
|
1109
|
+
if (role !== "system" && role !== "user" && role !== "assistant" && role !== "tool") {
|
|
1110
|
+
throw new Error(`Unexpected chat message role: ${String(role)}`);
|
|
1111
|
+
}
|
|
1112
|
+
return { role, content };
|
|
1113
|
+
});
|
|
1004
1114
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
import {
|
|
1009
|
-
LangfuseOtelSpanAttributes,
|
|
1010
|
-
startObservation
|
|
1011
|
-
} from "@langfuse/tracing";
|
|
1012
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
1013
|
-
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
1014
|
-
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
1015
|
-
|
|
1016
|
-
// src/capture.ts
|
|
1017
|
-
var DEFAULT_CAPTURE_MAX_BYTES = 262144;
|
|
1018
|
-
var MIN_CAPTURE_MAX_BYTES = 96;
|
|
1019
|
-
function validateCaptureMaxBytes(value) {
|
|
1020
|
-
const resolved = value ?? DEFAULT_CAPTURE_MAX_BYTES;
|
|
1021
|
-
if (!Number.isInteger(resolved) || resolved < MIN_CAPTURE_MAX_BYTES) {
|
|
1022
|
-
throw new TypeError(
|
|
1023
|
-
`Langfuse captureMaxBytes must be an integer of at least ${MIN_CAPTURE_MAX_BYTES}`
|
|
1024
|
-
);
|
|
1115
|
+
function buildAuthHeader2(publicKey, secretKey) {
|
|
1116
|
+
if (publicKey === void 0 || secretKey === void 0) {
|
|
1117
|
+
return {};
|
|
1025
1118
|
}
|
|
1026
|
-
|
|
1119
|
+
const encoded = Buffer.from(`${publicKey}:${secretKey}`).toString("base64");
|
|
1120
|
+
return { Authorization: `Basic ${encoded}` };
|
|
1027
1121
|
}
|
|
1028
|
-
function
|
|
1029
|
-
validateCaptureMaxBytes(maxBytes);
|
|
1030
|
-
const sanitized = sanitizeValue(value, 0, /* @__PURE__ */ new WeakSet());
|
|
1031
|
-
let serialized;
|
|
1122
|
+
async function readErrorBody2(response) {
|
|
1032
1123
|
try {
|
|
1033
|
-
|
|
1124
|
+
return await response.text();
|
|
1034
1125
|
} catch {
|
|
1035
|
-
return
|
|
1036
|
-
}
|
|
1037
|
-
const originalBytes = utf8Bytes(serialized);
|
|
1038
|
-
if (originalBytes <= maxBytes) {
|
|
1039
|
-
return sanitized;
|
|
1126
|
+
return "<unreadable>";
|
|
1040
1127
|
}
|
|
1041
|
-
const preview = boundedPreview(serialized, originalBytes, maxBytes);
|
|
1042
|
-
return {
|
|
1043
|
-
anviaTraceValue: "truncated",
|
|
1044
|
-
originalBytes,
|
|
1045
|
-
preview
|
|
1046
|
-
};
|
|
1047
1128
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
if (/^data:[^;,]+;base64,/i.test(value)) {
|
|
1054
|
-
return omitted("base64", utf8Bytes(value));
|
|
1055
|
-
}
|
|
1056
|
-
return value;
|
|
1129
|
+
|
|
1130
|
+
// src/tracing.ts
|
|
1131
|
+
var LangfuseObservationFactory = class {
|
|
1132
|
+
constructor(tracer) {
|
|
1133
|
+
this.tracer = tracer;
|
|
1057
1134
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
return
|
|
1135
|
+
tracer;
|
|
1136
|
+
agent(name, attributes, parent) {
|
|
1137
|
+
return new LangfuseAgent({ otelSpan: this.startSpan(name, parent), attributes });
|
|
1061
1138
|
}
|
|
1062
|
-
|
|
1063
|
-
return
|
|
1139
|
+
span(name, attributes, parent) {
|
|
1140
|
+
return new LangfuseSpan({ otelSpan: this.startSpan(name, parent), attributes });
|
|
1064
1141
|
}
|
|
1065
|
-
|
|
1066
|
-
return
|
|
1142
|
+
generation(name, attributes, parent) {
|
|
1143
|
+
return new LangfuseGeneration({ otelSpan: this.startSpan(name, parent), attributes });
|
|
1067
1144
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
const result2 = value.map((entry) => sanitizeValue(entry, depth + 1, seen));
|
|
1071
|
-
seen.delete(value);
|
|
1072
|
-
return result2;
|
|
1145
|
+
tool(name, attributes, parent) {
|
|
1146
|
+
return new LangfuseTool({ otelSpan: this.startSpan(name, parent), attributes });
|
|
1073
1147
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
for (const [key, entry] of Object.entries(record)) {
|
|
1077
|
-
if (key === "data" && typeof entry === "string" && (record.type === "base64" || record.type === "image" && typeof record.mediaType === "string")) {
|
|
1078
|
-
result[key] = omitted("base64", utf8Bytes(entry));
|
|
1079
|
-
continue;
|
|
1080
|
-
}
|
|
1081
|
-
result[key] = sanitizeValue(entry, depth + 1, seen);
|
|
1148
|
+
guardrail(name, attributes, parent) {
|
|
1149
|
+
return new LangfuseGuardrail({ otelSpan: this.startSpan(name, parent), attributes });
|
|
1082
1150
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
...originalBytes === void 0 ? {} : { originalBytes }
|
|
1091
|
-
};
|
|
1092
|
-
}
|
|
1093
|
-
function boundedPreview(value, originalBytes, maxBytes) {
|
|
1094
|
-
let low = 0;
|
|
1095
|
-
let high = value.length;
|
|
1096
|
-
while (low < high) {
|
|
1097
|
-
const middle = Math.ceil((low + high) / 2);
|
|
1098
|
-
const candidate = {
|
|
1099
|
-
anviaTraceValue: "truncated",
|
|
1100
|
-
originalBytes,
|
|
1101
|
-
preview: value.slice(0, middle)
|
|
1102
|
-
};
|
|
1103
|
-
if (utf8Bytes(JSON.stringify(candidate)) <= maxBytes) {
|
|
1104
|
-
low = middle;
|
|
1105
|
-
} else {
|
|
1106
|
-
high = middle - 1;
|
|
1107
|
-
}
|
|
1151
|
+
event(name, attributes, parent, timestamp) {
|
|
1152
|
+
const endTime = timestamp ?? /* @__PURE__ */ new Date();
|
|
1153
|
+
return new LangfuseEvent({
|
|
1154
|
+
otelSpan: this.startSpan(name, parent, timestamp),
|
|
1155
|
+
attributes,
|
|
1156
|
+
timestamp: endTime
|
|
1157
|
+
});
|
|
1108
1158
|
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
return typeof Buffer === "undefined" ? new TextEncoder().encode(value).byteLength : Buffer.byteLength(value, "utf8");
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// src/tracing.ts
|
|
1116
|
-
var langfuse = {
|
|
1117
|
-
create(options = {}) {
|
|
1118
|
-
return new LangfuseAgentObserver(options);
|
|
1159
|
+
startSpan(name, parent, startTime) {
|
|
1160
|
+
const parentContext = parent === void 0 ? ROOT_CONTEXT : "otelSpan" in parent ? trace.setSpan(ROOT_CONTEXT, parent.otelSpan) : trace.setSpanContext(ROOT_CONTEXT, parent);
|
|
1161
|
+
return this.tracer.startSpan(name, startTime === void 0 ? {} : { startTime }, parentContext);
|
|
1119
1162
|
}
|
|
1120
1163
|
};
|
|
1121
|
-
var
|
|
1122
|
-
processor;
|
|
1123
|
-
sdk;
|
|
1164
|
+
var LangfuseClient = class {
|
|
1124
1165
|
[langfuseResolvedConfigSymbol];
|
|
1125
1166
|
publicKey;
|
|
1126
1167
|
secretKey;
|
|
1127
1168
|
baseUrl;
|
|
1128
1169
|
serviceName;
|
|
1129
1170
|
timeoutMs;
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
constructor(options) {
|
|
1171
|
+
options;
|
|
1172
|
+
resource;
|
|
1173
|
+
initialization;
|
|
1174
|
+
closePromise;
|
|
1175
|
+
closed = false;
|
|
1176
|
+
constructor(options = {}) {
|
|
1177
|
+
this.options = options;
|
|
1138
1178
|
const resolvedConfig = resolveLangfuseConfig(options);
|
|
1139
1179
|
this[langfuseResolvedConfigSymbol] = resolvedConfig;
|
|
1140
1180
|
this.publicKey = resolvedConfig.publicKey;
|
|
@@ -1142,50 +1182,82 @@ var LangfuseAgentObserver = class {
|
|
|
1142
1182
|
this.baseUrl = resolvedConfig.baseUrl;
|
|
1143
1183
|
this.serviceName = resolvedConfig.serviceName;
|
|
1144
1184
|
this.timeoutMs = resolvedConfig.timeoutMs;
|
|
1145
|
-
|
|
1146
|
-
|
|
1185
|
+
}
|
|
1186
|
+
observer(options = {}) {
|
|
1187
|
+
this.assertOpen();
|
|
1188
|
+
return new LangfuseAgentObserver(this, resolveLangfuseCapture(options));
|
|
1189
|
+
}
|
|
1190
|
+
evalReporter(options = {}) {
|
|
1191
|
+
this.assertOpen();
|
|
1192
|
+
const reporter = createLangfuseEvalReporter(this, options);
|
|
1193
|
+
return {
|
|
1194
|
+
report: (args) => {
|
|
1195
|
+
this.assertOpen();
|
|
1196
|
+
return reporter.report(args);
|
|
1197
|
+
}
|
|
1147
1198
|
};
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1199
|
+
}
|
|
1200
|
+
promptClient(options = {}) {
|
|
1201
|
+
this.assertOpen();
|
|
1202
|
+
const prompts = createLangfusePromptClient(this, options);
|
|
1203
|
+
return {
|
|
1204
|
+
getPrompt: (getOptions) => {
|
|
1205
|
+
this.assertOpen();
|
|
1206
|
+
return prompts.getPrompt(getOptions);
|
|
1207
|
+
},
|
|
1208
|
+
getPromptText: (getOptions) => {
|
|
1209
|
+
this.assertOpen();
|
|
1210
|
+
return prompts.getPromptText(getOptions);
|
|
1211
|
+
},
|
|
1212
|
+
getPromptChat: (getOptions) => {
|
|
1213
|
+
this.assertOpen();
|
|
1214
|
+
return prompts.getPromptChat(getOptions);
|
|
1215
|
+
},
|
|
1216
|
+
refresh: () => {
|
|
1217
|
+
this.assertOpen();
|
|
1218
|
+
prompts.refresh();
|
|
1219
|
+
}
|
|
1157
1220
|
};
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1221
|
+
}
|
|
1222
|
+
datasetClient(options = {}) {
|
|
1223
|
+
this.assertOpen();
|
|
1224
|
+
const datasets = createLangfuseDatasetClient(this, options);
|
|
1225
|
+
const client = this;
|
|
1226
|
+
return {
|
|
1227
|
+
createDataset(dataset) {
|
|
1228
|
+
client.assertOpen();
|
|
1229
|
+
return datasets.createDataset(dataset);
|
|
1230
|
+
},
|
|
1231
|
+
getDataset(getOptions) {
|
|
1232
|
+
client.assertOpen();
|
|
1233
|
+
return datasets.getDataset(getOptions);
|
|
1234
|
+
},
|
|
1235
|
+
upsertItems(upsertOptions) {
|
|
1236
|
+
client.assertOpen();
|
|
1237
|
+
return datasets.upsertItems(upsertOptions);
|
|
1238
|
+
},
|
|
1239
|
+
runExperiment(experimentOptions) {
|
|
1240
|
+
client.assertOpen();
|
|
1241
|
+
return datasets.runExperiment(experimentOptions);
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
runEvalExperiment(options) {
|
|
1246
|
+
this.assertOpen();
|
|
1247
|
+
return runLangfuseEvalExperiment(this, options);
|
|
1248
|
+
}
|
|
1249
|
+
async startObservedRun(args, capture) {
|
|
1250
|
+
const resource = await this.resources();
|
|
1182
1251
|
const traceId = args.trace?.traceId;
|
|
1183
|
-
const capturedInput =
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1252
|
+
const capturedInput = captureInput(
|
|
1253
|
+
{
|
|
1254
|
+
instructions: args.instructions,
|
|
1255
|
+
prompt: args.prompt,
|
|
1256
|
+
history: args.history
|
|
1257
|
+
},
|
|
1258
|
+
capture
|
|
1259
|
+
);
|
|
1260
|
+
const capturedTraceMetadata = captureInput(args.trace?.metadata ?? {}, capture);
|
|
1189
1261
|
const metadata = {
|
|
1190
1262
|
agentName: args.agentName,
|
|
1191
1263
|
agentDescription: args.agentDescription,
|
|
@@ -1201,69 +1273,41 @@ var LangfuseAgentObserver = class {
|
|
|
1201
1273
|
input: capturedInput,
|
|
1202
1274
|
metadata
|
|
1203
1275
|
};
|
|
1204
|
-
if (args.trace?.version !== void 0)
|
|
1205
|
-
|
|
1206
|
-
}
|
|
1207
|
-
const root = startObservation(
|
|
1276
|
+
if (args.trace?.version !== void 0) rootAttributes.version = args.trace.version;
|
|
1277
|
+
const root = resource.observations.agent(
|
|
1208
1278
|
args.agentName ?? "agent.run",
|
|
1209
1279
|
rootAttributes,
|
|
1210
|
-
traceId === void 0 ?
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
spanId: "0000000000000001",
|
|
1215
|
-
traceFlags: 1
|
|
1216
|
-
}
|
|
1280
|
+
traceId === void 0 ? void 0 : {
|
|
1281
|
+
traceId,
|
|
1282
|
+
spanId: "0000000000000001",
|
|
1283
|
+
traceFlags: TraceFlags.SAMPLED
|
|
1217
1284
|
}
|
|
1218
1285
|
);
|
|
1219
1286
|
applyTraceAttributes(root, args, capturedTraceMetadata);
|
|
1220
|
-
|
|
1221
|
-
const runObserver = new LangfuseRunObserver(
|
|
1287
|
+
return new LangfuseRunObserver(
|
|
1222
1288
|
root,
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
promptRef,
|
|
1228
|
-
{
|
|
1229
|
-
redactor: this.redactor,
|
|
1230
|
-
redactInputs: this.redactInputs,
|
|
1231
|
-
redactOutputs: this.redactOutputs,
|
|
1232
|
-
captureMode: this.captureMode,
|
|
1233
|
-
captureMaxBytes: this.captureMaxBytes
|
|
1234
|
-
}
|
|
1289
|
+
resource.observations,
|
|
1290
|
+
{ traceId: root.traceId, observationId: root.id },
|
|
1291
|
+
resolvePromptRef(args),
|
|
1292
|
+
capture
|
|
1235
1293
|
);
|
|
1236
|
-
this.currentHandle = runObserver.getHandle();
|
|
1237
|
-
runObserver.setCurrentHandle = (handle) => {
|
|
1238
|
-
this.currentHandle = handle;
|
|
1239
|
-
};
|
|
1240
|
-
runObserver.clearCurrentHandle = () => {
|
|
1241
|
-
if (this.currentHandle === runObserver.getHandle()) {
|
|
1242
|
-
this.currentHandle = void 0;
|
|
1243
|
-
}
|
|
1244
|
-
};
|
|
1245
|
-
return runObserver;
|
|
1246
1294
|
}
|
|
1247
1295
|
async flush() {
|
|
1248
|
-
|
|
1249
|
-
await this.
|
|
1296
|
+
this.assertOpen();
|
|
1297
|
+
const resource = this.resource ?? (this.initialization === void 0 ? void 0 : await this.initialization);
|
|
1298
|
+
if (resource === void 0) return;
|
|
1299
|
+
await resource.queue?.flush();
|
|
1300
|
+
await resource.processor.forceFlush();
|
|
1250
1301
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1302
|
+
close() {
|
|
1303
|
+
this.closePromise ??= this.closeResources();
|
|
1304
|
+
return this.closePromise;
|
|
1254
1305
|
}
|
|
1255
|
-
async
|
|
1256
|
-
await this.
|
|
1306
|
+
async [Symbol.asyncDispose]() {
|
|
1307
|
+
await this.close();
|
|
1257
1308
|
}
|
|
1258
1309
|
scoreQueueDepth() {
|
|
1259
|
-
return this.queue?.depth() ?? 0;
|
|
1260
|
-
}
|
|
1261
|
-
getCurrentTrace() {
|
|
1262
|
-
return this.currentHandle;
|
|
1263
|
-
}
|
|
1264
|
-
captureInput(value) {
|
|
1265
|
-
const redacted = this.redactor === void 0 || this.redactInputs === void 0 ? value : applyRedaction(this.redactor, value, this.redactInputs);
|
|
1266
|
-
return sanitizeTraceValue(redacted, this.captureMaxBytes);
|
|
1310
|
+
return this.resource?.queue?.depth() ?? 0;
|
|
1267
1311
|
}
|
|
1268
1312
|
async score(args) {
|
|
1269
1313
|
if (args.traceId === void 0 || args.traceId.length === 0) {
|
|
@@ -1273,12 +1317,100 @@ var LangfuseAgentObserver = class {
|
|
|
1273
1317
|
throw new Error("Langfuse score requires publicKey and secretKey");
|
|
1274
1318
|
}
|
|
1275
1319
|
assertScoreValue(args.value, args.dataType);
|
|
1276
|
-
|
|
1277
|
-
|
|
1320
|
+
const resource = await this.resources();
|
|
1321
|
+
if (resource.queue !== null) {
|
|
1322
|
+
resource.queue.enqueue(args);
|
|
1278
1323
|
return;
|
|
1279
1324
|
}
|
|
1280
1325
|
await this.sendScore(args);
|
|
1281
1326
|
}
|
|
1327
|
+
resources() {
|
|
1328
|
+
this.assertOpen();
|
|
1329
|
+
if (this.resource !== void 0) return Promise.resolve(this.resource);
|
|
1330
|
+
this.initialization ??= this.createResources().then((resource) => {
|
|
1331
|
+
this.resource = resource;
|
|
1332
|
+
return resource;
|
|
1333
|
+
}).catch((error) => {
|
|
1334
|
+
this.initialization = void 0;
|
|
1335
|
+
throw error;
|
|
1336
|
+
});
|
|
1337
|
+
return this.initialization;
|
|
1338
|
+
}
|
|
1339
|
+
async createResources() {
|
|
1340
|
+
const resolvedConfig = this[langfuseResolvedConfigSymbol];
|
|
1341
|
+
const processorOptions = {
|
|
1342
|
+
baseUrl: this.baseUrl
|
|
1343
|
+
};
|
|
1344
|
+
if (this.publicKey !== void 0) processorOptions.publicKey = this.publicKey;
|
|
1345
|
+
if (this.secretKey !== void 0) processorOptions.secretKey = this.secretKey;
|
|
1346
|
+
if (resolvedConfig.environment !== void 0) {
|
|
1347
|
+
processorOptions.environment = resolvedConfig.environment;
|
|
1348
|
+
}
|
|
1349
|
+
if (resolvedConfig.release !== void 0) processorOptions.release = resolvedConfig.release;
|
|
1350
|
+
const processor = new LangfuseSpanProcessor(processorOptions);
|
|
1351
|
+
const providerOptions = {
|
|
1352
|
+
spanProcessors: [processor]
|
|
1353
|
+
};
|
|
1354
|
+
if (this.serviceName !== void 0) {
|
|
1355
|
+
providerOptions.resource = resourceFromAttributes({
|
|
1356
|
+
[SEMRESATTRS_SERVICE_NAME]: this.serviceName
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
let provider;
|
|
1360
|
+
try {
|
|
1361
|
+
provider = new NodeTracerProvider(providerOptions);
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
await processor.shutdown().catch(() => void 0);
|
|
1364
|
+
throw error;
|
|
1365
|
+
}
|
|
1366
|
+
try {
|
|
1367
|
+
const batchSize = this.options.scores?.batchSize ?? 0;
|
|
1368
|
+
const queue = batchSize > 0 && this.publicKey !== void 0 && this.secretKey !== void 0 ? new ScoreQueue({
|
|
1369
|
+
baseUrl: this.baseUrl,
|
|
1370
|
+
publicKey: this.publicKey,
|
|
1371
|
+
secretKey: this.secretKey,
|
|
1372
|
+
timeoutMs: this.timeoutMs,
|
|
1373
|
+
batchSize,
|
|
1374
|
+
flushIntervalMs: this.options.scores?.flushIntervalMs ?? 250,
|
|
1375
|
+
maxAttempts: scoreMaxAttempts(this.options.scores?.retries)
|
|
1376
|
+
}) : null;
|
|
1377
|
+
return {
|
|
1378
|
+
processor,
|
|
1379
|
+
provider,
|
|
1380
|
+
observations: new LangfuseObservationFactory(
|
|
1381
|
+
provider.getTracer("@anvia/langfuse", "1.0.0")
|
|
1382
|
+
),
|
|
1383
|
+
queue
|
|
1384
|
+
};
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
await provider.shutdown().catch(() => void 0);
|
|
1387
|
+
throw error;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
async closeResources() {
|
|
1391
|
+
this.closed = true;
|
|
1392
|
+
const pending = this.resource === void 0 ? this.initialization : Promise.resolve(this.resource);
|
|
1393
|
+
if (pending === void 0) return;
|
|
1394
|
+
let resource;
|
|
1395
|
+
try {
|
|
1396
|
+
resource = await pending;
|
|
1397
|
+
} catch {
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const settled = await Promise.allSettled([
|
|
1401
|
+
resource.queue?.shutdown() ?? Promise.resolve(),
|
|
1402
|
+
resource.provider.shutdown()
|
|
1403
|
+
]);
|
|
1404
|
+
const failures = settled.flatMap(
|
|
1405
|
+
(result) => result.status === "rejected" ? [result.reason] : []
|
|
1406
|
+
);
|
|
1407
|
+
if (failures.length > 0) {
|
|
1408
|
+
throw new AggregateError(failures, "Failed to close LangfuseClient.");
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
assertOpen() {
|
|
1412
|
+
if (this.closed) throw new Error("LangfuseClient is closed.");
|
|
1413
|
+
}
|
|
1282
1414
|
async sendScore(args) {
|
|
1283
1415
|
const body = buildScoreBody2(args);
|
|
1284
1416
|
const response = await fetch(`${this.baseUrl}/api/public/scores`, {
|
|
@@ -1297,6 +1429,37 @@ var LangfuseAgentObserver = class {
|
|
|
1297
1429
|
}
|
|
1298
1430
|
}
|
|
1299
1431
|
};
|
|
1432
|
+
var LangfuseAgentObserver = class {
|
|
1433
|
+
constructor(client, capture) {
|
|
1434
|
+
this.client = client;
|
|
1435
|
+
this.capture = capture;
|
|
1436
|
+
}
|
|
1437
|
+
client;
|
|
1438
|
+
capture;
|
|
1439
|
+
startRun(args) {
|
|
1440
|
+
return this.client.startObservedRun(args, this.capture);
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
function resolveLangfuseCapture(options) {
|
|
1444
|
+
return {
|
|
1445
|
+
redactor: options.redactInputs !== void 0 || options.redactOutputs !== void 0 ? createPiiRedactor(options.redaction) : void 0,
|
|
1446
|
+
redactInputs: options.redactInputs,
|
|
1447
|
+
redactOutputs: options.redactOutputs,
|
|
1448
|
+
captureMode: options.captureMode ?? "safe",
|
|
1449
|
+
captureMaxBytes: validateCaptureMaxBytes(options.captureMaxBytes)
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
function captureInput(value, capture) {
|
|
1453
|
+
const redacted = capture.redactor === void 0 || capture.redactInputs === void 0 ? value : applyRedaction(capture.redactor, value, capture.redactInputs);
|
|
1454
|
+
return sanitizeTraceValue(redacted, capture.captureMaxBytes);
|
|
1455
|
+
}
|
|
1456
|
+
function scoreMaxAttempts(retries) {
|
|
1457
|
+
if (retries === void 0) return 3;
|
|
1458
|
+
if (!Number.isSafeInteger(retries.maxAttempts) || retries.maxAttempts < 1) {
|
|
1459
|
+
throw new TypeError("Langfuse score retries.maxAttempts must be a positive integer.");
|
|
1460
|
+
}
|
|
1461
|
+
return retries.maxAttempts;
|
|
1462
|
+
}
|
|
1300
1463
|
function assertScoreValue(value, dataType) {
|
|
1301
1464
|
if (dataType === "NUMERIC") {
|
|
1302
1465
|
if (typeof value !== "number") {
|
|
@@ -1436,20 +1599,15 @@ function asMetadata(value) {
|
|
|
1436
1599
|
return isRecord(value) ? value : { value };
|
|
1437
1600
|
}
|
|
1438
1601
|
function eventStartTime(value) {
|
|
1439
|
-
if (value
|
|
1440
|
-
return Number.isNaN(value.getTime()) ? void 0 : value;
|
|
1441
|
-
}
|
|
1442
|
-
if (typeof value !== "string") {
|
|
1443
|
-
return void 0;
|
|
1444
|
-
}
|
|
1602
|
+
if (value === void 0) return void 0;
|
|
1445
1603
|
const parsed = new Date(value);
|
|
1446
1604
|
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
1447
1605
|
}
|
|
1448
1606
|
var LangfuseRunObserver = class {
|
|
1449
|
-
constructor(root,
|
|
1607
|
+
constructor(root, observations, trace2, promptRef, redaction) {
|
|
1450
1608
|
this.root = root;
|
|
1451
|
-
this.
|
|
1452
|
-
this.
|
|
1609
|
+
this.observations = observations;
|
|
1610
|
+
this.trace = trace2;
|
|
1453
1611
|
this.promptRef = promptRef;
|
|
1454
1612
|
this.redactor = redaction.redactor;
|
|
1455
1613
|
this.redactInputs = redaction.redactInputs;
|
|
@@ -1458,13 +1616,9 @@ var LangfuseRunObserver = class {
|
|
|
1458
1616
|
this.captureMaxBytes = redaction.captureMaxBytes;
|
|
1459
1617
|
}
|
|
1460
1618
|
root;
|
|
1619
|
+
observations;
|
|
1461
1620
|
trace;
|
|
1462
1621
|
turnSpans = /* @__PURE__ */ new Map();
|
|
1463
|
-
// Assigned by LangfuseAgentObserver.startRun so that the run can
|
|
1464
|
-
// publish trace-handle updates back to the agent observer.
|
|
1465
|
-
setCurrentHandle;
|
|
1466
|
-
clearCurrentHandle;
|
|
1467
|
-
handle;
|
|
1468
1622
|
promptRef;
|
|
1469
1623
|
redactor;
|
|
1470
1624
|
redactInputs;
|
|
@@ -1491,7 +1645,7 @@ var LangfuseRunObserver = class {
|
|
|
1491
1645
|
safeInput.tools = args.request.tools;
|
|
1492
1646
|
safeInput.providerTools = args.request.providerTools;
|
|
1493
1647
|
safeInput.outputSchema = args.request.outputSchema;
|
|
1494
|
-
safeInput.
|
|
1648
|
+
safeInput.providerOptions = args.request.providerOptions;
|
|
1495
1649
|
}
|
|
1496
1650
|
const metadata = {
|
|
1497
1651
|
turn: args.turn,
|
|
@@ -1499,7 +1653,7 @@ var LangfuseRunObserver = class {
|
|
|
1499
1653
|
toolNames: args.request.tools.map((tool) => tool.name),
|
|
1500
1654
|
providerToolNames: args.request.providerTools?.map((tool) => tool.name) ?? [],
|
|
1501
1655
|
hasOutputSchema: args.request.outputSchema !== void 0,
|
|
1502
|
-
|
|
1656
|
+
providerOptionKeys: isRecord(args.request.providerOptions) ? Object.keys(args.request.providerOptions) : []
|
|
1503
1657
|
};
|
|
1504
1658
|
if (this.captureMode === "full" && args.providerRequest !== void 0) {
|
|
1505
1659
|
metadata.providerRequest = args.providerRequest;
|
|
@@ -1507,7 +1661,7 @@ var LangfuseRunObserver = class {
|
|
|
1507
1661
|
if (args.modelInfo !== void 0) {
|
|
1508
1662
|
const modelInfo = {
|
|
1509
1663
|
provider: args.modelInfo.provider,
|
|
1510
|
-
|
|
1664
|
+
modelId: args.modelInfo.modelId
|
|
1511
1665
|
};
|
|
1512
1666
|
if (args.modelInfo.capabilities !== void 0) {
|
|
1513
1667
|
modelInfo.capabilities = args.modelInfo.capabilities;
|
|
@@ -1517,7 +1671,7 @@ var LangfuseRunObserver = class {
|
|
|
1517
1671
|
Object.assign(metadata, promptMetadata(this.promptRef));
|
|
1518
1672
|
const generationAttributes = {
|
|
1519
1673
|
input: this.redactInputValue(safeInput),
|
|
1520
|
-
model: args.
|
|
1674
|
+
model: args.modelInfo?.modelId ?? "unknown",
|
|
1521
1675
|
modelParameters: modelParameters(args.request),
|
|
1522
1676
|
metadata: asMetadata(this.redactInputValue(metadata))
|
|
1523
1677
|
};
|
|
@@ -1528,9 +1682,11 @@ var LangfuseRunObserver = class {
|
|
|
1528
1682
|
isFallback: false
|
|
1529
1683
|
};
|
|
1530
1684
|
}
|
|
1531
|
-
const generation =
|
|
1532
|
-
|
|
1533
|
-
|
|
1685
|
+
const generation = this.observations.generation(
|
|
1686
|
+
`model.turn.${args.turn}`,
|
|
1687
|
+
generationAttributes,
|
|
1688
|
+
turn
|
|
1689
|
+
);
|
|
1534
1690
|
return new LangfuseGenerationObserver(generation, this, /* @__PURE__ */ new Date());
|
|
1535
1691
|
}
|
|
1536
1692
|
startTool(args) {
|
|
@@ -1544,7 +1700,7 @@ var LangfuseRunObserver = class {
|
|
|
1544
1700
|
if (args.toolDefinition !== void 0) metadata.toolDefinition = args.toolDefinition;
|
|
1545
1701
|
if (args.toolMetadata !== void 0) metadata.toolMetadata = args.toolMetadata;
|
|
1546
1702
|
}
|
|
1547
|
-
const tool =
|
|
1703
|
+
const tool = this.observations.tool(
|
|
1548
1704
|
`tool.${args.toolName}`,
|
|
1549
1705
|
{
|
|
1550
1706
|
input: this.redactInputValue({
|
|
@@ -1553,14 +1709,16 @@ var LangfuseRunObserver = class {
|
|
|
1553
1709
|
}),
|
|
1554
1710
|
metadata: asMetadata(this.redactInputValue(metadata))
|
|
1555
1711
|
},
|
|
1556
|
-
|
|
1712
|
+
turn
|
|
1557
1713
|
);
|
|
1558
|
-
return new LangfuseToolObserver(tool, this);
|
|
1714
|
+
return new LangfuseToolObserver(tool, this, this.observations);
|
|
1559
1715
|
}
|
|
1560
1716
|
end(args) {
|
|
1561
1717
|
this.closeAllTurns();
|
|
1562
|
-
const
|
|
1718
|
+
const observedOutput = args.status === "completed" ? { status: args.status, output: args.output, text: args.text } : { status: args.status, stage: args.stage, text: args.text };
|
|
1719
|
+
const redactedOutput = this.redactOutputValue(observedOutput);
|
|
1563
1720
|
const metadata = {
|
|
1721
|
+
status: args.status,
|
|
1564
1722
|
usage: args.usage,
|
|
1565
1723
|
messageCount: args.messages.length,
|
|
1566
1724
|
sources: this.redactOutputValue(args.sources),
|
|
@@ -1573,7 +1731,6 @@ var LangfuseRunObserver = class {
|
|
|
1573
1731
|
output: redactedOutput,
|
|
1574
1732
|
metadata
|
|
1575
1733
|
}).end();
|
|
1576
|
-
this.clearCurrentHandle?.();
|
|
1577
1734
|
}
|
|
1578
1735
|
error(args) {
|
|
1579
1736
|
this.closeAllTurns();
|
|
@@ -1593,7 +1750,6 @@ var LangfuseRunObserver = class {
|
|
|
1593
1750
|
},
|
|
1594
1751
|
metadata
|
|
1595
1752
|
}).end();
|
|
1596
|
-
this.clearCurrentHandle?.();
|
|
1597
1753
|
}
|
|
1598
1754
|
event(args) {
|
|
1599
1755
|
const metadata = asMetadata(this.redactOutputValue(args.attributes ?? {}));
|
|
@@ -1602,43 +1758,19 @@ var LangfuseRunObserver = class {
|
|
|
1602
1758
|
attributes.level = args.level;
|
|
1603
1759
|
}
|
|
1604
1760
|
const startTime = eventStartTime(args.timestamp);
|
|
1605
|
-
this.
|
|
1606
|
-
asType: "event",
|
|
1607
|
-
...startTime === void 0 ? {} : { startTime }
|
|
1608
|
-
});
|
|
1609
|
-
}
|
|
1610
|
-
getHandle() {
|
|
1611
|
-
return this.handle;
|
|
1612
|
-
}
|
|
1613
|
-
buildHandle() {
|
|
1614
|
-
return {
|
|
1615
|
-
traceId: this.trace.traceId ?? "",
|
|
1616
|
-
observationId: this.trace.observationId ?? "",
|
|
1617
|
-
addAttributes: (attributes) => {
|
|
1618
|
-
this.root.update({ metadata: asMetadata(this.redactOutputValue(attributes)) });
|
|
1619
|
-
this.setCurrentHandle?.(this.handle);
|
|
1620
|
-
},
|
|
1621
|
-
addEvent: (name, attributes) => {
|
|
1622
|
-
this.root.startObservation(
|
|
1623
|
-
name,
|
|
1624
|
-
{ metadata: asMetadata(this.redactOutputValue(attributes ?? {})) },
|
|
1625
|
-
{ asType: "event" }
|
|
1626
|
-
);
|
|
1627
|
-
this.setCurrentHandle?.(this.handle);
|
|
1628
|
-
}
|
|
1629
|
-
};
|
|
1761
|
+
this.observations.event(args.name, attributes, this.root, startTime);
|
|
1630
1762
|
}
|
|
1631
1763
|
turnSpan(turn) {
|
|
1632
1764
|
const existing = this.turnSpans.get(turn);
|
|
1633
1765
|
if (existing !== void 0) {
|
|
1634
1766
|
return existing;
|
|
1635
1767
|
}
|
|
1636
|
-
const span = this.
|
|
1768
|
+
const span = this.observations.span(
|
|
1637
1769
|
`turn.${turn}`,
|
|
1638
1770
|
{
|
|
1639
1771
|
metadata: { turn }
|
|
1640
1772
|
},
|
|
1641
|
-
|
|
1773
|
+
this.root
|
|
1642
1774
|
);
|
|
1643
1775
|
this.turnSpans.set(turn, span);
|
|
1644
1776
|
return span;
|
|
@@ -1719,12 +1851,14 @@ function textFromObservedAssistantContent(content) {
|
|
|
1719
1851
|
return content.flatMap((item) => item.type === "text" ? [item.text] : []).join("\n");
|
|
1720
1852
|
}
|
|
1721
1853
|
var LangfuseToolObserver = class {
|
|
1722
|
-
constructor(tool, run) {
|
|
1854
|
+
constructor(tool, run, observations) {
|
|
1723
1855
|
this.tool = tool;
|
|
1724
1856
|
this.run = run;
|
|
1857
|
+
this.observations = observations;
|
|
1725
1858
|
}
|
|
1726
1859
|
tool;
|
|
1727
1860
|
run;
|
|
1861
|
+
observations;
|
|
1728
1862
|
childAgents = /* @__PURE__ */ new Map();
|
|
1729
1863
|
childGenerations = /* @__PURE__ */ new Map();
|
|
1730
1864
|
childTools = [];
|
|
@@ -1741,7 +1875,7 @@ var LangfuseToolObserver = class {
|
|
|
1741
1875
|
if (child.type === "turn_start") {
|
|
1742
1876
|
const promptMessage = isRecord(child.prompt) ? child.prompt : void 0;
|
|
1743
1877
|
const historyMessages = Array.isArray(child.history) ? child.history.filter(isRecord) : [];
|
|
1744
|
-
|
|
1878
|
+
this.observations.event(
|
|
1745
1879
|
`${agentLabel(agentId, agentName)}.turn.${childTurn}.start`,
|
|
1746
1880
|
{
|
|
1747
1881
|
input: this.run.redactInputValue({
|
|
@@ -1752,7 +1886,7 @@ var LangfuseToolObserver = class {
|
|
|
1752
1886
|
this.run.redactInputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1753
1887
|
)
|
|
1754
1888
|
},
|
|
1755
|
-
|
|
1889
|
+
agent
|
|
1756
1890
|
);
|
|
1757
1891
|
return;
|
|
1758
1892
|
}
|
|
@@ -1769,15 +1903,15 @@ var LangfuseToolObserver = class {
|
|
|
1769
1903
|
input.tools = request.tools;
|
|
1770
1904
|
input.providerTools = request.providerTools;
|
|
1771
1905
|
input.outputSchema = request.outputSchema;
|
|
1772
|
-
input.
|
|
1906
|
+
input.providerOptions = request.providerOptions;
|
|
1773
1907
|
}
|
|
1774
1908
|
const toolNames = Array.isArray(request.tools) ? request.tools.filter(isRecord).map((tool) => tool.name).filter((name) => typeof name === "string") : [];
|
|
1775
1909
|
const providerToolNames = Array.isArray(request.providerTools) ? request.providerTools.filter(isRecord).map((tool) => tool.name).filter((name) => typeof name === "string") : [];
|
|
1776
|
-
const generation =
|
|
1910
|
+
const generation = this.observations.generation(
|
|
1777
1911
|
`${agentLabel(agentId, agentName)}.model.turn.${childTurn}`,
|
|
1778
1912
|
{
|
|
1779
1913
|
input: this.run.redactInputValue(input),
|
|
1780
|
-
model: typeof
|
|
1914
|
+
model: typeof modelInfo?.modelId === "string" ? modelInfo.modelId : "unknown",
|
|
1781
1915
|
modelParameters: modelParameters(request),
|
|
1782
1916
|
metadata: asMetadata(
|
|
1783
1917
|
this.run.redactInputValue({
|
|
@@ -1790,7 +1924,7 @@ var LangfuseToolObserver = class {
|
|
|
1790
1924
|
})
|
|
1791
1925
|
)
|
|
1792
1926
|
},
|
|
1793
|
-
|
|
1927
|
+
agent
|
|
1794
1928
|
);
|
|
1795
1929
|
this.childGenerations.set(generationKey(agentId, childTurn), {
|
|
1796
1930
|
generation,
|
|
@@ -1830,7 +1964,7 @@ var LangfuseToolObserver = class {
|
|
|
1830
1964
|
if (child.type === "source" || child.type === "provider_tool_call") {
|
|
1831
1965
|
const childGeneration = this.childGenerations.get(generationKey(agentId, childTurn));
|
|
1832
1966
|
const parent = childGeneration?.generation ?? agent;
|
|
1833
|
-
|
|
1967
|
+
this.observations.event(
|
|
1834
1968
|
`${agentLabel(agentId, agentName)}.${child.type}`,
|
|
1835
1969
|
{
|
|
1836
1970
|
output: this.run.redactOutputValue(
|
|
@@ -1840,12 +1974,12 @@ var LangfuseToolObserver = class {
|
|
|
1840
1974
|
this.run.redactOutputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1841
1975
|
)
|
|
1842
1976
|
},
|
|
1843
|
-
|
|
1977
|
+
parent
|
|
1844
1978
|
);
|
|
1845
1979
|
return;
|
|
1846
1980
|
}
|
|
1847
1981
|
if (child.type === "guardrail_decision") {
|
|
1848
|
-
|
|
1982
|
+
this.observations.guardrail(
|
|
1849
1983
|
`${agentLabel(agentId, agentName)}.guardrail`,
|
|
1850
1984
|
{
|
|
1851
1985
|
output: this.run.redactOutputValue(child.decision),
|
|
@@ -1853,7 +1987,7 @@ var LangfuseToolObserver = class {
|
|
|
1853
1987
|
this.run.redactOutputValue(childMetadata(args, agentId, agentName, childTurn))
|
|
1854
1988
|
)
|
|
1855
1989
|
},
|
|
1856
|
-
|
|
1990
|
+
agent
|
|
1857
1991
|
).end();
|
|
1858
1992
|
return;
|
|
1859
1993
|
}
|
|
@@ -1863,14 +1997,13 @@ var LangfuseToolObserver = class {
|
|
|
1863
1997
|
output: this.run.redactOutputValue({ toolCall: child.toolCall })
|
|
1864
1998
|
});
|
|
1865
1999
|
const toolCall = child.toolCall;
|
|
1866
|
-
const
|
|
1867
|
-
const
|
|
1868
|
-
const
|
|
1869
|
-
const childTool = agent.startObservation(
|
|
2000
|
+
const toolName = typeof toolCall.toolName === "string" ? toolCall.toolName : "tool";
|
|
2001
|
+
const toolCallId = typeof toolCall.toolCallId === "string" ? toolCall.toolCallId : typeof toolCall.callId === "string" ? toolCall.callId : void 0;
|
|
2002
|
+
const childTool = this.observations.tool(
|
|
1870
2003
|
`${agentLabel(agentId, agentName)}.${toolName}`,
|
|
1871
2004
|
{
|
|
1872
2005
|
input: this.run.redactInputValue({
|
|
1873
|
-
args:
|
|
2006
|
+
args: toolCall.input,
|
|
1874
2007
|
toolCall
|
|
1875
2008
|
}),
|
|
1876
2009
|
metadata: asMetadata(
|
|
@@ -1881,7 +2014,7 @@ var LangfuseToolObserver = class {
|
|
|
1881
2014
|
})
|
|
1882
2015
|
)
|
|
1883
2016
|
},
|
|
1884
|
-
|
|
2017
|
+
agent
|
|
1885
2018
|
);
|
|
1886
2019
|
const childToolRecord = {
|
|
1887
2020
|
agentId,
|
|
@@ -1917,13 +2050,18 @@ var LangfuseToolObserver = class {
|
|
|
1917
2050
|
return;
|
|
1918
2051
|
}
|
|
1919
2052
|
if (child.type === "final") {
|
|
2053
|
+
const result = isRecord(child.result) ? child.result : {};
|
|
1920
2054
|
const update = {
|
|
1921
|
-
output: this.run.redactOutputValue(
|
|
2055
|
+
output: this.run.redactOutputValue({
|
|
2056
|
+
status: result.status,
|
|
2057
|
+
output: result.output,
|
|
2058
|
+
text: result.text
|
|
2059
|
+
})
|
|
1922
2060
|
};
|
|
1923
2061
|
const metadata = {};
|
|
1924
|
-
if (isRecord(
|
|
1925
|
-
if (this.run.isFullCapture() && Array.isArray(
|
|
1926
|
-
metadata.messages = this.run.redactTranscript(
|
|
2062
|
+
if (isRecord(result.usage)) metadata.usage = result.usage;
|
|
2063
|
+
if (this.run.isFullCapture() && Array.isArray(result.messages)) {
|
|
2064
|
+
metadata.messages = this.run.redactTranscript(result.messages);
|
|
1927
2065
|
}
|
|
1928
2066
|
if (Object.keys(metadata).length > 0) update.metadata = metadata;
|
|
1929
2067
|
agent.update(update).end();
|
|
@@ -1989,14 +2127,14 @@ var LangfuseToolObserver = class {
|
|
|
1989
2127
|
if (existing !== void 0) {
|
|
1990
2128
|
return existing;
|
|
1991
2129
|
}
|
|
1992
|
-
const agent = this.
|
|
2130
|
+
const agent = this.observations.agent(
|
|
1993
2131
|
`${agentLabel(agentId, agentName)}.run`,
|
|
1994
2132
|
{
|
|
1995
2133
|
metadata: asMetadata(
|
|
1996
2134
|
this.run.redactInputValue(childMetadata(args, agentId, agentName, args.turn))
|
|
1997
2135
|
)
|
|
1998
2136
|
},
|
|
1999
|
-
|
|
2137
|
+
this.tool
|
|
2000
2138
|
);
|
|
2001
2139
|
this.childAgents.set(agentId, agent);
|
|
2002
2140
|
return agent;
|
|
@@ -2032,12 +2170,8 @@ var LangfuseToolObserver = class {
|
|
|
2032
2170
|
};
|
|
2033
2171
|
export {
|
|
2034
2172
|
DEFAULT_PATTERNS,
|
|
2173
|
+
LangfuseClient,
|
|
2035
2174
|
LangfuseScoreError,
|
|
2036
|
-
|
|
2037
|
-
createLangfuseEvalReporter,
|
|
2038
|
-
createLangfusePromptClient,
|
|
2039
|
-
createPiiRedactor,
|
|
2040
|
-
langfuse,
|
|
2041
|
-
runEvalAsExperiment
|
|
2175
|
+
createPiiRedactor
|
|
2042
2176
|
};
|
|
2043
2177
|
//# sourceMappingURL=index.js.map
|