@dbx-tools/appkit-mastra 0.9.68 → 0.9.70

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/src/telemetry.ts CHANGED
@@ -36,11 +36,11 @@ import {
36
36
  updateActiveMlflowTraceTags,
37
37
  } from "./mlflow.ts";
38
38
  import {
39
+ APPKIT_AGENT_TRACE_ROOT_ATTR,
39
40
  MLFLOW_AGENT_TAG,
40
41
  MLFLOW_AGENT_TAG_ATTR,
41
42
  MLFLOW_GENIE_TAG,
42
43
  MLFLOW_GENIE_TAG_ATTR,
43
- MLFLOW_MODEL_TAG,
44
44
  MLFLOW_LOCAL_TAG,
45
45
  MLFLOW_OBO_AUTH_TAG,
46
46
  MLFLOW_SP_AUTH_TAG,
@@ -50,10 +50,9 @@ import {
50
50
  export {
51
51
  MLFLOW_AGENT_TAG,
52
52
  MLFLOW_AGENT_TAG_ATTR,
53
+ APPKIT_AGENT_TRACE_ROOT_ATTR,
53
54
  MLFLOW_GENIE_TAG,
54
55
  MLFLOW_GENIE_TAG_ATTR,
55
- MLFLOW_MODEL_TAG,
56
- MLFLOW_MODEL_TAG_ATTR,
57
56
  MLFLOW_LOCAL_TAG,
58
57
  MLFLOW_LOCAL_TAG_ATTR,
59
58
  MLFLOW_OBO_AUTH_TAG,
@@ -130,8 +129,8 @@ interface TraceTarget {
130
129
  }
131
130
 
132
131
  interface ChatTraceState {
133
- readonly models: Set<string>;
134
132
  readonly tags: Map<string, string>;
133
+ firstModel?: string;
135
134
  user?: string;
136
135
  }
137
136
 
@@ -187,21 +186,14 @@ function activeChatTraceState(): ChatTraceState | undefined {
187
186
  return context.active().getValue(CHAT_TRACE_STATE_KEY) as ChatTraceState | undefined;
188
187
  }
189
188
 
190
- function setChatTraceTag(
191
- state: ChatTraceState,
192
- name: string,
193
- value: ChatTraceTagValue,
194
- ): void {
189
+ function setChatTraceTag(state: ChatTraceState, name: string, value: ChatTraceTagValue): void {
195
190
  const tag = stringUtils.trimToNull(name);
196
191
  if (!tag) return;
197
192
  state.tags.set(tag, String(value));
198
193
  }
199
194
 
200
195
  /** Inject one MLflow trace tag into the active chat request. */
201
- export function recordActiveTraceTag(
202
- name: string,
203
- value: ChatTraceTagValue = true,
204
- ): void {
196
+ export function recordActiveTraceTag(name: string, value: ChatTraceTagValue = true): void {
205
197
  const state = activeChatTraceState();
206
198
  if (state) setChatTraceTag(state, name, value);
207
199
  }
@@ -217,11 +209,17 @@ export function recordActiveTraceTags(
217
209
  }
218
210
  }
219
211
 
220
- /** Record a selected model on the active chat trace, preserving first-use order. */
212
+ /** Record the first selected model as the active chat trace's `agent` tag. */
221
213
  export function recordActiveTraceModel(modelId: string): void {
222
214
  const value = stringUtils.trimToNull(modelId);
223
215
  if (!value) return;
224
- activeChatTraceState()?.models.add(value);
216
+ const state = activeChatTraceState();
217
+ if (!state || state.firstModel) return;
218
+ state.firstModel = value;
219
+ setChatTraceTag(state, MLFLOW_AGENT_TAG, value);
220
+ const span = trace.getActiveSpan();
221
+ if (span?.isRecording()) span.setAttribute(MLFLOW_AGENT_TAG_ATTR, value);
222
+ updateActiveMlflowTraceTags({ [MLFLOW_AGENT_TAG]: value });
225
223
  }
226
224
 
227
225
  /** Record the best resolved user identifier on the active chat trace. */
@@ -237,20 +235,6 @@ export function recordActiveTraceAuth(auth: "obo" | "service-principal"): void {
237
235
  recordActiveTraceTag(auth === "obo" ? MLFLOW_OBO_AUTH_TAG : MLFLOW_SP_AUTH_TAG);
238
236
  }
239
237
 
240
- /** Serialize model tags as a scalar or an ordered JSON array for multiple values. */
241
- export function modelTraceTag(models: Iterable<string>): string | undefined {
242
- const values: string[] = [];
243
- const seen = new Set<string>();
244
- for (const model of models) {
245
- const value = stringUtils.trimToNull(model);
246
- if (!value || seen.has(value)) continue;
247
- seen.add(value);
248
- values.push(value);
249
- }
250
- if (values.length === 0) return undefined;
251
- return values.length === 1 ? values[0] : JSON.stringify(values);
252
- }
253
-
254
238
  /** Publish the turn's MLflow trace id before the handler writes the body. */
255
239
  function stampMlflowTraceId(res: express.Response, span: Span): void {
256
240
  if (res.headersSent) return;
@@ -425,20 +409,18 @@ class AssistantResponseCollector {
425
409
  function resolveTraceTarget(): TraceTarget | undefined {
426
410
  const activeContext = context.active();
427
411
  if (directMlflowTracingActive()) {
428
- const span = trace
429
- .getTracer(CHAT_TURN_TRACER)
430
- .startSpan(
431
- "mastra.chat_turn",
432
- {
433
- kind: SpanKind.SERVER,
434
- attributes: {
435
- [MLFLOW_AGENT_TAG_ATTR]: "true",
436
- [MLFLOW_SPAN_TYPE_ATTR]: MLFLOW_SPAN_TYPE_AGENT,
437
- [GEN_AI_OPERATION_NAME_ATTR]: "invoke_agent",
438
- },
412
+ const span = trace.getTracer(CHAT_TURN_TRACER).startSpan(
413
+ "mastra.chat_turn",
414
+ {
415
+ kind: SpanKind.SERVER,
416
+ attributes: {
417
+ [APPKIT_AGENT_TRACE_ROOT_ATTR]: true,
418
+ [MLFLOW_SPAN_TYPE_ATTR]: MLFLOW_SPAN_TYPE_AGENT,
419
+ [GEN_AI_OPERATION_NAME_ATTR]: "invoke_agent",
439
420
  },
440
- trace.deleteSpan(activeContext),
441
- );
421
+ },
422
+ trace.deleteSpan(activeContext),
423
+ );
442
424
  if (!span.isRecording()) {
443
425
  span.end();
444
426
  return undefined;
@@ -454,20 +436,18 @@ function resolveTraceTarget(): TraceTarget | undefined {
454
436
  const active = trace.getActiveSpan();
455
437
  if (active?.isRecording()) return { span: active, owned: false };
456
438
 
457
- const span = trace
458
- .getTracer(CHAT_TURN_TRACER)
459
- .startSpan(
460
- "mastra.chat_turn",
461
- {
462
- kind: SpanKind.SERVER,
463
- attributes: {
464
- [MLFLOW_AGENT_TAG_ATTR]: "true",
465
- [MLFLOW_SPAN_TYPE_ATTR]: MLFLOW_SPAN_TYPE_AGENT,
466
- [GEN_AI_OPERATION_NAME_ATTR]: "invoke_agent",
467
- },
439
+ const span = trace.getTracer(CHAT_TURN_TRACER).startSpan(
440
+ "mastra.chat_turn",
441
+ {
442
+ kind: SpanKind.SERVER,
443
+ attributes: {
444
+ [APPKIT_AGENT_TRACE_ROOT_ATTR]: true,
445
+ [MLFLOW_SPAN_TYPE_ATTR]: MLFLOW_SPAN_TYPE_AGENT,
446
+ [GEN_AI_OPERATION_NAME_ATTR]: "invoke_agent",
468
447
  },
469
- activeContext,
470
- );
448
+ },
449
+ activeContext,
450
+ );
471
451
  if (!span.isRecording()) {
472
452
  span.end();
473
453
  return undefined;
@@ -506,9 +486,8 @@ export function chatTurnTelemetryMiddleware(
506
486
  next();
507
487
  return;
508
488
  }
509
- const traceState: ChatTraceState = { models: new Set(), tags: new Map() };
489
+ const traceState: ChatTraceState = { tags: new Map() };
510
490
  const traceRequestTime = Date.now();
511
- setChatTraceTag(traceState, MLFLOW_AGENT_TAG, true);
512
491
  if (!appkit.isDatabricksAppEnv()) {
513
492
  setChatTraceTag(traceState, MLFLOW_LOCAL_TAG, true);
514
493
  }
@@ -525,7 +504,6 @@ export function chatTurnTelemetryMiddleware(
525
504
  traceState.user = stampMlflowActor(target.span, req);
526
505
  target.span.setAttribute(MLFLOW_SPAN_TYPE_ATTR, MLFLOW_SPAN_TYPE_AGENT);
527
506
  target.span.setAttribute(GEN_AI_OPERATION_NAME_ATTR, "invoke_agent");
528
- target.span.setAttribute(MLFLOW_AGENT_TAG_ATTR, "true");
529
507
  const identity =
530
508
  typeof options.identity === "function" ? options.identity(req) : options.identity;
531
509
  if (identity) {
@@ -544,10 +522,7 @@ export function chatTurnTelemetryMiddleware(
544
522
  const fullInput = serialized(messages);
545
523
  requestPreview = textOnlyChatInput(messages) ?? fullInput;
546
524
  target.span.setAttribute(CHAT_MESSAGES_ATTR, fullInput);
547
- target.span.setAttribute(
548
- MLFLOW_SPAN_INPUTS_ATTR,
549
- requestPreview.slice(0, TRACE_IO_LIMIT),
550
- );
525
+ target.span.setAttribute(MLFLOW_SPAN_INPUTS_ATTR, requestPreview.slice(0, TRACE_IO_LIMIT));
551
526
  }
552
527
 
553
528
  const collector = new AssistantResponseCollector();
@@ -584,8 +559,6 @@ export function chatTurnTelemetryMiddleware(
584
559
  const finalizeTrace = (): void => {
585
560
  if (traceFinalized) return;
586
561
  traceFinalized = true;
587
- const model = modelTraceTag(traceState.models);
588
- if (model) setChatTraceTag(traceState, MLFLOW_MODEL_TAG, model);
589
562
  const tags = Object.fromEntries(traceState.tags);
590
563
  for (const [name, value] of traceState.tags) {
591
564
  target.span.setAttribute(`${MLFLOW_TRACE_TAG_PREFIX}${name}`, value);
@@ -651,7 +624,6 @@ export function chatTurnTelemetryMiddleware(
651
624
  .setSpan(context.active(), target.span)
652
625
  .setValue(CHAT_TRACE_STATE_KEY, traceState);
653
626
  context.with(chatContext, () => {
654
- updateActiveMlflowTraceTags({ [MLFLOW_AGENT_TAG]: "true" });
655
627
  next();
656
628
  });
657
629
  }
@@ -7,9 +7,6 @@ export const MLFLOW_AGENT_TAG = "agent";
7
7
  /** Experiment-UI tag marking a turn that called Genie. */
8
8
  export const MLFLOW_GENIE_TAG = "genie";
9
9
 
10
- /** Experiment-UI tag recording the model or ordered models used by a turn. */
11
- export const MLFLOW_MODEL_TAG = "model";
12
-
13
10
  /** Experiment-UI tag marking a turn that invoked OBO authentication. */
14
11
  export const MLFLOW_OBO_AUTH_TAG = "obo_auth";
15
12
 
@@ -25,8 +22,8 @@ export const MLFLOW_AGENT_TAG_ATTR = `${MLFLOW_TRACE_TAG_PREFIX}${MLFLOW_AGENT_T
25
22
  /** Attribute key for the `genie` trace tag. */
26
23
  export const MLFLOW_GENIE_TAG_ATTR = `${MLFLOW_TRACE_TAG_PREFIX}${MLFLOW_GENIE_TAG}`;
27
24
 
28
- /** Attribute key for the `model` trace tag. */
29
- export const MLFLOW_MODEL_TAG_ATTR = `${MLFLOW_TRACE_TAG_PREFIX}${MLFLOW_MODEL_TAG}`;
25
+ /** Internal root marker used by direct MLflow span filtering. */
26
+ export const APPKIT_AGENT_TRACE_ROOT_ATTR = "appkit.mastra.trace.agent";
30
27
 
31
28
  /** Attribute key for the `obo_auth` trace tag. */
32
29
  export const MLFLOW_OBO_AUTH_TAG_ATTR = `${MLFLOW_TRACE_TAG_PREFIX}${MLFLOW_OBO_AUTH_TAG}`;