@arizeai/openinference-instrumentation-openai 0.6.0 → 1.1.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/dist/esm/instrumentation.d.ts +19 -1
- package/dist/esm/instrumentation.d.ts.map +1 -1
- package/dist/esm/instrumentation.js +37 -16
- package/dist/esm/instrumentation.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esnext/instrumentation.d.ts +19 -1
- package/dist/esnext/instrumentation.d.ts.map +1 -1
- package/dist/esnext/instrumentation.js +35 -16
- package/dist/esnext/instrumentation.js.map +1 -1
- package/dist/esnext/tsconfig.esnext.tsbuildinfo +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/src/instrumentation.d.ts +19 -1
- package/dist/src/instrumentation.d.ts.map +1 -1
- package/dist/src/instrumentation.js +34 -15
- package/dist/src/instrumentation.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/test/openai.test.js +150 -5
- package/dist/test/openai.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/instrumentation.ts +75 -28
- package/src/version.ts +1 -1
package/src/instrumentation.ts
CHANGED
|
@@ -40,7 +40,11 @@ import {
|
|
|
40
40
|
import { assertUnreachable, isString } from "./typeUtils";
|
|
41
41
|
import { isTracingSuppressed } from "@opentelemetry/core";
|
|
42
42
|
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
OITracer,
|
|
45
|
+
safelyJSONStringify,
|
|
46
|
+
TraceConfigOptions,
|
|
47
|
+
} from "@arizeai/openinference-core";
|
|
44
48
|
|
|
45
49
|
const MODULE_NAME = "openai";
|
|
46
50
|
|
|
@@ -74,13 +78,34 @@ function getExecContext(span: Span) {
|
|
|
74
78
|
}
|
|
75
79
|
return execContext;
|
|
76
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* An auto instrumentation class for OpenAI that creates {@link https://github.com/Arize-ai/openinference/blob/main/spec/semantic_conventions.md|OpenInference} Compliant spans for the OpenAI API
|
|
83
|
+
* @param instrumentationConfig The config for the instrumentation @see {@link InstrumentationConfig}
|
|
84
|
+
* @param traceConfig The OpenInference trace configuration. Can be used to mask or redact sensitive information on spans. @see {@link TraceConfigOptions}
|
|
85
|
+
*/
|
|
77
86
|
export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
78
|
-
|
|
87
|
+
private oiTracer: OITracer;
|
|
88
|
+
constructor({
|
|
89
|
+
instrumentationConfig,
|
|
90
|
+
traceConfig,
|
|
91
|
+
}: {
|
|
92
|
+
/**
|
|
93
|
+
* The config for the instrumentation
|
|
94
|
+
* @see {@link InstrumentationConfig}
|
|
95
|
+
*/
|
|
96
|
+
instrumentationConfig?: InstrumentationConfig;
|
|
97
|
+
/**
|
|
98
|
+
* The OpenInference trace configuration. Can be used to mask or redact sensitive information on spans.
|
|
99
|
+
* @see {@link TraceConfigOptions}
|
|
100
|
+
*/
|
|
101
|
+
traceConfig?: TraceConfigOptions;
|
|
102
|
+
} = {}) {
|
|
79
103
|
super(
|
|
80
104
|
"@arizeai/openinference-instrumentation-openai",
|
|
81
105
|
VERSION,
|
|
82
|
-
Object.assign({},
|
|
106
|
+
Object.assign({}, instrumentationConfig),
|
|
83
107
|
);
|
|
108
|
+
this.oiTracer = new OITracer({ tracer: this.tracer, traceConfig });
|
|
84
109
|
}
|
|
85
110
|
|
|
86
111
|
protected init(): InstrumentationModuleDefinition<typeof openai> {
|
|
@@ -131,7 +156,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
|
131
156
|
) {
|
|
132
157
|
const body = args[0];
|
|
133
158
|
const { messages: _messages, ...invocationParameters } = body;
|
|
134
|
-
const span = instrumentation.
|
|
159
|
+
const span = instrumentation.oiTracer.startSpan(
|
|
135
160
|
`OpenAI Chat Completions`,
|
|
136
161
|
{
|
|
137
162
|
kind: SpanKind.INTERNAL,
|
|
@@ -150,13 +175,12 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
|
150
175
|
},
|
|
151
176
|
},
|
|
152
177
|
);
|
|
153
|
-
|
|
154
178
|
const execContext = getExecContext(span);
|
|
155
179
|
const execPromise = safeExecuteInTheMiddle<
|
|
156
180
|
ReturnType<ChatCompletionCreateType>
|
|
157
181
|
>(
|
|
158
182
|
() => {
|
|
159
|
-
return context.with(execContext, () => {
|
|
183
|
+
return context.with(trace.setSpan(execContext, span), () => {
|
|
160
184
|
return original.apply(this, args);
|
|
161
185
|
});
|
|
162
186
|
},
|
|
@@ -216,26 +240,29 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
|
216
240
|
) {
|
|
217
241
|
const body = args[0];
|
|
218
242
|
const { prompt: _prompt, ...invocationParameters } = body;
|
|
219
|
-
const span = instrumentation.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
243
|
+
const span = instrumentation.oiTracer.startSpan(
|
|
244
|
+
`OpenAI Completions`,
|
|
245
|
+
{
|
|
246
|
+
kind: SpanKind.INTERNAL,
|
|
247
|
+
attributes: {
|
|
248
|
+
[SemanticConventions.OPENINFERENCE_SPAN_KIND]:
|
|
249
|
+
OpenInferenceSpanKind.LLM,
|
|
250
|
+
[SemanticConventions.LLM_MODEL_NAME]: body.model,
|
|
251
|
+
[SemanticConventions.LLM_INVOCATION_PARAMETERS]:
|
|
252
|
+
JSON.stringify(invocationParameters),
|
|
253
|
+
[SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
|
|
254
|
+
[SemanticConventions.LLM_PROVIDER]: LLMProvider.OPENAI,
|
|
255
|
+
...getCompletionInputValueAndMimeType(body),
|
|
256
|
+
},
|
|
230
257
|
},
|
|
231
|
-
|
|
258
|
+
);
|
|
232
259
|
const execContext = getExecContext(span);
|
|
233
260
|
|
|
234
261
|
const execPromise = safeExecuteInTheMiddle<
|
|
235
262
|
ReturnType<CompletionsCreateType>
|
|
236
263
|
>(
|
|
237
264
|
() => {
|
|
238
|
-
return context.with(execContext, () => {
|
|
265
|
+
return context.with(trace.setSpan(execContext, span), () => {
|
|
239
266
|
return original.apply(this, args);
|
|
240
267
|
});
|
|
241
268
|
},
|
|
@@ -287,7 +314,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
|
287
314
|
const body = args[0];
|
|
288
315
|
const { input } = body;
|
|
289
316
|
const isStringInput = typeof input === "string";
|
|
290
|
-
const span = instrumentation.
|
|
317
|
+
const span = instrumentation.oiTracer.startSpan(`OpenAI Embeddings`, {
|
|
291
318
|
kind: SpanKind.INTERNAL,
|
|
292
319
|
attributes: {
|
|
293
320
|
[SemanticConventions.OPENINFERENCE_SPAN_KIND]:
|
|
@@ -307,7 +334,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
|
307
334
|
ReturnType<EmbeddingsCreateType>
|
|
308
335
|
>(
|
|
309
336
|
() => {
|
|
310
|
-
return context.with(execContext, () => {
|
|
337
|
+
return context.with(trace.setSpan(execContext, span), () => {
|
|
311
338
|
return original.apply(this, args);
|
|
312
339
|
});
|
|
313
340
|
},
|
|
@@ -345,7 +372,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
|
345
372
|
// This can fail if the module is made immutable via the runtime or bundler
|
|
346
373
|
module.openInferencePatched = true;
|
|
347
374
|
} catch (e) {
|
|
348
|
-
diag.
|
|
375
|
+
diag.debug(`Failed to set ${MODULE_NAME} patched flag on the module`, e);
|
|
349
376
|
}
|
|
350
377
|
|
|
351
378
|
return module;
|
|
@@ -475,15 +502,21 @@ function getChatCompletionInputMessageAttributes(
|
|
|
475
502
|
case "assistant":
|
|
476
503
|
if (message.tool_calls) {
|
|
477
504
|
message.tool_calls.forEach((toolCall, index) => {
|
|
505
|
+
const toolCallIndexPrefix = `${SemanticConventions.MESSAGE_TOOL_CALLS}.${index}.`;
|
|
506
|
+
|
|
507
|
+
// Add the tool call id if it exists
|
|
508
|
+
if (toolCall.id) {
|
|
509
|
+
attributes[
|
|
510
|
+
`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`
|
|
511
|
+
] = toolCall.id;
|
|
512
|
+
}
|
|
478
513
|
// Make sure the tool call has a function
|
|
479
514
|
if (toolCall.function) {
|
|
480
|
-
const toolCallIndexPrefix = `${SemanticConventions.MESSAGE_TOOL_CALLS}.${index}.`;
|
|
481
515
|
attributes[
|
|
482
|
-
toolCallIndexPrefix
|
|
516
|
+
`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_FUNCTION_NAME}`
|
|
483
517
|
] = toolCall.function.name;
|
|
484
518
|
attributes[
|
|
485
|
-
toolCallIndexPrefix
|
|
486
|
-
SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
|
|
519
|
+
`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON}`
|
|
487
520
|
] = toolCall.function.arguments;
|
|
488
521
|
}
|
|
489
522
|
});
|
|
@@ -493,8 +526,10 @@ function getChatCompletionInputMessageAttributes(
|
|
|
493
526
|
attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_NAME] = message.name;
|
|
494
527
|
break;
|
|
495
528
|
case "tool":
|
|
496
|
-
|
|
497
|
-
|
|
529
|
+
if (message.tool_call_id) {
|
|
530
|
+
attributes[`${SemanticConventions.MESSAGE_TOOL_CALL_ID}`] =
|
|
531
|
+
message.tool_call_id;
|
|
532
|
+
}
|
|
498
533
|
break;
|
|
499
534
|
case "system":
|
|
500
535
|
// There's nothing to add for the system. Content is captured above
|
|
@@ -585,6 +620,12 @@ function getChatCompletionOutputMessageAttributes(
|
|
|
585
620
|
if (message.tool_calls) {
|
|
586
621
|
message.tool_calls.forEach((toolCall, index) => {
|
|
587
622
|
const toolCallIndexPrefix = `${SemanticConventions.MESSAGE_TOOL_CALLS}.${index}.`;
|
|
623
|
+
// Add the tool call id if it exists
|
|
624
|
+
if (toolCall.id) {
|
|
625
|
+
attributes[
|
|
626
|
+
`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`
|
|
627
|
+
] = toolCall.id;
|
|
628
|
+
}
|
|
588
629
|
// Double check that the tool call has a function
|
|
589
630
|
// NB: OpenAI only supports tool calls with functions right now but this may change
|
|
590
631
|
if (toolCall.function) {
|
|
@@ -731,6 +772,12 @@ function getToolAndFunctionCallAttributesFromStreamChunk(
|
|
|
731
772
|
if (choice.delta.tool_calls) {
|
|
732
773
|
choice.delta.tool_calls.forEach((toolCall, index) => {
|
|
733
774
|
const toolCallIndexPrefix = `${SemanticConventions.MESSAGE_TOOL_CALLS}.${index}.`;
|
|
775
|
+
// Add the tool call id if it exists
|
|
776
|
+
if (toolCall.id) {
|
|
777
|
+
attributes[
|
|
778
|
+
`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`
|
|
779
|
+
] = toolCall.id;
|
|
780
|
+
}
|
|
734
781
|
// Double check that the tool call has a function
|
|
735
782
|
// NB: OpenAI only supports tool calls with functions right now but this may change
|
|
736
783
|
if (toolCall.function) {
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// this is an auto-generated file. see js/scripts/version-update.js
|
|
2
|
-
export const VERSION = "
|
|
2
|
+
export const VERSION = "1.1.0";
|