@arizeai/openinference-genai 0.2.0 → 0.3.1
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/commonjs/attributes.d.ts +18 -0
- package/dist/commonjs/attributes.d.ts.map +1 -1
- package/dist/commonjs/attributes.js +165 -8
- package/dist/commonjs/attributes.js.map +1 -1
- package/dist/commonjs/index.d.ts +2 -1
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/tsconfig.commonjs.tsbuildinfo +1 -1
- package/dist/commonjs/utils.d.ts.map +1 -1
- package/dist/commonjs/utils.js.map +1 -1
- package/dist/esm/attributes.d.ts +18 -0
- package/dist/esm/attributes.d.ts.map +1 -1
- package/dist/esm/attributes.js +158 -7
- package/dist/esm/attributes.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/attributes.ts +204 -6
package/src/attributes.ts
CHANGED
|
@@ -113,6 +113,14 @@ const TOOL_EXECUTION_PREFIXES = [
|
|
|
113
113
|
ATTR_GEN_AI_TOOL_TYPE,
|
|
114
114
|
] as const;
|
|
115
115
|
|
|
116
|
+
const ATTR_GEN_AI_SYSTEM_INSTRUCTIONS = "gen_ai.system_instructions" as const;
|
|
117
|
+
const ATTR_GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions" as const;
|
|
118
|
+
const ATTR_GEN_AI_TOOL_CALL_ARGUMENTS = "gen_ai.tool.call.arguments" as const;
|
|
119
|
+
const ATTR_GEN_AI_TOOL_CALL_RESULT = "gen_ai.tool.call.result" as const;
|
|
120
|
+
const ATTR_GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS = "gen_ai.usage.cache_read.input_tokens" as const;
|
|
121
|
+
const ATTR_GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS =
|
|
122
|
+
"gen_ai.usage.cache_creation.input_tokens" as const;
|
|
123
|
+
|
|
116
124
|
// Shared part parsing
|
|
117
125
|
type AnyPart = GenAIInputMessagePart | GenAIOutputMessagePart;
|
|
118
126
|
|
|
@@ -129,6 +137,70 @@ const isGenAIChatMessage = (value: unknown): value is ChatMessage => {
|
|
|
129
137
|
return true;
|
|
130
138
|
};
|
|
131
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Normalize a GenAI tool definition into the OpenAI-style tool schema shape expected by OpenInference.
|
|
142
|
+
* @param toolDefinition - The tool definition to normalize
|
|
143
|
+
* @returns The normalized tool definition, or the original value when it cannot be normalized
|
|
144
|
+
*/
|
|
145
|
+
const normalizeToolDefinition = (toolDefinition: unknown): unknown => {
|
|
146
|
+
if (
|
|
147
|
+
typeof toolDefinition !== "object" ||
|
|
148
|
+
toolDefinition === null ||
|
|
149
|
+
Array.isArray(toolDefinition)
|
|
150
|
+
) {
|
|
151
|
+
return toolDefinition;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const definition = toolDefinition as Record<string, unknown>;
|
|
155
|
+
if (typeof definition.function === "object" && definition.function !== null) {
|
|
156
|
+
return definition;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (typeof definition.name !== "string") {
|
|
160
|
+
return definition;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const parameters = definition.parameters ?? definition.inputSchema ?? definition.input_schema;
|
|
164
|
+
const normalizedFunction: Record<string, unknown> = { name: definition.name };
|
|
165
|
+
if (typeof definition.description === "string") {
|
|
166
|
+
normalizedFunction.description = definition.description;
|
|
167
|
+
}
|
|
168
|
+
if (parameters != null) {
|
|
169
|
+
normalizedFunction.parameters = parameters;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
type: typeof definition.type === "string" ? definition.type : "function",
|
|
174
|
+
function: normalizedFunction,
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const getSystemInstructionParts = (spanAttributes: Attributes): GenAIInputMessagePart[] | null => {
|
|
179
|
+
const systemInstructions = getString(spanAttributes[ATTR_GEN_AI_SYSTEM_INSTRUCTIONS]);
|
|
180
|
+
if (systemInstructions == null) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const parsedInstructions = safelyParseJSON(systemInstructions);
|
|
185
|
+
if (Array.isArray(parsedInstructions)) {
|
|
186
|
+
const parts = parsedInstructions.flatMap((part): GenAIInputMessagePart[] => {
|
|
187
|
+
if (
|
|
188
|
+
typeof part === "object" &&
|
|
189
|
+
part !== null &&
|
|
190
|
+
"type" in part &&
|
|
191
|
+
part.type === "text" &&
|
|
192
|
+
"content" in part
|
|
193
|
+
) {
|
|
194
|
+
return [{ type: "text", content: toStringContent(part.content) }];
|
|
195
|
+
}
|
|
196
|
+
return [];
|
|
197
|
+
});
|
|
198
|
+
return parts.length > 0 ? parts : null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return [{ type: "text", content: systemInstructions }];
|
|
202
|
+
};
|
|
203
|
+
|
|
132
204
|
/**
|
|
133
205
|
* Process genai message parts into openinference attributes
|
|
134
206
|
*
|
|
@@ -189,10 +261,7 @@ const processMessageParts = ({
|
|
|
189
261
|
const response = toStringContent(part.response);
|
|
190
262
|
|
|
191
263
|
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_TOOL_CALL_ID}`, id);
|
|
192
|
-
|
|
193
|
-
set(attrs, `${contentPrefix}${SemanticConventions.MESSAGE_CONTENT_TYPE}`, "text");
|
|
194
|
-
set(attrs, `${contentPrefix}${SemanticConventions.MESSAGE_CONTENT_TEXT}`, response);
|
|
195
|
-
contentIndex += 1;
|
|
264
|
+
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_CONTENT}`, response);
|
|
196
265
|
continue;
|
|
197
266
|
}
|
|
198
267
|
default: {
|
|
@@ -209,6 +278,30 @@ const processMessageParts = ({
|
|
|
209
278
|
}
|
|
210
279
|
};
|
|
211
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Set OpenInference attributes for a single tool response message.
|
|
283
|
+
*
|
|
284
|
+
* GenAI can group multiple tool_call_response parts under one tool-role message;
|
|
285
|
+
* each response needs its own OpenInference message to avoid overwriting siblings.
|
|
286
|
+
* @param params - The tool response message mapping parameters
|
|
287
|
+
*/
|
|
288
|
+
const setToolCallResponseMessage = ({
|
|
289
|
+
attrs,
|
|
290
|
+
msgPrefix,
|
|
291
|
+
part,
|
|
292
|
+
}: {
|
|
293
|
+
attrs: Attributes;
|
|
294
|
+
msgPrefix: string;
|
|
295
|
+
part: Extract<AnyPart, { type: "tool_call_response" }>;
|
|
296
|
+
}): void => {
|
|
297
|
+
const id = part.id ?? undefined;
|
|
298
|
+
const response = toStringContent(part.response);
|
|
299
|
+
|
|
300
|
+
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_ROLE}`, "tool");
|
|
301
|
+
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_TOOL_CALL_ID}`, id);
|
|
302
|
+
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_CONTENT}`, response);
|
|
303
|
+
};
|
|
304
|
+
|
|
212
305
|
/**
|
|
213
306
|
* Convert GenAI span attributes to OpenInference span attributes
|
|
214
307
|
* @param spanAttributes - The span attributes containing GenAI span attributes to convert
|
|
@@ -225,6 +318,9 @@ export const convertGenAISpanAttributesToOpenInferenceSpanAttributes = (
|
|
|
225
318
|
mapInvocationParameters(spanAttributes),
|
|
226
319
|
mapInputMessages(spanAttributes),
|
|
227
320
|
mapOutputMessages(spanAttributes),
|
|
321
|
+
mapAgent(spanAttributes),
|
|
322
|
+
mapSystemInstructions(spanAttributes),
|
|
323
|
+
mapToolDefinitions(spanAttributes),
|
|
228
324
|
mapTokenCounts(spanAttributes),
|
|
229
325
|
mapToolExecution(spanAttributes),
|
|
230
326
|
mapInputValue(spanAttributes),
|
|
@@ -241,6 +337,7 @@ export const convertGenAISpanAttributesToOpenInferenceSpanAttributes = (
|
|
|
241
337
|
export const mapProviderAndSystem = (spanAttributes: Attributes): Attributes => {
|
|
242
338
|
const attrs: Attributes = {};
|
|
243
339
|
const provider = getString(spanAttributes[ATTR_GEN_AI_PROVIDER_NAME]);
|
|
340
|
+
set(attrs, SemanticConventions.LLM_SYSTEM, provider);
|
|
244
341
|
set(attrs, SemanticConventions.LLM_PROVIDER, provider);
|
|
245
342
|
return attrs;
|
|
246
343
|
};
|
|
@@ -366,6 +463,9 @@ export const mapInputValue = (spanAttributes: Attributes): Attributes => {
|
|
|
366
463
|
// fallback to deprecated prompt attribute if input is not present
|
|
367
464
|
input = getString(spanAttributes[ATTR_GEN_AI_PROMPT]);
|
|
368
465
|
}
|
|
466
|
+
if (!input) {
|
|
467
|
+
input = getString(spanAttributes[ATTR_GEN_AI_INPUT_MESSAGES]);
|
|
468
|
+
}
|
|
369
469
|
// only set input value and mime type if input is present
|
|
370
470
|
if (input) {
|
|
371
471
|
set(attrs, SemanticConventions.INPUT_VALUE, input);
|
|
@@ -386,6 +486,9 @@ export const mapOutputValue = (spanAttributes: Attributes): Attributes => {
|
|
|
386
486
|
// fallback to deprecated completion attribute if output is not present
|
|
387
487
|
output = getString(spanAttributes[ATTR_GEN_AI_COMPLETION]);
|
|
388
488
|
}
|
|
489
|
+
if (!output) {
|
|
490
|
+
output = getString(spanAttributes[ATTR_GEN_AI_OUTPUT_MESSAGES]);
|
|
491
|
+
}
|
|
389
492
|
// only set output value and mime type if output is present
|
|
390
493
|
if (output) {
|
|
391
494
|
set(attrs, SemanticConventions.OUTPUT_VALUE, output);
|
|
@@ -394,6 +497,60 @@ export const mapOutputValue = (spanAttributes: Attributes): Attributes => {
|
|
|
394
497
|
return attrs;
|
|
395
498
|
};
|
|
396
499
|
|
|
500
|
+
/**
|
|
501
|
+
* Map GenAI agent attributes to OpenInference attributes.
|
|
502
|
+
* @param spanAttributes - The span attributes containing agent details
|
|
503
|
+
* @returns The mapped agent attributes
|
|
504
|
+
*/
|
|
505
|
+
export const mapAgent = (spanAttributes: Attributes): Attributes => {
|
|
506
|
+
const attrs: Attributes = {};
|
|
507
|
+
set(attrs, SemanticConventions.AGENT_NAME, getString(spanAttributes[ATTR_GEN_AI_AGENT_NAME]));
|
|
508
|
+
return attrs;
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Map GenAI system instructions into metadata for preservation.
|
|
513
|
+
* @param spanAttributes - The span attributes containing system instructions
|
|
514
|
+
* @returns The mapped metadata attributes
|
|
515
|
+
*/
|
|
516
|
+
export const mapSystemInstructions = (spanAttributes: Attributes): Attributes => {
|
|
517
|
+
const attrs: Attributes = {};
|
|
518
|
+
const systemInstructions = getString(spanAttributes[ATTR_GEN_AI_SYSTEM_INSTRUCTIONS]);
|
|
519
|
+
if (systemInstructions) {
|
|
520
|
+
set(attrs, `${SemanticConventions.METADATA}.gen_ai.system_instructions`, systemInstructions);
|
|
521
|
+
|
|
522
|
+
const msgPrefix = `${SemanticConventions.LLM_INPUT_MESSAGES}.0.`;
|
|
523
|
+
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_ROLE}`, "system");
|
|
524
|
+
processMessageParts({
|
|
525
|
+
attrs,
|
|
526
|
+
msgPrefix,
|
|
527
|
+
parts: getSystemInstructionParts(spanAttributes) ?? [],
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return attrs;
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Map GenAI tool definitions to OpenInference LLM tool schema attributes.
|
|
535
|
+
* @param spanAttributes - The span attributes containing tool definitions
|
|
536
|
+
* @returns The mapped tool schema attributes
|
|
537
|
+
*/
|
|
538
|
+
export const mapToolDefinitions = (spanAttributes: Attributes): Attributes => {
|
|
539
|
+
const attrs: Attributes = {};
|
|
540
|
+
const toolDefinitions = getString(spanAttributes[ATTR_GEN_AI_TOOL_DEFINITIONS]);
|
|
541
|
+
const parsedToolDefinitions = safelyParseJSON(toolDefinitions);
|
|
542
|
+
if (Array.isArray(parsedToolDefinitions)) {
|
|
543
|
+
parsedToolDefinitions.forEach((toolDefinition, index) => {
|
|
544
|
+
set(
|
|
545
|
+
attrs,
|
|
546
|
+
`${SemanticConventions.LLM_TOOLS}.${index}.${SemanticConventions.TOOL_JSON_SCHEMA}`,
|
|
547
|
+
safelyJSONStringify(normalizeToolDefinition(toolDefinition)),
|
|
548
|
+
);
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
return attrs;
|
|
552
|
+
};
|
|
553
|
+
|
|
397
554
|
/**
|
|
398
555
|
* Map input messages to openinference attributes
|
|
399
556
|
* @param spanAttributes - The span attributes containing input messages to map
|
|
@@ -404,13 +561,30 @@ export const mapInputMessages = (spanAttributes: Attributes): Attributes => {
|
|
|
404
561
|
const genAIInputMessages = safelyParseJSON(spanAttributes[ATTR_GEN_AI_INPUT_MESSAGES]);
|
|
405
562
|
|
|
406
563
|
if (Array.isArray(genAIInputMessages)) {
|
|
407
|
-
|
|
564
|
+
let msgIndex = getSystemInstructionParts(spanAttributes) != null ? 1 : 0;
|
|
565
|
+
(genAIInputMessages as unknown[]).forEach((msg) => {
|
|
408
566
|
if (!isGenAIChatMessage(msg)) return;
|
|
567
|
+
|
|
568
|
+
const toolCallResponses = msg.parts.filter(
|
|
569
|
+
(part): part is Extract<AnyPart, { type: "tool_call_response" }> =>
|
|
570
|
+
part?.type === "tool_call_response",
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
if (msg.role === "tool" && toolCallResponses.length > 0) {
|
|
574
|
+
toolCallResponses.forEach((part) => {
|
|
575
|
+
const msgPrefix = `${SemanticConventions.LLM_INPUT_MESSAGES}.${msgIndex}.`;
|
|
576
|
+
setToolCallResponseMessage({ attrs, msgPrefix, part });
|
|
577
|
+
msgIndex += 1;
|
|
578
|
+
});
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
409
582
|
const msgPrefix = `${SemanticConventions.LLM_INPUT_MESSAGES}.${msgIndex}.`;
|
|
410
583
|
// set the message role
|
|
411
584
|
set(attrs, `${msgPrefix}${SemanticConventions.MESSAGE_ROLE}`, msg.role);
|
|
412
585
|
// process and set the rest of the message parts
|
|
413
586
|
processMessageParts({ attrs, msgPrefix, parts: msg.parts });
|
|
587
|
+
msgIndex += 1;
|
|
414
588
|
});
|
|
415
589
|
}
|
|
416
590
|
|
|
@@ -450,6 +624,10 @@ export const mapTokenCounts = (spanAttributes: Attributes): Attributes => {
|
|
|
450
624
|
const attrs: Attributes = {};
|
|
451
625
|
const inputTokens = getNumber(spanAttributes[ATTR_GEN_AI_USAGE_INPUT_TOKENS]);
|
|
452
626
|
const outputTokens = getNumber(spanAttributes[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]);
|
|
627
|
+
const cacheReadInputTokens = getNumber(spanAttributes[ATTR_GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS]);
|
|
628
|
+
const cacheCreationInputTokens = getNumber(
|
|
629
|
+
spanAttributes[ATTR_GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS],
|
|
630
|
+
);
|
|
453
631
|
if (typeof inputTokens === "number") {
|
|
454
632
|
set(attrs, SemanticConventions.LLM_TOKEN_COUNT_PROMPT, inputTokens);
|
|
455
633
|
}
|
|
@@ -459,6 +637,16 @@ export const mapTokenCounts = (spanAttributes: Attributes): Attributes => {
|
|
|
459
637
|
if (typeof inputTokens === "number" && typeof outputTokens === "number") {
|
|
460
638
|
set(attrs, SemanticConventions.LLM_TOKEN_COUNT_TOTAL, inputTokens + outputTokens);
|
|
461
639
|
}
|
|
640
|
+
if (typeof cacheReadInputTokens === "number") {
|
|
641
|
+
set(attrs, SemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ, cacheReadInputTokens);
|
|
642
|
+
}
|
|
643
|
+
if (typeof cacheCreationInputTokens === "number") {
|
|
644
|
+
set(
|
|
645
|
+
attrs,
|
|
646
|
+
SemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE,
|
|
647
|
+
cacheCreationInputTokens,
|
|
648
|
+
);
|
|
649
|
+
}
|
|
462
650
|
return attrs;
|
|
463
651
|
};
|
|
464
652
|
|
|
@@ -473,11 +661,21 @@ export const mapToolExecution = (spanAttributes: Attributes): Attributes => {
|
|
|
473
661
|
const toolName = getString(spanAttributes[ATTR_GEN_AI_TOOL_NAME]);
|
|
474
662
|
const toolDescription = getString(spanAttributes[ATTR_GEN_AI_TOOL_DESCRIPTION]);
|
|
475
663
|
const toolCallId = getString(spanAttributes[ATTR_GEN_AI_TOOL_CALL_ID]);
|
|
664
|
+
const toolCallArguments = getString(spanAttributes[ATTR_GEN_AI_TOOL_CALL_ARGUMENTS]);
|
|
665
|
+
const toolCallResult = getString(spanAttributes[ATTR_GEN_AI_TOOL_CALL_RESULT]);
|
|
476
666
|
// parse supported tool details
|
|
477
|
-
// note: while openinference can track parameters, gen_ai does not provide this information
|
|
478
667
|
set(attrs, SemanticConventions.TOOL_NAME, toolName);
|
|
479
668
|
set(attrs, SemanticConventions.TOOL_DESCRIPTION, toolDescription);
|
|
480
669
|
set(attrs, SemanticConventions.TOOL_CALL_ID, toolCallId);
|
|
670
|
+
set(attrs, SemanticConventions.TOOL_PARAMETERS, toolCallArguments);
|
|
671
|
+
if (toolCallArguments) {
|
|
672
|
+
set(attrs, SemanticConventions.INPUT_VALUE, toolCallArguments);
|
|
673
|
+
set(attrs, SemanticConventions.INPUT_MIME_TYPE, getMimeType(toolCallArguments));
|
|
674
|
+
}
|
|
675
|
+
if (toolCallResult) {
|
|
676
|
+
set(attrs, SemanticConventions.OUTPUT_VALUE, toolCallResult);
|
|
677
|
+
set(attrs, SemanticConventions.OUTPUT_MIME_TYPE, getMimeType(toolCallResult));
|
|
678
|
+
}
|
|
481
679
|
|
|
482
680
|
return attrs;
|
|
483
681
|
};
|