xray-sdk 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/README.md +447 -300
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,426 +1,573 @@
1
- # X-Ray SDK
1
+ # xray-sdk
2
2
 
3
3
  **AI-powered observability for multi-step pipelines**
4
4
 
5
- X-Ray is a lightweight SDK that automatically tracks pipeline executions and generates human-readable reasoning for each step using LLMs.
5
+ Track your pipeline executions with automatic AI reasoning that explains "WHY" decisions were made. Debug faster with step-by-step insights and visual exploration.
6
6
 
7
- ## Features
7
+ ---
8
8
 
9
- **Automatic Step Tracking** - Track pipeline execution with simple `startStep()` / `endStep()` calls
10
- 🤖 **AI-Powered Reasoning** - Generate natural language explanations for each step using OpenAI
11
- 💾 **Flexible Storage** - In-memory or database-backed (Prisma + PostgreSQL)
12
- ⚡ **Async Processing** - Non-blocking reasoning generation with retry logic
13
- 🔄 **On-Demand Generation** - Only generate reasoning when you need it (cost savings)
14
- 📊 **Job Queue** - Built-in queue for managing concurrent LLM calls
15
-
16
- ## Installation
9
+ ## 📦 Installation
17
10
 
18
11
  ```bash
19
- npm install xray-sdk p-queue
12
+ npm install xray-sdk
20
13
  ```
21
14
 
22
- ### Optional Dependencies
15
+ ---
23
16
 
24
- ```bash
25
- # For database storage
26
- npm install @prisma/client
17
+ ## 🚀 Complete Setup Guide
27
18
 
28
- # For OpenAI reasoning
29
- npm install openai
30
- ```
19
+ Follow these steps to integrate X-Ray into your pipeline:
31
20
 
32
- ## Quick Start
21
+ ### Step 1: Get Your API Key
33
22
 
34
- ### Basic Usage (In-Memory)
23
+ 1. Visit the X-Ray Dashboard: **https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app**
24
+ 2. Click **"Create Account"** to sign up
25
+ 3. Go to **"API Keys"** page: https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app/api-key
26
+ 4. Click **"Generate New Key"** and copy your API key (format: `xray_xxxxx...`)
35
27
 
36
- ```typescript
37
- import { XRay, MemoryStorage } from 'xray-sdk'
28
+ ### Step 2: Configure Environment Variables
38
29
 
39
- const storage = new MemoryStorage()
40
- const xray = new XRay('my-execution-1', { projectId: 'demo' }, storage)
30
+ Create a `.env` file in your project root:
41
31
 
42
- // Track a step
43
- xray.startStep('fetch_data', { query: 'shoes' })
44
- const data = await fetchData('shoes')
45
- xray.endStep('fetch_data', { results: data.length })
32
+ ```bash
33
+ # X-Ray Dashboard Configuration
34
+ XRAY_API_URL="https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app"
46
35
 
47
- // End execution
48
- const execution = xray.end({ success: true })
49
- await xray.save()
36
+ # Your API key from Step 1
37
+ XRAY_API_KEY="xray_your_api_key_here"
50
38
 
51
- console.log('Execution saved:', execution.executionId)
39
+ # Optional: Only needed for client-side reasoning (advanced)
40
+ OPENAI_API_KEY="sk-..."
52
41
  ```
53
42
 
54
- ### With Database Storage (Prisma)
43
+ ### Step 3: Create HTTP Client Wrapper
44
+
45
+ Create a file `src/lib/xrayClient.ts` to handle API communication:
55
46
 
56
47
  ```typescript
57
- import { XRay, DatabaseStorage } from '@xray/sdk'
58
- import { PrismaClient } from '@prisma/client'
48
+ interface Execution {
49
+ executionId: string
50
+ startedAt: string
51
+ endedAt?: string
52
+ steps: Array<{
53
+ name: string
54
+ input?: any
55
+ output?: any
56
+ error?: string
57
+ durationMs?: number
58
+ }>
59
+ finalOutcome?: any
60
+ metadata?: Record<string, any>
61
+ }
59
62
 
