@arizeai/openinference-instrumentation-openai 4.0.5 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +1 -3
  2. package/dist/esm/instrumentation.d.ts +5 -4
  3. package/dist/esm/instrumentation.d.ts.map +1 -1
  4. package/dist/esm/instrumentation.js +23 -31
  5. package/dist/esm/instrumentation.js.map +1 -1
  6. package/dist/esm/responsesAttributes.d.ts +3 -3
  7. package/dist/esm/responsesAttributes.d.ts.map +1 -1
  8. package/dist/esm/responsesAttributes.js +30 -33
  9. package/dist/esm/responsesAttributes.js.map +1 -1
  10. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  11. package/dist/esm/version.d.ts +1 -1
  12. package/dist/esm/version.js +1 -1
  13. package/dist/esnext/instrumentation.d.ts +5 -4
  14. package/dist/esnext/instrumentation.d.ts.map +1 -1
  15. package/dist/esnext/instrumentation.js +21 -28
  16. package/dist/esnext/instrumentation.js.map +1 -1
  17. package/dist/esnext/responsesAttributes.d.ts +3 -3
  18. package/dist/esnext/responsesAttributes.d.ts.map +1 -1
  19. package/dist/esnext/responsesAttributes.js +30 -33
  20. package/dist/esnext/responsesAttributes.js.map +1 -1
  21. package/dist/esnext/tsconfig.esnext.tsbuildinfo +1 -1
  22. package/dist/esnext/version.d.ts +1 -1
  23. package/dist/esnext/version.js +1 -1
  24. package/dist/src/instrumentation.d.ts +5 -4
  25. package/dist/src/instrumentation.d.ts.map +1 -1
  26. package/dist/src/instrumentation.js +20 -27
  27. package/dist/src/instrumentation.js.map +1 -1
  28. package/dist/src/responsesAttributes.d.ts +3 -3
  29. package/dist/src/responsesAttributes.d.ts.map +1 -1
  30. package/dist/src/responsesAttributes.js +30 -33
  31. package/dist/src/responsesAttributes.js.map +1 -1
  32. package/dist/src/version.d.ts +1 -1
  33. package/dist/src/version.js +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +19 -19
  36. package/src/instrumentation.ts +126 -254
  37. package/src/responsesAttributes.ts +49 -90
  38. package/src/version.ts +1 -1
