@mastra/arize 0.0.0-main-test-2-20251127211532 → 0.0.0-mastra-auto-detect-server-20260108233416
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/CHANGELOG.md +209 -14
- package/README.md +86 -23
- package/dist/index.cjs +130 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +131 -103
- package/dist/index.js.map +1 -1
- package/dist/openInferenceOTLPExporter.d.ts.map +1 -1
- package/dist/tracing.d.ts +1 -1
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/gen-ai.d.ts +0 -20
- package/dist/gen-ai.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,108 +1,116 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var openinferenceSemanticConventions = require('@arizeai/openinference-semantic-conventions');
|
|
4
|
-
var logger = require('@mastra/core/logger');
|
|
5
4
|
var otelExporter = require('@mastra/otel-exporter');
|
|
6
5
|
var openinferenceGenai = require('@arizeai/openinference-genai');
|
|
7
6
|
var exporterTraceOtlpProto = require('@opentelemetry/exporter-trace-otlp-proto');
|
|
7
|
+
var incubating = require('@opentelemetry/semantic-conventions/incubating');
|
|
8
8
|
|
|
9
9
|
// src/tracing.ts
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
var GEN_AI_USAGE_REASONING_TOKENS = "gen_ai.usage.reasoning_tokens";
|
|
11
|
+
var GEN_AI_USAGE_CACHED_INPUT_TOKENS = "gen_ai.usage.cached_input_tokens";
|
|
12
|
+
var GEN_AI_USAGE_CACHE_WRITE_TOKENS = "gen_ai.usage.cache_write_tokens";
|
|
13
|
+
var GEN_AI_USAGE_AUDIO_INPUT_TOKENS = "gen_ai.usage.audio_input_tokens";
|
|
14
|
+
var GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS = "gen_ai.usage.audio_output_tokens";
|
|
15
|
+
var MASTRA_GENERAL_PREFIX = "mastra.";
|
|
16
|
+
var MASTRA_METADATA_PREFIX = "mastra.metadata.";
|
|
17
|
+
function convertUsageMetricsToOpenInference(attributes) {
|
|
18
|
+
const result = {};
|
|
19
|
+
const inputTokens = attributes[incubating.ATTR_GEN_AI_USAGE_INPUT_TOKENS];
|
|
20
|
+
const outputTokens = attributes[incubating.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS];
|
|
21
|
+
if (inputTokens !== void 0) {
|
|
22
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT] = inputTokens;
|
|
23
|
+
}
|
|
24
|
+
if (outputTokens !== void 0) {
|
|
25
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_COMPLETION] = outputTokens;
|
|
26
|
+
}
|
|
27
|
+
if (inputTokens !== void 0 && outputTokens !== void 0) {
|
|
28
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_TOTAL] = inputTokens + outputTokens;
|
|
29
|
+
}
|
|
30
|
+
const cachedInputTokens = attributes[GEN_AI_USAGE_CACHED_INPUT_TOKENS];
|
|
31
|
+
if (cachedInputTokens !== void 0) {
|
|
32
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cachedInputTokens;
|
|
33
|
+
}
|
|
34
|
+
const cacheWriteTokens = attributes[GEN_AI_USAGE_CACHE_WRITE_TOKENS];
|
|
35
|
+
if (cacheWriteTokens !== void 0) {
|
|
36
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheWriteTokens;
|
|
37
|
+
}
|
|
38
|
+
const reasoningTokens = attributes[GEN_AI_USAGE_REASONING_TOKENS];
|
|
39
|
+
if (reasoningTokens !== void 0) {
|
|
40
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING] = reasoningTokens;
|
|
41
|
+
}
|
|
42
|
+
const audioInputTokens = attributes[GEN_AI_USAGE_AUDIO_INPUT_TOKENS];
|
|
43
|
+
if (audioInputTokens !== void 0) {
|
|
44
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO] = audioInputTokens;
|
|
45
|
+
}
|
|
46
|
+
const audioOutputTokens = attributes[GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS];
|
|
47
|
+
if (audioOutputTokens !== void 0) {
|
|
48
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO] = audioOutputTokens;
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
function splitMastraAttributes(attributes) {
|
|
53
|
+
return Object.entries(attributes).reduce(
|
|
54
|
+
(acc, [key, value]) => {
|
|
55
|
+
if (key.startsWith(MASTRA_GENERAL_PREFIX)) {
|
|
56
|
+
if (key.startsWith(MASTRA_METADATA_PREFIX)) {
|
|
57
|
+
const strippedKey = key.slice(MASTRA_METADATA_PREFIX.length);
|
|
58
|
+
acc.mastraMetadata[strippedKey] = value;
|
|
59
|
+
} else {
|
|
60
|
+
acc.mastraOther[key] = value;
|
|
29
61
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return m;
|
|
37
|
-
}
|
|
38
|
-
const role = m.role;
|
|
39
|
-
let parts = [];
|
|
40
|
-
if (Array.isArray(m.content)) {
|
|
41
|
-
parts = m.content.map((c) => {
|
|
42
|
-
switch (c.type) {
|
|
43
|
-
case "text":
|
|
44
|
-
return {
|
|
45
|
-
type: "text",
|
|
46
|
-
content: c.text
|
|
47
|
-
};
|
|
48
|
-
case "tool-call":
|
|
49
|
-
return {
|
|
50
|
-
type: "tool_call",
|
|
51
|
-
id: c.toolCallId,
|
|
52
|
-
name: c.toolName,
|
|
53
|
-
arguments: JSON.stringify(c.input)
|
|
54
|
-
};
|
|
55
|
-
case "tool-result":
|
|
56
|
-
return {
|
|
57
|
-
type: "tool_call_response",
|
|
58
|
-
id: c.toolCallId,
|
|
59
|
-
name: c.toolName,
|
|
60
|
-
response: JSON.stringify(c.output.value)
|
|
61
|
-
};
|
|
62
|
-
default:
|
|
63
|
-
return c;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
} else {
|
|
67
|
-
parts = [
|
|
68
|
-
{
|
|
69
|
-
type: "text",
|
|
70
|
-
content: m.content
|
|
71
|
-
}
|
|
72
|
-
];
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
role,
|
|
76
|
-
parts
|
|
77
|
-
};
|
|
78
|
-
})
|
|
79
|
-
);
|
|
62
|
+
}
|
|
63
|
+
return acc;
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
mastraMetadata: {},
|
|
67
|
+
mastraOther: {}
|
|
80
68
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return inputOutputString;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// src/openInferenceOTLPExporter.ts
|
|
69
|
+
);
|
|
70
|
+
}
|
|
88
71
|
var OpenInferenceOTLPTraceExporter = class extends exporterTraceOtlpProto.OTLPTraceExporter {
|
|
89
72
|
export(spans, resultCallback) {
|
|
90
73
|
const processedSpans = spans.map((span) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
if (span.attributes?.["gen_ai.completion"] && typeof span.attributes["gen_ai.completion"] === "string") {
|
|
97
|
-
span.attributes["gen_ai.output.messages"] = convertMastraMessagesToGenAIMessages(
|
|
98
|
-
span.attributes["gen_ai.completion"]
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
const processedAttributes = openinferenceGenai.convertGenAISpanAttributesToOpenInferenceSpanAttributes(span.attributes);
|
|
74
|
+
const attributes = { ...span.attributes ?? {} };
|
|
75
|
+
const mutableSpan = span;
|
|
76
|
+
const { mastraMetadata, mastraOther } = splitMastraAttributes(attributes);
|
|
77
|
+
const processedAttributes = openinferenceGenai.convertGenAISpanAttributesToOpenInferenceSpanAttributes(attributes);
|
|
102
78
|
if (processedAttributes) {
|
|
103
|
-
|
|
79
|
+
const threadId = mastraMetadata["threadId"];
|
|
80
|
+
if (threadId) {
|
|
81
|
+
delete mastraMetadata["threadId"];
|
|
82
|
+
processedAttributes[openinferenceSemanticConventions.SESSION_ID] = threadId;
|
|
83
|
+
}
|
|
84
|
+
if (mastraOther["mastra.tags"]) {
|
|
85
|
+
processedAttributes[openinferenceSemanticConventions.TAG_TAGS] = mastraOther["mastra.tags"];
|
|
86
|
+
delete mastraOther["mastra.tags"];
|
|
87
|
+
}
|
|
88
|
+
const userId = mastraMetadata["userId"];
|
|
89
|
+
if (userId) {
|
|
90
|
+
delete mastraMetadata["userId"];
|
|
91
|
+
processedAttributes[openinferenceSemanticConventions.USER_ID] = userId;
|
|
92
|
+
}
|
|
93
|
+
if (Object.keys(mastraMetadata).length > 0) {
|
|
94
|
+
try {
|
|
95
|
+
processedAttributes[openinferenceSemanticConventions.METADATA] = JSON.stringify(mastraMetadata);
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const inputMessages = attributes[incubating.ATTR_GEN_AI_INPUT_MESSAGES];
|
|
100
|
+
if (inputMessages) {
|
|
101
|
+
processedAttributes[openinferenceSemanticConventions.INPUT_MIME_TYPE] = "application/json";
|
|
102
|
+
processedAttributes[openinferenceSemanticConventions.INPUT_VALUE] = inputMessages;
|
|
103
|
+
}
|
|
104
|
+
const outputMessages = attributes[incubating.ATTR_GEN_AI_OUTPUT_MESSAGES];
|
|
105
|
+
if (outputMessages) {
|
|
106
|
+
processedAttributes[openinferenceSemanticConventions.OUTPUT_MIME_TYPE] = "application/json";
|
|
107
|
+
processedAttributes[openinferenceSemanticConventions.OUTPUT_VALUE] = outputMessages;
|
|
108
|
+
}
|
|
109
|
+
const usageMetrics = convertUsageMetricsToOpenInference(attributes);
|
|
110
|
+
Object.assign(processedAttributes, usageMetrics);
|
|
111
|
+
mutableSpan.attributes = { ...processedAttributes, ...mastraOther };
|
|
104
112
|
}
|
|
105
|
-
return
|
|
113
|
+
return mutableSpan;
|
|
106
114
|
});
|
|
107
115
|
super.export(processedSpans, resultCallback);
|
|
108
116
|
}
|
|
@@ -113,21 +121,41 @@ var LOG_PREFIX = "[ArizeExporter]";
|
|
|
113
121
|
var ARIZE_AX_ENDPOINT = "https://otlp.arize.com/v1/traces";
|
|
114
122
|
var ArizeExporter = class extends otelExporter.OtelExporter {
|
|
115
123
|
name = "arize";
|
|
116
|
-
constructor(config) {
|
|
117
|
-
const
|
|
118
|
-
|
|
124
|
+
constructor(config = {}) {
|
|
125
|
+
const spaceId = config.spaceId ?? process.env.ARIZE_SPACE_ID;
|
|
126
|
+
const apiKey = config.apiKey ?? process.env.ARIZE_API_KEY ?? process.env.PHOENIX_API_KEY;
|
|
127
|
+
const projectName = config.projectName ?? process.env.ARIZE_PROJECT_NAME ?? process.env.PHOENIX_PROJECT_NAME;
|
|
128
|
+
let endpoint = config.endpoint ?? process.env.PHOENIX_ENDPOINT;
|
|
119
129
|
const headers = {
|
|
120
130
|
...config.headers
|
|
121
131
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
let disabledReason;
|
|
133
|
+
if (spaceId) {
|
|
134
|
+
if (!apiKey) {
|
|
135
|
+
disabledReason = `${LOG_PREFIX} API key is required for Arize AX. Set ARIZE_API_KEY environment variable or pass apiKey in config.`;
|
|
136
|
+
} else {
|
|
137
|
+
headers["space_id"] = spaceId;
|
|
138
|
+
headers["api_key"] = apiKey;
|
|
139
|
+
endpoint = endpoint || ARIZE_AX_ENDPOINT;
|
|
140
|
+
}
|
|
141
|
+
} else if (apiKey) {
|
|
142
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
143
|
+
}
|
|
144
|
+
if (!disabledReason && !endpoint) {
|
|
145
|
+
disabledReason = `${LOG_PREFIX} Endpoint is required in configuration. Set PHOENIX_ENDPOINT environment variable, or ARIZE_SPACE_ID for Arize AX, or pass endpoint in config.`;
|
|
128
146
|
}
|
|
129
|
-
if (
|
|
130
|
-
|
|
147
|
+
if (disabledReason) {
|
|
148
|
+
super({
|
|
149
|
+
...config,
|
|
150
|
+
provider: {
|
|
151
|
+
custom: {
|
|
152
|
+
endpoint: "http://disabled",
|
|
153
|
+
headers: {},
|
|
154
|
+
protocol: "http/protobuf"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
this.setDisabled(disabledReason);
|
|
131
159
|
return;
|
|
132
160
|
}
|
|
133
161
|
super({
|
|
@@ -137,7 +165,7 @@ var ArizeExporter = class extends otelExporter.OtelExporter {
|
|
|
137
165
|
}),
|
|
138
166
|
...config,
|
|
139
167
|
resourceAttributes: {
|
|
140
|
-
[openinferenceSemanticConventions.SEMRESATTRS_PROJECT_NAME]:
|
|
168
|
+
...projectName ? { [openinferenceSemanticConventions.SEMRESATTRS_PROJECT_NAME]: projectName } : {},
|
|
141
169
|
...config.resourceAttributes
|
|
142
170
|
},
|
|
143
171
|
provider: {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gen-ai.ts","../src/openInferenceOTLPExporter.ts","../src/tracing.ts"],"names":["OTLPTraceExporter","convertGenAISpanAttributesToOpenInferenceSpanAttributes","OtelExporter","logger","ConsoleLogger","SEMRESATTRS_PROJECT_NAME"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Type represenation of a gen_ai chat message part\n */\ntype GenAIMessagePart =\n | {\n type: 'text';\n content: string;\n }\n | {\n type: 'tool_call';\n id: string;\n name: string;\n arguments: string;\n }\n | {\n type: 'tool_call_response';\n id: string;\n name: string;\n response: string;\n };\n\n/**\n * Type representation of a gen_ai chat message\n */\ntype GenAIMessage = {\n role: string;\n parts: GenAIMessagePart[];\n};\n\n/**\n * Assumed type representation of a Mastra message content type\n */\ntype MastraMessagePart =\n | {\n type: 'text';\n text: string;\n }\n | { type: 'tool-call'; toolCallId: string; toolName: string; input: unknown }\n | { type: 'tool-result'; toolCallId: string; toolName: string; output: { value: unknown } };\n\n/**\n * Assumed type representation of a Mastra message\n */\ntype MastraMessage = {\n role: string;\n content: MastraMessagePart[];\n};\n\nconst isMastraMessagePart = (p: unknown): p is MastraMessagePart => {\n return (\n typeof p === 'object' &&\n p != null &&\n 'type' in p &&\n (p.type === 'text' || p.type === 'tool-call' || p.type === 'tool-result') &&\n ((p.type === 'text' && 'text' in p) ||\n (p.type === 'tool-call' && 'toolCallId' in p && 'toolName' in p && 'input' in p) ||\n (p.type === 'tool-result' && 'toolCallId' in p && 'toolName' in p && 'output' in p))\n );\n};\n\nconst isMastraMessage = (m: unknown): m is MastraMessage => {\n return (\n typeof m === 'object' &&\n m != null &&\n 'role' in m &&\n 'content' in m &&\n (typeof m.content === 'string' || (Array.isArray(m.content) && m.content.every(isMastraMessagePart)))\n );\n};\n\n/**\n * Convert an Input/Output string from a MastraSpan into a jsonified string that adheres to\n * OpenTelemetry gen_ai.input.messages and gen_ai.output.messages schema.\n * If parsing fails at any step, the original inputOutputString is returned unmodified.\n *\n * This conversion is best effort; It assumes a consistent shape for mastra messages, and converts\n * into the gen_ai input and output schemas as of October 20th, 2025.\n *\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-input-messages\n * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-input-messages.json\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-output-messages\n * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-output-messages.json\n *\n * @param inputOutputString a jsonified string that contains messages adhering to what appears to be\n * Mastra's message shape.\n * @returns a jsonified string that contains messages adhering to the OpenTelemetry gen_ai.input.messages and gen_ai.output.messages schema.\n * If parsing fails at any step, the original inputOutputString is returned unmodified.\n */\nexport const convertMastraMessagesToGenAIMessages = (inputOutputString: string): string => {\n try {\n const parsedIO = JSON.parse(inputOutputString) as unknown;\n if (typeof parsedIO !== 'object' || parsedIO == null || (!('messages' in parsedIO) && !('text' in parsedIO))) {\n // inputOutputString fails initial type guard, just return it\n return inputOutputString;\n }\n // if the IO simply contains a text string, return a single text message\n // formatted as a gen_ai assistant message, assuming its an assistant response\n if ('text' in parsedIO) {\n return JSON.stringify([\n {\n role: 'assistant',\n parts: [{ type: 'text', content: parsedIO.text as string }],\n } satisfies GenAIMessage,\n ]);\n }\n // if the IO contains messages, convert them to gen_ai messages\n if (Array.isArray(parsedIO.messages)) {\n return JSON.stringify(\n (parsedIO.messages as unknown[]).map(m => {\n if (!isMastraMessage(m)) {\n return m;\n }\n const role = m.role;\n let parts: GenAIMessagePart[] = [];\n if (Array.isArray(m.content)) {\n parts = m.content.map(c => {\n switch (c.type) {\n case 'text':\n return {\n type: 'text',\n content: c.text,\n };\n case 'tool-call':\n return {\n type: 'tool_call',\n id: c.toolCallId,\n name: c.toolName,\n arguments: JSON.stringify(c.input),\n };\n case 'tool-result':\n return {\n type: 'tool_call_response',\n id: c.toolCallId,\n name: c.toolName,\n response: JSON.stringify(c.output.value),\n };\n default:\n return c;\n }\n });\n } else {\n parts = [\n {\n type: 'text',\n content: m.content,\n },\n ];\n }\n return {\n role,\n parts,\n } satisfies GenAIMessage;\n }),\n );\n }\n // we've failed type-guards, just return original I/O string\n return inputOutputString;\n } catch {\n // silently fallback to original I/O string\n return inputOutputString;\n }\n};\n","import { convertGenAISpanAttributesToOpenInferenceSpanAttributes } from '@arizeai/openinference-genai';\nimport type { Mutable } from '@arizeai/openinference-genai/types';\nimport type { ExportResult } from '@opentelemetry/core';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport { convertMastraMessagesToGenAIMessages } from './gen-ai';\n\nexport class OpenInferenceOTLPTraceExporter extends OTLPTraceExporter {\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void) {\n const processedSpans = spans.map(span => {\n // convert Mastra input messages to GenAI messages if present\n if (span.attributes?.['gen_ai.prompt'] && typeof span.attributes['gen_ai.prompt'] === 'string') {\n span.attributes['gen_ai.input.messages'] = convertMastraMessagesToGenAIMessages(\n span.attributes['gen_ai.prompt'],\n );\n }\n // convert Mastra output messages to GenAI messages if present\n if (span.attributes?.['gen_ai.completion'] && typeof span.attributes['gen_ai.completion'] === 'string') {\n span.attributes['gen_ai.output.messages'] = convertMastraMessagesToGenAIMessages(\n span.attributes['gen_ai.completion'],\n );\n }\n const processedAttributes = convertGenAISpanAttributesToOpenInferenceSpanAttributes(span.attributes);\n // only add processed attributes if conversion was successful\n if (processedAttributes) {\n (span as Mutable<ReadableSpan>).attributes = processedAttributes;\n }\n return span;\n });\n\n super.export(processedSpans, resultCallback);\n }\n}\n","import { SEMRESATTRS_PROJECT_NAME } from '@arizeai/openinference-semantic-conventions';\nimport { ConsoleLogger } from '@mastra/core/logger';\nimport { OtelExporter } from '@mastra/otel-exporter';\nimport type { OtelExporterConfig } from '@mastra/otel-exporter';\n\nimport { OpenInferenceOTLPTraceExporter } from './openInferenceOTLPExporter.js';\n\nconst LOG_PREFIX = '[ArizeExporter]';\n\nexport const ARIZE_AX_ENDPOINT = 'https://otlp.arize.com/v1/traces';\n\nexport type ArizeExporterConfig = Omit<OtelExporterConfig, 'provider'> & {\n /**\n * Required if sending traces to Arize AX\n */\n spaceId?: string;\n /**\n * Required if sending traces to Arize AX, or to any other collector that\n * requires an Authorization header\n */\n apiKey?: string;\n /**\n * Collector endpoint destination for trace exports.\n * Required when sending traces to Phoenix, Phoenix Cloud, or other collectors.\n * Optional when sending traces to Arize AX.\n */\n endpoint?: string;\n /**\n * Optional project name to be added as a resource attribute using\n * OpenInference Semantic Conventions\n */\n projectName?: string;\n /**\n * Optional headers to be added to each OTLP request\n */\n headers?: Record<string, string>;\n};\n\nexport class ArizeExporter extends OtelExporter {\n name = 'arize';\n\n constructor(config: ArizeExporterConfig) {\n const logger = new ConsoleLogger({ level: config.logLevel ?? 'warn' });\n let endpoint: string | undefined = config.endpoint;\n const headers: Record<string, string> = {\n ...config.headers,\n };\n if (config.spaceId) {\n // arize ax header configuration\n headers['space_id'] = config.spaceId;\n headers['api_key'] = config.apiKey ?? '';\n endpoint = config.endpoint || ARIZE_AX_ENDPOINT;\n } else if (config.apiKey) {\n // standard otel header configuration\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n }\n if (!endpoint) {\n logger.error(`${LOG_PREFIX} Endpoint is required in configuration. Disabling exporter.`);\n return;\n }\n super({\n exporter: new OpenInferenceOTLPTraceExporter({\n url: endpoint,\n headers,\n }),\n ...config,\n resourceAttributes: {\n [SEMRESATTRS_PROJECT_NAME]: config.projectName,\n ...config.resourceAttributes,\n },\n provider: {\n custom: {\n endpoint,\n headers,\n protocol: 'http/protobuf',\n },\n } satisfies OtelExporterConfig['provider'],\n } satisfies OtelExporterConfig);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/openInferenceOTLPExporter.ts","../src/tracing.ts"],"names":["ATTR_GEN_AI_USAGE_INPUT_TOKENS","ATTR_GEN_AI_USAGE_OUTPUT_TOKENS","LLM_TOKEN_COUNT_PROMPT","LLM_TOKEN_COUNT_COMPLETION","LLM_TOKEN_COUNT_TOTAL","LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ","LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE","LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING","LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO","LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO","OTLPTraceExporter","convertGenAISpanAttributesToOpenInferenceSpanAttributes","SESSION_ID","TAG_TAGS","USER_ID","METADATA","ATTR_GEN_AI_INPUT_MESSAGES","INPUT_MIME_TYPE","INPUT_VALUE","ATTR_GEN_AI_OUTPUT_MESSAGES","OUTPUT_MIME_TYPE","OUTPUT_VALUE","OtelExporter","SEMRESATTRS_PROJECT_NAME"],"mappings":"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","file":"index.cjs","sourcesContent":["import { convertGenAISpanAttributesToOpenInferenceSpanAttributes } from '@arizeai/openinference-genai';\nimport type { Mutable } from '@arizeai/openinference-genai/types';\nimport {\n INPUT_MIME_TYPE,\n INPUT_VALUE,\n LLM_TOKEN_COUNT_COMPLETION,\n LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO,\n LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING,\n LLM_TOKEN_COUNT_PROMPT,\n LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO,\n LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ,\n LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE,\n LLM_TOKEN_COUNT_TOTAL,\n METADATA,\n OUTPUT_MIME_TYPE,\n OUTPUT_VALUE,\n SESSION_ID,\n TAG_TAGS,\n USER_ID,\n} from '@arizeai/openinference-semantic-conventions';\nimport type { ExportResult } from '@opentelemetry/core';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport {\n ATTR_GEN_AI_INPUT_MESSAGES,\n ATTR_GEN_AI_OUTPUT_MESSAGES,\n ATTR_GEN_AI_USAGE_INPUT_TOKENS,\n ATTR_GEN_AI_USAGE_OUTPUT_TOKENS,\n} from '@opentelemetry/semantic-conventions/incubating';\n\n// GenAI usage attribute keys (not all are in @opentelemetry/semantic-conventions yet)\nconst GEN_AI_USAGE_REASONING_TOKENS = 'gen_ai.usage.reasoning_tokens';\nconst GEN_AI_USAGE_CACHED_INPUT_TOKENS = 'gen_ai.usage.cached_input_tokens';\nconst GEN_AI_USAGE_CACHE_WRITE_TOKENS = 'gen_ai.usage.cache_write_tokens';\nconst GEN_AI_USAGE_AUDIO_INPUT_TOKENS = 'gen_ai.usage.audio_input_tokens';\nconst GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS = 'gen_ai.usage.audio_output_tokens';\n\nconst MASTRA_GENERAL_PREFIX = 'mastra.';\nconst MASTRA_METADATA_PREFIX = 'mastra.metadata.';\n\n/**\n * Converts GenAI usage metrics to OpenInference LLM token count attributes.\n * Maps from OTEL GenAI semantic conventions to OpenInference semantic conventions.\n *\n * @param attributes - The span attributes containing GenAI usage metrics\n * @returns OpenInference token count attributes\n */\nfunction convertUsageMetricsToOpenInference(attributes: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n\n const inputTokens = attributes[ATTR_GEN_AI_USAGE_INPUT_TOKENS];\n const outputTokens = attributes[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS];\n\n // Core token counts\n if (inputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT] = inputTokens;\n }\n if (outputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_COMPLETION] = outputTokens;\n }\n\n // Total tokens (compute if we have both input and output)\n if (inputTokens !== undefined && outputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_TOTAL] = inputTokens + outputTokens;\n }\n\n // Cache tokens (prompt details)\n const cachedInputTokens = attributes[GEN_AI_USAGE_CACHED_INPUT_TOKENS];\n if (cachedInputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cachedInputTokens;\n }\n\n const cacheWriteTokens = attributes[GEN_AI_USAGE_CACHE_WRITE_TOKENS];\n if (cacheWriteTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheWriteTokens;\n }\n\n // Reasoning tokens (completion details)\n const reasoningTokens = attributes[GEN_AI_USAGE_REASONING_TOKENS];\n if (reasoningTokens !== undefined) {\n result[LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING] = reasoningTokens;\n }\n\n // Audio tokens\n const audioInputTokens = attributes[GEN_AI_USAGE_AUDIO_INPUT_TOKENS];\n if (audioInputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO] = audioInputTokens;\n }\n\n const audioOutputTokens = attributes[GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS];\n if (audioOutputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO] = audioOutputTokens;\n }\n\n return result;\n}\n\n/**\n * Splits Mastra span attributes into two groups:\n * - `metadata`: keys starting with \"mastra.metadata.\" (prefix removed)\n * - `other`: all remaining keys starting with \"mastra.\"\n *\n * Any attributes not starting with \"mastra.\" are ignored entirely.\n */\nfunction splitMastraAttributes(attributes: Record<string, any>): {\n mastraMetadata: Record<string, any>;\n mastraOther: Record<string, any>;\n} {\n return Object.entries(attributes).reduce(\n (acc, [key, value]) => {\n if (key.startsWith(MASTRA_GENERAL_PREFIX)) {\n if (key.startsWith(MASTRA_METADATA_PREFIX)) {\n const strippedKey = key.slice(MASTRA_METADATA_PREFIX.length);\n acc.mastraMetadata[strippedKey] = value;\n } else {\n acc.mastraOther[key] = value;\n }\n }\n return acc;\n },\n {\n mastraMetadata: {} as Record<string, any>,\n mastraOther: {} as Record<string, any>,\n },\n );\n}\n\nexport class OpenInferenceOTLPTraceExporter extends OTLPTraceExporter {\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void) {\n const processedSpans = spans.map(span => {\n const attributes = { ...(span.attributes ?? {}) };\n const mutableSpan = span as Mutable<ReadableSpan>;\n\n const { mastraMetadata, mastraOther } = splitMastraAttributes(attributes);\n const processedAttributes = convertGenAISpanAttributesToOpenInferenceSpanAttributes(attributes);\n\n // only add processed attributes if conversion was successful\n if (processedAttributes) {\n const threadId = mastraMetadata['threadId'];\n if (threadId) {\n delete mastraMetadata['threadId'];\n processedAttributes[SESSION_ID] = threadId;\n }\n\n // Map mastra.tags to OpenInference native tag.tags convention (tags are only on root spans)\n if (mastraOther['mastra.tags']) {\n processedAttributes[TAG_TAGS] = mastraOther['mastra.tags'];\n delete mastraOther['mastra.tags'];\n }\n\n const userId = mastraMetadata['userId'];\n if (userId) {\n delete mastraMetadata['userId'];\n processedAttributes[USER_ID] = userId;\n }\n\n // Gather custom metadata into OpenInference metadata (flat best-effort)\n if (Object.keys(mastraMetadata).length > 0) {\n try {\n processedAttributes[METADATA] = JSON.stringify(mastraMetadata);\n } catch {\n // best-effort only\n }\n }\n\n const inputMessages = attributes[ATTR_GEN_AI_INPUT_MESSAGES];\n if (inputMessages) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = inputMessages;\n }\n const outputMessages = attributes[ATTR_GEN_AI_OUTPUT_MESSAGES];\n if (outputMessages) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = outputMessages;\n }\n\n // Convert GenAI usage metrics to OpenInference token count attributes\n const usageMetrics = convertUsageMetricsToOpenInference(attributes);\n Object.assign(processedAttributes, usageMetrics);\n\n mutableSpan.attributes = { ...processedAttributes, ...mastraOther };\n }\n\n return mutableSpan;\n });\n\n super.export(processedSpans, resultCallback);\n }\n}\n","import { SEMRESATTRS_PROJECT_NAME } from '@arizeai/openinference-semantic-conventions';\nimport { OtelExporter } from '@mastra/otel-exporter';\nimport type { OtelExporterConfig } from '@mastra/otel-exporter';\n\nimport { OpenInferenceOTLPTraceExporter } from './openInferenceOTLPExporter.js';\n\nconst LOG_PREFIX = '[ArizeExporter]';\n\nexport const ARIZE_AX_ENDPOINT = 'https://otlp.arize.com/v1/traces';\n\nexport type ArizeExporterConfig = Omit<OtelExporterConfig, 'provider'> & {\n /**\n * Required if sending traces to Arize AX\n */\n spaceId?: string;\n /**\n * Required if sending traces to Arize AX, or to any other collector that\n * requires an Authorization header\n */\n apiKey?: string;\n /**\n * Collector endpoint destination for trace exports.\n * Required when sending traces to Phoenix, Phoenix Cloud, or other collectors.\n * Optional when sending traces to Arize AX.\n */\n endpoint?: string;\n /**\n * Optional project name to be added as a resource attribute using\n * OpenInference Semantic Conventions\n */\n projectName?: string;\n /**\n * Optional headers to be added to each OTLP request\n */\n headers?: Record<string, string>;\n};\n\nexport class ArizeExporter extends OtelExporter {\n name = 'arize';\n\n constructor(config: ArizeExporterConfig = {}) {\n // Read configuration from config or environment variables\n // Priority: config > ARIZE_* env vars > PHOENIX_* env vars\n const spaceId = config.spaceId ?? process.env.ARIZE_SPACE_ID;\n const apiKey = config.apiKey ?? process.env.ARIZE_API_KEY ?? process.env.PHOENIX_API_KEY;\n const projectName = config.projectName ?? process.env.ARIZE_PROJECT_NAME ?? process.env.PHOENIX_PROJECT_NAME;\n\n // Determine endpoint: config > PHOENIX_ENDPOINT > ARIZE_AX_ENDPOINT (if spaceId is set)\n let endpoint: string | undefined = config.endpoint ?? process.env.PHOENIX_ENDPOINT;\n\n const headers: Record<string, string> = {\n ...config.headers,\n };\n\n // Validate credentials based on mode\n let disabledReason: string | undefined;\n\n if (spaceId) {\n // Arize AX mode requires an API key\n if (!apiKey) {\n disabledReason =\n `${LOG_PREFIX} API key is required for Arize AX. ` +\n `Set ARIZE_API_KEY environment variable or pass apiKey in config.`;\n } else {\n // arize ax header configuration\n headers['space_id'] = spaceId;\n headers['api_key'] = apiKey;\n endpoint = endpoint || ARIZE_AX_ENDPOINT;\n }\n } else if (apiKey) {\n // standard otel header configuration\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n if (!disabledReason && !endpoint) {\n disabledReason =\n `${LOG_PREFIX} Endpoint is required in configuration. ` +\n `Set PHOENIX_ENDPOINT environment variable, or ARIZE_SPACE_ID for Arize AX, or pass endpoint in config.`;\n }\n\n // If disabled, create with minimal config and disable\n if (disabledReason) {\n super({\n ...config,\n provider: {\n custom: {\n endpoint: 'http://disabled',\n headers: {},\n protocol: 'http/protobuf',\n },\n },\n });\n this.setDisabled(disabledReason);\n return;\n }\n\n super({\n exporter: new OpenInferenceOTLPTraceExporter({\n url: endpoint!,\n headers,\n }),\n ...config,\n resourceAttributes: {\n ...(projectName ? { [SEMRESATTRS_PROJECT_NAME]: projectName } : {}),\n ...config.resourceAttributes,\n },\n provider: {\n custom: {\n endpoint: endpoint!,\n headers,\n protocol: 'http/protobuf',\n },\n } satisfies OtelExporterConfig['provider'],\n } satisfies OtelExporterConfig);\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,106 +1,114 @@
|
|
|
1
|
-
import { SEMRESATTRS_PROJECT_NAME } from '@arizeai/openinference-semantic-conventions';
|
|
2
|
-
import { ConsoleLogger } from '@mastra/core/logger';
|
|
1
|
+
import { SEMRESATTRS_PROJECT_NAME, SESSION_ID, TAG_TAGS, USER_ID, METADATA, INPUT_MIME_TYPE, INPUT_VALUE, OUTPUT_MIME_TYPE, OUTPUT_VALUE, LLM_TOKEN_COUNT_PROMPT, LLM_TOKEN_COUNT_COMPLETION, LLM_TOKEN_COUNT_TOTAL, LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ, LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE, LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING, LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO, LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO } from '@arizeai/openinference-semantic-conventions';
|
|
3
2
|
import { OtelExporter } from '@mastra/otel-exporter';
|
|
4
3
|
import { convertGenAISpanAttributesToOpenInferenceSpanAttributes } from '@arizeai/openinference-genai';
|
|
5
4
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
|
|
5
|
+
import { ATTR_GEN_AI_INPUT_MESSAGES, ATTR_GEN_AI_OUTPUT_MESSAGES, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS } from '@opentelemetry/semantic-conventions/incubating';
|
|
6
6
|
|
|
7
7
|
// src/tracing.ts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
var GEN_AI_USAGE_REASONING_TOKENS = "gen_ai.usage.reasoning_tokens";
|
|
9
|
+
var GEN_AI_USAGE_CACHED_INPUT_TOKENS = "gen_ai.usage.cached_input_tokens";
|
|
10
|
+
var GEN_AI_USAGE_CACHE_WRITE_TOKENS = "gen_ai.usage.cache_write_tokens";
|
|
11
|
+
var GEN_AI_USAGE_AUDIO_INPUT_TOKENS = "gen_ai.usage.audio_input_tokens";
|
|
12
|
+
var GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS = "gen_ai.usage.audio_output_tokens";
|
|
13
|
+
var MASTRA_GENERAL_PREFIX = "mastra.";
|
|
14
|
+
var MASTRA_METADATA_PREFIX = "mastra.metadata.";
|
|
15
|
+
function convertUsageMetricsToOpenInference(attributes) {
|
|
16
|
+
const result = {};
|
|
17
|
+
const inputTokens = attributes[ATTR_GEN_AI_USAGE_INPUT_TOKENS];
|
|
18
|
+
const outputTokens = attributes[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS];
|
|
19
|
+
if (inputTokens !== void 0) {
|
|
20
|
+
result[LLM_TOKEN_COUNT_PROMPT] = inputTokens;
|
|
21
|
+
}
|
|
22
|
+
if (outputTokens !== void 0) {
|
|
23
|
+
result[LLM_TOKEN_COUNT_COMPLETION] = outputTokens;
|
|
24
|
+
}
|
|
25
|
+
if (inputTokens !== void 0 && outputTokens !== void 0) {
|
|
26
|
+
result[LLM_TOKEN_COUNT_TOTAL] = inputTokens + outputTokens;
|
|
27
|
+
}
|
|
28
|
+
const cachedInputTokens = attributes[GEN_AI_USAGE_CACHED_INPUT_TOKENS];
|
|
29
|
+
if (cachedInputTokens !== void 0) {
|
|
30
|
+
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cachedInputTokens;
|
|
31
|
+
}
|
|
32
|
+
const cacheWriteTokens = attributes[GEN_AI_USAGE_CACHE_WRITE_TOKENS];
|
|
33
|
+
if (cacheWriteTokens !== void 0) {
|
|
34
|
+
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheWriteTokens;
|
|
35
|
+
}
|
|
36
|
+
const reasoningTokens = attributes[GEN_AI_USAGE_REASONING_TOKENS];
|
|
37
|
+
if (reasoningTokens !== void 0) {
|
|
38
|
+
result[LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING] = reasoningTokens;
|
|
39
|
+
}
|
|
40
|
+
const audioInputTokens = attributes[GEN_AI_USAGE_AUDIO_INPUT_TOKENS];
|
|
41
|
+
if (audioInputTokens !== void 0) {
|
|
42
|
+
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO] = audioInputTokens;
|
|
43
|
+
}
|
|
44
|
+
const audioOutputTokens = attributes[GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS];
|
|
45
|
+
if (audioOutputTokens !== void 0) {
|
|
46
|
+
result[LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO] = audioOutputTokens;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function splitMastraAttributes(attributes) {
|
|
51
|
+
return Object.entries(attributes).reduce(
|
|
52
|
+
(acc, [key, value]) => {
|
|
53
|
+
if (key.startsWith(MASTRA_GENERAL_PREFIX)) {
|
|
54
|
+
if (key.startsWith(MASTRA_METADATA_PREFIX)) {
|
|
55
|
+
const strippedKey = key.slice(MASTRA_METADATA_PREFIX.length);
|
|
56
|
+
acc.mastraMetadata[strippedKey] = value;
|
|
57
|
+
} else {
|
|
58
|
+
acc.mastraOther[key] = value;
|
|
27
59
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return m;
|
|
35
|
-
}
|
|
36
|
-
const role = m.role;
|
|
37
|
-
let parts = [];
|
|
38
|
-
if (Array.isArray(m.content)) {
|
|
39
|
-
parts = m.content.map((c) => {
|
|
40
|
-
switch (c.type) {
|
|
41
|
-
case "text":
|
|
42
|
-
return {
|
|
43
|
-
type: "text",
|
|
44
|
-
content: c.text
|
|
45
|
-
};
|
|
46
|
-
case "tool-call":
|
|
47
|
-
return {
|
|
48
|
-
type: "tool_call",
|
|
49
|
-
id: c.toolCallId,
|
|
50
|
-
name: c.toolName,
|
|
51
|
-
arguments: JSON.stringify(c.input)
|
|
52
|
-
};
|
|
53
|
-
case "tool-result":
|
|
54
|
-
return {
|
|
55
|
-
type: "tool_call_response",
|
|
56
|
-
id: c.toolCallId,
|
|
57
|
-
name: c.toolName,
|
|
58
|
-
response: JSON.stringify(c.output.value)
|
|
59
|
-
};
|
|
60
|
-
default:
|
|
61
|
-
return c;
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
} else {
|
|
65
|
-
parts = [
|
|
66
|
-
{
|
|
67
|
-
type: "text",
|
|
68
|
-
content: m.content
|
|
69
|
-
}
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
role,
|
|
74
|
-
parts
|
|
75
|
-
};
|
|
76
|
-
})
|
|
77
|
-
);
|
|
60
|
+
}
|
|
61
|
+
return acc;
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
mastraMetadata: {},
|
|
65
|
+
mastraOther: {}
|
|
78
66
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return inputOutputString;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// src/openInferenceOTLPExporter.ts
|
|
67
|
+
);
|
|
68
|
+
}
|
|
86
69
|
var OpenInferenceOTLPTraceExporter = class extends OTLPTraceExporter {
|
|
87
70
|
export(spans, resultCallback) {
|
|
88
71
|
const processedSpans = spans.map((span) => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
if (span.attributes?.["gen_ai.completion"] && typeof span.attributes["gen_ai.completion"] === "string") {
|
|
95
|
-
span.attributes["gen_ai.output.messages"] = convertMastraMessagesToGenAIMessages(
|
|
96
|
-
span.attributes["gen_ai.completion"]
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
const processedAttributes = convertGenAISpanAttributesToOpenInferenceSpanAttributes(span.attributes);
|
|
72
|
+
const attributes = { ...span.attributes ?? {} };
|
|
73
|
+
const mutableSpan = span;
|
|
74
|
+
const { mastraMetadata, mastraOther } = splitMastraAttributes(attributes);
|
|
75
|
+
const processedAttributes = convertGenAISpanAttributesToOpenInferenceSpanAttributes(attributes);
|
|
100
76
|
if (processedAttributes) {
|
|
101
|
-
|
|
77
|
+
const threadId = mastraMetadata["threadId"];
|
|
78
|
+
if (threadId) {
|
|
79
|
+
delete mastraMetadata["threadId"];
|
|
80
|
+
processedAttributes[SESSION_ID] = threadId;
|
|
81
|
+
}
|
|
82
|
+
if (mastraOther["mastra.tags"]) {
|
|
83
|
+
processedAttributes[TAG_TAGS] = mastraOther["mastra.tags"];
|
|
84
|
+
delete mastraOther["mastra.tags"];
|
|
85
|
+
}
|
|
86
|
+
const userId = mastraMetadata["userId"];
|
|
87
|
+
if (userId) {
|
|
88
|
+
delete mastraMetadata["userId"];
|
|
89
|
+
processedAttributes[USER_ID] = userId;
|
|
90
|
+
}
|
|
91
|
+
if (Object.keys(mastraMetadata).length > 0) {
|
|
92
|
+
try {
|
|
93
|
+
processedAttributes[METADATA] = JSON.stringify(mastraMetadata);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const inputMessages = attributes[ATTR_GEN_AI_INPUT_MESSAGES];
|
|
98
|
+
if (inputMessages) {
|
|
99
|
+
processedAttributes[INPUT_MIME_TYPE] = "application/json";
|
|
100
|
+
processedAttributes[INPUT_VALUE] = inputMessages;
|
|
101
|
+
}
|
|
102
|
+
const outputMessages = attributes[ATTR_GEN_AI_OUTPUT_MESSAGES];
|
|
103
|
+
if (outputMessages) {
|
|
104
|
+
processedAttributes[OUTPUT_MIME_TYPE] = "application/json";
|
|
105
|
+
processedAttributes[OUTPUT_VALUE] = outputMessages;
|
|
106
|
+
}
|
|
107
|
+
const usageMetrics = convertUsageMetricsToOpenInference(attributes);
|
|
108
|
+
Object.assign(processedAttributes, usageMetrics);
|
|
109
|
+
mutableSpan.attributes = { ...processedAttributes, ...mastraOther };
|
|
102
110
|
}
|
|
103
|
-
return
|
|
111
|
+
return mutableSpan;
|
|
104
112
|
});
|
|
105
113
|
super.export(processedSpans, resultCallback);
|
|
106
114
|
}
|
|
@@ -111,21 +119,41 @@ var LOG_PREFIX = "[ArizeExporter]";
|
|
|
111
119
|
var ARIZE_AX_ENDPOINT = "https://otlp.arize.com/v1/traces";
|
|
112
120
|
var ArizeExporter = class extends OtelExporter {
|
|
113
121
|
name = "arize";
|
|
114
|
-
constructor(config) {
|
|
115
|
-
const
|
|
116
|
-
|
|
122
|
+
constructor(config = {}) {
|
|
123
|
+
const spaceId = config.spaceId ?? process.env.ARIZE_SPACE_ID;
|
|
124
|
+
const apiKey = config.apiKey ?? process.env.ARIZE_API_KEY ?? process.env.PHOENIX_API_KEY;
|
|
125
|
+
const projectName = config.projectName ?? process.env.ARIZE_PROJECT_NAME ?? process.env.PHOENIX_PROJECT_NAME;
|
|
126
|
+
let endpoint = config.endpoint ?? process.env.PHOENIX_ENDPOINT;
|
|
117
127
|
const headers = {
|
|
118
128
|
...config.headers
|
|
119
129
|
};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
let disabledReason;
|
|
131
|
+
if (spaceId) {
|
|
132
|
+
if (!apiKey) {
|
|
133
|
+
disabledReason = `${LOG_PREFIX} API key is required for Arize AX. Set ARIZE_API_KEY environment variable or pass apiKey in config.`;
|
|
134
|
+
} else {
|
|
135
|
+
headers["space_id"] = spaceId;
|
|
136
|
+
headers["api_key"] = apiKey;
|
|
137
|
+
endpoint = endpoint || ARIZE_AX_ENDPOINT;
|
|
138
|
+
}
|
|
139
|
+
} else if (apiKey) {
|
|
140
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
141
|
+
}
|
|
142
|
+
if (!disabledReason && !endpoint) {
|
|
143
|
+
disabledReason = `${LOG_PREFIX} Endpoint is required in configuration. Set PHOENIX_ENDPOINT environment variable, or ARIZE_SPACE_ID for Arize AX, or pass endpoint in config.`;
|
|
126
144
|
}
|
|
127
|
-
if (
|
|
128
|
-
|
|
145
|
+
if (disabledReason) {
|
|
146
|
+
super({
|
|
147
|
+
...config,
|
|
148
|
+
provider: {
|
|
149
|
+
custom: {
|
|
150
|
+
endpoint: "http://disabled",
|
|
151
|
+
headers: {},
|
|
152
|
+
protocol: "http/protobuf"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
this.setDisabled(disabledReason);
|
|
129
157
|
return;
|
|
130
158
|
}
|
|
131
159
|
super({
|
|
@@ -135,7 +163,7 @@ var ArizeExporter = class extends OtelExporter {
|
|
|
135
163
|
}),
|
|
136
164
|
...config,
|
|
137
165
|
resourceAttributes: {
|
|
138
|
-
[SEMRESATTRS_PROJECT_NAME]:
|
|
166
|
+
...projectName ? { [SEMRESATTRS_PROJECT_NAME]: projectName } : {},
|
|
139
167
|
...config.resourceAttributes
|
|
140
168
|
},
|
|
141
169
|
provider: {
|