@fallom/trace 0.2.2 → 0.2.4
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 +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +271 -393
- package/dist/index.mjs +254 -376
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -795,32 +795,6 @@ function generateHexId(length) {
|
|
|
795
795
|
crypto.getRandomValues(bytes);
|
|
796
796
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
797
797
|
}
|
|
798
|
-
function messagesToOtelAttributes(messages, completion, model, responseId) {
|
|
799
|
-
const attrs = {};
|
|
800
|
-
if (model) {
|
|
801
|
-
attrs["gen_ai.request.model"] = model;
|
|
802
|
-
attrs["gen_ai.response.model"] = model;
|
|
803
|
-
}
|
|
804
|
-
if (responseId) {
|
|
805
|
-
attrs["gen_ai.response.id"] = responseId;
|
|
806
|
-
}
|
|
807
|
-
if (messages) {
|
|
808
|
-
messages.forEach((msg, i) => {
|
|
809
|
-
attrs[`gen_ai.prompt.${i}.role`] = msg.role;
|
|
810
|
-
attrs[`gen_ai.prompt.${i}.content`] = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
if (completion) {
|
|
814
|
-
attrs["gen_ai.completion.0.role"] = completion.role;
|
|
815
|
-
attrs["gen_ai.completion.0.content"] = typeof completion.content === "string" ? completion.content : JSON.stringify(completion.content);
|
|
816
|
-
if (completion.tool_calls) {
|
|
817
|
-
attrs["gen_ai.completion.0.tool_calls"] = JSON.stringify(
|
|
818
|
-
completion.tool_calls
|
|
819
|
-
);
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
return attrs;
|
|
823
|
-
}
|
|
824
798
|
|
|
825
799
|
// src/trace/wrappers/openai.ts
|
|
826
800
|
function wrapOpenAI(client, sessionCtx) {
|
|
@@ -842,18 +816,25 @@ function wrapOpenAI(client, sessionCtx) {
|
|
|
842
816
|
try {
|
|
843
817
|
const response = await originalCreate(...args);
|
|
844
818
|
const endTime = Date.now();
|
|
845
|
-
const attributes =
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
819
|
+
const attributes = {
|
|
820
|
+
"fallom.sdk_version": "2",
|
|
821
|
+
"fallom.method": "chat.completions.create"
|
|
822
|
+
};
|
|
823
|
+
if (captureContent2) {
|
|
824
|
+
attributes["fallom.raw.request"] = JSON.stringify({
|
|
825
|
+
messages: params?.messages,
|
|
826
|
+
model: params?.model
|
|
827
|
+
});
|
|
828
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
829
|
+
text: response?.choices?.[0]?.message?.content,
|
|
830
|
+
finishReason: response?.choices?.[0]?.finish_reason,
|
|
831
|
+
responseId: response?.id,
|
|
832
|
+
model: response?.model
|
|
833
|
+
});
|
|
834
|
+
}
|
|
851
835
|
if (response?.usage) {
|
|
852
836
|
attributes["fallom.raw.usage"] = JSON.stringify(response.usage);
|
|
853
837
|
}
|
|
854
|
-
if (response?.choices?.[0]?.finish_reason) {
|
|
855
|
-
attributes["gen_ai.response.finish_reason"] = response.choices[0].finish_reason;
|
|
856
|
-
}
|
|
857
838
|
sendTrace({
|
|
858
839
|
config_key: ctx.configKey,
|
|
859
840
|
session_id: ctx.sessionId,
|
|
@@ -868,24 +849,12 @@ function wrapOpenAI(client, sessionCtx) {
|
|
|
868
849
|
end_time: new Date(endTime).toISOString(),
|
|
869
850
|
duration_ms: endTime - startTime,
|
|
870
851
|
status: "OK",
|
|
871
|
-
|
|
872
|
-
completion_tokens: response?.usage?.completion_tokens,
|
|
873
|
-
total_tokens: response?.usage?.total_tokens,
|
|
874
|
-
attributes: Object.keys(attributes).length > 0 ? attributes : void 0
|
|
852
|
+
attributes
|
|
875
853
|
}).catch(() => {
|
|
876
854
|
});
|
|
877
855
|
return response;
|
|
878
856
|
} catch (error) {
|
|
879
857
|
const endTime = Date.now();
|
|
880
|
-
const attributes = captureContent2 ? messagesToOtelAttributes(
|
|
881
|
-
params?.messages,
|
|
882
|
-
void 0,
|
|
883
|
-
params?.model,
|
|
884
|
-
void 0
|
|
885
|
-
) : void 0;
|
|
886
|
-
if (attributes) {
|
|
887
|
-
attributes["error.message"] = error?.message;
|
|
888
|
-
}
|
|
889
858
|
sendTrace({
|
|
890
859
|
config_key: ctx.configKey,
|
|
891
860
|
session_id: ctx.sessionId,
|
|
@@ -901,7 +870,10 @@ function wrapOpenAI(client, sessionCtx) {
|
|
|
901
870
|
duration_ms: endTime - startTime,
|
|
902
871
|
status: "ERROR",
|
|
903
872
|
error_message: error?.message,
|
|
904
|
-
attributes
|
|
873
|
+
attributes: {
|
|
874
|
+
"fallom.sdk_version": "2",
|
|
875
|
+
"fallom.method": "chat.completions.create"
|
|
876
|
+
}
|
|
905
877
|
}).catch(() => {
|
|
906
878
|
});
|
|
907
879
|
throw error;
|
|
@@ -928,21 +900,26 @@ function wrapAnthropic(client, sessionCtx) {
|
|
|
928
900
|
try {
|
|
929
901
|
const response = await originalCreate(...args);
|
|
930
902
|
const endTime = Date.now();
|
|
931
|
-
const attributes =
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
903
|
+
const attributes = {
|
|
904
|
+
"fallom.sdk_version": "2",
|
|
905
|
+
"fallom.method": "messages.create"
|
|
906
|
+
};
|
|
907
|
+
if (captureContent2) {
|
|
908
|
+
attributes["fallom.raw.request"] = JSON.stringify({
|
|
909
|
+
messages: params?.messages,
|
|
910
|
+
system: params?.system,
|
|
911
|
+
model: params?.model
|
|
912
|
+
});
|
|
913
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
914
|
+
text: response?.content?.[0]?.text,
|
|
915
|
+
finishReason: response?.stop_reason,
|
|
916
|
+
responseId: response?.id,
|
|
917
|
+
model: response?.model
|
|
918
|
+
});
|
|
939
919
|
}
|
|
940
920
|
if (response?.usage) {
|
|
941
921
|
attributes["fallom.raw.usage"] = JSON.stringify(response.usage);
|
|
942
922
|
}
|
|
943
|
-
if (response?.stop_reason) {
|
|
944
|
-
attributes["gen_ai.response.finish_reason"] = response.stop_reason;
|
|
945
|
-
}
|
|
946
923
|
sendTrace({
|
|
947
924
|
config_key: ctx.configKey,
|
|
948
925
|
session_id: ctx.sessionId,
|
|
@@ -957,27 +934,12 @@ function wrapAnthropic(client, sessionCtx) {
|
|
|
957
934
|
end_time: new Date(endTime).toISOString(),
|
|
958
935
|
duration_ms: endTime - startTime,
|
|
959
936
|
status: "OK",
|
|
960
|
-
|
|
961
|
-
completion_tokens: response?.usage?.output_tokens,
|
|
962
|
-
total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
|
|
963
|
-
attributes: Object.keys(attributes).length > 0 ? attributes : void 0
|
|
937
|
+
attributes
|
|
964
938
|
}).catch(() => {
|
|
965
939
|
});
|
|
966
940
|
return response;
|
|
967
941
|
} catch (error) {
|
|
968
942
|
const endTime = Date.now();
|
|
969
|
-
const attributes = captureContent2 ? messagesToOtelAttributes(
|
|
970
|
-
params?.messages,
|
|
971
|
-
void 0,
|
|
972
|
-
params?.model,
|
|
973
|
-
void 0
|
|
974
|
-
) : void 0;
|
|
975
|
-
if (attributes) {
|
|
976
|
-
attributes["error.message"] = error?.message;
|
|
977
|
-
if (params?.system) {
|
|
978
|
-
attributes["gen_ai.system_prompt"] = params.system;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
943
|
sendTrace({
|
|
982
944
|
config_key: ctx.configKey,
|
|
983
945
|
session_id: ctx.sessionId,
|
|
@@ -993,7 +955,10 @@ function wrapAnthropic(client, sessionCtx) {
|
|
|
993
955
|
duration_ms: endTime - startTime,
|
|
994
956
|
status: "ERROR",
|
|
995
957
|
error_message: error?.message,
|
|
996
|
-
attributes
|
|
958
|
+
attributes: {
|
|
959
|
+
"fallom.sdk_version": "2",
|
|
960
|
+
"fallom.method": "messages.create"
|
|
961
|
+
}
|
|
997
962
|
}).catch(() => {
|
|
998
963
|
});
|
|
999
964
|
throw error;
|
|
@@ -1004,50 +969,36 @@ function wrapAnthropic(client, sessionCtx) {
|
|
|
1004
969
|
|
|
1005
970
|
// src/trace/wrappers/google-ai.ts
|
|
1006
971
|
function wrapGoogleAI(model, sessionCtx) {
|
|
1007
|
-
const
|
|
972
|
+
const originalGenerateContent = model.generateContent.bind(model);
|
|
1008
973
|
const ctx = sessionCtx;
|
|
1009
974
|
model.generateContent = async function(...args) {
|
|
1010
975
|
if (!isInitialized()) {
|
|
1011
|
-
return
|
|
976
|
+
return originalGenerateContent(...args);
|
|
1012
977
|
}
|
|
1013
978
|
const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
|
|
1014
979
|
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1015
980
|
const spanId = generateHexId(16);
|
|
1016
981
|
const parentSpanId = traceCtx?.parentSpanId;
|
|
982
|
+
const request = args[0];
|
|
1017
983
|
const startTime = Date.now();
|
|
1018
984
|
const captureContent2 = shouldCaptureContent();
|
|
1019
985
|
try {
|
|
1020
|
-
const response = await
|
|
986
|
+
const response = await originalGenerateContent(...args);
|
|
1021
987
|
const endTime = Date.now();
|
|
1022
|
-
const result = response?.response;
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1025
|
-
|
|
988
|
+
const result = response?.response || response;
|
|
989
|
+
const attributes = {
|
|
990
|
+
"fallom.sdk_version": "2",
|
|
991
|
+
"fallom.method": "generateContent"
|
|
992
|
+
};
|
|
1026
993
|
if (captureContent2) {
|
|
1027
|
-
attributes["
|
|
1028
|
-
attributes["
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
attributes["gen_ai.prompt.0.content"] = input;
|
|
1033
|
-
} else if (input?.contents) {
|
|
1034
|
-
input.contents.forEach((content, i) => {
|
|
1035
|
-
attributes[`gen_ai.prompt.${i}.role`] = content.role || "user";
|
|
1036
|
-
attributes[`gen_ai.prompt.${i}.content`] = content.parts?.[0]?.text || JSON.stringify(content.parts);
|
|
1037
|
-
});
|
|
1038
|
-
}
|
|
1039
|
-
const outputText = result?.text?.();
|
|
1040
|
-
if (outputText) {
|
|
1041
|
-
attributes["gen_ai.completion.0.role"] = "assistant";
|
|
1042
|
-
attributes["gen_ai.completion.0.content"] = outputText;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
if (usage) {
|
|
1046
|
-
attributes["fallom.raw.usage"] = JSON.stringify(usage);
|
|
994
|
+
attributes["fallom.raw.request"] = JSON.stringify(request);
|
|
995
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
996
|
+
text: result?.text?.(),
|
|
997
|
+
candidates: result?.candidates
|
|
998
|
+
});
|
|
1047
999
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
attributes["gen_ai.response.finish_reason"] = candidate.finishReason;
|
|
1000
|
+
if (result?.usageMetadata) {
|
|
1001
|
+
attributes["fallom.raw.usage"] = JSON.stringify(result.usageMetadata);
|
|
1051
1002
|
}
|
|
1052
1003
|
sendTrace({
|
|
1053
1004
|
config_key: ctx.configKey,
|
|
@@ -1058,31 +1009,17 @@ function wrapGoogleAI(model, sessionCtx) {
|
|
|
1058
1009
|
parent_span_id: parentSpanId,
|
|
1059
1010
|
name: "generateContent",
|
|
1060
1011
|
kind: "llm",
|
|
1061
|
-
model:
|
|
1012
|
+
model: model.model || "gemini",
|
|
1062
1013
|
start_time: new Date(startTime).toISOString(),
|
|
1063
1014
|
end_time: new Date(endTime).toISOString(),
|
|
1064
1015
|
duration_ms: endTime - startTime,
|
|
1065
1016
|
status: "OK",
|
|
1066
|
-
|
|
1067
|
-
completion_tokens: usage?.candidatesTokenCount,
|
|
1068
|
-
total_tokens: usage?.totalTokenCount,
|
|
1069
|
-
attributes: Object.keys(attributes).length > 0 ? attributes : void 0
|
|
1017
|
+
attributes
|
|
1070
1018
|
}).catch(() => {
|
|
1071
1019
|
});
|
|
1072
1020
|
return response;
|
|
1073
1021
|
} catch (error) {
|
|
1074
1022
|
const endTime = Date.now();
|
|
1075
|
-
const modelName = model?.model || "gemini";
|
|
1076
|
-
const attributes = {};
|
|
1077
|
-
if (captureContent2) {
|
|
1078
|
-
attributes["gen_ai.request.model"] = modelName;
|
|
1079
|
-
attributes["error.message"] = error?.message;
|
|
1080
|
-
const input = args[0];
|
|
1081
|
-
if (typeof input === "string") {
|
|
1082
|
-
attributes["gen_ai.prompt.0.role"] = "user";
|
|
1083
|
-
attributes["gen_ai.prompt.0.content"] = input;
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
1023
|
sendTrace({
|
|
1087
1024
|
config_key: ctx.configKey,
|
|
1088
1025
|
session_id: ctx.sessionId,
|
|
@@ -1092,13 +1029,16 @@ function wrapGoogleAI(model, sessionCtx) {
|
|
|
1092
1029
|
parent_span_id: parentSpanId,
|
|
1093
1030
|
name: "generateContent",
|
|
1094
1031
|
kind: "llm",
|
|
1095
|
-
model:
|
|
1032
|
+
model: model.model || "gemini",
|
|
1096
1033
|
start_time: new Date(startTime).toISOString(),
|
|
1097
1034
|
end_time: new Date(endTime).toISOString(),
|
|
1098
1035
|
duration_ms: endTime - startTime,
|
|
1099
1036
|
status: "ERROR",
|
|
1100
1037
|
error_message: error?.message,
|
|
1101
|
-
attributes:
|
|
1038
|
+
attributes: {
|
|
1039
|
+
"fallom.sdk_version": "2",
|
|
1040
|
+
"fallom.method": "generateContent"
|
|
1041
|
+
}
|
|
1102
1042
|
}).catch(() => {
|
|
1103
1043
|
});
|
|
1104
1044
|
throw error;
|
|
@@ -1107,35 +1047,6 @@ function wrapGoogleAI(model, sessionCtx) {
|
|
|
1107
1047
|
return model;
|
|
1108
1048
|
}
|
|
1109
1049
|
|
|
1110
|
-
// src/trace/wrappers/vercel-ai/utils.ts
|
|
1111
|
-
function extractUsageFromResult(result, directUsage) {
|
|
1112
|
-
let usage = directUsage ?? result?.usage;
|
|
1113
|
-
const isValidNumber = (v) => v !== null && v !== void 0 && !Number.isNaN(v);
|
|
1114
|
-
let promptTokens = isValidNumber(usage?.promptTokens) ? usage.promptTokens : isValidNumber(usage?.inputTokens) ? usage.inputTokens : isValidNumber(usage?.prompt_tokens) ? usage.prompt_tokens : void 0;
|
|
1115
|
-
let completionTokens = isValidNumber(usage?.completionTokens) ? usage.completionTokens : isValidNumber(usage?.outputTokens) ? usage.outputTokens : isValidNumber(usage?.completion_tokens) ? usage.completion_tokens : void 0;
|
|
1116
|
-
let totalTokens = isValidNumber(usage?.totalTokens) ? usage.totalTokens : isValidNumber(usage?.total_tokens) ? usage.total_tokens : void 0;
|
|
1117
|
-
let cost;
|
|
1118
|
-
const orUsage = result?.experimental_providerMetadata?.openrouter?.usage;
|
|
1119
|
-
if (orUsage) {
|
|
1120
|
-
if (promptTokens === void 0 && isValidNumber(orUsage.promptTokens)) {
|
|
1121
|
-
promptTokens = orUsage.promptTokens;
|
|
1122
|
-
}
|
|
1123
|
-
if (completionTokens === void 0 && isValidNumber(orUsage.completionTokens)) {
|
|
1124
|
-
completionTokens = orUsage.completionTokens;
|
|
1125
|
-
}
|
|
1126
|
-
if (totalTokens === void 0 && isValidNumber(orUsage.totalTokens)) {
|
|
1127
|
-
totalTokens = orUsage.totalTokens;
|
|
1128
|
-
}
|
|
1129
|
-
if (isValidNumber(orUsage.cost)) {
|
|
1130
|
-
cost = orUsage.cost;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
if (totalTokens === void 0 && (promptTokens !== void 0 || completionTokens !== void 0)) {
|
|
1134
|
-
totalTokens = (promptTokens ?? 0) + (completionTokens ?? 0);
|
|
1135
|
-
}
|
|
1136
|
-
return { promptTokens, completionTokens, totalTokens, cost };
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
1050
|
// src/trace/wrappers/vercel-ai/generate-text.ts
|
|
1140
1051
|
function createGenerateTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
1141
1052
|
const ctx = sessionCtx;
|
|
@@ -1154,54 +1065,33 @@ function createGenerateTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1154
1065
|
const result = await aiModule.generateText(...args);
|
|
1155
1066
|
const endTime = Date.now();
|
|
1156
1067
|
if (debug || isDebugMode()) {
|
|
1157
|
-
console.log(
|
|
1158
|
-
"\n\u{1F50D} [Fallom Debug] generateText result keys:",
|
|
1159
|
-
Object.keys(result || {})
|
|
1160
|
-
);
|
|
1161
|
-
console.log(
|
|
1162
|
-
"\u{1F50D} [Fallom Debug] result.usage:",
|
|
1163
|
-
JSON.stringify(result?.usage, null, 2)
|
|
1164
|
-
);
|
|
1165
|
-
console.log(
|
|
1166
|
-
"\u{1F50D} [Fallom Debug] result.experimental_providerMetadata:",
|
|
1167
|
-
JSON.stringify(result?.experimental_providerMetadata, null, 2)
|
|
1168
|
-
);
|
|
1068
|
+
console.log("\n\u{1F50D} [Fallom Debug] generateText raw result:", JSON.stringify(result, null, 2));
|
|
1169
1069
|
}
|
|
1170
1070
|
const modelId = result?.response?.modelId || params?.model?.modelId || String(params?.model || "unknown");
|
|
1171
|
-
const attributes = {
|
|
1071
|
+
const attributes = {
|
|
1072
|
+
"fallom.sdk_version": "2",
|
|
1073
|
+
"fallom.method": "generateText"
|
|
1074
|
+
};
|
|
1172
1075
|
if (captureContent2) {
|
|
1173
|
-
attributes["
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
}
|
|
1185
|
-
if (result?.text) {
|
|
1186
|
-
attributes["gen_ai.completion.0.role"] = "assistant";
|
|
1187
|
-
attributes["gen_ai.completion.0.content"] = result.text;
|
|
1188
|
-
}
|
|
1189
|
-
if (result?.response?.id) {
|
|
1190
|
-
attributes["gen_ai.response.id"] = result.response.id;
|
|
1191
|
-
}
|
|
1076
|
+
attributes["fallom.raw.request"] = JSON.stringify({
|
|
1077
|
+
prompt: params?.prompt,
|
|
1078
|
+
messages: params?.messages,
|
|
1079
|
+
system: params?.system,
|
|
1080
|
+
model: modelId
|
|
1081
|
+
});
|
|
1082
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1083
|
+
text: result?.text,
|
|
1084
|
+
finishReason: result?.finishReason,
|
|
1085
|
+
responseId: result?.response?.id,
|
|
1086
|
+
modelId: result?.response?.modelId
|
|
1087
|
+
});
|
|
1192
1088
|
}
|
|
1193
1089
|
if (result?.usage) {
|
|
1194
1090
|
attributes["fallom.raw.usage"] = JSON.stringify(result.usage);
|
|
1195
1091
|
}
|
|
1196
1092
|
if (result?.experimental_providerMetadata) {
|
|
1197
|
-
attributes["fallom.raw.providerMetadata"] = JSON.stringify(
|
|
1198
|
-
result.experimental_providerMetadata
|
|
1199
|
-
);
|
|
1093
|
+
attributes["fallom.raw.providerMetadata"] = JSON.stringify(result.experimental_providerMetadata);
|
|
1200
1094
|
}
|
|
1201
|
-
if (result?.finishReason) {
|
|
1202
|
-
attributes["gen_ai.response.finish_reason"] = result.finishReason;
|
|
1203
|
-
}
|
|
1204
|
-
const usage = extractUsageFromResult(result);
|
|
1205
1095
|
sendTrace({
|
|
1206
1096
|
config_key: ctx.configKey,
|
|
1207
1097
|
session_id: ctx.sessionId,
|
|
@@ -1216,10 +1106,7 @@ function createGenerateTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1216
1106
|
end_time: new Date(endTime).toISOString(),
|
|
1217
1107
|
duration_ms: endTime - startTime,
|
|
1218
1108
|
status: "OK",
|
|
1219
|
-
|
|
1220
|
-
completion_tokens: usage.completionTokens,
|
|
1221
|
-
total_tokens: usage.totalTokens,
|
|
1222
|
-
attributes: captureContent2 ? attributes : void 0
|
|
1109
|
+
attributes
|
|
1223
1110
|
}).catch(() => {
|
|
1224
1111
|
});
|
|
1225
1112
|
return result;
|
|
@@ -1240,7 +1127,17 @@ function createGenerateTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1240
1127
|
end_time: new Date(endTime).toISOString(),
|
|
1241
1128
|
duration_ms: endTime - startTime,
|
|
1242
1129
|
status: "ERROR",
|
|
1243
|
-
error_message: error?.message
|
|
1130
|
+
error_message: error?.message,
|
|
1131
|
+
attributes: {
|
|
1132
|
+
"fallom.sdk_version": "2",
|
|
1133
|
+
"fallom.method": "generateText",
|
|
1134
|
+
"fallom.raw.request": JSON.stringify({
|
|
1135
|
+
prompt: params?.prompt,
|
|
1136
|
+
messages: params?.messages,
|
|
1137
|
+
system: params?.system,
|
|
1138
|
+
model: modelId
|
|
1139
|
+
})
|
|
1140
|
+
}
|
|
1244
1141
|
}).catch(() => {
|
|
1245
1142
|
});
|
|
1246
1143
|
throw error;
|
|
@@ -1269,15 +1166,17 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1269
1166
|
let firstTokenTime = null;
|
|
1270
1167
|
const modelId = params?.model?.modelId || String(params?.model || "unknown");
|
|
1271
1168
|
if (result?.usage) {
|
|
1272
|
-
|
|
1169
|
+
Promise.all([
|
|
1170
|
+
result.usage.catch(() => null),
|
|
1171
|
+
result.text?.catch(() => null),
|
|
1172
|
+
result.finishReason?.catch(() => null)
|
|
1173
|
+
]).then(async ([rawUsage, responseText, finishReason]) => {
|
|
1273
1174
|
const endTime = Date.now();
|
|
1274
1175
|
if (debug || isDebugMode()) {
|
|
1275
|
-
console.log(
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
);
|
|
1176
|
+
console.log("\n\u{1F50D} [Fallom Debug] streamText raw usage:", JSON.stringify(rawUsage, null, 2));
|
|
1177
|
+
console.log("\u{1F50D} [Fallom Debug] streamText response text:", responseText?.slice(0, 100));
|
|
1178
|
+
console.log("\u{1F50D} [Fallom Debug] streamText finish reason:", finishReason);
|
|
1279
1179
|
}
|
|
1280
|
-
log2("\u{1F4CA} streamText usage:", JSON.stringify(rawUsage, null, 2));
|
|
1281
1180
|
let providerMetadata = result?.experimental_providerMetadata;
|
|
1282
1181
|
if (providerMetadata && typeof providerMetadata.then === "function") {
|
|
1283
1182
|
try {
|
|
@@ -1286,28 +1185,35 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1286
1185
|
providerMetadata = void 0;
|
|
1287
1186
|
}
|
|
1288
1187
|
}
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1188
|
+
const attributes = {
|
|
1189
|
+
"fallom.sdk_version": "2",
|
|
1190
|
+
"fallom.method": "streamText",
|
|
1191
|
+
"fallom.is_streaming": true
|
|
1192
|
+
};
|
|
1294
1193
|
if (captureContent2) {
|
|
1295
|
-
attributes["
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1194
|
+
attributes["fallom.raw.request"] = JSON.stringify({
|
|
1195
|
+
prompt: params?.prompt,
|
|
1196
|
+
messages: params?.messages,
|
|
1197
|
+
system: params?.system,
|
|
1198
|
+
model: modelId
|
|
1199
|
+
});
|
|
1200
|
+
if (responseText || finishReason) {
|
|
1201
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1202
|
+
text: responseText,
|
|
1203
|
+
finishReason
|
|
1204
|
+
});
|
|
1299
1205
|
}
|
|
1300
1206
|
}
|
|
1301
|
-
if (firstTokenTime) {
|
|
1302
|
-
attributes["gen_ai.time_to_first_token_ms"] = firstTokenTime - startTime;
|
|
1303
|
-
}
|
|
1304
1207
|
if (rawUsage) {
|
|
1305
1208
|
attributes["fallom.raw.usage"] = JSON.stringify(rawUsage);
|
|
1306
1209
|
}
|
|
1307
1210
|
if (providerMetadata) {
|
|
1308
1211
|
attributes["fallom.raw.providerMetadata"] = JSON.stringify(providerMetadata);
|
|
1309
1212
|
}
|
|
1310
|
-
|
|
1213
|
+
if (firstTokenTime) {
|
|
1214
|
+
attributes["fallom.time_to_first_token_ms"] = firstTokenTime - startTime;
|
|
1215
|
+
}
|
|
1216
|
+
sendTrace({
|
|
1311
1217
|
config_key: ctx.configKey,
|
|
1312
1218
|
session_id: ctx.sessionId,
|
|
1313
1219
|
customer_id: ctx.customerId,
|
|
@@ -1321,13 +1227,10 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1321
1227
|
end_time: new Date(endTime).toISOString(),
|
|
1322
1228
|
duration_ms: endTime - startTime,
|
|
1323
1229
|
status: "OK",
|
|
1324
|
-
prompt_tokens: usage.promptTokens,
|
|
1325
|
-
completion_tokens: usage.completionTokens,
|
|
1326
|
-
total_tokens: usage.totalTokens,
|
|
1327
1230
|
time_to_first_token_ms: firstTokenTime ? firstTokenTime - startTime : void 0,
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1231
|
+
is_streaming: true,
|
|
1232
|
+
attributes
|
|
1233
|
+
}).catch(() => {
|
|
1331
1234
|
});
|
|
1332
1235
|
}).catch((error) => {
|
|
1333
1236
|
const endTime = Date.now();
|
|
@@ -1346,7 +1249,12 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1346
1249
|
end_time: new Date(endTime).toISOString(),
|
|
1347
1250
|
duration_ms: endTime - startTime,
|
|
1348
1251
|
status: "ERROR",
|
|
1349
|
-
error_message: error?.message
|
|
1252
|
+
error_message: error?.message,
|
|
1253
|
+
attributes: {
|
|
1254
|
+
"fallom.sdk_version": "2",
|
|
1255
|
+
"fallom.method": "streamText",
|
|
1256
|
+
"fallom.is_streaming": true
|
|
1257
|
+
}
|
|
1350
1258
|
}).catch(() => {
|
|
1351
1259
|
});
|
|
1352
1260
|
});
|
|
@@ -1394,25 +1302,30 @@ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1394
1302
|
const endTime = Date.now();
|
|
1395
1303
|
if (debug || isDebugMode()) {
|
|
1396
1304
|
console.log(
|
|
1397
|
-
"\n\u{1F50D} [Fallom Debug] generateObject result
|
|
1398
|
-
|
|
1399
|
-
);
|
|
1400
|
-
console.log(
|
|
1401
|
-
"\u{1F50D} [Fallom Debug] result.usage:",
|
|
1402
|
-
JSON.stringify(result?.usage, null, 2)
|
|
1305
|
+
"\n\u{1F50D} [Fallom Debug] generateObject raw result:",
|
|
1306
|
+
JSON.stringify(result, null, 2)
|
|
1403
1307
|
);
|
|
1404
1308
|
}
|
|
1405
1309
|
const modelId = result?.response?.modelId || params?.model?.modelId || String(params?.model || "unknown");
|
|
1406
|
-
const attributes = {
|
|
1310
|
+
const attributes = {
|
|
1311
|
+
"fallom.sdk_version": "2",
|
|
1312
|
+
"fallom.method": "generateObject"
|
|
1313
|
+
};
|
|
1407
1314
|
if (captureContent2) {
|
|
1408
|
-
attributes["
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
}
|
|
1315
|
+
attributes["fallom.raw.request"] = JSON.stringify({
|
|
1316
|
+
prompt: params?.prompt,
|
|
1317
|
+
messages: params?.messages,
|
|
1318
|
+
system: params?.system,
|
|
1319
|
+
model: modelId,
|
|
1320
|
+
schema: params?.schema ? "provided" : void 0
|
|
1321
|
+
// Don't send full schema, just note if present
|
|
1322
|
+
});
|
|
1323
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1324
|
+
object: result?.object,
|
|
1325
|
+
finishReason: result?.finishReason,
|
|
1326
|
+
responseId: result?.response?.id,
|
|
1327
|
+
modelId: result?.response?.modelId
|
|
1328
|
+
});
|
|
1416
1329
|
}
|
|
1417
1330
|
if (result?.usage) {
|
|
1418
1331
|
attributes["fallom.raw.usage"] = JSON.stringify(result.usage);
|
|
@@ -1422,10 +1335,6 @@ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1422
1335
|
result.experimental_providerMetadata
|
|
1423
1336
|
);
|
|
1424
1337
|
}
|
|
1425
|
-
if (result?.finishReason) {
|
|
1426
|
-
attributes["gen_ai.response.finish_reason"] = result.finishReason;
|
|
1427
|
-
}
|
|
1428
|
-
const usage = extractUsageFromResult(result);
|
|
1429
1338
|
sendTrace({
|
|
1430
1339
|
config_key: ctx.configKey,
|
|
1431
1340
|
session_id: ctx.sessionId,
|
|
@@ -1440,10 +1349,7 @@ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1440
1349
|
end_time: new Date(endTime).toISOString(),
|
|
1441
1350
|
duration_ms: endTime - startTime,
|
|
1442
1351
|
status: "OK",
|
|
1443
|
-
|
|
1444
|
-
completion_tokens: usage.completionTokens,
|
|
1445
|
-
total_tokens: usage.totalTokens,
|
|
1446
|
-
attributes: captureContent2 ? attributes : void 0
|
|
1352
|
+
attributes
|
|
1447
1353
|
}).catch(() => {
|
|
1448
1354
|
});
|
|
1449
1355
|
return result;
|
|
@@ -1464,7 +1370,11 @@ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1464
1370
|
end_time: new Date(endTime).toISOString(),
|
|
1465
1371
|
duration_ms: endTime - startTime,
|
|
1466
1372
|
status: "ERROR",
|
|
1467
|
-
error_message: error?.message
|
|
1373
|
+
error_message: error?.message,
|
|
1374
|
+
attributes: {
|
|
1375
|
+
"fallom.sdk_version": "2",
|
|
1376
|
+
"fallom.method": "generateObject"
|
|
1377
|
+
}
|
|
1468
1378
|
}).catch(() => {
|
|
1469
1379
|
});
|
|
1470
1380
|
throw error;
|
|
@@ -1473,9 +1383,6 @@ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1473
1383
|
}
|
|
1474
1384
|
|
|
1475
1385
|
// src/trace/wrappers/vercel-ai/stream-object.ts
|
|
1476
|
-
function log3(...args) {
|
|
1477
|
-
if (isDebugMode()) console.log("[Fallom]", ...args);
|
|
1478
|
-
}
|
|
1479
1386
|
function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
1480
1387
|
const ctx = sessionCtx;
|
|
1481
1388
|
return async (...args) => {
|
|
@@ -1483,7 +1390,6 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1483
1390
|
const startTime = Date.now();
|
|
1484
1391
|
const captureContent2 = shouldCaptureContent();
|
|
1485
1392
|
const result = await aiModule.streamObject(...args);
|
|
1486
|
-
log3("\u{1F50D} streamObject result keys:", Object.keys(result || {}));
|
|
1487
1393
|
if (!isInitialized()) {
|
|
1488
1394
|
return result;
|
|
1489
1395
|
}
|
|
@@ -1491,18 +1397,19 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1491
1397
|
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1492
1398
|
const spanId = generateHexId(16);
|
|
1493
1399
|
const parentSpanId = traceCtx?.parentSpanId;
|
|
1494
|
-
let firstTokenTime = null;
|
|
1495
1400
|
const modelId = params?.model?.modelId || String(params?.model || "unknown");
|
|
1496
1401
|
if (result?.usage) {
|
|
1497
|
-
|
|
1402
|
+
Promise.all([
|
|
1403
|
+
result.usage.catch(() => null),
|
|
1404
|
+
result.object?.catch(() => null),
|
|
1405
|
+
result.finishReason?.catch(() => null)
|
|
1406
|
+
]).then(async ([rawUsage, responseObject, finishReason]) => {
|
|
1498
1407
|
const endTime = Date.now();
|
|
1499
1408
|
if (debug || isDebugMode()) {
|
|
1500
|
-
console.log(
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
);
|
|
1409
|
+
console.log("\n\u{1F50D} [Fallom Debug] streamObject raw usage:", JSON.stringify(rawUsage, null, 2));
|
|
1410
|
+
console.log("\u{1F50D} [Fallom Debug] streamObject response object:", JSON.stringify(responseObject)?.slice(0, 100));
|
|
1411
|
+
console.log("\u{1F50D} [Fallom Debug] streamObject finish reason:", finishReason);
|
|
1504
1412
|
}
|
|
1505
|
-
log3("\u{1F4CA} streamObject usage:", JSON.stringify(rawUsage, null, 2));
|
|
1506
1413
|
let providerMetadata = result?.experimental_providerMetadata;
|
|
1507
1414
|
if (providerMetadata && typeof providerMetadata.then === "function") {
|
|
1508
1415
|
try {
|
|
@@ -1511,16 +1418,25 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1511
1418
|
providerMetadata = void 0;
|
|
1512
1419
|
}
|
|
1513
1420
|
}
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1421
|
+
const attributes = {
|
|
1422
|
+
"fallom.sdk_version": "2",
|
|
1423
|
+
"fallom.method": "streamObject",
|
|
1424
|
+
"fallom.is_streaming": true
|
|
1425
|
+
};
|
|
1519
1426
|
if (captureContent2) {
|
|
1520
|
-
attributes["
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1427
|
+
attributes["fallom.raw.request"] = JSON.stringify({
|
|
1428
|
+
prompt: params?.prompt,
|
|
1429
|
+
messages: params?.messages,
|
|
1430
|
+
system: params?.system,
|
|
1431
|
+
model: modelId,
|
|
1432
|
+
schema: params?.schema ? "provided" : void 0
|
|
1433
|
+
});
|
|
1434
|
+
if (responseObject || finishReason) {
|
|
1435
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1436
|
+
object: responseObject,
|
|
1437
|
+
finishReason
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1524
1440
|
}
|
|
1525
1441
|
if (rawUsage) {
|
|
1526
1442
|
attributes["fallom.raw.usage"] = JSON.stringify(rawUsage);
|
|
@@ -1542,10 +1458,8 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1542
1458
|
end_time: new Date(endTime).toISOString(),
|
|
1543
1459
|
duration_ms: endTime - startTime,
|
|
1544
1460
|
status: "OK",
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
total_tokens: usage.totalTokens,
|
|
1548
|
-
attributes: captureContent2 ? attributes : void 0
|
|
1461
|
+
is_streaming: true,
|
|
1462
|
+
attributes
|
|
1549
1463
|
}).catch(() => {
|
|
1550
1464
|
});
|
|
1551
1465
|
}).catch((error) => {
|
|
@@ -1564,31 +1478,16 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1564
1478
|
end_time: new Date(endTime).toISOString(),
|
|
1565
1479
|
duration_ms: endTime - startTime,
|
|
1566
1480
|
status: "ERROR",
|
|
1567
|
-
error_message: error?.message
|
|
1481
|
+
error_message: error?.message,
|
|
1482
|
+
attributes: {
|
|
1483
|
+
"fallom.sdk_version": "2",
|
|
1484
|
+
"fallom.method": "streamObject",
|
|
1485
|
+
"fallom.is_streaming": true
|
|
1486
|
+
}
|
|
1568
1487
|
}).catch(() => {
|
|
1569
1488
|
});
|
|
1570
1489
|
});
|
|
1571
1490
|
}
|
|
1572
|
-
if (result?.partialObjectStream) {
|
|
1573
|
-
const originalStream = result.partialObjectStream;
|
|
1574
|
-
const wrappedStream = (async function* () {
|
|
1575
|
-
for await (const chunk of originalStream) {
|
|
1576
|
-
if (!firstTokenTime) {
|
|
1577
|
-
firstTokenTime = Date.now();
|
|
1578
|
-
log3("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
|
|
1579
|
-
}
|
|
1580
|
-
yield chunk;
|
|
1581
|
-
}
|
|
1582
|
-
})();
|
|
1583
|
-
return new Proxy(result, {
|
|
1584
|
-
get(target, prop) {
|
|
1585
|
-
if (prop === "partialObjectStream") {
|
|
1586
|
-
return wrappedStream;
|
|
1587
|
-
}
|
|
1588
|
-
return target[prop];
|
|
1589
|
-
}
|
|
1590
|
-
});
|
|
1591
|
-
}
|
|
1592
1491
|
return result;
|
|
1593
1492
|
};
|
|
1594
1493
|
}
|
|
@@ -1607,105 +1506,69 @@ function wrapAISDK(ai, sessionCtx, options) {
|
|
|
1607
1506
|
// src/trace/wrappers/mastra.ts
|
|
1608
1507
|
function wrapMastraAgent(agent, sessionCtx) {
|
|
1609
1508
|
const originalGenerate = agent.generate.bind(agent);
|
|
1610
|
-
const agentName = agent.name || "MastraAgent";
|
|
1611
1509
|
const ctx = sessionCtx;
|
|
1612
1510
|
agent.generate = async function(...args) {
|
|
1613
1511
|
if (!isInitialized()) {
|
|
1614
1512
|
return originalGenerate(...args);
|
|
1615
1513
|
}
|
|
1616
|
-
const
|
|
1514
|
+
const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
|
|
1515
|
+
const traceId = traceCtx?.traceId || generateHexId(32);
|
|
1617
1516
|
const spanId = generateHexId(16);
|
|
1517
|
+
const parentSpanId = traceCtx?.parentSpanId;
|
|
1518
|
+
const input = args[0];
|
|
1618
1519
|
const startTime = Date.now();
|
|
1619
|
-
const
|
|
1520
|
+
const captureContent2 = shouldCaptureContent();
|
|
1620
1521
|
try {
|
|
1621
1522
|
const result = await originalGenerate(...args);
|
|
1622
1523
|
const endTime = Date.now();
|
|
1623
|
-
const model = result?.model?.modelId || "unknown";
|
|
1624
|
-
const toolCalls = [];
|
|
1625
|
-
if (result?.steps?.length) {
|
|
1626
|
-
for (const step of result.steps) {
|
|
1627
|
-
if (step.toolCalls?.length) {
|
|
1628
|
-
for (let i = 0; i < step.toolCalls.length; i++) {
|
|
1629
|
-
const tc = step.toolCalls[i];
|
|
1630
|
-
const tr = step.toolResults?.[i];
|
|
1631
|
-
toolCalls.push({
|
|
1632
|
-
name: tc.toolName,
|
|
1633
|
-
arguments: tc.args,
|
|
1634
|
-
result: tr?.result
|
|
1635
|
-
});
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
1524
|
const attributes = {
|
|
1641
|
-
"
|
|
1642
|
-
"
|
|
1643
|
-
"
|
|
1644
|
-
"fallom.source": "mastra-agent",
|
|
1645
|
-
"llm.request.type": "chat"
|
|
1525
|
+
"fallom.sdk_version": "2",
|
|
1526
|
+
"fallom.method": "agent.generate",
|
|
1527
|
+
"fallom.agent_name": agent.name || "unknown"
|
|
1646
1528
|
};
|
|
1647
|
-
if (
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
attributes[`gen_ai.prompt.${i}.content`] = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
1651
|
-
});
|
|
1652
|
-
}
|
|
1653
|
-
if (result?.text) {
|
|
1654
|
-
attributes["gen_ai.completion.0.role"] = "assistant";
|
|
1655
|
-
attributes["gen_ai.completion.0.content"] = result.text;
|
|
1656
|
-
attributes["gen_ai.completion.0.finish_reason"] = "stop";
|
|
1657
|
-
}
|
|
1658
|
-
if (toolCalls.length > 0) {
|
|
1659
|
-
attributes["fallom.tool_calls"] = JSON.stringify(toolCalls);
|
|
1660
|
-
toolCalls.forEach((tc, i) => {
|
|
1661
|
-
attributes[`gen_ai.completion.0.tool_calls.${i}.name`] = tc.name;
|
|
1662
|
-
attributes[`gen_ai.completion.0.tool_calls.${i}.type`] = "function";
|
|
1663
|
-
attributes[`gen_ai.completion.0.tool_calls.${i}.arguments`] = JSON.stringify(tc.arguments);
|
|
1664
|
-
});
|
|
1665
|
-
}
|
|
1666
|
-
if (result?.usage) {
|
|
1667
|
-
attributes["gen_ai.usage.prompt_tokens"] = result.usage.promptTokens;
|
|
1668
|
-
attributes["gen_ai.usage.completion_tokens"] = result.usage.completionTokens;
|
|
1669
|
-
attributes["llm.usage.total_tokens"] = result.usage.totalTokens;
|
|
1529
|
+
if (captureContent2) {
|
|
1530
|
+
attributes["fallom.raw.request"] = JSON.stringify(input);
|
|
1531
|
+
attributes["fallom.raw.response"] = JSON.stringify(result);
|
|
1670
1532
|
}
|
|
1671
|
-
|
|
1533
|
+
sendTrace({
|
|
1672
1534
|
config_key: ctx.configKey,
|
|
1673
1535
|
session_id: ctx.sessionId,
|
|
1674
1536
|
customer_id: ctx.customerId,
|
|
1675
1537
|
trace_id: traceId,
|
|
1676
1538
|
span_id: spanId,
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1539
|
+
parent_span_id: parentSpanId,
|
|
1540
|
+
name: `agent.${agent.name || "unknown"}.generate`,
|
|
1541
|
+
kind: "agent",
|
|
1680
1542
|
start_time: new Date(startTime).toISOString(),
|
|
1681
1543
|
end_time: new Date(endTime).toISOString(),
|
|
1682
1544
|
duration_ms: endTime - startTime,
|
|
1683
1545
|
status: "OK",
|
|
1684
|
-
prompt_tokens: result?.usage?.promptTokens,
|
|
1685
|
-
completion_tokens: result?.usage?.completionTokens,
|
|
1686
|
-
total_tokens: result?.usage?.totalTokens,
|
|
1687
1546
|
attributes
|
|
1688
|
-
}
|
|
1689
|
-
sendTrace(traceData).catch(() => {
|
|
1547
|
+
}).catch(() => {
|
|
1690
1548
|
});
|
|
1691
1549
|
return result;
|
|
1692
1550
|
} catch (error) {
|
|
1693
1551
|
const endTime = Date.now();
|
|
1694
|
-
|
|
1552
|
+
sendTrace({
|
|
1695
1553
|
config_key: ctx.configKey,
|
|
1696
1554
|
session_id: ctx.sessionId,
|
|
1697
1555
|
customer_id: ctx.customerId,
|
|
1698
1556
|
trace_id: traceId,
|
|
1699
1557
|
span_id: spanId,
|
|
1700
|
-
|
|
1701
|
-
|
|
1558
|
+
parent_span_id: parentSpanId,
|
|
1559
|
+
name: `agent.${agent.name || "unknown"}.generate`,
|
|
1560
|
+
kind: "agent",
|
|
1702
1561
|
start_time: new Date(startTime).toISOString(),
|
|
1703
1562
|
end_time: new Date(endTime).toISOString(),
|
|
1704
1563
|
duration_ms: endTime - startTime,
|
|
1705
1564
|
status: "ERROR",
|
|
1706
|
-
error_message: error
|
|
1707
|
-
|
|
1708
|
-
|
|
1565
|
+
error_message: error?.message,
|
|
1566
|
+
attributes: {
|
|
1567
|
+
"fallom.sdk_version": "2",
|
|
1568
|
+
"fallom.method": "agent.generate",
|
|
1569
|
+
"fallom.agent_name": agent.name || "unknown"
|
|
1570
|
+
}
|
|
1571
|
+
}).catch(() => {
|
|
1709
1572
|
});
|
|
1710
1573
|
throw error;
|
|
1711
1574
|
}
|
|
@@ -1745,6 +1608,9 @@ var FallomSession = class {
|
|
|
1745
1608
|
/**
|
|
1746
1609
|
* Wrap a Vercel AI SDK model to trace all calls (PostHog style).
|
|
1747
1610
|
* Returns the same model type with tracing injected.
|
|
1611
|
+
*
|
|
1612
|
+
* Note: This only captures tokens/timing, not prompt/completion content.
|
|
1613
|
+
* Use wrapAISDK for full content tracing.
|
|
1748
1614
|
*/
|
|
1749
1615
|
traceModel(model) {
|
|
1750
1616
|
const ctx = this.ctx;
|
|
@@ -1770,17 +1636,18 @@ var FallomSession = class {
|
|
|
1770
1636
|
trace_id: traceId,
|
|
1771
1637
|
span_id: spanId,
|
|
1772
1638
|
parent_span_id: traceCtx?.parentSpanId,
|
|
1773
|
-
name: "
|
|
1639
|
+
name: "doGenerate",
|
|
1774
1640
|
kind: "llm",
|
|
1775
1641
|
model: modelId,
|
|
1776
1642
|
start_time: new Date(startTime).toISOString(),
|
|
1777
1643
|
end_time: new Date(endTime).toISOString(),
|
|
1778
1644
|
duration_ms: endTime - startTime,
|
|
1779
1645
|
status: "OK",
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1646
|
+
attributes: {
|
|
1647
|
+
"fallom.sdk_version": "2",
|
|
1648
|
+
"fallom.method": "traceModel.doGenerate",
|
|
1649
|
+
...usage ? { "fallom.raw.usage": JSON.stringify(usage) } : {}
|
|
1650
|
+
}
|
|
1784
1651
|
}).catch(() => {
|
|
1785
1652
|
});
|
|
1786
1653
|
return result;
|
|
@@ -1793,14 +1660,15 @@ var FallomSession = class {
|
|
|
1793
1660
|
trace_id: traceId,
|
|
1794
1661
|
span_id: spanId,
|
|
1795
1662
|
parent_span_id: traceCtx?.parentSpanId,
|
|
1796
|
-
name: "
|
|
1663
|
+
name: "doGenerate",
|
|
1797
1664
|
kind: "llm",
|
|
1798
1665
|
model: model.modelId || "unknown",
|
|
1799
1666
|
start_time: new Date(startTime).toISOString(),
|
|
1800
1667
|
end_time: new Date(endTime).toISOString(),
|
|
1801
1668
|
duration_ms: endTime - startTime,
|
|
1802
1669
|
status: "ERROR",
|
|
1803
|
-
error_message: error instanceof Error ? error.message : String(error)
|
|
1670
|
+
error_message: error instanceof Error ? error.message : String(error),
|
|
1671
|
+
attributes: { "fallom.sdk_version": "2", "fallom.method": "traceModel.doGenerate" }
|
|
1804
1672
|
}).catch(() => {
|
|
1805
1673
|
});
|
|
1806
1674
|
throw error;
|
|
@@ -1825,14 +1693,19 @@ var FallomSession = class {
|
|
|
1825
1693
|
trace_id: traceId,
|
|
1826
1694
|
span_id: spanId,
|
|
1827
1695
|
parent_span_id: traceCtx?.parentSpanId,
|
|
1828
|
-
name: "
|
|
1696
|
+
name: "doStream",
|
|
1829
1697
|
kind: "llm",
|
|
1830
1698
|
model: modelId,
|
|
1831
1699
|
start_time: new Date(startTime).toISOString(),
|
|
1832
1700
|
end_time: new Date(Date.now()).toISOString(),
|
|
1833
1701
|
duration_ms: Date.now() - startTime,
|
|
1834
1702
|
status: "OK",
|
|
1835
|
-
is_streaming: true
|
|
1703
|
+
is_streaming: true,
|
|
1704
|
+
attributes: {
|
|
1705
|
+
"fallom.sdk_version": "2",
|
|
1706
|
+
"fallom.method": "traceModel.doStream",
|
|
1707
|
+
"fallom.is_streaming": true
|
|
1708
|
+
}
|
|
1836
1709
|
}).catch(() => {
|
|
1837
1710
|
});
|
|
1838
1711
|
return result;
|
|
@@ -1844,7 +1717,7 @@ var FallomSession = class {
|
|
|
1844
1717
|
trace_id: traceId,
|
|
1845
1718
|
span_id: spanId,
|
|
1846
1719
|
parent_span_id: traceCtx?.parentSpanId,
|
|
1847
|
-
name: "
|
|
1720
|
+
name: "doStream",
|
|
1848
1721
|
kind: "llm",
|
|
1849
1722
|
model: modelId,
|
|
1850
1723
|
start_time: new Date(startTime).toISOString(),
|
|
@@ -1852,7 +1725,12 @@ var FallomSession = class {
|
|
|
1852
1725
|
duration_ms: Date.now() - startTime,
|
|
1853
1726
|
status: "ERROR",
|
|
1854
1727
|
error_message: error instanceof Error ? error.message : String(error),
|
|
1855
|
-
is_streaming: true
|
|
1728
|
+
is_streaming: true,
|
|
1729
|
+
attributes: {
|
|
1730
|
+
"fallom.sdk_version": "2",
|
|
1731
|
+
"fallom.method": "traceModel.doStream",
|
|
1732
|
+
"fallom.is_streaming": true
|
|
1733
|
+
}
|
|
1856
1734
|
}).catch(() => {
|
|
1857
1735
|
});
|
|
1858
1736
|
throw error;
|
|
@@ -1905,7 +1783,7 @@ var promptCache = /* @__PURE__ */ new Map();
|
|
|
1905
1783
|
var promptABCache = /* @__PURE__ */ new Map();
|
|
1906
1784
|
var promptContext = null;
|
|
1907
1785
|
var SYNC_TIMEOUT = 2e3;
|
|
1908
|
-
function
|
|
1786
|
+
function log3(msg) {
|
|
1909
1787
|
if (debugMode2) {
|
|
1910
1788
|
console.log(`[Fallom Prompts] ${msg}`);
|
|
1911
1789
|
}
|
|
@@ -2008,10 +1886,10 @@ async function get(promptKey, options = {}) {
|
|
|
2008
1886
|
const { variables, version, debug = false } = options;
|
|
2009
1887
|
debugMode2 = debug;
|
|
2010
1888
|
ensureInit();
|
|
2011
|
-
|
|
1889
|
+
log3(`get() called: promptKey=${promptKey}`);
|
|
2012
1890
|
let promptData = promptCache.get(promptKey);
|
|
2013
1891
|
if (!promptData) {
|
|
2014
|
-
|
|
1892
|
+
log3("Not in cache, fetching...");
|
|
2015
1893
|
await fetchPrompts(SYNC_TIMEOUT);
|
|
2016
1894
|
promptData = promptCache.get(promptKey);
|
|
2017
1895
|
}
|
|
@@ -2033,7 +1911,7 @@ async function get(promptKey, options = {}) {
|
|
|
2033
1911
|
promptKey,
|
|
2034
1912
|
promptVersion: targetVersion
|
|
2035
1913
|
});
|
|
2036
|
-
|
|
1914
|
+
log3(`\u2705 Got prompt: ${promptKey} v${targetVersion}`);
|
|
2037
1915
|
return {
|
|
2038
1916
|
key: promptKey,
|
|
2039
1917
|
version: targetVersion,
|
|
@@ -2045,10 +1923,10 @@ async function getAB(abTestKey, sessionId, options = {}) {
|
|
|
2045
1923
|
const { variables, debug = false } = options;
|
|
2046
1924
|
debugMode2 = debug;
|
|
2047
1925
|
ensureInit();
|
|
2048
|
-
|
|
1926
|
+
log3(`getAB() called: abTestKey=${abTestKey}, sessionId=${sessionId}`);
|
|
2049
1927
|
let abData = promptABCache.get(abTestKey);
|
|
2050
1928
|
if (!abData) {
|
|
2051
|
-
|
|
1929
|
+
log3("Not in cache, fetching...");
|
|
2052
1930
|
await fetchPromptABTests(SYNC_TIMEOUT);
|
|
2053
1931
|
abData = promptABCache.get(abTestKey);
|
|
2054
1932
|
}
|
|
@@ -2063,8 +1941,8 @@ async function getAB(abTestKey, sessionId, options = {}) {
|
|
|
2063
1941
|
throw new Error(`Prompt A/B test '${abTestKey}' has no current version.`);
|
|
2064
1942
|
}
|
|
2065
1943
|
const { variants } = versionData;
|
|
2066
|
-
|
|
2067
|
-
|
|
1944
|
+
log3(`A/B test '${abTestKey}' has ${variants?.length ?? 0} variants`);
|
|
1945
|
+
log3(`Version data: ${JSON.stringify(versionData, null, 2)}`);
|
|
2068
1946
|
if (!variants || variants.length === 0) {
|
|
2069
1947
|
throw new Error(
|
|
2070
1948
|
`Prompt A/B test '${abTestKey}' has no variants configured.`
|
|
@@ -2110,7 +1988,7 @@ async function getAB(abTestKey, sessionId, options = {}) {
|
|
|
2110
1988
|
abTestKey,
|
|
2111
1989
|
variantIndex: selectedIndex
|
|
2112
1990
|
});
|
|
2113
|
-
|
|
1991
|
+
log3(
|
|
2114
1992
|
`\u2705 Got prompt from A/B: ${promptKey} v${targetVersion} (variant ${selectedIndex})`
|
|
2115
1993
|
);
|
|
2116
1994
|
return {
|