@mastra/observability 0.0.0-fix-8762-10172-link-langfuse-prompts-20251201220119 → 0.0.0-fix-request-context-as-query-key-20251209093005

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
@@ -953,9 +953,30 @@ var ModelSpanTracker = class {
953
953
  #accumulator = {};
954
954
  #stepIndex = 0;
955
955
  #chunkSequence = 0;
956
+ /** Tracks whether completionStartTime has been captured for this generation */
957
+ #completionStartTimeCaptured = false;
958
+ /** Tracks tool output accumulators by toolCallId for consolidating sub-agent streams */
959
+ #toolOutputAccumulators = /* @__PURE__ */ new Map();
960
+ /** Tracks toolCallIds that had streaming output (to skip redundant tool-result spans) */
961
+ #streamedToolCallIds = /* @__PURE__ */ new Set();
956
962
  constructor(modelSpan) {
957
963
  this.#modelSpan = modelSpan;
958
964
  }
965
+ /**
966
+ * Capture the completion start time (time to first token) when the first content chunk arrives.
967
+ * This is used by observability providers like Langfuse to calculate TTFT metrics.
968
+ */
969
+ #captureCompletionStartTime() {
970
+ if (this.#completionStartTimeCaptured || !this.#modelSpan) {
971
+ return;
972
+ }
973
+ this.#completionStartTimeCaptured = true;
974
+ this.#modelSpan.update({
975
+ attributes: {
976
+ completionStartTime: /* @__PURE__ */ new Date()
977
+ }
978
+ });
979
+ }
959
980
  /**
960
981
  * Get the tracing context for creating child spans.
961
982
  * Returns the current step span if active, otherwise the model span.
@@ -1180,6 +1201,77 @@ var ModelSpanTracker = class {
1180
1201
  break;
1181
1202
  }
1182
1203
  }
1204
+ /**
1205
+ * Handle tool-output chunks from sub-agents.
1206
+ * Consolidates streaming text/reasoning deltas into a single span per tool call.
1207
+ */
1208
+ #handleToolOutputChunk(chunk) {
1209
+ if (chunk.type !== "tool-output") return;
1210
+ const payload = chunk.payload;
1211
+ const { output, toolCallId, toolName } = payload;
1212
+ let acc = this.#toolOutputAccumulators.get(toolCallId);
1213
+ if (!acc) {
1214
+ if (!this.#currentStepSpan) {
1215
+ this.#startStepSpan();
1216
+ }
1217
+ acc = {
1218
+ toolName: toolName || "unknown",
1219
+ toolCallId,
1220
+ text: "",
1221
+ reasoning: "",
1222
+ sequenceNumber: this.#chunkSequence++,
1223
+ // Name the span 'tool-result' for consistency (tool-call → tool-result)
1224
+ span: this.#currentStepSpan?.createChildSpan({
1225
+ name: `chunk: 'tool-result'`,
1226
+ type: SpanType.MODEL_CHUNK,
1227
+ attributes: {
1228
+ chunkType: "tool-result",
1229
+ sequenceNumber: this.#chunkSequence - 1
1230
+ }
1231
+ })
1232
+ };
1233
+ this.#toolOutputAccumulators.set(toolCallId, acc);
1234
+ }
1235
+ if (output && typeof output === "object" && "type" in output) {
1236
+ const innerType = output.type;
1237
+ switch (innerType) {
1238
+ case "text-delta":
1239
+ if (output.payload?.text) {
1240
+ acc.text += output.payload.text;
1241
+ }
1242
+ break;
1243
+ case "reasoning-delta":
1244
+ if (output.payload?.text) {
1245
+ acc.reasoning += output.payload.text;
1246
+ }
1247
+ break;
1248
+ case "finish":
1249
+ case "workflow-finish":
1250
+ this.#endToolOutputSpan(toolCallId);
1251
+ break;
1252
+ }
1253
+ }
1254
+ }
1255
+ /**
1256
+ * End a tool output span and clean up the accumulator
1257
+ */
1258
+ #endToolOutputSpan(toolCallId) {
1259
+ const acc = this.#toolOutputAccumulators.get(toolCallId);
1260
+ if (!acc) return;
1261
+ const output = {
1262
+ toolCallId: acc.toolCallId,
1263
+ toolName: acc.toolName
1264
+ };
1265
+ if (acc.text) {
1266
+ output.text = acc.text;
1267
+ }
1268
+ if (acc.reasoning) {
1269
+ output.reasoning = acc.reasoning;
1270
+ }
1271
+ acc.span?.end({ output });
1272
+ this.#toolOutputAccumulators.delete(toolCallId);
1273
+ this.#streamedToolCallIds.add(toolCallId);
1274
+ }
1183
1275
  /**
1184
1276
  * Wraps a stream with model tracing transform to track MODEL_STEP and MODEL_CHUNK spans.
1185
1277
  *
@@ -1187,9 +1279,14 @@ var ModelSpanTracker = class {
1187
1279
  * create MODEL_STEP and MODEL_CHUNK spans for each semantic unit in the stream.
1188
1280
  */
