@mastra/observability 1.0.0-beta.2 → 1.0.0-beta.3
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 +31 -0
- package/dist/index.cjs +116 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +116 -1
- package/dist/index.js.map +1 -1
- package/dist/model-tracing.d.ts +0 -6
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/tracing-options.d.ts +27 -0
- package/dist/tracing-options.d.ts.map +1 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @mastra/observability
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add time-to-first-token (TTFT) support for Braintrust integration ([#10840](https://github.com/mastra-ai/mastra/pull/10840))
|
|
8
|
+
|
|
9
|
+
Adds `time_to_first_token` metric to Braintrust spans, populated from the `completionStartTime` attribute captured when the first streaming chunk arrives.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// time_to_first_token is now automatically sent to Braintrust
|
|
13
|
+
// as part of span metrics during streaming
|
|
14
|
+
const result = await agent.stream('Hello');
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Add time-to-first-token (TTFT) support for Langfuse integration ([#10781](https://github.com/mastra-ai/mastra/pull/10781))
|
|
18
|
+
|
|
19
|
+
Adds `completionStartTime` to model generation spans, which Langfuse uses to calculate TTFT metrics. The timestamp is automatically captured when the first content chunk arrives during streaming.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// completionStartTime is now automatically captured and sent to Langfuse
|
|
23
|
+
// enabling TTFT metrics in your Langfuse dashboard
|
|
24
|
+
const result = await agent.stream('Hello');
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- Consolidated tool-output chunks from nested agents into single tool-result spans ([#10836](https://github.com/mastra-ai/mastra/pull/10836))
|
|
28
|
+
|
|
29
|
+
- link langfuse prompts and helper functions ([#10738](https://github.com/mastra-ai/mastra/pull/10738))
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [[`3076c67`](https://github.com/mastra-ai/mastra/commit/3076c6778b18988ae7d5c4c5c466366974b2d63f), [`85d7ee1`](https://github.com/mastra-ai/mastra/commit/85d7ee18ff4e14d625a8a30ec6656bb49804989b), [`c6c1092`](https://github.com/mastra-ai/mastra/commit/c6c1092f8fbf76109303f69e000e96fd1960c4ce), [`81dc110`](https://github.com/mastra-ai/mastra/commit/81dc11008d147cf5bdc8996ead1aa61dbdebb6fc), [`7aedb74`](https://github.com/mastra-ai/mastra/commit/7aedb74883adf66af38e270e4068fd42e7a37036), [`8f02d80`](https://github.com/mastra-ai/mastra/commit/8f02d800777397e4b45d7f1ad041988a8b0c6630), [`d7aad50`](https://github.com/mastra-ai/mastra/commit/d7aad501ce61646b76b4b511e558ac4eea9884d0), [`ce0a73a`](https://github.com/mastra-ai/mastra/commit/ce0a73abeaa75b10ca38f9e40a255a645d50ebfb), [`a02e542`](https://github.com/mastra-ai/mastra/commit/a02e542d23179bad250b044b17ff023caa61739f), [`a372c64`](https://github.com/mastra-ai/mastra/commit/a372c640ad1fd12e8f0613cebdc682fc156b4d95), [`8846867`](https://github.com/mastra-ai/mastra/commit/8846867ffa9a3746767618e314bebac08eb77d87), [`42a42cf`](https://github.com/mastra-ai/mastra/commit/42a42cf3132b9786feecbb8c13c583dce5b0e198), [`ae08bf0`](https://github.com/mastra-ai/mastra/commit/ae08bf0ebc6a4e4da992b711c4a389c32ba84cf4), [`21735a7`](https://github.com/mastra-ai/mastra/commit/21735a7ef306963554a69a89b44f06c3bcd85141), [`1d877b8`](https://github.com/mastra-ai/mastra/commit/1d877b8d7b536a251c1a7a18db7ddcf4f68d6f8b)]:
|
|
32
|
+
- @mastra/core@1.0.0-beta.7
|
|
33
|
+
|
|
3
34
|
## 1.0.0-beta.2
|
|
4
35
|
|
|
5
36
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -955,9 +955,30 @@ var ModelSpanTracker = class {
|
|
|
955
955
|
#accumulator = {};
|
|
956
956
|
#stepIndex = 0;
|
|
957
957
|
#chunkSequence = 0;
|
|
958
|
+
/** Tracks whether completionStartTime has been captured for this generation */
|
|
959
|
+
#completionStartTimeCaptured = false;
|
|
960
|
+
/** Tracks tool output accumulators by toolCallId for consolidating sub-agent streams */
|
|
961
|
+
#toolOutputAccumulators = /* @__PURE__ */ new Map();
|
|
962
|
+
/** Tracks toolCallIds that had streaming output (to skip redundant tool-result spans) */
|
|
963
|
+
#streamedToolCallIds = /* @__PURE__ */ new Set();
|
|
958
964
|
constructor(modelSpan) {
|
|
959
965
|
this.#modelSpan = modelSpan;
|
|
960
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Capture the completion start time (time to first token) when the first content chunk arrives.
|
|
969
|
+
* This is used by observability providers like Langfuse to calculate TTFT metrics.
|
|
970
|
+
*/
|
|
971
|
+
#captureCompletionStartTime() {
|
|
972
|
+
if (this.#completionStartTimeCaptured || !this.#modelSpan) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
this.#completionStartTimeCaptured = true;
|
|
976
|
+
this.#modelSpan.update({
|
|
977
|
+
attributes: {
|
|
978
|
+
completionStartTime: /* @__PURE__ */ new Date()
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
961
982
|
/**
|
|
962
983
|
* Get the tracing context for creating child spans.
|
|
963
984
|
* Returns the current step span if active, otherwise the model span.
|
|
@@ -1182,6 +1203,77 @@ var ModelSpanTracker = class {
|
|
|
1182
1203
|
break;
|
|
1183
1204
|
}
|
|
1184
1205
|
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Handle tool-output chunks from sub-agents.
|
|
1208
|
+
* Consolidates streaming text/reasoning deltas into a single span per tool call.
|
|
1209
|
+
*/
|
|
1210
|
+
#handleToolOutputChunk(chunk) {
|
|
1211
|
+
if (chunk.type !== "tool-output") return;
|
|
1212
|
+
const payload = chunk.payload;
|
|
1213
|
+
const { output, toolCallId, toolName } = payload;
|
|
1214
|
+
let acc = this.#toolOutputAccumulators.get(toolCallId);
|
|
1215
|
+
if (!acc) {
|
|
1216
|
+
if (!this.#currentStepSpan) {
|
|
1217
|
+
this.#startStepSpan();
|
|
1218
|
+
}
|
|
1219
|
+
acc = {
|
|
1220
|
+
toolName: toolName || "unknown",
|
|
1221
|
+
toolCallId,
|
|
1222
|
+
text: "",
|
|
1223
|
+
reasoning: "",
|
|
1224
|
+
sequenceNumber: this.#chunkSequence++,
|
|
1225
|
+
// Name the span 'tool-result' for consistency (tool-call → tool-result)
|
|
1226
|
+
span: this.#currentStepSpan?.createChildSpan({
|
|
1227
|
+
name: `chunk: 'tool-result'`,
|
|
1228
|
+
type: observability.SpanType.MODEL_CHUNK,
|
|
1229
|
+
attributes: {
|
|
1230
|
+
chunkType: "tool-result",
|
|
1231
|
+
sequenceNumber: this.#chunkSequence - 1
|
|
1232
|
+
}
|
|
1233
|
+
})
|
|
1234
|
+
};
|
|
1235
|
+
this.#toolOutputAccumulators.set(toolCallId, acc);
|
|
1236
|
+
}
|
|
1237
|
+
if (output && typeof output === "object" && "type" in output) {
|
|
1238
|
+
const innerType = output.type;
|
|
1239
|
+
switch (innerType) {
|
|
1240
|
+
case "text-delta":
|
|
1241
|
+
if (output.payload?.text) {
|
|
1242
|
+
acc.text += output.payload.text;
|
|
1243
|
+
}
|
|
1244
|
+
break;
|
|
1245
|
+
case "reasoning-delta":
|
|
1246
|
+
if (output.payload?.text) {
|
|
1247
|
+
acc.reasoning += output.payload.text;
|
|
1248
|
+
}
|
|
1249
|
+
break;
|
|
1250
|
+
case "finish":
|
|
1251
|
+
case "workflow-finish":
|
|
1252
|
+
this.#endToolOutputSpan(toolCallId);
|
|
1253
|
+
break;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* End a tool output span and clean up the accumulator
|
|
1259
|
+
*/
|
|
1260
|
+
#endToolOutputSpan(toolCallId) {
|
|
1261
|
+
const acc = this.#toolOutputAccumulators.get(toolCallId);
|
|
1262
|
+
if (!acc) return;
|
|
1263
|
+
const output = {
|
|
1264
|
+
toolCallId: acc.toolCallId,
|
|
1265
|
+
toolName: acc.toolName
|
|
1266
|
+
};
|
|
1267
|
+
if (acc.text) {
|
|
1268
|
+
output.text = acc.text;
|
|
1269
|
+
}
|
|
1270
|
+
if (acc.reasoning) {
|
|
1271
|
+
output.reasoning = acc.reasoning;
|
|
1272
|
+
}
|
|
1273
|
+
acc.span?.end({ output });
|
|
1274
|
+
this.#toolOutputAccumulators.delete(toolCallId);
|
|
1275
|
+
this.#streamedToolCallIds.add(toolCallId);
|
|
1276
|
+
}
|
|
1185
1277
|
/**
|
|
1186
1278
|
* Wraps a stream with model tracing transform to track MODEL_STEP and MODEL_CHUNK spans.
|
|
1187
1279
|
*
|
|
@@ -1189,9 +1281,14 @@ var ModelSpanTracker = class {
|
|
|
1189
1281
|
* create MODEL_STEP and MODEL_CHUNK spans for each semantic unit in the stream.
|
|
1190
1282
|
*/
|
|
1191
1283
|
wrapStream(stream) {
|
|
1284
|
+
let captureCompletionStartTime = false;
|
|
1192
1285
|
return stream.pipeThrough(
|
|
1193
1286
|
new web.TransformStream({
|
|
1194
1287
|
transform: (chunk, controller) => {
|
|
1288
|
+
if (!captureCompletionStartTime) {
|
|
1289
|
+
captureCompletionStartTime = true;
|
|
1290
|
+
this.#captureCompletionStartTime();
|
|
1291
|
+
}
|
|
1195
1292
|
controller.enqueue(chunk);
|
|
1196
1293
|
switch (chunk.type) {
|
|
1197
1294
|
case "text-start":
|
|
@@ -1225,6 +1322,19 @@ var ModelSpanTracker = class {
|
|
|
1225
1322
|
case "start":
|
|
1226
1323
|
case "finish":
|
|
1227
1324
|
break;
|
|
1325
|
+
case "tool-output":
|
|
1326
|
+
this.#handleToolOutputChunk(chunk);
|
|
1327
|
+
break;
|
|
1328
|
+
case "tool-result": {
|
|
1329
|
+
const toolCallId = chunk.payload?.toolCallId;
|
|
1330
|
+
if (toolCallId && this.#streamedToolCallIds.has(toolCallId)) {
|
|
1331
|
+
this.#streamedToolCallIds.delete(toolCallId);
|
|
1332
|
+
break;
|
|
1333
|
+
}
|
|
1334
|
+
const { args, ...cleanPayload } = chunk.payload || {};
|
|
1335
|
+
this.#createEventSpan(chunk.type, cleanPayload);
|
|
1336
|
+
break;
|
|
1337
|
+
}
|
|
1228
1338
|
// Default: auto-create event span for all other chunk types
|
|
1229
1339
|
default: {
|
|
1230
1340
|
let outputPayload = chunk.payload;
|
|
@@ -2324,6 +2434,11 @@ var Observability = class extends base.MastraBase {
|
|
|
2324
2434
|
}
|
|
2325
2435
|
};
|
|
2326
2436
|
|
|
2437
|
+
// src/tracing-options.ts
|
|
2438
|
+
function buildTracingOptions(...updaters) {
|
|
2439
|
+
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2327
2442
|
exports.BaseExporter = BaseExporter;
|
|
2328
2443
|
exports.BaseObservabilityInstance = BaseObservabilityInstance;
|
|
2329
2444
|
exports.BaseSpan = BaseSpan;
|
|
@@ -2338,6 +2453,7 @@ exports.Observability = Observability;
|
|
|
2338
2453
|
exports.SamplingStrategyType = SamplingStrategyType;
|
|
2339
2454
|
exports.SensitiveDataFilter = SensitiveDataFilter;
|
|
2340
2455
|
exports.TestExporter = TestExporter;
|
|
2456
|
+
exports.buildTracingOptions = buildTracingOptions;
|
|
2341
2457
|
exports.deepClean = deepClean;
|
|
2342
2458
|
exports.getExternalParentId = getExternalParentId;
|
|
2343
2459
|
exports.observabilityConfigValueSchema = observabilityConfigValueSchema;
|