@@ -1,8 +1,35 @@
1
+ import type { Attributes, Span, Tracer, TracerProvider } from "@opentelemetry/api";
2
+ import { context, diag, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
3
+ import { isTracingSuppressed } from "@opentelemetry/core";
4
+ import type {
5
+ InstrumentationConfig,
6
+ InstrumentationModuleDefinition,
7
+ } from "@opentelemetry/instrumentation";
1
8
  import {
2
- OITracer,
3
- safelyJSONStringify,
4
- TraceConfigOptions,
5
- } from "@arizeai/openinference-core";
9
+ InstrumentationBase,
10
+ InstrumentationNodeModuleDefinition,
11
+ safeExecuteInTheMiddle,
12
+ } from "@opentelemetry/instrumentation";
13
+ import type openai from "openai";
14
+ import { APIPromise } from "openai";
15
+ import type { Completion, CreateEmbeddingResponse, EmbeddingCreateParams } from "openai/resources";
16
+ import type {
17
+ ChatCompletion,
18
+ ChatCompletionChunk,
19
+ ChatCompletionCreateParamsBase,
20
+ ChatCompletionMessage,
21
+ ChatCompletionMessageParam,
22
+ } from "openai/resources/chat/completions";
23
+ import type { CompletionCreateParamsBase } from "openai/resources/completions";
24
+ import type {
25
+ Response as ResponseType,
26
+ ResponseCreateParamsBase,
27
+ ResponseStreamEvent,
28
+ } from "openai/resources/responses/responses";
29
+ import type { Stream } from "openai/streaming";
30
+
31
+ import type { TraceConfigOptions } from "@arizeai/openinference-core";
32
+ import { OITracer, safelyJSONStringify } from "@arizeai/openinference-core";
6
33
  import {
7
34
  LLMProvider,
8
35
  LLMSystem,
@@ -11,26 +38,6 @@ import {
11
38
  SemanticConventions,
12
39
  } from "@arizeai/openinference-semantic-conventions";
13
40
 
14
- import {
15
- Attributes,
16
- context,
17
- diag,
18
- Span,
19
- SpanKind,
20
- SpanStatusCode,
21
- trace,
22
- Tracer,
23
- TracerProvider,
24
- } from "@opentelemetry/api";
25
- import { isTracingSuppressed } from "@opentelemetry/core";
26
- import {
27
- InstrumentationBase,
28
- InstrumentationConfig,
29
- InstrumentationModuleDefinition,
30
- InstrumentationNodeModuleDefinition,
31
- safeExecuteInTheMiddle,
32
- } from "@opentelemetry/instrumentation";
33
-
34
41
  import {
35
42
  consumeResponseStreamEvents,
36
43
  getResponsesInputMessagesAttributes,
@@ -40,27 +47,6 @@ import {
40
47
  import { assertUnreachable, isString } from "./typeUtils";
41
48
  import { VERSION } from "./version";
42
49
 
43
- import openai, { APIPromise } from "openai";
44
- import {
45
- Completion,
46
- CreateEmbeddingResponse,
47
- EmbeddingCreateParams,
48
- } from "openai/resources";
49
- import {
50
- ChatCompletion,
51
- ChatCompletionChunk,
52
- ChatCompletionCreateParamsBase,
53
- ChatCompletionMessage,
54
- ChatCompletionMessageParam,
55
- } from "openai/resources/chat/completions";
56
- import { CompletionCreateParamsBase } from "openai/resources/completions";
57
- import {
58
- Response as ResponseType,
59
- ResponseCreateParamsBase,
60
- ResponseStreamEvent,
61
- } from "openai/resources/responses/responses";
62
- import { Stream } from "openai/streaming";
63
-
64
50
  const MODULE_NAME = "openai";
65
51
 
66
52
  const INSTRUMENTATION_NAME = "@arizeai/openinference-instrumentation-openai";
@@ -86,9 +72,7 @@ export function isPatched() {
86
72
  function getExecContext(span: Span) {
87
73
  const activeContext = context.active();
88
74
  const suppressTracing = isTracingSuppressed(activeContext);
89
- const execContext = suppressTracing
90
- ? trace.setSpan(context.active(), span)
91
- : activeContext;
75
+ const execContext = suppressTracing ? trace.setSpan(context.active(), span) : activeContext;
92
76
  // Drop the span from the context
93
77
  if (suppressTracing) {
94
78
  trace.deleteSpan(activeContext);
@@ -190,17 +174,11 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
190
174
  */
191
175
  tracerProvider?: TracerProvider;
192
176
  } = {}) {
193
- super(
194
- INSTRUMENTATION_NAME,
195
- VERSION,
196
- Object.assign({}, instrumentationConfig),
197
- );
177
+ super(INSTRUMENTATION_NAME, VERSION, Object.assign({}, instrumentationConfig));
198
178
  this.tracerProvider = tracerProvider;
199
179
  this.traceConfig = traceConfig;
200
180
  this.oiTracer = new OITracer({
201
- tracer:
202
- this.tracerProvider?.getTracer(INSTRUMENTATION_NAME, VERSION) ??
203
- this.tracer,
181
+ tracer: this.tracerProvider?.getTracer(INSTRUMENTATION_NAME, VERSION) ?? this.tracer,
204
182
  traceConfig,
205
183
  });
206
184
  }
@@ -227,10 +205,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
227
205
 
228
206
  get tracer(): Tracer {
229
207
  if (this.tracerProvider) {
230
- return this.tracerProvider.getTracer(
231
- this.instrumentationName,
232
- this.instrumentationVersion,
233
- );
208
+ return this.tracerProvider.getTracer(this.instrumentationName, this.instrumentationVersion);
234
209
  }
235
210
  return super.tracer;
236
211
  }
@@ -259,8 +234,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
259
234
  const instrumentation: OpenAIInstrumentation = this;
260
235
 
261
236
  // Patch create chat completions
262
- type ChatCompletionCreateType =
263
- typeof module.OpenAI.Chat.Completions.prototype.create;
237
+ type ChatCompletionCreateType = typeof module.OpenAI.Chat.Completions.prototype.create;
264
238
 
265
239
  this._wrap(
266
240
  module.OpenAI.Chat.Completions.prototype,
@@ -273,25 +247,20 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
273
247
  ) {
274
248
  const body = args[0];
275
249
  const { messages: _messages, ...invocationParameters } = body;
276
- const span = instrumentation.oiTracer.startSpan(
277
- `OpenAI Chat Completions`,
278
- {
279
- kind: SpanKind.INTERNAL,
280
- attributes: {
281
- [SemanticConventions.OPENINFERENCE_SPAN_KIND]:
282
- OpenInferenceSpanKind.LLM,
283
- [SemanticConventions.LLM_MODEL_NAME]: body.model,
284
- [SemanticConventions.INPUT_VALUE]: JSON.stringify(body),
285
- [SemanticConventions.INPUT_MIME_TYPE]: MimeType.JSON,
286
- [SemanticConventions.LLM_INVOCATION_PARAMETERS]:
287
- JSON.stringify(invocationParameters),
288
- [SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
289
- [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
290
- ...getLLMInputMessagesAttributes(body),
291
- ...getLLMToolsJSONSchema(body),
292
- },
250
+ const span = instrumentation.oiTracer.startSpan(`OpenAI Chat Completions`, {
251
+ kind: SpanKind.INTERNAL,
252
+ attributes: {
253
+ [SemanticConventions.OPENINFERENCE_SPAN_KIND]: OpenInferenceSpanKind.LLM,
254
+ [SemanticConventions.LLM_MODEL_NAME]: body.model,
255
+ [SemanticConventions.INPUT_VALUE]: JSON.stringify(body),
256
+ [SemanticConventions.INPUT_MIME_TYPE]: MimeType.JSON,
257
+ [SemanticConventions.LLM_INVOCATION_PARAMETERS]: JSON.stringify(invocationParameters),
258
+ [SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
259
+ [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
260
+ ...getLLMInputMessagesAttributes(body),
261
+ ...getLLMToolsJSONSchema(body),
293
262
  },
294
- );
263
+ });
295
264
  const execContext = getExecContext(span);
296
265
  const execPromise = safeExecuteInTheMiddle(
297
266
  () => {
@@ -340,46 +309,34 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
340
309
 
341
310
  return result;
342
311
  };
343
- const wrappedPromise = invokeMaybeAPIPromise(
344
- execPromise,
345
- wrappedPromiseThen,
346
- );
312
+ const wrappedPromise = invokeMaybeAPIPromise(execPromise, wrappedPromiseThen);
347
313
  return context.bind(execContext, wrappedPromise);
348
314
  };
349
315
  },
350
316
  );
351
317
 
352
318
  // Patch create completions
353
- type CompletionsCreateType =
354
- typeof module.OpenAI.Completions.prototype.create;
319
+ type CompletionsCreateType = typeof module.OpenAI.Completions.prototype.create;
355
320
 
356
321
  this._wrap(
357
322
  module.OpenAI.Completions.prototype,
358
323
  "create",
359
324
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
360
325
  (original: CompletionsCreateType): any => {
361
- return function patchedCreate(
362
- this: unknown,
363
- ...args: Parameters<CompletionsCreateType>
364
- ) {
326
+ return function patchedCreate(this: unknown, ...args: Parameters<CompletionsCreateType>) {
365
327
  const body = args[0];
366
328
  const { prompt: _prompt, ...invocationParameters } = body;
367
- const span = instrumentation.oiTracer.startSpan(
368
- `OpenAI Completions`,
369
- {
370
- kind: SpanKind.INTERNAL,
371
- attributes: {
372
- [SemanticConventions.OPENINFERENCE_SPAN_KIND]:
373
- OpenInferenceSpanKind.LLM,
374
- [SemanticConventions.LLM_MODEL_NAME]: body.model,
375
- [SemanticConventions.LLM_INVOCATION_PARAMETERS]:
376
- JSON.stringify(invocationParameters),
377
- [SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
378
- [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
379
- ...getCompletionInputValueAndMimeType(body),
380
- },
329
+ const span = instrumentation.oiTracer.startSpan(`OpenAI Completions`, {
330
+ kind: SpanKind.INTERNAL,
331
+ attributes: {
332
+ [SemanticConventions.OPENINFERENCE_SPAN_KIND]: OpenInferenceSpanKind.LLM,
333
+ [SemanticConventions.LLM_MODEL_NAME]: body.model,
334
+ [SemanticConventions.LLM_INVOCATION_PARAMETERS]: JSON.stringify(invocationParameters),
335
+ [SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
336
+ [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
337
+ ...getCompletionInputValueAndMimeType(body),
381
338
  },
382
- );
339
+ });
383
340
  const execContext = getExecContext(span);
384
341
 
385
342
  const execPromise = safeExecuteInTheMiddle(
@@ -400,9 +357,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
400
357
  }
401
358
  },
402
359
  );
403
- const wrappedPromiseThen = (
404
- result: Completion | Stream<Completion>,
405
- ) => {
360
+ const wrappedPromiseThen = (result: Completion | Stream<Completion>) => {
406
361
  if (isCompletionResponse(result)) {
407
362
  // Record the results
408
363
  span.setAttributes({
@@ -418,18 +373,14 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
418
373
  }
419
374
  return result;
420
375
  };
421
- const wrappedPromise = invokeMaybeAPIPromise(
422
- execPromise,
423
- wrappedPromiseThen,
424
- );
376
+ const wrappedPromise = invokeMaybeAPIPromise(execPromise, wrappedPromiseThen);
425
377
  return context.bind(execContext, wrappedPromise);
426
378
  };
427
379
  },
428
380
  );
429
381
 
430
382
  // Patch embeddings
431
- type EmbeddingsCreateType =
432
- typeof module.OpenAI.Embeddings.prototype.create;
383
+ type EmbeddingsCreateType = typeof module.OpenAI.Embeddings.prototype.create;
433
384
  this._wrap(
434
385
  module.OpenAI.Embeddings.prototype,
435
386
  "create",
@@ -445,15 +396,10 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
445
396
  const span = instrumentation.oiTracer.startSpan(`OpenAI Embeddings`, {
446
397
  kind: SpanKind.INTERNAL,
447
398
  attributes: {
448
- [SemanticConventions.OPENINFERENCE_SPAN_KIND]:
449
- OpenInferenceSpanKind.EMBEDDING,
399
+ [SemanticConventions.OPENINFERENCE_SPAN_KIND]: OpenInferenceSpanKind.EMBEDDING,
450
400
  [SemanticConventions.EMBEDDING_MODEL_NAME]: body.model,
451
- [SemanticConventions.INPUT_VALUE]: isStringInput
452
- ? input
453
- : JSON.stringify(input),
454
- [SemanticConventions.INPUT_MIME_TYPE]: isStringInput
455
- ? MimeType.TEXT
456
- : MimeType.JSON,
401
+ [SemanticConventions.INPUT_VALUE]: isStringInput ? input : JSON.stringify(input),
402
+ [SemanticConventions.INPUT_MIME_TYPE]: isStringInput ? MimeType.TEXT : MimeType.JSON,
457
403
  [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
458
404
  ...getEmbeddingTextAttributes(body),
459
405
  },
@@ -489,10 +435,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
489
435
  span.end();
490
436
  return result;
491
437
  };
492
- const wrappedPromise = invokeMaybeAPIPromise(
493
- execPromise,
494
- wrappedPromiseThen,
495
- );
438
+ const wrappedPromise = invokeMaybeAPIPromise(execPromise, wrappedPromiseThen);
496
439
  return context.bind(execContext, wrappedPromise);
497
440
  };
498
441
  },
@@ -500,39 +443,31 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
500
443
 
501
444
  // Patch responses (if the patched module contains the Responses interface)
502
445
  if (module.OpenAI.Responses) {
503
- type ResponsesCreateType =
504
- typeof module.OpenAI.Responses.prototype.create;
446
+ type ResponsesCreateType = typeof module.OpenAI.Responses.prototype.create;
505
447
 
506
448
  this._wrap(
507
449
  module.OpenAI.Responses.prototype,
508
450
  "create",
509
451
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
510
452
  (original: ResponsesCreateType): any => {
511
- return function patchedCreate(
512
- this: unknown,
513
- ...args: Parameters<ResponsesCreateType>
514
- ) {
453
+ return function patchedCreate(this: unknown, ...args: Parameters<ResponsesCreateType>) {
515
454
  const body = args[0];
516
455
  const { input: _messages, ...invocationParameters } = body;
517
- const span = instrumentation.oiTracer.startSpan(
518
- `OpenAI Responses`,
519
- {
520
- kind: SpanKind.INTERNAL,
521
- attributes: {
522
- [SemanticConventions.OPENINFERENCE_SPAN_KIND]:
523
- OpenInferenceSpanKind.LLM,
524
- [SemanticConventions.LLM_MODEL_NAME]: body.model,
525
- [SemanticConventions.INPUT_VALUE]: JSON.stringify(body),
526
- [SemanticConventions.INPUT_MIME_TYPE]: MimeType.JSON,
527
- [SemanticConventions.LLM_INVOCATION_PARAMETERS]:
528
- JSON.stringify(invocationParameters),
529
- [SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
530
- [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
531
- ...getResponsesInputMessagesAttributes(body),
532
- ...getLLMToolsJSONSchema(body),
533
- },
456
+ const span = instrumentation.oiTracer.startSpan(`OpenAI Responses`, {
457
+ kind: SpanKind.INTERNAL,
458
+ attributes: {
459
+ [SemanticConventions.OPENINFERENCE_SPAN_KIND]: OpenInferenceSpanKind.LLM,
460
+ [SemanticConventions.LLM_MODEL_NAME]: body.model,
461
+ [SemanticConventions.INPUT_VALUE]: JSON.stringify(body),
462
+ [SemanticConventions.INPUT_MIME_TYPE]: MimeType.JSON,
463
+ [SemanticConventions.LLM_INVOCATION_PARAMETERS]:
464
+ JSON.stringify(invocationParameters),
465
+ [SemanticConventions.LLM_SYSTEM]: LLMSystem.OPENAI,
466
+ [SemanticConventions.LLM_PROVIDER]: getLLMProvider(this),
467
+ ...getResponsesInputMessagesAttributes(body),
468
+ ...getLLMToolsJSONSchema(body),
534
469
  },
535
- );
470
+ });
536
471
  const execContext = getExecContext(span);
537
472
  const execPromise = safeExecuteInTheMiddle(
538
473
  () => {
@@ -552,9 +487,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
552
487
  }
553
488
  },
554
489
  );
555
- const wrappedPromiseThen = (
556
- result: Stream<ResponseStreamEvent> | ResponseType,
557
- ) => {
490
+ const wrappedPromiseThen = (result: Stream<ResponseStreamEvent> | ResponseType) => {
558
491
  const recordSpan = (result?: ResponseType) => {
559
492
  if (!result) {
560
493
  span.setStatus({ code: SpanStatusCode.ERROR });
@@ -588,10 +521,7 @@ export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
588
521
 
589
522
  return result;
590
523
  };
591
- const wrappedPromise = invokeMaybeAPIPromise(
592
- execPromise,
593
- wrappedPromiseThen,
594
- );
524
+ const wrappedPromise = invokeMaybeAPIPromise(execPromise, wrappedPromiseThen);
595
525
  return context.bind(execContext, wrappedPromise);
596
526
  };
597
527
  },
@@ -648,9 +578,7 @@ function isChatCompletionResponse(
648
578
  /**
649
579
  * type-guard that checks if the response is a completion response
650
580
  */
651
- function isCompletionResponse(
652
- response: Stream<Completion> | Completion,
653
- ): response is Completion {
581
+ function isCompletionResponse(response: Stream<Completion> | Completion): response is Completion {
654
582
  return "choices" in response;
655
583
  }
656
584
 
@@ -660,17 +588,13 @@ function isCompletionResponse(
660
588
  function isPromptStringArray(
661
589
  prompt: CompletionCreateParamsBase["prompt"],
662
590
  ): prompt is Array<string> {
663
- return (
664
- Array.isArray(prompt) && prompt.every((item) => typeof item === "string")
665
- );
591
+ return Array.isArray(prompt) && prompt.every((item) => typeof item === "string");
666
592
  }
667
593
 
668
594
  /**
669
595
  * Converts the body of a chat completions request to LLM input messages
670
596
  */
671
- function getLLMInputMessagesAttributes(
672
- body: ChatCompletionCreateParamsBase,
673
- ): Attributes {
597
+ function getLLMInputMessagesAttributes(body: ChatCompletionCreateParamsBase): Attributes {
674
598
  return body.messages.reduce((acc, message, index) => {
675
599
  const messageAttributes = getChatCompletionInputMessageAttributes(message);
676
600
  const indexPrefix = `${SemanticConventions.LLM_INPUT_MESSAGES}.${index}.`;
@@ -702,9 +626,7 @@ function getLLMToolsJSONSchema(
702
626
  }, {});
703
627
  }
704
628
 
705
- function getChatCompletionInputMessageAttributes(
706
- message: ChatCompletionMessageParam,
707
- ): Attributes {
629
+ function getChatCompletionInputMessageAttributes(message: ChatCompletionMessageParam): Attributes {
708
630
  const role = message.role;
709
631
  const attributes: Attributes = {
710
632
  [SemanticConventions.MESSAGE_ROLE]: role,
@@ -716,16 +638,10 @@ function getChatCompletionInputMessageAttributes(
716
638
  message.content.forEach((part, index) => {
717
639
  const contentsIndexPrefix = `${SemanticConventions.MESSAGE_CONTENTS}.${index}.`;
718
640
  if (part.type === "text") {
719
- attributes[
720
- `${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_TYPE}`
721
- ] = "text";
722
- attributes[
723
- `${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_TEXT}`
724
- ] = part.text;
641
+ attributes[`${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_TYPE}`] = "text";
642
+ attributes[`${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_TEXT}`] = part.text;
725
643
  } else if (part.type === "image_url") {
726
- attributes[
727
- `${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_TYPE}`
728
- ] = "image";
644
+ attributes[`${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_TYPE}`] = "image";
729
645
  attributes[
730
646
  `${contentsIndexPrefix}${SemanticConventions.MESSAGE_CONTENT_IMAGE}.${SemanticConventions.IMAGE_URL}`
731
647
  ] = part.image_url.url;
@@ -743,15 +659,12 @@ function getChatCompletionInputMessageAttributes(
743
659
 
744
660
  // Add the tool call id if it exists
745
661
  if (toolCall.id) {
746
- attributes[
747
- `${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`
748
- ] = toolCall.id;
662
+ attributes[`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`] = toolCall.id;
749
663
  }
750
664
  // Make sure the tool call has a function
751
665
  if (toolCall.type === "function") {
752
- attributes[
753
- `${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_FUNCTION_NAME}`
754
- ] = toolCall.function.name;
666
+ attributes[`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_FUNCTION_NAME}`] =
667
+ toolCall.function.name;
755
668
  attributes[
756
669
  `${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON}`
757
670
  ] = toolCall.function.arguments;
@@ -767,8 +680,7 @@ function getChatCompletionInputMessageAttributes(
767
680
  break;
768
681
  case "tool":
769
682
  if (message.tool_call_id) {
770
- attributes[`${SemanticConventions.MESSAGE_TOOL_CALL_ID}`] =
771
- message.tool_call_id;
683
+ attributes[`${SemanticConventions.MESSAGE_TOOL_CALL_ID}`] = message.tool_call_id;
772
684
  }
773
685
  break;
774
686
  case "system":
@@ -787,9 +699,7 @@ function getChatCompletionInputMessageAttributes(
787
699
  /**
788
700
  * Converts the body of a completions request to input attributes
789
701
  */
790
- function getCompletionInputValueAndMimeType(
791
- body: CompletionCreateParamsBase,
792
- ): Attributes {
702
+ function getCompletionInputValueAndMimeType(body: CompletionCreateParamsBase): Attributes {
793
703
  if (typeof body.prompt === "string") {
794
704
  return {
795
705
  [SemanticConventions.INPUT_VALUE]: body.prompt,
@@ -812,17 +722,12 @@ function getCompletionInputValueAndMimeType(
812
722
  /**
813
723
  * Get usage attributes
814
724
  */
815
- function getUsageAttributes(
816
- completion: ChatCompletion | Completion,
817
- ): Attributes {
725
+ function getUsageAttributes(completion: ChatCompletion | Completion): Attributes {
818
726
  if (completion.usage) {
819
727
  const usageAttributes: Attributes = {
820
- [SemanticConventions.LLM_TOKEN_COUNT_COMPLETION]:
821
- completion.usage.completion_tokens,
822
- [SemanticConventions.LLM_TOKEN_COUNT_PROMPT]:
823
- completion.usage.prompt_tokens,
824
- [SemanticConventions.LLM_TOKEN_COUNT_TOTAL]:
825
- completion.usage.total_tokens,
728
+ [SemanticConventions.LLM_TOKEN_COUNT_COMPLETION]: completion.usage.completion_tokens,
729
+ [SemanticConventions.LLM_TOKEN_COUNT_PROMPT]: completion.usage.prompt_tokens,
730
+ [SemanticConventions.LLM_TOKEN_COUNT_TOTAL]: completion.usage.total_tokens,
826
731
  [SemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ]:
827
732
  completion.usage.prompt_tokens_details?.cached_tokens,
828
733
  [SemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO]:
@@ -840,9 +745,7 @@ function getUsageAttributes(
840
745
  /**
841
746
  * Converts the chat completion result to LLM output attributes
842
747
  */
843
- function getChatCompletionLLMOutputMessagesAttributes(
844
- chatCompletion: ChatCompletion,
845
- ): Attributes {
748
+ function getChatCompletionLLMOutputMessagesAttributes(chatCompletion: ChatCompletion): Attributes {
846
749
  // Right now support just the first choice
847
750
  const choice = chatCompletion.choices[0];
848
751
  if (!choice) {
@@ -859,9 +762,7 @@ function getChatCompletionLLMOutputMessagesAttributes(
859
762
  }, {} as Attributes);
860
763
  }
861
764
 
862
- function getChatCompletionOutputMessageAttributes(
863
- message: ChatCompletionMessage,
864
- ): Attributes {
765
+ function getChatCompletionOutputMessageAttributes(message: ChatCompletionMessage): Attributes {
865
766
  const role = message.role;
866
767
  const attributes: Attributes = {
867
768
  [SemanticConventions.MESSAGE_ROLE]: role,
@@ -874,18 +775,13 @@ function getChatCompletionOutputMessageAttributes(
874
775
  const toolCallIndexPrefix = `${SemanticConventions.MESSAGE_TOOL_CALLS}.${index}.`;
875
776
  // Add the tool call id if it exists
876
777
  if (toolCall.id) {
877
- attributes[
878
- `${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`
879
- ] = toolCall.id;
778
+ attributes[`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`] = toolCall.id;
880
779
  }
881
780
  if (toolCall.type === "function") {
882
- attributes[
883
- toolCallIndexPrefix + SemanticConventions.TOOL_CALL_FUNCTION_NAME
884
- ] = toolCall.function.name;
885
- attributes[
886
- toolCallIndexPrefix +
887
- SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
888
- ] = toolCall.function.arguments;
781
+ attributes[toolCallIndexPrefix + SemanticConventions.TOOL_CALL_FUNCTION_NAME] =
782
+ toolCall.function.name;
783
+ attributes[toolCallIndexPrefix + SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON] =
784
+ toolCall.function.arguments;
889
785
  } else {
890
786
  // TODO: switch to exhaustive checks
891
787
  diag.warn(`Unsupported tool type: ${toolCall.type}`);
@@ -893,8 +789,7 @@ function getChatCompletionOutputMessageAttributes(
893
789
  });
894
790
  }
895
791
  if (message.function_call) {
896
- attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_NAME] =
897
- message.function_call.name;
792
+ attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_NAME] = message.function_call.name;
898
793
  attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_ARGUMENTS_JSON] =
899
794
  message.function_call.arguments;
900
795
  }
@@ -904,9 +799,7 @@ function getChatCompletionOutputMessageAttributes(
904
799
  /**
905
800
  * Converts the completion result to output attributes
906
801
  */
907
- function getCompletionOutputValueAndMimeType(
908
- completion: Completion,
909
- ): Attributes {
802
+ function getCompletionOutputValueAndMimeType(completion: Completion): Attributes {
910
803
  // Right now support just the first choice
911
804
  const choice = completion.choices[0];
912
805
  if (!choice) {
@@ -921,9 +814,7 @@ function getCompletionOutputValueAndMimeType(
921
814
  /**
922
815
  * Converts the embedding result payload to embedding attributes
923
816
  */
924
- function getEmbeddingTextAttributes(
925
- request: EmbeddingCreateParams,
926
- ): Attributes {
817
+ function getEmbeddingTextAttributes(request: EmbeddingCreateParams): Attributes {
927
818
  if (typeof request.input === "string") {
928
819
  return {
929
820
  [`${SemanticConventions.EMBEDDING_EMBEDDINGS}.0.${SemanticConventions.EMBEDDING_TEXT}`]:
@@ -947,13 +838,10 @@ function getEmbeddingTextAttributes(
947
838
  /**
948
839
  * Converts the embedding result payload to embedding attributes
949
840
  */
950
- function getEmbeddingEmbeddingsAttributes(
951
- response: CreateEmbeddingResponse,
952
- ): Attributes {
841
+ function getEmbeddingEmbeddingsAttributes(response: CreateEmbeddingResponse): Attributes {
953
842
  return response.data.reduce((acc, embedding, index) => {
954
843
  const indexPrefix = `${SemanticConventions.EMBEDDING_EMBEDDINGS}.${index}.`;
955
- acc[`${indexPrefix}${SemanticConventions.EMBEDDING_VECTOR}`] =
956
- embedding.embedding;
844
+ acc[`${indexPrefix}${SemanticConventions.EMBEDDING_VECTOR}`] = embedding.embedding;
957
845
  return acc;
958
846
  }, {} as Attributes);
959
847
  }
@@ -961,10 +849,7 @@ function getEmbeddingEmbeddingsAttributes(
961
849
  /**
962
850
  * Consumes the stream chunks and adds them to the span
963
851
  */
964
- async function consumeChatCompletionStreamChunks(
965
- stream: Stream<ChatCompletionChunk>,
966
- span: Span,
967
- ) {
852
+ async function consumeChatCompletionStreamChunks(stream: Stream<ChatCompletionChunk>, span: Span) {
968
853
  let streamResponse = "";
969
854
  // Tool and function call attributes can also arrive in the stream
970
855
  // NB: the tools and function calls arrive in partial diffs
@@ -983,9 +868,7 @@ async function consumeChatCompletionStreamChunks(
983
868
  // Accumulate the tool and function call attributes
984
869
  const toolAndFunctionCallAttributesDiff =
985
870
  getToolAndFunctionCallAttributesFromStreamChunk(chunk);
986
- for (const [key, value] of Object.entries(
987
- toolAndFunctionCallAttributesDiff,
988
- )) {
871
+ for (const [key, value] of Object.entries(toolAndFunctionCallAttributesDiff)) {
989
872
  if (isString(toolAndFunctionCallAttributes[key]) && isString(value)) {
990
873
  toolAndFunctionCallAttributes[key] += value;
991
874
  } else if (isString(value)) {
@@ -999,8 +882,7 @@ async function consumeChatCompletionStreamChunks(
999
882
  const attributes: Attributes = {
1000
883
  [SemanticConventions.OUTPUT_VALUE]: streamResponse,
1001
884
  [SemanticConventions.OUTPUT_MIME_TYPE]: MimeType.TEXT,
1002
- [`${messageIndexPrefix}${SemanticConventions.MESSAGE_CONTENT}`]:
1003
- streamResponse,
885
+ [`${messageIndexPrefix}${SemanticConventions.MESSAGE_CONTENT}`]: streamResponse,
1004
886
  [`${messageIndexPrefix}${SemanticConventions.MESSAGE_ROLE}`]: "assistant",
1005
887
  };
1006
888
  // Add the tool and function call attributes
@@ -1014,9 +896,7 @@ async function consumeChatCompletionStreamChunks(
1014
896
  /**
1015
897
  * Extracts the semantic attributes from the stream chunk for tool_calls and function_calls
1016
898
  */
1017
- function getToolAndFunctionCallAttributesFromStreamChunk(
1018
- chunk: ChatCompletionChunk,
1019
- ): Attributes {
899
+ function getToolAndFunctionCallAttributesFromStreamChunk(chunk: ChatCompletionChunk): Attributes {
1020
900
  if (chunk.choices.length <= 0) {
1021
901
  return {};
1022
902
  }
@@ -1027,26 +907,20 @@ function getToolAndFunctionCallAttributesFromStreamChunk(
1027
907
  const toolCallIndexPrefix = `${SemanticConventions.MESSAGE_TOOL_CALLS}.${index}.`;
1028
908
  // Add the tool call id if it exists
1029
909
  if (toolCall.id) {
1030
- attributes[
1031
- `${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`
1032
- ] = toolCall.id;
910
+ attributes[`${toolCallIndexPrefix}${SemanticConventions.TOOL_CALL_ID}`] = toolCall.id;
1033
911
  }
1034
912
  // Double check that the tool call has a function
1035
913
  // NB: OpenAI only supports tool calls with functions right now but this may change
1036
914
  if (toolCall.function) {
1037
- attributes[
1038
- toolCallIndexPrefix + SemanticConventions.TOOL_CALL_FUNCTION_NAME
1039
- ] = toolCall.function.name;
1040
- attributes[
1041
- toolCallIndexPrefix +
1042
- SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
1043
- ] = toolCall.function.arguments;
915
+ attributes[toolCallIndexPrefix + SemanticConventions.TOOL_CALL_FUNCTION_NAME] =
916
+ toolCall.function.name;
917
+ attributes[toolCallIndexPrefix + SemanticConventions.TOOL_CALL_FUNCTION_ARGUMENTS_JSON] =
918
+ toolCall.function.arguments;
1044
919
  }
1045
920
  });
1046
921
  }
1047
922
  if (choice.delta.function_call) {
1048
- attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_NAME] =
1049
- choice.delta.function_call.name;
923
+ attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_NAME] = choice.delta.function_call.name;
1050
924
  attributes[SemanticConventions.MESSAGE_FUNCTION_CALL_ARGUMENTS_JSON] =
1051
925
  choice.delta.function_call.arguments;
1052
926
  }
@@ -1089,9 +963,7 @@ function invokeMaybeAPIPromise<T>(
1089
963
  return promise.then(then) as T;
1090
964
  } else {
1091
965
  // eslint-disable-next-line no-console
1092
- console.warn(
1093
- "Promise is not an APIPromise or a regular promise, cannot instrument.",
1094
- );
966
+ console.warn("Promise is not an APIPromise or a regular promise, cannot instrument.");
1095
967
  return promise;
1096
968
  }
1097
969
  }