Skip to content

Commit 40c6ea4

Browse files
committed
missing files
1 parent 3ccdc9f commit 40c6ea4

File tree

2 files changed

+648
-0
lines changed

2 files changed

+648
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { ReadableSpan } from "@opentelemetry/sdk-trace-node";
2+
import { SpanAttributes } from "@traceloop/ai-semantic-conventions";
3+
4+
const AI_GENERATE_TEXT_DO_GENERATE = "ai.generateText.doGenerate";
5+
const AI_STREAM_TEXT_DO_STREAM = "ai.streamText.doStream";
6+
const AI_RESPONSE_TEXT = "ai.response.text";
7+
const AI_PROMPT_MESSAGES = "ai.prompt.messages";
8+
const AI_USAGE_PROMPT_TOKENS = "ai.usage.promptTokens";
9+
const AI_USAGE_COMPLETION_TOKENS = "ai.usage.completionTokens";
10+
const AI_MODEL_PROVIDER = "ai.model.provider";
11+
12+
export const transformAiSdkSpanName = (span: ReadableSpan): void => {
13+
const nameMap: Record<string, string> = {
14+
[AI_GENERATE_TEXT_DO_GENERATE]: "ai.generateText.generate",
15+
[AI_STREAM_TEXT_DO_STREAM]: "ai.streamText.stream",
16+
};
17+
18+
if (span.name in nameMap) {
19+
// Unfortunately, the span name is not writable as this is not the intended behavior
20+
// but it is a workaround to set the correct span name
21+
(span as any).name = nameMap[span.name];
22+
}
23+
};
24+
25+
export const transformResponseText = (attributes: Record<string, any>): void => {
26+
if (AI_RESPONSE_TEXT in attributes) {
27+
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`] =
28+
attributes[AI_RESPONSE_TEXT];
29+
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`] = "assistant";
30+
delete attributes[AI_RESPONSE_TEXT];
31+
}
32+
};
33+
34+
export const transformPromptMessages = (attributes: Record<string, any>): void => {
35+
if (AI_PROMPT_MESSAGES in attributes) {
36+
try {
37+
const messages = JSON.parse(attributes[AI_PROMPT_MESSAGES] as string);
38+
messages.forEach(
39+
(msg: { role: string; content: any }, index: number) => {
40+
attributes[`${SpanAttributes.LLM_PROMPTS}.${index}.content`] =
41+
typeof msg.content === "string"
42+
? msg.content
43+
: JSON.stringify(msg.content);
44+
attributes[`${SpanAttributes.LLM_PROMPTS}.${index}.role`] = msg.role;
45+
},
46+
);
47+
delete attributes[AI_PROMPT_MESSAGES];
48+
} catch {
49+
// Skip if JSON parsing fails
50+
}
51+
}
52+
};
53+
54+
export const transformPromptTokens = (attributes: Record<string, any>): void => {
55+
if (AI_USAGE_PROMPT_TOKENS in attributes) {
56+
attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`] =
57+
attributes[AI_USAGE_PROMPT_TOKENS];
58+
delete attributes[AI_USAGE_PROMPT_TOKENS];
59+
}
60+
};
61+
62+
export const transformCompletionTokens = (attributes: Record<string, any>): void => {
63+
if (AI_USAGE_COMPLETION_TOKENS in attributes) {
64+
attributes[`${SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`] =
65+
attributes[AI_USAGE_COMPLETION_TOKENS];
66+
delete attributes[AI_USAGE_COMPLETION_TOKENS];
67+
}
68+
};
69+
70+
export const calculateTotalTokens = (attributes: Record<string, any>): void => {
71+
const promptTokens = attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`];
72+
const completionTokens = attributes[`${SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`];
73+
74+
if (promptTokens && completionTokens) {
75+
attributes[`${SpanAttributes.LLM_USAGE_TOTAL_TOKENS}`] =
76+
Number(promptTokens) + Number(completionTokens);
77+
}
78+
};
79+
80+
export const transformVendor = (attributes: Record<string, any>): void => {
81+
if (AI_MODEL_PROVIDER in attributes) {
82+
const vendor = attributes[AI_MODEL_PROVIDER];
83+
if (vendor && vendor.startsWith("openai")) {
84+
attributes[SpanAttributes.LLM_SYSTEM] = "OpenAI";
85+
} else {
86+
attributes[SpanAttributes.LLM_SYSTEM] = vendor;
87+
}
88+
delete attributes[AI_MODEL_PROVIDER];
89+
}
90+
};
91+
92+
export const transformAiSdkAttributes = (attributes: Record<string, any>): void => {
93+
transformResponseText(attributes);
94+
transformPromptMessages(attributes);
95+
transformPromptTokens(attributes);
96+
transformCompletionTokens(attributes);
97+
calculateTotalTokens(attributes);
98+
transformVendor(attributes);
99+
};
100+
101+
export const transformAiSdkSpan = (span: ReadableSpan): void => {
102+
transformAiSdkSpanName(span);
103+
transformAiSdkAttributes(span.attributes);
104+
};

0 commit comments

Comments
 (0)