@fallom/trace 0.1.5 → 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.js CHANGED
@@ -1118,6 +1118,39 @@ async function shutdown() {
1118
1118
  initialized2 = false;
1119
1119
  }
1120
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;
1121
1154
  async function sendTrace(trace) {
1122
1155
  try {
1123
1156
  const controller = new AbortController();
@@ -1151,16 +1184,30 @@ function wrapOpenAI(client) {
1151
1184
  promptCtx = getPromptContext2();
1152
1185
  } catch {
1153
1186
  }
1187
+ const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1188
+ const traceId = traceCtx?.traceId || generateHexId(32);
1189
+ const spanId = generateHexId(16);
1190
+ const parentSpanId = traceCtx?.parentSpanId;
1154
1191
  const params = args[0] || {};
1155
1192
  const startTime = Date.now();
1156
1193
  try {
1157
1194
  const response = await originalCreate(...args);
1158
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;
1159
1202
  sendTrace({
1160
1203
  config_key: ctx.configKey,
1161
1204
  session_id: ctx.sessionId,
1162
1205
  customer_id: ctx.customerId,
1206
+ trace_id: traceId,
1207
+ span_id: spanId,
1208
+ parent_span_id: parentSpanId,
1163
1209
  name: "chat.completions.create",
1210
+ kind: "llm",
1164
1211
  model: response?.model || params?.model,
1165
1212
  start_time: new Date(startTime).toISOString(),
1166
1213
  end_time: new Date(endTime).toISOString(),
@@ -1169,8 +1216,7 @@ function wrapOpenAI(client) {
1169
1216
  prompt_tokens: response?.usage?.prompt_tokens,
1170
1217
  completion_tokens: response?.usage?.completion_tokens,
1171
1218
  total_tokens: response?.usage?.total_tokens,
1172
- input: captureContent ? JSON.stringify(params?.messages) : void 0,
1173
- output: captureContent ? response?.choices?.[0]?.message?.content : void 0,
1219
+ attributes,
1174
1220
  prompt_key: promptCtx?.promptKey,
1175
1221
  prompt_version: promptCtx?.promptVersion,
1176
1222
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1180,17 +1226,31 @@ function wrapOpenAI(client) {
1180
1226
  return response;
1181
1227
  } catch (error) {
1182
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
+ }
1183
1238
  sendTrace({
1184
1239
  config_key: ctx.configKey,
1185
1240
  session_id: ctx.sessionId,
1186
1241
  customer_id: ctx.customerId,
1242
+ trace_id: traceId,
1243
+ span_id: spanId,
1244
+ parent_span_id: parentSpanId,
1187
1245
  name: "chat.completions.create",
1246
+ kind: "llm",
1188
1247
  model: params?.model,
1189
1248
  start_time: new Date(startTime).toISOString(),
1190
1249
  end_time: new Date(endTime).toISOString(),
1191
1250
  duration_ms: endTime - startTime,
1192
1251
  status: "ERROR",
1193
1252
  error_message: error?.message,
1253
+ attributes,
1194
1254
  prompt_key: promptCtx?.promptKey,
1195
1255
  prompt_version: promptCtx?.promptVersion,
1196
1256
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1215,16 +1275,33 @@ function wrapAnthropic(client) {
1215
1275
  promptCtx = getPromptContext2();
1216
1276
  } catch {
1217
1277
  }
1278
+ const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1279
+ const traceId = traceCtx?.traceId || generateHexId(32);
1280
+ const spanId = generateHexId(16);
1281
+ const parentSpanId = traceCtx?.parentSpanId;
1218
1282
  const params = args[0] || {};
1219
1283
  const startTime = Date.now();
1220
1284
  try {
1221
1285
  const response = await originalCreate(...args);
1222
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
+ }
1223
1296
  sendTrace({
1224
1297
  config_key: ctx.configKey,
1225
1298
  session_id: ctx.sessionId,
1226
1299
  customer_id: ctx.customerId,
1300
+ trace_id: traceId,
1301
+ span_id: spanId,
1302
+ parent_span_id: parentSpanId,
1227
1303
  name: "messages.create",
1304
+ kind: "llm",
1228
1305
  model: response?.model || params?.model,
1229
1306
  start_time: new Date(startTime).toISOString(),
1230
1307
  end_time: new Date(endTime).toISOString(),
@@ -1233,8 +1310,7 @@ function wrapAnthropic(client) {
1233
1310
  prompt_tokens: response?.usage?.input_tokens,
1234
1311
  completion_tokens: response?.usage?.output_tokens,
1235
1312
  total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
1236
- input: captureContent ? JSON.stringify(params?.messages) : void 0,
1237
- output: captureContent ? response?.content?.[0]?.text : void 0,
1313
+ attributes,
1238
1314
  prompt_key: promptCtx?.promptKey,
1239
1315
  prompt_version: promptCtx?.promptVersion,
1240
1316
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1244,17 +1320,34 @@ function wrapAnthropic(client) {
1244
1320
  return response;
1245
1321
  } catch (error) {
1246
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
+ }
1247
1335
  sendTrace({
1248
1336
  config_key: ctx.configKey,
1249
1337
  session_id: ctx.sessionId,
1250
1338
  customer_id: ctx.customerId,
1339
+ trace_id: traceId,
1340
+ span_id: spanId,
1341
+ parent_span_id: parentSpanId,
1251
1342
  name: "messages.create",
1343
+ kind: "llm",
1252
1344
  model: params?.model,
1253
1345
  start_time: new Date(startTime).toISOString(),
1254
1346
  end_time: new Date(endTime).toISOString(),
1255
1347
  duration_ms: endTime - startTime,
1256
1348
  status: "ERROR",
1257
1349
  error_message: error?.message,
1350
+ attributes,
1258
1351
  prompt_key: promptCtx?.promptKey,
1259
1352
  prompt_version: promptCtx?.promptVersion,
1260
1353
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1279,18 +1372,47 @@ function wrapGoogleAI(model) {
1279
1372
  promptCtx = getPromptContext2();
1280
1373
  } catch {
1281
1374
  }
1375
+ const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1376
+ const traceId = traceCtx?.traceId || generateHexId(32);
1377
+ const spanId = generateHexId(16);
1378
+ const parentSpanId = traceCtx?.parentSpanId;
1282
1379
  const startTime = Date.now();
1283
1380
  try {
1284
1381
  const response = await originalGenerate(...args);
1285
1382
  const endTime = Date.now();
1286
1383
  const result = response?.response;
1287
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
+ }
1288
1406
  sendTrace({
1289
1407
  config_key: ctx.configKey,
1290
1408
  session_id: ctx.sessionId,
1291
1409
  customer_id: ctx.customerId,
1410
+ trace_id: traceId,
1411
+ span_id: spanId,
1412
+ parent_span_id: parentSpanId,
1292
1413
  name: "generateContent",
1293
- model: model?.model || "gemini",
1414
+ kind: "llm",
1415
+ model: modelName,
1294
1416
  start_time: new Date(startTime).toISOString(),
1295
1417
  end_time: new Date(endTime).toISOString(),
1296
1418
  duration_ms: endTime - startTime,
@@ -1298,8 +1420,7 @@ function wrapGoogleAI(model) {
1298
1420
  prompt_tokens: usage?.promptTokenCount,
1299
1421
  completion_tokens: usage?.candidatesTokenCount,
1300
1422
  total_tokens: usage?.totalTokenCount,
1301
- input: captureContent ? JSON.stringify(args[0]) : void 0,
1302
- output: captureContent ? result?.text?.() : void 0,
1423
+ attributes: captureContent ? attributes : void 0,
1303
1424
  prompt_key: promptCtx?.promptKey,
1304
1425
  prompt_version: promptCtx?.promptVersion,
1305
1426
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1309,17 +1430,33 @@ function wrapGoogleAI(model) {
1309
1430
  return response;
1310
1431
  } catch (error) {
1311
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
+ }
1312
1444
  sendTrace({
1313
1445
  config_key: ctx.configKey,
1314
1446
  session_id: ctx.sessionId,
1315
1447
  customer_id: ctx.customerId,
1448
+ trace_id: traceId,
1449
+ span_id: spanId,
1450
+ parent_span_id: parentSpanId,
1316
1451
  name: "generateContent",
1317
- model: model?.model || "gemini",
1452
+ kind: "llm",
1453
+ model: modelName,
1318
1454
  start_time: new Date(startTime).toISOString(),
1319
1455
  end_time: new Date(endTime).toISOString(),
1320
1456
  duration_ms: endTime - startTime,
1321
1457
  status: "ERROR",
1322
1458
  error_message: error?.message,
1459
+ attributes: captureContent ? attributes : void 0,
1323
1460
  prompt_key: promptCtx?.promptKey,
1324
1461
  prompt_version: promptCtx?.promptVersion,
1325
1462
  prompt_ab_test_key: promptCtx?.abTestKey,
package/dist/index.mjs CHANGED
@@ -852,6 +852,39 @@ async function shutdown() {
852
852
  initialized = false;
853
853
  }
854
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;
855
888
  async function sendTrace(trace) {
856
889
  try {
857
890
  const controller = new AbortController();
@@ -885,16 +918,30 @@ function wrapOpenAI(client) {
885
918
  promptCtx = getPromptContext();
886
919
  } catch {
887
920
  }
921
+ const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
922
+ const traceId = traceCtx?.traceId || generateHexId(32);
923
+ const spanId = generateHexId(16);
924
+ const parentSpanId = traceCtx?.parentSpanId;
888
925
  const params = args[0] || {};
889
926
  const startTime = Date.now();
890
927
  try {
891
928
  const response = await originalCreate(...args);
892
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;
893
936
  sendTrace({
894
937
  config_key: ctx.configKey,
895
938
  session_id: ctx.sessionId,
896
939
  customer_id: ctx.customerId,
940
+ trace_id: traceId,
941
+ span_id: spanId,
942
+ parent_span_id: parentSpanId,
897
943
  name: "chat.completions.create",
944
+ kind: "llm",
898
945
  model: response?.model || params?.model,
899
946
  start_time: new Date(startTime).toISOString(),
900
947
  end_time: new Date(endTime).toISOString(),
@@ -903,8 +950,7 @@ function wrapOpenAI(client) {
903
950
  prompt_tokens: response?.usage?.prompt_tokens,
904
951
  completion_tokens: response?.usage?.completion_tokens,
905
952
  total_tokens: response?.usage?.total_tokens,
906
- input: captureContent ? JSON.stringify(params?.messages) : void 0,
907
- output: captureContent ? response?.choices?.[0]?.message?.content : void 0,
953
+ attributes,
908
954
  prompt_key: promptCtx?.promptKey,
909
955
  prompt_version: promptCtx?.promptVersion,
910
956
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -914,17 +960,31 @@ function wrapOpenAI(client) {
914
960
  return response;
915
961
  } catch (error) {
916
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
+ }
917
972
  sendTrace({
918
973
  config_key: ctx.configKey,
919
974
  session_id: ctx.sessionId,
920
975
  customer_id: ctx.customerId,
976
+ trace_id: traceId,
977
+ span_id: spanId,
978
+ parent_span_id: parentSpanId,
921
979
  name: "chat.completions.create",
980
+ kind: "llm",
922
981
  model: params?.model,
923
982
  start_time: new Date(startTime).toISOString(),
924
983
  end_time: new Date(endTime).toISOString(),
925
984
  duration_ms: endTime - startTime,
926
985
  status: "ERROR",
927
986
  error_message: error?.message,
987
+ attributes,
928
988
  prompt_key: promptCtx?.promptKey,
929
989
  prompt_version: promptCtx?.promptVersion,
930
990
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -949,16 +1009,33 @@ function wrapAnthropic(client) {
949
1009
  promptCtx = getPromptContext();
950
1010
  } catch {
951
1011
  }
1012
+ const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1013
+ const traceId = traceCtx?.traceId || generateHexId(32);
1014
+ const spanId = generateHexId(16);
1015
+ const parentSpanId = traceCtx?.parentSpanId;
952
1016
  const params = args[0] || {};
953
1017
  const startTime = Date.now();
954
1018
  try {
955
1019
  const response = await originalCreate(...args);
956
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
+ }
957
1030
  sendTrace({
958
1031
  config_key: ctx.configKey,
959
1032
  session_id: ctx.sessionId,
960
1033
  customer_id: ctx.customerId,
1034
+ trace_id: traceId,
1035
+ span_id: spanId,
1036
+ parent_span_id: parentSpanId,
961
1037
  name: "messages.create",
1038
+ kind: "llm",
962
1039
  model: response?.model || params?.model,
963
1040
  start_time: new Date(startTime).toISOString(),
964
1041
  end_time: new Date(endTime).toISOString(),
@@ -967,8 +1044,7 @@ function wrapAnthropic(client) {
967
1044
  prompt_tokens: response?.usage?.input_tokens,
968
1045
  completion_tokens: response?.usage?.output_tokens,
969
1046
  total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
970
- input: captureContent ? JSON.stringify(params?.messages) : void 0,
971
- output: captureContent ? response?.content?.[0]?.text : void 0,
1047
+ attributes,
972
1048
  prompt_key: promptCtx?.promptKey,
973
1049
  prompt_version: promptCtx?.promptVersion,
974
1050
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -978,17 +1054,34 @@ function wrapAnthropic(client) {
978
1054
  return response;
979
1055
  } catch (error) {
980
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
+ }
981
1069
  sendTrace({
982
1070
  config_key: ctx.configKey,
983
1071
  session_id: ctx.sessionId,
984
1072
  customer_id: ctx.customerId,
1073
+ trace_id: traceId,
1074
+ span_id: spanId,
1075
+ parent_span_id: parentSpanId,
985
1076
  name: "messages.create",
1077
+ kind: "llm",
986
1078
  model: params?.model,
987
1079
  start_time: new Date(startTime).toISOString(),
988
1080
  end_time: new Date(endTime).toISOString(),
989
1081
  duration_ms: endTime - startTime,
990
1082
  status: "ERROR",
991
1083
  error_message: error?.message,
1084
+ attributes,
992
1085
  prompt_key: promptCtx?.promptKey,
993
1086
  prompt_version: promptCtx?.promptVersion,
994
1087
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1013,18 +1106,47 @@ function wrapGoogleAI(model) {
1013
1106
  promptCtx = getPromptContext();
1014
1107
  } catch {
1015
1108
  }
1109
+ const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1110
+ const traceId = traceCtx?.traceId || generateHexId(32);
1111
+ const spanId = generateHexId(16);
1112
+ const parentSpanId = traceCtx?.parentSpanId;
1016
1113
  const startTime = Date.now();
1017
1114
  try {
1018
1115
  const response = await originalGenerate(...args);
1019
1116
  const endTime = Date.now();
1020
1117
  const result = response?.response;
1021
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
+ }
1022
1140
  sendTrace({
1023
1141
  config_key: ctx.configKey,
1024
1142
  session_id: ctx.sessionId,
1025
1143
  customer_id: ctx.customerId,
1144
+ trace_id: traceId,
1145
+ span_id: spanId,
1146
+ parent_span_id: parentSpanId,
1026
1147
  name: "generateContent",
1027
- model: model?.model || "gemini",
1148
+ kind: "llm",
1149
+ model: modelName,
1028
1150
  start_time: new Date(startTime).toISOString(),
1029
1151
  end_time: new Date(endTime).toISOString(),
1030
1152
  duration_ms: endTime - startTime,
@@ -1032,8 +1154,7 @@ function wrapGoogleAI(model) {
1032
1154
  prompt_tokens: usage?.promptTokenCount,
1033
1155
  completion_tokens: usage?.candidatesTokenCount,
1034
1156
  total_tokens: usage?.totalTokenCount,
1035
- input: captureContent ? JSON.stringify(args[0]) : void 0,
1036
- output: captureContent ? result?.text?.() : void 0,
1157
+ attributes: captureContent ? attributes : void 0,
1037
1158
  prompt_key: promptCtx?.promptKey,
1038
1159
  prompt_version: promptCtx?.promptVersion,
1039
1160
  prompt_ab_test_key: promptCtx?.abTestKey,
@@ -1043,17 +1164,33 @@ function wrapGoogleAI(model) {
1043
1164
  return response;
1044
1165
  } catch (error) {
1045
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
+ }
1046
1178
  sendTrace({
1047
1179
  config_key: ctx.configKey,
1048
1180
  session_id: ctx.sessionId,
1049
1181
  customer_id: ctx.customerId,
1182
+ trace_id: traceId,
1183
+ span_id: spanId,
1184
+ parent_span_id: parentSpanId,
1050
1185
  name: "generateContent",
1051
- model: model?.model || "gemini",
1186
+ kind: "llm",
1187
+ model: modelName,
1052
1188
  start_time: new Date(startTime).toISOString(),
1053
1189
  end_time: new Date(endTime).toISOString(),
1054
1190
  duration_ms: endTime - startTime,
1055
1191
  status: "ERROR",
1056
1192
  error_message: error?.message,
1193
+ attributes: captureContent ? attributes : void 0,
1057
1194
  prompt_key: promptCtx?.promptKey,
1058
1195
  prompt_version: promptCtx?.promptVersion,
1059
1196
  prompt_ab_test_key: promptCtx?.abTestKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fallom/trace",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Model A/B testing and tracing for LLM applications. Zero latency, production-ready.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",