@observyze/sdk 0.1.3 → 0.1.4
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/index-IZdiaORv.d.mts +477 -0
- package/dist/index-IZdiaORv.d.ts +477 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +63 -0
- package/dist/index.mjs +63 -0
- package/dist/opentelemetry/index.d.mts +1 -1
- package/dist/opentelemetry/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { SpanType, TokenUsage, Span as Span$1, TraceStatus, Trace as Trace$1 } from '@observyze/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SDK Configuration and Types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for Observyze SDK client
|
|
9
|
+
*/
|
|
10
|
+
interface ClientConfig {
|
|
11
|
+
/**
|
|
12
|
+
* API key for authentication with Observyze Ingestion Service
|
|
13
|
+
*/
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/**
|
|
16
|
+
* Endpoint URL for the Ingestion Service
|
|
17
|
+
* @default 'http://localhost:3001'
|
|
18
|
+
*/
|
|
19
|
+
endpoint?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Maximum number of traces to buffer before flushing
|
|
22
|
+
* @default 100
|
|
23
|
+
*/
|
|
24
|
+
batchSize?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Time in milliseconds to wait before auto-flushing buffered traces
|
|
27
|
+
* @default 5000
|
|
28
|
+
*/
|
|
29
|
+
flushInterval?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Enable automatic instrumentation of popular LLM libraries
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
enableAutoInstrumentation?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Organization ID (optional, can be extracted from API key)
|
|
37
|
+
*/
|
|
38
|
+
organizationId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Project ID for trace attribution
|
|
41
|
+
*/
|
|
42
|
+
projectId?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Enable debug logging
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
debug?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Dry run mode - don't send traces to server (useful for testing)
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
dryRun?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Phase 5: Automatically scrub PII from trace output before network transmission
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
enablePiiRedaction?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Phase 4: Autonomous Circuit Breaker
|
|
60
|
+
* Hallucination score threshold (0-1) above which execution is blocked
|
|
61
|
+
* @default 0.8
|
|
62
|
+
*/
|
|
63
|
+
hallucinationThreshold?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Phase 4: Autonomous Circuit Breaker
|
|
66
|
+
* Safety score threshold (0-1) above which execution is blocked
|
|
67
|
+
* @default 0.9
|
|
68
|
+
*/
|
|
69
|
+
safetyThreshold?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Minimum confidence threshold for circuit breaker blocking (0-1).
|
|
72
|
+
* If confidence is below this threshold, high scores trigger alert-only instead of halt.
|
|
73
|
+
* @default 0.4
|
|
74
|
+
*/
|
|
75
|
+
confidenceThreshold?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Evaluation service URL for real-time guardrail checks
|
|
78
|
+
* In production, this should be https://api.observyze.com
|
|
79
|
+
* @default 'http://localhost:3000'
|
|
80
|
+
*/
|
|
81
|
+
evalEndpoint?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Enable circuit breaker - block execution on high hallucination/safety scores
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
enableCircuitBreaker?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Fail closed when evaluation service is unreachable.
|
|
89
|
+
* If true, guardrail checks will block execution on errors (safe default).
|
|
90
|
+
* If false, guardrail checks will allow execution on errors (fail open).
|
|
91
|
+
* @default true
|
|
92
|
+
*/
|
|
93
|
+
failClosed?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Automatically redirect LLM client (OpenAI, Anthropic) base URLs to Observyze proxy gateway
|
|
96
|
+
* to ensure Redis-backed circuit breakers are enforced.
|
|
97
|
+
* @default true
|
|
98
|
+
*/
|
|
99
|
+
enableProxyRedirect?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Internal configuration with defaults applied
|
|
103
|
+
*/
|
|
104
|
+
interface ResolvedClientConfig extends Required<ClientConfig> {
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Result of a connection test.
|
|
108
|
+
* Verifies the SDK can reach Observyze and send a real trace end-to-end.
|
|
109
|
+
*/
|
|
110
|
+
interface TestConnectionResult {
|
|
111
|
+
/** Whether the test trace was accepted by Observyze */
|
|
112
|
+
ok: boolean;
|
|
113
|
+
/** The trace ID of the sent test trace (present when ok === true) */
|
|
114
|
+
traceId?: string;
|
|
115
|
+
/** HTTP status returned by the API (present when the request failed) */
|
|
116
|
+
status?: number;
|
|
117
|
+
/** Human-readable message with the outcome or the exact failure reason */
|
|
118
|
+
message: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Result of a guardrail evaluation check.
|
|
122
|
+
* score is null when evaluation could not be performed.
|
|
123
|
+
*/
|
|
124
|
+
interface GuardrailResult {
|
|
125
|
+
pass: boolean;
|
|
126
|
+
/** The hallucination score (0-1), or null if evaluation failed */
|
|
127
|
+
score: number | null;
|
|
128
|
+
/** Confidence in the evaluation score (0-1), null if unavailable */
|
|
129
|
+
confidence?: number | null;
|
|
130
|
+
/** The safety score (0-1), or null if evaluation failed */
|
|
131
|
+
safetyScore?: number | null;
|
|
132
|
+
/** Human-readable reason for the result */
|
|
133
|
+
reason?: string;
|
|
134
|
+
/** How the evaluation was performed */
|
|
135
|
+
evaluationSource?: 'live' | 'consensus' | 'nli_fast_path' | 'error' | 'disabled' | 'fallback';
|
|
136
|
+
/** Why a live evaluation didn't happen (only set when evaluationSource is 'error' or 'fallback') */
|
|
137
|
+
fallbackReason?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Trace and Span classes for capturing AI workflow execution
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Represents an individual operation within a trace
|
|
146
|
+
*/
|
|
147
|
+
declare class Span {
|
|
148
|
+
private data;
|
|
149
|
+
private startTime;
|
|
150
|
+
constructor(name: string, type: SpanType, parentSpanId?: string);
|
|
151
|
+
/**
|
|
152
|
+
* Set the input data for this span
|
|
153
|
+
*/
|
|
154
|
+
setInput(input: any): this;
|
|
155
|
+
/**
|
|
156
|
+
* Set the output data for this span
|
|
157
|
+
*/
|
|
158
|
+
setOutput(output: any): this;
|
|
159
|
+
/**
|
|
160
|
+
* Record an error that occurred during span execution
|
|
161
|
+
*/
|
|
162
|
+
setError(error: Error): this;
|
|
163
|
+
/**
|
|
164
|
+
* Set metadata for this span
|
|
165
|
+
*/
|
|
166
|
+
setMetadata(key: string, value: any): this;
|
|
167
|
+
/**
|
|
168
|
+
* Set multiple metadata fields at once
|
|
169
|
+
*/
|
|
170
|
+
setMetadataAll(metadata: Record<string, any>): this;
|
|
171
|
+
/**
|
|
172
|
+
* Set token usage information
|
|
173
|
+
*/
|
|
174
|
+
setTokens(tokens: TokenUsage): this;
|
|
175
|
+
/**
|
|
176
|
+
* End the span and calculate duration
|
|
177
|
+
*/
|
|
178
|
+
end(): void;
|
|
179
|
+
/**
|
|
180
|
+
* Get the span ID
|
|
181
|
+
*/
|
|
182
|
+
get id(): string;
|
|
183
|
+
/**
|
|
184
|
+
* Get the span data for serialization
|
|
185
|
+
*/
|
|
186
|
+
toJSON(): Span$1;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Represents a complete AI workflow execution
|
|
190
|
+
*/
|
|
191
|
+
declare class Trace {
|
|
192
|
+
private data;
|
|
193
|
+
private startTime;
|
|
194
|
+
private spans;
|
|
195
|
+
private ended;
|
|
196
|
+
constructor(name: string, organizationId: string, projectId?: string);
|
|
197
|
+
/**
|
|
198
|
+
* Start a new span within this trace
|
|
199
|
+
*/
|
|
200
|
+
startSpan(name: string, type: SpanType, parentSpanId?: string): Span;
|
|
201
|
+
/**
|
|
202
|
+
* Add metadata to the trace
|
|
203
|
+
*/
|
|
204
|
+
setMetadata(key: string, value: any): this;
|
|
205
|
+
/**
|
|
206
|
+
* Set multiple metadata fields at once
|
|
207
|
+
*/
|
|
208
|
+
setMetadataAll(metadata: Record<string, any>): this;
|
|
209
|
+
/**
|
|
210
|
+
* Add tags to the trace
|
|
211
|
+
*/
|
|
212
|
+
addTag(tag: string): this;
|
|
213
|
+
/**
|
|
214
|
+
* Add multiple tags at once
|
|
215
|
+
*/
|
|
216
|
+
addTags(tags: string[]): this;
|
|
217
|
+
/**
|
|
218
|
+
* Set the user ID associated with this trace
|
|
219
|
+
*/
|
|
220
|
+
setUserId(userId: string): this;
|
|
221
|
+
/**
|
|
222
|
+
* Set the session ID associated with this trace
|
|
223
|
+
*/
|
|
224
|
+
setSessionId(sessionId: string): this;
|
|
225
|
+
/**
|
|
226
|
+
* End the trace with a final status
|
|
227
|
+
*/
|
|
228
|
+
end(status?: TraceStatus): void;
|
|
229
|
+
/**
|
|
230
|
+
* Get the trace ID
|
|
231
|
+
*/
|
|
232
|
+
get id(): string;
|
|
233
|
+
/**
|
|
234
|
+
* Check if the trace has ended
|
|
235
|
+
*/
|
|
236
|
+
get isEnded(): boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Get the trace data for serialization
|
|
239
|
+
*/
|
|
240
|
+
toJSON(): Omit<Trace$1, '_id' | 'created_at' | 'updated_at'>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Auto-Instrumentation API
|
|
245
|
+
* Provides nw.wrap() API for instrumenting LLM clients
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Supported client types for auto-instrumentation
|
|
250
|
+
*/
|
|
251
|
+
type SupportedClient = {
|
|
252
|
+
chat: {
|
|
253
|
+
completions: {
|
|
254
|
+
create: Function;
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
} | {
|
|
258
|
+
messages: {
|
|
259
|
+
create: Function;
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Detect the type of LLM client and apply appropriate instrumentation
|
|
264
|
+
*/
|
|
265
|
+
declare function wrap<T extends SupportedClient>(client: T, nwClient: ObservyzeClient): T;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Observyze SDK Client
|
|
269
|
+
* Main entry point for instrumenting AI applications
|
|
270
|
+
*/
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Main SDK client for Observyze
|
|
274
|
+
*/
|
|
275
|
+
declare class ObservyzeClient {
|
|
276
|
+
private config;
|
|
277
|
+
private traceBuffer;
|
|
278
|
+
private flushTimer;
|
|
279
|
+
private isShuttingDown;
|
|
280
|
+
private readonly MAX_QUEUE_SIZE;
|
|
281
|
+
private readonly RETRY_DELAYS;
|
|
282
|
+
/**
|
|
283
|
+
* Parse a JSON API error response and extract trace_id, error code, and message.
|
|
284
|
+
* The api-gateway error handler includes these fields in every error response.
|
|
285
|
+
*/
|
|
286
|
+
private static parseApiError;
|
|
287
|
+
/**
|
|
288
|
+
* Format an API error into a user-friendly message with trace_id for correlation.
|
|
289
|
+
* Example output:
|
|
290
|
+
* "Observyze API error (401 [ref: err_a1b2c3d4]): MISSING_PROVIDER_KEY — No API key configured..."
|
|
291
|
+
*/
|
|
292
|
+
private static formatApiError;
|
|
293
|
+
constructor(config: ClientConfig);
|
|
294
|
+
/**
|
|
295
|
+
* Start a new trace
|
|
296
|
+
*/
|
|
297
|
+
startTrace(name: string, metadata?: Record<string, any>): Trace;
|
|
298
|
+
/**
|
|
299
|
+
* Buffer a completed trace for batch sending
|
|
300
|
+
*/
|
|
301
|
+
private bufferTrace;
|
|
302
|
+
/**
|
|
303
|
+
* Start the auto-flush timer
|
|
304
|
+
*/
|
|
305
|
+
private startFlushTimer;
|
|
306
|
+
/**
|
|
307
|
+
* Flush all buffered traces to the Ingestion Service
|
|
308
|
+
*/
|
|
309
|
+
flush(): Promise<void>;
|
|
310
|
+
/**
|
|
311
|
+
* Send traces with exponential backoff retry
|
|
312
|
+
*/
|
|
313
|
+
private sendWithRetry;
|
|
314
|
+
/**
|
|
315
|
+
* Shutdown the SDK and flush remaining traces
|
|
316
|
+
*/
|
|
317
|
+
shutdown(): Promise<void>;
|
|
318
|
+
/**
|
|
319
|
+
* Get current buffer size
|
|
320
|
+
*/
|
|
321
|
+
get bufferSize(): number;
|
|
322
|
+
/**
|
|
323
|
+
* Get SDK configuration
|
|
324
|
+
*/
|
|
325
|
+
getConfig(): Readonly<ResolvedClientConfig>;
|
|
326
|
+
/**
|
|
327
|
+
* Wrap an LLM client (OpenAI, Anthropic) to enable auto-instrumentation
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* import OpenAI from 'openai'
|
|
332
|
+
* import { ObservyzeClient } from '@observyze/sdk'
|
|
333
|
+
*
|
|
334
|
+
* const nw = new ObservyzeClient({ apiKey: 'your-api-key' })
|
|
335
|
+
* const openai = new OpenAI({ apiKey: 'openai-key' })
|
|
336
|
+
*
|
|
337
|
+
* // Wrap the client to enable auto-instrumentation
|
|
338
|
+
* nw.wrap(openai)
|
|
339
|
+
*
|
|
340
|
+
* // All calls are now automatically traced
|
|
341
|
+
* const response = await openai.chat.completions.create({
|
|
342
|
+
* model: 'gpt-4',
|
|
343
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
344
|
+
* })
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
wrap<T extends SupportedClient>(client: T): T;
|
|
348
|
+
/**
|
|
349
|
+
* Verify that the SDK can reach Observyze and send traces end-to-end.
|
|
350
|
+
*
|
|
351
|
+
* This is the definitive "is my integration working?" test for SDK users.
|
|
352
|
+
* It sends a real test trace through the EXACT same pipeline used by
|
|
353
|
+
* `flush()` / the wrapped LLM clients (same endpoint, apiKey, retry logic),
|
|
354
|
+
* so a successful call proves the whole chain works from your code:
|
|
355
|
+
* - apiKey is valid and authorized
|
|
356
|
+
* - endpoint is reachable from your environment
|
|
357
|
+
* - organization / project resolution works
|
|
358
|
+
* - the ingest pipeline accepts and stores traces
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```typescript
|
|
362
|
+
* const nw = new ObservyzeClient({ apiKey: process.env.OBSERVYZE_API_KEY })
|
|
363
|
+
* const result = await nw.testConnection()
|
|
364
|
+
* // { ok: true, traceId: 'nw_xxx', message: 'Connection successful...' }
|
|
365
|
+
* ```
|
|
366
|
+
*
|
|
367
|
+
* The returned traceId can be searched in the Observyze dashboard (Traces →
|
|
368
|
+
* search the trace name "Observyze Connection Test") to confirm it landed.
|
|
369
|
+
*/
|
|
370
|
+
testConnection(): Promise<TestConnectionResult>;
|
|
371
|
+
/**
|
|
372
|
+
* Sync local agent .history file to Observyze cloud
|
|
373
|
+
* Parses JSON/NDJSON agent history and sends to ingestion endpoint.
|
|
374
|
+
*/
|
|
375
|
+
syncLocalHistory(filePath: string): Promise<void>;
|
|
376
|
+
/**
|
|
377
|
+
* Industry-grade PII Redaction (Compliance & RBAC)
|
|
378
|
+
*
|
|
379
|
+
* Recursively scrubs PII from trace data before transmission to the cloud.
|
|
380
|
+
* Coverage: emails, JWTs, bearer tokens, AWS/API keys, SSNs, credit cards,
|
|
381
|
+
* phone numbers (US + E.164), IPv4/IPv6, passport numbers, ZIP codes, plus
|
|
382
|
+
* key-based redaction for sensitive JSON fields (password, token, api_key, etc.).
|
|
383
|
+
*
|
|
384
|
+
* Design:
|
|
385
|
+
* - Pure function, never mutates the original object
|
|
386
|
+
* - Depth-limited to 16 levels to prevent stack overflow on deep agent outputs
|
|
387
|
+
* - Key-aware: sensitive key names are fully redacted regardless of value format
|
|
388
|
+
*/
|
|
389
|
+
private static readonly PII_PATTERNS;
|
|
390
|
+
private static readonly SENSITIVE_KEYS;
|
|
391
|
+
private static isSensitiveKey;
|
|
392
|
+
private sanitizePII;
|
|
393
|
+
/**
|
|
394
|
+
* Phase 4: Autonomous Circuit Breakers (Requirement 4.1)
|
|
395
|
+
* Evaluate a trace or text for hallucination in real-time.
|
|
396
|
+
* If hallucination score > hallucinationThreshold, the SDK blocks execution.
|
|
397
|
+
*
|
|
398
|
+
* Returns GuardrailResult with score: null when evaluation couldn't be performed.
|
|
399
|
+
* In failClosed mode, null scores result in blocked execution.
|
|
400
|
+
* In failOpen mode, null scores allow execution through.
|
|
401
|
+
*/
|
|
402
|
+
checkGuardrails(content: string | any): Promise<GuardrailResult>;
|
|
403
|
+
/**
|
|
404
|
+
* Phase 4: Autonomous Circuit Breakers
|
|
405
|
+
* Execute an agent action wrapped with the Circuit Breaker.
|
|
406
|
+
* Pauses execution if hallucination score >= hallucinationThreshold and requests human review.
|
|
407
|
+
* @throws Error when execution is blocked by circuit breaker
|
|
408
|
+
*/
|
|
409
|
+
executeWithCircuitBreaker<T>(agentExecution: () => Promise<T>, traceContext?: any): Promise<T>;
|
|
410
|
+
/**
|
|
411
|
+
* Phase 4: Bug Bounty Protocol (Automated) (Requirement 4.2)
|
|
412
|
+
* Automatically shard persistent failure cases to external security researcher endpoints (e.g. HackerOne wrapper)
|
|
413
|
+
*/
|
|
414
|
+
reportBugBounty(traceId: string, securityEndpoint: string, failureContext: any): Promise<void>;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Observyze OpenTelemetry Span Exporter
|
|
419
|
+
*
|
|
420
|
+
* Implements `@opentelemetry/sdk-trace-base`'s `SpanExporter` interface
|
|
421
|
+
* so users can use the standard OTel Node.js SDK and export spans to
|
|
422
|
+
* the Observyze platform.
|
|
423
|
+
*
|
|
424
|
+
* Usage:
|
|
425
|
+
* ```typescript
|
|
426
|
+
* import { ObservyzeClient } from '@observyze/sdk'
|
|
427
|
+
* import { ObservyzeSpanExporter } from '@observyze/sdk/opentelemetry'
|
|
428
|
+
* import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
429
|
+
* import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
430
|
+
*
|
|
431
|
+
* const nw = new ObservyzeClient({ apiKey: 'nw_...' })
|
|
432
|
+
*
|
|
433
|
+
* const sdk = new NodeSDK({
|
|
434
|
+
* spanProcessor: new BatchSpanProcessor(
|
|
435
|
+
* new ObservyzeSpanExporter(nw, { serviceName: 'my-app' })
|
|
436
|
+
* )
|
|
437
|
+
* })
|
|
438
|
+
* sdk.start()
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Exporter configuration
|
|
444
|
+
*/
|
|
445
|
+
interface ObservyzeExporterConfig {
|
|
446
|
+
serviceName?: string;
|
|
447
|
+
projectId?: string;
|
|
448
|
+
defaultSpanType?: SpanType | 'llm' | 'tool' | 'agent' | 'chain' | 'retrieval';
|
|
449
|
+
headers?: Record<string, string>;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Observyze OpenTelemetry Span Exporter
|
|
453
|
+
*/
|
|
454
|
+
declare class ObservyzeSpanExporter {
|
|
455
|
+
private client;
|
|
456
|
+
private config;
|
|
457
|
+
constructor(client: ObservyzeClient, config?: ObservyzeExporterConfig);
|
|
458
|
+
/**
|
|
459
|
+
* Export spans — called by OTel SDK when spans are ready.
|
|
460
|
+
* Converts OTel spans to Observyze traces and buffers them.
|
|
461
|
+
*/
|
|
462
|
+
export(spans: any[], resultCallback: (result: {
|
|
463
|
+
code: number;
|
|
464
|
+
error?: Error;
|
|
465
|
+
}) => void): Promise<void>;
|
|
466
|
+
/**
|
|
467
|
+
* Called when the exporter is shut down.
|
|
468
|
+
* Flushes any remaining buffered traces via the SDK client.
|
|
469
|
+
*/
|
|
470
|
+
shutdown(): Promise<void>;
|
|
471
|
+
/**
|
|
472
|
+
* Called by the OTel SDK to force-export buffered spans.
|
|
473
|
+
*/
|
|
474
|
+
forceFlush(): Promise<void>;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export { type ClientConfig as C, ObservyzeClient as O, type ResolvedClientConfig as R, Span as S, type TestConnectionResult as T, type ObservyzeExporterConfig as a, ObservyzeSpanExporter as b, type SupportedClient as c, Trace as d, wrap as w };
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { SpanType, TokenUsage, Span as Span$1, TraceStatus, Trace as Trace$1 } from '@observyze/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SDK Configuration and Types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for Observyze SDK client
|
|
9
|
+
*/
|
|
10
|
+
interface ClientConfig {
|
|
11
|
+
/**
|
|
12
|
+
* API key for authentication with Observyze Ingestion Service
|
|
13
|
+
*/
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/**
|
|
16
|
+
* Endpoint URL for the Ingestion Service
|
|
17
|
+
* @default 'http://localhost:3001'
|
|
18
|
+
*/
|
|
19
|
+
endpoint?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Maximum number of traces to buffer before flushing
|
|
22
|
+
* @default 100
|
|
23
|
+
*/
|
|
24
|
+
batchSize?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Time in milliseconds to wait before auto-flushing buffered traces
|
|
27
|
+
* @default 5000
|
|
28
|
+
*/
|
|
29
|
+
flushInterval?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Enable automatic instrumentation of popular LLM libraries
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
enableAutoInstrumentation?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Organization ID (optional, can be extracted from API key)
|
|
37
|
+
*/
|
|
38
|
+
organizationId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Project ID for trace attribution
|
|
41
|
+
*/
|
|
42
|
+
projectId?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Enable debug logging
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
debug?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Dry run mode - don't send traces to server (useful for testing)
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
dryRun?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Phase 5: Automatically scrub PII from trace output before network transmission
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
enablePiiRedaction?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Phase 4: Autonomous Circuit Breaker
|
|
60
|
+
* Hallucination score threshold (0-1) above which execution is blocked
|
|
61
|
+
* @default 0.8
|
|
62
|
+
*/
|
|
63
|
+
hallucinationThreshold?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Phase 4: Autonomous Circuit Breaker
|
|
66
|
+
* Safety score threshold (0-1) above which execution is blocked
|
|
67
|
+
* @default 0.9
|
|
68
|
+
*/
|
|
69
|
+
safetyThreshold?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Minimum confidence threshold for circuit breaker blocking (0-1).
|
|
72
|
+
* If confidence is below this threshold, high scores trigger alert-only instead of halt.
|
|
73
|
+
* @default 0.4
|
|
74
|
+
*/
|
|
75
|
+
confidenceThreshold?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Evaluation service URL for real-time guardrail checks
|
|
78
|
+
* In production, this should be https://api.observyze.com
|
|
79
|
+
* @default 'http://localhost:3000'
|
|
80
|
+
*/
|
|
81
|
+
evalEndpoint?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Enable circuit breaker - block execution on high hallucination/safety scores
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
enableCircuitBreaker?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Fail closed when evaluation service is unreachable.
|
|
89
|
+
* If true, guardrail checks will block execution on errors (safe default).
|
|
90
|
+
* If false, guardrail checks will allow execution on errors (fail open).
|
|
91
|
+
* @default true
|
|
92
|
+
*/
|
|
93
|
+
failClosed?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Automatically redirect LLM client (OpenAI, Anthropic) base URLs to Observyze proxy gateway
|
|
96
|
+
* to ensure Redis-backed circuit breakers are enforced.
|
|
97
|
+
* @default true
|
|
98
|
+
*/
|
|
99
|
+
enableProxyRedirect?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Internal configuration with defaults applied
|
|
103
|
+
*/
|
|
104
|
+
interface ResolvedClientConfig extends Required<ClientConfig> {
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Result of a connection test.
|
|
108
|
+
* Verifies the SDK can reach Observyze and send a real trace end-to-end.
|
|
109
|
+
*/
|
|
110
|
+
interface TestConnectionResult {
|
|
111
|
+
/** Whether the test trace was accepted by Observyze */
|
|
112
|
+
ok: boolean;
|
|
113
|
+
/** The trace ID of the sent test trace (present when ok === true) */
|
|
114
|
+
traceId?: string;
|
|
115
|
+
/** HTTP status returned by the API (present when the request failed) */
|
|
116
|
+
status?: number;
|
|
117
|
+
/** Human-readable message with the outcome or the exact failure reason */
|
|
118
|
+
message: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Result of a guardrail evaluation check.
|
|
122
|
+
* score is null when evaluation could not be performed.
|
|
123
|
+
*/
|
|
124
|
+
interface GuardrailResult {
|
|
125
|
+
pass: boolean;
|
|
126
|
+
/** The hallucination score (0-1), or null if evaluation failed */
|
|
127
|
+
score: number | null;
|
|
128
|
+
/** Confidence in the evaluation score (0-1), null if unavailable */
|
|
129
|
+
confidence?: number | null;
|
|
130
|
+
/** The safety score (0-1), or null if evaluation failed */
|
|
131
|
+
safetyScore?: number | null;
|
|
132
|
+
/** Human-readable reason for the result */
|
|
133
|
+
reason?: string;
|
|
134
|
+
/** How the evaluation was performed */
|
|
135
|
+
evaluationSource?: 'live' | 'consensus' | 'nli_fast_path' | 'error' | 'disabled' | 'fallback';
|
|
136
|
+
/** Why a live evaluation didn't happen (only set when evaluationSource is 'error' or 'fallback') */
|
|
137
|
+
fallbackReason?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Trace and Span classes for capturing AI workflow execution
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Represents an individual operation within a trace
|
|
146
|
+
*/
|
|
147
|
+
declare class Span {
|
|
148
|
+
private data;
|
|
149
|
+
private startTime;
|
|
150
|
+
constructor(name: string, type: SpanType, parentSpanId?: string);
|
|
151
|
+
/**
|
|
152
|
+
* Set the input data for this span
|
|
153
|
+
*/
|
|
154
|
+
setInput(input: any): this;
|
|
155
|
+
/**
|
|
156
|
+
* Set the output data for this span
|
|
157
|
+
*/
|
|
158
|
+
setOutput(output: any): this;
|
|
159
|
+
/**
|
|
160
|
+
* Record an error that occurred during span execution
|
|
161
|
+
*/
|
|
162
|
+
setError(error: Error): this;
|
|
163
|
+
/**
|
|
164
|
+
* Set metadata for this span
|
|
165
|
+
*/
|
|
166
|
+
setMetadata(key: string, value: any): this;
|
|
167
|
+
/**
|
|
168
|
+
* Set multiple metadata fields at once
|
|
169
|
+
*/
|
|
170
|
+
setMetadataAll(metadata: Record<string, any>): this;
|
|
171
|
+
/**
|
|
172
|
+
* Set token usage information
|
|
173
|
+
*/
|
|
174
|
+
setTokens(tokens: TokenUsage): this;
|
|
175
|
+
/**
|
|
176
|
+
* End the span and calculate duration
|
|
177
|
+
*/
|
|
178
|
+
end(): void;
|
|
179
|
+
/**
|
|
180
|
+
* Get the span ID
|
|
181
|
+
*/
|
|
182
|
+
get id(): string;
|
|
183
|
+
/**
|
|
184
|
+
* Get the span data for serialization
|
|
185
|
+
*/
|
|
186
|
+
toJSON(): Span$1;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Represents a complete AI workflow execution
|
|
190
|
+
*/
|
|
191
|
+
declare class Trace {
|
|
192
|
+
private data;
|
|
193
|
+
private startTime;
|
|
194
|
+
private spans;
|
|
195
|
+
private ended;
|
|
196
|
+
constructor(name: string, organizationId: string, projectId?: string);
|
|
197
|
+
/**
|
|
198
|
+
* Start a new span within this trace
|
|
199
|
+
*/
|
|
200
|
+
startSpan(name: string, type: SpanType, parentSpanId?: string): Span;
|
|
201
|
+
/**
|
|
202
|
+
* Add metadata to the trace
|
|
203
|
+
*/
|
|
204
|
+
setMetadata(key: string, value: any): this;
|
|
205
|
+
/**
|
|
206
|
+
* Set multiple metadata fields at once
|
|
207
|
+
*/
|
|
208
|
+
setMetadataAll(metadata: Record<string, any>): this;
|
|
209
|
+
/**
|
|
210
|
+
* Add tags to the trace
|
|
211
|
+
*/
|
|
212
|
+
addTag(tag: string): this;
|
|
213
|
+
/**
|
|
214
|
+
* Add multiple tags at once
|
|
215
|
+
*/
|
|
216
|
+
addTags(tags: string[]): this;
|
|
217
|
+
/**
|
|
218
|
+
* Set the user ID associated with this trace
|
|
219
|
+
*/
|
|
220
|
+
setUserId(userId: string): this;
|
|
221
|
+
/**
|
|
222
|
+
* Set the session ID associated with this trace
|
|
223
|
+
*/
|
|
224
|
+
setSessionId(sessionId: string): this;
|
|
225
|
+
/**
|
|
226
|
+
* End the trace with a final status
|
|
227
|
+
*/
|
|
228
|
+
end(status?: TraceStatus): void;
|
|
229
|
+
/**
|
|
230
|
+
* Get the trace ID
|
|
231
|
+
*/
|
|
232
|
+
get id(): string;
|
|
233
|
+
/**
|
|
234
|
+
* Check if the trace has ended
|
|
235
|
+
*/
|
|
236
|
+
get isEnded(): boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Get the trace data for serialization
|
|
239
|
+
*/
|
|
240
|
+
toJSON(): Omit<Trace$1, '_id' | 'created_at' | 'updated_at'>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Auto-Instrumentation API
|
|
245
|
+
* Provides nw.wrap() API for instrumenting LLM clients
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Supported client types for auto-instrumentation
|
|
250
|
+
*/
|
|
251
|
+
type SupportedClient = {
|
|
252
|
+
chat: {
|
|
253
|
+
completions: {
|
|
254
|
+
create: Function;
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
} | {
|
|
258
|
+
messages: {
|
|
259
|
+
create: Function;
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Detect the type of LLM client and apply appropriate instrumentation
|
|
264
|
+
*/
|
|
265
|
+
declare function wrap<T extends SupportedClient>(client: T, nwClient: ObservyzeClient): T;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Observyze SDK Client
|
|
269
|
+
* Main entry point for instrumenting AI applications
|
|
270
|
+
*/
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Main SDK client for Observyze
|
|
274
|
+
*/
|
|
275
|
+
declare class ObservyzeClient {
|
|
276
|
+
private config;
|
|
277
|
+
private traceBuffer;
|
|
278
|
+
private flushTimer;
|
|
279
|
+
private isShuttingDown;
|
|
280
|
+
private readonly MAX_QUEUE_SIZE;
|
|
281
|
+
private readonly RETRY_DELAYS;
|
|
282
|
+
/**
|
|
283
|
+
* Parse a JSON API error response and extract trace_id, error code, and message.
|
|
284
|
+
* The api-gateway error handler includes these fields in every error response.
|
|
285
|
+
*/
|
|
286
|
+
private static parseApiError;
|
|
287
|
+
/**
|
|
288
|
+
* Format an API error into a user-friendly message with trace_id for correlation.
|
|
289
|
+
* Example output:
|
|
290
|
+
* "Observyze API error (401 [ref: err_a1b2c3d4]): MISSING_PROVIDER_KEY — No API key configured..."
|
|
291
|
+
*/
|
|
292
|
+
private static formatApiError;
|
|
293
|
+
constructor(config: ClientConfig);
|
|
294
|
+
/**
|
|
295
|
+
* Start a new trace
|
|
296
|
+
*/
|
|
297
|
+
startTrace(name: string, metadata?: Record<string, any>): Trace;
|
|
298
|
+
/**
|
|
299
|
+
* Buffer a completed trace for batch sending
|
|
300
|
+
*/
|
|
301
|
+
private bufferTrace;
|
|
302
|
+
/**
|
|
303
|
+
* Start the auto-flush timer
|
|
304
|
+
*/
|
|
305
|
+
private startFlushTimer;
|
|
306
|
+
/**
|
|
307
|
+
* Flush all buffered traces to the Ingestion Service
|
|
308
|
+
*/
|
|
309
|
+
flush(): Promise<void>;
|
|
310
|
+
/**
|
|
311
|
+
* Send traces with exponential backoff retry
|
|
312
|
+
*/
|
|
313
|
+
private sendWithRetry;
|
|
314
|
+
/**
|
|
315
|
+
* Shutdown the SDK and flush remaining traces
|
|
316
|
+
*/
|
|
317
|
+
shutdown(): Promise<void>;
|
|
318
|
+
/**
|
|
319
|
+
* Get current buffer size
|
|
320
|
+
*/
|
|
321
|
+
get bufferSize(): number;
|
|
322
|
+
/**
|
|
323
|
+
* Get SDK configuration
|
|
324
|
+
*/
|
|
325
|
+
getConfig(): Readonly<ResolvedClientConfig>;
|
|
326
|
+
/**
|
|
327
|
+
* Wrap an LLM client (OpenAI, Anthropic) to enable auto-instrumentation
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* import OpenAI from 'openai'
|
|
332
|
+
* import { ObservyzeClient } from '@observyze/sdk'
|
|
333
|
+
*
|
|
334
|
+
* const nw = new ObservyzeClient({ apiKey: 'your-api-key' })
|
|
335
|
+
* const openai = new OpenAI({ apiKey: 'openai-key' })
|
|
336
|
+
*
|
|
337
|
+
* // Wrap the client to enable auto-instrumentation
|
|
338
|
+
* nw.wrap(openai)
|
|
339
|
+
*
|
|
340
|
+
* // All calls are now automatically traced
|
|
341
|
+
* const response = await openai.chat.completions.create({
|
|
342
|
+
* model: 'gpt-4',
|
|
343
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
344
|
+
* })
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
wrap<T extends SupportedClient>(client: T): T;
|
|
348
|
+
/**
|
|
349
|
+
* Verify that the SDK can reach Observyze and send traces end-to-end.
|
|
350
|
+
*
|
|
351
|
+
* This is the definitive "is my integration working?" test for SDK users.
|
|
352
|
+
* It sends a real test trace through the EXACT same pipeline used by
|
|
353
|
+
* `flush()` / the wrapped LLM clients (same endpoint, apiKey, retry logic),
|
|
354
|
+
* so a successful call proves the whole chain works from your code:
|
|
355
|
+
* - apiKey is valid and authorized
|
|
356
|
+
* - endpoint is reachable from your environment
|
|
357
|
+
* - organization / project resolution works
|
|
358
|
+
* - the ingest pipeline accepts and stores traces
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```typescript
|
|
362
|
+
* const nw = new ObservyzeClient({ apiKey: process.env.OBSERVYZE_API_KEY })
|
|
363
|
+
* const result = await nw.testConnection()
|
|
364
|
+
* // { ok: true, traceId: 'nw_xxx', message: 'Connection successful...' }
|
|
365
|
+
* ```
|
|
366
|
+
*
|
|
367
|
+
* The returned traceId can be searched in the Observyze dashboard (Traces →
|
|
368
|
+
* search the trace name "Observyze Connection Test") to confirm it landed.
|
|
369
|
+
*/
|
|
370
|
+
testConnection(): Promise<TestConnectionResult>;
|
|
371
|
+
/**
|
|
372
|
+
* Sync local agent .history file to Observyze cloud
|
|
373
|
+
* Parses JSON/NDJSON agent history and sends to ingestion endpoint.
|
|
374
|
+
*/
|
|
375
|
+
syncLocalHistory(filePath: string): Promise<void>;
|
|
376
|
+
/**
|
|
377
|
+
* Industry-grade PII Redaction (Compliance & RBAC)
|
|
378
|
+
*
|
|
379
|
+
* Recursively scrubs PII from trace data before transmission to the cloud.
|
|
380
|
+
* Coverage: emails, JWTs, bearer tokens, AWS/API keys, SSNs, credit cards,
|
|
381
|
+
* phone numbers (US + E.164), IPv4/IPv6, passport numbers, ZIP codes, plus
|
|
382
|
+
* key-based redaction for sensitive JSON fields (password, token, api_key, etc.).
|
|
383
|
+
*
|
|
384
|
+
* Design:
|
|
385
|
+
* - Pure function, never mutates the original object
|
|
386
|
+
* - Depth-limited to 16 levels to prevent stack overflow on deep agent outputs
|
|
387
|
+
* - Key-aware: sensitive key names are fully redacted regardless of value format
|
|
388
|
+
*/
|
|
389
|
+
private static readonly PII_PATTERNS;
|
|
390
|
+
private static readonly SENSITIVE_KEYS;
|
|
391
|
+
private static isSensitiveKey;
|
|
392
|
+
private sanitizePII;
|
|
393
|
+
/**
|
|
394
|
+
* Phase 4: Autonomous Circuit Breakers (Requirement 4.1)
|
|
395
|
+
* Evaluate a trace or text for hallucination in real-time.
|
|
396
|
+
* If hallucination score > hallucinationThreshold, the SDK blocks execution.
|
|
397
|
+
*
|
|
398
|
+
* Returns GuardrailResult with score: null when evaluation couldn't be performed.
|
|
399
|
+
* In failClosed mode, null scores result in blocked execution.
|
|
400
|
+
* In failOpen mode, null scores allow execution through.
|
|
401
|
+
*/
|
|
402
|
+
checkGuardrails(content: string | any): Promise<GuardrailResult>;
|
|
403
|
+
/**
|
|
404
|
+
* Phase 4: Autonomous Circuit Breakers
|
|
405
|
+
* Execute an agent action wrapped with the Circuit Breaker.
|
|
406
|
+
* Pauses execution if hallucination score >= hallucinationThreshold and requests human review.
|
|
407
|
+
* @throws Error when execution is blocked by circuit breaker
|
|
408
|
+
*/
|
|
409
|
+
executeWithCircuitBreaker<T>(agentExecution: () => Promise<T>, traceContext?: any): Promise<T>;
|
|
410
|
+
/**
|
|
411
|
+
* Phase 4: Bug Bounty Protocol (Automated) (Requirement 4.2)
|
|
412
|
+
* Automatically shard persistent failure cases to external security researcher endpoints (e.g. HackerOne wrapper)
|
|
413
|
+
*/
|
|
414
|
+
reportBugBounty(traceId: string, securityEndpoint: string, failureContext: any): Promise<void>;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Observyze OpenTelemetry Span Exporter
|
|
419
|
+
*
|
|
420
|
+
* Implements `@opentelemetry/sdk-trace-base`'s `SpanExporter` interface
|
|
421
|
+
* so users can use the standard OTel Node.js SDK and export spans to
|
|
422
|
+
* the Observyze platform.
|
|
423
|
+
*
|
|
424
|
+
* Usage:
|
|
425
|
+
* ```typescript
|
|
426
|
+
* import { ObservyzeClient } from '@observyze/sdk'
|
|
427
|
+
* import { ObservyzeSpanExporter } from '@observyze/sdk/opentelemetry'
|
|
428
|
+
* import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
429
|
+
* import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
430
|
+
*
|
|
431
|
+
* const nw = new ObservyzeClient({ apiKey: 'nw_...' })
|
|
432
|
+
*
|
|
433
|
+
* const sdk = new NodeSDK({
|
|
434
|
+
* spanProcessor: new BatchSpanProcessor(
|
|
435
|
+
* new ObservyzeSpanExporter(nw, { serviceName: 'my-app' })
|
|
436
|
+
* )
|
|
437
|
+
* })
|
|
438
|
+
* sdk.start()
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Exporter configuration
|
|
444
|
+
*/
|
|
445
|
+
interface ObservyzeExporterConfig {
|
|
446
|
+
serviceName?: string;
|
|
447
|
+
projectId?: string;
|
|
448
|
+
defaultSpanType?: SpanType | 'llm' | 'tool' | 'agent' | 'chain' | 'retrieval';
|
|
449
|
+
headers?: Record<string, string>;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Observyze OpenTelemetry Span Exporter
|
|
453
|
+
*/
|
|
454
|
+
declare class ObservyzeSpanExporter {
|
|
455
|
+
private client;
|
|
456
|
+
private config;
|
|
457
|
+
constructor(client: ObservyzeClient, config?: ObservyzeExporterConfig);
|
|
458
|
+
/**
|
|
459
|
+
* Export spans — called by OTel SDK when spans are ready.
|
|
460
|
+
* Converts OTel spans to Observyze traces and buffers them.
|
|
461
|
+
*/
|
|
462
|
+
export(spans: any[], resultCallback: (result: {
|
|
463
|
+
code: number;
|
|
464
|
+
error?: Error;
|
|
465
|
+
}) => void): Promise<void>;
|
|
466
|
+
/**
|
|
467
|
+
* Called when the exporter is shut down.
|
|
468
|
+
* Flushes any remaining buffered traces via the SDK client.
|
|
469
|
+
*/
|
|
470
|
+
shutdown(): Promise<void>;
|
|
471
|
+
/**
|
|
472
|
+
* Called by the OTel SDK to force-export buffered spans.
|
|
473
|
+
*/
|
|
474
|
+
forceFlush(): Promise<void>;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export { type ClientConfig as C, ObservyzeClient as O, type ResolvedClientConfig as R, Span as S, type TestConnectionResult as T, type ObservyzeExporterConfig as a, ObservyzeSpanExporter as b, type SupportedClient as c, Trace as d, wrap as w };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as ObservyzeClient } from './index
|
|
2
|
-
export { C as ClientConfig, a as ObservyzeExporterConfig, b as ObservyzeSpanExporter, R as ResolvedClientConfig, S as Span, c as SupportedClient, T as Trace, w as wrap } from './index
|
|
1
|
+
import { O as ObservyzeClient } from './index-IZdiaORv.mjs';
|
|
2
|
+
export { C as ClientConfig, a as ObservyzeExporterConfig, b as ObservyzeSpanExporter, R as ResolvedClientConfig, S as Span, c as SupportedClient, T as TestConnectionResult, d as Trace, w as wrap } from './index-IZdiaORv.mjs';
|
|
3
3
|
export { Span as SpanData, SpanError, SpanType, TokenUsage, Trace as TraceData, TraceStatus } from '@observyze/types';
|
|
4
4
|
|
|
5
5
|
interface OpenAIClient {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as ObservyzeClient } from './index
|
|
2
|
-
export { C as ClientConfig, a as ObservyzeExporterConfig, b as ObservyzeSpanExporter, R as ResolvedClientConfig, S as Span, c as SupportedClient, T as Trace, w as wrap } from './index
|
|
1
|
+
import { O as ObservyzeClient } from './index-IZdiaORv.js';
|
|
2
|
+
export { C as ClientConfig, a as ObservyzeExporterConfig, b as ObservyzeSpanExporter, R as ResolvedClientConfig, S as Span, c as SupportedClient, T as TestConnectionResult, d as Trace, w as wrap } from './index-IZdiaORv.js';
|
|
3
3
|
export { Span as SpanData, SpanError, SpanType, TokenUsage, Trace as TraceData, TraceStatus } from '@observyze/types';
|
|
4
4
|
|
|
5
5
|
interface OpenAIClient {
|
package/dist/index.js
CHANGED
|
@@ -804,6 +804,69 @@ var ObservyzeClient = class _ObservyzeClient {
|
|
|
804
804
|
wrap(client) {
|
|
805
805
|
return wrap(client, this);
|
|
806
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* Verify that the SDK can reach Observyze and send traces end-to-end.
|
|
809
|
+
*
|
|
810
|
+
* This is the definitive "is my integration working?" test for SDK users.
|
|
811
|
+
* It sends a real test trace through the EXACT same pipeline used by
|
|
812
|
+
* `flush()` / the wrapped LLM clients (same endpoint, apiKey, retry logic),
|
|
813
|
+
* so a successful call proves the whole chain works from your code:
|
|
814
|
+
* - apiKey is valid and authorized
|
|
815
|
+
* - endpoint is reachable from your environment
|
|
816
|
+
* - organization / project resolution works
|
|
817
|
+
* - the ingest pipeline accepts and stores traces
|
|
818
|
+
*
|
|
819
|
+
* @example
|
|
820
|
+
* ```typescript
|
|
821
|
+
* const nw = new ObservyzeClient({ apiKey: process.env.OBSERVYZE_API_KEY })
|
|
822
|
+
* const result = await nw.testConnection()
|
|
823
|
+
* // { ok: true, traceId: 'nw_xxx', message: 'Connection successful...' }
|
|
824
|
+
* ```
|
|
825
|
+
*
|
|
826
|
+
* The returned traceId can be searched in the Observyze dashboard (Traces →
|
|
827
|
+
* search the trace name "Observyze Connection Test") to confirm it landed.
|
|
828
|
+
*/
|
|
829
|
+
async testConnection() {
|
|
830
|
+
if (this.config.dryRun) {
|
|
831
|
+
return {
|
|
832
|
+
ok: false,
|
|
833
|
+
message: "Dry-run mode is enabled, so no trace was actually sent. Set dryRun: false to run a real connection test."
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
const trace = new Trace(
|
|
837
|
+
"Observyze Connection Test",
|
|
838
|
+
this.config.organizationId,
|
|
839
|
+
this.config.projectId
|
|
840
|
+
);
|
|
841
|
+
const span = trace.startSpan("connection-test", import_types.SpanType.LLM);
|
|
842
|
+
span.setInput({ prompt: "Observyze SDK connection test" });
|
|
843
|
+
span.setOutput({ response: "Connection successful" });
|
|
844
|
+
span.setTokens({ input: 5, output: 4, total: 9 });
|
|
845
|
+
span.setMetadata("source", "sdk-test-connection");
|
|
846
|
+
span.end();
|
|
847
|
+
trace.setMetadata("source", "sdk-test-connection");
|
|
848
|
+
trace.addTag("setup-test");
|
|
849
|
+
trace.end(import_types.TraceStatus.SUCCESS);
|
|
850
|
+
try {
|
|
851
|
+
await this.sendWithRetry([trace]);
|
|
852
|
+
return {
|
|
853
|
+
ok: true,
|
|
854
|
+
traceId: trace.id,
|
|
855
|
+
message: `Connection successful. Test trace ${trace.id} was sent to Observyze. Search for "Observyze Connection Test" in Dashboard \u2192 Traces to confirm it landed.`
|
|
856
|
+
};
|
|
857
|
+
} catch (error) {
|
|
858
|
+
const rawMessage = error?.message || String(error);
|
|
859
|
+
const statusMatch = rawMessage.match(/\((\d{3})/);
|
|
860
|
+
const isNetworkFailure = !statusMatch && /fetch|network|ENOTFOUND|ECONNREFUSED|ETIMEDOUT/i.test(rawMessage);
|
|
861
|
+
const defaultEndpoint = "http://localhost:3001";
|
|
862
|
+
const hint = isNetworkFailure && this.config.endpoint === defaultEndpoint ? ` You are using the default endpoint (${defaultEndpoint}). For production, set endpoint: "https://api.observyze.com" in the ObservyzeClient config, then re-run.` : isNetworkFailure ? " Check that your endpoint is reachable from this environment (firewalls, proxies, DNS) and that you are not using a local endpoint in production." : "";
|
|
863
|
+
return {
|
|
864
|
+
ok: false,
|
|
865
|
+
...statusMatch ? { status: parseInt(statusMatch[1], 10) } : {},
|
|
866
|
+
message: rawMessage + hint
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
}
|
|
807
870
|
/**
|
|
808
871
|
* Sync local agent .history file to Observyze cloud
|
|
809
872
|
* Parses JSON/NDJSON agent history and sends to ingestion endpoint.
|
package/dist/index.mjs
CHANGED
|
@@ -563,6 +563,69 @@ var ObservyzeClient = class _ObservyzeClient {
|
|
|
563
563
|
wrap(client) {
|
|
564
564
|
return wrap(client, this);
|
|
565
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* Verify that the SDK can reach Observyze and send traces end-to-end.
|
|
568
|
+
*
|
|
569
|
+
* This is the definitive "is my integration working?" test for SDK users.
|
|
570
|
+
* It sends a real test trace through the EXACT same pipeline used by
|
|
571
|
+
* `flush()` / the wrapped LLM clients (same endpoint, apiKey, retry logic),
|
|
572
|
+
* so a successful call proves the whole chain works from your code:
|
|
573
|
+
* - apiKey is valid and authorized
|
|
574
|
+
* - endpoint is reachable from your environment
|
|
575
|
+
* - organization / project resolution works
|
|
576
|
+
* - the ingest pipeline accepts and stores traces
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```typescript
|
|
580
|
+
* const nw = new ObservyzeClient({ apiKey: process.env.OBSERVYZE_API_KEY })
|
|
581
|
+
* const result = await nw.testConnection()
|
|
582
|
+
* // { ok: true, traceId: 'nw_xxx', message: 'Connection successful...' }
|
|
583
|
+
* ```
|
|
584
|
+
*
|
|
585
|
+
* The returned traceId can be searched in the Observyze dashboard (Traces →
|
|
586
|
+
* search the trace name "Observyze Connection Test") to confirm it landed.
|
|
587
|
+
*/
|
|
588
|
+
async testConnection() {
|
|
589
|
+
if (this.config.dryRun) {
|
|
590
|
+
return {
|
|
591
|
+
ok: false,
|
|
592
|
+
message: "Dry-run mode is enabled, so no trace was actually sent. Set dryRun: false to run a real connection test."
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
const trace = new Trace(
|
|
596
|
+
"Observyze Connection Test",
|
|
597
|
+
this.config.organizationId,
|
|
598
|
+
this.config.projectId
|
|
599
|
+
);
|
|
600
|
+
const span = trace.startSpan("connection-test", SpanType.LLM);
|
|
601
|
+
span.setInput({ prompt: "Observyze SDK connection test" });
|
|
602
|
+
span.setOutput({ response: "Connection successful" });
|
|
603
|
+
span.setTokens({ input: 5, output: 4, total: 9 });
|
|
604
|
+
span.setMetadata("source", "sdk-test-connection");
|
|
605
|
+
span.end();
|
|
606
|
+
trace.setMetadata("source", "sdk-test-connection");
|
|
607
|
+
trace.addTag("setup-test");
|
|
608
|
+
trace.end(TraceStatus.SUCCESS);
|
|
609
|
+
try {
|
|
610
|
+
await this.sendWithRetry([trace]);
|
|
611
|
+
return {
|
|
612
|
+
ok: true,
|
|
613
|
+
traceId: trace.id,
|
|
614
|
+
message: `Connection successful. Test trace ${trace.id} was sent to Observyze. Search for "Observyze Connection Test" in Dashboard \u2192 Traces to confirm it landed.`
|
|
615
|
+
};
|
|
616
|
+
} catch (error) {
|
|
617
|
+
const rawMessage = error?.message || String(error);
|
|
618
|
+
const statusMatch = rawMessage.match(/\((\d{3})/);
|
|
619
|
+
const isNetworkFailure = !statusMatch && /fetch|network|ENOTFOUND|ECONNREFUSED|ETIMEDOUT/i.test(rawMessage);
|
|
620
|
+
const defaultEndpoint = "http://localhost:3001";
|
|
621
|
+
const hint = isNetworkFailure && this.config.endpoint === defaultEndpoint ? ` You are using the default endpoint (${defaultEndpoint}). For production, set endpoint: "https://api.observyze.com" in the ObservyzeClient config, then re-run.` : isNetworkFailure ? " Check that your endpoint is reachable from this environment (firewalls, proxies, DNS) and that you are not using a local endpoint in production." : "";
|
|
622
|
+
return {
|
|
623
|
+
ok: false,
|
|
624
|
+
...statusMatch ? { status: parseInt(statusMatch[1], 10) } : {},
|
|
625
|
+
message: rawMessage + hint
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
}
|
|
566
629
|
/**
|
|
567
630
|
* Sync local agent .history file to Observyze cloud
|
|
568
631
|
* Parses JSON/NDJSON agent history and sends to ingestion endpoint.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { a as ObservyzeExporterConfig, b as ObservyzeSpanExporter } from '../index
|
|
1
|
+
export { a as ObservyzeExporterConfig, b as ObservyzeSpanExporter } from '../index-IZdiaORv.mjs';
|
|
2
2
|
import '@observyze/types';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { a as ObservyzeExporterConfig, b as ObservyzeSpanExporter } from '../index
|
|
1
|
+
export { a as ObservyzeExporterConfig, b as ObservyzeSpanExporter } from '../index-IZdiaORv.js';
|
|
2
2
|
import '@observyze/types';
|