@struktur/telemetry 2.1.1 → 2.2.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/{src/adapters/langfuse/LangfuseAdapter.ts → dist/adapters/langfuse.js} +60 -149
- package/dist/adapters/langfuse.js.map +1 -0
- package/{src/adapters/phoenix/PhoenixAdapter.ts → dist/adapters/phoenix.js} +61 -159
- package/dist/adapters/phoenix.js.map +1 -0
- package/dist/factory.js +592 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.js +601 -0
- package/dist/index.js.map +1 -0
- package/dist/types.js +37 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -11
- package/src/adapters/langfuse/index.ts +0 -6
- package/src/adapters/phoenix/index.ts +0 -6
- package/src/factory.ts +0 -133
- package/src/index.ts +0 -55
- package/src/types.ts +0 -453
- package/tests/adapters/langfuse.test.ts +0 -118
- package/tests/adapters/phoenix.test.ts +0 -132
- package/tests/factory.test.ts +0 -93
- package/tests/types.test.ts +0 -248
|
@@ -1,145 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Span,
|
|
11
|
-
SpanResult,
|
|
12
|
-
TelemetryEvent,
|
|
13
|
-
TelemetryContext,
|
|
14
|
-
LangfuseConfig,
|
|
15
|
-
LLMCallEvent,
|
|
16
|
-
ValidationEvent,
|
|
17
|
-
ChunkEvent,
|
|
18
|
-
ToolCallEvent,
|
|
19
|
-
MergeEvent,
|
|
20
|
-
ParseEvent,
|
|
21
|
-
} from "../../types.js";
|
|
22
|
-
|
|
23
|
-
type OtelSpan = {
|
|
24
|
-
spanContext: () => { spanId: string; traceId: string };
|
|
25
|
-
setStatus: (status: { code: number; message?: string }) => void;
|
|
26
|
-
setAttribute: (key: string, value: string | number | boolean | undefined) => void;
|
|
27
|
-
setAttributes: (attrs: Record<string, string | number | boolean>) => void;
|
|
28
|
-
recordException: (error: Error) => void;
|
|
29
|
-
end: () => void;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Langfuse telemetry adapter using OpenTelemetry
|
|
34
|
-
*/
|
|
35
|
-
export class LangfuseAdapter implements TelemetryAdapter {
|
|
36
|
-
readonly name = "langfuse";
|
|
37
|
-
readonly version = "1.0.0";
|
|
38
|
-
|
|
39
|
-
private config: LangfuseConfig;
|
|
40
|
-
private sdk: { shutdown: () => Promise<void> } | null = null;
|
|
41
|
-
private activeSpans = new Map<string, OtelSpan>();
|
|
42
|
-
private otelApi: typeof import("@opentelemetry/api") | null = null;
|
|
43
|
-
|
|
44
|
-
constructor(config: LangfuseConfig) {
|
|
1
|
+
// src/adapters/langfuse/LangfuseAdapter.ts
|
|
2
|
+
var LangfuseAdapter = class {
|
|
3
|
+
name = "langfuse";
|
|
4
|
+
version = "1.0.0";
|
|
5
|
+
config;
|
|
6
|
+
sdk = null;
|
|
7
|
+
activeSpans = /* @__PURE__ */ new Map();
|
|
8
|
+
otelApi = null;
|
|
9
|
+
constructor(config) {
|
|
45
10
|
this.config = {
|
|
46
11
|
baseUrl: "https://cloud.langfuse.com",
|
|
47
|
-
...config
|
|
12
|
+
...config
|
|
48
13
|
};
|
|
49
14
|
}
|
|
50
|
-
|
|
51
|
-
async initialize(): Promise<void> {
|
|
52
|
-
// Dynamically import Langfuse OTel SDK
|
|
15
|
+
async initialize() {
|
|
53
16
|
const [{ LangfuseSpanProcessor }, { NodeSDK }, otelApi] = await Promise.all([
|
|
54
17
|
import("@langfuse/otel"),
|
|
55
18
|
import("@opentelemetry/sdk-node"),
|
|
56
|
-
import("@opentelemetry/api")
|
|
19
|
+
import("@opentelemetry/api")
|
|
57
20
|
]);
|
|
58
|
-
|
|
59
21
|
this.otelApi = otelApi;
|
|
60
|
-
|
|
61
22
|
const processor = new LangfuseSpanProcessor({
|
|
62
23
|
publicKey: this.config.publicKey,
|
|
63
24
|
secretKey: this.config.secretKey,
|
|
64
|
-
baseUrl: this.config.baseUrl
|
|
25
|
+
baseUrl: this.config.baseUrl
|
|
65
26
|
});
|
|
66
|
-
|
|
67
27
|
const sdk = new NodeSDK({
|
|
68
|
-
spanProcessors: [processor]
|
|
28
|
+
spanProcessors: [processor]
|
|
69
29
|
});
|
|
70
|
-
|
|
71
30
|
sdk.start();
|
|
72
31
|
this.sdk = sdk;
|
|
73
32
|
}
|
|
74
|
-
|
|
75
|
-
async shutdown(): Promise<void> {
|
|
33
|
+
async shutdown() {
|
|
76
34
|
if (this.sdk) {
|
|
77
35
|
await this.sdk.shutdown();
|
|
78
36
|
}
|
|
79
37
|
}
|
|
80
|
-
|
|
81
|
-
startSpan(context: SpanContext): Span {
|
|
38
|
+
startSpan(context) {
|
|
82
39
|
if (!this.otelApi) {
|
|
83
40
|
throw new Error("LangfuseAdapter not initialized");
|
|
84
41
|
}
|
|
85
|
-
|
|
86
42
|
const tracer = this.otelApi.trace.getTracer("struktur");
|
|
87
|
-
|
|
88
43
|
const otelSpan = tracer.startSpan(context.name, {
|
|
89
44
|
attributes: {
|
|
90
45
|
"observation.type": context.kind.toLowerCase(),
|
|
91
|
-
...context.attributes
|
|
92
|
-
}
|
|
93
|
-
})
|
|
94
|
-
|
|
46
|
+
...context.attributes
|
|
47
|
+
}
|
|
48
|
+
});
|
|
95
49
|
const spanContext = otelSpan.spanContext();
|
|
96
|
-
const span
|
|
50
|
+
const span = {
|
|
97
51
|
id: spanContext.spanId,
|
|
98
52
|
traceId: spanContext.traceId,
|
|
99
53
|
name: context.name,
|
|
100
54
|
kind: context.kind,
|
|
101
55
|
startTime: context.startTime ?? Date.now(),
|
|
102
|
-
parentId: context.parentSpan?.id
|
|
56
|
+
parentId: context.parentSpan?.id
|
|
103
57
|
};
|
|
104
|
-
|
|
105
58
|
this.activeSpans.set(span.id, otelSpan);
|
|
106
59
|
return span;
|
|
107
60
|
}
|
|
108
|
-
|
|
109
|
-
endSpan(span: Span, result?: SpanResult): void {
|
|
61
|
+
endSpan(span, result) {
|
|
110
62
|
const otelSpan = this.activeSpans.get(span.id);
|
|
111
63
|
if (!otelSpan) return;
|
|
112
|
-
|
|
113
64
|
if (result) {
|
|
114
65
|
otelSpan.setStatus({
|
|
115
66
|
code: result.status === "ok" ? 1 : 2,
|
|
116
|
-
message: result.error?.message
|
|
67
|
+
message: result.error?.message
|
|
117
68
|
});
|
|
118
|
-
|
|
119
|
-
if (result.output !== undefined) {
|
|
69
|
+
if (result.output !== void 0) {
|
|
120
70
|
try {
|
|
121
|
-
const outputStr = typeof result.output === "string"
|
|
122
|
-
? result.output
|
|
123
|
-
: JSON.stringify(result.output);
|
|
71
|
+
const outputStr = typeof result.output === "string" ? result.output : JSON.stringify(result.output);
|
|
124
72
|
otelSpan.setAttribute("output", outputStr);
|
|
125
73
|
} catch {
|
|
126
74
|
otelSpan.setAttribute("output", "[object]");
|
|
127
75
|
}
|
|
128
76
|
}
|
|
129
|
-
|
|
130
|
-
if (result.latencyMs !== undefined) {
|
|
77
|
+
if (result.latencyMs !== void 0) {
|
|
131
78
|
otelSpan.setAttribute("latency_ms", result.latencyMs);
|
|
132
79
|
}
|
|
133
80
|
}
|
|
134
|
-
|
|
135
81
|
otelSpan.end();
|
|
136
82
|
this.activeSpans.delete(span.id);
|
|
137
83
|
}
|
|
138
|
-
|
|
139
|
-
recordEvent(span: Span, event: TelemetryEvent): void {
|
|
84
|
+
recordEvent(span, event) {
|
|
140
85
|
const otelSpan = this.activeSpans.get(span.id);
|
|
141
86
|
if (!otelSpan) return;
|
|
142
|
-
|
|
143
87
|
switch (event.type) {
|
|
144
88
|
case "llm_call":
|
|
145
89
|
this.recordLLMCall(otelSpan, event);
|
|
@@ -161,14 +105,12 @@ export class LangfuseAdapter implements TelemetryAdapter {
|
|
|
161
105
|
break;
|
|
162
106
|
}
|
|
163
107
|
}
|
|
164
|
-
|
|
165
|
-
setAttributes(span: Span, attributes: Record<string, unknown>): void {
|
|
108
|
+
setAttributes(span, attributes) {
|
|
166
109
|
const otelSpan = this.activeSpans.get(span.id);
|
|
167
110
|
if (!otelSpan) return;
|
|
168
|
-
|
|
169
|
-
const stringAttrs: Record<string, string | number | boolean> = {};
|
|
111
|
+
const stringAttrs = {};
|
|
170
112
|
for (const [key, value] of Object.entries(attributes)) {
|
|
171
|
-
if (value !==
|
|
113
|
+
if (value !== void 0 && value !== null) {
|
|
172
114
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
173
115
|
stringAttrs[key] = value;
|
|
174
116
|
} else {
|
|
@@ -180,140 +122,109 @@ export class LangfuseAdapter implements TelemetryAdapter {
|
|
|
180
122
|
}
|
|
181
123
|
}
|
|
182
124
|
}
|
|
183
|
-
|
|
184
125
|
otelSpan.setAttributes(stringAttrs);
|
|
185
126
|
}
|
|
186
|
-
|
|
187
|
-
setContext(_context: TelemetryContext): void {
|
|
188
|
-
// Langfuse supports session_id, user_id, metadata, tags via span attributes
|
|
189
|
-
// These would be set on individual spans
|
|
127
|
+
setContext(_context) {
|
|
190
128
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const attrs: Record<string, string | number | boolean> = {
|
|
129
|
+
recordLLMCall(span, event) {
|
|
130
|
+
const attrs = {
|
|
194
131
|
model: event.model,
|
|
195
132
|
provider: event.provider,
|
|
196
133
|
input: JSON.stringify(event.input.messages),
|
|
197
134
|
temperature: event.input.temperature ?? "",
|
|
198
|
-
max_tokens: event.input.maxTokens ?? ""
|
|
135
|
+
max_tokens: event.input.maxTokens ?? ""
|
|
199
136
|
};
|
|
200
|
-
|
|
201
137
|
if (event.output) {
|
|
202
138
|
attrs.output = event.output.content;
|
|
203
|
-
|
|
204
139
|
if (event.output.usage) {
|
|
205
140
|
attrs["usage.input"] = event.output.usage.input;
|
|
206
141
|
attrs["usage.output"] = event.output.usage.output;
|
|
207
142
|
attrs["usage.total"] = event.output.usage.total;
|
|
208
143
|
}
|
|
209
144
|
}
|
|
210
|
-
|
|
211
145
|
attrs.latency_ms = event.latencyMs;
|
|
212
|
-
|
|
213
146
|
if (event.error) {
|
|
214
147
|
attrs.error = event.error.message;
|
|
215
148
|
span.recordException(event.error);
|
|
216
149
|
}
|
|
217
|
-
|
|
218
150
|
span.setAttributes(attrs);
|
|
219
151
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const attrs: Record<string, string | number | boolean> = {
|
|
152
|
+
recordValidation(span, event) {
|
|
153
|
+
const attrs = {
|
|
223
154
|
attempt: event.attempt,
|
|
224
155
|
max_attempts: event.maxAttempts,
|
|
225
|
-
success: event.success
|
|
156
|
+
success: event.success
|
|
226
157
|
};
|
|
227
|
-
|
|
228
158
|
if (event.errors && event.errors.length > 0) {
|
|
229
159
|
attrs.errors = JSON.stringify(event.errors);
|
|
230
160
|
}
|
|
231
|
-
|
|
232
|
-
if (event.latencyMs !== undefined) {
|
|
161
|
+
if (event.latencyMs !== void 0) {
|
|
233
162
|
attrs.latency_ms = event.latencyMs;
|
|
234
163
|
}
|
|
235
|
-
|
|
236
164
|
span.setAttributes(attrs);
|
|
237
165
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const attrs: Record<string, string | number | boolean> = {
|
|
166
|
+
recordChunk(span, event) {
|
|
167
|
+
const attrs = {
|
|
241
168
|
chunk_index: event.chunkIndex,
|
|
242
169
|
chunk_total: event.totalChunks,
|
|
243
170
|
chunk_tokens: event.tokens,
|
|
244
|
-
chunk_images: event.images
|
|
171
|
+
chunk_images: event.images
|
|
245
172
|
};
|
|
246
|
-
|
|
247
173
|
if (event.content) {
|
|
248
|
-
attrs.chunk_content = event.content.slice(0,
|
|
174
|
+
attrs.chunk_content = event.content.slice(0, 1e3);
|
|
249
175
|
}
|
|
250
|
-
|
|
251
176
|
span.setAttributes(attrs);
|
|
252
177
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const attrs: Record<string, string | number | boolean> = {
|
|
178
|
+
recordToolCall(span, event) {
|
|
179
|
+
const attrs = {
|
|
256
180
|
tool_name: event.toolName,
|
|
257
|
-
tool_args: JSON.stringify(event.args)
|
|
181
|
+
tool_args: JSON.stringify(event.args)
|
|
258
182
|
};
|
|
259
|
-
|
|
260
|
-
if (event.result !== undefined) {
|
|
183
|
+
if (event.result !== void 0) {
|
|
261
184
|
try {
|
|
262
185
|
attrs.tool_result = JSON.stringify(event.result);
|
|
263
186
|
} catch {
|
|
264
187
|
attrs.tool_result = "[object]";
|
|
265
188
|
}
|
|
266
189
|
}
|
|
267
|
-
|
|
268
190
|
if (event.error) {
|
|
269
191
|
attrs.tool_error = event.error.message;
|
|
270
192
|
}
|
|
271
|
-
|
|
272
|
-
if (event.latencyMs !== undefined) {
|
|
193
|
+
if (event.latencyMs !== void 0) {
|
|
273
194
|
attrs.latency_ms = event.latencyMs;
|
|
274
195
|
}
|
|
275
|
-
|
|
276
196
|
span.setAttributes(attrs);
|
|
277
|
-
|
|
278
197
|
if (event.error) {
|
|
279
198
|
span.recordException(event.error);
|
|
280
199
|
}
|
|
281
200
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const attrs: Record<string, string | number | boolean> = {
|
|
201
|
+
recordMerge(span, event) {
|
|
202
|
+
const attrs = {
|
|
285
203
|
strategy: event.strategy,
|
|
286
204
|
input_count: event.inputCount,
|
|
287
|
-
output_count: event.outputCount
|
|
205
|
+
output_count: event.outputCount
|
|
288
206
|
};
|
|
289
|
-
|
|
290
|
-
if (event.deduped !== undefined) {
|
|
207
|
+
if (event.deduped !== void 0) {
|
|
291
208
|
attrs.deduped = event.deduped;
|
|
292
209
|
}
|
|
293
|
-
|
|
294
210
|
span.setAttributes(attrs);
|
|
295
211
|
}
|
|
296
|
-
|
|
297
|
-
private recordParse(span: OtelSpan, event: ParseEvent): void {
|
|
212
|
+
recordParse(span, event) {
|
|
298
213
|
span.setAttributes({
|
|
299
214
|
mime_type: event.mimeType,
|
|
300
215
|
parser: event.parser,
|
|
301
216
|
input_size: event.inputSize,
|
|
302
217
|
output_tokens: event.outputTokens,
|
|
303
218
|
output_images: event.outputImages,
|
|
304
|
-
latency_ms: event.latencyMs
|
|
219
|
+
latency_ms: event.latencyMs
|
|
305
220
|
});
|
|
306
221
|
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Create a Langfuse telemetry adapter
|
|
311
|
-
*
|
|
312
|
-
* @param config - Langfuse configuration
|
|
313
|
-
* @returns Langfuse telemetry adapter
|
|
314
|
-
*/
|
|
315
|
-
export function createLangfuseAdapter(config: LangfuseConfig): LangfuseAdapter {
|
|
222
|
+
};
|
|
223
|
+
function createLangfuseAdapter(config) {
|
|
316
224
|
return new LangfuseAdapter(config);
|
|
317
225
|
}
|
|
318
|
-
|
|
319
|
-
|
|
226
|
+
export {
|
|
227
|
+
LangfuseAdapter,
|
|
228
|
+
createLangfuseAdapter
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=langfuse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/langfuse/LangfuseAdapter.ts"],"sourcesContent":["/**\n * Langfuse telemetry adapter\n * \n * Implements TelemetryAdapter for Langfuse using their OpenTelemetry SDK.\n */\n\nimport type {\n TelemetryAdapter,\n SpanContext,\n Span,\n SpanResult,\n TelemetryEvent,\n TelemetryContext,\n LangfuseConfig,\n LLMCallEvent,\n ValidationEvent,\n ChunkEvent,\n ToolCallEvent,\n MergeEvent,\n ParseEvent,\n} from \"../../types.js\";\n\ntype OtelSpan = {\n spanContext: () => { spanId: string; traceId: string };\n setStatus: (status: { code: number; message?: string }) => void;\n setAttribute: (key: string, value: string | number | boolean | undefined) => void;\n setAttributes: (attrs: Record<string, string | number | boolean>) => void;\n recordException: (error: Error) => void;\n end: () => void;\n};\n\n/**\n * Langfuse telemetry adapter using OpenTelemetry\n */\nexport class LangfuseAdapter implements TelemetryAdapter {\n readonly name = \"langfuse\";\n readonly version = \"1.0.0\";\n\n private config: LangfuseConfig;\n private sdk: { shutdown: () => Promise<void> } | null = null;\n private activeSpans = new Map<string, OtelSpan>();\n private otelApi: typeof import(\"@opentelemetry/api\") | null = null;\n\n constructor(config: LangfuseConfig) {\n this.config = {\n baseUrl: \"https://cloud.langfuse.com\",\n ...config,\n };\n }\n\n async initialize(): Promise<void> {\n // Dynamically import Langfuse OTel SDK\n const [{ LangfuseSpanProcessor }, { NodeSDK }, otelApi] = await Promise.all([\n import(\"@langfuse/otel\"),\n import(\"@opentelemetry/sdk-node\"),\n import(\"@opentelemetry/api\"),\n ]);\n\n this.otelApi = otelApi;\n\n const processor = new LangfuseSpanProcessor({\n publicKey: this.config.publicKey,\n secretKey: this.config.secretKey,\n baseUrl: this.config.baseUrl,\n });\n\n const sdk = new NodeSDK({\n spanProcessors: [processor],\n });\n\n sdk.start();\n this.sdk = sdk;\n }\n\n async shutdown(): Promise<void> {\n if (this.sdk) {\n await this.sdk.shutdown();\n }\n }\n\n startSpan(context: SpanContext): Span {\n if (!this.otelApi) {\n throw new Error(\"LangfuseAdapter not initialized\");\n }\n\n const tracer = this.otelApi.trace.getTracer(\"struktur\");\n\n const otelSpan = tracer.startSpan(context.name, {\n attributes: {\n \"observation.type\": context.kind.toLowerCase(),\n ...context.attributes,\n },\n }) as OtelSpan;\n\n const spanContext = otelSpan.spanContext();\n const span: Span = {\n id: spanContext.spanId,\n traceId: spanContext.traceId,\n name: context.name,\n kind: context.kind,\n startTime: context.startTime ?? Date.now(),\n parentId: context.parentSpan?.id,\n };\n\n this.activeSpans.set(span.id, otelSpan);\n return span;\n }\n\n endSpan(span: Span, result?: SpanResult): void {\n const otelSpan = this.activeSpans.get(span.id);\n if (!otelSpan) return;\n\n if (result) {\n otelSpan.setStatus({\n code: result.status === \"ok\" ? 1 : 2,\n message: result.error?.message,\n });\n\n if (result.output !== undefined) {\n try {\n const outputStr = typeof result.output === \"string\"\n ? result.output\n : JSON.stringify(result.output);\n otelSpan.setAttribute(\"output\", outputStr);\n } catch {\n otelSpan.setAttribute(\"output\", \"[object]\");\n }\n }\n\n if (result.latencyMs !== undefined) {\n otelSpan.setAttribute(\"latency_ms\", result.latencyMs);\n }\n }\n\n otelSpan.end();\n this.activeSpans.delete(span.id);\n }\n\n recordEvent(span: Span, event: TelemetryEvent): void {\n const otelSpan = this.activeSpans.get(span.id);\n if (!otelSpan) return;\n\n switch (event.type) {\n case \"llm_call\":\n this.recordLLMCall(otelSpan, event);\n break;\n case \"validation\":\n this.recordValidation(otelSpan, event);\n break;\n case \"chunk\":\n this.recordChunk(otelSpan, event);\n break;\n case \"tool_call\":\n this.recordToolCall(otelSpan, event);\n break;\n case \"merge\":\n this.recordMerge(otelSpan, event);\n break;\n case \"parse\":\n this.recordParse(otelSpan, event);\n break;\n }\n }\n\n setAttributes(span: Span, attributes: Record<string, unknown>): void {\n const otelSpan = this.activeSpans.get(span.id);\n if (!otelSpan) return;\n\n const stringAttrs: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined && value !== null) {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n stringAttrs[key] = value;\n } else {\n try {\n stringAttrs[key] = JSON.stringify(value);\n } catch {\n stringAttrs[key] = String(value);\n }\n }\n }\n }\n\n otelSpan.setAttributes(stringAttrs);\n }\n\n setContext(_context: TelemetryContext): void {\n // Langfuse supports session_id, user_id, metadata, tags via span attributes\n // These would be set on individual spans\n }\n\n private recordLLMCall(span: OtelSpan, event: LLMCallEvent): void {\n const attrs: Record<string, string | number | boolean> = {\n model: event.model,\n provider: event.provider,\n input: JSON.stringify(event.input.messages),\n temperature: event.input.temperature ?? \"\",\n max_tokens: event.input.maxTokens ?? \"\",\n };\n\n if (event.output) {\n attrs.output = event.output.content;\n \n if (event.output.usage) {\n attrs[\"usage.input\"] = event.output.usage.input;\n attrs[\"usage.output\"] = event.output.usage.output;\n attrs[\"usage.total\"] = event.output.usage.total;\n }\n }\n\n attrs.latency_ms = event.latencyMs;\n\n if (event.error) {\n attrs.error = event.error.message;\n span.recordException(event.error);\n }\n\n span.setAttributes(attrs);\n }\n\n private recordValidation(span: OtelSpan, event: ValidationEvent): void {\n const attrs: Record<string, string | number | boolean> = {\n attempt: event.attempt,\n max_attempts: event.maxAttempts,\n success: event.success,\n };\n\n if (event.errors && event.errors.length > 0) {\n attrs.errors = JSON.stringify(event.errors);\n }\n\n if (event.latencyMs !== undefined) {\n attrs.latency_ms = event.latencyMs;\n }\n\n span.setAttributes(attrs);\n }\n\n private recordChunk(span: OtelSpan, event: ChunkEvent): void {\n const attrs: Record<string, string | number | boolean> = {\n chunk_index: event.chunkIndex,\n chunk_total: event.totalChunks,\n chunk_tokens: event.tokens,\n chunk_images: event.images,\n };\n\n if (event.content) {\n attrs.chunk_content = event.content.slice(0, 1000);\n }\n\n span.setAttributes(attrs);\n }\n\n private recordToolCall(span: OtelSpan, event: ToolCallEvent): void {\n const attrs: Record<string, string | number | boolean> = {\n tool_name: event.toolName,\n tool_args: JSON.stringify(event.args),\n };\n\n if (event.result !== undefined) {\n try {\n attrs.tool_result = JSON.stringify(event.result);\n } catch {\n attrs.tool_result = \"[object]\";\n }\n }\n\n if (event.error) {\n attrs.tool_error = event.error.message;\n }\n\n if (event.latencyMs !== undefined) {\n attrs.latency_ms = event.latencyMs;\n }\n\n span.setAttributes(attrs);\n\n if (event.error) {\n span.recordException(event.error);\n }\n }\n\n private recordMerge(span: OtelSpan, event: MergeEvent): void {\n const attrs: Record<string, string | number | boolean> = {\n strategy: event.strategy,\n input_count: event.inputCount,\n output_count: event.outputCount,\n };\n\n if (event.deduped !== undefined) {\n attrs.deduped = event.deduped;\n }\n\n span.setAttributes(attrs);\n }\n\n private recordParse(span: OtelSpan, event: ParseEvent): void {\n span.setAttributes({\n mime_type: event.mimeType,\n parser: event.parser,\n input_size: event.inputSize,\n output_tokens: event.outputTokens,\n output_images: event.outputImages,\n latency_ms: event.latencyMs,\n });\n }\n}\n\n/**\n * Create a Langfuse telemetry adapter\n * \n * @param config - Langfuse configuration\n * @returns Langfuse telemetry adapter\n */\nexport function createLangfuseAdapter(config: LangfuseConfig): LangfuseAdapter {\n return new LangfuseAdapter(config);\n}\n\nexport type { LangfuseConfig };\n"],"mappings":"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","names":[]}
|