@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/README.md +208 -0
- package/dist/index.cjs +595 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +642 -0
- package/dist/index.d.ts +642 -0
- package/dist/index.js +556 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SentrialError = class _SentrialError extends Error {
|
|
3
|
+
/** HTTP status code (if applicable) */
|
|
4
|
+
status;
|
|
5
|
+
/** Error code from the API */
|
|
6
|
+
code;
|
|
7
|
+
/** Additional error details */
|
|
8
|
+
details;
|
|
9
|
+
constructor(message, options) {
|
|
10
|
+
super(message, { cause: options?.cause });
|
|
11
|
+
this.name = "SentrialError";
|
|
12
|
+
this.status = options?.status;
|
|
13
|
+
this.code = options?.code;
|
|
14
|
+
this.details = options?.details;
|
|
15
|
+
if (Error.captureStackTrace) {
|
|
16
|
+
Error.captureStackTrace(this, _SentrialError);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if the error is a rate limit error
|
|
21
|
+
*/
|
|
22
|
+
isRateLimitError() {
|
|
23
|
+
return this.status === 429;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if the error is an authentication error
|
|
27
|
+
*/
|
|
28
|
+
isAuthError() {
|
|
29
|
+
return this.status === 401 || this.status === 403;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if the error is a network/connection error
|
|
33
|
+
*/
|
|
34
|
+
isNetworkError() {
|
|
35
|
+
return this.code === "NETWORK_ERROR" || this.code === "ECONNREFUSED";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Convert to a plain object for logging
|
|
39
|
+
*/
|
|
40
|
+
toJSON() {
|
|
41
|
+
return {
|
|
42
|
+
name: this.name,
|
|
43
|
+
message: this.message,
|
|
44
|
+
status: this.status,
|
|
45
|
+
code: this.code,
|
|
46
|
+
details: this.details,
|
|
47
|
+
stack: this.stack
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var ApiError = class extends SentrialError {
|
|
52
|
+
constructor(message, status, code, details) {
|
|
53
|
+
super(message, { status, code, details });
|
|
54
|
+
this.name = "ApiError";
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var NetworkError = class extends SentrialError {
|
|
58
|
+
constructor(message, cause) {
|
|
59
|
+
super(message, { code: "NETWORK_ERROR", cause });
|
|
60
|
+
this.name = "NetworkError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var ValidationError = class extends SentrialError {
|
|
64
|
+
constructor(message, details) {
|
|
65
|
+
super(message, { code: "VALIDATION_ERROR", details });
|
|
66
|
+
this.name = "ValidationError";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/cost.ts
|
|
71
|
+
var OPENAI_PRICING = {
|
|
72
|
+
"gpt-5.2": { input: 5, output: 15 },
|
|
73
|
+
"gpt-5": { input: 4, output: 12 },
|
|
74
|
+
"gpt-4o": { input: 2.5, output: 10 },
|
|
75
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6 },
|
|
76
|
+
"gpt-4-turbo": { input: 10, output: 30 },
|
|
77
|
+
"gpt-4": { input: 30, output: 60 },
|
|
78
|
+
"gpt-3.5-turbo": { input: 0.5, output: 1.5 },
|
|
79
|
+
"o3": { input: 10, output: 40 },
|
|
80
|
+
"o3-mini": { input: 3, output: 12 },
|
|
81
|
+
"o1-preview": { input: 15, output: 60 },
|
|
82
|
+
"o1-mini": { input: 3, output: 12 }
|
|
83
|
+
};
|
|
84
|
+
var ANTHROPIC_PRICING = {
|
|
85
|
+
"claude-4.5-opus": { input: 20, output: 100 },
|
|
86
|
+
"claude-4.5-sonnet": { input: 4, output: 20 },
|
|
87
|
+
"claude-4-opus": { input: 18, output: 90 },
|
|
88
|
+
"claude-4-sonnet": { input: 3.5, output: 17.5 },
|
|
89
|
+
"claude-3-5-sonnet": { input: 3, output: 15 },
|
|
90
|
+
"claude-3-opus": { input: 15, output: 75 },
|
|
91
|
+
"claude-3-sonnet": { input: 3, output: 15 },
|
|
92
|
+
"claude-3-haiku": { input: 0.25, output: 1.25 }
|
|
93
|
+
};
|
|
94
|
+
var GOOGLE_PRICING = {
|
|
95
|
+
// Gemini 3 - Preview (Jan 2026)
|
|
96
|
+
"gemini-3-pro": { input: 2, output: 12 },
|
|
97
|
+
"gemini-3-flash": { input: 0.5, output: 3 },
|
|
98
|
+
// Gemini 2.5
|
|
99
|
+
"gemini-2.5-pro": { input: 1.25, output: 5 },
|
|
100
|
+
"gemini-2.5-flash": { input: 0.15, output: 0.6 },
|
|
101
|
+
// Gemini 2.0
|
|
102
|
+
"gemini-2.0-flash": { input: 0.1, output: 0.4 },
|
|
103
|
+
"gemini-2.0-flash-lite": { input: 0.075, output: 0.3 },
|
|
104
|
+
// Gemini 1.5
|
|
105
|
+
"gemini-1.5-pro": { input: 1.25, output: 5 },
|
|
106
|
+
"gemini-1.5-flash": { input: 0.075, output: 0.3 },
|
|
107
|
+
// Gemini 1.0
|
|
108
|
+
"gemini-1.0-pro": { input: 0.5, output: 1.5 }
|
|
109
|
+
};
|
|
110
|
+
function findModelKey(model, pricing) {
|
|
111
|
+
for (const key of Object.keys(pricing)) {
|
|
112
|
+
if (model.startsWith(key)) {
|
|
113
|
+
return key;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
function calculateCost(inputTokens, outputTokens, rates) {
|
|
119
|
+
const inputCost = inputTokens / 1e6 * rates.input;
|
|
120
|
+
const outputCost = outputTokens / 1e6 * rates.output;
|
|
121
|
+
return inputCost + outputCost;
|
|
122
|
+
}
|
|
123
|
+
function calculateOpenAICost(params) {
|
|
124
|
+
const { model, inputTokens, outputTokens } = params;
|
|
125
|
+
const modelKey = findModelKey(model, OPENAI_PRICING) ?? "gpt-4";
|
|
126
|
+
return calculateCost(inputTokens, outputTokens, OPENAI_PRICING[modelKey]);
|
|
127
|
+
}
|
|
128
|
+
function calculateAnthropicCost(params) {
|
|
129
|
+
const { model, inputTokens, outputTokens } = params;
|
|
130
|
+
const modelKey = findModelKey(model, ANTHROPIC_PRICING) ?? "claude-3-sonnet";
|
|
131
|
+
return calculateCost(inputTokens, outputTokens, ANTHROPIC_PRICING[modelKey]);
|
|
132
|
+
}
|
|
133
|
+
function calculateGoogleCost(params) {
|
|
134
|
+
const { model, inputTokens, outputTokens } = params;
|
|
135
|
+
const modelKey = findModelKey(model, GOOGLE_PRICING) ?? "gemini-2.0-flash";
|
|
136
|
+
return calculateCost(inputTokens, outputTokens, GOOGLE_PRICING[modelKey]);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/types.ts
|
|
140
|
+
var EventType = /* @__PURE__ */ ((EventType2) => {
|
|
141
|
+
EventType2["TOOL_CALL"] = "tool_call";
|
|
142
|
+
EventType2["LLM_DECISION"] = "llm_decision";
|
|
143
|
+
EventType2["STATE_CHANGE"] = "state_change";
|
|
144
|
+
EventType2["ERROR"] = "error";
|
|
145
|
+
return EventType2;
|
|
146
|
+
})(EventType || {});
|
|
147
|
+
|
|
148
|
+
// src/client.ts
|
|
149
|
+
var DEFAULT_API_URL = "https://api.sentrial.com";
|
|
150
|
+
var SentrialClient = class {
|
|
151
|
+
apiUrl;
|
|
152
|
+
apiKey;
|
|
153
|
+
failSilently;
|
|
154
|
+
currentState = {};
|
|
155
|
+
constructor(config = {}) {
|
|
156
|
+
this.apiUrl = (config.apiUrl ?? (typeof process !== "undefined" ? process.env?.SENTRIAL_API_URL : void 0) ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
157
|
+
this.apiKey = config.apiKey ?? (typeof process !== "undefined" ? process.env?.SENTRIAL_API_KEY : void 0);
|
|
158
|
+
this.failSilently = config.failSilently ?? true;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Make an HTTP request with graceful error handling
|
|
162
|
+
*/
|
|
163
|
+
async safeRequest(method, url, body) {
|
|
164
|
+
try {
|
|
165
|
+
const headers = {
|
|
166
|
+
"Content-Type": "application/json"
|
|
167
|
+
};
|
|
168
|
+
if (this.apiKey) {
|
|
169
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
170
|
+
}
|
|
171
|
+
const response = await fetch(url, {
|
|
172
|
+
method,
|
|
173
|
+
headers,
|
|
174
|
+
body: body ? JSON.stringify(body) : void 0
|
|
175
|
+
});
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
const errorBody = await response.text();
|
|
178
|
+
let errorData = {};
|
|
179
|
+
try {
|
|
180
|
+
errorData = JSON.parse(errorBody);
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
const error = new ApiError(
|
|
184
|
+
errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
185
|
+
response.status,
|
|
186
|
+
errorData.error?.code
|
|
187
|
+
);
|
|
188
|
+
if (this.failSilently) {
|
|
189
|
+
console.warn(`Sentrial: Request failed (${method} ${url}):`, error.message);
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
return await response.json();
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error instanceof SentrialError) {
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
const networkError = new NetworkError(
|
|
200
|
+
error instanceof Error ? error.message : "Unknown network error",
|
|
201
|
+
error instanceof Error ? error : void 0
|
|
202
|
+
);
|
|
203
|
+
if (this.failSilently) {
|
|
204
|
+
console.warn(`Sentrial: Request failed (${method} ${url}):`, networkError.message);
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
throw networkError;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Create a new session
|
|
212
|
+
*
|
|
213
|
+
* @param params - Session creation parameters
|
|
214
|
+
* @returns Session ID, or null if the request failed and failSilently is true
|
|
215
|
+
*/
|
|
216
|
+
async createSession(params) {
|
|
217
|
+
this.currentState = {};
|
|
218
|
+
const payload = {
|
|
219
|
+
name: params.name,
|
|
220
|
+
agentName: params.agentName,
|
|
221
|
+
userId: params.userId,
|
|
222
|
+
metadata: params.metadata
|
|
223
|
+
};
|
|
224
|
+
const response = await this.safeRequest(
|
|
225
|
+
"POST",
|
|
226
|
+
`${this.apiUrl}/api/sdk/sessions`,
|
|
227
|
+
payload
|
|
228
|
+
);
|
|
229
|
+
return response?.id ?? null;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Track a tool call event
|
|
233
|
+
*
|
|
234
|
+
* @param params - Tool call parameters
|
|
235
|
+
* @returns Event data
|
|
236
|
+
*/
|
|
237
|
+
async trackToolCall(params) {
|
|
238
|
+
const stateBefore = { ...this.currentState };
|
|
239
|
+
this.currentState[`${params.toolName}_result`] = params.toolOutput;
|
|
240
|
+
const payload = {
|
|
241
|
+
sessionId: params.sessionId,
|
|
242
|
+
eventType: "tool_call",
|
|
243
|
+
toolName: params.toolName,
|
|
244
|
+
toolInput: params.toolInput,
|
|
245
|
+
toolOutput: params.toolOutput,
|
|
246
|
+
reasoning: params.reasoning,
|
|
247
|
+
stateBefore,
|
|
248
|
+
stateAfter: { ...this.currentState },
|
|
249
|
+
estimatedCost: params.estimatedCost ?? 0
|
|
250
|
+
};
|
|
251
|
+
if (params.toolError !== void 0) payload.toolError = params.toolError;
|
|
252
|
+
if (params.tokenCount !== void 0) payload.tokenCount = params.tokenCount;
|
|
253
|
+
if (params.traceId !== void 0) payload.traceId = params.traceId;
|
|
254
|
+
if (params.spanId !== void 0) payload.spanId = params.spanId;
|
|
255
|
+
if (params.metadata !== void 0) payload.metadata = params.metadata;
|
|
256
|
+
return this.safeRequest("POST", `${this.apiUrl}/api/sdk/events`, payload);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Track an LLM decision event
|
|
260
|
+
*
|
|
261
|
+
* @param params - Decision parameters
|
|
262
|
+
* @returns Event data
|
|
263
|
+
*/
|
|
264
|
+
async trackDecision(params) {
|
|
265
|
+
const stateBefore = { ...this.currentState };
|
|
266
|
+
const payload = {
|
|
267
|
+
sessionId: params.sessionId,
|
|
268
|
+
eventType: "llm_decision",
|
|
269
|
+
reasoning: params.reasoning,
|
|
270
|
+
alternativesConsidered: params.alternatives,
|
|
271
|
+
confidence: params.confidence,
|
|
272
|
+
stateBefore,
|
|
273
|
+
stateAfter: { ...this.currentState },
|
|
274
|
+
estimatedCost: params.estimatedCost ?? 0
|
|
275
|
+
};
|
|
276
|
+
if (params.tokenCount !== void 0) payload.tokenCount = params.tokenCount;
|
|
277
|
+
if (params.traceId !== void 0) payload.traceId = params.traceId;
|
|
278
|
+
if (params.spanId !== void 0) payload.spanId = params.spanId;
|
|
279
|
+
if (params.metadata !== void 0) payload.metadata = params.metadata;
|
|
280
|
+
return this.safeRequest("POST", `${this.apiUrl}/api/sdk/events`, payload);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Track an error event
|
|
284
|
+
*
|
|
285
|
+
* @param params - Error parameters
|
|
286
|
+
* @returns Event data
|
|
287
|
+
*/
|
|
288
|
+
async trackError(params) {
|
|
289
|
+
const stateBefore = { ...this.currentState };
|
|
290
|
+
const toolError = {
|
|
291
|
+
message: params.errorMessage
|
|
292
|
+
};
|
|
293
|
+
if (params.errorType) toolError.type = params.errorType;
|
|
294
|
+
if (params.stackTrace) toolError.stack_trace = params.stackTrace;
|
|
295
|
+
const payload = {
|
|
296
|
+
sessionId: params.sessionId,
|
|
297
|
+
eventType: "error",
|
|
298
|
+
toolError,
|
|
299
|
+
stateBefore,
|
|
300
|
+
stateAfter: { ...this.currentState }
|
|
301
|
+
};
|
|
302
|
+
if (params.toolName !== void 0) payload.toolName = params.toolName;
|
|
303
|
+
if (params.traceId !== void 0) payload.traceId = params.traceId;
|
|
304
|
+
if (params.spanId !== void 0) payload.spanId = params.spanId;
|
|
305
|
+
if (params.metadata !== void 0) payload.metadata = params.metadata;
|
|
306
|
+
return this.safeRequest("POST", `${this.apiUrl}/api/sdk/events`, payload);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Update the current state
|
|
310
|
+
*
|
|
311
|
+
* @param key - State key
|
|
312
|
+
* @param value - State value
|
|
313
|
+
*/
|
|
314
|
+
updateState(key, value) {
|
|
315
|
+
this.currentState[key] = value;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Complete a session with performance metrics
|
|
319
|
+
*
|
|
320
|
+
* This is the recommended way to close sessions for performance monitoring.
|
|
321
|
+
*
|
|
322
|
+
* @param params - Session completion parameters
|
|
323
|
+
* @returns Updated session data
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```ts
|
|
327
|
+
* await client.completeSession({
|
|
328
|
+
* sessionId,
|
|
329
|
+
* success: true,
|
|
330
|
+
* estimatedCost: 0.023,
|
|
331
|
+
* promptTokens: 1500,
|
|
332
|
+
* completionTokens: 500,
|
|
333
|
+
* totalTokens: 2000,
|
|
334
|
+
* userInput: "What's the weather in San Francisco?",
|
|
335
|
+
* assistantOutput: "The weather in San Francisco is 65°F and sunny.",
|
|
336
|
+
* customMetrics: {
|
|
337
|
+
* customer_satisfaction: 4.5,
|
|
338
|
+
* order_value: 129.99,
|
|
339
|
+
* },
|
|
340
|
+
* });
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
async completeSession(params) {
|
|
344
|
+
const payload = {
|
|
345
|
+
status: params.success !== false ? "completed" : "failed",
|
|
346
|
+
success: params.success ?? true
|
|
347
|
+
};
|
|
348
|
+
if (params.failureReason !== void 0) payload.failureReason = params.failureReason;
|
|
349
|
+
if (params.estimatedCost !== void 0) payload.estimatedCost = params.estimatedCost;
|
|
350
|
+
if (params.customMetrics !== void 0) payload.customMetrics = params.customMetrics;
|
|
351
|
+
if (params.durationMs !== void 0) payload.durationMs = params.durationMs;
|
|
352
|
+
if (params.promptTokens !== void 0) payload.promptTokens = params.promptTokens;
|
|
353
|
+
if (params.completionTokens !== void 0) payload.completionTokens = params.completionTokens;
|
|
354
|
+
if (params.totalTokens !== void 0) payload.totalTokens = params.totalTokens;
|
|
355
|
+
if (params.userInput !== void 0) payload.userInput = params.userInput;
|
|
356
|
+
if (params.assistantOutput !== void 0) payload.assistantOutput = params.assistantOutput;
|
|
357
|
+
return this.safeRequest(
|
|
358
|
+
"PATCH",
|
|
359
|
+
`${this.apiUrl}/api/sdk/sessions/${params.sessionId}`,
|
|
360
|
+
payload
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Begin tracking an interaction (simplified API)
|
|
365
|
+
*
|
|
366
|
+
* @param params - Interaction parameters
|
|
367
|
+
* @returns Interaction object with finish() method
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```ts
|
|
371
|
+
* const interaction = await client.begin({
|
|
372
|
+
* userId: 'user_123',
|
|
373
|
+
* event: 'chat_message',
|
|
374
|
+
* input: message,
|
|
375
|
+
* convoId: 'convo_456',
|
|
376
|
+
* });
|
|
377
|
+
*
|
|
378
|
+
* // ... do your agent work ...
|
|
379
|
+
*
|
|
380
|
+
* await interaction.finish({ output: responseText });
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
async begin(params) {
|
|
384
|
+
const eventId = params.eventId ?? crypto.randomUUID();
|
|
385
|
+
const fullMetadata = params.metadata ? { ...params.metadata } : {};
|
|
386
|
+
if (params.input) fullMetadata.input = params.input;
|
|
387
|
+
if (params.convoId) fullMetadata.convo_id = params.convoId;
|
|
388
|
+
fullMetadata.event_id = eventId;
|
|
389
|
+
const sessionId = await this.createSession({
|
|
390
|
+
name: `${params.event}:${eventId.slice(0, 8)}`,
|
|
391
|
+
agentName: params.event,
|
|
392
|
+
userId: params.userId,
|
|
393
|
+
metadata: fullMetadata
|
|
394
|
+
});
|
|
395
|
+
if (params.input) {
|
|
396
|
+
this.currentState.input = params.input;
|
|
397
|
+
}
|
|
398
|
+
return new Interaction({
|
|
399
|
+
client: this,
|
|
400
|
+
sessionId,
|
|
401
|
+
eventId,
|
|
402
|
+
userId: params.userId,
|
|
403
|
+
event: params.event
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
// Cost calculation static methods for convenience
|
|
407
|
+
static calculateOpenAICost = calculateOpenAICost;
|
|
408
|
+
static calculateAnthropicCost = calculateAnthropicCost;
|
|
409
|
+
static calculateGoogleCost = calculateGoogleCost;
|
|
410
|
+
};
|
|
411
|
+
var Interaction = class {
|
|
412
|
+
client;
|
|
413
|
+
sessionId;
|
|
414
|
+
/** Event ID for this interaction */
|
|
415
|
+
eventId;
|
|
416
|
+
/** User ID for this interaction */
|
|
417
|
+
userId;
|
|
418
|
+
/** Event name for this interaction */
|
|
419
|
+
event;
|
|
420
|
+
finished = false;
|
|
421
|
+
success = true;
|
|
422
|
+
failureReason;
|
|
423
|
+
output;
|
|
424
|
+
degraded;
|
|
425
|
+
constructor(config) {
|
|
426
|
+
this.client = config.client;
|
|
427
|
+
this.sessionId = config.sessionId;
|
|
428
|
+
this.eventId = config.eventId;
|
|
429
|
+
this.userId = config.userId;
|
|
430
|
+
this.event = config.event;
|
|
431
|
+
this.degraded = config.sessionId === null;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Set the output for this interaction
|
|
435
|
+
*
|
|
436
|
+
* This will be used when finish() is called.
|
|
437
|
+
* Useful when you want to set the output but call finish() later.
|
|
438
|
+
*
|
|
439
|
+
* @param output - The output/response text
|
|
440
|
+
*/
|
|
441
|
+
setOutput(output) {
|
|
442
|
+
this.output = output;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Finish the interaction and record metrics
|
|
446
|
+
*
|
|
447
|
+
* @param params - Finish parameters
|
|
448
|
+
* @returns Updated session data, or null if degraded/already finished
|
|
449
|
+
*
|
|
450
|
+
* @example
|
|
451
|
+
* ```ts
|
|
452
|
+
* await interaction.finish({
|
|
453
|
+
* output: "Here's the answer to your question...",
|
|
454
|
+
* success: true,
|
|
455
|
+
* customMetrics: { satisfaction: 4.5 },
|
|
456
|
+
* });
|
|
457
|
+
* ```
|
|
458
|
+
*/
|
|
459
|
+
async finish(params = {}) {
|
|
460
|
+
if (this.finished) return null;
|
|
461
|
+
if (this.degraded) {
|
|
462
|
+
this.finished = true;
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
this.finished = true;
|
|
466
|
+
const finalOutput = params.output ?? this.output;
|
|
467
|
+
return this.client.completeSession({
|
|
468
|
+
sessionId: this.sessionId,
|
|
469
|
+
success: params.success ?? this.success,
|
|
470
|
+
failureReason: params.failureReason ?? this.failureReason,
|
|
471
|
+
estimatedCost: params.estimatedCost,
|
|
472
|
+
customMetrics: params.customMetrics,
|
|
473
|
+
promptTokens: params.promptTokens,
|
|
474
|
+
completionTokens: params.completionTokens,
|
|
475
|
+
totalTokens: params.totalTokens,
|
|
476
|
+
assistantOutput: finalOutput
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Track a tool call within this interaction
|
|
481
|
+
*/
|
|
482
|
+
async trackToolCall(params) {
|
|
483
|
+
if (this.degraded) return null;
|
|
484
|
+
return this.client.trackToolCall({
|
|
485
|
+
...params,
|
|
486
|
+
sessionId: this.sessionId
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Track an LLM decision within this interaction
|
|
491
|
+
*/
|
|
492
|
+
async trackDecision(params) {
|
|
493
|
+
if (this.degraded) return null;
|
|
494
|
+
return this.client.trackDecision({
|
|
495
|
+
...params,
|
|
496
|
+
sessionId: this.sessionId
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Track an error within this interaction
|
|
501
|
+
*/
|
|
502
|
+
async trackError(params) {
|
|
503
|
+
this.success = false;
|
|
504
|
+
this.failureReason = params.errorMessage;
|
|
505
|
+
if (this.degraded) return null;
|
|
506
|
+
return this.client.trackError({
|
|
507
|
+
...params,
|
|
508
|
+
sessionId: this.sessionId
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get the session ID (null if session creation failed)
|
|
513
|
+
*/
|
|
514
|
+
getSessionId() {
|
|
515
|
+
return this.sessionId;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Check if the interaction is in a degraded state (session creation failed)
|
|
519
|
+
*/
|
|
520
|
+
isDegraded() {
|
|
521
|
+
return this.degraded;
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
var defaultClient = null;
|
|
525
|
+
function getClient() {
|
|
526
|
+
if (!defaultClient) {
|
|
527
|
+
defaultClient = new SentrialClient();
|
|
528
|
+
}
|
|
529
|
+
return defaultClient;
|
|
530
|
+
}
|
|
531
|
+
function configure(config) {
|
|
532
|
+
defaultClient = new SentrialClient(config);
|
|
533
|
+
}
|
|
534
|
+
function begin(params) {
|
|
535
|
+
return getClient().begin(params);
|
|
536
|
+
}
|
|
537
|
+
var sentrial = {
|
|
538
|
+
configure,
|
|
539
|
+
begin
|
|
540
|
+
};
|
|
541
|
+
export {
|
|
542
|
+
ApiError,
|
|
543
|
+
EventType,
|
|
544
|
+
Interaction,
|
|
545
|
+
NetworkError,
|
|
546
|
+
SentrialClient,
|
|
547
|
+
SentrialError,
|
|
548
|
+
ValidationError,
|
|
549
|
+
begin,
|
|
550
|
+
calculateAnthropicCost,
|
|
551
|
+
calculateGoogleCost,
|
|
552
|
+
calculateOpenAICost,
|
|
553
|
+
configure,
|
|
554
|
+
sentrial
|
|
555
|
+
};
|
|
556
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/cost.ts","../src/types.ts","../src/client.ts"],"sourcesContent":["/**\n * Error classes for the Sentrial SDK\n */\n\n/**\n * Base error class for all Sentrial SDK errors\n */\nexport class SentrialError extends Error {\n /** HTTP status code (if applicable) */\n public readonly status?: number;\n /** Error code from the API */\n public readonly code?: string;\n /** Additional error details */\n public readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n options?: {\n status?: number;\n code?: string;\n details?: Record<string, unknown>;\n cause?: Error;\n }\n ) {\n super(message, { cause: options?.cause });\n this.name = 'SentrialError';\n this.status = options?.status;\n this.code = options?.code;\n this.details = options?.details;\n\n // Maintain proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SentrialError);\n }\n }\n\n /**\n * Check if the error is a rate limit error\n */\n isRateLimitError(): boolean {\n return this.status === 429;\n }\n\n /**\n * Check if the error is an authentication error\n */\n isAuthError(): boolean {\n return this.status === 401 || this.status === 403;\n }\n\n /**\n * Check if the error is a network/connection error\n */\n isNetworkError(): boolean {\n return this.code === 'NETWORK_ERROR' || this.code === 'ECONNREFUSED';\n }\n\n /**\n * Convert to a plain object for logging\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n code: this.code,\n details: this.details,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Error thrown when the API returns an error response\n */\nexport class ApiError extends SentrialError {\n constructor(\n message: string,\n status: number,\n code?: string,\n details?: Record<string, unknown>\n ) {\n super(message, { status, code, details });\n this.name = 'ApiError';\n }\n}\n\n/**\n * Error thrown when there's a network/connection issue\n */\nexport class NetworkError extends SentrialError {\n constructor(message: string, cause?: Error) {\n super(message, { code: 'NETWORK_ERROR', cause });\n this.name = 'NetworkError';\n }\n}\n\n/**\n * Error thrown when validation fails\n */\nexport class ValidationError extends SentrialError {\n constructor(message: string, details?: Record<string, unknown>) {\n super(message, { code: 'VALIDATION_ERROR', details });\n this.name = 'ValidationError';\n }\n}\n","/**\n * Cost calculation utilities for various LLM providers\n */\n\nimport type { CostParams } from './types.js';\n\n// ============================================================================\n// Pricing Data (per 1M tokens) - Updated Jan 2026\n// ============================================================================\n\nconst OPENAI_PRICING: Record<string, { input: number; output: number }> = {\n 'gpt-5.2': { input: 5.0, output: 15.0 },\n 'gpt-5': { input: 4.0, output: 12.0 },\n 'gpt-4o': { input: 2.5, output: 10.0 },\n 'gpt-4o-mini': { input: 0.15, output: 0.6 },\n 'gpt-4-turbo': { input: 10.0, output: 30.0 },\n 'gpt-4': { input: 30.0, output: 60.0 },\n 'gpt-3.5-turbo': { input: 0.5, output: 1.5 },\n 'o3': { input: 10.0, output: 40.0 },\n 'o3-mini': { input: 3.0, output: 12.0 },\n 'o1-preview': { input: 15.0, output: 60.0 },\n 'o1-mini': { input: 3.0, output: 12.0 },\n};\n\nconst ANTHROPIC_PRICING: Record<string, { input: number; output: number }> = {\n 'claude-4.5-opus': { input: 20.0, output: 100.0 },\n 'claude-4.5-sonnet': { input: 4.0, output: 20.0 },\n 'claude-4-opus': { input: 18.0, output: 90.0 },\n 'claude-4-sonnet': { input: 3.5, output: 17.5 },\n 'claude-3-5-sonnet': { input: 3.0, output: 15.0 },\n 'claude-3-opus': { input: 15.0, output: 75.0 },\n 'claude-3-sonnet': { input: 3.0, output: 15.0 },\n 'claude-3-haiku': { input: 0.25, output: 1.25 },\n};\n\nconst GOOGLE_PRICING: Record<string, { input: number; output: number }> = {\n // Gemini 3 - Preview (Jan 2026)\n 'gemini-3-pro': { input: 2.0, output: 12.0 },\n 'gemini-3-flash': { input: 0.5, output: 3.0 },\n // Gemini 2.5\n 'gemini-2.5-pro': { input: 1.25, output: 5.0 },\n 'gemini-2.5-flash': { input: 0.15, output: 0.6 },\n // Gemini 2.0\n 'gemini-2.0-flash': { input: 0.1, output: 0.4 },\n 'gemini-2.0-flash-lite': { input: 0.075, output: 0.3 },\n // Gemini 1.5\n 'gemini-1.5-pro': { input: 1.25, output: 5.0 },\n 'gemini-1.5-flash': { input: 0.075, output: 0.3 },\n // Gemini 1.0\n 'gemini-1.0-pro': { input: 0.5, output: 1.5 },\n};\n\n// ============================================================================\n// Helper Function\n// ============================================================================\n\nfunction findModelKey(\n model: string,\n pricing: Record<string, { input: number; output: number }>\n): string | null {\n for (const key of Object.keys(pricing)) {\n if (model.startsWith(key)) {\n return key;\n }\n }\n return null;\n}\n\nfunction calculateCost(\n inputTokens: number,\n outputTokens: number,\n rates: { input: number; output: number }\n): number {\n const inputCost = (inputTokens / 1_000_000) * rates.input;\n const outputCost = (outputTokens / 1_000_000) * rates.output;\n return inputCost + outputCost;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Calculate cost for OpenAI API calls\n *\n * @param params - Cost calculation parameters\n * @returns Estimated cost in USD\n *\n * @example\n * ```ts\n * const cost = calculateOpenAICost({\n * model: 'gpt-4o',\n * inputTokens: 1000,\n * outputTokens: 500,\n * });\n * console.log(`Cost: $${cost.toFixed(4)}`);\n * ```\n */\nexport function calculateOpenAICost(params: CostParams): number {\n const { model, inputTokens, outputTokens } = params;\n const modelKey = findModelKey(model, OPENAI_PRICING) ?? 'gpt-4';\n return calculateCost(inputTokens, outputTokens, OPENAI_PRICING[modelKey]!);\n}\n\n/**\n * Calculate cost for Anthropic API calls\n *\n * @param params - Cost calculation parameters\n * @returns Estimated cost in USD\n *\n * @example\n * ```ts\n * const cost = calculateAnthropicCost({\n * model: 'claude-3-5-sonnet',\n * inputTokens: 1000,\n * outputTokens: 500,\n * });\n * console.log(`Cost: $${cost.toFixed(4)}`);\n * ```\n */\nexport function calculateAnthropicCost(params: CostParams): number {\n const { model, inputTokens, outputTokens } = params;\n const modelKey = findModelKey(model, ANTHROPIC_PRICING) ?? 'claude-3-sonnet';\n return calculateCost(inputTokens, outputTokens, ANTHROPIC_PRICING[modelKey]!);\n}\n\n/**\n * Calculate cost for Google/Gemini API calls\n *\n * @param params - Cost calculation parameters\n * @returns Estimated cost in USD\n *\n * @example\n * ```ts\n * const cost = calculateGoogleCost({\n * model: 'gemini-2.0-flash',\n * inputTokens: 1000,\n * outputTokens: 500,\n * });\n * console.log(`Cost: $${cost.toFixed(4)}`);\n * ```\n */\nexport function calculateGoogleCost(params: CostParams): number {\n const { model, inputTokens, outputTokens } = params;\n const modelKey = findModelKey(model, GOOGLE_PRICING) ?? 'gemini-2.0-flash';\n return calculateCost(inputTokens, outputTokens, GOOGLE_PRICING[modelKey]!);\n}\n","/**\n * Type definitions for the Sentrial TypeScript SDK\n */\n\n// ============================================================================\n// Enums\n// ============================================================================\n\n/**\n * Event types that can be tracked in a session\n */\nexport enum EventType {\n TOOL_CALL = 'tool_call',\n LLM_DECISION = 'llm_decision',\n STATE_CHANGE = 'state_change',\n ERROR = 'error',\n}\n\n/**\n * Session status values\n */\nexport type SessionStatus = 'running' | 'completed' | 'failed' | 'cancelled';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n/**\n * Configuration options for SentrialClient\n */\nexport interface SentrialClientConfig {\n /** API key for authentication (defaults to SENTRIAL_API_KEY env var) */\n apiKey?: string;\n /** URL of the Sentrial API server (defaults to SENTRIAL_API_URL env var or production) */\n apiUrl?: string;\n /**\n * If true (default), SDK errors are logged but won't crash your app.\n * Set to false during development to see full errors.\n */\n failSilently?: boolean;\n}\n\n// ============================================================================\n// Session Types\n// ============================================================================\n\n/**\n * Parameters for creating a new session\n */\nexport interface CreateSessionParams {\n /** Name of the session */\n name: string;\n /** Identifier for the agent type (used for grouping) */\n agentName: string;\n /** External user ID (for grouping sessions by end-user) */\n userId: string;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for completing a session\n */\nexport interface CompleteSessionParams {\n /** Session ID */\n sessionId: string;\n /** Whether the session successfully completed its goal (default: true) */\n success?: boolean;\n /** If success=false, why did it fail? */\n failureReason?: string;\n /** Total estimated cost in USD for this session */\n estimatedCost?: number;\n /** Custom metrics (e.g., { customer_satisfaction: 4.5, steps_taken: 3 }) */\n customMetrics?: Record<string, number>;\n /** Duration in milliseconds (auto-calculated if not provided) */\n durationMs?: number;\n /** Number of prompt/input tokens used */\n promptTokens?: number;\n /** Number of completion/output tokens used */\n completionTokens?: number;\n /** Total tokens used (prompt + completion) */\n totalTokens?: number;\n /** The user's original query/input for this session */\n userInput?: string;\n /** The final assistant response for this session */\n assistantOutput?: string;\n}\n\n/**\n * Session data returned from the API\n */\nexport interface Session {\n id: string;\n agentId?: string;\n name: string;\n agentName: string;\n userId: string;\n status: SessionStatus;\n totalEvents: number;\n\n // User interaction tracking\n userInput?: string;\n assistantOutput?: string;\n\n // Performance tracking\n success?: boolean;\n failureReason?: string;\n estimatedCost?: number;\n customMetrics?: Record<string, unknown>;\n score?: number;\n metricScores?: Record<string, unknown>;\n metricReasonings?: Record<string, string>;\n\n // Token tracking\n promptTokens?: number;\n completionTokens?: number;\n totalTokens?: number;\n\n // Timestamps\n durationMs?: number;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n completedAt?: Date;\n}\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\n/**\n * Parameters for tracking a tool call event\n */\nexport interface TrackToolCallParams {\n /** Session ID */\n sessionId: string;\n /** Name of the tool */\n toolName: string;\n /** Tool input data */\n toolInput: Record<string, unknown>;\n /** Tool output data */\n toolOutput: Record<string, unknown>;\n /** Optional reasoning for why this tool was called */\n reasoning?: string;\n /** Estimated cost in USD for this tool call */\n estimatedCost?: number;\n /** Error details if the tool failed */\n toolError?: Record<string, unknown>;\n /** Number of tokens used by this tool call (for LLM-based tools) */\n tokenCount?: number;\n /** OpenTelemetry trace ID for distributed tracing */\n traceId?: string;\n /** OpenTelemetry span ID for distributed tracing */\n spanId?: string;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for tracking an LLM decision event\n */\nexport interface TrackDecisionParams {\n /** Session ID */\n sessionId: string;\n /** Decision reasoning */\n reasoning: string;\n /** Alternative options considered */\n alternatives?: string[];\n /** Confidence score (0.0 to 1.0) */\n confidence?: number;\n /** Estimated cost in USD for this decision */\n estimatedCost?: number;\n /** Number of tokens used */\n tokenCount?: number;\n /** OpenTelemetry trace ID for distributed tracing */\n traceId?: string;\n /** OpenTelemetry span ID for distributed tracing */\n spanId?: string;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for tracking an error event\n */\nexport interface TrackErrorParams {\n /** Session ID */\n sessionId: string;\n /** Error message */\n errorMessage: string;\n /** Type of error (e.g., \"ValueError\", \"APIError\") */\n errorType?: string;\n /** Name of the tool that caused the error (if applicable) */\n toolName?: string;\n /** Stack trace for debugging */\n stackTrace?: string;\n /** OpenTelemetry trace ID for distributed tracing */\n traceId?: string;\n /** OpenTelemetry span ID for distributed tracing */\n spanId?: string;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Event data returned from the API\n */\nexport interface Event {\n id: string;\n sessionId: string;\n eventType: EventType;\n timestamp: Date;\n sequenceNumber: number;\n\n // Tool call data\n toolName?: string;\n toolInput?: Record<string, unknown>;\n toolOutput?: Record<string, unknown>;\n toolError?: Record<string, unknown>;\n\n // LLM decision data\n reasoning?: string;\n alternativesConsidered?: string[];\n confidence?: number;\n\n // State tracking\n stateBefore?: Record<string, unknown>;\n stateAfter?: Record<string, unknown>;\n stateDiff?: Record<string, unknown>;\n\n // Performance tracking\n estimatedCost?: number;\n tokenCount?: number;\n\n // Metadata\n metadata?: Record<string, unknown>;\n traceId?: string;\n spanId?: string;\n}\n\n// ============================================================================\n// Interaction Types (Simple API)\n// ============================================================================\n\n/**\n * Parameters for beginning an interaction\n */\nexport interface BeginParams {\n /** External user ID for grouping sessions */\n userId: string;\n /** Event type/name (e.g., \"chat_message\", \"search_query\") */\n event: string;\n /** Optional input data for the interaction */\n input?: string;\n /** Optional custom event ID (auto-generated UUID if not provided) */\n eventId?: string;\n /** Optional conversation ID to group related interactions */\n convoId?: string;\n /** Optional additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for finishing an interaction\n */\nexport interface FinishParams {\n /** Output/response from the interaction */\n output?: string;\n /** Whether the interaction succeeded (default: true) */\n success?: boolean;\n /** Reason for failure if success=false */\n failureReason?: string;\n /** Total estimated cost in USD */\n estimatedCost?: number;\n /** Custom metrics */\n customMetrics?: Record<string, number>;\n /** Number of prompt/input tokens used */\n promptTokens?: number;\n /** Number of completion/output tokens used */\n completionTokens?: number;\n /** Total tokens used */\n totalTokens?: number;\n}\n\n// ============================================================================\n// Cost Calculation Types\n// ============================================================================\n\n/**\n * Parameters for cost calculation\n */\nexport interface CostParams {\n /** Model name (e.g., \"gpt-4\", \"claude-3-sonnet\") */\n model: string;\n /** Number of input tokens */\n inputTokens: number;\n /** Number of output tokens */\n outputTokens: number;\n}\n\n// ============================================================================\n// API Response Types\n// ============================================================================\n\n/**\n * Standard API response wrapper\n */\nexport interface ApiResponse<T> {\n data?: T;\n error?: {\n code: string;\n message: string;\n details?: Record<string, unknown>;\n };\n}\n","/**\n * Sentrial Client - Main SDK interface\n *\n * Captures agent sessions, tool calls, and metrics. This data powers:\n * - Signal detection (auto-detect patterns/anomalies)\n * - Root cause analysis (understand WHY agents fail)\n * - Code fixer (AI-suggested fixes with GitHub PRs)\n */\n\nimport { SentrialError, ApiError, NetworkError } from './errors.js';\nimport type {\n SentrialClientConfig,\n CreateSessionParams,\n CompleteSessionParams,\n TrackToolCallParams,\n TrackDecisionParams,\n TrackErrorParams,\n BeginParams,\n FinishParams,\n Session,\n Event,\n EventType,\n} from './types.js';\nimport { calculateOpenAICost, calculateAnthropicCost, calculateGoogleCost } from './cost.js';\n\n// Re-export EventType enum for convenience\nexport { EventType } from './types.js';\n\nconst DEFAULT_API_URL = 'https://api.sentrial.com';\n\n/**\n * Sentrial Client for agent observability.\n *\n * Captures the data needed for automated root cause analysis and fix suggestions.\n *\n * @example\n * ```ts\n * const client = new SentrialClient({\n * apiKey: 'sentrial_live_xxx',\n * apiUrl: 'https://api.sentrial.com',\n * });\n *\n * // Create a session for an agent run\n * const sessionId = await client.createSession({\n * name: 'Support Request #123',\n * agentName: 'support-agent',\n * userId: 'user_123',\n * });\n *\n * // Track events\n * await client.trackToolCall({\n * sessionId,\n * toolName: 'search_kb',\n * toolInput: { query: 'password reset' },\n * toolOutput: { articles: ['KB-001'] },\n * });\n *\n * // Complete session with metrics\n * await client.completeSession({\n * sessionId,\n * success: true,\n * customMetrics: { customer_satisfaction: 90 },\n * });\n * ```\n *\n * @remarks\n * By default, the SDK fails silently (failSilently=true) to ensure\n * monitoring never crashes your application. Set failSilently=false\n * during development to see errors.\n */\nexport class SentrialClient {\n private readonly apiUrl: string;\n private readonly apiKey?: string;\n private readonly failSilently: boolean;\n private currentState: Record<string, unknown> = {};\n\n constructor(config: SentrialClientConfig = {}) {\n this.apiUrl = (\n config.apiUrl ??\n (typeof process !== 'undefined' ? process.env?.SENTRIAL_API_URL : undefined) ??\n DEFAULT_API_URL\n ).replace(/\\/$/, '');\n\n this.apiKey =\n config.apiKey ??\n (typeof process !== 'undefined' ? process.env?.SENTRIAL_API_KEY : undefined);\n\n this.failSilently = config.failSilently ?? true;\n }\n\n /**\n * Make an HTTP request with graceful error handling\n */\n private async safeRequest<T>(\n method: string,\n url: string,\n body?: unknown\n ): Promise<T | null> {\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n let errorData: { error?: { message?: string; code?: string } } = {};\n try {\n errorData = JSON.parse(errorBody);\n } catch {\n // Ignore JSON parse errors\n }\n\n const error = new ApiError(\n errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`,\n response.status,\n errorData.error?.code\n );\n\n if (this.failSilently) {\n console.warn(`Sentrial: Request failed (${method} ${url}):`, error.message);\n return null;\n }\n throw error;\n }\n\n return (await response.json()) as T;\n } catch (error) {\n if (error instanceof SentrialError) {\n throw error;\n }\n\n const networkError = new NetworkError(\n error instanceof Error ? error.message : 'Unknown network error',\n error instanceof Error ? error : undefined\n );\n\n if (this.failSilently) {\n console.warn(`Sentrial: Request failed (${method} ${url}):`, networkError.message);\n return null;\n }\n throw networkError;\n }\n }\n\n /**\n * Create a new session\n *\n * @param params - Session creation parameters\n * @returns Session ID, or null if the request failed and failSilently is true\n */\n async createSession(params: CreateSessionParams): Promise<string | null> {\n // Clear state from previous sessions to prevent memory leaks\n this.currentState = {};\n\n const payload = {\n name: params.name,\n agentName: params.agentName,\n userId: params.userId,\n metadata: params.metadata,\n };\n\n const response = await this.safeRequest<{ id: string }>(\n 'POST',\n `${this.apiUrl}/api/sdk/sessions`,\n payload\n );\n\n return response?.id ?? null;\n }\n\n /**\n * Track a tool call event\n *\n * @param params - Tool call parameters\n * @returns Event data\n */\n async trackToolCall(params: TrackToolCallParams): Promise<Event | null> {\n const stateBefore = { ...this.currentState };\n\n // Update current state\n this.currentState[`${params.toolName}_result`] = params.toolOutput;\n\n const payload: Record<string, unknown> = {\n sessionId: params.sessionId,\n eventType: 'tool_call' as EventType,\n toolName: params.toolName,\n toolInput: params.toolInput,\n toolOutput: params.toolOutput,\n reasoning: params.reasoning,\n stateBefore,\n stateAfter: { ...this.currentState },\n estimatedCost: params.estimatedCost ?? 0,\n };\n\n if (params.toolError !== undefined) payload.toolError = params.toolError;\n if (params.tokenCount !== undefined) payload.tokenCount = params.tokenCount;\n if (params.traceId !== undefined) payload.traceId = params.traceId;\n if (params.spanId !== undefined) payload.spanId = params.spanId;\n if (params.metadata !== undefined) payload.metadata = params.metadata;\n\n return this.safeRequest<Event>('POST', `${this.apiUrl}/api/sdk/events`, payload);\n }\n\n /**\n * Track an LLM decision event\n *\n * @param params - Decision parameters\n * @returns Event data\n */\n async trackDecision(params: TrackDecisionParams): Promise<Event | null> {\n const stateBefore = { ...this.currentState };\n\n const payload: Record<string, unknown> = {\n sessionId: params.sessionId,\n eventType: 'llm_decision' as EventType,\n reasoning: params.reasoning,\n alternativesConsidered: params.alternatives,\n confidence: params.confidence,\n stateBefore,\n stateAfter: { ...this.currentState },\n estimatedCost: params.estimatedCost ?? 0,\n };\n\n if (params.tokenCount !== undefined) payload.tokenCount = params.tokenCount;\n if (params.traceId !== undefined) payload.traceId = params.traceId;\n if (params.spanId !== undefined) payload.spanId = params.spanId;\n if (params.metadata !== undefined) payload.metadata = params.metadata;\n\n return this.safeRequest<Event>('POST', `${this.apiUrl}/api/sdk/events`, payload);\n }\n\n /**\n * Track an error event\n *\n * @param params - Error parameters\n * @returns Event data\n */\n async trackError(params: TrackErrorParams): Promise<Event | null> {\n const stateBefore = { ...this.currentState };\n\n const toolError: Record<string, unknown> = {\n message: params.errorMessage,\n };\n if (params.errorType) toolError.type = params.errorType;\n if (params.stackTrace) toolError.stack_trace = params.stackTrace;\n\n const payload: Record<string, unknown> = {\n sessionId: params.sessionId,\n eventType: 'error' as EventType,\n toolError,\n stateBefore,\n stateAfter: { ...this.currentState },\n };\n\n if (params.toolName !== undefined) payload.toolName = params.toolName;\n if (params.traceId !== undefined) payload.traceId = params.traceId;\n if (params.spanId !== undefined) payload.spanId = params.spanId;\n if (params.metadata !== undefined) payload.metadata = params.metadata;\n\n return this.safeRequest<Event>('POST', `${this.apiUrl}/api/sdk/events`, payload);\n }\n\n /**\n * Update the current state\n *\n * @param key - State key\n * @param value - State value\n */\n updateState(key: string, value: unknown): void {\n this.currentState[key] = value;\n }\n\n /**\n * Complete a session with performance metrics\n *\n * This is the recommended way to close sessions for performance monitoring.\n *\n * @param params - Session completion parameters\n * @returns Updated session data\n *\n * @example\n * ```ts\n * await client.completeSession({\n * sessionId,\n * success: true,\n * estimatedCost: 0.023,\n * promptTokens: 1500,\n * completionTokens: 500,\n * totalTokens: 2000,\n * userInput: \"What's the weather in San Francisco?\",\n * assistantOutput: \"The weather in San Francisco is 65°F and sunny.\",\n * customMetrics: {\n * customer_satisfaction: 4.5,\n * order_value: 129.99,\n * },\n * });\n * ```\n */\n async completeSession(params: CompleteSessionParams): Promise<Session | null> {\n const payload: Record<string, unknown> = {\n status: params.success !== false ? 'completed' : 'failed',\n success: params.success ?? true,\n };\n\n if (params.failureReason !== undefined) payload.failureReason = params.failureReason;\n if (params.estimatedCost !== undefined) payload.estimatedCost = params.estimatedCost;\n if (params.customMetrics !== undefined) payload.customMetrics = params.customMetrics;\n if (params.durationMs !== undefined) payload.durationMs = params.durationMs;\n if (params.promptTokens !== undefined) payload.promptTokens = params.promptTokens;\n if (params.completionTokens !== undefined) payload.completionTokens = params.completionTokens;\n if (params.totalTokens !== undefined) payload.totalTokens = params.totalTokens;\n if (params.userInput !== undefined) payload.userInput = params.userInput;\n if (params.assistantOutput !== undefined) payload.assistantOutput = params.assistantOutput;\n\n return this.safeRequest<Session>(\n 'PATCH',\n `${this.apiUrl}/api/sdk/sessions/${params.sessionId}`,\n payload\n );\n }\n\n /**\n * Begin tracking an interaction (simplified API)\n *\n * @param params - Interaction parameters\n * @returns Interaction object with finish() method\n *\n * @example\n * ```ts\n * const interaction = await client.begin({\n * userId: 'user_123',\n * event: 'chat_message',\n * input: message,\n * convoId: 'convo_456',\n * });\n *\n * // ... do your agent work ...\n *\n * await interaction.finish({ output: responseText });\n * ```\n */\n async begin(params: BeginParams): Promise<Interaction> {\n const eventId = params.eventId ?? crypto.randomUUID();\n\n // Build metadata with optional fields\n const fullMetadata: Record<string, unknown> = params.metadata ? { ...params.metadata } : {};\n if (params.input) fullMetadata.input = params.input;\n if (params.convoId) fullMetadata.convo_id = params.convoId;\n fullMetadata.event_id = eventId;\n\n // Create session first (clears old state)\n const sessionId = await this.createSession({\n name: `${params.event}:${eventId.slice(0, 8)}`,\n agentName: params.event,\n userId: params.userId,\n metadata: fullMetadata,\n });\n\n // Store input in current_state AFTER createSession clears old state\n if (params.input) {\n this.currentState.input = params.input;\n }\n\n return new Interaction({\n client: this,\n sessionId,\n eventId,\n userId: params.userId,\n event: params.event,\n });\n }\n\n // Cost calculation static methods for convenience\n static calculateOpenAICost = calculateOpenAICost;\n static calculateAnthropicCost = calculateAnthropicCost;\n static calculateGoogleCost = calculateGoogleCost;\n}\n\n// ============================================================================\n// Interaction Class\n// ============================================================================\n\ninterface InteractionConfig {\n client: SentrialClient;\n sessionId: string | null;\n eventId: string;\n userId: string;\n event: string;\n}\n\n/**\n * Represents an in-progress interaction that can be finished.\n *\n * Created by SentrialClient.begin() - provides a clean begin/finish API pattern.\n *\n * @remarks\n * If session creation failed (sessionId is null), all tracking methods\n * become no-ops to ensure your application continues running.\n */\nexport class Interaction {\n private readonly client: SentrialClient;\n private readonly sessionId: string | null;\n /** Event ID for this interaction */\n public readonly eventId: string;\n /** User ID for this interaction */\n public readonly userId: string;\n /** Event name for this interaction */\n public readonly event: string;\n private finished = false;\n private success = true;\n private failureReason?: string;\n private output?: string;\n private readonly degraded: boolean;\n\n constructor(config: InteractionConfig) {\n this.client = config.client;\n this.sessionId = config.sessionId;\n this.eventId = config.eventId;\n this.userId = config.userId;\n this.event = config.event;\n this.degraded = config.sessionId === null;\n }\n\n /**\n * Set the output for this interaction\n *\n * This will be used when finish() is called.\n * Useful when you want to set the output but call finish() later.\n *\n * @param output - The output/response text\n */\n setOutput(output: string): void {\n this.output = output;\n }\n\n /**\n * Finish the interaction and record metrics\n *\n * @param params - Finish parameters\n * @returns Updated session data, or null if degraded/already finished\n *\n * @example\n * ```ts\n * await interaction.finish({\n * output: \"Here's the answer to your question...\",\n * success: true,\n * customMetrics: { satisfaction: 4.5 },\n * });\n * ```\n */\n async finish(params: FinishParams = {}): Promise<Session | null> {\n if (this.finished) return null;\n if (this.degraded) {\n this.finished = true;\n return null;\n }\n\n this.finished = true;\n\n // Use stored output if not provided\n const finalOutput = params.output ?? this.output;\n\n return this.client.completeSession({\n sessionId: this.sessionId!,\n success: params.success ?? this.success,\n failureReason: params.failureReason ?? this.failureReason,\n estimatedCost: params.estimatedCost,\n customMetrics: params.customMetrics,\n promptTokens: params.promptTokens,\n completionTokens: params.completionTokens,\n totalTokens: params.totalTokens,\n assistantOutput: finalOutput,\n });\n }\n\n /**\n * Track a tool call within this interaction\n */\n async trackToolCall(\n params: Omit<TrackToolCallParams, 'sessionId'>\n ): Promise<Event | null> {\n if (this.degraded) return null;\n\n return this.client.trackToolCall({\n ...params,\n sessionId: this.sessionId!,\n });\n }\n\n /**\n * Track an LLM decision within this interaction\n */\n async trackDecision(\n params: Omit<TrackDecisionParams, 'sessionId'>\n ): Promise<Event | null> {\n if (this.degraded) return null;\n\n return this.client.trackDecision({\n ...params,\n sessionId: this.sessionId!,\n });\n }\n\n /**\n * Track an error within this interaction\n */\n async trackError(\n params: Omit<TrackErrorParams, 'sessionId'>\n ): Promise<Event | null> {\n // Store failure info\n this.success = false;\n this.failureReason = params.errorMessage;\n\n if (this.degraded) return null;\n\n return this.client.trackError({\n ...params,\n sessionId: this.sessionId!,\n });\n }\n\n /**\n * Get the session ID (null if session creation failed)\n */\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /**\n * Check if the interaction is in a degraded state (session creation failed)\n */\n isDegraded(): boolean {\n return this.degraded;\n }\n}\n\n// ============================================================================\n// Module-level Simple API\n// ============================================================================\n\nlet defaultClient: SentrialClient | null = null;\n\nfunction getClient(): SentrialClient {\n if (!defaultClient) {\n defaultClient = new SentrialClient();\n }\n return defaultClient;\n}\n\n/**\n * Configure the default Sentrial client\n *\n * @param config - Client configuration\n *\n * @example\n * ```ts\n * import { sentrial } from '@sentrial/sdk';\n *\n * sentrial.configure({\n * apiKey: 'sentrial_live_xxx',\n * apiUrl: 'https://api.sentrial.com',\n * });\n * ```\n */\nexport function configure(config: SentrialClientConfig): void {\n defaultClient = new SentrialClient(config);\n}\n\n/**\n * Begin tracking an interaction (module-level convenience function)\n *\n * This is a shorthand for new SentrialClient().begin(...).\n * Configure the client first with sentrial.configure() or set SENTRIAL_API_KEY env var.\n *\n * @param params - Interaction parameters\n * @returns Interaction object with finish() method\n *\n * @example\n * ```ts\n * import { sentrial } from '@sentrial/sdk';\n *\n * sentrial.configure({ apiKey: 'sentrial_live_xxx' });\n *\n * const interaction = await sentrial.begin({\n * userId: 'user_123',\n * event: 'chat_message',\n * input: message,\n * });\n *\n * // ... do your agent work ...\n *\n * await interaction.finish({ output: responseText });\n * ```\n */\nexport function begin(params: BeginParams): Promise<Interaction> {\n return getClient().begin(params);\n}\n\n/**\n * Simple API namespace for module-level usage\n */\nexport const sentrial = {\n configure,\n begin,\n};\n"],"mappings":"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","names":["EventType"]}
|