@observyze/sdk 0.1.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/src/trace.ts ADDED
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Trace and Span classes for capturing AI workflow execution
3
+ */
4
+
5
+ import { SpanType, TraceStatus } from './types'
6
+ import type { Span as SpanData, Trace as TraceData, TokenUsage } from '@observyze/types'
7
+
8
+ /**
9
+ * Generates a unique ID for traces and spans
10
+ */
11
+ function generateId(): string {
12
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
13
+ }
14
+
15
+ /**
16
+ * Represents an individual operation within a trace
17
+ */
18
+ export class Span {
19
+ private data: SpanData
20
+ private startTime: number
21
+
22
+ constructor(name: string, type: SpanType, parentSpanId?: string) {
23
+ this.startTime = Date.now()
24
+ this.data = {
25
+ span_id: generateId(),
26
+ parent_span_id: parentSpanId,
27
+ name,
28
+ type,
29
+ start_time: new Date(this.startTime),
30
+ end_time: new Date(this.startTime), // Will be updated on end()
31
+ duration_ms: 0,
32
+ input: null,
33
+ output: null,
34
+ metadata: {}
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Set the input data for this span
40
+ */
41
+ setInput(input: any): this {
42
+ this.data.input = input
43
+ return this
44
+ }
45
+
46
+ /**
47
+ * Set the output data for this span
48
+ */
49
+ setOutput(output: any): this {
50
+ this.data.output = output
51
+ return this
52
+ }
53
+
54
+ /**
55
+ * Record an error that occurred during span execution
56
+ */
57
+ setError(error: Error): this {
58
+ this.data.error = {
59
+ message: error.message,
60
+ stack: error.stack,
61
+ code: (error as any).code
62
+ }
63
+ return this
64
+ }
65
+
66
+ /**
67
+ * Set metadata for this span
68
+ */
69
+ setMetadata(key: string, value: any): this {
70
+ this.data.metadata[key] = value
71
+ return this
72
+ }
73
+
74
+ /**
75
+ * Set multiple metadata fields at once
76
+ */
77
+ setMetadataAll(metadata: Record<string, any>): this {
78
+ this.data.metadata = { ...this.data.metadata, ...metadata }
79
+ return this
80
+ }
81
+
82
+ /**
83
+ * Set token usage information
84
+ */
85
+ setTokens(tokens: TokenUsage): this {
86
+ this.data.tokens = tokens
87
+ return this
88
+ }
89
+
90
+ /**
91
+ * End the span and calculate duration
92
+ */
93
+ end(): void {
94
+ const endTime = Date.now()
95
+ this.data.end_time = new Date(endTime)
96
+ this.data.duration_ms = endTime - this.startTime
97
+ }
98
+
99
+ /**
100
+ * Get the span ID
101
+ */
102
+ get id(): string {
103
+ return this.data.span_id
104
+ }
105
+
106
+ /**
107
+ * Get the span data for serialization
108
+ */
109
+ toJSON(): SpanData {
110
+ return { ...this.data }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Represents a complete AI workflow execution
116
+ */
117
+ export class Trace {
118
+ private data: Omit<TraceData, '_id' | 'created_at' | 'updated_at'>
119
+ private startTime: number
120
+ private spans: Span[] = []
121
+ private ended: boolean = false
122
+
123
+ constructor(
124
+ name: string,
125
+ organizationId: string,
126
+ projectId?: string
127
+ ) {
128
+ this.startTime = Date.now()
129
+ this.data = {
130
+ trace_id: generateId(),
131
+ organization_id: organizationId,
132
+ project_id: projectId,
133
+ name,
134
+ status: TraceStatus.RUNNING,
135
+ start_time: new Date(this.startTime),
136
+ end_time: new Date(this.startTime), // Will be updated on end()
137
+ duration_ms: 0,
138
+ metadata: {},
139
+ spans: [],
140
+ tags: []
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Start a new span within this trace
146
+ */
147
+ startSpan(name: string, type: SpanType, parentSpanId?: string): Span {
148
+ if (this.ended) {
149
+ throw new Error('Cannot start span on an ended trace')
150
+ }
151
+ const span = new Span(name, type, parentSpanId)
152
+ this.spans.push(span)
153
+ return span
154
+ }
155
+
156
+ /**
157
+ * Add metadata to the trace
158
+ */
159
+ setMetadata(key: string, value: any): this {
160
+ this.data.metadata[key] = value
161
+ return this
162
+ }
163
+
164
+ /**
165
+ * Set multiple metadata fields at once
166
+ */
167
+ setMetadataAll(metadata: Record<string, any>): this {
168
+ this.data.metadata = { ...this.data.metadata, ...metadata }
169
+ return this
170
+ }
171
+
172
+ /**
173
+ * Add tags to the trace
174
+ */
175
+ addTag(tag: string): this {
176
+ if (!this.data.tags.includes(tag)) {
177
+ this.data.tags.push(tag)
178
+ }
179
+ return this
180
+ }
181
+
182
+ /**
183
+ * Add multiple tags at once
184
+ */
185
+ addTags(tags: string[]): this {
186
+ tags.forEach(tag => this.addTag(tag))
187
+ return this
188
+ }
189
+
190
+ /**
191
+ * Set the user ID associated with this trace
192
+ */
193
+ setUserId(userId: string): this {
194
+ this.data.user_id = userId
195
+ return this
196
+ }
197
+
198
+ /**
199
+ * Set the session ID associated with this trace
200
+ */
201
+ setSessionId(sessionId: string): this {
202
+ this.data.session_id = sessionId
203
+ return this
204
+ }
205
+
206
+ /**
207
+ * End the trace with a final status
208
+ */
209
+ end(status: TraceStatus = TraceStatus.SUCCESS): void {
210
+ if (this.ended) {
211
+ return
212
+ }
213
+
214
+ const endTime = Date.now()
215
+ this.data.end_time = new Date(endTime)
216
+ this.data.duration_ms = endTime - this.startTime
217
+ this.data.status = status
218
+ this.data.spans = this.spans.map(span => span.toJSON())
219
+ this.ended = true
220
+ }
221
+
222
+ /**
223
+ * Get the trace ID
224
+ */
225
+ get id(): string {
226
+ return this.data.trace_id
227
+ }
228
+
229
+ /**
230
+ * Check if the trace has ended
231
+ */
232
+ get isEnded(): boolean {
233
+ return this.ended
234
+ }
235
+
236
+ /**
237
+ * Get the trace data for serialization
238
+ */
239
+ toJSON(): Omit<TraceData, '_id' | 'created_at' | 'updated_at'> {
240
+ return { ...this.data }
241
+ }
242
+ }
package/src/types.ts ADDED
@@ -0,0 +1,102 @@
1
+ /**
2
+ * SDK Configuration and Types
3
+ */
4
+
5
+ // Re-export types from @observyze/types for convenience
6
+ export { SpanType, TraceStatus } from '@observyze/types'
7
+
8
+ /**
9
+ * Configuration for Observyze SDK client
10
+ */
11
+ export interface ClientConfig {
12
+ /**
13
+ * API key for authentication with Observyze Ingestion Service
14
+ */
15
+ apiKey: string
16
+
17
+ /**
18
+ * Endpoint URL for the Ingestion Service
19
+ * @default 'http://localhost:3001'
20
+ */
21
+ endpoint?: string
22
+
23
+ /**
24
+ * Maximum number of traces to buffer before flushing
25
+ * @default 100
26
+ */
27
+ batchSize?: number
28
+
29
+ /**
30
+ * Time in milliseconds to wait before auto-flushing buffered traces
31
+ * @default 5000
32
+ */
33
+ flushInterval?: number
34
+
35
+ /**
36
+ * Enable automatic instrumentation of popular LLM libraries
37
+ * @default true
38
+ */
39
+ enableAutoInstrumentation?: boolean
40
+
41
+ /**
42
+ * Organization ID (optional, can be extracted from API key)
43
+ */
44
+ organizationId?: string
45
+
46
+ /**
47
+ * Project ID for trace attribution
48
+ */
49
+ projectId?: string
50
+
51
+ /**
52
+ * Enable debug logging
53
+ * @default false
54
+ */
55
+ debug?: boolean
56
+
57
+ /**
58
+ * Dry run mode - don't send traces to server (useful for testing)
59
+ * @default false
60
+ */
61
+ dryRun?: boolean
62
+
63
+ /**
64
+ * Phase 5: Automatically scrub PII from trace output before network transmission
65
+ * @default true
66
+ */
67
+ enablePiiRedaction?: boolean
68
+
69
+ /**
70
+ * Phase 4: Autonomous Circuit Breaker
71
+ * Hallucination score threshold (0-1) above which execution is blocked
72
+ * @default 0.8
73
+ */
74
+ hallucinationThreshold?: number
75
+
76
+ /**
77
+ * Phase 4: Autonomous Circuit Breaker
78
+ * Safety score threshold (0-1) above which execution is blocked
79
+ * @default 0.9
80
+ */
81
+ safetyThreshold?: number
82
+
83
+ /**
84
+ * Evaluation service URL for real-time guardrail checks
85
+ * In production, this should be https://api.observyze.com
86
+ * @default 'http://localhost:3000'
87
+ */
88
+ evalEndpoint?: string
89
+
90
+ /**
91
+ * Enable circuit breaker - block execution on high hallucination/safety scores
92
+ * @default true
93
+ */
94
+ enableCircuitBreaker?: boolean
95
+ }
96
+
97
+ /**
98
+ * Internal configuration with defaults applied
99
+ */
100
+ export interface ResolvedClientConfig extends Required<ClientConfig> {
101
+ // All fields are required after defaults are applied
102
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true,
9
+ "composite": false,
10
+ "incremental": false
11
+ },
12
+ "include": ["src/**/*"],
13
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
14
+ }