openlit 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/dist/config.d.ts +12 -4
- package/dist/config.js +7 -17
- package/dist/config.js.map +1 -1
- package/dist/evals/llm/anthropic.js +10 -6
- package/dist/evals/llm/anthropic.js.map +1 -1
- package/dist/evals/llm/openai.js +9 -5
- package/dist/evals/llm/openai.js.map +1 -1
- package/dist/features/__tests__/rule-engine.test.d.ts +1 -0
- package/dist/features/__tests__/rule-engine.test.js +146 -0
- package/dist/features/__tests__/rule-engine.test.js.map +1 -0
- package/dist/features/base.d.ts +2 -0
- package/dist/features/base.js +2 -0
- package/dist/features/base.js.map +1 -1
- package/dist/features/rule-engine.d.ts +6 -0
- package/dist/features/rule-engine.js +60 -0
- package/dist/features/rule-engine.js.map +1 -0
- package/dist/features/vault.js +1 -1
- package/dist/features/vault.js.map +1 -1
- package/dist/helpers.d.ts +93 -1
- package/dist/helpers.js +270 -8
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +95 -50
- package/dist/index.js.map +1 -1
- package/dist/instrumentation/__tests__/anthropic-wrapper.test.js +215 -27
- package/dist/instrumentation/__tests__/anthropic-wrapper.test.js.map +1 -1
- package/dist/instrumentation/__tests__/base-wrapper.test.js +19 -23
- package/dist/instrumentation/__tests__/base-wrapper.test.js.map +1 -1
- package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.d.ts +1 -0
- package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.js +422 -0
- package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.js.map +1 -0
- package/dist/instrumentation/__tests__/chroma-trace-comparison.test.js +1 -1
- package/dist/instrumentation/__tests__/chroma-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/cohere-wrapper.test.js +150 -25
- package/dist/instrumentation/__tests__/cohere-wrapper.test.js.map +1 -1
- package/dist/instrumentation/__tests__/google-ai-trace-comparison.test.js +152 -33
- package/dist/instrumentation/__tests__/google-ai-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/groq-trace-comparison.test.js +391 -45
- package/dist/instrumentation/__tests__/groq-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.d.ts +2 -2
- package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.js +323 -31
- package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/langchain-wrapper.test.d.ts +1 -0
- package/dist/instrumentation/__tests__/langchain-wrapper.test.js +282 -0
- package/dist/instrumentation/__tests__/langchain-wrapper.test.js.map +1 -0
- package/dist/instrumentation/__tests__/milvus-trace-comparison.test.js +1 -1
- package/dist/instrumentation/__tests__/milvus-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/mistral-trace-comparison.test.d.ts +0 -3
- package/dist/instrumentation/__tests__/mistral-trace-comparison.test.js +275 -68
- package/dist/instrumentation/__tests__/mistral-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/openai-wrapper.test.js +7 -9
- package/dist/instrumentation/__tests__/openai-wrapper.test.js.map +1 -1
- package/dist/instrumentation/__tests__/qdrant-trace-comparison.test.js +1 -1
- package/dist/instrumentation/__tests__/qdrant-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/replicate-trace-comparison.test.d.ts +2 -1
- package/dist/instrumentation/__tests__/replicate-trace-comparison.test.js +209 -21
- package/dist/instrumentation/__tests__/replicate-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/together-trace-comparison.test.js +231 -51
- package/dist/instrumentation/__tests__/together-trace-comparison.test.js.map +1 -1
- package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.d.ts +8 -0
- package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.js +446 -0
- package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.js.map +1 -0
- package/dist/instrumentation/anthropic/index.d.ts +2 -3
- package/dist/instrumentation/anthropic/index.js.map +1 -1
- package/dist/instrumentation/anthropic/wrapper.d.ts +1 -3
- package/dist/instrumentation/anthropic/wrapper.js +211 -91
- package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
- package/dist/instrumentation/azure-ai-inference/index.d.ts +11 -0
- package/dist/instrumentation/azure-ai-inference/index.js +76 -0
- package/dist/instrumentation/azure-ai-inference/index.js.map +1 -0
- package/dist/instrumentation/azure-ai-inference/wrapper.d.ts +42 -0
- package/dist/instrumentation/azure-ai-inference/wrapper.js +515 -0
- package/dist/instrumentation/azure-ai-inference/wrapper.js.map +1 -0
- package/dist/instrumentation/base-wrapper.d.ts +2 -1
- package/dist/instrumentation/base-wrapper.js +35 -23
- package/dist/instrumentation/base-wrapper.js.map +1 -1
- package/dist/instrumentation/bedrock/wrapper.d.ts +21 -3
- package/dist/instrumentation/bedrock/wrapper.js +318 -265
- package/dist/instrumentation/bedrock/wrapper.js.map +1 -1
- package/dist/instrumentation/chroma/wrapper.js +1 -1
- package/dist/instrumentation/chroma/wrapper.js.map +1 -1
- package/dist/instrumentation/claude-agent-sdk/index.d.ts +23 -0
- package/dist/instrumentation/claude-agent-sdk/index.js +83 -0
- package/dist/instrumentation/claude-agent-sdk/index.js.map +1 -0
- package/dist/instrumentation/claude-agent-sdk/wrapper.d.ts +13 -0
- package/dist/instrumentation/claude-agent-sdk/wrapper.js +1031 -0
- package/dist/instrumentation/claude-agent-sdk/wrapper.js.map +1 -0
- package/dist/instrumentation/cohere/index.d.ts +2 -3
- package/dist/instrumentation/cohere/index.js.map +1 -1
- package/dist/instrumentation/cohere/wrapper.d.ts +1 -1
- package/dist/instrumentation/cohere/wrapper.js +215 -56
- package/dist/instrumentation/cohere/wrapper.js.map +1 -1
- package/dist/instrumentation/google-adk/index.d.ts +57 -0
- package/dist/instrumentation/google-adk/index.js +371 -0
- package/dist/instrumentation/google-adk/index.js.map +1 -0
- package/dist/instrumentation/google-adk/utils.d.ts +45 -0
- package/dist/instrumentation/google-adk/utils.js +663 -0
- package/dist/instrumentation/google-adk/utils.js.map +1 -0
- package/dist/instrumentation/google-adk/wrapper.d.ts +11 -0
- package/dist/instrumentation/google-adk/wrapper.js +391 -0
- package/dist/instrumentation/google-adk/wrapper.js.map +1 -0
- package/dist/instrumentation/google-ai/wrapper.d.ts +7 -4
- package/dist/instrumentation/google-ai/wrapper.js +197 -61
- package/dist/instrumentation/google-ai/wrapper.js.map +1 -1
- package/dist/instrumentation/groq/wrapper.js +137 -65
- package/dist/instrumentation/groq/wrapper.js.map +1 -1
- package/dist/instrumentation/huggingface/wrapper.js +241 -39
- package/dist/instrumentation/huggingface/wrapper.js.map +1 -1
- package/dist/instrumentation/index.d.ts +2 -2
- package/dist/instrumentation/index.js +64 -6
- package/dist/instrumentation/index.js.map +1 -1
- package/dist/instrumentation/langchain/index.d.ts +0 -7
- package/dist/instrumentation/langchain/index.js +2 -20
- package/dist/instrumentation/langchain/index.js.map +1 -1
- package/dist/instrumentation/langchain/wrapper.d.ts +35 -0
- package/dist/instrumentation/langchain/wrapper.js +1098 -184
- package/dist/instrumentation/langchain/wrapper.js.map +1 -1
- package/dist/instrumentation/langgraph/index.d.ts +12 -0
- package/dist/instrumentation/langgraph/index.js +99 -0
- package/dist/instrumentation/langgraph/index.js.map +1 -0
- package/dist/instrumentation/langgraph/wrapper.d.ts +20 -0
- package/dist/instrumentation/langgraph/wrapper.js +619 -0
- package/dist/instrumentation/langgraph/wrapper.js.map +1 -0
- package/dist/instrumentation/llamaindex/index.d.ts +31 -6
- package/dist/instrumentation/llamaindex/index.js +180 -61
- package/dist/instrumentation/llamaindex/index.js.map +1 -1
- package/dist/instrumentation/llamaindex/wrapper.d.ts +15 -3
- package/dist/instrumentation/llamaindex/wrapper.js +670 -179
- package/dist/instrumentation/llamaindex/wrapper.js.map +1 -1
- package/dist/instrumentation/milvus/wrapper.js +1 -1
- package/dist/instrumentation/milvus/wrapper.js.map +1 -1
- package/dist/instrumentation/mistral/wrapper.js +154 -79
- package/dist/instrumentation/mistral/wrapper.js.map +1 -1
- package/dist/instrumentation/ollama/index.js +33 -4
- package/dist/instrumentation/ollama/index.js.map +1 -1
- package/dist/instrumentation/ollama/wrapper.d.ts +28 -2
- package/dist/instrumentation/ollama/wrapper.js +432 -48
- package/dist/instrumentation/ollama/wrapper.js.map +1 -1
- package/dist/instrumentation/openai/index.d.ts +2 -3
- package/dist/instrumentation/openai/index.js.map +1 -1
- package/dist/instrumentation/openai/wrapper.js +293 -194
- package/dist/instrumentation/openai/wrapper.js.map +1 -1
- package/dist/instrumentation/openai-agents/index.d.ts +20 -0
- package/dist/instrumentation/openai-agents/index.js +174 -0
- package/dist/instrumentation/openai-agents/index.js.map +1 -0
- package/dist/instrumentation/openai-agents/processor.d.ts +35 -0
- package/dist/instrumentation/openai-agents/processor.js +249 -0
- package/dist/instrumentation/openai-agents/processor.js.map +1 -0
- package/dist/instrumentation/openai-agents/utils.d.ts +20 -0
- package/dist/instrumentation/openai-agents/utils.js +624 -0
- package/dist/instrumentation/openai-agents/utils.js.map +1 -0
- package/dist/instrumentation/pinecone/wrapper.js +2 -2
- package/dist/instrumentation/pinecone/wrapper.js.map +1 -1
- package/dist/instrumentation/qdrant/wrapper.js +1 -1
- package/dist/instrumentation/qdrant/wrapper.js.map +1 -1
- package/dist/instrumentation/replicate/wrapper.js +103 -21
- package/dist/instrumentation/replicate/wrapper.js.map +1 -1
- package/dist/instrumentation/strands/index.d.ts +21 -0
- package/dist/instrumentation/strands/index.js +83 -0
- package/dist/instrumentation/strands/index.js.map +1 -0
- package/dist/instrumentation/strands/processor.d.ts +45 -0
- package/dist/instrumentation/strands/processor.js +545 -0
- package/dist/instrumentation/strands/processor.js.map +1 -0
- package/dist/instrumentation/strands/utils.d.ts +24 -0
- package/dist/instrumentation/strands/utils.js +360 -0
- package/dist/instrumentation/strands/utils.js.map +1 -0
- package/dist/instrumentation/together/wrapper.js +125 -51
- package/dist/instrumentation/together/wrapper.js.map +1 -1
- package/dist/instrumentation/vercel-ai/wrapper.d.ts +28 -2
- package/dist/instrumentation/vercel-ai/wrapper.js +314 -164
- package/dist/instrumentation/vercel-ai/wrapper.js.map +1 -1
- package/dist/llm/anthropic.js +10 -6
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/openai.js +9 -5
- package/dist/llm/openai.js.map +1 -1
- package/dist/otel/__tests__/metrics.test.js +16 -27
- package/dist/otel/__tests__/metrics.test.js.map +1 -1
- package/dist/otel/events.d.ts +11 -0
- package/dist/otel/events.js +74 -0
- package/dist/otel/events.js.map +1 -0
- package/dist/otel/metrics.d.ts +5 -6
- package/dist/otel/metrics.js +66 -48
- package/dist/otel/metrics.js.map +1 -1
- package/dist/otel/tracing.d.ts +6 -2
- package/dist/otel/tracing.js +71 -24
- package/dist/otel/tracing.js.map +1 -1
- package/dist/otel/utils.d.ts +11 -0
- package/dist/otel/utils.js +34 -0
- package/dist/otel/utils.js.map +1 -0
- package/dist/semantic-convention.d.ts +44 -5
- package/dist/semantic-convention.js +51 -8
- package/dist/semantic-convention.js.map +1 -1
- package/dist/types.d.ts +74 -22
- package/package.json +41 -9
|
@@ -1,21 +1,71 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
const api_1 = require("@opentelemetry/api");
|
|
7
40
|
const config_1 = __importDefault(require("../../config"));
|
|
8
|
-
const helpers_1 =
|
|
41
|
+
const helpers_1 = __importStar(require("../../helpers"));
|
|
9
42
|
const semantic_convention_1 = __importDefault(require("../../semantic-convention"));
|
|
10
43
|
const base_wrapper_1 = __importDefault(require("../base-wrapper"));
|
|
44
|
+
function spanCreationAttrs(operationName, requestModel) {
|
|
45
|
+
return {
|
|
46
|
+
[semantic_convention_1.default.GEN_AI_OPERATION]: operationName,
|
|
47
|
+
[semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_OPENAI,
|
|
48
|
+
[semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
|
|
49
|
+
[semantic_convention_1.default.SERVER_ADDRESS]: OpenAIWrapper.serverAddress,
|
|
50
|
+
[semantic_convention_1.default.SERVER_PORT]: OpenAIWrapper.serverPort,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
11
53
|
class OpenAIWrapper extends base_wrapper_1.default {
|
|
12
54
|
static _patchChatCompletionCreate(tracer) {
|
|
13
55
|
const genAIEndpoint = 'openai.resources.chat.completions';
|
|
14
56
|
return (originalMethod) => {
|
|
15
57
|
return async function (...args) {
|
|
16
|
-
|
|
58
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
59
|
+
return originalMethod.apply(this, args);
|
|
60
|
+
const requestModel = args[0]?.model || 'gpt-4o';
|
|
61
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT} ${requestModel}`;
|
|
62
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
63
|
+
const span = tracer.startSpan(spanName, {
|
|
64
|
+
kind: api_1.SpanKind.CLIENT,
|
|
65
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT, requestModel),
|
|
66
|
+
}, effectiveCtx);
|
|
17
67
|
return api_1.context
|
|
18
|
-
.with(api_1.trace.setSpan(
|
|
68
|
+
.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
19
69
|
return originalMethod.apply(this, args);
|
|
20
70
|
})
|
|
21
71
|
.then((response) => {
|
|
@@ -32,7 +82,16 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
32
82
|
})
|
|
33
83
|
.catch((e) => {
|
|
34
84
|
helpers_1.default.handleException(span, e);
|
|
85
|
+
base_wrapper_1.default.recordMetrics(span, {
|
|
86
|
+
genAIEndpoint,
|
|
87
|
+
model: requestModel,
|
|
88
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
89
|
+
serverAddress: OpenAIWrapper.serverAddress,
|
|
90
|
+
serverPort: OpenAIWrapper.serverPort,
|
|
91
|
+
errorType: e?.constructor?.name || '_OTHER',
|
|
92
|
+
});
|
|
35
93
|
span.end();
|
|
94
|
+
throw e;
|
|
36
95
|
});
|
|
37
96
|
};
|
|
38
97
|
};
|
|
@@ -50,10 +109,10 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
50
109
|
}
|
|
51
110
|
catch (e) {
|
|
52
111
|
helpers_1.default.handleException(span, e);
|
|
112
|
+
throw e;
|
|
53
113
|
}
|
|
54
114
|
finally {
|
|
55
115
|
span.end();
|
|
56
|
-
// Record metrics after span has ended if parameters are available
|
|
57
116
|
if (metricParams) {
|
|
58
117
|
base_wrapper_1.default.recordMetrics(span, metricParams);
|
|
59
118
|
}
|
|
@@ -94,7 +153,7 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
94
153
|
},
|
|
95
154
|
},
|
|
96
155
|
};
|
|
97
|
-
|
|
156
|
+
const toolCalls = [];
|
|
98
157
|
for await (const chunk of response) {
|
|
99
158
|
timestamps.push(Date.now());
|
|
100
159
|
result.id = chunk.id;
|
|
@@ -115,12 +174,10 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
115
174
|
if (chunk.choices[0]?.delta.content) {
|
|
116
175
|
result.choices[0].message.content += chunk.choices[0].delta.content;
|
|
117
176
|
}
|
|
118
|
-
// Improved tool calls handling for streaming
|
|
119
177
|
if (chunk.choices[0]?.delta.tool_calls) {
|
|
120
178
|
const deltaTools = chunk.choices[0].delta.tool_calls;
|
|
121
179
|
for (const tool of deltaTools) {
|
|
122
180
|
const idx = tool.index || 0;
|
|
123
|
-
// Extend array if needed
|
|
124
181
|
while (toolCalls.length <= idx) {
|
|
125
182
|
toolCalls.push({
|
|
126
183
|
id: '',
|
|
@@ -129,7 +186,6 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
129
186
|
});
|
|
130
187
|
}
|
|
131
188
|
if (tool.id) {
|
|
132
|
-
// New tool call
|
|
133
189
|
toolCalls[idx].id = tool.id;
|
|
134
190
|
toolCalls[idx].type = tool.type || 'function';
|
|
135
191
|
if (tool.function?.name) {
|
|
@@ -140,7 +196,6 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
140
196
|
}
|
|
141
197
|
}
|
|
142
198
|
else if (tool.function?.arguments) {
|
|
143
|
-
// Append arguments to existing tool call
|
|
144
199
|
toolCalls[idx].function.arguments += tool.function.arguments;
|
|
145
200
|
}
|
|
146
201
|
}
|
|
@@ -169,7 +224,6 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
169
224
|
};
|
|
170
225
|
}
|
|
171
226
|
args[0].tools = tools;
|
|
172
|
-
// Calculate TTFT and TBT
|
|
173
227
|
const ttft = timestamps.length > 0 ? (timestamps[0] - startTime) / 1000 : 0;
|
|
174
228
|
let tbt = 0;
|
|
175
229
|
if (timestamps.length > 1) {
|
|
@@ -188,107 +242,95 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
188
242
|
}
|
|
189
243
|
catch (e) {
|
|
190
244
|
helpers_1.default.handleException(span, e);
|
|
245
|
+
throw e;
|
|
191
246
|
}
|
|
192
247
|
finally {
|
|
193
248
|
span.end();
|
|
194
|
-
// Record metrics after span has ended if parameters are available
|
|
195
249
|
if (metricParams) {
|
|
196
250
|
base_wrapper_1.default.recordMetrics(span, metricParams);
|
|
197
251
|
}
|
|
198
252
|
}
|
|
199
253
|
}
|
|
200
254
|
static async _chatCompletionCommonSetter({ args, genAIEndpoint, result, span, ttft = 0, tbt = 0, }) {
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
255
|
+
const captureContent = config_1.default.captureMessageContent;
|
|
256
|
+
const requestModel = args[0]?.model || 'gpt-4o';
|
|
257
|
+
const { messages, frequency_penalty = 0, max_tokens = null, n = 1, presence_penalty = 0, seed = null, stop = null, temperature = 1, top_p, user, stream = false, tools: _tools, service_tier, } = args[0];
|
|
204
258
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TOP_P, top_p || 1);
|
|
205
|
-
|
|
259
|
+
if (max_tokens != null) {
|
|
260
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_MAX_TOKENS, max_tokens);
|
|
261
|
+
}
|
|
206
262
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TEMPERATURE, temperature);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
263
|
+
if (presence_penalty) {
|
|
264
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty);
|
|
265
|
+
}
|
|
266
|
+
if (frequency_penalty) {
|
|
267
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty);
|
|
268
|
+
}
|
|
269
|
+
if (seed != null) {
|
|
270
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_SEED, Number(seed));
|
|
271
|
+
}
|
|
210
272
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, stream);
|
|
211
273
|
if (stop) {
|
|
212
274
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_STOP_SEQUENCES, Array.isArray(stop) ? stop : [stop]);
|
|
213
275
|
}
|
|
214
|
-
if (
|
|
215
|
-
span.setAttribute(semantic_convention_1.default.
|
|
276
|
+
if (n && n !== 1) {
|
|
277
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_CHOICE_COUNT, n);
|
|
278
|
+
}
|
|
279
|
+
if (service_tier && service_tier !== 'auto') {
|
|
280
|
+
span.setAttribute(semantic_convention_1.default.OPENAI_REQUEST_SERVICE_TIER, service_tier);
|
|
216
281
|
}
|
|
217
|
-
if (
|
|
282
|
+
if (captureContent) {
|
|
218
283
|
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages(messages || []));
|
|
219
284
|
}
|
|
220
|
-
// Request Params attributes : End
|
|
221
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT);
|
|
222
285
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, result.id);
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
// Calculate cost of the operation
|
|
227
|
-
const cost = helpers_1.default.getChatModelCost(model, pricingInfo, result.usage.prompt_tokens, result.usage.completion_tokens);
|
|
286
|
+
const responseModel = result.model || requestModel;
|
|
287
|
+
const pricingInfo = config_1.default.pricingInfo || {};
|
|
288
|
+
const cost = helpers_1.default.getChatModelCost(requestModel, pricingInfo, result.usage.prompt_tokens, result.usage.completion_tokens);
|
|
228
289
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
229
290
|
genAIEndpoint,
|
|
230
|
-
model,
|
|
291
|
+
model: requestModel,
|
|
231
292
|
user,
|
|
232
293
|
cost,
|
|
233
294
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
234
295
|
serverAddress: OpenAIWrapper.serverAddress,
|
|
235
296
|
serverPort: OpenAIWrapper.serverPort,
|
|
236
297
|
});
|
|
237
|
-
// Response model
|
|
238
298
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, responseModel);
|
|
239
|
-
|
|
299
|
+
span.setAttribute(semantic_convention_1.default.OPENAI_API_TYPE, 'chat_completions');
|
|
240
300
|
if (result.system_fingerprint) {
|
|
241
|
-
span.setAttribute(semantic_convention_1.default.
|
|
301
|
+
span.setAttribute(semantic_convention_1.default.OPENAI_RESPONSE_SYSTEM_FINGERPRINT, result.system_fingerprint);
|
|
242
302
|
}
|
|
243
303
|
if (result.service_tier) {
|
|
244
|
-
span.setAttribute(semantic_convention_1.default.
|
|
245
|
-
}
|
|
246
|
-
// Token usage
|
|
247
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, result.usage.prompt_tokens);
|
|
248
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, result.usage.completion_tokens);
|
|
249
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_TOTAL_TOKENS, result.usage.total_tokens);
|
|
250
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_TOKEN_USAGE, result.usage.total_tokens);
|
|
251
|
-
// Enhanced token details
|
|
252
|
-
if (result.usage.completion_tokens_details) {
|
|
253
|
-
if (result.usage.completion_tokens_details.reasoning_tokens) {
|
|
254
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_REASONING_TOKENS, result.usage.completion_tokens_details.reasoning_tokens);
|
|
255
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_COMPLETION_TOKENS_DETAILS_REASONING, result.usage.completion_tokens_details.reasoning_tokens);
|
|
256
|
-
}
|
|
257
|
-
if (result.usage.completion_tokens_details.audio_tokens) {
|
|
258
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_COMPLETION_TOKENS_DETAILS_AUDIO, result.usage.completion_tokens_details.audio_tokens);
|
|
259
|
-
}
|
|
304
|
+
span.setAttribute(semantic_convention_1.default.OPENAI_RESPONSE_SERVICE_TIER, result.service_tier);
|
|
260
305
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
306
|
+
const inputTokens = result.usage.prompt_tokens;
|
|
307
|
+
const outputTokens = result.usage.completion_tokens;
|
|
308
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
|
|
309
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
|
|
310
|
+
if (result.usage.prompt_tokens_details?.cached_tokens) {
|
|
311
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, result.usage.prompt_tokens_details.cached_tokens);
|
|
312
|
+
}
|
|
313
|
+
if (result.usage.prompt_tokens_details?.cache_creation_tokens) {
|
|
314
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, result.usage.prompt_tokens_details.cache_creation_tokens);
|
|
268
315
|
}
|
|
269
|
-
// TTFT and TBT metrics
|
|
270
316
|
if (ttft > 0) {
|
|
271
317
|
span.setAttribute(semantic_convention_1.default.GEN_AI_SERVER_TTFT, ttft);
|
|
272
318
|
}
|
|
273
319
|
if (tbt > 0) {
|
|
274
320
|
span.setAttribute(semantic_convention_1.default.GEN_AI_SERVER_TBT, tbt);
|
|
275
321
|
}
|
|
276
|
-
// Finish reason
|
|
277
322
|
if (result.choices[0].finish_reason) {
|
|
278
323
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, [result.choices[0].finish_reason]);
|
|
279
324
|
}
|
|
280
|
-
// Output type
|
|
281
325
|
const outputType = typeof result.choices[0].message.content === 'string'
|
|
282
326
|
? semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_TEXT
|
|
283
327
|
: semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_JSON;
|
|
284
328
|
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_TYPE, outputType);
|
|
285
|
-
// Tool calls handling
|
|
286
329
|
if (result.choices[0].message.tool_calls) {
|
|
287
330
|
const toolCalls = result.choices[0].message.tool_calls;
|
|
288
331
|
const toolNames = toolCalls.map((t) => t.function?.name || '').filter(Boolean);
|
|
289
332
|
const toolIds = toolCalls.map((t) => t.id || '').filter(Boolean);
|
|
290
333
|
const toolArgs = toolCalls.map((t) => t.function?.arguments || '').filter(Boolean);
|
|
291
|
-
const toolTypes = toolCalls.map((t) => t.type || '').filter(Boolean);
|
|
292
334
|
if (toolNames.length > 0) {
|
|
293
335
|
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_NAME, toolNames.join(', '));
|
|
294
336
|
}
|
|
@@ -296,23 +338,41 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
296
338
|
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_CALL_ID, toolIds.join(', '));
|
|
297
339
|
}
|
|
298
340
|
if (toolArgs.length > 0) {
|
|
299
|
-
span.setAttribute(semantic_convention_1.default.
|
|
300
|
-
}
|
|
301
|
-
if (toolTypes.length > 0) {
|
|
302
|
-
const toolTypesStr = toolTypes.join(', ');
|
|
303
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_TYPE, toolTypesStr);
|
|
304
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_TYPE_OTEL, toolTypesStr);
|
|
341
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_ARGS, toolArgs.join(', '));
|
|
305
342
|
}
|
|
306
343
|
}
|
|
307
|
-
|
|
308
|
-
|
|
344
|
+
let inputMessagesJson;
|
|
345
|
+
let outputMessagesJson;
|
|
346
|
+
if (captureContent) {
|
|
309
347
|
const toolCalls = result.choices[0].message.tool_calls;
|
|
310
|
-
|
|
311
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES,
|
|
348
|
+
outputMessagesJson = helpers_1.default.buildOutputMessages(result.choices[0].message.content || '', result.choices[0].finish_reason || 'stop', toolCalls);
|
|
349
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, outputMessagesJson);
|
|
350
|
+
inputMessagesJson = helpers_1.default.buildInputMessages(messages || []);
|
|
351
|
+
}
|
|
352
|
+
if (!config_1.default.disableEvents) {
|
|
353
|
+
const eventAttrs = {
|
|
354
|
+
[semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
|
|
355
|
+
[semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
|
|
356
|
+
[semantic_convention_1.default.GEN_AI_RESPONSE_MODEL]: responseModel,
|
|
357
|
+
[semantic_convention_1.default.SERVER_ADDRESS]: OpenAIWrapper.serverAddress,
|
|
358
|
+
[semantic_convention_1.default.SERVER_PORT]: OpenAIWrapper.serverPort,
|
|
359
|
+
[semantic_convention_1.default.GEN_AI_RESPONSE_ID]: result.id,
|
|
360
|
+
[semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON]: [result.choices[0].finish_reason],
|
|
361
|
+
[semantic_convention_1.default.GEN_AI_OUTPUT_TYPE]: outputType,
|
|
362
|
+
[semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS]: inputTokens,
|
|
363
|
+
[semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS]: outputTokens,
|
|
364
|
+
};
|
|
365
|
+
if (captureContent) {
|
|
366
|
+
if (inputMessagesJson)
|
|
367
|
+
eventAttrs[semantic_convention_1.default.GEN_AI_INPUT_MESSAGES] = inputMessagesJson;
|
|
368
|
+
if (outputMessagesJson)
|
|
369
|
+
eventAttrs[semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES] = outputMessagesJson;
|
|
370
|
+
}
|
|
371
|
+
helpers_1.default.emitInferenceEvent(span, eventAttrs);
|
|
312
372
|
}
|
|
313
373
|
return {
|
|
314
374
|
genAIEndpoint,
|
|
315
|
-
model,
|
|
375
|
+
model: requestModel,
|
|
316
376
|
user,
|
|
317
377
|
cost,
|
|
318
378
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
@@ -320,23 +380,29 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
320
380
|
}
|
|
321
381
|
static _patchEmbedding(tracer) {
|
|
322
382
|
const genAIEndpoint = 'openai.resources.embeddings';
|
|
323
|
-
const traceContent = config_1.default.traceContent;
|
|
324
383
|
return (originalMethod) => {
|
|
325
384
|
return async function (...args) {
|
|
326
|
-
|
|
327
|
-
|
|
385
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
386
|
+
return originalMethod.apply(this, args);
|
|
387
|
+
const requestModel = args[0]?.model || 'text-embedding-ada-002';
|
|
388
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_EMBEDDING} ${requestModel}`;
|
|
389
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
390
|
+
const span = tracer.startSpan(spanName, {
|
|
391
|
+
kind: api_1.SpanKind.CLIENT,
|
|
392
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_EMBEDDING, requestModel),
|
|
393
|
+
}, effectiveCtx);
|
|
394
|
+
return api_1.context.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
395
|
+
const captureContent = config_1.default.captureMessageContent;
|
|
328
396
|
let metricParams;
|
|
329
397
|
try {
|
|
330
398
|
const response = await originalMethod.apply(this, args);
|
|
331
|
-
const
|
|
332
|
-
const pricingInfo =
|
|
333
|
-
const cost = helpers_1.default.getEmbedModelCost(
|
|
334
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_EMBEDDING);
|
|
399
|
+
const _responseModel = response.model || requestModel;
|
|
400
|
+
const pricingInfo = config_1.default.pricingInfo || {};
|
|
401
|
+
const cost = helpers_1.default.getEmbedModelCost(requestModel, pricingInfo, response.usage.prompt_tokens);
|
|
335
402
|
const { dimensions, encoding_format = 'float', input, user } = args[0];
|
|
336
|
-
// Set base span attributes
|
|
337
403
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
338
404
|
genAIEndpoint,
|
|
339
|
-
model,
|
|
405
|
+
model: requestModel,
|
|
340
406
|
user,
|
|
341
407
|
cost,
|
|
342
408
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
@@ -344,25 +410,18 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
344
410
|
serverPort: OpenAIWrapper.serverPort,
|
|
345
411
|
});
|
|
346
412
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
|
|
347
|
-
// Request Params attributes : Start
|
|
348
413
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_ENCODING_FORMATS, [encoding_format]);
|
|
349
414
|
if (dimensions) {
|
|
350
|
-
span.setAttribute(semantic_convention_1.default.
|
|
415
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_EMBEDDINGS_DIMENSION_COUNT, dimensions);
|
|
351
416
|
}
|
|
352
|
-
if (
|
|
353
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_USER, user);
|
|
354
|
-
}
|
|
355
|
-
if (traceContent) {
|
|
417
|
+
if (captureContent) {
|
|
356
418
|
const formattedInput = typeof input === 'string' ? input : JSON.stringify(input);
|
|
357
419
|
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, formattedInput);
|
|
358
420
|
}
|
|
359
|
-
// Request Params attributes : End
|
|
360
421
|
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, response.usage.prompt_tokens);
|
|
361
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_TOTAL_TOKENS, response.usage.total_tokens);
|
|
362
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_TOKEN_USAGE, response.usage.prompt_tokens);
|
|
363
422
|
metricParams = {
|
|
364
423
|
genAIEndpoint,
|
|
365
|
-
model,
|
|
424
|
+
model: requestModel,
|
|
366
425
|
user,
|
|
367
426
|
cost,
|
|
368
427
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
@@ -387,38 +446,40 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
387
446
|
const genAIEndpoint = 'openai.resources.fine_tuning.jobs';
|
|
388
447
|
return (originalMethod) => {
|
|
389
448
|
return async function (...args) {
|
|
390
|
-
|
|
391
|
-
|
|
449
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
450
|
+
return originalMethod.apply(this, args);
|
|
451
|
+
const requestModel = args[0]?.model || 'gpt-3.5-turbo';
|
|
452
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FINETUNING} ${requestModel}`;
|
|
453
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
454
|
+
const span = tracer.startSpan(spanName, {
|
|
455
|
+
kind: api_1.SpanKind.CLIENT,
|
|
456
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FINETUNING, requestModel),
|
|
457
|
+
}, effectiveCtx);
|
|
458
|
+
return api_1.context.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
392
459
|
let metricParams;
|
|
393
460
|
try {
|
|
394
461
|
const response = await originalMethod.apply(this, args);
|
|
395
|
-
const model = response.model || 'gpt-3.5-turbo';
|
|
396
462
|
const { hyperparameters = {}, suffix = '', training_file, user, validation_file, } = args[0];
|
|
397
|
-
// Set base span attributes
|
|
398
463
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
399
464
|
genAIEndpoint,
|
|
400
|
-
model,
|
|
465
|
+
model: requestModel,
|
|
401
466
|
user,
|
|
402
467
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
403
468
|
serverAddress: OpenAIWrapper.serverAddress,
|
|
404
469
|
serverPort: OpenAIWrapper.serverPort,
|
|
405
470
|
});
|
|
406
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FINETUNING);
|
|
407
|
-
// Request Params attributes : Start
|
|
408
471
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TRAINING_FILE, training_file);
|
|
409
472
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_VALIDATION_FILE, validation_file);
|
|
410
473
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_FINETUNE_BATCH_SIZE, hyperparameters?.batch_size || 'auto');
|
|
411
474
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_FINETUNE_MODEL_LRM, hyperparameters?.learning_rate_multiplier || 'auto');
|
|
412
475
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_FINETUNE_MODEL_EPOCHS, hyperparameters?.n_epochs || 'auto');
|
|
413
476
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_FINETUNE_MODEL_SUFFIX, suffix);
|
|
414
|
-
// Request Params attributes : End
|
|
415
477
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, response.id);
|
|
416
478
|
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, response.usage.prompt_tokens);
|
|
417
479
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_FINETUNE_STATUS, response.status);
|
|
418
|
-
// Store metric parameters for use after span ends
|
|
419
480
|
metricParams = {
|
|
420
481
|
genAIEndpoint,
|
|
421
|
-
model,
|
|
482
|
+
model: requestModel,
|
|
422
483
|
user,
|
|
423
484
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
424
485
|
};
|
|
@@ -426,10 +487,10 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
426
487
|
}
|
|
427
488
|
catch (e) {
|
|
428
489
|
helpers_1.default.handleException(span, e);
|
|
490
|
+
throw e;
|
|
429
491
|
}
|
|
430
492
|
finally {
|
|
431
493
|
span.end();
|
|
432
|
-
// Record metrics after span has ended if parameters are available
|
|
433
494
|
if (metricParams) {
|
|
434
495
|
base_wrapper_1.default.recordMetrics(span, metricParams);
|
|
435
496
|
}
|
|
@@ -440,51 +501,56 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
440
501
|
}
|
|
441
502
|
static _patchImageGenerate(tracer) {
|
|
442
503
|
const genAIEndpoint = 'openai.resources.images';
|
|
443
|
-
const traceContent = config_1.default.traceContent;
|
|
444
504
|
return (originalMethod) => {
|
|
445
505
|
return async function (...args) {
|
|
446
|
-
|
|
447
|
-
|
|
506
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
507
|
+
return originalMethod.apply(this, args);
|
|
508
|
+
const requestModel = args[0]?.model || 'dall-e-2';
|
|
509
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_IMAGE} ${requestModel}`;
|
|
510
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
511
|
+
const span = tracer.startSpan(spanName, {
|
|
512
|
+
kind: api_1.SpanKind.CLIENT,
|
|
513
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_IMAGE, requestModel),
|
|
514
|
+
}, effectiveCtx);
|
|
515
|
+
return api_1.context.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
516
|
+
const captureContent = config_1.default.captureMessageContent;
|
|
448
517
|
let metricParams;
|
|
449
518
|
try {
|
|
450
519
|
const response = await originalMethod.apply(this, args);
|
|
451
520
|
const { prompt, quality = 'standard', response_format = 'url', size = '1024x1024', style = 'vivid', user, } = args[0];
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
const pricingInfo = await config_1.default.updatePricingJson(config_1.default.pricing_json);
|
|
455
|
-
// Calculate cost of the operation
|
|
521
|
+
const responseModel = response.model || requestModel;
|
|
522
|
+
const pricingInfo = config_1.default.pricingInfo || {};
|
|
456
523
|
const cost = (response.data?.length || 1) *
|
|
457
|
-
helpers_1.default.getImageModelCost(
|
|
524
|
+
helpers_1.default.getImageModelCost(responseModel, pricingInfo, size, quality);
|
|
458
525
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
459
526
|
genAIEndpoint,
|
|
460
|
-
model,
|
|
527
|
+
model: requestModel,
|
|
461
528
|
user,
|
|
462
529
|
cost,
|
|
463
530
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
464
531
|
serverAddress: OpenAIWrapper.serverAddress,
|
|
465
532
|
serverPort: OpenAIWrapper.serverPort,
|
|
466
533
|
});
|
|
467
|
-
// Request Params attributes : Start
|
|
468
534
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IMAGE_SIZE, size);
|
|
469
535
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IMAGE_QUALITY, quality);
|
|
470
536
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IMAGE_STYLE, style);
|
|
471
|
-
if (
|
|
537
|
+
if (captureContent) {
|
|
472
538
|
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, prompt);
|
|
473
539
|
}
|
|
474
|
-
// Request Params attributes : End
|
|
475
|
-
let imagesCount = 0;
|
|
476
540
|
if (response.data) {
|
|
541
|
+
const imageUrls = [];
|
|
542
|
+
const revisedPrompts = [];
|
|
477
543
|
for (const items of response.data) {
|
|
478
|
-
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
imagesCount++;
|
|
544
|
+
revisedPrompts.push(items.revised_prompt || '');
|
|
545
|
+
const value = items[response_format];
|
|
546
|
+
imageUrls.push(value && !String(value).startsWith('data:') ? value : '[base64_image_data]');
|
|
482
547
|
}
|
|
548
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_IMAGE, imageUrls);
|
|
549
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_CONTENT_REVISED_PROMPT, revisedPrompts);
|
|
483
550
|
}
|
|
484
|
-
// Store metric parameters for use after span ends
|
|
485
551
|
metricParams = {
|
|
486
552
|
genAIEndpoint,
|
|
487
|
-
model,
|
|
553
|
+
model: requestModel,
|
|
488
554
|
user,
|
|
489
555
|
cost,
|
|
490
556
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
@@ -493,10 +559,10 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
493
559
|
}
|
|
494
560
|
catch (e) {
|
|
495
561
|
helpers_1.default.handleException(span, e);
|
|
562
|
+
throw e;
|
|
496
563
|
}
|
|
497
564
|
finally {
|
|
498
565
|
span.end();
|
|
499
|
-
// Record metrics after span has ended if parameters are available
|
|
500
566
|
if (metricParams) {
|
|
501
567
|
base_wrapper_1.default.recordMetrics(span, metricParams);
|
|
502
568
|
}
|
|
@@ -507,52 +573,57 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
507
573
|
}
|
|
508
574
|
static _patchImageVariation(tracer) {
|
|
509
575
|
const genAIEndpoint = 'openai.resources.images';
|
|
510
|
-
const traceContent = config_1.default.traceContent;
|
|
511
576
|
return (originalMethod) => {
|
|
512
577
|
return async function (...args) {
|
|
513
|
-
|
|
514
|
-
|
|
578
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
579
|
+
return originalMethod.apply(this, args);
|
|
580
|
+
const requestModel = args[0]?.model || 'dall-e-2';
|
|
581
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_IMAGE} ${requestModel}`;
|
|
582
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
583
|
+
const span = tracer.startSpan(spanName, {
|
|
584
|
+
kind: api_1.SpanKind.CLIENT,
|
|
585
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_IMAGE, requestModel),
|
|
586
|
+
}, effectiveCtx);
|
|
587
|
+
return api_1.context.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
588
|
+
const captureContent = config_1.default.captureMessageContent;
|
|
515
589
|
let metricParams;
|
|
516
590
|
try {
|
|
517
591
|
const response = await originalMethod.apply(this, args);
|
|
518
592
|
const { prompt, quality = 'standard', response_format = 'url', size = '1024x1024', style = 'vivid', user, } = args[0];
|
|
519
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_IMAGE);
|
|
520
593
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, response.created);
|
|
521
|
-
const
|
|
522
|
-
const pricingInfo =
|
|
523
|
-
// Calculate cost of the operation
|
|
594
|
+
const responseModel = response.model || requestModel;
|
|
595
|
+
const pricingInfo = config_1.default.pricingInfo || {};
|
|
524
596
|
const cost = (response.data?.length || 1) *
|
|
525
|
-
helpers_1.default.getImageModelCost(
|
|
597
|
+
helpers_1.default.getImageModelCost(responseModel, pricingInfo, size, quality);
|
|
526
598
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
527
599
|
genAIEndpoint,
|
|
528
|
-
model,
|
|
600
|
+
model: requestModel,
|
|
529
601
|
user,
|
|
530
602
|
cost,
|
|
531
603
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
532
604
|
serverAddress: OpenAIWrapper.serverAddress,
|
|
533
605
|
serverPort: OpenAIWrapper.serverPort,
|
|
534
606
|
});
|
|
535
|
-
// Request Params attributes : Start
|
|
536
607
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IMAGE_SIZE, size);
|
|
537
608
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IMAGE_QUALITY, quality);
|
|
538
609
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IMAGE_STYLE, style);
|
|
539
|
-
if (
|
|
610
|
+
if (captureContent) {
|
|
540
611
|
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, prompt);
|
|
541
612
|
}
|
|
542
|
-
// Request Params attributes : End
|
|
543
|
-
let imagesCount = 0;
|
|
544
613
|
if (response.data) {
|
|
614
|
+
const imageUrls = [];
|
|
615
|
+
const revisedPrompts = [];
|
|
545
616
|
for (const items of response.data) {
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
imagesCount++;
|
|
617
|
+
revisedPrompts.push(items.revised_prompt || '');
|
|
618
|
+
const value = items[response_format];
|
|
619
|
+
imageUrls.push(value && !String(value).startsWith('data:') ? value : '[base64_image_data]');
|
|
550
620
|
}
|
|
621
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_IMAGE, imageUrls);
|
|
622
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_CONTENT_REVISED_PROMPT, revisedPrompts);
|
|
551
623
|
}
|
|
552
|
-
// Store metric parameters for use after span ends
|
|
553
624
|
metricParams = {
|
|
554
625
|
genAIEndpoint,
|
|
555
|
-
model,
|
|
626
|
+
model: requestModel,
|
|
556
627
|
user,
|
|
557
628
|
cost,
|
|
558
629
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
@@ -561,10 +632,10 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
561
632
|
}
|
|
562
633
|
catch (e) {
|
|
563
634
|
helpers_1.default.handleException(span, e);
|
|
635
|
+
throw e;
|
|
564
636
|
}
|
|
565
637
|
finally {
|
|
566
638
|
span.end();
|
|
567
|
-
// Record metrics after span has ended if parameters are available
|
|
568
639
|
if (metricParams) {
|
|
569
640
|
base_wrapper_1.default.recordMetrics(span, metricParams);
|
|
570
641
|
}
|
|
@@ -575,41 +646,44 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
575
646
|
}
|
|
576
647
|
static _patchAudioCreate(tracer) {
|
|
577
648
|
const genAIEndpoint = 'openai.resources.audio.speech';
|
|
578
|
-
const traceContent = config_1.default.traceContent;
|
|
579
649
|
return (originalMethod) => {
|
|
580
650
|
return async function (...args) {
|
|
581
|
-
|
|
582
|
-
|
|
651
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
652
|
+
return originalMethod.apply(this, args);
|
|
653
|
+
const requestModel = args[0]?.model || 'tts-1';
|
|
654
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AUDIO} ${requestModel}`;
|
|
655
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
656
|
+
const span = tracer.startSpan(spanName, {
|
|
657
|
+
kind: api_1.SpanKind.CLIENT,
|
|
658
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AUDIO, requestModel),
|
|
659
|
+
}, effectiveCtx);
|
|
660
|
+
return api_1.context.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
661
|
+
const captureContent = config_1.default.captureMessageContent;
|
|
583
662
|
let metricParams;
|
|
584
663
|
try {
|
|
585
664
|
const response = await originalMethod.apply(this, args);
|
|
586
665
|
const { input, user, voice, response_format = 'mp3', speed = 1 } = args[0];
|
|
587
|
-
|
|
588
|
-
const
|
|
589
|
-
const
|
|
590
|
-
// Calculate cost of the operation
|
|
591
|
-
const cost = helpers_1.default.getAudioModelCost(model, pricingInfo, input);
|
|
666
|
+
const responseModel = response.model || requestModel;
|
|
667
|
+
const pricingInfo = config_1.default.pricingInfo || {};
|
|
668
|
+
const cost = helpers_1.default.getAudioModelCost(responseModel, pricingInfo, input);
|
|
592
669
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
593
670
|
genAIEndpoint,
|
|
594
|
-
model,
|
|
671
|
+
model: requestModel,
|
|
595
672
|
user,
|
|
596
673
|
cost,
|
|
597
674
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
598
675
|
serverAddress: OpenAIWrapper.serverAddress,
|
|
599
676
|
serverPort: OpenAIWrapper.serverPort,
|
|
600
677
|
});
|
|
601
|
-
// Request Params attributes : Start
|
|
602
678
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_AUDIO_VOICE, voice);
|
|
603
679
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_AUDIO_RESPONSE_FORMAT, response_format);
|
|
604
680
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_AUDIO_SPEED, speed);
|
|
605
|
-
if (
|
|
681
|
+
if (captureContent) {
|
|
606
682
|
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, input);
|
|
607
683
|
}
|
|
608
|
-
// Request Params attributes : End
|
|
609
|
-
// Store metric parameters for use after span ends
|
|
610
684
|
metricParams = {
|
|
611
685
|
genAIEndpoint,
|
|
612
|
-
model,
|
|
686
|
+
model: requestModel,
|
|
613
687
|
user,
|
|
614
688
|
cost,
|
|
615
689
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
@@ -618,10 +692,10 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
618
692
|
}
|
|
619
693
|
catch (e) {
|
|
620
694
|
helpers_1.default.handleException(span, e);
|
|
695
|
+
throw e;
|
|
621
696
|
}
|
|
622
697
|
finally {
|
|
623
698
|
span.end();
|
|
624
|
-
// Record metrics after span has ended if parameters are available
|
|
625
699
|
if (metricParams) {
|
|
626
700
|
base_wrapper_1.default.recordMetrics(span, metricParams);
|
|
627
701
|
}
|
|
@@ -634,9 +708,17 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
634
708
|
const genAIEndpoint = 'openai.resources.responses';
|
|
635
709
|
return (originalMethod) => {
|
|
636
710
|
return async function (...args) {
|
|
637
|
-
|
|
711
|
+
if ((0, helpers_1.isFrameworkLlmActive)())
|
|
712
|
+
return originalMethod.apply(this, args);
|
|
713
|
+
const requestModel = args[0]?.model || 'gpt-4o';
|
|
714
|
+
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT} ${requestModel}`;
|
|
715
|
+
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
|
|
716
|
+
const span = tracer.startSpan(spanName, {
|
|
717
|
+
kind: api_1.SpanKind.CLIENT,
|
|
718
|
+
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT, requestModel),
|
|
719
|
+
}, effectiveCtx);
|
|
638
720
|
return api_1.context
|
|
639
|
-
.with(api_1.trace.setSpan(
|
|
721
|
+
.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
|
|
640
722
|
return originalMethod.apply(this, args);
|
|
641
723
|
})
|
|
642
724
|
.then((response) => {
|
|
@@ -653,7 +735,16 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
653
735
|
})
|
|
654
736
|
.catch((e) => {
|
|
655
737
|
helpers_1.default.handleException(span, e);
|
|
738
|
+
base_wrapper_1.default.recordMetrics(span, {
|
|
739
|
+
genAIEndpoint,
|
|
740
|
+
model: requestModel,
|
|
741
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
742
|
+
serverAddress: OpenAIWrapper.serverAddress,
|
|
743
|
+
serverPort: OpenAIWrapper.serverPort,
|
|
744
|
+
errorType: e?.constructor?.name || '_OTHER',
|
|
745
|
+
});
|
|
656
746
|
span.end();
|
|
747
|
+
throw e;
|
|
657
748
|
});
|
|
658
749
|
};
|
|
659
750
|
};
|
|
@@ -671,6 +762,7 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
671
762
|
}
|
|
672
763
|
catch (e) {
|
|
673
764
|
helpers_1.default.handleException(span, e);
|
|
765
|
+
throw e;
|
|
674
766
|
}
|
|
675
767
|
finally {
|
|
676
768
|
span.end();
|
|
@@ -684,7 +776,6 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
684
776
|
const timestamps = [];
|
|
685
777
|
const startTime = Date.now();
|
|
686
778
|
try {
|
|
687
|
-
const { input } = args[0];
|
|
688
779
|
const result = {
|
|
689
780
|
id: '',
|
|
690
781
|
model: '',
|
|
@@ -700,7 +791,7 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
700
791
|
},
|
|
701
792
|
};
|
|
702
793
|
let llmResponse = '';
|
|
703
|
-
|
|
794
|
+
const responseTools = [];
|
|
704
795
|
for await (const chunk of response) {
|
|
705
796
|
timestamps.push(Date.now());
|
|
706
797
|
if (chunk.type === 'response.output_text.delta') {
|
|
@@ -740,7 +831,6 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
740
831
|
}
|
|
741
832
|
yield chunk;
|
|
742
833
|
}
|
|
743
|
-
// Construct output array
|
|
744
834
|
if (llmResponse) {
|
|
745
835
|
result.output.push({
|
|
746
836
|
type: 'message',
|
|
@@ -750,7 +840,6 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
750
840
|
if (responseTools.length > 0) {
|
|
751
841
|
result.output.push(...responseTools);
|
|
752
842
|
}
|
|
753
|
-
// Calculate TTFT and TBT
|
|
754
843
|
const ttft = timestamps.length > 0 ? (timestamps[0] - startTime) / 1000 : 0;
|
|
755
844
|
let tbt = 0;
|
|
756
845
|
if (timestamps.length > 1) {
|
|
@@ -769,6 +858,7 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
769
858
|
}
|
|
770
859
|
catch (e) {
|
|
771
860
|
helpers_1.default.handleException(span, e);
|
|
861
|
+
throw e;
|
|
772
862
|
}
|
|
773
863
|
finally {
|
|
774
864
|
span.end();
|
|
@@ -778,65 +868,57 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
778
868
|
}
|
|
779
869
|
}
|
|
780
870
|
static async _responsesCommonSetter({ args, genAIEndpoint, result, span, ttft = 0, tbt = 0, }) {
|
|
781
|
-
const
|
|
871
|
+
const captureContent = config_1.default.captureMessageContent;
|
|
872
|
+
const requestModel = args[0]?.model || 'gpt-4o';
|
|
782
873
|
const { input, temperature = 1.0, top_p = 1.0, max_output_tokens, reasoning, stream = false, } = args[0];
|
|
783
|
-
// Normalize Responses API input to messages array for buildInputMessages
|
|
784
874
|
const responsesMessages = typeof input === 'string'
|
|
785
875
|
? [{ role: 'user', content: input }]
|
|
786
876
|
: (Array.isArray(input) ? input : []);
|
|
787
|
-
// Request Params attributes
|
|
788
877
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TEMPERATURE, temperature);
|
|
789
878
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TOP_P, top_p);
|
|
790
|
-
|
|
879
|
+
if (max_output_tokens != null) {
|
|
880
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_MAX_TOKENS, max_output_tokens);
|
|
881
|
+
}
|
|
791
882
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, stream);
|
|
792
883
|
if (reasoning?.effort) {
|
|
793
884
|
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_REASONING_EFFORT, reasoning.effort);
|
|
794
885
|
}
|
|
795
|
-
if (
|
|
886
|
+
if (captureContent) {
|
|
796
887
|
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages(responsesMessages));
|
|
797
888
|
}
|
|
798
|
-
|
|
799
|
-
const
|
|
800
|
-
const responseModel = result.model || model;
|
|
801
|
-
const pricingInfo = await config_1.default.updatePricingJson(config_1.default.pricing_json);
|
|
802
|
-
// Calculate cost
|
|
889
|
+
const responseModel = result.model || requestModel;
|
|
890
|
+
const pricingInfo = config_1.default.pricingInfo || {};
|
|
803
891
|
const inputTokens = result.usage?.input_tokens || 0;
|
|
804
892
|
const outputTokens = result.usage?.output_tokens || 0;
|
|
805
|
-
const cost = helpers_1.default.getChatModelCost(
|
|
893
|
+
const cost = helpers_1.default.getChatModelCost(requestModel, pricingInfo, inputTokens, outputTokens);
|
|
806
894
|
OpenAIWrapper.setBaseSpanAttributes(span, {
|
|
807
895
|
genAIEndpoint,
|
|
808
|
-
model,
|
|
896
|
+
model: requestModel,
|
|
809
897
|
user: '',
|
|
810
898
|
cost,
|
|
811
899
|
aiSystem: OpenAIWrapper.aiSystem,
|
|
812
900
|
serverAddress: OpenAIWrapper.serverAddress,
|
|
813
901
|
serverPort: OpenAIWrapper.serverPort,
|
|
814
902
|
});
|
|
815
|
-
// Response attributes
|
|
816
903
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, result.id);
|
|
817
904
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, responseModel);
|
|
818
905
|
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, [result.status || 'completed']);
|
|
819
906
|
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_TYPE, semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_TEXT);
|
|
907
|
+
span.setAttribute(semantic_convention_1.default.OPENAI_API_TYPE, 'responses');
|
|
820
908
|
if (result.service_tier) {
|
|
821
|
-
span.setAttribute(semantic_convention_1.default.
|
|
909
|
+
span.setAttribute(semantic_convention_1.default.OPENAI_RESPONSE_SERVICE_TIER, result.service_tier);
|
|
822
910
|
}
|
|
823
|
-
// Token usage
|
|
824
911
|
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
|
|
825
912
|
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
|
|
826
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_TOTAL_TOKENS, inputTokens + outputTokens);
|
|
827
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_TOKEN_USAGE, inputTokens + outputTokens);
|
|
828
|
-
// Reasoning tokens
|
|
829
913
|
if (result.usage?.output_tokens_details?.reasoning_tokens) {
|
|
830
914
|
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_REASONING_TOKENS, result.usage.output_tokens_details.reasoning_tokens);
|
|
831
915
|
}
|
|
832
|
-
// TTFT and TBT metrics
|
|
833
916
|
if (ttft > 0) {
|
|
834
917
|
span.setAttribute(semantic_convention_1.default.GEN_AI_SERVER_TTFT, ttft);
|
|
835
918
|
}
|
|
836
919
|
if (tbt > 0) {
|
|
837
920
|
span.setAttribute(semantic_convention_1.default.GEN_AI_SERVER_TBT, tbt);
|
|
838
921
|
}
|
|
839
|
-
// Extract completion text from output
|
|
840
922
|
let completionText = '';
|
|
841
923
|
if (result.output && Array.isArray(result.output)) {
|
|
842
924
|
for (const item of result.output) {
|
|
@@ -849,13 +931,11 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
849
931
|
}
|
|
850
932
|
}
|
|
851
933
|
}
|
|
852
|
-
// Tool calls handling for Responses API
|
|
853
934
|
const toolCalls = result.tools || [];
|
|
854
935
|
if (toolCalls.length > 0) {
|
|
855
936
|
const toolNames = toolCalls.map((t) => t.name || '').filter(Boolean);
|
|
856
937
|
const toolIds = toolCalls.map((t) => t.call_id || '').filter(Boolean);
|
|
857
938
|
const toolArgs = toolCalls.map((t) => t.arguments || '').filter(Boolean);
|
|
858
|
-
const toolTypes = toolCalls.map((t) => t.type || '').filter(Boolean);
|
|
859
939
|
if (toolNames.length > 0) {
|
|
860
940
|
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_NAME, toolNames.join(', '));
|
|
861
941
|
}
|
|
@@ -863,21 +943,40 @@ class OpenAIWrapper extends base_wrapper_1.default {
|
|
|
863
943
|
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_CALL_ID, toolIds.join(', '));
|
|
864
944
|
}
|
|
865
945
|
if (toolArgs.length > 0) {
|
|
866
|
-
span.setAttribute(semantic_convention_1.default.
|
|
867
|
-
}
|
|
868
|
-
if (toolTypes.length > 0) {
|
|
869
|
-
const toolTypesStr = toolTypes.join(', ');
|
|
870
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_TYPE, toolTypesStr);
|
|
871
|
-
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_TYPE_OTEL, toolTypesStr);
|
|
946
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_ARGS, toolArgs.join(', '));
|
|
872
947
|
}
|
|
873
948
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
949
|
+
let inputMessagesJson;
|
|
950
|
+
let outputMessagesJson;
|
|
951
|
+
if (captureContent) {
|
|
952
|
+
outputMessagesJson = helpers_1.default.buildOutputMessages(completionText, result.status || 'stop');
|
|
953
|
+
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, outputMessagesJson);
|
|
954
|
+
inputMessagesJson = helpers_1.default.buildInputMessages(responsesMessages);
|
|
955
|
+
}
|
|
956
|
+
if (!config_1.default.disableEvents) {
|
|
957
|
+
const eventAttrs = {
|
|
958
|
+
[semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
|
|
959
|
+
[semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
|
|
960
|
+
[semantic_convention_1.default.GEN_AI_RESPONSE_MODEL]: responseModel,
|
|
961
|
+
[semantic_convention_1.default.SERVER_ADDRESS]: OpenAIWrapper.serverAddress,
|
|
962
|
+
[semantic_convention_1.default.SERVER_PORT]: OpenAIWrapper.serverPort,
|
|
963
|
+
[semantic_convention_1.default.GEN_AI_RESPONSE_ID]: result.id,
|
|
964
|
+
[semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON]: [result.status || 'completed'],
|
|
965
|
+
[semantic_convention_1.default.GEN_AI_OUTPUT_TYPE]: semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_TEXT,
|
|
966
|
+
[semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS]: inputTokens,
|
|
967
|
+
[semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS]: outputTokens,
|
|
968
|
+
};
|
|
969
|
+
if (captureContent) {
|
|
970
|
+
if (inputMessagesJson)
|
|
971
|
+
eventAttrs[semantic_convention_1.default.GEN_AI_INPUT_MESSAGES] = inputMessagesJson;
|
|
972
|
+
if (outputMessagesJson)
|
|
973
|
+
eventAttrs[semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES] = outputMessagesJson;
|
|
974
|
+
}
|
|
975
|
+
helpers_1.default.emitInferenceEvent(span, eventAttrs);
|
|
877
976
|
}
|
|
878
977
|
return {
|
|
879
978
|
genAIEndpoint,
|
|
880
|
-
model,
|
|
979
|
+
model: requestModel,
|
|
881
980
|
user: '',
|
|
882
981
|
cost,
|
|
883
982
|
aiSystem: OpenAIWrapper.aiSystem,
|