@cloudbase/agent-observability 1.0.1-alpha.10

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.
@@ -0,0 +1,1237 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // src/core/constants.ts
24
+ var import_openinference_semantic_conventions, OtelSpanAttributes;
25
+ var init_constants = __esm({
26
+ "src/core/constants.ts"() {
27
+ "use strict";
28
+ import_openinference_semantic_conventions = require("@arizeai/openinference-semantic-conventions");
29
+ OtelSpanAttributes = {
30
+ // OpenInference - re-export all standard conventions
31
+ ...import_openinference_semantic_conventions.SemanticConventions,
32
+ // AG-Kit Trace attributes (non-standard)
33
+ TRACE_NAME: "trace.name",
34
+ TRACE_TAGS: "trace.tags",
35
+ TRACE_PUBLIC: "trace.public",
36
+ TRACE_METADATA: "trace.metadata",
37
+ TRACE_INPUT: "trace.input",
38
+ TRACE_OUTPUT: "trace.output",
39
+ // AG-Kit Observation attributes (non-standard)
40
+ OBSERVATION_TYPE: "observation.type",
41
+ OBSERVATION_LEVEL: "observation.level",
42
+ OBSERVATION_STATUS_MESSAGE: "observation.status_message",
43
+ OBSERVATION_INPUT: "observation.input",
44
+ OBSERVATION_OUTPUT: "observation.output",
45
+ OBSERVATION_METADATA: "observation.metadata",
46
+ // AG-Kit LLM-specific (non-standard)
47
+ LLM_COMPLETION_START_TIME: "llm.completion_start_time",
48
+ LLM_MODEL_PARAMETERS: "llm.model_parameters",
49
+ LLM_USAGE_DETAILS: "llm.usage_details",
50
+ LLM_COST_DETAILS: "llm.cost_details",
51
+ // AG-Kit Retriever-specific (non-standard)
52
+ RETRIEVER_NAME: "retriever.name",
53
+ RETRIEVER_QUERY: "retriever.query",
54
+ RETRIEVER_INDEX_ID: "retriever.index_id",
55
+ RETRIEVER_TOP_K: "retriever.top_k",
56
+ // AG-Kit General (non-standard)
57
+ ENVIRONMENT: "environment",
58
+ RELEASE: "release",
59
+ VERSION: "version"
60
+ };
61
+ }
62
+ });
63
+
64
+ // src/core/attributes.ts
65
+ function createTraceAttributes({
66
+ name,
67
+ userId,
68
+ sessionId,
69
+ version,
70
+ release,
71
+ input,
72
+ output,
73
+ metadata,
74
+ tags,
75
+ environment,
76
+ public: isPublic
77
+ } = {}) {
78
+ const attributes = {
79
+ [OtelSpanAttributes.TRACE_NAME]: name,
80
+ // Use OpenInference standard attributes for user and session
81
+ [OtelSpanAttributes.USER_ID]: userId,
82
+ [OtelSpanAttributes.SESSION_ID]: sessionId,
83
+ [OtelSpanAttributes.VERSION]: version,
84
+ [OtelSpanAttributes.RELEASE]: release,
85
+ [OtelSpanAttributes.TRACE_INPUT]: _serialize(input),
86
+ [OtelSpanAttributes.TRACE_OUTPUT]: _serialize(output),
87
+ [OtelSpanAttributes.TRACE_TAGS]: tags,
88
+ [OtelSpanAttributes.ENVIRONMENT]: environment,
89
+ [OtelSpanAttributes.TRACE_PUBLIC]: isPublic,
90
+ ..._flattenAndSerializeMetadata(metadata, OtelSpanAttributes.TRACE_METADATA)
91
+ };
92
+ return Object.fromEntries(
93
+ Object.entries(attributes).filter(([_, v]) => v != null)
94
+ );
95
+ }
96
+ function createObservationAttributes(type, attributes) {
97
+ const {
98
+ metadata,
99
+ input,
100
+ output,
101
+ level,
102
+ statusMessage,
103
+ version,
104
+ completionStartTime,
105
+ model,
106
+ modelParameters,
107
+ usageDetails
108
+ } = attributes;
109
+ const otelAttributes = {
110
+ [import_openinference_semantic_conventions2.SemanticConventions.OPENINFERENCE_SPAN_KIND]: type.toUpperCase(),
111
+ [OtelSpanAttributes.OBSERVATION_TYPE]: type,
112
+ [OtelSpanAttributes.OBSERVATION_LEVEL]: level,
113
+ [OtelSpanAttributes.OBSERVATION_STATUS_MESSAGE]: statusMessage,
114
+ [OtelSpanAttributes.VERSION]: version,
115
+ // Use OpenInference input.value convention
116
+ [import_openinference_semantic_conventions2.SemanticConventions.INPUT_VALUE]: _serialize(input),
117
+ // Also set legacy agkit.observation.input for compatibility
118
+ [OtelSpanAttributes.OBSERVATION_INPUT]: _serialize(input),
119
+ // Use OpenInference output.value convention
120
+ [import_openinference_semantic_conventions2.SemanticConventions.OUTPUT_VALUE]: _serialize(output),
121
+ // Also set legacy agkit.observation.output for compatibility
122
+ [OtelSpanAttributes.OBSERVATION_OUTPUT]: _serialize(output)
123
+ };
124
+ if (type === "llm") {
125
+ if (model) {
126
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.LLM_MODEL_NAME] = model;
127
+ }
128
+ if (modelParameters) {
129
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.LLM_INVOCATION_PARAMETERS] = _serialize(modelParameters);
130
+ otelAttributes[OtelSpanAttributes.LLM_MODEL_PARAMETERS] = _serialize(modelParameters);
131
+ }
132
+ if (usageDetails) {
133
+ if (typeof usageDetails === "object") {
134
+ const usage = usageDetails;
135
+ if (usage.promptTokens !== void 0) {
136
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.LLM_TOKEN_COUNT_PROMPT] = usage.promptTokens;
137
+ }
138
+ if (usage.completionTokens !== void 0) {
139
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.LLM_TOKEN_COUNT_COMPLETION] = usage.completionTokens;
140
+ }
141
+ if (usage.totalTokens !== void 0) {
142
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.LLM_TOKEN_COUNT_TOTAL] = usage.totalTokens;
143
+ }
144
+ }
145
+ otelAttributes[OtelSpanAttributes.LLM_USAGE_DETAILS] = _serialize(usageDetails);
146
+ }
147
+ if (completionStartTime) {
148
+ otelAttributes[OtelSpanAttributes.LLM_COMPLETION_START_TIME] = _serialize(completionStartTime);
149
+ }
150
+ }
151
+ if (type === "embedding") {
152
+ if (model) {
153
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.EMBEDDING_MODEL_NAME] = model;
154
+ }
155
+ if (modelParameters) {
156
+ otelAttributes[import_openinference_semantic_conventions2.SemanticConventions.LLM_INVOCATION_PARAMETERS] = _serialize(modelParameters);
157
+ }
158
+ }
159
+ const metadataAttrs = _flattenAndSerializeMetadata(
160
+ metadata,
161
+ import_openinference_semantic_conventions2.SemanticConventions.METADATA
162
+ );
163
+ Object.assign(otelAttributes, metadataAttrs);
164
+ const obsetvabilityMetadataAttrs = _flattenAndSerializeMetadata(
165
+ metadata,
166
+ OtelSpanAttributes.OBSERVATION_METADATA
167
+ );
168
+ Object.assign(otelAttributes, obsetvabilityMetadataAttrs);
169
+ return Object.fromEntries(
170
+ Object.entries(otelAttributes).filter(([_, v]) => v != null)
171
+ );
172
+ }
173
+ function _serialize(obj) {
174
+ try {
175
+ if (typeof obj === "string") return obj;
176
+ if (obj instanceof Date) return obj.toISOString();
177
+ return obj != null ? JSON.stringify(obj) : void 0;
178
+ } catch {
179
+ return "<failed to serialize>";
180
+ }
181
+ }
182
+ function _flattenAndSerializeMetadata(metadata, prefix) {
183
+ const metadataAttributes = {};
184
+ if (metadata === void 0 || metadata === null) {
185
+ return metadataAttributes;
186
+ }
187
+ if (typeof metadata !== "object" || Array.isArray(metadata)) {
188
+ const serialized = _serialize(metadata);
189
+ if (serialized) {
190
+ metadataAttributes[prefix] = serialized;
191
+ }
192
+ } else {
193
+ for (const [key, value] of Object.entries(metadata)) {
194
+ const serialized = typeof value === "string" ? value : _serialize(value);
195
+ if (serialized) {
196
+ metadataAttributes[`${prefix}.${key}`] = serialized;
197
+ }
198
+ }
199
+ }
200
+ return metadataAttributes;
201
+ }
202
+ var import_openinference_semantic_conventions2;
203
+ var init_attributes = __esm({
204
+ "src/core/attributes.ts"() {
205
+ "use strict";
206
+ init_constants();
207
+ import_openinference_semantic_conventions2 = require("@arizeai/openinference-semantic-conventions");
208
+ }
209
+ });
210
+
211
+ // src/core/tracerProvider.ts
212
+ function createState() {
213
+ return {
214
+ isolatedTracerProvider: null
215
+ };
216
+ }
217
+ function getObservabilityGlobalState() {
218
+ const initialState = createState();
219
+ try {
220
+ const g = globalThis;
221
+ if (typeof g !== "object" || g === null) {
222
+ console.warn(
223
+ "[Observability] globalThis is not available, using fallback state"
224
+ );
225
+ return initialState;
226
+ }
227
+ if (!g[OBSERVABILITY_GLOBAL_SYMBOL]) {
228
+ Object.defineProperty(g, OBSERVABILITY_GLOBAL_SYMBOL, {
229
+ value: initialState,
230
+ writable: false,
231
+ configurable: false,
232
+ enumerable: false
233
+ });
234
+ }
235
+ return g[OBSERVABILITY_GLOBAL_SYMBOL];
236
+ } catch (err) {
237
+ console.error(
238
+ `[Observability] Failed to access global state: ${err instanceof Error ? err.message : String(err)}`
239
+ );
240
+ return initialState;
241
+ }
242
+ }
243
+ function setTracerProvider(provider) {
244
+ getObservabilityGlobalState().isolatedTracerProvider = provider;
245
+ }
246
+ function getTracerProvider() {
247
+ const { isolatedTracerProvider } = getObservabilityGlobalState();
248
+ if (isolatedTracerProvider) return isolatedTracerProvider;
249
+ return import_api.trace.getTracerProvider();
250
+ }
251
+ function getTracer() {
252
+ return getTracerProvider().getTracer(
253
+ OBSERVABILITY_SDK_NAME,
254
+ OBSERVABILITY_SDK_VERSION
255
+ );
256
+ }
257
+ var import_api, OBSERVABILITY_GLOBAL_SYMBOL, OBSERVABILITY_SDK_NAME, OBSERVABILITY_SDK_VERSION;
258
+ var init_tracerProvider = __esm({
259
+ "src/core/tracerProvider.ts"() {
260
+ "use strict";
261
+ import_api = require("@opentelemetry/api");
262
+ OBSERVABILITY_GLOBAL_SYMBOL = /* @__PURE__ */ Symbol.for("observability");
263
+ OBSERVABILITY_SDK_NAME = "ag-kit-observability";
264
+ OBSERVABILITY_SDK_VERSION = "0.1.0";
265
+ }
266
+ });
267
+
268
+ // src/core/spanWrapper.ts
269
+ var BaseObservation, ObservationSpan, ObservationLLM, ObservationEmbedding, ObservationAgent, ObservationTool, ObservationChain, ObservationRetriever, ObservationReranker, ObservationEvaluator, ObservationGuardrail;
270
+ var init_spanWrapper = __esm({
271
+ "src/core/spanWrapper.ts"() {
272
+ "use strict";
273
+ init_attributes();
274
+ init_tracerProvider();
275
+ BaseObservation = class {
276
+ /** The underlying OpenTelemetry span */
277
+ otelSpan;
278
+ /** The observation type */
279
+ type;
280
+ /** The span ID from the OpenTelemetry span context */
281
+ id;
282
+ /** The trace ID from the OpenTelemetry span context */
283
+ traceId;
284
+ constructor(params) {
285
+ this.otelSpan = params.otelSpan;
286
+ this.id = params.otelSpan.spanContext().spanId;
287
+ this.traceId = params.otelSpan.spanContext().traceId;
288
+ this.type = params.type;
289
+ if (params.attributes) {
290
+ this.otelSpan.setAttributes(
291
+ createObservationAttributes(params.type, params.attributes)
292
+ );
293
+ }
294
+ }
295
+ /** Gets the AG-Kit OpenTelemetry tracer instance */
296
+ get tracer() {
297
+ return getTracer();
298
+ }
299
+ /**
300
+ * Ends the observation, marking it as complete.
301
+ *
302
+ * @param endTime - Optional end time, defaults to current time
303
+ */
304
+ end(endTime) {
305
+ this.otelSpan.end(endTime);
306
+ }
307
+ /**
308
+ * Updates the OTEL span attributes.
309
+ *
310
+ * @param attributes - Attributes to update
311
+ * @internal
312
+ */
313
+ updateOtelSpanAttributes(attributes) {
314
+ this.otelSpan.setAttributes(
315
+ createObservationAttributes(this.type, attributes)
316
+ );
317
+ }
318
+ /**
319
+ * Updates the parent trace with new attributes.
320
+ *
321
+ * @param attributes - Trace attributes to set
322
+ * @returns This observation for method chaining
323
+ */
324
+ updateTrace(attributes) {
325
+ this.otelSpan.setAttributes(createTraceAttributes(attributes));
326
+ return this;
327
+ }
328
+ startObservation(name, attributes, options) {
329
+ const { startObservation: startObs } = (init_src(), __toCommonJS(src_exports));
330
+ const { asType = "span" } = options || {};
331
+ return startObs(name, attributes, {
332
+ asType,
333
+ parentSpanContext: this.otelSpan.spanContext()
334
+ });
335
+ }
336
+ };
337
+ ObservationSpan = class extends BaseObservation {
338
+ constructor(params) {
339
+ super({ ...params, type: "span" });
340
+ }
341
+ update(attributes) {
342
+ super.updateOtelSpanAttributes(attributes);
343
+ return this;
344
+ }
345
+ };
346
+ ObservationLLM = class extends BaseObservation {
347
+ constructor(params) {
348
+ super({ ...params, type: "llm" });
349
+ }
350
+ update(attributes) {
351
+ super.updateOtelSpanAttributes(attributes);
352
+ return this;
353
+ }
354
+ };
355
+ ObservationEmbedding = class extends BaseObservation {
356
+ constructor(params) {
357
+ super({ ...params, type: "embedding" });
358
+ }
359
+ update(attributes) {
360
+ super.updateOtelSpanAttributes(attributes);
361
+ return this;
362
+ }
363
+ };
364
+ ObservationAgent = class extends BaseObservation {
365
+ constructor(params) {
366
+ super({ ...params, type: "agent" });
367
+ }
368
+ update(attributes) {
369
+ super.updateOtelSpanAttributes(attributes);
370
+ return this;
371
+ }
372
+ };
373
+ ObservationTool = class extends BaseObservation {
374
+ constructor(params) {
375
+ super({ ...params, type: "tool" });
376
+ }
377
+ update(attributes) {
378
+ super.updateOtelSpanAttributes(attributes);
379
+ return this;
380
+ }
381
+ };
382
+ ObservationChain = class extends BaseObservation {
383
+ constructor(params) {
384
+ super({ ...params, type: "chain" });
385
+ }
386
+ update(attributes) {
387
+ super.updateOtelSpanAttributes(attributes);
388
+ return this;
389
+ }
390
+ };
391
+ ObservationRetriever = class extends BaseObservation {
392
+ constructor(params) {
393
+ super({ ...params, type: "retriever" });
394
+ }
395
+ update(attributes) {
396
+ super.updateOtelSpanAttributes(attributes);
397
+ return this;
398
+ }
399
+ };
400
+ ObservationReranker = class extends BaseObservation {
401
+ constructor(params) {
402
+ super({ ...params, type: "reranker" });
403
+ }
404
+ update(attributes) {
405
+ super.updateOtelSpanAttributes(attributes);
406
+ return this;
407
+ }
408
+ };
409
+ ObservationEvaluator = class extends BaseObservation {
410
+ constructor(params) {
411
+ super({ ...params, type: "evaluator" });
412
+ }
413
+ update(attributes) {
414
+ super.updateOtelSpanAttributes(attributes);
415
+ return this;
416
+ }
417
+ };
418
+ ObservationGuardrail = class extends BaseObservation {
419
+ constructor(params) {
420
+ super({ ...params, type: "guardrail" });
421
+ }
422
+ update(attributes) {
423
+ super.updateOtelSpanAttributes(attributes);
424
+ return this;
425
+ }
426
+ };
427
+ }
428
+ });
429
+
430
+ // src/index.ts
431
+ var src_exports = {};
432
+ __export(src_exports, {
433
+ ObservationAgent: () => ObservationAgent,
434
+ ObservationChain: () => ObservationChain,
435
+ ObservationEmbedding: () => ObservationEmbedding,
436
+ ObservationEvaluator: () => ObservationEvaluator,
437
+ ObservationGuardrail: () => ObservationGuardrail,
438
+ ObservationLLM: () => ObservationLLM,
439
+ ObservationReranker: () => ObservationReranker,
440
+ ObservationRetriever: () => ObservationRetriever,
441
+ ObservationSpan: () => ObservationSpan,
442
+ ObservationTool: () => ObservationTool,
443
+ createObservationAttributes: () => createObservationAttributes,
444
+ createTraceAttributes: () => createTraceAttributes,
445
+ getActiveSpanId: () => getActiveSpanId,
446
+ getActiveTraceId: () => getActiveTraceId,
447
+ getTracer: () => getTracer,
448
+ getTracerProvider: () => getTracerProvider,
449
+ observe: () => observe,
450
+ setTracerProvider: () => setTracerProvider,
451
+ startActiveObservation: () => startActiveObservation,
452
+ startObservation: () => startObservation,
453
+ updateActiveObservation: () => updateActiveObservation,
454
+ updateActiveTrace: () => updateActiveTrace
455
+ });
456
+ function createOtelSpan(params) {
457
+ return getTracer().startSpan(
458
+ params.name,
459
+ { startTime: params.startTime },
460
+ createParentContext(params.parentSpanContext)
461
+ );
462
+ }
463
+ function createParentContext(parentSpanContext) {
464
+ if (!parentSpanContext) return;
465
+ return import_api2.trace.setSpanContext(import_api2.context.active(), parentSpanContext);
466
+ }
467
+ function startObservation(name, attributes, options) {
468
+ const { asType = "span", ...observationOptions } = options || {};
469
+ const otelSpan = createOtelSpan({
470
+ name,
471
+ ...observationOptions
472
+ });
473
+ switch (asType) {
474
+ case "llm":
475
+ return new ObservationLLM({
476
+ otelSpan,
477
+ attributes
478
+ });
479
+ case "embedding":
480
+ return new ObservationEmbedding({
481
+ otelSpan,
482
+ attributes
483
+ });
484
+ case "agent":
485
+ return new ObservationAgent({
486
+ otelSpan,
487
+ attributes
488
+ });
489
+ case "tool":
490
+ return new ObservationTool({
491
+ otelSpan,
492
+ attributes
493
+ });
494
+ case "chain":
495
+ return new ObservationChain({
496
+ otelSpan,
497
+ attributes
498
+ });
499
+ case "retriever":
500
+ return new ObservationRetriever({
501
+ otelSpan,
502
+ attributes
503
+ });
504
+ case "reranker":
505
+ return new ObservationReranker({
506
+ otelSpan,
507
+ attributes
508
+ });
509
+ case "evaluator":
510
+ return new ObservationEvaluator({
511
+ otelSpan,
512
+ attributes
513
+ });
514
+ case "guardrail":
515
+ return new ObservationGuardrail({
516
+ otelSpan,
517
+ attributes
518
+ });
519
+ case "span":
520
+ default:
521
+ return new ObservationSpan({
522
+ otelSpan,
523
+ attributes
524
+ });
525
+ }
526
+ }
527
+ function updateActiveTrace(attributes) {
528
+ const span = import_api2.trace.getActiveSpan();
529
+ if (!span) {
530
+ console.warn(
531
+ "[Observability] No active OTEL span in context. Skipping trace update."
532
+ );
533
+ return;
534
+ }
535
+ span.setAttributes(createTraceAttributes(attributes));
536
+ }
537
+ function getActiveTraceId() {
538
+ return import_api2.trace.getActiveSpan()?.spanContext().traceId;
539
+ }
540
+ function getActiveSpanId() {
541
+ return import_api2.trace.getActiveSpan()?.spanContext().spanId;
542
+ }
543
+ function wrapPromise(promise, span, endOnExit) {
544
+ return promise.then(
545
+ (value) => {
546
+ if (endOnExit !== false) {
547
+ span.end();
548
+ }
549
+ return value;
550
+ },
551
+ (err) => {
552
+ span.setStatus({
553
+ code: import_api2.SpanStatusCode.ERROR,
554
+ message: err instanceof Error ? err.message : "Unknown error"
555
+ });
556
+ if (endOnExit !== false) {
557
+ span.end();
558
+ }
559
+ throw err;
560
+ }
561
+ );
562
+ }
563
+ function startActiveObservation(name, fn, options) {
564
+ const { asType = "span", endOnExit, ...observationOptions } = options || {};
565
+ return getTracer().startActiveSpan(
566
+ name,
567
+ { startTime: observationOptions?.startTime },
568
+ createParentContext(observationOptions?.parentSpanContext) ?? import_api2.context.active(),
569
+ (span) => {
570
+ try {
571
+ let observation;
572
+ switch (asType) {
573
+ case "llm":
574
+ observation = new ObservationLLM({ otelSpan: span });
575
+ break;
576
+ case "embedding":
577
+ observation = new ObservationEmbedding({ otelSpan: span });
578
+ break;
579
+ case "agent":
580
+ observation = new ObservationAgent({ otelSpan: span });
581
+ break;
582
+ case "tool":
583
+ observation = new ObservationTool({ otelSpan: span });
584
+ break;
585
+ case "chain":
586
+ observation = new ObservationChain({ otelSpan: span });
587
+ break;
588
+ case "retriever":
589
+ observation = new ObservationRetriever({ otelSpan: span });
590
+ break;
591
+ case "reranker":
592
+ observation = new ObservationReranker({ otelSpan: span });
593
+ break;
594
+ case "evaluator":
595
+ observation = new ObservationEvaluator({ otelSpan: span });
596
+ break;
597
+ case "guardrail":
598
+ observation = new ObservationGuardrail({ otelSpan: span });
599
+ break;
600
+ case "span":
601
+ default:
602
+ observation = new ObservationSpan({ otelSpan: span });
603
+ }
604
+ const result = fn(observation);
605
+ if (result instanceof Promise) {
606
+ return wrapPromise(
607
+ result,
608
+ span,
609
+ endOnExit
610
+ );
611
+ } else {
612
+ if (endOnExit !== false) {
613
+ span.end();
614
+ }
615
+ return result;
616
+ }
617
+ } catch (err) {
618
+ span.setStatus({
619
+ code: import_api2.SpanStatusCode.ERROR,
620
+ message: err instanceof Error ? err.message : "Unknown error"
621
+ });
622
+ if (endOnExit !== false) {
623
+ span.end();
624
+ }
625
+ throw err;
626
+ }
627
+ }
628
+ );
629
+ }
630
+ function updateActiveObservation(attributes) {
631
+ const span = import_api2.trace.getActiveSpan();
632
+ if (!span) {
633
+ console.warn(
634
+ "[Observability] No active OTEL span in context. Skipping observation update."
635
+ );
636
+ return;
637
+ }
638
+ span.setAttributes(createObservationAttributes("span", attributes));
639
+ }
640
+ function _captureArguments(args) {
641
+ if (args.length === 0) return {};
642
+ if (args.length === 1) return { arg: args[0] };
643
+ return { args };
644
+ }
645
+ function observe(fn, options = {}) {
646
+ const {
647
+ asType = "span",
648
+ captureInput = true,
649
+ captureOutput = true,
650
+ ...observationOptions
651
+ } = options;
652
+ const wrappedFunction = function(...args) {
653
+ const name = fn.name || "anonymous-function";
654
+ const inputData = captureInput ? _captureArguments(args) : void 0;
655
+ const observation = startObservation(
656
+ name,
657
+ inputData ? { input: inputData } : {},
658
+ {
659
+ ...observationOptions,
660
+ asType
661
+ }
662
+ );
663
+ const activeContext = import_api2.trace.setSpan(import_api2.context.active(), observation.otelSpan);
664
+ const result = import_api2.context.with(activeContext, () => fn.apply(this, args));
665
+ if (result instanceof Promise) {
666
+ return result.then(
667
+ (value) => {
668
+ if (captureOutput) {
669
+ observation.update({ output: value });
670
+ }
671
+ observation.end();
672
+ return value;
673
+ },
674
+ (err) => {
675
+ observation.update({
676
+ level: "ERROR",
677
+ statusMessage: err instanceof Error ? err.message : "Unknown error"
678
+ });
679
+ observation.end();
680
+ throw err;
681
+ }
682
+ );
683
+ }
684
+ if (captureOutput) {
685
+ observation.update({ output: result });
686
+ }
687
+ observation.end();
688
+ return result;
689
+ };
690
+ Object.defineProperty(wrappedFunction, "name", { value: fn.name });
691
+ Object.defineProperty(wrappedFunction, "length", { value: fn.length });
692
+ return wrappedFunction;
693
+ }
694
+ var import_api2;
695
+ var init_src = __esm({
696
+ "src/index.ts"() {
697
+ "use strict";
698
+ import_api2 = require("@opentelemetry/api");
699
+ init_attributes();
700
+ init_spanWrapper();
701
+ init_tracerProvider();
702
+ init_attributes();
703
+ init_tracerProvider();
704
+ }
705
+ });
706
+
707
+ // src/langchain/CallbackHandler.ts
708
+ var CallbackHandler_exports = {};
709
+ __export(CallbackHandler_exports, {
710
+ CallbackHandler: () => CallbackHandler
711
+ });
712
+ module.exports = __toCommonJS(CallbackHandler_exports);
713
+ var import_base = require("@langchain/core/callbacks/base");
714
+ var import_messages = require("@langchain/core/messages");
715
+ init_src();
716
+ var CallbackHandler = class extends import_base.BaseCallbackHandler {
717
+ name = "ObservabilityCallbackHandler";
718
+ userId;
719
+ version;
720
+ sessionId;
721
+ tags;
722
+ traceMetadata;
723
+ completionStartTimes = {};
724
+ promptToParentRunMap;
725
+ runMap = /* @__PURE__ */ new Map();
726
+ last_trace_id = null;
727
+ // External parent context from AG-UI.Server span
728
+ externalParentSpanContext;
729
+ // Adapter name for ROOT span prefix
730
+ adapterName;
731
+ constructor(params) {
732
+ super();
733
+ this.sessionId = params?.sessionId;
734
+ this.userId = params?.userId;
735
+ this.tags = params?.tags ?? [];
736
+ this.traceMetadata = params?.traceMetadata;
737
+ this.version = params?.version;
738
+ this.adapterName = params?.adapterName;
739
+ this.promptToParentRunMap = /* @__PURE__ */ new Map();
740
+ }
741
+ get logger() {
742
+ return console;
743
+ }
744
+ /**
745
+ * Set external parent SpanContext from AG-UI.Server span.
746
+ * This allows the CallbackHandler to link LangChain/LangGraph spans
747
+ * to the server-level span, creating a unified trace hierarchy.
748
+ *
749
+ * @param spanContext - SpanContext from the AG-UI.Server span
750
+ * @public
751
+ */
752
+ setExternalParentContext(spanContext) {
753
+ this.externalParentSpanContext = spanContext;
754
+ }
755
+ async handleLLMNewToken(token, _idx, runId, _parentRunId, _tags, _fields) {
756
+ if (runId && !(runId in this.completionStartTimes)) {
757
+ this.logger.debug(`LLM first streaming token: ${runId}`);
758
+ this.completionStartTimes[runId] = /* @__PURE__ */ new Date();
759
+ }
760
+ }
761
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, name) {
762
+ try {
763
+ this.logger.debug(`Chain start with Id: ${runId}`);
764
+ const runName = name ?? chain.id.at(-1)?.toString() ?? "Langchain Run";
765
+ this.registerPromptInfo(parentRunId, metadata);
766
+ let finalInput = inputs;
767
+ if (typeof inputs === "object" && "input" in inputs && Array.isArray(inputs["input"]) && inputs["input"].every((m) => m instanceof import_messages.BaseMessage)) {
768
+ finalInput = inputs["input"].map(
769
+ (m) => this.extractChatMessageContent(m)
770
+ );
771
+ } else if (typeof inputs === "object" && "messages" in inputs && Array.isArray(inputs["messages"]) && inputs["messages"].every((m) => m instanceof import_messages.BaseMessage)) {
772
+ finalInput = inputs["messages"].map(
773
+ (m) => this.extractChatMessageContent(m)
774
+ );
775
+ } else if (typeof inputs === "object" && "content" in inputs && typeof inputs["content"] === "string") {
776
+ finalInput = inputs["content"];
777
+ }
778
+ const observation = this.startAndRegisterObservation({
779
+ runName,
780
+ parentRunId,
781
+ runId,
782
+ tags,
783
+ metadata,
784
+ attributes: {
785
+ input: finalInput
786
+ },
787
+ asType: "span"
788
+ });
789
+ const traceTags = [.../* @__PURE__ */ new Set([...tags ?? [], ...this.tags])];
790
+ if (!parentRunId) {
791
+ observation.updateTrace({
792
+ tags: traceTags,
793
+ userId: metadata && "userId" in metadata && typeof metadata["userId"] === "string" ? metadata["userId"] : this.userId,
794
+ sessionId: metadata && "sessionId" in metadata && typeof metadata["sessionId"] === "string" ? metadata["sessionId"] : this.sessionId,
795
+ metadata: this.traceMetadata,
796
+ version: this.version
797
+ });
798
+ }
799
+ } catch (e) {
800
+ this.logger.debug(e instanceof Error ? e.message : String(e));
801
+ }
802
+ }
803
+ async handleAgentAction(action, runId, parentRunId) {
804
+ try {
805
+ this.logger.debug(`Agent action ${action.tool} with ID: ${runId}`);
806
+ this.startAndRegisterObservation({
807
+ runId,
808
+ parentRunId,
809
+ runName: action.tool,
810
+ attributes: {
811
+ input: action
812
+ },
813
+ asType: "tool"
814
+ });
815
+ } catch (e) {
816
+ this.logger.debug(e instanceof Error ? e.message : String(e));
817
+ }
818
+ }
819
+ async handleAgentEnd(action, runId, _parentRunId) {
820
+ try {
821
+ this.logger.debug(`Agent finish with ID: ${runId}`);
822
+ this.handleObservationEnd({
823
+ runId,
824
+ attributes: { output: action }
825
+ });
826
+ } catch (e) {
827
+ this.logger.debug(e instanceof Error ? e.message : String(e));
828
+ }
829
+ }
830
+ async handleChainError(err, runId, _parentRunId) {
831
+ try {
832
+ this.logger.debug(`Chain error: ${err} with ID: ${runId}`);
833
+ this.handleObservationEnd({
834
+ runId,
835
+ attributes: {
836
+ level: "ERROR",
837
+ statusMessage: err.toString()
838
+ }
839
+ });
840
+ } catch (e) {
841
+ this.logger.debug(e instanceof Error ? e.message : String(e));
842
+ }
843
+ }
844
+ async handleGenerationStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, name) {
845
+ this.logger.debug(
846
+ `Generation start with ID: ${runId} and parentRunId ${parentRunId}`
847
+ );
848
+ const runName = name ?? llm.id.at(-1)?.toString() ?? "Langchain Generation";
849
+ const modelParameters = {};
850
+ const invocationParams = extraParams?.["invocation_params"];
851
+ for (const [key, value] of Object.entries({
852
+ temperature: invocationParams?.temperature,
853
+ max_tokens: invocationParams?.max_tokens,
854
+ top_p: invocationParams?.top_p,
855
+ frequency_penalty: invocationParams?.frequency_penalty,
856
+ presence_penalty: invocationParams?.presence_penalty,
857
+ request_timeout: invocationParams?.request_timeout
858
+ })) {
859
+ if (value !== void 0 && value !== null) {
860
+ modelParameters[key] = value;
861
+ }
862
+ }
863
+ let extractedModelName;
864
+ if (extraParams) {
865
+ const invocationParamsModelName = extraParams.invocation_params.model;
866
+ const metadataModelName = metadata && "ls_model_name" in metadata ? metadata["ls_model_name"] : void 0;
867
+ extractedModelName = invocationParamsModelName ?? metadataModelName;
868
+ }
869
+ const registeredPrompt = this.promptToParentRunMap.get(
870
+ parentRunId ?? "root"
871
+ );
872
+ if (registeredPrompt && parentRunId) {
873
+ this.deregisterPromptInfo(parentRunId);
874
+ }
875
+ this.startAndRegisterObservation({
876
+ runId,
877
+ parentRunId,
878
+ metadata,
879
+ tags,
880
+ runName,
881
+ attributes: {
882
+ input: messages,
883
+ model: extractedModelName,
884
+ modelParameters
885
+ },
886
+ asType: "llm"
887
+ });
888
+ }
889
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, name) {
890
+ try {
891
+ this.logger.debug(`Chat model start with ID: ${runId}`);
892
+ const prompts = messages.flatMap(
893
+ (message) => message.map((m) => this.extractChatMessageContent(m))
894
+ );
895
+ this.handleGenerationStart(
896
+ llm,
897
+ prompts,
898
+ runId,
899
+ parentRunId,
900
+ extraParams,
901
+ tags,
902
+ metadata,
903
+ name
904
+ );
905
+ } catch (e) {
906
+ this.logger.debug(e instanceof Error ? e.message : String(e));
907
+ }
908
+ }
909
+ async handleChainEnd(outputs, runId, _parentRunId) {
910
+ try {
911
+ this.logger.debug(`Chain end with ID: ${runId}`);
912
+ let finalOutput = outputs;
913
+ if (typeof outputs === "object" && "output" in outputs && typeof outputs["output"] === "string") {
914
+ finalOutput = outputs["output"];
915
+ } else if (typeof outputs === "object" && "messages" in outputs && Array.isArray(outputs["messages"]) && outputs["messages"].every((m) => m instanceof import_messages.BaseMessage)) {
916
+ finalOutput = {
917
+ messages: outputs.messages.map(
918
+ (message) => this.extractChatMessageContent(message)
919
+ )
920
+ };
921
+ }
922
+ this.handleObservationEnd({
923
+ runId,
924
+ attributes: {
925
+ output: finalOutput
926
+ }
927
+ });
928
+ this.deregisterPromptInfo(runId);
929
+ } catch (e) {
930
+ this.logger.debug(e instanceof Error ? e.message : String(e));
931
+ }
932
+ }
933
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, name) {
934
+ try {
935
+ this.logger.debug(`LLM start with ID: ${runId}`);
936
+ this.handleGenerationStart(
937
+ llm,
938
+ prompts,
939
+ runId,
940
+ parentRunId,
941
+ extraParams,
942
+ tags,
943
+ metadata,
944
+ name
945
+ );
946
+ } catch (e) {
947
+ this.logger.debug(e instanceof Error ? e.message : String(e));
948
+ }
949
+ }
950
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, name) {
951
+ try {
952
+ this.logger.debug(`Tool start with ID: ${runId}`);
953
+ this.startAndRegisterObservation({
954
+ runId,
955
+ parentRunId,
956
+ runName: name ?? tool.id.at(-1)?.toString() ?? "Tool execution",
957
+ attributes: {
958
+ input
959
+ },
960
+ metadata,
961
+ tags,
962
+ asType: "tool"
963
+ });
964
+ } catch (e) {
965
+ this.logger.debug(e instanceof Error ? e.message : String(e));
966
+ }
967
+ }
968
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
969
+ try {
970
+ this.logger.debug(`Retriever start with ID: ${runId}`);
971
+ this.startAndRegisterObservation({
972
+ runId,
973
+ parentRunId,
974
+ runName: name ?? retriever.id.at(-1)?.toString() ?? "Retriever",
975
+ attributes: {
976
+ input: query
977
+ },
978
+ tags,
979
+ metadata,
980
+ asType: "span"
981
+ });
982
+ } catch (e) {
983
+ this.logger.debug(e instanceof Error ? e.message : String(e));
984
+ }
985
+ }
986
+ async handleRetrieverEnd(documents, runId, _parentRunId) {
987
+ try {
988
+ this.logger.debug(`Retriever end with ID: ${runId}`);
989
+ this.handleObservationEnd({
990
+ runId,
991
+ attributes: {
992
+ output: documents
993
+ }
994
+ });
995
+ } catch (e) {
996
+ this.logger.debug(e instanceof Error ? e.message : String(e));
997
+ }
998
+ }
999
+ async handleRetrieverError(err, runId, _parentRunId) {
1000
+ try {
1001
+ this.logger.debug(`Retriever error: ${err} with ID: ${runId}`);
1002
+ this.handleObservationEnd({
1003
+ runId,
1004
+ attributes: {
1005
+ level: "ERROR",
1006
+ statusMessage: err.toString()
1007
+ }
1008
+ });
1009
+ } catch (e) {
1010
+ this.logger.debug(e instanceof Error ? e.message : String(e));
1011
+ }
1012
+ }
1013
+ async handleToolEnd(output, runId, _parentRunId) {
1014
+ try {
1015
+ this.logger.debug(`Tool end with ID: ${runId}`);
1016
+ this.handleObservationEnd({
1017
+ runId,
1018
+ attributes: { output }
1019
+ });
1020
+ } catch (e) {
1021
+ this.logger.debug(e instanceof Error ? e.message : String(e));
1022
+ }
1023
+ }
1024
+ async handleToolError(err, runId, _parentRunId) {
1025
+ try {
1026
+ this.logger.debug(`Tool error ${err} with ID: ${runId}`);
1027
+ this.handleObservationEnd({
1028
+ runId,
1029
+ attributes: {
1030
+ level: "ERROR",
1031
+ statusMessage: err.toString()
1032
+ }
1033
+ });
1034
+ } catch (e) {
1035
+ this.logger.debug(e instanceof Error ? e.message : String(e));
1036
+ }
1037
+ }
1038
+ async handleLLMEnd(output, runId, _parentRunId) {
1039
+ try {
1040
+ this.logger.debug(`LLM end with ID: ${runId}`);
1041
+ const lastResponse = output.generations[output.generations.length - 1][output.generations[output.generations.length - 1].length - 1];
1042
+ const llmUsage = this.extractUsageMetadata(lastResponse) ?? output.llmOutput?.["tokenUsage"];
1043
+ const modelName = this.extractModelNameFromMetadata(lastResponse);
1044
+ const usageDetails = {
1045
+ input: llmUsage?.input_tokens ?? ("promptTokens" in llmUsage ? llmUsage?.promptTokens : void 0),
1046
+ output: llmUsage?.output_tokens ?? ("completionTokens" in llmUsage ? llmUsage?.completionTokens : void 0),
1047
+ total: llmUsage?.total_tokens ?? ("totalTokens" in llmUsage ? llmUsage?.totalTokens : void 0)
1048
+ };
1049
+ if (llmUsage && "input_token_details" in llmUsage) {
1050
+ for (const [key, val] of Object.entries(
1051
+ llmUsage["input_token_details"] ?? {}
1052
+ )) {
1053
+ usageDetails[`input_${key}`] = val;
1054
+ if ("input" in usageDetails && typeof val === "number") {
1055
+ usageDetails["input"] = Math.max(0, usageDetails["input"] - val);
1056
+ }
1057
+ }
1058
+ }
1059
+ if (llmUsage && "output_token_details" in llmUsage) {
1060
+ for (const [key, val] of Object.entries(
1061
+ llmUsage["output_token_details"] ?? {}
1062
+ )) {
1063
+ usageDetails[`output_${key}`] = val;
1064
+ if ("output" in usageDetails && typeof val === "number") {
1065
+ usageDetails["output"] = Math.max(0, usageDetails["output"] - val);
1066
+ }
1067
+ }
1068
+ }
1069
+ const extractedOutput = "message" in lastResponse ? this.extractChatMessageContent(
1070
+ lastResponse["message"]
1071
+ ) : lastResponse.text;
1072
+ this.handleObservationEnd({
1073
+ runId,
1074
+ attributes: {
1075
+ model: modelName,
1076
+ output: extractedOutput,
1077
+ completionStartTime: runId in this.completionStartTimes ? this.completionStartTimes[runId] : void 0,
1078
+ usageDetails
1079
+ }
1080
+ });
1081
+ if (runId in this.completionStartTimes) {
1082
+ delete this.completionStartTimes[runId];
1083
+ }
1084
+ } catch (e) {
1085
+ this.logger.debug(e instanceof Error ? e.message : String(e));
1086
+ }
1087
+ }
1088
+ async handleLLMError(err, runId, _parentRunId) {
1089
+ try {
1090
+ this.logger.debug(`LLM error ${err} with ID: ${runId}`);
1091
+ this.handleObservationEnd({
1092
+ runId,
1093
+ attributes: {
1094
+ level: "ERROR",
1095
+ statusMessage: err.toString()
1096
+ }
1097
+ });
1098
+ } catch (e) {
1099
+ this.logger.debug(e instanceof Error ? e.message : String(e));
1100
+ }
1101
+ }
1102
+ registerPromptInfo(parentRunId, metadata) {
1103
+ if (metadata && "promptInfo" in metadata && parentRunId) {
1104
+ this.promptToParentRunMap.set(
1105
+ parentRunId,
1106
+ metadata.promptInfo
1107
+ );
1108
+ }
1109
+ }
1110
+ deregisterPromptInfo(runId) {
1111
+ this.promptToParentRunMap.delete(runId);
1112
+ }
1113
+ startAndRegisterObservation(params) {
1114
+ const { runName, runId, parentRunId, attributes, metadata, tags, asType } = params;
1115
+ let parentSpanContext;
1116
+ if (parentRunId) {
1117
+ parentSpanContext = this.runMap.get(parentRunId)?.otelSpan.spanContext();
1118
+ } else if (this.externalParentSpanContext) {
1119
+ parentSpanContext = this.externalParentSpanContext;
1120
+ }
1121
+ let finalRunName = runName;
1122
+ if (!parentRunId && this.adapterName) {
1123
+ finalRunName = `Adapter.${this.adapterName}`;
1124
+ }
1125
+ const observation = startObservation(
1126
+ finalRunName,
1127
+ {
1128
+ version: this.version,
1129
+ metadata: this.joinTagsAndMetaData(tags, metadata),
1130
+ ...attributes
1131
+ },
1132
+ {
1133
+ asType: asType ?? "span",
1134
+ parentSpanContext
1135
+ }
1136
+ );
1137
+ this.runMap.set(runId, observation);
1138
+ return observation;
1139
+ }
1140
+ handleObservationEnd(params) {
1141
+ const { runId, attributes = {} } = params;
1142
+ const observation = this.runMap.get(runId);
1143
+ if (!observation) {
1144
+ this.logger.warn("Observation not found in runMap. Skipping operation.");
1145
+ return;
1146
+ }
1147
+ observation.update(attributes).end();
1148
+ this.last_trace_id = observation.traceId;
1149
+ this.runMap.delete(runId);
1150
+ }
1151
+ joinTagsAndMetaData(tags, metadata1, metadata2) {
1152
+ const finalDict = {};
1153
+ if (tags && tags.length > 0) {
1154
+ finalDict.tags = tags;
1155
+ }
1156
+ if (metadata1) {
1157
+ Object.assign(finalDict, metadata1);
1158
+ }
1159
+ if (metadata2) {
1160
+ Object.assign(finalDict, metadata2);
1161
+ }
1162
+ return this.stripObservabilityKeysFromMetadata(finalDict);
1163
+ }
1164
+ stripObservabilityKeysFromMetadata(metadata) {
1165
+ if (!metadata) {
1166
+ return;
1167
+ }
1168
+ const reservedKeys = ["promptInfo", "userId", "sessionId"];
1169
+ return Object.fromEntries(
1170
+ Object.entries(metadata).filter(([key, _]) => !reservedKeys.includes(key))
1171
+ );
1172
+ }
1173
+ extractUsageMetadata(generation) {
1174
+ try {
1175
+ const usageMetadata = "message" in generation && (import_messages.AIMessage.isInstance(generation["message"]) || import_messages.AIMessageChunk.isInstance(generation["message"])) ? generation["message"].usage_metadata : void 0;
1176
+ return usageMetadata;
1177
+ } catch (err) {
1178
+ this.logger.debug(`Error extracting usage metadata: ${err}`);
1179
+ return;
1180
+ }
1181
+ }
1182
+ extractModelNameFromMetadata(generation) {
1183
+ try {
1184
+ return "message" in generation && (import_messages.AIMessage.isInstance(generation["message"]) || import_messages.AIMessageChunk.isInstance(generation["message"])) ? generation["message"].response_metadata.model_name : void 0;
1185
+ } catch {
1186
+ }
1187
+ }
1188
+ extractChatMessageContent(message) {
1189
+ let response = void 0;
1190
+ if (message.getType() === "human") {
1191
+ response = { content: message.content, role: "user" };
1192
+ } else if (message.getType() === "generic") {
1193
+ response = {
1194
+ content: message.content,
1195
+ role: "human"
1196
+ };
1197
+ } else if (message.getType() === "ai") {
1198
+ response = { content: message.content, role: "assistant" };
1199
+ if ("tool_calls" in message && Array.isArray(message.tool_calls) && (message.tool_calls?.length ?? 0) > 0) {
1200
+ response["tool_calls"] = message["tool_calls"];
1201
+ }
1202
+ if ("additional_kwargs" in message && "tool_calls" in message["additional_kwargs"]) {
1203
+ response["tool_calls"] = message["additional_kwargs"]["tool_calls"];
1204
+ }
1205
+ } else if (message.getType() === "system") {
1206
+ response = { content: message.content, role: "system" };
1207
+ } else if (message.getType() === "function") {
1208
+ response = {
1209
+ content: message.content,
1210
+ additional_kwargs: message.additional_kwargs,
1211
+ role: message.name
1212
+ };
1213
+ } else if (message.getType() === "tool") {
1214
+ response = {
1215
+ content: message.content,
1216
+ additional_kwargs: message.additional_kwargs,
1217
+ role: message.name
1218
+ };
1219
+ } else if (!message.name) {
1220
+ response = { content: message.content };
1221
+ } else {
1222
+ response = {
1223
+ role: message.name,
1224
+ content: message.content
1225
+ };
1226
+ }
1227
+ if ((message.additional_kwargs.function_call || message.additional_kwargs.tool_calls) && response["tool_calls"] === void 0) {
1228
+ return { ...response, additional_kwargs: message.additional_kwargs };
1229
+ }
1230
+ return response;
1231
+ }
1232
+ };
1233
+ // Annotate the CommonJS export names for ESM import in node:
1234
+ 0 && (module.exports = {
1235
+ CallbackHandler
1236
+ });
1237
+ //# sourceMappingURL=langchain.js.map