@dbx-tools/appkit-mastra 0.9.38 → 0.9.43

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.
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Copy each Mastra chat turn's request/response onto its OTel root span
3
+ * so Databricks-managed MLflow can display them.
4
+ *
5
+ * Why this exists: MLflow's UC `<target>_trace_unified` view picks the
6
+ * one span whose `parent_span_id` is empty and reads request/response
7
+ * from `mlflow.spanInputs` / `mlflow.spanOutputs` (or the `gen_ai.*`
8
+ * equivalents) on THAT span only. Mastra records the turn on its
9
+ * `invoke_agent` child under `mastra.agent_run.input` / `.output`, keys
10
+ * the view never reads, so chat traces arrive with both columns null
11
+ * even when the spans themselves look healthy.
12
+ *
13
+ * AppKit's HTTP instrumentation records the server span in OTel RPC metadata,
14
+ * which remains available even when Express makes a middleware-layer child
15
+ * active. When instrumentation is unavailable, this module creates one
16
+ * request-lifetime server span and runs Mastra under it.
17
+ *
18
+ * @module
19
+ */
20
+ import { StringDecoder } from "node:string_decoder";
21
+ import { json, log, object } from "@dbx-tools/shared-core";
22
+ import { context, SpanKind, trace } from "@opentelemetry/api";
23
+ import { getRPCMetadata, RPCType } from "@opentelemetry/core";
24
+ const logger = log.logger("mastra/telemetry");
25
+ /** Cap on each payload copied onto a span, so one turn cannot bloat the export. */
26
+ export const TRACE_IO_LIMIT = 8_000;
27
+ /** Bound for a non-streaming body captured through `res.end` instead of `res.json`. */
28
+ const RESPONSE_BODY_LIMIT = TRACE_IO_LIMIT * 4;
29
+ /** Tracer scope used only when AppKit did not create a recording HTTP span. */
30
+ const CHAT_TURN_TRACER = "@dbx-tools/appkit-mastra/telemetry";
31
+ /**
32
+ * Mount-relative Mastra agent invoke paths that carry a chat turn body
33
+ * (`messages`) and stream an assistant answer. Resume / approve verbs
34
+ * are intentionally excluded: their bodies are tool decisions, not the
35
+ * user prompt, and they rarely produce a fresh answer worth surfacing.
36
+ */
37
+ const AGENT_TURN_ROUTE = /^(?:\/agents\/[^/]+\/(?:stream|generate)(?:\/|$)|\/chat\/[^/]+$)/i;
38
+ /** Attribute keys the MLflow UC `*_trace_unified` view reads from the root span. */
39
+ export const MLFLOW_SPAN_INPUTS_ATTR = "mlflow.spanInputs";
40
+ /** Root-span attribute consumed as chat output by MLflow unified trace views. */
41
+ export const MLFLOW_SPAN_OUTPUTS_ATTR = "mlflow.spanOutputs";
42
+ /** Full serialized request messages retained when the MLflow preview is plain text. */
43
+ export const CHAT_MESSAGES_ATTR = "appkit.mastra.chat.messages";
44
+ /** Full serialized response retained when the MLflow preview is plain text. */
45
+ export const CHAT_RESPONSE_ATTR = "appkit.mastra.chat.response";
46
+ /** Credential mode used by Databricks calls in this chat turn. */
47
+ export const CHAT_IDENTITY_ATTR = "appkit.mastra.identity.mode";
48
+ /** Whether the streamed turn emitted a Genie tool or progress event. */
49
+ export const CHAT_GENIE_USED_ATTR = "appkit.mastra.genie.used";
50
+ /** Return one raw prompt when the request is exactly one text-only user message. */
51
+ export function textOnlyChatInput(messages) {
52
+ if (typeof messages === "string")
53
+ return messages || undefined;
54
+ if (!Array.isArray(messages) || messages.length !== 1)
55
+ return undefined;
56
+ const message = messages[0];
57
+ if (!object.isRecord(message) || message.role !== "user")
58
+ return undefined;
59
+ if (typeof message.content === "string")
60
+ return message.content || undefined;
61
+ return textFromParts(message.parts) ?? textFromParts(message.content);
62
+ }
63
+ function textFromParts(value) {
64
+ if (!Array.isArray(value) || value.length === 0)
65
+ return undefined;
66
+ const text = [];
67
+ for (const part of value) {
68
+ if (!object.isRecord(part) || part.type !== "text" || typeof part.text !== "string") {
69
+ return undefined;
70
+ }
71
+ text.push(part.text);
72
+ }
73
+ const joined = text.join("");
74
+ return joined || undefined;
75
+ }
76
+ function serialized(value, limit = TRACE_IO_LIMIT) {
77
+ return JSON.stringify(value)?.slice(0, limit) ?? String(value).slice(0, limit);
78
+ }
79
+ function sseFrame(line) {
80
+ if (!line.startsWith("data:"))
81
+ return undefined;
82
+ return json.parse(line.slice(5));
83
+ }
84
+ function valueUsesGenie(value, depth = 0) {
85
+ if (depth > 3)
86
+ return false;
87
+ if (Array.isArray(value))
88
+ return value.some((item) => valueUsesGenie(item, depth + 1));
89
+ if (!object.isRecord(value))
90
+ return false;
91
+ if (value.type === "data-genie-progress" ||
92
+ value.type === "ask_genie_done" ||
93
+ value.toolName === "ask_genie" ||
94
+ value.tool_name === "ask_genie" ||
95
+ value.name === "ask_genie") {
96
+ return true;
97
+ }
98
+ return ["data", "event", "payload"].some((key) => valueUsesGenie(value[key], depth + 1));
99
+ }
100
+ /** Return the assistant text from one SSE line, or an empty string. */
101
+ function assistantTextFromSseLine(line) {
102
+ return assistantTextFromSseFrame(sseFrame(line));
103
+ }
104
+ function assistantTextFromSseFrame(frame) {
105
+ if (!object.isRecord(frame) || frame.type !== "text-delta")
106
+ return "";
107
+ const text = typeof frame.delta === "string"
108
+ ? frame.delta
109
+ : object.isRecord(frame.payload)
110
+ ? frame.payload.text
111
+ : undefined;
112
+ return typeof text === "string" ? text : "";
113
+ }
114
+ /**
115
+ * Concatenate the assistant's answer out of an AI SDK SSE transcript.
116
+ *
117
+ * The agent streams its reply as `text-delta` frames
118
+ * (`data: {"type":"text-delta","payload":{"text":"..."}}`), so the full
119
+ * answer only ever exists as deltas on the wire and has to be
120
+ * reassembled here.
121
+ */
122
+ export function assistantTextFromSse(body) {
123
+ const parts = [];
124
+ for (const line of body.split("\n")) {
125
+ const text = assistantTextFromSseLine(line);
126
+ if (text)
127
+ parts.push(text);
128
+ }
129
+ return parts.join("").slice(0, TRACE_IO_LIMIT);
130
+ }
131
+ /** Read the final assistant text from a non-streaming Mastra response. */
132
+ export function assistantTextFromJson(body) {
133
+ if (!object.isRecord(body) || typeof body.text !== "string")
134
+ return "";
135
+ return body.text.slice(0, TRACE_IO_LIMIT);
136
+ }
137
+ /** Incrementally assemble UTF-8 SSE text while retaining a bounded JSON fallback. */
138
+ class AssistantResponseCollector {
139
+ decoder = new StringDecoder("utf8");
140
+ answer = "";
141
+ body = "";
142
+ pendingLine = "";
143
+ finished = false;
144
+ genie = false;
145
+ write(chunk) {
146
+ if (this.finished)
147
+ return;
148
+ if (typeof chunk === "string") {
149
+ this.consume(chunk);
150
+ return;
151
+ }
152
+ if (ArrayBuffer.isView(chunk)) {
153
+ this.consume(this.decoder.write(Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)));
154
+ }
155
+ }
156
+ finish() {
157
+ if (this.finished)
158
+ return this.answer || this.jsonAnswer();
159
+ this.finished = true;
160
+ this.consume(this.decoder.end());
161
+ this.consumeSseLine(this.pendingLine);
162
+ this.pendingLine = "";
163
+ return this.answer || this.jsonAnswer();
164
+ }
165
+ rawBody() {
166
+ return this.body.slice(0, TRACE_IO_LIMIT);
167
+ }
168
+ usedGenie() {
169
+ return this.genie;
170
+ }
171
+ consume(text) {
172
+ if (!text)
173
+ return;
174
+ if (this.body.length < RESPONSE_BODY_LIMIT) {
175
+ this.body += text.slice(0, RESPONSE_BODY_LIMIT - this.body.length);
176
+ }
177
+ this.pendingLine += text;
178
+ let newline = this.pendingLine.indexOf("\n");
179
+ while (newline >= 0) {
180
+ this.consumeSseLine(this.pendingLine.slice(0, newline).replace(/\r$/, ""));
181
+ this.pendingLine = this.pendingLine.slice(newline + 1);
182
+ newline = this.pendingLine.indexOf("\n");
183
+ }
184
+ if (this.pendingLine.length > RESPONSE_BODY_LIMIT) {
185
+ this.pendingLine = this.pendingLine.slice(-RESPONSE_BODY_LIMIT);
186
+ }
187
+ }
188
+ consumeSseLine(line) {
189
+ const frame = sseFrame(line);
190
+ this.genie ||= valueUsesGenie(frame);
191
+ if (this.answer.length >= TRACE_IO_LIMIT)
192
+ return;
193
+ const text = assistantTextFromSseFrame(frame);
194
+ this.answer += text.slice(0, TRACE_IO_LIMIT - this.answer.length);
195
+ }
196
+ jsonAnswer() {
197
+ return assistantTextFromJson(json.parse(this.body));
198
+ }
199
+ }
200
+ /**
201
+ * Select the span MLflow treats as the request root.
202
+ *
203
+ * OTel HTTP instrumentation stores its server span in RPC metadata. That span
204
+ * wins over an active Express child. If no recording local span exists, create
205
+ * one under the current context so enabled W3C propagation remains intact.
206
+ */
207
+ function resolveTraceTarget() {
208
+ const activeContext = context.active();
209
+ const rpc = getRPCMetadata(activeContext);
210
+ if (rpc?.type === RPCType.HTTP && rpc.span.isRecording()) {
211
+ return { span: rpc.span, owned: false };
212
+ }
213
+ const active = trace.getActiveSpan();
214
+ if (active?.isRecording())
215
+ return { span: active, owned: false };
216
+ const span = trace
217
+ .getTracer(CHAT_TURN_TRACER)
218
+ .startSpan("mastra.chat_turn", { kind: SpanKind.SERVER }, activeContext);
219
+ if (!span.isRecording()) {
220
+ span.end();
221
+ return undefined;
222
+ }
223
+ return { span, owned: true };
224
+ }
225
+ /**
226
+ * Express middleware that stamps chat turn I/O onto the exported OTel root.
227
+ *
228
+ * Tee `res.write`, `res.json`, and `res.end` instead of listening for `finish`:
229
+ * HTTP instrumentation ends its server span on finish, and attributes set
230
+ * after a span ends never reach the exporter.
231
+ *
232
+ * `path` is mount-relative (what the Mastra sub-app sees), e.g.
233
+ * `/agents/support/stream`.
234
+ */
235
+ export function chatTurnTelemetryMiddleware(req, res, next, options = {}) {
236
+ if (req.method !== "POST" || !AGENT_TURN_ROUTE.test(req.path)) {
237
+ next();
238
+ return;
239
+ }
240
+ const target = resolveTraceTarget();
241
+ if (!target) {
242
+ next();
243
+ return;
244
+ }
245
+ const identity = typeof options.identity === "function" ? options.identity(req) : options.identity;
246
+ if (identity) {
247
+ target.span.setAttribute(CHAT_IDENTITY_ATTR, identity);
248
+ }
249
+ target.span.setAttribute(CHAT_GENIE_USED_ATTR, false);
250
+ const messages = req.body?.messages;
251
+ if (messages !== undefined) {
252
+ const fullInput = serialized(messages);
253
+ target.span.setAttribute(CHAT_MESSAGES_ATTR, fullInput);
254
+ target.span.setAttribute(MLFLOW_SPAN_INPUTS_ATTR, (textOnlyChatInput(messages) ?? fullInput).slice(0, TRACE_IO_LIMIT));
255
+ }
256
+ const collector = new AssistantResponseCollector();
257
+ let outputRecorded = false;
258
+ let fullOutputRecorded = false;
259
+ let ownedSpanEnded = false;
260
+ const passThroughWrite = res.write.bind(res);
261
+ const passThroughEnd = res.end.bind(res);
262
+ const passThroughJson = res.json.bind(res);
263
+ const recordOutput = (answer) => {
264
+ if (outputRecorded || !answer)
265
+ return;
266
+ target.span.setAttribute(MLFLOW_SPAN_OUTPUTS_ATTR, answer.slice(0, TRACE_IO_LIMIT));
267
+ outputRecorded = true;
268
+ };
269
+ const recordFullOutput = (response) => {
270
+ if (fullOutputRecorded || !response)
271
+ return;
272
+ target.span.setAttribute(CHAT_RESPONSE_ATTR, response.slice(0, TRACE_IO_LIMIT));
273
+ fullOutputRecorded = true;
274
+ };
275
+ const recordGenie = (used) => {
276
+ if (used)
277
+ target.span.setAttribute(CHAT_GENIE_USED_ATTR, true);
278
+ };
279
+ const endOwnedSpan = () => {
280
+ if (!target.owned || ownedSpanEnded)
281
+ return;
282
+ ownedSpanEnded = true;
283
+ target.span.end();
284
+ };
285
+ res.write = ((chunk, ...rest) => {
286
+ collector.write(chunk);
287
+ return passThroughWrite(chunk, ...rest);
288
+ });
289
+ res.json = ((body) => {
290
+ recordFullOutput(serialized(body));
291
+ recordGenie(valueUsesGenie(body));
292
+ recordOutput(assistantTextFromJson(body));
293
+ return passThroughJson(body);
294
+ });
295
+ res.end = ((chunk, ...rest) => {
296
+ collector.write(chunk);
297
+ recordOutput(collector.finish());
298
+ recordFullOutput(collector.rawBody());
299
+ recordGenie(collector.usedGenie());
300
+ try {
301
+ return passThroughEnd(chunk, ...rest);
302
+ }
303
+ finally {
304
+ endOwnedSpan();
305
+ }
306
+ });
307
+ res.once("close", () => {
308
+ recordOutput(collector.finish());
309
+ recordFullOutput(collector.rawBody());
310
+ recordGenie(collector.usedGenie());
311
+ endOwnedSpan();
312
+ });
313
+ context.with(trace.setSpan(context.active(), target.span), next);
314
+ }
315
+ /**
316
+ * Install {@link chatTurnTelemetryMiddleware} on a Mastra Express sub-app.
317
+ *
318
+ * Call before `MastraServer.init()` so the layer sits ahead of the agent
319
+ * routes. Safe to call unconditionally: when no recording tracer is registered,
320
+ * the middleware is a no-op.
321
+ */
322
+ export function attachChatTurnTelemetry(app, options = {}) {
323
+ app.use((req, res, next) => chatTurnTelemetryMiddleware(req, res, next, options));
324
+ logger.info("chat turn telemetry middleware attached", options);
325
+ }
326
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVsZW1ldHJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RlbGVtZXRyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBRUgsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXBELE9BQU8sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzNELE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBYSxNQUFNLG9CQUFvQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxjQUFjLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFHOUQsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0FBRTlDLG1GQUFtRjtBQUNuRixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsS0FBSyxDQUFDO0FBRXBDLHVGQUF1RjtBQUN2RixNQUFNLG1CQUFtQixHQUFHLGNBQWMsR0FBRyxDQUFDLENBQUM7QUFFL0MsK0VBQStFO0FBQy9FLE1BQU0sZ0JBQWdCLEdBQUcsb0NBQW9DLENBQUM7QUFFOUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLGdCQUFnQixHQUFHLG1FQUFtRSxDQUFDO0FBRTdGLG9GQUFvRjtBQUNwRixNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxtQkFBbUIsQ0FBQztBQUMzRCxpRkFBaUY7QUFDakYsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsb0JBQW9CLENBQUM7QUFDN0QsdUZBQXVGO0FBQ3ZGLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLDZCQUE2QixDQUFDO0FBQ2hFLCtFQUErRTtBQUMvRSxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyw2QkFBNkIsQ0FBQztBQUNoRSxrRUFBa0U7QUFDbEUsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdB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Q25DLElBQUksQ0FBQztZQUNILE9BQU8sY0FBYyxDQUFDLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO1FBQ3hDLENBQUM7Z0JBQVMsQ0FBQztZQUNULFlBQVksRUFBRSxDQUFDO1FBQ2pCLENBQUM7SUFDSCxDQUFDLENBQW1CLENBQUM7SUFFckIsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO1FBQ3JCLFlBQVksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUNqQyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUN0QyxXQUFXLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDbkMsWUFBWSxFQUFFLENBQUM7SUFDakIsQ0FBQyxDQUFDLENBQUM7SUFFSCxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUNuRSxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLHVCQUF1QixDQUNyQyxHQUFvQixFQUNwQixVQUFvQyxFQUFFO0lBRXRDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsMkJBQTJCLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUNsRixNQUFNLENBQUMsSUFBSSxDQUFDLHlDQUF5QyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQ2xFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHkgZWFjaCBNYXN0cmEgY2hhdCB0dXJuJ3MgcmVxdWVzdC9yZXNwb25zZSBvbnRvIGl0cyBPVGVsIHJvb3Qgc3BhblxuICogc28gRGF0YWJyaWNrcy1tYW5hZ2VkIE1MZmxvdyBjYW4gZGlzcGxheSB0aGVtLlxuICpcbiAqIFdoeSB0aGlzIGV4aXN0czogTUxmbG93J3MgVUMgYDx0YXJnZXQ+X3RyYWNlX3VuaWZpZWRgIHZpZXcgcGlja3MgdGhlXG4gKiBvbmUgc3BhbiB3aG9zZSBgcGFyZW50X3NwYW5faWRgIGlzIGVtcHR5IGFuZCByZWFkcyByZXF1ZXN0L3Jlc3BvbnNlXG4gKiBmcm9tIGBtbGZsb3cuc3BhbklucHV0c2AgLyBgbWxmbG93LnNwYW5PdXRwdXRzYCAob3IgdGhlIGBnZW5fYWkuKmBcbiAqIGVxdWl2YWxlbnRzKSBvbiBUSEFUIHNwYW4gb25seS4gTWFzdHJhIHJlY29yZHMgdGhlIHR1cm4gb24gaXRzXG4gKiBgaW52b2tlX2FnZW50YCBjaGlsZCB1bmRlciBgbWFzdHJhLmFnZW50X3J1bi5pbnB1dGAgLyBgLm91dHB1dGAsIGtleXNcbiAqIHRoZSB2aWV3IG5ldmVyIHJlYWRzLCBzbyBjaGF0IHRyYWNlcyBhcnJpdmUgd2l0aCBib3RoIGNvbHVtbnMgbnVsbFxuICogZXZlbiB3aGVuIHRoZSBzcGFucyB0aGVtc2VsdmVzIGxvb2sgaGVhbHRoeS5cbiAqXG4gKiBBcHBLaXQncyBIVFRQIGluc3RydW1lbnRhdGlvbiByZWNvcmRzIHRoZSBzZXJ2ZXIgc3BhbiBpbiBPVGVsIFJQQyBtZXRhZGF0YSxcbiAqIHdoaWNoIHJlbWFpbnMgYXZhaWxhYmxlIGV2ZW4gd2hlbiBFeHByZXNzIG1ha2VzIGEgbWlkZGxld2FyZS1sYXllciBjaGlsZFxuICogYWN0aXZlLiBXaGVuIGluc3RydW1lbnRhdGlvbiBpcyB1bmF2YWlsYWJsZSwgdGhpcyBtb2R1bGUgY3JlYXRlcyBvbmVcbiAqIHJlcXVlc3QtbGlmZXRpbWUgc2VydmVyIHNwYW4gYW5kIHJ1bnMgTWFzdHJhIHVuZGVyIGl0LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBTdHJpbmdEZWNvZGVyIH0gZnJvbSBcIm5vZGU6c3RyaW5nX2RlY29kZXJcIjtcblxuaW1wb3J0IHsganNvbiwgbG9nLCBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgY29udGV4dCwgU3BhbktpbmQsIHRyYWNlLCB0eXBlIFNwYW4gfSBmcm9tIFwiQG9wZW50ZWxlbWV0cnkvYXBpXCI7XG5pbXBvcnQgeyBnZXRSUENNZXRhZGF0YSwgUlBDVHlwZSB9IGZyb20gXCJAb3BlbnRlbGVtZXRyeS9jb3JlXCI7XG5pbXBvcnQgdHlwZSBleHByZXNzIGZyb20gXCJleHByZXNzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJtYXN0cmEvdGVsZW1ldHJ5XCIpO1xuXG4vKiogQ2FwIG9uIGVhY2ggcGF5bG9hZCBjb3BpZWQgb250byBhIHNwYW4sIHNvIG9uZSB0dXJuIGNhbm5vdCBibG9hdCB0aGUgZXhwb3J0LiAqL1xuZXhwb3J0IGNvbnN0IFRSQUNFX0lPX0xJTUlUID0gOF8wMDA7XG5cbi8qKiBCb3VuZCBmb3IgYSBub24tc3RyZWFtaW5nIGJvZHkgY2FwdHVyZWQgdGhyb3VnaCBgcmVzLmVuZGAgaW5zdGVhZCBvZiBgcmVzLmpzb25gLiAqL1xuY29uc3QgUkVTUE9OU0VfQk9EWV9MSU1JVCA9IFRSQUNFX0lPX0xJTUlUICogNDtcblxuLyoqIFRyYWNlciBzY29wZSB1c2VkIG9ubHkgd2hlbiBBcHBLaXQgZGlkIG5vdCBjcmVhdGUgYSByZWNvcmRpbmcgSFRUUCBzcGFuLiAqL1xuY29uc3QgQ0hBVF9UVVJOX1RSQUNFUiA9IFwiQGRieC10b29scy9hcHBraXQtbWFzdHJhL3RlbGVtZXRyeVwiO1xuXG4vKipcbiAqIE1vdW50LXJlbGF0aXZlIE1hc3RyYSBhZ2VudCBpbnZva2UgcGF0aHMgdGhhdCBjYXJyeSBhIGNoYXQgdHVybiBib2R5XG4gKiAoYG1lc3NhZ2VzYCkgYW5kIHN0cmVhbSBhbiBhc3Npc3RhbnQgYW5zd2VyLiBSZXN1bWUgLyBhcHByb3ZlIHZlcmJzXG4gKiBhcmUgaW50ZW50aW9uYWxseSBleGNsdWRlZDogdGhlaXIgYm9kaWVzIGFyZSB0b29sIGRlY2lzaW9ucywgbm90IHRoZVxuICogdXNlciBwcm9tcHQsIGFuZCB0aGV5IHJhcmVseSBwcm9kdWNlIGEgZnJlc2ggYW5zd2VyIHdvcnRoIHN1cmZhY2luZy5cbiAqL1xuY29uc3QgQUdFTlRfVFVSTl9ST1VURSA9IC9eKD86XFwvYWdlbnRzXFwvW14vXStcXC8oPzpzdHJlYW18Z2VuZXJhdGUpKD86XFwvfCQpfFxcL2NoYXRcXC9bXi9dKyQpL2k7XG5cbi8qKiBBdHRyaWJ1dGUga2V5cyB0aGUgTUxmbG93IFVDIGAqX3RyYWNlX3VuaWZpZWRgIHZpZXcgcmVhZHMgZnJvbSB0aGUgcm9vdCBzcGFuLiAqL1xuZXhwb3J0IGNvbnN0IE1MRkxPV19TUEFOX0lOUFVUU19BVFRSID0gXCJtbGZsb3cuc3BhbklucHV0c1wiO1xuLyoqIFJvb3Qtc3BhbiBhdHRyaWJ1dGUgY29uc3VtZWQgYXMgY2hhdCBvdXRwdXQgYnkgTUxmbG93IHVuaWZpZWQgdHJhY2Ugdmlld3MuICovXG5leHBvcnQgY29uc3QgTUxGTE9XX1NQQU5fT1VUUFVUU19BVFRSID0gXCJtbGZsb3cuc3Bhbk91dHB1dHNcIjtcbi8qKiBGdWxsIHNlcmlhbGl6ZWQgcmVxdWVzdCBtZXNzYWdlcyByZXRhaW5lZCB3aGVuIHRoZSBNTGZsb3cgcHJldmlldyBpcyBwbGFpbiB0ZXh0LiAqL1xuZXhwb3J0IGNvbnN0IENIQVRfTUVTU0FHRVNfQVRUUiA9IFwiYXBwa2l0Lm1hc3RyYS5jaGF0Lm1lc3NhZ2VzXCI7XG4vKiogRnVsbCBzZXJpYWxpemVkIHJlc3BvbnNlIHJldGFpbmVkIHdoZW4gdGhlIE1MZmxvdyBwcmV2aWV3IGlzIHBsYWluIHRleHQuICovXG5leHBvcnQgY29uc3QgQ0hBVF9SRVNQT05TRV9BVFRSID0gXCJhcHBraXQubWFzdHJhLmNoYXQucmVzcG9uc2VcIjtcbi8qKiBDcmVkZW50aWFsIG1vZGUgdXNlZCBieSBEYXRhYnJpY2tzIGNhbGxzIGluIHRoaXMgY2hhdCB0dXJuLiAqL1xuZXhwb3J0IGNvbnN0IENIQVRfSURFTlRJVFlfQVRUUiA9IFwiYXBwa2l0Lm1hc3RyYS5pZGVudGl0eS5tb2RlXCI7XG4vKiogV2hldGhlciB0aGUgc3RyZWFtZWQgdHVybiBlbWl0dGVkIGEgR2VuaWUgdG9vbCBvciBwcm9ncmVzcyBldmVudC4gKi9cbmV4cG9ydCBjb25zdCBDSEFUX0dFTklFX1VTRURfQVRUUiA9IFwiYXBwa2l0Lm1hc3RyYS5nZW5pZS51c2VkXCI7XG5cbi8qKiBSb290LXNwYW4gbWV0YWRhdGEga25vd24gYmVmb3JlIGEgY2hhdCByZXF1ZXN0IGlzIGRpc3BhdGNoZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIENoYXRUdXJuVGVsZW1ldHJ5T3B0aW9ucyB7XG4gIHJlYWRvbmx5IGlkZW50aXR5PzpcbiAgICBcIm9ib1wiIHwgXCJzZXJ2aWNlLXByaW5jaXBhbFwiIHwgKChyZXF1ZXN0OiBleHByZXNzLlJlcXVlc3QpID0+IFwib2JvXCIgfCBcInNlcnZpY2UtcHJpbmNpcGFsXCIpO1xufVxuXG5pbnRlcmZhY2UgVHJhY2VUYXJnZXQge1xuICBzcGFuOiBTcGFuO1xuICBvd25lZDogYm9vbGVhbjtcbn1cblxuLyoqIFJldHVybiBvbmUgcmF3IHByb21wdCB3aGVuIHRoZSByZXF1ZXN0IGlzIGV4YWN0bHkgb25lIHRleHQtb25seSB1c2VyIG1lc3NhZ2UuICovXG5leHBvcnQgZnVuY3Rpb24gdGV4dE9ubHlDaGF0SW5wdXQobWVzc2FnZXM6IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAodHlwZW9mIG1lc3NhZ2VzID09PSBcInN0cmluZ1wiKSByZXR1cm4gbWVzc2FnZXMgfHwgdW5kZWZpbmVkO1xuICBpZiAoIUFycmF5LmlzQXJyYXkobWVzc2FnZXMpIHx8IG1lc3NhZ2VzLmxlbmd0aCAhPT0gMSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgbWVzc2FnZSA9IG1lc3NhZ2VzWzBdO1xuICBpZiAoIW9iamVjdC5pc1JlY29yZChtZXNzYWdlKSB8fCBtZXNzYWdlLnJvbGUgIT09IFwidXNlclwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAodHlwZW9mIG1lc3NhZ2UuY29udGVudCA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIG1lc3NhZ2UuY29udGVudCB8fCB1bmRlZmluZWQ7XG4gIHJldHVybiB0ZXh0RnJvbVBhcnRzKG1lc3NhZ2UucGFydHMpID8/IHRleHRGcm9tUGFydHMobWVzc2FnZS5jb250ZW50KTtcbn1cblxuZnVuY3Rpb24gdGV4dEZyb21QYXJ0cyh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkgfHwgdmFsdWUubGVuZ3RoID09PSAwKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCB0ZXh0OiBzdHJpbmdbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHBhcnQgb2YgdmFsdWUpIHtcbiAgICBpZiAoIW9iamVjdC5pc1JlY29yZChwYXJ0KSB8fCBwYXJ0LnR5cGUgIT09IFwidGV4dFwiIHx8IHR5cGVvZiBwYXJ0LnRleHQgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHRleHQucHVzaChwYXJ0LnRleHQpO1xuICB9XG4gIGNvbnN0IGpvaW5lZCA9IHRleHQuam9pbihcIlwiKTtcbiAgcmV0dXJuIGpvaW5lZCB8fCB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIHNlcmlhbGl6ZWQodmFsdWU6IHVua25vd24sIGxpbWl0ID0gVFJBQ0VfSU9fTElNSVQpOiBzdHJpbmcge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpPy5zbGljZSgwLCBsaW1pdCkgPz8gU3RyaW5nKHZhbHVlKS5zbGljZSgwLCBsaW1pdCk7XG59XG5cbmZ1bmN0aW9uIHNzZUZyYW1lKGxpbmU6IHN0cmluZyk6IHVua25vd24ge1xuICBpZiAoIWxpbmUuc3RhcnRzV2l0aChcImRhdGE6XCIpKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4ganNvbi5wYXJzZShsaW5lLnNsaWNlKDUpKTtcbn1cblxuZnVuY3Rpb24gdmFsdWVVc2VzR2VuaWUodmFsdWU6IHVua25vd24sIGRlcHRoID0gMCk6IGJvb2xlYW4ge1xuICBpZiAoZGVwdGggPiAzKSByZXR1cm4gZmFsc2U7XG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLnNvbWUoKGl0ZW0pID0+IHZhbHVlVXNlc0dlbmllKGl0ZW0sIGRlcHRoICsgMSkpO1xuICBpZiAoIW9iamVjdC5pc1JlY29yZCh2YWx1ZSkpIHJldHVybiBmYWxzZTtcbiAgaWYgKFxuICAgIHZhbHVlLnR5cGUgPT09IFwiZGF0YS1nZW5pZS1wcm9ncmVzc1wiIHx8XG4gICAgdmFsdWUudHlwZSA9PT0gXCJhc2tfZ2VuaWVfZG9uZVwiIHx8XG4gICAgdmFsdWUudG9vbE5hbWUgPT09IFwiYXNrX2dlbmllXCIgfHxcbiAgICB2YWx1ZS50b29sX25hbWUgPT09IFwiYXNrX2dlbmllXCIgfHxcbiAgICB2YWx1ZS5uYW1lID09PSBcImFza19nZW5pZVwiXG4gICkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBbXCJkYXRhXCIsIFwiZXZlbnRcIiwgXCJwYXlsb2FkXCJdLnNvbWUoKGtleSkgPT4gdmFsdWVVc2VzR2VuaWUodmFsdWVba2V5XSwgZGVwdGggKyAxKSk7XG59XG5cbi8qKiBSZXR1cm4gdGhlIGFzc2lzdGFudCB0ZXh0IGZyb20gb25lIFNTRSBsaW5lLCBvciBhbiBlbXB0eSBzdHJpbmcuICovXG5mdW5jdGlvbiBhc3Npc3RhbnRUZXh0RnJvbVNzZUxpbmUobGluZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGFzc2lzdGFudFRleHRGcm9tU3NlRnJhbWUoc3NlRnJhbWUobGluZSkpO1xufVxuXG5mdW5jdGlvbiBhc3Npc3RhbnRUZXh0RnJvbVNzZUZyYW1lKGZyYW1lOiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKCFvYmplY3QuaXNSZWNvcmQoZnJhbWUpIHx8IGZyYW1lLnR5cGUgIT09IFwidGV4dC1kZWx0YVwiKSByZXR1cm4gXCJcIjtcbiAgY29uc3QgdGV4dCA9XG4gICAgdHlwZW9mIGZyYW1lLmRlbHRhID09PSBcInN0cmluZ1wiXG4gICAgICA/IGZyYW1lLmRlbHRhXG4gICAgICA6IG9iamVjdC5pc1JlY29yZChmcmFtZS5wYXlsb2FkKVxuICAgICAgICA/IGZyYW1lLnBheWxvYWQudGV4dFxuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgcmV0dXJuIHR5cGVvZiB0ZXh0ID09PSBcInN0cmluZ1wiID8gdGV4dCA6IFwiXCI7XG59XG5cbi8qKlxuICogQ29uY2F0ZW5hdGUgdGhlIGFzc2lzdGFudCdzIGFuc3dlciBvdXQgb2YgYW4gQUkgU0RLIFNTRSB0cmFuc2NyaXB0LlxuICpcbiAqIFRoZSBhZ2VudCBzdHJlYW1zIGl0cyByZXBseSBhcyBgdGV4dC1kZWx0YWAgZnJhbWVzXG4gKiAoYGRhdGE6IHtcInR5cGVcIjpcInRleHQtZGVsdGFcIixcInBheWxvYWRcIjp7XCJ0ZXh0XCI6XCIuLi5cIn19YCksIHNvIHRoZSBmdWxsXG4gKiBhbnN3ZXIgb25seSBldmVyIGV4aXN0cyBhcyBkZWx0YXMgb24gdGhlIHdpcmUgYW5kIGhhcyB0byBiZVxuICogcmVhc3NlbWJsZWQgaGVyZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2lzdGFudFRleHRGcm9tU3NlKGJvZHk6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGxpbmUgb2YgYm9keS5zcGxpdChcIlxcblwiKSkge1xuICAgIGNvbnN0IHRleHQgPSBhc3Npc3RhbnRUZXh0RnJvbVNzZUxpbmUobGluZSk7XG4gICAgaWYgKHRleHQpIHBhcnRzLnB1c2godGV4dCk7XG4gIH1cbiAgcmV0dXJuIHBhcnRzLmpvaW4oXCJcIikuc2xpY2UoMCwgVFJBQ0VfSU9fTElNSVQpO1xufVxuXG4vKiogUmVhZCB0aGUgZmluYWwgYXNzaXN0YW50IHRleHQgZnJvbSBhIG5vbi1zdHJlYW1pbmcgTWFzdHJhIHJlc3BvbnNlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2lzdGFudFRleHRGcm9tSnNvbihib2R5OiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKCFvYmplY3QuaXNSZWNvcmQoYm9keSkgfHwgdHlwZW9mIGJvZHkudGV4dCAhPT0gXCJzdHJpbmdcIikgcmV0dXJuIFwiXCI7XG4gIHJldHVybiBib2R5LnRleHQuc2xpY2UoMCwgVFJBQ0VfSU9fTElNSVQpO1xufVxuXG4vKiogSW5jcmVtZW50YWxseSBhc3NlbWJsZSBVVEYtOCBTU0UgdGV4dCB3aGlsZSByZXRhaW5pbmcgYSBib3VuZGVkIEpTT04gZmFsbGJhY2suICovXG5jbGFzcyBBc3Npc3RhbnRSZXNwb25zZUNvbGxlY3RvciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVjb2RlciA9IG5ldyBTdHJpbmdEZWNvZGVyKFwidXRmOFwiKTtcbiAgcHJpdmF0ZSBhbnN3ZXIgPSBcIlwiO1xuICBwcml2YXRlIGJvZHkgPSBcIlwiO1xuICBwcml2YXRlIHBlbmRpbmdMaW5lID0gXCJcIjtcbiAgcHJpdmF0ZSBmaW5pc2hlZCA9IGZhbHNlO1xuICBwcml2YXRlIGdlbmllID0gZmFsc2U7XG5cbiAgd3JpdGUoY2h1bms6IHVua25vd24pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5maW5pc2hlZCkgcmV0dXJuO1xuICAgIGlmICh0eXBlb2YgY2h1bmsgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHRoaXMuY29uc3VtZShjaHVuayk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoY2h1bmspKSB7XG4gICAgICB0aGlzLmNvbnN1bWUoXG4gICAgICAgIHRoaXMuZGVjb2Rlci53cml0ZShCdWZmZXIuZnJvbShjaHVuay5idWZmZXIsIGNodW5rLmJ5dGVPZmZzZXQsIGNodW5rLmJ5dGVMZW5ndGgpKSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgZmluaXNoKCk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMuZmluaXNoZWQpIHJldHVybiB0aGlzLmFuc3dlciB8fCB0aGlzLmpzb25BbnN3ZXIoKTtcbiAgICB0aGlzLmZpbmlzaGVkID0gdHJ1ZTtcbiAgICB0aGlzLmNvbnN1bWUodGhpcy5kZWNvZGVyLmVuZCgpKTtcbiAgICB0aGlzLmNvbnN1bWVTc2VMaW5lKHRoaXMucGVuZGluZ0xpbmUpO1xuICAgIHRoaXMucGVuZGluZ0xpbmUgPSBcIlwiO1xuICAgIHJldHVybiB0aGlzLmFuc3dlciB8fCB0aGlzLmpzb25BbnN3ZXIoKTtcbiAgfVxuXG4gIHJhd0JvZHkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5ib2R5LnNsaWNlKDAsIFRSQUNFX0lPX0xJTUlUKTtcbiAgfVxuXG4gIHVzZWRHZW5pZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5nZW5pZTtcbiAgfVxuXG4gIHByaXZhdGUgY29uc3VtZSh0ZXh0OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIXRleHQpIHJldHVybjtcbiAgICBpZiAodGhpcy5ib2R5Lmxlbmd0aCA8IFJFU1BPTlNFX0JPRFlfTElNSVQpIHtcbiAgICAgIHRoaXMuYm9keSArPSB0ZXh0LnNsaWNlKDAsIFJFU1BPTlNFX0JPRFlfTElNSVQgLSB0aGlzLmJvZHkubGVuZ3RoKTtcbiAgICB9XG4gICAgdGhpcy5wZW5kaW5nTGluZSArPSB0ZXh0O1xuICAgIGxldCBuZXdsaW5lID0gdGhpcy5wZW5kaW5nTGluZS5pbmRleE9mKFwiXFxuXCIpO1xuICAgIHdoaWxlIChuZXdsaW5lID49IDApIHtcbiAgICAgIHRoaXMuY29uc3VtZVNzZUxpbmUodGhpcy5wZW5kaW5nTGluZS5zbGljZSgwLCBuZXdsaW5lKS5yZXBsYWNlKC9cXHIkLywgXCJcIikpO1xuICAgICAgdGhpcy5wZW5kaW5nTGluZSA9IHRoaXMucGVuZGluZ0xpbmUuc2xpY2UobmV3bGluZSArIDEpO1xuICAgICAgbmV3bGluZSA9IHRoaXMucGVuZGluZ0xpbmUuaW5kZXhPZihcIlxcblwiKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucGVuZGluZ0xpbmUubGVuZ3RoID4gUkVTUE9OU0VfQk9EWV9MSU1JVCkge1xuICAgICAgdGhpcy5wZW5kaW5nTGluZSA9IHRoaXMucGVuZGluZ0xpbmUuc2xpY2UoLVJFU1BPTlNFX0JPRFlfTElNSVQpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY29uc3VtZVNzZUxpbmUobGluZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgZnJhbWUgPSBzc2VGcmFtZShsaW5lKTtcbiAgICB0aGlzLmdlbmllIHx8PSB2YWx1ZVVzZXNHZW5pZShmcmFtZSk7XG4gICAgaWYgKHRoaXMuYW5zd2VyLmxlbmd0aCA+PSBUUkFDRV9JT19MSU1JVCkgcmV0dXJuO1xuICAgIGNvbnN0IHRleHQgPSBhc3Npc3RhbnRUZXh0RnJvbVNzZUZyYW1lKGZyYW1lKTtcbiAgICB0aGlzLmFuc3dlciArPSB0ZXh0LnNsaWNlKDAsIFRSQUNFX0lPX0xJTUlUIC0gdGhpcy5hbnN3ZXIubGVuZ3RoKTtcbiAgfVxuXG4gIHByaXZhdGUganNvbkFuc3dlcigpOiBzdHJpbmcge1xuICAgIHJldHVybiBhc3Npc3RhbnRUZXh0RnJvbUpzb24oanNvbi5wYXJzZSh0aGlzLmJvZHkpKTtcbiAgfVxufVxuXG4vKipcbiAqIFNlbGVjdCB0aGUgc3BhbiBNTGZsb3cgdHJlYXRzIGFzIHRoZSByZXF1ZXN0IHJvb3QuXG4gKlxuICogT1RlbCBIVFRQIGluc3RydW1lbnRhdGlvbiBzdG9yZXMgaXRzIHNlcnZlciBzcGFuIGluIFJQQyBtZXRhZGF0YS4gVGhhdCBzcGFuXG4gKiB3aW5zIG92ZXIgYW4gYWN0aXZlIEV4cHJlc3MgY2hpbGQuIElmIG5vIHJlY29yZGluZyBsb2NhbCBzcGFuIGV4aXN0cywgY3JlYXRlXG4gKiBvbmUgdW5kZXIgdGhlIGN1cnJlbnQgY29udGV4dCBzbyBlbmFibGVkIFczQyBwcm9wYWdhdGlvbiByZW1haW5zIGludGFjdC5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVRyYWNlVGFyZ2V0KCk6IFRyYWNlVGFyZ2V0IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgYWN0aXZlQ29udGV4dCA9IGNvbnRleHQuYWN0aXZlKCk7XG4gIGNvbnN0IHJwYyA9IGdldFJQQ01ldGFkYXRhKGFjdGl2ZUNvbnRleHQpO1xuICBpZiAocnBjPy50eXBlID09PSBSUENUeXBlLkhUVFAgJiYgcnBjLnNwYW4uaXNSZWNvcmRpbmcoKSkge1xuICAgIHJldHVybiB7IHNwYW46IHJwYy5zcGFuLCBvd25lZDogZmFsc2UgfTtcbiAgfVxuXG4gIGNvbnN0IGFjdGl2ZSA9IHRyYWNlLmdldEFjdGl2ZVNwYW4oKTtcbiAgaWYgKGFjdGl2ZT8uaXNSZWNvcmRpbmcoKSkgcmV0dXJuIHsgc3BhbjogYWN0aXZlLCBvd25lZDogZmFsc2UgfTtcblxuICBjb25zdCBzcGFuID0gdHJhY2VcbiAgICAuZ2V0VHJhY2VyKENIQVRfVFVSTl9UUkFDRVIpXG4gICAgLnN0YXJ0U3BhbihcIm1hc3RyYS5jaGF0X3R1cm5cIiwgeyBraW5kOiBTcGFuS2luZC5TRVJWRVIgfSwgYWN0aXZlQ29udGV4dCk7XG4gIGlmICghc3Bhbi5pc1JlY29yZGluZygpKSB7XG4gICAgc3Bhbi5lbmQoKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiB7IHNwYW4sIG93bmVkOiB0cnVlIH07XG59XG5cbi8qKlxuICogRXhwcmVzcyBtaWRkbGV3YXJlIHRoYXQgc3RhbXBzIGNoYXQgdHVybiBJL08gb250byB0aGUgZXhwb3J0ZWQgT1RlbCByb290LlxuICpcbiAqIFRlZSBgcmVzLndyaXRlYCwgYHJlcy5qc29uYCwgYW5kIGByZXMuZW5kYCBpbnN0ZWFkIG9mIGxpc3RlbmluZyBmb3IgYGZpbmlzaGA6XG4gKiBIVFRQIGluc3RydW1lbnRhdGlvbiBlbmRzIGl0cyBzZXJ2ZXIgc3BhbiBvbiBmaW5pc2gsIGFuZCBhdHRyaWJ1dGVzIHNldFxuICogYWZ0ZXIgYSBzcGFuIGVuZHMgbmV2ZXIgcmVhY2ggdGhlIGV4cG9ydGVyLlxuICpcbiAqIGBwYXRoYCBpcyBtb3VudC1yZWxhdGl2ZSAod2hhdCB0aGUgTWFzdHJhIHN1Yi1hcHAgc2VlcyksIGUuZy5cbiAqIGAvYWdlbnRzL3N1cHBvcnQvc3RyZWFtYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoYXRUdXJuVGVsZW1ldHJ5TWlkZGxld2FyZShcbiAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gIHJlczogZXhwcmVzcy5SZXNwb25zZSxcbiAgbmV4dDogZXhwcmVzcy5OZXh0RnVuY3Rpb24sXG4gIG9wdGlvbnM6IENoYXRUdXJuVGVsZW1ldHJ5T3B0aW9ucyA9IHt9LFxuKTogdm9pZCB7XG4gIGlmIChyZXEubWV0aG9kICE9PSBcIlBPU1RcIiB8fCAhQUdFTlRfVFVSTl9ST1VURS50ZXN0KHJlcS5wYXRoKSkge1xuICAgIG5leHQoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgY29uc3QgdGFyZ2V0ID0gcmVzb2x2ZVRyYWNlVGFyZ2V0KCk7XG4gIGlmICghdGFyZ2V0KSB7XG4gICAgbmV4dCgpO1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBpZGVudGl0eSA9XG4gICAgdHlwZW9mIG9wdGlvbnMuaWRlbnRpdHkgPT09IFwiZnVuY3Rpb25cIiA/IG9wdGlvbnMuaWRlbnRpdHkocmVxKSA6IG9wdGlvbnMuaWRlbnRpdHk7XG4gIGlmIChpZGVudGl0eSkge1xuICAgIHRhcmdldC5zcGFuLnNldEF0dHJpYnV0ZShDSEFUX0lERU5USVRZX0FUVFIsIGlkZW50aXR5KTtcbiAgfVxuICB0YXJnZXQuc3Bhbi5zZXRBdHRyaWJ1dGUoQ0hBVF9HRU5JRV9VU0VEX0FUVFIsIGZhbHNlKTtcblxuICBjb25zdCBtZXNzYWdlcyA9IChyZXEuYm9keSBhcyB7IG1lc3NhZ2VzPzogdW5rbm93biB9IHwgdW5kZWZpbmVkKT8ubWVzc2FnZXM7XG4gIGlmIChtZXNzYWdlcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgZnVsbElucHV0ID0gc2VyaWFsaXplZChtZXNzYWdlcyk7XG4gICAgdGFyZ2V0LnNwYW4uc2V0QXR0cmlidXRlKENIQVRfTUVTU0FHRVNfQVRUUiwgZnVsbElucHV0KTtcbiAgICB0YXJnZXQuc3Bhbi5zZXRBdHRyaWJ1dGUoXG4gICAgICBNTEZMT1dfU1BBTl9JTlBVVFNfQVRUUixcbiAgICAgICh0ZXh0T25seUNoYXRJbnB1dChtZXNzYWdlcykgPz8gZnVsbElucHV0KS5zbGljZSgwLCBUUkFDRV9JT19MSU1JVCksXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGNvbGxlY3RvciA9IG5ldyBBc3Npc3RhbnRSZXNwb25zZUNvbGxlY3RvcigpO1xuICBsZXQgb3V0cHV0UmVjb3JkZWQgPSBmYWxzZTtcbiAgbGV0IGZ1bGxPdXRwdXRSZWNvcmRlZCA9IGZhbHNlO1xuICBsZXQgb3duZWRTcGFuRW5kZWQgPSBmYWxzZTtcbiAgY29uc3QgcGFzc1Rocm91Z2hXcml0ZSA9IHJlcy53cml0ZS5iaW5kKHJlcykgYXMgKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gYm9vbGVhbjtcbiAgY29uc3QgcGFzc1Rocm91Z2hFbmQgPSByZXMuZW5kLmJpbmQocmVzKSBhcyAoLi4uYXJnczogdW5rbm93bltdKSA9PiB1bmtub3duO1xuICBjb25zdCBwYXNzVGhyb3VnaEpzb24gPSByZXMuanNvbi5iaW5kKHJlcykgYXMgKGJvZHk/OiB1bmtub3duKSA9PiBleHByZXNzLlJlc3BvbnNlO1xuICBjb25zdCByZWNvcmRPdXRwdXQgPSAoYW5zd2VyOiBzdHJpbmcpOiB2b2lkID0+IHtcbiAgICBpZiAob3V0cHV0UmVjb3JkZWQgfHwgIWFuc3dlcikgcmV0dXJuO1xuICAgIHRhcmdldC5zcGFuLnNldEF0dHJpYnV0ZShNTEZMT1dfU1BBTl9PVVRQVVRTX0FUVFIsIGFuc3dlci5zbGljZSgwLCBUUkFDRV9JT19MSU1JVCkpO1xuICAgIG91dHB1dFJlY29yZGVkID0gdHJ1ZTtcbiAgfTtcbiAgY29uc3QgcmVjb3JkRnVsbE91dHB1dCA9IChyZXNwb25zZTogc3RyaW5nKTogdm9pZCA9PiB7XG4gICAgaWYgKGZ1bGxPdXRwdXRSZWNvcmRlZCB8fCAhcmVzcG9uc2UpIHJldHVybjtcbiAgICB0YXJnZXQuc3Bhbi5zZXRBdHRyaWJ1dGUoQ0hBVF9SRVNQT05TRV9BVFRSLCByZXNwb25zZS5zbGljZSgwLCBUUkFDRV9JT19MSU1JVCkpO1xuICAgIGZ1bGxPdXRwdXRSZWNvcmRlZCA9IHRydWU7XG4gIH07XG4gIGNvbnN0IHJlY29yZEdlbmllID0gKHVzZWQ6IGJvb2xlYW4pOiB2b2lkID0+IHtcbiAgICBpZiAodXNlZCkgdGFyZ2V0LnNwYW4uc2V0QXR0cmlidXRlKENIQVRfR0VOSUVfVVNFRF9BVFRSLCB0cnVlKTtcbiAgfTtcbiAgY29uc3QgZW5kT3duZWRTcGFuID0gKCk6IHZvaWQgPT4ge1xuICAgIGlmICghdGFyZ2V0Lm93bmVkIHx8IG93bmVkU3BhbkVuZGVkKSByZXR1cm47XG4gICAgb3duZWRTcGFuRW5kZWQgPSB0cnVlO1xuICAgIHRhcmdldC5zcGFuLmVuZCgpO1xuICB9O1xuXG4gIHJlcy53cml0ZSA9ICgoY2h1bms6IHVua25vd24sIC4uLnJlc3Q6IHVua25vd25bXSkgPT4ge1xuICAgIGNvbGxlY3Rvci53cml0ZShjaHVuayk7XG4gICAgcmV0dXJuIHBhc3NUaHJvdWdoV3JpdGUoY2h1bmssIC4uLnJlc3QpO1xuICB9KSBhcyB0eXBlb2YgcmVzLndyaXRlO1xuXG4gIHJlcy5qc29uID0gKChib2R5PzogdW5rbm93bikgPT4ge1xuICAgIHJlY29yZEZ1bGxPdXRwdXQoc2VyaWFsaXplZChib2R5KSk7XG4gICAgcmVjb3JkR2VuaWUodmFsdWVVc2VzR2VuaWUoYm9keSkpO1xuICAgIHJlY29yZE91dHB1dChhc3Npc3RhbnRUZXh0RnJvbUpzb24oYm9keSkpO1xuICAgIHJldHVybiBwYXNzVGhyb3VnaEpzb24oYm9keSk7XG4gIH0pIGFzIHR5cGVvZiByZXMuanNvbjtcblxuICByZXMuZW5kID0gKChjaHVuaz86IHVua25vd24sIC4uLnJlc3Q6IHVua25vd25bXSkgPT4ge1xuICAgIGNvbGxlY3Rvci53cml0ZShjaHVuayk7XG4gICAgcmVjb3JkT3V0cHV0KGNvbGxlY3Rvci5maW5pc2goKSk7XG4gICAgcmVjb3JkRnVsbE91dHB1dChjb2xsZWN0b3IucmF3Qm9keSgpKTtcbiAgICByZWNvcmRHZW5pZShjb2xsZWN0b3IudXNlZEdlbmllKCkpO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gcGFzc1Rocm91Z2hFbmQoY2h1bmssIC4uLnJlc3QpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBlbmRPd25lZFNwYW4oKTtcbiAgICB9XG4gIH0pIGFzIHR5cGVvZiByZXMuZW5kO1xuXG4gIHJlcy5vbmNlKFwiY2xvc2VcIiwgKCkgPT4ge1xuICAgIHJlY29yZE91dHB1dChjb2xsZWN0b3IuZmluaXNoKCkpO1xuICAgIHJlY29yZEZ1bGxPdXRwdXQoY29sbGVjdG9yLnJhd0JvZHkoKSk7XG4gICAgcmVjb3JkR2VuaWUoY29sbGVjdG9yLnVzZWRHZW5pZSgpKTtcbiAgICBlbmRPd25lZFNwYW4oKTtcbiAgfSk7XG5cbiAgY29udGV4dC53aXRoKHRyYWNlLnNldFNwYW4oY29udGV4dC5hY3RpdmUoKSwgdGFyZ2V0LnNwYW4pLCBuZXh0KTtcbn1cblxuLyoqXG4gKiBJbnN0YWxsIHtAbGluayBjaGF0VHVyblRlbGVtZXRyeU1pZGRsZXdhcmV9IG9uIGEgTWFzdHJhIEV4cHJlc3Mgc3ViLWFwcC5cbiAqXG4gKiBDYWxsIGJlZm9yZSBgTWFzdHJhU2VydmVyLmluaXQoKWAgc28gdGhlIGxheWVyIHNpdHMgYWhlYWQgb2YgdGhlIGFnZW50XG4gKiByb3V0ZXMuIFNhZmUgdG8gY2FsbCB1bmNvbmRpdGlvbmFsbHk6IHdoZW4gbm8gcmVjb3JkaW5nIHRyYWNlciBpcyByZWdpc3RlcmVkLFxuICogdGhlIG1pZGRsZXdhcmUgaXMgYSBuby1vcC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaENoYXRUdXJuVGVsZW1ldHJ5KFxuICBhcHA6IGV4cHJlc3MuRXhwcmVzcyxcbiAgb3B0aW9uczogQ2hhdFR1cm5UZWxlbWV0cnlPcHRpb25zID0ge30sXG4pOiB2b2lkIHtcbiAgYXBwLnVzZSgocmVxLCByZXMsIG5leHQpID0+IGNoYXRUdXJuVGVsZW1ldHJ5TWlkZGxld2FyZShyZXEsIHJlcywgbmV4dCwgb3B0aW9ucykpO1xuICBsb2dnZXIuaW5mbyhcImNoYXQgdHVybiB0ZWxlbWV0cnkgbWlkZGxld2FyZSBhdHRhY2hlZFwiLCBvcHRpb25zKTtcbn1cbiJdfQ==
@@ -1 +1 @@
1
- {"root":["../src/agents.ts","../src/chart.ts","../src/chat.ts","../src/config.ts","../src/defaults.ts","../src/evaluation.ts","../src/filesystems.ts","../src/genie.ts","../src/identity.ts","../src/mcp.ts","../src/memory.ts","../src/mlflow.ts","../src/model.ts","../src/monty-sandbox.ts","../src/observability.ts","../src/plugin.ts","../src/processors.ts","../src/remote-skills.ts","../src/rest.ts","../src/sandbox.ts","../src/server.ts","../src/serving-sanitize.ts","../src/serving.ts","../src/skill-paths.ts","../src/statement.ts","../src/storage-schema.ts","../src/style.ts","../src/summarize.ts","../src/trace-io.ts","../src/validation.ts","../src/workspaces.ts","../src/writer.ts","../index.ts"],"version":"5.9.3"}
1
+ {"root":["../src/agents.ts","../src/chart.ts","../src/chat.ts","../src/config.ts","../src/defaults.ts","../src/evaluation.ts","../src/filesystems.ts","../src/genie.ts","../src/identity.ts","../src/mcp.ts","../src/memory.ts","../src/mlflow.ts","../src/model.ts","../src/monty-sandbox.ts","../src/observability.ts","../src/plugin.ts","../src/processors.ts","../src/remote-skills.ts","../src/rest.ts","../src/sandbox.ts","../src/server.ts","../src/serving-sanitize.ts","../src/serving.ts","../src/skill-paths.ts","../src/statement.ts","../src/storage-schema.ts","../src/style.ts","../src/summarize.ts","../src/telemetry.ts","../src/validation.ts","../src/workspaces.ts","../src/writer.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -33,18 +33,18 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@databricks/appkit": "0.81.0",
36
- "@dbx-tools/appkit": "^0.9.38",
37
- "@dbx-tools/core": "^0.9.38",
38
- "@dbx-tools/databricks": "^0.9.38",
39
- "@dbx-tools/fs": "^0.9.38",
40
- "@dbx-tools/genie": "^0.9.38",
41
- "@dbx-tools/model": "^0.9.38",
42
- "@dbx-tools/path": "^0.9.38",
43
- "@dbx-tools/shared-core": "^0.9.38",
44
- "@dbx-tools/shared-fs": "^0.9.38",
45
- "@dbx-tools/shared-genie": "^0.9.38",
46
- "@dbx-tools/shared-mastra": "^0.9.38",
47
- "@dbx-tools/shared-model": "^0.9.38",
36
+ "@dbx-tools/appkit": "^0.9.43",
37
+ "@dbx-tools/core": "^0.9.43",
38
+ "@dbx-tools/databricks": "^0.9.43",
39
+ "@dbx-tools/fs": "^0.9.43",
40
+ "@dbx-tools/genie": "^0.9.43",
41
+ "@dbx-tools/model": "^0.9.43",
42
+ "@dbx-tools/path": "^0.9.43",
43
+ "@dbx-tools/shared-core": "^0.9.43",
44
+ "@dbx-tools/shared-fs": "^0.9.43",
45
+ "@dbx-tools/shared-genie": "^0.9.43",
46
+ "@dbx-tools/shared-mastra": "^0.9.43",
47
+ "@dbx-tools/shared-model": "^0.9.43",
48
48
  "@mastra/ai-sdk": "1.10.5",
49
49
  "@mastra/core": "1.71.0",
50
50
  "@mastra/express": "1.5.15",
@@ -185,9 +185,9 @@
185
185
  "types": "./lib/src/summarize.d.ts",
186
186
  "default": "./lib/src/summarize.js"
187
187
  },
188
- "./trace-io": {
189
- "types": "./lib/src/trace-io.d.ts",
190
- "default": "./lib/src/trace-io.js"
188
+ "./telemetry": {
189
+ "types": "./lib/src/telemetry.d.ts",
190
+ "default": "./lib/src/telemetry.js"
191
191
  },
192
192
  "./validation": {
193
193
  "types": "./lib/src/validation.d.ts",
@@ -204,7 +204,7 @@
204
204
  "./package.json": "./package.json"
205
205
  }
206
206
  },
207
- "version": "0.9.38",
207
+ "version": "0.9.43",
208
208
  "types": "./lib/index.d.ts",
209
209
  "dbxToolsConfig": {
210
210
  "tags": [
@@ -329,9 +329,9 @@
329
329
  "types": "./lib/src/summarize.d.ts",
330
330
  "default": "./lib/src/summarize.js"
331
331
  },
332
- "./trace-io": {
333
- "types": "./lib/src/trace-io.d.ts",
334
- "default": "./lib/src/trace-io.js"
332
+ "./telemetry": {
333
+ "types": "./lib/src/telemetry.d.ts",
334
+ "default": "./lib/src/telemetry.js"
335
335
  },
336
336
  "./validation": {
337
337
  "types": "./lib/src/validation.d.ts",
@@ -37,7 +37,7 @@
37
37
  * `OTEL_PROPAGATORS=none` so Apps ingress `traceparent` does not hide
38
38
  * every request-scoped root span from the UC `*_trace_unified` view.
39
39
  * Chat request/response on that root span is stamped by
40
- * `traceIo.attachChatTurnTraceIo` (see `trace-io.ts`).
40
+ * `telemetry.attachChatTurnTelemetry` (see `telemetry.ts`).
41
41
  *
42
42
  * @module
43
43
  */
package/src/plugin.ts CHANGED
@@ -111,7 +111,7 @@ import {
111
111
  } from "./server.ts";
112
112
  import { resolveServingConfig } from "./serving.ts";
113
113
  import { fetchStatementData, STATEMENT_ROW_CAP } from "./statement.ts";
114
- import { attachChatTurnTraceIo } from "./trace-io.ts";
114
+ import { attachChatTurnTelemetry } from "./telemetry.ts";
115
115
  import { invalidFields } from "./validation.ts";
116
116
 
117
117
  const GENIE_MANIFEST = pluginRegistry.data(genie).plugin.manifest;
@@ -1133,7 +1133,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
1133
1133
  // `mastra.agent_run.*` attributes sit on a child span the view
1134
1134
  // never reads). Must run before `MastraServer.init` so the layer
1135
1135
  // sits ahead of the agent routes.
1136
- attachChatTurnTraceIo(this.mastraApp);
1136
+ attachChatTurnTelemetry(this.mastraApp, {
1137
+ identity: (request) =>
1138
+ useServicePrincipal(this.identityMode, request) ? "service-principal" : "obo",
1139
+ });
1137
1140
  this.mastraServer = new MastraServer(this.config, {
1138
1141
  app: this.mastraApp,
1139
1142
  mastra: this.mastra,