UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

144 lines (143 loc) 5.34 kB
/** * LangSmith Exporter * Exports spans to LangSmith observability platform */ import { logger } from "../../utils/logger.js"; /** * Build a LangSmith dotted_order value: "{datetime}.{id}" * Format: YYYYMMDDTHHmmssSSSSSSZ.<id> (datetime in UTC with microseconds) */ function buildDottedOrder(isoTime, id) { const d = new Date(isoTime); const pad2 = (n) => String(n).padStart(2, "0"); const microseconds = String(d.getUTCMilliseconds() * 1000).padStart(6, "0"); const dt = `${d.getUTCFullYear()}${pad2(d.getUTCMonth() + 1)}${pad2(d.getUTCDate())}T` + `${pad2(d.getUTCHours())}${pad2(d.getUTCMinutes())}${pad2(d.getUTCSeconds())}` + `${microseconds}Z`; return `${dt}.${id}`; } import { SpanSerializer } from "../utils/spanSerializer.js"; import { BaseExporter } from "./baseExporter.js"; /** * LangSmith exporter for LangChain ecosystem observability * Supports runs with proper type mapping */ export class LangSmithExporter extends BaseExporter { apiKey; projectName; endpoint; constructor(config) { super("langsmith", config); this.apiKey = config.apiKey; this.projectName = config.projectName ?? "default"; this.endpoint = config.endpoint ?? "https://api.smith.langchain.com"; } async initialize() { if (this.initialized) { return; } // Verify API key with a test request try { const response = await fetch(`${this.endpoint}/api/v1/info`, { headers: { "x-api-key": this.apiKey }, }); if (!response.ok) { throw new Error(`LangSmith initialization failed: ${response.statusText}`); } } catch (error) { // Allow initialization to proceed even if API is unreachable // This enables offline/test scenarios logger.warn("[LangSmith] Could not verify API connection:", error instanceof Error ? error.message : error); } this.initialized = true; this.startFlushInterval(this.config.flushIntervalMs ?? 5000); } async exportSpan(span) { const startTime = Date.now(); try { const langsmithRun = SpanSerializer.toLangSmithFormat(span); const response = await fetch(`${this.endpoint}/api/v1/runs`, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": this.apiKey, }, body: JSON.stringify({ ...langsmithRun, session_name: this.projectName, }), }); if (!response.ok) { throw new Error(`Export failed: ${response.statusText}`); } return this.createSuccessResult(1, Date.now() - startTime); } catch (error) { return this.createFailureResult([span.spanId], error instanceof Error ? error.message : String(error), Date.now() - startTime); } } async exportBatch(spans) { const startTime = Date.now(); try { const post = spans.map((s) => { const run = SpanSerializer.toLangSmithFormat(s); // LangSmith /api/v1/runs/batch requires dotted_order and trace_id on each run const dotted_order = buildDottedOrder(run.start_time ?? s.startTime, run.id); return { ...run, trace_id: run.trace_id ?? run.id, dotted_order, session_name: this.projectName, }; }); const response = await fetch(`${this.endpoint}/api/v1/runs/batch`, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": this.apiKey, }, body: JSON.stringify({ post }), }); if (!response.ok) { throw new Error(`Batch export failed: ${response.statusText}`); } return this.createSuccessResult(spans.length, Date.now() - startTime); } catch (error) { return this.createFailureResult(spans.map((s) => s.spanId), error instanceof Error ? error.message : String(error), Date.now() - startTime); } } async flush() { if (this.buffer.length > 0) { const spans = [...this.buffer]; this.buffer = []; await this.exportBatch(spans); } } async shutdown() { await this.flush(); this.stopFlushInterval(); this.initialized = false; } async healthCheck() { try { await this.withRetry(() => this.ping(), "health check"); return this.createHealthStatus(true); } catch { return this.createHealthStatus(false, ["Health check failed"]); } } /** * Verify connectivity to LangSmith API */ async ping() { const response = await fetch(`${this.endpoint}/api/v1/info`, { headers: { "x-api-key": this.apiKey }, }); if (!response.ok) { throw new Error(`LangSmith API unreachable: ${response.status}`); } } }