@mastra/observability 1.17.5-alpha.2 → 1.17.6-alpha.0

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 CHANGED
@@ -1792,7 +1792,38 @@ function getProvidedCostContext(attrs, usage) {
1792
1792
  });
1793
1793
  return contexts;
1794
1794
  }
1795
+ /**
1796
+ * Entity types the processor runner assigns to the spans it creates, one per
1797
+ * pipeline phase.
1798
+ */
1799
+ const PROCESSOR_ENTITY_TYPES = /* @__PURE__ */ new Set([
1800
+ _mastra_core_observability.EntityType.INPUT_PROCESSOR,
1801
+ _mastra_core_observability.EntityType.INPUT_STEP_PROCESSOR,
1802
+ _mastra_core_observability.EntityType.OUTPUT_PROCESSOR,
1803
+ _mastra_core_observability.EntityType.OUTPUT_STEP_PROCESSOR,
1804
+ _mastra_core_observability.EntityType.TOOL_RESULT_PROCESSOR
1805
+ ]);
1806
+ /**
1807
+ * Whether this span measures a processor running, for `mastra_processor_duration_ms`.
1808
+ *
1809
+ * A processor may declare a domain span type (e.g. the skills processor emits
1810
+ * `SKILL_ACTION`), so `PROCESSOR_RUN` alone no longer identifies one. A
1811
+ * processor entity type alone is not enough either: spans that are not
1812
+ * processors borrow one — observational memory wraps its observer and reflector
1813
+ * model calls in a `GENERIC` span tagged `OUTPUT_STEP_PROCESSOR`, and counting
1814
+ * those model-call durations would swamp a metric measuring processor overhead.
1815
+ *
1816
+ * So require the pipeline attribute the runner stamps on every processor span
1817
+ * it creates ('legacy' from the runner, 'workflow' from processor workflows),
1818
+ * which spans merely borrowing the entity type do not set.
1819
+ */
1820
+ function isProcessorSpan(span) {
1821
+ if (!span.entityType || !PROCESSOR_ENTITY_TYPES.has(span.entityType)) return false;
1822
+ if (span.type === _mastra_core_observability.SpanType.PROCESSOR_RUN) return true;
1823
+ return Boolean(span.attributes?.processorExecutor);
1824
+ }
1795
1825
  function getDurationMetricName(span) {
1826
+ if (isProcessorSpan(span)) return "mastra_processor_duration_ms";
1796
1827
  switch (span.type) {
1797
1828
  case _mastra_core_observability.SpanType.AGENT_RUN: return "mastra_agent_duration_ms";
1798
1829
  case _mastra_core_observability.SpanType.TOOL_CALL:
@@ -2851,6 +2882,8 @@ var BaseSpan = class BaseSpan {
2851
2882
  correlationContext;
2852
2883
  /** Child spans that have started but not yet ended */
2853
2884
  #openChildren;
2885
+ /** The span whose open-child set currently tracks this span: the parent, or a live ancestor after promotion */
2886
+ #openChildrenOwner;
2854
2887
  /**
2855
2888
  * Subclasses can override to unconditionally mark the span as excluded.
2856
2889
  * NoOpSpan uses this because it is never exported regardless of config.
@@ -2873,7 +2906,10 @@ var BaseSpan = class BaseSpan {
2873
2906
  this.tracingPolicy = options.tracingPolicy;
2874
2907
  this.traceState = options.traceState;
2875
2908
  const parent = options.parent;
2876
- if (!this.isEvent && parent instanceof BaseSpan && parent.isValid) (parent.#openChildren ??= /* @__PURE__ */ new Set()).add(this);
2909
+ if (!this.isEvent && parent instanceof BaseSpan && parent.isValid) {
2910
+ (parent.#openChildren ??= /* @__PURE__ */ new Set()).add(this);
2911
+ this.#openChildrenOwner = parent;
2912
+ }
2877
2913
  this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
2878
2914
  const entityParent = this.getParentSpan(false);
2879
2915
  this.entityType = options.entityType ?? entityParent?.entityType;
@@ -2916,10 +2952,34 @@ var BaseSpan = class BaseSpan {
2916
2952
  if (this.#openChildren) for (const child of [...this.#openChildren]) child.endTree(options);
2917
2953
  this.end(options);
2918
2954
  }
2919
- /** Release this span from its parent's open-child set once it has ended */
2955
+ /** Close any still-open descendant spans without applying options to them */
2956
+ endOpenDescendants() {
2957
+ if (this.#openChildren) for (const child of [...this.#openChildren]) child.endTree();
2958
+ }
2959
+ /**
2960
+ * Release this span from its parent's open-child set once it has ended.
2961
+ * Children still open at that moment are handed to the nearest ancestor
2962
+ * that has not ended, so a later endTree() on that ancestor can still
2963
+ * reach them (e.g. a model span that finalizes on abort before the
2964
+ * agent run's terminal handler closes the tree).
2965
+ */
2920
2966
  detachFromParent() {
2921
- const parent = this.parent;
2922
- if (parent instanceof BaseSpan) parent.#openChildren?.delete(this);
2967
+ const owner = this.#openChildrenOwner;
2968
+ if (owner) {
2969
+ owner.#openChildren?.delete(this);
2970
+ this.#openChildrenOwner = void 0;
2971
+ }
2972
+ if (this.#openChildren?.size) {
2973
+ let ancestor = this.parent;
2974
+ while (ancestor instanceof BaseSpan && ancestor.endTime) ancestor = ancestor.parent;
2975
+ if (ancestor instanceof BaseSpan) {
2976
+ for (const child of this.#openChildren) {
2977
+ (ancestor.#openChildren ??= /* @__PURE__ */ new Set()).add(child);
2978
+ child.#openChildrenOwner = ancestor;
2979
+ }
2980
+ this.#openChildren.clear();
2981
+ }
2982
+ }
2923
2983
  }
2924
2984
  createChildSpan(options) {
2925
2985
  return this.observabilityInstance.startSpan({
@@ -3142,6 +3202,7 @@ var DefaultSpan = class extends BaseSpan {
3142
3202
  end(options) {
3143
3203
  if (this.isEvent) return;
3144
3204
  if (this.endTime) return;
3205
+ if (options?.endTree) this.endOpenDescendants();
3145
3206
  this.endTime = /* @__PURE__ */ new Date();
3146
3207
  this.detachFromParent();
3147
3208
  if (options?.metadata) this.metadata = {
@@ -3157,7 +3218,7 @@ var DefaultSpan = class extends BaseSpan {
3157
3218
  }
3158
3219
  error(options) {
3159
3220
  if (this.isEvent) return;
3160
- const { error, endSpan = true, attributes, metadata } = options;
3221
+ const { error, endSpan = true, endTree, attributes, metadata } = options;
3161
3222
  if (metadata) this.metadata = {
3162
3223
  ...this.metadata,
3163
3224
  ...deepClean(this.prepareSpanMetadata(metadata), this.deepCleanOptions)
@@ -3181,7 +3242,8 @@ var DefaultSpan = class extends BaseSpan {
3181
3242
  ...deepClean(attributes, this.deepCleanOptions)
3182
3243
  };
3183
3244
  }
3184
- if (endSpan) this.end();
3245
+ if (endTree) this.end({ endTree: true });
3246
+ else if (endSpan) this.end();
3185
3247
  else this.update({});
3186
3248
  }
3187
3249
  update(options) {