@juspay/neurolink 9.24.0 → 9.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/adapters/tts/googleTTSHandler.js +26 -1
- package/dist/adapters/video/vertexVideoHandler.js +23 -17
- package/dist/cli/commands/config.d.ts +3 -3
- package/dist/cli/commands/observability.d.ts +53 -0
- package/dist/cli/commands/observability.js +453 -0
- package/dist/cli/commands/telemetry.d.ts +63 -0
- package/dist/cli/commands/telemetry.js +689 -0
- package/dist/cli/factories/commandFactory.js +29 -15
- package/dist/cli/parser.js +6 -9
- package/dist/cli/utils/formatters.d.ts +13 -0
- package/dist/cli/utils/formatters.js +23 -0
- package/dist/constants/contextWindows.js +6 -0
- package/dist/constants/enums.d.ts +6 -0
- package/dist/constants/enums.js +8 -2
- package/dist/context/budgetChecker.js +75 -48
- package/dist/context/contextCompactor.js +135 -127
- package/dist/core/baseProvider.d.ts +5 -0
- package/dist/core/baseProvider.js +158 -102
- package/dist/core/conversationMemoryInitializer.js +7 -4
- package/dist/core/conversationMemoryManager.d.ts +2 -0
- package/dist/core/conversationMemoryManager.js +6 -2
- package/dist/core/modules/GenerationHandler.d.ts +2 -2
- package/dist/core/modules/GenerationHandler.js +12 -12
- package/dist/evaluation/ragasEvaluator.js +39 -19
- package/dist/evaluation/scoring.js +46 -20
- package/dist/features/ppt/presentationOrchestrator.js +23 -0
- package/dist/features/ppt/slideGenerator.js +13 -0
- package/dist/features/ppt/slideRenderers.d.ts +1 -1
- package/dist/features/ppt/slideRenderers.js +6 -4
- package/dist/features/ppt/slideTypeInference.d.ts +1 -1
- package/dist/features/ppt/slideTypeInference.js +75 -73
- package/dist/files/fileTools.d.ts +6 -6
- package/dist/index.d.ts +46 -12
- package/dist/index.js +79 -17
- package/dist/lib/adapters/tts/googleTTSHandler.js +26 -1
- package/dist/lib/adapters/video/vertexVideoHandler.js +23 -17
- package/dist/lib/constants/contextWindows.js +6 -0
- package/dist/lib/constants/enums.d.ts +6 -0
- package/dist/lib/constants/enums.js +8 -2
- package/dist/lib/context/budgetChecker.js +75 -48
- package/dist/lib/context/contextCompactor.js +135 -127
- package/dist/lib/core/baseProvider.d.ts +5 -0
- package/dist/lib/core/baseProvider.js +158 -102
- package/dist/lib/core/conversationMemoryInitializer.js +7 -4
- package/dist/lib/core/conversationMemoryManager.d.ts +2 -0
- package/dist/lib/core/conversationMemoryManager.js +6 -2
- package/dist/lib/core/modules/GenerationHandler.d.ts +2 -2
- package/dist/lib/core/modules/GenerationHandler.js +12 -12
- package/dist/lib/evaluation/ragasEvaluator.js +39 -19
- package/dist/lib/evaluation/scoring.js +46 -20
- package/dist/lib/features/ppt/presentationOrchestrator.js +23 -0
- package/dist/lib/features/ppt/slideGenerator.js +13 -0
- package/dist/lib/features/ppt/slideRenderers.d.ts +1 -1
- package/dist/lib/features/ppt/slideRenderers.js +6 -4
- package/dist/lib/features/ppt/slideTypeInference.d.ts +1 -1
- package/dist/lib/features/ppt/slideTypeInference.js +75 -73
- package/dist/lib/files/fileTools.d.ts +6 -6
- package/dist/lib/index.d.ts +46 -12
- package/dist/lib/index.js +79 -17
- package/dist/lib/mcp/httpRateLimiter.js +39 -12
- package/dist/lib/mcp/httpRetryHandler.js +22 -1
- package/dist/lib/mcp/mcpClientFactory.js +13 -15
- package/dist/lib/memory/memoryRetrievalTools.js +22 -0
- package/dist/lib/neurolink.d.ts +64 -72
- package/dist/lib/neurolink.js +984 -566
- package/dist/lib/observability/exporterRegistry.d.ts +152 -0
- package/dist/lib/observability/exporterRegistry.js +414 -0
- package/dist/lib/observability/exporters/arizeExporter.d.ts +32 -0
- package/dist/lib/observability/exporters/arizeExporter.js +139 -0
- package/dist/lib/observability/exporters/baseExporter.d.ts +117 -0
- package/dist/lib/observability/exporters/baseExporter.js +191 -0
- package/dist/lib/observability/exporters/braintrustExporter.d.ts +30 -0
- package/dist/lib/observability/exporters/braintrustExporter.js +155 -0
- package/dist/lib/observability/exporters/datadogExporter.d.ts +37 -0
- package/dist/lib/observability/exporters/datadogExporter.js +197 -0
- package/dist/lib/observability/exporters/index.d.ts +13 -0
- package/dist/lib/observability/exporters/index.js +14 -0
- package/dist/lib/observability/exporters/laminarExporter.d.ts +48 -0
- package/dist/lib/observability/exporters/laminarExporter.js +303 -0
- package/dist/lib/observability/exporters/langfuseExporter.d.ts +47 -0
- package/dist/lib/observability/exporters/langfuseExporter.js +200 -0
- package/dist/lib/observability/exporters/langsmithExporter.d.ts +26 -0
- package/dist/lib/observability/exporters/langsmithExporter.js +124 -0
- package/dist/lib/observability/exporters/otelExporter.d.ts +39 -0
- package/dist/lib/observability/exporters/otelExporter.js +165 -0
- package/dist/lib/observability/exporters/posthogExporter.d.ts +48 -0
- package/dist/lib/observability/exporters/posthogExporter.js +288 -0
- package/dist/lib/observability/exporters/sentryExporter.d.ts +32 -0
- package/dist/lib/observability/exporters/sentryExporter.js +166 -0
- package/dist/lib/observability/index.d.ts +25 -0
- package/dist/lib/observability/index.js +32 -0
- package/dist/lib/observability/metricsAggregator.d.ts +260 -0
- package/dist/lib/observability/metricsAggregator.js +553 -0
- package/dist/lib/observability/otelBridge.d.ts +49 -0
- package/dist/lib/observability/otelBridge.js +132 -0
- package/dist/lib/observability/retryPolicy.d.ts +192 -0
- package/dist/lib/observability/retryPolicy.js +384 -0
- package/dist/lib/observability/sampling/index.d.ts +4 -0
- package/dist/lib/observability/sampling/index.js +5 -0
- package/dist/lib/observability/sampling/samplers.d.ts +116 -0
- package/dist/lib/observability/sampling/samplers.js +217 -0
- package/dist/lib/observability/spanProcessor.d.ts +129 -0
- package/dist/lib/observability/spanProcessor.js +288 -0
- package/dist/lib/observability/tokenTracker.d.ts +156 -0
- package/dist/lib/observability/tokenTracker.js +414 -0
- package/dist/lib/observability/types/exporterTypes.d.ts +250 -0
- package/dist/lib/observability/types/exporterTypes.js +6 -0
- package/dist/lib/observability/types/index.d.ts +6 -0
- package/dist/lib/observability/types/index.js +5 -0
- package/dist/lib/observability/types/spanTypes.d.ts +244 -0
- package/dist/lib/observability/types/spanTypes.js +93 -0
- package/dist/lib/observability/utils/index.d.ts +4 -0
- package/dist/lib/observability/utils/index.js +5 -0
- package/dist/lib/observability/utils/spanSerializer.d.ts +115 -0
- package/dist/lib/observability/utils/spanSerializer.js +287 -0
- package/dist/lib/providers/amazonSagemaker.d.ts +5 -4
- package/dist/lib/providers/amazonSagemaker.js +3 -4
- package/dist/lib/providers/googleVertex.d.ts +7 -0
- package/dist/lib/providers/googleVertex.js +80 -2
- package/dist/lib/rag/pipeline/RAGPipeline.d.ts +0 -5
- package/dist/lib/rag/pipeline/RAGPipeline.js +122 -87
- package/dist/lib/rag/ragIntegration.js +30 -0
- package/dist/lib/rag/retrieval/hybridSearch.js +22 -0
- package/dist/lib/server/abstract/baseServerAdapter.js +51 -19
- package/dist/lib/server/middleware/common.js +44 -12
- package/dist/lib/services/server/ai/observability/instrumentation.d.ts +2 -2
- package/dist/lib/services/server/ai/observability/instrumentation.js +10 -5
- package/dist/lib/types/conversationMemoryInterface.d.ts +2 -0
- package/dist/lib/types/modelTypes.d.ts +18 -18
- package/dist/lib/types/providers.d.ts +5 -0
- package/dist/lib/utils/pricing.js +25 -1
- package/dist/lib/utils/ttsProcessor.js +74 -59
- package/dist/lib/workflow/config.d.ts +36 -36
- package/dist/lib/workflow/core/ensembleExecutor.js +10 -0
- package/dist/lib/workflow/core/judgeScorer.js +20 -2
- package/dist/lib/workflow/core/workflowRunner.js +34 -1
- package/dist/mcp/httpRateLimiter.js +39 -12
- package/dist/mcp/httpRetryHandler.js +22 -1
- package/dist/mcp/mcpClientFactory.js +13 -15
- package/dist/memory/memoryRetrievalTools.js +22 -0
- package/dist/neurolink.d.ts +64 -72
- package/dist/neurolink.js +984 -566
- package/dist/observability/FEATURE-STATUS.md +269 -0
- package/dist/observability/exporterRegistry.d.ts +152 -0
- package/dist/observability/exporterRegistry.js +413 -0
- package/dist/observability/exporters/arizeExporter.d.ts +32 -0
- package/dist/observability/exporters/arizeExporter.js +138 -0
- package/dist/observability/exporters/baseExporter.d.ts +117 -0
- package/dist/observability/exporters/baseExporter.js +190 -0
- package/dist/observability/exporters/braintrustExporter.d.ts +30 -0
- package/dist/observability/exporters/braintrustExporter.js +154 -0
- package/dist/observability/exporters/datadogExporter.d.ts +37 -0
- package/dist/observability/exporters/datadogExporter.js +196 -0
- package/dist/observability/exporters/index.d.ts +13 -0
- package/dist/observability/exporters/index.js +13 -0
- package/dist/observability/exporters/laminarExporter.d.ts +48 -0
- package/dist/observability/exporters/laminarExporter.js +302 -0
- package/dist/observability/exporters/langfuseExporter.d.ts +47 -0
- package/dist/observability/exporters/langfuseExporter.js +199 -0
- package/dist/observability/exporters/langsmithExporter.d.ts +26 -0
- package/dist/observability/exporters/langsmithExporter.js +123 -0
- package/dist/observability/exporters/otelExporter.d.ts +39 -0
- package/dist/observability/exporters/otelExporter.js +164 -0
- package/dist/observability/exporters/posthogExporter.d.ts +48 -0
- package/dist/observability/exporters/posthogExporter.js +287 -0
- package/dist/observability/exporters/sentryExporter.d.ts +32 -0
- package/dist/observability/exporters/sentryExporter.js +165 -0
- package/dist/observability/index.d.ts +25 -0
- package/dist/observability/index.js +31 -0
- package/dist/observability/metricsAggregator.d.ts +260 -0
- package/dist/observability/metricsAggregator.js +552 -0
- package/dist/observability/otelBridge.d.ts +49 -0
- package/dist/observability/otelBridge.js +131 -0
- package/dist/observability/retryPolicy.d.ts +192 -0
- package/dist/observability/retryPolicy.js +383 -0
- package/dist/observability/sampling/index.d.ts +4 -0
- package/dist/observability/sampling/index.js +4 -0
- package/dist/observability/sampling/samplers.d.ts +116 -0
- package/dist/observability/sampling/samplers.js +216 -0
- package/dist/observability/spanProcessor.d.ts +129 -0
- package/dist/observability/spanProcessor.js +287 -0
- package/dist/observability/tokenTracker.d.ts +156 -0
- package/dist/observability/tokenTracker.js +413 -0
- package/dist/observability/types/exporterTypes.d.ts +250 -0
- package/dist/observability/types/exporterTypes.js +5 -0
- package/dist/observability/types/index.d.ts +6 -0
- package/dist/observability/types/index.js +4 -0
- package/dist/observability/types/spanTypes.d.ts +244 -0
- package/dist/observability/types/spanTypes.js +92 -0
- package/dist/observability/utils/index.d.ts +4 -0
- package/dist/observability/utils/index.js +4 -0
- package/dist/observability/utils/spanSerializer.d.ts +115 -0
- package/dist/observability/utils/spanSerializer.js +286 -0
- package/dist/providers/amazonSagemaker.d.ts +5 -4
- package/dist/providers/amazonSagemaker.js +3 -4
- package/dist/providers/googleVertex.d.ts +7 -0
- package/dist/providers/googleVertex.js +80 -2
- package/dist/rag/pipeline/RAGPipeline.d.ts +0 -5
- package/dist/rag/pipeline/RAGPipeline.js +122 -87
- package/dist/rag/ragIntegration.js +30 -0
- package/dist/rag/retrieval/hybridSearch.js +22 -0
- package/dist/server/abstract/baseServerAdapter.js +51 -19
- package/dist/server/middleware/common.js +44 -12
- package/dist/services/server/ai/observability/instrumentation.d.ts +2 -2
- package/dist/services/server/ai/observability/instrumentation.js +10 -5
- package/dist/types/conversationMemoryInterface.d.ts +2 -0
- package/dist/types/providers.d.ts +5 -0
- package/dist/utils/pricing.js +25 -1
- package/dist/utils/ttsProcessor.js +74 -59
- package/dist/workflow/config.d.ts +52 -52
- package/dist/workflow/core/ensembleExecutor.js +10 -0
- package/dist/workflow/core/judgeScorer.js +20 -2
- package/dist/workflow/core/workflowRunner.js +34 -1
- package/package.json +1 -1
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Laminar Exporter
|
|
3
|
+
* Exports spans to Laminar LLM tracing platform
|
|
4
|
+
* @see https://docs.laminar.run/
|
|
5
|
+
*/
|
|
6
|
+
import { logger } from "../../utils/logger.js";
|
|
7
|
+
import { SpanStatus, SpanType } from "../types/spanTypes.js";
|
|
8
|
+
import { BaseExporter } from "./baseExporter.js";
|
|
9
|
+
/**
|
|
10
|
+
* Laminar exporter for LLM pipeline tracing and monitoring
|
|
11
|
+
* Supports detailed traces with input/output tracking
|
|
12
|
+
*/
|
|
13
|
+
export class LaminarExporter extends BaseExporter {
|
|
14
|
+
apiKey;
|
|
15
|
+
projectApiKey;
|
|
16
|
+
baseUrl;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super("laminar", config);
|
|
19
|
+
this.apiKey = config.apiKey;
|
|
20
|
+
this.projectApiKey = config.projectApiKey;
|
|
21
|
+
this.baseUrl = config.baseUrl ?? "https://api.laminar.run";
|
|
22
|
+
}
|
|
23
|
+
async initialize() {
|
|
24
|
+
if (this.initialized) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Verify API key by making a test call
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(`${this.baseUrl}/v1/health`, {
|
|
30
|
+
headers: this.getHeaders(),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
logger.warn("[Laminar] Could not verify API connection:", response.statusText);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
logger.warn("[Laminar] Could not verify API connection:", error instanceof Error ? error.message : error);
|
|
38
|
+
}
|
|
39
|
+
this.initialized = true;
|
|
40
|
+
this.startFlushInterval(this.config.flushIntervalMs ?? 5000);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get authorization headers
|
|
44
|
+
*/
|
|
45
|
+
getHeaders() {
|
|
46
|
+
const headers = {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
49
|
+
};
|
|
50
|
+
// Add project API key if provided
|
|
51
|
+
if (this.projectApiKey) {
|
|
52
|
+
headers["X-Project-Api-Key"] = this.projectApiKey;
|
|
53
|
+
}
|
|
54
|
+
return headers;
|
|
55
|
+
}
|
|
56
|
+
async exportSpan(span) {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
try {
|
|
59
|
+
const trace = this.convertToLaminarTrace(span);
|
|
60
|
+
const response = await fetch(`${this.baseUrl}/v1/traces`, {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: this.getHeaders(),
|
|
63
|
+
body: JSON.stringify(trace),
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new Error(`Export failed: ${response.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
return this.createSuccessResult(1, Date.now() - startTime);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return this.createFailureResult([span.spanId], error instanceof Error ? error.message : String(error), Date.now() - startTime);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async exportBatch(spans) {
|
|
75
|
+
const startTime = Date.now();
|
|
76
|
+
try {
|
|
77
|
+
const traces = spans.map((s) => this.convertToLaminarTrace(s));
|
|
78
|
+
const response = await fetch(`${this.baseUrl}/v1/traces/batch`, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: this.getHeaders(),
|
|
81
|
+
body: JSON.stringify({ traces }),
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
throw new Error(`Batch export failed: ${response.statusText}`);
|
|
85
|
+
}
|
|
86
|
+
return this.createSuccessResult(spans.length, Date.now() - startTime);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return this.createFailureResult(spans.map((s) => s.spanId), error instanceof Error ? error.message : String(error), Date.now() - startTime);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async flush() {
|
|
93
|
+
if (this.buffer.length > 0) {
|
|
94
|
+
const spans = [...this.buffer];
|
|
95
|
+
this.buffer = [];
|
|
96
|
+
await this.exportBatch(spans);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async shutdown() {
|
|
100
|
+
await this.flush();
|
|
101
|
+
this.stopFlushInterval();
|
|
102
|
+
this.initialized = false;
|
|
103
|
+
}
|
|
104
|
+
async healthCheck() {
|
|
105
|
+
try {
|
|
106
|
+
await this.withRetry(() => this.ping(), "health check");
|
|
107
|
+
return this.createHealthStatus(true);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return this.createHealthStatus(false, ["Health check failed"]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Verify connectivity to Laminar API
|
|
115
|
+
*/
|
|
116
|
+
async ping() {
|
|
117
|
+
const response = await fetch(`${this.baseUrl}/v1/health`, {
|
|
118
|
+
headers: this.getHeaders(),
|
|
119
|
+
});
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
throw new Error(`Laminar API unreachable: ${response.status}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert span to Laminar trace format
|
|
126
|
+
*/
|
|
127
|
+
convertToLaminarTrace(span) {
|
|
128
|
+
return {
|
|
129
|
+
// Core identifiers
|
|
130
|
+
trace_id: span.traceId,
|
|
131
|
+
span_id: span.spanId,
|
|
132
|
+
parent_span_id: span.parentSpanId,
|
|
133
|
+
// Trace metadata
|
|
134
|
+
name: span.name,
|
|
135
|
+
type: this.mapSpanTypeToLaminarType(span.type),
|
|
136
|
+
start_time: span.startTime,
|
|
137
|
+
end_time: span.endTime,
|
|
138
|
+
duration_ms: span.durationMs,
|
|
139
|
+
// Status
|
|
140
|
+
status: this.mapSpanStatus(span.status),
|
|
141
|
+
status_message: span.statusMessage,
|
|
142
|
+
// Model information
|
|
143
|
+
model: {
|
|
144
|
+
provider: span.attributes["ai.provider"],
|
|
145
|
+
name: span.attributes["ai.model"],
|
|
146
|
+
version: span.attributes["ai.model.version"],
|
|
147
|
+
},
|
|
148
|
+
// Token usage
|
|
149
|
+
usage: {
|
|
150
|
+
input_tokens: span.attributes["ai.tokens.input"],
|
|
151
|
+
output_tokens: span.attributes["ai.tokens.output"],
|
|
152
|
+
total_tokens: span.attributes["ai.tokens.total"],
|
|
153
|
+
cache_read_tokens: span.attributes["ai.tokens.cache_read"],
|
|
154
|
+
cache_creation_tokens: span.attributes["ai.tokens.cache_creation"],
|
|
155
|
+
reasoning_tokens: span.attributes["ai.tokens.reasoning"],
|
|
156
|
+
},
|
|
157
|
+
// Cost tracking
|
|
158
|
+
cost: {
|
|
159
|
+
input: span.attributes["ai.cost.input"],
|
|
160
|
+
output: span.attributes["ai.cost.output"],
|
|
161
|
+
total: span.attributes["ai.cost.total"],
|
|
162
|
+
currency: span.attributes["ai.cost.currency"] || "USD",
|
|
163
|
+
},
|
|
164
|
+
// Generation parameters
|
|
165
|
+
parameters: {
|
|
166
|
+
temperature: span.attributes["ai.temperature"],
|
|
167
|
+
max_tokens: span.attributes["ai.max_tokens"],
|
|
168
|
+
top_p: span.attributes["ai.top_p"],
|
|
169
|
+
stop_sequences: span.attributes["ai.stop_sequences"],
|
|
170
|
+
},
|
|
171
|
+
// Input/Output
|
|
172
|
+
input: span.attributes["input"],
|
|
173
|
+
output: span.attributes["output"],
|
|
174
|
+
// Tool information
|
|
175
|
+
tool: span.attributes["tool.name"]
|
|
176
|
+
? {
|
|
177
|
+
name: span.attributes["tool.name"],
|
|
178
|
+
server: span.attributes["tool.server"],
|
|
179
|
+
success: span.attributes["tool.success"],
|
|
180
|
+
}
|
|
181
|
+
: undefined,
|
|
182
|
+
// Error information
|
|
183
|
+
error: span.status === SpanStatus.ERROR
|
|
184
|
+
? {
|
|
185
|
+
type: span.attributes["error.type"],
|
|
186
|
+
message: span.attributes["error.message"],
|
|
187
|
+
stack: span.attributes["error.stack"],
|
|
188
|
+
}
|
|
189
|
+
: undefined,
|
|
190
|
+
// User and session context
|
|
191
|
+
context: {
|
|
192
|
+
user_id: span.attributes["user.id"],
|
|
193
|
+
session_id: span.attributes["session.id"],
|
|
194
|
+
environment: span.attributes["deployment.environment"] || this.config.environment,
|
|
195
|
+
service: {
|
|
196
|
+
name: span.attributes["service.name"],
|
|
197
|
+
version: span.attributes["service.version"] || this.config.version,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
// Events
|
|
201
|
+
events: span.events.map((event) => ({
|
|
202
|
+
name: event.name,
|
|
203
|
+
timestamp: event.timestamp,
|
|
204
|
+
attributes: event.attributes,
|
|
205
|
+
})),
|
|
206
|
+
// Links to related spans
|
|
207
|
+
links: span.links.map((link) => ({
|
|
208
|
+
trace_id: link.traceId,
|
|
209
|
+
span_id: link.spanId,
|
|
210
|
+
attributes: link.attributes,
|
|
211
|
+
})),
|
|
212
|
+
// Additional metadata
|
|
213
|
+
metadata: this.extractMetadata(span.attributes),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Map NeuroLink span type to Laminar type
|
|
218
|
+
*/
|
|
219
|
+
mapSpanTypeToLaminarType(type) {
|
|
220
|
+
const typeMap = {
|
|
221
|
+
[SpanType.AGENT_RUN]: "agent",
|
|
222
|
+
[SpanType.WORKFLOW_STEP]: "workflow",
|
|
223
|
+
[SpanType.TOOL_CALL]: "tool",
|
|
224
|
+
[SpanType.MODEL_GENERATION]: "llm",
|
|
225
|
+
[SpanType.EMBEDDING]: "embedding",
|
|
226
|
+
[SpanType.RETRIEVAL]: "retrieval",
|
|
227
|
+
[SpanType.MEMORY]: "memory",
|
|
228
|
+
[SpanType.CONTEXT_COMPACTION]: "custom",
|
|
229
|
+
[SpanType.RAG]: "retrieval",
|
|
230
|
+
[SpanType.EVALUATION]: "custom",
|
|
231
|
+
[SpanType.MCP_TRANSPORT]: "tool",
|
|
232
|
+
[SpanType.MEDIA_GENERATION]: "llm",
|
|
233
|
+
[SpanType.PPT_GENERATION]: "custom",
|
|
234
|
+
[SpanType.WORKFLOW]: "workflow",
|
|
235
|
+
[SpanType.TTS]: "custom",
|
|
236
|
+
[SpanType.SERVER_REQUEST]: "custom",
|
|
237
|
+
[SpanType.CUSTOM]: "custom",
|
|
238
|
+
};
|
|
239
|
+
return typeMap[type] || "custom";
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Map span status to Laminar status format
|
|
243
|
+
*/
|
|
244
|
+
mapSpanStatus(status) {
|
|
245
|
+
switch (status) {
|
|
246
|
+
case SpanStatus.OK:
|
|
247
|
+
return "success";
|
|
248
|
+
case SpanStatus.ERROR:
|
|
249
|
+
return "error";
|
|
250
|
+
default:
|
|
251
|
+
return "unset";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Extract additional metadata from span attributes
|
|
256
|
+
* Filters out standard attributes that are already handled
|
|
257
|
+
*/
|
|
258
|
+
extractMetadata(attributes) {
|
|
259
|
+
const standardKeys = new Set([
|
|
260
|
+
"service.name",
|
|
261
|
+
"service.version",
|
|
262
|
+
"deployment.environment",
|
|
263
|
+
"user.id",
|
|
264
|
+
"session.id",
|
|
265
|
+
"ai.provider",
|
|
266
|
+
"ai.model",
|
|
267
|
+
"ai.model.version",
|
|
268
|
+
"ai.tokens.input",
|
|
269
|
+
"ai.tokens.output",
|
|
270
|
+
"ai.tokens.total",
|
|
271
|
+
"ai.tokens.cache_read",
|
|
272
|
+
"ai.tokens.cache_creation",
|
|
273
|
+
"ai.tokens.reasoning",
|
|
274
|
+
"ai.cost.input",
|
|
275
|
+
"ai.cost.output",
|
|
276
|
+
"ai.cost.total",
|
|
277
|
+
"ai.cost.currency",
|
|
278
|
+
"ai.temperature",
|
|
279
|
+
"ai.max_tokens",
|
|
280
|
+
"ai.top_p",
|
|
281
|
+
"ai.stop_sequences",
|
|
282
|
+
"tool.name",
|
|
283
|
+
"tool.server",
|
|
284
|
+
"tool.success",
|
|
285
|
+
"error.type",
|
|
286
|
+
"error.message",
|
|
287
|
+
"error.stack",
|
|
288
|
+
"error",
|
|
289
|
+
"input",
|
|
290
|
+
"output",
|
|
291
|
+
"expected",
|
|
292
|
+
"scores",
|
|
293
|
+
]);
|
|
294
|
+
const metadata = {};
|
|
295
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
296
|
+
if (!standardKeys.has(key) && value !== undefined) {
|
|
297
|
+
metadata[key] = value;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return metadata;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Langfuse Exporter
|
|
3
|
+
* Exports spans to Langfuse observability platform
|
|
4
|
+
*/
|
|
5
|
+
import type { ExporterHealthStatus, ExportResult, LangfuseExporterConfig, SpanData } from "../types/index.js";
|
|
6
|
+
import { BaseExporter } from "./baseExporter.js";
|
|
7
|
+
/**
|
|
8
|
+
* Langfuse exporter for LLM observability
|
|
9
|
+
* Supports traces, generations, spans, and scores
|
|
10
|
+
*/
|
|
11
|
+
export declare class LangfuseExporter extends BaseExporter {
|
|
12
|
+
private readonly publicKey;
|
|
13
|
+
private readonly secretKey;
|
|
14
|
+
private readonly baseUrl;
|
|
15
|
+
private readonly release?;
|
|
16
|
+
constructor(config: LangfuseExporterConfig);
|
|
17
|
+
initialize(): Promise<void>;
|
|
18
|
+
exportSpan(span: SpanData): Promise<ExportResult>;
|
|
19
|
+
exportBatch(spans: SpanData[]): Promise<ExportResult>;
|
|
20
|
+
flush(): Promise<void>;
|
|
21
|
+
shutdown(): Promise<void>;
|
|
22
|
+
healthCheck(): Promise<ExporterHealthStatus>;
|
|
23
|
+
/**
|
|
24
|
+
* Verify connectivity to Langfuse API
|
|
25
|
+
*/
|
|
26
|
+
protected ping(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Create a Langfuse trace
|
|
29
|
+
*/
|
|
30
|
+
private createTrace;
|
|
31
|
+
/**
|
|
32
|
+
* Create a Langfuse span
|
|
33
|
+
*/
|
|
34
|
+
private createSpan;
|
|
35
|
+
/**
|
|
36
|
+
* Create a Langfuse generation (for LLM calls)
|
|
37
|
+
*/
|
|
38
|
+
private createGeneration;
|
|
39
|
+
/**
|
|
40
|
+
* Make API call to Langfuse
|
|
41
|
+
*/
|
|
42
|
+
private apiCall;
|
|
43
|
+
/**
|
|
44
|
+
* Extract tags from span attributes
|
|
45
|
+
*/
|
|
46
|
+
private extractTags;
|
|
47
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Langfuse Exporter
|
|
3
|
+
* Exports spans to Langfuse observability platform
|
|
4
|
+
*/
|
|
5
|
+
import { SpanType } from "../types/spanTypes.js";
|
|
6
|
+
import { SpanSerializer } from "../utils/spanSerializer.js";
|
|
7
|
+
import { BaseExporter } from "./baseExporter.js";
|
|
8
|
+
/**
|
|
9
|
+
* Langfuse exporter for LLM observability
|
|
10
|
+
* Supports traces, generations, spans, and scores
|
|
11
|
+
*/
|
|
12
|
+
export class LangfuseExporter extends BaseExporter {
|
|
13
|
+
publicKey;
|
|
14
|
+
secretKey;
|
|
15
|
+
baseUrl;
|
|
16
|
+
release;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super("langfuse", config);
|
|
19
|
+
this.publicKey = config.publicKey;
|
|
20
|
+
this.secretKey = config.secretKey;
|
|
21
|
+
this.baseUrl = config.baseUrl ?? "https://cloud.langfuse.com";
|
|
22
|
+
this.release = config.release;
|
|
23
|
+
}
|
|
24
|
+
async initialize() {
|
|
25
|
+
if (this.initialized) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Verify credentials with a simple check
|
|
29
|
+
if (!this.publicKey || !this.secretKey) {
|
|
30
|
+
throw new Error("Langfuse publicKey and secretKey are required");
|
|
31
|
+
}
|
|
32
|
+
this.initialized = true;
|
|
33
|
+
this.startFlushInterval(this.config.flushIntervalMs ?? 5000);
|
|
34
|
+
}
|
|
35
|
+
async exportSpan(span) {
|
|
36
|
+
const startTime = Date.now();
|
|
37
|
+
try {
|
|
38
|
+
// Create trace if this is a root span
|
|
39
|
+
if (!span.parentSpanId) {
|
|
40
|
+
await this.createTrace(span);
|
|
41
|
+
}
|
|
42
|
+
// Create span/generation based on type
|
|
43
|
+
if (span.type === SpanType.MODEL_GENERATION) {
|
|
44
|
+
await this.createGeneration(span);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
await this.createSpan(span);
|
|
48
|
+
}
|
|
49
|
+
return this.createSuccessResult(1, Date.now() - startTime);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return this.createFailureResult([span.spanId], error instanceof Error ? error.message : String(error), Date.now() - startTime);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async exportBatch(spans) {
|
|
56
|
+
const startTime = Date.now();
|
|
57
|
+
const results = await Promise.allSettled(spans.map((s) => this.exportSpan(s)));
|
|
58
|
+
const successful = results.filter((r) => r.status === "fulfilled" && r.value.success).length;
|
|
59
|
+
const failed = spans.length - successful;
|
|
60
|
+
return {
|
|
61
|
+
success: failed === 0,
|
|
62
|
+
exportedCount: successful,
|
|
63
|
+
failedCount: failed,
|
|
64
|
+
errors: results
|
|
65
|
+
.filter((r) => r.status === "rejected" ||
|
|
66
|
+
(r.status === "fulfilled" && !r.value.success))
|
|
67
|
+
.map((r, i) => ({
|
|
68
|
+
spanId: spans[i].spanId,
|
|
69
|
+
error: r.status === "rejected" ? String(r.reason) : "Export failed",
|
|
70
|
+
retryable: true,
|
|
71
|
+
})),
|
|
72
|
+
durationMs: Date.now() - startTime,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async flush() {
|
|
76
|
+
if (this.buffer.length > 0) {
|
|
77
|
+
const spans = [...this.buffer];
|
|
78
|
+
this.buffer = [];
|
|
79
|
+
await this.exportBatch(spans);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async shutdown() {
|
|
83
|
+
await this.flush();
|
|
84
|
+
this.stopFlushInterval();
|
|
85
|
+
this.initialized = false;
|
|
86
|
+
}
|
|
87
|
+
async healthCheck() {
|
|
88
|
+
try {
|
|
89
|
+
await this.withRetry(() => this.ping(), "health check");
|
|
90
|
+
return this.createHealthStatus(true);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return this.createHealthStatus(false, ["Health check failed"]);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Verify connectivity to Langfuse API
|
|
98
|
+
*/
|
|
99
|
+
async ping() {
|
|
100
|
+
const credentials = Buffer.from(`${this.publicKey}:${this.secretKey}`).toString("base64");
|
|
101
|
+
const response = await fetch(`${this.baseUrl}/api/public/health`, {
|
|
102
|
+
method: "GET",
|
|
103
|
+
headers: {
|
|
104
|
+
Authorization: `Basic ${credentials}`,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok && response.status !== 404) {
|
|
108
|
+
// 404 is acceptable as health endpoint may not exist
|
|
109
|
+
throw new Error(`Langfuse API unreachable: ${response.status}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a Langfuse trace
|
|
114
|
+
*/
|
|
115
|
+
async createTrace(span) {
|
|
116
|
+
const body = {
|
|
117
|
+
id: span.traceId,
|
|
118
|
+
name: span.name,
|
|
119
|
+
userId: span.attributes["user.id"],
|
|
120
|
+
sessionId: span.attributes["session.id"],
|
|
121
|
+
metadata: span.attributes,
|
|
122
|
+
release: this.release,
|
|
123
|
+
tags: this.extractTags(span),
|
|
124
|
+
};
|
|
125
|
+
await this.apiCall("/api/public/traces", body);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create a Langfuse span
|
|
129
|
+
*/
|
|
130
|
+
async createSpan(span) {
|
|
131
|
+
const langfuseSpan = SpanSerializer.toLangfuseFormat(span);
|
|
132
|
+
const body = {
|
|
133
|
+
...langfuseSpan,
|
|
134
|
+
traceId: span.traceId,
|
|
135
|
+
};
|
|
136
|
+
await this.apiCall("/api/public/spans", body);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Create a Langfuse generation (for LLM calls)
|
|
140
|
+
*/
|
|
141
|
+
async createGeneration(span) {
|
|
142
|
+
const langfuseSpan = SpanSerializer.toLangfuseFormat(span);
|
|
143
|
+
const body = {
|
|
144
|
+
traceId: span.traceId,
|
|
145
|
+
id: langfuseSpan.id,
|
|
146
|
+
parentObservationId: langfuseSpan.parentObservationId,
|
|
147
|
+
name: langfuseSpan.name,
|
|
148
|
+
startTime: langfuseSpan.startTime,
|
|
149
|
+
endTime: langfuseSpan.endTime,
|
|
150
|
+
model: span.attributes["ai.model"],
|
|
151
|
+
modelParameters: {
|
|
152
|
+
temperature: span.attributes["ai.temperature"],
|
|
153
|
+
maxTokens: span.attributes["ai.max_tokens"],
|
|
154
|
+
topP: span.attributes["ai.top_p"],
|
|
155
|
+
},
|
|
156
|
+
input: langfuseSpan.input,
|
|
157
|
+
output: langfuseSpan.output,
|
|
158
|
+
usage: langfuseSpan.usage,
|
|
159
|
+
metadata: langfuseSpan.metadata,
|
|
160
|
+
level: langfuseSpan.level,
|
|
161
|
+
statusMessage: langfuseSpan.statusMessage,
|
|
162
|
+
};
|
|
163
|
+
await this.apiCall("/api/public/generations", body);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Make API call to Langfuse
|
|
167
|
+
*/
|
|
168
|
+
async apiCall(path, body) {
|
|
169
|
+
const credentials = Buffer.from(`${this.publicKey}:${this.secretKey}`).toString("base64");
|
|
170
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
171
|
+
method: "POST",
|
|
172
|
+
headers: {
|
|
173
|
+
"Content-Type": "application/json",
|
|
174
|
+
Authorization: `Basic ${credentials}`,
|
|
175
|
+
},
|
|
176
|
+
body: JSON.stringify(body),
|
|
177
|
+
});
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
const text = await response.text();
|
|
180
|
+
throw new Error(`Langfuse API error: ${response.status} - ${text}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Extract tags from span attributes
|
|
185
|
+
*/
|
|
186
|
+
extractTags(span) {
|
|
187
|
+
const tags = [];
|
|
188
|
+
if (span.attributes["ai.provider"]) {
|
|
189
|
+
tags.push(`provider:${span.attributes["ai.provider"]}`);
|
|
190
|
+
}
|
|
191
|
+
if (span.attributes["ai.model"]) {
|
|
192
|
+
tags.push(`model:${span.attributes["ai.model"]}`);
|
|
193
|
+
}
|
|
194
|
+
if (span.attributes["deployment.environment"]) {
|
|
195
|
+
tags.push(`env:${span.attributes["deployment.environment"]}`);
|
|
196
|
+
}
|
|
197
|
+
return tags;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangSmith Exporter
|
|
3
|
+
* Exports spans to LangSmith observability platform
|
|
4
|
+
*/
|
|
5
|
+
import type { ExporterHealthStatus, ExportResult, LangSmithExporterConfig, SpanData } from "../types/index.js";
|
|
6
|
+
import { BaseExporter } from "./baseExporter.js";
|
|
7
|
+
/**
|
|
8
|
+
* LangSmith exporter for LangChain ecosystem observability
|
|
9
|
+
* Supports runs with proper type mapping
|
|
10
|
+
*/
|
|
11
|
+
export declare class LangSmithExporter extends BaseExporter {
|
|
12
|
+
private readonly apiKey;
|
|
13
|
+
private readonly projectName;
|
|
14
|
+
private readonly endpoint;
|
|
15
|
+
constructor(config: LangSmithExporterConfig);
|
|
16
|
+
initialize(): Promise<void>;
|
|
17
|
+
exportSpan(span: SpanData): Promise<ExportResult>;
|
|
18
|
+
exportBatch(spans: SpanData[]): Promise<ExportResult>;
|
|
19
|
+
flush(): Promise<void>;
|
|
20
|
+
shutdown(): Promise<void>;
|
|
21
|
+
healthCheck(): Promise<ExporterHealthStatus>;
|
|
22
|
+
/**
|
|
23
|
+
* Verify connectivity to LangSmith API
|
|
24
|
+
*/
|
|
25
|
+
protected ping(): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangSmith Exporter
|
|
3
|
+
* Exports spans to LangSmith observability platform
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from "../../utils/logger.js";
|
|
6
|
+
import { SpanSerializer } from "../utils/spanSerializer.js";
|
|
7
|
+
import { BaseExporter } from "./baseExporter.js";
|
|
8
|
+
/**
|
|
9
|
+
* LangSmith exporter for LangChain ecosystem observability
|
|
10
|
+
* Supports runs with proper type mapping
|
|
11
|
+
*/
|
|
12
|
+
export class LangSmithExporter extends BaseExporter {
|
|
13
|
+
apiKey;
|
|
14
|
+
projectName;
|
|
15
|
+
endpoint;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super("langsmith", config);
|
|
18
|
+
this.apiKey = config.apiKey;
|
|
19
|
+
this.projectName = config.projectName ?? "default";
|
|
20
|
+
this.endpoint = config.endpoint ?? "https://api.smith.langchain.com";
|
|
21
|
+
}
|
|
22
|
+
async initialize() {
|
|
23
|
+
if (this.initialized) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// Verify API key with a test request
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch(`${this.endpoint}/api/v1/info`, {
|
|
29
|
+
headers: { "x-api-key": this.apiKey },
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw new Error(`LangSmith initialization failed: ${response.statusText}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// Allow initialization to proceed even if API is unreachable
|
|
37
|
+
// This enables offline/test scenarios
|
|
38
|
+
logger.warn("[LangSmith] Could not verify API connection:", error instanceof Error ? error.message : error);
|
|
39
|
+
}
|
|
40
|
+
this.initialized = true;
|
|
41
|
+
this.startFlushInterval(this.config.flushIntervalMs ?? 5000);
|
|
42
|
+
}
|
|
43
|
+
async exportSpan(span) {
|
|
44
|
+
const startTime = Date.now();
|
|
45
|
+
try {
|
|
46
|
+
const langsmithRun = SpanSerializer.toLangSmithFormat(span);
|
|
47
|
+
const response = await fetch(`${this.endpoint}/api/v1/runs`, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
"x-api-key": this.apiKey,
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
...langsmithRun,
|
|
55
|
+
session_name: this.projectName,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error(`Export failed: ${response.statusText}`);
|
|
60
|
+
}
|
|
61
|
+
return this.createSuccessResult(1, Date.now() - startTime);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
return this.createFailureResult([span.spanId], error instanceof Error ? error.message : String(error), Date.now() - startTime);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async exportBatch(spans) {
|
|
68
|
+
const startTime = Date.now();
|
|
69
|
+
try {
|
|
70
|
+
const runs = spans.map((s) => ({
|
|
71
|
+
...SpanSerializer.toLangSmithFormat(s),
|
|
72
|
+
session_name: this.projectName,
|
|
73
|
+
}));
|
|
74
|
+
const response = await fetch(`${this.endpoint}/api/v1/runs/batch`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
"x-api-key": this.apiKey,
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify({ runs }),
|
|
81
|
+
});
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
throw new Error(`Batch export failed: ${response.statusText}`);
|
|
84
|
+
}
|
|
85
|
+
return this.createSuccessResult(spans.length, Date.now() - startTime);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return this.createFailureResult(spans.map((s) => s.spanId), error instanceof Error ? error.message : String(error), Date.now() - startTime);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async flush() {
|
|
92
|
+
if (this.buffer.length > 0) {
|
|
93
|
+
const spans = [...this.buffer];
|
|
94
|
+
this.buffer = [];
|
|
95
|
+
await this.exportBatch(spans);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async shutdown() {
|
|
99
|
+
await this.flush();
|
|
100
|
+
this.stopFlushInterval();
|
|
101
|
+
this.initialized = false;
|
|
102
|
+
}
|
|
103
|
+
async healthCheck() {
|
|
104
|
+
try {
|
|
105
|
+
await this.withRetry(() => this.ping(), "health check");
|
|
106
|
+
return this.createHealthStatus(true);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return this.createHealthStatus(false, ["Health check failed"]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Verify connectivity to LangSmith API
|
|
114
|
+
*/
|
|
115
|
+
async ping() {
|
|
116
|
+
const response = await fetch(`${this.endpoint}/api/v1/info`, {
|
|
117
|
+
headers: { "x-api-key": this.apiKey },
|
|
118
|
+
});
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(`LangSmith API unreachable: ${response.status}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|