@mastra/langsmith 1.0.2 → 1.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/dist/helpers.d.ts +83 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/index.cjs +65 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -7
- package/dist/index.js.map +1 -1
- package/dist/tracing.d.ts +10 -1
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @mastra/langsmith
|
|
2
2
|
|
|
3
|
+
## 1.1.0-alpha.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added `withLangsmithMetadata` helper for dynamic LangSmith configuration per-span. ([#12690](https://github.com/mastra-ai/mastra/pull/12690))
|
|
8
|
+
|
|
9
|
+
**Why:** Previously, `projectName` could only be set globally in the exporter config. Users needed to dynamically route traces to different LangSmith projects based on runtime conditions (e.g., customer tier, environment).
|
|
10
|
+
|
|
11
|
+
**Before:**
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
const tracingOptions = buildTracingOptions();
|
|
15
|
+
// No way to override projectName per-span
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**After:**
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { buildTracingOptions } from '@mastra/observability';
|
|
22
|
+
import { withLangsmithMetadata } from '@mastra/langsmith';
|
|
23
|
+
|
|
24
|
+
const tracingOptions = buildTracingOptions(
|
|
25
|
+
withLangsmithMetadata({
|
|
26
|
+
projectName: 'enterprise-traces',
|
|
27
|
+
sessionId: 'user-123',
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Follows the same pattern as `withLangfusePrompt` in the Langfuse exporter.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [[`717ffab`](https://github.com/mastra-ai/mastra/commit/717ffab42cfd58ff723b5c19ada4939997773004), [`e4b6dab`](https://github.com/mastra-ai/mastra/commit/e4b6dab171c5960e340b3ea3ea6da8d64d2b8672), [`5719fa8`](https://github.com/mastra-ai/mastra/commit/5719fa8880e86e8affe698ec4b3807c7e0e0a06f), [`83cda45`](https://github.com/mastra-ai/mastra/commit/83cda4523e588558466892bff8f80f631a36945a), [`11804ad`](https://github.com/mastra-ai/mastra/commit/11804adf1d6be46ebe216be40a43b39bb8b397d7), [`aa95f95`](https://github.com/mastra-ai/mastra/commit/aa95f958b186ae5c9f4219c88e268f5565c277a2), [`f5501ae`](https://github.com/mastra-ai/mastra/commit/f5501aedb0a11106c7db7e480d6eaf3971b7bda8), [`44573af`](https://github.com/mastra-ai/mastra/commit/44573afad0a4bc86f627d6cbc0207961cdcb3bc3), [`00e3861`](https://github.com/mastra-ai/mastra/commit/00e3861863fbfee78faeb1ebbdc7c0223aae13ff), [`7bfbc52`](https://github.com/mastra-ai/mastra/commit/7bfbc52a8604feb0fff2c0a082c13c0c2a3df1a2), [`1445994`](https://github.com/mastra-ai/mastra/commit/1445994aee19c9334a6a101cf7bd80ca7ed4d186), [`61f44a2`](https://github.com/mastra-ai/mastra/commit/61f44a26861c89e364f367ff40825bdb7f19df55), [`37145d2`](https://github.com/mastra-ai/mastra/commit/37145d25f99dc31f1a9105576e5452609843ce32), [`fdad759`](https://github.com/mastra-ai/mastra/commit/fdad75939ff008b27625f5ec0ce9c6915d99d9ec), [`e4569c5`](https://github.com/mastra-ai/mastra/commit/e4569c589e00c4061a686c9eb85afe1b7050b0a8), [`7309a85`](https://github.com/mastra-ai/mastra/commit/7309a85427281a8be23f4fb80ca52e18eaffd596), [`99424f6`](https://github.com/mastra-ai/mastra/commit/99424f6862ffb679c4ec6765501486034754a4c2), [`44eb452`](https://github.com/mastra-ai/mastra/commit/44eb4529b10603c279688318bebf3048543a1d61), [`6c40593`](https://github.com/mastra-ai/mastra/commit/6c40593d6d2b1b68b0c45d1a3a4c6ac5ecac3937), [`8c1135d`](https://github.com/mastra-ai/mastra/commit/8c1135dfb91b057283eae7ee11f9ec28753cc64f), [`dd39e54`](https://github.com/mastra-ai/mastra/commit/dd39e54ea34532c995b33bee6e0e808bf41a7341), [`b6fad9a`](https://github.com/mastra-ai/mastra/commit/b6fad9a602182b1cc0df47cd8c55004fa829ad61), [`4129c07`](https://github.com/mastra-ai/mastra/commit/4129c073349b5a66643fd8136ebfe9d7097cf793), [`5b930ab`](https://github.com/mastra-ai/mastra/commit/5b930aba1834d9898e8460a49d15106f31ac7c8d), [`4be93d0`](https://github.com/mastra-ai/mastra/commit/4be93d09d68e20aaf0ea3f210749422719618b5f), [`047635c`](https://github.com/mastra-ai/mastra/commit/047635ccd7861d726c62d135560c0022a5490aec), [`8c90ff4`](https://github.com/mastra-ai/mastra/commit/8c90ff4d3414e7f2a2d216ea91274644f7b29133), [`ed232d1`](https://github.com/mastra-ai/mastra/commit/ed232d1583f403925dc5ae45f7bee948cf2a182b), [`3891795`](https://github.com/mastra-ai/mastra/commit/38917953518eb4154a984ee36e6ededdcfe80f72), [`4f955b2`](https://github.com/mastra-ai/mastra/commit/4f955b20c7f66ed282ee1fd8709696fa64c4f19d), [`55a4c90`](https://github.com/mastra-ai/mastra/commit/55a4c9044ac7454349b9f6aeba0bbab5ee65d10f)]:
|
|
37
|
+
- @mastra/core@1.3.0-alpha.1
|
|
38
|
+
|
|
3
39
|
## 1.0.2
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangSmith Tracing Options Helpers
|
|
3
|
+
*
|
|
4
|
+
* These helpers integrate with the `buildTracingOptions` pattern from
|
|
5
|
+
* `@mastra/observability` to add LangSmith-specific tracing features.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { buildTracingOptions } from '@mastra/observability';
|
|
10
|
+
* import { withLangsmithMetadata } from '@mastra/langsmith';
|
|
11
|
+
*
|
|
12
|
+
* const agent = new Agent({
|
|
13
|
+
* defaultGenerateOptions: {
|
|
14
|
+
* tracingOptions: buildTracingOptions(
|
|
15
|
+
* withLangsmithMetadata({ projectName: 'my-project' })
|
|
16
|
+
* ),
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import type { TracingOptionsUpdater } from '@mastra/observability';
|
|
22
|
+
/**
|
|
23
|
+
* LangSmith vendor metadata that can be passed via span metadata.
|
|
24
|
+
* These fields are extracted by the LangSmith exporter and used
|
|
25
|
+
* to override default configuration on a per-span basis.
|
|
26
|
+
*/
|
|
27
|
+
export interface LangSmithMetadataInput {
|
|
28
|
+
/**
|
|
29
|
+
* Override the project name for this span and its children.
|
|
30
|
+
* This allows dynamically routing traces to different LangSmith projects.
|
|
31
|
+
*/
|
|
32
|
+
projectName?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Session ID for grouping related traces in LangSmith.
|
|
35
|
+
*/
|
|
36
|
+
sessionId?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Session name for display in LangSmith.
|
|
39
|
+
*/
|
|
40
|
+
sessionName?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Adds LangSmith metadata to the tracing options.
|
|
44
|
+
*
|
|
45
|
+
* The metadata is added under `metadata.langsmith` and allows you to:
|
|
46
|
+
* - Route traces to different LangSmith projects via `projectName`
|
|
47
|
+
* - Group traces by session via `sessionId` and `sessionName`
|
|
48
|
+
*
|
|
49
|
+
* @param metadata - The LangSmith metadata to add
|
|
50
|
+
* @returns A TracingOptionsUpdater function for use with `buildTracingOptions`
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { buildTracingOptions } from '@mastra/observability';
|
|
55
|
+
* import { withLangsmithMetadata } from '@mastra/langsmith';
|
|
56
|
+
*
|
|
57
|
+
* // Route traces to a specific project
|
|
58
|
+
* const tracingOptions = buildTracingOptions(
|
|
59
|
+
* withLangsmithMetadata({ projectName: 'customer-support' }),
|
|
60
|
+
* );
|
|
61
|
+
*
|
|
62
|
+
* // Or set multiple fields
|
|
63
|
+
* const tracingOptions = buildTracingOptions(
|
|
64
|
+
* withLangsmithMetadata({
|
|
65
|
+
* projectName: 'my-project',
|
|
66
|
+
* sessionId: 'session-123',
|
|
67
|
+
* }),
|
|
68
|
+
* );
|
|
69
|
+
*
|
|
70
|
+
* // Use in agent config
|
|
71
|
+
* const agent = new Agent({
|
|
72
|
+
* name: 'support-agent',
|
|
73
|
+
* model: openai('gpt-4o'),
|
|
74
|
+
* defaultGenerateOptions: {
|
|
75
|
+
* tracingOptions: buildTracingOptions(
|
|
76
|
+
* withLangsmithMetadata({ projectName: 'support-traces' })
|
|
77
|
+
* ),
|
|
78
|
+
* },
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater;
|
|
83
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,qBAAqB,CAW7F"}
|
package/dist/index.cjs
CHANGED
|
@@ -94,7 +94,7 @@ var LangSmithExporter = class extends observability.TrackingExporter {
|
|
|
94
94
|
}
|
|
95
95
|
const payload = {
|
|
96
96
|
name: span.name,
|
|
97
|
-
...this.buildRunTreePayload(span, true)
|
|
97
|
+
...this.buildRunTreePayload(span, traceData, true)
|
|
98
98
|
};
|
|
99
99
|
const langSmithSpan = span.isRootSpan ? new langsmith.RunTree(payload) : parent.createChild(payload);
|
|
100
100
|
await langSmithSpan.postRun();
|
|
@@ -131,7 +131,7 @@ var LangSmithExporter = class extends observability.TrackingExporter {
|
|
|
131
131
|
if (!langSmithSpan) {
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
|
-
const updatePayload = this.buildRunTreePayload(span);
|
|
134
|
+
const updatePayload = this.buildRunTreePayload(span, traceData);
|
|
135
135
|
langSmithSpan.metadata = {
|
|
136
136
|
...langSmithSpan.metadata,
|
|
137
137
|
...updatePayload.metadata
|
|
@@ -163,20 +163,64 @@ var LangSmithExporter = class extends observability.TrackingExporter {
|
|
|
163
163
|
}
|
|
164
164
|
await langSmithSpan.patchRun();
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Find LangSmith vendor metadata by walking up the span hierarchy and merging.
|
|
168
|
+
* Metadata is merged from ancestors with child values taking precedence over parent values.
|
|
169
|
+
*
|
|
170
|
+
* TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class
|
|
171
|
+
* and reuse here and in LangfuseExporter.findLangfusePrompt()
|
|
172
|
+
*/
|
|
173
|
+
findLangsmithMetadata(traceData, span) {
|
|
174
|
+
const metadataChain = [];
|
|
175
|
+
let currentSpanId = span.id;
|
|
176
|
+
while (currentSpanId) {
|
|
177
|
+
const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });
|
|
178
|
+
if (providerMetadata) {
|
|
179
|
+
metadataChain.push(providerMetadata);
|
|
180
|
+
}
|
|
181
|
+
currentSpanId = traceData.getParentId({ spanId: currentSpanId });
|
|
182
|
+
}
|
|
183
|
+
if (metadataChain.length === 0) {
|
|
184
|
+
return void 0;
|
|
185
|
+
}
|
|
186
|
+
const merged = {};
|
|
187
|
+
for (let i = metadataChain.length - 1; i >= 0; i--) {
|
|
188
|
+
const meta = metadataChain[i];
|
|
189
|
+
if (meta.projectName !== void 0) merged.projectName = meta.projectName;
|
|
190
|
+
if (meta.sessionId !== void 0) merged.sessionId = meta.sessionId;
|
|
191
|
+
if (meta.sessionName !== void 0) merged.sessionName = meta.sessionName;
|
|
192
|
+
}
|
|
193
|
+
this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {
|
|
194
|
+
traceId: span.traceId,
|
|
195
|
+
spanId: span.id,
|
|
196
|
+
metadataKeys: Object.keys(merged),
|
|
197
|
+
ancestorCount: metadataChain.length
|
|
198
|
+
});
|
|
199
|
+
return merged;
|
|
200
|
+
}
|
|
201
|
+
buildRunTreePayload(span, traceData, isNew = false) {
|
|
202
|
+
const vendorMetadata = this.findLangsmithMetadata(traceData, span);
|
|
203
|
+
const spanMetadata = span.metadata ? utils.omitKeys(span.metadata, ["langsmith"]) : {};
|
|
167
204
|
const payload = {
|
|
168
205
|
client: this.#client,
|
|
169
206
|
metadata: {
|
|
170
207
|
mastra_span_type: span.type,
|
|
171
|
-
...
|
|
208
|
+
...spanMetadata
|
|
172
209
|
}
|
|
173
210
|
};
|
|
174
211
|
if (isNew) {
|
|
175
212
|
payload.run_type = mapSpanType(span.type);
|
|
176
213
|
payload.start_time = span.startTime.getTime();
|
|
177
214
|
}
|
|
178
|
-
|
|
179
|
-
|
|
215
|
+
const projectName = vendorMetadata?.projectName ?? this.config.projectName;
|
|
216
|
+
if (projectName) {
|
|
217
|
+
payload.project_name = projectName;
|
|
218
|
+
}
|
|
219
|
+
if (vendorMetadata?.sessionId) {
|
|
220
|
+
payload.metadata.session_id = vendorMetadata.sessionId;
|
|
221
|
+
}
|
|
222
|
+
if (vendorMetadata?.sessionName) {
|
|
223
|
+
payload.metadata.session_name = vendorMetadata.sessionName;
|
|
180
224
|
}
|
|
181
225
|
if (span.isRootSpan && span.tags?.length) {
|
|
182
226
|
payload.tags = span.tags;
|
|
@@ -219,6 +263,21 @@ var LangSmithExporter = class extends observability.TrackingExporter {
|
|
|
219
263
|
}
|
|
220
264
|
};
|
|
221
265
|
|
|
266
|
+
// src/helpers.ts
|
|
267
|
+
function withLangsmithMetadata(metadata) {
|
|
268
|
+
return (opts) => ({
|
|
269
|
+
...opts,
|
|
270
|
+
metadata: {
|
|
271
|
+
...opts.metadata,
|
|
272
|
+
langsmith: {
|
|
273
|
+
...opts.metadata?.langsmith,
|
|
274
|
+
...metadata
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
222
280
|
exports.LangSmithExporter = LangSmithExporter;
|
|
281
|
+
exports.withLangsmithMetadata = withLangsmithMetadata;
|
|
223
282
|
//# sourceMappingURL=index.cjs.map
|
|
224
283
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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"]}
|
|
1
|
+
{"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":["SpanType","TrackingExporter","Client","RunTree","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\n\n/**\n * LangSmithUsageMetrics\n *\n * Canonical metric keys expected by LangSmith for LLM usage accounting.\n * See: https://docs.langchain.com/langsmith/log-llm-trace#provide-token-and-cost-information\n */\nexport interface LangSmithUsageMetrics {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n input_token_details?: {\n [key: string]: number;\n };\n output_token_details?: {\n [key: string]: number;\n };\n}\n\n/**\n * Formats UsageStats to LangSmith's expected metric format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangSmithUsageMetrics {\n const metrics: LangSmithUsageMetrics = {};\n\n if (usage?.inputTokens !== undefined) {\n metrics.input_tokens = usage.inputTokens;\n }\n\n if (usage?.outputTokens !== undefined) {\n metrics.output_tokens = usage.outputTokens;\n }\n\n // Compute total if we have both\n if (metrics.input_tokens !== undefined && metrics.output_tokens !== undefined) {\n metrics.total_tokens = metrics.input_tokens + metrics.output_tokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n reasoning_tokens: usage.outputDetails.reasoning,\n };\n }\n\n if (usage?.inputDetails?.cacheRead !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_read: usage.inputDetails.cacheRead,\n };\n }\n\n if (usage?.inputDetails?.cacheWrite !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_write: usage.inputDetails.cacheWrite,\n };\n }\n\n if (usage?.inputDetails?.audio !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n audio: usage.inputDetails.audio,\n };\n }\n\n if (usage?.outputDetails?.audio !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n audio: usage.outputDetails.audio,\n };\n }\n\n return metrics;\n}\n","/**\n * LangSmith Exporter for Mastra Tracing\n *\n * This exporter sends observability data to LangSmith\n * Root spans become top-level LangSmith RunTrees (no trace wrapper).\n * Events are handled as zero-duration RunTrees with matching start/end times.\n */\n\nimport type { AnyExportedSpan, ModelGenerationAttributes, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport type { LangSmithMetadataInput } from './helpers';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {\n /** LangSmith client instance */\n client?: Client;\n /**\n * The name of the LangSmith project to send traces to.\n * Overrides the LANGCHAIN_PROJECT environment variable.\n * If neither is set, traces are sent to the \"default\" project.\n */\n projectName?: string;\n}\n\ntype LangSmithRoot = undefined;\ntype LangSmithSpan = RunTree;\ntype LangSmithEvent = RunTree;\ntype LangSmithMetadata = LangSmithMetadataInput;\ntype LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;\n\n// Default span type for all spans\nconst DEFAULT_SPAN_TYPE = 'chain';\n\n// Exceptions to the default mapping\nconst SPAN_TYPE_EXCEPTIONS: Partial<Record<SpanType, 'llm' | 'tool' | 'chain'>> = {\n [SpanType.MODEL_GENERATION]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_CONDITIONAL_EVAL]: 'chain',\n [SpanType.WORKFLOW_WAIT_EVENT]: 'chain',\n};\n\n// Mapping function - returns valid LangSmith span types\nfunction mapSpanType(spanType: SpanType): 'llm' | 'tool' | 'chain' {\n return SPAN_TYPE_EXCEPTIONS[spanType] ?? DEFAULT_SPAN_TYPE;\n}\n\nfunction isKVMap(value: unknown): value is KVMap {\n return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport class LangSmithExporter extends TrackingExporter<\n LangSmithRoot,\n LangSmithSpan,\n LangSmithEvent,\n LangSmithMetadata,\n LangSmithExporterConfig\n> {\n override name = 'langsmith';\n #client: Client | undefined;\n\n constructor(config: LangSmithExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n super({\n ...config,\n apiKey,\n });\n\n if (!apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);\n return;\n }\n\n this.#client = config.client ?? new Client(this.config);\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithSpan | undefined> {\n const { span, traceData } = args;\n\n const parent = span.isRootSpan ? undefined : traceData.getParent(args);\n\n if (!span.isRootSpan && !parent) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n const payload = {\n name: span.name,\n ...this.buildRunTreePayload(span, traceData, true),\n };\n\n const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent!.createChild(payload);\n\n await langSmithSpan.postRun();\n return langSmithSpan;\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithEvent | undefined> {\n const langSmithSpan = await this._buildSpan(args);\n\n if (!langSmithSpan) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n // use start-time as end-time to make an event span.\n await langSmithSpan.end({ endTime: args.span.startTime.getTime() });\n await langSmithSpan.patchRun();\n return langSmithSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });\n }\n\n protected override async _abortSpan(args: {\n span: LangSmithSpan;\n traceData: LangSmithTraceData;\n reason: SpanErrorInfo;\n }): Promise<void> {\n const { span, reason } = args;\n span.error = reason.message;\n span.metadata = {\n ...span.metadata,\n errorDetails: reason,\n };\n await span.end();\n await span.patchRun();\n }\n\n private async handleSpanUpdateOrEnd(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n isEnd: boolean;\n }): Promise<void> {\n const { span, traceData, isEnd } = args;\n\n const langSmithSpan = traceData.getSpan({ spanId: span.id });\n if (!langSmithSpan) {\n //update occurred before span start, return early data\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span, traceData);\n\n langSmithSpan.metadata = {\n ...langSmithSpan.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langSmithSpan.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langSmithSpan.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langSmithSpan.error = updatePayload.error;\n }\n\n // Add new_token event for TTFT tracking on MODEL_GENERATION spans\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = (span.attributes ?? {}) as ModelGenerationAttributes;\n if (modelAttr.completionStartTime !== undefined) {\n langSmithSpan.addEvent({\n name: 'new_token',\n time: modelAttr.completionStartTime.toISOString(),\n });\n }\n }\n\n if (isEnd) {\n // End the span with the correct endTime\n if (span.endTime) {\n await langSmithSpan.end({ endTime: span.endTime.getTime() });\n } else {\n await langSmithSpan.end();\n }\n }\n await langSmithSpan.patchRun();\n }\n\n /**\n * Find LangSmith vendor metadata by walking up the span hierarchy and merging.\n * Metadata is merged from ancestors with child values taking precedence over parent values.\n *\n * TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class\n * and reuse here and in LangfuseExporter.findLangfusePrompt()\n */\n private findLangsmithMetadata(\n traceData: LangSmithTraceData,\n span: AnyExportedSpan,\n ): LangSmithMetadataInput | undefined {\n // Collect metadata from all ancestors (current span first, then parents)\n const metadataChain: LangSmithMetadataInput[] = [];\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n if (providerMetadata) {\n metadataChain.push(providerMetadata);\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n if (metadataChain.length === 0) {\n return undefined;\n }\n\n // Merge from ancestors to current span (parent values first, child values override)\n const merged: LangSmithMetadataInput = {};\n for (let i = metadataChain.length - 1; i >= 0; i--) {\n const meta = metadataChain[i]!;\n if (meta.projectName !== undefined) merged.projectName = meta.projectName;\n if (meta.sessionId !== undefined) merged.sessionId = meta.sessionId;\n if (meta.sessionName !== undefined) merged.sessionName = meta.sessionName;\n }\n\n this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {\n traceId: span.traceId,\n spanId: span.id,\n metadataKeys: Object.keys(merged),\n ancestorCount: metadataChain.length,\n });\n\n return merged;\n }\n\n private buildRunTreePayload(\n span: AnyExportedSpan,\n traceData: LangSmithTraceData,\n isNew = false,\n ): Partial<RunTreeConfig> {\n // Extract vendor metadata from span hierarchy\n const vendorMetadata = this.findLangsmithMetadata(traceData, span);\n\n // Build metadata, omitting the langsmith vendor key\n const spanMetadata = span.metadata ? omitKeys(span.metadata, ['langsmith']) : {};\n\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...spanMetadata,\n },\n };\n\n if (isNew) {\n payload.run_type = mapSpanType(span.type);\n payload.start_time = span.startTime.getTime();\n }\n\n // Add project name - vendor metadata takes precedence over config\n const projectName = vendorMetadata?.projectName ?? this.config.projectName;\n if (projectName) {\n payload.project_name = projectName;\n }\n\n // Add session info to metadata if provided via vendor metadata\n if (vendorMetadata?.sessionId) {\n payload.metadata.session_id = vendorMetadata.sessionId;\n }\n if (vendorMetadata?.sessionName) {\n payload.metadata.session_name = vendorMetadata.sessionName;\n }\n\n // Add tags for root spans\n if (span.isRootSpan && span.tags?.length) {\n payload.tags = span.tags;\n }\n\n // Core span data\n if (span.input !== undefined) {\n payload.inputs = isKVMap(span.input) ? span.input : { input: span.input };\n }\n\n if (span.output !== undefined) {\n payload.outputs = isKVMap(span.output) ? span.output : { output: span.output };\n }\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n // See: https://docs.langchain.com/langsmith/log-llm-trace\n if (modelAttr.model !== undefined) {\n // Note - this should map to a model name recognized by LangSmith\n // eg “gpt-4o-mini”, “claude-3-opus-20240307”, etc.\n payload.metadata.ls_model_name = modelAttr.model;\n }\n\n // Provider goes to metadata (if provided by attributes)\n if (modelAttr.provider !== undefined) {\n // Note - this should map to a provider name recognized by\n // LangSmith eg “openai”, “anthropic”, etc.\n payload.metadata.ls_provider = modelAttr.provider;\n }\n\n // Usage/token info goes to metrics\n payload.metadata.usage_metadata = formatUsageMetrics(modelAttr.usage);\n\n // Model parameters go to metadata\n if (modelAttr.parameters !== undefined) {\n payload.metadata.modelParameters = modelAttr.parameters;\n }\n\n // Other LLM attributes go to metadata\n const otherAttributes = omitKeys(attributes, ['model', 'provider', 'usage', 'parameters', 'completionStartTime']);\n payload.metadata = {\n ...payload.metadata,\n ...otherAttributes,\n };\n } else {\n // For non-LLM spans, put all attributes in metadata\n payload.metadata = {\n ...payload.metadata,\n ...attributes,\n };\n }\n\n // Handle errors\n if (span.errorInfo) {\n payload.error = span.errorInfo.message;\n payload.metadata.errorDetails = span.errorInfo;\n }\n\n return payload;\n }\n}\n","/**\n * LangSmith Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add LangSmith-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'my-project' })\n * ),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * LangSmith vendor metadata that can be passed via span metadata.\n * These fields are extracted by the LangSmith exporter and used\n * to override default configuration on a per-span basis.\n */\nexport interface LangSmithMetadataInput {\n /**\n * Override the project name for this span and its children.\n * This allows dynamically routing traces to different LangSmith projects.\n */\n projectName?: string;\n /**\n * Session ID for grouping related traces in LangSmith.\n */\n sessionId?: string;\n /**\n * Session name for display in LangSmith.\n */\n sessionName?: string;\n}\n\n/**\n * Adds LangSmith metadata to the tracing options.\n *\n * The metadata is added under `metadata.langsmith` and allows you to:\n * - Route traces to different LangSmith projects via `projectName`\n * - Group traces by session via `sessionId` and `sessionName`\n *\n * @param metadata - The LangSmith metadata to add\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * // Route traces to a specific project\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'customer-support' }),\n * );\n *\n * // Or set multiple fields\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({\n * projectName: 'my-project',\n * sessionId: 'session-123',\n * }),\n * );\n *\n * // Use in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'support-traces' })\n * ),\n * },\n * });\n * ```\n */\nexport function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langsmith: {\n ...(opts.metadata?.langsmith as Record<string, unknown>),\n ...metadata,\n },\n },\n });\n}\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,WAAW,CAAC;AAG1B,cAAc,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -92,7 +92,7 @@ var LangSmithExporter = class extends TrackingExporter {
|
|
|
92
92
|
}
|
|
93
93
|
const payload = {
|
|
94
94
|
name: span.name,
|
|
95
|
-
...this.buildRunTreePayload(span, true)
|
|
95
|
+
...this.buildRunTreePayload(span, traceData, true)
|
|
96
96
|
};
|
|
97
97
|
const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent.createChild(payload);
|
|
98
98
|
await langSmithSpan.postRun();
|
|
@@ -129,7 +129,7 @@ var LangSmithExporter = class extends TrackingExporter {
|
|
|
129
129
|
if (!langSmithSpan) {
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
|
-
const updatePayload = this.buildRunTreePayload(span);
|
|
132
|
+
const updatePayload = this.buildRunTreePayload(span, traceData);
|
|
133
133
|
langSmithSpan.metadata = {
|
|
134
134
|
...langSmithSpan.metadata,
|
|
135
135
|
...updatePayload.metadata
|
|
@@ -161,20 +161,64 @@ var LangSmithExporter = class extends TrackingExporter {
|
|
|
161
161
|
}
|
|
162
162
|
await langSmithSpan.patchRun();
|
|
163
163
|
}
|
|
164
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Find LangSmith vendor metadata by walking up the span hierarchy and merging.
|
|
166
|
+
* Metadata is merged from ancestors with child values taking precedence over parent values.
|
|
167
|
+
*
|
|
168
|
+
* TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class
|
|
169
|
+
* and reuse here and in LangfuseExporter.findLangfusePrompt()
|
|
170
|
+
*/
|
|
171
|
+
findLangsmithMetadata(traceData, span) {
|
|
172
|
+
const metadataChain = [];
|
|
173
|
+
let currentSpanId = span.id;
|
|
174
|
+
while (currentSpanId) {
|
|
175
|
+
const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });
|
|
176
|
+
if (providerMetadata) {
|
|
177
|
+
metadataChain.push(providerMetadata);
|
|
178
|
+
}
|
|
179
|
+
currentSpanId = traceData.getParentId({ spanId: currentSpanId });
|
|
180
|
+
}
|
|
181
|
+
if (metadataChain.length === 0) {
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
const merged = {};
|
|
185
|
+
for (let i = metadataChain.length - 1; i >= 0; i--) {
|
|
186
|
+
const meta = metadataChain[i];
|
|
187
|
+
if (meta.projectName !== void 0) merged.projectName = meta.projectName;
|
|
188
|
+
if (meta.sessionId !== void 0) merged.sessionId = meta.sessionId;
|
|
189
|
+
if (meta.sessionName !== void 0) merged.sessionName = meta.sessionName;
|
|
190
|
+
}
|
|
191
|
+
this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {
|
|
192
|
+
traceId: span.traceId,
|
|
193
|
+
spanId: span.id,
|
|
194
|
+
metadataKeys: Object.keys(merged),
|
|
195
|
+
ancestorCount: metadataChain.length
|
|
196
|
+
});
|
|
197
|
+
return merged;
|
|
198
|
+
}
|
|
199
|
+
buildRunTreePayload(span, traceData, isNew = false) {
|
|
200
|
+
const vendorMetadata = this.findLangsmithMetadata(traceData, span);
|
|
201
|
+
const spanMetadata = span.metadata ? omitKeys(span.metadata, ["langsmith"]) : {};
|
|
165
202
|
const payload = {
|
|
166
203
|
client: this.#client,
|
|
167
204
|
metadata: {
|
|
168
205
|
mastra_span_type: span.type,
|
|
169
|
-
...
|
|
206
|
+
...spanMetadata
|
|
170
207
|
}
|
|
171
208
|
};
|
|
172
209
|
if (isNew) {
|
|
173
210
|
payload.run_type = mapSpanType(span.type);
|
|
174
211
|
payload.start_time = span.startTime.getTime();
|
|
175
212
|
}
|
|
176
|
-
|
|
177
|
-
|
|
213
|
+
const projectName = vendorMetadata?.projectName ?? this.config.projectName;
|
|
214
|
+
if (projectName) {
|
|
215
|
+
payload.project_name = projectName;
|
|
216
|
+
}
|
|
217
|
+
if (vendorMetadata?.sessionId) {
|
|
218
|
+
payload.metadata.session_id = vendorMetadata.sessionId;
|
|
219
|
+
}
|
|
220
|
+
if (vendorMetadata?.sessionName) {
|
|
221
|
+
payload.metadata.session_name = vendorMetadata.sessionName;
|
|
178
222
|
}
|
|
179
223
|
if (span.isRootSpan && span.tags?.length) {
|
|
180
224
|
payload.tags = span.tags;
|
|
@@ -217,6 +261,20 @@ var LangSmithExporter = class extends TrackingExporter {
|
|
|
217
261
|
}
|
|
218
262
|
};
|
|
219
263
|
|
|
220
|
-
|
|
264
|
+
// src/helpers.ts
|
|
265
|
+
function withLangsmithMetadata(metadata) {
|
|
266
|
+
return (opts) => ({
|
|
267
|
+
...opts,
|
|
268
|
+
metadata: {
|
|
269
|
+
...opts.metadata,
|
|
270
|
+
langsmith: {
|
|
271
|
+
...opts.metadata?.langsmith,
|
|
272
|
+
...metadata
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export { LangSmithExporter, withLangsmithMetadata };
|
|
221
279
|
//# sourceMappingURL=index.js.map
|
|
222
280
|
//# sourceMappingURL=index.js.map
|
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 { 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\n\n/**\n * LangSmithUsageMetrics\n *\n * Canonical metric keys expected by LangSmith for LLM usage accounting.\n * See: https://docs.langchain.com/langsmith/log-llm-trace#provide-token-and-cost-information\n */\nexport interface LangSmithUsageMetrics {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n input_token_details?: {\n [key: string]: number;\n };\n output_token_details?: {\n [key: string]: number;\n };\n}\n\n/**\n * Formats UsageStats to LangSmith's expected metric format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangSmithUsageMetrics {\n const metrics: LangSmithUsageMetrics = {};\n\n if (usage?.inputTokens !== undefined) {\n metrics.input_tokens = usage.inputTokens;\n }\n\n if (usage?.outputTokens !== undefined) {\n metrics.output_tokens = usage.outputTokens;\n }\n\n // Compute total if we have both\n if (metrics.input_tokens !== undefined && metrics.output_tokens !== undefined) {\n metrics.total_tokens = metrics.input_tokens + metrics.output_tokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n reasoning_tokens: usage.outputDetails.reasoning,\n };\n }\n\n if (usage?.inputDetails?.cacheRead !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_read: usage.inputDetails.cacheRead,\n };\n }\n\n if (usage?.inputDetails?.cacheWrite !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n cache_write: usage.inputDetails.cacheWrite,\n };\n }\n\n if (usage?.inputDetails?.audio !== undefined) {\n metrics.input_token_details = {\n ...(metrics.input_token_details ?? {}),\n audio: usage.inputDetails.audio,\n };\n }\n\n if (usage?.outputDetails?.audio !== undefined) {\n metrics.output_token_details = {\n ...(metrics.output_token_details ?? {}),\n audio: usage.outputDetails.audio,\n };\n }\n\n return metrics;\n}\n","/**\n * LangSmith Exporter for Mastra Tracing\n *\n * This exporter sends observability data to LangSmith\n * Root spans become top-level LangSmith RunTrees (no trace wrapper).\n * Events are handled as zero-duration RunTrees with matching start/end times.\n */\n\nimport type { AnyExportedSpan, ModelGenerationAttributes, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport type { ClientConfig, RunTreeConfig } from 'langsmith';\nimport { Client, RunTree } from 'langsmith';\nimport type { KVMap } from 'langsmith/schemas';\nimport type { LangSmithMetadataInput } from './helpers';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {\n /** LangSmith client instance */\n client?: Client;\n /**\n * The name of the LangSmith project to send traces to.\n * Overrides the LANGCHAIN_PROJECT environment variable.\n * If neither is set, traces are sent to the \"default\" project.\n */\n projectName?: string;\n}\n\ntype LangSmithRoot = undefined;\ntype LangSmithSpan = RunTree;\ntype LangSmithEvent = RunTree;\ntype LangSmithMetadata = LangSmithMetadataInput;\ntype LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;\n\n// Default span type for all spans\nconst DEFAULT_SPAN_TYPE = 'chain';\n\n// Exceptions to the default mapping\nconst SPAN_TYPE_EXCEPTIONS: Partial<Record<SpanType, 'llm' | 'tool' | 'chain'>> = {\n [SpanType.MODEL_GENERATION]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_CONDITIONAL_EVAL]: 'chain',\n [SpanType.WORKFLOW_WAIT_EVENT]: 'chain',\n};\n\n// Mapping function - returns valid LangSmith span types\nfunction mapSpanType(spanType: SpanType): 'llm' | 'tool' | 'chain' {\n return SPAN_TYPE_EXCEPTIONS[spanType] ?? DEFAULT_SPAN_TYPE;\n}\n\nfunction isKVMap(value: unknown): value is KVMap {\n return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date);\n}\n\nexport class LangSmithExporter extends TrackingExporter<\n LangSmithRoot,\n LangSmithSpan,\n LangSmithEvent,\n LangSmithMetadata,\n LangSmithExporterConfig\n> {\n override name = 'langsmith';\n #client: Client | undefined;\n\n constructor(config: LangSmithExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.LANGSMITH_API_KEY;\n\n super({\n ...config,\n apiKey,\n });\n\n if (!apiKey) {\n this.setDisabled(`Missing required credentials (apiKey: ${!!apiKey})`);\n return;\n }\n\n this.#client = config.client ?? new Client(this.config);\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithSpan | undefined> {\n const { span, traceData } = args;\n\n const parent = span.isRootSpan ? undefined : traceData.getParent(args);\n\n if (!span.isRootSpan && !parent) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n const payload = {\n name: span.name,\n ...this.buildRunTreePayload(span, traceData, true),\n };\n\n const langSmithSpan = span.isRootSpan ? new RunTree(payload) : parent!.createChild(payload);\n\n await langSmithSpan.postRun();\n return langSmithSpan;\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n }): Promise<LangSmithEvent | undefined> {\n const langSmithSpan = await this._buildSpan(args);\n\n if (!langSmithSpan) {\n // parent doesn't exist and not creating rootSpan, return early data\n return;\n }\n\n // use start-time as end-time to make an event span.\n await langSmithSpan.end({ endTime: args.span.startTime.getTime() });\n await langSmithSpan.patchRun();\n return langSmithSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: false });\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangSmithTraceData }): Promise<void> {\n await this.handleSpanUpdateOrEnd({ ...args, isEnd: true });\n }\n\n protected override async _abortSpan(args: {\n span: LangSmithSpan;\n traceData: LangSmithTraceData;\n reason: SpanErrorInfo;\n }): Promise<void> {\n const { span, reason } = args;\n span.error = reason.message;\n span.metadata = {\n ...span.metadata,\n errorDetails: reason,\n };\n await span.end();\n await span.patchRun();\n }\n\n private async handleSpanUpdateOrEnd(args: {\n span: AnyExportedSpan;\n traceData: LangSmithTraceData;\n isEnd: boolean;\n }): Promise<void> {\n const { span, traceData, isEnd } = args;\n\n const langSmithSpan = traceData.getSpan({ spanId: span.id });\n if (!langSmithSpan) {\n //update occurred before span start, return early data\n return;\n }\n\n const updatePayload = this.buildRunTreePayload(span, traceData);\n\n langSmithSpan.metadata = {\n ...langSmithSpan.metadata,\n ...updatePayload.metadata,\n };\n if (updatePayload.inputs != null) {\n langSmithSpan.inputs = updatePayload.inputs;\n }\n if (updatePayload.outputs != null) {\n langSmithSpan.outputs = updatePayload.outputs;\n }\n if (updatePayload.error != null) {\n langSmithSpan.error = updatePayload.error;\n }\n\n // Add new_token event for TTFT tracking on MODEL_GENERATION spans\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = (span.attributes ?? {}) as ModelGenerationAttributes;\n if (modelAttr.completionStartTime !== undefined) {\n langSmithSpan.addEvent({\n name: 'new_token',\n time: modelAttr.completionStartTime.toISOString(),\n });\n }\n }\n\n if (isEnd) {\n // End the span with the correct endTime\n if (span.endTime) {\n await langSmithSpan.end({ endTime: span.endTime.getTime() });\n } else {\n await langSmithSpan.end();\n }\n }\n await langSmithSpan.patchRun();\n }\n\n /**\n * Find LangSmith vendor metadata by walking up the span hierarchy and merging.\n * Metadata is merged from ancestors with child values taking precedence over parent values.\n *\n * TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class\n * and reuse here and in LangfuseExporter.findLangfusePrompt()\n */\n private findLangsmithMetadata(\n traceData: LangSmithTraceData,\n span: AnyExportedSpan,\n ): LangSmithMetadataInput | undefined {\n // Collect metadata from all ancestors (current span first, then parents)\n const metadataChain: LangSmithMetadataInput[] = [];\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n if (providerMetadata) {\n metadataChain.push(providerMetadata);\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n if (metadataChain.length === 0) {\n return undefined;\n }\n\n // Merge from ancestors to current span (parent values first, child values override)\n const merged: LangSmithMetadataInput = {};\n for (let i = metadataChain.length - 1; i >= 0; i--) {\n const meta = metadataChain[i]!;\n if (meta.projectName !== undefined) merged.projectName = meta.projectName;\n if (meta.sessionId !== undefined) merged.sessionId = meta.sessionId;\n if (meta.sessionName !== undefined) merged.sessionName = meta.sessionName;\n }\n\n this.logger.debug(`${this.name}: merged vendor metadata from hierarchy`, {\n traceId: span.traceId,\n spanId: span.id,\n metadataKeys: Object.keys(merged),\n ancestorCount: metadataChain.length,\n });\n\n return merged;\n }\n\n private buildRunTreePayload(\n span: AnyExportedSpan,\n traceData: LangSmithTraceData,\n isNew = false,\n ): Partial<RunTreeConfig> {\n // Extract vendor metadata from span hierarchy\n const vendorMetadata = this.findLangsmithMetadata(traceData, span);\n\n // Build metadata, omitting the langsmith vendor key\n const spanMetadata = span.metadata ? omitKeys(span.metadata, ['langsmith']) : {};\n\n const payload: Partial<RunTreeConfig> & { metadata: KVMap } = {\n client: this.#client,\n metadata: {\n mastra_span_type: span.type,\n ...spanMetadata,\n },\n };\n\n if (isNew) {\n payload.run_type = mapSpanType(span.type);\n payload.start_time = span.startTime.getTime();\n }\n\n // Add project name - vendor metadata takes precedence over config\n const projectName = vendorMetadata?.projectName ?? this.config.projectName;\n if (projectName) {\n payload.project_name = projectName;\n }\n\n // Add session info to metadata if provided via vendor metadata\n if (vendorMetadata?.sessionId) {\n payload.metadata.session_id = vendorMetadata.sessionId;\n }\n if (vendorMetadata?.sessionName) {\n payload.metadata.session_name = vendorMetadata.sessionName;\n }\n\n // Add tags for root spans\n if (span.isRootSpan && span.tags?.length) {\n payload.tags = span.tags;\n }\n\n // Core span data\n if (span.input !== undefined) {\n payload.inputs = isKVMap(span.input) ? span.input : { input: span.input };\n }\n\n if (span.output !== undefined) {\n payload.outputs = isKVMap(span.output) ? span.output : { output: span.output };\n }\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n // See: https://docs.langchain.com/langsmith/log-llm-trace\n if (modelAttr.model !== undefined) {\n // Note - this should map to a model name recognized by LangSmith\n // eg “gpt-4o-mini”, “claude-3-opus-20240307”, etc.\n payload.metadata.ls_model_name = modelAttr.model;\n }\n\n // Provider goes to metadata (if provided by attributes)\n if (modelAttr.provider !== undefined) {\n // Note - this should map to a provider name recognized by\n // LangSmith eg “openai”, “anthropic”, etc.\n payload.metadata.ls_provider = modelAttr.provider;\n }\n\n // Usage/token info goes to metrics\n payload.metadata.usage_metadata = formatUsageMetrics(modelAttr.usage);\n\n // Model parameters go to metadata\n if (modelAttr.parameters !== undefined) {\n payload.metadata.modelParameters = modelAttr.parameters;\n }\n\n // Other LLM attributes go to metadata\n const otherAttributes = omitKeys(attributes, ['model', 'provider', 'usage', 'parameters', 'completionStartTime']);\n payload.metadata = {\n ...payload.metadata,\n ...otherAttributes,\n };\n } else {\n // For non-LLM spans, put all attributes in metadata\n payload.metadata = {\n ...payload.metadata,\n ...attributes,\n };\n }\n\n // Handle errors\n if (span.errorInfo) {\n payload.error = span.errorInfo.message;\n payload.metadata.errorDetails = span.errorInfo;\n }\n\n return payload;\n }\n}\n","/**\n * LangSmith Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add LangSmith-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'my-project' })\n * ),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * LangSmith vendor metadata that can be passed via span metadata.\n * These fields are extracted by the LangSmith exporter and used\n * to override default configuration on a per-span basis.\n */\nexport interface LangSmithMetadataInput {\n /**\n * Override the project name for this span and its children.\n * This allows dynamically routing traces to different LangSmith projects.\n */\n projectName?: string;\n /**\n * Session ID for grouping related traces in LangSmith.\n */\n sessionId?: string;\n /**\n * Session name for display in LangSmith.\n */\n sessionName?: string;\n}\n\n/**\n * Adds LangSmith metadata to the tracing options.\n *\n * The metadata is added under `metadata.langsmith` and allows you to:\n * - Route traces to different LangSmith projects via `projectName`\n * - Group traces by session via `sessionId` and `sessionName`\n *\n * @param metadata - The LangSmith metadata to add\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangsmithMetadata } from '@mastra/langsmith';\n *\n * // Route traces to a specific project\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'customer-support' }),\n * );\n *\n * // Or set multiple fields\n * const tracingOptions = buildTracingOptions(\n * withLangsmithMetadata({\n * projectName: 'my-project',\n * sessionId: 'session-123',\n * }),\n * );\n *\n * // Use in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangsmithMetadata({ projectName: 'support-traces' })\n * ),\n * },\n * });\n * ```\n */\nexport function withLangsmithMetadata(metadata: LangSmithMetadataInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langsmith: {\n ...(opts.metadata?.langsmith as Record<string, unknown>),\n ...metadata,\n },\n },\n });\n}\n"]}
|
package/dist/tracing.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { TrackingExporter } from '@mastra/observability';
|
|
|
10
10
|
import type { TraceData, TrackingExporterConfig } from '@mastra/observability';
|
|
11
11
|
import type { ClientConfig } from 'langsmith';
|
|
12
12
|
import { Client, RunTree } from 'langsmith';
|
|
13
|
+
import type { LangSmithMetadataInput } from './helpers.js';
|
|
13
14
|
export interface LangSmithExporterConfig extends ClientConfig, TrackingExporterConfig {
|
|
14
15
|
/** LangSmith client instance */
|
|
15
16
|
client?: Client;
|
|
@@ -23,7 +24,7 @@ export interface LangSmithExporterConfig extends ClientConfig, TrackingExporterC
|
|
|
23
24
|
type LangSmithRoot = undefined;
|
|
24
25
|
type LangSmithSpan = RunTree;
|
|
25
26
|
type LangSmithEvent = RunTree;
|
|
26
|
-
type LangSmithMetadata =
|
|
27
|
+
type LangSmithMetadata = LangSmithMetadataInput;
|
|
27
28
|
type LangSmithTraceData = TraceData<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata>;
|
|
28
29
|
export declare class LangSmithExporter extends TrackingExporter<LangSmithRoot, LangSmithSpan, LangSmithEvent, LangSmithMetadata, LangSmithExporterConfig> {
|
|
29
30
|
#private;
|
|
@@ -56,6 +57,14 @@ export declare class LangSmithExporter extends TrackingExporter<LangSmithRoot, L
|
|
|
56
57
|
reason: SpanErrorInfo;
|
|
57
58
|
}): Promise<void>;
|
|
58
59
|
private handleSpanUpdateOrEnd;
|
|
60
|
+
/**
|
|
61
|
+
* Find LangSmith vendor metadata by walking up the span hierarchy and merging.
|
|
62
|
+
* Metadata is merged from ancestors with child values taking precedence over parent values.
|
|
63
|
+
*
|
|
64
|
+
* TODO(2.0): Extract shared `findVendorMetadata()` to base TrackingExporter class
|
|
65
|
+
* and reuse here and in LangfuseExporter.findLangfusePrompt()
|
|
66
|
+
*/
|
|
67
|
+
private findLangsmithMetadata;
|
|
59
68
|
private buildRunTreePayload;
|
|
60
69
|
}
|
|
61
70
|
export {};
|
package/dist/tracing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA6B,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA6B,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAGxD,MAAM,WAAW,uBAAwB,SAAQ,YAAY,EAAE,sBAAsB;IACnF,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,aAAa,GAAG,SAAS,CAAC;AAC/B,KAAK,aAAa,GAAG,OAAO,CAAC;AAC7B,KAAK,cAAc,GAAG,OAAO,CAAC;AAC9B,KAAK,iBAAiB,GAAG,sBAAsB,CAAC;AAChD,KAAK,kBAAkB,GAAG,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,CAAC,CAAC;AAuBrG,qBAAa,iBAAkB,SAAQ,gBAAgB,CACrD,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,uBAAuB,CACxB;;IACU,IAAI,SAAe;gBAGhB,MAAM,GAAE,uBAA4B;IAiBhD,UAAmB,iBAAiB,UAAQ;cACnB,UAAU,CAAC,KAAK,EAAE;QACzC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;cAIb,UAAU,CAAC,IAAI,EAAE;QACxC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;cAqBb,WAAW,CAAC,IAAI,EAAE;QACzC,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,kBAAkB,CAAC;KAC/B,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;cAcd,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAI1F,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAI1F,UAAU,CAAC,IAAI,EAAE;QACxC,IAAI,EAAE,aAAa,CAAC;QACpB,SAAS,EAAE,kBAAkB,CAAC;QAC9B,MAAM,EAAE,aAAa,CAAC;KACvB,GAAG,OAAO,CAAC,IAAI,CAAC;YAWH,qBAAqB;IAmDnC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IAuC7B,OAAO,CAAC,mBAAmB;CAqG5B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/langsmith",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.1.0-alpha.0",
|
|
4
4
|
"description": "Langsmith observability provider for Mastra - includes tracing and future observability features",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"vitest": "4.0.16",
|
|
40
40
|
"zod": "^3.25.76",
|
|
41
41
|
"@internal/lint": "0.0.57",
|
|
42
|
-
"@mastra/core": "1.2.0",
|
|
43
42
|
"@internal/types-builder": "0.0.32",
|
|
43
|
+
"@mastra/core": "1.3.0-alpha.1",
|
|
44
44
|
"@observability/test-utils": "0.0.1"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|