@mastra/langsmith 1.1.20 → 1.2.0-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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # @mastra/langsmith
2
2
 
3
+ ## 1.2.0-alpha.1
4
+
5
+ ### Minor Changes
6
+
7
+ - Mastra Eval results are now forwarded to LangSmith. ([#16185](https://github.com/mastra-ai/mastra/pull/16185))
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`6742347`](https://github.com/mastra-ai/mastra/commit/6742347d71955d7639adc9ddf6ff8282de7ee3ba), [`7b0ad1f`](https://github.com/mastra-ai/mastra/commit/7b0ad1f5c53dc118c6da12ae82ae2587037dc2b8), [`62666c3`](https://github.com/mastra-ai/mastra/commit/62666c367eaeac3941ead454b1d38810cc855721), [`4af2160`](https://github.com/mastra-ai/mastra/commit/4af2160322f4718cac421930cce85641e9512389), [`b2fd6be`](https://github.com/mastra-ai/mastra/commit/b2fd6beef989f5e463c9a33d8a6c20ac1800e011), [`136c959`](https://github.com/mastra-ai/mastra/commit/136c9592fb0eeb0cd212f28629d8a29b7557a2fc), [`00106be`](https://github.com/mastra-ai/mastra/commit/00106bede59b81e5b0e9cd6aad8d3b5dbc336387), [`4df7cc7`](https://github.com/mastra-ai/mastra/commit/4df7cc79342fd065fe7fdeef93c094db14b12bcd), [`aca3121`](https://github.com/mastra-ai/mastra/commit/aca31211233dac25459f140ea4fcfb3a5af64c18), [`7b0ad1f`](https://github.com/mastra-ai/mastra/commit/7b0ad1f5c53dc118c6da12ae82ae2587037dc2b8), [`9cdf38e`](https://github.com/mastra-ai/mastra/commit/9cdf38e58506e1109c8b38f97cd7770978a4218e), [`990851e`](https://github.com/mastra-ai/mastra/commit/990851edcb0e30be5c2c18b6532f1a876cc2d335), [`6068a6c`](https://github.com/mastra-ai/mastra/commit/6068a6c42950fad3ebfc92346417896ba60803d2), [`00106be`](https://github.com/mastra-ai/mastra/commit/00106bede59b81e5b0e9cd6aad8d3b5dbc336387), [`e2a079c`](https://github.com/mastra-ai/mastra/commit/e2a079cc3755b1895f7bd5dc36e9be81b11c7c22), [`534a456`](https://github.com/mastra-ai/mastra/commit/534a456a25e4df1e5407e7e632f4cb3b1fa14f9d), [`36bae07`](https://github.com/mastra-ai/mastra/commit/36bae07c0e70b1b3006f2fd20830e8883dcbd066)]:
12
+ - @mastra/core@1.33.0-alpha.7
13
+ - @mastra/observability@1.12.0-alpha.1
14
+
15
+ ## 1.1.21-alpha.0
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [[`00ef282`](https://github.com/mastra-ai/mastra/commit/00ef2826034d006b984b3f19cd33ba0bba14d6c6)]:
20
+ - @mastra/observability@1.12.0-alpha.0
21
+
3
22
  ## 1.1.20
4
23
 
5
24
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -53,6 +53,7 @@ function formatUsageMetrics(usage) {
53
53
  }
54
54
 
55
55
  // src/tracing.ts
56
+ var DEFAULT_RUN_ID_CACHE_MAX_ENTRIES = 1e4;
56
57
  var DEFAULT_SPAN_TYPE = "chain";
57
58
  var SPAN_TYPE_EXCEPTIONS = {
58
59
  [observability$1.SpanType.MODEL_GENERATION]: "llm",
@@ -70,18 +71,50 @@ function isKVMap(value) {
70
71
  var LangSmithExporter = class extends observability.TrackingExporter {
71
72
  name = "langsmith";
72
73
  #client;
74
+ /**
75
+ * Maps Mastra `span.id` to the runId LangSmith allocated when the corresponding
76
+ * RunTree was created. LangSmith's `createFeedback` requires the LangSmith runId,
77
+ * not the Mastra span id, so scores submitted via `onScoreEvent` look up the
78
+ * LangSmith runId here before calling the API.
79
+ *
80
+ * Bounded LRU keyed by Mastra span id — entries are evicted oldest-first when
81
+ * size exceeds `#runIdCacheMaxEntries` so the cache cannot grow without bound.
82
+ */
83
+ #langsmithRunIdBySpanId = /* @__PURE__ */ new Map();
84
+ #runIdCacheMaxEntries;
73
85
  constructor(config = {}) {
74
86
  const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;
75
87
  super({
76
88
  ...config,
77
89
  apiKey
78
90
  });
91
+ this.#runIdCacheMaxEntries = Math.max(1, config.runIdCacheMaxEntries ?? DEFAULT_RUN_ID_CACHE_MAX_ENTRIES);
79
92
  if (!apiKey) {
80
93
  this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);
81
94
  return;
82
95
  }
83
96
  this.#client = config.client ?? new langsmith.Client(this.config);
84
97
  }
98
+ /** Look up the LangSmith runId for a Mastra span id, refreshing its LRU position on hit. */
99
+ #getLangsmithRunId(spanId) {
100
+ const runId = this.#langsmithRunIdBySpanId.get(spanId);
101
+ if (runId === void 0) return void 0;
102
+ this.#langsmithRunIdBySpanId.delete(spanId);
103
+ this.#langsmithRunIdBySpanId.set(spanId, runId);
104
+ return runId;
105
+ }
106
+ /** Remember the LangSmith runId for a Mastra span id, evicting oldest entries when full. */
107
+ #rememberLangsmithRunId(spanId, runId) {
108
+ if (this.#langsmithRunIdBySpanId.has(spanId)) {
109
+ this.#langsmithRunIdBySpanId.delete(spanId);
110
+ }
111
+ this.#langsmithRunIdBySpanId.set(spanId, runId);
112
+ while (this.#langsmithRunIdBySpanId.size > this.#runIdCacheMaxEntries) {
113
+ const oldest = this.#langsmithRunIdBySpanId.keys().next().value;
114
+ if (oldest === void 0) break;
115
+ this.#langsmithRunIdBySpanId.delete(oldest);
116
+ }
117
+ }
85
118
  /**
86
119
  * Flush pending trace batches to LangSmith.
87
120
  * The LangSmith Client internally batches API calls; this ensures
@@ -93,6 +126,55 @@ var LangSmithExporter = class extends observability.TrackingExporter {
93
126
  await this.#client.awaitPendingTraceBatches();
94
127
  }
95
128
  }
129
+ async _postShutdown() {
130
+ this.#langsmithRunIdBySpanId.clear();
131
+ }
132
+ async onScoreEvent(event) {
133
+ if (!this.#client) return;
134
+ const { score } = event;
135
+ if (!score.spanId) {
136
+ this.logger.warn("LangSmith exporter: dropping score with no spanId; trace-level scoring is not yet supported", {
137
+ scorerId: score.scorerId
138
+ });
139
+ return;
140
+ }
141
+ const langsmithRunId = this.#getLangsmithRunId(score.spanId);
142
+ if (!langsmithRunId) {
143
+ this.logger.warn(
144
+ "LangSmith exporter: dropping score for a span that was not previously emitted to LangSmith (span_started must be processed before submitting a score for it)",
145
+ {
146
+ traceId: score.traceId,
147
+ spanId: score.spanId,
148
+ scorerId: score.scorerId
149
+ }
150
+ );
151
+ return;
152
+ }
153
+ const key = score.scorerName ?? score.scorerId;
154
+ try {
155
+ await this.#client.createFeedback(langsmithRunId, key, {
156
+ score: score.score,
157
+ ...score.reason ? { comment: score.reason } : {},
158
+ feedbackId: score.scoreId,
159
+ ...score.scoreTraceId ? { sourceRunId: score.scoreTraceId } : {},
160
+ sourceInfo: {
161
+ // User-supplied metadata is spread first so the authoritative reserved
162
+ // fields below cannot be overwritten by `scorerId` / `scoreSource` keys
163
+ // a caller may have set inside metadata.
164
+ ...score.metadata ?? {},
165
+ scorerId: score.scorerId,
166
+ ...score.scoreSource ? { scoreSource: score.scoreSource } : {}
167
+ }
168
+ });
169
+ } catch (err) {
170
+ this.logger.error("LangSmith exporter: Failed to submit feedback", {
171
+ error: err,
172
+ traceId: score.traceId,
173
+ spanId: score.spanId,
174
+ scorerId: score.scorerId
175
+ });
176
+ }
177
+ }
96
178
  skipBuildRootTask = true;
97
179
  async _buildRoot(_args) {
98
180
  throw new Error("Method not implemented.");
@@ -108,6 +190,9 @@ var LangSmithExporter = class extends observability.TrackingExporter {
108
190
  ...this.buildRunTreePayload(span, traceData, true)
109
191
  };
110
192
  const langSmithSpan = span.isRootSpan ? new langsmith.RunTree(payload) : parent.createChild(payload);
193
+ if (langSmithSpan.id) {
194
+ this.#rememberLangsmithRunId(span.id, langSmithSpan.id);
195
+ }
111
196
  await langSmithSpan.postRun();
112
197
  return langSmithSpan;
113
198
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":["SpanType","TrackingExporter","Client","RunTree","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\n\n/**\n * LangSmithUsageMetrics\n *\n * Canonical metric keys expected by LangSmith for LLM usage accounting.\n * See: https://docs.langchain.com/langsmith/log-llm-trace#provide-token-and-cost-information\n */\nexport interface LangSmithUsageMetrics {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n input_token_details?: {\n [key: string]: number;\n };\n output_token_details?: {\n [key: string]: number;\n };\n}\n\n/**\n * Formats UsageStats to LangSmith's expected metric format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangSmithUsageMetrics {\n const metrics: LangSmithUsageMetrics = {};\n\n if (usage?.inputTokens !== undefined) {\n metrics.input_tokens = usage.inputTokens;\n }\n\n if (usage?.outputTokens !== undefined) {\n metrics.output_tokens = usage.outputTokens;\n }\n\n // Compute total if we have both\n if (metrics.input_tokens !== undefined && metrics.output_tokens !== undefined) {\n metrics.total_tokens = metrics.input_tokens + metrics.output_tokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n reasoning_tokens: usage.outputDetails.reasoning,\n };\n }\n\n if (usage?.inputDetails?.cacheRead !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_read: usage.inputDetails.cacheRead,\n };\n }\n\n if (usage?.inputDetails?.cacheWrite !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_write: usage.inputDetails.cacheWrite,\n };\n }\n\n if (usage?.inputDetails?.audio !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n audio: usage.inputDetails.audio,\n };\n }\n\n if (usage?.outputDetails?.audio !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n audio: usage.outputDetails.audio,\n };\n }\n\n return metrics;\n}\n","/**\n * LangSmith Exporter for Mastra Tracing\n *\n * This exporter sends observability data to LangSmith\n * Root spans become top-level LangSmith RunTrees (no trace wrapper).\n * Events are handled as zero-duration RunTrees with matching start/end times.\n */\n\nimport type { AnyExportedSpan, ModelGenerationAttributes, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport type { LangSmithMetadataInput } from './helpers';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {\n /** LangSmith client instance */\n client?: Client;\n /**\n * The name of the LangSmith project to send traces to.\n * Overrides the LANGCHAIN_PROJECT environment variable.\n * If neither is set, traces are sent to the \"default\" project.\n */\n projectName?: string;\n}\n\ntype LangSmithRoot = undefined;\ntype LangSmithSpan = RunTree;\ntype LangSmithEvent = RunTree;\ntype LangSmithMetadata = LangSmithMetadataInput;\ntype LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;\n\n// Default span type for all spans\nconst DEFAULT_SPAN_TYPE = 'chain';\n\n// Exceptions to the default mapping\nconst SPAN_TYPE_EXCEPTIONS: Partial<Record<SpanType, 'llm' | 'tool' | 'chain'>> = {\n [SpanType.MODEL_GENERATION]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_CONDITIONAL_EVAL]: 'chain',\n [SpanType.WORKFLOW_WAIT_EVENT]: 'chain',\n};\n\n// Mapping function - returns valid LangSmith span types\nfunction mapSpanType(spanType: SpanType): 'llm' | 'tool' | 'chain' {\n return SPAN_TYPE_EXCEPTIONS[spanType] ?? DEFAULT_SPAN_TYPE;\n}\n\nfunction isKVMap(value: unknown): value is KVMap {\n return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport class LangSmithExporter extends TrackingExporter<\n LangSmithRoot,\n LangSmithSpan,\n LangSmithEvent,\n LangSmithMetadata,\n LangSmithExporterConfig\n> {\n override name = 'langsmith';\n #client: Client | undefined;\n\n constructor(config: LangSmithExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n super({\n ...config,\n apiKey,\n });\n\n if (!apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);\n return;\n }\n\n this.#client = config.client ?? new Client(this.config);\n }\n\n /**\n * Flush pending trace batches to LangSmith.\n * The LangSmith Client internally batches API calls; this ensures\n * all queued runs are sent before the process exits or the flush\n * caller continues.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.awaitPendingTraceBatches();\n }\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithSpan | undefined> {\n const { span, traceData } = args;\n\n const parent = span.isRootSpan ? undefined : traceData.getParent(args);\n\n if (!span.isRootSpan && !parent) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n const payload = {\n name: span.name,\n ...this.buildRunTreePayload(span, traceData, true),\n };\n\n const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent!.createChild(payload);\n\n await langSmithSpan.postRun();\n return langSmithSpan;\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithEvent | undefined> {\n const langSmithSpan = await this._buildSpan(args);\n\n if (!langSmithSpan) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n // use start-time as end-time to make an event span.\n await langSmithSpan.end({ endTime: args.span.startTime.getTime() });\n await langSmithSpan.patchRun();\n return langSmithSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });\n }\n\n protected override async _abortSpan(args: {\n span: LangSmithSpan;\n traceData: LangSmithTraceData;\n reason: SpanErrorInfo;\n }): Promise<void> {\n const { span, reason } = args;\n span.error = reason.message;\n span.metadata = {\n ...span.metadata,\n errorDetails: reason,\n };\n await span.end();\n await span.patchRun();\n }\n\n private async handleSpanUpdateOrEnd(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n isEnd: boolean;\n }): Promise<void> {\n const { span, traceData, isEnd } = args;\n\n const langSmithSpan = traceData.getSpan({ spanId: span.id });\n if (!langSmithSpan) {\n //update occurred before span start, return early data\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span, traceData);\n\n langSmithSpan.metadata = {\n ...langSmithSpan.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langSmithSpan.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langSmithSpan.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langSmithSpan.error = updatePayload.error;\n }\n\n // Add new_token event for TTFT tracking on MODEL_GENERATION spans\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = (span.attributes ?? {}) as ModelGenerationAttributes;\n if (modelAttr.completionStartTime !== undefined) {\n langSmithSpan.addEvent({\n name: 'new_token',\n time: modelAttr.completionStartTime.toISOString(),\n });\n }\n }\n\n if (isEnd) {\n // End the span with the correct endTime\n if (span.endTime) {\n await langSmithSpan.end({ endTime: span.endTime.getTime() });\n } else {\n await langSmithSpan.end();\n }\n }\n await langSmithSpan.patchRun();\n }\n\n /**\n * Find LangSmith vendor metadata by walking up the span hierarchy and merging.\n * Metadata is merged from ancestors with child values taking precedence over parent values.\n *\n * TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class\n * and reuse here and in LangfuseExporter.findLangfusePrompt()\n */\n private findLangsmithMetadata(\n traceData: LangSmithTraceData,\n span: AnyExportedSpan,\n ): LangSmithMetadataInput | undefined {\n // Collect metadata from all ancestors (current span first, then parents)\n const metadataChain: LangSmithMetadataInput[] = [];\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n if (providerMetadata) {\n metadataChain.push(providerMetadata);\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n if (metadataChain.length === 0) {\n return undefined;\n }\n\n // Merge from ancestors to current span (parent values first, child values override)\n const merged: LangSmithMetadataInput = {};\n for (let i = metadataChain.length - 1; i >= 0; i--) {\n const meta = metadataChain[i]!;\n if (meta.projectName !== undefined) merged.projectName = meta.projectName;\n if (meta.sessionId !== undefined) merged.sessionId = meta.sessionId;\n if (meta.sessionName !== undefined) merged.sessionName = meta.sessionName;\n }\n\n this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {\n traceId: span.traceId,\n spanId: span.id,\n metadataKeys: Object.keys(merged),\n ancestorCount: metadataChain.length,\n });\n\n return merged;\n }\n\n private buildRunTreePayload(\n span: AnyExportedSpan,\n traceData: LangSmithTraceData,\n isNew = false,\n ): Partial<RunTreeConfig> {\n // Extract vendor metadata from span hierarchy\n const vendorMetadata = this.findLangsmithMetadata(traceData, span);\n\n // Build metadata, omitting the langsmith vendor key\n const spanMetadata = span.metadata ? omitKeys(span.metadata, ['langsmith']) : {};\n\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...spanMetadata,\n },\n };\n\n if (isNew) {\n payload.run_type = mapSpanType(span.type);\n payload.start_time = span.startTime.getTime();\n }\n\n // Add project name - vendor metadata takes precedence over config\n const projectName = vendorMetadata?.projectName ?? this.config.projectName;\n if (projectName) {\n payload.project_name = projectName;\n }\n\n // Add session info to metadata if provided via vendor metadata\n if (vendorMetadata?.sessionId) {\n payload.metadata.session_id = vendorMetadata.sessionId;\n }\n if (vendorMetadata?.sessionName) {\n payload.metadata.session_name = vendorMetadata.sessionName;\n }\n\n // Add tags for root spans\n if (span.isRootSpan && span.tags?.length) {\n payload.tags = span.tags;\n }\n\n // Core span data\n if (span.input !== undefined) {\n payload.inputs = isKVMap(span.input) ? span.input : { input: span.input };\n }\n\n if (span.output !== undefined) {\n payload.outputs = isKVMap(span.output) ? span.output : { output: span.output };\n }\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n // See: https://docs.langchain.com/langsmith/log-llm-trace\n if (modelAttr.model !== undefined) {\n // Note - this should map to a model name recognized by LangSmith\n // eg “gpt-4o-mini”, “claude-3-opus-20240307”, etc.\n payload.metadata.ls_model_name = modelAttr.model;\n }\n\n // Provider goes to metadata (if provided by attributes)\n if (modelAttr.provider !== undefined) {\n // Note - this should map to a provider name recognized by\n // LangSmith eg “openai”, “anthropic”, etc.\n payload.metadata.ls_provider = modelAttr.provider;\n }\n\n // Usage/token info goes to metrics\n payload.metadata.usage_metadata = formatUsageMetrics(modelAttr.usage);\n\n // Model parameters go to metadata\n if (modelAttr.parameters !== undefined) {\n payload.metadata.modelParameters = modelAttr.parameters;\n }\n\n // Other LLM attributes go to metadata\n const otherAttributes = omitKeys(attributes, ['model', 'provider', 'usage', 'parameters', 'completionStartTime']);\n payload.metadata = {\n ...payload.metadata,\n ...otherAttributes,\n };\n } else {\n // For non-LLM spans, put all attributes in metadata\n payload.metadata = {\n ...payload.metadata,\n ...attributes,\n };\n }\n\n // Handle errors\n if (span.errorInfo) {\n payload.error = span.errorInfo.message;\n payload.metadata.errorDetails = span.errorInfo;\n }\n\n return payload;\n }\n}\n","/**\n * LangSmith Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add LangSmith-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'my-project' })\n * ),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * LangSmith vendor metadata that can be passed via span metadata.\n * These fields are extracted by the LangSmith exporter and used\n * to override default configuration on a per-span basis.\n */\nexport interface LangSmithMetadataInput {\n /**\n * Override the project name for this span and its children.\n * This allows dynamically routing traces to different LangSmith projects.\n */\n projectName?: string;\n /**\n * Session ID for grouping related traces in LangSmith.\n */\n sessionId?: string;\n /**\n * Session name for display in LangSmith.\n */\n sessionName?: string;\n}\n\n/**\n * Adds LangSmith metadata to the tracing options.\n *\n * The metadata is added under `metadata.langsmith` and allows you to:\n * - Route traces to different LangSmith projects via `projectName`\n * - Group traces by session via `sessionId` and `sessionName`\n *\n * @param metadata - The LangSmith metadata to add\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * // Route traces to a specific project\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'customer-support' }),\n * );\n *\n * // Or set multiple fields\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({\n * projectName: 'my-project',\n * sessionId: 'session-123',\n * }),\n * );\n *\n * // Use in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'support-traces' })\n * ),\n * },\n * });\n * ```\n */\nexport function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langsmith: {\n ...(opts.metadata?.langsmith as Record<string, unknown>),\n ...metadata,\n },\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":["SpanType","TrackingExporter","Client","RunTree","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\n\n/**\n * LangSmithUsageMetrics\n *\n * Canonical metric keys expected by LangSmith for LLM usage accounting.\n * See: https://docs.langchain.com/langsmith/log-llm-trace#provide-token-and-cost-information\n */\nexport interface LangSmithUsageMetrics {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n input_token_details?: {\n [key: string]: number;\n };\n output_token_details?: {\n [key: string]: number;\n };\n}\n\n/**\n * Formats UsageStats to LangSmith's expected metric format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangSmithUsageMetrics {\n const metrics: LangSmithUsageMetrics = {};\n\n if (usage?.inputTokens !== undefined) {\n metrics.input_tokens = usage.inputTokens;\n }\n\n if (usage?.outputTokens !== undefined) {\n metrics.output_tokens = usage.outputTokens;\n }\n\n // Compute total if we have both\n if (metrics.input_tokens !== undefined && metrics.output_tokens !== undefined) {\n metrics.total_tokens = metrics.input_tokens + metrics.output_tokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n reasoning_tokens: usage.outputDetails.reasoning,\n };\n }\n\n if (usage?.inputDetails?.cacheRead !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_read: usage.inputDetails.cacheRead,\n };\n }\n\n if (usage?.inputDetails?.cacheWrite !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_write: usage.inputDetails.cacheWrite,\n };\n }\n\n if (usage?.inputDetails?.audio !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n audio: usage.inputDetails.audio,\n };\n }\n\n if (usage?.outputDetails?.audio !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n audio: usage.outputDetails.audio,\n };\n }\n\n return metrics;\n}\n","/**\n * LangSmith Exporter for Mastra Tracing\n *\n * This exporter sends observability data to LangSmith\n * Root spans become top-level LangSmith RunTrees (no trace wrapper).\n * Events are handled as zero-duration RunTrees with matching start/end times.\n */\n\nimport type { AnyExportedSpan, ModelGenerationAttributes, ScoreEvent, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport type { LangSmithMetadataInput } from './helpers';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {\n /** LangSmith client instance */\n client?: Client;\n /**\n * The name of the LangSmith project to send traces to.\n * Overrides the LANGCHAIN_PROJECT environment variable.\n * If neither is set, traces are sent to the \"default\" project.\n */\n projectName?: string;\n /**\n * Maximum number of `spanId → langsmithRunId` mappings to retain for resolving\n * `onScoreEvent` lookups. Older entries are evicted in LRU order when the cap\n * is exceeded so long-running processes do not grow unbounded.\n * Defaults to 10000.\n */\n runIdCacheMaxEntries?: number;\n}\n\nconst DEFAULT_RUN_ID_CACHE_MAX_ENTRIES = 10_000;\n\ntype LangSmithRoot = undefined;\ntype LangSmithSpan = RunTree;\ntype LangSmithEvent = RunTree;\ntype LangSmithMetadata = LangSmithMetadataInput;\ntype LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;\n\n// Default span type for all spans\nconst DEFAULT_SPAN_TYPE = 'chain';\n\n// Exceptions to the default mapping\nconst SPAN_TYPE_EXCEPTIONS: Partial<Record<SpanType, 'llm' | 'tool' | 'chain'>> = {\n [SpanType.MODEL_GENERATION]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_CONDITIONAL_EVAL]: 'chain',\n [SpanType.WORKFLOW_WAIT_EVENT]: 'chain',\n};\n\n// Mapping function - returns valid LangSmith span types\nfunction mapSpanType(spanType: SpanType): 'llm' | 'tool' | 'chain' {\n return SPAN_TYPE_EXCEPTIONS[spanType] ?? DEFAULT_SPAN_TYPE;\n}\n\nfunction isKVMap(value: unknown): value is KVMap {\n return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport class LangSmithExporter extends TrackingExporter<\n LangSmithRoot,\n LangSmithSpan,\n LangSmithEvent,\n LangSmithMetadata,\n LangSmithExporterConfig\n> {\n override name = 'langsmith';\n #client: Client | undefined;\n\n /**\n * Maps Mastra `span.id` to the runId LangSmith allocated when the corresponding\n * RunTree was created. LangSmith's `createFeedback` requires the LangSmith runId,\n * not the Mastra span id, so scores submitted via `onScoreEvent` look up the\n * LangSmith runId here before calling the API.\n *\n * Bounded LRU keyed by Mastra span id — entries are evicted oldest-first when\n * size exceeds `#runIdCacheMaxEntries` so the cache cannot grow without bound.\n */\n #langsmithRunIdBySpanId = new Map<string, string>();\n #runIdCacheMaxEntries: number;\n\n constructor(config: LangSmithExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n super({\n ...config,\n apiKey,\n });\n\n this.#runIdCacheMaxEntries = Math.max(1, config.runIdCacheMaxEntries ?? DEFAULT_RUN_ID_CACHE_MAX_ENTRIES);\n\n if (!apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);\n return;\n }\n\n this.#client = config.client ?? new Client(this.config);\n }\n\n /** Look up the LangSmith runId for a Mastra span id, refreshing its LRU position on hit. */\n #getLangsmithRunId(spanId: string): string | undefined {\n const runId = this.#langsmithRunIdBySpanId.get(spanId);\n if (runId === undefined) return undefined;\n // Re-insert to mark as most-recently-used (Map preserves insertion order).\n this.#langsmithRunIdBySpanId.delete(spanId);\n this.#langsmithRunIdBySpanId.set(spanId, runId);\n return runId;\n }\n\n /** Remember the LangSmith runId for a Mastra span id, evicting oldest entries when full. */\n #rememberLangsmithRunId(spanId: string, runId: string): void {\n if (this.#langsmithRunIdBySpanId.has(spanId)) {\n this.#langsmithRunIdBySpanId.delete(spanId);\n }\n this.#langsmithRunIdBySpanId.set(spanId, runId);\n while (this.#langsmithRunIdBySpanId.size > this.#runIdCacheMaxEntries) {\n const oldest = this.#langsmithRunIdBySpanId.keys().next().value;\n if (oldest === undefined) break;\n this.#langsmithRunIdBySpanId.delete(oldest);\n }\n }\n\n /**\n * Flush pending trace batches to LangSmith.\n * The LangSmith Client internally batches API calls; this ensures\n * all queued runs are sent before the process exits or the flush\n * caller continues.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.awaitPendingTraceBatches();\n }\n }\n\n protected override async _postShutdown(): Promise<void> {\n this.#langsmithRunIdBySpanId.clear();\n }\n\n async onScoreEvent(event: ScoreEvent): Promise<void> {\n if (!this.#client) return;\n\n const { score } = event;\n if (!score.spanId) {\n this.logger.warn('LangSmith exporter: dropping score with no spanId; trace-level scoring is not yet supported', {\n scorerId: score.scorerId,\n });\n return;\n }\n\n const langsmithRunId = this.#getLangsmithRunId(score.spanId);\n if (!langsmithRunId) {\n this.logger.warn(\n 'LangSmith exporter: dropping score for a span that was not previously emitted to LangSmith ' +\n '(span_started must be processed before submitting a score for it)',\n {\n traceId: score.traceId,\n spanId: score.spanId,\n scorerId: score.scorerId,\n },\n );\n return;\n }\n\n const key = score.scorerName ?? score.scorerId;\n\n try {\n await this.#client.createFeedback(langsmithRunId, key, {\n score: score.score,\n ...(score.reason ? { comment: score.reason } : {}),\n feedbackId: score.scoreId,\n ...(score.scoreTraceId ? { sourceRunId: score.scoreTraceId } : {}),\n sourceInfo: {\n // User-supplied metadata is spread first so the authoritative reserved\n // fields below cannot be overwritten by `scorerId` / `scoreSource` keys\n // a caller may have set inside metadata.\n ...(score.metadata ?? {}),\n scorerId: score.scorerId,\n ...(score.scoreSource ? { scoreSource: score.scoreSource } : {}),\n },\n });\n } catch (err) {\n this.logger.error('LangSmith exporter: Failed to submit feedback', {\n error: err,\n traceId: score.traceId,\n spanId: score.spanId,\n scorerId: score.scorerId,\n });\n }\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithSpan | undefined> {\n const { span, traceData } = args;\n\n const parent = span.isRootSpan ? undefined : traceData.getParent(args);\n\n if (!span.isRootSpan && !parent) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n const payload = {\n name: span.name,\n ...this.buildRunTreePayload(span, traceData, true),\n };\n\n const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent!.createChild(payload);\n\n if (langSmithSpan.id) {\n this.#rememberLangsmithRunId(span.id, langSmithSpan.id);\n }\n\n await langSmithSpan.postRun();\n return langSmithSpan;\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithEvent | undefined> {\n const langSmithSpan = await this._buildSpan(args);\n\n if (!langSmithSpan) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n // use start-time as end-time to make an event span.\n await langSmithSpan.end({ endTime: args.span.startTime.getTime() });\n await langSmithSpan.patchRun();\n return langSmithSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });\n }\n\n protected override async _abortSpan(args: {\n span: LangSmithSpan;\n traceData: LangSmithTraceData;\n reason: SpanErrorInfo;\n }): Promise<void> {\n const { span, reason } = args;\n span.error = reason.message;\n span.metadata = {\n ...span.metadata,\n errorDetails: reason,\n };\n await span.end();\n await span.patchRun();\n }\n\n private async handleSpanUpdateOrEnd(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n isEnd: boolean;\n }): Promise<void> {\n const { span, traceData, isEnd } = args;\n\n const langSmithSpan = traceData.getSpan({ spanId: span.id });\n if (!langSmithSpan) {\n //update occurred before span start, return early data\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span, traceData);\n\n langSmithSpan.metadata = {\n ...langSmithSpan.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langSmithSpan.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langSmithSpan.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langSmithSpan.error = updatePayload.error;\n }\n\n // Add new_token event for TTFT tracking on MODEL_GENERATION spans\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = (span.attributes ?? {}) as ModelGenerationAttributes;\n if (modelAttr.completionStartTime !== undefined) {\n langSmithSpan.addEvent({\n name: 'new_token',\n time: modelAttr.completionStartTime.toISOString(),\n });\n }\n }\n\n if (isEnd) {\n // End the span with the correct endTime\n if (span.endTime) {\n await langSmithSpan.end({ endTime: span.endTime.getTime() });\n } else {\n await langSmithSpan.end();\n }\n }\n await langSmithSpan.patchRun();\n }\n\n /**\n * Find LangSmith vendor metadata by walking up the span hierarchy and merging.\n * Metadata is merged from ancestors with child values taking precedence over parent values.\n *\n * TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class\n * and reuse here and in LangfuseExporter.findLangfusePrompt()\n */\n private findLangsmithMetadata(\n traceData: LangSmithTraceData,\n span: AnyExportedSpan,\n ): LangSmithMetadataInput | undefined {\n // Collect metadata from all ancestors (current span first, then parents)\n const metadataChain: LangSmithMetadataInput[] = [];\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n if (providerMetadata) {\n metadataChain.push(providerMetadata);\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n if (metadataChain.length === 0) {\n return undefined;\n }\n\n // Merge from ancestors to current span (parent values first, child values override)\n const merged: LangSmithMetadataInput = {};\n for (let i = metadataChain.length - 1; i >= 0; i--) {\n const meta = metadataChain[i]!;\n if (meta.projectName !== undefined) merged.projectName = meta.projectName;\n if (meta.sessionId !== undefined) merged.sessionId = meta.sessionId;\n if (meta.sessionName !== undefined) merged.sessionName = meta.sessionName;\n }\n\n this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {\n traceId: span.traceId,\n spanId: span.id,\n metadataKeys: Object.keys(merged),\n ancestorCount: metadataChain.length,\n });\n\n return merged;\n }\n\n private buildRunTreePayload(\n span: AnyExportedSpan,\n traceData: LangSmithTraceData,\n isNew = false,\n ): Partial<RunTreeConfig> {\n // Extract vendor metadata from span hierarchy\n const vendorMetadata = this.findLangsmithMetadata(traceData, span);\n\n // Build metadata, omitting the langsmith vendor key\n const spanMetadata = span.metadata ? omitKeys(span.metadata, ['langsmith']) : {};\n\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...spanMetadata,\n },\n };\n\n if (isNew) {\n payload.run_type = mapSpanType(span.type);\n payload.start_time = span.startTime.getTime();\n }\n\n // Add project name - vendor metadata takes precedence over config\n const projectName = vendorMetadata?.projectName ?? this.config.projectName;\n if (projectName) {\n payload.project_name = projectName;\n }\n\n // Add session info to metadata if provided via vendor metadata\n if (vendorMetadata?.sessionId) {\n payload.metadata.session_id = vendorMetadata.sessionId;\n }\n if (vendorMetadata?.sessionName) {\n payload.metadata.session_name = vendorMetadata.sessionName;\n }\n\n // Add tags for root spans\n if (span.isRootSpan && span.tags?.length) {\n payload.tags = span.tags;\n }\n\n // Core span data\n if (span.input !== undefined) {\n payload.inputs = isKVMap(span.input) ? span.input : { input: span.input };\n }\n\n if (span.output !== undefined) {\n payload.outputs = isKVMap(span.output) ? span.output : { output: span.output };\n }\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n // See: https://docs.langchain.com/langsmith/log-llm-trace\n if (modelAttr.model !== undefined) {\n // Note - this should map to a model name recognized by LangSmith\n // eg “gpt-4o-mini”, “claude-3-opus-20240307”, etc.\n payload.metadata.ls_model_name = modelAttr.model;\n }\n\n // Provider goes to metadata (if provided by attributes)\n if (modelAttr.provider !== undefined) {\n // Note - this should map to a provider name recognized by\n // LangSmith eg “openai”, “anthropic”, etc.\n payload.metadata.ls_provider = modelAttr.provider;\n }\n\n // Usage/token info goes to metrics\n payload.metadata.usage_metadata = formatUsageMetrics(modelAttr.usage);\n\n // Model parameters go to metadata\n if (modelAttr.parameters !== undefined) {\n payload.metadata.modelParameters = modelAttr.parameters;\n }\n\n // Other LLM attributes go to metadata\n const otherAttributes = omitKeys(attributes, ['model', 'provider', 'usage', 'parameters', 'completionStartTime']);\n payload.metadata = {\n ...payload.metadata,\n ...otherAttributes,\n };\n } else {\n // For non-LLM spans, put all attributes in metadata\n payload.metadata = {\n ...payload.metadata,\n ...attributes,\n };\n }\n\n // Handle errors\n if (span.errorInfo) {\n payload.error = span.errorInfo.message;\n payload.metadata.errorDetails = span.errorInfo;\n }\n\n return payload;\n }\n}\n","/**\n * LangSmith Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add LangSmith-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'my-project' })\n * ),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * LangSmith vendor metadata that can be passed via span metadata.\n * These fields are extracted by the LangSmith exporter and used\n * to override default configuration on a per-span basis.\n */\nexport interface LangSmithMetadataInput {\n /**\n * Override the project name for this span and its children.\n * This allows dynamically routing traces to different LangSmith projects.\n */\n projectName?: string;\n /**\n * Session ID for grouping related traces in LangSmith.\n */\n sessionId?: string;\n /**\n * Session name for display in LangSmith.\n */\n sessionName?: string;\n}\n\n/**\n * Adds LangSmith metadata to the tracing options.\n *\n * The metadata is added under `metadata.langsmith` and allows you to:\n * - Route traces to different LangSmith projects via `projectName`\n * - Group traces by session via `sessionId` and `sessionName`\n *\n * @param metadata - The LangSmith metadata to add\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * // Route traces to a specific project\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'customer-support' }),\n * );\n *\n * // Or set multiple fields\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({\n * projectName: 'my-project',\n * sessionId: 'session-123',\n * }),\n * );\n *\n * // Use in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'support-traces' })\n * ),\n * },\n * });\n * ```\n */\nexport function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langsmith: {\n ...(opts.metadata?.langsmith as Record<string, unknown>),\n ...metadata,\n },\n },\n });\n}\n"]}
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ function formatUsageMetrics(usage) {
51
51
  }
52
52
 
53
53
  // src/tracing.ts
54
+ var DEFAULT_RUN_ID_CACHE_MAX_ENTRIES = 1e4;
54
55
  var DEFAULT_SPAN_TYPE = "chain";
55
56
  var SPAN_TYPE_EXCEPTIONS = {
56
57
  [SpanType.MODEL_GENERATION]: "llm",
@@ -68,18 +69,50 @@ function isKVMap(value) {
68
69
  var LangSmithExporter = class extends TrackingExporter {
69
70
  name = "langsmith";
70
71
  #client;
72
+ /**
73
+ * Maps Mastra `span.id` to the runId LangSmith allocated when the corresponding
74
+ * RunTree was created. LangSmith's `createFeedback` requires the LangSmith runId,
75
+ * not the Mastra span id, so scores submitted via `onScoreEvent` look up the
76
+ * LangSmith runId here before calling the API.
77
+ *
78
+ * Bounded LRU keyed by Mastra span id — entries are evicted oldest-first when
79
+ * size exceeds `#runIdCacheMaxEntries` so the cache cannot grow without bound.
80
+ */
81
+ #langsmithRunIdBySpanId = /* @__PURE__ */ new Map();
82
+ #runIdCacheMaxEntries;
71
83
  constructor(config = {}) {
72
84
  const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;
73
85
  super({
74
86
  ...config,
75
87
  apiKey
76
88
  });
89
+ this.#runIdCacheMaxEntries = Math.max(1, config.runIdCacheMaxEntries ?? DEFAULT_RUN_ID_CACHE_MAX_ENTRIES);
77
90
  if (!apiKey) {
78
91
  this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);
79
92
  return;
80
93
  }
81
94
  this.#client = config.client ?? new Client(this.config);
82
95
  }
96
+ /** Look up the LangSmith runId for a Mastra span id, refreshing its LRU position on hit. */
97
+ #getLangsmithRunId(spanId) {
98
+ const runId = this.#langsmithRunIdBySpanId.get(spanId);
99
+ if (runId === void 0) return void 0;
100
+ this.#langsmithRunIdBySpanId.delete(spanId);
101
+ this.#langsmithRunIdBySpanId.set(spanId, runId);
102
+ return runId;
103
+ }
104
+ /** Remember the LangSmith runId for a Mastra span id, evicting oldest entries when full. */
105
+ #rememberLangsmithRunId(spanId, runId) {
106
+ if (this.#langsmithRunIdBySpanId.has(spanId)) {
107
+ this.#langsmithRunIdBySpanId.delete(spanId);
108
+ }
109
+ this.#langsmithRunIdBySpanId.set(spanId, runId);
110
+ while (this.#langsmithRunIdBySpanId.size > this.#runIdCacheMaxEntries) {
111
+ const oldest = this.#langsmithRunIdBySpanId.keys().next().value;
112
+ if (oldest === void 0) break;
113
+ this.#langsmithRunIdBySpanId.delete(oldest);
114
+ }
115
+ }
83
116
  /**
84
117
  * Flush pending trace batches to LangSmith.
85
118
  * The LangSmith Client internally batches API calls; this ensures
@@ -91,6 +124,55 @@ var LangSmithExporter = class extends TrackingExporter {
91
124
  await this.#client.awaitPendingTraceBatches();
92
125
  }
93
126
  }
127
+ async _postShutdown() {
128
+ this.#langsmithRunIdBySpanId.clear();
129
+ }
130
+ async onScoreEvent(event) {
131
+ if (!this.#client) return;
132
+ const { score } = event;
133
+ if (!score.spanId) {
134
+ this.logger.warn("LangSmith exporter: dropping score with no spanId; trace-level scoring is not yet supported", {
135
+ scorerId: score.scorerId
136
+ });
137
+ return;
138
+ }
139
+ const langsmithRunId = this.#getLangsmithRunId(score.spanId);
140
+ if (!langsmithRunId) {
141
+ this.logger.warn(
142
+ "LangSmith exporter: dropping score for a span that was not previously emitted to LangSmith (span_started must be processed before submitting a score for it)",
143
+ {
144
+ traceId: score.traceId,
145
+ spanId: score.spanId,
146
+ scorerId: score.scorerId
147
+ }
148
+ );
149
+ return;
150
+ }
151
+ const key = score.scorerName ?? score.scorerId;
152
+ try {
153
+ await this.#client.createFeedback(langsmithRunId, key, {
154
+ score: score.score,
155
+ ...score.reason ? { comment: score.reason } : {},
156
+ feedbackId: score.scoreId,
157
+ ...score.scoreTraceId ? { sourceRunId: score.scoreTraceId } : {},
158
+ sourceInfo: {
159
+ // User-supplied metadata is spread first so the authoritative reserved
160
+ // fields below cannot be overwritten by `scorerId` / `scoreSource` keys
161
+ // a caller may have set inside metadata.
162
+ ...score.metadata ?? {},
163
+ scorerId: score.scorerId,
164
+ ...score.scoreSource ? { scoreSource: score.scoreSource } : {}
165
+ }
166
+ });
167
+ } catch (err) {
168
+ this.logger.error("LangSmith exporter: Failed to submit feedback", {
169
+ error: err,
170
+ traceId: score.traceId,
171
+ spanId: score.spanId,
172
+ scorerId: score.scorerId
173
+ });
174
+ }
175
+ }
94
176
  skipBuildRootTask = true;
95
177
  async _buildRoot(_args) {
96
178
  throw new Error("Method not implemented.");
@@ -106,6 +188,9 @@ var LangSmithExporter = class extends TrackingExporter {
106
188
  ...this.buildRunTreePayload(span, traceData, true)
107
189
  };
108
190
  const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent.createChild(payload);
191
+ if (langSmithSpan.id) {
192
+ this.#rememberLangsmithRunId(span.id, langSmithSpan.id);
193
+ }
109
194
  await langSmithSpan.postRun();
110
195
  return langSmithSpan;
111
196
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\n\n/**\n * LangSmithUsageMetrics\n *\n * Canonical metric keys expected by LangSmith for LLM usage accounting.\n * See: https://docs.langchain.com/langsmith/log-llm-trace#provide-token-and-cost-information\n */\nexport interface LangSmithUsageMetrics {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n input_token_details?: {\n [key: string]: number;\n };\n output_token_details?: {\n [key: string]: number;\n };\n}\n\n/**\n * Formats UsageStats to LangSmith's expected metric format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangSmithUsageMetrics {\n const metrics: LangSmithUsageMetrics = {};\n\n if (usage?.inputTokens !== undefined) {\n metrics.input_tokens = usage.inputTokens;\n }\n\n if (usage?.outputTokens !== undefined) {\n metrics.output_tokens = usage.outputTokens;\n }\n\n // Compute total if we have both\n if (metrics.input_tokens !== undefined && metrics.output_tokens !== undefined) {\n metrics.total_tokens = metrics.input_tokens + metrics.output_tokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n reasoning_tokens: usage.outputDetails.reasoning,\n };\n }\n\n if (usage?.inputDetails?.cacheRead !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_read: usage.inputDetails.cacheRead,\n };\n }\n\n if (usage?.inputDetails?.cacheWrite !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_write: usage.inputDetails.cacheWrite,\n };\n }\n\n if (usage?.inputDetails?.audio !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n audio: usage.inputDetails.audio,\n };\n }\n\n if (usage?.outputDetails?.audio !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n audio: usage.outputDetails.audio,\n };\n }\n\n return metrics;\n}\n","/**\n * LangSmith Exporter for Mastra Tracing\n *\n * This exporter sends observability data to LangSmith\n * Root spans become top-level LangSmith RunTrees (no trace wrapper).\n * Events are handled as zero-duration RunTrees with matching start/end times.\n */\n\nimport type { AnyExportedSpan, ModelGenerationAttributes, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport type { LangSmithMetadataInput } from './helpers';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {\n /** LangSmith client instance */\n client?: Client;\n /**\n * The name of the LangSmith project to send traces to.\n * Overrides the LANGCHAIN_PROJECT environment variable.\n * If neither is set, traces are sent to the \"default\" project.\n */\n projectName?: string;\n}\n\ntype LangSmithRoot = undefined;\ntype LangSmithSpan = RunTree;\ntype LangSmithEvent = RunTree;\ntype LangSmithMetadata = LangSmithMetadataInput;\ntype LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;\n\n// Default span type for all spans\nconst DEFAULT_SPAN_TYPE = 'chain';\n\n// Exceptions to the default mapping\nconst SPAN_TYPE_EXCEPTIONS: Partial<Record<SpanType, 'llm' | 'tool' | 'chain'>> = {\n [SpanType.MODEL_GENERATION]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_CONDITIONAL_EVAL]: 'chain',\n [SpanType.WORKFLOW_WAIT_EVENT]: 'chain',\n};\n\n// Mapping function - returns valid LangSmith span types\nfunction mapSpanType(spanType: SpanType): 'llm' | 'tool' | 'chain' {\n return SPAN_TYPE_EXCEPTIONS[spanType] ?? DEFAULT_SPAN_TYPE;\n}\n\nfunction isKVMap(value: unknown): value is KVMap {\n return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport class LangSmithExporter extends TrackingExporter<\n LangSmithRoot,\n LangSmithSpan,\n LangSmithEvent,\n LangSmithMetadata,\n LangSmithExporterConfig\n> {\n override name = 'langsmith';\n #client: Client | undefined;\n\n constructor(config: LangSmithExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n super({\n ...config,\n apiKey,\n });\n\n if (!apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);\n return;\n }\n\n this.#client = config.client ?? new Client(this.config);\n }\n\n /**\n * Flush pending trace batches to LangSmith.\n * The LangSmith Client internally batches API calls; this ensures\n * all queued runs are sent before the process exits or the flush\n * caller continues.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.awaitPendingTraceBatches();\n }\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithSpan | undefined> {\n const { span, traceData } = args;\n\n const parent = span.isRootSpan ? undefined : traceData.getParent(args);\n\n if (!span.isRootSpan && !parent) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n const payload = {\n name: span.name,\n ...this.buildRunTreePayload(span, traceData, true),\n };\n\n const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent!.createChild(payload);\n\n await langSmithSpan.postRun();\n return langSmithSpan;\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithEvent | undefined> {\n const langSmithSpan = await this._buildSpan(args);\n\n if (!langSmithSpan) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n // use start-time as end-time to make an event span.\n await langSmithSpan.end({ endTime: args.span.startTime.getTime() });\n await langSmithSpan.patchRun();\n return langSmithSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });\n }\n\n protected override async _abortSpan(args: {\n span: LangSmithSpan;\n traceData: LangSmithTraceData;\n reason: SpanErrorInfo;\n }): Promise<void> {\n const { span, reason } = args;\n span.error = reason.message;\n span.metadata = {\n ...span.metadata,\n errorDetails: reason,\n };\n await span.end();\n await span.patchRun();\n }\n\n private async handleSpanUpdateOrEnd(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n isEnd: boolean;\n }): Promise<void> {\n const { span, traceData, isEnd } = args;\n\n const langSmithSpan = traceData.getSpan({ spanId: span.id });\n if (!langSmithSpan) {\n //update occurred before span start, return early data\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span, traceData);\n\n langSmithSpan.metadata = {\n ...langSmithSpan.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langSmithSpan.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langSmithSpan.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langSmithSpan.error = updatePayload.error;\n }\n\n // Add new_token event for TTFT tracking on MODEL_GENERATION spans\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = (span.attributes ?? {}) as ModelGenerationAttributes;\n if (modelAttr.completionStartTime !== undefined) {\n langSmithSpan.addEvent({\n name: 'new_token',\n time: modelAttr.completionStartTime.toISOString(),\n });\n }\n }\n\n if (isEnd) {\n // End the span with the correct endTime\n if (span.endTime) {\n await langSmithSpan.end({ endTime: span.endTime.getTime() });\n } else {\n await langSmithSpan.end();\n }\n }\n await langSmithSpan.patchRun();\n }\n\n /**\n * Find LangSmith vendor metadata by walking up the span hierarchy and merging.\n * Metadata is merged from ancestors with child values taking precedence over parent values.\n *\n * TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class\n * and reuse here and in LangfuseExporter.findLangfusePrompt()\n */\n private findLangsmithMetadata(\n traceData: LangSmithTraceData,\n span: AnyExportedSpan,\n ): LangSmithMetadataInput | undefined {\n // Collect metadata from all ancestors (current span first, then parents)\n const metadataChain: LangSmithMetadataInput[] = [];\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n if (providerMetadata) {\n metadataChain.push(providerMetadata);\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n if (metadataChain.length === 0) {\n return undefined;\n }\n\n // Merge from ancestors to current span (parent values first, child values override)\n const merged: LangSmithMetadataInput = {};\n for (let i = metadataChain.length - 1; i >= 0; i--) {\n const meta = metadataChain[i]!;\n if (meta.projectName !== undefined) merged.projectName = meta.projectName;\n if (meta.sessionId !== undefined) merged.sessionId = meta.sessionId;\n if (meta.sessionName !== undefined) merged.sessionName = meta.sessionName;\n }\n\n this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {\n traceId: span.traceId,\n spanId: span.id,\n metadataKeys: Object.keys(merged),\n ancestorCount: metadataChain.length,\n });\n\n return merged;\n }\n\n private buildRunTreePayload(\n span: AnyExportedSpan,\n traceData: LangSmithTraceData,\n isNew = false,\n ): Partial<RunTreeConfig> {\n // Extract vendor metadata from span hierarchy\n const vendorMetadata = this.findLangsmithMetadata(traceData, span);\n\n // Build metadata, omitting the langsmith vendor key\n const spanMetadata = span.metadata ? omitKeys(span.metadata, ['langsmith']) : {};\n\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...spanMetadata,\n },\n };\n\n if (isNew) {\n payload.run_type = mapSpanType(span.type);\n payload.start_time = span.startTime.getTime();\n }\n\n // Add project name - vendor metadata takes precedence over config\n const projectName = vendorMetadata?.projectName ?? this.config.projectName;\n if (projectName) {\n payload.project_name = projectName;\n }\n\n // Add session info to metadata if provided via vendor metadata\n if (vendorMetadata?.sessionId) {\n payload.metadata.session_id = vendorMetadata.sessionId;\n }\n if (vendorMetadata?.sessionName) {\n payload.metadata.session_name = vendorMetadata.sessionName;\n }\n\n // Add tags for root spans\n if (span.isRootSpan && span.tags?.length) {\n payload.tags = span.tags;\n }\n\n // Core span data\n if (span.input !== undefined) {\n payload.inputs = isKVMap(span.input) ? span.input : { input: span.input };\n }\n\n if (span.output !== undefined) {\n payload.outputs = isKVMap(span.output) ? span.output : { output: span.output };\n }\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n // See: https://docs.langchain.com/langsmith/log-llm-trace\n if (modelAttr.model !== undefined) {\n // Note - this should map to a model name recognized by LangSmith\n // eg “gpt-4o-mini”, “claude-3-opus-20240307”, etc.\n payload.metadata.ls_model_name = modelAttr.model;\n }\n\n // Provider goes to metadata (if provided by attributes)\n if (modelAttr.provider !== undefined) {\n // Note - this should map to a provider name recognized by\n // LangSmith eg “openai”, “anthropic”, etc.\n payload.metadata.ls_provider = modelAttr.provider;\n }\n\n // Usage/token info goes to metrics\n payload.metadata.usage_metadata = formatUsageMetrics(modelAttr.usage);\n\n // Model parameters go to metadata\n if (modelAttr.parameters !== undefined) {\n payload.metadata.modelParameters = modelAttr.parameters;\n }\n\n // Other LLM attributes go to metadata\n const otherAttributes = omitKeys(attributes, ['model', 'provider', 'usage', 'parameters', 'completionStartTime']);\n payload.metadata = {\n ...payload.metadata,\n ...otherAttributes,\n };\n } else {\n // For non-LLM spans, put all attributes in metadata\n payload.metadata = {\n ...payload.metadata,\n ...attributes,\n };\n }\n\n // Handle errors\n if (span.errorInfo) {\n payload.error = span.errorInfo.message;\n payload.metadata.errorDetails = span.errorInfo;\n }\n\n return payload;\n }\n}\n","/**\n * LangSmith Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add LangSmith-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'my-project' })\n * ),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * LangSmith vendor metadata that can be passed via span metadata.\n * These fields are extracted by the LangSmith exporter and used\n * to override default configuration on a per-span basis.\n */\nexport interface LangSmithMetadataInput {\n /**\n * Override the project name for this span and its children.\n * This allows dynamically routing traces to different LangSmith projects.\n */\n projectName?: string;\n /**\n * Session ID for grouping related traces in LangSmith.\n */\n sessionId?: string;\n /**\n * Session name for display in LangSmith.\n */\n sessionName?: string;\n}\n\n/**\n * Adds LangSmith metadata to the tracing options.\n *\n * The metadata is added under `metadata.langsmith` and allows you to:\n * - Route traces to different LangSmith projects via `projectName`\n * - Group traces by session via `sessionId` and `sessionName`\n *\n * @param metadata - The LangSmith metadata to add\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * // Route traces to a specific project\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'customer-support' }),\n * );\n *\n * // Or set multiple fields\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({\n * projectName: 'my-project',\n * sessionId: 'session-123',\n * }),\n * );\n *\n * // Use in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'support-traces' })\n * ),\n * },\n * });\n * ```\n */\nexport function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langsmith: {\n ...(opts.metadata?.langsmith as Record<string, unknown>),\n ...metadata,\n },\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\n\n/**\n * LangSmithUsageMetrics\n *\n * Canonical metric keys expected by LangSmith for LLM usage accounting.\n * See: https://docs.langchain.com/langsmith/log-llm-trace#provide-token-and-cost-information\n */\nexport interface LangSmithUsageMetrics {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n input_token_details?: {\n [key: string]: number;\n };\n output_token_details?: {\n [key: string]: number;\n };\n}\n\n/**\n * Formats UsageStats to LangSmith's expected metric format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangSmithUsageMetrics {\n const metrics: LangSmithUsageMetrics = {};\n\n if (usage?.inputTokens !== undefined) {\n metrics.input_tokens = usage.inputTokens;\n }\n\n if (usage?.outputTokens !== undefined) {\n metrics.output_tokens = usage.outputTokens;\n }\n\n // Compute total if we have both\n if (metrics.input_tokens !== undefined && metrics.output_tokens !== undefined) {\n metrics.total_tokens = metrics.input_tokens + metrics.output_tokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n reasoning_tokens: usage.outputDetails.reasoning,\n };\n }\n\n if (usage?.inputDetails?.cacheRead !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_read: usage.inputDetails.cacheRead,\n };\n }\n\n if (usage?.inputDetails?.cacheWrite !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_write: usage.inputDetails.cacheWrite,\n };\n }\n\n if (usage?.inputDetails?.audio !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n audio: usage.inputDetails.audio,\n };\n }\n\n if (usage?.outputDetails?.audio !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n audio: usage.outputDetails.audio,\n };\n }\n\n return metrics;\n}\n","/**\n * LangSmith Exporter for Mastra Tracing\n *\n * This exporter sends observability data to LangSmith\n * Root spans become top-level LangSmith RunTrees (no trace wrapper).\n * Events are handled as zero-duration RunTrees with matching start/end times.\n */\n\nimport type { AnyExportedSpan, ModelGenerationAttributes, ScoreEvent, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport type { LangSmithMetadataInput } from './helpers';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {\n /** LangSmith client instance */\n client?: Client;\n /**\n * The name of the LangSmith project to send traces to.\n * Overrides the LANGCHAIN_PROJECT environment variable.\n * If neither is set, traces are sent to the \"default\" project.\n */\n projectName?: string;\n /**\n * Maximum number of `spanId → langsmithRunId` mappings to retain for resolving\n * `onScoreEvent` lookups. Older entries are evicted in LRU order when the cap\n * is exceeded so long-running processes do not grow unbounded.\n * Defaults to 10000.\n */\n runIdCacheMaxEntries?: number;\n}\n\nconst DEFAULT_RUN_ID_CACHE_MAX_ENTRIES = 10_000;\n\ntype LangSmithRoot = undefined;\ntype LangSmithSpan = RunTree;\ntype LangSmithEvent = RunTree;\ntype LangSmithMetadata = LangSmithMetadataInput;\ntype LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;\n\n// Default span type for all spans\nconst DEFAULT_SPAN_TYPE = 'chain';\n\n// Exceptions to the default mapping\nconst SPAN_TYPE_EXCEPTIONS: Partial<Record<SpanType, 'llm' | 'tool' | 'chain'>> = {\n [SpanType.MODEL_GENERATION]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_CONDITIONAL_EVAL]: 'chain',\n [SpanType.WORKFLOW_WAIT_EVENT]: 'chain',\n};\n\n// Mapping function - returns valid LangSmith span types\nfunction mapSpanType(spanType: SpanType): 'llm' | 'tool' | 'chain' {\n return SPAN_TYPE_EXCEPTIONS[spanType] ?? DEFAULT_SPAN_TYPE;\n}\n\nfunction isKVMap(value: unknown): value is KVMap {\n return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport class LangSmithExporter extends TrackingExporter<\n LangSmithRoot,\n LangSmithSpan,\n LangSmithEvent,\n LangSmithMetadata,\n LangSmithExporterConfig\n> {\n override name = 'langsmith';\n #client: Client | undefined;\n\n /**\n * Maps Mastra `span.id` to the runId LangSmith allocated when the corresponding\n * RunTree was created. LangSmith's `createFeedback` requires the LangSmith runId,\n * not the Mastra span id, so scores submitted via `onScoreEvent` look up the\n * LangSmith runId here before calling the API.\n *\n * Bounded LRU keyed by Mastra span id — entries are evicted oldest-first when\n * size exceeds `#runIdCacheMaxEntries` so the cache cannot grow without bound.\n */\n #langsmithRunIdBySpanId = new Map<string, string>();\n #runIdCacheMaxEntries: number;\n\n constructor(config: LangSmithExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n super({\n ...config,\n apiKey,\n });\n\n this.#runIdCacheMaxEntries = Math.max(1, config.runIdCacheMaxEntries ?? DEFAULT_RUN_ID_CACHE_MAX_ENTRIES);\n\n if (!apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);\n return;\n }\n\n this.#client = config.client ?? new Client(this.config);\n }\n\n /** Look up the LangSmith runId for a Mastra span id, refreshing its LRU position on hit. */\n #getLangsmithRunId(spanId: string): string | undefined {\n const runId = this.#langsmithRunIdBySpanId.get(spanId);\n if (runId === undefined) return undefined;\n // Re-insert to mark as most-recently-used (Map preserves insertion order).\n this.#langsmithRunIdBySpanId.delete(spanId);\n this.#langsmithRunIdBySpanId.set(spanId, runId);\n return runId;\n }\n\n /** Remember the LangSmith runId for a Mastra span id, evicting oldest entries when full. */\n #rememberLangsmithRunId(spanId: string, runId: string): void {\n if (this.#langsmithRunIdBySpanId.has(spanId)) {\n this.#langsmithRunIdBySpanId.delete(spanId);\n }\n this.#langsmithRunIdBySpanId.set(spanId, runId);\n while (this.#langsmithRunIdBySpanId.size > this.#runIdCacheMaxEntries) {\n const oldest = this.#langsmithRunIdBySpanId.keys().next().value;\n if (oldest === undefined) break;\n this.#langsmithRunIdBySpanId.delete(oldest);\n }\n }\n\n /**\n * Flush pending trace batches to LangSmith.\n * The LangSmith Client internally batches API calls; this ensures\n * all queued runs are sent before the process exits or the flush\n * caller continues.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.awaitPendingTraceBatches();\n }\n }\n\n protected override async _postShutdown(): Promise<void> {\n this.#langsmithRunIdBySpanId.clear();\n }\n\n async onScoreEvent(event: ScoreEvent): Promise<void> {\n if (!this.#client) return;\n\n const { score } = event;\n if (!score.spanId) {\n this.logger.warn('LangSmith exporter: dropping score with no spanId; trace-level scoring is not yet supported', {\n scorerId: score.scorerId,\n });\n return;\n }\n\n const langsmithRunId = this.#getLangsmithRunId(score.spanId);\n if (!langsmithRunId) {\n this.logger.warn(\n 'LangSmith exporter: dropping score for a span that was not previously emitted to LangSmith ' +\n '(span_started must be processed before submitting a score for it)',\n {\n traceId: score.traceId,\n spanId: score.spanId,\n scorerId: score.scorerId,\n },\n );\n return;\n }\n\n const key = score.scorerName ?? score.scorerId;\n\n try {\n await this.#client.createFeedback(langsmithRunId, key, {\n score: score.score,\n ...(score.reason ? { comment: score.reason } : {}),\n feedbackId: score.scoreId,\n ...(score.scoreTraceId ? { sourceRunId: score.scoreTraceId } : {}),\n sourceInfo: {\n // User-supplied metadata is spread first so the authoritative reserved\n // fields below cannot be overwritten by `scorerId` / `scoreSource` keys\n // a caller may have set inside metadata.\n ...(score.metadata ?? {}),\n scorerId: score.scorerId,\n ...(score.scoreSource ? { scoreSource: score.scoreSource } : {}),\n },\n });\n } catch (err) {\n this.logger.error('LangSmith exporter: Failed to submit feedback', {\n error: err,\n traceId: score.traceId,\n spanId: score.spanId,\n scorerId: score.scorerId,\n });\n }\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithSpan | undefined> {\n const { span, traceData } = args;\n\n const parent = span.isRootSpan ? undefined : traceData.getParent(args);\n\n if (!span.isRootSpan && !parent) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n const payload = {\n name: span.name,\n ...this.buildRunTreePayload(span, traceData, true),\n };\n\n const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent!.createChild(payload);\n\n if (langSmithSpan.id) {\n this.#rememberLangsmithRunId(span.id, langSmithSpan.id);\n }\n\n await langSmithSpan.postRun();\n return langSmithSpan;\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithEvent | undefined> {\n const langSmithSpan = await this._buildSpan(args);\n\n if (!langSmithSpan) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n // use start-time as end-time to make an event span.\n await langSmithSpan.end({ endTime: args.span.startTime.getTime() });\n await langSmithSpan.patchRun();\n return langSmithSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });\n }\n\n protected override async _abortSpan(args: {\n span: LangSmithSpan;\n traceData: LangSmithTraceData;\n reason: SpanErrorInfo;\n }): Promise<void> {\n const { span, reason } = args;\n span.error = reason.message;\n span.metadata = {\n ...span.metadata,\n errorDetails: reason,\n };\n await span.end();\n await span.patchRun();\n }\n\n private async handleSpanUpdateOrEnd(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n isEnd: boolean;\n }): Promise<void> {\n const { span, traceData, isEnd } = args;\n\n const langSmithSpan = traceData.getSpan({ spanId: span.id });\n if (!langSmithSpan) {\n //update occurred before span start, return early data\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span, traceData);\n\n langSmithSpan.metadata = {\n ...langSmithSpan.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langSmithSpan.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langSmithSpan.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langSmithSpan.error = updatePayload.error;\n }\n\n // Add new_token event for TTFT tracking on MODEL_GENERATION spans\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = (span.attributes ?? {}) as ModelGenerationAttributes;\n if (modelAttr.completionStartTime !== undefined) {\n langSmithSpan.addEvent({\n name: 'new_token',\n time: modelAttr.completionStartTime.toISOString(),\n });\n }\n }\n\n if (isEnd) {\n // End the span with the correct endTime\n if (span.endTime) {\n await langSmithSpan.end({ endTime: span.endTime.getTime() });\n } else {\n await langSmithSpan.end();\n }\n }\n await langSmithSpan.patchRun();\n }\n\n /**\n * Find LangSmith vendor metadata by walking up the span hierarchy and merging.\n * Metadata is merged from ancestors with child values taking precedence over parent values.\n *\n * TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class\n * and reuse here and in LangfuseExporter.findLangfusePrompt()\n */\n private findLangsmithMetadata(\n traceData: LangSmithTraceData,\n span: AnyExportedSpan,\n ): LangSmithMetadataInput | undefined {\n // Collect metadata from all ancestors (current span first, then parents)\n const metadataChain: LangSmithMetadataInput[] = [];\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n if (providerMetadata) {\n metadataChain.push(providerMetadata);\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n if (metadataChain.length === 0) {\n return undefined;\n }\n\n // Merge from ancestors to current span (parent values first, child values override)\n const merged: LangSmithMetadataInput = {};\n for (let i = metadataChain.length - 1; i >= 0; i--) {\n const meta = metadataChain[i]!;\n if (meta.projectName !== undefined) merged.projectName = meta.projectName;\n if (meta.sessionId !== undefined) merged.sessionId = meta.sessionId;\n if (meta.sessionName !== undefined) merged.sessionName = meta.sessionName;\n }\n\n this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {\n traceId: span.traceId,\n spanId: span.id,\n metadataKeys: Object.keys(merged),\n ancestorCount: metadataChain.length,\n });\n\n return merged;\n }\n\n private buildRunTreePayload(\n span: AnyExportedSpan,\n traceData: LangSmithTraceData,\n isNew = false,\n ): Partial<RunTreeConfig> {\n // Extract vendor metadata from span hierarchy\n const vendorMetadata = this.findLangsmithMetadata(traceData, span);\n\n // Build metadata, omitting the langsmith vendor key\n const spanMetadata = span.metadata ? omitKeys(span.metadata, ['langsmith']) : {};\n\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...spanMetadata,\n },\n };\n\n if (isNew) {\n payload.run_type = mapSpanType(span.type);\n payload.start_time = span.startTime.getTime();\n }\n\n // Add project name - vendor metadata takes precedence over config\n const projectName = vendorMetadata?.projectName ?? this.config.projectName;\n if (projectName) {\n payload.project_name = projectName;\n }\n\n // Add session info to metadata if provided via vendor metadata\n if (vendorMetadata?.sessionId) {\n payload.metadata.session_id = vendorMetadata.sessionId;\n }\n if (vendorMetadata?.sessionName) {\n payload.metadata.session_name = vendorMetadata.sessionName;\n }\n\n // Add tags for root spans\n if (span.isRootSpan && span.tags?.length) {\n payload.tags = span.tags;\n }\n\n // Core span data\n if (span.input !== undefined) {\n payload.inputs = isKVMap(span.input) ? span.input : { input: span.input };\n }\n\n if (span.output !== undefined) {\n payload.outputs = isKVMap(span.output) ? span.output : { output: span.output };\n }\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n // See: https://docs.langchain.com/langsmith/log-llm-trace\n if (modelAttr.model !== undefined) {\n // Note - this should map to a model name recognized by LangSmith\n // eg “gpt-4o-mini”, “claude-3-opus-20240307”, etc.\n payload.metadata.ls_model_name = modelAttr.model;\n }\n\n // Provider goes to metadata (if provided by attributes)\n if (modelAttr.provider !== undefined) {\n // Note - this should map to a provider name recognized by\n // LangSmith eg “openai”, “anthropic”, etc.\n payload.metadata.ls_provider = modelAttr.provider;\n }\n\n // Usage/token info goes to metrics\n payload.metadata.usage_metadata = formatUsageMetrics(modelAttr.usage);\n\n // Model parameters go to metadata\n if (modelAttr.parameters !== undefined) {\n payload.metadata.modelParameters = modelAttr.parameters;\n }\n\n // Other LLM attributes go to metadata\n const otherAttributes = omitKeys(attributes, ['model', 'provider', 'usage', 'parameters', 'completionStartTime']);\n payload.metadata = {\n ...payload.metadata,\n ...otherAttributes,\n };\n } else {\n // For non-LLM spans, put all attributes in metadata\n payload.metadata = {\n ...payload.metadata,\n ...attributes,\n };\n }\n\n // Handle errors\n if (span.errorInfo) {\n payload.error = span.errorInfo.message;\n payload.metadata.errorDetails = span.errorInfo;\n }\n\n return payload;\n }\n}\n","/**\n * LangSmith Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add LangSmith-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'my-project' })\n * ),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * LangSmith vendor metadata that can be passed via span metadata.\n * These fields are extracted by the LangSmith exporter and used\n * to override default configuration on a per-span basis.\n */\nexport interface LangSmithMetadataInput {\n /**\n * Override the project name for this span and its children.\n * This allows dynamically routing traces to different LangSmith projects.\n */\n projectName?: string;\n /**\n * Session ID for grouping related traces in LangSmith.\n */\n sessionId?: string;\n /**\n * Session name for display in LangSmith.\n */\n sessionName?: string;\n}\n\n/**\n * Adds LangSmith metadata to the tracing options.\n *\n * The metadata is added under `metadata.langsmith` and allows you to:\n * - Route traces to different LangSmith projects via `projectName`\n * - Group traces by session via `sessionId` and `sessionName`\n *\n * @param metadata - The LangSmith metadata to add\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * // Route traces to a specific project\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'customer-support' }),\n * );\n *\n * // Or set multiple fields\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({\n * projectName: 'my-project',\n * sessionId: 'session-123',\n * }),\n * );\n *\n * // Use in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'support-traces' })\n * ),\n * },\n * });\n * ```\n */\nexport function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langsmith: {\n ...(opts.metadata?.langsmith as Record<string, unknown>),\n ...metadata,\n },\n },\n });\n}\n"]}
package/dist/tracing.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * Root spans become top-level LangSmith RunTrees (no trace wrapper).
6
6
  * Events are handled as zero-duration RunTrees with matching start/end times.
7
7
  */
8
- import type { AnyExportedSpan, SpanErrorInfo } from '@mastra/core/observability';
8
+ import type { AnyExportedSpan, ScoreEvent, SpanErrorInfo } from '@mastra/core/observability';
9
9
  import { TrackingExporter } from '@mastra/observability';
10
10
  import type { TraceData, TrackingExporterConfig } from '@mastra/observability';
11
11
  import type { ClientConfig } from 'langsmith';
@@ -20,6 +20,13 @@ export interface LangSmithExporterConfig extends ClientConfig, TrackingExporterC
20
20
  * If neither is set, traces are sent to the "default" project.
21
21
  */
22
22
  projectName?: string;
23
+ /**
24
+ * Maximum number of `spanId → langsmithRunId` mappings to retain for resolving
25
+ * `onScoreEvent` lookups. Older entries are evicted in LRU order when the cap
26
+ * is exceeded so long-running processes do not grow unbounded.
27
+ * Defaults to 10000.
28
+ */
29
+ runIdCacheMaxEntries?: number;
23
30
  }
24
31
  type LangSmithRoot = undefined;
25
32
  type LangSmithSpan = RunTree;
@@ -37,6 +44,8 @@ export declare class LangSmithExporter extends TrackingExporter<LangSmithRoot, L
37
44
  * caller continues.
38
45
  */
39
46
  protected _flush(): Promise<void>;
47
+ protected _postShutdown(): Promise<void>;
48
+ onScoreEvent(event: ScoreEvent): Promise<void>;
40
49
  protected skipBuildRootTask: boolean;
41
50
  protected _buildRoot(_args: {
42
51
  span: AnyExportedSpan;
@@ -1 +1 @@
1
- {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA6B,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAGxD,MAAM,WAAW,uBAAwB,SAAQ,YAAY,EAAE,sBAAsB;IACnF,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,aAAa,GAAG,SAAS,CAAC;AAC/B,KAAK,aAAa,GAAG,OAAO,CAAC;AAC7B,KAAK,cAAc,GAAG,OAAO,CAAC;AAC9B,KAAK,iBAAiB,GAAG,sBAAsB,CAAC;AAChD,KAAK,kBAAkB,GAAG,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,CAAC,CAAC;AAuBrG,qBAAa,iBAAkB,SAAQ,gBAAgB,CACrD,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,uBAAuB,CACxB;;IACU,IAAI,SAAe;gBAGhB,MAAM,GAAE,uBAA4B;IAiBhD;;;;;OAKG;cACsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAMhD,UAAmB,iBAAiB,UAAQ;cACnB,UAAU,CAAC,KAAK,EAAE;QACzC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;cAIb,UAAU,CAAC,IAAI,EAAE;QACxC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;cAqBb,WAAW,CAAC,IAAI,EAAE;QACzC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;cAcd,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAI1F,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAI1F,UAAU,CAAC,IAAI,EAAE;QACxC,IAAI,EAAE,aAAa,CAAC;QACpB,SAAS,EAAE,kBAAkB,CAAC;QAC9B,MAAM,EAAE,aAAa,CAAC;KACvB,GAAG,OAAO,CAAC,IAAI,CAAC;YAWH,qBAAqB;IAmDnC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IAuC7B,OAAO,CAAC,mBAAmB;CAqG5B"}
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA6B,UAAU,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGxH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAGxD,MAAM,WAAW,uBAAwB,SAAQ,YAAY,EAAE,sBAAsB;IACnF,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAID,KAAK,aAAa,GAAG,SAAS,CAAC;AAC/B,KAAK,aAAa,GAAG,OAAO,CAAC;AAC7B,KAAK,cAAc,GAAG,OAAO,CAAC;AAC9B,KAAK,iBAAiB,GAAG,sBAAsB,CAAC;AAChD,KAAK,kBAAkB,GAAG,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,CAAC,CAAC;AAuBrG,qBAAa,iBAAkB,SAAQ,gBAAgB,CACrD,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,uBAAuB,CACxB;;IACU,IAAI,SAAe;gBAehB,MAAM,GAAE,uBAA4B;IA0ChD;;;;;OAKG;cACsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;cAMvB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjD,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDpD,UAAmB,iBAAiB,UAAQ;cACnB,UAAU,CAAC,KAAK,EAAE;QACzC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;cAIb,UAAU,CAAC,IAAI,EAAE;QACxC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;cAyBb,WAAW,CAAC,IAAI,EAAE;QACzC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;cAcd,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAI1F,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAI1F,UAAU,CAAC,IAAI,EAAE;QACxC,IAAI,EAAE,aAAa,CAAC;QACpB,SAAS,EAAE,kBAAkB,CAAC;QAC9B,MAAM,EAAE,aAAa,CAAC;KACvB,GAAG,OAAO,CAAC,IAAI,CAAC;YAWH,qBAAqB;IAmDnC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IAuC7B,OAAO,CAAC,mBAAmB;CAqG5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/langsmith",
3
- "version": "1.1.20",
3
+ "version": "1.2.0-alpha.1",
4
4
  "description": "Langsmith observability provider for Mastra - includes tracing and future observability features",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,10 +25,10 @@
25
25
  "license": "Apache-2.0",
26
26
  "dependencies": {
27
27
  "langsmith": "^0.5.10",
28
- "@mastra/observability": "1.11.1"
28
+ "@mastra/observability": "1.12.0-alpha.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@ai-sdk/openai": "^2.0.103",
31
+ "@ai-sdk/openai": "^2.0.106",
32
32
  "@types/node": "22.19.15",
33
33
  "@vitest/coverage-v8": "4.1.5",
34
34
  "@vitest/ui": "4.1.5",
@@ -38,13 +38,13 @@
38
38
  "typescript": "^6.0.3",
39
39
  "vitest": "4.1.5",
40
40
  "zod": "^4.3.6",
41
- "@internal/lint": "0.0.91",
42
- "@internal/types-builder": "0.0.66",
43
- "@mastra/core": "1.32.0",
41
+ "@internal/types-builder": "0.0.67",
42
+ "@internal/lint": "0.0.92",
43
+ "@mastra/core": "1.33.0-alpha.7",
44
44
  "@observability/test-utils": "0.0.1"
45
45
  },
46
46
  "peerDependencies": {
47
- "@mastra/core": ">=1.0.0-0 <2.0.0-0"
47
+ "@mastra/core": ">=1.16.0-0 <2.0.0-0"
48
48
  },
49
49
  "homepage": "https://mastra.ai",
50
50
  "repository": {