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

155 lines 5.87 kB
/** * Braintrust Exporter * Exports spans to Braintrust AI evaluation platform */ import { logger } from "../../utils/logger.js"; import { BaseExporter } from "./baseExporter.js"; /** * Braintrust exporter for AI evaluation and scoring * Supports project logs and evaluation metrics */ export class BraintrustExporter extends BaseExporter { apiKey; projectName; endpoint; constructor(config) { super("braintrust", config); this.apiKey = config.apiKey; this.projectName = config.projectName; this.endpoint = config.endpoint ?? "https://api.braintrust.dev"; } async initialize() { if (this.initialized) { return; } // Verify API key try { const response = await fetch(`${this.endpoint}/v1/project`, { headers: { Authorization: `Bearer ${this.apiKey}` }, }); if (!response.ok) { throw new Error(`Braintrust initialization failed: ${response.statusText}`); } } catch (error) { logger.warn("[Braintrust] 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 log = this.convertToBraintrustLog(span); const response = await fetch(`${this.endpoint}/v1/project_logs/${this.projectName}/insert`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.apiKey}`, }, body: JSON.stringify({ events: [log] }), }); 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 events = spans.map((s) => this.convertToBraintrustLog(s)); const response = await fetch(`${this.endpoint}/v1/project_logs/${this.projectName}/insert`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.apiKey}`, }, body: JSON.stringify({ events }), }); 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 Braintrust API */ async ping() { const response = await fetch(`${this.endpoint}/v1/project`, { headers: { Authorization: `Bearer ${this.apiKey}` }, }); if (!response.ok) { throw new Error(`Braintrust API unreachable: ${response.status}`); } } /** * Convert span to Braintrust log format */ convertToBraintrustLog(span) { return { project_name: this.projectName, id: span.spanId, span_id: span.spanId, root_span_id: span.parentSpanId ? undefined : span.spanId, span_parents: span.parentSpanId ? [span.parentSpanId] : [], input: span.attributes["input"], output: span.attributes["output"], expected: span.attributes["expected"], scores: span.attributes["scores"], metadata: { // Pick only safe, non-PII attributes for metadata (avoid leaking input/output) ...(span.attributes["ai.provider"] !== undefined && { "ai.provider": span.attributes["ai.provider"], }), ...(span.attributes["ai.model"] !== undefined && { "ai.model": span.attributes["ai.model"], }), // Explicit fields placed after spread so they always win provider: span.attributes["ai.provider"], model: span.attributes["ai.model"], type: span.type, status: span.status, statusMessage: span.statusMessage, }, metrics: { tokens: span.attributes["ai.tokens.total"], prompt_tokens: span.attributes["ai.tokens.input"], completion_tokens: span.attributes["ai.tokens.output"], cost: span.attributes["ai.cost.total"], duration_ms: span.durationMs, }, created: span.startTime, end_time: span.endTime, }; } } //# sourceMappingURL=braintrustExporter.js.map