@cloudbase/agent-observability 1.0.1-alpha.16 → 1.0.1-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.mjs CHANGED
@@ -1,4 +1,78 @@
1
- import "./chunk-NFEGQTCC.mjs";
1
+ import "./chunk-WMJKH4XE.mjs";
2
+
3
+ // src/server/SingleLineConsoleSpanExporter.ts
4
+ var SingleLineConsoleSpanExporter = class {
5
+ /**
6
+ * Export spans as single-line JSON.
7
+ */
8
+ export(spans, resultCallback) {
9
+ try {
10
+ for (const span of spans) {
11
+ const spanDict = this.spanToDict(span);
12
+ const jsonLine = JSON.stringify(spanDict);
13
+ console.log(jsonLine);
14
+ }
15
+ resultCallback({ code: 0 /* SUCCESS */ });
16
+ } catch (error) {
17
+ resultCallback({ code: 1 /* FAILED */, error });
18
+ }
19
+ }
20
+ /**
21
+ * Shutdown the exporter.
22
+ */
23
+ shutdown() {
24
+ return Promise.resolve();
25
+ }
26
+ /**
27
+ * Force flush the exporter.
28
+ */
29
+ forceFlush() {
30
+ return Promise.resolve();
31
+ }
32
+ /**
33
+ * Convert a ReadableSpan to a dictionary for JSON serialization.
34
+ */
35
+ spanToDict(span) {
36
+ const context = span.spanContext();
37
+ const parentId = span.parentSpanId || span.parentSpanContext?.spanId;
38
+ return {
39
+ name: span.name,
40
+ context: {
41
+ trace_id: context.traceId,
42
+ span_id: context.spanId,
43
+ trace_flags: context.traceFlags
44
+ },
45
+ kind: span.kind,
46
+ parent_id: parentId,
47
+ start_time: span.startTime,
48
+ end_time: span.endTime,
49
+ status: {
50
+ status_code: span.status.code,
51
+ description: span.status.message
52
+ },
53
+ attributes: span.attributes,
54
+ events: span.events.map((event) => ({
55
+ name: event.name,
56
+ timestamp: event.time,
57
+ attributes: event.attributes
58
+ })),
59
+ links: span.links.map((link) => ({
60
+ context: {
61
+ trace_id: link.context.traceId,
62
+ span_id: link.context.spanId
63
+ },
64
+ attributes: link.attributes
65
+ })),
66
+ resource: {
67
+ attributes: span.resource.attributes
68
+ }
69
+ };
70
+ }
71
+ };
72
+ function isSingleLineConsoleExporterEnabled() {
73
+ const value = process.env.CONSOLE_EXPORTER_SINGLE_LINE?.toLowerCase() || "true";
74
+ return ["true", "1", "yes", "on"].includes(value);
75
+ }
2
76
 
3
77
  // src/server/setup.ts
4
78
  var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["true", "1", "yes", "on"]);
