@mastra/arthur 0.2.7 → 0.2.8-alpha.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/CHANGELOG.md +25 -0
- package/dist/index.cjs +8 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @mastra/arthur
|
|
2
2
|
|
|
3
|
+
## 0.2.8-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`1723e09`](https://github.com/mastra-ai/mastra/commit/1723e099829892419ddbfe49287acfeac2522724), [`629f9e9`](https://github.com/mastra-ai/mastra/commit/629f9e9a7e56aa8f129515a3923c5813298790c7), [`25168fb`](https://github.com/mastra-ai/mastra/commit/25168fb9c1de9db7f8171df4f58ceb842c53aa29), [`ab34b5a`](https://github.com/mastra-ai/mastra/commit/ab34b5a2191b8e4353df1dbf7b9155e7d6628d79), [`5fb6c2a`](https://github.com/mastra-ai/mastra/commit/5fb6c2a95c1843cc231704b91354311fc1f34a71), [`394f0cf`](https://github.com/mastra-ai/mastra/commit/394f0cfc31e6b4d801219fdef2e9cc69e5bc8682), [`3d7f709`](https://github.com/mastra-ai/mastra/commit/3d7f709b615e588050bb6283c4ee5cfe2978cbde), [`48a42f1`](https://github.com/mastra-ai/mastra/commit/48a42f114a4006a95e0b7a1b5ad1a24815a175c2), [`2c83efc`](https://github.com/mastra-ai/mastra/commit/2c83efc4482b3efe50830e3b8b4ba9a8d219edff), [`282a10c`](https://github.com/mastra-ai/mastra/commit/282a10c9446e9922afe80e10e3770481c8ac8a28)]:
|
|
8
|
+
- @mastra/core@1.31.0-alpha.0
|
|
9
|
+
- @mastra/otel-exporter@1.0.21-alpha.1
|
|
10
|
+
|
|
11
|
+
## 0.2.8-alpha.0
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: ([#15966](https://github.com/mastra-ai/mastra/pull/15966))
|
|
16
|
+
- `gen_ai.usage.cached_input_tokens` → `gen_ai.usage.cache_read.input_tokens`
|
|
17
|
+
- `gen_ai.usage.cache_write_tokens` → `gen_ai.usage.cache_creation.input_tokens`
|
|
18
|
+
|
|
19
|
+
`gen_ai.usage.input_tokens` is unchanged and remains the total prompt-token count. Cache attributes are emitted separately as subsets of that total.
|
|
20
|
+
|
|
21
|
+
Updated Arize, Arthur, and Sentry mappings so cache values continue to flow through those exporters.
|
|
22
|
+
|
|
23
|
+
Direct consumers should update any dashboards, alerts, or queries that reference the old attribute names.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [[`724ec57`](https://github.com/mastra-ai/mastra/commit/724ec5736c4b0baf84d3baa7877ac3cf04947995)]:
|
|
26
|
+
- @mastra/otel-exporter@1.0.21-alpha.0
|
|
27
|
+
|
|
3
28
|
## 0.2.7
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -8,8 +8,8 @@ var incubating = require('@opentelemetry/semantic-conventions/incubating');
|
|
|
8
8
|
|
|
9
9
|
// src/tracing.ts
|
|
10
10
|
var GEN_AI_USAGE_REASONING_TOKENS = "gen_ai.usage.reasoning_tokens";
|
|
11
|
-
var
|
|
12
|
-
var
|
|
11
|
+
var GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS = "gen_ai.usage.cache_read.input_tokens";
|
|
12
|
+
var GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS = "gen_ai.usage.cache_creation.input_tokens";
|
|
13
13
|
var GEN_AI_USAGE_AUDIO_INPUT_TOKENS = "gen_ai.usage.audio_input_tokens";
|
|
14
14
|
var GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS = "gen_ai.usage.audio_output_tokens";
|
|
15
15
|
var MASTRA_GENERAL_PREFIX = "mastra.";
|
|
@@ -42,13 +42,13 @@ function convertUsageMetricsToOpenInference(attributes) {
|
|
|
42
42
|
if (inputTokens !== void 0 && outputTokens !== void 0) {
|
|
43
43
|
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_TOTAL] = inputTokens + outputTokens;
|
|
44
44
|
}
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
47
|
-
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] =
|
|
45
|
+
const cacheReadInputTokens = attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS];
|
|
46
|
+
if (cacheReadInputTokens !== void 0) {
|
|
47
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cacheReadInputTokens;
|
|
48
48
|
}
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] =
|
|
49
|
+
const cacheCreationInputTokens = attributes[GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS];
|
|
50
|
+
if (cacheCreationInputTokens !== void 0) {
|
|
51
|
+
result[openinferenceSemanticConventions.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheCreationInputTokens;
|
|
52
52
|
}
|
|
53
53
|
const reasoningTokens = attributes[GEN_AI_USAGE_REASONING_TOKENS];
|
|
54
54
|
if (reasoningTokens !== void 0) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/openInferenceOTLPExporter.ts","../src/tracing.ts"],"names":["OpenInferenceSpanKind","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","ATTR_GEN_AI_TOOL_CALL_ARGUMENTS","INPUT_MIME_TYPE","INPUT_VALUE","ATTR_GEN_AI_OUTPUT_MESSAGES","ATTR_GEN_AI_TOOL_CALL_RESULT","OUTPUT_MIME_TYPE","OUTPUT_VALUE","SemanticConventions","OtelExporter"],"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 OpenInferenceSpanKind,\n OUTPUT_MIME_TYPE,\n OUTPUT_VALUE,\n SemanticConventions,\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 ATTR_GEN_AI_TOOL_CALL_ARGUMENTS,\n ATTR_GEN_AI_TOOL_CALL_RESULT,\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.';\nconst MASTRA_MODEL_STEP_INPUT = 'mastra.model_step.input';\nconst MASTRA_MODEL_STEP_OUTPUT = 'mastra.model_step.output';\nconst MASTRA_MODEL_CHUNK_OUTPUT = 'mastra.model_chunk.output';\nconst MASTRA_SPAN_TYPE = 'mastra.span.type';\n\n/**\n * Maps Mastra span types to OpenInference span kinds for proper trace categorization.\n *\n * Only non-CHAIN types are mapped here - all other span types default to CHAIN.\n */\nconst SPAN_TYPE_TO_KIND: Record<string, OpenInferenceSpanKind> = {\n // Model spans -> LLM\n model_generation: OpenInferenceSpanKind.LLM,\n model_step: OpenInferenceSpanKind.LLM,\n model_chunk: OpenInferenceSpanKind.LLM,\n // Tool spans -> TOOL\n tool_call: OpenInferenceSpanKind.TOOL,\n mcp_tool_call: OpenInferenceSpanKind.TOOL,\n // Agent spans -> AGENT\n agent_run: OpenInferenceSpanKind.AGENT,\n};\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 =\n attributes[ATTR_GEN_AI_INPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_ARGUMENTS] ??\n mastraOther[MASTRA_MODEL_STEP_INPUT];\n if (inputMessages) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = inputMessages;\n }\n const outputMessages =\n attributes[ATTR_GEN_AI_OUTPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_RESULT] ??\n mastraOther[MASTRA_MODEL_STEP_OUTPUT] ??\n mastraOther[MASTRA_MODEL_CHUNK_OUTPUT];\n if (outputMessages) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = outputMessages;\n }\n\n // Map generic Mastra span input/output to OpenInference input/output\n // These are set by Mastra's gen-ai-semantics.ts for non-LLM/tool spans\n // (e.g., mastra.processor_run.input, mastra.workflow_run.input, etc.)\n if (!processedAttributes[INPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.input')) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = mastraOther[key];\n break;\n }\n }\n }\n if (!processedAttributes[OUTPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.output')) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = mastraOther[key];\n break;\n }\n }\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 // Set span kind based on mastra.span.type for proper trace categorization\n const spanType = mastraOther[MASTRA_SPAN_TYPE];\n if (typeof spanType === 'string') {\n mutableSpan.attributes[SemanticConventions.OPENINFERENCE_SPAN_KIND] =\n SPAN_TYPE_TO_KIND[spanType] ?? OpenInferenceSpanKind.CHAIN;\n }\n }\n\n return mutableSpan;\n });\n\n super.export(processedSpans, resultCallback);\n }\n}\n","import type { InitExporterOptions } from '@mastra/core/observability';\nimport { OtelExporter } from '@mastra/otel-exporter';\nimport type { OtelExporterConfig } from '@mastra/otel-exporter';\n\nimport { OpenInferenceOTLPTraceExporter } from './openInferenceOTLPExporter.js';\n\nconst LOG_PREFIX = '[ArthurExporter]';\n\nexport type ArthurExporterConfig = Omit<OtelExporterConfig, 'provider' | 'exporter'> & {\n /**\n * Arthur API key for authentication.\n * Falls back to ARTHUR_API_KEY environment variable.\n */\n apiKey?: string;\n /**\n * Arthur platform endpoint (e.g. https://app.arthur.ai).\n * Falls back to ARTHUR_BASE_URL environment variable.\n */\n endpoint?: string;\n /**\n * Arthur task ID to associate traces with.\n * Falls back to ARTHUR_TASK_ID environment variable.\n * At least one of taskId or serviceName (from the observability config) should be provided.\n */\n taskId?: string;\n /**\n * Optional headers to be added to each OTLP request.\n * Note: the Authorization header is managed internally when apiKey is provided.\n */\n headers?: Record<string, string>;\n};\n\n/**\n * Exports Mastra traces to Arthur AI using OpenInference semantic conventions.\n *\n * Supports zero-config setup via environment variables (ARTHUR_API_KEY, ARTHUR_BASE_URL,\n * ARTHUR_TASK_ID) or explicit configuration. Automatically disables itself with a warning\n * when required credentials are missing.\n *\n * @example\n * ```ts\n * const mastra = new Mastra({\n * observability: new Observability({\n * configs: {\n * arthur: {\n * serviceName: 'my-service',\n * exporters: [new ArthurExporter()],\n * },\n * },\n * }),\n * });\n * ```\n */\nexport class ArthurExporter extends OtelExporter {\n name = 'arthur';\n private taskId?: string;\n\n /**\n * @param config - Arthur exporter configuration. All fields are optional when\n * the corresponding environment variables are set.\n */\n constructor(config: ArthurExporterConfig = {}) {\n const apiKey = config.apiKey ?? process.env.ARTHUR_API_KEY;\n const endpoint = config.endpoint ?? process.env.ARTHUR_BASE_URL;\n const taskId = config.taskId ?? process.env.ARTHUR_TASK_ID;\n\n const headers: Record<string, string> = {\n ...config.headers,\n };\n\n let disabledReason: string | undefined;\n\n if (!apiKey) {\n disabledReason =\n `${LOG_PREFIX} API key is required. ` + `Set ARTHUR_API_KEY environment variable or pass apiKey in config.`;\n } else {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n if (!disabledReason && !endpoint) {\n disabledReason =\n `${LOG_PREFIX} Endpoint is required. ` + `Set ARTHUR_BASE_URL environment variable or pass endpoint in config.`;\n }\n\n // Ensure the endpoint ends with /api/v1/traces\n const tracesEndpoint = endpoint ? `${stripTrailingSlashes(endpoint)}/api/v1/traces` : 'http://disabled';\n\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: tracesEndpoint,\n headers,\n }),\n ...config,\n resourceAttributes: {\n ...(taskId ? { 'arthur.task.id': taskId } : {}),\n ...config.resourceAttributes,\n },\n provider: {\n custom: {\n endpoint: tracesEndpoint,\n headers,\n protocol: 'http/protobuf',\n },\n } satisfies OtelExporterConfig['provider'],\n } satisfies OtelExporterConfig);\n\n this.taskId = taskId;\n }\n\n /**\n * Called after construction with the observability config.\n * Validates that traces can be routed to a task via either taskId or serviceName.\n */\n init(options: InitExporterOptions) {\n super.init(options);\n\n const serviceName = options.config?.serviceName;\n\n if (this.taskId && serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Both taskId and serviceName are set. Arthur Engine will use serviceName to route traces, ` +\n `ignoring the provided taskId.`,\n );\n } else if (!this.taskId && !serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Neither taskId nor serviceName is set. Set ARTHUR_TASK_ID environment variable, ` +\n `pass taskId in config, or set serviceName in the observability config so Arthur Engine can route traces to a task.`,\n );\n }\n }\n}\n\n/**\n * Remove trailing '/' characters procedurally. Avoids the polynomial\n * backtracking that a greedy regex like `/\\/+$/` can exhibit when the\n * input is attacker-controlled.\n */\nfunction stripTrailingSlashes(s: string): string {\n let end = s.length;\n while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) {\n end--;\n }\n return end === s.length ? s : s.slice(0, end);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/openInferenceOTLPExporter.ts","../src/tracing.ts"],"names":["OpenInferenceSpanKind","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","ATTR_GEN_AI_TOOL_CALL_ARGUMENTS","INPUT_MIME_TYPE","INPUT_VALUE","ATTR_GEN_AI_OUTPUT_MESSAGES","ATTR_GEN_AI_TOOL_CALL_RESULT","OUTPUT_MIME_TYPE","OUTPUT_VALUE","SemanticConventions","OtelExporter"],"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 OpenInferenceSpanKind,\n OUTPUT_MIME_TYPE,\n OUTPUT_VALUE,\n SemanticConventions,\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 ATTR_GEN_AI_TOOL_CALL_ARGUMENTS,\n ATTR_GEN_AI_TOOL_CALL_RESULT,\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_CACHE_READ_INPUT_TOKENS = 'gen_ai.usage.cache_read.input_tokens';\nconst GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS = 'gen_ai.usage.cache_creation.input_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.';\nconst MASTRA_MODEL_STEP_INPUT = 'mastra.model_step.input';\nconst MASTRA_MODEL_STEP_OUTPUT = 'mastra.model_step.output';\nconst MASTRA_MODEL_CHUNK_OUTPUT = 'mastra.model_chunk.output';\nconst MASTRA_SPAN_TYPE = 'mastra.span.type';\n\n/**\n * Maps Mastra span types to OpenInference span kinds for proper trace categorization.\n *\n * Only non-CHAIN types are mapped here - all other span types default to CHAIN.\n */\nconst SPAN_TYPE_TO_KIND: Record<string, OpenInferenceSpanKind> = {\n // Model spans -> LLM\n model_generation: OpenInferenceSpanKind.LLM,\n model_step: OpenInferenceSpanKind.LLM,\n model_chunk: OpenInferenceSpanKind.LLM,\n // Tool spans -> TOOL\n tool_call: OpenInferenceSpanKind.TOOL,\n mcp_tool_call: OpenInferenceSpanKind.TOOL,\n // Agent spans -> AGENT\n agent_run: OpenInferenceSpanKind.AGENT,\n};\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 cacheReadInputTokens = attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS];\n if (cacheReadInputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cacheReadInputTokens;\n }\n\n const cacheCreationInputTokens = attributes[GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS];\n if (cacheCreationInputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheCreationInputTokens;\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 =\n attributes[ATTR_GEN_AI_INPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_ARGUMENTS] ??\n mastraOther[MASTRA_MODEL_STEP_INPUT];\n if (inputMessages) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = inputMessages;\n }\n const outputMessages =\n attributes[ATTR_GEN_AI_OUTPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_RESULT] ??\n mastraOther[MASTRA_MODEL_STEP_OUTPUT] ??\n mastraOther[MASTRA_MODEL_CHUNK_OUTPUT];\n if (outputMessages) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = outputMessages;\n }\n\n // Map generic Mastra span input/output to OpenInference input/output\n // These are set by Mastra's gen-ai-semantics.ts for non-LLM/tool spans\n // (e.g., mastra.processor_run.input, mastra.workflow_run.input, etc.)\n if (!processedAttributes[INPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.input')) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = mastraOther[key];\n break;\n }\n }\n }\n if (!processedAttributes[OUTPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.output')) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = mastraOther[key];\n break;\n }\n }\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 // Set span kind based on mastra.span.type for proper trace categorization\n const spanType = mastraOther[MASTRA_SPAN_TYPE];\n if (typeof spanType === 'string') {\n mutableSpan.attributes[SemanticConventions.OPENINFERENCE_SPAN_KIND] =\n SPAN_TYPE_TO_KIND[spanType] ?? OpenInferenceSpanKind.CHAIN;\n }\n }\n\n return mutableSpan;\n });\n\n super.export(processedSpans, resultCallback);\n }\n}\n","import type { InitExporterOptions } from '@mastra/core/observability';\nimport { OtelExporter } from '@mastra/otel-exporter';\nimport type { OtelExporterConfig } from '@mastra/otel-exporter';\n\nimport { OpenInferenceOTLPTraceExporter } from './openInferenceOTLPExporter.js';\n\nconst LOG_PREFIX = '[ArthurExporter]';\n\nexport type ArthurExporterConfig = Omit<OtelExporterConfig, 'provider' | 'exporter'> & {\n /**\n * Arthur API key for authentication.\n * Falls back to ARTHUR_API_KEY environment variable.\n */\n apiKey?: string;\n /**\n * Arthur platform endpoint (e.g. https://app.arthur.ai).\n * Falls back to ARTHUR_BASE_URL environment variable.\n */\n endpoint?: string;\n /**\n * Arthur task ID to associate traces with.\n * Falls back to ARTHUR_TASK_ID environment variable.\n * At least one of taskId or serviceName (from the observability config) should be provided.\n */\n taskId?: string;\n /**\n * Optional headers to be added to each OTLP request.\n * Note: the Authorization header is managed internally when apiKey is provided.\n */\n headers?: Record<string, string>;\n};\n\n/**\n * Exports Mastra traces to Arthur AI using OpenInference semantic conventions.\n *\n * Supports zero-config setup via environment variables (ARTHUR_API_KEY, ARTHUR_BASE_URL,\n * ARTHUR_TASK_ID) or explicit configuration. Automatically disables itself with a warning\n * when required credentials are missing.\n *\n * @example\n * ```ts\n * const mastra = new Mastra({\n * observability: new Observability({\n * configs: {\n * arthur: {\n * serviceName: 'my-service',\n * exporters: [new ArthurExporter()],\n * },\n * },\n * }),\n * });\n * ```\n */\nexport class ArthurExporter extends OtelExporter {\n name = 'arthur';\n private taskId?: string;\n\n /**\n * @param config - Arthur exporter configuration. All fields are optional when\n * the corresponding environment variables are set.\n */\n constructor(config: ArthurExporterConfig = {}) {\n const apiKey = config.apiKey ?? process.env.ARTHUR_API_KEY;\n const endpoint = config.endpoint ?? process.env.ARTHUR_BASE_URL;\n const taskId = config.taskId ?? process.env.ARTHUR_TASK_ID;\n\n const headers: Record<string, string> = {\n ...config.headers,\n };\n\n let disabledReason: string | undefined;\n\n if (!apiKey) {\n disabledReason =\n `${LOG_PREFIX} API key is required. ` + `Set ARTHUR_API_KEY environment variable or pass apiKey in config.`;\n } else {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n if (!disabledReason && !endpoint) {\n disabledReason =\n `${LOG_PREFIX} Endpoint is required. ` + `Set ARTHUR_BASE_URL environment variable or pass endpoint in config.`;\n }\n\n // Ensure the endpoint ends with /api/v1/traces\n const tracesEndpoint = endpoint ? `${stripTrailingSlashes(endpoint)}/api/v1/traces` : 'http://disabled';\n\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: tracesEndpoint,\n headers,\n }),\n ...config,\n resourceAttributes: {\n ...(taskId ? { 'arthur.task.id': taskId } : {}),\n ...config.resourceAttributes,\n },\n provider: {\n custom: {\n endpoint: tracesEndpoint,\n headers,\n protocol: 'http/protobuf',\n },\n } satisfies OtelExporterConfig['provider'],\n } satisfies OtelExporterConfig);\n\n this.taskId = taskId;\n }\n\n /**\n * Called after construction with the observability config.\n * Validates that traces can be routed to a task via either taskId or serviceName.\n */\n init(options: InitExporterOptions) {\n super.init(options);\n\n const serviceName = options.config?.serviceName;\n\n if (this.taskId && serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Both taskId and serviceName are set. Arthur Engine will use serviceName to route traces, ` +\n `ignoring the provided taskId.`,\n );\n } else if (!this.taskId && !serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Neither taskId nor serviceName is set. Set ARTHUR_TASK_ID environment variable, ` +\n `pass taskId in config, or set serviceName in the observability config so Arthur Engine can route traces to a task.`,\n );\n }\n }\n}\n\n/**\n * Remove trailing '/' characters procedurally. Avoids the polynomial\n * backtracking that a greedy regex like `/\\/+$/` can exhibit when the\n * input is attacker-controlled.\n */\nfunction stripTrailingSlashes(s: string): string {\n let end = s.length;\n while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) {\n end--;\n }\n return end === s.length ? s : s.slice(0, end);\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import { ATTR_GEN_AI_INPUT_MESSAGES, ATTR_GEN_AI_TOOL_CALL_ARGUMENTS, ATTR_GEN_A
|
|
|
6
6
|
|
|
7
7
|
// src/tracing.ts
|
|
8
8
|
var GEN_AI_USAGE_REASONING_TOKENS = "gen_ai.usage.reasoning_tokens";
|
|
9
|
-
var
|
|
10
|
-
var
|
|
9
|
+
var GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS = "gen_ai.usage.cache_read.input_tokens";
|
|
10
|
+
var GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS = "gen_ai.usage.cache_creation.input_tokens";
|
|
11
11
|
var GEN_AI_USAGE_AUDIO_INPUT_TOKENS = "gen_ai.usage.audio_input_tokens";
|
|
12
12
|
var GEN_AI_USAGE_AUDIO_OUTPUT_TOKENS = "gen_ai.usage.audio_output_tokens";
|
|
13
13
|
var MASTRA_GENERAL_PREFIX = "mastra.";
|
|
@@ -40,13 +40,13 @@ function convertUsageMetricsToOpenInference(attributes) {
|
|
|
40
40
|
if (inputTokens !== void 0 && outputTokens !== void 0) {
|
|
41
41
|
result[LLM_TOKEN_COUNT_TOTAL] = inputTokens + outputTokens;
|
|
42
42
|
}
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] =
|
|
43
|
+
const cacheReadInputTokens = attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS];
|
|
44
|
+
if (cacheReadInputTokens !== void 0) {
|
|
45
|
+
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cacheReadInputTokens;
|
|
46
46
|
}
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] =
|
|
47
|
+
const cacheCreationInputTokens = attributes[GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS];
|
|
48
|
+
if (cacheCreationInputTokens !== void 0) {
|
|
49
|
+
result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheCreationInputTokens;
|
|
50
50
|
}
|
|
51
51
|
const reasoningTokens = attributes[GEN_AI_USAGE_REASONING_TOKENS];
|
|
52
52
|
if (reasoningTokens !== void 0) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/openInferenceOTLPExporter.ts","../src/tracing.ts"],"names":[],"mappings":"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","file":"index.js","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 OpenInferenceSpanKind,\n OUTPUT_MIME_TYPE,\n OUTPUT_VALUE,\n SemanticConventions,\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 ATTR_GEN_AI_TOOL_CALL_ARGUMENTS,\n ATTR_GEN_AI_TOOL_CALL_RESULT,\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.';\nconst MASTRA_MODEL_STEP_INPUT = 'mastra.model_step.input';\nconst MASTRA_MODEL_STEP_OUTPUT = 'mastra.model_step.output';\nconst MASTRA_MODEL_CHUNK_OUTPUT = 'mastra.model_chunk.output';\nconst MASTRA_SPAN_TYPE = 'mastra.span.type';\n\n/**\n * Maps Mastra span types to OpenInference span kinds for proper trace categorization.\n *\n * Only non-CHAIN types are mapped here - all other span types default to CHAIN.\n */\nconst SPAN_TYPE_TO_KIND: Record<string, OpenInferenceSpanKind> = {\n // Model spans -> LLM\n model_generation: OpenInferenceSpanKind.LLM,\n model_step: OpenInferenceSpanKind.LLM,\n model_chunk: OpenInferenceSpanKind.LLM,\n // Tool spans -> TOOL\n tool_call: OpenInferenceSpanKind.TOOL,\n mcp_tool_call: OpenInferenceSpanKind.TOOL,\n // Agent spans -> AGENT\n agent_run: OpenInferenceSpanKind.AGENT,\n};\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 =\n attributes[ATTR_GEN_AI_INPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_ARGUMENTS] ??\n mastraOther[MASTRA_MODEL_STEP_INPUT];\n if (inputMessages) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = inputMessages;\n }\n const outputMessages =\n attributes[ATTR_GEN_AI_OUTPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_RESULT] ??\n mastraOther[MASTRA_MODEL_STEP_OUTPUT] ??\n mastraOther[MASTRA_MODEL_CHUNK_OUTPUT];\n if (outputMessages) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = outputMessages;\n }\n\n // Map generic Mastra span input/output to OpenInference input/output\n // These are set by Mastra's gen-ai-semantics.ts for non-LLM/tool spans\n // (e.g., mastra.processor_run.input, mastra.workflow_run.input, etc.)\n if (!processedAttributes[INPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.input')) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = mastraOther[key];\n break;\n }\n }\n }\n if (!processedAttributes[OUTPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.output')) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = mastraOther[key];\n break;\n }\n }\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 // Set span kind based on mastra.span.type for proper trace categorization\n const spanType = mastraOther[MASTRA_SPAN_TYPE];\n if (typeof spanType === 'string') {\n mutableSpan.attributes[SemanticConventions.OPENINFERENCE_SPAN_KIND] =\n SPAN_TYPE_TO_KIND[spanType] ?? OpenInferenceSpanKind.CHAIN;\n }\n }\n\n return mutableSpan;\n });\n\n super.export(processedSpans, resultCallback);\n }\n}\n","import type { InitExporterOptions } from '@mastra/core/observability';\nimport { OtelExporter } from '@mastra/otel-exporter';\nimport type { OtelExporterConfig } from '@mastra/otel-exporter';\n\nimport { OpenInferenceOTLPTraceExporter } from './openInferenceOTLPExporter.js';\n\nconst LOG_PREFIX = '[ArthurExporter]';\n\nexport type ArthurExporterConfig = Omit<OtelExporterConfig, 'provider' | 'exporter'> & {\n /**\n * Arthur API key for authentication.\n * Falls back to ARTHUR_API_KEY environment variable.\n */\n apiKey?: string;\n /**\n * Arthur platform endpoint (e.g. https://app.arthur.ai).\n * Falls back to ARTHUR_BASE_URL environment variable.\n */\n endpoint?: string;\n /**\n * Arthur task ID to associate traces with.\n * Falls back to ARTHUR_TASK_ID environment variable.\n * At least one of taskId or serviceName (from the observability config) should be provided.\n */\n taskId?: string;\n /**\n * Optional headers to be added to each OTLP request.\n * Note: the Authorization header is managed internally when apiKey is provided.\n */\n headers?: Record<string, string>;\n};\n\n/**\n * Exports Mastra traces to Arthur AI using OpenInference semantic conventions.\n *\n * Supports zero-config setup via environment variables (ARTHUR_API_KEY, ARTHUR_BASE_URL,\n * ARTHUR_TASK_ID) or explicit configuration. Automatically disables itself with a warning\n * when required credentials are missing.\n *\n * @example\n * ```ts\n * const mastra = new Mastra({\n * observability: new Observability({\n * configs: {\n * arthur: {\n * serviceName: 'my-service',\n * exporters: [new ArthurExporter()],\n * },\n * },\n * }),\n * });\n * ```\n */\nexport class ArthurExporter extends OtelExporter {\n name = 'arthur';\n private taskId?: string;\n\n /**\n * @param config - Arthur exporter configuration. All fields are optional when\n * the corresponding environment variables are set.\n */\n constructor(config: ArthurExporterConfig = {}) {\n const apiKey = config.apiKey ?? process.env.ARTHUR_API_KEY;\n const endpoint = config.endpoint ?? process.env.ARTHUR_BASE_URL;\n const taskId = config.taskId ?? process.env.ARTHUR_TASK_ID;\n\n const headers: Record<string, string> = {\n ...config.headers,\n };\n\n let disabledReason: string | undefined;\n\n if (!apiKey) {\n disabledReason =\n `${LOG_PREFIX} API key is required. ` + `Set ARTHUR_API_KEY environment variable or pass apiKey in config.`;\n } else {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n if (!disabledReason && !endpoint) {\n disabledReason =\n `${LOG_PREFIX} Endpoint is required. ` + `Set ARTHUR_BASE_URL environment variable or pass endpoint in config.`;\n }\n\n // Ensure the endpoint ends with /api/v1/traces\n const tracesEndpoint = endpoint ? `${stripTrailingSlashes(endpoint)}/api/v1/traces` : 'http://disabled';\n\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: tracesEndpoint,\n headers,\n }),\n ...config,\n resourceAttributes: {\n ...(taskId ? { 'arthur.task.id': taskId } : {}),\n ...config.resourceAttributes,\n },\n provider: {\n custom: {\n endpoint: tracesEndpoint,\n headers,\n protocol: 'http/protobuf',\n },\n } satisfies OtelExporterConfig['provider'],\n } satisfies OtelExporterConfig);\n\n this.taskId = taskId;\n }\n\n /**\n * Called after construction with the observability config.\n * Validates that traces can be routed to a task via either taskId or serviceName.\n */\n init(options: InitExporterOptions) {\n super.init(options);\n\n const serviceName = options.config?.serviceName;\n\n if (this.taskId && serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Both taskId and serviceName are set. Arthur Engine will use serviceName to route traces, ` +\n `ignoring the provided taskId.`,\n );\n } else if (!this.taskId && !serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Neither taskId nor serviceName is set. Set ARTHUR_TASK_ID environment variable, ` +\n `pass taskId in config, or set serviceName in the observability config so Arthur Engine can route traces to a task.`,\n );\n }\n }\n}\n\n/**\n * Remove trailing '/' characters procedurally. Avoids the polynomial\n * backtracking that a greedy regex like `/\\/+$/` can exhibit when the\n * input is attacker-controlled.\n */\nfunction stripTrailingSlashes(s: string): string {\n let end = s.length;\n while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) {\n end--;\n }\n return end === s.length ? s : s.slice(0, end);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/openInferenceOTLPExporter.ts","../src/tracing.ts"],"names":[],"mappings":";;;;;;;AAmCA,IAAM,6BAAA,GAAgC,+BAAA;AACtC,IAAM,oCAAA,GAAuC,sCAAA;AAC7C,IAAM,wCAAA,GAA2C,0CAAA;AACjD,IAAM,+BAAA,GAAkC,iCAAA;AACxC,IAAM,gCAAA,GAAmC,kCAAA;AAEzC,IAAM,qBAAA,GAAwB,SAAA;AAC9B,IAAM,sBAAA,GAAyB,kBAAA;AAC/B,IAAM,uBAAA,GAA0B,yBAAA;AAChC,IAAM,wBAAA,GAA2B,0BAAA;AACjC,IAAM,yBAAA,GAA4B,2BAAA;AAClC,IAAM,gBAAA,GAAmB,kBAAA;AAOzB,IAAM,iBAAA,GAA2D;AAAA;AAAA,EAE/D,kBAAkB,qBAAA,CAAsB,GAAA;AAAA,EACxC,YAAY,qBAAA,CAAsB,GAAA;AAAA,EAClC,aAAa,qBAAA,CAAsB,GAAA;AAAA;AAAA,EAEnC,WAAW,qBAAA,CAAsB,IAAA;AAAA,EACjC,eAAe,qBAAA,CAAsB,IAAA;AAAA;AAAA,EAErC,WAAW,qBAAA,CAAsB;AACnC,CAAA;AASA,SAAS,mCAAmC,UAAA,EAAsD;AAChG,EAAA,MAAM,SAA8B,EAAC;AAErC,EAAA,MAAM,WAAA,GAAc,WAAW,8BAA8B,CAAA;AAC7D,EAAA,MAAM,YAAA,GAAe,WAAW,+BAA+B,CAAA;AAG/D,EAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,IAAA,MAAA,CAAO,sBAAsB,CAAA,GAAI,WAAA;AAAA,EACnC;AACA,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,MAAA,CAAO,0BAA0B,CAAA,GAAI,YAAA;AAAA,EACvC;AAGA,EAAA,IAAI,WAAA,KAAgB,MAAA,IAAa,YAAA,KAAiB,MAAA,EAAW;AAC3D,IAAA,MAAA,CAAO,qBAAqB,IAAI,WAAA,GAAc,YAAA;AAAA,EAChD;AAGA,EAAA,MAAM,oBAAA,GAAuB,WAAW,oCAAoC,CAAA;AAC5E,EAAA,IAAI,yBAAyB,MAAA,EAAW;AACtC,IAAA,MAAA,CAAO,yCAAyC,CAAA,GAAI,oBAAA;AAAA,EACtD;AAEA,EAAA,MAAM,wBAAA,GAA2B,WAAW,wCAAwC,CAAA;AACpF,EAAA,IAAI,6BAA6B,MAAA,EAAW;AAC1C,IAAA,MAAA,CAAO,0CAA0C,CAAA,GAAI,wBAAA;AAAA,EACvD;AAGA,EAAA,MAAM,eAAA,GAAkB,WAAW,6BAA6B,CAAA;AAChE,EAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,IAAA,MAAA,CAAO,4CAA4C,CAAA,GAAI,eAAA;AAAA,EACzD;AAGA,EAAA,MAAM,gBAAA,GAAmB,WAAW,+BAA+B,CAAA;AACnE,EAAA,IAAI,qBAAqB,MAAA,EAAW;AAClC,IAAA,MAAA,CAAO,oCAAoC,CAAA,GAAI,gBAAA;AAAA,EACjD;AAEA,EAAA,MAAM,iBAAA,GAAoB,WAAW,gCAAgC,CAAA;AACrE,EAAA,IAAI,sBAAsB,MAAA,EAAW;AACnC,IAAA,MAAA,CAAO,wCAAwC,CAAA,GAAI,iBAAA;AAAA,EACrD;AAEA,EAAA,OAAO,MAAA;AACT;AASA,SAAS,sBAAsB,UAAA,EAG7B;AACA,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,CAAE,MAAA;AAAA,IAChC,CAAC,GAAA,EAAK,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACrB,MAAA,IAAI,GAAA,CAAI,UAAA,CAAW,qBAAqB,CAAA,EAAG;AACzC,QAAA,IAAI,GAAA,CAAI,UAAA,CAAW,sBAAsB,CAAA,EAAG;AAC1C,UAAA,MAAM,WAAA,GAAc,GAAA,CAAI,KAAA,CAAM,sBAAA,CAAuB,MAAM,CAAA;AAC3D,UAAA,GAAA,CAAI,cAAA,CAAe,WAAW,CAAA,GAAI,KAAA;AAAA,QACpC,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,WAAA,CAAY,GAAG,CAAA,GAAI,KAAA;AAAA,QACzB;AAAA,MACF;AACA,MAAA,OAAO,GAAA;AAAA,IACT,CAAA;AAAA,IACA;AAAA,MACE,gBAAgB,EAAC;AAAA,MACjB,aAAa;AAAC;AAChB,GACF;AACF;AAEO,IAAM,8BAAA,GAAN,cAA6C,iBAAA,CAAkB;AAAA,EACpE,MAAA,CAAO,OAAuB,cAAA,EAAgD;AAC5E,IAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AACvC,MAAA,MAAM,aAAa,EAAE,GAAI,IAAA,CAAK,UAAA,IAAc,EAAC,EAAG;AAChD,MAAA,MAAM,WAAA,GAAc,IAAA;AAEpB,MAAA,MAAM,EAAE,cAAA,EAAgB,WAAA,EAAY,GAAI,sBAAsB,UAAU,CAAA;AACxE,MAAA,MAAM,mBAAA,GAAsB,wDAAwD,UAAU,CAAA;AAG9F,MAAA,IAAI,mBAAA,EAAqB;AACvB,QAAA,MAAM,QAAA,GAAW,eAAe,UAAU,CAAA;AAC1C,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,OAAO,eAAe,UAAU,CAAA;AAChC,UAAA,mBAAA,CAAoB,UAAU,CAAA,GAAI,QAAA;AAAA,QACpC;AAGA,QAAA,IAAI,WAAA,CAAY,aAAa,CAAA,EAAG;AAC9B,UAAA,mBAAA,CAAoB,QAAQ,CAAA,GAAI,WAAA,CAAY,aAAa,CAAA;AACzD,UAAA,OAAO,YAAY,aAAa,CAAA;AAAA,QAClC;AAEA,QAAA,MAAM,MAAA,GAAS,eAAe,QAAQ,CAAA;AACtC,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,OAAO,eAAe,QAAQ,CAAA;AAC9B,UAAA,mBAAA,CAAoB,OAAO,CAAA,GAAI,MAAA;AAAA,QACjC;AAGA,QAAA,IAAI,MAAA,CAAO,IAAA,CAAK,cAAc,CAAA,CAAE,SAAS,CAAA,EAAG;AAC1C,UAAA,IAAI;AACF,YAAA,mBAAA,CAAoB,QAAQ,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,cAAc,CAAA;AAAA,UAC/D,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AAEA,QAAA,MAAM,aAAA,GACJ,WAAW,0BAA0B,CAAA,IACrC,WAAW,+BAA+B,CAAA,IAC1C,YAAY,uBAAuB,CAAA;AACrC,QAAA,IAAI,aAAA,EAAe;AACjB,UAAA,mBAAA,CAAoB,eAAe,CAAA,GAAI,kBAAA;AACvC,UAAA,mBAAA,CAAoB,WAAW,CAAA,GAAI,aAAA;AAAA,QACrC;AACA,QAAA,MAAM,cAAA,GACJ,UAAA,CAAW,2BAA2B,CAAA,IACtC,UAAA,CAAW,4BAA4B,CAAA,IACvC,WAAA,CAAY,wBAAwB,CAAA,IACpC,WAAA,CAAY,yBAAyB,CAAA;AACvC,QAAA,IAAI,cAAA,EAAgB;AAClB,UAAA,mBAAA,CAAoB,gBAAgB,CAAA,GAAI,kBAAA;AACxC,UAAA,mBAAA,CAAoB,YAAY,CAAA,GAAI,cAAA;AAAA,QACtC;AAKA,QAAA,IAAI,CAAC,mBAAA,CAAoB,WAAW,CAAA,EAAG;AACrC,UAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAAG;AAC1C,YAAA,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,EAAG;AAC1B,cAAA,mBAAA,CAAoB,eAAe,CAAA,GAAI,kBAAA;AACvC,cAAA,mBAAA,CAAoB,WAAW,CAAA,GAAI,WAAA,CAAY,GAAG,CAAA;AAClD,cAAA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,QAAA,IAAI,CAAC,mBAAA,CAAoB,YAAY,CAAA,EAAG;AACtC,UAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAAG;AAC1C,YAAA,IAAI,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AAC3B,cAAA,mBAAA,CAAoB,gBAAgB,CAAA,GAAI,kBAAA;AACxC,cAAA,mBAAA,CAAoB,YAAY,CAAA,GAAI,WAAA,CAAY,GAAG,CAAA;AACnD,cAAA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAGA,QAAA,MAAM,YAAA,GAAe,mCAAmC,UAAU,CAAA;AAClE,QAAA,MAAA,CAAO,MAAA,CAAO,qBAAqB,YAAY,CAAA;AAE/C,QAAA,WAAA,CAAY,UAAA,GAAa,EAAE,GAAG,mBAAA,EAAqB,GAAG,WAAA,EAAY;AAGlE,QAAA,MAAM,QAAA,GAAW,YAAY,gBAAgB,CAAA;AAC7C,QAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,UAAA,WAAA,CAAY,WAAW,mBAAA,CAAoB,uBAAuB,IAChE,iBAAA,CAAkB,QAAQ,KAAK,qBAAA,CAAsB,KAAA;AAAA,QACzD;AAAA,MACF;AAEA,MAAA,OAAO,WAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,KAAA,CAAM,MAAA,CAAO,gBAAgB,cAAc,CAAA;AAAA,EAC7C;AACF,CAAA;;;ACnPA,IAAM,UAAA,GAAa,kBAAA;AA+CZ,IAAM,cAAA,GAAN,cAA6B,YAAA,CAAa;AAAA,EAC/C,IAAA,GAAO,QAAA;AAAA,EACC,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,WAAA,CAAY,MAAA,GAA+B,EAAC,EAAG;AAC7C,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,cAAA;AAC5C,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,eAAA;AAChD,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,cAAA;AAE5C,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,GAAG,MAAA,CAAO;AAAA,KACZ;AAEA,IAAA,IAAI,cAAA;AAEJ,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,cAAA,GACE,GAAG,UAAU,CAAA,uFAAA,CAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,MAAM,CAAA,CAAA;AAAA,IAC7C;AAEA,IAAA,IAAI,CAAC,cAAA,IAAkB,CAAC,QAAA,EAAU;AAChC,MAAA,cAAA,GACE,GAAG,UAAU,CAAA,2FAAA,CAAA;AAAA,IACjB;AAGA,IAAA,MAAM,iBAAiB,QAAA,GAAW,CAAA,EAAG,oBAAA,CAAqB,QAAQ,CAAC,CAAA,cAAA,CAAA,GAAmB,iBAAA;AAEtF,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,KAAA,CAAM;AAAA,QACJ,GAAG,MAAA;AAAA,QACH,QAAA,EAAU;AAAA,UACR,MAAA,EAAQ;AAAA,YACN,QAAA,EAAU,iBAAA;AAAA,YACV,SAAS,EAAC;AAAA,YACV,QAAA,EAAU;AAAA;AACZ;AACF,OACD,CAAA;AACD,MAAA,IAAA,CAAK,YAAY,cAAc,CAAA;AAC/B,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM;AAAA,MACJ,QAAA,EAAU,IAAI,8BAAA,CAA+B;AAAA,QAC3C,GAAA,EAAK,cAAA;AAAA,QACL;AAAA,OACD,CAAA;AAAA,MACD,GAAG,MAAA;AAAA,MACH,kBAAA,EAAoB;AAAA,QAClB,GAAI,MAAA,GAAS,EAAE,gBAAA,EAAkB,MAAA,KAAW,EAAC;AAAA,QAC7C,GAAG,MAAA,CAAO;AAAA,OACZ;AAAA,MACA,QAAA,EAAU;AAAA,QACR,MAAA,EAAQ;AAAA,UACN,QAAA,EAAU,cAAA;AAAA,UACV,OAAA;AAAA,UACA,QAAA,EAAU;AAAA;AACZ;AACF,KAC4B,CAAA;AAE9B,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,OAAA,EAA8B;AACjC,IAAA,KAAA,CAAM,KAAK,OAAO,CAAA;AAElB,IAAA,MAAM,WAAA,GAAc,QAAQ,MAAA,EAAQ,WAAA;AAEpC,IAAA,IAAI,IAAA,CAAK,UAAU,WAAA,EAAa;AAC9B,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,QACV,GAAG,UAAU,CAAA,uHAAA;AAAA,OAEf;AAAA,IACF,CAAA,MAAA,IAAW,CAAC,IAAA,CAAK,MAAA,IAAU,CAAC,WAAA,EAAa;AACvC,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,QACV,GAAG,UAAU,CAAA,mMAAA;AAAA,OAEf;AAAA,IACF;AAAA,EACF;AACF;AAOA,SAAS,qBAAqB,CAAA,EAAmB;AAC/C,EAAA,IAAI,MAAM,CAAA,CAAE,MAAA;AACZ,EAAA,OAAO,MAAM,CAAA,IAAK,CAAA,CAAE,WAAW,GAAA,GAAM,CAAC,MAAM,EAAA,EAAc;AACxD,IAAA,GAAA,EAAA;AAAA,EACF;AACA,EAAA,OAAO,QAAQ,CAAA,CAAE,MAAA,GAAS,IAAI,CAAA,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AAC9C","file":"index.js","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 OpenInferenceSpanKind,\n OUTPUT_MIME_TYPE,\n OUTPUT_VALUE,\n SemanticConventions,\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 ATTR_GEN_AI_TOOL_CALL_ARGUMENTS,\n ATTR_GEN_AI_TOOL_CALL_RESULT,\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_CACHE_READ_INPUT_TOKENS = 'gen_ai.usage.cache_read.input_tokens';\nconst GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS = 'gen_ai.usage.cache_creation.input_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.';\nconst MASTRA_MODEL_STEP_INPUT = 'mastra.model_step.input';\nconst MASTRA_MODEL_STEP_OUTPUT = 'mastra.model_step.output';\nconst MASTRA_MODEL_CHUNK_OUTPUT = 'mastra.model_chunk.output';\nconst MASTRA_SPAN_TYPE = 'mastra.span.type';\n\n/**\n * Maps Mastra span types to OpenInference span kinds for proper trace categorization.\n *\n * Only non-CHAIN types are mapped here - all other span types default to CHAIN.\n */\nconst SPAN_TYPE_TO_KIND: Record<string, OpenInferenceSpanKind> = {\n // Model spans -> LLM\n model_generation: OpenInferenceSpanKind.LLM,\n model_step: OpenInferenceSpanKind.LLM,\n model_chunk: OpenInferenceSpanKind.LLM,\n // Tool spans -> TOOL\n tool_call: OpenInferenceSpanKind.TOOL,\n mcp_tool_call: OpenInferenceSpanKind.TOOL,\n // Agent spans -> AGENT\n agent_run: OpenInferenceSpanKind.AGENT,\n};\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 cacheReadInputTokens = attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS];\n if (cacheReadInputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ] = cacheReadInputTokens;\n }\n\n const cacheCreationInputTokens = attributes[GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS];\n if (cacheCreationInputTokens !== undefined) {\n result[LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE] = cacheCreationInputTokens;\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 =\n attributes[ATTR_GEN_AI_INPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_ARGUMENTS] ??\n mastraOther[MASTRA_MODEL_STEP_INPUT];\n if (inputMessages) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = inputMessages;\n }\n const outputMessages =\n attributes[ATTR_GEN_AI_OUTPUT_MESSAGES] ??\n attributes[ATTR_GEN_AI_TOOL_CALL_RESULT] ??\n mastraOther[MASTRA_MODEL_STEP_OUTPUT] ??\n mastraOther[MASTRA_MODEL_CHUNK_OUTPUT];\n if (outputMessages) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = outputMessages;\n }\n\n // Map generic Mastra span input/output to OpenInference input/output\n // These are set by Mastra's gen-ai-semantics.ts for non-LLM/tool spans\n // (e.g., mastra.processor_run.input, mastra.workflow_run.input, etc.)\n if (!processedAttributes[INPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.input')) {\n processedAttributes[INPUT_MIME_TYPE] = 'application/json';\n processedAttributes[INPUT_VALUE] = mastraOther[key];\n break;\n }\n }\n }\n if (!processedAttributes[OUTPUT_VALUE]) {\n for (const key of Object.keys(mastraOther)) {\n if (key.endsWith('.output')) {\n processedAttributes[OUTPUT_MIME_TYPE] = 'application/json';\n processedAttributes[OUTPUT_VALUE] = mastraOther[key];\n break;\n }\n }\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 // Set span kind based on mastra.span.type for proper trace categorization\n const spanType = mastraOther[MASTRA_SPAN_TYPE];\n if (typeof spanType === 'string') {\n mutableSpan.attributes[SemanticConventions.OPENINFERENCE_SPAN_KIND] =\n SPAN_TYPE_TO_KIND[spanType] ?? OpenInferenceSpanKind.CHAIN;\n }\n }\n\n return mutableSpan;\n });\n\n super.export(processedSpans, resultCallback);\n }\n}\n","import type { InitExporterOptions } from '@mastra/core/observability';\nimport { OtelExporter } from '@mastra/otel-exporter';\nimport type { OtelExporterConfig } from '@mastra/otel-exporter';\n\nimport { OpenInferenceOTLPTraceExporter } from './openInferenceOTLPExporter.js';\n\nconst LOG_PREFIX = '[ArthurExporter]';\n\nexport type ArthurExporterConfig = Omit<OtelExporterConfig, 'provider' | 'exporter'> & {\n /**\n * Arthur API key for authentication.\n * Falls back to ARTHUR_API_KEY environment variable.\n */\n apiKey?: string;\n /**\n * Arthur platform endpoint (e.g. https://app.arthur.ai).\n * Falls back to ARTHUR_BASE_URL environment variable.\n */\n endpoint?: string;\n /**\n * Arthur task ID to associate traces with.\n * Falls back to ARTHUR_TASK_ID environment variable.\n * At least one of taskId or serviceName (from the observability config) should be provided.\n */\n taskId?: string;\n /**\n * Optional headers to be added to each OTLP request.\n * Note: the Authorization header is managed internally when apiKey is provided.\n */\n headers?: Record<string, string>;\n};\n\n/**\n * Exports Mastra traces to Arthur AI using OpenInference semantic conventions.\n *\n * Supports zero-config setup via environment variables (ARTHUR_API_KEY, ARTHUR_BASE_URL,\n * ARTHUR_TASK_ID) or explicit configuration. Automatically disables itself with a warning\n * when required credentials are missing.\n *\n * @example\n * ```ts\n * const mastra = new Mastra({\n * observability: new Observability({\n * configs: {\n * arthur: {\n * serviceName: 'my-service',\n * exporters: [new ArthurExporter()],\n * },\n * },\n * }),\n * });\n * ```\n */\nexport class ArthurExporter extends OtelExporter {\n name = 'arthur';\n private taskId?: string;\n\n /**\n * @param config - Arthur exporter configuration. All fields are optional when\n * the corresponding environment variables are set.\n */\n constructor(config: ArthurExporterConfig = {}) {\n const apiKey = config.apiKey ?? process.env.ARTHUR_API_KEY;\n const endpoint = config.endpoint ?? process.env.ARTHUR_BASE_URL;\n const taskId = config.taskId ?? process.env.ARTHUR_TASK_ID;\n\n const headers: Record<string, string> = {\n ...config.headers,\n };\n\n let disabledReason: string | undefined;\n\n if (!apiKey) {\n disabledReason =\n `${LOG_PREFIX} API key is required. ` + `Set ARTHUR_API_KEY environment variable or pass apiKey in config.`;\n } else {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n if (!disabledReason && !endpoint) {\n disabledReason =\n `${LOG_PREFIX} Endpoint is required. ` + `Set ARTHUR_BASE_URL environment variable or pass endpoint in config.`;\n }\n\n // Ensure the endpoint ends with /api/v1/traces\n const tracesEndpoint = endpoint ? `${stripTrailingSlashes(endpoint)}/api/v1/traces` : 'http://disabled';\n\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: tracesEndpoint,\n headers,\n }),\n ...config,\n resourceAttributes: {\n ...(taskId ? { 'arthur.task.id': taskId } : {}),\n ...config.resourceAttributes,\n },\n provider: {\n custom: {\n endpoint: tracesEndpoint,\n headers,\n protocol: 'http/protobuf',\n },\n } satisfies OtelExporterConfig['provider'],\n } satisfies OtelExporterConfig);\n\n this.taskId = taskId;\n }\n\n /**\n * Called after construction with the observability config.\n * Validates that traces can be routed to a task via either taskId or serviceName.\n */\n init(options: InitExporterOptions) {\n super.init(options);\n\n const serviceName = options.config?.serviceName;\n\n if (this.taskId && serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Both taskId and serviceName are set. Arthur Engine will use serviceName to route traces, ` +\n `ignoring the provided taskId.`,\n );\n } else if (!this.taskId && !serviceName) {\n this.logger.warn(\n `${LOG_PREFIX} Neither taskId nor serviceName is set. Set ARTHUR_TASK_ID environment variable, ` +\n `pass taskId in config, or set serviceName in the observability config so Arthur Engine can route traces to a task.`,\n );\n }\n }\n}\n\n/**\n * Remove trailing '/' characters procedurally. Avoids the polynomial\n * backtracking that a greedy regex like `/\\/+$/` can exhibit when the\n * input is attacker-controlled.\n */\nfunction stripTrailingSlashes(s: string): string {\n let end = s.length;\n while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) {\n end--;\n }\n return end === s.length ? s : s.slice(0, end);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/arthur",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8-alpha.1",
|
|
4
4
|
"description": "Arthur AI observability provider for Mastra - exports traces using OpenInference semantic conventions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
|
|
31
31
|
"@opentelemetry/sdk-trace-base": "^2.7.0",
|
|
32
32
|
"@opentelemetry/semantic-conventions": "^1.40.0",
|
|
33
|
-
"@mastra/otel-exporter": "1.0.
|
|
33
|
+
"@mastra/otel-exporter": "1.0.21-alpha.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "22.19.15",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"vitest": "4.1.5",
|
|
43
43
|
"@internal/lint": "0.0.89",
|
|
44
44
|
"@internal/types-builder": "0.0.64",
|
|
45
|
-
"@mastra/core": "1.
|
|
45
|
+
"@mastra/core": "1.31.0-alpha.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@mastra/core": ">=1.0.0-0 <2.0.0-0"
|