@mastra/observability 1.0.0-beta.2 → 1.0.0-beta.4
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 +40 -0
- package/dist/index.cjs +176 -3
- 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 +176 -4
- package/dist/index.js.map +1 -1
- package/dist/model-tracing.d.ts +4 -9
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/spans/base.d.ts.map +1 -1
- package/dist/tracing-options.d.ts +27 -0
- package/dist/tracing-options.d.ts.map +1 -0
- package/dist/usage.d.ts +21 -0
- package/dist/usage.d.ts.map +1 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @mastra/observability
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed CachedToken tracking in all Observability Exporters. Also fixed TimeToFirstToken in Langfuse, Braintrust, PostHog exporters. Fixed trace formatting in Posthog Exporter. ([#11029](https://github.com/mastra-ai/mastra/pull/11029))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`edb07e4`](https://github.com/mastra-ai/mastra/commit/edb07e49283e0c28bd094a60e03439bf6ecf0221), [`b7e17d3`](https://github.com/mastra-ai/mastra/commit/b7e17d3f5390bb5a71efc112204413656fcdc18d), [`261473a`](https://github.com/mastra-ai/mastra/commit/261473ac637e633064a22076671e2e02b002214d), [`5d7000f`](https://github.com/mastra-ai/mastra/commit/5d7000f757cd65ea9dc5b05e662fd83dfd44e932), [`4f0331a`](https://github.com/mastra-ai/mastra/commit/4f0331a79bf6eb5ee598a5086e55de4b5a0ada03), [`8a000da`](https://github.com/mastra-ai/mastra/commit/8a000da0c09c679a2312f6b3aa05b2ca78ca7393)]:
|
|
10
|
+
- @mastra/core@1.0.0-beta.10
|
|
11
|
+
|
|
12
|
+
## 1.0.0-beta.3
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Add time-to-first-token (TTFT) support for Braintrust integration ([#10840](https://github.com/mastra-ai/mastra/pull/10840))
|
|
17
|
+
|
|
18
|
+
Adds `time_to_first_token` metric to Braintrust spans, populated from the `completionStartTime` attribute captured when the first streaming chunk arrives.
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// time_to_first_token is now automatically sent to Braintrust
|
|
22
|
+
// as part of span metrics during streaming
|
|
23
|
+
const result = await agent.stream('Hello');
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- Add time-to-first-token (TTFT) support for Langfuse integration ([#10781](https://github.com/mastra-ai/mastra/pull/10781))
|
|
27
|
+
|
|
28
|
+
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.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// completionStartTime is now automatically captured and sent to Langfuse
|
|
32
|
+
// enabling TTFT metrics in your Langfuse dashboard
|
|
33
|
+
const result = await agent.stream('Hello');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Consolidated tool-output chunks from nested agents into single tool-result spans ([#10836](https://github.com/mastra-ai/mastra/pull/10836))
|
|
37
|
+
|
|
38
|
+
- link langfuse prompts and helper functions ([#10738](https://github.com/mastra-ai/mastra/pull/10738))
|
|
39
|
+
|
|
40
|
+
- 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)]:
|
|
41
|
+
- @mastra/core@1.0.0-beta.7
|
|
42
|
+
|
|
3
43
|
## 1.0.0-beta.2
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -948,6 +948,58 @@ var TestExporter = class extends BaseExporter {
|
|
|
948
948
|
this.logger.info("TestExporter shutdown");
|
|
949
949
|
}
|
|
950
950
|
};
|
|
951
|
+
|
|
952
|
+
// src/usage.ts
|
|
953
|
+
function extractUsageMetrics(usage, providerMetadata) {
|
|
954
|
+
if (!usage) {
|
|
955
|
+
return {};
|
|
956
|
+
}
|
|
957
|
+
const inputDetails = {};
|
|
958
|
+
const outputDetails = {};
|
|
959
|
+
let inputTokens = usage.inputTokens;
|
|
960
|
+
const outputTokens = usage.outputTokens;
|
|
961
|
+
if (usage.cachedInputTokens) {
|
|
962
|
+
inputDetails.cacheRead = usage.cachedInputTokens;
|
|
963
|
+
}
|
|
964
|
+
if (usage.reasoningTokens) {
|
|
965
|
+
outputDetails.reasoning = usage.reasoningTokens;
|
|
966
|
+
}
|
|
967
|
+
const anthropic = providerMetadata?.anthropic;
|
|
968
|
+
if (anthropic) {
|
|
969
|
+
if (anthropic.cacheReadInputTokens) {
|
|
970
|
+
inputDetails.cacheRead = anthropic.cacheReadInputTokens;
|
|
971
|
+
}
|
|
972
|
+
if (anthropic.cacheCreationInputTokens) {
|
|
973
|
+
inputDetails.cacheWrite = anthropic.cacheCreationInputTokens;
|
|
974
|
+
}
|
|
975
|
+
if (anthropic.cacheReadInputTokens || anthropic.cacheCreationInputTokens) {
|
|
976
|
+
inputDetails.text = usage.inputTokens;
|
|
977
|
+
inputTokens = (usage.inputTokens ?? 0) + (anthropic.cacheReadInputTokens ?? 0) + (anthropic.cacheCreationInputTokens ?? 0);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
const google = providerMetadata?.google;
|
|
981
|
+
if (google?.usageMetadata) {
|
|
982
|
+
if (google.usageMetadata.cachedContentTokenCount) {
|
|
983
|
+
inputDetails.cacheRead = google.usageMetadata.cachedContentTokenCount;
|
|
984
|
+
}
|
|
985
|
+
if (google.usageMetadata.thoughtsTokenCount) {
|
|
986
|
+
outputDetails.reasoning = google.usageMetadata.thoughtsTokenCount;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
const result = {
|
|
990
|
+
inputTokens,
|
|
991
|
+
outputTokens
|
|
992
|
+
};
|
|
993
|
+
if (Object.keys(inputDetails).length > 0) {
|
|
994
|
+
result.inputDetails = inputDetails;
|
|
995
|
+
}
|
|
996
|
+
if (Object.keys(outputDetails).length > 0) {
|
|
997
|
+
result.outputDetails = outputDetails;
|
|
998
|
+
}
|
|
999
|
+
return result;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/model-tracing.ts
|
|
951
1003
|
var ModelSpanTracker = class {
|
|
952
1004
|
#modelSpan;
|
|
953
1005
|
#currentStepSpan;
|
|
@@ -955,9 +1007,23 @@ var ModelSpanTracker = class {
|
|
|
955
1007
|
#accumulator = {};
|
|
956
1008
|
#stepIndex = 0;
|
|
957
1009
|
#chunkSequence = 0;
|
|
1010
|
+
#completionStartTime;
|
|
1011
|
+
/** Tracks tool output accumulators by toolCallId for consolidating sub-agent streams */
|
|
1012
|
+
#toolOutputAccumulators = /* @__PURE__ */ new Map();
|
|
1013
|
+
/** Tracks toolCallIds that had streaming output (to skip redundant tool-result spans) */
|
|
1014
|
+
#streamedToolCallIds = /* @__PURE__ */ new Set();
|
|
958
1015
|
constructor(modelSpan) {
|
|
959
1016
|
this.#modelSpan = modelSpan;
|
|
960
1017
|
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Capture the completion start time (time to first token) when the first content chunk arrives.
|
|
1020
|
+
*/
|
|
1021
|
+
#captureCompletionStartTime() {
|
|
1022
|
+
if (this.#completionStartTime) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
this.#completionStartTime = /* @__PURE__ */ new Date();
|
|
1026
|
+
}
|
|
961
1027
|
/**
|
|
962
1028
|
* Get the tracing context for creating child spans.
|
|
963
1029
|
* Returns the current step span if active, otherwise the model span.
|
|
@@ -974,10 +1040,16 @@ var ModelSpanTracker = class {
|
|
|
974
1040
|
this.#modelSpan?.error(options);
|
|
975
1041
|
}
|
|
976
1042
|
/**
|
|
977
|
-
* End the generation span
|
|
1043
|
+
* End the generation span with optional raw usage data.
|
|
1044
|
+
* If usage is provided, it will be converted to UsageStats with cache token details.
|
|
978
1045
|
*/
|
|
979
1046
|
endGeneration(options) {
|
|
980
|
-
|
|
1047
|
+
const { usage, providerMetadata, ...spanOptions } = options ?? {};
|
|
1048
|
+
if (spanOptions.attributes) {
|
|
1049
|
+
spanOptions.attributes.completionStartTime = this.#completionStartTime;
|
|
1050
|
+
spanOptions.attributes.usage = extractUsageMetrics(usage, providerMetadata);
|
|
1051
|
+
}
|
|
1052
|
+
this.#modelSpan?.end(spanOptions);
|
|
981
1053
|
}
|
|
982
1054
|
/**
|
|
983
1055
|
* Update the generation span
|
|
@@ -1007,9 +1079,10 @@ var ModelSpanTracker = class {
|
|
|
1007
1079
|
#endStepSpan(payload) {
|
|
1008
1080
|
if (!this.#currentStepSpan) return;
|
|
1009
1081
|
const output = payload.output;
|
|
1010
|
-
const { usage, ...otherOutput } = output;
|
|
1082
|
+
const { usage: rawUsage, ...otherOutput } = output;
|
|
1011
1083
|
const stepResult = payload.stepResult;
|
|
1012
1084
|
const metadata = payload.metadata;
|
|
1085
|
+
const usage = extractUsageMetrics(rawUsage, metadata?.providerMetadata);
|
|
1013
1086
|
const cleanMetadata = metadata ? { ...metadata } : void 0;
|
|
1014
1087
|
if (cleanMetadata?.request) {
|
|
1015
1088
|
delete cleanMetadata.request;
|
|
@@ -1182,6 +1255,77 @@ var ModelSpanTracker = class {
|
|
|
1182
1255
|
break;
|
|
1183
1256
|
}
|
|
1184
1257
|
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Handle tool-output chunks from sub-agents.
|
|
1260
|
+
* Consolidates streaming text/reasoning deltas into a single span per tool call.
|
|
1261
|
+
*/
|
|
1262
|
+
#handleToolOutputChunk(chunk) {
|
|
1263
|
+
if (chunk.type !== "tool-output") return;
|
|
1264
|
+
const payload = chunk.payload;
|
|
1265
|
+
const { output, toolCallId, toolName } = payload;
|
|
1266
|
+
let acc = this.#toolOutputAccumulators.get(toolCallId);
|
|
1267
|
+
if (!acc) {
|
|
1268
|
+
if (!this.#currentStepSpan) {
|
|
1269
|
+
this.#startStepSpan();
|
|
1270
|
+
}
|
|
1271
|
+
acc = {
|
|
1272
|
+
toolName: toolName || "unknown",
|
|
1273
|
+
toolCallId,
|
|
1274
|
+
text: "",
|
|
1275
|
+
reasoning: "",
|
|
1276
|
+
sequenceNumber: this.#chunkSequence++,
|
|
1277
|
+
// Name the span 'tool-result' for consistency (tool-call → tool-result)
|
|
1278
|
+
span: this.#currentStepSpan?.createChildSpan({
|
|
1279
|
+
name: `chunk: 'tool-result'`,
|
|
1280
|
+
type: observability.SpanType.MODEL_CHUNK,
|
|
1281
|
+
attributes: {
|
|
1282
|
+
chunkType: "tool-result",
|
|
1283
|
+
sequenceNumber: this.#chunkSequence - 1
|
|
1284
|
+
}
|
|
1285
|
+
})
|
|
1286
|
+
};
|
|
1287
|
+
this.#toolOutputAccumulators.set(toolCallId, acc);
|
|
1288
|
+
}
|
|
1289
|
+
if (output && typeof output === "object" && "type" in output) {
|
|
1290
|
+
const innerType = output.type;
|
|
1291
|
+
switch (innerType) {
|
|
1292
|
+
case "text-delta":
|
|
1293
|
+
if (output.payload?.text) {
|
|
1294
|
+
acc.text += output.payload.text;
|
|
1295
|
+
}
|
|
1296
|
+
break;
|
|
1297
|
+
case "reasoning-delta":
|
|
1298
|
+
if (output.payload?.text) {
|
|
1299
|
+
acc.reasoning += output.payload.text;
|
|
1300
|
+
}
|
|
1301
|
+
break;
|
|
1302
|
+
case "finish":
|
|
1303
|
+
case "workflow-finish":
|
|
1304
|
+
this.#endToolOutputSpan(toolCallId);
|
|
1305
|
+
break;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* End a tool output span and clean up the accumulator
|
|
1311
|
+
*/
|
|
1312
|
+
#endToolOutputSpan(toolCallId) {
|
|
1313
|
+
const acc = this.#toolOutputAccumulators.get(toolCallId);
|
|
1314
|
+
if (!acc) return;
|
|
1315
|
+
const output = {
|
|
1316
|
+
toolCallId: acc.toolCallId,
|
|
1317
|
+
toolName: acc.toolName
|
|
1318
|
+
};
|
|
1319
|
+
if (acc.text) {
|
|
1320
|
+
output.text = acc.text;
|
|
1321
|
+
}
|
|
1322
|
+
if (acc.reasoning) {
|
|
1323
|
+
output.reasoning = acc.reasoning;
|
|
1324
|
+
}
|
|
1325
|
+
acc.span?.end({ output });
|
|
1326
|
+
this.#toolOutputAccumulators.delete(toolCallId);
|
|
1327
|
+
this.#streamedToolCallIds.add(toolCallId);
|
|
1328
|
+
}
|
|
1185
1329
|
/**
|
|
1186
1330
|
* Wraps a stream with model tracing transform to track MODEL_STEP and MODEL_CHUNK spans.
|
|
1187
1331
|
*
|
|
@@ -1192,6 +1336,13 @@ var ModelSpanTracker = class {
|
|
|
1192
1336
|
return stream.pipeThrough(
|
|
1193
1337
|
new web.TransformStream({
|
|
1194
1338
|
transform: (chunk, controller) => {
|
|
1339
|
+
switch (chunk.type) {
|
|
1340
|
+
case "text-delta":
|
|
1341
|
+
case "tool-call-delta":
|
|
1342
|
+
case "reasoning-delta":
|
|
1343
|
+
this.#captureCompletionStartTime();
|
|
1344
|
+
break;
|
|
1345
|
+
}
|
|
1195
1346
|
controller.enqueue(chunk);
|
|
1196
1347
|
switch (chunk.type) {
|
|
1197
1348
|
case "text-start":
|
|
@@ -1225,6 +1376,19 @@ var ModelSpanTracker = class {
|
|
|
1225
1376
|
case "start":
|
|
1226
1377
|
case "finish":
|
|
1227
1378
|
break;
|
|
1379
|
+
case "tool-output":
|
|
1380
|
+
this.#handleToolOutputChunk(chunk);
|
|
1381
|
+
break;
|
|
1382
|
+
case "tool-result": {
|
|
1383
|
+
const toolCallId = chunk.payload?.toolCallId;
|
|
1384
|
+
if (toolCallId && this.#streamedToolCallIds.has(toolCallId)) {
|
|
1385
|
+
this.#streamedToolCallIds.delete(toolCallId);
|
|
1386
|
+
break;
|
|
1387
|
+
}
|
|
1388
|
+
const { args, ...cleanPayload } = chunk.payload || {};
|
|
1389
|
+
this.#createEventSpan(chunk.type, cleanPayload);
|
|
1390
|
+
break;
|
|
1391
|
+
}
|
|
1228
1392
|
// Default: auto-create event span for all other chunk types
|
|
1229
1393
|
default: {
|
|
1230
1394
|
let outputPayload = chunk.payload;
|
|
@@ -1436,6 +1600,9 @@ function deepClean(value, options = {}, _seen = /* @__PURE__ */ new WeakSet(), _
|
|
|
1436
1600
|
return "[Circular]";
|
|
1437
1601
|
}
|
|
1438
1602
|
_seen.add(value);
|
|
1603
|
+
if (value instanceof Date) {
|
|
1604
|
+
return value;
|
|
1605
|
+
}
|
|
1439
1606
|
if (Array.isArray(value)) {
|
|
1440
1607
|
return value.map((item) => deepClean(item, options, _seen, _depth + 1));
|
|
1441
1608
|
}
|
|
@@ -2324,6 +2491,11 @@ var Observability = class extends base.MastraBase {
|
|
|
2324
2491
|
}
|
|
2325
2492
|
};
|
|
2326
2493
|
|
|
2494
|
+
// src/tracing-options.ts
|
|
2495
|
+
function buildTracingOptions(...updaters) {
|
|
2496
|
+
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2327
2499
|
exports.BaseExporter = BaseExporter;
|
|
2328
2500
|
exports.BaseObservabilityInstance = BaseObservabilityInstance;
|
|
2329
2501
|
exports.BaseSpan = BaseSpan;
|
|
@@ -2338,6 +2510,7 @@ exports.Observability = Observability;
|
|
|
2338
2510
|
exports.SamplingStrategyType = SamplingStrategyType;
|
|
2339
2511
|
exports.SensitiveDataFilter = SensitiveDataFilter;
|
|
2340
2512
|
exports.TestExporter = TestExporter;
|
|
2513
|
+
exports.buildTracingOptions = buildTracingOptions;
|
|
2341
2514
|
exports.deepClean = deepClean;
|
|
2342
2515
|
exports.getExternalParentId = getExternalParentId;
|
|
2343
2516
|
exports.observabilityConfigValueSchema = observabilityConfigValueSchema;
|