@mastra/langsmith 1.0.0-beta.9 → 1.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { SpanType } from '@mastra/core/observability';
2
2
  import { omitKeys } from '@mastra/core/utils';
3
- import { BaseExporter } from '@mastra/observability';
3
+ import { TrackingExporter } from '@mastra/observability';
4
4
  import { Client, RunTree } from 'langsmith';
5
5
 
6
6
  // src/tracing.ts
@@ -65,117 +65,88 @@ function mapSpanType(spanType) {
65
65
  function isKVMap(value) {
66
66
  return value != null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
67
67
  }
68
- var LangSmithExporter = class extends BaseExporter {
68
+ var LangSmithExporter = class extends TrackingExporter {
69
69
  name = "langsmith";
70
- traceMap = /* @__PURE__ */ new Map();
71
- config;
72
- client;
73
- constructor(config) {
74
- super(config);
75
- config.apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;
76
- if (!config.apiKey) {
77
- this.setDisabled(`Missing required credentials (apiKey: ${!!config.apiKey})`);
78
- this.config = null;
79
- this.client = null;
70
+ #client;
71
+ constructor(config = {}) {
72
+ const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;
73
+ super({
74
+ ...config,
75
+ apiKey
76
+ });
77
+ if (!apiKey) {
78
+ this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);
80
79
  return;
81
80
  }
82
- this.client = config.client ?? new Client(config);
83
- this.config = config;
81
+ this.#client = config.client ?? new Client(this.config);
84
82
  }
85
- async _exportTracingEvent(event) {
86
- if (event.exportedSpan.isEvent) {
87
- await this.handleEventSpan(event.exportedSpan);
88
- return;
89
- }
90
- switch (event.type) {
91
- case "span_started":
92
- await this.handleSpanStarted(event.exportedSpan);
93
- break;
94
- case "span_updated":
95
- await this.handleSpanUpdateOrEnd(event.exportedSpan, false);
96
- break;
97
- case "span_ended":
98
- await this.handleSpanUpdateOrEnd(event.exportedSpan, true);
99
- break;
100
- }
83
+ skipBuildRootTask = true;
84
+ async _buildRoot(_args) {
85
+ throw new Error("Method not implemented.");
101
86
  }
102
- initializeRootSpan(span) {
103
- if (this.traceMap.has(span.traceId)) {
104
- this.logger.debug("LangSmith exporter: Reusing existing trace from local map", {
105
- traceId: span.traceId,
106
- spanId: span.id,
107
- spanName: span.name
108
- });
87
+ async _buildSpan(args) {
88
+ const { span, traceData } = args;
89
+ const parent = span.isRootSpan ? void 0 : traceData.getParent(args);
90
+ if (!span.isRootSpan && !parent) {
109
91
  return;
110
92
  }
111
- this.traceMap.set(span.traceId, { spans: /* @__PURE__ */ new Map(), activeIds: /* @__PURE__ */ new Set() });
112
- }
113
- async handleSpanStarted(span) {
114
- this.logger.debug("LangSmith exporter: handleSpanStarted", span.id, span.name);
115
- if (span.isRootSpan) {
116
- this.initializeRootSpan(span);
117
- }
118
- const method = "handleSpanStarted";
119
- const spanData = this.getSpanData({ span, method });
120
- if (!spanData) {
121
- return;
122
- }
123
- if (!span.isEvent) {
124
- spanData.activeIds.add(span.id);
125
- }
126
93
  const payload = {
127
94
  name: span.name,
128
- run_type: mapSpanType(span.type),
129
- ...this.buildRunTreePayload(span)
95
+ ...this.buildRunTreePayload(span, true)
130
96
  };
131
- const langsmithParent = this.getLangSmithParent({ spanData, span, method });
132
- let langsmithRunTree;
133
- if (!langsmithParent) {
134
- langsmithRunTree = new RunTree(payload);
135
- } else {
136
- langsmithRunTree = langsmithParent.createChild(payload);
137
- }
138
- spanData.spans.set(span.id, langsmithRunTree);
139
- await langsmithRunTree.postRun();
97
+ const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent.createChild(payload);
98
+ await langSmithSpan.postRun();
99
+ return langSmithSpan;
140
100
  }
141
- async handleSpanUpdateOrEnd(span, isEnd) {
142
- this.logger.debug("LangSmith exporter: handleSpanUpdateOrEnd", span.id, span.name, "isEnd:", isEnd);
143
- const method = isEnd ? "handleSpanEnd" : "handleSpanUpdate";
144
- const spanData = this.getSpanData({ span, method });
145
- if (!spanData) {
101
+ async _buildEvent(args) {
102
+ const langSmithSpan = await this._buildSpan(args);
103
+ if (!langSmithSpan) {
146
104
  return;
147
105
  }
148
- const langsmithRunTree = spanData.spans.get(span.id);
149
- if (!langsmithRunTree) {
150
- this.logger.warn("LangSmith exporter: No LangSmith span found for span update/end", {
151
- traceId: span.traceId,
152
- spanId: span.id,
153
- spanName: span.name,
154
- spanType: span.type,
155
- isRootSpan: span.isRootSpan,
156
- parentSpanId: span.parentSpanId,
157
- method
158
- });
106
+ await langSmithSpan.end({ endTime: args.span.startTime.getTime() });
107
+ await langSmithSpan.patchRun();
108
+ return langSmithSpan;
109
+ }
110
+ async _updateSpan(args) {
111
+ await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });
112
+ }
113
+ async _finishSpan(args) {
114
+ await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });
115
+ }
116
+ async _abortSpan(args) {
117
+ const { span, reason } = args;
118
+ span.error = reason.message;
119
+ span.metadata = {
120
+ ...span.metadata,
121
+ errorDetails: reason
122
+ };
123
+ await span.end();
124
+ await span.patchRun();
125
+ }
126
+ async handleSpanUpdateOrEnd(args) {
127
+ const { span, traceData, isEnd } = args;
128
+ const langSmithSpan = traceData.getSpan({ spanId: span.id });
129
+ if (!langSmithSpan) {
159
130
  return;
160
131
  }
161
132
  const updatePayload = this.buildRunTreePayload(span);
162
- langsmithRunTree.metadata = {
163
- ...langsmithRunTree.metadata,
133
+ langSmithSpan.metadata = {
134
+ ...langSmithSpan.metadata,
164
135
  ...updatePayload.metadata
165
136
  };
166
137
  if (updatePayload.inputs != null) {
167
- langsmithRunTree.inputs = updatePayload.inputs;
138
+ langSmithSpan.inputs = updatePayload.inputs;
168
139
  }
169
140
  if (updatePayload.outputs != null) {
170
- langsmithRunTree.outputs = updatePayload.outputs;
141
+ langSmithSpan.outputs = updatePayload.outputs;
171
142
  }
172
143
  if (updatePayload.error != null) {
173
- langsmithRunTree.error = updatePayload.error;
144
+ langSmithSpan.error = updatePayload.error;
174
145
  }
175
146
  if (span.type === SpanType.MODEL_GENERATION) {
176
147
  const modelAttr = span.attributes ?? {};
177
148
  if (modelAttr.completionStartTime !== void 0) {
178
- langsmithRunTree.addEvent({
149
+ langSmithSpan.addEvent({
179
150
  name: "new_token",
180
151
  time: modelAttr.completionStartTime.toISOString()
181
152
  });
@@ -183,96 +154,25 @@ var LangSmithExporter = class extends BaseExporter {
183
154
  }
184
155
  if (isEnd) {
185
156
  if (span.endTime) {
186
- await langsmithRunTree.end({ endTime: span.endTime.getTime() / 1e3 });
157
+ await langSmithSpan.end({ endTime: span.endTime.getTime() });
187
158
  } else {
188
- await langsmithRunTree.end();
189
- }
190
- await langsmithRunTree.patchRun();
191
- if (!span.isEvent) {
192
- spanData.activeIds.delete(span.id);
193
- }
194
- if (spanData.activeIds.size === 0) {
195
- this.traceMap.delete(span.traceId);
159
+ await langSmithSpan.end();
196
160
  }
197
161
  }
162
+ await langSmithSpan.patchRun();
198
163
  }
199
- async handleEventSpan(span) {
200
- if (span.isRootSpan) {
201
- this.logger.debug("LangSmith exporter: Creating logger for event", {
202
- traceId: span.traceId,
203
- spanId: span.id,
204
- spanName: span.name,
205
- method: "handleEventSpan"
206
- });
207
- this.initializeRootSpan(span);
208
- }
209
- const method = "handleEventSpan";
210
- const spanData = this.getSpanData({ span, method });
211
- if (!spanData) {
212
- return;
213
- }
214
- const langsmithParent = this.getLangSmithParent({ spanData, span, method });
164
+ buildRunTreePayload(span, isNew = false) {
215
165
  const payload = {
216
- ...this.buildRunTreePayload(span),
217
- name: span.name,
218
- type: mapSpanType(span.type),
219
- startTime: span.startTime.getTime() / 1e3
220
- };
221
- let langsmithRunTree;
222
- if (!langsmithParent) {
223
- langsmithRunTree = new RunTree(payload);
224
- } else {
225
- langsmithRunTree = langsmithParent.createChild(payload);
226
- }
227
- await langsmithRunTree.postRun();
228
- await langsmithRunTree.end({ endTime: span.startTime.getTime() / 1e3 });
229
- await langsmithRunTree.patchRun();
230
- }
231
- getSpanData(options) {
232
- const { span, method } = options;
233
- if (this.traceMap.has(span.traceId)) {
234
- return this.traceMap.get(span.traceId);
235
- }
236
- this.logger.warn("LangSmith exporter: No span data found for span", {
237
- traceId: span.traceId,
238
- spanId: span.id,
239
- spanName: span.name,
240
- spanType: span.type,
241
- isRootSpan: span.isRootSpan,
242
- parentSpanId: span.parentSpanId,
243
- method
244
- });
245
- }
246
- getLangSmithParent(options) {
247
- const { spanData, span, method } = options;
248
- const parentId = span.parentSpanId;
249
- if (!parentId) {
250
- return void 0;
251
- }
252
- if (spanData.spans.has(parentId)) {
253
- return spanData.spans.get(parentId);
254
- }
255
- if (parentId && !spanData.spans.has(parentId)) {
256
- return void 0;
257
- }
258
- this.logger.warn("LangSmith exporter: No parent data found for span", {
259
- traceId: span.traceId,
260
- spanId: span.id,
261
- spanName: span.name,
262
- spanType: span.type,
263
- isRootSpan: span.isRootSpan,
264
- parentSpanId: span.parentSpanId,
265
- method
266
- });
267
- }
268
- buildRunTreePayload(span) {
269
- const payload = {
270
- client: this.client,
166
+ client: this.#client,
271
167
  metadata: {
272
168
  mastra_span_type: span.type,
273
169
  ...span.metadata
274
170
  }
275
171
  };
172
+ if (isNew) {
173
+ payload.run_type = mapSpanType(span.type);
174
+ payload.start_time = span.startTime.getTime();
175
+ }
276
176
  if (this.config.projectName) {
277
177
  payload.project_name = this.config.projectName;
278
178
  }
@@ -298,7 +198,7 @@ var LangSmithExporter = class extends BaseExporter {
298
198
  if (modelAttr.parameters !== void 0) {
299
199
  payload.metadata.modelParameters = modelAttr.parameters;
300
200
  }
301
- const otherAttributes = omitKeys(attributes, ["model", "usage", "parameters", "completionStartTime"]);
201
+ const otherAttributes = omitKeys(attributes, ["model", "provider", "usage", "parameters", "completionStartTime"]);
302
202
  payload.metadata = {
303
203
  ...payload.metadata,
304
204
  ...otherAttributes
@@ -315,19 +215,6 @@ var LangSmithExporter = class extends BaseExporter {
315
215
  }
316
216
  return payload;
317
217
  }
318
- async shutdown() {
319
- if (!this.config) {
320
- return;
321
- }
322
- for (const [_traceId, spanData] of this.traceMap) {
323
- for (const [_spanId, runTree] of spanData.spans) {
324
- await runTree.end();
325
- await runTree.patchRun();
326
- }
327
- }
328
- this.traceMap.clear();
329
- await super.shutdown();
330
- }
331
218
  };
332
219
 
333
220
  export { LangSmithExporter };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/metrics.ts","../src/tracing.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 { TracingEvent, AnyExportedSpan, ModelGenerationAttributes } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, BaseExporterConfig {\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 SpanData = {\n spans: Map<string, RunTree>; // Maps span.id to LangSmith RunTrees\n activeIds: Set<string>; // Tracks started (non-event) spans not yet ended, including root\n};\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 BaseExporter {\n name = 'langsmith';\n private traceMap = new Map<string, SpanData>();\n private config: LangSmithExporterConfig;\n private client: Client;\n\n constructor(config: LangSmithExporterConfig) {\n super(config);\n\n config.apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n if (!config.apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!config.apiKey})`);\n this.config = null as any;\n this.client = null as any;\n return;\n }\n\n this.client = config.client ?? new Client(config);\n this.config = config;\n }\n\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (event.exportedSpan.isEvent) {\n await this.handleEventSpan(event.exportedSpan);\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.exportedSpan);\n break;\n case 'span_updated':\n await this.handleSpanUpdateOrEnd(event.exportedSpan, false);\n break;\n case 'span_ended':\n await this.handleSpanUpdateOrEnd(event.exportedSpan, true);\n break;\n }\n }\n\n private initializeRootSpan(span: AnyExportedSpan) {\n // Check if trace already exists - reuse existing trace data\n if (this.traceMap.has(span.traceId)) {\n this.logger.debug('LangSmith exporter: Reusing existing trace from local map', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n });\n return;\n }\n\n this.traceMap.set(span.traceId, { spans: new Map(), activeIds: new Set() });\n }\n\n private async handleSpanStarted(span: AnyExportedSpan): Promise<void> {\n this.logger.debug('LangSmith exporter: handleSpanStarted', span.id, span.name);\n if (span.isRootSpan) {\n this.initializeRootSpan(span);\n }\n\n const method = 'handleSpanStarted';\n const spanData = this.getSpanData({ span, method });\n if (!spanData) {\n return;\n }\n\n // Refcount: track active non-event spans (including root)\n if (!span.isEvent) {\n spanData.activeIds.add(span.id);\n }\n\n const payload = {\n name: span.name,\n run_type: mapSpanType(span.type),\n ...this.buildRunTreePayload(span),\n };\n\n const langsmithParent = this.getLangSmithParent({ spanData, span, method });\n let langsmithRunTree: RunTree;\n if (!langsmithParent) {\n langsmithRunTree = new RunTree(payload);\n } else {\n langsmithRunTree = langsmithParent.createChild(payload);\n }\n\n spanData.spans.set(span.id, langsmithRunTree);\n\n await langsmithRunTree.postRun();\n }\n\n private async handleSpanUpdateOrEnd(span: AnyExportedSpan, isEnd: boolean): Promise<void> {\n this.logger.debug('LangSmith exporter: handleSpanUpdateOrEnd', span.id, span.name, 'isEnd:', isEnd);\n const method = isEnd ? 'handleSpanEnd' : 'handleSpanUpdate';\n\n const spanData = this.getSpanData({ span, method });\n if (!spanData) {\n return;\n }\n\n const langsmithRunTree = spanData.spans.get(span.id);\n if (!langsmithRunTree) {\n this.logger.warn('LangSmith exporter: No LangSmith span found for span update/end', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span);\n langsmithRunTree.metadata = {\n ...langsmithRunTree.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langsmithRunTree.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langsmithRunTree.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langsmithRunTree.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 langsmithRunTree.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 (convert milliseconds to seconds)\n if (span.endTime) {\n await langsmithRunTree.end({ endTime: span.endTime.getTime() / 1000 });\n } else {\n await langsmithRunTree.end();\n }\n await langsmithRunTree.patchRun();\n\n // Refcount: mark this span as ended\n if (!span.isEvent) {\n spanData.activeIds.delete(span.id);\n }\n\n // If no more active spans remain for this trace, clean up the trace entry\n if (spanData.activeIds.size === 0) {\n this.traceMap.delete(span.traceId);\n }\n }\n }\n\n private async handleEventSpan(span: AnyExportedSpan): Promise<void> {\n if (span.isRootSpan) {\n this.logger.debug('LangSmith exporter: Creating logger for event', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n method: 'handleEventSpan',\n });\n this.initializeRootSpan(span);\n }\n\n const method = 'handleEventSpan';\n const spanData = this.getSpanData({ span, method });\n if (!spanData) {\n return;\n }\n\n const langsmithParent = this.getLangSmithParent({ spanData, span, method });\n const payload = {\n ...this.buildRunTreePayload(span),\n name: span.name,\n type: mapSpanType(span.type),\n startTime: span.startTime.getTime() / 1000,\n };\n\n let langsmithRunTree: RunTree;\n if (!langsmithParent) {\n langsmithRunTree = new RunTree(payload);\n } else {\n langsmithRunTree = langsmithParent.createChild(payload);\n }\n\n await langsmithRunTree.postRun();\n\n await langsmithRunTree.end({ endTime: span.startTime.getTime() / 1000 });\n await langsmithRunTree.patchRun();\n }\n\n private getSpanData(options: { span: AnyExportedSpan; method: string }): SpanData | undefined {\n const { span, method } = options;\n if (this.traceMap.has(span.traceId)) {\n return this.traceMap.get(span.traceId);\n }\n\n this.logger.warn('LangSmith exporter: No span data found for span', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n }\n\n private getLangSmithParent(options: {\n spanData: SpanData;\n span: AnyExportedSpan;\n method: string;\n }): RunTree | undefined {\n const { spanData, span, method } = options;\n\n const parentId = span.parentSpanId;\n if (!parentId) {\n return undefined;\n }\n\n if (spanData.spans.has(parentId)) {\n return spanData.spans.get(parentId);\n }\n\n if (parentId && !spanData.spans.has(parentId)) {\n // This means the parent exists but isn't tracked as a LangSmith span,\n // which happens when the parent is the root span\n return undefined;\n }\n\n this.logger.warn('LangSmith exporter: No parent data found for span', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n }\n\n private buildRunTreePayload(span: AnyExportedSpan): Partial<RunTreeConfig> {\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.client,\n metadata: {\n mastra_span_type: span.type,\n ...span.metadata,\n },\n };\n\n // Add project name if configured\n if (this.config.projectName) {\n payload.project_name = this.config.projectName;\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', '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 async shutdown(): Promise<void> {\n if (!this.config) {\n return;\n }\n\n // End all active spans\n for (const [_traceId, spanData] of this.traceMap) {\n for (const [_spanId, runTree] of spanData.spans) {\n await runTree.end();\n await runTree.patchRun();\n }\n }\n this.traceMap.clear();\n await super.shutdown();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/metrics.ts","../src/tracing.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 { 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 = unknown;\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 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, 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);\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 private buildRunTreePayload(span: AnyExportedSpan, isNew = false): Partial<RunTreeConfig> {\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...span.metadata,\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 if configured\n if (this.config.projectName) {\n payload.project_name = this.config.projectName;\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"]}
package/dist/tracing.d.ts CHANGED
@@ -5,12 +5,12 @@
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 { TracingEvent } from '@mastra/core/observability';
9
- import { BaseExporter } from '@mastra/observability';
10
- import type { BaseExporterConfig } from '@mastra/observability';
8
+ import type { AnyExportedSpan, SpanErrorInfo } from '@mastra/core/observability';
9
+ import { TrackingExporter } from '@mastra/observability';
10
+ import type { TraceData, TrackingExporterConfig } from '@mastra/observability';
11
11
  import type { ClientConfig } from 'langsmith';
12
- import { Client } from 'langsmith';
13
- export interface LangSmithExporterConfig extends ClientConfig, BaseExporterConfig {
12
+ import { Client, RunTree } from 'langsmith';
13
+ export interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {
14
14
  /** LangSmith client instance */
15
15
  client?: Client;
16
16
  /**
@@ -20,20 +20,43 @@ export interface LangSmithExporterConfig extends ClientConfig, BaseExporterConfi
20
20
  */
21
21
  projectName?: string;
22
22
  }
23
- export declare class LangSmithExporter extends BaseExporter {
23
+ type LangSmithRoot = undefined;
24
+ type LangSmithSpan = RunTree;
25
+ type LangSmithEvent = RunTree;
26
+ type LangSmithMetadata = unknown;
27
+ type LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;
28
+ export declare class LangSmithExporter extends TrackingExporter<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata, LangSmithExporterConfig> {
29
+ #private;
24
30
  name: string;
25
- private traceMap;
26
- private config;
27
- private client;
28
- constructor(config: LangSmithExporterConfig);
29
- protected _exportTracingEvent(event: TracingEvent): Promise<void>;
30
- private initializeRootSpan;
31
- private handleSpanStarted;
31
+ constructor(config?: LangSmithExporterConfig);
32
+ protected skipBuildRootTask: boolean;
33
+ protected _buildRoot(_args: {
34
+ span: AnyExportedSpan;
35
+ traceData: LangSmithTraceData;
36
+ }): Promise<LangSmithRoot | undefined>;
37
+ protected _buildSpan(args: {
38
+ span: AnyExportedSpan;
39
+ traceData: LangSmithTraceData;
40
+ }): Promise<LangSmithSpan | undefined>;
41
+ protected _buildEvent(args: {
42
+ span: AnyExportedSpan;
43
+ traceData: LangSmithTraceData;
44
+ }): Promise<LangSmithEvent | undefined>;
45
+ protected _updateSpan(args: {
46
+ span: AnyExportedSpan;
47
+ traceData: LangSmithTraceData;
48
+ }): Promise<void>;
49
+ protected _finishSpan(args: {
50
+ span: AnyExportedSpan;
51
+ traceData: LangSmithTraceData;
52
+ }): Promise<void>;
53
+ protected _abortSpan(args: {
54
+ span: LangSmithSpan;
55
+ traceData: LangSmithTraceData;
56
+ reason: SpanErrorInfo;
57
+ }): Promise<void>;
32
58
  private handleSpanUpdateOrEnd;
33
- private handleEventSpan;
34
- private getSpanData;
35
- private getLangSmithParent;
36
59
  private buildRunTreePayload;
37
- shutdown(): Promise<void>;
38
60
  }
61
+ export {};
39
62
  //# sourceMappingURL=tracing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA8C,MAAM,4BAA4B,CAAC;AAG3G,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAW,MAAM,WAAW,CAAC;AAI5C,MAAM,WAAW,uBAAwB,SAAQ,YAAY,EAAE,kBAAkB;IAC/E,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA4BD,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,IAAI,SAAe;IACnB,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,uBAAuB;cAgB3B,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBvE,OAAO,CAAC,kBAAkB;YAcZ,iBAAiB;YAoCjB,qBAAqB;YAsErB,eAAe;IAsC7B,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,kBAAkB;IAiC1B,OAAO,CAAC,mBAAmB;IA8ErB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAehC"}
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;AAI5C,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,OAAO,CAAC;AACjC,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,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,OAAO,CAAC,mBAAmB;CAkF5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/langsmith",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.1-alpha.0",
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,22 +25,23 @@
25
25
  "license": "Apache-2.0",
26
26
  "dependencies": {
27
27
  "langsmith": ">=0.3.79",
28
- "@mastra/observability": "1.0.0-beta.8"
28
+ "@mastra/observability": "1.1.0-alpha.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@ai-sdk/openai": "^2.0.35",
32
- "@types/node": "22.13.17",
32
+ "@types/node": "22.19.7",
33
33
  "@vitest/coverage-v8": "4.0.12",
34
34
  "@vitest/ui": "4.0.12",
35
- "dotenv": "^17.2.2",
35
+ "dotenv": "^17.2.3",
36
36
  "eslint": "^9.37.0",
37
- "tsup": "^8.5.0",
38
- "typescript": "^5.8.3",
39
- "vitest": "4.0.12",
37
+ "tsup": "^8.5.1",
38
+ "typescript": "^5.9.3",
39
+ "vitest": "4.0.16",
40
40
  "zod": "^3.25.76",
41
- "@internal/types-builder": "0.0.28",
42
- "@mastra/core": "1.0.0-beta.16",
43
- "@internal/lint": "0.0.53"
41
+ "@internal/types-builder": "0.0.30",
42
+ "@mastra/core": "1.1.0-alpha.0",
43
+ "@observability/test-utils": "0.0.1",
44
+ "@internal/lint": "0.0.55"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "@mastra/core": ">=1.0.0-0 <2.0.0-0"