@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/dist/index.d.ts CHANGED
@@ -11,4 +11,5 @@ export * from './spans/index.js';
11
11
  export * from './exporters/index.js';
12
12
  export * from './span_processors/index.js';
13
13
  export * from './model-tracing.js';
14
+ export * from './tracing-options.js';
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,cAAc,UAAU,CAAC;AAGzB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,cAAc,UAAU,CAAC;AAGzB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -946,6 +946,58 @@ var TestExporter = class extends BaseExporter {
946
946
  this.logger.info("TestExporter shutdown");
947
947
  }
948
948
  };
949
+
950
+ // src/usage.ts
951
+ function extractUsageMetrics(usage, providerMetadata) {
952
+ if (!usage) {
953
+ return {};
954
+ }
955
+ const inputDetails = {};
956
+ const outputDetails = {};
957
+ let inputTokens = usage.inputTokens;
958
+ const outputTokens = usage.outputTokens;
959
+ if (usage.cachedInputTokens) {
960
+ inputDetails.cacheRead = usage.cachedInputTokens;
961
+ }
962
+ if (usage.reasoningTokens) {
963
+ outputDetails.reasoning = usage.reasoningTokens;
964
+ }
965
+ const anthropic = providerMetadata?.anthropic;
966
+ if (anthropic) {
967
+ if (anthropic.cacheReadInputTokens) {
968
+ inputDetails.cacheRead = anthropic.cacheReadInputTokens;
969
+ }
970
+ if (anthropic.cacheCreationInputTokens) {
971
+ inputDetails.cacheWrite = anthropic.cacheCreationInputTokens;
972
+ }
973
+ if (anthropic.cacheReadInputTokens || anthropic.cacheCreationInputTokens) {
974
+ inputDetails.text = usage.inputTokens;
975
+ inputTokens = (usage.inputTokens ?? 0) + (anthropic.cacheReadInputTokens ?? 0) + (anthropic.cacheCreationInputTokens ?? 0);
976
+ }
977
+ }
978
+ const google = providerMetadata?.google;
979
+ if (google?.usageMetadata) {
980
+ if (google.usageMetadata.cachedContentTokenCount) {
981
+ inputDetails.cacheRead = google.usageMetadata.cachedContentTokenCount;
982
+ }
983
+ if (google.usageMetadata.thoughtsTokenCount) {
984
+ outputDetails.reasoning = google.usageMetadata.thoughtsTokenCount;
985
+ }
986
+ }
987
+ const result = {
988
+ inputTokens,
989
+ outputTokens
990
+ };
991
+ if (Object.keys(inputDetails).length > 0) {
992
+ result.inputDetails = inputDetails;
993
+ }
994
+ if (Object.keys(outputDetails).length > 0) {
995
+ result.outputDetails = outputDetails;
996
+ }
997
+ return result;
998
+ }
999
+
1000
+ // src/model-tracing.ts
949
1001
  var ModelSpanTracker = class {
950
1002
  #modelSpan;
951
1003
  #currentStepSpan;
@@ -953,9 +1005,23 @@ var ModelSpanTracker = class {
953
1005
  #accumulator = {};
954
1006
  #stepIndex = 0;
955
1007
  #chunkSequence = 0;
1008
+ #completionStartTime;
1009
+ /** Tracks tool output accumulators by toolCallId for consolidating sub-agent streams */
1010
+ #toolOutputAccumulators = /* @__PURE__ */ new Map();
1011
+ /** Tracks toolCallIds that had streaming output (to skip redundant tool-result spans) */
1012
+ #streamedToolCallIds = /* @__PURE__ */ new Set();
956
1013
  constructor(modelSpan) {
957
1014
  this.#modelSpan = modelSpan;
958
1015
  }
1016
+ /**
1017
+ * Capture the completion start time (time to first token) when the first content chunk arrives.
1018
+ */
1019
+ #captureCompletionStartTime() {
1020
+ if (this.#completionStartTime) {
1021
+ return;
1022
+ }
1023
+ this.#completionStartTime = /* @__PURE__ */ new Date();
1024
+ }
959
1025
  /**
960
1026
  * Get the tracing context for creating child spans.
961
1027
  * Returns the current step span if active, otherwise the model span.
@@ -972,10 +1038,16 @@ var ModelSpanTracker = class {
972
1038
  this.#modelSpan?.error(options);
973
1039
  }
974
1040
  /**
975
- * End the generation span
1041
+ * End the generation span with optional raw usage data.
1042
+ * If usage is provided, it will be converted to UsageStats with cache token details.
976
1043
  */
977
1044
  endGeneration(options) {
978
- this.#modelSpan?.end(options);
1045
+ const { usage, providerMetadata, ...spanOptions } = options ?? {};
1046
+ if (spanOptions.attributes) {
1047
+ spanOptions.attributes.completionStartTime = this.#completionStartTime;
1048
+ spanOptions.attributes.usage = extractUsageMetrics(usage, providerMetadata);
1049
+ }
1050
+ this.#modelSpan?.end(spanOptions);
979
1051
  }
980
1052
  /**
981
1053
  * Update the generation span
@@ -1005,9 +1077,10 @@ var ModelSpanTracker = class {
1005
1077
  #endStepSpan(payload) {
1006
1078
  if (!this.#currentStepSpan) return;
1007
1079
  const output = payload.output;
1008
- const { usage, ...otherOutput } = output;
1080
+ const { usage: rawUsage, ...otherOutput } = output;
1009
1081
  const stepResult = payload.stepResult;
1010
1082
  const metadata = payload.metadata;
1083
+ const usage = extractUsageMetrics(rawUsage, metadata?.providerMetadata);
1011
1084
  const cleanMetadata = metadata ? { ...metadata } : void 0;
1012
1085
  if (cleanMetadata?.request) {
1013
1086
  delete cleanMetadata.request;
@@ -1180,6 +1253,77 @@ var ModelSpanTracker = class {
1180
1253
  break;
1181
1254
  }
1182
1255
  }
1256
+ /**
1257
+ * Handle tool-output chunks from sub-agents.
1258
+ * Consolidates streaming text/reasoning deltas into a single span per tool call.
1259
+ */
1260
+ #handleToolOutputChunk(chunk) {
1261
+ if (chunk.type !== "tool-output") return;
1262
+ const payload = chunk.payload;
1263
+ const { output, toolCallId, toolName } = payload;
1264
+ let acc = this.#toolOutputAccumulators.get(toolCallId);
1265
+ if (!acc) {
1266
+ if (!this.#currentStepSpan) {
1267
+ this.#startStepSpan();
1268
+ }
1269
+ acc = {
1270
+ toolName: toolName || "unknown",
1271
+ toolCallId,
1272
+ text: "",
1273
+ reasoning: "",
1274
+ sequenceNumber: this.#chunkSequence++,
1275
+ // Name the span 'tool-result' for consistency (tool-call → tool-result)
1276
+ span: this.#currentStepSpan?.createChildSpan({
1277
+ name: `chunk: 'tool-result'`,
1278
+ type: SpanType.MODEL_CHUNK,
1279
+ attributes: {
1280
+ chunkType: "tool-result",
1281
+ sequenceNumber: this.#chunkSequence - 1
1282
+ }
1283
+ })
1284
+ };
1285
+ this.#toolOutputAccumulators.set(toolCallId, acc);
1286
+ }
1287
+ if (output && typeof output === "object" && "type" in output) {
1288
+ const innerType = output.type;
1289
+ switch (innerType) {
1290
+ case "text-delta":
1291
+ if (output.payload?.text) {
1292
+ acc.text += output.payload.text;
1293
+ }
1294
+ break;
1295
+ case "reasoning-delta":
1296
+ if (output.payload?.text) {
1297
+ acc.reasoning += output.payload.text;
1298
+ }
1299
+ break;
1300
+ case "finish":
1301
+ case "workflow-finish":
1302
+ this.#endToolOutputSpan(toolCallId);
1303
+ break;
1304
+ }
1305
+ }
1306
+ }
1307
+ /**
1308
+ * End a tool output span and clean up the accumulator
1309
+ */
1310
+ #endToolOutputSpan(toolCallId) {
1311
+ const acc = this.#toolOutputAccumulators.get(toolCallId);
1312
+ if (!acc) return;
1313
+ const output = {
1314
+ toolCallId: acc.toolCallId,
1315
+ toolName: acc.toolName
1316
+ };
1317
+ if (acc.text) {
1318
+ output.text = acc.text;
1319
+ }
1320
+ if (acc.reasoning) {
1321
+ output.reasoning = acc.reasoning;
1322
+ }
1323
+ acc.span?.end({ output });
1324
+ this.#toolOutputAccumulators.delete(toolCallId);
1325
+ this.#streamedToolCallIds.add(toolCallId);
1326
+ }
1183
1327
  /**
1184
1328
  * Wraps a stream with model tracing transform to track MODEL_STEP and MODEL_CHUNK spans.
1185
1329
  *
@@ -1190,6 +1334,13 @@ var ModelSpanTracker = class {
1190
1334
  return stream.pipeThrough(
1191
1335
  new TransformStream({
1192
1336
  transform: (chunk, controller) => {
1337
+ switch (chunk.type) {
1338
+ case "text-delta":
1339
+ case "tool-call-delta":
1340
+ case "reasoning-delta":
1341
+ this.#captureCompletionStartTime();
1342
+ break;
1343
+ }
1193
1344
  controller.enqueue(chunk);
1194
1345
  switch (chunk.type) {
1195
1346
  case "text-start":
@@ -1223,6 +1374,19 @@ var ModelSpanTracker = class {
1223
1374
  case "start":
1224
1375
  case "finish":
1225
1376
  break;
1377
+ case "tool-output":
1378
+ this.#handleToolOutputChunk(chunk);
1379
+ break;
1380
+ case "tool-result": {
1381
+ const toolCallId = chunk.payload?.toolCallId;
1382
+ if (toolCallId && this.#streamedToolCallIds.has(toolCallId)) {
1383
+ this.#streamedToolCallIds.delete(toolCallId);
1384
+ break;
1385
+ }
1386
+ const { args, ...cleanPayload } = chunk.payload || {};
1387
+ this.#createEventSpan(chunk.type, cleanPayload);
1388
+ break;
1389
+ }
1226
1390
  // Default: auto-create event span for all other chunk types
1227
1391
  default: {
1228
1392
  let outputPayload = chunk.payload;
@@ -1434,6 +1598,9 @@ function deepClean(value, options = {}, _seen = /* @__PURE__ */ new WeakSet(), _
1434
1598
  return "[Circular]";