60
- const prisma = new PrismaClient()
61
- const storage = new DatabaseStorage(prisma)
63
+ export class XRayClient {
64
+ private apiUrl: string
65
+ private apiKey: string
62
66
 
63
- const xray = new XRay('my-execution-2', { projectId: 'demo' }, storage)
67
+ constructor(apiUrl: string, apiKey: string) {
68
+ this.apiUrl = apiUrl
69
+ this.apiKey = apiKey
70
+ }
64
71
 
65
- // Track steps
66
- xray.startStep('step1', { input: 'data' })
67
- xray.endStep('step1', { output: 'result' })
72
+ async saveExecution(execution: Execution): Promise<{ executionId: string }> {
73
+ const response = await fetch(\`\${this.apiUrl}/api/logs\`, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'x-api-key': this.apiKey,
77
+ 'Content-Type': 'application/json'
78
+ },
79
+ body: JSON.stringify(execution)
80
+ })
68
81
 
69
- // Save to database
70
- const execution = xray.end({ success: true })
71
- await xray.save()
72
- ```
82
+ if (!response.ok) {
83
+ throw new Error(\`X-Ray API Error: \${response.statusText}\`)
84
+ }
73
85
 
74
- ### With AI Reasoning (OpenAI)
86
+ return await response.json()
87
+ }
88
+ }
75
89
 
76
- ```typescript
77
- import {
78
- XRay,
79
- DatabaseStorage,
80
- ReasoningQueue,
81
- createOpenAIGenerator
82
- } from '@xray/sdk'
83
- import { PrismaClient } from '@prisma/client'
84
- import OpenAI from 'openai'
90
+ // Helper function to create client from environment variables
91
+ export function createXRayClient(): XRayClient {
92
+ const apiUrl = process.env.XRAY_API_URL
93
+ const apiKey = process.env.XRAY_API_KEY
85
94
 
86
- const prisma = new PrismaClient()
87
- const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
95
+ if (!apiUrl || !apiKey) {
96
+ throw new Error('Missing XRAY_API_URL or XRAY_API_KEY in environment')
97
+ }
88
98
 
89
- // Setup storage and reasoning
90
- const storage = new DatabaseStorage(prisma)
91
- const generator = createOpenAIGenerator(openai)
92
- const queue = new ReasoningQueue(
93
- storage,
94
- generator,
95
- { concurrency: 3, debug: true },
96
- prisma
97
- )
99
+ return new XRayClient(apiUrl, apiKey)
100
+ }
101
+ ```
98
102
 
99
- // Run pipeline
100
- const xray = new XRay('my-execution-3', { projectId: 'demo' }, storage)
103
+ **💡 Tip:** See the full implementation at \`demo-app/src/lib/xrayClient.ts\` in the repository.
101
104
 
102
- xray.startStep('search', { query: 'laptops' })
103
- const results = await search('laptops')
104
- xray.endStep('search', { count: results.length })
105
+ ### Step 4: Track Your Pipeline with XRay
105
106
 
106
- xray.startStep('filter', { threshold: 4.5 })
107
- const filtered = results.filter(r => r.rating >= 4.5)
108
- xray.endStep('filter', { remaining: filtered.length })
107
+ Wrap your pipeline logic with X-Ray tracking:
109
108
 
110
- // Save execution (without reasoning)
111
- const execution = xray.end({ success: true })
112
- await xray.save()
109
+ ```typescript
110
+ import { XRay } from 'xray-sdk'
111
+ import { createXRayClient } from './lib/xrayClient'
112
+
113
+ async function myPipeline() {
114
+ // 1. Create XRay instance with unique execution ID
115
+ const executionId = \`pipeline-\${Date.now()}\`
116
+ const xray = new XRay(executionId, {
117
+ pipeline: 'my-pipeline-name',
118
+ domain: 'data-processing' // Optional metadata
119
+ })
120
+
121
+ // 2. Track each step with startStep() and endStep()
122
+
123
+ // Step 1: Fetch data
124
+ xray.startStep('fetch_data', { source: 'api.example.com', limit: 100 })
125
+ const data = await fetchData()
126
+ xray.endStep('fetch_data', { records: data.length, size_kb: 45 })
127
+
128
+ // Step 2: Process data
129
+ xray.startStep('process_data', { records: data.length })
130
+ const processed = processData(data)
131
+ xray.endStep('process_data', {
132
+ processed: processed.length,
133
+ skipped: data.length - processed.length
134
+ })
135
+
136
+ // Step 3: Save results
137
+ xray.startStep('save_results', { records: processed.length })
138
+ await saveResults(processed)
139
+ xray.endStep('save_results', { success: true })
140
+
141
+ // 3. Complete execution
142
+ const execution = xray.end({
143
+ status: 'success',
144
+ total_processed: processed.length
145
+ })
146
+
147
+ // 4. Send to X-Ray Dashboard
148
+ const client = createXRayClient()
149
+ await client.saveExecution(execution)
150
+
151
+ // 5. View in dashboard
152
+ console.log(\`✅ View execution: https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app/execution/\${executionId}\`)
153
+ }
154
+ ```
113
155
 
114
- // Enqueue reasoning generation (async)
115
- await xray.enqueueReasoning(queue)
156
+ ### Step 5: View Results in Dashboard
116
157
 
117
- console.log('✅ Execution saved, reasoning generating in background')
118
- ```
158
+ 1. Run your pipeline: \`npm run your-pipeline-command\`
159
+ 2. Copy the execution URL from console output
160
+ 3. Open the URL in your browser
161
+ 4. Watch AI reasoning generate automatically for each step
119
162
 
120
- ### On-Demand Reasoning (Recommended)
163
+ **✨ AI Reasoning explains:**
164
+ - WHY this step produced this output
165
+ - What metrics/thresholds drove the decision
166
+ - What might be wrong if numbers look suspicious
121
167
 
122
- Instead of auto-generating reasoning, trigger it only when viewing an execution:
168
+ Example reasoning:
169
+ > "Only 3/10 candidates met minRating≥4.0 AND minReviews≥100; 7 failed due to low ratings/reviews"
123
170
 
124
- ```typescript
125
- // Pipeline API - just save execution
126
- const execution = xray.end({ success: true })
127
- await xray.save()
128
- return { executionId: execution.executionId } // Returns instantly
171
+ ---
129
172
 
130
- // Later, when user views execution detail page
131
- await queue.processExecution(executionId) // Generate reasoning now
132
- ```
173
+ ## 📚 Complete Examples
133
174
 
134
- This approach:
135
- - ✅ API responds instantly (~150ms)
136
- - ✅ Saves LLM costs (only generate for executions users actually view)
137
- - ✅ Better user experience
175
+ See the \`demo-app/\` directory for production-ready examples:
138
176
 
139
- ## API Reference
177
+ ### Example 1: Basic Data Pipeline
140
178
 
141
- ### XRay
179
+ **File:** \`demo-app/src/1-basic-example.ts\`
142
180
 
143
181
  ```typescript
144
- class XRay {
145
- constructor(executionId: string, metadata?: Record<string, any>, storage?: StorageProvider)
182
+ import { XRay } from 'xray-sdk'
183
+ import { createXRayClient } from './lib/xrayClient'
146
184
 
147
- // V1 API (backward compatible)
148
- logStep(step: { name: string, input: any, output: any, metadata?: any }): void
185
+ const xray = new XRay(\`basic-\${Date.now()}\`, {
186
+ pipeline: 'data-ingestion'
187
+ })
149
188
 
150
- // V2 API (recommended)
151
- startStep(name: string, input: any, metadata?: any): void
152
- endStep(name: string, output: any): void
153
- errorStep(name: string, error: Error): void
189
+ // Track data ingestion
190
+ xray.startStep('ingest', { source: 'api', limit: 1000 })
191
+ const rawData = await fetch('https://api.example.com/data')
192
+ xray.endStep('ingest', { records: 1000, size_mb: 2.3 })
193
+
194
+ // Track validation
195
+ xray.startStep('validate', { records: 1000 })
196
+ const valid = rawData.filter(isValid)
197
+ xray.endStep('validate', {
198
+ valid: valid.length,
199
+ invalid: rawData.length - valid.length
200
+ })
154
201
 
155
- end(finalOutcome: any): Execution
156
- save(): Promise<void>
157
- enqueueReasoning(queue: ReasoningQueue): Promise<void>
158
- getExecution(): Execution
159
- }
202
+ const execution = xray.end({ status: 'success' })
203
+ await createXRayClient().saveExecution(execution)
160
204
  ```
161
205
 
162
- ### StorageProvider
206
+ ### Example 2: E-Commerce Competitor Selection
207
+
208
+ **File:** \`demo-app/src/2-ecommerce-example.ts\`
163
209
 
164
210
  ```typescript
165
- interface StorageProvider {
166
- saveExecution(execution: Execution): Promise<void>
167
- getExecutionById(executionId: string): Promise<Execution | undefined>
168
- getAllExecutions(): Promise<Execution[]>
169
- updateStepReasoning(executionId: string, stepName: string, reasoning: string): Promise<void>
170
- }
171
- ```
211
+ import { XRay } from 'xray-sdk'
212
+ import { createXRayClient } from './lib/xrayClient'
172
213
 
173
- **Implementations:**
174
- - `MemoryStorage` - In-memory storage (testing)
175
- - `DatabaseStorage` - Prisma + PostgreSQL (production)
214
+ const xray = new XRay(\`ecommerce-\${Date.now()}\`, {
215
+ pipeline: 'competitor-selection',
216
+ domain: 'e-commerce'
217
+ })
176
218
 
177
- ### ReasoningQueue
219
+ // Step 1: Generate search keywords
220
+ xray.startStep('generate_keywords', {
221
+ product_title: 'Water Bottle 32oz Insulated'
222
+ })
223
+ const keywords = ['water bottle', 'insulated bottle', '32oz bottle']
224
+ xray.endStep('generate_keywords', { keywords, count: 3 })
225
+
226
+ // Step 2: Search for candidates
227
+ xray.startStep('search_competitors', { keywords, limit: 50 })
228
+ const candidates = await searchAmazon(keywords)
229
+ xray.endStep('search_competitors', {
230
+ total_results: 2847,
231
+ candidates_fetched: 10
232
+ })
178
233
 
179
- ```typescript
180
- class ReasoningQueue {
181
- constructor(
182
- storage: StorageProvider,
183
- generator: ReasoningGenerator,
184
- config?: Partial<ReasoningConfig>,
185
- prismaClient?: any
186
- )
187
-
188
- enqueue(executionId: string, stepName: string): Promise<string>
189
- enqueueExecution(executionId: string): Promise<string[]>
190
- processExecution(executionId: string): Promise<void>
191
- getStats(): QueueStats
192
- getJob(jobId: string): ReasoningJob | undefined
193
- }
234
+ // Step 3: Filter and select best competitor
235
+ xray.startStep('filter_and_select', {
236
+ candidates: 10,
237
+ filters: { minRating: 4.0, minReviews: 100 }
238
+ })
239
+ const filtered = candidates.filter(c => c.rating >= 4.0 && c.reviews >= 100)
240
+ const selected = filtered[0]
241
+ xray.endStep('filter_and_select', {
242
+ passed: 3,
243
+ failed: 7,
244
+ selected: selected.title
245
+ })
246
+
247
+ const execution = xray.end({
248
+ competitor: selected,
249
+ confidence: 0.95
250
+ })
251
+ await createXRayClient().saveExecution(execution)
194
252
  ```
195
253
 
196
- ### Reasoning Generators
254
+ ### Example 3: Error Handling
255
+
256
+ **File:** \`demo-app/src/3-error-handling-example.ts\`
197
257
 
198
258
  ```typescript
199
- // OpenAI-powered reasoning
200
- const generator = createOpenAIGenerator(openaiClient)
259
+ import { XRay } from 'xray-sdk'
260
+ import { createXRayClient } from './lib/xrayClient'
201
261
 
202
- // Simple reasoning (no LLM)
203
- const generator = createSimpleGenerator()
262
+ const xray = new XRay(\`error-demo-\${Date.now()}\`, {
263
+ pipeline: 'risky-pipeline'
264
+ })
204
265
 
205
- // Custom reasoning
206
- const generator: ReasoningGenerator = async (step: Step) => {
207
- return `My custom reasoning for ${step.name}`
266
+ xray.startStep('risky_operation', { input: 'data' })
267
+ try {
268
+ const result = await riskyOperation()
269
+ xray.endStep('risky_operation', { result })
270
+ } catch (error) {
271
+ // Track errors with errorStep()
272
+ xray.errorStep('risky_operation', error as Error)
208
273
  }
274
+
275
+ const execution = xray.end({ status: 'failed' })
276
+ await createXRayClient().saveExecution(execution)
277
+
278
+ // Dashboard will show error with AI reasoning explaining what went wrong
209
279
  ```
210
280
 
211
- ## Configuration
281
+ ### Example 4: Movie Recommendation Pipeline
212
282
 
213
- ### Reasoning Config
283
+ **File:** \`demo-app/src/4-movie-example.ts\`
214
284
 
215
285
  ```typescript
216
- interface ReasoningConfig {
217
- concurrency: number // Parallel LLM calls (default: 3)
218
- maxRetries: number // Max retries per job (default: 4)
219
- retryDelays: number[] // Backoff delays in ms (default: [1000, 2000, 4000, 8000])
220
- debug: boolean // Enable logging (default: false)
221
- }
286
+ import { XRay } from 'xray-sdk'
287
+ import { createXRayClient } from './lib/xrayClient'
222
288
 
223
- const config = createReasoningConfig({
224
- concurrency: 5,
225
- maxRetries: 3,
226
- debug: true
289
+ const xray = new XRay(\`movie-\${Date.now()}\`, {
290
+ pipeline: 'movie-recommendation',
291
+ domain: 'entertainment'
227
292
  })
228
293
 
229
- const queue = new ReasoningQueue(storage, generator, config)
294
+ // Step 1: Extract themes from favorite movie
295
+ xray.startStep('extract_themes', { movie: 'Inception' })
296
+ const themes = ['time manipulation', 'mind-bending', 'layered reality']
297
+ xray.endStep('extract_themes', { themes, count: 3 })
298
+
299
+ // Step 2: Search for similar movies
300
+ xray.startStep('search_movies', { themes, limit: 20 })
301
+ const candidates = await searchMovies(themes)
302
+ xray.endStep('search_movies', { total: 47, fetched: 20 })
303
+
304
+ // Step 3: Filter by criteria
305
+ xray.startStep('filter_movies', {
306
+ candidates: 20,
307
+ minRating: 7.5,
308
+ maxAge: 15
309
+ })
310
+ const filtered = candidates.filter(m => m.rating >= 7.5 && m.yearsSinceRelease <= 15)
311
+ xray.endStep('filter_movies', { passed: 5, failed: 15 })
312
+
313
+ // Step 4: Score and rank
314
+ xray.startStep('score_and_rank', { movies: 5 })
315
+ const scored = scoreMovies(filtered)
316
+ const topPick = scored[0]
317
+ xray.endStep('score_and_rank', { top_score: topPick.score })
318
+
319
+ // Step 5: Get metadata
320
+ xray.startStep('get_metadata', { movie_id: topPick.id })
321
+ const metadata = await getMovieMetadata(topPick.id)
322
+ xray.endStep('get_metadata', { title: metadata.title })
323
+
324
+ const execution = xray.end({
325
+ recommendation: metadata,
326
+ confidence: 0.92
327
+ })
328
+ await createXRayClient().saveExecution(execution)
230
329
  ```
231
330
 
232
- ## Prisma Schema
233
-
234
- If using `DatabaseStorage`, add this to your Prisma schema:
235
-
236
- ```prisma
237
- model Execution {
238
- id String @id @default(cuid())
239
- executionId String @unique
240
- projectId String @default("default")
241
- metadata Json?
242
- finalOutcome Json?
243
- startedAt DateTime @default(now())
244
- completedAt DateTime?
245
- steps Step[]
246
- reasoningJobs ReasoningJob[]
247
- }
331
+ ---
248
332
 
249
- model Step {
250
- id String @id @default(cuid())
251
- executionId String
252
- execution Execution @relation(fields: [executionId], references: [id], onDelete: Cascade)
253
- name String
254
- input Json?
255
- output Json?
256
- error String?
257
- durationMs Int?
258
- reasoning String?
259
- createdAt DateTime @default(now())
260
- }
333
+ ## 🎯 Core API Reference
261
334
 
262
- model ReasoningJob {
263
- id String @id @default(cuid())
264
- executionId String
265
- execution Execution @relation(fields: [executionId], references: [id], onDelete: Cascade)
266
- stepName String
267
- status String
268
- reasoning String?
269
- error String?
270
- attempts Int @default(0)
271
- createdAt DateTime @default(now())
272
- completedAt DateTime?
273
-
274
- @@unique([executionId, stepName])
275
- }
276
- ```
335
+ ### XRay Class
277
336
 
278
- Then run:
279
- ```bash
280
- npx prisma migrate dev --name add_xray
281
- npx prisma generate
282
- ```
337
+ ```typescript
338
+ import { XRay } from 'xray-sdk'
283
339
 
284
- ## Examples
340
+ // Create instance
341
+ const xray = new XRay(executionId: string, metadata?: Record<string, any>)
285
342
 
286
- ### Example 1: Simple Pipeline
343
+ // Track steps
344
+ xray.startStep(name: string, input?: any)
345
+ xray.endStep(name: string, output?: any)
346
+ xray.errorStep(name: string, error: Error)
287
347
 
288
- ```typescript
289
- import { XRay, MemoryStorage } from '@xray/sdk'
348
+ // Complete execution
349
+ const execution = xray.end(finalOutcome?: any)
350
+ ```
290
351
 
291
- async function runPipeline() {
292
- const storage = new MemoryStorage()
293
- const xray = new XRay('exec-1', {}, storage)
352
+ ### Key Methods
294
353
 
295
- xray.startStep('fetch', { url: 'https://api.example.com' })
296
- const data = await fetch('https://api.example.com').then(r => r.json())
297
- xray.endStep('fetch', { count: data.length })
354
+ | Method | Description | Example |
355
+ |--------|-------------|---------|
356
+ | \`startStep(name, input?)\` | Start tracking a step | \`xray.startStep('fetch_data', { source: 'api' })\` |
357
+ | \`endStep(name, output?)\` | End step successfully | \`xray.endStep('fetch_data', { records: 1000 })\` |
358
+ | \`errorStep(name, error)\` | Mark step as failed | \`xray.errorStep('fetch_data', new Error('timeout'))\` |
359
+ | \`end(finalOutcome?)\` | Complete execution | \`xray.end({ status: 'success', total: 1000 })\` |
298
360
 
299
- xray.startStep('process', { data })
300
- const processed = data.map(d => d.value * 2)
301
- xray.endStep('process', { result: processed })
361
+ ---
302
362
 
303
- const execution = xray.end({ total: processed.length })
304
- await xray.save()
363
+ ## 🔒 Security & Reasoning Options
305
364
 
306
- return execution
307
- }
308
- ```
365
+ X-Ray offers **two secure ways** to generate AI reasoning:
309
366
 
310
- ### Example 2: With Error Handling
367
+ ### Option 1: Server-Side Reasoning (Default, Recommended)
311
368
 
312
- ```typescript
313
- xray.startStep('risky_operation', { input: 'data' })
314
- try {
315
- const result = await riskyOperation()
316
- xray.endStep('risky_operation', { result })
317
- } catch (error) {
318
- xray.errorStep('risky_operation', error as Error)
319
- }
320
- ```
369
+ **How it works:**
370
+ 1. Send execution WITHOUT reasoning to dashboard
371
+ 2. Dashboard generates reasoning using its own OpenAI key
372
+ 3. Reasoning appears automatically when you view the execution
321
373
 
322
- ### Example 3: Custom Storage
374
+ **Pros:**
375
+ - ✅ No OpenAI API key needed from you
376
+ - ✅ Zero cost for you
377
+ - ✅ Zero setup required
323
378
 
379
+ **Code:**
324
380
  ```typescript
325
- import { StorageProvider, Execution } from '@xray/sdk'
326
-
327
- class S3Storage implements StorageProvider {
328
- async saveExecution(execution: Execution): Promise<void> {
329
- // Upload to S3
330
- await s3.putObject({
331
- Bucket: 'my-bucket',
332
- Key: `executions/${execution.executionId}.json`,
333
- Body: JSON.stringify(execution)
334
- })
335
- }
336
-
337
- async getExecutionById(id: string): Promise<Execution | undefined> {
338
- // Download from S3
339
- const obj = await s3.getObject({
340
- Bucket: 'my-bucket',
341
- Key: `executions/${id}.json`
342
- })
343
- return JSON.parse(obj.Body.toString())
344
- }
345
-
346
- // ... implement other methods
347
- }
381
+ const execution = xray.end({ status: 'success' })
382
+ await client.saveExecution(execution)
383
+ // Dashboard will generate reasoning automatically
348
384
  ```
349
385
 
350
- ## Best Practices
386
+ ### Option 2: Client-Side Reasoning (Advanced)
351
387
 
352
- ### 1. Use On-Demand Reasoning
388
+ **How it works:**
389
+ 1. Generate reasoning locally using YOUR OpenAI key
390
+ 2. Send execution WITH reasoning to dashboard
391
+ 3. Your API key never leaves your infrastructure
353
392
 
354
- Don't generate reasoning on every pipeline run - only when users view executions:
393
+ **Pros:**
394
+ - ✅ Full control over OpenAI usage
395
+ - ✅ Works with sensitive data (never sent to dashboard)
396
+ - ✅ No dependency on dashboard's rate limits
355
397
 
398
+ **Code:**
356
399
  ```typescript
357
- // Bad: Auto-generate reasoning (slow, expensive)
358
- await xray.save()
359
- await xray.enqueueReasoning(queue) // Blocks API response
360
- return { executionId }
400
+ import { XRay, MemoryStorage, ReasoningQueue, createOpenAIGenerator } from 'xray-sdk'
401
+ import OpenAI from 'openai'
361
402
 
362
- // Good: Generate on-demand (fast, cost-effective)
363
- await xray.save()
364
- return { executionId } // Returns instantly
403
+ // 1. Track execution
404
+ const xray = new XRay(executionId, { pipeline: 'my-pipeline' })
405
+ xray.startStep('process', { input: 'data' })
406
+ xray.endStep('process', { output: 'result' })
407
+ const execution = xray.end({ status: 'success' })
365
408
 
366
- // Later, when viewing execution:
409
+ // 2. Generate reasoning CLIENT-SIDE
410
+ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
411
+ const storage = new MemoryStorage()
412
+ await storage.saveExecution(execution)
413
+
414
+ const generator = createOpenAIGenerator(openai)
415
+ const queue = new ReasoningQueue(storage, generator)
367
416
  await queue.processExecution(executionId)
417
+
418
+ // 3. Get execution with reasoning
419
+ const executionWithReasoning = await storage.getExecutionById(executionId)
420
+
421
+ // 4. Send to dashboard
422
+ await client.saveExecution(executionWithReasoning)
368
423
  ```
369
424
 
370
- ### 2. Use Database Storage in Production
425
+ **See:** \`demo-app/src/7-standalone-reasoning.ts\` for complete example
426
+
427
+ ---
428
+
429
+ ## 🏗️ Advanced Features
430
+
431
+ ### Custom Storage
371
432
 
372
433
  ```typescript
373
- // Bad: In-memory (data lost on restart)
434
+ import { MemoryStorage, DatabaseStorage } from 'xray-sdk'
435
+
436
+ // In-memory (for testing)
374
437
  const storage = new MemoryStorage()
375
438
 
376
- // Good: Database-backed (persistent)
377
- const storage = new DatabaseStorage(prisma)
439
+ // Database (requires Prisma setup)
440
+ const storage = new DatabaseStorage(prisma, userId)
378
441
  ```
379
442
 
380
- ### 3. Configure Concurrency
443
+ ### Reasoning Queue Configuration
381
444
 
382
445
  ```typescript
383
- // Balance API costs vs speed
446
+ import { ReasoningQueue, createOpenAIGenerator } from 'xray-sdk'
447
+
384
448
  const queue = new ReasoningQueue(storage, generator, {
385
- concurrency: 3, // 3 parallel LLM calls
386
- maxRetries: 4, // Retry failed jobs
387
- debug: true // Enable logging
449
+ concurrency: 3, // Process 3 steps in parallel
450
+ maxRetries: 4, // Retry failed reasoning jobs
451
+ debug: true // Enable detailed logging
388
452
  })
453
+
454
+ await queue.processExecution(executionId)
389
455
  ```
390
456
 
391
- ### 4. Handle Errors Gracefully
457
+ ### TypeScript Types
392
458
 
393
459
  ```typescript
394
- xray.startStep('step', { input })
395
- try {
396
- const result = await operation()
397
- xray.endStep('step', { result })
398
- } catch (error) {
399
- xray.errorStep('step', error as Error)
400
- // Continue pipeline or throw
460
+ import { Execution, Step, XRay } from 'xray-sdk'
461
+
462
+ const execution: Execution = {
463
+ executionId: 'exec-123',
464
+ startedAt: '2024-01-01T00:00:00Z',
465
+ endedAt: '2024-01-01T00:01:00Z',
466
+ steps: [
467
+ {
468
+ name: 'step1',
469
+ input: { data: 'test' },
470
+ output: { result: 'success' },
471
+ durationMs: 150
472
+ }
473
+ ],
474
+ finalOutcome: { status: 'success' }
401
475
  }
402
476
  ```
403
477
 
404
- ## TypeScript
478
+ ---
405
479
 
406
- Full TypeScript support with type definitions:
480
+ ## 📊 Dashboard Features
407
481
 
408
- ```typescript
409
- import { Execution, Step, ReasoningJob, QueueStats } from '@xray/sdk'
482
+ The X-Ray Dashboard provides:
483
+
484
+ | Feature | Description |
485
+ |---------|-------------|
486
+ | **Execution List** | Browse all pipeline runs with status indicators |
487
+ | **Step-by-Step View** | Detailed breakdown showing input/output for each step |
488
+ | **AI Reasoning** | Automatic "WHY" explanations for decisions |
489
+ | **Real-Time Updates** | Watch reasoning generate live (polls every 2 seconds) |
490
+ | **JSON Viewer** | Inspect raw execution data |
491
+ | **Search & Filter** | Find executions by ID, pipeline name, or metadata |
492
+
493
+ **Dashboard URL:** https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app
494
+
495
+ ---
496
+
497
+ ## 🎯 Use Cases
498
+
499
+ - **E-Commerce**: Competitor selection, product matching, price optimization
500
+ - **Content Recommendation**: Movie/music recommendations, personalization engines
501
+ - **Data Pipelines**: ETL processes, data validation, transformation workflows
502
+ - **LLM Workflows**: Multi-step AI reasoning, autonomous agent systems
503
+ - **Debugging**: Understand why pipeline decisions were made, identify bottlenecks
504
+
505
+ ---
506
+
507
+ ## ✅ Integration Checklist
410
508
 
411
- const execution: Execution = xray.getExecution()
412
- const stats: QueueStats = queue.getStats()
509
+ Use this checklist to verify your integration:
510
+
511
+ - [ ] Install \`xray-sdk\` package (\`npm install xray-sdk\`)
512
+ - [ ] Create account on dashboard
513
+ - [ ] Get API key from https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app/api-key
514
+ - [ ] Set environment variables (\`XRAY_API_URL\`, \`XRAY_API_KEY\`)
515
+ - [ ] Create HTTP client wrapper (\`src/lib/xrayClient.ts\`)
516
+ - [ ] Add \`XRay\` tracking to your pipeline (startStep/endStep)
517
+ - [ ] Test with a simple pipeline execution
518
+ - [ ] Verify execution appears in dashboard
519
+ - [ ] Verify AI reasoning generates automatically
520
+ - [ ] (Optional) Set up client-side reasoning for sensitive workloads
521
+
522
+ ---
523
+
524
+ ## 🚀 Quick Start Summary
525
+
526
+ ```bash
527
+ # 1. Install
528
+ npm install xray-sdk
529
+
530
+ # 2. Get API key
531
+ # Visit: https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app/api-key
532
+
533
+ # 3. Configure .env
534
+ XRAY_API_URL="https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app"
535
+ XRAY_API_KEY="xray_your_key_here"
536
+
537
+ # 4. Copy HTTP client
538
+ # See: demo-app/src/lib/xrayClient.ts
539
+
540
+ # 5. Track your pipeline
541
+ # See: demo-app/src/2-ecommerce-example.ts
542
+
543
+ # 6. Run and view results
544
+ npm run your-pipeline
545
+ # Open execution URL in browser
413
546
  ```
414
547
 
415
- ## License
548
+ ---
549
+
550
+ ## 📚 Additional Resources
551
+
552
+ - **Demo App**: See \`demo-app/\` directory for 5 production-ready examples
553
+ - **Main README**: See \`../README.md\` for project overview
554
+ - **Security Guide**: See \`../SECURITY.md\` for best practices
555
+ - **Architecture**: See \`../XRAY_ARCHITECTURE_OVERVIEW.md\` for system design
556
+
557
+ ---
558
+
559
+ ## 📝 License
560
+
561
+ ISC
416
562
 
417
- MIT
563
+ ---
418
564
 
419
- ## Contributing
565
+ ## 🆘 Support
420
566
 
421
- Contributions welcome! Please open an issue or PR.
567
+ - **Dashboard**: https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app
568
+ - **Get API Key**: https://x-ray-library-sdk-git-main-devdurgesh619s-projects.vercel.app/api-key
569
+ - **Examples**: See \`demo-app/\` directory in the repository
422
570
 
423
- ## Support
571
+ ---
424
572
 
425
- - GitHub Issues: https://github.com/yourusername/xray-sdk/issues
426
- - Documentation: https://xray-sdk.dev
573
+ Start tracking your pipelines today with X-Ray! 🚀
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Lightweight execution tracing for LLM pipelines with automatic reasoning generation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",