@mastra/observability 1.20.2-alpha.0 → 1.21.0-alpha.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/dist/index.cjs +93 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -23
- package/dist/index.js.map +1 -1
- package/dist/metrics/auto-extract.d.ts +1 -1
- package/dist/metrics/auto-extract.d.ts.map +1 -1
- package/dist/metrics/pricing-data.json +2573 -935
- package/dist/model-tracing.d.ts +3 -2
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/spans/base.d.ts +2 -2
- package/dist/spans/base.d.ts.map +1 -1
- package/package.json +6 -7
package/dist/index.js
CHANGED
|
@@ -1943,12 +1943,20 @@ function emitDurationMetrics(span, metrics) {
|
|
|
1943
1943
|
const durationMs = span.endTime.getTime() - span.startTime.getTime();
|
|
1944
1944
|
metrics.emit(durationMetricName, durationMs, { status: span.errorInfo ? "error" : "ok" });
|
|
1945
1945
|
}
|
|
1946
|
-
/** Emit token usage metrics for a model-generation span. */
|
|
1946
|
+
/** Emit token usage metrics for a model-generation or classifier-evaluation span. */
|
|
1947
1947
|
function emitTokenMetrics(span, metrics) {
|
|
1948
|
-
if (span.type
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1948
|
+
if (span.type === SpanType.MODEL_GENERATION) {
|
|
1949
|
+
const attrs = span.attributes;
|
|
1950
|
+
if (attrs?.usage) emitUsageMetrics(attrs, attrs.usage, metrics);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (span.type === SpanType.CLASSIFIER_EVALUATION) {
|
|
1954
|
+
const attrs = span.attributes;
|
|
1955
|
+
if (attrs?.usage) emitUsageMetrics({
|
|
1956
|
+
provider: attrs.provider,
|
|
1957
|
+
model: attrs.modelId
|
|
1958
|
+
}, attrs.usage, metrics);
|
|
1959
|
+
}
|
|
1952
1960
|
}
|
|
1953
1961
|
/**
|
|
1954
1962
|
* Emit token usage metrics from an explicit usage payload, using the supplied
|
|
@@ -2480,6 +2488,26 @@ function extractStepInput(payload) {
|
|
|
2480
2488
|
}
|
|
2481
2489
|
}
|
|
2482
2490
|
/**
|
|
2491
|
+
* Chunks that come from the model provider. The first one marks the response's
|
|
2492
|
+
* first chunk, matching OTel's `gen_ai.response.time_to_first_chunk`. Everything
|
|
2493
|
+
* else, such as lifecycle markers or `data-*` parts a processor writes before the
|
|
2494
|
+
* model call, is Mastra's own and does not count.
|
|
2495
|
+
*/
|
|
2496
|
+
const MODEL_RESPONSE_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
2497
|
+
"response-metadata",
|
|
2498
|
+
"raw",
|
|
2499
|
+
"text-start",
|
|
2500
|
+
"text-delta",
|
|
2501
|
+
"reasoning-start",
|
|
2502
|
+
"reasoning-delta",
|
|
2503
|
+
"reasoning-file",
|
|
2504
|
+
"tool-call-input-streaming-start",
|
|
2505
|
+
"tool-call-delta",
|
|
2506
|
+
"tool-call",
|
|
2507
|
+
"source",
|
|
2508
|
+
"file"
|
|
2509
|
+
]);
|
|
2510
|
+
/**
|
|
2483
2511
|
* Manages MODEL_STEP and MODEL_CHUNK span tracking for streaming Model responses.
|
|
2484
2512
|
*
|
|
2485
2513
|
* Should be instantiated once per MODEL_GENERATION span and shared across
|
|
@@ -2496,6 +2524,15 @@ var ModelSpanTracker = class {
|
|
|
2496
2524
|
#chunkSequence = 0;
|
|
2497
2525
|
#completionStartTime;
|
|
2498
2526
|
#inferenceCompletionStartTime;
|
|
2527
|
+
/**
|
|
2528
|
+
* True between a step's `step-start` and `step-finish` chunks, the window in which
|
|
2529
|
+
* the provider responds. Chunks outside it, such as a `tool-call` replayed for a
|
|
2530
|
+
* finished background task on resume, are Mastra's own and never start the clock.
|
|
2531
|
+
* Durable runs wrap one step's provider stream at a time, so every chunk there counts.
|
|
2532
|
+
*/
|
|
2533
|
+
#inModelResponse = false;
|
|
2534
|
+
/** Set only by the agent's main loop; receives the first chunk's completionStartTime. */
|
|
2535
|
+
#agentRunSpan;
|
|
2499
2536
|
#currentStepInputIsFinal = false;
|
|
2500
2537
|
/** When true, step-finish chunks don't auto-close the step span (for durable execution) */
|
|
2501
2538
|
#deferStepClose = false;
|
|
@@ -2503,8 +2540,9 @@ var ModelSpanTracker = class {
|
|
|
2503
2540
|
#pendingStepFinishPayload;
|
|
2504
2541
|
/** Static request-side context applied to every MODEL_INFERENCE span */
|
|
2505
2542
|
#inferenceContext;
|
|
2506
|
-
constructor(modelSpan) {
|
|
2543
|
+
constructor(modelSpan, options) {
|
|
2507
2544
|
this.#modelSpan = modelSpan;
|
|
2545
|
+
this.#agentRunSpan = options?.agentRunSpan;
|
|
2508
2546
|
}
|
|
2509
2547
|
/**
|
|
2510
2548
|
* Set request-side context applied to subsequent MODEL_INFERENCE spans.
|
|
@@ -2514,12 +2552,22 @@ var ModelSpanTracker = class {
|
|
|
2514
2552
|
this.#inferenceContext = context;
|
|
2515
2553
|
}
|
|
2516
2554
|
/**
|
|
2517
|
-
*
|
|
2555
|
+
* Record when the provider's first chunk arrived and copy that clock up the
|
|
2556
|
+
* agent's own chain (inference → step → generation → agent run), first write
|
|
2557
|
+
* wins at each level. Time to first chunk is derived later as
|
|
2558
|
+
* `completionStartTime - startTime` on whichever span is being read.
|
|
2518
2559
|
*/
|
|
2519
2560
|
#captureCompletionStartTime() {
|
|
2561
|
+
this.#ensureStepAndInference();
|
|
2562
|
+
if (this.#inferenceCompletionStartTime) return;
|
|
2520
2563
|
const now = /* @__PURE__ */ new Date();
|
|
2564
|
+
this.#inferenceCompletionStartTime = now;
|
|
2521
2565
|
this.#completionStartTime ??= now;
|
|
2522
|
-
|
|
2566
|
+
for (const span of [
|
|
2567
|
+
this.#currentStepSpan,
|
|
2568
|
+
this.#modelSpan,
|
|
2569
|
+
this.#agentRunSpan
|
|
2570
|
+
]) if (span && !span.attributes?.completionStartTime) span.update({ attributes: { completionStartTime: now } });
|
|
2523
2571
|
}
|
|
2524
2572
|
/**
|
|
2525
2573
|
* Get the tracing context for creating child spans.
|
|
@@ -2563,13 +2611,16 @@ var ModelSpanTracker = class {
|
|
|
2563
2611
|
}, model);
|
|
2564
2612
|
if (providerCostContext && !spanOptions.attributes) spanOptions.attributes = {};
|
|
2565
2613
|
if (spanOptions.attributes) {
|
|
2566
|
-
spanOptions.attributes.completionStartTime = this.#completionStartTime;
|
|
2614
|
+
spanOptions.attributes.completionStartTime = this.#completionStartTime ?? spanOptions.attributes.completionStartTime;
|
|
2567
2615
|
spanOptions.attributes.usage = extractUsageMetrics(usage, providerMetadata);
|
|
2568
2616
|
spanOptions.attributes.costContext = providerCostContext ?? spanOptions.attributes.costContext;
|
|
2569
2617
|
if (!spanOptions.attributes.costContext) spanOptions.attributes.costContext = getGatewayCostContext({ stepProviderMetadata });
|
|
2570
2618
|
}
|
|
2571
2619
|
this.#modelSpan?.end(spanOptions);
|
|
2572
2620
|
}
|
|
2621
|
+
getCompletionStartTime() {
|
|
2622
|
+
return this.#completionStartTime;
|
|
2623
|
+
}
|
|
2573
2624
|
/**
|
|
2574
2625
|
* Update the generation span
|
|
2575
2626
|
*/
|
|
@@ -2637,6 +2688,7 @@ var ModelSpanTracker = class {
|
|
|
2637
2688
|
});
|
|
2638
2689
|
this.#currentStepInputIsFinal = Array.isArray(payload?.inputMessages);
|
|
2639
2690
|
this.#chunkSequence = 0;
|
|
2691
|
+
this.#inferenceCompletionStartTime = void 0;
|
|
2640
2692
|
}
|
|
2641
2693
|
/**
|
|
2642
2694
|
* End the current MODEL_INFERENCE span when the provider stream finishes.
|
|
@@ -2767,6 +2819,26 @@ var ModelSpanTracker = class {
|
|
|
2767
2819
|
this.#stepIndex++;
|
|
2768
2820
|
}
|
|
2769
2821
|
/**
|
|
2822
|
+
* A suspended step emits no step-finish; its suspension chunk carries the
|
|
2823
|
+
* step usage instead. Close MODEL_INFERENCE and MODEL_STEP with that usage so
|
|
2824
|
+
* the suspended call is not reported without tokens.
|
|
2825
|
+
*/
|
|
2826
|
+
#endSuspendedStep(chunk) {
|
|
2827
|
+
if (chunk.type !== "tool-call-suspended" && chunk.type !== "tool-call-approval") return;
|
|
2828
|
+
const usage = chunk.payload.usage;
|
|
2829
|
+
if (!usage) return;
|
|
2830
|
+
this.#inModelResponse = false;
|
|
2831
|
+
this.#endStepSpan({
|
|
2832
|
+
output: { usage },
|
|
2833
|
+
stepResult: {
|
|
2834
|
+
reason: "suspended",
|
|
2835
|
+
isContinued: false,
|
|
2836
|
+
warnings: []
|
|
2837
|
+
},
|
|
2838
|
+
metadata: {}
|
|
2839
|
+
});
|
|
2840
|
+
}
|
|
2841
|
+
/**
|
|
2770
2842
|
* Returns the parent span for chunks. Chunks parent under MODEL_INFERENCE
|
|
2771
2843
|
* (the provider call) when available, falling back to MODEL_STEP only if
|
|
2772
2844
|
* startStep() was bypassed.
|
|
@@ -2938,8 +3010,8 @@ var ModelSpanTracker = class {
|
|
|
2938
3010
|
#handleToolApprovalChunk(chunk) {
|
|
2939
3011
|
if (chunk.type !== "tool-call-approval") return;
|
|
2940
3012
|
const payload = chunk.payload;
|
|
2941
|
-
this.#ensureStepAndInference();
|
|
2942
|
-
if (this.#chunkParent()?.createEventSpan({
|
|
3013
|
+
if (payload.usage || this.#currentStepSpan) this.#ensureStepAndInference();
|
|
3014
|
+
if ((this.#chunkParent() ?? this.#modelSpan)?.createEventSpan({
|
|
2943
3015
|
name: `chunk: 'tool-call-approval'`,
|
|
2944
3016
|
type: SpanType.MODEL_CHUNK,
|
|
2945
3017
|
attributes: {
|
|
@@ -2958,12 +3030,10 @@ var ModelSpanTracker = class {
|
|
|
2958
3030
|
*/
|
|
2959
3031
|
wrapStream(stream) {
|
|
2960
3032
|
return stream.pipeThrough(new TransformStream({ transform: (chunk, controller) => {
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
this.#captureCompletionStartTime();
|
|
2966
|
-
break;
|
|
3033
|
+
if ((this.#inModelResponse || this.#deferStepClose) && MODEL_RESPONSE_CHUNK_TYPES.has(chunk.type)) this.#captureCompletionStartTime();
|
|
3034
|
+
if (chunk.type === "tool-call-suspended" || chunk.type === "tool-call-approval") {
|
|
3035
|
+
if (chunk.type === "tool-call-approval") this.#handleToolApprovalChunk(chunk);
|
|
3036
|
+
this.#endSuspendedStep(chunk);
|
|
2967
3037
|
}
|
|
2968
3038
|
controller.enqueue(chunk);
|
|
2969
3039
|
switch (chunk.type) {
|
|
@@ -2988,11 +3058,13 @@ var ModelSpanTracker = class {
|
|
|
2988
3058
|
this.#handleObjectChunk(chunk);
|
|
2989
3059
|
break;
|
|
2990
3060
|
case "step-start":
|
|
3061
|
+
this.#inModelResponse = true;
|
|
2991
3062
|
if (this.#currentStepSpan) this.updateStep(chunk.payload);
|
|
2992
3063
|
else this.startStep(chunk.payload);
|
|
2993
3064
|
if (!this.#currentInferenceSpan) this.startInference(chunk.payload);
|
|
2994
3065
|
break;
|
|
2995
3066
|
case "step-finish":
|
|
3067
|
+
this.#inModelResponse = false;
|
|
2996
3068
|
if (this.#deferStepClose) {
|
|
2997
3069
|
this.#pendingStepFinishPayload = chunk.payload;
|
|
2998
3070
|
this.#endChunkSpan();
|
|
@@ -3010,13 +3082,11 @@ var ModelSpanTracker = class {
|
|
|
3010
3082
|
case "tripwire":
|
|
3011
3083
|
case "watch":
|
|
3012
3084
|
case "tool-error":
|
|
3013
|
-
case "tool-call-suspended":
|
|
3014
3085
|
case "reasoning-signature":
|
|
3015
3086
|
case "redacted-reasoning":
|
|
3016
3087
|
case "step-output": break;
|
|
3017
|
-
case "tool-call-
|
|
3018
|
-
|
|
3019
|
-
break;
|
|
3088
|
+
case "tool-call-suspended":
|
|
3089
|
+
case "tool-call-approval": break;
|
|
3020
3090
|
case "tool-output": break;
|
|
3021
3091
|
case "tool-result": {
|
|
3022
3092
|
const { toolCallId, toolName, isError, dynamic, providerExecuted, providerMetadata, result, args: _args } = chunk.payload || {};
|
|
@@ -3350,9 +3420,9 @@ var BaseSpan = class BaseSpan {
|
|
|
3350
3420
|
* Create a ModelSpanTracker for this span (only works if this is a MODEL_GENERATION span)
|
|
3351
3421
|
* Returns undefined for non-MODEL_GENERATION spans
|
|
3352
3422
|
*/
|
|
3353
|
-
createTracker() {
|
|
3423
|
+
createTracker(options) {
|
|
3354
3424
|
if (this.type !== SpanType.MODEL_GENERATION) return;
|
|
3355
|
-
return new ModelSpanTracker(this);
|
|
3425
|
+
return new ModelSpanTracker(this, options);
|
|
3356
3426
|
}
|
|
3357
3427
|
/** Returns `TRUE` if the span is the root span of a trace */
|
|
3358
3428
|
get isRootSpan() {
|