@fallom/trace 0.1.4 → 0.1.6
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.d.mts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +171 -13
- package/dist/index.mjs +171 -13
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
interface SessionContext {
|
|
8
8
|
configKey: string;
|
|
9
9
|
sessionId: string;
|
|
10
|
+
customerId?: string;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
13
|
* Initialize Fallom tracing. Auto-instruments all LLM calls.
|
|
@@ -42,34 +43,36 @@ declare function init$3(options?: {
|
|
|
42
43
|
* Set the current session context.
|
|
43
44
|
*
|
|
44
45
|
* All subsequent LLM calls in this async context will be
|
|
45
|
-
* automatically tagged with this configKey and
|
|
46
|
+
* automatically tagged with this configKey, sessionId, and customerId.
|
|
46
47
|
*
|
|
47
48
|
* @param configKey - Your config name (e.g., "linkedin-agent")
|
|
48
49
|
* @param sessionId - Your session/conversation ID
|
|
50
|
+
* @param customerId - Optional customer/user identifier for analytics
|
|
49
51
|
*
|
|
50
52
|
* @example
|
|
51
53
|
* ```typescript
|
|
52
|
-
* trace.setSession("linkedin-agent", sessionId);
|
|
53
|
-
* await agent.run(message); // Automatically traced with session
|
|
54
|
+
* trace.setSession("linkedin-agent", sessionId, "user_123");
|
|
55
|
+
* await agent.run(message); // Automatically traced with session + customer
|
|
54
56
|
* ```
|
|
55
57
|
*/
|
|
56
|
-
declare function setSession(configKey: string, sessionId: string): void;
|
|
58
|
+
declare function setSession(configKey: string, sessionId: string, customerId?: string): void;
|
|
57
59
|
/**
|
|
58
60
|
* Run a function with session context.
|
|
59
61
|
* Use this to ensure session context propagates across async boundaries.
|
|
60
62
|
*
|
|
61
63
|
* @param configKey - Your config name
|
|
62
64
|
* @param sessionId - Your session ID
|
|
65
|
+
* @param customerId - Optional customer/user identifier
|
|
63
66
|
* @param fn - Function to run with session context
|
|
64
67
|
*
|
|
65
68
|
* @example
|
|
66
69
|
* ```typescript
|
|
67
|
-
* await trace.runWithSession("my-agent", sessionId, async () => {
|
|
70
|
+
* await trace.runWithSession("my-agent", sessionId, "user_123", async () => {
|
|
68
71
|
* await agent.run(message); // Has session context
|
|
69
72
|
* });
|
|
70
73
|
* ```
|
|
71
74
|
*/
|
|
72
|
-
declare function runWithSession<T>(configKey: string, sessionId: string,
|
|
75
|
+
declare function runWithSession<T>(configKey: string, sessionId: string, customerIdOrFn: string | (() => T), fn?: () => T): T;
|
|
73
76
|
/**
|
|
74
77
|
* Get current session context, if any.
|
|
75
78
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
interface SessionContext {
|
|
8
8
|
configKey: string;
|
|
9
9
|
sessionId: string;
|
|
10
|
+
customerId?: string;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
13
|
* Initialize Fallom tracing. Auto-instruments all LLM calls.
|
|
@@ -42,34 +43,36 @@ declare function init$3(options?: {
|
|
|
42
43
|
* Set the current session context.
|
|
43
44
|
*
|
|
44
45
|
* All subsequent LLM calls in this async context will be
|
|
45
|
-
* automatically tagged with this configKey and
|
|
46
|
+
* automatically tagged with this configKey, sessionId, and customerId.
|
|
46
47
|
*
|
|
47
48
|
* @param configKey - Your config name (e.g., "linkedin-agent")
|
|
48
49
|
* @param sessionId - Your session/conversation ID
|
|
50
|
+
* @param customerId - Optional customer/user identifier for analytics
|
|
49
51
|
*
|
|
50
52
|
* @example
|
|
51
53
|
* ```typescript
|
|
52
|
-
* trace.setSession("linkedin-agent", sessionId);
|
|
53
|
-
* await agent.run(message); // Automatically traced with session
|
|
54
|
+
* trace.setSession("linkedin-agent", sessionId, "user_123");
|
|
55
|
+
* await agent.run(message); // Automatically traced with session + customer
|
|
54
56
|
* ```
|
|
55
57
|
*/
|
|
56
|
-
declare function setSession(configKey: string, sessionId: string): void;
|
|
58
|
+
declare function setSession(configKey: string, sessionId: string, customerId?: string): void;
|
|
57
59
|
/**
|
|
58
60
|
* Run a function with session context.
|
|
59
61
|
* Use this to ensure session context propagates across async boundaries.
|
|
60
62
|
*
|
|
61
63
|
* @param configKey - Your config name
|
|
62
64
|
* @param sessionId - Your session ID
|
|
65
|
+
* @param customerId - Optional customer/user identifier
|
|
63
66
|
* @param fn - Function to run with session context
|
|
64
67
|
*
|
|
65
68
|
* @example
|
|
66
69
|
* ```typescript
|
|
67
|
-
* await trace.runWithSession("my-agent", sessionId, async () => {
|
|
70
|
+
* await trace.runWithSession("my-agent", sessionId, "user_123", async () => {
|
|
68
71
|
* await agent.run(message); // Has session context
|
|
69
72
|
* });
|
|
70
73
|
* ```
|
|
71
74
|
*/
|
|
72
|
-
declare function runWithSession<T>(configKey: string, sessionId: string,
|
|
75
|
+
declare function runWithSession<T>(configKey: string, sessionId: string, customerIdOrFn: string | (() => T), fn?: () => T): T;
|
|
73
76
|
/**
|
|
74
77
|
* Get current session context, if any.
|
|
75
78
|
*/
|
package/dist/index.js
CHANGED
|
@@ -930,7 +930,15 @@ var fallomSpanProcessor = {
|
|
|
930
930
|
if (ctx) {
|
|
931
931
|
span2.setAttribute("fallom.config_key", ctx.configKey);
|
|
932
932
|
span2.setAttribute("fallom.session_id", ctx.sessionId);
|
|
933
|
-
|
|
933
|
+
if (ctx.customerId) {
|
|
934
|
+
span2.setAttribute("fallom.customer_id", ctx.customerId);
|
|
935
|
+
}
|
|
936
|
+
log2(
|
|
937
|
+
" Added session context:",
|
|
938
|
+
ctx.configKey,
|
|
939
|
+
ctx.sessionId,
|
|
940
|
+
ctx.customerId
|
|
941
|
+
);
|
|
934
942
|
} else {
|
|
935
943
|
log2(" No session context available");
|
|
936
944
|
}
|
|
@@ -1044,16 +1052,23 @@ async function tryAddInstrumentation(instrumentations, pkg, className) {
|
|
|
1044
1052
|
log2(` \u274C ${pkg} not installed`);
|
|
1045
1053
|
}
|
|
1046
1054
|
}
|
|
1047
|
-
function setSession(configKey, sessionId) {
|
|
1055
|
+
function setSession(configKey, sessionId, customerId) {
|
|
1048
1056
|
const store = sessionStorage.getStore();
|
|
1049
1057
|
if (store) {
|
|
1050
1058
|
store.configKey = configKey;
|
|
1051
1059
|
store.sessionId = sessionId;
|
|
1060
|
+
store.customerId = customerId;
|
|
1052
1061
|
}
|
|
1053
|
-
fallbackSession = { configKey, sessionId };
|
|
1062
|
+
fallbackSession = { configKey, sessionId, customerId };
|
|
1054
1063
|
}
|
|
1055
|
-
function runWithSession(configKey, sessionId, fn) {
|
|
1056
|
-
|
|
1064
|
+
function runWithSession(configKey, sessionId, customerIdOrFn, fn) {
|
|
1065
|
+
if (typeof customerIdOrFn === "function") {
|
|
1066
|
+
return sessionStorage.run({ configKey, sessionId }, customerIdOrFn);
|
|
1067
|
+
}
|
|
1068
|
+
return sessionStorage.run(
|
|
1069
|
+
{ configKey, sessionId, customerId: customerIdOrFn },
|
|
1070
|
+
fn
|
|
1071
|
+
);
|
|
1057
1072
|
}
|
|
1058
1073
|
function getSession() {
|
|
1059
1074
|
return sessionStorage.getStore() || fallbackSession || void 0;
|
|
@@ -1103,6 +1118,39 @@ async function shutdown() {
|
|
|
1103
1118
|
initialized2 = false;
|
|
1104
1119
|
}
|
|
1105
1120
|
}
|
|
1121
|
+
function messagesToOtelAttributes(messages, completion, model, responseId) {
|
|
1122
|
+
const attrs = {};
|
|
1123
|
+
if (model) {
|
|
1124
|
+
attrs["gen_ai.request.model"] = model;
|
|
1125
|
+
attrs["gen_ai.response.model"] = model;
|
|
1126
|
+
}
|
|
1127
|
+
if (responseId) {
|
|
1128
|
+
attrs["gen_ai.response.id"] = responseId;
|
|
1129
|
+
}
|
|
1130
|
+
if (messages) {
|
|
1131
|
+
messages.forEach((msg, i) => {
|
|
1132
|
+
attrs[`gen_ai.prompt.${i}.role`] = msg.role;
|
|
1133
|
+
attrs[`gen_ai.prompt.${i}.content`] = msg.content;
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
if (completion) {
|
|
1137
|
+
attrs["gen_ai.completion.0.role"] = completion.role;
|
|
1138
|
+
attrs["gen_ai.completion.0.content"] = completion.content;
|
|
1139
|
+
if (completion.tool_calls) {
|
|
1140
|
+
attrs["gen_ai.completion.0.tool_calls"] = JSON.stringify(
|
|
1141
|
+
completion.tool_calls
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return attrs;
|
|
1146
|
+
}
|
|
1147
|
+
function generateHexId(length) {
|
|
1148
|
+
const bytes = new Uint8Array(length / 2);
|
|
1149
|
+
crypto.getRandomValues(bytes);
|
|
1150
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1151
|
+
}
|
|
1152
|
+
var traceContextStorage = new import_async_hooks.AsyncLocalStorage();
|
|
1153
|
+
var fallbackTraceContext = null;
|
|
1106
1154
|
async function sendTrace(trace) {
|
|
1107
1155
|
try {
|
|
1108
1156
|
const controller = new AbortController();
|
|
@@ -1136,15 +1184,30 @@ function wrapOpenAI(client) {
|
|
|
1136
1184
|
promptCtx = getPromptContext2();
|
|
1137
1185
|
} catch {
|
|
1138
1186
|
}
|
|
1187
|
+
const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
|
|
1188
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1189
|
+
const spanId = generateHexId(16);
|
|
1190
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
1139
1191
|
const params = args[0] || {};
|
|
1140
1192
|
const startTime = Date.now();
|
|
1141
1193
|
try {
|
|
1142
1194
|
const response = await originalCreate(...args);
|
|
1143
1195
|
const endTime = Date.now();
|
|
1196
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
1197
|
+
params?.messages,
|
|
1198
|
+
response?.choices?.[0]?.message,
|
|
1199
|
+
response?.model || params?.model,
|
|
1200
|
+
response?.id
|
|
1201
|
+
) : void 0;
|
|
1144
1202
|
sendTrace({
|
|
1145
1203
|
config_key: ctx.configKey,
|
|
1146
1204
|
session_id: ctx.sessionId,
|
|
1205
|
+
customer_id: ctx.customerId,
|
|
1206
|
+
trace_id: traceId,
|
|
1207
|
+
span_id: spanId,
|
|
1208
|
+
parent_span_id: parentSpanId,
|
|
1147
1209
|
name: "chat.completions.create",
|
|
1210
|
+
kind: "llm",
|
|
1148
1211
|
model: response?.model || params?.model,
|
|
1149
1212
|
start_time: new Date(startTime).toISOString(),
|
|
1150
1213
|
end_time: new Date(endTime).toISOString(),
|
|
@@ -1153,8 +1216,7 @@ function wrapOpenAI(client) {
|
|
|
1153
1216
|
prompt_tokens: response?.usage?.prompt_tokens,
|
|
1154
1217
|
completion_tokens: response?.usage?.completion_tokens,
|
|
1155
1218
|
total_tokens: response?.usage?.total_tokens,
|
|
1156
|
-
|
|
1157
|
-
output: captureContent ? response?.choices?.[0]?.message?.content : void 0,
|
|
1219
|
+
attributes,
|
|
1158
1220
|
prompt_key: promptCtx?.promptKey,
|
|
1159
1221
|
prompt_version: promptCtx?.promptVersion,
|
|
1160
1222
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -1164,16 +1226,31 @@ function wrapOpenAI(client) {
|
|
|
1164
1226
|
return response;
|
|
1165
1227
|
} catch (error) {
|
|
1166
1228
|
const endTime = Date.now();
|
|
1229
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
1230
|
+
params?.messages,
|
|
1231
|
+
void 0,
|
|
1232
|
+
params?.model,
|
|
1233
|
+
void 0
|
|
1234
|
+
) : void 0;
|
|
1235
|
+
if (attributes) {
|
|
1236
|
+
attributes["error.message"] = error?.message;
|
|
1237
|
+
}
|
|
1167
1238
|
sendTrace({
|
|
1168
1239
|
config_key: ctx.configKey,
|
|
1169
1240
|
session_id: ctx.sessionId,
|
|
1241
|
+
customer_id: ctx.customerId,
|
|
1242
|
+
trace_id: traceId,
|
|
1243
|
+
span_id: spanId,
|
|
1244
|
+
parent_span_id: parentSpanId,
|
|
1170
1245
|
name: "chat.completions.create",
|
|
1246
|
+
kind: "llm",
|
|
1171
1247
|
model: params?.model,
|
|
1172
1248
|
start_time: new Date(startTime).toISOString(),
|
|
1173
1249
|
end_time: new Date(endTime).toISOString(),
|
|
1174
1250
|
duration_ms: endTime - startTime,
|
|
1175
1251
|
status: "ERROR",
|
|
1176
1252
|
error_message: error?.message,
|
|
1253
|
+
attributes,
|
|
1177
1254
|
prompt_key: promptCtx?.promptKey,
|
|
1178
1255
|
prompt_version: promptCtx?.promptVersion,
|
|
1179
1256
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -1198,15 +1275,33 @@ function wrapAnthropic(client) {
|
|
|
1198
1275
|
promptCtx = getPromptContext2();
|
|
1199
1276
|
} catch {
|
|
1200
1277
|
}
|
|
1278
|
+
const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
|
|
1279
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1280
|
+
const spanId = generateHexId(16);
|
|
1281
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
1201
1282
|
const params = args[0] || {};
|
|
1202
1283
|
const startTime = Date.now();
|
|
1203
1284
|
try {
|
|
1204
1285
|
const response = await originalCreate(...args);
|
|
1205
1286
|
const endTime = Date.now();
|
|
1287
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
1288
|
+
params?.messages,
|
|
1289
|
+
{ role: "assistant", content: response?.content?.[0]?.text || "" },
|
|
1290
|
+
response?.model || params?.model,
|
|
1291
|
+
response?.id
|
|
1292
|
+
) : void 0;
|
|
1293
|
+
if (attributes && params?.system) {
|
|
1294
|
+
attributes["gen_ai.system_prompt"] = params.system;
|
|
1295
|
+
}
|
|
1206
1296
|
sendTrace({
|
|
1207
1297
|
config_key: ctx.configKey,
|
|
1208
1298
|
session_id: ctx.sessionId,
|
|
1299
|
+
customer_id: ctx.customerId,
|
|
1300
|
+
trace_id: traceId,
|
|
1301
|
+
span_id: spanId,
|
|
1302
|
+
parent_span_id: parentSpanId,
|
|
1209
1303
|
name: "messages.create",
|
|
1304
|
+
kind: "llm",
|
|
1210
1305
|
model: response?.model || params?.model,
|
|
1211
1306
|
start_time: new Date(startTime).toISOString(),
|
|
1212
1307
|
end_time: new Date(endTime).toISOString(),
|
|
@@ -1215,8 +1310,7 @@ function wrapAnthropic(client) {
|
|
|
1215
1310
|
prompt_tokens: response?.usage?.input_tokens,
|
|
1216
1311
|
completion_tokens: response?.usage?.output_tokens,
|
|
1217
1312
|
total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
|
|
1218
|
-
|
|
1219
|
-
output: captureContent ? response?.content?.[0]?.text : void 0,
|
|
1313
|
+
attributes,
|
|
1220
1314
|
prompt_key: promptCtx?.promptKey,
|
|
1221
1315
|
prompt_version: promptCtx?.promptVersion,
|
|
1222
1316
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -1226,16 +1320,34 @@ function wrapAnthropic(client) {
|
|
|
1226
1320
|
return response;
|
|
1227
1321
|
} catch (error) {
|
|
1228
1322
|
const endTime = Date.now();
|
|
1323
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
1324
|
+
params?.messages,
|
|
1325
|
+
void 0,
|
|
1326
|
+
params?.model,
|
|
1327
|
+
void 0
|
|
1328
|
+
) : void 0;
|
|
1329
|
+
if (attributes) {
|
|
1330
|
+
attributes["error.message"] = error?.message;
|
|
1331
|
+
if (params?.system) {
|
|
1332
|
+
attributes["gen_ai.system_prompt"] = params.system;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1229
1335
|
sendTrace({
|
|
1230
1336
|
config_key: ctx.configKey,
|
|
1231
1337
|
session_id: ctx.sessionId,
|
|
1338
|
+
customer_id: ctx.customerId,
|
|
1339
|
+
trace_id: traceId,
|
|
1340
|
+
span_id: spanId,
|
|
1341
|
+
parent_span_id: parentSpanId,
|
|
1232
1342
|
name: "messages.create",
|
|
1343
|
+
kind: "llm",
|
|
1233
1344
|
model: params?.model,
|
|
1234
1345
|
start_time: new Date(startTime).toISOString(),
|
|
1235
1346
|
end_time: new Date(endTime).toISOString(),
|
|
1236
1347
|
duration_ms: endTime - startTime,
|
|
1237
1348
|
status: "ERROR",
|
|
1238
1349
|
error_message: error?.message,
|
|
1350
|
+
attributes,
|
|
1239
1351
|
prompt_key: promptCtx?.promptKey,
|
|
1240
1352
|
prompt_version: promptCtx?.promptVersion,
|
|
1241
1353
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -1260,17 +1372,47 @@ function wrapGoogleAI(model) {
|
|
|
1260
1372
|
promptCtx = getPromptContext2();
|
|
1261
1373
|
} catch {
|
|
1262
1374
|
}
|
|
1375
|
+
const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
|
|
1376
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1377
|
+
const spanId = generateHexId(16);
|
|
1378
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
1263
1379
|
const startTime = Date.now();
|
|
1264
1380
|
try {
|
|
1265
1381
|
const response = await originalGenerate(...args);
|
|
1266
1382
|
const endTime = Date.now();
|
|
1267
1383
|
const result = response?.response;
|
|
1268
1384
|
const usage = result?.usageMetadata;
|
|
1385
|
+
const modelName = model?.model || "gemini";
|
|
1386
|
+
const attributes = {};
|
|
1387
|
+
if (captureContent) {
|
|
1388
|
+
attributes["gen_ai.request.model"] = modelName;
|
|
1389
|
+
attributes["gen_ai.response.model"] = modelName;
|
|
1390
|
+
const input = args[0];
|
|
1391
|
+
if (typeof input === "string") {
|
|
1392
|
+
attributes["gen_ai.prompt.0.role"] = "user";
|
|
1393
|
+
attributes["gen_ai.prompt.0.content"] = input;
|
|
1394
|
+
} else if (input?.contents) {
|
|
1395
|
+
input.contents.forEach((content, i) => {
|
|
1396
|
+
attributes[`gen_ai.prompt.${i}.role`] = content.role || "user";
|
|
1397
|
+
attributes[`gen_ai.prompt.${i}.content`] = content.parts?.[0]?.text || JSON.stringify(content.parts);
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
const outputText = result?.text?.();
|
|
1401
|
+
if (outputText) {
|
|
1402
|
+
attributes["gen_ai.completion.0.role"] = "assistant";
|
|
1403
|
+
attributes["gen_ai.completion.0.content"] = outputText;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1269
1406
|
sendTrace({
|
|
1270
1407
|
config_key: ctx.configKey,
|
|
1271
1408
|
session_id: ctx.sessionId,
|
|
1409
|
+
customer_id: ctx.customerId,
|
|
1410
|
+
trace_id: traceId,
|
|
1411
|
+
span_id: spanId,
|
|
1412
|
+
parent_span_id: parentSpanId,
|
|
1272
1413
|
name: "generateContent",
|
|
1273
|
-
|
|
1414
|
+
kind: "llm",
|
|
1415
|
+
model: modelName,
|
|
1274
1416
|
start_time: new Date(startTime).toISOString(),
|
|
1275
1417
|
end_time: new Date(endTime).toISOString(),
|
|
1276
1418
|
duration_ms: endTime - startTime,
|
|
@@ -1278,8 +1420,7 @@ function wrapGoogleAI(model) {
|
|
|
1278
1420
|
prompt_tokens: usage?.promptTokenCount,
|
|
1279
1421
|
completion_tokens: usage?.candidatesTokenCount,
|
|
1280
1422
|
total_tokens: usage?.totalTokenCount,
|
|
1281
|
-
|
|
1282
|
-
output: captureContent ? result?.text?.() : void 0,
|
|
1423
|
+
attributes: captureContent ? attributes : void 0,
|
|
1283
1424
|
prompt_key: promptCtx?.promptKey,
|
|
1284
1425
|
prompt_version: promptCtx?.promptVersion,
|
|
1285
1426
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -1289,16 +1430,33 @@ function wrapGoogleAI(model) {
|
|
|
1289
1430
|
return response;
|
|
1290
1431
|
} catch (error) {
|
|
1291
1432
|
const endTime = Date.now();
|
|
1433
|
+
const modelName = model?.model || "gemini";
|
|
1434
|
+
const attributes = {};
|
|
1435
|
+
if (captureContent) {
|
|
1436
|
+
attributes["gen_ai.request.model"] = modelName;
|
|
1437
|
+
attributes["error.message"] = error?.message;
|
|
1438
|
+
const input = args[0];
|
|
1439
|
+
if (typeof input === "string") {
|
|
1440
|
+
attributes["gen_ai.prompt.0.role"] = "user";
|
|
1441
|
+
attributes["gen_ai.prompt.0.content"] = input;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1292
1444
|
sendTrace({
|
|
1293
1445
|
config_key: ctx.configKey,
|
|
1294
1446
|
session_id: ctx.sessionId,
|
|
1447
|
+
customer_id: ctx.customerId,
|
|
1448
|
+
trace_id: traceId,
|
|
1449
|
+
span_id: spanId,
|
|
1450
|
+
parent_span_id: parentSpanId,
|
|
1295
1451
|
name: "generateContent",
|
|
1296
|
-
|
|
1452
|
+
kind: "llm",
|
|
1453
|
+
model: modelName,
|
|
1297
1454
|
start_time: new Date(startTime).toISOString(),
|
|
1298
1455
|
end_time: new Date(endTime).toISOString(),
|
|
1299
1456
|
duration_ms: endTime - startTime,
|
|
1300
1457
|
status: "ERROR",
|
|
1301
1458
|
error_message: error?.message,
|
|
1459
|
+
attributes: captureContent ? attributes : void 0,
|
|
1302
1460
|
prompt_key: promptCtx?.promptKey,
|
|
1303
1461
|
prompt_version: promptCtx?.promptVersion,
|
|
1304
1462
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
package/dist/index.mjs
CHANGED
|
@@ -664,7 +664,15 @@ var fallomSpanProcessor = {
|
|
|
664
664
|
if (ctx) {
|
|
665
665
|
span2.setAttribute("fallom.config_key", ctx.configKey);
|
|
666
666
|
span2.setAttribute("fallom.session_id", ctx.sessionId);
|
|
667
|
-
|
|
667
|
+
if (ctx.customerId) {
|
|
668
|
+
span2.setAttribute("fallom.customer_id", ctx.customerId);
|
|
669
|
+
}
|
|
670
|
+
log(
|
|
671
|
+
" Added session context:",
|
|
672
|
+
ctx.configKey,
|
|
673
|
+
ctx.sessionId,
|
|
674
|
+
ctx.customerId
|
|
675
|
+
);
|
|
668
676
|
} else {
|
|
669
677
|
log(" No session context available");
|
|
670
678
|
}
|
|
@@ -778,16 +786,23 @@ async function tryAddInstrumentation(instrumentations, pkg, className) {
|
|
|
778
786
|
log(` \u274C ${pkg} not installed`);
|
|
779
787
|
}
|
|
780
788
|
}
|
|
781
|
-
function setSession(configKey, sessionId) {
|
|
789
|
+
function setSession(configKey, sessionId, customerId) {
|
|
782
790
|
const store = sessionStorage.getStore();
|
|
783
791
|
if (store) {
|
|
784
792
|
store.configKey = configKey;
|
|
785
793
|
store.sessionId = sessionId;
|
|
794
|
+
store.customerId = customerId;
|
|
786
795
|
}
|
|
787
|
-
fallbackSession = { configKey, sessionId };
|
|
796
|
+
fallbackSession = { configKey, sessionId, customerId };
|
|
788
797
|
}
|
|
789
|
-
function runWithSession(configKey, sessionId, fn) {
|
|
790
|
-
|
|
798
|
+
function runWithSession(configKey, sessionId, customerIdOrFn, fn) {
|
|
799
|
+
if (typeof customerIdOrFn === "function") {
|
|
800
|
+
return sessionStorage.run({ configKey, sessionId }, customerIdOrFn);
|
|
801
|
+
}
|
|
802
|
+
return sessionStorage.run(
|
|
803
|
+
{ configKey, sessionId, customerId: customerIdOrFn },
|
|
804
|
+
fn
|
|
805
|
+
);
|
|
791
806
|
}
|
|
792
807
|
function getSession() {
|
|
793
808
|
return sessionStorage.getStore() || fallbackSession || void 0;
|
|
@@ -837,6 +852,39 @@ async function shutdown() {
|
|
|
837
852
|
initialized = false;
|
|
838
853
|
}
|
|
839
854
|
}
|
|
855
|
+
function messagesToOtelAttributes(messages, completion, model, responseId) {
|
|
856
|
+
const attrs = {};
|
|
857
|
+
if (model) {
|
|
858
|
+
attrs["gen_ai.request.model"] = model;
|
|
859
|
+
attrs["gen_ai.response.model"] = model;
|
|
860
|
+
}
|
|
861
|
+
if (responseId) {
|
|
862
|
+
attrs["gen_ai.response.id"] = responseId;
|
|
863
|
+
}
|
|
864
|
+
if (messages) {
|
|
865
|
+
messages.forEach((msg, i) => {
|
|
866
|
+
attrs[`gen_ai.prompt.${i}.role`] = msg.role;
|
|
867
|
+
attrs[`gen_ai.prompt.${i}.content`] = msg.content;
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
if (completion) {
|
|
871
|
+
attrs["gen_ai.completion.0.role"] = completion.role;
|
|
872
|
+
attrs["gen_ai.completion.0.content"] = completion.content;
|
|
873
|
+
if (completion.tool_calls) {
|
|
874
|
+
attrs["gen_ai.completion.0.tool_calls"] = JSON.stringify(
|
|
875
|
+
completion.tool_calls
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return attrs;
|
|
880
|
+
}
|
|
881
|
+
function generateHexId(length) {
|
|
882
|
+
const bytes = new Uint8Array(length / 2);
|
|
883
|
+
crypto.getRandomValues(bytes);
|
|
884
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
885
|
+
}
|
|
886
|
+
var traceContextStorage = new AsyncLocalStorage();
|
|
887
|
+
var fallbackTraceContext = null;
|
|
840
888
|
async function sendTrace(trace) {
|
|
841
889
|
try {
|
|
842
890
|
const controller = new AbortController();
|
|
@@ -870,15 +918,30 @@ function wrapOpenAI(client) {
|
|
|
870
918
|
promptCtx = getPromptContext();
|
|
871
919
|
} catch {
|
|
872
920
|
}
|
|
921
|
+
const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
|
|
922
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
923
|
+
const spanId = generateHexId(16);
|
|
924
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
873
925
|
const params = args[0] || {};
|
|
874
926
|
const startTime = Date.now();
|
|
875
927
|
try {
|
|
876
928
|
const response = await originalCreate(...args);
|
|
877
929
|
const endTime = Date.now();
|
|
930
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
931
|
+
params?.messages,
|
|
932
|
+
response?.choices?.[0]?.message,
|
|
933
|
+
response?.model || params?.model,
|
|
934
|
+
response?.id
|
|
935
|
+
) : void 0;
|
|
878
936
|
sendTrace({
|
|
879
937
|
config_key: ctx.configKey,
|
|
880
938
|
session_id: ctx.sessionId,
|
|
939
|
+
customer_id: ctx.customerId,
|
|
940
|
+
trace_id: traceId,
|
|
941
|
+
span_id: spanId,
|
|
942
|
+
parent_span_id: parentSpanId,
|
|
881
943
|
name: "chat.completions.create",
|
|
944
|
+
kind: "llm",
|
|
882
945
|
model: response?.model || params?.model,
|
|
883
946
|
start_time: new Date(startTime).toISOString(),
|
|
884
947
|
end_time: new Date(endTime).toISOString(),
|
|
@@ -887,8 +950,7 @@ function wrapOpenAI(client) {
|
|
|
887
950
|
prompt_tokens: response?.usage?.prompt_tokens,
|
|
888
951
|
completion_tokens: response?.usage?.completion_tokens,
|
|
889
952
|
total_tokens: response?.usage?.total_tokens,
|
|
890
|
-
|
|
891
|
-
output: captureContent ? response?.choices?.[0]?.message?.content : void 0,
|
|
953
|
+
attributes,
|
|
892
954
|
prompt_key: promptCtx?.promptKey,
|
|
893
955
|
prompt_version: promptCtx?.promptVersion,
|
|
894
956
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -898,16 +960,31 @@ function wrapOpenAI(client) {
|
|
|
898
960
|
return response;
|
|
899
961
|
} catch (error) {
|
|
900
962
|
const endTime = Date.now();
|
|
963
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
964
|
+
params?.messages,
|
|
965
|
+
void 0,
|
|
966
|
+
params?.model,
|
|
967
|
+
void 0
|
|
968
|
+
) : void 0;
|
|
969
|
+
if (attributes) {
|
|
970
|
+
attributes["error.message"] = error?.message;
|
|
971
|
+
}
|
|
901
972
|
sendTrace({
|
|
902
973
|
config_key: ctx.configKey,
|
|
903
974
|
session_id: ctx.sessionId,
|
|
975
|
+
customer_id: ctx.customerId,
|
|
976
|
+
trace_id: traceId,
|
|
977
|
+
span_id: spanId,
|
|
978
|
+
parent_span_id: parentSpanId,
|
|
904
979
|
name: "chat.completions.create",
|
|
980
|
+
kind: "llm",
|
|
905
981
|
model: params?.model,
|
|
906
982
|
start_time: new Date(startTime).toISOString(),
|
|
907
983
|
end_time: new Date(endTime).toISOString(),
|
|
908
984
|
duration_ms: endTime - startTime,
|
|
909
985
|
status: "ERROR",
|
|
910
986
|
error_message: error?.message,
|
|
987
|
+
attributes,
|
|
911
988
|
prompt_key: promptCtx?.promptKey,
|
|
912
989
|
prompt_version: promptCtx?.promptVersion,
|
|
913
990
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -932,15 +1009,33 @@ function wrapAnthropic(client) {
|
|
|
932
1009
|
promptCtx = getPromptContext();
|
|
933
1010
|
} catch {
|
|
934
1011
|
}
|
|
1012
|
+
const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
|
|
1013
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1014
|
+
const spanId = generateHexId(16);
|
|
1015
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
935
1016
|
const params = args[0] || {};
|
|
936
1017
|
const startTime = Date.now();
|
|
937
1018
|
try {
|
|
938
1019
|
const response = await originalCreate(...args);
|
|
939
1020
|
const endTime = Date.now();
|
|
1021
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
1022
|
+
params?.messages,
|
|
1023
|
+
{ role: "assistant", content: response?.content?.[0]?.text || "" },
|
|
1024
|
+
response?.model || params?.model,
|
|
1025
|
+
response?.id
|
|
1026
|
+
) : void 0;
|
|
1027
|
+
if (attributes && params?.system) {
|
|
1028
|
+
attributes["gen_ai.system_prompt"] = params.system;
|
|
1029
|
+
}
|
|
940
1030
|
sendTrace({
|
|
941
1031
|
config_key: ctx.configKey,
|
|
942
1032
|
session_id: ctx.sessionId,
|
|
1033
|
+
customer_id: ctx.customerId,
|
|
1034
|
+
trace_id: traceId,
|
|
1035
|
+
span_id: spanId,
|
|
1036
|
+
parent_span_id: parentSpanId,
|
|
943
1037
|
name: "messages.create",
|
|
1038
|
+
kind: "llm",
|
|
944
1039
|
model: response?.model || params?.model,
|
|
945
1040
|
start_time: new Date(startTime).toISOString(),
|
|
946
1041
|
end_time: new Date(endTime).toISOString(),
|
|
@@ -949,8 +1044,7 @@ function wrapAnthropic(client) {
|
|
|
949
1044
|
prompt_tokens: response?.usage?.input_tokens,
|
|
950
1045
|
completion_tokens: response?.usage?.output_tokens,
|
|
951
1046
|
total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
|
|
952
|
-
|
|
953
|
-
output: captureContent ? response?.content?.[0]?.text : void 0,
|
|
1047
|
+
attributes,
|
|
954
1048
|
prompt_key: promptCtx?.promptKey,
|
|
955
1049
|
prompt_version: promptCtx?.promptVersion,
|
|
956
1050
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -960,16 +1054,34 @@ function wrapAnthropic(client) {
|
|
|
960
1054
|
return response;
|
|
961
1055
|
} catch (error) {
|
|
962
1056
|
const endTime = Date.now();
|
|
1057
|
+
const attributes = captureContent ? messagesToOtelAttributes(
|
|
1058
|
+
params?.messages,
|
|
1059
|
+
void 0,
|
|
1060
|
+
params?.model,
|
|
1061
|
+
void 0
|
|
1062
|
+
) : void 0;
|
|
1063
|
+
if (attributes) {
|
|
1064
|
+
attributes["error.message"] = error?.message;
|
|
1065
|
+
if (params?.system) {
|
|
1066
|
+
attributes["gen_ai.system_prompt"] = params.system;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
963
1069
|
sendTrace({
|
|
964
1070
|
config_key: ctx.configKey,
|
|
965
1071
|
session_id: ctx.sessionId,
|
|
1072
|
+
customer_id: ctx.customerId,
|
|
1073
|
+
trace_id: traceId,
|
|
1074
|
+
span_id: spanId,
|
|
1075
|
+
parent_span_id: parentSpanId,
|
|
966
1076
|
name: "messages.create",
|
|
1077
|
+
kind: "llm",
|
|
967
1078
|
model: params?.model,
|
|
968
1079
|
start_time: new Date(startTime).toISOString(),
|
|
969
1080
|
end_time: new Date(endTime).toISOString(),
|
|
970
1081
|
duration_ms: endTime - startTime,
|
|
971
1082
|
status: "ERROR",
|
|
972
1083
|
error_message: error?.message,
|
|
1084
|
+
attributes,
|
|
973
1085
|
prompt_key: promptCtx?.promptKey,
|
|
974
1086
|
prompt_version: promptCtx?.promptVersion,
|
|
975
1087
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -994,17 +1106,47 @@ function wrapGoogleAI(model) {
|
|
|
994
1106
|
promptCtx = getPromptContext();
|
|
995
1107
|
} catch {
|
|
996
1108
|
}
|
|
1109
|
+
const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
|
|
1110
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1111
|
+
const spanId = generateHexId(16);
|
|
1112
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
997
1113
|
const startTime = Date.now();
|
|
998
1114
|
try {
|
|
999
1115
|
const response = await originalGenerate(...args);
|
|
1000
1116
|
const endTime = Date.now();
|
|
1001
1117
|
const result = response?.response;
|
|
1002
1118
|
const usage = result?.usageMetadata;
|
|
1119
|
+
const modelName = model?.model || "gemini";
|
|
1120
|
+
const attributes = {};
|
|
1121
|
+
if (captureContent) {
|
|
1122
|
+
attributes["gen_ai.request.model"] = modelName;
|
|
1123
|
+
attributes["gen_ai.response.model"] = modelName;
|
|
1124
|
+
const input = args[0];
|
|
1125
|
+
if (typeof input === "string") {
|
|
1126
|
+
attributes["gen_ai.prompt.0.role"] = "user";
|
|
1127
|
+
attributes["gen_ai.prompt.0.content"] = input;
|
|
1128
|
+
} else if (input?.contents) {
|
|
1129
|
+
input.contents.forEach((content, i) => {
|
|
1130
|
+
attributes[`gen_ai.prompt.${i}.role`] = content.role || "user";
|
|
1131
|
+
attributes[`gen_ai.prompt.${i}.content`] = content.parts?.[0]?.text || JSON.stringify(content.parts);
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
const outputText = result?.text?.();
|
|
1135
|
+
if (outputText) {
|
|
1136
|
+
attributes["gen_ai.completion.0.role"] = "assistant";
|
|
1137
|
+
attributes["gen_ai.completion.0.content"] = outputText;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1003
1140
|
sendTrace({
|
|
1004
1141
|
config_key: ctx.configKey,
|
|
1005
1142
|
session_id: ctx.sessionId,
|
|
1143
|
+
customer_id: ctx.customerId,
|
|
1144
|
+
trace_id: traceId,
|
|
1145
|
+
span_id: spanId,
|
|
1146
|
+
parent_span_id: parentSpanId,
|
|
1006
1147
|
name: "generateContent",
|
|
1007
|
-
|
|
1148
|
+
kind: "llm",
|
|
1149
|
+
model: modelName,
|
|
1008
1150
|
start_time: new Date(startTime).toISOString(),
|
|
1009
1151
|
end_time: new Date(endTime).toISOString(),
|
|
1010
1152
|
duration_ms: endTime - startTime,
|
|
@@ -1012,8 +1154,7 @@ function wrapGoogleAI(model) {
|
|
|
1012
1154
|
prompt_tokens: usage?.promptTokenCount,
|
|
1013
1155
|
completion_tokens: usage?.candidatesTokenCount,
|
|
1014
1156
|
total_tokens: usage?.totalTokenCount,
|
|
1015
|
-
|
|
1016
|
-
output: captureContent ? result?.text?.() : void 0,
|
|
1157
|
+
attributes: captureContent ? attributes : void 0,
|
|
1017
1158
|
prompt_key: promptCtx?.promptKey,
|
|
1018
1159
|
prompt_version: promptCtx?.promptVersion,
|
|
1019
1160
|
prompt_ab_test_key: promptCtx?.abTestKey,
|
|
@@ -1023,16 +1164,33 @@ function wrapGoogleAI(model) {
|
|
|
1023
1164
|
return response;
|
|
1024
1165
|
} catch (error) {
|
|
1025
1166
|
const endTime = Date.now();
|
|
1167
|
+
const modelName = model?.model || "gemini";
|
|
1168
|
+
const attributes = {};
|
|
1169
|
+
if (captureContent) {
|
|
1170
|
+
attributes["gen_ai.request.model"] = modelName;
|
|
1171
|
+
attributes["error.message"] = error?.message;
|
|
1172
|
+
const input = args[0];
|
|
1173
|
+
if (typeof input === "string") {
|
|
1174
|
+
attributes["gen_ai.prompt.0.role"] = "user";
|
|
1175
|
+
attributes["gen_ai.prompt.0.content"] = input;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1026
1178
|
sendTrace({
|
|
1027
1179
|
config_key: ctx.configKey,
|
|
1028
1180
|
session_id: ctx.sessionId,
|
|
1181
|
+
customer_id: ctx.customerId,
|
|
1182
|
+
trace_id: traceId,
|
|
1183
|
+
span_id: spanId,
|
|
1184
|
+
parent_span_id: parentSpanId,
|
|
1029
1185
|
name: "generateContent",
|
|
1030
|
-
|
|
1186
|
+
kind: "llm",
|
|
1187
|
+
model: modelName,
|
|
1031
1188
|
start_time: new Date(startTime).toISOString(),
|
|
1032
1189
|
end_time: new Date(endTime).toISOString(),
|
|
1033
1190
|
duration_ms: endTime - startTime,
|
|
1034
1191
|
status: "ERROR",
|
|
1035
1192
|
error_message: error?.message,
|
|
1193
|
+
attributes: captureContent ? attributes : void 0,
|
|
1036
1194
|
prompt_key: promptCtx?.promptKey,
|
|
1037
1195
|
prompt_version: promptCtx?.promptVersion,
|
|
1038
1196
|
prompt_ab_test_key: promptCtx?.abTestKey,
|