1435
1599
  }
1436
1600
  _seen.add(value);
1601
+ if (value instanceof Date) {
1602
+ return value;
1603
+ }
1437
1604
  if (Array.isArray(value)) {
1438
1605
  return value.map((item) => deepClean(item, options, _seen, _depth + 1));
1439
1606
  }
@@ -2322,6 +2489,11 @@ var Observability = class extends MastraBase {
2322
2489
  }
2323
2490
  };
2324
2491
 
2325
- export { BaseExporter, BaseObservabilityInstance, BaseSpan, CloudExporter, ConsoleExporter, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, ModelSpanTracker, NoOpSpan, Observability, SamplingStrategyType, SensitiveDataFilter, TestExporter, deepClean, getExternalParentId, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, samplingStrategySchema };
2492
+ // src/tracing-options.ts
2493
+ function buildTracingOptions(...updaters) {
2494
+ return updaters.reduce((opts, updater) => updater(opts), {});
2495
+ }
2496
+
2497
+ export { BaseExporter, BaseObservabilityInstance, BaseSpan, CloudExporter, ConsoleExporter, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, ModelSpanTracker, NoOpSpan, Observability, SamplingStrategyType, SensitiveDataFilter, TestExporter, buildTracingOptions, deepClean, getExternalParentId, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, samplingStrategySchema };
2326
2498
  //# sourceMappingURL=index.js.map
2327
2499
  //# sourceMappingURL=index.js.map