@sentrial/sdk 0.2.0 → 0.3.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 +464 -162
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +168 -65
- package/dist/index.d.ts +168 -65
- package/dist/index.js +459 -162
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -47,7 +47,12 @@ __export(index_exports, {
|
|
|
47
47
|
getSessionContext: () => getSessionContext,
|
|
48
48
|
getSystemPrompt: () => getSystemPrompt,
|
|
49
49
|
getVariantName: () => getVariantName,
|
|
50
|
+
hashValue: () => hashValue,
|
|
50
51
|
isExperimentMode: () => isExperimentMode,
|
|
52
|
+
redactPayload: () => redactPayload,
|
|
53
|
+
redactString: () => redactString,
|
|
54
|
+
redactValue: () => redactValue,
|
|
55
|
+
replaceMatch: () => replaceMatch,
|
|
51
56
|
sentrial: () => sentrial,
|
|
52
57
|
setClient: () => setClient,
|
|
53
58
|
setDefaultClient: () => setDefaultClient,
|
|
@@ -132,26 +137,126 @@ var ValidationError = class extends SentrialError {
|
|
|
132
137
|
}
|
|
133
138
|
};
|
|
134
139
|
|
|
140
|
+
// src/redact.ts
|
|
141
|
+
var import_crypto = require("crypto");
|
|
142
|
+
var DEFAULT_FIELDS = [
|
|
143
|
+
"userInput",
|
|
144
|
+
"assistantOutput",
|
|
145
|
+
"toolInput",
|
|
146
|
+
"toolOutput"
|
|
147
|
+
];
|
|
148
|
+
var DEFAULT_BUILTIN = {
|
|
149
|
+
emails: true,
|
|
150
|
+
phones: true,
|
|
151
|
+
ssns: true,
|
|
152
|
+
creditCards: true,
|
|
153
|
+
ipAddresses: true
|
|
154
|
+
};
|
|
155
|
+
var EMAIL_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
156
|
+
var PHONE_PATTERN = /(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g;
|
|
157
|
+
var SSN_PATTERN = /\b\d{3}-\d{2}-\d{4}\b/g;
|
|
158
|
+
var CREDIT_CARD_PATTERN = /\b(?:\d[-\s]?){13,19}\b/g;
|
|
159
|
+
var IP_ADDRESS_PATTERN = /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b/g;
|
|
160
|
+
var BUILTIN_PATTERNS = {
|
|
161
|
+
emails: { pattern: EMAIL_PATTERN, label: "EMAIL" },
|
|
162
|
+
phones: { pattern: PHONE_PATTERN, label: "PHONE" },
|
|
163
|
+
ssns: { pattern: SSN_PATTERN, label: "SSN" },
|
|
164
|
+
creditCards: { pattern: CREDIT_CARD_PATTERN, label: "CREDIT_CARD" },
|
|
165
|
+
ipAddresses: { pattern: IP_ADDRESS_PATTERN, label: "IP_ADDRESS" }
|
|
166
|
+
};
|
|
167
|
+
function hashValue(value) {
|
|
168
|
+
return (0, import_crypto.createHash)("sha256").update(value).digest("hex").slice(0, 6);
|
|
169
|
+
}
|
|
170
|
+
function replaceMatch(match, label, mode) {
|
|
171
|
+
switch (mode) {
|
|
172
|
+
case "label":
|
|
173
|
+
return `[${label}]`;
|
|
174
|
+
case "hash":
|
|
175
|
+
return `[PII:${hashValue(match)}]`;
|
|
176
|
+
case "remove":
|
|
177
|
+
return "";
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function redactString(value, mode, builtinPatterns, customPatterns) {
|
|
181
|
+
let result = value;
|
|
182
|
+
for (const [key, config] of Object.entries(BUILTIN_PATTERNS)) {
|
|
183
|
+
if (builtinPatterns[key]) {
|
|
184
|
+
const regex = new RegExp(config.pattern.source, config.pattern.flags);
|
|
185
|
+
result = result.replace(regex, (match) => replaceMatch(match, config.label, mode));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
for (const custom of customPatterns) {
|
|
189
|
+
const regex = new RegExp(custom.pattern.source, custom.pattern.flags);
|
|
190
|
+
result = result.replace(regex, (match) => replaceMatch(match, custom.label, mode));
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
function redactValue(value, mode, builtinPatterns, customPatterns) {
|
|
195
|
+
if (typeof value === "string") {
|
|
196
|
+
return redactString(value, mode, builtinPatterns, customPatterns);
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(value)) {
|
|
199
|
+
return value.map((item) => redactValue(item, mode, builtinPatterns, customPatterns));
|
|
200
|
+
}
|
|
201
|
+
if (value !== null && typeof value === "object") {
|
|
202
|
+
const result = {};
|
|
203
|
+
for (const [key, val] of Object.entries(value)) {
|
|
204
|
+
result[key] = redactValue(val, mode, builtinPatterns, customPatterns);
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
function redactPayload(payload, config) {
|
|
211
|
+
if (!config.enabled) {
|
|
212
|
+
return payload;
|
|
213
|
+
}
|
|
214
|
+
const mode = config.mode ?? "label";
|
|
215
|
+
const fields = config.fields ?? DEFAULT_FIELDS;
|
|
216
|
+
const builtinPatterns = {
|
|
217
|
+
...DEFAULT_BUILTIN,
|
|
218
|
+
...config.builtinPatterns
|
|
219
|
+
};
|
|
220
|
+
const customPatterns = config.customPatterns ?? [];
|
|
221
|
+
const result = { ...payload };
|
|
222
|
+
for (const field of fields) {
|
|
223
|
+
if (field in result && result[field] !== void 0 && result[field] !== null) {
|
|
224
|
+
result[field] = redactValue(result[field], mode, builtinPatterns, customPatterns);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
|
|
135
230
|
// src/cost.ts
|
|
136
231
|
var OPENAI_PRICING = {
|
|
137
232
|
"gpt-5.2": { input: 5, output: 15 },
|
|
138
233
|
"gpt-5": { input: 4, output: 12 },
|
|
234
|
+
"gpt-4.1": { input: 2, output: 8 },
|
|
235
|
+
"gpt-4.1-mini": { input: 0.4, output: 1.6 },
|
|
236
|
+
"gpt-4.1-nano": { input: 0.1, output: 0.4 },
|
|
139
237
|
"gpt-4o": { input: 2.5, output: 10 },
|
|
140
238
|
"gpt-4o-mini": { input: 0.15, output: 0.6 },
|
|
141
239
|
"gpt-4-turbo": { input: 10, output: 30 },
|
|
142
240
|
"gpt-4": { input: 30, output: 60 },
|
|
143
241
|
"gpt-3.5-turbo": { input: 0.5, output: 1.5 },
|
|
242
|
+
"o4-mini": { input: 1.1, output: 4.4 },
|
|
144
243
|
"o3": { input: 10, output: 40 },
|
|
145
|
-
"o3-mini": { input:
|
|
244
|
+
"o3-mini": { input: 1.1, output: 4.4 },
|
|
245
|
+
"o3-pro": { input: 20, output: 80 },
|
|
246
|
+
"o1": { input: 15, output: 60 },
|
|
146
247
|
"o1-preview": { input: 15, output: 60 },
|
|
147
248
|
"o1-mini": { input: 3, output: 12 }
|
|
148
249
|
};
|
|
149
250
|
var ANTHROPIC_PRICING = {
|
|
251
|
+
"claude-opus-4": { input: 15, output: 75 },
|
|
252
|
+
"claude-sonnet-4": { input: 3, output: 15 },
|
|
150
253
|
"claude-4.5-opus": { input: 20, output: 100 },
|
|
151
254
|
"claude-4.5-sonnet": { input: 4, output: 20 },
|
|
152
255
|
"claude-4-opus": { input: 18, output: 90 },
|
|
153
256
|
"claude-4-sonnet": { input: 3.5, output: 17.5 },
|
|
257
|
+
"claude-3-7-sonnet": { input: 3, output: 15 },
|
|
154
258
|
"claude-3-5-sonnet": { input: 3, output: 15 },
|
|
259
|
+
"claude-3-5-haiku": { input: 0.8, output: 4 },
|
|
155
260
|
"claude-3-opus": { input: 15, output: 75 },
|
|
156
261
|
"claude-3-sonnet": { input: 3, output: 15 },
|
|
157
262
|
"claude-3-haiku": { input: 0.25, output: 1.25 }
|
|
@@ -222,11 +327,75 @@ var SentrialClient = class {
|
|
|
222
327
|
apiUrl;
|
|
223
328
|
apiKey;
|
|
224
329
|
failSilently;
|
|
330
|
+
piiConfig;
|
|
331
|
+
piiConfigNeedsHydration = false;
|
|
332
|
+
piiHydrationPromise;
|
|
225
333
|
currentState = {};
|
|
226
334
|
constructor(config = {}) {
|
|
227
335
|
this.apiUrl = (config.apiUrl ?? (typeof process !== "undefined" ? process.env?.SENTRIAL_API_URL : void 0) ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
228
336
|
this.apiKey = config.apiKey ?? (typeof process !== "undefined" ? process.env?.SENTRIAL_API_KEY : void 0);
|
|
229
337
|
this.failSilently = config.failSilently ?? true;
|
|
338
|
+
if (config.pii === true) {
|
|
339
|
+
this.piiConfig = { enabled: true };
|
|
340
|
+
this.piiConfigNeedsHydration = true;
|
|
341
|
+
} else if (config.pii && typeof config.pii === "object") {
|
|
342
|
+
this.piiConfig = config.pii;
|
|
343
|
+
this.piiConfigNeedsHydration = false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Fetch the organization's PII config from the server.
|
|
348
|
+
*
|
|
349
|
+
* Called lazily on the first request when `pii: true` was passed to the constructor.
|
|
350
|
+
* Uses a single shared promise so concurrent requests don't trigger duplicate fetches.
|
|
351
|
+
*/
|
|
352
|
+
async hydratePiiConfig() {
|
|
353
|
+
if (!this.piiConfigNeedsHydration) return;
|
|
354
|
+
if (this.piiHydrationPromise) {
|
|
355
|
+
await this.piiHydrationPromise;
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
this.piiHydrationPromise = (async () => {
|
|
359
|
+
try {
|
|
360
|
+
const headers = {};
|
|
361
|
+
if (this.apiKey) {
|
|
362
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
363
|
+
}
|
|
364
|
+
const controller = new AbortController();
|
|
365
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
366
|
+
let response;
|
|
367
|
+
try {
|
|
368
|
+
response = await fetch(`${this.apiUrl}/api/sdk/pii-config`, {
|
|
369
|
+
method: "GET",
|
|
370
|
+
headers,
|
|
371
|
+
signal: controller.signal
|
|
372
|
+
});
|
|
373
|
+
} finally {
|
|
374
|
+
clearTimeout(timeoutId);
|
|
375
|
+
}
|
|
376
|
+
if (response.ok) {
|
|
377
|
+
const data = await response.json();
|
|
378
|
+
if (data.config) {
|
|
379
|
+
this.piiConfig = {
|
|
380
|
+
enabled: data.config.enabled,
|
|
381
|
+
mode: data.config.mode,
|
|
382
|
+
fields: data.config.fields,
|
|
383
|
+
builtinPatterns: data.config.builtinPatterns,
|
|
384
|
+
customPatterns: (data.config.customPatterns || []).map(
|
|
385
|
+
(cp) => ({
|
|
386
|
+
pattern: new RegExp(cp.pattern, "g"),
|
|
387
|
+
label: cp.label
|
|
388
|
+
})
|
|
389
|
+
),
|
|
390
|
+
enhancedDetection: data.config.enhancedDetection
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} catch {
|
|
395
|
+
}
|
|
396
|
+
this.piiConfigNeedsHydration = false;
|
|
397
|
+
})();
|
|
398
|
+
await this.piiHydrationPromise;
|
|
230
399
|
}
|
|
231
400
|
/**
|
|
232
401
|
* Make an HTTP request with retry logic and exponential backoff.
|
|
@@ -235,6 +404,9 @@ var SentrialClient = class {
|
|
|
235
404
|
* Up to MAX_RETRIES attempts with exponential backoff.
|
|
236
405
|
*/
|
|
237
406
|
async safeRequest(method, url, body) {
|
|
407
|
+
if (this.piiConfigNeedsHydration) {
|
|
408
|
+
await this.hydratePiiConfig();
|
|
409
|
+
}
|
|
238
410
|
let lastError;
|
|
239
411
|
let backoff = INITIAL_BACKOFF_MS;
|
|
240
412
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -245,6 +417,7 @@ var SentrialClient = class {
|
|
|
245
417
|
if (this.apiKey) {
|
|
246
418
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
247
419
|
}
|
|
420
|
+
const finalBody = this.piiConfig && body && typeof body === "object" ? redactPayload(body, this.piiConfig) : body;
|
|
248
421
|
const controller = new AbortController();
|
|
249
422
|
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
250
423
|
let response;
|
|
@@ -252,7 +425,7 @@ var SentrialClient = class {
|
|
|
252
425
|
response = await fetch(url, {
|
|
253
426
|
method,
|
|
254
427
|
headers,
|
|
255
|
-
body:
|
|
428
|
+
body: finalBody ? JSON.stringify(finalBody) : void 0,
|
|
256
429
|
signal: controller.signal
|
|
257
430
|
});
|
|
258
431
|
} finally {
|
|
@@ -324,6 +497,9 @@ var SentrialClient = class {
|
|
|
324
497
|
if (params.parentSessionId) {
|
|
325
498
|
payload.parentSessionId = params.parentSessionId;
|
|
326
499
|
}
|
|
500
|
+
if (params.convoId) {
|
|
501
|
+
payload.convoId = params.convoId;
|
|
502
|
+
}
|
|
327
503
|
const response = await this.safeRequest(
|
|
328
504
|
"POST",
|
|
329
505
|
`${this.apiUrl}/api/sdk/sessions`,
|
|
@@ -530,6 +706,7 @@ var SentrialClient = class {
|
|
|
530
706
|
name: `${params.event}:${eventId.slice(0, 8)}`,
|
|
531
707
|
agentName: params.event,
|
|
532
708
|
userId: params.userId,
|
|
709
|
+
convoId: params.convoId,
|
|
533
710
|
metadata: fullMetadata
|
|
534
711
|
});
|
|
535
712
|
if (params.input) {
|
|
@@ -694,7 +871,8 @@ function configureVercel(config) {
|
|
|
694
871
|
});
|
|
695
872
|
_globalConfig = {
|
|
696
873
|
defaultAgent: config.defaultAgent,
|
|
697
|
-
userId: config.userId
|
|
874
|
+
userId: config.userId,
|
|
875
|
+
convoId: config.convoId
|
|
698
876
|
};
|
|
699
877
|
}
|
|
700
878
|
function getClient2() {
|
|
@@ -709,11 +887,15 @@ function extractModelInfo(model) {
|
|
|
709
887
|
return { modelId, provider };
|
|
710
888
|
}
|
|
711
889
|
function guessProvider(modelId) {
|
|
712
|
-
|
|
713
|
-
if (
|
|
714
|
-
if (
|
|
715
|
-
if (
|
|
716
|
-
if (
|
|
890
|
+
const id = modelId.toLowerCase();
|
|
891
|
+
if (id.includes("gpt") || id.includes("o1") || id.includes("o3") || id.includes("o4") || id.startsWith("chatgpt")) return "openai";
|
|
892
|
+
if (id.includes("claude")) return "anthropic";
|
|
893
|
+
if (id.includes("gemini")) return "google";
|
|
894
|
+
if (id.includes("mistral") || id.includes("mixtral") || id.includes("codestral") || id.includes("pixtral")) return "mistral";
|
|
895
|
+
if (id.includes("llama")) return "meta";
|
|
896
|
+
if (id.includes("deepseek")) return "deepseek";
|
|
897
|
+
if (id.includes("command")) return "cohere";
|
|
898
|
+
if (id.includes("qwen")) return "alibaba";
|
|
717
899
|
return "unknown";
|
|
718
900
|
}
|
|
719
901
|
function calculateCostForCall(provider, modelId, promptTokens, completionTokens) {
|
|
@@ -725,6 +907,12 @@ function calculateCostForCall(provider, modelId, promptTokens, completionTokens)
|
|
|
725
907
|
return calculateAnthropicCost(params);
|
|
726
908
|
case "google":
|
|
727
909
|
return calculateGoogleCost(params);
|
|
910
|
+
case "deepseek":
|
|
911
|
+
return promptTokens / 1e6 * 0.27 + completionTokens / 1e6 * 1.1;
|
|
912
|
+
case "cohere":
|
|
913
|
+
return promptTokens / 1e6 * 0.5 + completionTokens / 1e6 * 1.5;
|
|
914
|
+
case "mistral":
|
|
915
|
+
return promptTokens / 1e6 * 2 + completionTokens / 1e6 * 6;
|
|
728
916
|
default:
|
|
729
917
|
return promptTokens * 3e-6 + completionTokens * 6e-6;
|
|
730
918
|
}
|
|
@@ -733,7 +921,10 @@ function extractInput(params) {
|
|
|
733
921
|
if (params.prompt) return params.prompt;
|
|
734
922
|
if (params.messages && params.messages.length > 0) {
|
|
735
923
|
const lastUserMessage = [...params.messages].reverse().find((m) => m.role === "user");
|
|
736
|
-
|
|
924
|
+
if (lastUserMessage) {
|
|
925
|
+
return typeof lastUserMessage.content === "string" ? lastUserMessage.content : JSON.stringify(lastUserMessage.content);
|
|
926
|
+
}
|
|
927
|
+
return JSON.stringify(params.messages);
|
|
737
928
|
}
|
|
738
929
|
return "";
|
|
739
930
|
}
|
|
@@ -750,23 +941,25 @@ function wrapTools(tools, sessionId, client) {
|
|
|
750
941
|
try {
|
|
751
942
|
const result = await originalExecute(...args);
|
|
752
943
|
const durationMs = Date.now() - startTime;
|
|
753
|
-
|
|
944
|
+
client.trackToolCall({
|
|
754
945
|
sessionId,
|
|
755
946
|
toolName,
|
|
756
947
|
toolInput: args[0],
|
|
757
948
|
toolOutput: result,
|
|
758
949
|
reasoning: `Tool executed in ${durationMs}ms`
|
|
950
|
+
}).catch(() => {
|
|
759
951
|
});
|
|
760
952
|
return result;
|
|
761
953
|
} catch (error) {
|
|
762
954
|
const durationMs = Date.now() - startTime;
|
|
763
|
-
|
|
955
|
+
client.trackToolCall({
|
|
764
956
|
sessionId,
|
|
765
957
|
toolName,
|
|
766
958
|
toolInput: args[0],
|
|
767
959
|
toolOutput: {},
|
|
768
960
|
toolError: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
769
961
|
reasoning: `Tool failed after ${durationMs}ms`
|
|
962
|
+
}).catch(() => {
|
|
770
963
|
});
|
|
771
964
|
throw error;
|
|
772
965
|
}
|
|
@@ -778,19 +971,68 @@ function wrapTools(tools, sessionId, client) {
|
|
|
778
971
|
}
|
|
779
972
|
return wrappedTools;
|
|
780
973
|
}
|
|
781
|
-
function
|
|
974
|
+
function wrapToolsAsync(tools, sessionPromise, client) {
|
|
975
|
+
const wrappedTools = {};
|
|
976
|
+
for (const [toolName, tool] of Object.entries(tools)) {
|
|
977
|
+
if (typeof tool.execute === "function") {
|
|
978
|
+
const originalExecute = tool.execute;
|
|
979
|
+
wrappedTools[toolName] = {
|
|
980
|
+
...tool,
|
|
981
|
+
execute: async (...args) => {
|
|
982
|
+
const startTime = Date.now();
|
|
983
|
+
const sid = await sessionPromise;
|
|
984
|
+
try {
|
|
985
|
+
const result = await originalExecute(...args);
|
|
986
|
+
const durationMs = Date.now() - startTime;
|
|
987
|
+
if (sid) {
|
|
988
|
+
client.trackToolCall({
|
|
989
|
+
sessionId: sid,
|
|
990
|
+
toolName,
|
|
991
|
+
toolInput: args[0],
|
|
992
|
+
toolOutput: result,
|
|
993
|
+
reasoning: `Tool executed in ${durationMs}ms`
|
|
994
|
+
}).catch(() => {
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
return result;
|
|
998
|
+
} catch (error) {
|
|
999
|
+
const durationMs = Date.now() - startTime;
|
|
1000
|
+
if (sid) {
|
|
1001
|
+
client.trackToolCall({
|
|
1002
|
+
sessionId: sid,
|
|
1003
|
+
toolName,
|
|
1004
|
+
toolInput: args[0],
|
|
1005
|
+
toolOutput: {},
|
|
1006
|
+
toolError: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
1007
|
+
reasoning: `Tool failed after ${durationMs}ms`
|
|
1008
|
+
}).catch(() => {
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
throw error;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
} else {
|
|
1016
|
+
wrappedTools[toolName] = tool;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return wrappedTools;
|
|
1020
|
+
}
|
|
1021
|
+
function wrapGenerateText(originalFn, client, config) {
|
|
782
1022
|
return async (params) => {
|
|
783
1023
|
const startTime = Date.now();
|
|
784
1024
|
const { modelId, provider } = extractModelInfo(params.model);
|
|
785
1025
|
const input = extractInput(params);
|
|
786
1026
|
const sessionId = await client.createSession({
|
|
787
1027
|
name: `generateText: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
788
|
-
agentName:
|
|
789
|
-
userId:
|
|
1028
|
+
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
1029
|
+
userId: config.userId ?? "anonymous",
|
|
1030
|
+
convoId: config.convoId,
|
|
790
1031
|
metadata: {
|
|
791
1032
|
model: modelId,
|
|
792
1033
|
provider,
|
|
793
|
-
function: "generateText"
|
|
1034
|
+
function: "generateText",
|
|
1035
|
+
...params.maxSteps ? { maxSteps: params.maxSteps } : {}
|
|
794
1036
|
}
|
|
795
1037
|
});
|
|
796
1038
|
if (!sessionId) {
|
|
@@ -804,23 +1046,46 @@ function wrapGenerateText(originalFn, client) {
|
|
|
804
1046
|
try {
|
|
805
1047
|
const result = await originalFn(wrappedParams);
|
|
806
1048
|
const durationMs = Date.now() - startTime;
|
|
1049
|
+
const resolvedModelId = result.response?.modelId || modelId;
|
|
807
1050
|
const promptTokens = result.usage?.promptTokens || 0;
|
|
808
1051
|
const completionTokens = result.usage?.completionTokens || 0;
|
|
809
1052
|
const totalTokens = result.usage?.totalTokens || promptTokens + completionTokens;
|
|
810
|
-
const cost = calculateCostForCall(provider,
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
1053
|
+
const cost = calculateCostForCall(provider, resolvedModelId, promptTokens, completionTokens);
|
|
1054
|
+
const steps = result.steps;
|
|
1055
|
+
if (steps && steps.length >= 1) {
|
|
1056
|
+
for (let i = 0; i < steps.length; i++) {
|
|
1057
|
+
const step = steps[i];
|
|
1058
|
+
await client.trackEvent({
|
|
1059
|
+
sessionId,
|
|
1060
|
+
eventType: "llm_call",
|
|
1061
|
+
eventData: {
|
|
1062
|
+
model: resolvedModelId,
|
|
1063
|
+
provider,
|
|
1064
|
+
step: i + 1,
|
|
1065
|
+
total_steps: steps.length,
|
|
1066
|
+
prompt_tokens: step.usage?.promptTokens || 0,
|
|
1067
|
+
completion_tokens: step.usage?.completionTokens || 0,
|
|
1068
|
+
total_tokens: step.usage?.totalTokens || 0,
|
|
1069
|
+
finish_reason: step.finishReason,
|
|
1070
|
+
tool_calls: step.toolCalls?.map((tc) => tc.toolName)
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
822
1073
|
}
|
|
823
|
-
}
|
|
1074
|
+
} else {
|
|
1075
|
+
await client.trackEvent({
|
|
1076
|
+
sessionId,
|
|
1077
|
+
eventType: "llm_call",
|
|
1078
|
+
eventData: {
|
|
1079
|
+
model: resolvedModelId,
|
|
1080
|
+
provider,
|
|
1081
|
+
prompt_tokens: promptTokens,
|
|
1082
|
+
completion_tokens: completionTokens,
|
|
1083
|
+
total_tokens: totalTokens,
|
|
1084
|
+
finish_reason: result.finishReason,
|
|
1085
|
+
tool_calls: result.toolCalls?.map((tc) => tc.toolName)
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
824
1089
|
await client.completeSession({
|
|
825
1090
|
sessionId,
|
|
826
1091
|
success: true,
|
|
@@ -849,134 +1114,139 @@ function wrapGenerateText(originalFn, client) {
|
|
|
849
1114
|
}
|
|
850
1115
|
};
|
|
851
1116
|
}
|
|
852
|
-
function wrapStreamText(originalFn, client) {
|
|
1117
|
+
function wrapStreamText(originalFn, client, config) {
|
|
853
1118
|
return (params) => {
|
|
854
1119
|
const startTime = Date.now();
|
|
855
1120
|
const { modelId, provider } = extractModelInfo(params.model);
|
|
856
1121
|
const input = extractInput(params);
|
|
857
1122
|
let sessionId = null;
|
|
858
|
-
const sessionPromise =
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1123
|
+
const sessionPromise = (async () => {
|
|
1124
|
+
try {
|
|
1125
|
+
const id = await client.createSession({
|
|
1126
|
+
name: `streamText: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
1127
|
+
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
1128
|
+
userId: config.userId ?? "anonymous",
|
|
1129
|
+
convoId: config.convoId,
|
|
1130
|
+
metadata: {
|
|
1131
|
+
model: modelId,
|
|
1132
|
+
provider,
|
|
1133
|
+
function: "streamText"
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
sessionId = id;
|
|
1137
|
+
if (id) {
|
|
1138
|
+
client.setInput(id, input).catch(() => {
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
return id;
|
|
1142
|
+
} catch {
|
|
1143
|
+
return null;
|
|
866
1144
|
}
|
|
867
|
-
})
|
|
868
|
-
sessionId = id;
|
|
869
|
-
if (id) client.setInput(id, input);
|
|
870
|
-
return id;
|
|
871
|
-
});
|
|
1145
|
+
})();
|
|
872
1146
|
const wrappedParams = {
|
|
873
1147
|
...params,
|
|
874
1148
|
tools: params.tools ? wrapToolsAsync(params.tools, sessionPromise, client) : void 0
|
|
875
1149
|
};
|
|
876
1150
|
const result = originalFn(wrappedParams);
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
1151
|
+
let tracked = false;
|
|
1152
|
+
async function trackCompletion(fullText, error) {
|
|
1153
|
+
if (tracked) return;
|
|
1154
|
+
tracked = true;
|
|
1155
|
+
const durationMs = Date.now() - startTime;
|
|
1156
|
+
const sid = sessionId || await sessionPromise;
|
|
1157
|
+
if (!sid) return;
|
|
1158
|
+
if (error) {
|
|
1159
|
+
await client.trackError({
|
|
1160
|
+
sessionId: sid,
|
|
1161
|
+
errorType: error.name || "Error",
|
|
1162
|
+
errorMessage: error.message || "Unknown error"
|
|
1163
|
+
});
|
|
1164
|
+
await client.completeSession({
|
|
1165
|
+
sessionId: sid,
|
|
1166
|
+
success: false,
|
|
1167
|
+
failureReason: error.message || "Unknown error",
|
|
1168
|
+
durationMs
|
|
1169
|
+
});
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
let usage;
|
|
880
1173
|
try {
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
yield chunk;
|
|
884
|
-
}
|
|
885
|
-
const durationMs = Date.now() - startTime;
|
|
886
|
-
const sid = sessionId || await sessionPromise;
|
|
887
|
-
if (sid) {
|
|
888
|
-
const usage = result.usage ? await result.usage : void 0;
|
|
889
|
-
const promptTokens = usage?.promptTokens || 0;
|
|
890
|
-
const completionTokens = usage?.completionTokens || 0;
|
|
891
|
-
const totalTokens = usage?.totalTokens || promptTokens + completionTokens;
|
|
892
|
-
const cost = calculateCostForCall(provider, modelId, promptTokens, completionTokens);
|
|
893
|
-
await client.completeSession({
|
|
894
|
-
sessionId: sid,
|
|
895
|
-
success: true,
|
|
896
|
-
output: fullText,
|
|
897
|
-
durationMs,
|
|
898
|
-
estimatedCost: cost,
|
|
899
|
-
promptTokens,
|
|
900
|
-
completionTokens,
|
|
901
|
-
totalTokens
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
} catch (error) {
|
|
905
|
-
const durationMs = Date.now() - startTime;
|
|
906
|
-
const sid = sessionId || await sessionPromise;
|
|
907
|
-
if (sid) {
|
|
908
|
-
await client.trackError({
|
|
909
|
-
sessionId: sid,
|
|
910
|
-
errorType: error instanceof Error ? error.name : "Error",
|
|
911
|
-
errorMessage: error instanceof Error ? error.message : "Unknown error"
|
|
912
|
-
});
|
|
913
|
-
await client.completeSession({
|
|
914
|
-
sessionId: sid,
|
|
915
|
-
success: false,
|
|
916
|
-
failureReason: error instanceof Error ? error.message : "Unknown error",
|
|
917
|
-
durationMs
|
|
918
|
-
});
|
|
919
|
-
}
|
|
920
|
-
throw error;
|
|
1174
|
+
usage = result.usage ? await result.usage : void 0;
|
|
1175
|
+
} catch {
|
|
921
1176
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
const sessionId = await sessionPromise;
|
|
936
|
-
try {
|
|
937
|
-
const result = await originalExecute(...args);
|
|
938
|
-
const durationMs = Date.now() - startTime;
|
|
939
|
-
if (sessionId) {
|
|
940
|
-
await client.trackToolCall({
|
|
941
|
-
sessionId,
|
|
942
|
-
toolName,
|
|
943
|
-
toolInput: args[0],
|
|
944
|
-
toolOutput: result,
|
|
945
|
-
reasoning: `Tool executed in ${durationMs}ms`
|
|
946
|
-
});
|
|
947
|
-
}
|
|
948
|
-
return result;
|
|
949
|
-
} catch (error) {
|
|
950
|
-
const durationMs = Date.now() - startTime;
|
|
951
|
-
if (sessionId) {
|
|
952
|
-
await client.trackToolCall({
|
|
953
|
-
sessionId,
|
|
954
|
-
toolName,
|
|
955
|
-
toolInput: args[0],
|
|
956
|
-
toolOutput: {},
|
|
957
|
-
toolError: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
958
|
-
reasoning: `Tool failed after ${durationMs}ms`
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
throw error;
|
|
962
|
-
}
|
|
1177
|
+
const promptTokens = usage?.promptTokens || 0;
|
|
1178
|
+
const completionTokens = usage?.completionTokens || 0;
|
|
1179
|
+
const totalTokens = usage?.totalTokens || promptTokens + completionTokens;
|
|
1180
|
+
const cost = calculateCostForCall(provider, modelId, promptTokens, completionTokens);
|
|
1181
|
+
await client.trackEvent({
|
|
1182
|
+
sessionId: sid,
|
|
1183
|
+
eventType: "llm_call",
|
|
1184
|
+
eventData: {
|
|
1185
|
+
model: modelId,
|
|
1186
|
+
provider,
|
|
1187
|
+
prompt_tokens: promptTokens,
|
|
1188
|
+
completion_tokens: completionTokens,
|
|
1189
|
+
total_tokens: totalTokens
|
|
963
1190
|
}
|
|
964
|
-
};
|
|
1191
|
+
});
|
|
1192
|
+
await client.completeSession({
|
|
1193
|
+
sessionId: sid,
|
|
1194
|
+
success: true,
|
|
1195
|
+
output: fullText,
|
|
1196
|
+
durationMs,
|
|
1197
|
+
estimatedCost: cost,
|
|
1198
|
+
promptTokens,
|
|
1199
|
+
completionTokens,
|
|
1200
|
+
totalTokens
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
const textProp = result.text;
|
|
1204
|
+
if (typeof textProp === "string") {
|
|
1205
|
+
trackCompletion(textProp).catch(() => {
|
|
1206
|
+
});
|
|
1207
|
+
} else if (textProp != null && typeof textProp.then === "function") {
|
|
1208
|
+
const originalTextPromise = textProp;
|
|
1209
|
+
result.text = originalTextPromise.then((text) => {
|
|
1210
|
+
trackCompletion(text).catch(() => {
|
|
1211
|
+
});
|
|
1212
|
+
return text;
|
|
1213
|
+
}).catch((err) => {
|
|
1214
|
+
trackCompletion("", err instanceof Error ? err : new Error(String(err))).catch(() => {
|
|
1215
|
+
});
|
|
1216
|
+
throw err;
|
|
1217
|
+
});
|
|
965
1218
|
} else {
|
|
966
|
-
|
|
1219
|
+
const originalTextStream = result.textStream;
|
|
1220
|
+
let fullText = "";
|
|
1221
|
+
result.textStream = (async function* () {
|
|
1222
|
+
try {
|
|
1223
|
+
for await (const chunk of originalTextStream) {
|
|
1224
|
+
fullText += chunk;
|
|
1225
|
+
yield chunk;
|
|
1226
|
+
}
|
|
1227
|
+
await trackCompletion(fullText);
|
|
1228
|
+
} catch (error) {
|
|
1229
|
+
await trackCompletion(
|
|
1230
|
+
"",
|
|
1231
|
+
error instanceof Error ? error : new Error(String(error))
|
|
1232
|
+
);
|
|
1233
|
+
throw error;
|
|
1234
|
+
}
|
|
1235
|
+
})();
|
|
967
1236
|
}
|
|
968
|
-
|
|
969
|
-
|
|
1237
|
+
return result;
|
|
1238
|
+
};
|
|
970
1239
|
}
|
|
971
|
-
function wrapGenerateObject(originalFn, client) {
|
|
1240
|
+
function wrapGenerateObject(originalFn, client, config) {
|
|
972
1241
|
return async (params) => {
|
|
973
1242
|
const startTime = Date.now();
|
|
974
1243
|
const { modelId, provider } = extractModelInfo(params.model);
|
|
975
1244
|
const input = extractInput(params);
|
|
976
1245
|
const sessionId = await client.createSession({
|
|
977
1246
|
name: `generateObject: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
978
|
-
agentName:
|
|
979
|
-
userId:
|
|
1247
|
+
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
1248
|
+
userId: config.userId ?? "anonymous",
|
|
1249
|
+
convoId: config.convoId,
|
|
980
1250
|
metadata: {
|
|
981
1251
|
model: modelId,
|
|
982
1252
|
provider,
|
|
@@ -990,10 +1260,11 @@ function wrapGenerateObject(originalFn, client) {
|
|
|
990
1260
|
try {
|
|
991
1261
|
const result = await originalFn(params);
|
|
992
1262
|
const durationMs = Date.now() - startTime;
|
|
1263
|
+
const resolvedModelId = result.response?.modelId || modelId;
|
|
993
1264
|
const promptTokens = result.usage?.promptTokens || 0;
|
|
994
1265
|
const completionTokens = result.usage?.completionTokens || 0;
|
|
995
1266
|
const totalTokens = result.usage?.totalTokens || promptTokens + completionTokens;
|
|
996
|
-
const cost = calculateCostForCall(provider,
|
|
1267
|
+
const cost = calculateCostForCall(provider, resolvedModelId, promptTokens, completionTokens);
|
|
997
1268
|
await client.completeSession({
|
|
998
1269
|
sessionId,
|
|
999
1270
|
success: true,
|
|
@@ -1022,38 +1293,51 @@ function wrapGenerateObject(originalFn, client) {
|
|
|
1022
1293
|
}
|
|
1023
1294
|
};
|
|
1024
1295
|
}
|
|
1025
|
-
function wrapStreamObject(originalFn, client) {
|
|
1296
|
+
function wrapStreamObject(originalFn, client, config) {
|
|
1026
1297
|
return (params) => {
|
|
1027
1298
|
const startTime = Date.now();
|
|
1028
1299
|
const { modelId, provider } = extractModelInfo(params.model);
|
|
1029
1300
|
const input = extractInput(params);
|
|
1030
|
-
const sessionPromise =
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1301
|
+
const sessionPromise = (async () => {
|
|
1302
|
+
try {
|
|
1303
|
+
const id = await client.createSession({
|
|
1304
|
+
name: `streamObject: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
1305
|
+
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
1306
|
+
userId: config.userId ?? "anonymous",
|
|
1307
|
+
convoId: config.convoId,
|
|
1308
|
+
metadata: {
|
|
1309
|
+
model: modelId,
|
|
1310
|
+
provider,
|
|
1311
|
+
function: "streamObject"
|
|
1312
|
+
}
|
|
1313
|
+
});
|
|
1314
|
+
if (id) {
|
|
1315
|
+
client.setInput(id, input).catch(() => {
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
return id;
|
|
1319
|
+
} catch {
|
|
1320
|
+
return null;
|
|
1038
1321
|
}
|
|
1039
|
-
})
|
|
1040
|
-
if (id) client.setInput(id, input);
|
|
1041
|
-
return id;
|
|
1042
|
-
});
|
|
1322
|
+
})();
|
|
1043
1323
|
const result = originalFn(params);
|
|
1044
1324
|
if (result.object) {
|
|
1045
1325
|
const originalObjectPromise = result.object;
|
|
1046
1326
|
result.object = originalObjectPromise.then(async (obj) => {
|
|
1047
1327
|
const durationMs = Date.now() - startTime;
|
|
1048
|
-
const
|
|
1049
|
-
if (
|
|
1050
|
-
|
|
1328
|
+
const sid = await sessionPromise;
|
|
1329
|
+
if (sid) {
|
|
1330
|
+
let usage;
|
|
1331
|
+
try {
|
|
1332
|
+
usage = result.usage ? await result.usage : void 0;
|
|
1333
|
+
} catch {
|
|
1334
|
+
}
|
|
1051
1335
|
const promptTokens = usage?.promptTokens || 0;
|
|
1052
1336
|
const completionTokens = usage?.completionTokens || 0;
|
|
1053
1337
|
const totalTokens = usage?.totalTokens || promptTokens + completionTokens;
|
|
1054
1338
|
const cost = calculateCostForCall(provider, modelId, promptTokens, completionTokens);
|
|
1055
1339
|
await client.completeSession({
|
|
1056
|
-
sessionId,
|
|
1340
|
+
sessionId: sid,
|
|
1057
1341
|
success: true,
|
|
1058
1342
|
output: JSON.stringify(obj),
|
|
1059
1343
|
durationMs,
|
|
@@ -1066,15 +1350,15 @@ function wrapStreamObject(originalFn, client) {
|
|
|
1066
1350
|
return obj;
|
|
1067
1351
|
}).catch(async (error) => {
|
|
1068
1352
|
const durationMs = Date.now() - startTime;
|
|
1069
|
-
const
|
|
1070
|
-
if (
|
|
1353
|
+
const sid = await sessionPromise;
|
|
1354
|
+
if (sid) {
|
|
1071
1355
|
await client.trackError({
|
|
1072
|
-
sessionId,
|
|
1356
|
+
sessionId: sid,
|
|
1073
1357
|
errorType: error instanceof Error ? error.name : "Error",
|
|
1074
1358
|
errorMessage: error instanceof Error ? error.message : "Unknown error"
|
|
1075
1359
|
});
|
|
1076
1360
|
await client.completeSession({
|
|
1077
|
-
sessionId,
|
|
1361
|
+
sessionId: sid,
|
|
1078
1362
|
success: false,
|
|
1079
1363
|
failureReason: error instanceof Error ? error.message : "Unknown error",
|
|
1080
1364
|
durationMs
|
|
@@ -1086,14 +1370,27 @@ function wrapStreamObject(originalFn, client) {
|
|
|
1086
1370
|
return result;
|
|
1087
1371
|
};
|
|
1088
1372
|
}
|
|
1089
|
-
function wrapAISDK(ai) {
|
|
1090
|
-
const client = getClient2();
|
|
1373
|
+
function wrapAISDK(ai, options) {
|
|
1374
|
+
const client = options?.client ?? getClient2();
|
|
1375
|
+
const config = {
|
|
1376
|
+
defaultAgent: options?.defaultAgent ?? _globalConfig.defaultAgent,
|
|
1377
|
+
userId: options?.userId ?? _globalConfig.userId,
|
|
1378
|
+
convoId: options?.convoId ?? _globalConfig.convoId
|
|
1379
|
+
};
|
|
1091
1380
|
return {
|
|
1092
|
-
generateText: ai.generateText ? wrapGenerateText(ai.generateText, client) : wrapGenerateText(
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1381
|
+
generateText: ai.generateText ? wrapGenerateText(ai.generateText, client, config) : wrapGenerateText(
|
|
1382
|
+
() => Promise.reject(new Error("generateText not available")),
|
|
1383
|
+
client,
|
|
1384
|
+
config
|
|
1385
|
+
),
|
|
1386
|
+
streamText: ai.streamText ? wrapStreamText(ai.streamText, client, config) : wrapStreamText(() => ({ textStream: (async function* () {
|
|
1387
|
+
})() }), client, config),
|
|
1388
|
+
generateObject: ai.generateObject ? wrapGenerateObject(ai.generateObject, client, config) : wrapGenerateObject(
|
|
1389
|
+
() => Promise.reject(new Error("generateObject not available")),
|
|
1390
|
+
client,
|
|
1391
|
+
config
|
|
1392
|
+
),
|
|
1393
|
+
streamObject: ai.streamObject ? wrapStreamObject(ai.streamObject, client, config) : wrapStreamObject(() => ({}), client, config)
|
|
1097
1394
|
};
|
|
1098
1395
|
}
|
|
1099
1396
|
|
|
@@ -2138,7 +2435,12 @@ var Experiment = class {
|
|
|
2138
2435
|
getSessionContext,
|
|
2139
2436
|
getSystemPrompt,
|
|
2140
2437
|
getVariantName,
|
|
2438
|
+
hashValue,
|
|
2141
2439
|
isExperimentMode,
|
|
2440
|
+
redactPayload,
|
|
2441
|
+
redactString,
|
|
2442
|
+
redactValue,
|
|
2443
|
+
replaceMatch,
|
|
2142
2444
|
sentrial,
|
|
2143
2445
|
setClient,
|
|
2144
2446
|
setDefaultClient,
|