1189
1281
  wrapStream(stream) {
1282
+ let captureCompletionStartTime = false;
1190
1283
  return stream.pipeThrough(
1191
1284
  new TransformStream({
1192
1285
  transform: (chunk, controller) => {
1286
+ if (!captureCompletionStartTime) {
1287
+ captureCompletionStartTime = true;
1288
+ this.#captureCompletionStartTime();
1289
+ }
1193
1290
  controller.enqueue(chunk);
1194
1291
  switch (chunk.type) {
1195
1292
  case "text-start":
@@ -1223,6 +1320,19 @@ var ModelSpanTracker = class {
1223
1320
  case "start":
1224
1321
  case "finish":
1225
1322
  break;
1323
+ case "tool-output":
1324
+ this.#handleToolOutputChunk(chunk);
1325
+ break;
1326
+ case "tool-result": {
1327
+ const toolCallId = chunk.payload?.toolCallId;
1328
+ if (toolCallId && this.#streamedToolCallIds.has(toolCallId)) {
1329
+ this.#streamedToolCallIds.delete(toolCallId);
1330
+ break;
1331
+ }
1332
+ const { args, ...cleanPayload } = chunk.payload || {};
1333
+ this.#createEventSpan(chunk.type, cleanPayload);
1334
+ break;
1335
+ }
1226
1336
  // Default: auto-create event span for all other chunk types
1227
1337
  default: {
1228
1338
  let outputPayload = chunk.payload;
@@ -1301,6 +1411,7 @@ var BaseSpan = class {
1301
1411
  output;
1302
1412
  errorInfo;
1303
1413
  metadata;
1414
+ tags;
1304
1415
  traceState;
1305
1416
  /** Parent span ID (for root spans that are children of external spans) */
1306
1417
  parentSpanId;
@@ -1315,6 +1426,7 @@ var BaseSpan = class {
1315
1426
  this.isEvent = options.isEvent ?? false;
1316
1427
  this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
1317
1428
  this.traceState = options.traceState;
1429
+ this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
1318
1430
  if (this.isEvent) {
1319
1431
  this.output = deepClean(options.output);
1320
1432
  } else {
@@ -1377,7 +1489,9 @@ var BaseSpan = class {
1377
1489
  errorInfo: this.errorInfo,
1378
1490
  isEvent: this.isEvent,
1379
1491
  isRootSpan: this.isRootSpan,
1380
- parentSpanId: this.getParentSpanId(includeInternalSpans)
1492
+ parentSpanId: this.getParentSpanId(includeInternalSpans),
1493
+ // Tags are only included for root spans
1494
+ ...this.isRootSpan && this.tags?.length ? { tags: this.tags } : {}
1381
1495
  };
1382
1496
  }
1383
1497
  get externalTraceId() {
@@ -1675,11 +1789,15 @@ var BaseObservabilityInstance = class extends MastraBase {
1675
1789
  } else {
1676
1790
  traceState = this.computeTraceState(tracingOptions);
1677
1791
  }
1678
- const enrichedMetadata = this.extractMetadataFromRequestContext(requestContext, metadata, traceState);
1792
+ const tracingMetadata = !options.parent ? tracingOptions?.metadata : void 0;
1793
+ const mergedMetadata = metadata || tracingMetadata ? { ...metadata, ...tracingMetadata } : void 0;
1794
+ const enrichedMetadata = this.extractMetadataFromRequestContext(requestContext, mergedMetadata, traceState);
1795
+ const tags = !options.parent ? tracingOptions?.tags : void 0;
1679
1796
  const span = this.createSpan({
1680
1797
  ...rest,
1681
1798
  metadata: enrichedMetadata,
1682
- traceState
1799
+ traceState,
1800
+ tags
1683
1801
  });
1684
1802
  if (span.isEvent) {
1685
1803
  this.emitSpanEnded(span);
@@ -2084,9 +2202,16 @@ var SensitiveDataFilter = class {
2084
2202
  /**
2085
2203
  * Recursively filter objects/arrays for sensitive keys.
2086
2204
  * Handles circular references by replacing with a marker.
2205
+ * Also attempts to parse and redact JSON strings.
2087
2206
  */
2088
2207
  deepFilter(obj, seen = /* @__PURE__ */ new WeakSet()) {
2089
2208
  if (obj === null || typeof obj !== "object") {
2209
+ if (typeof obj === "string") {
2210
+ const trimmed = obj.trim();
2211
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2212
+ return this.redactJsonString(obj);
2213
+ }
2214
+ }
2090
2215
  return obj;
2091
2216
  }
2092
2217
  if (seen.has(obj)) {
@@ -2139,6 +2264,22 @@ var SensitiveDataFilter = class {
2139
2264
  return normalizedKey === sensitiveField;
2140
2265
  });
2141
2266
  }
2267
+ /**
2268
+ * Attempt to parse a string as JSON and redact sensitive fields within it.
2269
+ * If parsing fails or no sensitive data is found, returns the original string.
2270
+ */
2271
+ redactJsonString(str) {
2272
+ try {
2273
+ const parsed = JSON.parse(str);
2274
+ if (parsed && typeof parsed === "object") {
2275
+ const filtered = this.deepFilter(parsed, /* @__PURE__ */ new WeakSet());
2276
+ return JSON.stringify(filtered);
2277
+ }
2278
+ return str;
2279
+ } catch {
2280
+ return str;
2281
+ }
2282
+ }
2142
2283
  /**
2143
2284
  * Redact a sensitive value.
2144
2285
  * - Full style: replaces with a fixed token.
@@ -2291,6 +2432,11 @@ var Observability = class extends MastraBase {
2291
2432
  }
2292
2433
  };
2293
2434
 
2294
- export { BaseExporter, BaseObservabilityInstance, BaseSpan, CloudExporter, ConsoleExporter, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, ModelSpanTracker, NoOpSpan, Observability, SamplingStrategyType, SensitiveDataFilter, TestExporter, deepClean, getExternalParentId, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, samplingStrategySchema };
2435
+ // src/tracing-options.ts
2436
+ function buildTracingOptions(...updaters) {
2437
+ return updaters.reduce((opts, updater) => updater(opts), {});
2438
+ }
2439
+
2440
+ export { BaseExporter, BaseObservabilityInstance, BaseSpan, CloudExporter, ConsoleExporter, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, ModelSpanTracker, NoOpSpan, Observability, SamplingStrategyType, SensitiveDataFilter, TestExporter, buildTracingOptions, deepClean, getExternalParentId, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, samplingStrategySchema };
2295
2441
  //# sourceMappingURL=index.js.map
2296
2442
  //# sourceMappingURL=index.js.map