@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.
@@ -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--b41_E-1.mjs';
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--b41_E-1.mjs';
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--b41_E-1.js';
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--b41_E-1.js';
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--b41_E-1.mjs';
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--b41_E-1.js';
1
+ export { a as ObservyzeExporterConfig, b as ObservyzeSpanExporter } from '../index-IZdiaORv.js';
2
2
  import '@observyze/types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@observyze/sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Node.js SDK for Observyze AI Observability Platform",
5
5
  "files": [
6
6
  "dist"