@mastra/laminar 1.0.0-beta.2
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 +17 -0
- package/README.md +84 -0
- package/dist/index.cjs +472 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +468 -0
- package/dist/index.js.map +1 -0
- package/dist/tracing.d.ts +77 -0
- package/dist/tracing.d.ts.map +1 -0
- package/package.json +68 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @mastra/laminar
|
|
2
|
+
|
|
3
|
+
## 1.0.0-beta.2
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- Initial add of @mastra/laminar observability exporter ([#11758](https://github.com/mastra-ai/mastra/pull/11758))
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 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)]:
|
|
12
|
+
- @mastra/core@1.0.0-beta.22
|
|
13
|
+
- @mastra/observability@1.0.0-beta.11
|
|
14
|
+
|
|
15
|
+
## 1.0.0-beta.1
|
|
16
|
+
|
|
17
|
+
- Initial release of `@mastra/laminar`.
|
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @mastra/laminar
|
|
2
|
+
|
|
3
|
+
Laminar observability exporter for Mastra applications.
|
|
4
|
+
|
|
5
|
+
Exports Mastra spans to Laminar via OTLP/HTTP (protobuf) and supports sending scorer results to Laminar Evaluators.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @mastra/laminar
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Zero-Config Setup
|
|
16
|
+
|
|
17
|
+
The exporter automatically reads credentials from environment variables:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Required
|
|
21
|
+
LMNR_PROJECT_API_KEY=lmnr_...
|
|
22
|
+
|
|
23
|
+
# Optional
|
|
24
|
+
LMNR_BASE_URL=https://api.lmnr.ai
|
|
25
|
+
LAMINAR_ENDPOINT=https://api.lmnr.ai/v1/traces
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { LaminarExporter } from '@mastra/laminar';
|
|
30
|
+
|
|
31
|
+
const mastra = new Mastra({
|
|
32
|
+
...,
|
|
33
|
+
observability: {
|
|
34
|
+
configs: {
|
|
35
|
+
laminar: {
|
|
36
|
+
serviceName: 'my-service',
|
|
37
|
+
exporters: [new LaminarExporter()],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Explicit Configuration
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { LaminarExporter } from '@mastra/laminar';
|
|
48
|
+
|
|
49
|
+
const mastra = new Mastra({
|
|
50
|
+
...,
|
|
51
|
+
observability: {
|
|
52
|
+
configs: {
|
|
53
|
+
laminar: {
|
|
54
|
+
serviceName: 'my-service',
|
|
55
|
+
exporters: [
|
|
56
|
+
new LaminarExporter({
|
|
57
|
+
apiKey: 'lmnr_...',
|
|
58
|
+
baseUrl: 'https://api.lmnr.ai',
|
|
59
|
+
endpoint: 'https://api.lmnr.ai/v1/traces', // Optional
|
|
60
|
+
realtime: false, // Optional
|
|
61
|
+
}),
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Configuration Options
|
|
70
|
+
|
|
71
|
+
| Option | Type | Description |
|
|
72
|
+
| --------------- | ----------------------- | --------------------------------------------------------------------------------- |
|
|
73
|
+
| `apiKey` | `string` | Laminar project API key. Defaults to `LMNR_PROJECT_API_KEY` env var |
|
|
74
|
+
| `baseUrl` | `string` | Laminar base URL. Defaults to `LMNR_BASE_URL` env var or `https://api.lmnr.ai` |
|
|
75
|
+
| `endpoint` | `string` | OTLP/HTTP traces endpoint. Defaults to `LAMINAR_ENDPOINT` env var or `/v1/traces` |
|
|
76
|
+
| `headers` | `Record<string,string>` | Additional OTLP headers |
|
|
77
|
+
| `realtime` | `boolean` | Flush after each span for immediate visibility. Defaults to `false` |
|
|
78
|
+
| `disableBatch` | `boolean` | Disable batching (SimpleSpanProcessor). Defaults to `false` |
|
|
79
|
+
| `batchSize` | `number` | Max spans per batch (BatchSpanProcessor). Defaults to `512` |
|
|
80
|
+
| `timeoutMillis` | `number` | OTLP export timeout (ms). Defaults to `30000` |
|
|
81
|
+
|
|
82
|
+
## Notes
|
|
83
|
+
|
|
84
|
+
- The exporter sets Laminar-specific attributes (`lmnr.span.*`, `lmnr.association.properties.*`) so traces render correctly in Laminar.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var observability$1 = require('@mastra/core/observability');
|
|
4
|
+
var observability = require('@mastra/observability');
|
|
5
|
+
var api = require('@opentelemetry/api');
|
|
6
|
+
var exporterTraceOtlpProto = require('@opentelemetry/exporter-trace-otlp-proto');
|
|
7
|
+
var resources = require('@opentelemetry/resources');
|
|
8
|
+
var sdkTraceBase = require('@opentelemetry/sdk-trace-base');
|
|
9
|
+
var semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
10
|
+
|
|
11
|
+
// src/tracing.ts
|
|
12
|
+
var LMNR_SPAN_INPUT = "lmnr.span.input";
|
|
13
|
+
var LMNR_SPAN_OUTPUT = "lmnr.span.output";
|
|
14
|
+
var LMNR_SPAN_TYPE = "lmnr.span.type";
|
|
15
|
+
var LMNR_SPAN_PATH = "lmnr.span.path";
|
|
16
|
+
var LMNR_SPAN_IDS_PATH = "lmnr.span.ids_path";
|
|
17
|
+
var LMNR_SPAN_INSTRUMENTATION_SOURCE = "lmnr.span.instrumentation_source";
|
|
18
|
+
var LMNR_SPAN_SDK_VERSION = "lmnr.span.sdk_version";
|
|
19
|
+
var LMNR_SPAN_LANGUAGE_VERSION = "lmnr.span.language_version";
|
|
20
|
+
var LMNR_ASSOCIATION_PREFIX = "lmnr.association.properties";
|
|
21
|
+
var LMNR_SESSION_ID = `${LMNR_ASSOCIATION_PREFIX}.session_id`;
|
|
22
|
+
var LMNR_USER_ID = `${LMNR_ASSOCIATION_PREFIX}.user_id`;
|
|
23
|
+
var LMNR_TAGS = `${LMNR_ASSOCIATION_PREFIX}.tags`;
|
|
24
|
+
var GEN_AI_SYSTEM = "gen_ai.system";
|
|
25
|
+
var GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
26
|
+
var GEN_AI_RESPONSE_MODEL = "gen_ai.response.model";
|
|
27
|
+
var GEN_AI_USAGE_INPUT_TOKENS = "gen_ai.usage.input_tokens";
|
|
28
|
+
var GEN_AI_USAGE_OUTPUT_TOKENS = "gen_ai.usage.output_tokens";
|
|
29
|
+
var GEN_AI_CACHE_WRITE_INPUT_TOKENS = "gen_ai.usage.cache_creation_input_tokens";
|
|
30
|
+
var GEN_AI_CACHE_READ_INPUT_TOKENS = "gen_ai.usage.cache_read_input_tokens";
|
|
31
|
+
var LaminarExporter = class extends observability.BaseExporter {
|
|
32
|
+
name = "laminar";
|
|
33
|
+
config;
|
|
34
|
+
traceMap = /* @__PURE__ */ new Map();
|
|
35
|
+
resource;
|
|
36
|
+
scope;
|
|
37
|
+
processor;
|
|
38
|
+
exporter;
|
|
39
|
+
isSetup = false;
|
|
40
|
+
constructor(config = {}) {
|
|
41
|
+
super(config);
|
|
42
|
+
const apiKey = config.apiKey ?? process.env.LMNR_PROJECT_API_KEY;
|
|
43
|
+
if (!apiKey) {
|
|
44
|
+
this.setDisabled(
|
|
45
|
+
"Missing required API key. Set LMNR_PROJECT_API_KEY environment variable or pass apiKey in config."
|
|
46
|
+
);
|
|
47
|
+
this.config = null;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const envEndpoint = process.env.LAMINAR_ENDPOINT;
|
|
51
|
+
const baseUrl = stripTrailingSlash(config.baseUrl ?? process.env.LMNR_BASE_URL ?? "https://api.lmnr.ai");
|
|
52
|
+
const endpoint = config.endpoint ?? envEndpoint ?? `${baseUrl}/v1/traces`;
|
|
53
|
+
const headers = {
|
|
54
|
+
...config.headers,
|
|
55
|
+
Authorization: `Bearer ${apiKey}`
|
|
56
|
+
};
|
|
57
|
+
this.config = {
|
|
58
|
+
apiKey,
|
|
59
|
+
baseUrl,
|
|
60
|
+
endpoint,
|
|
61
|
+
headers,
|
|
62
|
+
realtime: config.realtime ?? false,
|
|
63
|
+
disableBatch: config.disableBatch ?? false,
|
|
64
|
+
batchSize: config.batchSize ?? 512,
|
|
65
|
+
timeoutMillis: config.timeoutMillis ?? 3e4
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
init(options) {
|
|
69
|
+
const serviceName = options.config?.serviceName || "mastra-service";
|
|
70
|
+
this.resource = resources.resourceFromAttributes({
|
|
71
|
+
[semanticConventions.ATTR_SERVICE_NAME]: serviceName,
|
|
72
|
+
[semanticConventions.ATTR_SERVICE_VERSION]: "unknown",
|
|
73
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_NAME]: "@mastra/laminar",
|
|
74
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_VERSION]: "unknown",
|
|
75
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_LANGUAGE]: "nodejs"
|
|
76
|
+
});
|
|
77
|
+
this.scope = {
|
|
78
|
+
name: "@mastra/laminar",
|
|
79
|
+
version: "unknown"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async _exportTracingEvent(event) {
|
|
83
|
+
if (event.type === observability$1.TracingEventType.SPAN_STARTED && !event.exportedSpan.isEvent) {
|
|
84
|
+
this.handleSpanStarted(event.exportedSpan);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (event.type !== observability$1.TracingEventType.SPAN_ENDED) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
await this.handleSpanEnded(event.exportedSpan);
|
|
91
|
+
}
|
|
92
|
+
handleSpanStarted(span) {
|
|
93
|
+
const traceState = this.getOrCreateTraceState(span.traceId);
|
|
94
|
+
const name = span.name;
|
|
95
|
+
const parentId = span.parentSpanId;
|
|
96
|
+
const parentPath = parentId ? traceState.spanPathById.get(parentId) : void 0;
|
|
97
|
+
const parentIdsPath = parentId ? traceState.spanIdsPathById.get(parentId) : void 0;
|
|
98
|
+
const spanPath = parentPath ? [...parentPath, name] : [name];
|
|
99
|
+
const spanIdsPath = parentIdsPath ? [...parentIdsPath, otelSpanIdToUUID(span.id)] : [otelSpanIdToUUID(span.id)];
|
|
100
|
+
traceState.spanPathById.set(span.id, spanPath);
|
|
101
|
+
traceState.spanIdsPathById.set(span.id, spanIdsPath);
|
|
102
|
+
traceState.activeSpanIds.add(span.id);
|
|
103
|
+
}
|
|
104
|
+
async handleSpanEnded(span) {
|
|
105
|
+
if (!this.config) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
await this.setupIfNeeded();
|
|
109
|
+
if (!this.processor || !this.exporter) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const traceState = this.getOrCreateTraceState(span.traceId);
|
|
113
|
+
if (!traceState.spanPathById.has(span.id) || !traceState.spanIdsPathById.has(span.id)) {
|
|
114
|
+
const name = span.name;
|
|
115
|
+
const parentId = span.parentSpanId;
|
|
116
|
+
const parentPath = parentId ? traceState.spanPathById.get(parentId) : void 0;
|
|
117
|
+
const parentIdsPath = parentId ? traceState.spanIdsPathById.get(parentId) : void 0;
|
|
118
|
+
const spanPath = parentPath ? [...parentPath, name] : [name];
|
|
119
|
+
const spanIdsPath = parentIdsPath ? [...parentIdsPath, otelSpanIdToUUID(span.id)] : [otelSpanIdToUUID(span.id)];
|
|
120
|
+
traceState.spanPathById.set(span.id, spanPath);
|
|
121
|
+
traceState.spanIdsPathById.set(span.id, spanIdsPath);
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const otelSpan = this.convertSpanToOtel(span, traceState);
|
|
125
|
+
this.processor.onEnd(otelSpan);
|
|
126
|
+
if (this.config.realtime) {
|
|
127
|
+
await this.processor.forceFlush();
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
this.logger.error("[LaminarExporter] Failed to export span", { error, spanId: span.id, traceId: span.traceId });
|
|
131
|
+
} finally {
|
|
132
|
+
traceState.activeSpanIds.delete(span.id);
|
|
133
|
+
if (traceState.activeSpanIds.size === 0) {
|
|
134
|
+
this.traceMap.delete(span.traceId);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
getOrCreateTraceState(traceId) {
|
|
139
|
+
const existing = this.traceMap.get(traceId);
|
|
140
|
+
if (existing) return existing;
|
|
141
|
+
const created = {
|
|
142
|
+
spanPathById: /* @__PURE__ */ new Map(),
|
|
143
|
+
spanIdsPathById: /* @__PURE__ */ new Map(),
|
|
144
|
+
activeSpanIds: /* @__PURE__ */ new Set()
|
|
145
|
+
};
|
|
146
|
+
this.traceMap.set(traceId, created);
|
|
147
|
+
return created;
|
|
148
|
+
}
|
|
149
|
+
convertSpanToOtel(span, traceState) {
|
|
150
|
+
if (!this.resource || !this.scope) {
|
|
151
|
+
this.resource = resources.resourceFromAttributes({
|
|
152
|
+
[semanticConventions.ATTR_SERVICE_NAME]: "mastra-service",
|
|
153
|
+
[semanticConventions.ATTR_SERVICE_VERSION]: "unknown",
|
|
154
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_NAME]: "@mastra/laminar",
|
|
155
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_VERSION]: "unknown",
|
|
156
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_LANGUAGE]: "nodejs"
|
|
157
|
+
});
|
|
158
|
+
this.scope = { name: "@mastra/laminar", version: "unknown" };
|
|
159
|
+
}
|
|
160
|
+
const name = span.name;
|
|
161
|
+
const kind = getSpanKind(span.type);
|
|
162
|
+
const startTime = dateToHrTime(span.startTime);
|
|
163
|
+
const endTime = span.endTime ? dateToHrTime(span.endTime) : startTime;
|
|
164
|
+
const duration = computeDuration(span.startTime, span.endTime);
|
|
165
|
+
const { status, events } = buildStatusAndEvents(span, startTime);
|
|
166
|
+
const traceId = normalizeTraceId(span.traceId);
|
|
167
|
+
const spanId = normalizeSpanId(span.id);
|
|
168
|
+
const spanContext = {
|
|
169
|
+
traceId,
|
|
170
|
+
spanId,
|
|
171
|
+
traceFlags: api.TraceFlags.SAMPLED,
|
|
172
|
+
isRemote: false
|
|
173
|
+
};
|
|
174
|
+
const parentSpanContext = span.parentSpanId ? {
|
|
175
|
+
traceId,
|
|
176
|
+
spanId: normalizeSpanId(span.parentSpanId),
|
|
177
|
+
traceFlags: api.TraceFlags.SAMPLED,
|
|
178
|
+
isRemote: false
|
|
179
|
+
} : void 0;
|
|
180
|
+
const attributes = buildLaminarAttributes(span, traceState);
|
|
181
|
+
const links = [];
|
|
182
|
+
const readable = {
|
|
183
|
+
name,
|
|
184
|
+
kind,
|
|
185
|
+
spanContext: () => spanContext,
|
|
186
|
+
parentSpanContext,
|
|
187
|
+
startTime,
|
|
188
|
+
endTime,
|
|
189
|
+
status,
|
|
190
|
+
attributes,
|
|
191
|
+
links,
|
|
192
|
+
events,
|
|
193
|
+
duration,
|
|
194
|
+
ended: true,
|
|
195
|
+
resource: this.resource,
|
|
196
|
+
instrumentationScope: this.scope,
|
|
197
|
+
droppedAttributesCount: 0,
|
|
198
|
+
droppedEventsCount: 0,
|
|
199
|
+
droppedLinksCount: 0
|
|
200
|
+
};
|
|
201
|
+
return readable;
|
|
202
|
+
}
|
|
203
|
+
async setupIfNeeded() {
|
|
204
|
+
if (this.isSetup || !this.config) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
this.exporter = new exporterTraceOtlpProto.OTLPTraceExporter({
|
|
208
|
+
url: this.config.endpoint,
|
|
209
|
+
headers: this.config.headers,
|
|
210
|
+
timeoutMillis: this.config.timeoutMillis
|
|
211
|
+
});
|
|
212
|
+
this.processor = this.config.disableBatch ? new sdkTraceBase.SimpleSpanProcessor(this.exporter) : new sdkTraceBase.BatchSpanProcessor(this.exporter, {
|
|
213
|
+
maxExportBatchSize: this.config.batchSize,
|
|
214
|
+
exportTimeoutMillis: this.config.timeoutMillis
|
|
215
|
+
});
|
|
216
|
+
this.isSetup = true;
|
|
217
|
+
}
|
|
218
|
+
async _addScoreToTrace({
|
|
219
|
+
traceId,
|
|
220
|
+
spanId,
|
|
221
|
+
score,
|
|
222
|
+
reason,
|
|
223
|
+
scorerName,
|
|
224
|
+
metadata
|
|
225
|
+
}) {
|
|
226
|
+
if (!this.config) return;
|
|
227
|
+
const payload = {
|
|
228
|
+
name: scorerName,
|
|
229
|
+
score,
|
|
230
|
+
source: "Code",
|
|
231
|
+
metadata: { ...metadata ?? {}, ...reason ? { reason } : {} }
|
|
232
|
+
};
|
|
233
|
+
if (spanId) {
|
|
234
|
+
payload.spanId = otelSpanIdToUUID(spanId);
|
|
235
|
+
} else {
|
|
236
|
+
payload.traceId = otelTraceIdToUUID(traceId);
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const scoreHeaders = {
|
|
240
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
241
|
+
"content-type": "application/json"
|
|
242
|
+
};
|
|
243
|
+
const response = await fetch(`${stripTrailingSlash(this.config.baseUrl)}/v1/evaluators/score`, {
|
|
244
|
+
method: "POST",
|
|
245
|
+
headers: scoreHeaders,
|
|
246
|
+
body: JSON.stringify(payload)
|
|
247
|
+
});
|
|
248
|
+
if (!response.ok) {
|
|
249
|
+
this.logger.warn("[LaminarExporter] Failed to attach score to trace/span", {
|
|
250
|
+
status: response.status,
|
|
251
|
+
statusText: response.statusText,
|
|
252
|
+
traceId,
|
|
253
|
+
spanId,
|
|
254
|
+
scorerName
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
this.logger.error("[LaminarExporter] Error attaching score to trace/span", {
|
|
259
|
+
error,
|
|
260
|
+
traceId,
|
|
261
|
+
spanId,
|
|
262
|
+
scorerName
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async shutdown() {
|
|
267
|
+
try {
|
|
268
|
+
await this.processor?.shutdown();
|
|
269
|
+
} finally {
|
|
270
|
+
this.traceMap.clear();
|
|
271
|
+
await super.shutdown();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
function buildLaminarAttributes(span, traceState) {
|
|
276
|
+
const attributes = {};
|
|
277
|
+
const spanPath = traceState.spanPathById.get(span.id);
|
|
278
|
+
const spanIdsPath = traceState.spanIdsPathById.get(span.id);
|
|
279
|
+
if (spanPath) {
|
|
280
|
+
attributes[LMNR_SPAN_PATH] = spanPath;
|
|
281
|
+
}
|
|
282
|
+
if (spanIdsPath) {
|
|
283
|
+
attributes[LMNR_SPAN_IDS_PATH] = spanIdsPath;
|
|
284
|
+
}
|
|
285
|
+
attributes[LMNR_SPAN_TYPE] = mapLaminarSpanType(span.type);
|
|
286
|
+
attributes[LMNR_SPAN_INSTRUMENTATION_SOURCE] = "javascript";
|
|
287
|
+
attributes[LMNR_SPAN_SDK_VERSION] = "unknown";
|
|
288
|
+
attributes[LMNR_SPAN_LANGUAGE_VERSION] = process.version;
|
|
289
|
+
const sessionId = span.metadata?.sessionId;
|
|
290
|
+
if (typeof sessionId === "string" && sessionId.length > 0) {
|
|
291
|
+
attributes[LMNR_SESSION_ID] = sessionId;
|
|
292
|
+
}
|
|
293
|
+
const userId = span.metadata?.userId;
|
|
294
|
+
if (typeof userId === "string" && userId.length > 0) {
|
|
295
|
+
attributes[LMNR_USER_ID] = userId;
|
|
296
|
+
}
|
|
297
|
+
if (span.metadata) {
|
|
298
|
+
for (const [key, value] of Object.entries(span.metadata)) {
|
|
299
|
+
if (key === "sessionId" || key === "userId" || value === void 0 || value === null) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const attributeValue = toLaminarAttributeValue(value);
|
|
303
|
+
if (attributeValue === void 0) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
attributes[`${LMNR_ASSOCIATION_PREFIX}.metadata.${key}`] = attributeValue;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (span.isRootSpan && span.tags?.length) {
|
|
310
|
+
attributes[LMNR_TAGS] = span.tags;
|
|
311
|
+
}
|
|
312
|
+
if (span.input !== void 0) {
|
|
313
|
+
attributes[LMNR_SPAN_INPUT] = serializeForLaminar(getLaminarSpanInput(span));
|
|
314
|
+
}
|
|
315
|
+
if (span.output !== void 0) {
|
|
316
|
+
attributes[LMNR_SPAN_OUTPUT] = serializeForLaminar(span.output);
|
|
317
|
+
}
|
|
318
|
+
if (span.type === observability$1.SpanType.MODEL_GENERATION) {
|
|
319
|
+
const modelAttrs = span.attributes ?? {};
|
|
320
|
+
if (modelAttrs.provider) {
|
|
321
|
+
attributes[GEN_AI_SYSTEM] = normalizeProvider(modelAttrs.provider);
|
|
322
|
+
}
|
|
323
|
+
if (modelAttrs.model) {
|
|
324
|
+
attributes[GEN_AI_REQUEST_MODEL] = modelAttrs.model;
|
|
325
|
+
}
|
|
326
|
+
if (modelAttrs.responseModel) {
|
|
327
|
+
attributes[GEN_AI_RESPONSE_MODEL] = modelAttrs.responseModel;
|
|
328
|
+
}
|
|
329
|
+
Object.assign(attributes, formatLaminarUsage(modelAttrs.usage));
|
|
330
|
+
}
|
|
331
|
+
return attributes;
|
|
332
|
+
}
|
|
333
|
+
function mapLaminarSpanType(spanType) {
|
|
334
|
+
switch (spanType) {
|
|
335
|
+
case observability$1.SpanType.MODEL_GENERATION:
|
|
336
|
+
case observability$1.SpanType.MODEL_STEP:
|
|
337
|
+
case observability$1.SpanType.MODEL_CHUNK:
|
|
338
|
+
return "LLM";
|
|
339
|
+
case observability$1.SpanType.TOOL_CALL:
|
|
340
|
+
case observability$1.SpanType.MCP_TOOL_CALL:
|
|
341
|
+
return "TOOL";
|
|
342
|
+
default:
|
|
343
|
+
return "DEFAULT";
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function formatLaminarUsage(usage) {
|
|
347
|
+
if (!usage) return {};
|
|
348
|
+
const out = {};
|
|
349
|
+
if (usage.inputTokens !== void 0) {
|
|
350
|
+
out[GEN_AI_USAGE_INPUT_TOKENS] = usage.inputTokens;
|
|
351
|
+
}
|
|
352
|
+
if (usage.outputTokens !== void 0) {
|
|
353
|
+
out[GEN_AI_USAGE_OUTPUT_TOKENS] = usage.outputTokens;
|
|
354
|
+
}
|
|
355
|
+
if (usage.inputDetails?.cacheWrite !== void 0) {
|
|
356
|
+
out[GEN_AI_CACHE_WRITE_INPUT_TOKENS] = usage.inputDetails.cacheWrite;
|
|
357
|
+
}
|
|
358
|
+
if (usage.inputDetails?.cacheRead !== void 0) {
|
|
359
|
+
out[GEN_AI_CACHE_READ_INPUT_TOKENS] = usage.inputDetails.cacheRead;
|
|
360
|
+
}
|
|
361
|
+
return out;
|
|
362
|
+
}
|
|
363
|
+
function serializeForLaminar(value) {
|
|
364
|
+
if (typeof value === "string") {
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
return JSON.stringify(value);
|
|
369
|
+
} catch {
|
|
370
|
+
return "[unserializable]";
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function getLaminarSpanInput(span) {
|
|
374
|
+
if (span.type !== observability$1.SpanType.MODEL_GENERATION) {
|
|
375
|
+
return span.input;
|
|
376
|
+
}
|
|
377
|
+
const input = span.input;
|
|
378
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
379
|
+
return input;
|
|
380
|
+
}
|
|
381
|
+
const maybeMessages = input.messages;
|
|
382
|
+
return Array.isArray(maybeMessages) ? maybeMessages : input;
|
|
383
|
+
}
|
|
384
|
+
function toLaminarAttributeValue(value) {
|
|
385
|
+
if (value === void 0 || value === null) {
|
|
386
|
+
return void 0;
|
|
387
|
+
}
|
|
388
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
389
|
+
return value;
|
|
390
|
+
}
|
|
391
|
+
if (Array.isArray(value)) {
|
|
392
|
+
const isHomogeneous = value.every((v) => typeof v === "string") || value.every((v) => typeof v === "number") || value.every((v) => typeof v === "boolean");
|
|
393
|
+
if (isHomogeneous) return value;
|
|
394
|
+
}
|
|
395
|
+
return serializeForLaminar(value);
|
|
396
|
+
}
|
|
397
|
+
function dateToHrTime(date) {
|
|
398
|
+
const ms = date.getTime();
|
|
399
|
+
const seconds = Math.floor(ms / 1e3);
|
|
400
|
+
const nanoseconds = ms % 1e3 * 1e6;
|
|
401
|
+
return [seconds, nanoseconds];
|
|
402
|
+
}
|
|
403
|
+
function computeDuration(start, end) {
|
|
404
|
+
if (!end) return [0, 0];
|
|
405
|
+
const diffMs = end.getTime() - start.getTime();
|
|
406
|
+
return [Math.floor(diffMs / 1e3), diffMs % 1e3 * 1e6];
|
|
407
|
+
}
|
|
408
|
+
function buildStatusAndEvents(span, defaultTime) {
|
|
409
|
+
const events = [];
|
|
410
|
+
if (span.errorInfo) {
|
|
411
|
+
const status = {
|
|
412
|
+
code: api.SpanStatusCode.ERROR,
|
|
413
|
+
message: span.errorInfo.message
|
|
414
|
+
};
|
|
415
|
+
events.push({
|
|
416
|
+
name: "exception",
|
|
417
|
+
attributes: {
|
|
418
|
+
"exception.message": span.errorInfo.message,
|
|
419
|
+
"exception.type": "Error",
|
|
420
|
+
...span.errorInfo.details?.stack && {
|
|
421
|
+
"exception.stacktrace": span.errorInfo.details.stack
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
time: defaultTime,
|
|
425
|
+
droppedAttributesCount: 0
|
|
426
|
+
});
|
|
427
|
+
return { status, events };
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
status: { code: api.SpanStatusCode.OK },
|
|
431
|
+
events
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function getSpanKind(type) {
|
|
435
|
+
switch (type) {
|
|
436
|
+
case observability$1.SpanType.MODEL_GENERATION:
|
|
437
|
+
case observability$1.SpanType.MCP_TOOL_CALL:
|
|
438
|
+
return api.SpanKind.CLIENT;
|
|
439
|
+
default:
|
|
440
|
+
return api.SpanKind.INTERNAL;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function stripTrailingSlash(url) {
|
|
444
|
+
return url.replace(/\/+$/g, "");
|
|
445
|
+
}
|
|
446
|
+
function normalizeTraceId(traceId) {
|
|
447
|
+
let id = traceId.toLowerCase();
|
|
448
|
+
if (id.startsWith("0x")) id = id.slice(2);
|
|
449
|
+
return id.padStart(32, "0").slice(-32);
|
|
450
|
+
}
|
|
451
|
+
function normalizeSpanId(spanId) {
|
|
452
|
+
let id = spanId.toLowerCase();
|
|
453
|
+
if (id.startsWith("0x")) id = id.slice(2);
|
|
454
|
+
return id.padStart(16, "0").slice(-16);
|
|
455
|
+
}
|
|
456
|
+
function otelSpanIdToUUID(spanId) {
|
|
457
|
+
const normalized = normalizeSpanId(spanId);
|
|
458
|
+
return normalized.padStart(32, "0").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
|
|
459
|
+
}
|
|
460
|
+
function otelTraceIdToUUID(traceId) {
|
|
461
|
+
const normalized = normalizeTraceId(traceId);
|
|
462
|
+
return normalized.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
|
|
463
|
+
}
|
|
464
|
+
function normalizeProvider(provider) {
|
|
465
|
+
return provider.split(".").shift()?.toLowerCase().trim() || provider.toLowerCase().trim();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
exports.LaminarExporter = LaminarExporter;
|
|
469
|
+
exports.otelSpanIdToUUID = otelSpanIdToUUID;
|
|
470
|
+
exports.otelTraceIdToUUID = otelTraceIdToUUID;
|
|
471
|
+
//# sourceMappingURL=index.cjs.map
|
|
472
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tracing.ts"],"names":["BaseExporter","resourceFromAttributes","ATTR_SERVICE_NAME","ATTR_SERVICE_VERSION","ATTR_TELEMETRY_SDK_NAME","ATTR_TELEMETRY_SDK_VERSION","ATTR_TELEMETRY_SDK_LANGUAGE","TracingEventType","TraceFlags","OTLPTraceExporter","SimpleSpanProcessor","BatchSpanProcessor","SpanType","SpanStatusCode","SpanKind"],"mappings":";;;;;;;;;;;AAiCA,IAAM,eAAA,GAAkB,iBAAA;AACxB,IAAM,gBAAA,GAAmB,kBAAA;AACzB,IAAM,cAAA,GAAiB,gBAAA;AACvB,IAAM,cAAA,GAAiB,gBAAA;AACvB,IAAM,kBAAA,GAAqB,oBAAA;AAC3B,IAAM,gCAAA,GAAmC,kCAAA;AACzC,IAAM,qBAAA,GAAwB,uBAAA;AAC9B,IAAM,0BAAA,GAA6B,4BAAA;AAEnC,IAAM,uBAAA,GAA0B,6BAAA;AAChC,IAAM,eAAA,GAAkB,GAAG,uBAAuB,CAAA,WAAA,CAAA;AAClD,IAAM,YAAA,GAAe,GAAG,uBAAuB,CAAA,QAAA,CAAA;AAC/C,IAAM,SAAA,GAAY,GAAG,uBAAuB,CAAA,KAAA,CAAA;AAG5C,IAAM,aAAA,GAAgB,eAAA;AACtB,IAAM,oBAAA,GAAuB,sBAAA;AAC7B,IAAM,qBAAA,GAAwB,uBAAA;AAC9B,IAAM,yBAAA,GAA4B,2BAAA;AAClC,IAAM,0BAAA,GAA6B,4BAAA;AACnC,IAAM,+BAAA,GAAkC,0CAAA;AACxC,IAAM,8BAAA,GAAiC,sCAAA;AA+DhC,IAAM,eAAA,GAAN,cAA8BA,0BAAA,CAAa;AAAA,EAChD,IAAA,GAAO,SAAA;AAAA,EAEC,MAAA;AAAA,EACA,QAAA,uBAAe,GAAA,EAAwB;AAAA,EAEvC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EAElB,WAAA,CAAY,MAAA,GAAgC,EAAC,EAAG;AAC9C,IAAA,KAAA,CAAM,MAAM,CAAA;AAEZ,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,oBAAA;AAC5C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,IAAA,CAAK,WAAA;AAAA,QACH;AAAA,OACF;AACA,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,WAAA,GAAc,QAAQ,GAAA,CAAI,gBAAA;AAChC,IAAA,MAAM,UAAU,kBAAA,CAAmB,MAAA,CAAO,WAAW,OAAA,CAAQ,GAAA,CAAI,iBAAiB,qBAAqB,CAAA;AACvG,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,IAAY,WAAA,IAAe,GAAG,OAAO,CAAA,UAAA,CAAA;AAE7D,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,GAAG,MAAA,CAAO,OAAA;AAAA,MACV,aAAA,EAAe,UAAU,MAAM,CAAA;AAAA,KACjC;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,MAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA,EAAU,OAAO,QAAA,IAAY,KAAA;AAAA,MAC7B,YAAA,EAAc,OAAO,YAAA,IAAgB,KAAA;AAAA,MACrC,SAAA,EAAW,OAAO,SAAA,IAAa,GAAA;AAAA,MAC/B,aAAA,EAAe,OAAO,aAAA,IAAiB;AAAA,KACzC;AAAA,EACF;AAAA,EAEA,KAAK,OAAA,EAAoC;AAEvC,IAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,MAAA,EAAQ,WAAA,IAAe,gBAAA;AAEnD,IAAA,IAAA,CAAK,WAAWC,gCAAA,CAAuB;AAAA,MACrC,CAACC,qCAAiB,GAAG,WAAA;AAAA,MACrB,CAACC,wCAAoB,GAAG,SAAA;AAAA,MACxB,CAACC,2CAAuB,GAAG,iBAAA;AAAA,MAC3B,CAACC,8CAA0B,GAAG,SAAA;AAAA,MAC9B,CAACC,+CAA2B,GAAG;AAAA,KAChC,CAAA;AAED,IAAA,IAAA,CAAK,KAAA,GAAQ;AAAA,MACX,IAAA,EAAM,iBAAA;AAAA,MACN,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAAA,EAEA,MAAgB,oBAAoB,KAAA,EAAoC;AAEtE,IAAA,IAAI,MAAM,IAAA,KAASC,gCAAA,CAAiB,gBAAgB,CAAC,KAAA,CAAM,aAAa,OAAA,EAAS;AAC/E,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAM,YAAY,CAAA;AACzC,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,KAAA,CAAM,IAAA,KAASA,gCAAA,CAAiB,UAAA,EAAY;AAC9C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,CAAK,eAAA,CAAgB,KAAA,CAAM,YAAY,CAAA;AAAA,EAC/C;AAAA,EAEQ,kBAAkB,IAAA,EAA6B;AACrD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,qBAAA,CAAsB,IAAA,CAAK,OAAO,CAAA;AAC1D,IAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAElB,IAAA,MAAM,WAAW,IAAA,CAAK,YAAA;AACtB,IAAA,MAAM,aAAa,QAAA,GAAW,UAAA,CAAW,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA,GAAI,MAAA;AACtE,IAAA,MAAM,gBAAgB,QAAA,GAAW,UAAA,CAAW,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA,GAAI,MAAA;AAE5E,IAAA,MAAM,QAAA,GAAW,aAAa,CAAC,GAAG,YAAY,IAAI,CAAA,GAAI,CAAC,IAAI,CAAA;AAC3D,IAAA,MAAM,WAAA,GAAc,aAAA,GAAgB,CAAC,GAAG,eAAe,gBAAA,CAAiB,IAAA,CAAK,EAAE,CAAC,CAAA,GAAI,CAAC,gBAAA,CAAiB,IAAA,CAAK,EAAE,CAAC,CAAA;AAE9G,IAAA,UAAA,CAAW,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,QAAQ,CAAA;AAC7C,IAAA,UAAA,CAAW,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,WAAW,CAAA;AACnD,IAAA,UAAA,CAAW,aAAA,CAAc,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AAAA,EACtC;AAAA,EAEA,MAAc,gBAAgB,IAAA,EAAsC;AAClE,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAK,aAAA,EAAc;AAEzB,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA,IAAa,CAAC,KAAK,QAAA,EAAU;AACrC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,qBAAA,CAAsB,IAAA,CAAK,OAAO,CAAA;AAG1D,IAAA,IAAI,CAAC,UAAA,CAAW,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,IAAK,CAAC,UAAA,CAAW,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AACrF,MAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,MAAA,MAAM,WAAW,IAAA,CAAK,YAAA;AACtB,MAAA,MAAM,aAAa,QAAA,GAAW,UAAA,CAAW,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA,GAAI,MAAA;AACtE,MAAA,MAAM,gBAAgB,QAAA,GAAW,UAAA,CAAW,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA,GAAI,MAAA;AAE5E,MAAA,MAAM,QAAA,GAAW,aAAa,CAAC,GAAG,YAAY,IAAI,CAAA,GAAI,CAAC,IAAI,CAAA;AAC3D,MAAA,MAAM,WAAA,GAAc,aAAA,GAAgB,CAAC,GAAG,eAAe,gBAAA,CAAiB,IAAA,CAAK,EAAE,CAAC,CAAA,GAAI,CAAC,gBAAA,CAAiB,IAAA,CAAK,EAAE,CAAC,CAAA;AAE9G,MAAA,UAAA,CAAW,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,QAAQ,CAAA;AAC7C,MAAA,UAAA,CAAW,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,WAAW,CAAA;AAAA,IACrD;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,iBAAA,CAAkB,IAAA,EAAM,UAAU,CAAA;AACxD,MAAA,IAAA,CAAK,SAAA,CAAU,MAAM,QAAQ,CAAA;AAE7B,MAAA,IAAI,IAAA,CAAK,OAAO,QAAA,EAAU;AACxB,QAAA,MAAM,IAAA,CAAK,UAAU,UAAA,EAAW;AAAA,MAClC;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,yCAAA,EAA2C,EAAE,KAAA,EAAO,MAAA,EAAQ,IAAA,CAAK,EAAA,EAAI,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,CAAA;AAAA,IAChH,CAAA,SAAE;AAEA,MAAA,UAAA,CAAW,aAAA,CAAc,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA;AAEvC,MAAA,IAAI,UAAA,CAAW,aAAA,CAAc,IAAA,KAAS,CAAA,EAAG;AACvC,QAAA,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAAsB,OAAA,EAA6B;AACzD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA;AAC1C,IAAA,IAAI,UAAU,OAAO,QAAA;AAErB,IAAA,MAAM,OAAA,GAAsB;AAAA,MAC1B,YAAA,sBAAkB,GAAA,EAAI;AAAA,MACtB,eAAA,sBAAqB,GAAA,EAAI;AAAA,MACzB,aAAA,sBAAmB,GAAA;AAAI,KACzB;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAA,EAAS,OAAO,CAAA;AAClC,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEQ,iBAAA,CAAkB,MAAuB,UAAA,EAAsC;AACrF,IAAA,IAAI,CAAC,IAAA,CAAK,QAAA,IAAY,CAAC,KAAK,KAAA,EAAO;AAEjC,MAAA,IAAA,CAAK,WAAWN,gCAAA,CAAuB;AAAA,QACrC,CAACC,qCAAiB,GAAG,gBAAA;AAAA,QACrB,CAACC,wCAAoB,GAAG,SAAA;AAAA,QACxB,CAACC,2CAAuB,GAAG,iBAAA;AAAA,QAC3B,CAACC,8CAA0B,GAAG,SAAA;AAAA,QAC9B,CAACC,+CAA2B,GAAG;AAAA,OAChC,CAAA;AACD,MAAA,IAAA,CAAK,KAAA,GAAQ,EAAE,IAAA,EAAM,iBAAA,EAAmB,SAAS,SAAA,EAAU;AAAA,IAC7D;AAEA,IAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,IAAA,MAAM,IAAA,GAAO,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA;AAElC,IAAA,MAAM,SAAA,GAAY,YAAA,CAAa,IAAA,CAAK,SAAS,CAAA;AAC7C,IAAA,MAAM,UAAU,IAAA,CAAK,OAAA,GAAU,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA,GAAI,SAAA;AAC5D,IAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,IAAA,CAAK,SAAA,EAAW,KAAK,OAAO,CAAA;AAE7D,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,oBAAA,CAAqB,MAAM,SAAS,CAAA;AAE/D,IAAA,MAAM,OAAA,GAAU,gBAAA,CAAiB,IAAA,CAAK,OAAO,CAAA;AAC7C,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,EAAE,CAAA;AAEtC,IAAA,MAAM,WAAA,GAA2B;AAAA,MAC/B,OAAA;AAAA,MACA,MAAA;AAAA,MACA,YAAYE,cAAA,CAAW,OAAA;AAAA,MACvB,QAAA,EAAU;AAAA,KACZ;AAEA,IAAA,MAAM,iBAAA,GAAoB,KAAK,YAAA,GAC3B;AAAA,MACE,OAAA;AAAA,MACA,MAAA,EAAQ,eAAA,CAAgB,IAAA,CAAK,YAAY,CAAA;AAAA,MACzC,YAAYA,cAAA,CAAW,OAAA;AAAA,MACvB,QAAA,EAAU;AAAA,KACZ,GACA,MAAA;AAEJ,IAAA,MAAM,UAAA,GAAa,sBAAA,CAAuB,IAAA,EAAM,UAAU,CAAA;AAE1D,IAAA,MAAM,QAAgB,EAAC;AAEvB,IAAA,MAAM,QAAA,GAAyB;AAAA,MAC7B,IAAA;AAAA,MACA,IAAA;AAAA,MACA,aAAa,MAAM,WAAA;AAAA,MACnB,iBAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,MACA,KAAA,EAAO,IAAA;AAAA,MACP,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,sBAAsB,IAAA,CAAK,KAAA;AAAA,MAC3B,sBAAA,EAAwB,CAAA;AAAA,MACxB,kBAAA,EAAoB,CAAA;AAAA,MACpB,iBAAA,EAAmB;AAAA,KACrB;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,MAAc,aAAA,GAA+B;AAC3C,IAAA,IAAI,IAAA,CAAK,OAAA,IAAW,CAAC,IAAA,CAAK,MAAA,EAAQ;AAChC,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,QAAA,GAAW,IAAIC,wCAAA,CAAkB;AAAA,MACpC,GAAA,EAAK,KAAK,MAAA,CAAO,QAAA;AAAA,MACjB,OAAA,EAAS,KAAK,MAAA,CAAO,OAAA;AAAA,MACrB,aAAA,EAAe,KAAK,MAAA,CAAO;AAAA,KAC5B,CAAA;AAED,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,YAAA,GACzB,IAAIC,gCAAA,CAAoB,IAAA,CAAK,QAAQ,CAAA,GACrC,IAAIC,+BAAA,CAAmB,IAAA,CAAK,QAAA,EAAU;AAAA,MACpC,kBAAA,EAAoB,KAAK,MAAA,CAAO,SAAA;AAAA,MAChC,mBAAA,EAAqB,KAAK,MAAA,CAAO;AAAA,KAClC,CAAA;AAEL,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAAA,EACjB;AAAA,EAEA,MAAM,gBAAA,CAAiB;AAAA,IACrB,OAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF,EAOkB;AAChB,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAElB,IAAA,MAAM,OAAA,GAAmC;AAAA,MACvC,IAAA,EAAM,UAAA;AAAA,MACN,KAAA;AAAA,MACA,MAAA,EAAQ,MAAA;AAAA,MACR,QAAA,EAAU,EAAE,GAAI,QAAA,IAAY,EAAC,EAAI,GAAI,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAC;AAAG,KACjE;AAEA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAA,CAAQ,MAAA,GAAS,iBAAiB,MAAM,CAAA;AAAA,IAC1C,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,OAAA,GAAU,kBAAkB,OAAO,CAAA;AAAA,IAC7C;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,YAAA,GAAuC;AAAA,QAC3C,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,CAAA;AAAA,QAC3C,cAAA,EAAgB;AAAA,OAClB;AAEA,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,mBAAmB,IAAA,CAAK,MAAA,CAAO,OAAO,CAAC,CAAA,oBAAA,CAAA,EAAwB;AAAA,QAC7F,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,YAAA;AAAA,QACT,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,OAC7B,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,IAAA,CAAK,MAAA,CAAO,KAAK,wDAAA,EAA0D;AAAA,UACzE,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,YAAY,QAAA,CAAS,UAAA;AAAA,UACrB,OAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,uDAAA,EAAyD;AAAA,QACzE,KAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,GAA0B;AAC9B,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,IACjC,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,MAAA,MAAM,MAAM,QAAA,EAAS;AAAA,IACvB;AAAA,EACF;AACF;AAEA,SAAS,sBAAA,CAAuB,MAAuB,UAAA,EAAoC;AACzF,EAAA,MAAM,aAAyB,EAAC;AAEhC,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,YAAA,CAAa,GAAA,CAAI,KAAK,EAAE,CAAA;AACpD,EAAA,MAAM,WAAA,GAAc,UAAA,CAAW,eAAA,CAAgB,GAAA,CAAI,KAAK,EAAE,CAAA;AAE1D,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,UAAA,CAAW,cAAc,CAAA,GAAI,QAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,UAAA,CAAW,kBAAkB,CAAA,GAAI,WAAA;AAAA,EACnC;AAEA,EAAA,UAAA,CAAW,cAAc,CAAA,GAAI,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAA;AACzD,EAAA,UAAA,CAAW,gCAAgC,CAAA,GAAI,YAAA;AAG/C,EAAA,UAAA,CAAW,qBAAqB,CAAA,GAAI,SAAA;AACpC,EAAA,UAAA,CAAW,0BAA0B,IAAI,OAAA,CAAQ,OAAA;AAGjD,EAAA,MAAM,SAAA,GAAY,KAAK,QAAA,EAAU,SAAA;AACjC,EAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,CAAU,SAAS,CAAA,EAAG;AACzD,IAAA,UAAA,CAAW,eAAe,CAAA,GAAI,SAAA;AAAA,EAChC;AAEA,EAAA,MAAM,MAAA,GAAS,KAAK,QAAA,EAAU,MAAA;AAC9B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,CAAO,SAAS,CAAA,EAAG;AACnD,IAAA,UAAA,CAAW,YAAY,CAAA,GAAI,MAAA;AAAA,EAC7B;AAIA,EAAA,IAAI,KAAK,QAAA,EAAU;AACjB,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,EAAG;AACxD,MAAA,IAAI,QAAQ,WAAA,IAAe,GAAA,KAAQ,YAAY,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,EAAM;AACpF,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,cAAA,GAAiB,wBAAwB,KAAK,CAAA;AACpD,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA;AAAA,MACF;AAEA,MAAA,UAAA,CAAW,CAAA,EAAG,uBAAuB,CAAA,UAAA,EAAa,GAAG,EAAE,CAAA,GAAI,cAAA;AAAA,IAC7D;AAAA,EACF;AAEA,EAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ;AACxC,IAAA,UAAA,CAAW,SAAS,IAAI,IAAA,CAAK,IAAA;AAAA,EAC/B;AAGA,EAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,IAAA,UAAA,CAAW,eAAe,CAAA,GAAI,mBAAA,CAAoB,mBAAA,CAAoB,IAAI,CAAC,CAAA;AAAA,EAC7E;AAEA,EAAA,IAAI,IAAA,CAAK,WAAW,MAAA,EAAW;AAC7B,IAAA,UAAA,CAAW,gBAAgB,CAAA,GAAI,mBAAA,CAAoB,IAAA,CAAK,MAAM,CAAA;AAAA,EAChE;AAEA,EAAA,IAAI,IAAA,CAAK,IAAA,KAASC,wBAAA,CAAS,gBAAA,EAAkB;AAC3C,IAAA,MAAM,UAAA,GAAc,IAAA,CAAK,UAAA,IAAc,EAAC;AAExC,IAAA,IAAI,WAAW,QAAA,EAAU;AACvB,MAAA,UAAA,CAAW,aAAa,CAAA,GAAI,iBAAA,CAAkB,UAAA,CAAW,QAAQ,CAAA;AAAA,IACnE;AAEA,IAAA,IAAI,WAAW,KAAA,EAAO;AACpB,MAAA,UAAA,CAAW,oBAAoB,IAAI,UAAA,CAAW,KAAA;AAAA,IAChD;AAEA,IAAA,IAAI,WAAW,aAAA,EAAe;AAC5B,MAAA,UAAA,CAAW,qBAAqB,IAAI,UAAA,CAAW,aAAA;AAAA,IACjD;AAEA,IAAA,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,kBAAA,CAAmB,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,EAChE;AAEA,EAAA,OAAO,UAAA;AACT;AAEA,SAAS,mBAAmB,QAAA,EAAqC;AAC/D,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAKA,wBAAA,CAAS,gBAAA;AAAA,IACd,KAAKA,wBAAA,CAAS,UAAA;AAAA,IACd,KAAKA,wBAAA,CAAS,WAAA;AACZ,MAAA,OAAO,KAAA;AAAA,IACT,KAAKA,wBAAA,CAAS,SAAA;AAAA,IACd,KAAKA,wBAAA,CAAS,aAAA;AACZ,MAAA,OAAO,MAAA;AAAA,IACT;AACE,MAAA,OAAO,SAAA;AAAA;AAEb;AAEA,SAAS,mBAAmB,KAAA,EAAgC;AAC1D,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AAEpB,EAAA,MAAM,MAAkB,EAAC;AAEzB,EAAA,IAAI,KAAA,CAAM,gBAAgB,MAAA,EAAW;AACnC,IAAA,GAAA,CAAI,yBAAyB,IAAI,KAAA,CAAM,WAAA;AAAA,EACzC;AAEA,EAAA,IAAI,KAAA,CAAM,iBAAiB,MAAA,EAAW;AACpC,IAAA,GAAA,CAAI,0BAA0B,IAAI,KAAA,CAAM,YAAA;AAAA,EAC1C;AAEA,EAAA,IAAI,KAAA,CAAM,YAAA,EAAc,UAAA,KAAe,MAAA,EAAW;AAChD,IAAA,GAAA,CAAI,+BAA+B,CAAA,GAAI,KAAA,CAAM,YAAA,CAAa,UAAA;AAAA,EAC5D;AAEA,EAAA,IAAI,KAAA,CAAM,YAAA,EAAc,SAAA,KAAc,MAAA,EAAW;AAC/C,IAAA,GAAA,CAAI,8BAA8B,CAAA,GAAI,KAAA,CAAM,YAAA,CAAa,SAAA;AAAA,EAC3D;AAEA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,oBAAoB,KAAA,EAAwB;AACnD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,kBAAA;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,IAAA,EAAgC;AAG3D,EAAA,IAAI,IAAA,CAAK,IAAA,KAASA,wBAAA,CAAS,gBAAA,EAAkB;AAC3C,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAEA,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,EAAA,IAAI,CAAC,SAAS,OAAO,KAAA,KAAU,YAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/D,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,gBAAiB,KAAA,CAAiC,QAAA;AACxD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,aAAa,CAAA,GAAI,aAAA,GAAgB,KAAA;AACxD;AAEA,SAAS,wBAAwB,KAAA,EAAgD;AAC/E,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,SAAA,EAAW;AACxF,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,MAAM,aAAA,GACJ,MAAM,KAAA,CAAM,CAAA,CAAA,KAAK,OAAO,CAAA,KAAM,QAAQ,KACtC,KAAA,CAAM,KAAA,CAAM,OAAK,OAAO,CAAA,KAAM,QAAQ,CAAA,IACtC,KAAA,CAAM,MAAM,CAAA,CAAA,KAAK,OAAO,MAAM,SAAS,CAAA;AACzC,IAAA,IAAI,eAAe,OAAO,KAAA;AAAA,EAC5B;AAEA,EAAA,OAAO,oBAAoB,KAAK,CAAA;AAClC;AAKA,SAAS,aAAa,IAAA,EAAoB;AACxC,EAAA,MAAM,EAAA,GAAK,KAAK,OAAA,EAAQ;AACxB,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,GAAI,CAAA;AACpC,EAAA,MAAM,WAAA,GAAe,KAAK,GAAA,GAAQ,GAAA;AAClC,EAAA,OAAO,CAAC,SAAS,WAAW,CAAA;AAC9B;AAEA,SAAS,eAAA,CAAgB,OAAa,GAAA,EAAoB;AACxD,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,CAAC,GAAG,CAAC,CAAA;AACtB,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,OAAA,EAAQ,GAAI,MAAM,OAAA,EAAQ;AAC7C,EAAA,OAAO,CAAC,KAAK,KAAA,CAAM,MAAA,GAAS,GAAI,CAAA,EAAI,MAAA,GAAS,MAAQ,GAAS,CAAA;AAChE;AAEA,SAAS,oBAAA,CACP,MACA,WAAA,EAC8C;AAC9C,EAAA,MAAM,SAAuB,EAAC;AAE9B,EAAA,IAAI,KAAK,SAAA,EAAW;AAClB,IAAA,MAAM,MAAA,GAAqB;AAAA,MACzB,MAAMC,kBAAA,CAAe,KAAA;AAAA,MACrB,OAAA,EAAS,KAAK,SAAA,CAAU;AAAA,KAC1B;AAEA,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,WAAA;AAAA,MACN,UAAA,EAAY;AAAA,QACV,mBAAA,EAAqB,KAAK,SAAA,CAAU,OAAA;AAAA,QACpC,gBAAA,EAAkB,OAAA;AAAA,QAClB,GAAI,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS,KAAA,IAAS;AAAA,UACnC,sBAAA,EAAwB,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ;AAAA;AACjD,OACF;AAAA,MACA,IAAA,EAAM,WAAA;AAAA,MACN,sBAAA,EAAwB;AAAA,KACzB,CAAA;AAED,IAAA,OAAO,EAAE,QAAQ,MAAA,EAAO;AAAA,EAC1B;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,EAAE,IAAA,EAAMA,kBAAA,CAAe,EAAA,EAAG;AAAA,IAClC;AAAA,GACF;AACF;AAEA,SAAS,YAAY,IAAA,EAA0B;AAC7C,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAKD,wBAAA,CAAS,gBAAA;AAAA,IACd,KAAKA,wBAAA,CAAS,aAAA;AACZ,MAAA,OAAOE,YAAA,CAAS,MAAA;AAAA,IAClB;AACE,MAAA,OAAOA,YAAA,CAAS,QAAA;AAAA;AAEtB;AAEA,SAAS,mBAAmB,GAAA,EAAqB;AAC/C,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AAChC;AAEA,SAAS,iBAAiB,OAAA,EAAyB;AACjD,EAAA,IAAI,EAAA,GAAK,QAAQ,WAAA,EAAY;AAC7B,EAAA,IAAI,GAAG,UAAA,CAAW,IAAI,GAAG,EAAA,GAAK,EAAA,CAAG,MAAM,CAAC,CAAA;AACxC,EAAA,OAAO,GAAG,QAAA,CAAS,EAAA,EAAI,GAAG,CAAA,CAAE,MAAM,GAAG,CAAA;AACvC;AAEA,SAAS,gBAAgB,MAAA,EAAwB;AAC/C,EAAA,IAAI,EAAA,GAAK,OAAO,WAAA,EAAY;AAC5B,EAAA,IAAI,GAAG,UAAA,CAAW,IAAI,GAAG,EAAA,GAAK,EAAA,CAAG,MAAM,CAAC,CAAA;AACxC,EAAA,OAAO,GAAG,QAAA,CAAS,EAAA,EAAI,GAAG,CAAA,CAAE,MAAM,GAAG,CAAA;AACvC;AAEO,SAAS,iBAAiB,MAAA,EAAwB;AACvD,EAAA,MAAM,UAAA,GAAa,gBAAgB,MAAM,CAAA;AACzC,EAAA,OAAO,WACJ,QAAA,CAAS,EAAA,EAAI,GAAG,CAAA,CAChB,OAAA,CAAQ,wEAAwE,gBAAgB,CAAA;AACrG;AAEO,SAAS,kBAAkB,OAAA,EAAyB;AACzD,EAAA,MAAM,UAAA,GAAa,iBAAiB,OAAO,CAAA;AAC3C,EAAA,OAAO,UAAA,CAAW,OAAA,CAAQ,sEAAA,EAAwE,gBAAgB,CAAA;AACpH;AAEA,SAAS,kBAAkB,QAAA,EAA0B;AACnD,EAAA,OAAO,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,KAAA,EAAM,EAAG,WAAA,EAAY,CAAE,IAAA,EAAK,IAAK,QAAA,CAAS,WAAA,GAAc,IAAA,EAAK;AAC1F","file":"index.cjs","sourcesContent":["/**\n * Laminar Exporter for Mastra Observability\n *\n * This exporter sends observability data to Laminar via OTLP/HTTP (protobuf).\n * It also implements addScoreToTrace() to attach scorer results in Laminar.\n */\n\nimport type {\n AnyExportedSpan,\n InitExporterOptions,\n ModelGenerationAttributes,\n TracingEvent,\n UsageStats,\n} from '@mastra/core/observability';\nimport { SpanType, TracingEventType } from '@mastra/core/observability';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport { SpanKind, SpanStatusCode, TraceFlags } from '@opentelemetry/api';\nimport type { Attributes, HrTime, Link, SpanContext, SpanStatus } from '@opentelemetry/api';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport type { Resource } from '@opentelemetry/resources';\nimport { BatchSpanProcessor, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport type { ReadableSpan, SpanExporter, TimedEvent } from '@opentelemetry/sdk-trace-base';\nimport {\n ATTR_SERVICE_NAME,\n ATTR_SERVICE_VERSION,\n ATTR_TELEMETRY_SDK_LANGUAGE,\n ATTR_TELEMETRY_SDK_NAME,\n ATTR_TELEMETRY_SDK_VERSION,\n} from '@opentelemetry/semantic-conventions';\n\n// Laminar span attributes\nconst LMNR_SPAN_INPUT = 'lmnr.span.input';\nconst LMNR_SPAN_OUTPUT = 'lmnr.span.output';\nconst LMNR_SPAN_TYPE = 'lmnr.span.type';\nconst LMNR_SPAN_PATH = 'lmnr.span.path';\nconst LMNR_SPAN_IDS_PATH = 'lmnr.span.ids_path';\nconst LMNR_SPAN_INSTRUMENTATION_SOURCE = 'lmnr.span.instrumentation_source';\nconst LMNR_SPAN_SDK_VERSION = 'lmnr.span.sdk_version';\nconst LMNR_SPAN_LANGUAGE_VERSION = 'lmnr.span.language_version';\n\nconst LMNR_ASSOCIATION_PREFIX = 'lmnr.association.properties';\nconst LMNR_SESSION_ID = `${LMNR_ASSOCIATION_PREFIX}.session_id`;\nconst LMNR_USER_ID = `${LMNR_ASSOCIATION_PREFIX}.user_id`;\nconst LMNR_TAGS = `${LMNR_ASSOCIATION_PREFIX}.tags`;\n\n// Laminar GenAI attributes (as used by Laminar backend)\nconst GEN_AI_SYSTEM = 'gen_ai.system';\nconst GEN_AI_REQUEST_MODEL = 'gen_ai.request.model';\nconst GEN_AI_RESPONSE_MODEL = 'gen_ai.response.model';\nconst GEN_AI_USAGE_INPUT_TOKENS = 'gen_ai.usage.input_tokens';\nconst GEN_AI_USAGE_OUTPUT_TOKENS = 'gen_ai.usage.output_tokens';\nconst GEN_AI_CACHE_WRITE_INPUT_TOKENS = 'gen_ai.usage.cache_creation_input_tokens';\nconst GEN_AI_CACHE_READ_INPUT_TOKENS = 'gen_ai.usage.cache_read_input_tokens';\n\ntype LaminarSpanType = 'DEFAULT' | 'LLM' | 'TOOL';\n\ntype TraceState = {\n spanPathById: Map<string, string[]>;\n spanIdsPathById: Map<string, string[]>;\n activeSpanIds: Set<string>;\n};\n\ntype InstrumentationScope = {\n name: string;\n version?: string;\n schemaUrl?: string;\n};\n\nexport interface LaminarExporterConfig extends BaseExporterConfig {\n /**\n * Laminar project API key. Defaults to `process.env.LMNR_PROJECT_API_KEY`.\n */\n apiKey?: string;\n /**\n * Base URL for Laminar APIs. Defaults to `process.env.LMNR_BASE_URL` or `https://api.lmnr.ai`.\n *\n * Used for:\n * - trace exports (if `endpoint`/`LAMINAR_ENDPOINT` are not set)\n * - evaluator scoring (`/v1/evaluators/score`)\n */\n baseUrl?: string;\n /**\n * Full OTLP/HTTP traces endpoint. Defaults to `process.env.LAMINAR_ENDPOINT` or `${baseUrl}/v1/traces`.\n */\n endpoint?: string;\n /**\n * Additional headers to include in OTLP requests.\n */\n headers?: Record<string, string>;\n /**\n * Flush after each span for near-realtime visibility.\n */\n realtime?: boolean;\n /**\n * Disable batching (uses SimpleSpanProcessor).\n */\n disableBatch?: boolean;\n /**\n * Max spans to export per batch (BatchSpanProcessor only).\n */\n batchSize?: number;\n /**\n * OTLP export timeout in milliseconds.\n */\n timeoutMillis?: number;\n}\n\ntype ResolvedLaminarConfig = Required<Pick<LaminarExporterConfig, 'realtime' | 'disableBatch' | 'batchSize'>> & {\n apiKey: string;\n baseUrl: string;\n endpoint: string;\n headers: Record<string, string>;\n timeoutMillis: number;\n};\n\nexport class LaminarExporter extends BaseExporter {\n name = 'laminar';\n\n private config: ResolvedLaminarConfig | null;\n private traceMap = new Map<string, TraceState>();\n\n private resource?: Resource;\n private scope?: InstrumentationScope;\n private processor?: BatchSpanProcessor | SimpleSpanProcessor;\n private exporter?: SpanExporter;\n private isSetup = false;\n\n constructor(config: LaminarExporterConfig = {}) {\n super(config);\n\n const apiKey = config.apiKey ?? process.env.LMNR_PROJECT_API_KEY;\n if (!apiKey) {\n this.setDisabled(\n 'Missing required API key. Set LMNR_PROJECT_API_KEY environment variable or pass apiKey in config.',\n );\n this.config = null;\n return;\n }\n\n const envEndpoint = process.env.LAMINAR_ENDPOINT;\n const baseUrl = stripTrailingSlash(config.baseUrl ?? process.env.LMNR_BASE_URL ?? 'https://api.lmnr.ai');\n const endpoint = config.endpoint ?? envEndpoint ?? `${baseUrl}/v1/traces`;\n\n const headers: Record<string, string> = {\n ...config.headers,\n Authorization: `Bearer ${apiKey}`,\n };\n\n this.config = {\n apiKey,\n baseUrl,\n endpoint,\n headers,\n realtime: config.realtime ?? false,\n disableBatch: config.disableBatch ?? false,\n batchSize: config.batchSize ?? 512,\n timeoutMillis: config.timeoutMillis ?? 30000,\n };\n }\n\n init(options: InitExporterOptions): void {\n // Build resource & scope lazily so we can include serviceName.\n const serviceName = options.config?.serviceName || 'mastra-service';\n\n this.resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: 'unknown',\n [ATTR_TELEMETRY_SDK_NAME]: '@mastra/laminar',\n [ATTR_TELEMETRY_SDK_VERSION]: 'unknown',\n [ATTR_TELEMETRY_SDK_LANGUAGE]: 'nodejs',\n });\n\n this.scope = {\n name: '@mastra/laminar',\n version: 'unknown',\n };\n }\n\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n // Track hierarchy on span start to build lmnr.span.path/ids_path for child spans.\n if (event.type === TracingEventType.SPAN_STARTED && !event.exportedSpan.isEvent) {\n this.handleSpanStarted(event.exportedSpan);\n return;\n }\n\n // Only export when the span is ended (including event spans).\n if (event.type !== TracingEventType.SPAN_ENDED) {\n return;\n }\n\n await this.handleSpanEnded(event.exportedSpan);\n }\n\n private handleSpanStarted(span: AnyExportedSpan): void {\n const traceState = this.getOrCreateTraceState(span.traceId);\n const name = span.name;\n\n const parentId = span.parentSpanId;\n const parentPath = parentId ? traceState.spanPathById.get(parentId) : undefined;\n const parentIdsPath = parentId ? traceState.spanIdsPathById.get(parentId) : undefined;\n\n const spanPath = parentPath ? [...parentPath, name] : [name];\n const spanIdsPath = parentIdsPath ? [...parentIdsPath, otelSpanIdToUUID(span.id)] : [otelSpanIdToUUID(span.id)];\n\n traceState.spanPathById.set(span.id, spanPath);\n traceState.spanIdsPathById.set(span.id, spanIdsPath);\n traceState.activeSpanIds.add(span.id);\n }\n\n private async handleSpanEnded(span: AnyExportedSpan): Promise<void> {\n if (!this.config) {\n return;\n }\n\n await this.setupIfNeeded();\n\n if (!this.processor || !this.exporter) {\n return;\n }\n\n const traceState = this.getOrCreateTraceState(span.traceId);\n\n // Ensure we have path data even for event spans (which never emit SPAN_STARTED).\n if (!traceState.spanPathById.has(span.id) || !traceState.spanIdsPathById.has(span.id)) {\n const name = span.name;\n const parentId = span.parentSpanId;\n const parentPath = parentId ? traceState.spanPathById.get(parentId) : undefined;\n const parentIdsPath = parentId ? traceState.spanIdsPathById.get(parentId) : undefined;\n\n const spanPath = parentPath ? [...parentPath, name] : [name];\n const spanIdsPath = parentIdsPath ? [...parentIdsPath, otelSpanIdToUUID(span.id)] : [otelSpanIdToUUID(span.id)];\n\n traceState.spanPathById.set(span.id, spanPath);\n traceState.spanIdsPathById.set(span.id, spanIdsPath);\n }\n\n try {\n const otelSpan = this.convertSpanToOtel(span, traceState);\n this.processor.onEnd(otelSpan);\n\n if (this.config.realtime) {\n await this.processor.forceFlush();\n }\n } catch (error) {\n this.logger.error('[LaminarExporter] Failed to export span', { error, spanId: span.id, traceId: span.traceId });\n } finally {\n // Refcount cleanup (non-event spans only; event spans never enter active set)\n traceState.activeSpanIds.delete(span.id);\n\n if (traceState.activeSpanIds.size === 0) {\n this.traceMap.delete(span.traceId);\n }\n }\n }\n\n private getOrCreateTraceState(traceId: string): TraceState {\n const existing = this.traceMap.get(traceId);\n if (existing) return existing;\n\n const created: TraceState = {\n spanPathById: new Map(),\n spanIdsPathById: new Map(),\n activeSpanIds: new Set(),\n };\n this.traceMap.set(traceId, created);\n return created;\n }\n\n private convertSpanToOtel(span: AnyExportedSpan, traceState: TraceState): ReadableSpan {\n if (!this.resource || !this.scope) {\n // init() is optional; fall back to defaults if it wasn't called for some reason.\n this.resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: 'mastra-service',\n [ATTR_SERVICE_VERSION]: 'unknown',\n [ATTR_TELEMETRY_SDK_NAME]: '@mastra/laminar',\n [ATTR_TELEMETRY_SDK_VERSION]: 'unknown',\n [ATTR_TELEMETRY_SDK_LANGUAGE]: 'nodejs',\n });\n this.scope = { name: '@mastra/laminar', version: 'unknown' };\n }\n\n const name = span.name;\n const kind = getSpanKind(span.type);\n\n const startTime = dateToHrTime(span.startTime);\n const endTime = span.endTime ? dateToHrTime(span.endTime) : startTime;\n const duration = computeDuration(span.startTime, span.endTime);\n\n const { status, events } = buildStatusAndEvents(span, startTime);\n\n const traceId = normalizeTraceId(span.traceId);\n const spanId = normalizeSpanId(span.id);\n\n const spanContext: SpanContext = {\n traceId,\n spanId,\n traceFlags: TraceFlags.SAMPLED,\n isRemote: false,\n };\n\n const parentSpanContext = span.parentSpanId\n ? {\n traceId,\n spanId: normalizeSpanId(span.parentSpanId),\n traceFlags: TraceFlags.SAMPLED,\n isRemote: false,\n }\n : undefined;\n\n const attributes = buildLaminarAttributes(span, traceState);\n\n const links: Link[] = [];\n\n const readable: ReadableSpan = {\n name,\n kind,\n spanContext: () => spanContext,\n parentSpanContext,\n startTime,\n endTime,\n status,\n attributes,\n links,\n events,\n duration,\n ended: true,\n resource: this.resource,\n instrumentationScope: this.scope,\n droppedAttributesCount: 0,\n droppedEventsCount: 0,\n droppedLinksCount: 0,\n };\n\n return readable;\n }\n\n private async setupIfNeeded(): Promise<void> {\n if (this.isSetup || !this.config) {\n return;\n }\n\n this.exporter = new OTLPTraceExporter({\n url: this.config.endpoint,\n headers: this.config.headers,\n timeoutMillis: this.config.timeoutMillis,\n });\n\n this.processor = this.config.disableBatch\n ? new SimpleSpanProcessor(this.exporter)\n : new BatchSpanProcessor(this.exporter, {\n maxExportBatchSize: this.config.batchSize,\n exportTimeoutMillis: this.config.timeoutMillis,\n });\n\n this.isSetup = true;\n }\n\n async _addScoreToTrace({\n traceId,\n spanId,\n score,\n reason,\n scorerName,\n metadata,\n }: {\n traceId: string;\n spanId?: string;\n score: number;\n reason?: string;\n scorerName: string;\n metadata?: Record<string, any>;\n }): Promise<void> {\n if (!this.config) return;\n\n const payload: Record<string, unknown> = {\n name: scorerName,\n score,\n source: 'Code',\n metadata: { ...(metadata ?? {}), ...(reason ? { reason } : {}) },\n };\n\n if (spanId) {\n payload.spanId = otelSpanIdToUUID(spanId);\n } else {\n payload.traceId = otelTraceIdToUUID(traceId);\n }\n\n try {\n const scoreHeaders: Record<string, string> = {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'content-type': 'application/json',\n };\n\n const response = await fetch(`${stripTrailingSlash(this.config.baseUrl)}/v1/evaluators/score`, {\n method: 'POST',\n headers: scoreHeaders,\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n this.logger.warn('[LaminarExporter] Failed to attach score to trace/span', {\n status: response.status,\n statusText: response.statusText,\n traceId,\n spanId,\n scorerName,\n });\n }\n } catch (error) {\n this.logger.error('[LaminarExporter] Error attaching score to trace/span', {\n error,\n traceId,\n spanId,\n scorerName,\n });\n }\n }\n\n async shutdown(): Promise<void> {\n try {\n await this.processor?.shutdown();\n } finally {\n this.traceMap.clear();\n await super.shutdown();\n }\n }\n}\n\nfunction buildLaminarAttributes(span: AnyExportedSpan, traceState: TraceState): Attributes {\n const attributes: Attributes = {};\n\n const spanPath = traceState.spanPathById.get(span.id);\n const spanIdsPath = traceState.spanIdsPathById.get(span.id);\n\n if (spanPath) {\n attributes[LMNR_SPAN_PATH] = spanPath;\n }\n\n if (spanIdsPath) {\n attributes[LMNR_SPAN_IDS_PATH] = spanIdsPath;\n }\n\n attributes[LMNR_SPAN_TYPE] = mapLaminarSpanType(span.type);\n attributes[LMNR_SPAN_INSTRUMENTATION_SOURCE] = 'javascript';\n\n // These attributes are optional in Laminar, but helpful for debugging.\n attributes[LMNR_SPAN_SDK_VERSION] = 'unknown';\n attributes[LMNR_SPAN_LANGUAGE_VERSION] = process.version;\n\n // Association properties\n const sessionId = span.metadata?.sessionId;\n if (typeof sessionId === 'string' && sessionId.length > 0) {\n attributes[LMNR_SESSION_ID] = sessionId;\n }\n\n const userId = span.metadata?.userId;\n if (typeof userId === 'string' && userId.length > 0) {\n attributes[LMNR_USER_ID] = userId;\n }\n\n // Attach Mastra metadata as Laminar trace/span metadata (best-effort, scalar/array-only)\n // Laminar treats `lmnr.association.properties.metadata.*` as freeform metadata.\n if (span.metadata) {\n for (const [key, value] of Object.entries(span.metadata)) {\n if (key === 'sessionId' || key === 'userId' || value === undefined || value === null) {\n continue;\n }\n\n const attributeValue = toLaminarAttributeValue(value);\n if (attributeValue === undefined) {\n continue;\n }\n\n attributes[`${LMNR_ASSOCIATION_PREFIX}.metadata.${key}`] = attributeValue;\n }\n }\n\n if (span.isRootSpan && span.tags?.length) {\n attributes[LMNR_TAGS] = span.tags;\n }\n\n // Span input/output (Laminar prefers these over gen_ai.* / other conventions)\n if (span.input !== undefined) {\n attributes[LMNR_SPAN_INPUT] = serializeForLaminar(getLaminarSpanInput(span));\n }\n\n if (span.output !== undefined) {\n attributes[LMNR_SPAN_OUTPUT] = serializeForLaminar(span.output);\n }\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n if (modelAttrs.provider) {\n attributes[GEN_AI_SYSTEM] = normalizeProvider(modelAttrs.provider);\n }\n\n if (modelAttrs.model) {\n attributes[GEN_AI_REQUEST_MODEL] = modelAttrs.model;\n }\n\n if (modelAttrs.responseModel) {\n attributes[GEN_AI_RESPONSE_MODEL] = modelAttrs.responseModel;\n }\n\n Object.assign(attributes, formatLaminarUsage(modelAttrs.usage));\n }\n\n return attributes;\n}\n\nfunction mapLaminarSpanType(spanType: SpanType): LaminarSpanType {\n switch (spanType) {\n case SpanType.MODEL_GENERATION:\n case SpanType.MODEL_STEP:\n case SpanType.MODEL_CHUNK:\n return 'LLM';\n case SpanType.TOOL_CALL:\n case SpanType.MCP_TOOL_CALL:\n return 'TOOL';\n default:\n return 'DEFAULT';\n }\n}\n\nfunction formatLaminarUsage(usage?: UsageStats): Attributes {\n if (!usage) return {};\n\n const out: Attributes = {};\n\n if (usage.inputTokens !== undefined) {\n out[GEN_AI_USAGE_INPUT_TOKENS] = usage.inputTokens;\n }\n\n if (usage.outputTokens !== undefined) {\n out[GEN_AI_USAGE_OUTPUT_TOKENS] = usage.outputTokens;\n }\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n out[GEN_AI_CACHE_WRITE_INPUT_TOKENS] = usage.inputDetails.cacheWrite;\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n out[GEN_AI_CACHE_READ_INPUT_TOKENS] = usage.inputDetails.cacheRead;\n }\n\n return out;\n}\n\nfunction serializeForLaminar(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n\nfunction getLaminarSpanInput(span: AnyExportedSpan): unknown {\n // Mastra MODEL_GENERATION spans commonly use `{ messages, ... }` as input.\n // Laminar can render rich chat views when `lmnr.span.input` is a message list.\n if (span.type !== SpanType.MODEL_GENERATION) {\n return span.input;\n }\n\n const input = span.input;\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n return input;\n }\n\n const maybeMessages = (input as { messages?: unknown }).messages;\n return Array.isArray(maybeMessages) ? maybeMessages : input;\n}\n\nfunction toLaminarAttributeValue(value: unknown): Attributes[string] | undefined {\n if (value === undefined || value === null) {\n return undefined;\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n\n if (Array.isArray(value)) {\n const isHomogeneous =\n value.every(v => typeof v === 'string') ||\n value.every(v => typeof v === 'number') ||\n value.every(v => typeof v === 'boolean');\n if (isHomogeneous) return value;\n }\n\n return serializeForLaminar(value);\n}\n\n/**\n * Convert JavaScript Date to hrtime format\n */\nfunction dateToHrTime(date: Date): HrTime {\n const ms = date.getTime();\n const seconds = Math.floor(ms / 1000);\n const nanoseconds = (ms % 1000) * 1_000_000;\n return [seconds, nanoseconds];\n}\n\nfunction computeDuration(start: Date, end?: Date): HrTime {\n if (!end) return [0, 0];\n const diffMs = end.getTime() - start.getTime();\n return [Math.floor(diffMs / 1000), (diffMs % 1000) * 1_000_000];\n}\n\nfunction buildStatusAndEvents(\n span: AnyExportedSpan,\n defaultTime: HrTime,\n): { status: SpanStatus; events: TimedEvent[] } {\n const events: TimedEvent[] = [];\n\n if (span.errorInfo) {\n const status: SpanStatus = {\n code: SpanStatusCode.ERROR,\n message: span.errorInfo.message,\n };\n\n events.push({\n name: 'exception',\n attributes: {\n 'exception.message': span.errorInfo.message,\n 'exception.type': 'Error',\n ...(span.errorInfo.details?.stack && {\n 'exception.stacktrace': span.errorInfo.details.stack as string,\n }),\n },\n time: defaultTime,\n droppedAttributesCount: 0,\n });\n\n return { status, events };\n }\n\n return {\n status: { code: SpanStatusCode.OK },\n events,\n };\n}\n\nfunction getSpanKind(type: SpanType): SpanKind {\n switch (type) {\n case SpanType.MODEL_GENERATION:\n case SpanType.MCP_TOOL_CALL:\n return SpanKind.CLIENT;\n default:\n return SpanKind.INTERNAL;\n }\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/g, '');\n}\n\nfunction normalizeTraceId(traceId: string): string {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) id = id.slice(2);\n return id.padStart(32, '0').slice(-32);\n}\n\nfunction normalizeSpanId(spanId: string): string {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) id = id.slice(2);\n return id.padStart(16, '0').slice(-16);\n}\n\nexport function otelSpanIdToUUID(spanId: string): string {\n const normalized = normalizeSpanId(spanId);\n return normalized\n .padStart(32, '0')\n .replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, '$1-$2-$3-$4-$5');\n}\n\nexport function otelTraceIdToUUID(traceId: string): string {\n const normalized = normalizeTraceId(traceId);\n return normalized.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, '$1-$2-$3-$4-$5');\n}\n\nfunction normalizeProvider(provider: string): string {\n return provider.split('.').shift()?.toLowerCase().trim() || provider.toLowerCase().trim();\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Laminar Observability Provider for Mastra
|
|
3
|
+
*
|
|
4
|
+
* This package provides Laminar-specific observability features for Mastra applications.
|
|
5
|
+
* Currently includes tracing + score export.
|
|
6
|
+
*/
|
|
7
|
+
export * from './tracing.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,WAAW,CAAC"}
|