@mastra/datadog 1.1.1-alpha.0 → 1.2.0-alpha.2

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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # @mastra/datadog
2
2
 
3
+ ## 1.2.0-alpha.2
4
+
5
+ ### Minor Changes
6
+
7
+ - Mastra Eval results are now forwarded to Datadog. ([#16185](https://github.com/mastra-ai/mastra/pull/16185))
8
+
9
+ - Mapped `MODEL_INFERENCE` spans to Datadog's `llm` kind (with token usage and model/provider attached) and `MODEL_STEP` to `workflow`. Falls back to the previous mapping when paired with an older `@mastra/core` that does not emit `MODEL_INFERENCE`. ([#16363](https://github.com/mastra-ai/mastra/pull/16363))
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [[`6742347`](https://github.com/mastra-ai/mastra/commit/6742347d71955d7639adc9ddf6ff8282de7ee3ba), [`7b0ad1f`](https://github.com/mastra-ai/mastra/commit/7b0ad1f5c53dc118c6da12ae82ae2587037dc2b8), [`62666c3`](https://github.com/mastra-ai/mastra/commit/62666c367eaeac3941ead454b1d38810cc855721), [`4af2160`](https://github.com/mastra-ai/mastra/commit/4af2160322f4718cac421930cce85641e9512389), [`b2fd6be`](https://github.com/mastra-ai/mastra/commit/b2fd6beef989f5e463c9a33d8a6c20ac1800e011), [`136c959`](https://github.com/mastra-ai/mastra/commit/136c9592fb0eeb0cd212f28629d8a29b7557a2fc), [`00106be`](https://github.com/mastra-ai/mastra/commit/00106bede59b81e5b0e9cd6aad8d3b5dbc336387), [`4df7cc7`](https://github.com/mastra-ai/mastra/commit/4df7cc79342fd065fe7fdeef93c094db14b12bcd), [`aca3121`](https://github.com/mastra-ai/mastra/commit/aca31211233dac25459f140ea4fcfb3a5af64c18), [`7b0ad1f`](https://github.com/mastra-ai/mastra/commit/7b0ad1f5c53dc118c6da12ae82ae2587037dc2b8), [`9cdf38e`](https://github.com/mastra-ai/mastra/commit/9cdf38e58506e1109c8b38f97cd7770978a4218e), [`990851e`](https://github.com/mastra-ai/mastra/commit/990851edcb0e30be5c2c18b6532f1a876cc2d335), [`6068a6c`](https://github.com/mastra-ai/mastra/commit/6068a6c42950fad3ebfc92346417896ba60803d2), [`00106be`](https://github.com/mastra-ai/mastra/commit/00106bede59b81e5b0e9cd6aad8d3b5dbc336387), [`e2a079c`](https://github.com/mastra-ai/mastra/commit/e2a079cc3755b1895f7bd5dc36e9be81b11c7c22), [`534a456`](https://github.com/mastra-ai/mastra/commit/534a456a25e4df1e5407e7e632f4cb3b1fa14f9d), [`36bae07`](https://github.com/mastra-ai/mastra/commit/36bae07c0e70b1b3006f2fd20830e8883dcbd066)]:
14
+ - @mastra/core@1.33.0-alpha.7
15
+ - @mastra/observability@1.12.0-alpha.1
16
+
17
+ ## 1.1.1-alpha.1
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies [[`00ef282`](https://github.com/mastra-ai/mastra/commit/00ef2826034d006b984b3f19cd33ba0bba14d6c6)]:
22
+ - @mastra/observability@1.12.0-alpha.0
23
+
3
24
  ## 1.1.1-alpha.0
4
25
 
5
26
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EAIZ,mBAAmB,EACnB,iBAAiB,EACjB,QAAQ,EACR,OAAO,EACR,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA8DhE;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,YAAa,YAAW,mBAAmB;IAC5E,IAAI,SAAoB;IAExB,OAAO,CAAC,MAAM,CAA8E;IAC5F,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,cAAc,CAA6B;gBAEvC,MAAM,GAAE,mBAAwB;IAyC5C;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,SAAS;IAgErE;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIrE;;OAEG;IACH,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAIvD,OAAO,CAAC,sBAAsB;IAmB9B;;OAEG;cACa,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BvE,OAAO,CAAC,kBAAkB;IA0C1B,OAAO,CAAC,eAAe;IASvB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAwD7B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,gBAAgB;IA2FxB,OAAO,CAAC,YAAY;IASd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CA2BhC"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EAKZ,mBAAmB,EACnB,iBAAiB,EACjB,QAAQ,EACR,OAAO,EACR,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA+DhE;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,YAAa,YAAW,mBAAmB;IAC5E,IAAI,SAAoB;IAExB,OAAO,CAAC,MAAM,CAA8E;IAC5F,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,cAAc,CAA6B;gBAEvC,MAAM,GAAE,mBAAwB;IAyC5C;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,SAAS;IAgErE;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIrE;;OAEG;IACH,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAIvD,OAAO,CAAC,sBAAsB;IAmB9B;;OAEG;cACa,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BvE,OAAO,CAAC,kBAAkB;IA0C1B,OAAO,CAAC,eAAe;IASvB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAwD7B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,gBAAgB;IA8FxB,OAAO,CAAC,YAAY;IASd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CA2BhC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Feature detection for paired @mastra/core and @mastra/observability versions.
3
+ *
4
+ * `coreFeatures` is a hard peer dependency, so it can be imported statically.
5
+ * `observabilityFeatures` is loaded via dynamic import so this exporter degrades
6
+ * gracefully against older `@mastra/observability` versions that don't export it
7
+ * (per the pattern documented in `observability/mastra/src/features.ts`).
8
+ *
9
+ * Detection runs once at module load. Callers consume the result through the
10
+ * sync `isModelInferenceEnabled()` accessor, which conservatively returns
11
+ * `false` until detection settles — long enough only to cover the microtask
12
+ * window before any spans are emitted in practice.
13
+ */
14
+ /**
15
+ * Returns true when both packages report the `model-inference-span` feature,
16
+ * meaning MODEL_INFERENCE spans are emitted by the tracker. Drives the
17
+ * Datadog kind mapping and usage-source switch (legacy: MODEL_STEP carries
18
+ * 'llm' kind + usage; new: MODEL_INFERENCE does).
19
+ */
20
+ export declare function isModelInferenceEnabled(): boolean;
21
+ /**
22
+ * @internal Test-only override. Allows tests to simulate a paired older or
23
+ * newer `@mastra/observability` without juggling dynamic imports.
24
+ */
25
+ export declare function __setObservabilityFeaturesForTest(features: ReadonlySet<string> | undefined): void;
26
+ //# sourceMappingURL=features.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../src/features.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA0BH;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,GAAG,IAAI,CAIjG"}
package/dist/index.cjs CHANGED
@@ -4,12 +4,29 @@ var observability$1 = require('@mastra/core/observability');
4
4
  var utils = require('@mastra/core/utils');
5
5
  var observability = require('@mastra/observability');
6
6
  var tracer3 = require('dd-trace');
7
+ var features = require('@mastra/core/features');
7
8
 
8
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
10
 
10
11
  var tracer3__default = /*#__PURE__*/_interopDefault(tracer3);
11
12
 
12
13
  // src/bridge.ts
14
+ var FEATURE = "model-inference-span";
15
+ var observabilityFeatures;
16
+ var featureLoadPromise;
17
+ function loadObservabilityFeatures() {
18
+ if (!featureLoadPromise) {
19
+ featureLoadPromise = import('@mastra/observability').then((mod) => {
20
+ observabilityFeatures = mod.observabilityFeatures;
21
+ }).catch(() => {
22
+ });
23
+ }
24
+ return featureLoadPromise;
25
+ }
26
+ void loadObservabilityFeatures();
27
+ function isModelInferenceEnabled() {
28
+ return observabilityFeatures?.has(FEATURE) === true && features.coreFeatures.has(FEATURE);
29
+ }
13
30
 
14
31
  // src/metrics.ts
15
32
  function formatUsageMetrics(usage) {
@@ -35,18 +52,26 @@ function formatUsageMetrics(usage) {
35
52
  }
36
53
  return Object.keys(result).length > 0 ? result : void 0;
37
54
  }
38
- var SPAN_TYPE_TO_KIND = {
55
+ var SPAN_TYPE_TO_KIND_LEGACY = {
39
56
  [observability$1.SpanType.AGENT_RUN]: "agent",
40
- // MODEL_GENERATION is the wrapper around 1..N MODEL_STEPs (the actual API calls).
41
- // It maps to 'workflow' so Datadog doesn't double-count it as an LLM call.
42
57
  [observability$1.SpanType.MODEL_GENERATION]: "workflow",
43
- // MODEL_STEP is "Single model execution step within a generation (one API call)"
44
- // per packages/core/src/observability/types/tracing.ts, so it is the real LLM span.
45
58
  [observability$1.SpanType.MODEL_STEP]: "llm",
46
59
  [observability$1.SpanType.TOOL_CALL]: "tool",
47
60
  [observability$1.SpanType.MCP_TOOL_CALL]: "tool",
48
61
  [observability$1.SpanType.WORKFLOW_RUN]: "workflow"
49
62
  };
63
+ var SPAN_TYPE_TO_KIND_INFERENCE = {
64
+ [observability$1.SpanType.AGENT_RUN]: "agent",
65
+ [observability$1.SpanType.MODEL_GENERATION]: "workflow",
66
+ [observability$1.SpanType.MODEL_STEP]: "workflow",
67
+ [observability$1.SpanType.MODEL_INFERENCE]: "llm",
68
+ [observability$1.SpanType.TOOL_CALL]: "tool",
69
+ [observability$1.SpanType.MCP_TOOL_CALL]: "tool",
70
+ [observability$1.SpanType.WORKFLOW_RUN]: "workflow"
71
+ };
72
+ function getSpanTypeToKind() {
73
+ return isModelInferenceEnabled() ? SPAN_TYPE_TO_KIND_INFERENCE : SPAN_TYPE_TO_KIND_LEGACY;
74
+ }
50
75
  var tracerInitFlag = { done: false };
51
76
  function ensureTracer(config) {
52
77
  if (tracerInitFlag.done) return;
@@ -72,7 +97,7 @@ function ensureTracer(config) {
72
97
  tracerInitFlag.done = true;
73
98
  }
74
99
  function kindFor(spanType) {
75
- return SPAN_TYPE_TO_KIND[spanType] || "task";
100
+ return getSpanTypeToKind()[spanType] || "task";
76
101
  }
77
102
  function toDate(value) {
78
103
  return value instanceof Date ? value : new Date(value);
@@ -447,7 +472,8 @@ var DatadogBridge = class extends observability.BaseExporter {
447
472
  if (span.output !== void 0) {
448
473
  annotations.outputData = formatOutput(span.output, span.type);
449
474
  }
450
- if (span.type === observability$1.SpanType.MODEL_STEP) {
475
+ const usageSpanType = isModelInferenceEnabled() ? observability$1.SpanType.MODEL_INFERENCE : observability$1.SpanType.MODEL_STEP;
476
+ if (span.type === usageSpanType) {
451
477
  const usage = span.attributes?.usage;
452
478
  const metrics = formatUsageMetrics(usage);
453
479
  if (metrics) {
@@ -713,7 +739,8 @@ var DatadogExporter = class extends observability.BaseExporter {
713
739
  if (span.output !== void 0) {
714
740
  annotations.outputData = formatOutput(span.output, span.type);
715
741
  }
716
- if (span.type === observability$1.SpanType.MODEL_STEP) {
742
+ const usageSpanType = isModelInferenceEnabled() ? observability$1.SpanType.MODEL_INFERENCE : observability$1.SpanType.MODEL_STEP;
743
+ if (span.type === usageSpanType) {
717
744
  const usage = span.attributes?.usage;
718
745
  const metrics = formatUsageMetrics(usage);
719
746
  if (metrics) {
@@ -783,6 +810,63 @@ var DatadogExporter = class extends observability.BaseExporter {
783
810
  }
784
811
  return annotations;
785
812
  }
813
+ /**
814
+ * Submit an eval score to Datadog LLM Observability for the matching ddSpan.
815
+ *
816
+ * Ordering constraint: the matching span must have already been emitted to dd-trace
817
+ * (i.e. its `SPAN_ENDED` event must have been processed and the trace tree flushed).
818
+ * On Mastra's normal scoring path this is always true — scorer hooks fire after the
819
+ * scored entity completes, so the root span has ended by the time `onScoreEvent` runs.
820
+ *
821
+ * If a score arrives for an unexported span (either before `SPAN_ENDED` or after the
822
+ * `traceState` entry has been cleaned up), the event is dropped and a warning is logged
823
+ * so the misuse is observable. Scores must therefore only be submitted for spans whose
824
+ * lifecycle has completed.
825
+ */
826
+ async onScoreEvent(event) {
827
+ if (this.isDisabled || !tracer3__default.default.llmobs?.submitEvaluation) return;
828
+ const { score } = event;
829
+ if (!score.traceId || !score.spanId) {
830
+ this.logger.warn("Datadog exporter: dropping score with no traceId/spanId", {
831
+ scorerId: score.scorerId
832
+ });
833
+ return;
834
+ }
835
+ const ctx = this.traceState.get(score.traceId)?.contexts.get(score.spanId);
836
+ const exported = ctx?.exported;
837
+ if (!exported) {
838
+ this.logger.warn(
839
+ "Datadog exporter: dropping score for span that has not been emitted to dd-trace yet (span_ended must be processed before submitting a score for it)",
840
+ {
841
+ traceId: score.traceId,
842
+ spanId: score.spanId,
843
+ scorerId: score.scorerId
844
+ }
845
+ );
846
+ return;
847
+ }
848
+ try {
849
+ tracer3__default.default.llmobs.submitEvaluation(
850
+ { traceId: exported.traceId, spanId: exported.spanId },
851
+ {
852
+ label: score.scorerName ?? score.scorerId,
853
+ value: score.score,
854
+ metricType: "score",
855
+ mlApp: this.config.mlApp,
856
+ timestampMs: score.timestamp instanceof Date ? score.timestamp.getTime() : Date.now(),
857
+ ...score.reason ? { reasoning: score.reason } : {},
858
+ ...score.metadata ? { metadata: score.metadata } : {}
859
+ }
860
+ );
861
+ } catch (err) {
862
+ this.logger.error("Datadog exporter: Failed to submit evaluation", {
863
+ error: err,
864
+ traceId: score.traceId,
865
+ spanId: score.spanId,
866
+ scorerId: score.scorerId
867
+ });
868
+ }
869
+ }
786
870
  /**
787
871
  * Force flush any buffered spans without shutting down the exporter.
788
872
  * This is useful in serverless environments where you need to ensure spans