@mastra/langsmith 1.0.0-beta.10 → 1.0.0-beta.12

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,48 @@
1
1
  # @mastra/langsmith
2
2
 
3
+ ## 1.0.0-beta.12
4
+
5
+ ### Minor Changes
6
+
7
+ - Added `TrackingExporter` base class with improved handling for: ([#11870](https://github.com/mastra-ai/mastra/pull/11870))
8
+ - **Out-of-order span processing**: Spans that arrive before their parents are now queued and processed once dependencies are available
9
+ - **Delayed cleanup**: Trace data is retained briefly after spans end to handle late-arriving updates
10
+ - **Memory management**: Configurable limits on pending and total traces to prevent memory leaks
11
+
12
+ New configuration options on `TrackingExporterConfig`:
13
+ - `earlyQueueMaxAttempts` - Max retry attempts for queued events (default: 5)
14
+ - `earlyQueueTTLMs` - TTL for queued events in ms (default: 30000)
15
+ - `traceCleanupDelayMs` - Delay before cleaning up completed traces (default: 30000)
16
+ - `maxPendingCleanupTraces` - Soft cap on traces awaiting cleanup (default: 100)
17
+ - `maxTotalTraces` - Hard cap on total traces (default: 500)
18
+
19
+ Updated @mastra/braintrust, @mastra/langfuse, @mastra/langsmith, @mastra/posthog to use the new TrackingExporter
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [[`ebae12a`](https://github.com/mastra-ai/mastra/commit/ebae12a2dd0212e75478981053b148a2c246962d), [`c61a0a5`](https://github.com/mastra-ai/mastra/commit/c61a0a5de4904c88fd8b3718bc26d1be1c2ec6e7), [`69136e7`](https://github.com/mastra-ai/mastra/commit/69136e748e32f57297728a4e0f9a75988462f1a7), [`449aed2`](https://github.com/mastra-ai/mastra/commit/449aed2ba9d507b75bf93d427646ea94f734dfd1), [`eb648a2`](https://github.com/mastra-ai/mastra/commit/eb648a2cc1728f7678768dd70cd77619b448dab9), [`0131105`](https://github.com/mastra-ai/mastra/commit/0131105532e83bdcbb73352fc7d0879eebf140dc), [`9d5059e`](https://github.com/mastra-ai/mastra/commit/9d5059eae810829935fb08e81a9bb7ecd5b144a7), [`ef756c6`](https://github.com/mastra-ai/mastra/commit/ef756c65f82d16531c43f49a27290a416611e526), [`b00ccd3`](https://github.com/mastra-ai/mastra/commit/b00ccd325ebd5d9e37e34dd0a105caae67eb568f), [`3bdfa75`](https://github.com/mastra-ai/mastra/commit/3bdfa7507a91db66f176ba8221aa28dd546e464a), [`e770de9`](https://github.com/mastra-ai/mastra/commit/e770de941a287a49b1964d44db5a5763d19890a6), [`52e2716`](https://github.com/mastra-ai/mastra/commit/52e2716b42df6eff443de72360ae83e86ec23993), [`27b4040`](https://github.com/mastra-ai/mastra/commit/27b4040bfa1a95d92546f420a02a626b1419a1d6), [`610a70b`](https://github.com/mastra-ai/mastra/commit/610a70bdad282079f0c630e0d7bb284578f20151), [`8dc7f55`](https://github.com/mastra-ai/mastra/commit/8dc7f55900395771da851dc7d78d53ae84fe34ec), [`8379099`](https://github.com/mastra-ai/mastra/commit/8379099fc467af6bef54dd7f80c9bd75bf8bbddf), [`b06be72`](https://github.com/mastra-ai/mastra/commit/b06be7223d5ef23edc98c01a67ef713c6cc039f9), [`8c0ec25`](https://github.com/mastra-ai/mastra/commit/8c0ec25646c8a7df253ed1e5ff4863a0d3f1316c), [`ff4d9a6`](https://github.com/mastra-ai/mastra/commit/ff4d9a6704fc87b31a380a76ed22736fdedbba5a), [`69821ef`](https://github.com/mastra-ai/mastra/commit/69821ef806482e2c44e2197ac0b050c3fe3a5285), [`1ed5716`](https://github.com/mastra-ai/mastra/commit/1ed5716830867b3774c4a1b43cc0d82935f32b96), [`4186bdd`](https://github.com/mastra-ai/mastra/commit/4186bdd00731305726fa06adba0b076a1d50b49f), [`7aaf973`](https://github.com/mastra-ai/mastra/commit/7aaf973f83fbbe9521f1f9e7a4fd99b8de464617)]:
24
+ - @mastra/core@1.0.0-beta.22
25
+ - @mastra/observability@1.0.0-beta.11
26
+
27
+ ## 1.0.0-beta.11
28
+
29
+ ### Patch Changes
30
+
31
+ - Add embedded documentation support for Mastra packages ([#11472](https://github.com/mastra-ai/mastra/pull/11472))
32
+
33
+ Mastra packages now include embedded documentation in the published npm package under `dist/docs/`. This enables coding agents and AI assistants to understand and use the framework by reading documentation directly from `node_modules`.
34
+
35
+ Each package includes:
36
+ - **SKILL.md** - Entry point explaining the package's purpose and capabilities
37
+ - **SOURCE_MAP.json** - Machine-readable index mapping exports to types and implementation files
38
+ - **Topic folders** - Conceptual documentation organized by feature area
39
+
40
+ Documentation is driven by the `packages` frontmatter field in MDX files, which maps docs to their corresponding packages. CI validation ensures all docs include this field.
41
+
42
+ - Updated dependencies [[`d2d3e22`](https://github.com/mastra-ai/mastra/commit/d2d3e22a419ee243f8812a84e3453dd44365ecb0), [`bc72b52`](https://github.com/mastra-ai/mastra/commit/bc72b529ee4478fe89ecd85a8be47ce0127b82a0), [`05b8bee`](https://github.com/mastra-ai/mastra/commit/05b8bee9e50e6c2a4a2bf210eca25ee212ca24fa), [`c042bd0`](https://github.com/mastra-ai/mastra/commit/c042bd0b743e0e86199d0cb83344ca7690e34a9c), [`940a2b2`](https://github.com/mastra-ai/mastra/commit/940a2b27480626ed7e74f55806dcd2181c1dd0c2), [`e0941c3`](https://github.com/mastra-ai/mastra/commit/e0941c3d7fc75695d5d258e7008fd5d6e650800c), [`0c0580a`](https://github.com/mastra-ai/mastra/commit/0c0580a42f697cd2a7d5973f25bfe7da9055038a), [`28f5f89`](https://github.com/mastra-ai/mastra/commit/28f5f89705f2409921e3c45178796c0e0d0bbb64), [`e601b27`](https://github.com/mastra-ai/mastra/commit/e601b272c70f3a5ecca610373aa6223012704892), [`3d3366f`](https://github.com/mastra-ai/mastra/commit/3d3366f31683e7137d126a3a57174a222c5801fb), [`5a4953f`](https://github.com/mastra-ai/mastra/commit/5a4953f7d25bb15ca31ed16038092a39cb3f98b3), [`eb9e522`](https://github.com/mastra-ai/mastra/commit/eb9e522ce3070a405e5b949b7bf5609ca51d7fe2), [`20e6f19`](https://github.com/mastra-ai/mastra/commit/20e6f1971d51d3ff6dd7accad8aaaae826d540ed), [`8a6734a`](https://github.com/mastra-ai/mastra/commit/8a6734a9b3eb192ada1f723d248b08b2258dd6b3), [`4f0b3c6`](https://github.com/mastra-ai/mastra/commit/4f0b3c66f196c06448487f680ccbb614d281e2f7), [`74c4f22`](https://github.com/mastra-ai/mastra/commit/74c4f22ed4c71e72598eacc346ba95cdbc00294f), [`81b6a8f`](https://github.com/mastra-ai/mastra/commit/81b6a8ff79f49a7549d15d66624ac1a0b8f5f971), [`e4d366a`](https://github.com/mastra-ai/mastra/commit/e4d366aeb500371dd4210d6aa8361a4c21d87034), [`a4f010b`](https://github.com/mastra-ai/mastra/commit/a4f010b22e4355a5fdee70a1fe0f6e4a692cc29e), [`73b0bb3`](https://github.com/mastra-ai/mastra/commit/73b0bb394dba7c9482eb467a97ab283dbc0ef4db), [`5627a8c`](https://github.com/mastra-ai/mastra/commit/5627a8c6dc11fe3711b3fa7a6ffd6eb34100a306), [`3ff45d1`](https://github.com/mastra-ai/mastra/commit/3ff45d10e0c80c5335a957ab563da72feb623520), [`251df45`](https://github.com/mastra-ai/mastra/commit/251df4531407dfa46d805feb40ff3fb49769f455), [`f894d14`](https://github.com/mastra-ai/mastra/commit/f894d148946629af7b1f452d65a9cf864cec3765), [`c2b9547`](https://github.com/mastra-ai/mastra/commit/c2b9547bf435f56339f23625a743b2147ab1c7a6), [`580b592`](https://github.com/mastra-ai/mastra/commit/580b5927afc82fe460dfdf9a38a902511b6b7e7f), [`58e3931`](https://github.com/mastra-ai/mastra/commit/58e3931af9baa5921688566210f00fb0c10479fa), [`08bb631`](https://github.com/mastra-ai/mastra/commit/08bb631ae2b14684b2678e3549d0b399a6f0561e), [`4fba91b`](https://github.com/mastra-ai/mastra/commit/4fba91bec7c95911dc28e369437596b152b04cd0), [`12b0cc4`](https://github.com/mastra-ai/mastra/commit/12b0cc4077d886b1a552637dedb70a7ade93528c)]:
43
+ - @mastra/core@1.0.0-beta.20
44
+ - @mastra/observability@1.0.0-beta.10
45
+
3
46
  ## 1.0.0-beta.10
4
47
 
5
48
  ### Patch Changes
package/README.md CHANGED
@@ -10,22 +10,51 @@ npm install @mastra/langsmith
10
10
 
11
11
  ## Usage
12
12
 
13
+ ### Zero-Config Setup
14
+
15
+ The exporter automatically reads credentials from environment variables:
16
+
17
+ ```bash
18
+ # Required
19
+ LANGSMITH_API_KEY=lsv2_pt_...
20
+
21
+ # Optional
22
+ LANGCHAIN_PROJECT=my-project # Project name, defaults to "default"
23
+ ```
24
+
13
25
  ```typescript
14
26
  import { LangSmithExporter } from '@mastra/langsmith';
15
27
 
16
- // Set process.env.LANGSMITH_TRACING = "true";
28
+ const mastra = new Mastra({
29
+ ...,
30
+ observability: {
31
+ configs: {
32
+ langsmith: {
33
+ serviceName: 'my-service',
34
+ exporters: [new LangSmithExporter()],
35
+ },
36
+ },
37
+ },
38
+ });
39
+ ```
40
+
41
+ ### Explicit Configuration
42
+
43
+ You can also pass credentials directly:
44
+
45
+ ```typescript
46
+ import { LangSmithExporter } from '@mastra/langsmith';
17
47
 
18
- // Use with Mastra
19
48
  const mastra = new Mastra({
20
49
  ...,
21
50
  observability: {
22
51
  configs: {
23
52
  langsmith: {
24
- serviceName: 'service',
53
+ serviceName: 'my-service',
25
54
  exporters: [
26
55
  new LangSmithExporter({
27
- apiKey: process.env.LANGSMITH_API_KEY, // Defaults to process.env.LANGSMITH_API_KEY
28
- projectName: 'my-custom-project', // Optional: specify which LangSmith project to send traces to
56
+ apiKey: 'lsv2_pt_...',
57
+ projectName: 'my-custom-project', // Optional
29
58
  }),
30
59
  ],
31
60
  },
@@ -38,7 +67,7 @@ const mastra = new Mastra({
38
67
 
39
68
  | Option | Type | Description |
40
69
  | ------------- | -------- | ------------------------------------------------------------------------------------------ |
41
- | `apiKey` | `string` | LangSmith API key. Defaults to `process.env.LANGSMITH_API_KEY` |
70
+ | `apiKey` | `string` | LangSmith API key. Defaults to `LANGSMITH_API_KEY` env var |
42
71
  | `projectName` | `string` | The name of the LangSmith project to send traces to. Overrides `LANGCHAIN_PROJECT` env var |
43
72
  | `apiUrl` | `string` | Custom LangSmith API URL (for self-hosted instances) |
44
73
  | `client` | `Client` | Custom LangSmith client instance |
package/dist/index.cjs CHANGED
@@ -67,117 +67,88 @@ function mapSpanType(spanType) {
67
67
  function isKVMap(value) {
68
68
  return value != null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
69
69
  }
70
- var LangSmithExporter = class extends observability.BaseExporter {
70
+ var LangSmithExporter = class extends observability.TrackingExporter {
71
71
  name = "langsmith";
72
- traceMap = /* @__PURE__ */ new Map();
73
- config;
74
- client;
75
- constructor(config) {
76
- super(config);
77
- config.apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;
78
- if (!config.apiKey) {
79
- this.setDisabled(`Missing required credentials (apiKey: ${!!config.apiKey})`);
80
- this.config = null;
81
- this.client = null;
72
+ #client;
73
+ constructor(config = {}) {
74
+ const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;
75
+ super({
76
+ ...config,
77
+ apiKey
78
+ });
79
+ if (!apiKey) {
80
+ this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);
82
81
  return;
83
82
  }
84
- this.client = config.client ?? new langsmith.Client(config);
85
- this.config = config;
83
+ this.#client = config.client ?? new langsmith.Client(this.config);
86
84
  }
87
- async _exportTracingEvent(event) {
88
- if (event.exportedSpan.isEvent) {
89
- await this.handleEventSpan(event.exportedSpan);
90
- return;
91
- }
92
- switch (event.type) {
93
- case "span_started":
94
- await this.handleSpanStarted(event.exportedSpan);
95
- break;
96
- case "span_updated":
97
- await this.handleSpanUpdateOrEnd(event.exportedSpan, false);
98
- break;
99
- case "span_ended":
100
- await this.handleSpanUpdateOrEnd(event.exportedSpan, true);
101
- break;
102
- }
85
+ skipBuildRootTask = true;
86
+ async _buildRoot(_args) {
87
+ throw new Error("Method not implemented.");
103
88
  }
104
- initializeRootSpan(span) {
105
- if (this.traceMap.has(span.traceId)) {
106
- this.logger.debug("LangSmith exporter: Reusing existing trace from local map", {
107
- traceId: span.traceId,
108
- spanId: span.id,
109
- spanName: span.name
110
- });
89
+ async _buildSpan(args) {
90
+ const { span, traceData } = args;
91
+ const parent = span.isRootSpan ? void 0 : traceData.getParent(args);
92
+ if (!span.isRootSpan && !parent) {
111
93
  return;
112
94
  }
113
- this.traceMap.set(span.traceId, { spans: /* @__PURE__ */ new Map(), activeIds: /* @__PURE__ */ new Set() });
114
- }
115
- async handleSpanStarted(span) {
116
- this.logger.debug("LangSmith exporter: handleSpanStarted", span.id, span.name);
117
- if (span.isRootSpan) {
118
- this.initializeRootSpan(span);
119
- }
120
- const method = "handleSpanStarted";
121
- const spanData = this.getSpanData({ span, method });
122
- if (!spanData) {
123
- return;
124
- }
125
- if (!span.isEvent) {
126
- spanData.activeIds.add(span.id);
127
- }
128
95
  const payload = {
129
96
  name: span.name,
130
- run_type: mapSpanType(span.type),
131
- ...this.buildRunTreePayload(span)
97
+ ...this.buildRunTreePayload(span, true)
132
98
  };
133
- const langsmithParent = this.getLangSmithParent({ spanData, span, method });
134
- let langsmithRunTree;
135
- if (!langsmithParent) {
136
- langsmithRunTree = new langsmith.RunTree(payload);
137
- } else {
138
- langsmithRunTree = langsmithParent.createChild(payload);
139
- }
140
- spanData.spans.set(span.id, langsmithRunTree);
141
- await langsmithRunTree.postRun();
99
+ const langSmithSpan = span.isRootSpan ? new langsmith.RunTree(payload) : parent.createChild(payload);
100
+ await langSmithSpan.postRun();
101
+ return langSmithSpan;
142
102
  }
143
- async handleSpanUpdateOrEnd(span, isEnd) {
144
- this.logger.debug("LangSmith exporter: handleSpanUpdateOrEnd", span.id, span.name, "isEnd:", isEnd);
145
- const method = isEnd ? "handleSpanEnd" : "handleSpanUpdate";
146
- const spanData = this.getSpanData({ span, method });
147
- if (!spanData) {
103
+ async _buildEvent(args) {
104
+ const langSmithSpan = await this._buildSpan(args);
105
+ if (!langSmithSpan) {
148
106
  return;
149
107
  }
150
- const langsmithRunTree = spanData.spans.get(span.id);
151
- if (!langsmithRunTree) {
152
- this.logger.warn("LangSmith exporter: No LangSmith span found for span update/end", {
153
- traceId: span.traceId,
154
- spanId: span.id,
155
- spanName: span.name,
156
- spanType: span.type,
157
- isRootSpan: span.isRootSpan,
158
- parentSpanId: span.parentSpanId,
159
- method
160
- });
108
+ await langSmithSpan.end({ endTime: args.span.startTime.getTime() });
109
+ await langSmithSpan.patchRun();
110
+ return langSmithSpan;
111
+ }
112
+ async _updateSpan(args) {
113
+ await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });
114
+ }
115
+ async _finishSpan(args) {
116
+ await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });
117
+ }
118
+ async _abortSpan(args) {
119
+ const { span, reason } = args;
120
+ span.error = reason.message;
121
+ span.metadata = {
122
+ ...span.metadata,
123
+ errorDetails: reason
124
+ };
125
+ await span.end();
126
+ await span.patchRun();
127
+ }
128
+ async handleSpanUpdateOrEnd(args) {
129
+ const { span, traceData, isEnd } = args;
130
+ const langSmithSpan = traceData.getSpan({ spanId: span.id });
131
+ if (!langSmithSpan) {
161
132
  return;
162
133
  }
163
134
  const updatePayload = this.buildRunTreePayload(span);
164
- langsmithRunTree.metadata = {
165
- ...langsmithRunTree.metadata,
135
+ langSmithSpan.metadata = {
136
+ ...langSmithSpan.metadata,
166
137
  ...updatePayload.metadata
167
138
  };
168
139
  if (updatePayload.inputs != null) {
169
- langsmithRunTree.inputs = updatePayload.inputs;
140
+ langSmithSpan.inputs = updatePayload.inputs;
170
141
  }
171
142
  if (updatePayload.outputs != null) {
172
- langsmithRunTree.outputs = updatePayload.outputs;
143
+ langSmithSpan.outputs = updatePayload.outputs;
173
144
  }
174
145
  if (updatePayload.error != null) {
175
- langsmithRunTree.error = updatePayload.error;
146
+ langSmithSpan.error = updatePayload.error;
176
147
  }
177
148
  if (span.type === observability$1.SpanType.MODEL_GENERATION) {
178
149
  const modelAttr = span.attributes ?? {};
179
150
  if (modelAttr.completionStartTime !== void 0) {
180
- langsmithRunTree.addEvent({
151
+ langSmithSpan.addEvent({
181
152
  name: "new_token",
182
153
  time: modelAttr.completionStartTime.toISOString()
183
154
  });
@@ -185,96 +156,25 @@ var LangSmithExporter = class extends observability.BaseExporter {
185
156
  }
186
157
  if (isEnd) {
187
158
  if (span.endTime) {
188
- await langsmithRunTree.end({ endTime: span.endTime.getTime() / 1e3 });
159
+ await langSmithSpan.end({ endTime: span.endTime.getTime() });
189
160
  } else {
190
- await langsmithRunTree.end();
191
- }
192
- await langsmithRunTree.patchRun();
193
- if (!span.isEvent) {
194
- spanData.activeIds.delete(span.id);
195
- }
196
- if (spanData.activeIds.size === 0) {
197
- this.traceMap.delete(span.traceId);
161
+ await langSmithSpan.end();
198
162
  }
199
163
  }
164
+ await langSmithSpan.patchRun();
200
165
  }
201
- async handleEventSpan(span) {
202
- if (span.isRootSpan) {
203
- this.logger.debug("LangSmith exporter: Creating logger for event", {
204
- traceId: span.traceId,
205
- spanId: span.id,
206
- spanName: span.name,
207
- method: "handleEventSpan"
208
- });
209
- this.initializeRootSpan(span);
210
- }
211
- const method = "handleEventSpan";
212
- const spanData = this.getSpanData({ span, method });
213
- if (!spanData) {
214
- return;
215
- }
216
- const langsmithParent = this.getLangSmithParent({ spanData, span, method });
166
+ buildRunTreePayload(span, isNew = false) {
217
167
  const payload = {
218
- ...this.buildRunTreePayload(span),
219
- name: span.name,
220
- type: mapSpanType(span.type),
221
- startTime: span.startTime.getTime() / 1e3
222
- };
223
- let langsmithRunTree;
224
- if (!langsmithParent) {
225
- langsmithRunTree = new langsmith.RunTree(payload);
226
- } else {
227
- langsmithRunTree = langsmithParent.createChild(payload);
228
- }
229
- await langsmithRunTree.postRun();
230
- await langsmithRunTree.end({ endTime: span.startTime.getTime() / 1e3 });
231
- await langsmithRunTree.patchRun();
232
- }
233
- getSpanData(options) {
234
- const { span, method } = options;
235
- if (this.traceMap.has(span.traceId)) {
236
- return this.traceMap.get(span.traceId);
237
- }
238
- this.logger.warn("LangSmith exporter: No span data found for span", {
239
- traceId: span.traceId,
240
- spanId: span.id,
241
- spanName: span.name,
242
- spanType: span.type,
243
- isRootSpan: span.isRootSpan,
244
- parentSpanId: span.parentSpanId,
245
- method
246
- });
247
- }
248
- getLangSmithParent(options) {
249
- const { spanData, span, method } = options;
250
- const parentId = span.parentSpanId;
251
- if (!parentId) {
252
- return void 0;
253
- }
254
- if (spanData.spans.has(parentId)) {
255
- return spanData.spans.get(parentId);
256
- }
257
- if (parentId && !spanData.spans.has(parentId)) {
258
- return void 0;
259
- }
260
- this.logger.warn("LangSmith exporter: No parent data found for span", {
261
- traceId: span.traceId,
262
- spanId: span.id,
263
- spanName: span.name,
264
- spanType: span.type,
265
- isRootSpan: span.isRootSpan,
266
- parentSpanId: span.parentSpanId,
267
- method
268
- });
269
- }
270
- buildRunTreePayload(span) {
271
- const payload = {
272
- client: this.client,
168
+ client: this.#client,
273
169
  metadata: {
274
170
  mastra_span_type: span.type,
275
171
  ...span.metadata
276
172
  }
277
173
  };
174
+ if (isNew) {
175
+ payload.run_type = mapSpanType(span.type);
176
+ payload.start_time = span.startTime.getTime();
177
+ }
278
178
  if (this.config.projectName) {
279
179
  payload.project_name = this.config.projectName;
280
180
  }
@@ -300,7 +200,7 @@ var LangSmithExporter = class extends observability.BaseExporter {
300
200
  if (modelAttr.parameters !== void 0) {
301
201
  payload.metadata.modelParameters = modelAttr.parameters;
302
202
  }
303
- const otherAttributes = utils.omitKeys(attributes, ["model", "usage", "parameters", "completionStartTime"]);
203
+ const otherAttributes = utils.omitKeys(attributes, ["model", "provider", "usage", "parameters", "completionStartTime"]);
304
204
  payload.metadata = {
305
205
  ...payload.metadata,
306
206
  ...otherAttributes
@@ -317,19 +217,6 @@ var LangSmithExporter = class extends observability.BaseExporter {
317
217
  }
318
218
  return payload;
319
219
  }
320
- async shutdown() {
321
- if (!this.config) {
322
- return;
323
- }
324
- for (const [_traceId, spanData] of this.traceMap) {
325
- for (const [_spanId, runTree] of spanData.spans) {
326
- await runTree.end();
327
- await runTree.patchRun();
328
- }
329
- }
330
- this.traceMap.clear();
331
- await super.shutdown();
332
- }
333
220
  };
334
221
 
335
222
  exports.LangSmithExporter = LangSmithExporter;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/metrics.ts","../src/tracing.ts"],"names":["SpanType","BaseExporter","Client","RunTree","omitKeys"],"mappings":";;;;;;;;;;AAuBO,SAAS,mBAAmB,KAAA,EAA2C;AAC5E,EAAA,MAAM,UAAiC,EAAC;AAExC,EAAA,IAAI,KAAA,EAAO,gBAAgB,MAAA,EAAW;AACpC,IAAA,OAAA,CAAQ,eAAe,KAAA,CAAM,WAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,KAAA,EAAO,iBAAiB,MAAA,EAAW;AACrC,IAAA,OAAA,CAAQ,gBAAgB,KAAA,CAAM,YAAA;AAAA,EAChC;AAGA,EAAA,IAAI,OAAA,CAAQ,YAAA,KAAiB,MAAA,IAAa,OAAA,CAAQ,kBAAkB,MAAA,EAAW;AAC7E,IAAA,OAAA,CAAQ,YAAA,GAAe,OAAA,CAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;AAAA,EACxD;AAEA,EAAA,IAAI,KAAA,EAAO,aAAA,EAAe,SAAA,KAAc,MAAA,EAAW;AACjD,IAAA,OAAA,CAAQ,oBAAA,GAAuB;AAAA,MAC7B,GAAI,OAAA,CAAQ,oBAAA,IAAwB,EAAC;AAAA,MACrC,gBAAA,EAAkB,MAAM,aAAA,CAAc;AAAA,KACxC;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,EAAO,YAAA,EAAc,SAAA,KAAc,MAAA,EAAW;AAChD,IAAA,OAAA,CAAQ,mBAAA,GAAsB;AAAA,MAC5B,GAAI,OAAA,CAAQ,mBAAA,IAAuB,EAAC;AAAA,MACpC,UAAA,EAAY,MAAM,YAAA,CAAa;AAAA,KACjC;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,EAAO,YAAA,EAAc,UAAA,KAAe,MAAA,EAAW;AACjD,IAAA,OAAA,CAAQ,mBAAA,GAAsB;AAAA,MAC5B,GAAI,OAAA,CAAQ,mBAAA,IAAuB,EAAC;AAAA,MACpC,WAAA,EAAa,MAAM,YAAA,CAAa;AAAA,KAClC;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,EAAO,YAAA,EAAc,KAAA,KAAU,MAAA,EAAW;AAC5C,IAAA,OAAA,CAAQ,mBAAA,GAAsB;AAAA,MAC5B,GAAI,OAAA,CAAQ,mBAAA,IAAuB,EAAC;AAAA,MACpC,KAAA,EAAO,MAAM,YAAA,CAAa;AAAA,KAC5B;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,EAAO,aAAA,EAAe,KAAA,KAAU,MAAA,EAAW;AAC7C,IAAA,OAAA,CAAQ,oBAAA,GAAuB;AAAA,MAC7B,GAAI,OAAA,CAAQ,oBAAA,IAAwB,EAAC;AAAA,MACrC,KAAA,EAAO,MAAM,aAAA,CAAc;AAAA,KAC7B;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;;;ACxCA,IAAM,iBAAA,GAAoB,OAAA;AAG1B,IAAM,oBAAA,GAA4E;AAAA,EAChF,CAACA,wBAAA,CAAS,gBAAgB,GAAG,KAAA;AAAA,EAC7B,CAACA,wBAAA,CAAS,SAAS,GAAG,MAAA;AAAA,EACtB,CAACA,wBAAA,CAAS,aAAa,GAAG,MAAA;AAAA,EAC1B,CAACA,wBAAA,CAAS,yBAAyB,GAAG,OAAA;AAAA,EACtC,CAACA,wBAAA,CAAS,mBAAmB,GAAG;AAClC,CAAA;AAGA,SAAS,YAAY,QAAA,EAA8C;AACjE,EAAA,OAAO,oBAAA,CAAqB,QAAQ,CAAA,IAAK,iBAAA;AAC3C;AAEA,SAAS,QAAQ,KAAA,EAAgC;AAC/C,EAAA,OAAO,KAAA,IAAS,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,EAAE,KAAA,YAAiB,IAAA,CAAA;AACnG;AAEO,IAAM,iBAAA,GAAN,cAAgCC,0BAAA,CAAa;AAAA,EAClD,IAAA,GAAO,WAAA;AAAA,EACC,QAAA,uBAAe,GAAA,EAAsB;AAAA,EACrC,MAAA;AAAA,EACA,MAAA;AAAA,EAER,YAAY,MAAA,EAAiC;AAC3C,IAAA,KAAA,CAAM,MAAM,CAAA;AAEZ,IAAA,MAAA,CAAO,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,iBAAA;AAE7C,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,IAAA,CAAK,YAAY,CAAA,sCAAA,EAAyC,CAAC,CAAC,MAAA,CAAO,MAAM,CAAA,CAAA,CAAG,CAAA;AAC5E,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,IAAIC,iBAAO,MAAM,CAAA;AAChD,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA,EAEA,MAAgB,oBAAoB,KAAA,EAAoC;AACtE,IAAA,IAAI,KAAA,CAAM,aAAa,OAAA,EAAS;AAC9B,MAAA,MAAM,IAAA,CAAK,eAAA,CAAgB,KAAA,CAAM,YAAY,CAAA;AAC7C,MAAA;AAAA,IACF;AAEA,IAAA,QAAQ,MAAM,IAAA;AAAM,MAClB,KAAK,cAAA;AACH,QAAA,MAAM,IAAA,CAAK,iBAAA,CAAkB,KAAA,CAAM,YAAY,CAAA;AAC/C,QAAA;AAAA,MACF,KAAK,cAAA;AACH,QAAA,MAAM,IAAA,CAAK,qBAAA,CAAsB,KAAA,CAAM,YAAA,EAAc,KAAK,CAAA;AAC1D,QAAA;AAAA,MACF,KAAK,YAAA;AACH,QAAA,MAAM,IAAA,CAAK,qBAAA,CAAsB,KAAA,CAAM,YAAA,EAAc,IAAI,CAAA;AACzD,QAAA;AAAA;AACJ,EACF;AAAA,EAEQ,mBAAmB,IAAA,EAAuB;AAEhD,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,EAAG;AACnC,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,2DAAA,EAA6D;AAAA,QAC7E,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,QAAQ,IAAA,CAAK,EAAA;AAAA,QACb,UAAU,IAAA,CAAK;AAAA,OAChB,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,kBAAO,IAAI,GAAA,EAAI,EAAG,SAAA,kBAAW,IAAI,GAAA,IAAO,CAAA;AAAA,EAC5E;AAAA,EAEA,MAAc,kBAAkB,IAAA,EAAsC;AACpE,IAAA,IAAA,CAAK,OAAO,KAAA,CAAM,uCAAA,EAAyC,IAAA,CAAK,EAAA,EAAI,KAAK,IAAI,CAAA;AAC7E,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,IAAA,CAAK,mBAAmB,IAAI,CAAA;AAAA,IAC9B;AAEA,IAAA,MAAM,MAAA,GAAS,mBAAA;AACf,IAAA,MAAM,WAAW,IAAA,CAAK,WAAA,CAAY,EAAE,IAAA,EAAM,QAAQ,CAAA;AAClD,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,MAAA,QAAA,CAAS,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AAAA,IAChC;AAEA,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,QAAA,EAAU,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA;AAAA,MAC/B,GAAG,IAAA,CAAK,mBAAA,CAAoB,IAAI;AAAA,KAClC;AAEA,IAAA,MAAM,kBAAkB,IAAA,CAAK,kBAAA,CAAmB,EAAE,QAAA,EAAU,IAAA,EAAM,QAAQ,CAAA;AAC1E,IAAA,IAAI,gBAAA;AACJ,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA,gBAAA,GAAmB,IAAIC,kBAAQ,OAAO,CAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,gBAAA,GAAmB,eAAA,CAAgB,YAAY,OAAO,CAAA;AAAA,IACxD;AAEA,IAAA,QAAA,CAAS,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,gBAAgB,CAAA;AAE5C,IAAA,MAAM,iBAAiB,OAAA,EAAQ;AAAA,EACjC;AAAA,EAEA,MAAc,qBAAA,CAAsB,IAAA,EAAuB,KAAA,EAA+B;AACxF,IAAA,IAAA,CAAK,MAAA,CAAO,MAAM,2CAAA,EAA6C,IAAA,CAAK,IAAI,IAAA,CAAK,IAAA,EAAM,UAAU,KAAK,CAAA;AAClG,IAAA,MAAM,MAAA,GAAS,QAAQ,eAAA,GAAkB,kBAAA;AAEzC,IAAA,MAAM,WAAW,IAAA,CAAK,WAAA,CAAY,EAAE,IAAA,EAAM,QAAQ,CAAA;AAClD,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,gBAAA,GAAmB,QAAA,CAAS,KAAA,CAAM,GAAA,CAAI,KAAK,EAAE,CAAA;AACnD,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,iEAAA,EAAmE;AAAA,QAClF,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,QAAQ,IAAA,CAAK,EAAA;AAAA,QACb,UAAU,IAAA,CAAK,IAAA;AAAA,QACf,UAAU,IAAA,CAAK,IAAA;AAAA,QACf,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB;AAAA,OACD,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,mBAAA,CAAoB,IAAI,CAAA;AACnD,IAAA,gBAAA,CAAiB,QAAA,GAAW;AAAA,MAC1B,GAAG,gBAAA,CAAiB,QAAA;AAAA,MACpB,GAAG,aAAA,CAAc;AAAA,KACnB;AACA,IAAA,IAAI,aAAA,CAAc,UAAU,IAAA,EAAM;AAChC,MAAA,gBAAA,CAAiB,SAAS,aAAA,CAAc,MAAA;AAAA,IAC1C;AACA,IAAA,IAAI,aAAA,CAAc,WAAW,IAAA,EAAM;AACjC,MAAA,gBAAA,CAAiB,UAAU,aAAA,CAAc,OAAA;AAAA,IAC3C;AACA,IAAA,IAAI,aAAA,CAAc,SAAS,IAAA,EAAM;AAC/B,MAAA,gBAAA,CAAiB,QAAQ,aAAA,CAAc,KAAA;AAAA,IACzC;AAGA,IAAA,IAAI,IAAA,CAAK,IAAA,KAASH,wBAAA,CAAS,gBAAA,EAAkB;AAC3C,MAAA,MAAM,SAAA,GAAa,IAAA,CAAK,UAAA,IAAc,EAAC;AACvC,MAAA,IAAI,SAAA,CAAU,wBAAwB,MAAA,EAAW;AAC/C,QAAA,gBAAA,CAAiB,QAAA,CAAS;AAAA,UACxB,IAAA,EAAM,WAAA;AAAA,UACN,IAAA,EAAM,SAAA,CAAU,mBAAA,CAAoB,WAAA;AAAY,SACjD,CAAA;AAAA,MACH;AAAA,IACF;AAEA,IAAA,IAAI,KAAA,EAAO;AAET,MAAA,IAAI,KAAK,OAAA,EAAS;AAChB,QAAA,MAAM,gBAAA,CAAiB,IAAI,EAAE,OAAA,EAAS,KAAK,OAAA,CAAQ,OAAA,EAAQ,GAAI,GAAA,EAAM,CAAA;AAAA,MACvE,CAAA,MAAO;AACL,QAAA,MAAM,iBAAiB,GAAA,EAAI;AAAA,MAC7B;AACA,MAAA,MAAM,iBAAiB,QAAA,EAAS;AAGhC,MAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,QAAA,QAAA,CAAS,SAAA,CAAU,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA;AAAA,MACnC;AAGA,MAAA,IAAI,QAAA,CAAS,SAAA,CAAU,IAAA,KAAS,CAAA,EAAG;AACjC,QAAA,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,IAAA,EAAsC;AAClE,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,+CAAA,EAAiD;AAAA,QACjE,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,QAAQ,IAAA,CAAK,EAAA;AAAA,QACb,UAAU,IAAA,CAAK,IAAA;AAAA,QACf,MAAA,EAAQ;AAAA,OACT,CAAA;AACD,MAAA,IAAA,CAAK,mBAAmB,IAAI,CAAA;AAAA,IAC9B;AAEA,IAAA,MAAM,MAAA,GAAS,iBAAA;AACf,IAAA,MAAM,WAAW,IAAA,CAAK,WAAA,CAAY,EAAE,IAAA,EAAM,QAAQ,CAAA;AAClD,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,kBAAkB,IAAA,CAAK,kBAAA,CAAmB,EAAE,QAAA,EAAU,IAAA,EAAM,QAAQ,CAAA;AAC1E,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,GAAG,IAAA,CAAK,mBAAA,CAAoB,IAAI,CAAA;AAAA,MAChC,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,IAAA,EAAM,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA;AAAA,MAC3B,SAAA,EAAW,IAAA,CAAK,SAAA,CAAU,OAAA,EAAQ,GAAI;AAAA,KACxC;AAEA,IAAA,IAAI,gBAAA;AACJ,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA,gBAAA,GAAmB,IAAIG,kBAAQ,OAAO,CAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,gBAAA,GAAmB,eAAA,CAAgB,YAAY,OAAO,CAAA;AAAA,IACxD;AAEA,IAAA,MAAM,iBAAiB,OAAA,EAAQ;AAE/B,IAAA,MAAM,gBAAA,CAAiB,IAAI,EAAE,OAAA,EAAS,KAAK,SAAA,CAAU,OAAA,EAAQ,GAAI,GAAA,EAAM,CAAA;AACvE,IAAA,MAAM,iBAAiB,QAAA,EAAS;AAAA,EAClC;AAAA,EAEQ,YAAY,OAAA,EAA0E;AAC5F,IAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,OAAA;AACzB,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,EAAG;AACnC,MAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA;AAAA,IACvC;AAEA,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,iDAAA,EAAmD;AAAA,MAClE,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,QAAQ,IAAA,CAAK,EAAA;AAAA,MACb,UAAU,IAAA,CAAK,IAAA;AAAA,MACf,UAAU,IAAA,CAAK,IAAA;AAAA,MACf,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEQ,mBAAmB,OAAA,EAIH;AACtB,IAAA,MAAM,EAAE,QAAA,EAAU,IAAA,EAAM,MAAA,EAAO,GAAI,OAAA;AAEnC,IAAA,MAAM,WAAW,IAAA,CAAK,YAAA;AACtB,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,QAAA,CAAS,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA,EAAG;AAChC,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAAA,IACpC;AAEA,IAAA,IAAI,YAAY,CAAC,QAAA,CAAS,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA,EAAG;AAG7C,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,mDAAA,EAAqD;AAAA,MACpE,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,QAAQ,IAAA,CAAK,EAAA;AAAA,MACb,UAAU,IAAA,CAAK,IAAA;AAAA,MACf,UAAU,IAAA,CAAK,IAAA;AAAA,MACf,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEQ,oBAAoB,IAAA,EAA+C;AACzE,IAAA,MAAM,OAAA,GAAwD;AAAA,MAC5D,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,QAAA,EAAU;AAAA,QACR,kBAAkB,IAAA,CAAK,IAAA;AAAA,QACvB,GAAG,IAAA,CAAK;AAAA;AACV,KACF;AAGA,IAAA,IAAI,IAAA,CAAK,OAAO,WAAA,EAAa;AAC3B,MAAA,OAAA,CAAQ,YAAA,GAAe,KAAK,MAAA,CAAO,WAAA;AAAA,IACrC;AAGA,IAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ;AACxC,MAAA,OAAA,CAAQ,OAAO,IAAA,CAAK,IAAA;AAAA,IACtB;AAGA,IAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,MAAA,OAAA,CAAQ,MAAA,GAAS,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,GAAI,KAAK,KAAA,GAAQ,EAAE,KAAA,EAAO,IAAA,CAAK,KAAA,EAAM;AAAA,IAC1E;AAEA,IAAA,IAAI,IAAA,CAAK,WAAW,MAAA,EAAW;AAC7B,MAAA,OAAA,CAAQ,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,GAAI,KAAK,MAAA,GAAS,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO;AAAA,IAC/E;AAEA,IAAA,MAAM,UAAA,GAAc,IAAA,CAAK,UAAA,IAAc,EAAC;AAExC,IAAA,IAAI,IAAA,CAAK,IAAA,KAASH,wBAAA,CAAS,gBAAA,EAAkB;AAC3C,MAAA,MAAM,SAAA,GAAY,UAAA;AAGlB,MAAA,IAAI,SAAA,CAAU,UAAU,MAAA,EAAW;AAGjC,QAAA,OAAA,CAAQ,QAAA,CAAS,gBAAgB,SAAA,CAAU,KAAA;AAAA,MAC7C;AAGA,MAAA,IAAI,SAAA,CAAU,aAAa,MAAA,EAAW;AAGpC,QAAA,OAAA,CAAQ,QAAA,CAAS,cAAc,SAAA,CAAU,QAAA;AAAA,MAC3C;AAGA,MAAA,OAAA,CAAQ,QAAA,CAAS,cAAA,GAAiB,kBAAA,CAAmB,SAAA,CAAU,KAAK,CAAA;AAGpE,MAAA,IAAI,SAAA,CAAU,eAAe,MAAA,EAAW;AACtC,QAAA,OAAA,CAAQ,QAAA,CAAS,kBAAkB,SAAA,CAAU,UAAA;AAAA,MAC/C;AAGA,MAAA,MAAM,eAAA,GAAkBI,eAAS,UAAA,EAAY,CAAC,SAAS,OAAA,EAAS,YAAA,EAAc,qBAAqB,CAAC,CAAA;AACpG,MAAA,OAAA,CAAQ,QAAA,GAAW;AAAA,QACjB,GAAG,OAAA,CAAQ,QAAA;AAAA,QACX,GAAG;AAAA,OACL;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,OAAA,CAAQ,QAAA,GAAW;AAAA,QACjB,GAAG,OAAA,CAAQ,QAAA;AAAA,QACX,GAAG;AAAA,OACL;AAAA,IACF;AAGA,IAAA,IAAI,KAAK,SAAA,EAAW;AAClB,MAAA,OAAA,CAAQ,KAAA,GAAQ,KAAK,SAAA,CAAU,OAAA;AAC/B,MAAA,OAAA,CAAQ,QAAA,CAAS,eAAe,IAAA,CAAK,SAAA;AAAA,IACvC;AAEA,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEA,MAAM,QAAA,GAA0B;AAC9B,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA;AAAA,IACF;AAGA,IAAA,KAAA,MAAW,CAAC,QAAA,EAAU,QAAQ,CAAA,IAAK,KAAK,QAAA,EAAU;AAChD,MAAA,KAAA,MAAW,CAAC,OAAA,EAAS,OAAO,CAAA,IAAK,SAAS,KAAA,EAAO;AAC/C,QAAA,MAAM,QAAQ,GAAA,EAAI;AAClB,QAAA,MAAM,QAAQ,QAAA,EAAS;AAAA,MACzB;AAAA,IACF;AACA,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,IAAA,MAAM,MAAM,QAAA,EAAS;AAAA,EACvB;AACF","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 { 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":["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 { 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/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.10",
3
+ "version": "1.0.0-beta.12",
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,7 +25,7 @@
25
25
  "license": "Apache-2.0",
26
26
  "dependencies": {
27
27
  "langsmith": ">=0.3.79",
28
- "@mastra/observability": "1.0.0-beta.9"
28
+ "@mastra/observability": "1.0.0-beta.11"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@ai-sdk/openai": "^2.0.35",
@@ -35,12 +35,13 @@
35
35
  "dotenv": "^17.2.2",
36
36
  "eslint": "^9.37.0",
37
37
  "tsup": "^8.5.0",
38
- "typescript": "^5.8.3",
39
- "vitest": "4.0.12",
38
+ "typescript": "^5.9.3",
39
+ "vitest": "4.0.16",
40
40
  "zod": "^3.25.76",
41
41
  "@internal/lint": "0.0.53",
42
42
  "@internal/types-builder": "0.0.28",
43
- "@mastra/core": "1.0.0-beta.18"
43
+ "@mastra/core": "1.0.0-beta.22",
44
+ "@observability/test-utils": "0.0.1"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "@mastra/core": ">=1.0.0-0 <2.0.0-0"