@@ -54,21 +128,22 @@ async function setupConsoleExporter(config) {
54
128
  const { NodeTracerProvider } = await import("@opentelemetry/sdk-trace-node");
55
129
  const { ConsoleSpanExporter, BatchSpanProcessor } = await import("@opentelemetry/sdk-trace-base");
56
130
  const batchConfig = resolveBatchConfig(config.batch);
131
+ const useSingleLine = isSingleLineConsoleExporterEnabled();
132
+ const exporter = useSingleLine ? new SingleLineConsoleSpanExporter() : new ConsoleSpanExporter();
133
+ const exporterType = useSingleLine ? "single-line" : "multi-line";
57
134
  let provider = trace.getTracerProvider();
58
135
  const isRealProvider = "addSpanProcessor" in provider;
59
136
  if (isRealProvider) {
60
- const exporter = new ConsoleSpanExporter();
61
137
  const processor = new BatchSpanProcessor(exporter, batchConfig);
62
138
  provider.addSpanProcessor(processor);
63
139
  console.info(
64
- `[Observability] Console exporter configured (batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`
140
+ `[Observability] Console exporter configured (${exporterType}, batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`
65
141
  );
66
142
  } else {
67
143
  const resource = resourceFromAttributes({
68
144
  "service.name": process.env.OTEL_SERVICE_NAME || "ag-ui-server",
69
145
  "service.version": "1.0.0"
70
146
  });
71
- const exporter = new ConsoleSpanExporter();
72
147
  const processor = new BatchSpanProcessor(exporter, batchConfig);
73
148
  const tracerProvider = new NodeTracerProvider({
74
149
  resource,
@@ -76,7 +151,7 @@ async function setupConsoleExporter(config) {
76
151
  });
77
152
  tracerProvider.register();
78
153
  console.info(
79
- `[Observability] Console exporter configured (batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`
154
+ `[Observability] Console exporter configured (${exporterType}, batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`
80
155
  );
81
156
  }
82
157
  }
@@ -84,7 +159,7 @@ async function setupOTLPExporter(config) {
84
159
  const { trace } = await import("@opentelemetry/api");
85
160
  const { resourceFromAttributes } = await import("@opentelemetry/resources");
86
161
  const { NodeTracerProvider } = await import("@opentelemetry/sdk-trace-node");
87
- const { OTLPTraceExporter } = await import("./esm-PGEDANAI.mjs");
162
+ const { OTLPTraceExporter } = await import("./esm-M4BB7YBD.mjs");
88
163
  const { BatchSpanProcessor } = await import("@opentelemetry/sdk-trace-base");
89
164
  const batchConfig = resolveBatchConfig(config.batch);
90
165
  let provider = trace.getTracerProvider();
@@ -172,6 +247,8 @@ var ExporterType = {
172
247
  };
173
248
  export {
174
249
  ExporterType,
250
+ SingleLineConsoleSpanExporter,
251
+ isSingleLineConsoleExporterEnabled,
175
252
  setupObservability
176
253
  };
177
254
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server/setup.ts","../src/server/config.ts"],"sourcesContent":["/**\n * Observability setup implementation for AG-Kit Server.\n *\n * Merges configuration from environment variables and parameters,\n * then applies each exporter configuration.\n *\n * @packageDocumentation\n */\n\nimport type {\n BatchConfig,\n ObservabilityConfig,\n ConsoleTraceConfig,\n OTLPTraceConfig,\n CustomTraceConfig,\n} from './config';\n\nexport type {\n BatchConfig,\n ObservabilityConfig,\n ConsoleTraceConfig,\n OTLPTraceConfig,\n CustomTraceConfig,\n} from './config';\n\n/**\n * Environment variable truthy values.\n * Matches Python SDK implementation for consistency.\n */\nconst TRUTHY_ENV_VALUES = new Set(['true', '1', 'yes', 'on']);\n\n/**\n * Merged configuration result.\n * Console config allows merge (param overrides env),\n * while OTLP and custom configs are arrays (additive).\n */\ninterface MergedConfig {\n console?: ConsoleTraceConfig | null;\n otlp: OTLPTraceConfig[];\n custom: CustomTraceConfig[];\n}\n\n/**\n * Default batch configuration.\n */\nconst DEFAULT_BATCH_CONFIG: Required<BatchConfig> = {\n maxExportBatchSize: 100,\n scheduledDelayMillis: 5000,\n maxQueueSize: 2048,\n exportTimeoutMillis: 30000,\n};\n\n/**\n * Merge environment variable and parameter configurations.\n *\n * - AUTO_TRACES_STDOUT env adds a console config\n * - Parameter configs override/extend env configs\n */\nfunction mergeConfigs(paramConfigs: ObservabilityConfig[]): MergedConfig {\n const result: MergedConfig = {\n console: null,\n otlp: [],\n custom: [],\n };\n\n // 1. Check AUTO_TRACES_STDOUT env\n const autoTracesStdout = process.env.AUTO_TRACES_STDOUT?.toLowerCase() || '';\n if (TRUTHY_ENV_VALUES.has(autoTracesStdout)) {\n result.console = { type: 'console' };\n console.debug(\n `[Observability] AUTO_TRACES_STDOUT=${autoTracesStdout}, console exporter enabled`\n );\n }\n\n // 2. Process parameter configs\n for (const config of paramConfigs) {\n switch (config.type) {\n case 'console':\n // Parameter overrides env (merge batch config)\n result.console = { ...result.console, ...config };\n break;\n\n case 'otlp':\n result.otlp.push(config);\n break;\n\n case 'custom':\n result.custom.push(config);\n break;\n }\n }\n\n return result;\n}\n\n/**\n * Apply batch configuration with defaults.\n */\nfunction resolveBatchConfig(batch?: BatchConfig): Required<BatchConfig> {\n return { ...DEFAULT_BATCH_CONFIG, ...batch };\n}\n\n/**\n * Safe wrapper for exporter setup functions.\n * Ensures individual exporter failures don't crash the entire setup.\n */\nasync function safeSetup(\n name: string,\n setupFn: () => Promise<void>\n): Promise<void> {\n try {\n await setupFn();\n } catch (error) {\n console.warn(\n `[Observability] ${name} setup failed (non-fatal): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n // Don't rethrow - allow other exporters to continue\n }\n}\n\n/**\n * Setup console exporter.\n */\nasync function setupConsoleExporter(config: ConsoleTraceConfig): Promise<void> {\n const { trace } = await import('@opentelemetry/api');\n const { resourceFromAttributes } = await import('@opentelemetry/resources');\n const { NodeTracerProvider } = await import('@opentelemetry/sdk-trace-node');\n const { ConsoleSpanExporter, BatchSpanProcessor } = await import(\n '@opentelemetry/sdk-trace-base'\n );\n\n const batchConfig = resolveBatchConfig(config.batch);\n\n // Check if a real TracerProvider already exists\n let provider = trace.getTracerProvider();\n const isRealProvider = 'addSpanProcessor' in provider;\n\n if (isRealProvider) {\n // Add processor to existing provider\n const exporter = new ConsoleSpanExporter();\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n (provider as any).addSpanProcessor(processor);\n\n console.info(\n `[Observability] Console exporter configured (batch=${batchConfig.maxExportBatchSize}, ` +\n `delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n } else {\n // Create new provider with console exporter\n const resource = resourceFromAttributes({\n 'service.name': process.env.OTEL_SERVICE_NAME || 'ag-ui-server',\n 'service.version': '1.0.0',\n });\n\n const exporter = new ConsoleSpanExporter();\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [processor],\n });\n\n tracerProvider.register();\n\n console.info(\n `[Observability] Console exporter configured (batch=${batchConfig.maxExportBatchSize}, ` +\n `delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n }\n}\n\n/**\n * Setup OTLP exporter.\n */\nasync function setupOTLPExporter(config: OTLPTraceConfig): Promise<void> {\n const { trace } = await import('@opentelemetry/api');\n const { resourceFromAttributes } = await import('@opentelemetry/resources');\n const { NodeTracerProvider } = await import('@opentelemetry/sdk-trace-node');\n const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http');\n const { BatchSpanProcessor } = await import('@opentelemetry/sdk-trace-base');\n\n const batchConfig = resolveBatchConfig(config.batch);\n\n // Check if a real TracerProvider already exists\n let provider = trace.getTracerProvider();\n const isRealProvider = 'addSpanProcessor' in provider;\n\n if (isRealProvider) {\n // Add processor to existing provider\n const exporter = new OTLPTraceExporter({\n url: config.url,\n headers: config.headers,\n timeoutMillis: config.timeout ?? 10000,\n });\n\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n (provider as any).addSpanProcessor(processor);\n\n console.info(\n `[Observability] OTLP exporter configured (url=${config.url}, ` +\n `batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n } else {\n // Create new provider with OTLP exporter\n const resource = resourceFromAttributes({\n 'service.name': process.env.OTEL_SERVICE_NAME || 'ag-ui-server',\n 'service.version': '1.0.0',\n });\n\n const exporter = new OTLPTraceExporter({\n url: config.url,\n headers: config.headers,\n timeoutMillis: config.timeout ?? 10000,\n });\n\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [processor],\n });\n\n tracerProvider.register();\n\n console.info(\n `[Observability] OTLP exporter configured (url=${config.url}, ` +\n `batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n }\n}\n\n/**\n * Setup custom exporter.\n */\nasync function setupCustomExporter(config: CustomTraceConfig): Promise<void> {\n await config.setup();\n console.info(`[Observability] Custom exporter setup completed`);\n}\n\n/**\n * Setup observability from merged configuration.\n *\n * @internal\n */\nasync function applyMergedConfigs(merged: MergedConfig): Promise<void> {\n const setupTasks: Promise<void>[] = [];\n\n // Apply console (non-blocking)\n if (merged.console) {\n setupTasks.push(safeSetup('Console exporter', () => setupConsoleExporter(merged.console!)));\n }\n\n // Apply otlp (non-blocking)\n for (const otlp of merged.otlp) {\n setupTasks.push(safeSetup(`OTLP exporter (${otlp.url})`, () => setupOTLPExporter(otlp)));\n }\n\n // Apply custom (non-blocking)\n for (const custom of merged.custom) {\n setupTasks.push(safeSetup('Custom exporter', () => setupCustomExporter(custom)));\n }\n\n // Wait for all exporters to complete (or fail gracefully)\n await Promise.all(setupTasks);\n\n if (merged.console || merged.otlp.length > 0 || merged.custom.length > 0) {\n console.info(`[Observability] Setup completed`);\n }\n}\n\n/**\n * Setup observability from configuration.\n *\n * Merges environment variable (AUTO_TRACES_STDOUT) with parameter configs,\n * then applies each exporter configuration.\n *\n * Environment variables act as presets, parameter configs override or extend.\n *\n * Returns a promise that resolves when setup is complete. This allows callers\n * to await initialization before proceeding, eliminating race conditions.\n *\n * The returned promise is cached - subsequent calls return the same promise\n * to avoid duplicate initialization.\n *\n * @param configs - Observability configuration(s)\n *\n * @example\n * ```typescript\n * // Console only (from env)\n * await setupObservability();\n *\n * // Console + OTLP\n * await setupObservability([\n * { type: 'console' },\n * { type: 'otlp', url: 'http://localhost:4318/v1/traces' }\n * ]);\n *\n * // OTLP only\n * await setupObservability({\n * type: 'otlp',\n * url: 'https://cloud.langfuse.com/api/public/otlp/v1/traces',\n * headers: { 'Authorization': 'Basic xxx' }\n * });\n * ```\n *\n * @public\n */\n\nlet setupPromise: Promise<void> | null = null;\n\nexport async function setupObservability(\n configs?: ObservabilityConfig | ObservabilityConfig[]\n): Promise<void> {\n // Return cached promise if setup is in progress or completed\n if (setupPromise) {\n return setupPromise;\n }\n\n // Create the setup promise\n setupPromise = (async () => {\n try {\n // Normalize to array\n const configsArray = configs\n ? Array.isArray(configs)\n ? configs\n : [configs]\n : [];\n\n // Merge env and parameter configs\n const merged = mergeConfigs(configsArray);\n\n // Apply merged configs\n await applyMergedConfigs(merged);\n } catch (error) {\n // Reset promise on error to allow retry\n setupPromise = null;\n // Silent failure - observability should never block main flow\n console.warn(\n `[Observability] Setup failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n })();\n\n return setupPromise;\n}\n","/**\n * Observability configuration types for AG-Kit Server.\n *\n * Provides a unified configuration interface for trace exporters:\n * - Console: Development/debugging output\n * - OTLP: Production export to Langfuse, Jaeger, etc.\n * - Custom: User-defined setup logic\n *\n * @packageDocumentation\n */\n\n/**\n * Trace exporter type constants.\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * { type: ExporterType.Console }\n * { type: ExporterType.OTLP }\n * { type: ExporterType.Custom }\n * ```\n *\n * @public\n */\nexport const ExporterType = {\n /** Console exporter - outputs traces to stdout */\n Console: 'console',\n /** OTLP exporter - sends traces to OTLP-compatible backend */\n OTLP: 'otlp',\n /** Custom exporter - user-defined setup logic */\n Custom: 'custom',\n} as const;\n\n/**\n * Trace exporter type literal values.\n *\n * @public\n */\nexport type ExporterType = typeof ExporterType[keyof typeof ExporterType];\n\n/**\n * Batch processing configuration for span exporters.\n *\n * Used by BatchSpanProcessor to optimize performance:\n * - Collects spans in memory and exports them in batches\n * - Reduces I/O operations (console) or network requests (OTLP)\n * - Recommended for production environments\n *\n * @public\n */\nexport interface BatchConfig {\n /** Maximum number of spans per export batch (default: 100) */\n maxExportBatchSize?: number;\n /** Maximum delay in milliseconds before exporting (default: 5000) */\n scheduledDelayMillis?: number;\n /** Maximum queue size (default: 2048) */\n maxQueueSize?: number;\n /** Export timeout in milliseconds (default: 30000) */\n exportTimeoutMillis?: number;\n}\n\n/**\n * Console trace exporter configuration.\n *\n * Outputs traces to stdout in JSON format using ConsoleSpanExporter.\n * Useful for development and debugging.\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * { type: ExporterType.Console }\n * { type: ExporterType.Console, batch: { maxExportBatchSize: 200 } }\n * ```\n *\n * @public\n */\nexport interface ConsoleTraceConfig {\n /** Discriminator for console exporter */\n type: typeof ExporterType.Console;\n /** Optional batch processing configuration */\n batch?: BatchConfig;\n}\n\n/**\n * OTLP trace exporter configuration.\n *\n * Exports traces via OTLP protocol to any compatible backend:\n * - Langfuse: https://cloud.langfuse.com/api/public/otlp/v1/traces\n * - Jaeger: http://localhost:4318/v1/traces\n * - OTel Collector: custom endpoint\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * {\n * type: ExporterType.OTLP,\n * url: 'https://cloud.langfuse.com/api/public/otlp/v1/traces',\n * headers: {\n * 'Authorization': 'Basic ' + btoa('pk-lf-xxx:sk-lf-xxx')\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface OTLPTraceConfig {\n /** Discriminator for OTLP exporter */\n type: typeof ExporterType.OTLP;\n /** OTLP endpoint URL (http/https) */\n url: string;\n /** Optional HTTP headers for authentication */\n headers?: Record<string, string>;\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Optional batch processing configuration */\n batch?: BatchConfig;\n}\n\n/**\n * Custom trace exporter configuration.\n *\n * Allows users to provide custom trace setup logic.\n * Useful for integrations not covered by console/otlp.\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * {\n * type: ExporterType.Custom,\n * setup: async () => {\n * const exporter = new MyCustomExporter();\n * const provider = new BasicTracerProvider();\n * provider.addSpanProcessor(new SimpleSpanProcessor(exporter));\n * provider.register();\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface CustomTraceConfig {\n /** Discriminator for custom setup */\n type: typeof ExporterType.Custom;\n /** User-defined setup function */\n setup: () => Promise<void> | void;\n}\n\n/**\n * Union type of all supported trace exporter configurations.\n *\n * @public\n */\nexport type ObservabilityConfig =\n | ConsoleTraceConfig\n | OTLPTraceConfig\n | CustomTraceConfig;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/server/SingleLineConsoleSpanExporter.ts","../src/server/setup.ts","../src/server/config.ts"],"sourcesContent":["/**\n * Custom console exporter that outputs single-line JSON.\n *\n * This exporter outputs spans as single-line JSON for easier parsing\n * with line-based tools (grep, jq, etc.).\n *\n * To switch back to standard multi-line output, use ConsoleSpanExporter instead.\n *\n * @example\n * ```typescript\n * // Single-line (current default)\n * const exporter = new SingleLineConsoleSpanExporter();\n *\n * // Multi-line (standard OTel)\n * import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';\n * const exporter = new ConsoleSpanExporter();\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { SpanExporter, ReadableSpan } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Export result codes.\n */\nexport enum ExportResultCode {\n SUCCESS = 0,\n FAILED = 1,\n}\n\n/**\n * Export result interface.\n */\nexport interface ExportResult {\n code: ExportResultCode;\n error?: Error;\n}\n\n/**\n * Custom console exporter that outputs single-line JSON.\n *\n * This exporter outputs spans as single-line JSON for easier parsing\n * with line-based tools (grep, jq, etc.).\n */\nexport class SingleLineConsoleSpanExporter implements SpanExporter {\n /**\n * Export spans as single-line JSON.\n */\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n try {\n for (const span of spans) {\n const spanDict = this.spanToDict(span);\n // Single-line JSON output\n const jsonLine = JSON.stringify(spanDict);\n console.log(jsonLine);\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n } catch (error) {\n resultCallback({ code: ExportResultCode.FAILED, error: error as Error });\n }\n }\n\n /**\n * Shutdown the exporter.\n */\n shutdown(): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Force flush the exporter.\n */\n forceFlush?(): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Convert a ReadableSpan to a dictionary for JSON serialization.\n */\n private spanToDict(span: ReadableSpan): Record<string, unknown> {\n const context = span.spanContext();\n\n // Get parent span ID from parentSpanContext if available\n // Some versions use parentSpanId directly, others use parentSpanContext.spanId\n const parentId = (span as any).parentSpanId || span.parentSpanContext?.spanId;\n\n return {\n name: span.name,\n context: {\n trace_id: context.traceId,\n span_id: context.spanId,\n trace_flags: context.traceFlags,\n },\n kind: span.kind,\n parent_id: parentId,\n start_time: span.startTime,\n end_time: span.endTime,\n status: {\n status_code: span.status.code,\n description: span.status.message,\n },\n attributes: span.attributes,\n events: span.events.map((event) => ({\n name: event.name,\n timestamp: event.time,\n attributes: event.attributes,\n })),\n links: span.links.map((link) => ({\n context: {\n trace_id: link.context.traceId,\n span_id: link.context.spanId,\n },\n attributes: link.attributes,\n })),\n resource: {\n attributes: span.resource.attributes,\n },\n };\n }\n}\n\n/**\n * Check if single-line console exporter should be used.\n *\n * Set CONSOLE_EXPORTER_SINGLE_LINE=false to use standard multi-line output.\n */\nexport function isSingleLineConsoleExporterEnabled(): boolean {\n const value = process.env.CONSOLE_EXPORTER_SINGLE_LINE?.toLowerCase() || 'true';\n return ['true', '1', 'yes', 'on'].includes(value);\n}\n","/**\n * Observability setup implementation for AG-Kit Server.\n *\n * Merges configuration from environment variables and parameters,\n * then applies each exporter configuration.\n *\n * @packageDocumentation\n */\n\nimport type {\n BatchConfig,\n ObservabilityConfig,\n ConsoleTraceConfig,\n OTLPTraceConfig,\n CustomTraceConfig,\n} from './config';\nimport {\n SingleLineConsoleSpanExporter,\n isSingleLineConsoleExporterEnabled,\n} from './SingleLineConsoleSpanExporter';\n\nexport type {\n BatchConfig,\n ObservabilityConfig,\n ConsoleTraceConfig,\n OTLPTraceConfig,\n CustomTraceConfig,\n} from './config';\nexport { SingleLineConsoleSpanExporter } from './SingleLineConsoleSpanExporter';\n\n/**\n * Environment variable truthy values.\n * Matches Python SDK implementation for consistency.\n */\nconst TRUTHY_ENV_VALUES = new Set(['true', '1', 'yes', 'on']);\n\n/**\n * Merged configuration result.\n * Console config allows merge (param overrides env),\n * while OTLP and custom configs are arrays (additive).\n */\ninterface MergedConfig {\n console?: ConsoleTraceConfig | null;\n otlp: OTLPTraceConfig[];\n custom: CustomTraceConfig[];\n}\n\n/**\n * Default batch configuration.\n */\nconst DEFAULT_BATCH_CONFIG: Required<BatchConfig> = {\n maxExportBatchSize: 100,\n scheduledDelayMillis: 5000,\n maxQueueSize: 2048,\n exportTimeoutMillis: 30000,\n};\n\n/**\n * Merge environment variable and parameter configurations.\n *\n * - AUTO_TRACES_STDOUT env adds a console config\n * - Parameter configs override/extend env configs\n */\nfunction mergeConfigs(paramConfigs: ObservabilityConfig[]): MergedConfig {\n const result: MergedConfig = {\n console: null,\n otlp: [],\n custom: [],\n };\n\n // 1. Check AUTO_TRACES_STDOUT env\n const autoTracesStdout = process.env.AUTO_TRACES_STDOUT?.toLowerCase() || '';\n if (TRUTHY_ENV_VALUES.has(autoTracesStdout)) {\n result.console = { type: 'console' };\n console.debug(\n `[Observability] AUTO_TRACES_STDOUT=${autoTracesStdout}, console exporter enabled`\n );\n }\n\n // 2. Process parameter configs\n for (const config of paramConfigs) {\n switch (config.type) {\n case 'console':\n // Parameter overrides env (merge batch config)\n result.console = { ...result.console, ...config };\n break;\n\n case 'otlp':\n result.otlp.push(config);\n break;\n\n case 'custom':\n result.custom.push(config);\n break;\n }\n }\n\n return result;\n}\n\n/**\n * Apply batch configuration with defaults.\n */\nfunction resolveBatchConfig(batch?: BatchConfig): Required<BatchConfig> {\n return { ...DEFAULT_BATCH_CONFIG, ...batch };\n}\n\n/**\n * Safe wrapper for exporter setup functions.\n * Ensures individual exporter failures don't crash the entire setup.\n */\nasync function safeSetup(\n name: string,\n setupFn: () => Promise<void>\n): Promise<void> {\n try {\n await setupFn();\n } catch (error) {\n console.warn(\n `[Observability] ${name} setup failed (non-fatal): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n // Don't rethrow - allow other exporters to continue\n }\n}\n\n/**\n * Setup console exporter.\n *\n * Uses SingleLineConsoleSpanExporter by default for easier parsing with line-based tools.\n * Set CONSOLE_EXPORTER_SINGLE_LINE=false to use standard multi-line output.\n */\nasync function setupConsoleExporter(config: ConsoleTraceConfig): Promise<void> {\n const { trace } = await import('@opentelemetry/api');\n const { resourceFromAttributes } = await import('@opentelemetry/resources');\n const { NodeTracerProvider } = await import('@opentelemetry/sdk-trace-node');\n const { ConsoleSpanExporter, BatchSpanProcessor } = await import(\n '@opentelemetry/sdk-trace-base'\n );\n\n const batchConfig = resolveBatchConfig(config.batch);\n\n // Choose exporter type based on CONSOLE_EXPORTER_SINGLE_LINE env var\n // Single-line: easier for parsing with line-based tools (grep, jq, etc.)\n // Multi-line: more human-readable for debugging\n const useSingleLine = isSingleLineConsoleExporterEnabled();\n const exporter = useSingleLine\n ? new SingleLineConsoleSpanExporter()\n : new ConsoleSpanExporter();\n const exporterType = useSingleLine ? 'single-line' : 'multi-line';\n\n // Check if a real TracerProvider already exists\n let provider = trace.getTracerProvider();\n const isRealProvider = 'addSpanProcessor' in provider;\n\n if (isRealProvider) {\n // Add processor to existing provider\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n (provider as any).addSpanProcessor(processor);\n\n console.info(\n `[Observability] Console exporter configured (${exporterType}, batch=${batchConfig.maxExportBatchSize}, ` +\n `delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n } else {\n // Create new provider with console exporter\n const resource = resourceFromAttributes({\n 'service.name': process.env.OTEL_SERVICE_NAME || 'ag-ui-server',\n 'service.version': '1.0.0',\n });\n\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [processor],\n });\n\n tracerProvider.register();\n\n console.info(\n `[Observability] Console exporter configured (${exporterType}, batch=${batchConfig.maxExportBatchSize}, ` +\n `delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n }\n}\n\n/**\n * Setup OTLP exporter.\n */\nasync function setupOTLPExporter(config: OTLPTraceConfig): Promise<void> {\n const { trace } = await import('@opentelemetry/api');\n const { resourceFromAttributes } = await import('@opentelemetry/resources');\n const { NodeTracerProvider } = await import('@opentelemetry/sdk-trace-node');\n const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http');\n const { BatchSpanProcessor } = await import('@opentelemetry/sdk-trace-base');\n\n const batchConfig = resolveBatchConfig(config.batch);\n\n // Check if a real TracerProvider already exists\n let provider = trace.getTracerProvider();\n const isRealProvider = 'addSpanProcessor' in provider;\n\n if (isRealProvider) {\n // Add processor to existing provider\n const exporter = new OTLPTraceExporter({\n url: config.url,\n headers: config.headers,\n timeoutMillis: config.timeout ?? 10000,\n });\n\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n (provider as any).addSpanProcessor(processor);\n\n console.info(\n `[Observability] OTLP exporter configured (url=${config.url}, ` +\n `batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n } else {\n // Create new provider with OTLP exporter\n const resource = resourceFromAttributes({\n 'service.name': process.env.OTEL_SERVICE_NAME || 'ag-ui-server',\n 'service.version': '1.0.0',\n });\n\n const exporter = new OTLPTraceExporter({\n url: config.url,\n headers: config.headers,\n timeoutMillis: config.timeout ?? 10000,\n });\n\n const processor = new BatchSpanProcessor(exporter, batchConfig);\n\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [processor],\n });\n\n tracerProvider.register();\n\n console.info(\n `[Observability] OTLP exporter configured (url=${config.url}, ` +\n `batch=${batchConfig.maxExportBatchSize}, delay=${batchConfig.scheduledDelayMillis}ms)`\n );\n }\n}\n\n/**\n * Setup custom exporter.\n */\nasync function setupCustomExporter(config: CustomTraceConfig): Promise<void> {\n await config.setup();\n console.info(`[Observability] Custom exporter setup completed`);\n}\n\n/**\n * Setup observability from merged configuration.\n *\n * @internal\n */\nasync function applyMergedConfigs(merged: MergedConfig): Promise<void> {\n const setupTasks: Promise<void>[] = [];\n\n // Apply console (non-blocking)\n if (merged.console) {\n setupTasks.push(safeSetup('Console exporter', () => setupConsoleExporter(merged.console!)));\n }\n\n // Apply otlp (non-blocking)\n for (const otlp of merged.otlp) {\n setupTasks.push(safeSetup(`OTLP exporter (${otlp.url})`, () => setupOTLPExporter(otlp)));\n }\n\n // Apply custom (non-blocking)\n for (const custom of merged.custom) {\n setupTasks.push(safeSetup('Custom exporter', () => setupCustomExporter(custom)));\n }\n\n // Wait for all exporters to complete (or fail gracefully)\n await Promise.all(setupTasks);\n\n if (merged.console || merged.otlp.length > 0 || merged.custom.length > 0) {\n console.info(`[Observability] Setup completed`);\n }\n}\n\n/**\n * Setup observability from configuration.\n *\n * Merges environment variable (AUTO_TRACES_STDOUT) with parameter configs,\n * then applies each exporter configuration.\n *\n * Environment variables act as presets, parameter configs override or extend.\n *\n * Returns a promise that resolves when setup is complete. This allows callers\n * to await initialization before proceeding, eliminating race conditions.\n *\n * The returned promise is cached - subsequent calls return the same promise\n * to avoid duplicate initialization.\n *\n * @param configs - Observability configuration(s)\n *\n * @example\n * ```typescript\n * // Console only (from env)\n * await setupObservability();\n *\n * // Console + OTLP\n * await setupObservability([\n * { type: 'console' },\n * { type: 'otlp', url: 'http://localhost:4318/v1/traces' }\n * ]);\n *\n * // OTLP only\n * await setupObservability({\n * type: 'otlp',\n * url: 'https://cloud.langfuse.com/api/public/otlp/v1/traces',\n * headers: { 'Authorization': 'Basic xxx' }\n * });\n * ```\n *\n * @public\n */\n\nlet setupPromise: Promise<void> | null = null;\n\nexport async function setupObservability(\n configs?: ObservabilityConfig | ObservabilityConfig[]\n): Promise<void> {\n // Return cached promise if setup is in progress or completed\n if (setupPromise) {\n return setupPromise;\n }\n\n // Create the setup promise\n setupPromise = (async () => {\n try {\n // Normalize to array\n const configsArray = configs\n ? Array.isArray(configs)\n ? configs\n : [configs]\n : [];\n\n // Merge env and parameter configs\n const merged = mergeConfigs(configsArray);\n\n // Apply merged configs\n await applyMergedConfigs(merged);\n } catch (error) {\n // Reset promise on error to allow retry\n setupPromise = null;\n // Silent failure - observability should never block main flow\n console.warn(\n `[Observability] Setup failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n })();\n\n return setupPromise;\n}\n","/**\n * Observability configuration types for AG-Kit Server.\n *\n * Provides a unified configuration interface for trace exporters:\n * - Console: Development/debugging output\n * - OTLP: Production export to Langfuse, Jaeger, etc.\n * - Custom: User-defined setup logic\n *\n * @packageDocumentation\n */\n\n/**\n * Trace exporter type constants.\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * { type: ExporterType.Console }\n * { type: ExporterType.OTLP }\n * { type: ExporterType.Custom }\n * ```\n *\n * @public\n */\nexport const ExporterType = {\n /** Console exporter - outputs traces to stdout */\n Console: 'console',\n /** OTLP exporter - sends traces to OTLP-compatible backend */\n OTLP: 'otlp',\n /** Custom exporter - user-defined setup logic */\n Custom: 'custom',\n} as const;\n\n/**\n * Trace exporter type literal values.\n *\n * @public\n */\nexport type ExporterType = typeof ExporterType[keyof typeof ExporterType];\n\n/**\n * Batch processing configuration for span exporters.\n *\n * Used by BatchSpanProcessor to optimize performance:\n * - Collects spans in memory and exports them in batches\n * - Reduces I/O operations (console) or network requests (OTLP)\n * - Recommended for production environments\n *\n * @public\n */\nexport interface BatchConfig {\n /** Maximum number of spans per export batch (default: 100) */\n maxExportBatchSize?: number;\n /** Maximum delay in milliseconds before exporting (default: 5000) */\n scheduledDelayMillis?: number;\n /** Maximum queue size (default: 2048) */\n maxQueueSize?: number;\n /** Export timeout in milliseconds (default: 30000) */\n exportTimeoutMillis?: number;\n}\n\n/**\n * Console trace exporter configuration.\n *\n * Outputs traces to stdout in JSON format using ConsoleSpanExporter.\n * Useful for development and debugging.\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * { type: ExporterType.Console }\n * { type: ExporterType.Console, batch: { maxExportBatchSize: 200 } }\n * ```\n *\n * @public\n */\nexport interface ConsoleTraceConfig {\n /** Discriminator for console exporter */\n type: typeof ExporterType.Console;\n /** Optional batch processing configuration */\n batch?: BatchConfig;\n}\n\n/**\n * OTLP trace exporter configuration.\n *\n * Exports traces via OTLP protocol to any compatible backend:\n * - Langfuse: https://cloud.langfuse.com/api/public/otlp/v1/traces\n * - Jaeger: http://localhost:4318/v1/traces\n * - OTel Collector: custom endpoint\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * {\n * type: ExporterType.OTLP,\n * url: 'https://cloud.langfuse.com/api/public/otlp/v1/traces',\n * headers: {\n * 'Authorization': 'Basic ' + btoa('pk-lf-xxx:sk-lf-xxx')\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface OTLPTraceConfig {\n /** Discriminator for OTLP exporter */\n type: typeof ExporterType.OTLP;\n /** OTLP endpoint URL (http/https) */\n url: string;\n /** Optional HTTP headers for authentication */\n headers?: Record<string, string>;\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Optional batch processing configuration */\n batch?: BatchConfig;\n}\n\n/**\n * Custom trace exporter configuration.\n *\n * Allows users to provide custom trace setup logic.\n * Useful for integrations not covered by console/otlp.\n *\n * @example\n * ```typescript\n * import { ExporterType } from '@cloudbase/agent-observability/server';\n *\n * {\n * type: ExporterType.Custom,\n * setup: async () => {\n * const exporter = new MyCustomExporter();\n * const provider = new BasicTracerProvider();\n * provider.addSpanProcessor(new SimpleSpanProcessor(exporter));\n * provider.register();\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface CustomTraceConfig {\n /** Discriminator for custom setup */\n type: typeof ExporterType.Custom;\n /** User-defined setup function */\n setup: () => Promise<void> | void;\n}\n\n/**\n * Union type of all supported trace exporter configurations.\n *\n * @public\n */\nexport type ObservabilityConfig =\n | ConsoleTraceConfig\n | OTLPTraceConfig\n | CustomTraceConfig;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/agent-observability",
3
- "version": "1.0.1-alpha.16",
3
+ "version": "1.0.1-alpha.18",
4
4
  "description": "OpenInference-compatible observability for AG-Kit",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -65,7 +65,7 @@
65
65
  "@arizeai/openinference-semantic-conventions": "^2.1.7",
66
66
  "@opentelemetry/api": "^1.9.0",
67
67
  "@opentelemetry/semantic-conventions": "^1.39.0",
68
- "@cloudbase/agent-shared": "^1.0.1-alpha.16"
68
+ "@cloudbase/agent-shared": "^1.0.1-alpha.18"
69
69
  },
70
70
  "optionalDependencies": {
71
71
  "@opentelemetry/exporter-trace-otlp-http": "^0.210.0",
@@ -1,6 +1,6 @@
1
- import { OBSERVABILITY_TRACER_NAME, OtelSpanAttributes } from "./constants.js";
1
+ import { OBSERVABILITY_TRACER_NAME, OtelSpanAttributes } from "./constants";
2
2
  import { SemanticConventions } from "@arizeai/openinference-semantic-conventions";
3
- import { ObservationAttributes, TraceAttributes, ObservationType } from "../types.js";
3
+ import { ObservationAttributes, TraceAttributes, ObservationType, LLMMessage, Document, ToolCall } from "../types";
4
4
  import { type Attributes } from "@opentelemetry/api";
5
5
 
6
6
  /**
@@ -111,6 +111,20 @@ export function createObservationAttributes(
111
111
  if (model) {
112
112
  otelAttributes[SemanticConventions.LLM_MODEL_NAME] = model;
113
113
  }
114
+ // Extract system and provider safely
115
+ const system = (attributes as Record<string, unknown>)?.system;
116
+ const provider = (attributes as Record<string, unknown>)?.provider;
117
+ const inputMessages = (attributes as Record<string, unknown>)?.inputMessages;
118
+ const outputMessages = (attributes as Record<string, unknown>)?.outputMessages;
119
+ const inputMimeType = (attributes as Record<string, unknown>)?.inputMimeType;
120
+ const outputMimeType = (attributes as Record<string, unknown>)?.outputMimeType;
121
+
122
+ if (system !== undefined) {
123
+ otelAttributes[SemanticConventions.LLM_SYSTEM] = String(system);
124
+ }
125
+ if (provider !== undefined) {
126
+ otelAttributes[SemanticConventions.LLM_PROVIDER] = String(provider);
127
+ }
114
128
  if (modelParameters) {
115
129
  otelAttributes[SemanticConventions.LLM_INVOCATION_PARAMETERS] =
116
130
  _serialize(modelParameters);
@@ -143,6 +157,22 @@ export function createObservationAttributes(
143
157
  otelAttributes[OtelSpanAttributes.LLM_COMPLETION_START_TIME] =
144
158
  _serialize(completionStartTime);
145
159
  }
160
+ // Flatten LLM messages
161
+ if (inputMessages !== undefined && Array.isArray(inputMessages)) {
162
+ const messageAttrs = _flattenLLMMessages(inputMessages as LLMMessage[], "llm.input_messages");
163
+ Object.assign(otelAttributes, messageAttrs);
164
+ }
165
+ if (outputMessages !== undefined && Array.isArray(outputMessages)) {
166
+ const messageAttrs = _flattenLLMMessages(outputMessages as LLMMessage[], "llm.output_messages");
167
+ Object.assign(otelAttributes, messageAttrs);
168
+ }
169
+ // Add MIME types
170
+ if (inputMimeType !== undefined) {
171
+ otelAttributes[SemanticConventions.INPUT_MIME_TYPE] = String(inputMimeType);
172
+ }
173
+ if (outputMimeType !== undefined) {
174
+ otelAttributes[SemanticConventions.OUTPUT_MIME_TYPE] = String(outputMimeType);
175
+ }
146
176
  }
147
177
 
148
178
  // Embedding-specific attributes
@@ -156,6 +186,51 @@ export function createObservationAttributes(
156
186
  }
157
187
  }
158
188
 
189
+ // Tool-specific attributes
190
+ if (type === "tool") {
191
+ const toolName = (attributes as Record<string, unknown>)?.toolName ?? (attributes as Record<string, unknown>)?.tool_name;
192
+ const toolDescription = (attributes as Record<string, unknown>)?.toolDescription;
193
+ const toolParameters = (attributes as Record<string, unknown>)?.toolParameters;
194
+ const toolCall = (attributes as Record<string, unknown>)?.toolCall;
195
+
196
+ if (toolName !== undefined) {
197
+ otelAttributes[SemanticConventions.TOOL_NAME] = String(toolName);
198
+ }
199
+ if (toolDescription !== undefined) {
200
+ otelAttributes[SemanticConventions.TOOL_DESCRIPTION] = String(toolDescription);
201
+ }
202
+ if (toolParameters !== undefined) {
203
+ otelAttributes[SemanticConventions.TOOL_PARAMETERS] = _serialize(toolParameters);
204
+ }
205
+ // Flatten tool call if present
206
+ if (toolCall !== undefined && typeof toolCall === "object") {
207
+ const toolCallAttrs = _flattenToolCall(toolCall as ToolCall);
208
+ Object.assign(otelAttributes, toolCallAttrs);
209
+ }
210
+ }
211
+
212
+ // Agent-specific attributes
213
+ if (type === "agent") {
214
+ const agentName = (attributes as Record<string, unknown>)?.agentName;
215
+ if (agentName !== undefined) {
216
+ otelAttributes[SemanticConventions.AGENT_NAME] = String(agentName);
217
+ }
218
+ }
219
+
220
+ // Retriever-specific attributes
221
+ if (type === "retriever") {
222
+ const documents = (attributes as Record<string, unknown>)?.documents;
223
+ const query = (attributes as Record<string, unknown>)?.query;
224
+
225
+ if (documents !== undefined && Array.isArray(documents)) {
226
+ const docAttrs = _flattenDocuments(documents as Document[]);
227
+ Object.assign(otelAttributes, docAttrs);
228
+ }
229
+ if (query !== undefined) {
230
+ otelAttributes["retriever.query"] = String(query);
231
+ }
232
+ }
233
+
159
234
  // Add metadata (use OpenInference metadata convention)
160
235
  const metadataAttrs = _flattenAndSerializeMetadata(
161
236
  metadata,
@@ -170,6 +245,14 @@ export function createObservationAttributes(
170
245
  );
171
246
  Object.assign(otelAttributes, obsetvabilityMetadataAttrs);
172
247
 
248
+ // Pass through any additional custom attributes (e.g., agui.thread_id, agui.run_id)
249
+ // Only pass through attributes that haven't been set yet to avoid overwriting internal ones
250
+ for (const [key, value] of Object.entries(attributes)) {
251
+ if (!(key in otelAttributes) && value !== undefined && value !== null) {
252
+ otelAttributes[key] = typeof value === 'string' ? value : _serialize(value);
253
+ }
254
+ }
255
+
173
256
  // Filter out null/undefined values
174
257
  return Object.fromEntries(
175
258
  Object.entries(otelAttributes).filter(([_, v]) => v != null),
@@ -231,3 +314,161 @@ function _flattenAndSerializeMetadata(
231
314
 
232
315
  return metadataAttributes;
233
316
  }
317
+
318
+ /**
319
+ * Flattens LLM messages into OpenTelemetry attributes.
320
+ *
321
+ * Follows OpenInference convention:
322
+ * - llm.input_messages.{i}.message.role
323
+ * - llm.input_messages.{i}.message.content
324
+ * - llm.input_messages.{i}.message.tool_calls
325
+ *
326
+ * @param messages - Array of LLM messages
327
+ * @param prefix - Attribute prefix ('llm.input_messages' or 'llm.output_messages')
328
+ * @returns Flattened message attributes
329
+ * @internal
330
+ */
331
+ function _flattenLLMMessages(
332
+ messages: LLMMessage[] | undefined,
333
+ prefix: string,
334
+ ): Record<string, string> {
335
+ const attributes: Record<string, string> = {};
336
+
337
+ if (!messages || !Array.isArray(messages)) {
338
+ return attributes;
339
+ }
340
+
341
+ try {
342
+ messages.forEach((msg, index) => {
343
+ if (!msg || typeof msg !== "object") return;
344
+
345
+ const baseKey = `${prefix}.${index}.message`;
346
+
347
+ if (msg.role !== undefined) {
348
+ attributes[`${baseKey}.role`] = String(msg.role);
349
+ }
350
+ if (msg.content !== undefined) {
351
+ attributes[`${baseKey}.content`] = String(msg.content);
352
+ }
353
+ if (msg.toolCallId !== undefined) {
354
+ attributes[`${baseKey}.tool_call_id`] = String(msg.toolCallId);
355
+ }
356
+
357
+ // Flatten tool calls if present
358
+ if (msg.toolCalls && Array.isArray(msg.toolCalls)) {
359
+ msg.toolCalls.forEach((toolCall, tcIndex) => {
360
+ if (!toolCall || typeof toolCall !== "object") return;
361
+
362
+ const tcKey = `${baseKey}.tool_calls.${tcIndex}`;
363
+
364
+ if (toolCall.id !== undefined) {
365
+ attributes[`${tcKey}.id`] = String(toolCall.id);
366
+ }
367
+ if (toolCall.function !== undefined) {
368
+ if (toolCall.function.name !== undefined) {
369
+ attributes[`${tcKey}.function.name`] = String(toolCall.function.name);
370
+ }
371
+ if (toolCall.function.arguments !== undefined) {
372
+ attributes[`${tcKey}.function.arguments`] = String(toolCall.function.arguments);
373
+ }
374
+ }
375
+ });
376
+ }
377
+ });
378
+ } catch (e) {
379
+ // Silent fail - don't block business logic for observability
380
+ }
381
+
382
+ return attributes;
383
+ }
384
+
385
+ /**
386
+ * Flattens documents into OpenTelemetry attributes.
387
+ *
388
+ * Follows OpenInference convention:
389
+ * - retrieval.documents.{i}.document.id
390
+ * - retrieval.documents.{i}.document.content
391
+ * - retrieval.documents.{i}.document.score
392
+ * - retrieval.documents.{i}.document.metadata
393
+ *
394
+ * @param documents - Array of documents
395
+ * @returns Flattened document attributes
396
+ * @internal
397
+ */
398
+ function _flattenDocuments(
399
+ documents: Document[] | undefined,
400
+ ): Record<string, string> {
401
+ const attributes: Record<string, string> = {};
402
+
403
+ if (!documents || !Array.isArray(documents)) {
404
+ return attributes;
405
+ }
406
+
407
+ try {
408
+ documents.forEach((doc, index) => {
409
+ if (!doc || typeof doc !== "object") return;
410
+
411
+ const baseKey = `retrieval.documents.${index}.document`;
412
+
413
+ if (doc.id !== undefined) {
414
+ attributes[`${baseKey}.id`] = String(doc.id);
415
+ }
416
+ if (doc.content !== undefined) {
417
+ attributes[`${baseKey}.content`] = String(doc.content);
418
+ }
419
+ if (doc.score !== undefined) {
420
+ attributes[`${baseKey}.score`] = String(doc.score);
421
+ }
422
+ if (doc.metadata !== undefined && typeof doc.metadata === "object") {
423
+ const metadataSerialized = _serialize(doc.metadata);
424
+ if (metadataSerialized) {
425
+ attributes[`${baseKey}.metadata`] = metadataSerialized;
426
+ }
427
+ }
428
+ });
429
+ } catch (e) {
430
+ // Silent fail - don't block business logic for observability
431
+ }
432
+
433
+ return attributes;
434
+ }
435
+
436
+ /**
437
+ * Flattens tool call into OpenTelemetry attributes.
438
+ *
439
+ * Follows OpenInference convention:
440
+ * - tool_call.id
441
+ * - tool_call.function.name
442
+ * - tool_call.function.arguments
443
+ *
444
+ * @param toolCall - Tool call object
445
+ * @returns Flattened tool call attributes
446
+ * @internal
447
+ */
448
+ function _flattenToolCall(
449
+ toolCall: ToolCall | undefined,
450
+ ): Record<string, string> {
451
+ const attributes: Record<string, string> = {};
452
+
453
+ if (!toolCall || typeof toolCall !== "object") {
454
+ return attributes;
455
+ }
456
+
457
+ try {
458
+ if (toolCall.id !== undefined) {
459
+ attributes["tool_call.id"] = String(toolCall.id);
460
+ }
461
+ if (toolCall.function !== undefined) {
462
+ if (toolCall.function.name !== undefined) {
463
+ attributes["tool_call.function.name"] = String(toolCall.function.name);
464
+ }
465
+ if (toolCall.function.arguments !== undefined) {
466
+ attributes["tool_call.function.arguments"] = String(toolCall.function.arguments);
467
+ }
468
+ }
469
+ } catch (e) {
470
+ // Silent fail - don't block business logic for observability
471
+ }
472
+
473
+ return attributes;
474
+ }
@@ -1,13 +1,13 @@
1
1
  import { Span, TimeInput } from "@opentelemetry/api";
2
2
 
3
- import { createObservationAttributes, createTraceAttributes } from "./attributes.js";
4
- import { getTracer } from "./tracerProvider.js";
3
+ import { createObservationAttributes, createTraceAttributes } from "./attributes";
4
+ import { getTracer } from "./tracerProvider";
5
5
  import {
6
6
  BaseSpanAttributes,
7
7
  LLMAttributes,
8
8
  TraceAttributes,
9
9
  ObservationType,
10
- } from "../types.js";
10
+ } from "../types";
11
11
  import type {
12
12
  ToolAttributes,
13
13
  AgentAttributes,
@@ -18,7 +18,7 @@ import type {
18
18
  GuardrailAttributes,
19
19
  EmbeddingAttributes,
20
20
  ObservationAttributes,
21
- } from "../types.js";
21
+ } from "../types";
22
22
 
23
23
  /**
24
24
  * Union type representing any observation wrapper.
@@ -194,7 +194,7 @@ abstract class BaseObservation {
194
194
  options?: { asType?: ObservationType },
195
195
  ): Observation {
196
196
  // Import here to avoid circular dependency
197
- const { startObservation: startObs } = require("../index.js");
197
+ const { startObservation: startObs } = require("../index");
198
198
  const { asType = "span" } = options || {};
199
199
 
200
200
  return startObs(name, attributes, {
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ import { trace, context, TimeInput, SpanStatusCode, Span, SpanContext } from "@o
9
9
  import {
10
10
  createObservationAttributes,
11
11
  createTraceAttributes,
12
- } from "./core/attributes.js";
12
+ } from "./core/attributes";
13
13
  import {
14
14
  ObservationSpan,
15
15
  ObservationLLM,
@@ -22,8 +22,8 @@ import {
22
22
  ObservationEvaluator,
23
23
  ObservationGuardrail,
24
24
  type Observation,
25
- } from "./core/spanWrapper.js";
26
- import { getTracer } from "./core/tracerProvider.js";
25
+ } from "./core/spanWrapper";
26
+ import { getTracer } from "./core/tracerProvider";
27
27
  import {
28
28
  ObservationType,
29
29
  ObservationLevel,
@@ -39,7 +39,10 @@ import {
39
39
  EmbeddingAttributes,
40
40
  ObservationAttributes,
41
41
  TraceAttributes,
42
- } from "./types.js";
42
+ LLMMessage,
43
+ ToolCall,
44
+ Document,
45
+ } from "./types";
43
46
 
44
47
  // Export types
45
48
  export type {
@@ -57,6 +60,9 @@ export type {
57
60
  EmbeddingAttributes,
58
61
  ObservationAttributes,
59
62
  TraceAttributes,
63
+ LLMMessage,
64
+ ToolCall,
65
+ Document,
60
66
  };
61
67
 
62
68
  // Export observation classes
@@ -80,12 +86,12 @@ export type { Observation };
80
86
  export {
81
87
  createTraceAttributes,
82
88
  createObservationAttributes,
83
- } from "./core/attributes.js";
89
+ } from "./core/attributes";
84
90
  export {
85
91
  setTracerProvider,
86
92
  getTracerProvider,
87
93
  getTracer,
88
- } from "./core/tracerProvider.js";
94
+ } from "./core/tracerProvider";
89
95
 
90
96
  /**
91
97
  * Options for starting observations (spans).