@sentrial/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/dist/index.cjs ADDED
@@ -0,0 +1,595 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ApiError: () => ApiError,
24
+ EventType: () => EventType,
25
+ Interaction: () => Interaction,
26
+ NetworkError: () => NetworkError,
27
+ SentrialClient: () => SentrialClient,
28
+ SentrialError: () => SentrialError,
29
+ ValidationError: () => ValidationError,
30
+ begin: () => begin,
31
+ calculateAnthropicCost: () => calculateAnthropicCost,
32
+ calculateGoogleCost: () => calculateGoogleCost,
33
+ calculateOpenAICost: () => calculateOpenAICost,
34
+ configure: () => configure,
35
+ sentrial: () => sentrial
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/errors.ts
40
+ var SentrialError = class _SentrialError extends Error {
41
+ /** HTTP status code (if applicable) */
42
+ status;
43
+ /** Error code from the API */
44
+ code;
45
+ /** Additional error details */
46
+ details;
47
+ constructor(message, options) {
48
+ super(message, { cause: options?.cause });
49
+ this.name = "SentrialError";
50
+ this.status = options?.status;
51
+ this.code = options?.code;
52
+ this.details = options?.details;
53
+ if (Error.captureStackTrace) {
54
+ Error.captureStackTrace(this, _SentrialError);
55
+ }
56
+ }
57
+ /**
58
+ * Check if the error is a rate limit error
59
+ */
60
+ isRateLimitError() {
61
+ return this.status === 429;
62
+ }
63
+ /**
64
+ * Check if the error is an authentication error
65
+ */
66
+ isAuthError() {
67
+ return this.status === 401 || this.status === 403;
68
+ }
69
+ /**
70
+ * Check if the error is a network/connection error
71
+ */
72
+ isNetworkError() {
73
+ return this.code === "NETWORK_ERROR" || this.code === "ECONNREFUSED";
74
+ }
75
+ /**
76
+ * Convert to a plain object for logging
77
+ */
78
+ toJSON() {
79
+ return {
80
+ name: this.name,
81
+ message: this.message,
82
+ status: this.status,
83
+ code: this.code,
84
+ details: this.details,
85
+ stack: this.stack
86
+ };
87
+ }
88
+ };
89
+ var ApiError = class extends SentrialError {
90
+ constructor(message, status, code, details) {
91
+ super(message, { status, code, details });
92
+ this.name = "ApiError";
93
+ }
94
+ };
95
+ var NetworkError = class extends SentrialError {
96
+ constructor(message, cause) {
97
+ super(message, { code: "NETWORK_ERROR", cause });
98
+ this.name = "NetworkError";
99
+ }
100
+ };
101
+ var ValidationError = class extends SentrialError {
102
+ constructor(message, details) {
103
+ super(message, { code: "VALIDATION_ERROR", details });
104
+ this.name = "ValidationError";
105
+ }
106
+ };
107
+
108
+ // src/cost.ts
109
+ var OPENAI_PRICING = {
110
+ "gpt-5.2": { input: 5, output: 15 },
111
+ "gpt-5": { input: 4, output: 12 },
112
+ "gpt-4o": { input: 2.5, output: 10 },
113
+ "gpt-4o-mini": { input: 0.15, output: 0.6 },
114
+ "gpt-4-turbo": { input: 10, output: 30 },
115
+ "gpt-4": { input: 30, output: 60 },
116
+ "gpt-3.5-turbo": { input: 0.5, output: 1.5 },
117
+ "o3": { input: 10, output: 40 },
118
+ "o3-mini": { input: 3, output: 12 },
119
+ "o1-preview": { input: 15, output: 60 },
120
+ "o1-mini": { input: 3, output: 12 }
121
+ };
122
+ var ANTHROPIC_PRICING = {
123
+ "claude-4.5-opus": { input: 20, output: 100 },
124
+ "claude-4.5-sonnet": { input: 4, output: 20 },
125
+ "claude-4-opus": { input: 18, output: 90 },
126
+ "claude-4-sonnet": { input: 3.5, output: 17.5 },
127
+ "claude-3-5-sonnet": { input: 3, output: 15 },
128
+ "claude-3-opus": { input: 15, output: 75 },
129
+ "claude-3-sonnet": { input: 3, output: 15 },
130
+ "claude-3-haiku": { input: 0.25, output: 1.25 }
131
+ };
132
+ var GOOGLE_PRICING = {
133
+ // Gemini 3 - Preview (Jan 2026)
134
+ "gemini-3-pro": { input: 2, output: 12 },
135
+ "gemini-3-flash": { input: 0.5, output: 3 },
136
+ // Gemini 2.5
137
+ "gemini-2.5-pro": { input: 1.25, output: 5 },
138
+ "gemini-2.5-flash": { input: 0.15, output: 0.6 },
139
+ // Gemini 2.0
140
+ "gemini-2.0-flash": { input: 0.1, output: 0.4 },
141
+ "gemini-2.0-flash-lite": { input: 0.075, output: 0.3 },
142
+ // Gemini 1.5
143
+ "gemini-1.5-pro": { input: 1.25, output: 5 },
144
+ "gemini-1.5-flash": { input: 0.075, output: 0.3 },
145
+ // Gemini 1.0
146
+ "gemini-1.0-pro": { input: 0.5, output: 1.5 }
147
+ };
148
+ function findModelKey(model, pricing) {
149
+ for (const key of Object.keys(pricing)) {
150
+ if (model.startsWith(key)) {
151
+ return key;
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ function calculateCost(inputTokens, outputTokens, rates) {
157
+ const inputCost = inputTokens / 1e6 * rates.input;
158
+ const outputCost = outputTokens / 1e6 * rates.output;
159
+ return inputCost + outputCost;
160
+ }
161
+ function calculateOpenAICost(params) {
162
+ const { model, inputTokens, outputTokens } = params;
163
+ const modelKey = findModelKey(model, OPENAI_PRICING) ?? "gpt-4";
164
+ return calculateCost(inputTokens, outputTokens, OPENAI_PRICING[modelKey]);
165
+ }
166
+ function calculateAnthropicCost(params) {
167
+ const { model, inputTokens, outputTokens } = params;
168
+ const modelKey = findModelKey(model, ANTHROPIC_PRICING) ?? "claude-3-sonnet";
169
+ return calculateCost(inputTokens, outputTokens, ANTHROPIC_PRICING[modelKey]);
170
+ }
171
+ function calculateGoogleCost(params) {
172
+ const { model, inputTokens, outputTokens } = params;
173
+ const modelKey = findModelKey(model, GOOGLE_PRICING) ?? "gemini-2.0-flash";
174
+ return calculateCost(inputTokens, outputTokens, GOOGLE_PRICING[modelKey]);
175
+ }
176
+
177
+ // src/types.ts
178
+ var EventType = /* @__PURE__ */ ((EventType2) => {
179
+ EventType2["TOOL_CALL"] = "tool_call";
180
+ EventType2["LLM_DECISION"] = "llm_decision";
181
+ EventType2["STATE_CHANGE"] = "state_change";
182
+ EventType2["ERROR"] = "error";
183
+ return EventType2;
184
+ })(EventType || {});
185
+
186
+ // src/client.ts
187
+ var DEFAULT_API_URL = "https://api.sentrial.com";
188
+ var SentrialClient = class {
189
+ apiUrl;
190
+ apiKey;
191
+ failSilently;
192
+ currentState = {};
193
+ constructor(config = {}) {
194
+ this.apiUrl = (config.apiUrl ?? (typeof process !== "undefined" ? process.env?.SENTRIAL_API_URL : void 0) ?? DEFAULT_API_URL).replace(/\/$/, "");
195
+ this.apiKey = config.apiKey ?? (typeof process !== "undefined" ? process.env?.SENTRIAL_API_KEY : void 0);
196
+ this.failSilently = config.failSilently ?? true;
197
+ }
198
+ /**
199
+ * Make an HTTP request with graceful error handling
200
+ */
201
+ async safeRequest(method, url, body) {
202
+ try {
203
+ const headers = {
204
+ "Content-Type": "application/json"
205
+ };
206
+ if (this.apiKey) {
207
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
208
+ }
209
+ const response = await fetch(url, {
210
+ method,
211
+ headers,
212
+ body: body ? JSON.stringify(body) : void 0
213
+ });
214
+ if (!response.ok) {
215
+ const errorBody = await response.text();
216
+ let errorData = {};
217
+ try {
218
+ errorData = JSON.parse(errorBody);
219
+ } catch {
220
+ }
221
+ const error = new ApiError(
222
+ errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`,
223
+ response.status,
224
+ errorData.error?.code
225
+ );
226
+ if (this.failSilently) {
227
+ console.warn(`Sentrial: Request failed (${method} ${url}):`, error.message);
228
+ return null;
229
+ }
230
+ throw error;
231
+ }
232
+ return await response.json();
233
+ } catch (error) {
234
+ if (error instanceof SentrialError) {
235
+ throw error;
236
+ }
237
+ const networkError = new NetworkError(
238
+ error instanceof Error ? error.message : "Unknown network error",
239
+ error instanceof Error ? error : void 0
240
+ );
241
+ if (this.failSilently) {
242
+ console.warn(`Sentrial: Request failed (${method} ${url}):`, networkError.message);
243
+ return null;
244
+ }
245
+ throw networkError;
246
+ }
247
+ }
248
+ /**
249
+ * Create a new session
250
+ *
251
+ * @param params - Session creation parameters
252
+ * @returns Session ID, or null if the request failed and failSilently is true
253
+ */
254
+ async createSession(params) {
255
+ this.currentState = {};
256
+ const payload = {
257
+ name: params.name,
258
+ agentName: params.agentName,
259
+ userId: params.userId,
260
+ metadata: params.metadata
261
+ };
262
+ const response = await this.safeRequest(
263
+ "POST",
264
+ `${this.apiUrl}/api/sdk/sessions`,
265
+ payload
266
+ );
267
+ return response?.id ?? null;
268
+ }
269
+ /**
270
+ * Track a tool call event
271
+ *
272
+ * @param params - Tool call parameters
273
+ * @returns Event data
274
+ */
275
+ async trackToolCall(params) {
276
+ const stateBefore = { ...this.currentState };
277
+ this.currentState[`${params.toolName}_result`] = params.toolOutput;
278
+ const payload = {
279
+ sessionId: params.sessionId,
280
+ eventType: "tool_call",
281
+ toolName: params.toolName,
282
+ toolInput: params.toolInput,
283
+ toolOutput: params.toolOutput,
284
+ reasoning: params.reasoning,
285
+ stateBefore,
286
+ stateAfter: { ...this.currentState },
287
+ estimatedCost: params.estimatedCost ?? 0
288
+ };
289
+ if (params.toolError !== void 0) payload.toolError = params.toolError;
290
+ if (params.tokenCount !== void 0) payload.tokenCount = params.tokenCount;
291
+ if (params.traceId !== void 0) payload.traceId = params.traceId;
292
+ if (params.spanId !== void 0) payload.spanId = params.spanId;
293
+ if (params.metadata !== void 0) payload.metadata = params.metadata;
294
+ return this.safeRequest("POST", `${this.apiUrl}/api/sdk/events`, payload);
295
+ }
296
+ /**
297
+ * Track an LLM decision event
298
+ *
299
+ * @param params - Decision parameters
300
+ * @returns Event data
301
+ */
302
+ async trackDecision(params) {
303
+ const stateBefore = { ...this.currentState };
304
+ const payload = {
305
+ sessionId: params.sessionId,
306
+ eventType: "llm_decision",
307
+ reasoning: params.reasoning,
308
+ alternativesConsidered: params.alternatives,
309
+ confidence: params.confidence,
310
+ stateBefore,
311
+ stateAfter: { ...this.currentState },
312
+ estimatedCost: params.estimatedCost ?? 0
313
+ };
314
+ if (params.tokenCount !== void 0) payload.tokenCount = params.tokenCount;
315
+ if (params.traceId !== void 0) payload.traceId = params.traceId;
316
+ if (params.spanId !== void 0) payload.spanId = params.spanId;
317
+ if (params.metadata !== void 0) payload.metadata = params.metadata;
318
+ return this.safeRequest("POST", `${this.apiUrl}/api/sdk/events`, payload);
319
+ }
320
+ /**
321
+ * Track an error event
322
+ *
323
+ * @param params - Error parameters
324
+ * @returns Event data
325
+ */
326
+ async trackError(params) {
327
+ const stateBefore = { ...this.currentState };
328
+ const toolError = {
329
+ message: params.errorMessage
330
+ };
331
+ if (params.errorType) toolError.type = params.errorType;
332
+ if (params.stackTrace) toolError.stack_trace = params.stackTrace;
333
+ const payload = {
334
+ sessionId: params.sessionId,
335
+ eventType: "error",
336
+ toolError,
337
+ stateBefore,
338
+ stateAfter: { ...this.currentState }
339
+ };
340
+ if (params.toolName !== void 0) payload.toolName = params.toolName;
341
+ if (params.traceId !== void 0) payload.traceId = params.traceId;
342
+ if (params.spanId !== void 0) payload.spanId = params.spanId;
343
+ if (params.metadata !== void 0) payload.metadata = params.metadata;
344
+ return this.safeRequest("POST", `${this.apiUrl}/api/sdk/events`, payload);
345
+ }
346
+ /**
347
+ * Update the current state
348
+ *
349
+ * @param key - State key
350
+ * @param value - State value
351
+ */
352
+ updateState(key, value) {
353
+ this.currentState[key] = value;
354
+ }
355
+ /**
356
+ * Complete a session with performance metrics
357
+ *
358
+ * This is the recommended way to close sessions for performance monitoring.
359
+ *
360
+ * @param params - Session completion parameters
361
+ * @returns Updated session data
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * await client.completeSession({
366
+ * sessionId,
367
+ * success: true,
368
+ * estimatedCost: 0.023,
369
+ * promptTokens: 1500,
370
+ * completionTokens: 500,
371
+ * totalTokens: 2000,
372
+ * userInput: "What's the weather in San Francisco?",
373
+ * assistantOutput: "The weather in San Francisco is 65°F and sunny.",
374
+ * customMetrics: {
375
+ * customer_satisfaction: 4.5,
376
+ * order_value: 129.99,
377
+ * },
378
+ * });
379
+ * ```
380
+ */
381
+ async completeSession(params) {
382
+ const payload = {
383
+ status: params.success !== false ? "completed" : "failed",
384
+ success: params.success ?? true
385
+ };
386
+ if (params.failureReason !== void 0) payload.failureReason = params.failureReason;
387
+ if (params.estimatedCost !== void 0) payload.estimatedCost = params.estimatedCost;
388
+ if (params.customMetrics !== void 0) payload.customMetrics = params.customMetrics;
389
+ if (params.durationMs !== void 0) payload.durationMs = params.durationMs;
390
+ if (params.promptTokens !== void 0) payload.promptTokens = params.promptTokens;
391
+ if (params.completionTokens !== void 0) payload.completionTokens = params.completionTokens;
392
+ if (params.totalTokens !== void 0) payload.totalTokens = params.totalTokens;
393
+ if (params.userInput !== void 0) payload.userInput = params.userInput;
394
+ if (params.assistantOutput !== void 0) payload.assistantOutput = params.assistantOutput;
395
+ return this.safeRequest(
396
+ "PATCH",
397
+ `${this.apiUrl}/api/sdk/sessions/${params.sessionId}`,
398
+ payload
399
+ );
400
+ }
401
+ /**
402
+ * Begin tracking an interaction (simplified API)
403
+ *
404
+ * @param params - Interaction parameters
405
+ * @returns Interaction object with finish() method
406
+ *
407
+ * @example
408
+ * ```ts
409
+ * const interaction = await client.begin({
410
+ * userId: 'user_123',
411
+ * event: 'chat_message',
412
+ * input: message,
413
+ * convoId: 'convo_456',
414
+ * });
415
+ *
416
+ * // ... do your agent work ...
417
+ *
418
+ * await interaction.finish({ output: responseText });
419
+ * ```
420
+ */
421
+ async begin(params) {
422
+ const eventId = params.eventId ?? crypto.randomUUID();
423
+ const fullMetadata = params.metadata ? { ...params.metadata } : {};
424
+ if (params.input) fullMetadata.input = params.input;
425
+ if (params.convoId) fullMetadata.convo_id = params.convoId;
426
+ fullMetadata.event_id = eventId;
427
+ const sessionId = await this.createSession({
428
+ name: `${params.event}:${eventId.slice(0, 8)}`,
429
+ agentName: params.event,
430
+ userId: params.userId,
431
+ metadata: fullMetadata
432
+ });
433
+ if (params.input) {
434
+ this.currentState.input = params.input;
435
+ }
436
+ return new Interaction({
437
+ client: this,
438
+ sessionId,
439
+ eventId,
440
+ userId: params.userId,
441
+ event: params.event
442
+ });
443
+ }
444
+ // Cost calculation static methods for convenience
445
+ static calculateOpenAICost = calculateOpenAICost;
446
+ static calculateAnthropicCost = calculateAnthropicCost;
447
+ static calculateGoogleCost = calculateGoogleCost;
448
+ };
449
+ var Interaction = class {
450
+ client;
451
+ sessionId;
452
+ /** Event ID for this interaction */
453
+ eventId;
454
+ /** User ID for this interaction */
455
+ userId;
456
+ /** Event name for this interaction */
457
+ event;
458
+ finished = false;
459
+ success = true;
460
+ failureReason;
461
+ output;
462
+ degraded;
463
+ constructor(config) {
464
+ this.client = config.client;
465
+ this.sessionId = config.sessionId;
466
+ this.eventId = config.eventId;
467
+ this.userId = config.userId;
468
+ this.event = config.event;
469
+ this.degraded = config.sessionId === null;
470
+ }
471
+ /**
472
+ * Set the output for this interaction
473
+ *
474
+ * This will be used when finish() is called.
475
+ * Useful when you want to set the output but call finish() later.
476
+ *
477
+ * @param output - The output/response text
478
+ */
479
+ setOutput(output) {
480
+ this.output = output;
481
+ }
482
+ /**
483
+ * Finish the interaction and record metrics
484
+ *
485
+ * @param params - Finish parameters
486
+ * @returns Updated session data, or null if degraded/already finished
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * await interaction.finish({
491
+ * output: "Here's the answer to your question...",
492
+ * success: true,
493
+ * customMetrics: { satisfaction: 4.5 },
494
+ * });
495
+ * ```
496
+ */
497
+ async finish(params = {}) {
498
+ if (this.finished) return null;
499
+ if (this.degraded) {
500
+ this.finished = true;
501
+ return null;
502
+ }
503
+ this.finished = true;
504
+ const finalOutput = params.output ?? this.output;
505
+ return this.client.completeSession({
506
+ sessionId: this.sessionId,
507
+ success: params.success ?? this.success,
508
+ failureReason: params.failureReason ?? this.failureReason,
509
+ estimatedCost: params.estimatedCost,
510
+ customMetrics: params.customMetrics,
511
+ promptTokens: params.promptTokens,
512
+ completionTokens: params.completionTokens,
513
+ totalTokens: params.totalTokens,
514
+ assistantOutput: finalOutput
515
+ });
516
+ }
517
+ /**
518
+ * Track a tool call within this interaction
519
+ */
520
+ async trackToolCall(params) {
521
+ if (this.degraded) return null;
522
+ return this.client.trackToolCall({
523
+ ...params,
524
+ sessionId: this.sessionId
525
+ });
526
+ }
527
+ /**
528
+ * Track an LLM decision within this interaction
529
+ */
530
+ async trackDecision(params) {
531
+ if (this.degraded) return null;
532
+ return this.client.trackDecision({
533
+ ...params,
534
+ sessionId: this.sessionId
535
+ });
536
+ }
537
+ /**
538
+ * Track an error within this interaction
539
+ */
540
+ async trackError(params) {
541
+ this.success = false;
542
+ this.failureReason = params.errorMessage;
543
+ if (this.degraded) return null;
544
+ return this.client.trackError({
545
+ ...params,
546
+ sessionId: this.sessionId
547
+ });
548
+ }
549
+ /**
550
+ * Get the session ID (null if session creation failed)
551
+ */
552
+ getSessionId() {
553
+ return this.sessionId;
554
+ }
555
+ /**
556
+ * Check if the interaction is in a degraded state (session creation failed)
557
+ */
558
+ isDegraded() {
559
+ return this.degraded;
560
+ }
561
+ };
562
+ var defaultClient = null;
563
+ function getClient() {
564
+ if (!defaultClient) {
565
+ defaultClient = new SentrialClient();
566
+ }
567
+ return defaultClient;
568
+ }
569
+ function configure(config) {
570
+ defaultClient = new SentrialClient(config);
571
+ }
572
+ function begin(params) {
573
+ return getClient().begin(params);
574
+ }
575
+ var sentrial = {
576
+ configure,
577
+ begin
578
+ };
579
+ // Annotate the CommonJS export names for ESM import in node:
580
+ 0 && (module.exports = {
581
+ ApiError,
582
+ EventType,
583
+ Interaction,
584
+ NetworkError,
585
+ SentrialClient,
586
+ SentrialError,
587
+ ValidationError,
588
+ begin,
589
+ calculateAnthropicCost,
590
+ calculateGoogleCost,
591
+ calculateOpenAICost,
592
+ configure,
593
+ sentrial
594
+ });
595
+ //# sourceMappingURL=index.cjs.map